Merge remote-tracking branch 'origin/dev_NEW_pro' into dev_NEW_pro
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | # æ¬å°æä»¶ä¸ä¼ README |
| | | |
| | | æ¬ææ¡£åºäºä»¥ä¸å®ç°æ´çï¼ |
| | | |
| | | - `src/components/AttachmentUpload/file/index.vue` |
| | | - `src/components/AttachmentUpload/image/index.vue` |
| | | - `src/components/AttachmentPreview/image/index.vue` |
| | | - `src/components/Dialog/FileList.vue` |
| | | - `src/api/basicData/common.js` |
| | | - `src/api/publicApi/commonFile.js` |
| | | |
| | | ç¸å
³ç»ä»¶å·²å¨ `src/main.js` 䏿³¨å为å
¨å±ç»ä»¶ï¼å¯ç´æ¥å¨é¡µé¢ä¸ä½¿ç¨ï¼ |
| | | |
| | | - `FileUpload` |
| | | - `ImageUpload` |
| | | - `ImagePreview` |
| | | - `FileListDialog` |
| | | |
| | | ## 1. åè½æ¦è§ |
| | | |
| | | å½åè¿å¥ä¸ä¼ è½å主è¦å为 4 é¨åï¼ |
| | | |
| | | 1. `FileUpload`ï¼æ®éæä»¶ä¸ä¼ ï¼æ¯æææ½ãæ¹éä¸ä¼ ãé¢è§ãå é¤ |
| | | 2. `ImageUpload`ï¼å¾çä¸ä¼ ï¼æ¯æå¾çå¢å±ç¤ºãé¢è§ãå é¤ |
| | | 3. `ImagePreview`ï¼å¾çå表é¢è§å±ç¤º |
| | | 4. `FileListDialog`ï¼ä¸å¡éä»¶å¼¹çªï¼æ¯ææ¥è¯¢ãä¸ä¼ ãå é¤ãä¸è½½ |
| | | |
| | | ä¸ä¼ åºå±ç»ä¸èµ°æ¥å£ï¼ |
| | | |
| | | - `POST /common/upload` |
| | | |
| | | å¯¹åºæ¹æ³å¨ `src/api/basicData/common.js`ï¼ |
| | | |
| | | ```js |
| | | uploadFile(data) |
| | | ``` |
| | | |
| | | ## 2. ä¸ä¼ æ¥å£è¯´æ |
| | | |
| | | ### 2.1 éç¨ä¸ä¼ æ¥å£ |
| | | |
| | | æä»¶ä¸ä¼ ç»ä»¶åå¾çä¸ä¼ ç»ä»¶é½è°ç¨äºï¼ |
| | | |
| | | ```js |
| | | import { uploadFile } from '@/api/basicData/common' |
| | | ``` |
| | | |
| | | æ¥å£ç¹å¾ï¼ |
| | | |
| | | - è¯·æ±æ¹å¼ï¼`POST` |
| | | - å°åï¼`/common/upload` |
| | | - 请æ±ç±»åï¼`multipart/form-data` |
| | | - æ¯æ `FormData` æ¹éä¸ä¼ |
| | | - é»è®¤å段åï¼`files` |
| | | |
| | | ç»ä»¶å
é¨ä¼è¿æ ·ç»è£
åæ°ï¼ |
| | | |
| | | ```js |
| | | const formData = new FormData() |
| | | validFiles.forEach((file) => { |
| | | formData.append(props.uploadFieldName, file.raw) |
| | | }) |
| | | ``` |
| | | |
| | | ### 2.2 ä¸ä¼ è¿åå¼è¦æ± |
| | | |
| | | ä¸ä¼ æååï¼ç»ä»¶ä¼å°è¯ä»ä»¥ä¸ç»æä¸æåæ°ç»ï¼ |
| | | |
| | | - `response` |
| | | - `response.data` |
| | | - `response.data.data` |
| | | - `response.payload` |
| | | - `response.payload.data` |
| | | - `response.rows` |
| | | - `response.result` |
| | | |
| | | å æ¤å端è¿åæ°ç»æ¶ï¼ä¸é¢ä»»æä¸ç§ç»æé½å¯ä»¥è¢«è¯å«ã |
| | | |
| | | ç»ä»¶å±ç¤ºæ¶å¸¸ç¨å°çåæ®µæï¼ |
| | | |
| | | - æä»¶åï¼`name` / `originalFilename` / `fileName` / `uidFilename` |
| | | - æä»¶å°åï¼`url` / `downloadURL` |
| | | - å¾çå°åï¼`url` / `previewURL` / `previewUrl` |
| | | - 主é®ï¼`id` |
| | | |
| | | 建议ä¸ä¼ æ¥å£è¿åçå项对象尽éå
å«ï¼ |
| | | |
| | | ```js |
| | | { |
| | | id: 1, |
| | | originalFilename: 'demo.pdf', |
| | | downloadURL: 'https://xxx/demo.pdf', |
| | | previewURL: 'https://xxx/demo.png' |
| | | } |
| | | ``` |
| | | |
| | | ## 3. FileUpload æä»¶ä¸ä¼ ç»ä»¶ |
| | | |
| | | ç»ä»¶è·¯å¾ï¼ |
| | | |
| | | `src/components/AttachmentUpload/file/index.vue` |
| | | |
| | | ### 3.1 åºç¡ç¨æ³ |
| | | |
| | | ```vue |
| | | <template> |
| | | <FileUpload v-model:file-list="fileList" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | |
| | | const fileList = ref([]) |
| | | </script> |
| | | ``` |
| | | |
| | | ### 3.2 常ç¨å±æ§ |
| | | |
| | | | 屿§ | 说æ | ç±»å | é»è®¤å¼ | |
| | | | --- | --- | --- | --- | |
| | | | `fileList` | ç»å®æä»¶å表 | `Array` | `[]` | |
| | | | `limit` | æå¤§ä¸ä¼ æ°é | `Number` | `10` | |
| | | | `fileSize` | å个æä»¶å¤§å°éå¶ï¼åä½ MB | `Number` | `50` | |
| | | | `fileType` | å
许ä¸ä¼ çæä»¶ç±»åï¼å¦ `['pdf', 'docx']` | `Array` | `[]` | |
| | | | `buttonText` | ä¸ä¼ æç¤ºææ¡ | `String` | `åå»éæ©æä»¶` | |
| | | | `disabled` | æ¯å¦ç¦ç¨ | `Boolean` | `false` | |
| | | | `uploadFieldName` | `FormData` åæ®µå | `String` | `files` | |
| | | | `index` | è¡¨æ ¼/åè¡¨è¡æ¨¡å¼ä¸çå½åè¡ç´¢å¼ | `Number` | `-1` | |
| | | | `childrenKey` | è¡å
æè½½å段å | `String` | `files` | |
| | | |
| | | ### 3.3 äºä»¶ |
| | | |
| | | | äºä»¶ | 说æ | |
| | | | --- | --- | |
| | | | `update:fileList` | æä»¶å表ååæ¶è§¦å | |
| | | | `change` | æä»¶å表ååæ¶è§¦åï¼è¿åææ°å表 | |
| | | |
| | | ### 3.4 éå¶è§å |
| | | |
| | | ç»ä»¶å
å·²å®ç°ï¼ |
| | | |
| | | - æä»¶æ°ééå¶ |
| | | - æä»¶å¤§å°éå¶ |
| | | - æä»¶ç±»åæ ¡éª |
| | | - ä¸ä¼ ä¸ç¶æéå® |
| | | - 失败åèªå¨æ¸
空å½åéæ©éå |
| | | |
| | | ä¾å¦éå¶ PDF/Wordï¼ |
| | | |
| | | ```vue |
| | | <FileUpload |
| | | v-model:file-list="fileList" |
| | | :limit="5" |
| | | :file-size="20" |
| | | :file-type="['pdf', 'doc', 'docx']" |
| | | /> |
| | | ``` |
| | | |
| | | ### 3.5 è¿åæ°æ®æ ¼å¼å»ºè®® |
| | | |
| | | `FileUpload` æ´é忥æ¶è¿æ ·çåè¡¨ï¼ |
| | | |
| | | ```js |
| | | [ |
| | | { |
| | | id: 1, |
| | | originalFilename: 'åå.pdf', |
| | | downloadURL: 'https://xxx/contract.pdf' |
| | | } |
| | | ] |
| | | ``` |
| | | |
| | | å 为ç»ä»¶æå¼æä»¶æ¶ä¼ä¼å
读åï¼ |
| | | |
| | | ```js |
| | | url || downloadURL || previewURL || previewUrl |
| | | ``` |
| | | |
| | | ### 3.6 è¡å
åµå¥æ¨¡å¼ |
| | | |
| | | 妿ä¸ä¼ ç»ä»¶æ¾å¨è¡¨æ ¼æä¸è¡ä¸ï¼å¯é
å `index` å `childrenKey` 使ç¨ï¼ |
| | | |
| | | ```vue |
| | | <FileUpload |
| | | v-model:file-list="tableData" |
| | | :index="scope.$index" |
| | | children-key="files" |
| | | /> |
| | | ``` |
| | | |
| | | æ¤æ¶ç»ä»¶ä¼èªå¨è¯»åï¼ |
| | | |
| | | ```js |
| | | tableData[scope.$index].files |
| | | ``` |
| | | |
| | | ## 4. ImageUpload å¾çä¸ä¼ ç»ä»¶ |
| | | |
| | | ç»ä»¶è·¯å¾ï¼ |
| | | |
| | | `src/components/AttachmentUpload/image/index.vue` |
| | | |
| | | ### 4.1 åºç¡ç¨æ³ |
| | | |
| | | ```vue |
| | | <template> |
| | | <ImageUpload v-model:file-list="imageList" /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | |
| | | const imageList = ref([]) |
| | | </script> |
| | | ``` |
| | | |
| | | ### 4.2 é»è®¤è¡ä¸º |
| | | |
| | | å¾çä¸ä¼ ç»ä»¶é»è®¤ï¼ |
| | | |
| | | - æå¤ä¸ä¼ `10` å¼ |
| | | - åå¼ ä¸è¶
è¿ `10MB` |
| | | - é»è®¤æ¯ææ ¼å¼ï¼`png / jpg / jpeg / webp` |
| | | - ä½¿ç¨ `picture-card` 飿 ¼å±ç¤º |
| | | - ç¹å»ç¼©ç¥å¾å¯é¢è§å¤§å¾ |
| | | |
| | | ### 4.3 常ç¨ç¤ºä¾ |
| | | |
| | | ```vue |
| | | <ImageUpload |
| | | v-model:file-list="imageList" |
| | | :limit="9" |
| | | :file-size="5" |
| | | :file-type="['png', 'jpg', 'jpeg']" |
| | | button-text="ä¸ä¼ å¾ç" |
| | | /> |
| | | ``` |
| | | |
| | | ### 4.4 è¿åæ°æ®æ ¼å¼å»ºè®® |
| | | |
| | | `ImageUpload` å±ç¤ºå¾çæ¶ä¼å
读åï¼ |
| | | |
| | | ```js |
| | | url || previewURL || previewUrl |
| | | ``` |
| | | |
| | | 建议å端è¿åï¼ |
| | | |
| | | ```js |
| | | [ |
| | | { |
| | | id: 1, |
| | | originalFilename: 'ç°åºå¾ç.jpg', |
| | | previewURL: 'https://xxx/image.jpg' |
| | | } |
| | | ] |
| | | ``` |
| | | |
| | | ### 4.5 è¡å
åµå¥æ¨¡å¼ |
| | | |
| | | å¾çç»ä»¶åæ ·æ¯æè¡å
åæ®µååï¼ |
| | | |
| | | ```vue |
| | | <ImageUpload |
| | | v-model:file-list="tableData" |
| | | :index="scope.$index" |
| | | children-key="images" |
| | | /> |
| | | ``` |
| | | |
| | | é»è®¤åååæ®µä¸º `images`ã |
| | | |
| | | ## 5. ImagePreview å¾çé¢è§ç»ä»¶ |
| | | |
| | | ç»ä»¶è·¯å¾ï¼ |
| | | |
| | | `src/components/AttachmentPreview/image/index.vue` |
| | | |
| | | ### 5.1 åºç¡ç¨æ³ |
| | | |
| | | ```vue |
| | | <ImagePreview :file-list="imageList" /> |
| | | ``` |
| | | |
| | | ### 5.2 å¯é
置项 |
| | | |
| | | | 屿§ | 说æ | ç±»å | é»è®¤å¼ | |
| | | | --- | --- | --- | --- | |
| | | | `fileList` | å¾çå表 | `Array` | `[]` | |
| | | | `thumbSize` | 缩ç¥å¾å¤§å° | `Number` | `72` | |
| | | | `gap` | 缩ç¥å¾é´è· | `Number` | `10` | |
| | | |
| | | ### 5.3 æ°æ®è¦æ± |
| | | |
| | | ç»ä»¶ä¼è¿æ»¤æ²¡æ `previewURL` ç项ï¼å æ¤å¦æè¦æ£å¸¸æ¾ç¤ºï¼å»ºè®®è³å°å
å«ï¼ |
| | | |
| | | ```js |
| | | [ |
| | | { |
| | | previewURL: 'https://xxx/image.jpg', |
| | | originalFilename: 'å¾ç1.jpg' |
| | | } |
| | | ] |
| | | ``` |
| | | |
| | | 妿å表为空ï¼ç»ä»¶æ¾ç¤ºâææ å¾çâã |
| | | |
| | | ## 6. FileListDialog éä»¶å¼¹çªç»ä»¶ |
| | | |
| | | ç»ä»¶è·¯å¾ï¼ |
| | | |
| | | `src/components/Dialog/FileList.vue` |
| | | |
| | | è¿ä¸ªç»ä»¶éåä¸å¡è¡¨åæè¯¦æ
页éçâé件管çâåºæ¯ï¼è½åå
æ¬ï¼ |
| | | |
| | | - æ ¹æ®ä¸å¡ä¸»é®æ¥è¯¢éä»¶å表 |
| | | - æå¼å¼¹çªæ¥çéä»¶ |
| | | - å¨å¼¹çªä¸ç»§ç»ä¸ä¼ éä»¶ |
| | | - å é¤éä»¶ |
| | | - ä¸è½½éä»¶ |
| | | |
| | | ### 6.1 ç»ä»¶å±æ§ |
| | | |
| | | | 屿§ | 说æ | ç±»å | é»è®¤å¼ | |
| | | | --- | --- | --- | --- | |
| | | | `visible` | æ¯å¦æ¾ç¤ºå¼¹çª | `Boolean` | å¿
ä¼ | |
| | | | `recordType` | ä¸å¡ç±»å | `String` | `''` | |
| | | | `recordId` | ä¸å¡ä¸»é® | `Number` | `0` | |
| | | | `title` | å¼¹çªæ é¢ | `String` | `éä»¶` | |
| | | | `width` | å¼¹çªå®½åº¦ | `String` | `50%` | |
| | | | `showActions` | æ¯å¦æ¾ç¤ºä¸è½½/å 餿ä½å | `Boolean` | `true` | |
| | | |
| | | ### 6.2 åºç¡ç¨æ³ |
| | | |
| | | ```vue |
| | | <template> |
| | | <el-button @click="visible = true">æ¥çéä»¶</el-button> |
| | | |
| | | <FileListDialog |
| | | v-model:visible="visible" |
| | | record-type="salesLedger" |
| | | :record-id="rowId" |
| | | title="éä»¶å表" |
| | | /> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | |
| | | const visible = ref(false) |
| | | const rowId = ref(1001) |
| | | </script> |
| | | ``` |
| | | |
| | | ### 6.3 ç»ä»¶å
é¨ä¾èµçæ¥å£ |
| | | |
| | | `FileListDialog` æ¬èº«ä¸ç´æ¥è°ç¨ `commonFile.js`ï¼èæ¯ä¾èµï¼ |
| | | |
| | | - `attachmentList` |
| | | - `createAttachment` |
| | | - `deleteAttachment` |
| | | |
| | | å¤çé»è¾ä¸ºï¼ |
| | | |
| | | 1. æå¼å¼¹çªåæ ¹æ® `recordType + recordId` æ¥è¯¢éä»¶ |
| | | 2. ç¹å»âä¸ä¼ éä»¶âåï¼å
é¨ä½¿ç¨ `AttachmentUpload/file` å
ä¸ä¼ å° `/common/upload` |
| | | 3. ä¸ä¼ æååï¼å°è¿åçæä»¶å¯¹è±¡åå·²æå表ä¸èµ·æäº¤ç» `createAttachment` |
| | | 4. å 餿¶è°ç¨ `deleteAttachment` |
| | | 5. ä¸è½½æ¶ç´æ¥ `window.open(downloadURL, '_blank')` |
| | | |
| | | å æ¤è¿éè¦ç¹å«æ³¨æï¼ |
| | | |
| | | - `recordType` å `recordId` å¿
é¡»æ¯ææä¸å¡æ è¯ |
| | | - ä¸ä¼ æåè¿åçæ°æ®ï¼éè¦è½è¢« `createAttachment` ç´æ¥æ¥æ¶ |
| | | - å表ä¸çä¸è½½å°ååæ®µåºä¸º `downloadURL` |
| | | |
| | | ## 7. commonFile.js 说æ |
| | | |
| | | æä»¶è·¯å¾ï¼ |
| | | |
| | | `src/api/publicApi/commonFile.js` |
| | | |
| | | å½åæä»¶æä¾çæ¯å
Œ
±æä»¶å 餿¥å£ï¼ |
| | | |
| | | ```js |
| | | delCommonFile(ids) |
| | | delCommonFileInvoiceLedger(ids) |
| | | ``` |
| | | |
| | | å¯¹åºæ¥å£ï¼ |
| | | |
| | | - `/commonFile/delCommonFile` |
| | | - `/invoiceLedger/delFile` |
| | | |
| | | è¿ä¸¤ä¸ªæ¹æ³æ´éåå·²ç»åå
·ä½ä¸å¡ç»å®åçâå é¤å·²ä¿åéä»¶âåºæ¯ï¼ä¸è´è´£ä¸ä¼ æä»¶æ¬èº«ã |
| | | |
| | | 示ä¾ï¼ |
| | | |
| | | ```js |
| | | import { delCommonFile } from '@/api/publicApi/commonFile' |
| | | |
| | | await delCommonFile([1, 2, 3]) |
| | | ``` |
| | | |
| | | ## 8. æ¨èä½¿ç¨æ¹å¼ |
| | | |
| | | ### 8.1 æ®éä¸å¡è¡¨åä¸ä¼ éä»¶ |
| | | |
| | | ```vue |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" /> |
| | | ``` |
| | | |
| | | æäº¤è¡¨åæ¶ç´æ¥å¸¦ä¸ï¼ |
| | | |
| | | ```js |
| | | { |
| | | ...form, |
| | | storageBlobDTOs: form.storageBlobDTOs |
| | | } |
| | | ``` |
| | | |
| | | ### 8.2 å¾çç±»ä¸å¡ |
| | | |
| | | ```vue |
| | | <ImageUpload v-model:file-list="form.images" /> |
| | | <ImagePreview :file-list="form.images" /> |
| | | ``` |
| | | |
| | | ### 8.3 å·²è½åºé件管ç |
| | | |
| | | ```vue |
| | | <FileListDialog |
| | | v-model:visible="dialogVisible" |
| | | :record-type="recordType" |
| | | :record-id="recordId" |
| | | /> |
| | | ``` |
| | | |
| | | éå详æ
页ã审æ¹é¡µãå°è´¦é¡µè¿ç±»âæ¥çå¹¶ç»´æ¤å½åä¸å¡éä»¶âçåºæ¯ã |
| | | |
| | | ## 9. 注æäºé¡¹ |
| | | |
| | | 1. `FileUpload` å `ImageUpload` åªæ¯è´è´£ææä»¶å
ä¼ å° `/common/upload`ï¼ä¸çäºå·²ç»åä¸å¡æ°æ®ç»å®ã |
| | | 2. 妿ä¸å¡éè¦æä¹
åéä»¶å
³ç³»ï¼ä»éè¦å¨ä¿åè¡¨åæ¶æè¿åçæä»¶å¯¹è±¡æäº¤ç»ä¸å¡æ¥å£ã |
| | | 3. `ImagePreview` å½ååªè¯å« `previewURL`ï¼å¦æå端åªè¿å `url`ï¼é¢è§ç»ä»¶å°ä¸ä¼å±ç¤ºï¼æå¥½ç»ä¸è¡¥é½ `previewURL`ã |
| | | 4. `FileListDialog` ä¾èµ `recordType`ã`recordId` æ¥è¯¢åä¿åéä»¶å
³ç³»ï¼æ°å¢ä¸å¡æ¶è¦å
确认å端å
³èæ¥å£å¯ç¨ã |
| | | 5. å 餿¬å°å表项åå é¤å·²ä¿åéä»¶æ¯ä¸¤ä»¶äºï¼ |
| | | - ä¸ä¼ ç»ä»¶éçå é¤ï¼åªä¼ä»å½åå端ç»å®æ°ç»ä¸ç§»é¤ |
| | | - `commonFile.js` / `deleteAttachment`ï¼ææ¯çæ£è°ç¨å端å é¤ |
| | | |
| | | ## 10. ä¸å¥æå¸¸è§ç页é¢åæ³ |
| | | |
| | | ```vue |
| | | <template> |
| | | <el-form :model="form"> |
| | | <el-form-item label="éä»¶"> |
| | | <FileUpload v-model:file-list="form.storageBlobDTOs" :limit="5" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="ç°åºå¾ç"> |
| | | <ImageUpload v-model:file-list="form.images" :limit="9" /> |
| | | </el-form-item> |
| | | |
| | | <el-form-item label="å¾çé¢è§"> |
| | | <ImagePreview :file-list="form.images" /> |
| | | </el-form-item> |
| | | </el-form> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref } from 'vue' |
| | | |
| | | const form = ref({ |
| | | storageBlobDTOs: [], |
| | | images: [], |
| | | }) |
| | | </script> |
| | | ``` |
| | | |
| | | å¦æä½ çç®æ æ¯âå
ä¸ä¼ ï¼åè·ä¸å¡ä¸èµ·ä¿åâï¼è¿å¥åæ³å¯ä»¥ç´æ¥ä½ä¸ºåºç¡æ¨¡æ¿ä½¿ç¨ã |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | { |
| | | "compilerOptions": { |
| | | "baseUrl": ".", |
| | | "paths": { |
| | | "@/*": ["src/*"], |
| | | "~/*": ["./*"] |
| | | } |
| | | }, |
| | | "include": ["src/**/*.js", "src/**/*.vue", "vite.config.js"] |
| | | } |
| | |
| | | import request from '@/utils/request' |
| | | import request from "@/utils/request"; |
| | | |
| | | // å·¥åºå表å页æ¥è¯¢ |
| | | export function productProcessListPage(query) { |
| | | return request({ |
| | | url: '/productProcess/listPage', |
| | | method: 'get', |
| | | params: query |
| | | }) |
| | | url: "/technologyOperation/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | | } |
| | |
| | | }); |
| | | } |
| | | |
| | | // ç产订å-ä¿®æ¹ |
| | | export function updateProductOrder(data) { |
| | | return request({ |
| | | url: "/productionOrder/updateOrder", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | | } |
| | | |
| | | export function delProductOrder(ids) { |
| | | return request({ |
| | | url: `/productionOrder/delete`, |
| | |
| | | // å页æ¥è¯¢ |
| | | export function listPage(query) { |
| | | return request({ |
| | | url: "/productProcess/listPage", |
| | | url: "/technologyOperation/listPage", |
| | | method: "get", |
| | | params: query, |
| | | }); |
| | |
| | | // 导å
¥æ°æ® |
| | | export function importData(data) { |
| | | return request({ |
| | | url: "/productProcess/importData", |
| | | url: "/technologyOperation/importData", |
| | | method: "post", |
| | | data: data, |
| | | }); |
| | |
| | | // ä¸è½½æ¨¡æ¿ |
| | | export function downloadTemplate() { |
| | | return request({ |
| | | url: "/productProcess/downloadTemplate", |
| | | url: "/technologyOperation/downloadTemplate", |
| | | method: "post", |
| | | responseType: "blob", |
| | | }); |
| | |
| | | @close="handleClose" |
| | | class="attachment-dialog"> |
| | | <!-- å·¥å
·æ --> |
| | | <div class="toolbar"> |
| | | <div v-if="editable" |
| | | class="toolbar"> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="handleUpload"> |
| | |
| | | <el-dialog v-model="uploadDialogVisible" |
| | | title="ä¸ä¼ éä»¶" |
| | | width="50%" |
| | | @close="handleUploadClose"> |
| | | @close="closeUpload"> |
| | | <AttachmentUpload v-model:file-list="newFileList" /> |
| | | <template #footer> |
| | | <el-button @click="handleUploadClose">å
³é</el-button> |
| | | <el-button @click="saveUpload">ä¿å</el-button> |
| | | <el-button @click="closeUpload">å
³é</el-button> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æä»¶åè¡¨è¡¨æ ¼ --> |
| | |
| | | <el-button link |
| | | type="primary" |
| | | size="small" |
| | | :href="scope.row.downloadURL" |
| | | class="download-link"> |
| | | class="download-link" |
| | | @click="downloadFile(scope.row.downloadURL)"> |
| | | ä¸è½½ |
| | | </el-button> |
| | | <el-button link |
| | | <el-button v-if="editable" |
| | | link |
| | | type="danger" |
| | | size="small" |
| | | @click="handleDelete(scope.row)"> |
| | |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | editable: { |
| | | type: Boolean, |
| | | default: true, |
| | | }, |
| | | }); |
| | | |
| | | const emit = defineEmits(["close", "download", "upload", "delete"]); |
| | |
| | | uploadDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleUploadClose = async () => { |
| | | const saveUpload = async () => { |
| | | // æ£æ¥æ¯å¦ææ°ä¸ä¼ çæä»¶ |
| | | if (newFileList.value.length > 0) { |
| | | try { |
| | |
| | | proxy?.$modal?.msgError("ä¸ä¼ 失败"); |
| | | } |
| | | } |
| | | uploadDialogVisible.value = false; |
| | | }; |
| | | |
| | | const closeUpload = () => { |
| | | newFileList.value = []; |
| | | uploadDialogVisible.value = false; |
| | | }; |
| | | |
| | |
| | | }); |
| | | }; |
| | | |
| | | const downloadFile = url => { |
| | | window.open(url, "_blank"); |
| | | }; |
| | | onMounted(() => { |
| | | setList(); |
| | | }); |
| | |
| | | class="lims-table"> |
| | | <el-table-column align="center" |
| | | type="selection" |
| | | :selectable="selectable" |
| | | width="55" |
| | | v-if="isSelection" /> |
| | | <el-table-column align="center" |
| | |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | selectable: { |
| | | type: Function, |
| | | default: () => true, |
| | | }, |
| | | isShowPagination: { |
| | | type: Boolean, |
| | | default: true, |
| | |
| | | <template> |
| | | <div :class="{ 'has-logo': showLogo }" class="sidebar-container"> |
| | | <logo v-if="showLogo" :collapse="isCollapse" /> |
| | | <div :class="{ 'has-logo': showLogo }" |
| | | class="sidebar-container"> |
| | | <logo v-if="showLogo" |
| | | :collapse="isCollapse" /> |
| | | <el-scrollbar wrap-class="scrollbar-wrapper"> |
| | | <el-menu |
| | | :default-active="activeMenu" |
| | | <el-menu :default-active="activeMenu" |
| | | :collapse="isCollapse" |
| | | :background-color="getMenuBackground" |
| | | :text-color="getMenuTextColor" |
| | |
| | | :active-text-color="theme" |
| | | :collapse-transition="false" |
| | | mode="vertical" |
| | | :class="sideTheme" |
| | | > |
| | | <sidebar-item |
| | | v-for="(route, index) in sidebarRouters" |
| | | :class="sideTheme"> |
| | | <sidebar-item v-for="(route, index) in sidebarRouters" |
| | | :key="route.path + index" |
| | | :item="route" |
| | | :base-path="route.path" |
| | | /> |
| | | :base-path="route.path" /> |
| | | </el-menu> |
| | | </el-scrollbar> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import Logo from './Logo' |
| | | import SidebarItem from './SidebarItem' |
| | | import variables from '@/assets/styles/variables.module.scss' |
| | | import useAppStore from '@/store/modules/app' |
| | | import useSettingsStore from '@/store/modules/settings' |
| | | import usePermissionStore from '@/store/modules/permission' |
| | | import Logo from "./Logo"; |
| | | import SidebarItem from "./SidebarItem"; |
| | | import variables from "@/assets/styles/variables.module.scss"; |
| | | import useAppStore from "@/store/modules/app"; |
| | | import useSettingsStore from "@/store/modules/settings"; |
| | | import usePermissionStore from "@/store/modules/permission"; |
| | | |
| | | const route = useRoute() |
| | | const appStore = useAppStore() |
| | | const settingsStore = useSettingsStore() |
| | | const permissionStore = usePermissionStore() |
| | | const route = useRoute(); |
| | | const appStore = useAppStore(); |
| | | const settingsStore = useSettingsStore(); |
| | | const permissionStore = usePermissionStore(); |
| | | |
| | | const sidebarRouters = computed(() => permissionStore.sidebarRouters) |
| | | const showLogo = computed(() => settingsStore.sidebarLogo) |
| | | const sideTheme = computed(() => settingsStore.sideTheme) |
| | | const theme = computed(() => settingsStore.theme) |
| | | const isCollapse = computed(() => !appStore.sidebar.opened) |
| | | const sidebarRouters = computed(() => permissionStore.sidebarRouters); |
| | | const showLogo = computed(() => settingsStore.sidebarLogo); |
| | | const sideTheme = computed(() => settingsStore.sideTheme); |
| | | const theme = computed(() => settingsStore.theme); |
| | | const isCollapse = computed(() => !appStore.sidebar.opened); |
| | | |
| | | const getMenuBackground = computed(() => 'var(--sidebar-bg)') |
| | | const getMenuBackground = computed(() => "var(--sidebar-bg)"); |
| | | |
| | | const getMenuTextColor = computed(() => { |
| | | if (settingsStore.isDark) { |
| | | return 'var(--sidebar-text)' |
| | | return "var(--sidebar-text)"; |
| | | } |
| | | return sideTheme.value === 'theme-dark' ? variables.menuText : variables.menuLightText |
| | | }) |
| | | return sideTheme.value === "theme-dark" |
| | | ? variables.menuText |
| | | : variables.menuLightText; |
| | | }); |
| | | |
| | | const activeMenu = computed(() => { |
| | | const { meta, path } = route |
| | | const { meta, path } = route; |
| | | if (meta.activeMenu) { |
| | | return meta.activeMenu |
| | | return meta.activeMenu; |
| | | } |
| | | return path |
| | | }) |
| | | return path; |
| | | }); |
| | | </script> |
| | | |
| | | <style lang="scss" scoped> |
| | |
| | | background-color: var(--menu-active-bg, rgba(0, 0, 0, 0.06)) !important; |
| | | border-radius: 14px; |
| | | margin: 0 10px 6px !important; |
| | | width: calc(100% - 20px) !important; |
| | | // width: calc(100% - 20px) !important; |
| | | padding-left: 10px !important; |
| | | padding-right: 10px !important; |
| | | box-sizing: border-box; |
| | |
| | | import ImageUpload from "@/components/AttachmentUpload/image"; |
| | | // å¾çé¢è§ç»ä»¶ |
| | | import ImagePreview from "@/components/AttachmentPreview/image"; |
| | | // éä»¶å¼¹çªç»ä»¶ |
| | | import FileListDialog from "@/components/Dialog/FileList.vue"; |
| | | // åå
¸æ ç¾ç»ä»¶ |
| | | import DictTag from "@/components/DictTag"; |
| | | // è¡¨æ ¼ç»ä»¶ |
| | |
| | | app.component("FileUpload", FileUpload); |
| | | app.component("ImageUpload", ImageUpload); |
| | | app.component("ImagePreview", ImagePreview); |
| | | app.component("FileListDialog", FileListDialog); |
| | | app.component("RightToolbar", RightToolbar); |
| | | app.component("Editor", Editor); |
| | | app.component("PIMTable", PIMTable); |
| | |
| | | path: "general-ledger", |
| | | component: () => import("@/views/financialManagement/generalLedger/index.vue"), |
| | | name: "GeneralLedger", |
| | | meta: { title: "æ»å¸ç§ç®" } |
| | | meta: { title: "æ»å¸ç§ç®" }, |
| | | }, |
| | | { |
| | | path: "sales-out", |
| | | component: () => import("@/views/financialManagement/receivable/salesOut.vue"), |
| | | name: "SalesOut", |
| | | meta: { title: "éå®åºåº" } |
| | | meta: { title: "éå®åºåº" }, |
| | | }, |
| | | { |
| | | path: "sales-return", |
| | | component: () => import("@/views/financialManagement/receivable/salesReturn.vue"), |
| | | name: "SalesReturn", |
| | | meta: { title: "éå®éè´§" } |
| | | meta: { title: "éå®éè´§" }, |
| | | }, |
| | | { |
| | | path: "receivable-reconciliation", |
| | | component: () => import("@/views/financialManagement/receivable/reconciliation.vue"), |
| | | name: "ReceivableReconciliation", |
| | | meta: { title: "åºæ¶å¯¹è´¦" } |
| | | meta: { title: "åºæ¶å¯¹è´¦" }, |
| | | }, |
| | | { |
| | | path: "invoice-apply", |
| | | component: () => import("@/views/financialManagement/receivable/invoiceApply.vue"), |
| | | name: "InvoiceApply", |
| | | meta: { title: "å¼ç¥¨ç³è¯·" } |
| | | meta: { title: "å¼ç¥¨ç³è¯·" }, |
| | | }, |
| | | { |
| | | path: "output-invoice", |
| | | component: () => import("@/views/financialManagement/receivable/outputInvoice.vue"), |
| | | name: "OutputInvoice", |
| | | meta: { title: "é项å票" } |
| | | meta: { title: "é项å票" }, |
| | | }, |
| | | { |
| | | path: "receipt", |
| | | component: () => import("@/views/financialManagement/receivable/receipt.vue"), |
| | | name: "Receipt", |
| | | meta: { title: "æ¶æ¬¾å" } |
| | | meta: { title: "æ¶æ¬¾å" }, |
| | | }, |
| | | { |
| | | path: "purchase-in", |
| | | component: () => import("@/views/financialManagement/payable/purchaseIn.vue"), |
| | | name: "PurchaseIn", |
| | | meta: { title: "éè´å
¥åº" } |
| | | meta: { title: "éè´å
¥åº" }, |
| | | }, |
| | | { |
| | | path: "payable-reconciliation", |
| | | component: () => import("@/views/financialManagement/payable/reconciliation.vue"), |
| | | name: "PayableReconciliation", |
| | | meta: { title: "åºä»å¯¹è´¦" } |
| | | meta: { title: "åºä»å¯¹è´¦" }, |
| | | }, |
| | | { |
| | | path: "input-invoice", |
| | | component: () => import("@/views/financialManagement/payable/input-invoice.vue"), |
| | | name: "InputInvoice", |
| | | meta: { title: "è¿é¡¹å票" } |
| | | meta: { title: "è¿é¡¹å票" }, |
| | | }, |
| | | { |
| | | path: "payment-apply", |
| | | component: () => import("@/views/financialManagement/payable/paymentApply.vue"), |
| | | name: "PaymentApply", |
| | | meta: { title: "仿¬¾ç³è¯·" } |
| | | meta: { title: "仿¬¾ç³è¯·" }, |
| | | }, |
| | | { |
| | | path: "payment", |
| | | component: () => import("@/views/financialManagement/payable/payment.vue"), |
| | | name: "Payment", |
| | | meta: { title: "仿¬¾å" } |
| | | meta: { title: "仿¬¾å" }, |
| | | }, |
| | | { |
| | | path: "fixed-assets", |
| | | component: () => import("@/views/financialManagement/assets/fixedAssets.vue"), |
| | | name: "FixedAssets", |
| | | meta: { title: "åºå®èµäº§" } |
| | | meta: { title: "åºå®èµäº§" }, |
| | | }, |
| | | { |
| | | path: "intangible-assets", |
| | | component: () => import("@/views/financialManagement/assets/intangibleAssets.vue"), |
| | | name: "IntangibleAssets", |
| | | meta: { title: "æ å½¢èµäº§" } |
| | | meta: { title: "æ å½¢èµäº§" }, |
| | | }, |
| | | { |
| | | path: "voucher", |
| | | component: () => import("@/views/financialManagement/voucher/index.vue"), |
| | | name: "Voucher", |
| | | meta: { title: "åè¯" } |
| | | meta: { title: "åè¯" }, |
| | | }, |
| | | { |
| | | path: "voucher-general-ledger", |
| | | component: () => import("@/views/financialManagement/voucher/generalLedger.vue"), |
| | | name: "VoucherGeneralLedger", |
| | | meta: { title: "ç§ç®æ»å¸" } |
| | | meta: { title: "ç§ç®æ»å¸" }, |
| | | }, |
| | | { |
| | | path: "voucher-detail-ledger", |
| | | component: () => import("@/views/financialManagement/voucher/detailLedger.vue"), |
| | | name: "VoucherDetailLedger", |
| | | meta: { title: "ç§ç®æç»å¸" } |
| | | } |
| | | ] |
| | | } |
| | | meta: { title: "ç§ç®æç»å¸" }, |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | |
| | | // å¨æè·¯ç±ï¼åºäºç¨æ·æé卿å»å è½½ |
| | |
| | | <div class="app-container product-view"> |
| | | <div class="left"> |
| | | <div> |
| | | <el-input |
| | | v-model="search" |
| | | <el-input v-model="search" |
| | | style="width: 210px" |
| | | placeholder="è¾å
¥å
³é®åè¿è¡æç´¢" |
| | | @change="searchFilter" |
| | | @clear="searchFilter" |
| | | clearable |
| | | prefix-icon="Search" |
| | | /> |
| | | <el-button |
| | | v-if="false" |
| | | prefix-icon="Search" /> |
| | | <el-button v-if="false" |
| | | type="primary" |
| | | @click="openProDia('addOne')" |
| | | style="margin-left: 10px" |
| | | >æ°å¢äº§å大类</el-button |
| | | > |
| | | style="margin-left: 10px">æ°å¢äº§å大类</el-button> |
| | | </div> |
| | | <div ref="containerRef"> |
| | | <el-tree |
| | | ref="tree" |
| | | <el-tree ref="tree" |
| | | v-loading="treeLoad" |
| | | :data="list" |
| | | @node-click="handleNodeClick" |
| | |
| | | highlight-current |
| | | node-key="id" |
| | | class="product-tree-scroll" |
| | | style="height: calc(100vh - 190px); overflow-y: auto" |
| | | > |
| | | style="height: calc(100vh - 190px); overflow-y: auto"> |
| | | <template #default="{ node, data }"> |
| | | <div class="custom-tree-node"> |
| | | <span class="tree-node-content"> |
| | |
| | | <span class="tree-node-label">{{ data.label }}</span> |
| | | </span> |
| | | <div> |
| | | <el-button |
| | | type="primary" |
| | | <el-button type="primary" |
| | | link |
| | | :disabled="isTopLevelNode(data, node)" |
| | | @click="openProDia('edit', data)" |
| | | > |
| | | @click="openProDia('edit', data)"> |
| | | ç¼è¾ |
| | | </el-button> |
| | | <el-button type="primary" link @click="openProDia('add', data)"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="openProDia('add', data)"> |
| | | æ·»å 产å |
| | | </el-button> |
| | | <el-button |
| | | v-if="!node.childNodes.length" |
| | | <el-button v-if="!node.childNodes.length" |
| | | style="margin-left: 4px" |
| | | type="danger" |
| | | link |
| | | :disabled="isTopLevelNode(data, node)" |
| | | @click="remove(node, data)" |
| | | > |
| | | @click="remove(node, data)"> |
| | | å é¤ |
| | | </el-button> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="right"> |
| | | <div style="margin-bottom: 10px" v-if="isShowButton"> |
| | | <el-button type="primary" @click="openModelDia('add')"> |
| | | <div style="margin-bottom: 10px" |
| | | v-if="isShowButton"> |
| | | <el-button type="primary" |
| | | @click="openModelDia('add')"> |
| | | æ°å¢è§æ ¼åå· |
| | | </el-button> |
| | | <ImportExcel :product-id="currentId" @uploadSuccess="getModelList" /> |
| | | <el-button |
| | | type="danger" |
| | | <ImportExcel :product-id="currentId" |
| | | @uploadSuccess="getModelList" /> |
| | | <el-button type="danger" |
| | | @click="handleDelete" |
| | | style="margin-left: 10px" |
| | | plain |
| | | > |
| | | plain> |
| | | å é¤ |
| | | </el-button> |
| | | </div> |
| | | <PIMTable |
| | | rowKey="id" |
| | | <PIMTable rowKey="id" |
| | | :column="tableColumn" |
| | | :tableData="tableData" |
| | | :page="page" |
| | | :isSelection="true" |
| | | @selection-change="handleSelectionChange" |
| | | :tableLoading="tableLoading" |
| | | @pagination="pagination" |
| | | ></PIMTable> |
| | | @pagination="pagination"></PIMTable> |
| | | </div> |
| | | <el-dialog v-model="productDia" title="产å" width="400px" @keydown.enter.prevent> |
| | | <el-form |
| | | :model="form" |
| | | <el-dialog v-model="productDia" |
| | | title="产å" |
| | | width="400px" |
| | | @keydown.enter.prevent> |
| | | <el-form :model="form" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="rules" |
| | | ref="formRef" |
| | | > |
| | | ref="formRef"> |
| | | <el-row :gutter="30"> |
| | | <el-col :span="24"> |
| | | <el-form-item label="产ååç§°ï¼" prop="productName"> |
| | | <el-input |
| | | v-model="form.productName" |
| | | <el-form-item label="产ååç§°ï¼" |
| | | prop="productName"> |
| | | <el-input v-model="form.productName" |
| | | placeholder="请è¾å
¥äº§ååç§°" |
| | | maxlength="20" |
| | | show-word-limit |
| | | clearable |
| | | @keydown.enter.prevent |
| | | /> |
| | | @keydown.enter.prevent /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitForm">确认</el-button> |
| | | <el-button @click="closeProDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <el-dialog |
| | | v-model="modelDia" |
| | | <el-dialog v-model="modelDia" |
| | | title="è§æ ¼åå·" |
| | | width="400px" |
| | | @close="closeModelDia" |
| | | @keydown.enter.prevent |
| | | > |
| | | <el-form |
| | | :model="modelForm" |
| | | @keydown.enter.prevent> |
| | | <el-form :model="modelForm" |
| | | label-width="140px" |
| | | label-position="top" |
| | | :rules="modelRules" |
| | | ref="modelFormRef" |
| | | > |
| | | ref="modelFormRef"> |
| | | <el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" prop="model"> |
| | | <el-input |
| | | v-model="modelForm.model" |
| | | <el-form-item label="产åç¼å·ï¼" |
| | | prop="productCode"> |
| | | <el-input v-model="modelForm.productCode" |
| | | placeholder="请è¾å
¥äº§åç¼å·" |
| | | clearable |
| | | @keydown.enter.prevent /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="è§æ ¼åå·ï¼" |
| | | prop="model"> |
| | | <el-input v-model="modelForm.model" |
| | | placeholder="请è¾å
¥è§æ ¼åå·" |
| | | clearable |
| | | @keydown.enter.prevent |
| | | /> |
| | | @keydown.enter.prevent /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | <el-row> |
| | | <el-col :span="24"> |
| | | <el-form-item label="åä½ï¼" prop="unit"> |
| | | <el-input |
| | | v-model="modelForm.unit" |
| | | <el-form-item label="åä½ï¼" |
| | | prop="unit"> |
| | | <el-input v-model="modelForm.unit" |
| | | placeholder="请è¾å
¥åä½" |
| | | clearable |
| | | @keydown.enter.prevent |
| | | /> |
| | | @keydown.enter.prevent /> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | | </el-form> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button type="primary" @click="submitModelForm">确认</el-button> |
| | | <el-button type="primary" |
| | | @click="submitModelForm">确认</el-button> |
| | | <el-button @click="closeModelDia">åæ¶</el-button> |
| | | </div> |
| | | </template> |
| | |
| | | ); |
| | | }; |
| | | |
| | | loadExpandedKeys().forEach((key) => expandedKeySet.add(key)); |
| | | loadExpandedKeys().forEach(key => expandedKeySet.add(key)); |
| | | |
| | | const syncExpandedKeysFromTree = () => { |
| | | const keys = []; |
| | | const walk = (nodes) => { |
| | | (nodes || []).forEach((item) => { |
| | | const walk = nodes => { |
| | | (nodes || []).forEach(item => { |
| | | if (item.expanded && item.data?.id !== undefined) { |
| | | keys.push(item.data.id); |
| | | } |
| | |
| | | |
| | | walk(tree.value?.root?.childNodes); |
| | | expandedKeySet.clear(); |
| | | keys.forEach((key) => expandedKeySet.add(key)); |
| | | keys.forEach(key => expandedKeySet.add(key)); |
| | | expandedKeys.value = keys; |
| | | saveExpandedKeys(); |
| | | }; |
| | | |
| | | const normalizeExpandedKeys = (treeData) => { |
| | | const normalizeExpandedKeys = treeData => { |
| | | const parentMap = new Map(); |
| | | const walk = (nodes, parentId = null) => { |
| | | (nodes || []).forEach((item) => { |
| | | (nodes || []).forEach(item => { |
| | | parentMap.set(item.id, parentId); |
| | | if (item.children && item.children.length) { |
| | | walk(item.children, item.id); |
| | |
| | | |
| | | walk(treeData); |
| | | |
| | | const normalizedKeys = Array.from(expandedKeySet).filter((key) => { |
| | | const normalizedKeys = Array.from(expandedKeySet).filter(key => { |
| | | if (!parentMap.has(key)) { |
| | | return false; |
| | | } |
| | |
| | | |
| | | if (normalizedKeys.length !== expandedKeySet.size) { |
| | | expandedKeySet.clear(); |
| | | normalizedKeys.forEach((key) => expandedKeySet.add(key)); |
| | | normalizedKeys.forEach(key => expandedKeySet.add(key)); |
| | | saveExpandedKeys(); |
| | | } |
| | | }; |
| | |
| | | const expandedKeys = ref([]); |
| | | const tableColumn = ref([ |
| | | { |
| | | label: "产åç¼å·", |
| | | prop: "productCode", |
| | | }, |
| | | { |
| | | label: "è§æ ¼åå·", |
| | | prop: "model", |
| | | }, |
| | |
| | | { |
| | | name: "ç¼è¾", |
| | | type: "text", |
| | | clickFun: (row) => { |
| | | clickFun: row => { |
| | | openModelDia("edit", row); |
| | | }, |
| | | }, |
| | |
| | | modelForm: { |
| | | model: "", |
| | | unit: "", |
| | | productCode: "", |
| | | }, |
| | | modelRules: { |
| | | model: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | unit: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | productCode: [{ required: true, message: "请è¾å
¥", trigger: "blur" }], |
| | | }, |
| | | }); |
| | | const { form, rules, modelForm, modelRules } = toRefs(data); |
| | |
| | | const getProductTreeList = () => { |
| | | treeLoad.value = true; |
| | | productTreeList() |
| | | .then((res) => { |
| | | .then(res => { |
| | | list.value = res || []; |
| | | normalizeExpandedKeys(list.value); |
| | | expandedKeys.value = Array.from(expandedKeySet); |
| | |
| | | tree.value?.setDefaultExpandedKeys?.(expandedKeys.value); |
| | | }); |
| | | }) |
| | | .catch((err) => { |
| | | .catch(err => { |
| | | console.error(err); |
| | | }) |
| | | .finally(() => { |
| | | treeLoad.value = false; |
| | | }); |
| | | }; |
| | | const handleNodeExpand = (data) => { |
| | | const handleNodeExpand = data => { |
| | | nextTick(syncExpandedKeysFromTree); |
| | | }; |
| | | const handleNodeCollapse = (data, node) => { |
| | | node?.eachNode?.((item) => { |
| | | node?.eachNode?.(item => { |
| | | item.collapse(); |
| | | }); |
| | | nextTick(syncExpandedKeysFromTree); |
| | |
| | | modelOperationType.value = type; |
| | | modelDia.value = true; |
| | | modelForm.value.model = ""; |
| | | modelForm.value.model = ""; |
| | | modelForm.value.unit = ""; |
| | | modelForm.value.productCode = ""; |
| | | modelForm.value.id = ""; |
| | | if (type === "edit") { |
| | | modelForm.value = { ...data }; |
| | |
| | | }; |
| | | // æäº¤äº§ååç§°ä¿®æ¹ |
| | | const submitForm = () => { |
| | | proxy.$refs.formRef.validate((valid) => { |
| | | proxy.$refs.formRef.validate(valid => { |
| | | if (valid) { |
| | | if (operationType.value === "add") { |
| | | form.value.parentId = currentId.value; |
| | |
| | | form.value.id = currentId.value; |
| | | form.value.parentId = ""; |
| | | } |
| | | addOrEditProduct(form.value).then((res) => { |
| | | addOrEditProduct(form.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeProDia(); |
| | | getProductTreeList(); |
| | |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delProduct(ids) |
| | | .then((res) => { |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getProductTreeList(); |
| | | }) |
| | |
| | | |
| | | // æäº¤è§æ ¼åå·ä¿®æ¹ |
| | | const submitModelForm = () => { |
| | | proxy.$refs.modelFormRef.validate((valid) => { |
| | | proxy.$refs.modelFormRef.validate(valid => { |
| | | if (valid) { |
| | | modelForm.value.productId = currentId.value; |
| | | addOrEditProductModel(modelForm.value).then((res) => { |
| | | addOrEditProductModel(modelForm.value).then(res => { |
| | | proxy.$modal.msgSuccess("æäº¤æå"); |
| | | closeModelDia(); |
| | | getModelList(); |
| | |
| | | modelDia.value = false; |
| | | }; |
| | | // è¡¨æ ¼éæ©æ°æ® |
| | | const handleSelectionChange = (selection) => { |
| | | const handleSelectionChange = selection => { |
| | | selectedRows.value = selection; |
| | | }; |
| | | |
| | | // æ¥è¯¢è§æ ¼åå· |
| | | const pagination = (obj) => { |
| | | const pagination = obj => { |
| | | page.current = obj.page; |
| | | page.size = obj.limit; |
| | | getModelList(); |
| | |
| | | id: currentId.value, |
| | | current: page.current, |
| | | size: page.size, |
| | | }).then((res) => { |
| | | }).then(res => { |
| | | console.log("res", res); |
| | | tableData.value = res.records; |
| | | page.total = res.total; |
| | |
| | | const handleDelete = () => { |
| | | let ids = []; |
| | | if (selectedRows.value.length > 0) { |
| | | ids = selectedRows.value.map((item) => item.id); |
| | | ids = selectedRows.value.map(item => item.id); |
| | | } else { |
| | | proxy.$modal.msgWarning("è¯·éæ©æ°æ®"); |
| | | return; |
| | |
| | | .then(() => { |
| | | tableLoading.value = true; |
| | | delProductModel(ids) |
| | | .then((res) => { |
| | | .then(res => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | getModelList(); |
| | | }) |
| | |
| | | </el-table-column> |
| | | </el-table> |
| | | </el-dialog> |
| | | <FileListDialog ref="fileListDialogRef" |
| | | v-model="fileDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :delete-method="handleAttachmentDelete" |
| | | :rules-regulations-management-id="currentFileRuleId" |
| | | :name-column-label="'éä»¶åç§°'" |
| | | @upload="handleAttachmentUpload"/> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="rules_regulations_management" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | addReadingStatus, |
| | | updateReadingStatus, |
| | | } from "@/api/collaborativeApproval/sealManagement.js"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | import { |
| | | listRuleFiles, |
| | | delRuleFile, |
| | |
| | | total: 0, |
| | | }); |
| | | // éä»¶å¼¹çª |
| | | const fileDialogVisible = ref(false); |
| | | const fileListDialogRef = ref(null); |
| | | const currentFileRuleId = ref(null); |
| | | const filePage = reactive({ |
| | | current: 1, |
| | | size: 1000, |
| | | total: 0, |
| | | }); |
| | | // è§ç« å¶åº¦ç¸å
³ |
| | | const showRegulationDialog = ref(false); |
| | | const showRegulationDetailDialog = ref(false); |
| | |
| | | ); |
| | | }; |
| | | |
| | | // éä»¶ï¼æ¥è¯¢ |
| | | const fetchRuleFiles = async rulesRegulationsManagementId => { |
| | | const params = { |
| | | current: filePage.current, |
| | | size: filePage.size, |
| | | rulesRegulationsManagementId, |
| | | }; |
| | | const res = await listRuleFiles(params); |
| | | const records = res?.data?.records || []; |
| | | filePage.total = res?.data?.total || records.length; |
| | | const mapped = records.map(item => ({ |
| | | id: item.id, |
| | | name: item.fileName || item.name, |
| | | url: item.fileUrl || item.url, |
| | | raw: item, |
| | | })); |
| | | fileListDialogRef.value?.setList(mapped); |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const openFileDialog = async row => { |
| | | currentFileRuleId.value = row.id; |
| | | fileDialogVisible.value = true; |
| | | await fetchRuleFiles(row.id); |
| | | }; |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // å·æ°éä»¶å表 |
| | | const refreshFileList = async () => { |
| | | if (!currentFileRuleId.value) return; |
| | | await fetchRuleFiles(currentFileRuleId.value); |
| | | }; |
| | | |
| | | // ä¸ä¼ éä»¶ï¼ç±åç»ä»¶è§¦åï¼ |
| | | const handleAttachmentUpload = async filePayload => { |
| | | if (!currentFileRuleId.value) return; |
| | | const payload = { |
| | | name: filePayload?.fileName || filePayload?.name, |
| | | url: filePayload?.fileUrl || filePayload?.url, |
| | | rulesRegulationsManagementId: currentFileRuleId.value, |
| | | }; |
| | | await addRuleFile(payload); |
| | | ElMessage.success("æä»¶ä¸ä¼ æå"); |
| | | await refreshFileList(); |
| | | }; |
| | | |
| | | // å é¤éä»¶ |
| | | const handleAttachmentDelete = async row => { |
| | | if (!row?.id) return false; |
| | | try { |
| | | await ElMessageBox.confirm("确认å é¤è¯¥éä»¶ï¼", "æç¤º", { type: "warning" }); |
| | | } catch { |
| | | return false; |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | await delRuleFile([row.id]); |
| | | ElMessage.success("å 餿å"); |
| | | await refreshFileList(); |
| | | }; |
| | | |
| | | // è·åè§ç« å¶åº¦åè¡¨æ°æ® |
| | | const getRegulationList = async () => { |
| | |
| | | ></PIMTable> |
| | | </div> |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="å®åéä»¶" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :upload-method="handleFileUpload" |
| | | :delete-method="handleFileDelete" |
| | | /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="after_sales_service" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick } from "vue"; |
| | | import {onMounted, ref, reactive, toRefs, getCurrentInstance, nextTick, defineAsyncComponent} from "vue"; |
| | | import FormDia from "@/views/customerService/afterSalesHandling/components/formDia.vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import request from "@/utils/request"; |
| | | import { getToken } from "@/utils/auth"; |
| | | import { |
| | | afterSalesServiceListPage, |
| | | afterSalesServiceFileListPage, |
| | | afterSalesServiceFileDel, |
| | | } from "@/api/customerService/index.js"; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore() |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | |
| | | }) |
| | | } |
| | | |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = async (row) => { |
| | | currentFileRow.value = row |
| | | try { |
| | | const res = await afterSalesServiceFileListPage({ |
| | | afterSalesServiceId: row.id, |
| | | current: 1, |
| | | size: 100, |
| | | }) |
| | | if (res.code === 200 && fileListRef.value) { |
| | | const fileList = (res.data?.records || []).map((item) => ({ |
| | | name: item.name || item.fileName, |
| | | url: item.url || item.fileUrl, |
| | | id: item.id, |
| | | ...item, |
| | | })) |
| | | fileListRef.value.open(fileList) |
| | | fileListDialogVisible.value = true |
| | | } else { |
| | | fileListRef.value?.open([]) |
| | | fileListDialogVisible.value = true |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("è·åéä»¶å表失败") |
| | | fileListRef.value?.open([]) |
| | | fileListDialogVisible.value = true |
| | | } |
| | | } |
| | | |
| | | // ä¸ä¼ éä»¶ |
| | | const handleFileUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | | proxy.$modal.msgWarning("请å
éæ©æ°æ®") |
| | | return |
| | | } |
| | | return new Promise((resolve) => { |
| | | const input = document.createElement("input") |
| | | input.type = "file" |
| | | input.style.display = "none" |
| | | input.onchange = async (e) => { |
| | | const file = e.target.files[0] |
| | | if (!file) { |
| | | resolve(null) |
| | | return |
| | | } |
| | | try { |
| | | const formData = new FormData() |
| | | formData.append("file", file) |
| | | formData.append("id", currentFileRow.value.id) |
| | | const uploadRes = await request({ |
| | | url: "/afterSalesService/file/upload", |
| | | method: "post", |
| | | data: formData, |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | Authorization: `Bearer ${getToken()}`, |
| | | }, |
| | | }) |
| | | if (uploadRes.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå") |
| | | // éæ°è·åæä»¶å表 |
| | | const listRes = await afterSalesServiceFileListPage({ |
| | | afterSalesServiceId: currentFileRow.value.id, |
| | | current: 1, |
| | | size: 100, |
| | | }) |
| | | if (listRes.code === 200 && fileListRef.value) { |
| | | const fileList = (listRes.data?.records || []).map((item) => ({ |
| | | name: item.fileName, |
| | | url: item.fileUrl, |
| | | id: item.id, |
| | | ...item, |
| | | })) |
| | | fileListRef.value.setList(fileList) |
| | | } |
| | | resolve({ name: file.name, url: "", id: null }) |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败") |
| | | resolve(null) |
| | | } |
| | | } catch (err) { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败") |
| | | resolve(null) |
| | | } finally { |
| | | document.body.removeChild(input) |
| | | } |
| | | } |
| | | document.body.appendChild(input) |
| | | input.click() |
| | | }) |
| | | } |
| | | |
| | | // å é¤éä»¶ |
| | | const handleFileDelete = async (row) => { |
| | | try { |
| | | // æ·»å ç¡®è®¤å¯¹è¯æ¡ |
| | | const confirmResult = await ElMessageBox.confirm( |
| | | 'ç¡®å®è¦å é¤è¿ä¸ªéä»¶åï¼', |
| | | 'å é¤ç¡®è®¤', |
| | | { |
| | | confirmButtonText: 'ç¡®å®', |
| | | cancelButtonText: 'åæ¶', |
| | | type: 'warning' |
| | | } |
| | | ) |
| | | |
| | | if (confirmResult === 'confirm') { |
| | | const res = await afterSalesServiceFileDel(row.id) |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("å 餿å") |
| | | if (currentFileRow.value && fileListRef.value) { |
| | | const listRes = await afterSalesServiceFileListPage({ |
| | | afterSalesServiceId: currentFileRow.value.id, |
| | | current: 1, |
| | | size: 100, |
| | | }) |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map((item) => ({ |
| | | name: item.fileName, |
| | | url: item.fileUrl, |
| | | id: item.id, |
| | | ...item, |
| | | })) |
| | | fileListRef.value.setList(fileList) |
| | | } |
| | | } |
| | | } else { |
| | | proxy.$modal.msgError(res.msg || "å é¤å¤±è´¥") |
| | | return false |
| | | } |
| | | } |
| | | } catch (error) { |
| | | // å¦æç¨æ·åæ¶å é¤ï¼ä¸æ¾ç¤ºéè¯¯ä¿¡æ¯ |
| | | if (error !== 'cancel') { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥") |
| | | } |
| | | return false |
| | | } |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | |
| | | // æ¥è¯¢å表 |
| | |
| | | form.value.entryDate = getCurrentDate(); |
| | | } |
| | | |
| | | // ä¸ä¼ åæ ¡æ£ |
| | | function handleBeforeUpload(file) { |
| | | proxy.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); |
| | | return true; |
| | | } |
| | | // ä¸ä¼ 失败 |
| | | function handleUploadError(err) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | // ä¸ä¼ æååè° |
| | | function handleUploadSuccess(res, file, uploadFiles) { |
| | | proxy.$modal.closeLoading(); |
| | | if (res.code === 200) { |
| | | file.tempId = res.data.tempId; |
| | | form.value.tempFileIds.push(file.tempId); |
| | | proxy.$modal.msgSuccess("ä¸ä¼ æå"); |
| | | } else { |
| | | proxy.$modal.msgError(res.msg); |
| | | proxy.$refs.fileUpload.handleRemove(file); |
| | | } |
| | | } |
| | | // ç§»é¤æä»¶ |
| | | function handleRemove(file) { |
| | | if (operationType.value === "edit") { |
| | | let ids = []; |
| | | ids.push(file.id); |
| | | delLedgerFile(ids).then((res) => { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | // å¤çæææ¥æè¾å
¥ï¼åªå
è®¸æ£æ´æ° |
| | | const handleValidInput = (value) => { |
| | | if (value === '' || value === null || value === undefined) { |
| | |
| | | </PIMTable> |
| | | </div> |
| | | <Modal ref="modalRef" @success="getTableData"></Modal> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="account_expense" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | import { listPage, delAccountExpense, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/expenseManagement"; |
| | | import { onMounted, getCurrentInstance, ref, computed } from "vue"; |
| | | import { listPage, delAccountExpense } from "@/api/financialManagement/expenseManagement"; |
| | | import {onMounted, getCurrentInstance, ref, computed, defineAsyncComponent} from "vue"; |
| | | import Modal from "./Modal.vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import request from "@/utils/request"; |
| | | import { getToken } from "@/utils/auth"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | defineOptions({ |
| | | name: "æ¯åºç®¡ç", |
| | |
| | | const modalRef = ref(); |
| | | const { checkout_payment } = proxy.useDict("checkout_payment"); |
| | | const { expense_types } = proxy.useDict("expense_types"); |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const currentFileRow = ref(null); |
| | | const accountType = ref('æ¯åº'); |
| | | |
| | | const { |
| | |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = async (row) => { |
| | | currentFileRow.value = row; |
| | | accountType.value = 'æ¯åº'; |
| | | try { |
| | | const res = await fileListPage({ |
| | | accountId: row.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (res.code === 200 && fileListRef.value) { |
| | | // å°æ°æ®è½¬æ¢ä¸º FileListDialog éè¦çæ ¼å¼ |
| | | const fileList = (res.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.open(fileList); |
| | | fileListDialogVisible.value = true; |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("è·åéä»¶å表失败"); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ éä»¶ |
| | | const handleUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | | proxy.$modal.msgWarning("请å
éæ©æ°æ®"); |
| | | return null; |
| | | } |
| | | |
| | | return new Promise((resolve) => { |
| | | // å建ä¸ä¸ªéèçæä»¶è¾å
¥å
ç´ |
| | | const input = document.createElement('input'); |
| | | input.type = 'file'; |
| | | input.style.display = 'none'; |
| | | input.onchange = async (e) => { |
| | | const file = e.target.files[0]; |
| | | if (!file) { |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // ä½¿ç¨ FormData ä¸ä¼ æä»¶ |
| | | const formData = new FormData(); |
| | | formData.append('file', file); |
| | | |
| | | const uploadRes = await request({ |
| | | url: '/file/upload', |
| | | method: 'post', |
| | | data: formData, |
| | | headers: { |
| | | 'Content-Type': 'multipart/form-data', |
| | | Authorization: `Bearer ${getToken()}` |
| | | } |
| | | }); |
| | | |
| | | if (uploadRes.code === 200) { |
| | | // ä¿åéä»¶ä¿¡æ¯ |
| | | const fileData = { |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | name: uploadRes.data.originalName || file.name, |
| | | url: uploadRes.data.tempPath || uploadRes.data.url |
| | | }; |
| | | |
| | | const saveRes = await fileAdd(fileData); |
| | | if (saveRes.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | // éæ°å è½½æä»¶å表 |
| | | const listRes = await fileListPage({ |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (listRes.code === 200 && fileListRef.value) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | // è¿åæ°æä»¶ä¿¡æ¯ |
| | | resolve({ |
| | | name: fileData.name, |
| | | url: fileData.url, |
| | | id: saveRes.data?.id |
| | | }); |
| | | } else { |
| | | proxy.$modal.msgError(saveRes.msg || "æä»¶ä¿å失败"); |
| | | resolve(null); |
| | | } |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } finally { |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤éä»¶ |
| | | const handleFileDelete = async (row) => { |
| | | try { |
| | | const res = await fileDel([row.id]); |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | // éæ°å è½½æä»¶å表 |
| | | if (currentFileRow.value && fileListRef.value) { |
| | | const listRes = await fileListPage({ |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | } |
| | | return true; // è¿å true 表示å 餿åï¼ç»ä»¶ä¼æ´æ°å表 |
| | | } else { |
| | | proxy.$modal.msgError(res.msg || "å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getTableData(); |
| | |
| | | </PIMTable> |
| | | </div> |
| | | <Modal ref="modalRef" @success="getTableData"></Modal> |
| | | <!-- todo éä»¶é¢è§ç¸å
³ --> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | /> |
| | | <FileListDialog v-if="fileListDialogVisible" :record-id="currentRecordId" record-type="account_income" v-model:visible="fileListDialogVisible"/> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { usePaginationApi } from "@/hooks/usePaginationApi"; |
| | | import { listPage, delAccountIncome, fileListPage, fileAdd, fileDel } from "@/api/financialManagement/revenueManagement"; |
| | | import {listPage, delAccountIncome} from "@/api/financialManagement/revenueManagement"; |
| | | import { onMounted, getCurrentInstance, ref, computed } from "vue"; |
| | | import Modal from "./Modal.vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import dayjs from "dayjs"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import request from "@/utils/request"; |
| | | import { getToken } from "@/utils/auth"; |
| | | |
| | | defineOptions({ |
| | | name: "æ¶å
¥ç®¡ç", |
| | |
| | | const { income_types } = proxy.useDict("income_types"); |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const currentFileRow = ref(null); |
| | | const accountType = ref('æ¶å
¥'); |
| | | const currentRecordId = ref(0); |
| | | |
| | | const incomeMethodOptions = computed(() => { |
| | | const merged = [...(payment_methods.value || []), ...(receipt_payment_type.value || [])]; |
| | |
| | | }; |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFilesFormDia = async (row) => { |
| | | currentFileRow.value = row; |
| | | accountType.value = 'æ¶å
¥'; |
| | | try { |
| | | const res = await fileListPage({ |
| | | accountId: row.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (res.code === 200 && fileListRef.value) { |
| | | // å°æ°æ®è½¬æ¢ä¸º FileListDialog éè¦çæ ¼å¼ |
| | | const fileList = (res.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.open(fileList); |
| | | currentRecordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("è·åéä»¶å表失败"); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ éä»¶ |
| | | const handleUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | | proxy.$modal.msgWarning("请å
éæ©æ°æ®"); |
| | | return null; |
| | | } |
| | | |
| | | return new Promise((resolve) => { |
| | | // å建ä¸ä¸ªéèçæä»¶è¾å
¥å
ç´ |
| | | const input = document.createElement('input'); |
| | | input.type = 'file'; |
| | | input.style.display = 'none'; |
| | | input.onchange = async (e) => { |
| | | const file = e.target.files[0]; |
| | | if (!file) { |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // ä½¿ç¨ FormData ä¸ä¼ æä»¶ |
| | | const formData = new FormData(); |
| | | formData.append('file', file); |
| | | |
| | | const uploadRes = await request({ |
| | | url: '/file/upload', |
| | | method: 'post', |
| | | data: formData, |
| | | headers: { |
| | | 'Content-Type': 'multipart/form-data', |
| | | Authorization: `Bearer ${getToken()}` |
| | | } |
| | | }); |
| | | |
| | | if (uploadRes.code === 200) { |
| | | // ä¿åéä»¶ä¿¡æ¯ |
| | | const fileData = { |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | name: uploadRes.data.originalName || file.name, |
| | | url: uploadRes.data.tempPath || uploadRes.data.url |
| | | }; |
| | | |
| | | const saveRes = await fileAdd(fileData); |
| | | if (saveRes.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | // éæ°å è½½æä»¶å表 |
| | | const listRes = await fileListPage({ |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (listRes.code === 200 && fileListRef.value) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | // è¿åæ°æä»¶ä¿¡æ¯ |
| | | resolve({ |
| | | name: fileData.name, |
| | | url: fileData.url, |
| | | id: saveRes.data?.id |
| | | }); |
| | | } else { |
| | | proxy.$modal.msgError(saveRes.msg || "æä»¶ä¿å失败"); |
| | | resolve(null); |
| | | } |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } finally { |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤éä»¶ |
| | | const handleFileDelete = async (row) => { |
| | | try { |
| | | const res = await fileDel([row.id]); |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | // éæ°å è½½æä»¶å表 |
| | | if (currentFileRow.value && fileListRef.value) { |
| | | const listRes = await fileListPage({ |
| | | accountId: currentFileRow.value.id, |
| | | accountType: accountType.value, |
| | | current: 1, |
| | | size: 100 |
| | | }); |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | } |
| | | } |
| | | return true; // è¿å true 表示å 餿åï¼ç»ä»¶ä¼æ´æ°å表 |
| | | } else { |
| | | proxy.$modal.msgError(res.msg || "å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | onMounted(() => { |
| | |
| | | .table_list { |
| | | margin-top: unset; |
| | | } |
| | | |
| | | .actions { |
| | | display: flex; |
| | | justify-content: space-between; |
| | |
| | | style="width: 100%" /> |
| | | </el-form-item> |
| | | <el-form-item label="æ¹å·" |
| | | prop="batchNo" |
| | | :rules="[ |
| | | { |
| | | required: true, |
| | | message: '请è¾å
¥æ¹å·', |
| | | trigger: 'blur', |
| | | } |
| | | ]"> |
| | | prop="batchNo"> |
| | | <el-input v-model="formState.batchNo" |
| | | placeholder="请è¾å
¥æ¹å·" /> |
| | | </el-form-item> |
| | |
| | | <el-button |
| | | type="primary" |
| | | link |
| | | @click="downLoadFile(row)" |
| | | @click="openFileDialog(row)" |
| | | > |
| | | éä»¶ |
| | | </el-button> |
| | |
| | | </template> |
| | | </PIMTable> |
| | | </div> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="éä»¶å表" |
| | | :showUploadButton="true" |
| | | :showDeleteButton="true" |
| | | :deleteMethod="handleDeleteFile" |
| | | :uploadMethod="handleFileUpload" |
| | | :rulesRegulationsManagementId="currentRowId" |
| | | /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="ticket_registration" :record-id="recordId" /> |
| | | <EditModal ref="editmodalRef" @success="getTableData"></EditModal> |
| | | </div> |
| | | </template> |
| | |
| | | import { onMounted } from "vue"; |
| | | import { ElMessageBox } from "element-plus"; |
| | | import EditModal from "./Modal/EditModal.vue"; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | const userStore = useUserStore(); |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | defineOptions({ |
| | | name: "æ¥ç¥¨å°è´¦", |
| | |
| | | onCurrentChange(page); |
| | | }; |
| | | |
| | | const downLoadFile = row => { |
| | | currentRowId.value = row.id; |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(row.commonFiles || []); |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ éä»¶ï¼èªå®ä¹ä¸ä¼ æ¹æ³ï¼ |
| | | const handleFileUpload = async () => { |
| | | if (!currentRowId.value) { |
| | | proxy.$modal.msgWarning("缺å°ç»è®°IDï¼æ æ³ä¿åéä»¶"); |
| | | return; |
| | | } |
| | | |
| | | return new Promise((resolve) => { |
| | | // å建ä¸ä¸ªéèçæä»¶è¾å
¥å
ç´ |
| | | const input = document.createElement('input'); |
| | | input.type = 'file'; |
| | | input.style.display = 'none'; |
| | | input.onchange = async (e) => { |
| | | const file = e.target.files[0]; |
| | | if (!file) { |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // ä½¿ç¨ FormData ä¸ä¼ æä»¶ |
| | | const formData = new FormData(); |
| | | formData.append('file', file); |
| | | formData.append('type', '4'); // type åæ°ï¼ç¨æ·æªæå®å
·ä½å¼ï¼å
ä¼ ç©ºå符串 |
| | | formData.append('id', currentRowId.value); // å½åè¡ç id |
| | | |
| | | const uploadRes = await request({ |
| | | url: '/file/uploadByCommon', |
| | | method: 'post', |
| | | data: formData, |
| | | headers: { |
| | | 'Content-Type': 'multipart/form-data', |
| | | Authorization: `Bearer ${getToken()}` |
| | | } |
| | | }); |
| | | |
| | | if (uploadRes.code === 200) { |
| | | proxy.$modal.msgSuccess("éä»¶ä¸ä¼ æå"); |
| | | |
| | | // å·æ°å表è·åææ°æ°æ® |
| | | await new Promise((resolveRefresh) => { |
| | | // è°ç¨ API è·åææ°åè¡¨æ°æ® |
| | | productRecordPage({ |
| | | ...filters, |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize |
| | | }).then(({ code, data }) => { |
| | | if (code === 200) { |
| | | // æ´æ°æ°æ®å表 |
| | | dataList.value = data.records; |
| | | pagination.total = data.total; |
| | | |
| | | // ä»å¤é¨æ°æ®è·å commonFiles |
| | | const currentRow = dataList.value.find(row => row.id === currentRowId.value); |
| | | if (currentRow && fileListRef.value) { |
| | | // å·æ°éä»¶å表ï¼ä½¿ç¨ä»å¤é¨è·åçææ° commonFiles |
| | | fileListRef.value.open(currentRow.commonFiles || []); |
| | | } |
| | | resolveRefresh(); |
| | | } else { |
| | | resolveRefresh(); |
| | | } |
| | | }).catch(() => { |
| | | resolveRefresh(); |
| | | }); |
| | | }); |
| | | |
| | | resolve({ |
| | | name: uploadRes.data?.originalName || file.name, |
| | | url: uploadRes.data?.tempPath || uploadRes.data?.url, |
| | | id: uploadRes.data?.id |
| | | }); |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } |
| | | } catch (error) { |
| | | console.error("éä»¶ä¸ä¼ 失败:", error); |
| | | proxy.$modal.msgError("éä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } finally { |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | | }; |
| | | |
| | | // å é¤éä»¶ |
| | | const handleDeleteFile = async (file) => { |
| | | try { |
| | | await delCommonFile([file.id]); |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | |
| | | // å·æ°å表è·åææ°æ°æ® |
| | | await new Promise((resolveRefresh) => { |
| | | // è°ç¨ API è·åææ°åè¡¨æ°æ® |
| | | productRecordPage({ |
| | | ...filters, |
| | | current: pagination.currentPage, |
| | | size: pagination.pageSize |
| | | }).then(({ code, data }) => { |
| | | if (code === 200) { |
| | | // æ´æ°æ°æ®å表 |
| | | dataList.value = data.records; |
| | | pagination.total = data.total; |
| | | |
| | | // ä»å¤é¨æ°æ®è·å commonFiles |
| | | const currentRow = dataList.value.find(row => row.id === currentRowId.value); |
| | | if (currentRow && fileListRef.value) { |
| | | // å·æ°éä»¶å表ï¼ä½¿ç¨ä»å¤é¨è·åçææ° commonFiles |
| | | fileListRef.value.open(currentRow.commonFiles || []); |
| | | } |
| | | resolveRefresh(); |
| | | } else { |
| | | resolveRefresh(); |
| | | } |
| | | }).catch(() => { |
| | | resolveRefresh(); |
| | | }); |
| | | }); |
| | | |
| | | return true; |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | }; |
| | | |
| | | const openEdit = (row) => { |
| | | editmodalRef.value.open(row); |
| | |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button type="primary" |
| | | @click="handleQuery"> æç´¢ </el-button> |
| | | @click="handleQuery"> æç´¢ |
| | | </el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | |
| | | <el-button @click="handleOut">导åº</el-button> |
| | | <el-button type="danger" |
| | | plain |
| | | @click="handleDelete">å é¤</el-button> |
| | | @click="handleDelete">å é¤ |
| | | </el-button> |
| | | </div> |
| | | <el-table :data="tableData" |
| | | border |
| | |
| | | <el-button link |
| | | type="primary" |
| | | @click="openForm('edit', scope.row)" |
| | | :disabled="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== 4">ç¼è¾</el-button> |
| | | :disabled="scope.row.approvalStatus !== 1 && scope.row.approvalStatus !== 4">ç¼è¾ |
| | | </el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="downLoadFile(scope.row)">éä»¶</el-button> |
| | | @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <el-option v-for="item in supplierList" |
| | | :key="item.id" |
| | | :label="item.supplierName" |
| | | :value="item.id" >{{item.supplierName + '---' + item.supplierType}}</el-option> |
| | | :value="item.id">{{ item.supplierName + '---' + item.supplierType }} |
| | | </el-option> |
| | | </el-select> |
| | | </el-form-item> |
| | | </el-col> |
| | |
| | | <el-form-item label="产åä¿¡æ¯ï¼" |
| | | prop="entryDate"> |
| | | <el-button type="primary" |
| | | @click="openProductForm('add')">æ·»å </el-button> |
| | | @click="openProductForm('add')">æ·»å |
| | | </el-button> |
| | | <el-button plain |
| | | type="danger" |
| | | @click="deleteProduct">å é¤</el-button> |
| | | @click="deleteProduct">å é¤ |
| | | </el-button> |
| | | </el-form-item> |
| | | <div class="select-button-group" |
| | | style="width: 500px; margin: 20px 0;" |
| | |
| | | <template #default="scope"> |
| | | <el-button link |
| | | type="primary" |
| | | @click="openProductForm('edit', scope.row, scope.$index)">ç¼è¾</el-button> |
| | | @click="openProductForm('edit', scope.row, scope.$index)">ç¼è¾ |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | <el-col :span="24"> |
| | | <el-form-item label="éä»¶ææï¼" |
| | | prop="purchaseLedgerFiles"> |
| | | <el-upload v-model:file-list="fileList" |
| | | :action="upload.url" |
| | | multiple |
| | | ref="fileUpload" |
| | | auto-upload |
| | | :headers="upload.headers" |
| | | :before-upload="handleBeforeUpload" |
| | | :on-error="handleUploadError" |
| | | :on-success="handleUploadSuccess" |
| | | :on-remove="handleRemove"> |
| | | <el-button type="primary">ä¸ä¼ </el-button> |
| | | <template #tip> |
| | | <div class="el-upload__tip"> |
| | | æä»¶æ ¼å¼æ¯æ |
| | | docï¼docxï¼xlsï¼xlsxï¼pptï¼pptxï¼pdfï¼txtï¼xmlï¼jpgï¼jpegï¼pngï¼gifï¼bmpï¼rarï¼zipï¼7z |
| | | </div> |
| | | </template> |
| | | </el-upload> |
| | | <FileUpload v-model:file-list="fileList"/> |
| | | </el-form-item> |
| | | </el-col> |
| | | </el-row> |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <FileListDialog |
| | | ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="éä»¶å表" |
| | | /> |
| | | <FileList v-if="fileListDialogVisible" v-model:visible="fileListDialogVisible" record-type="purchase_ledger" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import {Search, Delete} from "@element-plus/icons-vue"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import { getToken } from "@/utils/auth"; |
| | | import pagination from "@/components/PIMTable/Pagination.vue"; |
| | | import { |
| | |
| | | } from "vue"; |
| | | import { Search, Delete } from "@element-plus/icons-vue"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import FormDialog from '@/components/Dialog/FormDialog.vue'; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import { |
| | | getSalesLedgerWithProducts, |
| | | addOrUpdateSalesLedgerProduct, |
| | | delProduct, |
| | | delLedgerFile, |
| | |
| | | delPurchaseTemplate, |
| | | } from "@/api/procurementManagement/procurementLedger.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | |
| | | const salesContractList = ref([]); |
| | | const supplierList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const fileListDialogVisible = ref(false) |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { modelList, productTreeList } from "@/api/basicData/product.js"; |
| | | import dayjs from "dayjs"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | |
| | | const userStore = useUserStore(); |
| | | |
| | |
| | | const purchaseRes = await getPurchaseById({ id: row.id, type: 2 }); |
| | | form.value = { ...purchaseRes }; |
| | | productData.value = purchaseRes.productData || []; |
| | | fileList.value = purchaseRes.salesLedgerFiles || []; |
| | | fileList.value = purchaseRes.storageBlobVOS || []; |
| | | } catch (error) { |
| | | console.error("å è½½éè´å°è´¦æ°æ®å¤±è´¥:", error); |
| | | proxy.$modal.msgError("å è½½æ°æ®å¤±è´¥"); |
| | |
| | | proxy.$modal.msgError("å è½½åºç¡æ°æ®å¤±è´¥"); |
| | | } |
| | | }; |
| | | |
| | | // ä¸ä¼ åæ ¡æ£ |
| | | function handleBeforeUpload(file) { |
| | | // æ ¡æ£æä»¶å¤§å° |
| | |
| | | proxy.$modal.loading("æ£å¨ä¸ä¼ æä»¶ï¼è¯·ç¨å..."); |
| | | return true; |
| | | } |
| | | |
| | | // ä¸ä¼ 失败 |
| | | function handleUploadError(err) { |
| | | proxy.$modal.msgError("ä¸ä¼ æä»¶å¤±è´¥"); |
| | | proxy.$modal.closeLoading(); |
| | | } |
| | | |
| | | // ä¸ä¼ æååè° |
| | | function handleUploadSuccess(res, file, uploadFiles) { |
| | | proxy.$modal.closeLoading(); |
| | |
| | | proxy.$refs.fileUpload.handleRemove(file); |
| | | } |
| | | } |
| | | |
| | | // ç§»é¤æä»¶ |
| | | async function handleRemove(file) { |
| | | if (!file?.id) { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // æäº¤è¡¨å |
| | | const submitForm = () => { |
| | | proxy.$refs["formRef"].validate(valid => { |
| | |
| | | proxy.$modal.msgWarning("请添å 产åä¿¡æ¯"); |
| | | return; |
| | | } |
| | | let tempFileIds = []; |
| | | if (fileList.value.length > 0) { |
| | | tempFileIds = fileList.value.map(item => item.tempId); |
| | | } |
| | | form.value.tempFileIds = tempFileIds; |
| | | form.value.storageBlobDTOS = fileList.value; |
| | | form.value.type = 2; |
| | | |
| | | // 妿salesLedgerId为空ï¼åä¸ä¼ ésalesContractNo |
| | |
| | | } |
| | | return null; // æ²¡ææ¾å°èç¹ï¼è¿ånull |
| | | }; |
| | | |
| | | function convertIdToValue(data) { |
| | | return data.map(item => { |
| | | const { id, children, ...rest } = item; |
| | |
| | | return newItem; |
| | | }); |
| | | } |
| | | |
| | | // æäº¤äº§å表å |
| | | const submitProduct = () => { |
| | | proxy.$refs["productFormRef"].validate(valid => { |
| | |
| | | proxy.$modal.msg("已忶"); |
| | | }); |
| | | }; |
| | | |
| | | // è·åå½åæ¥æå¹¶æ ¼å¼å为 YYYY-MM-DD |
| | | function getCurrentDate() { |
| | | const today = new Date(); |
| | |
| | | const day = String(today.getDate()).padStart(2, "0"); |
| | | return `${year}-${month}-${day}`; |
| | | } |
| | | |
| | | const mathNum = () => { |
| | | if (!productForm.value.taxRate) { |
| | | proxy.$modal.msgWarning("请å
éæ©ç¨ç"); |
| | |
| | | } |
| | | }; |
| | | |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const downLoadFile = row => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(row.salesLedgerFiles); |
| | | } |
| | | }; |
| | | |
| | | // è·å模æ¿ä¿¡æ¯ |
| | | const getTemplateList = async () => { |
| | | let res = await getPurchaseTemplateList(); |
| | |
| | | templateList.value = res.data; |
| | | } |
| | | }; |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileListDialogVisible.value = true |
| | | } |
| | | |
| | | // å 餿¨¡æ¿ |
| | | const handleDeleteTemplate = async (item) => { |
| | |
| | | opacity: 0.6; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | .el-row { |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | } |
| | | |
| | | .no-arrow-select { |
| | | --el-select-suffix-icon-color: transparent; /* éèé»è®¤ä¸æç®å¤´ */ |
| | | } |
| | | |
| | | .select-button-group { |
| | | display: flex; |
| | | align-items: center; |
| | |
| | | // å é¤å¾æ æ ·å¼ |
| | | .delete-icon { |
| | | transition: all 0.3s; |
| | | |
| | | &:hover { |
| | | color: #f56c6c !important; |
| | | transform: scale(1.2); |
| | |
| | | import EditProcess from "@/views/productionManagement/processRoute/Edit.vue"; |
| | | import RouteItemForm from "@/views/productionManagement/processRoute/ItemsForm.vue"; |
| | | import { listPage, del } from "@/api/productionManagement/processRoute.js"; |
| | | import FileList from "@/components/Dialog/FileList.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | import { useRouter } from "vue-router"; |
| | | import { ElMessage, ElMessageBox } from "element-plus"; |
| | | |
| | |
| | | style="margin-right: 10px;"> |
| | | å¡çè§å¾ |
| | | </el-button> |
| | | <el-button type="primary" |
| | | <el-button v-if="editable" |
| | | type="primary" |
| | | @click="handleAdd">æ°å¢</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | link |
| | | size="small" |
| | | @click="handleEdit(scope.row)" |
| | | :disabled="scope.row.isComplete">ç¼è¾</el-button> |
| | | :disabled="scope.row.isComplete || !editable">ç¼è¾</el-button> |
| | | <el-button type="danger" |
| | | link |
| | | size="small" |
| | | @click="handleDelete(scope.row)" |
| | | :disabled="scope.row.isComplete">å é¤</el-button> |
| | | :disabled="scope.row.isComplete || !editable">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | style="margin-right: 10px;"> |
| | | è¡¨æ ¼è§å¾ |
| | | </el-button> |
| | | <el-button type="primary" |
| | | <el-button v-if="editable" |
| | | type="primary" |
| | | @click="handleAdd">æ°å¢</el-button> |
| | | </div> |
| | | </div> |
| | |
| | | link |
| | | size="small" |
| | | @click="handleEdit(item)" |
| | | :disabled="item.isComplete">ç¼è¾</el-button> |
| | | :disabled="item.isComplete || !editable">ç¼è¾</el-button> |
| | | <el-button type="info" |
| | | link |
| | | size="small" |
| | |
| | | link |
| | | size="small" |
| | | @click="handleDelete(item)" |
| | | :disabled="item.isComplete">å é¤</el-button> |
| | | :disabled="item.isComplete || !editable">å é¤</el-button> |
| | | </div> |
| | | </div> |
| | | </div> |
| | |
| | | style="margin-top: 20px;"> |
| | | <div class="section-title">BOM ç»æ</div> |
| | | <div class="section-actions" |
| | | v-if="pageType === 'order'"> |
| | | v-if="pageType === 'order' && editable"> |
| | | <el-button v-if="!bomDataValue.isEdit" |
| | | type="primary" |
| | | @click="bomDataValue.isEdit = true"> |
| | |
| | | @confirm="handleProductSelect" |
| | | single /> |
| | | <!-- åæ°åè¡¨å¯¹è¯æ¡ --> |
| | | <!-- :editable="!routeInfo.status" --> |
| | | <ProcessParamListDialog v-model="showParamListDialog" |
| | | :title="`${currentProcess ? (currentProcess.processName || currentProcess.technologyOperationName || currentProcess.operationName) : ''} - åæ°å表`" |
| | | :route-id="routeId" |
| | |
| | | :process="currentProcess" |
| | | :page-type="pageType" |
| | | :param-list="paramList" |
| | | :editable="editable" |
| | | @getsyncProcessParamItem="getsyncProcessParamItem" |
| | | @refresh="refreshParamList" /> |
| | | </div> |
| | |
| | | const routeId = computed(() => route.query.id); |
| | | const orderId = computed(() => route.query.orderId); |
| | | const pageType = computed(() => route.query.type); |
| | | const editable = computed(() => route.query.editable !== "false"); |
| | | |
| | | const tableLoading = ref(false); |
| | | const tableData = ref([]); |
| | |
| | | // åå§åææ½æåº |
| | | const initSortable = () => { |
| | | destroySortable(); |
| | | if (!editable.value) return; |
| | | |
| | | if (viewMode.value === "table") { |
| | | // è¡¨æ ¼è§å¾çææ½æåº |
| | |
| | | controls-position="right" |
| | | placeholder="è¾å
¥å®é
æ°é" |
| | | style="width: 100%;" |
| | | :disabled="row.returned" |
| | | :disabled="row.returned || orderRow?.end" |
| | | @change="val => handleActualQtyChange(row, val)" /> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button type="warning" |
| | | <el-button v-if="!orderRow?.end" |
| | | type="warning" |
| | | :loading="materialReturnConfirming" |
| | | :disabled="!canOpenReturnSummary" |
| | | @click="openReturnSummaryDialog"> |
| | |
| | | value="3" /> |
| | | <el-option label="已忶" |
| | | value="4" /> |
| | | <el-option label="å·²ç»æ" |
| | | value="5" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | |
| | | :tableLoading="tableLoading" |
| | | :row-class-name="tableRowClassName" |
| | | :isSelection="true" |
| | | :selectable="row => !row.endOrder" |
| | | @selection-change="handleSelectionChange" |
| | | @pagination="pagination"> |
| | | <template #completionStatus="{ row }"> |
| | |
| | | listProcessBom, |
| | | delProductOrder, |
| | | getProductOrderSource, |
| | | updateProductOrder, |
| | | } from "@/api/productionManagement/productionOrder.js"; |
| | | import { listMain as getOrderProcessRouteMain } from "@/api/productionManagement/productProcessRoute.js"; |
| | | import MaterialLedgerDialog from "@/views/productionManagement/productionOrder/components/MaterialLedgerDialog.vue"; |
| | |
| | | prop: "npsNo", |
| | | width: "150px", |
| | | }, |
| | | // 1.å¾
å¼å§ã2.è¿è¡ä¸ã3.已宿ã4.已忶 |
| | | // 1.å¾
å¼å§ã2.è¿è¡ä¸ã3.已宿ã4.已忶ã5.å·²ç»æ |
| | | { |
| | | label: "ç¶æ", |
| | | prop: "status", |
| | |
| | | ? "è¿è¡ä¸" |
| | | : val === 3 |
| | | ? "已宿" |
| | | : val === 5 |
| | | ? "å·²ç»æ" |
| | | : "已忶", |
| | | formatType: val => |
| | | val === 1 |
| | |
| | | ? "warning" |
| | | : val === 3 |
| | | ? "success" |
| | | : "danger", |
| | | : val === 5 |
| | | ? "danger" |
| | | : "info", |
| | | }, |
| | | { |
| | | label: "产ååç§°", |
| | |
| | | label: "æä½", |
| | | align: "center", |
| | | fixed: "right", |
| | | width: 260, |
| | | width: 280, |
| | | operation: [ |
| | | { |
| | | name: "å·¥èºè·¯çº¿", |
| | |
| | | { |
| | | name: "ç»å®å·¥èºè·¯çº¿", |
| | | type: "text", |
| | | showHide: row => !row.processRouteCode, |
| | | showHide: row => !row.processRouteCode && !row.endOrder, |
| | | clickFun: row => { |
| | | openBindRouteDialog(row, "add"); |
| | | }, |
| | |
| | | { |
| | | name: "æ´æ¢å·¥èºè·¯çº¿", |
| | | type: "text", |
| | | showHide: row => row.processRouteCode, |
| | | showHide: row => row.processRouteCode && !row.endOrder, |
| | | clickFun: row => { |
| | | openBindRouteDialog(row, "change"); |
| | | }, |
| | |
| | | name: "颿", |
| | | type: "text", |
| | | color: "#5EC7AB", |
| | | showHide: row => !row.endOrder, |
| | | clickFun: row => { |
| | | openMaterialDialog(row); |
| | | }, |
| | |
| | | name: "è¡¥æ", |
| | | type: "text", |
| | | color: "#5EC7AB", |
| | | showHide: row => !row.endOrder, |
| | | clickFun: row => { |
| | | openMaterialSupplementDialog(row); |
| | | }, |
| | |
| | | { |
| | | name: "æå°é¢æå", |
| | | type: "text", |
| | | color: "#409eff", |
| | | color: "#5EC7AB", |
| | | showHide: row => !row.endOrder, |
| | | clickFun: row => { |
| | | handlePrint(row); |
| | | }, |
| | | }, |
| | | { |
| | | name: "ç产追溯", |
| | | type: "text", |
| | | color: "#409eff", |
| | | clickFun: row => { |
| | | router.push({ |
| | | path: "/productionManagement/productionTraceability", |
| | | query: { |
| | | npsNo: row.npsNo, |
| | | productName: row.productName, |
| | | model: row.model, |
| | | }, |
| | | }); |
| | | }, |
| | | }, |
| | | { |
| | | name: "ç»æè®¢å", |
| | | type: "text", |
| | | color: "red", |
| | | showHide: row => !row.endOrder, |
| | | clickFun: row => { |
| | | handleEndOrder(row); |
| | | }, |
| | | }, |
| | | ], |
| | |
| | | quantity: row.quantity || 0, |
| | | orderId, |
| | | type: "order", |
| | | editable: !row.endOrder, |
| | | }, |
| | | }); |
| | | } catch (e) { |
| | |
| | | }); |
| | | }; |
| | | |
| | | // ç»æè®¢å |
| | | const handleEndOrder = row => { |
| | | ElMessageBox.confirm(`æ¯å¦ç¡®è®¤ç»æè®¢åï¼${row.npsNo}ï¼`, "æç¤º", { |
| | | confirmButtonText: "ç¡®å®", |
| | | cancelButtonText: "åæ¶", |
| | | type: "warning", |
| | | }) |
| | | .then(() => { |
| | | const params = { |
| | | id: row.id, |
| | | endOrder: true, |
| | | }; |
| | | updateProductOrder(params).then(() => { |
| | | proxy.$modal.msgSuccess("ç»æè®¢åæå"); |
| | | getList(); |
| | | }); |
| | | }) |
| | | .catch(() => {}); |
| | | }; |
| | | |
| | | const handleConfirmRoute = () => {}; |
| | | |
| | | onMounted(() => { |
| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <template> |
| | | <div class="app-container"> |
| | | <el-card style="height:82vh;overflow:auto;"> |
| | | <template #header> |
| | | <div class="card-header"> |
| | | <el-form :inline="true" |
| | | :model="searchForm" |
| | | class="search-form"> |
| | | <el-form-item label="ç产订åå·"> |
| | | <el-select v-model="selectedNpsNo" |
| | | filterable |
| | | remote |
| | | reserve-keyword |
| | | placeholder="请è¾å
¥ç产订åå·" |
| | | :loading="npsNoLoading" |
| | | :remote-method="handleNpsNoSearch" |
| | | @change="handleSearch" |
| | | style="width: 400px;"> |
| | | <el-option v-for="option in npsNoOptions" |
| | | :key="option.id" |
| | | :label="option.npsNo + '-' + option.productName + '-' + option.model" |
| | | :value="option.id" /> |
| | | </el-select> |
| | | </el-form-item> |
| | | <el-form-item> |
| | | <el-button @click="handleBack">è¿å</el-button> |
| | | </el-form-item> |
| | | </el-form> |
| | | </div> |
| | | </template> |
| | | <!-- åºç¡ä¿¡æ¯ --> |
| | | <div v-if="rowData.productionOrderDto" |
| | | class="detail-section"> |
| | | <h3 class="section-title">åºç¡ä¿¡æ¯</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="ç产订åå·">{{ rowData.productionOrderDto?.npsNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ rowData.productionOrderDto?.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产åè§æ ¼">{{ rowData.productionOrderDto?.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç©æç¼ç ">{{ rowData.productionOrderDto?.materialCode || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è®¡åæ°é">{{ rowData.productionOrderDto?.quantity || 0 }} <span class="unit">{{ rowData.productionOrderDto?.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="å½åç¶æ"> |
| | | <el-tag :type="getStatusType(rowData.productionOrderDto?.status)"> |
| | | {{ getStatusText(rowData.productionOrderDto?.status) }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="客æ·åç§°">{{ rowData.productionOrderDto?.customerName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¥æ">{{ rowData.productionOrderDto?.startTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="宿è¿åº¦"> |
| | | <el-progress :percentage="rowData.productionOrderDto?.completionStatus" |
| | | :color="customColors(rowData.productionOrderDto?.completionStatus)" |
| | | :status="rowData.productionOrderDto?.completionStatus === 100 ? 'success' : ''" |
| | | style="width: 120px;" /> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <el-empty v-else |
| | | description="请æç´¢ç产订åå·" /> |
| | | <!-- ç产æ¥å·¥è®°å½ --> |
| | | <div v-if="rowData.productionRecords && rowData.productionRecords.length > 0" |
| | | class="progress-container"> |
| | | <div class="progress-section"> |
| | | <h3 class="section-title">å·¥åä¿¡æ¯</h3> |
| | | <div class="order-item"> |
| | | <el-table :data="rowData.productionRecords" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column prop="productNo" |
| | | label="å·¥åç¼å·" |
| | | align="center"> |
| | | </el-table-column> |
| | | <el-table-column prop="productName" |
| | | label="产ååç§°" |
| | | align="center" /> |
| | | <el-table-column prop="model" |
| | | label="è§æ ¼" |
| | | align="center" /> |
| | | <el-table-column prop="processName" |
| | | label="å·¥åºåç§°" |
| | | align="center" /> |
| | | <el-table-column prop="requiredQuantity" |
| | | label="éæ±æ°é" |
| | | align="center" /> |
| | | <el-table-column prop="completedQuantity" |
| | | label="宿æ°é" |
| | | align="center" /> |
| | | <el-table-column label="详æ
" |
| | | align="center" |
| | | width="200"> |
| | | <template #default="{ row }"> |
| | | <el-link @click="handleClickStep(row)" |
| | | type="primary">æ¥å·¥è®°å½</el-link> |
| | | <el-link @click="handleClickQuality(row)" |
| | | style="margin-left:20px" |
| | | type="primary">è´¨æ£ä¿¡æ¯</el-link> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <el-empty v-else-if="rowData.productionOrderDto" |
| | | description="ææ æ¥å·¥è®°å½" /> |
| | | </el-card> |
| | | <!-- ç产æ¥å·¥è¯¦æ
å¼¹çª --> |
| | | <el-dialog v-model="detailDialogVisible" |
| | | title="ç产æ¥å·¥è¯¦æ
" |
| | | width="1000px" |
| | | :close-on-click-modal="false" |
| | | custom-class="custom-dialog"> |
| | | <div class="detail-container"> |
| | | <!-- åºç¡ä¿¡æ¯ --> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">åºç¡ä¿¡æ¯</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="ç产工åå·">{{ detailData.npsNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="çç»"> |
| | | <el-tag :type="detailData.schedule === 'ç½ç' ? 'primary' : 'warning'">{{ detailData.schedule || '-' }}</el-tag> |
| | | </el-descriptions-item> |
| | | <el-descriptions-item label="产åç¼ç ">{{ detailData.materialCode || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ detailData.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è§æ ¼">{{ detailData.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="åæ ¼æ°é"><span class="num2">{{ detailData.qualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="ä¸åæ ¼æ°é"><span class="num3">{{ detailData.unqualifiedQuantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="æ»æ°é"><span class="num1">{{ detailData.quantity || 0 }}</span> <span class="unit">{{ detailData.unit || '-' }}</span></el-descriptions-item> |
| | | <el-descriptions-item label="å¼å§æ¶é´">{{ detailData.reportingTime || '-' }}</el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">æ¥å·¥æç»</h3> |
| | | <el-table :data="[detailData]" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column label="æ¥å·¥åå·" |
| | | prop="productNo" |
| | | align="center" /> |
| | | <el-table-column label="äº§åºæ°é" |
| | | prop="qualifiedQuantity" |
| | | align="center" /> |
| | | <el-table-column label="æ¥åºæ°é" |
| | | prop="unqualifiedQuantity" |
| | | align="center" /> |
| | | <el-table-column label="å建æ¶é´" |
| | | prop="reportingTime" |
| | | align="center" /> |
| | | <el-table-column label="æä½" |
| | | align="center" |
| | | width="200"> |
| | | <template #default="{ row }"> |
| | | <el-button type="primary" |
| | | link |
| | | @click="showInput(row.id)">æ¥çæå
¥</el-button> |
| | | <el-button type="primary" |
| | | link |
| | | @click="showParamDetail(row.productionOperationParamList)">åæ°è¯¦æ
</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="detailDialogVisible = false">å
³é</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- æå
¥æ¨¡ææ¡ --> |
| | | <input-modal v-if="isShowInput" |
| | | v-model:visible="isShowInput" |
| | | :production-product-main-id="isShowingId" /> |
| | | <!-- åæ°è¯¦æ
å¼¹çª --> |
| | | <el-dialog v-model="paramDetailVisible" |
| | | title="åæ°è¯¦æ
" |
| | | width="600px"> |
| | | <div v-if="currentParams && currentParams.length > 0" |
| | | class="param-detail-list"> |
| | | <el-descriptions :column="1" |
| | | border> |
| | | <el-descriptions-item v-for="param in currentParams" |
| | | :key="param.id" |
| | | :label="param.paramName"> |
| | | {{ param.inputValue }} |
| | | <span v-if="param.unit && param.unit !== '/'" |
| | | class="unit-text">({{ param.unit }})</span> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | </div> |
| | | <el-empty v-else |
| | | description="ææ åæ°æ°æ®" /> |
| | | <template #footer> |
| | | <span class="dialog-footer"> |
| | | <el-button @click="paramDetailVisible = false">å
³é</el-button> |
| | | </span> |
| | | </template> |
| | | </el-dialog> |
| | | <!-- è´¨æ£ä¿¡æ¯å¼¹çª --> |
| | | <el-dialog v-model="qualityDialogVisible" |
| | | title="è´¨æ£è¯¦æ
" |
| | | width="1000px" |
| | | :close-on-click-modal="false" |
| | | custom-class="custom-dialog"> |
| | | <div class="detail-container"> |
| | | <div v-for="(record, index) in qualityRecords" |
| | | :key="record.id" |
| | | class="quality-record-block"> |
| | | <div class="detail-section"> |
| | | <h3 class="section-title">æ£æµè®°å½ {{ index + 1 }} - {{ record.checkTime }}</h3> |
| | | <el-descriptions :column="3" |
| | | border> |
| | | <el-descriptions-item label="æ£æµæ¥æ">{{ record.checkTime || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="ç产工åå·">{{ record.workOrderNo || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="å·¥åº">{{ record.process || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£éªå">{{ record.checkName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="产ååç§°">{{ record.productName || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="è§æ ¼åå·">{{ record.model || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ°é">{{ record.quantity || 0 }} {{ record.unit || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£æµåä½">{{ record.checkCompany || '-' }}</el-descriptions-item> |
| | | <el-descriptions-item label="æ£æµç»æ"> |
| | | <el-tag :type="record.checkResult === 'åæ ¼' ? 'success' : 'danger'"> |
| | | {{ record.checkResult || '-' }} |
| | | </el-tag> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <h4 class="sub-section-title">æ£éªææ å表</h4> |
| | | <el-table :data="record.inspectItems" |
| | | border |
| | | style="width: 100%"> |
| | | <el-table-column label="åºå·" |
| | | type="index" |
| | | width="60" |
| | | align="center" /> |
| | | <el-table-column label="ææ " |
| | | prop="itemName" |
| | | align="center" /> |
| | | <el-table-column label="åä½" |
| | | prop="unit" |
| | | align="center" /> |
| | | <el-table-column label="æ åå¼" |
| | | prop="standardValue" |
| | | align="center" /> |
| | | <el-table-column label="å
æ§å¼" |
| | | prop="controlValue" |
| | | align="center" /> |
| | | <el-table-column label="å®é
å¼" |
| | | prop="actualValue" |
| | | align="center" /> |
| | | </el-table> |
| | | </div> |
| | | <!-- <div class="detail-section"> |
| | | |
| | | </div> --> |
| | | <el-divider v-if="index < qualityRecords.length - 1" /> |
| | | </div> |
| | | </div> |
| | | <template #footer> |
| | | <div class="dialog-footer"> |
| | | <el-button @click="qualityDialogVisible = false">å
³é</el-button> |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { ref, reactive, onMounted } from "vue"; |
| | | import { useRoute, useRouter } from "vue-router"; |
| | | import { ElMessage } from "element-plus"; |
| | | import InputModal from "@/views/productionManagement/productionReporting/Input.vue"; |
| | | |
| | | const route = useRoute(); |
| | | const router = useRouter(); |
| | | |
| | | // æç´¢ç¸å
³ |
| | | const searchForm = reactive({ |
| | | npsNo: "", |
| | | }); |
| | | const selectedNpsNo = ref(null); |
| | | const npsNoLoading = ref(false); |
| | | const npsNoOptions = ref([ |
| | | { |
| | | id: 1, |
| | | npsNo: "PO20240301001", |
| | | productName: "ç²¾å¯æ¶²å缸", |
| | | model: "HG-100/50-500", |
| | | materialCode: "MAT-2024-001", |
| | | quantity: 500, |
| | | unit: "ä»¶", |
| | | status: 1, |
| | | customerName: "éå·¥æºæ¢°æéå
¬å¸", |
| | | startTime: "2024-03-01", |
| | | completionStatus: 65, |
| | | }, |
| | | { |
| | | id: 2, |
| | | npsNo: "PO20240301002", |
| | | productName: "å·¥ä¸ä¼ºæçµæº", |
| | | model: "SV-400W-3000", |
| | | materialCode: "MAT-2024-002", |
| | | quantity: 200, |
| | | unit: "å°", |
| | | status: 2, |
| | | customerName: "èªå¨å设å¤ç§æå
¬å¸", |
| | | startTime: "2024-03-02", |
| | | completionStatus: 100, |
| | | }, |
| | | { |
| | | id: 3, |
| | | npsNo: "PO20240301003", |
| | | productName: "é«åå¯å°å", |
| | | model: "SR-80-5", |
| | | materialCode: "MAT-2024-003", |
| | | quantity: 5000, |
| | | unit: "个", |
| | | status: 0, |
| | | customerName: "å¯å°ç³»ç»é
ä»¶å", |
| | | startTime: "2024-03-05", |
| | | completionStatus: 0, |
| | | }, |
| | | ]); |
| | | |
| | | // 详æ
æ°æ® |
| | | const rowData = reactive({ |
| | | productionOrderDto: null, |
| | | productionRecords: [], |
| | | }); |
| | | |
| | | // æ¥å·¥è¯¦æ
å¼¹çª |
| | | const detailDialogVisible = ref(false); |
| | | const detailData = ref({}); |
| | | |
| | | // æå
¥æ¨¡ææ¡ |
| | | const isShowInput = ref(false); |
| | | const isShowingId = ref(0); |
| | | const showInput = id => { |
| | | isShowInput.value = true; |
| | | isShowingId.value = id; |
| | | }; |
| | | |
| | | // åæ°è¯¦æ
å¼¹çª |
| | | const paramDetailVisible = ref(false); |
| | | const currentParams = ref([]); |
| | | const showParamDetail = params => { |
| | | currentParams.value = params || []; |
| | | paramDetailVisible.value = true; |
| | | }; |
| | | |
| | | // è´¨æ£ä¿¡æ¯å¼¹çª |
| | | const qualityDialogVisible = ref(false); |
| | | const qualityRecords = ref([]); |
| | | |
| | | // ç¶æå¤ç |
| | | const getStatusType = status => { |
| | | const typeMap = { 0: "info", 1: "primary", 2: "success" }; |
| | | return typeMap[status] || "info"; |
| | | }; |
| | | const getStatusText = status => { |
| | | const statusMap = { 0: "æªå¼å§", 1: "ç产ä¸", 2: "已宿" }; |
| | | return statusMap[status] || "æªç¥"; |
| | | }; |
| | | const customColors = percentage => { |
| | | if (percentage < 30) return "#f56c6c"; |
| | | if (percentage < 70) return "#e6a23c"; |
| | | return "#67c23a"; |
| | | }; |
| | | |
| | | // 模ææç´¢æ¹æ³ |
| | | const handleNpsNoSearch = query => { |
| | | if (query) { |
| | | npsNoLoading.value = true; |
| | | setTimeout(() => { |
| | | npsNoLoading.value = false; |
| | | }, 300); |
| | | } |
| | | }; |
| | | |
| | | const handleSearch = id => { |
| | | const selected = npsNoOptions.value.find(item => item.id === id); |
| | | if (selected) { |
| | | rowData.productionOrderDto = selected; |
| | | rowData.productionRecords = [ |
| | | { |
| | | id: 1001, |
| | | productNo: "MO-2024-001-01", |
| | | productName: selected.productName, |
| | | model: selected.model, |
| | | processName: "æ¯å¯å å·¥", |
| | | requiredQuantity: selected.quantity, |
| | | completedQuantity: Math.floor(selected.quantity * 0.4), |
| | | qualifiedQuantity: Math.floor(selected.quantity * 0.4) - 2, |
| | | unqualifiedQuantity: 2, |
| | | reportingTime: "2024-03-01 10:00:00", |
| | | schedule: "ç½ç", |
| | | postName: "å¼ ä¸", |
| | | unit: selected.unit, |
| | | }, |
| | | { |
| | | id: 1002, |
| | | productNo: "MO-2024-001-02", |
| | | productName: selected.productName, |
| | | model: selected.model, |
| | | processName: "ç²¾å å·¥", |
| | | requiredQuantity: Math.floor(selected.quantity * 0.4), |
| | | completedQuantity: Math.floor(selected.quantity * 0.25), |
| | | qualifiedQuantity: Math.floor(selected.quantity * 0.25), |
| | | unqualifiedQuantity: 0, |
| | | reportingTime: "2024-03-01 16:00:00", |
| | | schedule: "ç½ç", |
| | | postName: "æå", |
| | | unit: selected.unit, |
| | | }, |
| | | ]; |
| | | } |
| | | }; |
| | | |
| | | const handleBack = () => { |
| | | router.back(); |
| | | }; |
| | | |
| | | const handleClickStep = row => { |
| | | detailData.value = { |
| | | id: row.id || Math.floor(Math.random() * 1000), |
| | | productNo: row.productNo, |
| | | npsNo: rowData.productionOrderDto.npsNo, |
| | | schedule: row.schedule, |
| | | postName: row.postName, |
| | | materialCode: rowData.productionOrderDto.materialCode, |
| | | productName: row.productName, |
| | | model: row.model, |
| | | qualifiedQuantity: row.qualifiedQuantity, |
| | | unqualifiedQuantity: row.unqualifiedQuantity || 0, |
| | | quantity: row.completedQuantity, |
| | | unit: row.unit, |
| | | reportingTime: row.reportingTime, |
| | | productionOperationParamList: [ |
| | | { id: 1, paramName: "主轴转é", inputValue: "2400", unit: "rpm" }, |
| | | { id: 2, paramName: "è¿ç»é度", inputValue: "120", unit: "mm/min" }, |
| | | { id: 3, paramName: "ååæ·±åº¦", inputValue: "0.5", unit: "mm" }, |
| | | { id: 4, paramName: "å·å´æ¶²åå", inputValue: "0.6", unit: "Mpa" }, |
| | | ], |
| | | }; |
| | | detailDialogVisible.value = true; |
| | | }; |
| | | |
| | | const handleClickQuality = row => { |
| | | qualityRecords.value = [ |
| | | { |
| | | id: 2001, |
| | | checkTime: "2024-03-01 11:30:00", |
| | | workOrderNo: row.productNo, |
| | | process: row.processName, |
| | | checkName: "è´¨éé¨-ç建å½", |
| | | productName: row.productName, |
| | | model: row.model, |
| | | unit: row.unit, |
| | | quantity: row.completedQuantity, |
| | | checkCompany: "å
é¨å®éªå®¤", |
| | | checkResult: "åæ ¼", |
| | | inspectItems: [ |
| | | { |
| | | id: 1, |
| | | itemName: "å¤å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "100.00±0.05", |
| | | controlValue: "100.00±0.03", |
| | | actualValue: "100.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 2, |
| | | itemName: "å
å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "50.00+0.02/-0", |
| | | controlValue: "50.00+0.01/-0", |
| | | actualValue: "50.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 3, |
| | | itemName: "表é¢ç²ç³åº¦", |
| | | unit: "Ra", |
| | | standardValue: "â¤1.6", |
| | | controlValue: "â¤1.2", |
| | | actualValue: "0.8", |
| | | result: "åæ ¼", |
| | | }, |
| | | ], |
| | | }, |
| | | { |
| | | id: 2001, |
| | | checkTime: "2024-03-01 11:30:00", |
| | | workOrderNo: row.productNo, |
| | | process: row.processName, |
| | | checkName: "è´¨éé¨-ç建å½", |
| | | productName: row.productName, |
| | | model: row.model, |
| | | unit: row.unit, |
| | | quantity: row.completedQuantity, |
| | | checkCompany: "å
é¨å®éªå®¤", |
| | | checkResult: "åæ ¼", |
| | | inspectItems: [ |
| | | { |
| | | id: 1, |
| | | itemName: "å¤å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "100.00±0.05", |
| | | controlValue: "100.00±0.03", |
| | | actualValue: "100.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 2, |
| | | itemName: "å
å¾å°ºå¯¸", |
| | | unit: "mm", |
| | | standardValue: "50.00+0.02/-0", |
| | | controlValue: "50.00+0.01/-0", |
| | | actualValue: "50.01", |
| | | result: "åæ ¼", |
| | | }, |
| | | { |
| | | id: 3, |
| | | itemName: "表é¢ç²ç³åº¦", |
| | | unit: "Ra", |
| | | standardValue: "â¤1.6", |
| | | controlValue: "â¤1.2", |
| | | actualValue: "0.8", |
| | | result: "åæ ¼", |
| | | }, |
| | | ], |
| | | }, |
| | | ]; |
| | | qualityDialogVisible.value = true; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | if (route.query.npsNo) { |
| | | const npsNo = route.query.npsNo; |
| | | const found = npsNoOptions.value.find(item => item.npsNo === npsNo); |
| | | if (found) { |
| | | selectedNpsNo.value = found.id; |
| | | handleSearch(found.id); |
| | | } else { |
| | | // å¦ææ²¡æ¾å°ï¼å建ä¸ä¸ªä¸´æ¶ç |
| | | const mockItem = { |
| | | id: Date.now(), |
| | | npsNo: npsNo, |
| | | productName: route.query.productName || "ç²¾å¯æ¶²å缸", |
| | | model: route.query.model || "HG-100/50-500", |
| | | materialCode: "MAT-2024-MOCK", |
| | | quantity: 100, |
| | | unit: "ä»¶", |
| | | status: 1, |
| | | customerName: "模æå®¢æ·", |
| | | startTime: "2024-03-01", |
| | | completionStatus: 50, |
| | | }; |
| | | npsNoOptions.value.push(mockItem); |
| | | selectedNpsNo.value = mockItem.id; |
| | | handleSearch(mockItem.id); |
| | | } |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped> |
| | | .app-container { |
| | | padding: 20px; |
| | | background-color: #f5f7fa; |
| | | min-height: 100vh; |
| | | } |
| | | |
| | | .card-header { |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | padding: 0 10px; |
| | | } |
| | | |
| | | .search-form { |
| | | width: 100%; |
| | | } |
| | | |
| | | .search-form .el-form-item { |
| | | margin-right: 10px; |
| | | } |
| | | |
| | | .detail-section { |
| | | margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 10px; |
| | | padding: 24px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08); |
| | | transition: all 0.3s ease; |
| | | } |
| | | |
| | | .detail-section:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12); |
| | | } |
| | | |
| | | .section-title { |
| | | font-size: 16px; |
| | | font-weight: 600; |
| | | margin-bottom: 20px; |
| | | color: #1a1a1a; |
| | | border-bottom: 2px solid #409eff; |
| | | padding-bottom: 10px; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .section-title::before { |
| | | content: ""; |
| | | display: inline-block; |
| | | width: 4px; |
| | | height: 16px; |
| | | background-color: #409eff; |
| | | margin-right: 8px; |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .sub-section-title { |
| | | font-size: 14px; |
| | | font-weight: 600; |
| | | margin-bottom: 16px; |
| | | color: #303133; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .sub-section-title::before { |
| | | content: ""; |
| | | display: inline-block; |
| | | width: 3px; |
| | | height: 12px; |
| | | background-color: #67c23a; |
| | | margin-right: 8px; |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .unit { |
| | | font-size: 12px; |
| | | color: #909399; |
| | | margin-left: 4px; |
| | | } |
| | | |
| | | :deep(.el-descriptions) { |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | :deep(.el-descriptions__row:nth-child(odd)) { |
| | | background-color: #f9f9f9; |
| | | } |
| | | |
| | | :deep(.el-descriptions__label) { |
| | | font-weight: 500; |
| | | color: #606266; |
| | | background-color: #f5f7fa; |
| | | } |
| | | |
| | | :deep(.el-descriptions__content) { |
| | | color: #303133; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .progress-container { |
| | | display: flex; |
| | | gap: 24px; |
| | | } |
| | | |
| | | .progress-section { |
| | | margin-bottom: 24px; |
| | | background-color: #ffffff; |
| | | border-radius: 10px; |
| | | padding: 24px; |
| | | box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.08); |
| | | flex: 1; |
| | | transition: all 0.3s ease; |
| | | width: 100%; |
| | | } |
| | | |
| | | .progress-section:hover { |
| | | box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.12); |
| | | } |
| | | |
| | | .order-item { |
| | | margin-bottom: 20px; |
| | | border-radius: 8px; |
| | | overflow: hidden; |
| | | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | :deep(.el-table) { |
| | | border-radius: 8px; |
| | | box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05); |
| | | } |
| | | |
| | | :deep(.el-table th) { |
| | | background-color: #f5f7fa !important; |
| | | font-weight: 600; |
| | | color: #606266; |
| | | } |
| | | |
| | | :deep(.el-progress-bar__inner) { |
| | | border-radius: 10px; |
| | | } |
| | | |
| | | :deep(.el-tag) { |
| | | border-radius: 12px; |
| | | padding: 2px 10px; |
| | | } |
| | | |
| | | /* å¼¹çªæ ·å¼ */ |
| | | .detail-container { |
| | | max-height: 600px; |
| | | overflow-y: auto; |
| | | padding: 0 16px; |
| | | } |
| | | |
| | | .process-item { |
| | | margin-bottom: 24px; |
| | | padding: 20px; |
| | | background-color: #ffffff; |
| | | border-radius: 8px; |
| | | border: 1px solid #ebeef5; |
| | | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); |
| | | } |
| | | |
| | | .process-header { |
| | | margin-bottom: 20px; |
| | | padding-bottom: 12px; |
| | | border-bottom: 1px solid #f0f2f5; |
| | | } |
| | | |
| | | .process-title { |
| | | font-size: 15px; |
| | | font-weight: 600; |
| | | margin-bottom: 12px; |
| | | color: #1a1a1a; |
| | | display: flex; |
| | | align-items: center; |
| | | } |
| | | |
| | | .process-title::before { |
| | | content: ""; |
| | | display: inline-block; |
| | | width: 4px; |
| | | height: 16px; |
| | | background-color: #409eff; |
| | | margin-right: 8px; |
| | | border-radius: 2px; |
| | | } |
| | | |
| | | .process-info { |
| | | display: flex; |
| | | gap: 20px; |
| | | font-size: 13px; |
| | | color: #606266; |
| | | } |
| | | |
| | | .process-label { |
| | | padding: 4px 12px; |
| | | background-color: #ecf5ff; |
| | | border-radius: 4px; |
| | | color: #409eff; |
| | | font-weight: 500; |
| | | } |
| | | |
| | | .process-details { |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | .num1 { |
| | | color: #1107cc; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .num2 { |
| | | color: #0fcf25; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .num3 { |
| | | color: #d31818; |
| | | font-weight: 600; |
| | | } |
| | | |
| | | .dialog-footer { |
| | | text-align: center; |
| | | padding: 20px; |
| | | border-top: 1px solid #ebeef5; |
| | | } |
| | | |
| | | .dialog-footer .el-button { |
| | | min-width: 100px; |
| | | padding: 8px 20px; |
| | | } |
| | | |
| | | /* èªå®ä¹å¯¹è¯æ¡æ ·å¼ */ |
| | | :deep(.custom-dialog) { |
| | | border-radius: 12px; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | :deep(.custom-dialog .el-dialog__header) { |
| | | background-color: #f5f7fa; |
| | | padding: 20px; |
| | | border-bottom: 1px solid #ebeef5; |
| | | } |
| | | |
| | | :deep(.custom-dialog .el-dialog__title) { |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #1a1a1a; |
| | | } |
| | | |
| | | :deep(.custom-dialog .el-dialog__body) { |
| | | padding: 20px; |
| | | } |
| | | |
| | | .unit-text { |
| | | margin-left: 5px; |
| | | color: #909399; |
| | | font-size: 12px; |
| | | } |
| | | |
| | | .param-detail-list { |
| | | padding: 10px; |
| | | } |
| | | </style> |
| | |
| | | width: "140", |
| | | }, |
| | | { |
| | | label: "æå®æ¥å·¥äºº", |
| | | prop: "userNames", |
| | | width: "180", |
| | | }, |
| | | { |
| | | label: "æä½", |
| | | width: "200", |
| | | align: "center", |
| | |
| | | @refresh="getList" /> |
| | | <FileList v-if="fileDialogVisible" |
| | | v-model:visible="fileDialogVisible" |
| | | :editable="!currentWorkOrderRow?.endOrder" |
| | | :record-type="'production_operation_task'" |
| | | :record-id="currentWorkOrderId" /> |
| | | </div> |
| | |
| | | import QRCode from "qrcode"; |
| | | import { getCurrentInstance, reactive, toRefs } from "vue"; |
| | | import MaterialDialog from "./components/MaterialDialog.vue"; |
| | | import FileList from "@/components/Dialog/FileList.vue"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | import useUserStore from "@/store/modules/user"; |
| | | const { proxy } = getCurrentInstance(); |
| | | const userStore = useUserStore(); |
| | | |
| | | const tableColumn = ref([ |
| | | { |
| | |
| | | clickFun: row => { |
| | | showReportDialog(row); |
| | | }, |
| | | disabled: row => row.planQuantity <= 0, |
| | | showHide: row => !row.endOrder, |
| | | disabled: row => { |
| | | if (row.planQuantity <= 0) return true; |
| | | if (!row.userIds) return false; |
| | | try { |
| | | const userIds = |
| | | typeof row.userIds === "string" |
| | | ? JSON.parse(row.userIds) |
| | | : row.userIds; |
| | | if (Array.isArray(userIds)) { |
| | | return !userIds.some(id => String(id) === String(userStore.id)); |
| | | } |
| | | return true; |
| | | } catch (e) { |
| | | return true; |
| | | } |
| | | }, |
| | | }, |
| | | ], |
| | | }, |
| | |
| | | const printTransferCard = () => { |
| | | window.print(); |
| | | }; |
| | | const currentWorkOrderRow = ref(null); |
| | | |
| | | const openWorkOrderFiles = row => { |
| | | currentWorkOrderId.value = row.id; |
| | | currentWorkOrderRow.value = row; |
| | | fileDialogVisible.value = true; |
| | | }; |
| | | |
| | |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | userStore.getInfo(); |
| | | getList(); |
| | | // è·åç¨æ·å表 |
| | | userListNoPageByTenantId().then(res => { |
| | |
| | | </el-row> |
| | | </el-form> |
| | | </FormDialog> |
| | | <!-- todo éä»¶é¢è§ç¸å
³ --> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :is-show-pagination="true" |
| | | :page="filePagination" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | @pagination="paginationSearch" |
| | | title="éä»¶å表" /> |
| | | <FileListDialog |
| | | v-if="fileListDialogVisible" |
| | | :record-id="currentRecordId" |
| | | record-type="safe_hidden" |
| | | v-model:visible="fileListDialogVisible"/> |
| | | |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { |
| | |
| | | safeHiddenUpdate, |
| | | safeHiddenDel, |
| | | fileListPage, |
| | | safeHiddenFileAdd, |
| | | safeHiddenFileDel, |
| | | } from "@/api/safeProduction/dangerInvestigation.js"; |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import request from "@/utils/request"; |
| | | import dayjs from "dayjs"; |
| | | import { get } from "@vueuse/core"; |
| | | |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | |
| | | const selectedRows = ref([]); |
| | | const userList = ref([]); |
| | | const tableLoading = ref(false); |
| | | const currentRecordId = ref(0); |
| | | const page = reactive({ |
| | | current: 1, |
| | | size: 100, |
| | |
| | | const fileListDialogVisible = ref(false); |
| | | const currentFileRow = ref(null); |
| | | const downLoadFile = row => { |
| | | currentFileRow.value = row; |
| | | fileListPage({ |
| | | safeHiddenId: row.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }).then(res => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.data.records || []); |
| | | console.log("res.data", res.data); |
| | | filePagination.value.total = res.data.total || 0; |
| | | } |
| | | }); |
| | | currentRecordId.value = row.id; |
| | | fileListDialogVisible.value = true; |
| | | }; |
| | | const currentUserId = ref(""); |
| | | const currentUserName = ref(""); |
| | |
| | | userList.value = res.data; |
| | | }); |
| | | }); |
| | | // ä¸ä¼ éä»¶ |
| | | const handleUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | | proxy.$modal.msgWarning("请å
éæ©æ°æ®"); |
| | | return null; |
| | | } |
| | | |
| | | return new Promise(resolve => { |
| | | // å建ä¸ä¸ªéèçæä»¶è¾å
¥å
ç´ |
| | | const input = document.createElement("input"); |
| | | input.type = "file"; |
| | | input.style.display = "none"; |
| | | input.onchange = async e => { |
| | | const file = e.target.files[0]; |
| | | if (!file) { |
| | | resolve(null); |
| | | return; |
| | | } |
| | | |
| | | try { |
| | | // ä½¿ç¨ FormData ä¸ä¼ æä»¶ |
| | | const formData = new FormData(); |
| | | formData.append("file", file); |
| | | |
| | | const uploadRes = await request({ |
| | | url: "/file/upload", |
| | | method: "post", |
| | | data: formData, |
| | | headers: { |
| | | "Content-Type": "multipart/form-data", |
| | | Authorization: `Bearer ${getToken()}`, |
| | | }, |
| | | }); |
| | | |
| | | if (uploadRes.code === 200) { |
| | | // ä¿åéä»¶ä¿¡æ¯ |
| | | const fileData = { |
| | | safeHiddenId: currentFileRow.value.id, |
| | | name: uploadRes.data.originalName || file.name, |
| | | url: uploadRes.data.tempPath || uploadRes.data.url, |
| | | }; |
| | | |
| | | const saveRes = await safeHiddenFileAdd(fileData); |
| | | if (saveRes.code === 200) { |
| | | proxy.$modal.msgSuccess("æä»¶ä¸ä¼ æå"); |
| | | // éæ°å è½½æä»¶å表 |
| | | const listRes = await fileListPage({ |
| | | safeHiddenId: currentFileRow.value.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }); |
| | | if (listRes.code === 200 && fileListRef.value) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item, |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | filePagination.value.total = listRes.data?.total || 0; |
| | | } |
| | | // è¿åæ°æä»¶ä¿¡æ¯ |
| | | resolve({ |
| | | name: fileData.name, |
| | | url: fileData.url, |
| | | id: saveRes.data?.id, |
| | | }); |
| | | } else { |
| | | proxy.$modal.msgError(saveRes.msg || "æä»¶ä¿å失败"); |
| | | resolve(null); |
| | | } |
| | | } else { |
| | | proxy.$modal.msgError(uploadRes.msg || "æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("æä»¶ä¸ä¼ 失败"); |
| | | resolve(null); |
| | | } finally { |
| | | document.body.removeChild(input); |
| | | } |
| | | }; |
| | | |
| | | document.body.appendChild(input); |
| | | input.click(); |
| | | }); |
| | | }; |
| | | // å页æ¥è¯¢æä»¶å表 |
| | | const paginationSearch = async (page, size) => { |
| | | filePagination.value.current = page; |
| | | filePagination.value.size = size; |
| | | const listRes = await fileListPage({ |
| | | safeHiddenId: currentFileRow.value.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }); |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item, |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | filePagination.value.total = listRes.data?.total || 0; |
| | | } |
| | | }; |
| | | // å é¤éä»¶ |
| | | const handleFileDelete = async row => { |
| | | try { |
| | | const res = await safeHiddenFileDel([row.id]); |
| | | if (res.code === 200) { |
| | | proxy.$modal.msgSuccess("å 餿å"); |
| | | // éæ°å è½½æä»¶å表 |
| | | if (currentFileRow.value && fileListRef.value) { |
| | | const listRes = await fileListPage({ |
| | | safeHiddenId: currentFileRow.value.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }); |
| | | if (listRes.code === 200) { |
| | | const fileList = (listRes.data?.records || []).map(item => ({ |
| | | name: item.name, |
| | | url: item.url, |
| | | id: item.id, |
| | | ...item, |
| | | })); |
| | | fileListRef.value.setList(fileList); |
| | | filePagination.value.total = listRes.data?.total || 0; |
| | | } |
| | | } |
| | | return true; // è¿å true 表示å 餿åï¼ç»ä»¶ä¼æ´æ°å表 |
| | | } else { |
| | | proxy.$modal.msgError(res.msg || "å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | } catch (error) { |
| | | proxy.$modal.msgError("å é¤å¤±è´¥"); |
| | | return false; |
| | | } |
| | | }; |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | |
| | | <el-button link |
| | | type="primary" |
| | | size="small" |
| | | @click="downLoadFile(scope.row)">éä»¶</el-button> |
| | | @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </el-form> |
| | | </FormDialog> |
| | | <!-- todo éä»¶é¢è§ç¸å
³ --> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :is-show-pagination="true" |
| | | :page="filePagination" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | @pagination="paginationSearch" |
| | | title="éä»¶å表" /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="safe_certification" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { |
| | |
| | | import useFormData from "@/hooks/useFormData.js"; |
| | | import request from "@/utils/request"; |
| | | import dayjs from "dayjs"; |
| | | |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | const userStore = useUserStore(); |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | |
| | | size: 10, |
| | | total: 0, |
| | | }); |
| | | const downLoadFile = row => { |
| | | currentFileRow.value = row; |
| | | fileListPage({ |
| | | safeCertificationId: row.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }).then(res => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.data.records); |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | filePagination.value.total = res.data.total || 0; |
| | | }); |
| | | }; |
| | | |
| | | const currentFactoryName = ref(""); |
| | | const getCurrentFactoryName = async () => { |
| | | let res = await userStore.getInfo(); |
| | |
| | | <el-descriptions-item label="éä»¶å表:"> |
| | | <el-button type="primary" |
| | | size="small" |
| | | @click="downLoadFile(endform)">éä»¶å表</el-button> |
| | | @click="openFileDialog(endform)">éä»¶å表</el-button> |
| | | </el-descriptions-item> |
| | | </el-descriptions> |
| | | <!-- <el-divider style="margin: 20px 0;" /> --> |
| | |
| | | </template> |
| | | </el-dialog> |
| | | <!-- todo éä»¶é¢è§ç¸å
³ --> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | :show-upload-button="true" |
| | | :show-delete-button="true" |
| | | :is-show-pagination="true" |
| | | :page="filePagination" |
| | | :upload-method="handleUpload" |
| | | :delete-method="handleFileDelete" |
| | | @pagination="paginationSearch" |
| | | title="éä»¶å表" /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="safe_training" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { Search } from "@element-plus/icons-vue"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import { |
| | | onMounted, |
| | | ref, |
| | |
| | | import useUserStore from "@/store/modules/user"; |
| | | import dayjs from "dayjs"; |
| | | const userStore = useUserStore(); |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | // 表åéªè¯è§å |
| | | const rules = { |
| | |
| | | name: "éä»¶", |
| | | type: "text", |
| | | clickFun: row => { |
| | | downLoadFile(row); |
| | | openFileDialog(row); |
| | | }, |
| | | color: "#007AFF", |
| | | }, |
| | |
| | | form.value.principalMobile = selectedUser.phonenumber; |
| | | } |
| | | }; |
| | | /** |
| | | * ä¸è½½æä»¶ |
| | | * |
| | | * @param row ä¸è½½æä»¶çç¸å
³ä¿¡æ¯å¯¹è±¡ |
| | | */ |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const currentFileRow = ref(null); |
| | | const downLoadFile = row => { |
| | | currentFileRow.value = row; |
| | | safeTrainingFileListPage({ |
| | | safeTrainingId: row.id, |
| | | current: filePagination.value.current, |
| | | size: filePagination.value.size, |
| | | }).then(res => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.data.records); |
| | | filePagination.value.total = res.data?.total || 0; |
| | | |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // ä¸ä¼ éä»¶ |
| | | const handleUpload = async () => { |
| | | if (!currentFileRow.value) { |
| | |
| | | <el-table-column fixed="right" label="æä½" width="150" align="center"> |
| | | <template #default="scope"> |
| | | <el-button link type="primary" @click="openForm(scope.row)">ç¼è¾</el-button> |
| | | <el-button link type="primary" @click="downLoadFile(scope.row)">éä»¶</el-button> |
| | | <el-button link type="primary" @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | <el-button link type="primary" @click="delInvoiceLedger(scope.row)">å é¤</el-button> |
| | | </template> |
| | | </el-table-column> |
| | |
| | | </div> |
| | | </template> |
| | | </el-dialog> |
| | | <FileListDialog ref="fileListRef" v-model="fileListDialogVisible" /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="invoice_registration_product" :record-id="recordId" /> |
| | | </div> |
| | | </template> |
| | | |
| | |
| | | import useUserStore from "@/store/modules/user.js"; |
| | | import useFormData from "@/hooks/useFormData"; |
| | | import dayjs from "dayjs"; |
| | | import FileListDialog from '@/components/Dialog/FileListDialog.vue'; |
| | | import { getCurrentDate } from "@/utils/index.js"; |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | const { proxy } = getCurrentInstance(); |
| | | const tableData = ref([]); |
| | |
| | | getList(); |
| | | }; |
| | | |
| | | //éä»¶ç¸å
³ |
| | | const fileListRef = ref(null) |
| | | const fileListDialogVisible = ref(false) |
| | | //æ¥çéä»¶ |
| | | const downLoadFile = (row) => { |
| | | invoiceLedgerProductInfo({ id: row.id }).then((res) => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.data.fileList) |
| | | fileListDialogVisible.value = true |
| | | } |
| | | }); |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | |
| | | onMounted(() => { |
| | |
| | | :disabled="!scope.row.isEdit || scope.row.hasProductionRecord || !canEditLedger(scope.row)">ç¼è¾</el-button> |
| | | <el-button link |
| | | type="primary" |
| | | @click="downLoadFile(scope.row)">éä»¶</el-button> |
| | | @click="openFileDialog(scope.row)">éä»¶</el-button> |
| | | </template> |
| | | </el-table-column> |
| | | </el-table> |
| | |
| | | </FormDialog> |
| | | <!-- // todo éä»¶é¢è§ç¸å
³ --> |
| | | <!-- éä»¶åè¡¨å¼¹çª --> |
| | | <FileListDialog ref="fileListRef" |
| | | v-model="fileListDialogVisible" |
| | | title="éä»¶å表" /> |
| | | <FileList v-if="fileDialogVisible" v-model:visible="fileDialogVisible" record-type="sales_ledger" :record-id="recordId" /> |
| | | <!-- æå°é¢è§å¼¹çª --> |
| | | <el-dialog v-model="printPreviewVisible" |
| | | title="æå°é¢è§" |
| | |
| | | import { onMounted, ref, getCurrentInstance } from "vue"; |
| | | import { addShippingInfo } from "@/api/salesManagement/deliveryLedger.js"; |
| | | import { ElMessageBox, ElMessage } from "element-plus"; |
| | | import { UploadFilled, Download } from "@element-plus/icons-vue"; |
| | | import useUserStore from "@/store/modules/user"; |
| | | import { userListNoPage } from "@/api/system/user.js"; |
| | | import FileListDialog from "@/components/Dialog/FileListDialog.vue"; |
| | | import FormDialog from "@/components/Dialog/FormDialog.vue"; |
| | | import { getQuotationList } from "@/api/salesManagement/salesQuotation.js"; |
| | | import { |
| | |
| | | import { useRouter, useRoute } from "vue-router"; |
| | | import { listCustomerPrivatePool } from "@/api/basicData/customerFile.js"; |
| | | import FileUpload from "@/components/AttachmentUpload/file/index.vue"; |
| | | |
| | | const FileList = defineAsyncComponent(() => import("@/components/Dialog/FileList.vue")); |
| | | |
| | | const router = useRouter(); |
| | | const route = useRoute(); |
| | | const userStore = useUserStore(); |
| | |
| | | return statusStr === "å¾
åè´§" || statusStr === "å®¡æ ¸æç»"; |
| | | }; |
| | | |
| | | /** |
| | | * ä¸è½½æä»¶ |
| | | * |
| | | * @param row ä¸è½½æä»¶çç¸å
³ä¿¡æ¯å¯¹è±¡ |
| | | */ |
| | | const fileListRef = ref(null); |
| | | const fileListDialogVisible = ref(false); |
| | | const downLoadFile = row => { |
| | | getSalesLedgerWithProducts({ id: row.id, type: 1 }).then(res => { |
| | | if (fileListRef.value) { |
| | | fileListRef.value.open(res.salesLedgerFiles); |
| | | // æå¼éä»¶å¼¹çª |
| | | const recordId =ref(0) |
| | | const fileDialogVisible = ref(false) |
| | | |
| | | // æå¼éä»¶å¼¹æ¡ |
| | | const openFileDialog = async (row) => { |
| | | recordId.value = row.id |
| | | fileDialogVisible.value = true |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // æå¼åè´§å¼¹æ¡ |
| | | const openDeliveryForm = row => { |