已添加8个文件
已重命名1个文件
已修改8个文件
已删除6个文件
| | |
| | | "tslib": "^2.7.0", |
| | | "uview-plus": "^3.4.62", |
| | | "vue": "3.4.21", |
| | | "vue-i18n": "^9.14.2" |
| | | "vue-i18n": "^9.14.2", |
| | | "@vueup/vue-quill": "^1.2.0" |
| | | }, |
| | | "devDependencies": { |
| | | "@dcloudio/types": "^3.4.14", |
| | |
| | | "vite": "5.4.10", |
| | | "vue-tsc": "2.1.6" |
| | | } |
| | | } |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | import request from '@/utils/request'; |
| | | |
| | | export function getExamineList(data) { |
| | | return request({ |
| | | url: "/meeting/applicationList", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function getRoomEnum() { |
| | | return request({ |
| | | url: "/meeting/roomEnum", |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function saveMeetingApplication(data){ |
| | | return request({ |
| | | url: "/meeting/saveMeetingApplication", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function getMeetingPublish(data){ |
| | | return request({ |
| | | url: "/meeting/meetingPublishList", |
| | | method: "post", |
| | | data: data |
| | | }); |
| | | } |
| | | |
| | | export function getMeetingMinutesByMeetingId(id){ |
| | | return request({ |
| | | url: "/meeting/getMeetingMinutesByMeetingId/"+id, |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | export function saveMeetingMinutes(data){ |
| | | return request({ |
| | | url: "/meeting/saveMeetingMinutes", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | // èªå¨æ´¾å·¥ |
| | | export function productionDispatchList(query) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/productionDispatchList", |
| | | method: "post", |
| | | data: query, |
| | | }); |
| | | } |
| | | // è·åçæºæ£å¨å·¥ä½éæ°æ® |
| | | export function schedulingList(query) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/list", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | |
| | | // ä¿åçæºè®¾ç½® |
| | | export function addSpeculatTrading(data) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/addSpeculatTrading", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹çæºè®¾ç½® |
| | | export function updateSpeculatTrading(data) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/updateSpeculatTrading", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // æ¥è¯¢æèç |
| | | export function getLossRate() { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/loss", |
| | | method: "get", |
| | | }); |
| | | } |
| | | |
| | | // æ°å¢æèç |
| | | export function addLossRate(data) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/addLoss", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | // ä¿®æ¹æèç |
| | | export function updateLossRate(data) { |
| | | return request({ |
| | | url: "/salesLedger/scheduling/updateLoss", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | |
| | | params: query, |
| | | }); |
| | | } |
| | | // æ ¹æ®IDè·åå·¥å详æ
|
| | | export function getProductWorkOrderById(query) { |
| | | return request({ |
| | | url: "/productWorkOrder/getProductWorkOrderById", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | | // ç产æ¥å·¥ |
| | | export function productionReport(query) { |
| | | return request({ |
| | |
| | | data: query, |
| | | }); |
| | | } |
| | | // æ°å¢æ¥å·¥ |
| | | // æ°å¢äº§å主表 |
| | | export function addProductMain(data) { |
| | | return request({ |
| | | url: "/productionProductMain/addProductMain", |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="editor-container"> |
| | | <div class="editor"> |
| | | <QuillEditor v-model:content="content" |
| | | contentType="html" |
| | | @textChange="(e) => emit('update:modelValue', content)" |
| | | :options="options" |
| | | :style="styles" /> |
| | | </div> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, computed, watch } from "vue"; |
| | | import { QuillEditor } from "@vueup/vue-quill"; |
| | | import "@vueup/vue-quill/dist/vue-quill.snow.css"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | const props = defineProps({ |
| | | /* ç¼è¾å¨çå
容 */ |
| | | modelValue: { |
| | | type: String, |
| | | }, |
| | | /* é«åº¦ */ |
| | | height: { |
| | | type: Number, |
| | | default: null, |
| | | }, |
| | | /* æå°é«åº¦ */ |
| | | minHeight: { |
| | | type: Number, |
| | | default: null, |
| | | }, |
| | | /* åªè¯» */ |
| | | readOnly: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | /* ä¸ä¼ æä»¶å¤§å°éå¶(MB) */ |
| | | fileSize: { |
| | | type: Number, |
| | | default: 5, |
| | | }, |
| | | /* ç±»åï¼base64æ ¼å¼ãurlæ ¼å¼ï¼ */ |
| | | type: { |
| | | type: String, |
| | | default: "url", |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(["update:modelValue"]); |
| | | |
| | | const styles = computed(() => { |
| | | let style = {}; |
| | | if (props.minHeight) { |
| | | style.minHeight = `${props.minHeight}px`; |
| | | } |
| | | if (props.height) { |
| | | style.height = `${props.height}px`; |
| | | } |
| | | return style; |
| | | }); |
| | | |
| | | const content = ref(""); |
| | | |
| | | watch( |
| | | () => props.modelValue, |
| | | v => { |
| | | if (v !== content.value) { |
| | | content.value = v == undefined ? "<p></p>" : v; |
| | | } |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | |
| | | const options = { |
| | | theme: "snow", |
| | | bounds: document.body, |
| | | debug: "warn", |
| | | modules: { |
| | | // å·¥å
·æ é
ç½® |
| | | toolbar: [ |
| | | [{ align: [] }], // 坹齿¹å¼ |
| | | ["bold", "italic", "underline", "strike"], // å ç² æä½ ä¸å线 å é¤çº¿ |
| | | ["blockquote", "code-block"], // å¼ç¨ 代ç å |
| | | [{ list: "ordered" }, { list: "bullet" }], // æåºãæ åºå表 |
| | | [{ indent: "-1" }, { indent: "+1" }], // ç¼©è¿ |
| | | [{ size: ["small", false, "large", "huge"] }], // åä½å¤§å° |
| | | [{ header: [1, 2, 3, 4, 5, 6, false] }], // æ é¢ |
| | | [{ color: [] }, { background: [] }], // åä½é¢è²ãåä½èæ¯é¢è² |
| | | ["clean"], // æ¸
é¤ææ¬æ ¼å¼ |
| | | ["link", "image", "video"], // 龿¥ãå¾çãè§é¢ |
| | | ], |
| | | }, |
| | | placeholder: "请è¾å
¥å
容", |
| | | readOnly: props.readOnly, |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | | .editor-container { |
| | | width: 100%; |
| | | } |
| | | |
| | | .editor-img-uploader { |
| | | display: none; |
| | | } |
| | | |
| | | .editor { |
| | | width: 100%; |
| | | } |
| | | |
| | | .quill-editor { |
| | | border: 1px solid #e8e8e8; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | /* Quillç¼è¾å¨æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow) { |
| | | border-bottom: 1px solid #e8e8e8; |
| | | border-radius: 8px 8px 0 0; |
| | | padding: 8px 12px; |
| | | } |
| | | |
| | | :deep(.ql-container.ql-snow) { |
| | | min-height: 300px; |
| | | border-radius: 0 0 8px 8px; |
| | | } |
| | | |
| | | :deep(.ql-editor) { |
| | | min-height: 300px; |
| | | font-size: 14px; |
| | | line-height: 1.5; |
| | | padding: 12px; |
| | | } |
| | | |
| | | /* ç§»å¨ç«¯éé
*/ |
| | | @media (max-width: 768px) { |
| | | :deep(.ql-toolbar.ql-snow) { |
| | | padding: 6px 8px; |
| | | } |
| | | |
| | | :deep(.ql-editor) { |
| | | font-size: 13px; |
| | | padding: 10px; |
| | | } |
| | | } |
| | | |
| | | /* å¾çæ ·å¼ */ |
| | | :deep(.ql-editor img) { |
| | | max-width: 100%; |
| | | height: auto; |
| | | border-radius: 4px; |
| | | margin: 8px 0; |
| | | } |
| | | |
| | | /* å·¥å
·æ æé®æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow .ql-button) { |
| | | height: 28px; |
| | | width: 28px; |
| | | padding: 4px; |
| | | } |
| | | |
| | | :deep(.ql-toolbar.ql-snow .ql-picker-label) { |
| | | height: 28px; |
| | | padding: 4px 8px; |
| | | } |
| | | |
| | | /* æç¤ºæ¡æ ·å¼ */ |
| | | :deep(.ql-snow .ql-tooltip[data-mode="link"])::before { |
| | | content: "请è¾å
¥é¾æ¥å°å:"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-tooltip.ql-editing a.ql-action)::after { |
| | | border-right: 0px; |
| | | content: "ä¿å"; |
| | | padding-right: 0px; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-tooltip[data-mode="video"])::before { |
| | | content: "请è¾å
¥è§é¢å°å:"; |
| | | } |
| | | |
| | | /* åä½å¤§å°é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item)::before { |
| | | content: "14px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"])::before { |
| | | content: "10px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"])::before { |
| | | content: "18px"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"])::before { |
| | | content: "32px"; |
| | | } |
| | | |
| | | /* æ é¢é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item)::before { |
| | | content: "ææ¬"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"])::before { |
| | | content: "æ é¢1"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"])::before { |
| | | content: "æ é¢2"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"])::before { |
| | | content: "æ é¢3"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"])::before { |
| | | content: "æ é¢4"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"])::before { |
| | | content: "æ é¢5"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"])::before { |
| | | content: "æ é¢6"; |
| | | } |
| | | |
| | | /* åä½é项 */ |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-label)::before, |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-item)::before { |
| | | content: "æ ååä½"; |
| | | } |
| | | |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"])::before, |
| | | :deep(.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"])::before { |
| | | content: "衬线åä½"; |
| | | } |
| | | |
| | | :deep( |
| | | .ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"] |
| | | )::before, |
| | | :deep( |
| | | .ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"] |
| | | )::before { |
| | | content: "ç宽åä½"; |
| | | } |
| | | </style> |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetExamine/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®å®¡æ¹", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetExamine/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "审æ¹", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetPublish/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®åå¸", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetPublish/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "åå¸", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetSummary/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ä¼è®®æ»ç»", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/managementMeetings/meetSummary/approve", |
| | | "style": { |
| | | "navigationBarTitleText": "æ»ç»", |
| | | "navigationStyle": "custom" |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/cooperativeOffice/collaborativeApproval/detail", |
| | | "style": { |
| | | "navigationBarTitleText": "å®¡æ¹æµç¨", |
| | |
| | | } |
| | | }, |
| | | { |
| | | "path": "pages/productionManagement/productionReporting/index", |
| | | "path": "pages/productionManagement/productionReport/index", |
| | | "style": { |
| | | "navigationBarTitleText": "ç产æ¥å·¥", |
| | | "navigationStyle": "custom" |
| | |
| | | "navigationBarTitleText": "RuoYi", |
| | | "navigationBarBackgroundColor": "#FFFFFF" |
| | | } |
| | | } |
| | | } |
| | |
| | | <view class="hero-section"> |
| | | <view class="bg-img"> |
| | | <view class="hero-content"> |
| | | <text class="hero-title">æµ·å·å¼å¿é£å</text> |
| | | <text class="hero-title">åæ³°ä¼ä¸</text> |
| | | </view> |
| | | <view class="hero-wave"></view> |
| | | </view> |
| | |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- è¥éç®¡çæ¨¡å --> |
| | | <view class="common-module marketing-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">è¥é管ç</text> |
| | | </view> |
| | | </view> |
| | | <view class="module-content"> |
| | | <up-grid :border="false" |
| | | col="4"> |
| | | <up-grid-item v-for="(item, index) in marketingItems" |
| | | :key="index" |
| | | @click="handleCommonItemClick(item)"> |
| | | <view class="icon-container" |
| | | :style="{ background: item.bgColor }"> |
| | | <up-icon :name="item.icon" |
| | | :size="58" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-label">{{item.label}}</text> |
| | | </up-grid-item> |
| | | </up-grid> |
| | | </view> |
| | | </view> |
| | | <!-- éè´ç®¡ç模å --> |
| | | <view class="common-module purchase-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">éè´ç®¡ç</text> |
| | | </view> |
| | | </view> |
| | | <view class="module-content"> |
| | | <up-grid :border="false" |
| | | col="4"> |
| | | <up-grid-item v-for="(item, index) in purchaseItems" |
| | | :key="index" |
| | | @click="handleCommonItemClick(item)"> |
| | | <view class="icon-container" |
| | | :style="{ background: item.bgColor }"> |
| | | <up-icon :name="item.icon" |
| | | :size="58" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-label">{{item.label}}</text> |
| | | </up-grid-item> |
| | | </up-grid> |
| | | </view> |
| | | </view> |
| | | <!-- åååå
¬æ¨¡å --> |
| | | <view class="common-module collaboration-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">åååå
¬</text> |
| | | </view> |
| | | </view> |
| | | <view class="module-content"> |
| | | <up-grid :border="false" |
| | | col="4"> |
| | | <up-grid-item v-for="(item, index) in collaborationItems" |
| | | :key="index" |
| | | @click="handleCommonItemClick(item)"> |
| | | <view class="icon-container" |
| | | :style="{ background: item.bgColor }"> |
| | | <up-icon :name="item.icon" |
| | | :size="58" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-label">{{item.label}}</text> |
| | | </up-grid-item> |
| | | </up-grid> |
| | | </view> |
| | | </view> |
| | | <!-- å
¥åºç®¡ç --> |
| | | <view class="common-module collaboration-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">ä»å¨ç©æµ</text> |
| | | </view> |
| | | </view> |
| | | <view class="module-content"> |
| | | <up-grid :border="false" |
| | | col="4"> |
| | | <up-grid-item v-for="(item, index) in inventoryManagement" |
| | | :key="index" |
| | | @click="handleCommonItemClick(item)"> |
| | | <view class="icon-container" |
| | | :style="{ background: item.bgColor }"> |
| | | <up-icon :name="item.icon" |
| | | :size="58" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-label">{{item.label}}</text> |
| | | </up-grid-item> |
| | | </up-grid> |
| | | </view> |
| | | </view> |
| | | <!-- <view class="common-module marketing-module">--> |
| | | <!-- <view class="module-header">--> |
| | | <!-- <view class="module-title-container">--> |
| | | <!-- <text class="module-title">è¥é管ç</text>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <view class="module-content">--> |
| | | <!-- <up-grid :border="false"--> |
| | | <!-- col="4">--> |
| | | <!-- <up-grid-item v-for="(item, index) in marketingItems"--> |
| | | <!-- :key="index"--> |
| | | <!-- @click="handleCommonItemClick(item)">--> |
| | | <!-- <view class="icon-container"--> |
| | | <!-- :style="{ background: item.bgColor }">--> |
| | | <!-- <up-icon :name="item.icon"--> |
| | | <!-- :size="58"--> |
| | | <!-- color="#ffffff"></up-icon>--> |
| | | <!-- </view>--> |
| | | <!-- <text class="item-label">{{item.label}}</text>--> |
| | | <!-- </up-grid-item>--> |
| | | <!-- </up-grid>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <!– éè´ç®¡çæ¨¡å –>--> |
| | | <!-- <view class="common-module purchase-module">--> |
| | | <!-- <view class="module-header">--> |
| | | <!-- <view class="module-title-container">--> |
| | | <!-- <text class="module-title">éè´ç®¡ç</text>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <view class="module-content">--> |
| | | <!-- <up-grid :border="false"--> |
| | | <!-- col="4">--> |
| | | <!-- <up-grid-item v-for="(item, index) in purchaseItems"--> |
| | | <!-- :key="index"--> |
| | | <!-- @click="handleCommonItemClick(item)">--> |
| | | <!-- <view class="icon-container"--> |
| | | <!-- :style="{ background: item.bgColor }">--> |
| | | <!-- <up-icon :name="item.icon"--> |
| | | <!-- :size="58"--> |
| | | <!-- color="#ffffff"></up-icon>--> |
| | | <!-- </view>--> |
| | | <!-- <text class="item-label">{{item.label}}</text>--> |
| | | <!-- </up-grid-item>--> |
| | | <!-- </up-grid>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <!– åååå
¬æ¨¡å –>--> |
| | | <!-- <view class="common-module collaboration-module">--> |
| | | <!-- <view class="module-header">--> |
| | | <!-- <view class="module-title-container">--> |
| | | <!-- <text class="module-title">åååå
¬</text>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <view class="module-content">--> |
| | | <!-- <up-grid :border="false"--> |
| | | <!-- col="4">--> |
| | | <!-- <up-grid-item v-for="(item, index) in collaborationItems"--> |
| | | <!-- :key="index"--> |
| | | <!-- @click="handleCommonItemClick(item)">--> |
| | | <!-- <view class="icon-container"--> |
| | | <!-- :style="{ background: item.bgColor }">--> |
| | | <!-- <up-icon :name="item.icon"--> |
| | | <!-- :size="58"--> |
| | | <!-- color="#ffffff"></up-icon>--> |
| | | <!-- </view>--> |
| | | <!-- <text class="item-label">{{item.label}}</text>--> |
| | | <!-- </up-grid-item>--> |
| | | <!-- </up-grid>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- çäº§ç®¡æ§æ¨¡å --> |
| | | <view class="common-module production-module"> |
| | | <!-- <view class="common-module production-module">--> |
| | | <!-- <view class="module-header">--> |
| | | <!-- <view class="module-title-container">--> |
| | | <!-- <text class="module-title">ç产管æ§</text>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <view class="module-content">--> |
| | | <!-- <up-grid--> |
| | | <!-- :border="false"--> |
| | | <!-- col="4"--> |
| | | <!-- >--> |
| | | <!-- <up-grid-item--> |
| | | <!-- v-for="(item, index) in productionItems"--> |
| | | <!-- :key="index"--> |
| | | <!-- @click="handleCommonItemClick(item)"--> |
| | | <!-- >--> |
| | | <!-- <view class="icon-container" :style="{ background: item.bgColor }">--> |
| | | <!-- <up-icon--> |
| | | <!-- :name="item.icon"--> |
| | | <!-- :size="58"--> |
| | | <!-- color="#ffffff"--> |
| | | <!-- ></up-icon>--> |
| | | <!-- </view>--> |
| | | <!-- <text class="item-label">{{item.label}}</text>--> |
| | | <!-- </up-grid-item>--> |
| | | <!-- </up-grid>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- çäº§ç®¡æ§æ¨¡å --> |
| | | <view class="common-module equipment-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">ç产管æ§</text> |
| | |
| | | </view> |
| | | </view> |
| | | <!-- 设å¤ç®¡ç模å --> |
| | | <view class="common-module equipment-module"> |
| | | <view class="module-header"> |
| | | <view class="module-title-container"> |
| | | <text class="module-title">设å¤ç®¡ç</text> |
| | | </view> |
| | | </view> |
| | | <view class="module-content"> |
| | | <up-grid :border="false" |
| | | col="4"> |
| | | <up-grid-item v-for="(item, index) in equipmentItems" |
| | | :key="index" |
| | | @click="handleCommonItemClick(item)"> |
| | | <view class="icon-container" |
| | | :style="{ background: item.bgColor }"> |
| | | <up-icon :name="item.icon" |
| | | :size="58" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-label">{{item.label}}</text> |
| | | </up-grid-item> |
| | | </up-grid> |
| | | </view> |
| | | </view> |
| | | <!-- <view class="common-module equipment-module">--> |
| | | <!-- <view class="module-header">--> |
| | | <!-- <view class="module-title-container">--> |
| | | <!-- <text class="module-title">设å¤ç®¡ç</text>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | <!-- <view class="module-content">--> |
| | | <!-- <up-grid :border="false"--> |
| | | <!-- col="4">--> |
| | | <!-- <up-grid-item v-for="(item, index) in equipmentItems"--> |
| | | <!-- :key="index"--> |
| | | <!-- @click="handleCommonItemClick(item)">--> |
| | | <!-- <view class="icon-container"--> |
| | | <!-- :style="{ background: item.bgColor }">--> |
| | | <!-- <up-icon :name="item.icon"--> |
| | | <!-- :size="58"--> |
| | | <!-- color="#ffffff"></up-icon>--> |
| | | <!-- </view>--> |
| | | <!-- <text class="item-label">{{item.label}}</text>--> |
| | | <!-- </up-grid-item>--> |
| | | <!-- </up-grid>--> |
| | | <!-- </view>--> |
| | | <!-- </view>--> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, nextTick, reactive } from "vue"; |
| | | import dayjs from "dayjs"; |
| | | import { userLoginFacotryList, noticesList } from "@/api/login"; |
| | | import { userLoginFacotryList } from "@/api/login"; |
| | | import { getProductWorkOrderById } from "@/api/productionManagement/productionReporting"; |
| | | import modal from "@/plugins/modal"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const factoryId = ref(""); |
| | |
| | | label: "ä¼è®®ç³è¯·", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®å®¡æ¹", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®åå¸", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "ä¼è®®æ»ç»", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/xietongshenpi@2x.png", |
| | | label: "åå审æ¹", |
| | | }, |
| | |
| | | icon: "/static/images/icon/kehubaifang@2x.png", |
| | | label: "å®¢æ·æè®¿", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/qingjiaguanli@2x.png", |
| | | label: "éç¥å
Œ", |
| | | }, |
| | | ]); |
| | | // åååå
¬åè½æ°æ®inventoryManagement/receiptManagement |
| | | const inventoryManagement = reactive([ |
| | | { |
| | | icon: "/static/images/icon/rukuguanli@2x.png", |
| | | label: "èªå®ä¹å
¥åº", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/zidingyichuku.png", |
| | | label: "èªå®ä¹åºåº", |
| | | }, |
| | | ]); |
| | | |
| | | // ç产管æ§åè½æ°æ® |
| | | const productionItems = reactive([ |
| | | { |
| | | icon: "/static/images/icon/shengchandingdan@2x.png", |
| | | label: "ç产订å", |
| | | bgColor: "#FF9800", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/shengchanpaigong@2x.png", |
| | | label: "ç产派工", |
| | | bgColor: "#FF6B35", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/shengchanpaichan@2x.png", |
| | | label: "å·¥åºæäº§", |
| | | bgColor: "#E91E63", |
| | | }, |
| | | // { |
| | | // icon: "/static/images/icon/shengchandingdan@2x.png", |
| | | // label: "ç产订å", |
| | | // bgColor: "#FF9800", |
| | | // }, |
| | | // { |
| | | // icon: "/static/images/icon/shengchanpaigong@2x.png", |
| | | // label: "ç产派工", |
| | | // bgColor: "#FF6B35", |
| | | // }, |
| | | // { |
| | | // icon: "/static/images/icon/shengchanpaichan@2x.png", |
| | | // label: "å·¥åºæäº§", |
| | | // bgColor: "#E91E63", |
| | | // }, |
| | | { |
| | | icon: "/static/images/icon/shengchanbaogong@2x.png", |
| | | label: "ç产æ¥å·¥", |
| | | bgColor: "#673AB7", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/shengchanhesuan@2x.png", |
| | | label: "çäº§æ ¸ç®", |
| | | bgColor: "#3F51B5", |
| | | }, |
| | | // { |
| | | // icon: "/static/images/icon/shengchanhesuan@2x.png", |
| | | // label: "çäº§æ ¸ç®", |
| | | // bgColor: "#3F51B5", |
| | | // }, |
| | | ]); |
| | | |
| | | // 设å¤ç®¡çåè½æ°æ® |
| | | const equipmentItems = reactive([ |
| | | { |
| | | icon: "/static/images/icon/shebeitaizhang@2x.png", |
| | | label: "设å¤å°è´¦", |
| | | }, |
| | | // { |
| | | // icon: '/static/images/icon/shebeitaizhang@2x.png', |
| | | // label: '设å¤å°è´¦', |
| | | // }, |
| | | { |
| | | icon: "/static/images/icon/shbeibaoxiu@2x.png", |
| | | label: "è®¾å¤æ¥ä¿®", |
| | |
| | | icon: "/static/images/icon/xunjianshangchuan@2x.png", |
| | | label: "å·¡æ£ä¸ä¼ ", |
| | | }, |
| | | // { |
| | | // icon: '/static/images/icon/guzhangfenxi@2x.png', |
| | | // label: 'åæè¿½æº¯', |
| | | // bgColor: '#ff9800' |
| | | // }, |
| | | // { |
| | | // icon: '/static/images/icon/zhinengpaidan@2x.png', |
| | | // label: 'æºè½æ´¾å', |
| | | // bgColor: '#ff6b35' |
| | | // }, |
| | | // { |
| | | // icon: '/static/images/icon/zuoyezhidao@2x.png', |
| | | // label: 'ä½ä¸æå¯¼', |
| | | // bgColor: '#4caf50' |
| | | // }, |
| | | // { |
| | | // icon: '/static/images/icon/jieguoyanzheng@2x.png', |
| | | // label: 'ç»æéªè¯', |
| | | // bgColor: '#9c27b0' |
| | | // } |
| | | { |
| | | icon: "/static/images/icon/guzhangfenxi@2x.png", |
| | | label: "åæè¿½æº¯", |
| | | bgColor: "#ff9800", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/zhinengpaidan@2x.png", |
| | | label: "æºè½æ´¾å", |
| | | bgColor: "#ff6b35", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/zuoyezhidao@2x.png", |
| | | label: "ä½ä¸æå¯¼", |
| | | bgColor: "#4caf50", |
| | | }, |
| | | { |
| | | icon: "/static/images/icon/jieguoyanzheng@2x.png", |
| | | label: "ç»æéªè¯", |
| | | bgColor: "#9c27b0", |
| | | }, |
| | | ]); |
| | | |
| | | // å¤ç常ç¨åè½ç¹å» |
| | |
| | | url: "/pages/managementMeetings/meetApplication/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®å®¡æ¹": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetExamine/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®åå¸": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetPublish/index", |
| | | }); |
| | | break; |
| | | case "ä¼è®®æ»ç»": |
| | | uni.navigateTo({ |
| | | url: "/pages/managementMeetings/meetSummary/index", |
| | | }); |
| | | break; |
| | | case "åå审æ¹": |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/collaborativeApproval/index", |
| | |
| | | case "å®¢æ·æè®¿": |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/clientVisit/index", |
| | | }); |
| | | break; |
| | | case "éç¥å
Œ": |
| | | uni.navigateTo({ |
| | | url: "/pages/cooperativeOffice/noticeManagement/index", |
| | | }); |
| | | break; |
| | | case "èªå®ä¹å
¥åº": |
| | | uni.navigateTo({ |
| | | url: "/pages/inventoryManagement/receiptManagement/index", |
| | | }); |
| | | break; |
| | | case "èªå®ä¹åºåº": |
| | | uni.navigateTo({ |
| | | url: "/pages/inventoryManagement/issueManagement/index", |
| | | }); |
| | | break; |
| | | case "ç产订å": |
| | |
| | | break; |
| | | case "å·¥åºæäº§": |
| | | uni.navigateTo({ |
| | | url: "/pages/productionManagement/operationScheduling/index", |
| | | url: "/pages/productionManagement/processScheduling/index", |
| | | }); |
| | | break; |
| | | case "ç产æ¥å·¥": |
| | | getcode(); |
| | | // uni.navigateTo({ |
| | | // url: '/pages/productionManagement/productionReporting/index' |
| | | // }); |
| | | break; |
| | | case "çäº§æ ¸ç®": |
| | | uni.navigateTo({ |
| | | url: "/pages/productionManagement/productionCosting/index", |
| | | url: "/pages/productionManagement/productionAccounting/index", |
| | | }); |
| | | break; |
| | | case "设å¤å°è´¦": |
| | |
| | | }); |
| | | } |
| | | }; |
| | | const getcode = () => { |
| | | uni.scanCode({ |
| | | success: res => { |
| | | // è§£æäºç»´ç å
容 |
| | | const scanResult = res.result; |
| | | let orderRow = ""; |
| | | |
| | | // å°è¯ä»æ«ç ç»æä¸æåorderRowåæ° |
| | | try { |
| | | // å¤çæ··åæ ¼å¼: http://...?orderRow={...} |
| | | const orderRowStart = scanResult.indexOf("orderRow={"); |
| | | // æåä»orderRow={å¼å§çJSONå
容 |
| | | const jsonPart = scanResult.substring(orderRowStart + 9); // 9æ¯"orderRow=".length |
| | | // å°è¯ç´æ¥ä½¿ç¨è¿ä¸ªJSONé¨å |
| | | orderRow = jsonPart; |
| | | } catch (e) { |
| | | orderRow = ""; |
| | | } |
| | | try { |
| | | JSON.parse(orderRow); |
| | | } catch (error) { |
| | | modal.msgError("订åè§£æå¤±è´¥"); |
| | | return; |
| | | } |
| | | // æ«ç æåå跳转å°ç产æ¥å·¥é¡µé¢ï¼å¹¶ä¼ éorderRowåæ° |
| | | uni.navigateTo({ |
| | | url: `/pages/productionManagement/productionReporting/index?orderRow=${orderRow}`, |
| | | }); |
| | | }, |
| | | fail: err => { |
| | | uni.showToast({ |
| | | title: "æ«ç 失败", |
| | | icon: "none", |
| | | }); |
| | | // uni.navigateTo({ |
| | | // url: `/pages/productionManagement/productionReporting/index`, |
| | | // }); |
| | | }, |
| | | }); |
| | | }; |
| | | // å建对åç»ä»¶çå¼ç¨ |
| | | const uToastRef = ref(null); |
| | | |
| | | function getUserLoginFacotryList() { |
| | | userLoginFacotryList({ |
| | | userName: userStore.nickName, |
| | | }) |
| | | userLoginFacotryList({ userName: userStore.nickName }) |
| | | .then(res => { |
| | | // æ£æ¥res.dataæ¯å¦ä¸ºæ°ç» |
| | | factoryList.value[0] = []; |
| | |
| | | factoryList.value = []; |
| | | }); |
| | | } |
| | | const getcode = () => { |
| | | uni.scanCode({ |
| | | success: async res => { |
| | | // è§£æäºç»´ç å
容 |
| | | const scanResult = res.result; |
| | | let orderRow = ""; |
| | | |
| | | // å¤ææ«æç»ææ¯å¦ä¸ºçº¯æ°åï¼idï¼ |
| | | const isNumericId = /^\d+$/.test(scanResult.trim()); |
| | | |
| | | if (isNumericId) { |
| | | // 妿æ¯çº¯æ°åï¼æ ¹æ® id è·åå·¥åæ°æ® |
| | | const workOrderId = scanResult.trim(); |
| | | modal.loading("æ£å¨è·åå·¥åä¿¡æ¯..."); |
| | | try { |
| | | const workRes = await getProductWorkOrderById({ id: workOrderId }); |
| | | modal.closeLoading(); |
| | | |
| | | console.log("å·¥åæ¥è¯¢ç»æ:", workRes); |
| | | |
| | | if (workRes.code === 200 && workRes.data) { |
| | | // æ°æ¥å£è¿åçæ¯å个对象ï¼ä¸æ¯æ°ç» |
| | | const workData = workRes.data; |
| | | console.log("工忰æ®:", workData); |
| | | |
| | | orderRow = JSON.stringify({ |
| | | id: workData.id || workOrderId, |
| | | planQuantity: workData.planQuantity - workData.completeQuantity, |
| | | productProcessRouteItemId: |
| | | workData.productProcessRouteItemId || |
| | | workData.产åå·¥èºè·¯çº¿é¡¹ID || |
| | | "", |
| | | }); |
| | | |
| | | console.log("æé çorderRow:", orderRow); |
| | | } else { |
| | | modal.msgError("æªæ¾å°å¯¹åºçå·¥åä¿¡æ¯"); |
| | | return; |
| | | } |
| | | } catch (error) { |
| | | modal.closeLoading(); |
| | | console.error("è·åå·¥åä¿¡æ¯å¤±è´¥:", error); |
| | | modal.msgError("è·åå·¥åä¿¡æ¯å¤±è´¥: " + (error.message || "æªç¥é误")); |
| | | return; |
| | | } |
| | | } else { |
| | | // 妿䏿¯çº¯æ°åï¼å°è¯ä»æ«ç ç»æä¸æåorderRowåæ° |
| | | try { |
| | | // å¤çæ··åæ ¼å¼: http://...?orderRow={...} |
| | | const orderRowStart = scanResult.indexOf("orderRow={"); |
| | | if (orderRowStart !== -1) { |
| | | // æåä»orderRow={å¼å§çJSONå
容 |
| | | const jsonPart = scanResult.substring(orderRowStart + 9); // 9æ¯"orderRow=".length |
| | | orderRow = jsonPart; |
| | | } else { |
| | | // å¦æç´æ¥æ¯JSONå符串ï¼å°è¯è§£æ |
| | | orderRow = scanResult; |
| | | } |
| | | } catch (e) { |
| | | console.error(e, "è§£æå¤±è´¥====????====="); |
| | | orderRow = ""; |
| | | } |
| | | |
| | | // éªè¯æ¯å¦ä¸ºææçJSON |
| | | try { |
| | | JSON.parse(orderRow); |
| | | } catch (error) { |
| | | modal.msgError("订åè§£æå¤±è´¥ï¼è¯·æ£æ¥äºç»´ç æ ¼å¼"); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | console.log(orderRow, "orderRow======@@@@@@@@"); |
| | | // æ«ç æåå跳转å°ç产æ¥å·¥é¡µé¢ï¼å¹¶ä¼ éorderRowåæ° |
| | | uni.navigateTo({ |
| | | url: `/pages/productionManagement/productionReport/index?orderRow=${orderRow}`, |
| | | }); |
| | | }, |
| | | fail: err => { |
| | | uni.showToast({ |
| | | title: "æ«ç 失败", |
| | | icon: "none", |
| | | }); |
| | | }, |
| | | }); |
| | | }; |
| | | const changeFactory = async arr => { |
| | | show.value = false; |
| | | const factoryId = factoryListTem.value[arr.indexs[0]].deptId; |
| | |
| | | modal.closeLoading(); |
| | | }); |
| | | }; |
| | | |
| | | function loginSuccess(result) { |
| | | uni.reLaunch({ |
| | | url: "/pages/index", |
| | |
| | | uToastRef.value.success(`ç¹å»äºç¬¬${name + 1}个`); // 注æï¼è¿éå 1æ¯å 为é常æä»¬æ¯ä»ç¬¬1个å¼å§è®¡æ°ç |
| | | } |
| | | }; |
| | | const isShowNoticesList = ref(true); |
| | | // è·åå
¬åæ°é |
| | | const getNoticesList = () => { |
| | | if (!isShowNoticesList.value) { |
| | | return; |
| | | } |
| | | const current_date = dayjs().format("YYYY-MM-DD"); |
| | | noticesList({ |
| | | current: -1, |
| | | size: -1, |
| | | status: 1, |
| | | current_date, |
| | | }) |
| | | .then(resp => { |
| | | console.log("noticesList", resp); |
| | | if ( |
| | | resp.code != 200 || |
| | | !resp.data || |
| | | !resp.data.records || |
| | | !resp.data.records.length |
| | | ) { |
| | | return; |
| | | } |
| | | const res = uni.getAppAuthorizeSetting(); |
| | | if (res.notificationAuthorized == "denied") { |
| | | uni.showModal({ |
| | | title: "æç¤º", |
| | | content: "请å¨è®¾ç½®ä¸å¼å¯éç¥æé", |
| | | success: res => { |
| | | if (res.confirm) { |
| | | uni.openAppAuthorizeSetting({ |
| | | success: res => {}, |
| | | }); |
| | | } else { |
| | | isShowNoticesList.value = false; |
| | | } |
| | | }, |
| | | }); |
| | | return; |
| | | } |
| | | resp.data.records.map(item => { |
| | | createPushMessage(item.title); |
| | | }); |
| | | }) |
| | | .catch(error => { |
| | | // modal.msgError("è·åå
¬åæ°é:", error); |
| | | }); |
| | | }; |
| | | |
| | | const createPushMessage = text => { |
| | | uni.createPushMessage({ |
| | | title: "å
¬åéç¥", |
| | | content: text || "", |
| | | success: resp => { |
| | | console.log("success", resp); |
| | | isShowNoticesList.value = false; |
| | | }, |
| | | fail: resp => { |
| | | console.log("fail", resp); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | // è®¾ç½®ç¨æ·ä¿¡æ¯ |
| | |
| | | // å¯å¨éç¥ç¶æå®æ¶å¨ |
| | | startStatusTimer(); |
| | | }); |
| | | onShow(() => { |
| | | getNoticesList(); |
| | | }); |
| | | </script> |
| | | |
| | | |
| | | <style scoped lang="scss"> |
| | | .content { |
| | |
| | | letter-spacing: 0.03125rem; |
| | | text-shadow: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.5); |
| | | } |
| | | |
| | | .hero-subtitle { |
| | | font-size: 0.8125rem; |
| | | margin-top: 0.375rem; |
| | | } |
| | | |
| | | .hero-wave { |
| | | height: 2.75rem; |
| | | } |
| | |
| | | 0% { |
| | | transform: translateX(-100%) translateY(-100%) rotate(45deg); |
| | | } |
| | | |
| | | 100% { |
| | | transform: translateX(100%) translateY(100%) rotate(45deg); |
| | | } |
| | |
| | | opacity: 0; |
| | | transform: translateY(-1.25rem); |
| | | } |
| | | |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | |
| | | opacity: 0; |
| | | transform: translateY(1.25rem); |
| | | } |
| | | |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | |
| | | opacity: 0; |
| | | transform: translateY(0.5rem) scale(0.96); |
| | | } |
| | | |
| | | 100% { |
| | | opacity: 1; |
| | | transform: translateY(0) scale(1); |
| | |
| | | } |
| | | |
| | | .notice-unit { |
| | | color: #666666; |
| | | font-size: 0.875rem; |
| | | margin-left: 0.125rem; |
| | | font-weight: 600; |
| | | font-size: 1rem; |
| | | color: #1976d2; |
| | | margin-left: 0.25rem; |
| | | } |
| | | |
| | | /* åè½æ¨¡åæ ·å¼ */ |
| | |
| | | .content { |
| | | background: linear-gradient(135deg, #121317 0%, #161a20 100%); |
| | | } |
| | | |
| | | .content::before { |
| | | background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="dots" width="20" height="20" patternUnits="userSpaceOnUse"><circle cx="10" cy="10" r="1" fill="rgba(255, 255, 255, 0.05)"/></pattern></defs><rect width="100" height="100" fill="url(%23dots)"/></svg>'); |
| | | } |
| | | |
| | | .common-module { |
| | | background: linear-gradient(135deg, #1e1f24 0%, #23252b 100%); |
| | | box-shadow: 0 0.375rem 1.5rem rgba(0, 0, 0, 0.35); |
| | | } |
| | | |
| | | .module-title { |
| | | color: #e9edf3; |
| | | } |
| | | |
| | | .module-subtitle, |
| | | .item-label, |
| | | .notice-text, |
| | |
| | | .notice-label { |
| | | color: #c7cbd3; |
| | | } |
| | | |
| | | .notice { |
| | | background: linear-gradient(135deg, #1b2330 0%, #1a2432 100%); |
| | | border-color: rgba(255, 255, 255, 0.06); |
| | | box-shadow: 0 0.375rem 1.25rem rgba(0, 0, 0, 0.4); |
| | | } |
| | | |
| | | .notice-status, |
| | | .notice-number { |
| | | color: #8ab4ff; |
| | | } |
| | | |
| | | .bg-img { |
| | | background: linear-gradient(135deg, #1f4fb9 0%, #0e3a8a 100%); |
| | | } |
| | |
| | | from { |
| | | transform: rotate(0deg); |
| | | } |
| | | |
| | | to { |
| | | transform: rotate(360deg); |
| | | } |
| | |
| | | opacity: 0; |
| | | transform: translateY(-1.25rem); |
| | | } |
| | | |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | |
| | | opacity: 0; |
| | | transform: translateY(1.25rem); |
| | | } |
| | | |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | |
| | | opacity: 0; |
| | | transform: translateY(0.5rem) scale(0.96); |
| | | } |
| | | |
| | | 100% { |
| | | opacity: 1; |
| | | transform: translateY(0) scale(1); |
| | |
| | | .notice-left { |
| | | margin-right: 1rem; |
| | | } |
| | | |
| | | .notice-status { |
| | | font-size: 1rem; |
| | | } |
| | | |
| | | .notice-separator { |
| | | width: 0.0625rem; |
| | | height: 1.5rem; |
| | | margin-right: 1rem; |
| | | } |
| | | |
| | | .notice-label { |
| | | font-size: 0.875rem; |
| | | margin-right: 0.75rem; |
| | | } |
| | | |
| | | .notice-text { |
| | | font-size: 0.875rem; |
| | | } |
| | | |
| | | .notice-number { |
| | | font-size: 1rem; |
| | | margin-left: 0.25rem; |
| | | } |
| | | |
| | | .notice-unit { |
| | | font-size: 0.875rem; |
| | | margin-left: 0.125rem; |
| | |
| | | margin-top: 0.25rem; |
| | | margin-bottom: 0.625rem; |
| | | } |
| | | |
| | | .grid-text { |
| | | font-size: 0.875rem; |
| | | } |
| | |
| | | .common-module { |
| | | box-shadow: 0 0.375rem 1.5rem rgba(0, 0, 0, 0.35); |
| | | } |
| | | |
| | | .notice { |
| | | box-shadow: 0 0.375rem 1.25rem rgba(0, 0, 0, 0.4); |
| | | } |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="审æ¹" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <u-button class="reject-btn" |
| | | @click="handleReject">ä¸éè¿</u-button> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">éè¿</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine"; |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const isEdit = ref(false); |
| | | |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | }); |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const submitForm = status => { |
| | | // è°ç¨å端 |
| | | saveMeetingApplication({ id: approvalData.value.id, status: status }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("å®¡æ¹æäº¤æå"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "å®¡æ¹æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("å®¡æ¹æä½å¤±è´¥:", error); |
| | | showToast("å®¡æ¹æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleReject = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®ä¸éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(2); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®å®¡æ¹" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | å®¡æ¹ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getExamineList, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getExamineList({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
å®¡æ ¸"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetExamine/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetExamine/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="åå¸" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®è¯´æ</text> |
| | | <text class="info-value">{{ approvalData.description }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- å叿è§è¾å
¥ --> |
| | | <view v-if="isEdit" |
| | | class="approval-input"> |
| | | <view class="input-header"> |
| | | <text class="input-title">å叿è§</text> |
| | | </view> |
| | | <view class="input-content"> |
| | | <u-textarea v-model="approvalOpinion" |
| | | rows="4" |
| | | placeholder="请è¾å
¥å叿è§" |
| | | maxlength="200" |
| | | count /> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <!-- <u-button class="reject-btn" |
| | | @click="handleReject">ä¸éè¿</u-button> --> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">åå¸</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted, computed } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { saveMeetingApplication } from "@/api/managementMeetings/meetExamine"; |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const approvalOpinion = ref(""); |
| | | const isEdit = ref(false); |
| | | |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼é»è®¤å叿è§ä¸ºå½åå®¡æ¹æè§ |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | console.log(approvalData.value, "approvalData.value"); |
| | | }); |
| | | |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
åå¸"; |
| | | } else if (params == 1) { |
| | | return "å·²åå¸"; |
| | | } else if (params == 2) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const submitForm = status => { |
| | | // æ ¡éªåå¸æè§ |
| | | if (!approvalOpinion.value?.trim()) { |
| | | showToast("请è¾å
¥å叿è§"); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端 |
| | | saveMeetingApplication({ |
| | | id: approvalData.value.id, |
| | | publishStatus: status, |
| | | publishComment: approvalOpinion.value, // æ·»å åå¸æè§ |
| | | }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("å叿å"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "å叿ä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("å叿ä½å¤±è´¥:", error); |
| | | showToast("å叿ä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦åå¸è¯¥ä¼è®®åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | |
| | | const handleReject = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®ä¸éè¿è¯¥ä¼è®®ç³è¯·åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(2); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®åå¸" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | åå¸ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getMeetingPublish, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getMeetingPublish({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
åå¸"; |
| | | } else if (params == 1) { |
| | | return "å·²åå¸"; |
| | | } else if (params == 2) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetPublish/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetPublish/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <view class="approve-page"> |
| | | <PageHeader title="æ»ç»" |
| | | @back="goBack" /> |
| | | <!-- ç³è¯·ä¿¡æ¯ --> |
| | | <view class="application-info"> |
| | | <view class="info-header"> |
| | | <text class="info-title">ä¼è®®ä¿¡æ¯</text> |
| | | </view> |
| | | <view class="info-content"> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®ä¸»é¢</text> |
| | | <text class="info-value">{{ approvalData.title }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ç³è¯·äºº</text> |
| | | <text class="info-value">{{ approvalData.applicant }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">主ç人</text> |
| | | <text class="info-value">{{ approvalData.host }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®æ¶é´</text> |
| | | <text class="info-value">{{ formatDateTime(approvalData.meetingTime) }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®å°ç¹</text> |
| | | <text class="info-value">{{ approvalData.location }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">审æ¹ç¶æ</text> |
| | | <text class="info-value tag" |
| | | :class="getTagClass(approvalData.approveNodeStatus)"> |
| | | {{ formatReceiptType(approvalData.approveNodeStatus) }} |
| | | </text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">ä¼è®®è¯´æ</text> |
| | | <text class="info-value">{{ approvalData.description }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººæ°</text> |
| | | <text class="info-value">{{ approvalData.participants.length }}</text> |
| | | </view> |
| | | <view class="info-row"> |
| | | <text class="info-label">åä¼äººå</text> |
| | | <text class="info-value">{{ approvalData.participants.map(it => it.name).join("ã") }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æäº¤æè§è¾å
¥ --> |
| | | <view v-if="isEdit" |
| | | class="approval-input"> |
| | | <view class="input-header"> |
| | | <text class="input-title">ä¼è®®çºªè¦</text> |
| | | </view> |
| | | <view class="input-content"> |
| | | <Editor v-model:modelValue="minutesContent" |
| | | :height="300" /> |
| | | </view> |
| | | </view> |
| | | <!-- åºé¨æä½æé® --> |
| | | <view v-if="isEdit" |
| | | class="footer-actions"> |
| | | <u-button class="approve-btn" |
| | | @click="handleApprove">æäº¤</u-button> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | <script setup> |
| | | import { ref, onMounted, nextTick } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import { |
| | | saveMeetingMinutes, |
| | | getMeetingMinutesByMeetingId, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import Editor from "@/components/Editor/index.vue"; |
| | | |
| | | const approvalData = ref({}); |
| | | const approvalSteps = ref([]); |
| | | const isEdit = ref(false); |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | if (options.item) { |
| | | approvalData.value = JSON.parse(options.item); |
| | | } |
| | | // ç¼è¾æ¨¡å¼ä¸ï¼é»è®¤æäº¤æè§ä¸ºå½åå®¡æ¹æè§ |
| | | if (options.edit) { |
| | | isEdit.value = options.edit === "true" ? true : false; |
| | | } |
| | | getMeetingMinutes(); |
| | | console.log(approvalData.value, "approvalData.value"); |
| | | }); |
| | | const goBack = () => { |
| | | uni.removeStorageSync("approveId"); |
| | | uni.navigateBack(); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
审æ¹"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | const minutesContent = ref(""); |
| | | const minutesContentId = ref(""); |
| | | const getMeetingMinutes = () => { |
| | | getMeetingMinutesByMeetingId(approvalData.value.id) |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | |
| | | if (res.data) { |
| | | minutesContent.value = res.data.content; |
| | | minutesContentId.value = res.data.id; |
| | | } else { |
| | | minutesContent.value = `<h2>${approvalData.value.title}ä¼è®®çºªè¦</h2> |
| | | <p><strong>ä¼è®®æ¶é´ï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .meetingTime |
| | | }</p> |
| | | <p><strong>ä¼è®®å°ç¹ï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .location |
| | | }</p> |
| | | <p><strong>主æäººï¼</strong>${ |
| | | approvalData |
| | | .value |
| | | .host |
| | | }</p> |
| | | <p><strong>åä¼äººåï¼</strong></p> |
| | | <ol> |
| | | ${approvalData.value.participants |
| | | .map( |
| | | p => |
| | | `<li>${p.name}</li>` |
| | | ) |
| | | .join( |
| | | "" |
| | | )} |
| | | </ol> |
| | | <p><strong>ä¼è®®å
容ï¼</strong></p> |
| | | <ol> |
| | | <li>è®®é¢ä¸ï¼ |
| | | <ul> |
| | | <li>讨论å
容ï¼</li> |
| | | <li>å³è®®äºé¡¹ï¼</li> |
| | | </ul> |
| | | </li> |
| | | <li>è®®é¢äºï¼ |
| | | <ul> |
| | | <li>讨论å
容ï¼</li> |
| | | <li>å³è®®äºé¡¹ï¼</li> |
| | | </ul> |
| | | </li> |
| | | </ol> |
| | | <p><strong>夿³¨ï¼</strong></p>`; |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("è·åä¼è®®çºªè¦å¤±è´¥:", error); |
| | | showToast("è·åä¼è®®çºªè¦å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | const submitForm = status => { |
| | | console.log(minutesContent.value, "坿æ¬"); |
| | | if (!minutesContent.value) { |
| | | ElMessage.warning("请è¾å
¥ä¼è®®çºªè¦å
容"); |
| | | return; |
| | | } |
| | | |
| | | // è°ç¨å端 |
| | | saveMeetingMinutes({ |
| | | id: minutesContentId.value, |
| | | content: minutesContent.value, |
| | | meetingId: approvalData.value.id, |
| | | title: approvalData.value.title, |
| | | }) |
| | | .then(res => { |
| | | if (res.code === 200) { |
| | | showToast("æäº¤æå"); |
| | | // æç¤ºåè¿åä¸ä¸ä¸ªé¡µé¢ |
| | | setTimeout(() => { |
| | | goBack(); // å
鍿¯ uni.navigateBack() |
| | | }, 800); |
| | | } else { |
| | | showToast(res.message || "æäº¤æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | } |
| | | }) |
| | | .catch(error => { |
| | | console.error("æäº¤æä½å¤±è´¥:", error); |
| | | showToast("æäº¤æä½å¤±è´¥ï¼è¯·éè¯"); |
| | | }); |
| | | }; |
| | | |
| | | const handleApprove = () => { |
| | | uni.showModal({ |
| | | title: "确认æä½", |
| | | content: "ç¡®å®è¦æäº¤è¯¥ä¼è®®æ»ç»åï¼", |
| | | success: res => { |
| | | if (res.confirm) submitForm(1); |
| | | }, |
| | | }); |
| | | }; |
| | | // åå§èç¹æ°æ®ï¼ç¨äºæäº¤é»è¾ï¼ |
| | | const activities = ref([]); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .approve-page { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding-bottom: 80px; |
| | | } |
| | | |
| | | .header { |
| | | display: flex; |
| | | align-items: center; |
| | | background: #fff; |
| | | padding: 16px 20px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | position: sticky; |
| | | top: 0; |
| | | z-index: 100; |
| | | } |
| | | |
| | | .title { |
| | | flex: 1; |
| | | text-align: center; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .application-info { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .info-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .info-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .info-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .info-row { |
| | | display: flex; |
| | | align-items: center; |
| | | margin-bottom: 12px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | } |
| | | |
| | | .info-label { |
| | | font-size: 14px; |
| | | color: #666; |
| | | width: 80px; |
| | | flex-shrink: 0; |
| | | } |
| | | |
| | | .info-value { |
| | | font-size: 14px; |
| | | color: #333; |
| | | flex: 1; |
| | | } |
| | | |
| | | .approval-process { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .process-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .process-steps { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .process-step { |
| | | display: flex; |
| | | position: relative; |
| | | margin-bottom: 24px; |
| | | |
| | | &:last-child { |
| | | margin-bottom: 0; |
| | | |
| | | .step-line { |
| | | display: none; |
| | | } |
| | | } |
| | | } |
| | | |
| | | .step-indicator { |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | margin-right: 16px; |
| | | } |
| | | |
| | | .step-dot { |
| | | width: 32px; |
| | | height: 32px; |
| | | border-radius: 50%; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | position: relative; |
| | | z-index: 2; |
| | | } |
| | | |
| | | .process-step.completed .step-dot { |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | .process-step.current .step-dot { |
| | | background: #1890ff; |
| | | color: #fff; |
| | | animation: pulse 2s infinite; |
| | | } |
| | | |
| | | .process-step.pending .step-dot { |
| | | background: #d9d9d9; |
| | | color: #999; |
| | | } |
| | | |
| | | .step-line { |
| | | width: 2px; |
| | | height: 40px; |
| | | background: #d9d9d9; |
| | | margin-top: 8px; |
| | | } |
| | | |
| | | .process-step.completed .step-line { |
| | | background: #52c41a; |
| | | } |
| | | |
| | | .process-step.rejected .step-dot { |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | .process-step.rejected .step-line { |
| | | background: #ff4d4f; |
| | | } |
| | | |
| | | .step-content { |
| | | flex: 1; |
| | | padding-top: 4px; |
| | | } |
| | | |
| | | .step-info { |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .step-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-approver { |
| | | font-size: 14px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .step-time { |
| | | font-size: 12px; |
| | | color: #999; |
| | | display: block; |
| | | } |
| | | |
| | | .step-opinion { |
| | | background: #f8f9fa; |
| | | padding: 12px; |
| | | border-radius: 8px; |
| | | border-left: 4px solid #52c41a; |
| | | } |
| | | |
| | | .opinion-label { |
| | | font-size: 12px; |
| | | color: #666; |
| | | display: block; |
| | | margin-bottom: 4px; |
| | | } |
| | | |
| | | .opinion-content { |
| | | font-size: 14px; |
| | | color: #333; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .approval-input { |
| | | background: #fff; |
| | | margin: 16px; |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .input-header { |
| | | padding: 16px; |
| | | border-bottom: 1px solid #f0f0f0; |
| | | background: #f8f9fa; |
| | | } |
| | | |
| | | .input-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .input-content { |
| | | padding: 16px; |
| | | } |
| | | |
| | | .footer-actions { |
| | | position: fixed; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | background: #fff; |
| | | display: flex; |
| | | justify-content: space-around; |
| | | align-items: center; |
| | | padding: 16px; |
| | | box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); |
| | | z-index: 1000; |
| | | } |
| | | |
| | | .reject-btn { |
| | | width: 120px; |
| | | background: #ff4d4f; |
| | | color: #fff; |
| | | } |
| | | |
| | | .approve-btn { |
| | | width: 120px; |
| | | background: #52c41a; |
| | | color: #fff; |
| | | } |
| | | |
| | | /* éé
u-buttonæ ·å¼ */ |
| | | :deep(.u-button) { |
| | | border-radius: 6px; |
| | | } |
| | | |
| | | @keyframes pulse { |
| | | 0% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0.7); |
| | | } |
| | | 70% { |
| | | box-shadow: 0 0 0 10px rgba(24, 144, 255, 0); |
| | | } |
| | | 100% { |
| | | box-shadow: 0 0 0 0 rgba(24, 144, 255, 0); |
| | | } |
| | | } |
| | | .signature-section { |
| | | background: #fff; |
| | | padding: 12px 16px 16px; |
| | | border-top: 1px solid #f0f0f0; |
| | | } |
| | | .signature-header { |
| | | margin-bottom: 8px; |
| | | } |
| | | .signature-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | .signature-box { |
| | | width: 100%; |
| | | height: 180px; |
| | | background: #fff; |
| | | border: 1px dashed #d9d9d9; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | } |
| | | .signature-actions { |
| | | margin-top: 8px; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | /* å·¥å
·æ æé®æ ·å¼ */ |
| | | :deep(.ql-toolbar.ql-snow .ql-button) { |
| | | height: 28px; |
| | | width: 28px; |
| | | padding: 4px; |
| | | } |
| | | :deep(.ql-toolbar.ql-snow .ql-picker-label) { |
| | | height: 28px; |
| | | padding: 4px 8px; |
| | | } |
| | | </style> |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | // 审æ¹ç®¡çä¸»é¡µé¢ |
| | | <template> |
| | | <view class="sales-account"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ä¼è®®æ»ç»" |
| | | @back="goBack" /> |
| | | <!-- æç´¢åçéåºå --> |
| | | <view class="search-section"> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input class="search-text" |
| | | placeholder="请è¾å
¥ä¼è®®ä¸»é¢" |
| | | v-model="searchForm.title" |
| | | clearable /> |
| | | </view> |
| | | <view class="search-button" |
| | | @click="getList"> |
| | | <up-icon name="search" |
| | | size="24" |
| | | color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- 审æ¹å表 --> |
| | | <view class="ledger-list" |
| | | v-if="ledgerList.length > 0"> |
| | | <view v-for="(item, index) in ledgerList" |
| | | :key="index"> |
| | | <view class="ledger-item"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" |
| | | size="16" |
| | | color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.title }}</text> |
| | | </view> |
| | | <view class="item-tag"> |
| | | <u-tag :type="getTagClass(item.status)">{{ formatReceiptType(item.status) }}</u-tag> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç³è¯·äºº</text> |
| | | <text class="detail-value">{{ item.applicant }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">主ç人</text> |
| | | <text class="detail-value">{{ item.host }}</text> |
| | | </view> |
| | | <view class="detail-row-approveReason"> |
| | | <text class="detail-label">ä¼è®®æ¶é´</text> |
| | | <text class="detail-value highlightBlue">{{ formatDateTime(item.meetingTime) }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ä¼è®®å°ç¹</text> |
| | | <text class="detail-value">{{ item.location }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä¼äººæ°</text> |
| | | <text class="detail-value">{{ item.participants.length }}</text> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | <view class="actions"> |
| | | <u-button type="primary" |
| | | size="small" |
| | | class="action-btn view" |
| | | @click="viewDetail(item)"> |
| | | 详æ
|
| | | </u-button> |
| | | <u-button type="success" |
| | | size="small" |
| | | class="action-btn approve" |
| | | :disabled="item.status != 0" |
| | | @click="approve(item)"> |
| | | æ·»å çºªè¦ |
| | | </u-button> |
| | | </view> |
| | | <!-- <view class="detail-info" |
| | | style="align-items: flex-end;"> |
| | | <view class="detail-row"> |
| | | |
| | | </view> |
| | | </view> --> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view v-else |
| | | class="no-data"> |
| | | <text>ææ æ°æ®</text> |
| | | </view> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, toRefs, reactive } from "vue"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import { |
| | | getMeetingPublish, |
| | | getRoomEnum, |
| | | } from "@/api/managementMeetings/meetExamine"; |
| | | import { getStaffOnJob } from "@/api/personnelManagement/onboarding"; |
| | | import { onShow } from "@dcloudio/uni-app"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const userStore = useUserStore(); |
| | | // æ°æ® |
| | | const ledgerList = ref([]); |
| | | const data = reactive({ |
| | | searchForm: { |
| | | title: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // è¿åä¸ä¸é¡µ |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // æ¿é´æä¸¾ |
| | | const roomEnum = ref([]); |
| | | // æ¿é´æä¸¾æ¥è¯¢ |
| | | const getRoomEnumList = () => { |
| | | return getRoomEnum() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | roomEnum.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // åå·¥å表 |
| | | const staffList = ref([]); |
| | | // åå·¥å表æ¥è¯¢ |
| | | const getStaffOnJobList = () => { |
| | | return getStaffOnJob() |
| | | .then(res => { |
| | | console.log(res.data, "res.data"); |
| | | staffList.value = res.data; |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¥è¯¢å表 |
| | | const getList = () => { |
| | | showLoadingToast("å è½½ä¸..."); |
| | | const page = { |
| | | current: -1, |
| | | size: -1, |
| | | }; |
| | | getMeetingPublish({ |
| | | ...page, |
| | | ...searchForm.value, |
| | | }) |
| | | .then(res => { |
| | | console.log(res.data.records, "res.data.records"); |
| | | ledgerList.value = res.data.records.map(it => { |
| | | console.log(it, "it1"); |
| | | let room = roomEnum.value.find(room => it.roomId === room.id); |
| | | it.location = `${room.name}(${room.location})`; |
| | | let staffs = JSON.parse(it.participants); |
| | | it.staffCount = staffs.size; |
| | | it.meetingTime = `${it.meetingDate} ${dayjs(it.startTime).format( |
| | | "HH:mm:ss" |
| | | )} ~ ${dayjs(it.endTime).format("HH:mm:ss")}`; |
| | | it.participants = staffList.value |
| | | .filter(staff => staffs.some(id => id == staff.id)) |
| | | .map(staff => { |
| | | return { |
| | | id: staff.id, |
| | | name: `${staff.staffName}(${staff.postJob})`, |
| | | }; |
| | | }); |
| | | console.log(it, "it2"); |
| | | |
| | | return it; |
| | | }); |
| | | |
| | | closeToast(); |
| | | }) |
| | | .catch(() => { |
| | | closeToast(); |
| | | }); |
| | | }; |
| | | // æ¾ç¤ºå è½½æç¤º |
| | | const showLoadingToast = message => { |
| | | uni.showLoading({ |
| | | title: message, |
| | | mask: true, |
| | | }); |
| | | }; |
| | | const formatDateTime = dateTime => { |
| | | if (!dateTime) return ""; |
| | | return dateTime.replace(" ", "\n"); |
| | | }; |
| | | |
| | | // å
³éæç¤º |
| | | const closeToast = () => { |
| | | uni.hideLoading(); |
| | | }; |
| | | |
| | | // æ ¼å¼å忬¾æ¹å¼ |
| | | const formatReceiptType = params => { |
| | | if (params == 0) { |
| | | return "å¾
审æ¹"; |
| | | } else if (params == 1) { |
| | | return "å·²éè¿"; |
| | | } else if (params == 2) { |
| | | return "æªéè¿"; |
| | | } else if (params == 3) { |
| | | return "已忶"; |
| | | } else { |
| | | return "æªç¥"; |
| | | } |
| | | }; |
| | | // è·åæ ç¾æ ·å¼ç±» |
| | | const getTagClass = type => { |
| | | if (type == 0) { |
| | | return "info"; |
| | | } else if (type == 1) { |
| | | return "success"; |
| | | } else if (type == 2) { |
| | | return "warning"; |
| | | } else if (type == 3) { |
| | | return "danger"; |
| | | } else { |
| | | return "info"; |
| | | } |
| | | }; |
| | | |
| | | // ç¹å»å®¡æ ¸ |
| | | const approve = item => { |
| | | // uni.setStorageSync("approveId", item.approveId); |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetSummary/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=true", |
| | | }); |
| | | }; |
| | | // æ¥ç详æ
|
| | | const viewDetail = item => { |
| | | uni.navigateTo({ |
| | | url: |
| | | "/pages/managementMeetings/meetSummary/approve?item=" + |
| | | JSON.stringify(item) + |
| | | "&edit=false", |
| | | }); |
| | | }; |
| | | |
| | | onShow(async () => { |
| | | // 页é¢å è½½å®æåçåå§åé»è¾ |
| | | try { |
| | | // çå¾
ä¸¤ä¸ªå¼æ¥æ¹æ³æ§è¡å®æ |
| | | await Promise.all([getRoomEnumList(), getStaffOnJobList()]); |
| | | // ä¸¤ä¸ªæ¹æ³æ§è¡å®æååæ§è¡ getList() |
| | | getList(); |
| | | } catch (error) { |
| | | console.error("åå§åæ°æ®å¤±è´¥:", error); |
| | | // å³ä½¿åºé乿§è¡ getList()ï¼ç¡®ä¿é¡µé¢è½æ£å¸¸å è½½ |
| | | getList(); |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import "../../../styles/sales-common.scss"; |
| | | |
| | | .u-divider { |
| | | margin: 0 !important; |
| | | } |
| | | |
| | | // ææ¡£å¾æ æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .document-icon { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // æµ®å¨æé®æ ·å¼ - è¦çå
Œ
±æ ·å¼ä¸çèæ¯è² |
| | | .fab-button { |
| | | background: #ed8d05; |
| | | } |
| | | |
| | | // ç¹ææ ·å¼ |
| | | .detail-row-user { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | } |
| | | |
| | | .detail-row-approveReason { |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: space-between; |
| | | margin-bottom: 8px; |
| | | } |
| | | |
| | | .detail-value.highlightBlue { |
| | | color: #2979ff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlightYellow { |
| | | color: #ed8d05; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .approver-value { |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .approver-chip { |
| | | display: inline-flex; |
| | | align-items: center; |
| | | gap: 6px; |
| | | background: #f0f6ff; |
| | | color: #2b7cff; |
| | | border: 1px solid #e0efff; |
| | | border-radius: 999px; |
| | | padding: 4px 10px; |
| | | max-width: 100%; |
| | | } |
| | | |
| | | .approver-name { |
| | | font-size: 12px; |
| | | color: #2b7cff; |
| | | overflow: hidden; |
| | | text-overflow: ellipsis; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | gap: 10px; |
| | | align-items: center; |
| | | justify-content: flex-end; |
| | | margin-top: 18rpx; |
| | | } |
| | | |
| | | .action-btn { |
| | | border-radius: 16px; |
| | | height: 28px; |
| | | line-height: 28px; |
| | | padding: 0 12px; |
| | | } |
| | | </style> |
| | |
| | | <template> |
| | | <uni-popup |
| | | ref="popupRef" |
| | | type="bottom" |
| | | <up-popup |
| | | v-model:show="show" |
| | | mode="bottom" |
| | | :round="20" |
| | | :safeAreaInsetBottom="true" |
| | | @close="handleClose" |
| | |
| | | > |
| | | <!-- 项ç®åºæ¬ä¿¡æ¯ --> |
| | | <view class="form-section"> |
| | | <text class="section-title">产åä¿¡æ¯</text> |
| | | <!-- <up-form-item label="项ç®åç§°" prop="projectName"> |
| | | <text class="section-title">项ç®ä¿¡æ¯</text> |
| | | <up-form-item label="项ç®åç§°" prop="projectName"> |
| | | <up-input |
| | | v-model="form.projectName" |
| | | disabled |
| | | placeholder="项ç®åç§°" |
| | | /> |
| | | </up-form-item> --> |
| | | </up-form-item> |
| | | <up-form-item label="产å大类" prop="productCategory"> |
| | | <up-input |
| | | v-model="form.productCategory" |
| | | disabled |
| | | placeholder="产å大类" |
| | | /> |
| | | </up-form-item> |
| | | <up-form-item label="è§æ ¼åå·" prop="specificationModel"> |
| | | <up-input |
| | | v-model="form.specificationModel" |
| | | disabled |
| | | placeholder="è§æ ¼åå·" |
| | | /> |
| | | </up-form-item> |
| | | <up-form-item label="ç»å®æºå¨" prop="speculativeTradingName"> |
| | | <up-input |
| | | v-model="form.speculativeTradingName" |
| | | disabled |
| | | placeholder="ç»å®æºå¨" |
| | | /> |
| | | </up-form-item> |
| | | </view> |
| | |
| | | <view class="form-section"> |
| | | <text class="section-title">派工信æ¯</text> |
| | | <up-form-item label="派工人" prop="schedulingUserId" required> |
| | | <uni-data-select v-model="form.schedulingUserId" :localdata="userColumns" :clear="false"></uni-data-select> |
| | | <up-input |
| | | v-model="selectedUserName" |
| | | placeholder="è¯·éæ©æ´¾å·¥äºº" |
| | | readonly |
| | | @click="showUserPicker = true" |
| | | suffixIcon="arrow-down" |
| | | /> |
| | | </up-form-item> |
| | | <up-form-item label="æ´¾å·¥æ¥æ" prop="schedulingDate" required> |
| | | <uni-datetime-picker type="date" :clear-icon="false" v-model="form.schedulingDate"> |
| | | <view class="datetime-picker-value"> |
| | | {{form.schedulingDate}} |
| | | </view> |
| | | </uni-datetime-picker> |
| | | <up-input |
| | | v-model="form.schedulingDate" |
| | | placeholder="è¯·éæ©æ´¾å·¥æ¥æ" |
| | | readonly |
| | | @click="showDatePicker = true" |
| | | suffixIcon="calendar" |
| | | /> |
| | | </up-form-item> |
| | | </view> |
| | | </up-form> |
| | |
| | | /> |
| | | </view> |
| | | </view> |
| | | </uni-popup> |
| | | |
| | | <!-- 人åéæ©å¨ --> |
| | | <up-picker |
| | | v-model="showUserPicker" |
| | | :columns="userColumns" |
| | | @confirm="handleUserSelect" |
| | | @cancel="showUserPicker = false" |
| | | /> |
| | | |
| | | <!-- æ¥æéæ©å¨ --> |
| | | <up-datetime-picker |
| | | v-model="showDatePicker" |
| | | mode="date" |
| | | @confirm="handleDateSelect" |
| | | @cancel="showDatePicker = false" |
| | | /> |
| | | </up-popup> |
| | | </template> |
| | | |
| | | <script setup> |
| | |
| | | const emit = defineEmits(['confirm']); |
| | | |
| | | // å¼¹çªæ¾ç¤ºç¶æ |
| | | const popupRef = ref(); |
| | | const show = ref(false); |
| | | const submitting = ref(false); |
| | | |
| | | // 鿩卿¾ç¤ºç¶æ |
| | | const showUserPicker = ref(false); |
| | | const showDatePicker = ref(false); |
| | | |
| | | // ç¨æ·å表 |
| | | const userList = ref([]); |
| | | const userColumns = computed(() => { |
| | | return userList.value.map(user => ({ |
| | | text: user.nickName, |
| | | const userColumns = computed(() => [ |
| | | userList.value.map(user => ({ |
| | | label: user.nickName, |
| | | value: user.userId |
| | | })) |
| | | ]); |
| | | |
| | | // éä¸çç¨æ·åç§°ï¼ç¨äºæ¾ç¤ºï¼ |
| | | const selectedUserName = computed(() => { |
| | | const user = userList.value.find(u => u.userId === form.schedulingUserId); |
| | | return user ? user.nickName : ''; |
| | | }); |
| | | |
| | | // è¡¨åæ°æ® |
| | |
| | | |
| | | // 表åéªè¯è§å |
| | | const rules = reactive({ |
| | | // schedulingNum: [ |
| | | // { required: true, message: "请è¾å
¥æäº§æ°é", trigger: "blur" } |
| | | // ], |
| | | // schedulingUserId: [ |
| | | // { required: true, message: "è¯·éæ©æ´¾å·¥äºº", trigger: "change" } |
| | | // ], |
| | | // schedulingDate: [ |
| | | // { required: true, message: "è¯·éæ©æ´¾å·¥æ¥æ", trigger: "change" } |
| | | // ] |
| | | schedulingNum: [ |
| | | { required: true, message: "请è¾å
¥æäº§æ°é", trigger: "blur" } |
| | | ], |
| | | schedulingUserId: [ |
| | | { required: true, message: "è¯·éæ©æ´¾å·¥äºº", trigger: "change" } |
| | | ], |
| | | schedulingDate: [ |
| | | { required: true, message: "è¯·éæ©æ´¾å·¥æ¥æ", trigger: "change" } |
| | | ] |
| | | }); |
| | | |
| | | // 表åå¼ç¨ |
| | |
| | | schedulingUserId: userStore.id, |
| | | schedulingDate: dayjs().format("YYYY-MM-DD") |
| | | }); |
| | | popupRef.value.open() |
| | | |
| | | show.value = true; |
| | | } catch (error) { |
| | | console.log(error) |
| | | uni.showToast({ |
| | | title: 'å è½½ç¨æ·å表失败', |
| | | icon: 'error' |
| | |
| | | } |
| | | }; |
| | | |
| | | // å¤çç¨æ·éæ© |
| | | const handleUserSelect = (params) => { |
| | | if (params.value && params.value.length > 0) { |
| | | form.schedulingUserId = params.value[0]; |
| | | } |
| | | showUserPicker.value = false; |
| | | }; |
| | | |
| | | // å¤çæ¥æéæ© |
| | | const handleDateSelect = (params) => { |
| | | if (params.value) { |
| | | form.schedulingDate = dayjs(params.value).format("YYYY-MM-DD"); |
| | | } |
| | | showDatePicker.value = false; |
| | | }; |
| | | |
| | | // 确认派工 |
| | | const handleConfirm = async () => { |
| | | if(!form.schedulingNum){ |
| | | uni.showToast({ |
| | | title: '请è¾å
¥æäº§æ°é', |
| | | icon:'none' |
| | | }) |
| | | return |
| | | } |
| | | if(!form.schedulingUserId){ |
| | | uni.showToast({ |
| | | title: 'è¯·éæ©æ´¾å·¥äºº', |
| | | icon:'none' |
| | | }) |
| | | return |
| | | } |
| | | if(!form.schedulingDate){ |
| | | uni.showToast({ |
| | | title: 'è¯·éæ©æ´¾å·¥æ¥æ', |
| | | icon:'none' |
| | | }) |
| | | return |
| | | } |
| | | try { |
| | | // 表åéªè¯ |
| | | const valid = await formRef.value?.validate(); |
| | | if (!valid) return; |
| | | |
| | | if (form.schedulingNum <= 0) { |
| | | uni.showToast({ |
| | | title: 'æäº§æ°éå¿
须大äº0', |
| | |
| | | |
| | | // å
³éå¼¹çª |
| | | const handleClose = () => { |
| | | popupRef.value.close() |
| | | show.value = false; |
| | | showUserPicker.value = false; |
| | | showDatePicker.value = false; |
| | | |
| | | // é置表å |
| | | Object.assign(form, { |
| | | projectName: "", |
| | |
| | | flex: 1; |
| | | padding: 0 20px; |
| | | overflow-y: auto; |
| | | .datetime-picker-value{ |
| | | font-size: 14px; |
| | | border: 1px solid #e5e5e5; |
| | | box-sizing: border-box; |
| | | border-radius: 4px; |
| | | padding: 0 5px; |
| | | padding-left: 10px; |
| | | position: relative; |
| | | display: flex; |
| | | -webkit-user-select: none; |
| | | -moz-user-select: none; |
| | | user-select: none; |
| | | flex-direction: row; |
| | | align-items: center; |
| | | width: 100%; |
| | | flex: 1; |
| | | height: 35px; |
| | | } |
| | | } |
| | | |
| | | .form-section { |
| | |
| | | <view class="production-dispatching"> |
| | | <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> |
| | | <PageHeader title="ç产派工" @back="goBack" /> |
| | | |
| | | <!-- çæºç¶æå±ç¤º --> |
| | | <view class="machines-section"> |
| | | <view class="section-title">çæºç¶æ</view> |
| | | <view class="machines-grid"> |
| | | <view v-for="machine in machines" :key="machine.id" class="machine-card"> |
| | | <view class="machine-title">çæº{{ machine.id }}</view> |
| | | <view class="machine-metrics"> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">æ»é(kg)</text> |
| | | <up-input |
| | | v-model="machineTotal[machine.key]" |
| | | type="number" |
| | | placeholder="请è¾å
¥æ»é" |
| | | border="surround" |
| | | size="mini" |
| | | class="metric-input" |
| | | @change="updateMachineVacant(machine.key)" |
| | | /> |
| | | </view> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">æ£å¨ç产(kg)</text> |
| | | <text class="metric-value">{{ machineInProduction[machine.key] }}</text> |
| | | </view> |
| | | <view class="metric-item"> |
| | | <text class="metric-label">空ä½é(kg)</text> |
| | | <text class="metric-value">{{ machineVacant[machine.key] }}</text> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <!-- æèç设置 --> |
| | | <view class="loss-rate-section"> |
| | | <view class="section-title">æèç设置</view> |
| | | <view class="loss-rate-content"> |
| | | <view class="loss-rate-item"> |
| | | <up-button |
| | | class="loss-rate-btn" |
| | | type="primary" |
| | | plain |
| | | size="small" |
| | | @click="showLossRateSheet = true" |
| | | >{{ lossRate ? `æèç: ${lossRate}%` : 'è¯·éæ©æèç' }}</up-button> |
| | | <up-action-sheet |
| | | :show="showLossRateSheet" |
| | | :actions="lossRateOptions" |
| | | @select="onLossRateSelect" |
| | | title="éæ©æèç" |
| | | @close="showLossRateSheet = false" |
| | | /> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | <view class="save-section"> |
| | | <up-button type="primary" @click="saveMachineTotals" size="normal" class="save-btn">ä¿åçæºè®¾ç½®</up-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- æç´¢åºå --> |
| | | <view class="search-section"> |
| | | <view class="search-form"> |
| | | <view class="search-item"> |
| | | <text class="search-label">客æ·åç§°</text> |
| | | <view class="search-bar"> |
| | | <view class="search-input"> |
| | | <up-input |
| | | class="search-text" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°æç´¢" |
| | | v-model="searchForm.customerName" |
| | | placeholder="请è¾å
¥å®¢æ·åç§°" |
| | | @change="handleQuery" |
| | | clearable |
| | | border="surround" |
| | | class="search-input" |
| | | /> |
| | | </view> |
| | | <view class="search-item"> |
| | | <text class="search-label">项ç®åç§°</text> |
| | | <up-input |
| | | v-model="searchForm.projectName" |
| | | placeholder="请è¾å
¥é¡¹ç®åç§°" |
| | | @change="handleQuery" |
| | | clearable |
| | | border="surround" |
| | | class="search-input" |
| | | /> |
| | | </view> |
| | | <view class="search-buttons"> |
| | | <up-button type="primary" @click="handleQuery" size="small" class="search-btn">æç´¢</up-button> |
| | | <up-button @click="handleReset" size="small" class="reset-btn">éç½®</up-button> |
| | | <view class="filter-button" @click="handleQuery"> |
| | | <up-icon name="search" size="24" color="#999"></up-icon> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- æ¹éæä½åºå --> |
| | | <view class="batch-actions-section" v-if="showBatchActions"> |
| | | <view class="batch-info"> |
| | | <text class="batch-text">已鿩 {{ selectedItems.length }} 个项ç®</text> |
| | | </view> |
| | | <view class="batch-buttons"> |
| | | <up-button type="primary" size="small" @click="handleAutoDispatch" class="batch-btn">èªå¨æ´¾å</up-button> |
| | | <up-button type="default" size="small" @click="clearSelection" class="batch-btn">åæ¶éæ©</up-button> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- å
¨éæä½åºå --> |
| | | <view class="select-all-section" v-if="tableData.length > 0"> |
| | | <view class="select-all-content"> |
| | | <up-checkbox |
| | | v-model="isAllSelected" |
| | | @change="toggleAllSelection" |
| | | label="å
¨é" |
| | | class="select-all-checkbox" |
| | | :disabled="tableData.length === 0 || tableData.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName).length === 0" |
| | | /> |
| | | </view> |
| | | </view> |
| | | |
| | | <!-- ç产派工å表 --> |
| | | <view class="ledger-list" v-if="tableData.length > 0"> |
| | | <view v-for="(item, index) in tableData" :key="item.id || index" class="list-item"> |
| | | <view v-for="(item, index) in tableData" :key="item.id || index"> |
| | | <view class="ledger-item"> |
| | | <!-- éæ©å¤éæ¡ --> |
| | | <view class="item-checkbox"> |
| | | <up-checkbox |
| | | :model-value="selectedItems.some(selected => selected.id === item.id)" |
| | | @change="(checked) => toggleItemSelection(item, checked)" |
| | | :disabled="item.pendingQuantity <= 0 || !item.speculativeTradingName" |
| | | shape="circle" |
| | | /> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.salesContractNo }}</text> |
| | | </view> |
| | | </view> |
| | | <up-divider></up-divider> |
| | | |
| | | <view class="item-details"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å½å
¥æ¥æ</text> |
| | | <text class="detail-value">{{ item.entryDate }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·åç§°</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项ç®åç§°</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产å大类</text> |
| | | <text class="detail-value">{{ item.productCategory }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">è§æ ¼åå·</text> |
| | | <text class="detail-value">{{ item.specificationModel }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ»æ°é</text> |
| | | <text class="detail-value">{{ item.quantity }} {{ item.unit }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æäº§æ°é</text> |
| | | <text class="detail-value highlight">{{ item.schedulingNum }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¾
ææ°é</text> |
| | | <text class="detail-value" :class="{ 'danger': item.pendingQuantity <= 0 }">{{ item.pendingQuantity }}</text> |
| | | </view> |
| | | </view> |
| | | |
| | | <view class="item-content"> |
| | | <view class="item-header"> |
| | | <view class="item-left"> |
| | | <view class="document-icon"> |
| | | <up-icon name="file-text" size="16" color="#ffffff"></up-icon> |
| | | </view> |
| | | <text class="item-id">{{ item.salesContractNo }}</text> |
| | | </view> |
| | | <text class="entry-date">{{ item.entryDate }}</text> |
| | | </view> |
| | | |
| | | <view class="item-details"> |
| | | <!-- <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> --> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·åç§°</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <!-- <view class="detail-row"> |
| | | <text class="detail-label">项ç®åç§°</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> --> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产å大类</text> |
| | | <text class="detail-value">{{ item.productCategory }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">è§æ ¼åå·</text> |
| | | <text class="detail-value">{{ item.specificationModel }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">ç»å®æºå¨</text> |
| | | <text class="detail-value">{{ item.speculativeTradingName }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">åä½</text> |
| | | <text class="detail-value">{{ item.unit }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å½å
¥æ¥æ</text> |
| | | <text class="detail-value">{{ item.entryDate }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æ°é</text> |
| | | <text class="detail-value">{{ item.quantity }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">æäº§æ°é</text> |
| | | <text class="detail-value highlight">{{ item.schedulingNum }}</text> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">å¾
ææ°é</text> |
| | | <text class="detail-value" :class="{ 'danger': item.pendingQuantity <= 0 }">{{ item.pendingQuantity }}</text> |
| | | </view> |
| | | |
| | | <!-- æä½æé®åºå --> |
| | | <view class="action-buttons"> |
| | | <up-button |
| | | type="primary" |
| | | size="small" |
| | | @click="handleDispatch(item)" |
| | | class="action-btn" |
| | | :disabled="item.pendingQuantity <= 0 || !item.speculativeTradingName" |
| | | > |
| | | {{ item.pendingQuantity <= 0 ? 'æ éæ´¾å·¥' : !item.speculativeTradingName ? 'æªç»å®æºå¨' : 'ç产派工' }} |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | <!-- æä½æé®åºå --> |
| | | <view class="action-buttons"> |
| | | <up-button |
| | | type="primary" |
| | | size="small" |
| | | @click="handleDispatch(item)" |
| | | class="action-btn" |
| | | :disabled="item.pendingQuantity <= 0" |
| | | > |
| | | ç产派工 |
| | | </up-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | <view v-else class="no-data"> |
| | | <up-empty mode="data" icon="http://cdn.uviewui.com/uview/empty/data.png"> |
| | | <text class="no-data-text">ææ çäº§æ´¾å·¥æ°æ®</text> |
| | | </up-empty> |
| | | <text>ææ çäº§æ´¾å·¥æ°æ®</text> |
| | | </view> |
| | | |
| | | <!-- æ´¾å·¥å¼¹çª --> |
| | | <DispatchModal ref="dispatchModalRef" @confirm="handleDispatchConfirm" /> |
| | | |
| | | <!-- èªå¨æ´¾åå¼¹çª --> |
| | | <AutoDispatchDia ref="autoDispatchDia" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import { ref, reactive, toRefs, getCurrentInstance } from "vue"; |
| | | import { onShow } from '@dcloudio/uni-app'; |
| | | import dayjs from "dayjs"; |
| | | import {schedulingListPage, schedulingList, addSpeculatTrading, updateSpeculatTrading, getLossRate, addLossRate, updateLossRate} from "@/api/productionManagement/productionOrder.js"; |
| | | import {schedulingListPage} from "@/api/productionManagement/productionOrder.js"; |
| | | import PageHeader from "@/components/PageHeader.vue"; |
| | | import DispatchModal from "./components/DispatchModal.vue"; |
| | | import AutoDispatchDia from "./components/autoDispatchDia.vue"; |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | |
| | | // å è½½ç¶æ |
| | |
| | | // åè¡¨æ°æ® |
| | | const tableData = ref([]); |
| | | |
| | | // éæ©ç¸å
³æ°æ® |
| | | const selectedItems = ref([]); |
| | | const isAllSelected = ref(false); |
| | | const showBatchActions = ref(false); |
| | | |
| | | // æç´¢è¡¨åæ°æ® |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | projectName: "", |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | |
| | | // å页é
ç½® |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | | total: 0, |
| | | current: -1, |
| | | size: -1, |
| | | }); |
| | | |
| | | // çæºç¶ææ°æ® |
| | | const machineTotal = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | const machineInProduction = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | const machineVacant = reactive({ |
| | | m1: 0, |
| | | m2: 0, |
| | | m3: 0, |
| | | m4: 0, |
| | | }) |
| | | |
| | | // çæºé
ç½®æ°ç» |
| | | const machines = [ |
| | | { id: 1, key: 'm1' }, |
| | | { id: 2, key: 'm2' }, |
| | | { id: 3, key: 'm3' }, |
| | | { id: 4, key: 'm4' } |
| | | ] |
| | | |
| | | // æ¯å¦ææ¥è¯¢æ°æ®ï¼ç¨äºå¤ææ¯æ°å¢è¿æ¯ä¿®æ¹ï¼ |
| | | const hasQueryData = ref(false); |
| | | |
| | | // æèçç¸å
³æ°æ® |
| | | const lossRate = ref(""); // å½åéæ©çæèç |
| | | const showLossRateSheet = ref(false); // æ§å¶æèç鿩颿¿æ¾ç¤º |
| | | const lossRateOptions = ref([ |
| | | { name: "6%", value: "6" }, |
| | | { name: "7%", value: "7" }, |
| | | { name: "8%", value: "8" }, |
| | | { name: "9%", value: "9" }, |
| | | { name: "10%", value: "10" } |
| | | ]); |
| | | const lossRateData = ref(null); // æèçæ¥è¯¢è¿åçæ°æ® |
| | | |
| | | // 派工弹çªå¼ç¨ |
| | | const dispatchModalRef = ref(); |
| | | |
| | | // èªå¨æ´¾åå¼¹çªå¼ç¨ |
| | | const autoDispatchDia = ref(); |
| | | |
| | | // éç¨æç¤ºå½æ° |
| | | const showLoadingToast = (message) => { |
| | |
| | | uni.navigateBack(); |
| | | }; |
| | | |
| | | // éç½®æç´¢ |
| | | const handleReset = () => { |
| | | searchForm.value.customerName = ""; |
| | | searchForm.value.projectName = ""; |
| | | handleQuery(); |
| | | }; |
| | | |
| | | // æ¥è¯¢å表 |
| | | const handleQuery = () => { |
| | | page.current = 1; |
| | | getList(); |
| | | }; |
| | | |
| | | // è·åçæºçäº§æ°æ® |
| | | const getMachineProductionData = () => { |
| | | schedulingList().then((res) => { |
| | | if (res.data && Array.isArray(res.data)) { |
| | | // éç½®æ°æ® |
| | | machineInProduction.m1 = 0; |
| | | machineInProduction.m2 = 0; |
| | | machineInProduction.m3 = 0; |
| | | machineInProduction.m4 = 0; |
| | | |
| | | // å¤ççæºæ°æ® |
| | | res.data.forEach(item => { |
| | | const machineId = Number(item.id); |
| | | if (machineId >= 1 && machineId <= 4) { |
| | | const machineKey = `m${machineId}`; |
| | | |
| | | if (item.workLoad !== null && item.workLoad !== undefined) { |
| | | machineTotal[machineKey] = Number(item.workLoad) || 0; |
| | | } |
| | | |
| | | if (item.currentWorkLoad !== null && item.currentWorkLoad !== undefined) { |
| | | machineInProduction[machineKey] = Number(item.currentWorkLoad) || 0; |
| | | } |
| | | |
| | | // 计ç®ç©ºä½é |
| | | machineVacant[machineKey] = machineTotal[machineKey] - machineInProduction[machineKey]; |
| | | } |
| | | }); |
| | | } |
| | | }).catch(err => { |
| | | console.error('è·åçæºæ°æ®å¤±è´¥:', err); |
| | | }); |
| | | }; |
| | | |
| | | // æèçéæ©äºä»¶ |
| | | const onLossRateSelect = (action) => { |
| | | lossRate.value = action.value; |
| | | showLossRateSheet.value = false; |
| | | console.log('éæ©äºæèç:', action.name, 'å¼:', action.value); |
| | | }; |
| | | |
| | | // è·åæèçæ°æ® |
| | | const getLossRateData = () => { |
| | | getLossRate().then((res) => { |
| | | if (res.data) { |
| | | lossRateData.value = res.data; |
| | | // 设置å½åéæ©çæèç |
| | | if (res.data.rate !== null && res.data.rate !== undefined) { |
| | | lossRate.value = res.data.rate.toString(); |
| | | } |
| | | } |
| | | }).catch(err => { |
| | | console.error('è·åæèç失败:', err); |
| | | }); |
| | | }; |
| | | |
| | | // è·ååè¡¨æ°æ® |
| | |
| | | loading.value = true; |
| | | showLoadingToast('å è½½ä¸...'); |
| | | |
| | | // æé 请æ±åæ° |
| | | const params = { ...searchForm.value, ...page }; |
| | | |
| | | schedulingListPage(params).then((res) => { |
| | | loading.value = false; |
| | | closeToast(); |
| | | |
| | | // å¤çæ¯æ¡æ°æ®ï¼å¢å pendingQuantityåæ®µ |
| | | tableData.value = (res.data.records || []).map(item => ({ |
| | | ...item, |
| | | pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0) |
| | | })).filter(item => item.pendingQuantity > 0); |
| | | |
| | | page.total = res.data.total || 0; |
| | | |
| | | // è·åçæºæ°æ® |
| | | getMachineProductionData(); |
| | | |
| | | // è·åæèçæ°æ® |
| | | getLossRateData(); |
| | | |
| | | ...item, |
| | | pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0) |
| | | })); |
| | | }).catch(() => { |
| | | loading.value = false; |
| | | closeToast(); |
| | |
| | | return; |
| | | } |
| | | |
| | | if (!item.speculativeTradingName) { |
| | | uni.showToast({ |
| | | title: 'è¯¥é¡¹ç®æªç»å®æºå¨ï¼æ æ³æ´¾å·¥', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | dispatchModalRef.value?.open(item); |
| | | }; |
| | | |
| | |
| | | getList(); // å·æ°å表 |
| | | }; |
| | | |
| | | // æ´æ°çæºç©ºä½é |
| | | const updateMachineVacant = (machineKey) => { |
| | | machineVacant[machineKey] = (Number(machineTotal[machineKey]) || 0) - (Number(machineInProduction[machineKey]) || 0); |
| | | }; |
| | | |
| | | // è·åçæºæ¥è¯¢æ°æ® |
| | | const getMachineQueryData = (machineId) => { |
| | | // è¿ééè¦æ ¹æ®å®é
æ
åµä»æ¥è¯¢æ°æ®ä¸è·å对åºççæºæ°æ® |
| | | // ææ¶è¿åä¸ä¸ªæ¨¡ææ°æ® |
| | | return { |
| | | id: machineId, |
| | | name: `çæº${machineId}`, |
| | | workLoad: machineTotal[`m${machineId}`] || 0, |
| | | currentWorkLoad: machineInProduction[`m${machineId}`] || 0 |
| | | }; |
| | | }; |
| | | |
| | | // ä¿åæèç设置 |
| | | const saveLossRate = () => { |
| | | if (!lossRate.value) { |
| | | console.log('æªéæ©æèçï¼è·³è¿ä¿å'); |
| | | return Promise.resolve(); |
| | | } |
| | | |
| | | const lossRateDataToSave = { |
| | | rate: parseFloat(lossRate.value) || 0 |
| | | }; |
| | | |
| | | // å¦æææ¥è¯¢å°çæèçæ°æ®ï¼è¯´ææ¯ä¿®æ¹æä½ï¼éè¦ä¼ éid |
| | | if (lossRateData.value && lossRateData.value.id) { |
| | | lossRateDataToSave.id = lossRateData.value.id; |
| | | } |
| | | |
| | | console.log('ä¿åæèçæ°æ®:', lossRateDataToSave); |
| | | |
| | | // æ ¹æ®æ¯å¦ææèçæ°æ®å³å®è°ç¨æ°å¢æ¥å£è¿æ¯ä¿®æ¹æ¥å£ |
| | | const saveLossApi = lossRateData.value && lossRateData.value.id ? updateLossRate : addLossRate; |
| | | const successMessage = lossRateData.value && lossRateData.value.id ? 'æèçä¿®æ¹æå' : 'æèçæ°å¢æå'; |
| | | |
| | | return saveLossApi(lossRateDataToSave).then(res => { |
| | | console.log('æèçä¿åæå:', res); |
| | | uni.showToast({ |
| | | title: successMessage, |
| | | icon: 'success' |
| | | }); |
| | | |
| | | // æ´æ°æèçæ°æ® |
| | | if (res.data) { |
| | | lossRateData.value = res.data; |
| | | } |
| | | |
| | | return res; |
| | | }).catch(err => { |
| | | console.error('æèçä¿å失败:', err); |
| | | uni.showToast({ |
| | | title: 'æèçä¿å失败', |
| | | icon: 'none' |
| | | }); |
| | | throw err; |
| | | }); |
| | | }; |
| | | |
| | | // ä¿åçæºæ»é设置 |
| | | const saveMachineTotals = () => { |
| | | // æé ä¿åæ°æ®æ°ç»ï¼ä½¿ç¨machinesæ°ç»å¾ªç¯æå»º |
| | | const saveData = machines.map(machine => { |
| | | const machineData = { |
| | | name: `çæº${machine.id}`, // çæºåç§° |
| | | workLoad: machineTotal[machine.key] || 0, // æ»é |
| | | vacant: machineVacant[machine.key] || 0 // 空ä½é |
| | | }; |
| | | |
| | | // 妿æ¯ä¿®æ¹æä½ï¼éè¦ä¼ éidåæ®µ |
| | | if (hasQueryData.value) { |
| | | // è¿ééè¦ä»æ¥è¯¢æ°æ®ä¸è·å对åºçid |
| | | // å设æ¥è¯¢æ°æ®ä¸æ¯ä¸ªçæºæ°æ®é½æidåæ®µ |
| | | const queryData = getMachineQueryData(machine.id); |
| | | if (queryData && queryData.id) { |
| | | machineData.id = queryData.id; |
| | | } |
| | | } |
| | | |
| | | return machineData; |
| | | }); |
| | | |
| | | console.log('ä¿åçæºè®¾ç½®æ°æ®:', saveData); |
| | | |
| | | // æ ¹æ®æ¯å¦ææ¥è¯¢æ°æ®å³å®è°ç¨æ°å¢æ¥å£è¿æ¯ä¿®æ¹æ¥å£ |
| | | const saveApi = hasQueryData.value ? updateSpeculatTrading : addSpeculatTrading; |
| | | const successMessage = hasQueryData.value ? 'çæºè®¾ç½®ä¿®æ¹æå' : 'çæºè®¾ç½®æ°å¢æå'; |
| | | |
| | | console.log(`è°ç¨æ¥å£: ${hasQueryData.value ? 'ä¿®æ¹' : 'æ°å¢'}`); |
| | | |
| | | // å
ä¿åæèçï¼åä¿åçæºè®¾ç½® |
| | | saveLossRate().then(() => { |
| | | // è°ç¨å端APIä¿åçæºè®¾ç½® |
| | | return saveApi(saveData); |
| | | }).then(res => { |
| | | uni.showToast({ |
| | | title: successMessage, |
| | | icon: 'success' |
| | | }); |
| | | console.log('ä¿åæå:', res); |
| | | |
| | | // ä¿åæååï¼è®¾ç½®hasQueryData为trueï¼ä¸æ¬¡ä¿åå°è°ç¨ä¿®æ¹æ¥å£ |
| | | if (!hasQueryData.value) { |
| | | hasQueryData.value = true; |
| | | } |
| | | }).catch(err => { |
| | | uni.showToast({ |
| | | title: 'ä¿å失败', |
| | | icon: 'none' |
| | | }); |
| | | console.error('ä¿å失败:', err); |
| | | }); |
| | | }; |
| | | |
| | | // 忢å个项ç®éæ©ç¶æ |
| | | const toggleItemSelection = (item, checked) => { |
| | | // ä»
å
è®¸éæ©å·²ç»å®æºå¨ä¸å¾
æ´¾æ°é>0çé¡¹ç® |
| | | if (!item.speculativeTradingName || item.pendingQuantity <= 0) return; |
| | | |
| | | console.log('åæ¢éæ©ç¶æ:', item.id, checked); |
| | | |
| | | // ä½¿ç¨æ´ä¸¥æ ¼çæ¯è¾é»è¾ï¼ç¡®ä¿IDå¯ä¸æ§ |
| | | const index = selectedItems.value.findIndex(selected => { |
| | | // 深度æ¯è¾å¯¹è±¡ï¼ç¡®ä¿æ¯åä¸ä¸ªé¡¹ç® |
| | | return JSON.stringify(selected) === JSON.stringify(item); |
| | | }); |
| | | |
| | | if (checked) { |
| | | // 妿éä¸ä¸ä¸å¨éä¸å表ä¸ï¼åæ·»å |
| | | if (index === -1) { |
| | | selectedItems.value.push({...item}); // å建æ°å¯¹è±¡ï¼é¿å
å¼ç¨é®é¢ |
| | | console.log('æ·»å 项ç®åé䏿°é:', selectedItems.value.length); |
| | | } |
| | | } else { |
| | | // 妿忶éä¸ä¸å¨éä¸å表ä¸ï¼åç§»é¤ |
| | | if (index > -1) { |
| | | selectedItems.value.splice(index, 1); |
| | | console.log('ç§»é¤é¡¹ç®åé䏿°é:', selectedItems.value.length); |
| | | } |
| | | } |
| | | |
| | | console.log('å½åéä¸é¡¹ç®å表:', selectedItems.value.map(s => s.id)); |
| | | updateAllSelectedStatus(); |
| | | updateBatchActionsVisibility(); |
| | | }; |
| | | |
| | | // 忢å
¨éç¶æ |
| | | const toggleAllSelection = () => { |
| | | if (isAllSelected.value) { |
| | | selectedItems.value = []; |
| | | } else { |
| | | selectedItems.value = tableData.value.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName).map(item => ({ ...item })); |
| | | } |
| | | isAllSelected.value = !isAllSelected.value; |
| | | updateBatchActionsVisibility(); |
| | | }; |
| | | |
| | | // æ´æ°å
¨éç¶æ |
| | | const updateAllSelectedStatus = () => { |
| | | const selectableItems = tableData.value.filter(item => item.pendingQuantity > 0 && item.speculativeTradingName); |
| | | if (selectableItems.length > 0 && selectedItems.value.length === selectableItems.length && |
| | | selectableItems.every(item => selectedItems.value.some(selected => selected.id === item.id))) { |
| | | isAllSelected.value = true; |
| | | } else { |
| | | isAllSelected.value = false; |
| | | } |
| | | }; |
| | | |
| | | // æ´æ°æ¹éæä½æ¾ç¤ºç¶æ |
| | | const updateBatchActionsVisibility = () => { |
| | | showBatchActions.value = selectedItems.value.length > 0; |
| | | }; |
| | | |
| | | // æ¸
ç©ºéæ© |
| | | const clearSelection = () => { |
| | | selectedItems.value = []; |
| | | isAllSelected.value = false; |
| | | showBatchActions.value = false; |
| | | }; |
| | | |
| | | // è·åéä¸çé¡¹ç® |
| | | const getSelectedItems = () => { |
| | | return selectedItems.value; |
| | | }; |
| | | |
| | | // å¤çèªå¨æ´¾å |
| | | const handleAutoDispatch = () => { |
| | | if (selectedItems.value.length === 0) { |
| | | uni.showToast({ |
| | | title: 'è¯·éæ©è¦æ´¾å·¥ç项ç®', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // æ£æ¥æ¯å¦ææéä¸é¡¹ç®é½æç»å®æºå¨ |
| | | const unboundItems = selectedItems.value.filter(item => !item.speculativeTradingName); |
| | | if (unboundItems.length > 0) { |
| | | uni.showToast({ |
| | | title: 'æé项ç®ä¸ææªç»å®æºå¨ç项ç®ï¼æ æ³èªå¨æ´¾å', |
| | | icon: 'none' |
| | | }); |
| | | return; |
| | | } |
| | | |
| | | // ç¡®ä¿ä¼ éçæ¯å®æ´çéä¸é¡¹ç®æ°ç» |
| | | autoDispatchDia.value?.openDialog([...selectedItems.value]); |
| | | }; |
| | | |
| | | // 页颿¾ç¤ºæ¶å è½½æ°æ® |
| | | onShow(() => { |
| | | // å è½½åè¡¨æ°æ® |
| | | getList(); |
| | | clearSelection(); |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | @import '@/styles/sales-common.scss'; |
| | | |
| | | // çäº§æ´¾å·¥é¡µé¢æ ·å¼ |
| | | .production-dispatching { |
| | | min-height: 100vh; |
| | | background: #f8f9fa; |
| | | padding: 20rpx; |
| | | position: relative; |
| | | } |
| | | |
| | | // æèç设置åºå |
| | | .loss-rate-section { |
| | | background: #ffffff; |
| | | border: 1rpx solid #e4e7ed; |
| | | border-radius: 12rpx; |
| | | padding: 32rpx; |
| | | margin-top: 24rpx; |
| | | margin-bottom: 32rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.08); |
| | | } |
| | | |
| | | .loss-rate-section .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .loss-rate-section .loss-rate-content { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24rpx; |
| | | } |
| | | |
| | | .loss-rate-section .loss-rate-content .loss-rate-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 24rpx; |
| | | } |
| | | |
| | | .loss-rate-section .loss-rate-content .loss-rate-label { |
| | | font-size: 30rpx; |
| | | font-weight: 500; |
| | | color: #303133; |
| | | min-width: 140rpx; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .loss-rate-section .loss-rate-content .loss-rate-btn { |
| | | min-width: 260rpx; |
| | | font-size: 28rpx; |
| | | height: 64rpx; |
| | | line-height: 64rpx; |
| | | border-radius: 8rpx; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | // çæºç¶æåºå |
| | | .machines-section { |
| | | margin-bottom: 30rpx; |
| | | } |
| | | |
| | | .machines-section .section-title { |
| | | font-size: 32rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | margin-bottom: 20rpx; |
| | | } |
| | | |
| | | .machines-grid { |
| | | display: grid; |
| | | grid-template-columns: 1fr 1fr; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .machine-card { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | padding: 24rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | border: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .machine-title { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | text-align: center; |
| | | margin-bottom: 20rpx; |
| | | padding-bottom: 16rpx; |
| | | border-bottom: 2rpx solid #3498db; |
| | | } |
| | | |
| | | .machine-metrics { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .metric-item { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 8rpx 0; |
| | | } |
| | | |
| | | .metric-label { |
| | | font-size: 24rpx; |
| | | color: #6c757d; |
| | | } |
| | | |
| | | .metric-value { |
| | | font-size: 26rpx; |
| | | font-weight: 600; |
| | | color: #2c3e50; |
| | | } |
| | | |
| | | // è¾å
¥æ¡æ ·å¼ |
| | | .metric-input { |
| | | width: 120rpx; |
| | | text-align: right; |
| | | } |
| | | |
| | | // ä¿ååºå |
| | | .save-section { |
| | | display: flex; |
| | | justify-content: center; |
| | | margin-top: 30rpx; |
| | | padding-top: 20rpx; |
| | | border-top: 1rpx solid #e9ecef; |
| | | } |
| | | |
| | | .save-btn { |
| | | min-width: 200rpx; |
| | | } |
| | | |
| | | // æç´¢åºå |
| | | .search-section { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | padding: 24rpx; |
| | | margin-bottom: 30rpx; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | .search-form { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .search-item { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 20rpx; |
| | | } |
| | | |
| | | .search-label { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | min-width: 140rpx; |
| | | } |
| | | |
| | | .search-input { |
| | | flex: 1; |
| | | } |
| | | |
| | | .search-buttons { |
| | | display: flex; |
| | | gap: 20rpx; |
| | | justify-content: flex-end; |
| | | margin-top: 10rpx; |
| | | } |
| | | |
| | | .search-btn, .reset-btn { |
| | | min-width: 120rpx; |
| | | } |
| | | |
| | | // åè¡¨æ ·å¼ |
| | | .ledger-list { |
| | | display: flex; |
| | | flex-direction: column; |
| | | gap: 24rpx; |
| | | } |
| | | |
| | | .list-item { |
| | | background: #ffffff; |
| | | border-radius: 16rpx; |
| | | overflow: hidden; |
| | | box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | // åè¡¨é¡¹æ ·å¼ |
| | | .ledger-item { |
| | | padding: 0; |
| | | } |
| | | |
| | | .item-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 24rpx 24rpx 0 24rpx; |
| | | } |
| | | |
| | | .item-left { |
| | | display: flex; |
| | | align-items: center; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .document-icon { |
| | | width: 48rpx; |
| | | height: 48rpx; |
| | | background: #409eff; |
| | | border-radius: 8rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | } |
| | | |
| | | .item-id { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #303133; |
| | | } |
| | | |
| | | .entry-date { |
| | | font-size: 24rpx; |
| | | color: #909399; |
| | | } |
| | | |
| | | .item-details { |
| | | padding: 24rpx; |
| | | } |
| | | |
| | | .detail-row { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 12rpx 0; |
| | | border-bottom: 1rpx solid #f5f5f5; |
| | | } |
| | | |
| | | .detail-row:last-child { |
| | | border-bottom: none; |
| | | } |
| | | |
| | | .detail-label { |
| | | font-size: 26rpx; |
| | | color: #606266; |
| | | } |
| | | |
| | | .detail-value { |
| | | font-size: 26rpx; |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .detail-value.highlight { |
| | | color: #ff6b35; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | color: #ee0a24; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .action-buttons { |
| | | padding: 0 24rpx 24rpx 24rpx; |
| | | display: flex; |
| | | justify-content: flex-end; |
| | | } |
| | | |
| | | .action-btn { |
| | | min-width: 180rpx; |
| | | } |
| | | |
| | | // æ¹éæä½åºåæ ·å¼ |
| | | .batch-actions-section { |
| | | background: #e8f4ff; |
| | | border: 1rpx solid #409eff; |
| | | border-radius: 12rpx; |
| | | padding: 20rpx 24rpx; |
| | | margin-bottom: 24rpx; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .batch-actions-section .batch-text { |
| | | font-size: 28rpx; |
| | | font-weight: 600; |
| | | color: #409eff; |
| | | } |
| | | |
| | | .batch-actions-section .batch-buttons { |
| | | display: flex; |
| | | gap: 16rpx; |
| | | } |
| | | |
| | | .batch-actions-section .batch-btn { |
| | | min-width: 140rpx; |
| | | } |
| | | |
| | | // å
¨éæä½åºåæ ·å¼ |
| | | .select-all-section { |
| | | background: #ffffff; |
| | | border-radius: 12rpx; |
| | | padding: 20rpx 24rpx; |
| | | margin-bottom: 16rpx; |
| | | border: 1rpx solid #e4e7ed; |
| | | } |
| | | |
| | | .select-all-section .select-all-content { |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .select-all-section .select-all-checkbox { |
| | | font-size: 28rpx; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | // åè¡¨é¡¹éæ©æ¡æ ·å¼ |
| | | .ledger-item { |
| | | display: flex; |
| | | align-items: flex-start; |
| | | padding: 0; |
| | | } |
| | | |
| | | .item-checkbox { |
| | | padding: 24rpx 16rpx 0 24rpx; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .item-content { |
| | | flex: 1; |
| | | } |
| | | |
| | | // ç©ºç¶æ |
| | | .no-data { |
| | | padding: 100rpx 0; |
| | | text-align: center; |
| | | } |
| | | |
| | | .no-data-text { |
| | | font-size: 28rpx; |
| | | color: #909399; |
| | | margin-top: 20rpx; |
| | | } |
| | | |
| | | // ç¹å»ç¼è¾åºåæ ·å¼ |
| | | .metric-value-container { |
| | | cursor: pointer; |
| | | min-width: 120rpx; |
| | | text-align: right; |
| | | padding: 4rpx 8rpx; |
| | | border-radius: 4rpx; |
| | | transition: all 0.2s ease; |
| | | } |
| | | |
| | | .metric-value-container:hover { |
| | | background-color: #f0f8ff; |
| | | border: 1rpx solid #409eff; |
| | | .detail-value.highlight { |
| | | color: #ff6b35; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .detail-value.danger { |
| | | color: #ee0a24; |
| | | font-weight: 600; |
| | | } |
| | | } |
| | | |
| | | // éé
uView ç»ä»¶æ ·å¼ |
| | | :deep(.up-input) { |
| | | background: transparent; |
| | | } |
| | | |
| | | :deep(.up-input__content) { |
| | | background: #f8f9fa; |
| | | } |
| | | </style> |
| | | </style> |
| | |
| | | <text class="detail-label">å½å
¥æ¥æ</text> |
| | | <text class="detail-value">{{ item.entryDate }}</text> |
| | | </view> |
| | | <!-- <view class="detail-row"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·ååå·</text> |
| | | <text class="detail-value">{{ item.customerContractNo }}</text> |
| | | </view> --> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">客æ·åç§°</text> |
| | | <text class="detail-value">{{ item.customerName }}</text> |
| | | </view> |
| | | <!-- <view class="detail-row"> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">项ç®åç§°</text> |
| | | <text class="detail-value">{{ item.projectName }}</text> |
| | | </view> --> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">仿¬¾ç¶æ</text> |
| | | <view v-if="item.status=='已宿'" class="detail-value"> |
| | | <uni-tag :inverted="true" text="已宿" type="success" size="mini" /> |
| | | </view> |
| | | <view v-else-if="item.status=='æªå®æ'" class="detail-value"> |
| | | <uni-tag :inverted="true" text="æªå®æ" type="error" size="mini" /> |
| | | </view> |
| | | <view v-else class="detail-value"> |
| | | <uni-tag :inverted="true" :text="item.status" type="primary" size="mini" /> |
| | | </view> |
| | | </view> |
| | | <view class="detail-row"> |
| | | <text class="detail-label">产å大类</text> |
| | |
| | | schedulingListPage(params).then((res) => { |
| | | loading.value = false; |
| | | closeToast(); |
| | | |
| | | tableData.value = res.data.records || []; |
| | | }).catch(() => { |
| | | loading.value = false; |
| ÎļþÃû´Ó src/pages/productionManagement/productionReporting/index.vue ÐÞ¸Ä |
| | |
| | | required> |
| | | <u-input v-model="form.userName" |
| | | placeholder="è¯·éæ©ç产人" |
| | | readonly /> |
| | | readonly |
| | | @click="openProducerPicker" |
| | | suffix-icon="arrow-down" /> |
| | | </u-form-item> |
| | | </view> |
| | | <!-- 使ç¨FooterButtonsç»ä»¶ --> |
| | |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, onMounted } from "vue"; |
| | | import { ref, nextTick } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import FooterButtons from "@/components/FooterButtons.vue"; |
| | | import modal from "@/plugins/modal"; |
| | | |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | |
| | | }; |
| | | import { addProductMain } from "@/api/productionManagement/productionReporting"; |
| | | import { getInfo } from "@/api/login"; |
| | | import { userListNoPageByTenantId } from "@/api/system/user"; |
| | | |
| | | // 表åå¼ç¨ |
| | | const formRef = ref(); |
| | | |
| | | // è¡¨åæ°æ® |
| | | let form = ref({ |
| | | planQuantity: 0, |
| | | quantity: 0, |
| | | planQuantity: "", |
| | | quantity: "", |
| | | userName: "", |
| | | workOrderId: "", |
| | | reportWork: "", |
| | | productProcessRouteItemId: "", |
| | | userId: "", |
| | | productMainId: null, |
| | | schedulingUserId: "", |
| | | }); |
| | | let schedulingUserName = ref(""); |
| | | |
| | | // æ¥æéæ©å¨ç¶æ |
| | | const showEnterDatePicker = ref(false); |
| | | const enterDateValue = ref(Date.now()); |
| | | |
| | | // çäº§äººéæ©å¨ç¶æ |
| | | const showProducerPicker = ref(false); |
| | | const producerList = ref([]); |
| | | |
| | | // æå¼çäº§äººéæ©å¨ |
| | | const openProducerPicker = async () => { |
| | | if (producerList.value.length === 0) { |
| | | // 妿å表为空ï¼å
å è½½ç¨æ·å表 |
| | | try { |
| | | const res = await userListNoPageByTenantId(); |
| | | const users = res.data || []; |
| | | // 转æ¢ä¸º action-sheet éè¦çæ ¼å¼ |
| | | producerList.value = users.map(user => ({ |
| | | name: user.nickName || user.userName, |
| | | value: user.userId, |
| | | })); |
| | | } catch (error) { |
| | | console.error("å è½½ç¨æ·å表失败:", error); |
| | | showToast("å è½½ç¨æ·å表失败"); |
| | | return; |
| | | } |
| | | } |
| | | showProducerPicker.value = true; |
| | | }; |
| | | |
| | | // çäº§äººéæ©ç¡®è®¤ |
| | | const onProducerConfirm = e => { |
| | | form.value.schedulingUserId = e.value; |
| | | schedulingUserName.value = e.name; |
| | | form.value.userName = e.name; |
| | | form.value.userId = e.value; // åæ¶æ´æ° userId |
| | | showProducerPicker.value = false; |
| | | }; |
| | | |
| | |
| | | showToast("请è¾å
¥æ¬æ¬¡ç产æ°é"); |
| | | return; |
| | | } |
| | | if (form.value.quantity > form.value.planQuantity) { |
| | | if (!form.value.schedulingUserId) { |
| | | submitting.value = false; |
| | | showToast("è¯·éæ©ç产人"); |
| | | return; |
| | | } |
| | | // 转æ¢ä¸ºæ°åè¿è¡æ¯è¾ |
| | | const quantity = Number(form.value.quantity); |
| | | const planQuantity = Number(form.value.planQuantity); |
| | | if (quantity > planQuantity) { |
| | | submitting.value = false; |
| | | showToast("æ¬æ¬¡ç产æ°éä¸è½å¤§äºå¾
ç产æ°é"); |
| | | return; |
| | | } |
| | | console.log(form.value, "form.value"); |
| | | // åå¤æäº¤æ°æ®ï¼ç¡®ä¿æ°éåæ®µä¸ºæ°åç±»å |
| | | const submitData = { |
| | | ...form.value, |
| | | quantity: Number(form.value.quantity), |
| | | planQuantity: Number(form.value.planQuantity) || 0, |
| | | }; |
| | | console.log(submitData, "submitData"); |
| | | |
| | | addProductMain(form.value).then(res => { |
| | | addProductMain(submitData).then(res => { |
| | | if (res.code === 200) { |
| | | showToast("æ¥å·¥æå"); |
| | | submitting.value = false; |
| | |
| | | console.log(options, "options"); |
| | | try { |
| | | const orderRow = JSON.parse(options.orderRow); |
| | | console.log("æé çorderRow:", orderRow); |
| | | console.log(orderRow, "orderRow======########"); |
| | | form.value.planQuantity = orderRow.planQuantity; |
| | | form.value.quantity = orderRow.quantity; |
| | | form.value.productProcessRouteItemId = orderRow.productProcessRouteItemId; |
| | | form.value.workOrderId = orderRow.id; |
| | | form.value.reportWork = orderRow.reportWork; |
| | | form.value.productMainId = orderRow.productMainId; |
| | | // ç¡®ä¿ planQuantity 转æ¢ä¸ºå符串ï¼ä»¥ä¾¿å¨ u-input 䏿£ç¡®æ¾ç¤º |
| | | form.value.planQuantity = orderRow.planQuantity != null ? String(orderRow.planQuantity) : ""; |
| | | form.value.productProcessRouteItemId = orderRow.productProcessRouteItemId || ""; |
| | | form.value.workOrderId = orderRow.id || ""; |
| | | getInfo().then(res => { |
| | | // é»è®¤ä½¿ç¨å½åç»å½ç¨æ·ï¼ä½å
è®¸ç¨æ·ä¿®æ¹ |
| | | form.value.userId = res.user.userId; |
| | | form.value.userName = res.user.userName; |
| | | form.value.schedulingUserId = res.user.userId; |
| | | }); |
| | | // ä½¿ç¨ nextTick ç¡®ä¿ DOM æ´æ° |
| | | nextTick(() => { |
| | | console.log("form.value after assignment:", form.value); |
| | | }); |
| | | } catch (error) { |
| | | modal.msgError("订åè§£æå¤±è´¥"); |
| | | console.error("订åè§£æå¤±è´¥:", error); |
| | | showToast("订åè§£æå¤±è´¥"); |
| | | goBack(); |
| | | return; |
| | | } |