|  |  | 
 |  |  | # åéå¿
须以 VITE_ ä¸ºåç¼æè½æ´é²ç»å¤é¨è¯»å | 
 |  |  |  | 
 |  |  | # é¡¹ç®è¿è¡ç端å£å· | 
 |  |  | VITE_APP_PORT = 4096 | 
 |  |  |  | 
 |  |  | # API åºç¡è·¯å¾ï¼å¼åç¯å¢ä¸ç请æ±åç¼ | 
 |  |  | # VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes' | 
 |  |  | # VITE_APP_BASE_API = 'http://192.168.0.206:7002/mes' # é¹è£ | 
 |  |  | VITE_APP_BASE_API = 'http://192.168.0.244:8893/mes' #  | 
 |  |  |  | 
 |  |  | # API æå¡å¨ç URL | 
 |  |  | # VITE_APP_API_URL = 'http://114.132.189.42:7002/mes' | 
 |  |  | VITE_APP_API_URL = 'http://192.168.0.244:8893/mes' # | 
 |  |  | VITE_APP_PORT=3000 | 
 |  |  | VITE_APP_BASE_API=/api | 
 |  |  | VITE_APP_API_URL=http://192.168.10.170:7002/mes | 
 
 |  |  | 
 |  |  |  | 
 |  |  |  | 
 |  |  | # API åºç¡è·¯å¾ï¼å¼åç¯å¢ä¸ç请æ±åç¼ | 
 |  |  | # VITE_APP_BASE_API = 'http://114.132.189.42:7002/mes' | 
 |  |  | # API æå¡å¨ç URL | 
 |  |  | # VITE_APP_API_URL = 'http://114.132.189.42:7002/mes' | 
 |  |  | # å±±ä¸ | 
 |  |  | VITE_APP_API_URL = 'http://192.168.100.131:7002/mes' | 
 |  |  | VITE_APP_PORT=3000 | 
 |  |  | VITE_APP_BASE_API=/api | 
 |  |  | VITE_APP_API_URL=http://192.168.10.170:7002/mes | 
 
| ¶Ô±ÈÐÂÎļþ | 
 |  |  | 
 |  |  | import request from "@/utils/request"; | 
 |  |  | import { BaseResult } from "@/models/base"; | 
 |  |  | import { getToken } from "@/utils/cache"; | 
 |  |  | import { ResultCodeEnum } from "@/enums/ResultCodeEnum"; | 
 |  |  |  | 
 |  |  | // H5 ä½¿ç¨ VITE_APP_BASE_API ä½ä¸ºä»£çè·¯å¾ï¼å
¶ä»å¹³å°ä½¿ç¨ VITE_APP_API_URL ä½ä¸ºè¯·æ±è·¯å¾ | 
 |  |  | let baseApi = import.meta.env.VITE_APP_API_URL; | 
 |  |  | // #ifdef H5 | 
 |  |  | baseApi = import.meta.env.VITE_APP_BASE_API; | 
 |  |  | // #endif | 
 |  |  |  | 
 |  |  | const AttachmentAPI = { | 
 |  |  |   // ä¸ä¼ å个éä»¶æä»¶ | 
 |  |  |   uploadSingleFile(filePath: string) { | 
 |  |  |     return new Promise<BaseResult<any>>((resolve, reject) => { | 
 |  |  |       uni.uploadFile({ | 
 |  |  |         url: `${baseApi}/app/addAttachmentFiles`, | 
 |  |  |         filePath: filePath, | 
 |  |  |         name: "files", | 
 |  |  |         header: { | 
 |  |  |           Authorization: getToken() ? `Bearer ${getToken()}` : "", | 
 |  |  |         }, | 
 |  |  |         success: (uploadRes) => { | 
 |  |  |           try { | 
 |  |  |             const result = JSON.parse(uploadRes.data) as BaseResult<any>; | 
 |  |  |             // ä¸å¡ç¶æç  00000 è¡¨ç¤ºæå | 
 |  |  |             if (result.code === ResultCodeEnum.SUCCESS) { | 
 |  |  |               resolve(result); | 
 |  |  |             } else { | 
 |  |  |               // å
¶ä»ä¸å¡å¤ç失败 | 
 |  |  |               uni.showToast({ | 
 |  |  |                 title: result.msg || "æä»¶ä¸ä¼ å¤±è´¥", | 
 |  |  |                 icon: "none", | 
 |  |  |               }); | 
 |  |  |               reject({ | 
 |  |  |                 message: result.msg || "ä¸å¡å¤ç失败", | 
 |  |  |                 code: result.code, | 
 |  |  |               }); | 
 |  |  |             } | 
 |  |  |           } catch (e) { | 
 |  |  |             reject(e); | 
 |  |  |           } | 
 |  |  |         }, | 
 |  |  |         fail: (error) => { | 
 |  |  |           console.log("upload fail error", error); | 
 |  |  |           uni.showToast({ | 
 |  |  |             title: "æä»¶ä¸ä¼ è¯·æ±å¤±è´¥", | 
 |  |  |             icon: "none", | 
 |  |  |             duration: 2000, | 
 |  |  |           }); | 
 |  |  |           reject({ | 
 |  |  |             message: "æä»¶ä¸ä¼ è¯·æ±å¤±è´¥", | 
 |  |  |             error, | 
 |  |  |           }); | 
 |  |  |         }, | 
 |  |  |       }); | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // æ¹éä¸ä¼ éä»¶æä»¶ | 
 |  |  |   uploadAttachmentFiles(files: string[]) { | 
 |  |  |     return Promise.all(files.map((filePath) => AttachmentAPI.uploadSingleFile(filePath))); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // æ¥å·¥æ·»å éä»¶ | 
 |  |  |   addOutputAttachments(params: { id: number; attachmentIds: string }) { | 
 |  |  |     return request<BaseResult<any>>({ | 
 |  |  |       url: "/app/addOutputAttachments", | 
 |  |  |       method: "POST", | 
 |  |  |       data: params, | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // æ¥çéä»¶å表 | 
 |  |  |   listAttachmentFiles(attachmentIds: number[]) { | 
 |  |  |     return request<BaseResult<any[]>>({ | 
 |  |  |       url: "/app/listAttachmentFiles", | 
 |  |  |       method: "POST", | 
 |  |  |       data: attachmentIds, | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // å é¤éä»¶æä»¶ | 
 |  |  |   deleteAttachmentFile(attachmentId: number) { | 
 |  |  |     return request<BaseResult<any>>({ | 
 |  |  |       url: "/app/deleteAttachmentFile", | 
 |  |  |       method: "POST", | 
 |  |  |       data: { attachmentId }, | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | export default AttachmentAPI; | 
 
 |  |  | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // è·åæ¥å·¥è¯¦æ
ï¼å
å«éä»¶IDï¼ | 
 |  |  |   getReportDetail(params: { id: number }) { | 
 |  |  |     return request<BaseResult<any>>({ | 
 |  |  |       url: "/app/getReportDetail", | 
 |  |  |       method: "GET", | 
 |  |  |       data: params, | 
 |  |  |     }); | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  |   // æ¥è¯¢èªæ£ä¿¡æ¯ | 
 |  |  |   getSelfInspection(params: any) { | 
 |  |  |     return request<BaseResult<any>>({ | 
 
 |  |  | 
 |  |  |     "autoscan": true, | 
 |  |  |     "custom": { | 
 |  |  |       "^wd-(.*)": "wot-design-uni/components/wd-$1/wd-$1.vue", | 
 |  |  |       "^cu-(.*)": "@/components/cu-$1/index.vue", | 
 |  |  |       "^cu-(.*)": "@/components/cu-$1/index.vue" | 
 |  |  |     } | 
 |  |  |   }, | 
 |  |  |  | 
 |  |  | 
 |  |  |         "navigationBarTitleText": "æä¸è¯¦æ
" | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |      { | 
 |  |  |     { | 
 |  |  |       "path": "pages/production/detail/twistDetail", | 
 |  |  |       "style": { | 
 |  |  |         "navigationBarTitleText": "ç»çº¿è¯¦æ
" | 
 |  |  | 
 |  |  |       "path": "pages/production/wire/report/wire", | 
 |  |  |       "style": { | 
 |  |  |         "navigationBarTitleText": "æä¸æ¥å·¥" | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     { | 
 |  |  |       "path": "pages/production/wire/attachment/index", | 
 |  |  |       "style": { | 
 |  |  |         "navigationBarTitleText": "æä¸éä»¶" | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     { | 
 |  |  | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     { | 
 |  |  |       "path": "pages/production/twist/attachment/index", | 
 |  |  |       "style": { | 
 |  |  |         "navigationBarTitleText": "ç»çº¿éä»¶" | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     { | 
 |  |  |       "path": "pages/production/twist/report/edit", | 
 |  |  |       "style": { | 
 |  |  |         "navigationBarTitleText": "ç»çº¿æ¥å·¥ä¸æ¥" | 
 
| ¶Ô±ÈÐÂÎļþ | 
 |  |  | 
 |  |  | <template> | 
 |  |  |   <view class="attachment-container"> | 
 |  |  |     <!-- å¤´é¨æä½åº --> | 
 |  |  |     <view class="header-actions"> | 
 |  |  |       <wd-button | 
 |  |  |         icon="file-add" | 
 |  |  |         :round="false" | 
 |  |  |         size="small" | 
 |  |  |         custom-class="add_btn" | 
 |  |  |         @click="addAttachment" | 
 |  |  |       > | 
 |  |  |         æ°å¢ | 
 |  |  |       </wd-button> | 
 |  |  |     </view> | 
 |  |  |  | 
 |  |  |     <!-- éä»¶å表 --> | 
 |  |  |     <view class="attachment-list"> | 
 |  |  |       <wd-status-tip v-if="attachmentList.length === 0" image="content" tip="ææ éä»¶" /> | 
 |  |  |  | 
 |  |  |       <wd-card | 
 |  |  |         v-for="item in attachmentList" | 
 |  |  |         :key="item.id" | 
 |  |  |         type="rectangle" | 
 |  |  |         custom-class="attachment-card" | 
 |  |  |         :border="false" | 
 |  |  |       > | 
 |  |  |         <view class="attachment-item" @click="previewAttachment(item)"> | 
 |  |  |           <view class="attachment-info"> | 
 |  |  |             <view class="attachment-name">{{ item.bucketFileName || item.name }}</view> | 
 |  |  |             <view class="attachment-meta"> | 
 |  |  |               <text class="file-type">{{ getFileType(item.bucketFileName) }}</text> | 
 |  |  |               <text class="upload-time">{{ formatTime(item.createTime) }}</text> | 
 |  |  |             </view> | 
 |  |  |           </view> | 
 |  |  |           <view class="attachment-actions"> | 
 |  |  |             <wd-icon name="delete" color="#ff4757" @click.stop="deleteAttachment(item.id)" /> | 
 |  |  |           </view> | 
 |  |  |         </view> | 
 |  |  |       </wd-card> | 
 |  |  |     </view> | 
 |  |  |  | 
 |  |  |     <wd-toast /> | 
 |  |  |   </view> | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | <script setup lang="ts"> | 
 |  |  | import { ref, onMounted } from "vue"; | 
 |  |  | import { useToast } from "wot-design-uni"; | 
 |  |  | import AttachmentAPI from "@/api/product/attachment"; | 
 |  |  |  | 
 |  |  | const toast = useToast(); | 
 |  |  |  | 
 |  |  | // é¡µé¢åæ° | 
 |  |  | const reportId = ref(""); | 
 |  |  | const reportType = ref("ç»çº¿"); | 
 |  |  | const attachmentList = ref<any[]>([]); | 
 |  |  |  | 
 |  |  | // è·åéä»¶å表 | 
 |  |  | const getAttachmentList = async () => { | 
 |  |  |   try { | 
 |  |  |     const pages = getCurrentPages(); | 
 |  |  |     const currentPage = pages[pages.length - 1]; | 
 |  |  |     const options = (currentPage as any).options; | 
 |  |  |     const currentReportId = options?.reportId; | 
 |  |  |  | 
 |  |  |     if (currentReportId) { | 
 |  |  |       reportId.value = currentReportId; | 
 |  |  |  | 
 |  |  |       // ç´æ¥è°ç¨éç¨æ¥çæ¥å£æ¥è¯¢éä»¶å表 | 
 |  |  |       // ä½¿ç¨ç¤ºä¾ä¸çéä»¶IDæ°ç» [850,851] | 
 |  |  |       const attachmentIds: number[] = [850, 851]; // ä½¿ç¨HTTPæä»¶ä¸çç¤ºä¾æ°æ® | 
 |  |  |  | 
 |  |  |       const { data } = await AttachmentAPI.listAttachmentFiles(attachmentIds); | 
 |  |  |       attachmentList.value = data || []; | 
 |  |  |     } else { | 
 |  |  |       attachmentList.value = []; | 
 |  |  |     } | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error("è·åéä»¶å表失败:", error); | 
 |  |  |     toast.show("è·åéä»¶å表失败"); | 
 |  |  |     attachmentList.value = []; | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ°å¢éä»¶ | 
 |  |  | const addAttachment = () => { | 
 |  |  |   uni.chooseFile({ | 
 |  |  |     count: 9, // æå¤éæ©9个æä»¶ | 
 |  |  |     type: "all", // ææç±»åæä»¶ | 
 |  |  |     success: async (res) => { | 
 |  |  |       try { | 
 |  |  |         toast.show("æ£å¨ä¸ä¼ ..."); | 
 |  |  |  | 
 |  |  |         // ä¸ä¼ æä»¶ | 
 |  |  |         const filePaths = Array.isArray(res.tempFilePaths) | 
 |  |  |           ? res.tempFilePaths | 
 |  |  |           : [res.tempFilePaths]; | 
 |  |  |         const uploadResults = await AttachmentAPI.uploadAttachmentFiles(filePaths); | 
 |  |  |  | 
 |  |  |         // æåéä»¶ID | 
 |  |  |         const attachmentIds = uploadResults.map((result) => result.data.id).join(","); | 
 |  |  |  | 
 |  |  |         // å
³èå°æ¥å·¥ | 
 |  |  |         await AttachmentAPI.addOutputAttachments({ | 
 |  |  |           id: parseInt(reportId.value), | 
 |  |  |           attachmentIds: attachmentIds, | 
 |  |  |         }); | 
 |  |  |  | 
 |  |  |         toast.show("ä¸ä¼ æå"); | 
 |  |  |         // éæ°è·åéä»¶å表 | 
 |  |  |         await getAttachmentList(); | 
 |  |  |       } catch (error) { | 
 |  |  |         console.error("ä¸ä¼ å¤±è´¥:", error); | 
 |  |  |         toast.show("ä¸ä¼ å¤±è´¥"); | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     fail: (error) => { | 
 |  |  |       console.error("éæ©æä»¶å¤±è´¥:", error); | 
 |  |  |       toast.show("éæ©æä»¶å¤±è´¥"); | 
 |  |  |     }, | 
 |  |  |   }); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // å é¤éä»¶ | 
 |  |  | const deleteAttachment = async (attachmentId: number) => { | 
 |  |  |   try { | 
 |  |  |     uni.showModal({ | 
 |  |  |       title: "确认å é¤", | 
 |  |  |       content: "ç¡®å®è¦å é¤è¿ä¸ªéä»¶åï¼", | 
 |  |  |       success: async (res) => { | 
 |  |  |         if (res.confirm) { | 
 |  |  |           // å端æå¨å é¤ï¼ç´æ¥ä»å表ä¸ç§»é¤è¿æ¡æ°æ® | 
 |  |  |           attachmentList.value = attachmentList.value.filter((item) => item.id !== attachmentId); | 
 |  |  |  | 
 |  |  |           // è·åå©ä½çéä»¶IDç»å | 
 |  |  |           const remainingIds = attachmentList.value.map((item) => item.id); | 
 |  |  |           const attachmentIds = remainingIds.join(","); | 
 |  |  |  | 
 |  |  |           // è°ç¨æ¥å·¥æ·»å éä»¶æ¥å£ï¼æ´æ°éä»¶å
³è | 
 |  |  |           await AttachmentAPI.addOutputAttachments({ | 
 |  |  |             id: parseInt(reportId.value), | 
 |  |  |             attachmentIds: attachmentIds, | 
 |  |  |           }); | 
 |  |  |  | 
 |  |  |           toast.show("å é¤æå"); | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |     }); | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error("å é¤å¤±è´¥:", error); | 
 |  |  |     toast.show("å é¤å¤±è´¥"); | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // é¢è§éä»¶ | 
 |  |  | const previewAttachment = (item: any) => { | 
 |  |  |   // æ ¹æ®æä»¶ç±»åè¿è¡é¢è§ | 
 |  |  |   const fileName = item.bucketFileName || item.name; | 
 |  |  |   const fileType = getFileType(fileName); | 
 |  |  |  | 
 |  |  |   if (fileType.startsWith("image")) { | 
 |  |  |     // å¾çé¢è§ | 
 |  |  |     uni.previewImage({ | 
 |  |  |       urls: [item.url], | 
 |  |  |       current: item.url, | 
 |  |  |     }); | 
 |  |  |   } else { | 
 |  |  |     // å
¶ä»æä»¶ç±»åï¼å¯ä»¥ä¸è½½ææå¼ | 
 |  |  |     uni.downloadFile({ | 
 |  |  |       url: item.url, | 
 |  |  |       success: (res) => { | 
 |  |  |         uni.openDocument({ | 
 |  |  |           filePath: res.tempFilePath, | 
 |  |  |           success: () => { | 
 |  |  |             console.log("æå¼ææ¡£æå"); | 
 |  |  |           }, | 
 |  |  |           fail: (error) => { | 
 |  |  |             console.error("æå¼ææ¡£å¤±è´¥:", error); | 
 |  |  |             toast.show("æ æ³é¢è§æ¤æä»¶ç±»å"); | 
 |  |  |           }, | 
 |  |  |         }); | 
 |  |  |       }, | 
 |  |  |       fail: (error) => { | 
 |  |  |         console.error("ä¸è½½æä»¶å¤±è´¥:", error); | 
 |  |  |         toast.show("ä¸è½½æä»¶å¤±è´¥"); | 
 |  |  |       }, | 
 |  |  |     }); | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // è·åæä»¶ç±»å | 
 |  |  | const getFileType = (fileName: string) => { | 
 |  |  |   if (!fileName) return "unknown"; | 
 |  |  |   const extension = fileName.split(".").pop()?.toLowerCase(); | 
 |  |  |   switch (extension) { | 
 |  |  |     case "jpg": | 
 |  |  |     case "jpeg": | 
 |  |  |     case "png": | 
 |  |  |     case "gif": | 
 |  |  |     case "bmp": | 
 |  |  |     case "webp": | 
 |  |  |       return "image"; | 
 |  |  |     case "pdf": | 
 |  |  |       return "pdf"; | 
 |  |  |     case "doc": | 
 |  |  |     case "docx": | 
 |  |  |       return "word"; | 
 |  |  |     case "xls": | 
 |  |  |     case "xlsx": | 
 |  |  |       return "excel"; | 
 |  |  |     case "ppt": | 
 |  |  |     case "pptx": | 
 |  |  |       return "powerpoint"; | 
 |  |  |     case "txt": | 
 |  |  |       return "text"; | 
 |  |  |     case "zip": | 
 |  |  |     case "rar": | 
 |  |  |       return "archive"; | 
 |  |  |     default: | 
 |  |  |       return "file"; | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ ¼å¼åæä»¶å¤§å° | 
 |  |  | const formatFileSize = (size: number) => { | 
 |  |  |   if (size < 1024) return size + " B"; | 
 |  |  |   if (size < 1024 * 1024) return (size / 1024).toFixed(1) + " KB"; | 
 |  |  |   return (size / (1024 * 1024)).toFixed(1) + " MB"; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ ¼å¼åæ¶é´ | 
 |  |  | const formatTime = (time: string) => { | 
 |  |  |   const date = new Date(time); | 
 |  |  |   return date.toLocaleString(); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | onMounted(() => { | 
 |  |  |   getAttachmentList(); | 
 |  |  | }); | 
 |  |  | </script> | 
 |  |  |  | 
 |  |  | <style lang="scss" scoped> | 
 |  |  | .attachment-container { | 
 |  |  |   padding: 12px; | 
 |  |  |   background: #f3f9f8; | 
 |  |  |   min-height: 100vh; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .header-actions { | 
 |  |  |   margin-bottom: 12px; | 
 |  |  |  | 
 |  |  |   :deep(.add_btn) { | 
 |  |  |     background: #0d867f; | 
 |  |  |     color: white; | 
 |  |  |     border: none; | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .attachment-list { | 
 |  |  |   .attachment-card { | 
 |  |  |     margin-bottom: 12px; | 
 |  |  |     border-radius: 4px; | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .attachment-item { | 
 |  |  |   display: flex; | 
 |  |  |   align-items: center; | 
 |  |  |   padding: 12px; | 
 |  |  |  | 
 |  |  |   .attachment-info { | 
 |  |  |     flex: 1; | 
 |  |  |  | 
 |  |  |     .attachment-name { | 
 |  |  |       font-size: 16px; | 
 |  |  |       font-weight: 500; | 
 |  |  |       color: #333; | 
 |  |  |       margin-bottom: 4px; | 
 |  |  |       word-break: break-all; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     .attachment-meta { | 
 |  |  |       display: flex; | 
 |  |  |       gap: 12px; | 
 |  |  |       font-size: 12px; | 
 |  |  |       color: #999; | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   .attachment-actions { | 
 |  |  |     margin-left: 12px; | 
 |  |  |  | 
 |  |  |     :deep(.wd-icon) { | 
 |  |  |       font-size: 20px; | 
 |  |  |       cursor: pointer; | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  | } | 
 |  |  | </style> | 
 
 |  |  | 
 |  |  |       <template #top> | 
 |  |  |         <CardTitle title="æ¥å·¥ä¿¡æ¯" :hideAction="true" :full="false" @action="addReport" /> | 
 |  |  |       </template> | 
 |  |  |       <wd-card v-for="(item, index) in twistReportList" type="rectangle" custom-class="round"> | 
 |  |  |       <wd-card v-for="item in twistReportList" :key="item.id" type="rectangle" custom-class="round"> | 
 |  |  |         <template #title> | 
 |  |  |           <view class="flex justify-between"> | 
 |  |  |             <view> | 
 |  |  | 
 |  |  |         </template> | 
 |  |  |         <ProductionCard :data="cardAttr" :value="item" /> | 
 |  |  |         <template #footer> | 
 |  |  |           <wd-button size="small" plain @click="toAttachment(item.id)" style="margin-right: 10px"> | 
 |  |  |             éä»¶ | 
 |  |  |           </wd-button> | 
 |  |  |           <wd-button size="small" plain @click="toCheck(item.id)">èªæ£</wd-button> | 
 |  |  |         </template> | 
 |  |  |       </wd-card> | 
 |  |  | 
 |  |  |   dialog.visible = false; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const toAttachment = (id: number) => { | 
 |  |  |   uni.navigateTo({ | 
 |  |  |     url: `/pages/production/twist/attachment/index?reportId=${id}`, | 
 |  |  |   }); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const toCheck = (id: number) => { | 
 |  |  |   uni.navigateTo({ | 
 |  |  |     url: `/pages/production/twist/selfInspect/index?id=${id}`, | 
 
| ¶Ô±ÈÐÂÎļþ | 
 |  |  | 
 |  |  | <template> | 
 |  |  |   <view class="attachment-container"> | 
 |  |  |     <!-- å¤´é¨æä½åº --> | 
 |  |  |     <view class="header-actions"> | 
 |  |  |       <wd-button | 
 |  |  |         icon="file-add" | 
 |  |  |         :round="false" | 
 |  |  |         size="small" | 
 |  |  |         custom-class="add_btn" | 
 |  |  |         @click="addAttachment" | 
 |  |  |       > | 
 |  |  |         æ°å¢ | 
 |  |  |       </wd-button> | 
 |  |  |     </view> | 
 |  |  |  | 
 |  |  |     <!-- éä»¶å表 --> | 
 |  |  |     <view class="attachment-list"> | 
 |  |  |       <wd-status-tip v-if="attachmentList.length === 0" image="content" tip="ææ éä»¶" /> | 
 |  |  |  | 
 |  |  |       <wd-card | 
 |  |  |         v-for="item in attachmentList" | 
 |  |  |         :key="item.id" | 
 |  |  |         type="rectangle" | 
 |  |  |         custom-class="attachment-card" | 
 |  |  |         :border="false" | 
 |  |  |       > | 
 |  |  |         <view class="attachment-item" @click="previewAttachment(item)"> | 
 |  |  |           <view class="attachment-info"> | 
 |  |  |             <view class="attachment-name">{{ item.bucketFileName || item.name }}</view> | 
 |  |  |             <view class="attachment-meta"> | 
 |  |  |               <text class="file-type">{{ getFileType(item.bucketFileName) }}</text> | 
 |  |  |               <text class="upload-time">{{ formatTime(item.createTime) }}</text> | 
 |  |  |             </view> | 
 |  |  |           </view> | 
 |  |  |           <view class="attachment-actions"> | 
 |  |  |             <wd-icon name="delete" color="#ff4757" @click.stop="deleteAttachment(item.id)" /> | 
 |  |  |           </view> | 
 |  |  |         </view> | 
 |  |  |       </wd-card> | 
 |  |  |     </view> | 
 |  |  |  | 
 |  |  |     <wd-toast /> | 
 |  |  |   </view> | 
 |  |  | </template> | 
 |  |  |  | 
 |  |  | <script setup lang="ts"> | 
 |  |  | import { ref, onMounted } from "vue"; | 
 |  |  | import { useToast } from "wot-design-uni"; | 
 |  |  | import AttachmentAPI from "@/api/product/attachment"; | 
 |  |  |  | 
 |  |  | const toast = useToast(); | 
 |  |  |  | 
 |  |  | // é¡µé¢åæ° | 
 |  |  | const reportId = ref(""); | 
 |  |  | const reportType = ref("æä¸"); | 
 |  |  | const attachmentList = ref<any[]>([]); | 
 |  |  |  | 
 |  |  | // è·åéä»¶å表 | 
 |  |  | const getAttachmentList = async () => { | 
 |  |  |   try { | 
 |  |  |     const pages = getCurrentPages(); | 
 |  |  |     const currentPage = pages[pages.length - 1]; | 
 |  |  |     const options = (currentPage as any).options; | 
 |  |  |     const currentReportId = options?.reportId; | 
 |  |  |  | 
 |  |  |     if (currentReportId) { | 
 |  |  |       reportId.value = currentReportId; | 
 |  |  |  | 
 |  |  |       // ç´æ¥è°ç¨éç¨æ¥çæ¥å£æ¥è¯¢éä»¶å表 | 
 |  |  |       // ä½¿ç¨ç¤ºä¾ä¸çéä»¶IDæ°ç» [850,851] | 
 |  |  |       const attachmentIds: number[] = [850, 851]; // ä½¿ç¨HTTPæä»¶ä¸çç¤ºä¾æ°æ® | 
 |  |  |  | 
 |  |  |       const { data } = await AttachmentAPI.listAttachmentFiles(attachmentIds); | 
 |  |  |       attachmentList.value = data || []; | 
 |  |  |     } else { | 
 |  |  |       attachmentList.value = []; | 
 |  |  |     } | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error("è·åéä»¶å表失败:", error); | 
 |  |  |     toast.show("è·åéä»¶å表失败"); | 
 |  |  |     attachmentList.value = []; | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ°å¢éä»¶ | 
 |  |  | const addAttachment = () => { | 
 |  |  |   uni.chooseFile({ | 
 |  |  |     count: 9, // æå¤éæ©9个æä»¶ | 
 |  |  |     type: "all", // ææç±»åæä»¶ | 
 |  |  |     success: async (res) => { | 
 |  |  |       try { | 
 |  |  |         toast.show("æ£å¨ä¸ä¼ ..."); | 
 |  |  |  | 
 |  |  |         // ä¸ä¼ æä»¶ | 
 |  |  |         const filePaths = Array.isArray(res.tempFilePaths) | 
 |  |  |           ? res.tempFilePaths | 
 |  |  |           : [res.tempFilePaths]; | 
 |  |  |         const uploadResults = await AttachmentAPI.uploadAttachmentFiles(filePaths); | 
 |  |  |  | 
 |  |  |         // æåéä»¶ID | 
 |  |  |         const attachmentIds = uploadResults.map((result) => result.data.id).join(","); | 
 |  |  |  | 
 |  |  |         // å
³èå°æ¥å·¥ | 
 |  |  |         await AttachmentAPI.addOutputAttachments({ | 
 |  |  |           id: parseInt(reportId.value), | 
 |  |  |           attachmentIds: attachmentIds, | 
 |  |  |         }); | 
 |  |  |  | 
 |  |  |         toast.show("ä¸ä¼ æå"); | 
 |  |  |         // éæ°è·åéä»¶å表 | 
 |  |  |         await getAttachmentList(); | 
 |  |  |       } catch (error) { | 
 |  |  |         console.error("ä¸ä¼ å¤±è´¥:", error); | 
 |  |  |         toast.show("ä¸ä¼ å¤±è´¥"); | 
 |  |  |       } | 
 |  |  |     }, | 
 |  |  |     fail: (error) => { | 
 |  |  |       console.error("éæ©æä»¶å¤±è´¥:", error); | 
 |  |  |       toast.show("éæ©æä»¶å¤±è´¥"); | 
 |  |  |     }, | 
 |  |  |   }); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // å é¤éä»¶ | 
 |  |  | const deleteAttachment = async (attachmentId: number) => { | 
 |  |  |   try { | 
 |  |  |     uni.showModal({ | 
 |  |  |       title: "确认å é¤", | 
 |  |  |       content: "ç¡®å®è¦å é¤è¿ä¸ªéä»¶åï¼", | 
 |  |  |       success: async (res) => { | 
 |  |  |         if (res.confirm) { | 
 |  |  |           // å端æå¨å é¤ï¼ç´æ¥ä»å表ä¸ç§»é¤è¿æ¡æ°æ® | 
 |  |  |           attachmentList.value = attachmentList.value.filter((item) => item.id !== attachmentId); | 
 |  |  |  | 
 |  |  |           // è·åå©ä½çéä»¶IDç»å | 
 |  |  |           const remainingIds = attachmentList.value.map((item) => item.id); | 
 |  |  |           const attachmentIds = remainingIds.join(","); | 
 |  |  |  | 
 |  |  |           // è°ç¨æ¥å·¥æ·»å éä»¶æ¥å£ï¼æ´æ°éä»¶å
³è | 
 |  |  |           await AttachmentAPI.addOutputAttachments({ | 
 |  |  |             id: parseInt(reportId.value), | 
 |  |  |             attachmentIds: attachmentIds, | 
 |  |  |           }); | 
 |  |  |  | 
 |  |  |           toast.show("å é¤æå"); | 
 |  |  |         } | 
 |  |  |       }, | 
 |  |  |     }); | 
 |  |  |   } catch (error) { | 
 |  |  |     console.error("å é¤å¤±è´¥:", error); | 
 |  |  |     toast.show("å é¤å¤±è´¥"); | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // é¢è§éä»¶ | 
 |  |  | const previewAttachment = (item: any) => { | 
 |  |  |   // æ ¹æ®æä»¶ç±»åè¿è¡é¢è§ | 
 |  |  |   const fileName = item.bucketFileName || item.name; | 
 |  |  |   const fileType = getFileType(fileName); | 
 |  |  |  | 
 |  |  |   if (fileType.startsWith("image")) { | 
 |  |  |     // å¾çé¢è§ | 
 |  |  |     uni.previewImage({ | 
 |  |  |       urls: [item.url], | 
 |  |  |       current: item.url, | 
 |  |  |     }); | 
 |  |  |   } else { | 
 |  |  |     // å
¶ä»æä»¶ç±»åï¼å¯ä»¥ä¸è½½ææå¼ | 
 |  |  |     uni.downloadFile({ | 
 |  |  |       url: item.url, | 
 |  |  |       success: (res) => { | 
 |  |  |         uni.openDocument({ | 
 |  |  |           filePath: res.tempFilePath, | 
 |  |  |           success: () => { | 
 |  |  |             console.log("æå¼ææ¡£æå"); | 
 |  |  |           }, | 
 |  |  |           fail: (error) => { | 
 |  |  |             console.error("æå¼ææ¡£å¤±è´¥:", error); | 
 |  |  |             toast.show("æ æ³é¢è§æ¤æä»¶ç±»å"); | 
 |  |  |           }, | 
 |  |  |         }); | 
 |  |  |       }, | 
 |  |  |       fail: (error) => { | 
 |  |  |         console.error("ä¸è½½æä»¶å¤±è´¥:", error); | 
 |  |  |         toast.show("ä¸è½½æä»¶å¤±è´¥"); | 
 |  |  |       }, | 
 |  |  |     }); | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // è·åæä»¶ç±»å | 
 |  |  | const getFileType = (fileName: string) => { | 
 |  |  |   if (!fileName) return "unknown"; | 
 |  |  |   const extension = fileName.split(".").pop()?.toLowerCase(); | 
 |  |  |   switch (extension) { | 
 |  |  |     case "jpg": | 
 |  |  |     case "jpeg": | 
 |  |  |     case "png": | 
 |  |  |     case "gif": | 
 |  |  |     case "bmp": | 
 |  |  |     case "webp": | 
 |  |  |       return "image"; | 
 |  |  |     case "pdf": | 
 |  |  |       return "pdf"; | 
 |  |  |     case "doc": | 
 |  |  |     case "docx": | 
 |  |  |       return "word"; | 
 |  |  |     case "xls": | 
 |  |  |     case "xlsx": | 
 |  |  |       return "excel"; | 
 |  |  |     case "ppt": | 
 |  |  |     case "pptx": | 
 |  |  |       return "powerpoint"; | 
 |  |  |     case "txt": | 
 |  |  |       return "text"; | 
 |  |  |     case "zip": | 
 |  |  |     case "rar": | 
 |  |  |       return "archive"; | 
 |  |  |     default: | 
 |  |  |       return "file"; | 
 |  |  |   } | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ ¼å¼åæä»¶å¤§å° | 
 |  |  | const formatFileSize = (size: number) => { | 
 |  |  |   if (size < 1024) return size + " B"; | 
 |  |  |   if (size < 1024 * 1024) return (size / 1024).toFixed(1) + " KB"; | 
 |  |  |   return (size / (1024 * 1024)).toFixed(1) + " MB"; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | // æ ¼å¼åæ¶é´ | 
 |  |  | const formatTime = (time: string) => { | 
 |  |  |   const date = new Date(time); | 
 |  |  |   return date.toLocaleString(); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | onMounted(() => { | 
 |  |  |   getAttachmentList(); | 
 |  |  | }); | 
 |  |  | </script> | 
 |  |  |  | 
 |  |  | <style lang="scss" scoped> | 
 |  |  | .attachment-container { | 
 |  |  |   padding: 12px; | 
 |  |  |   background: #f3f9f8; | 
 |  |  |   min-height: 100vh; | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .header-actions { | 
 |  |  |   margin-bottom: 12px; | 
 |  |  |  | 
 |  |  |   :deep(.add_btn) { | 
 |  |  |     background: #0d867f; | 
 |  |  |     color: white; | 
 |  |  |     border: none; | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .attachment-list { | 
 |  |  |   .attachment-card { | 
 |  |  |     margin-bottom: 12px; | 
 |  |  |     border-radius: 4px; | 
 |  |  |   } | 
 |  |  | } | 
 |  |  |  | 
 |  |  | .attachment-item { | 
 |  |  |   display: flex; | 
 |  |  |   align-items: center; | 
 |  |  |   padding: 12px; | 
 |  |  |  | 
 |  |  |   .attachment-info { | 
 |  |  |     flex: 1; | 
 |  |  |  | 
 |  |  |     .attachment-name { | 
 |  |  |       font-size: 16px; | 
 |  |  |       font-weight: 500; | 
 |  |  |       color: #333; | 
 |  |  |       margin-bottom: 4px; | 
 |  |  |       word-break: break-all; | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     .attachment-meta { | 
 |  |  |       display: flex; | 
 |  |  |       gap: 12px; | 
 |  |  |       font-size: 12px; | 
 |  |  |       color: #999; | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  |  | 
 |  |  |   .attachment-actions { | 
 |  |  |     margin-left: 12px; | 
 |  |  |  | 
 |  |  |     :deep(.wd-icon) { | 
 |  |  |       font-size: 20px; | 
 |  |  |       cursor: pointer; | 
 |  |  |     } | 
 |  |  |   } | 
 |  |  | } | 
 |  |  | </style> | 
 
 |  |  | 
 |  |  |         </template> | 
 |  |  |         <ProductionCard :data="cardAttr" :value="item" /> | 
 |  |  |         <template #footer> | 
 |  |  |           <wd-button size="small" plain @click="toAttachment(item.id)" style="margin-right: 10px"> | 
 |  |  |             éä»¶ | 
 |  |  |           </wd-button> | 
 |  |  |           <wd-button size="small" plain @click="toCheck(item.id)">èªæ£</wd-button> | 
 |  |  |         </template> | 
 |  |  |       </wd-card> | 
 |  |  | 
 |  |  |   dialog.visible = false; | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const toAttachment = (id: number) => { | 
 |  |  |   uni.navigateTo({ | 
 |  |  |     url: `/pages/production/wire/attachment/index?reportId=${id}`, | 
 |  |  |   }); | 
 |  |  | }; | 
 |  |  |  | 
 |  |  | const toCheck = (id: number) => { | 
 |  |  |   uni.navigateTo({ | 
 |  |  |     url: `/pages/production/wire/selfInspect/index?id=${id}`, |