ZN
3 小时以前 aaf2e90e8f2967dde6f3bd5351523234881e2c98
Merge remote-tracking branch 'origin/dev_KTHG' into dev_KTHG
已添加3个文件
已修改14个文件
2734 ■■■■■ 文件已修改
README.md 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/favicon/KTHGico.ico 补丁 | 查看 | 原始文档 | blame | 历史
multiple/assets/logo/KTHGLogo.png 补丁 | 查看 | 原始文档 | blame | 历史
multiple/config.json 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/equipmentManagement/spareParts.js 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basicData/product/ProductSelectDialog.vue 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/formDia.vue 573 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue 462 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/inspectionManagement/index.vue 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/repair/Modal/MaintainModal.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/spareParts/index.vue 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/DetailDialog.vue 219 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/equipmentManagement/upkeep/index.vue 1177 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/receiptManagement/Record.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/New.vue 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/inventoryManagement/stockManagement/Qualified.vue 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
README.md
@@ -11,10 +11,10 @@
## å¹³å°ç®€ä»‹
* æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
* é…å¥—后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) æˆ– [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) ç‰ˆæœ¬ã€‚
* å‰ç«¯æŠ€æœ¯æ ˆï¼ˆ[Vue2](https://cn.vuejs.org) + [Element](https://github.com/ElemeFE/element) + [Vue CLI](https://cli.vuejs.org/zh)),请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui)。
* é˜¿é‡Œäº‘折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)  
- æœ¬ä»“库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) ç‰ˆæœ¬ã€‚
- é…å¥—后端代码仓库地址[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue) æˆ– [RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast) ç‰ˆæœ¬ã€‚
- å‰ç«¯æŠ€æœ¯æ ˆï¼ˆ[Vue2](https://cn.vuejs.org) + [Element](https://github.com/ElemeFE/element) + [Vue CLI](https://cli.vuejs.org/zh)),请移步[RuoYi-Vue](https://gitee.com/y_project/RuoYi-Vue/tree/master/ruoyi-ui)。
- é˜¿é‡Œäº‘折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)  
## å‰ç«¯è¿è¡Œ
@@ -33,7 +33,7 @@
# æž„建测试环境 yarn build:stage
# æž„建生产环境 yarn build:prod
# æž„建生产环境 yarn build:prod -- --company="AAA"
# æž„建生产环境 yarn build:prod -- --company="KTHG"
# å‰ç«¯è®¿é—®åœ°å€ http://localhost:80
```
@@ -51,16 +51,16 @@
10. ç™»å½•日志:系统登录日志记录查询包含登录异常。
11. åœ¨çº¿ç”¨æˆ·ï¼šå½“前系统中活跃用户状态监控。
12. å®šæ—¶ä»»åŠ¡ï¼šåœ¨çº¿ï¼ˆæ·»åŠ ã€ä¿®æ”¹ã€åˆ é™¤)任务调度包含执行结果日志。
13. ä»£ç ç”Ÿæˆï¼šå‰åŽç«¯ä»£ç çš„生成(java、html、xml、sql)支持CRUD下载 ã€‚
14. ç³»ç»ŸæŽ¥å£ï¼šæ ¹æ®ä¸šåŠ¡ä»£ç è‡ªåŠ¨ç”Ÿæˆç›¸å…³çš„api接口文档。
15. æœåŠ¡ç›‘æŽ§ï¼šç›‘è§†å½“å‰ç³»ç»ŸCPU、内存、磁盘、堆栈等相关信息。
13. ä»£ç ç”Ÿæˆï¼šå‰åŽç«¯ä»£ç çš„生成(java、html、xml、sql)支持 CRUD ä¸‹è½½ ã€‚
14. ç³»ç»ŸæŽ¥å£ï¼šæ ¹æ®ä¸šåŠ¡ä»£ç è‡ªåŠ¨ç”Ÿæˆç›¸å…³çš„ api æŽ¥å£æ–‡æ¡£ã€‚
15. æœåŠ¡ç›‘æŽ§ï¼šç›‘è§†å½“å‰ç³»ç»Ÿ CPU、内存、磁盘、堆栈等相关信息。
16. ç¼“存监控:对系统的缓存信息查询,命令统计等。
17. åœ¨çº¿æž„建器:拖动表单元素生成相应的HTML代码。
18. è¿žæŽ¥æ± ç›‘视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
17. åœ¨çº¿æž„建器:拖动表单元素生成相应的 HTML ä»£ç ã€‚
18. è¿žæŽ¥æ± ç›‘视:监视当前系统数据库连接池状态,可进行分析 SQL æ‰¾å‡ºç³»ç»Ÿæ€§èƒ½ç“¶é¢ˆã€‚
## åœ¨çº¿ä½“验
- admin/admin123
- admin/admin123
- é™†é™†ç»­ç»­æ”¶åˆ°ä¸€äº›æ‰“赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
演示地址:http://vue.ruoyi.vip  
@@ -103,7 +103,6 @@
    </tr>
</table>
## è‹¥ä¾å‰åŽç«¯åˆ†ç¦»äº¤æµç¾¤
QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/已满-151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [![加入QQ群](https://img.shields.io/badge/已满-224622315-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [![加入QQ群](https://img.shields.io/badge/已满-287842588-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [![加入QQ群](https://img.shields.io/badge/已满-187944233-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [![加入QQ群](https://img.shields.io/badge/228578329-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) ç‚¹å‡»æŒ‰é’®å…¥ç¾¤ã€‚
QQ ç¾¤ï¼š [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/已满-151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [![加入QQ群](https://img.shields.io/badge/已满-224622315-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [![加入QQ群](https://img.shields.io/badge/已满-287842588-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [![加入QQ群](https://img.shields.io/badge/已满-187944233-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) [![加入QQ群](https://img.shields.io/badge/228578329-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=G6r5KGCaa3pqdbUSXNIgYloyb8e0_L0D&authKey=4w8tF1eGW7%2FedWn%2FHAypQksdrML%2BDHolQSx7094Agm7Luakj9EbfPnSTxSi2T1LQ&noverify=0&group_code=228578329) ç‚¹å‡»æŒ‰é’®å…¥ç¾¤ã€‚
multiple/assets/favicon/KTHGico.ico
multiple/assets/logo/KTHGLogo.png
multiple/config.json
@@ -7,15 +7,15 @@
    "logo": "logo/HYSNLogo.png",
    "favicon": "favicon/HYSNico.ico"
  },
  "TEST": {
  "KTHG": {
    "env": {
      "VITE_APP_TITLE": "中小企业数字化转型二级套餐包",
      "VITE_BASE_API": "http://1.15.17.182:9003",
      "VITE_JAVA_API": "http://1.15.17.182:9002"
      "VITE_APP_TITLE": "坤泰化工信息管理",
      "VITE_BASE_API": "http://1.15.17.182:9011",
      "VITE_JAVA_API": "http://1.15.17.182:9010"
    },
    "screen": "screen/HYSNView.png",
    "logo": "logo/ZGLTLogo.png",
    "favicon": "favicon/favicon.ico"
    "screen": "screen/DHDCView.png",
    "logo": "logo/KTHGLogo.png",
    "favicon": "favicon/KTHGico.ico"
  },
  "screen": "/src/assets/images/login-background.png",
  "logo": "/src/assets/logo/logo.png",
src/api/equipmentManagement/spareParts.js
@@ -20,6 +20,15 @@
  });
};
// æŸ¥è¯¢å¤‡ä»¶é€‰é¡¹
export const getSparePartsOptions = (params) => {
  return request({
    url: "/spareParts/getByIdDeviceId",
    method: "get",
    params,
  });
};
/**
 * @desc æ–°å¢ž
 */
src/views/basicData/product/ProductSelectDialog.vue
@@ -20,6 +20,7 @@
      @selection-change="handleSelectionChange" @select="handleSelect">
      <el-table-column type="selection" width="55" />
      <el-table-column type="index" label="序号" width="60" />
      <el-table-column prop="parentName" label="类型" min-width="160" />
      <el-table-column prop="productName" label="产品大类" min-width="160" />
      <el-table-column prop="model" label="型号名称" min-width="200" />
      <el-table-column prop="unit" label="单位" min-width="160" />
src/views/equipmentManagement/inspectionManagement/components/formDia.vue
@@ -1,90 +1,185 @@
<template>
  <div>
    <el-dialog :title="operationType === 'add' ? '新增巡检任务' : '编辑巡检任务'"
               v-model="dialogVisitable" width="800px" @close="cancel">
      <el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
               v-model="dialogVisitable"
               width="900px"
               @close="cancel">
      <el-form ref="formRef"
               :model="form"
               :rules="rules"
               label-width="180px">
        <el-row>
          <el-col :span="12">
            <el-form-item label="设备名称" prop="taskId">
              <el-select v-model="form.taskId" @change="setDeviceModel">
                <el-option
                  v-for="(item, index) in deviceOptions"
                  :key="index"
                  :label="item.deviceName"
                  :value="item.id"
                ></el-option>
              </el-select>
            <el-form-item label="巡检任务名称"
                          prop="taskName">
              <el-input v-model="form.taskName"
                        placeholder="请输入巡检任务名称"
                        type="textarea" />
              <!-- <el-select v-model="form.taskId"
                         @change="setDeviceModel">
                <el-option v-for="(item, index) in deviceOptions"
                           :key="index"
                           :label="item.deviceName"
                           :value="item.id"></el-option>
              </el-select> -->
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="巡检人" prop="inspector">
              <el-select v-model="form.inspector" placeholder="请选择" multiple clearable>
                <el-option v-for="item in userList" :label="item.nickName" :value="item.userId" :key="item.userId"/>
            <el-form-item label="巡检人"
                          prop="inspector">
              <el-select v-model="form.inspector"
                         placeholder="请选择"
                         multiple
                         clearable>
                <el-option v-for="item in userList"
                           :label="item.nickName"
                           :value="item.userId"
                           :key="item.userId" />
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row v-show="false">
          <el-col :span="12">
            <el-form-item label="必须拍照视为巡检成功"
                          prop="takePhone">
              <el-radio-group v-model="form.takePhone">
                <el-radio :label="true">是</el-radio>
                <el-radio :label="false">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="上传相册照片"
                          prop="takeAlbum">
              <el-radio-group v-model="form.takeAlbum">
                <el-radio :label="false">不可</el-radio>
                <el-radio :label="true">可</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="备注" prop="remarks">
              <el-input v-model="form.remarks" placeholder="请输入备注" type="textarea" />
            <el-form-item label="备注"
                          prop="remarks">
              <el-input v-model="form.remarks"
                        placeholder="请输入备注"
                        type="textarea" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12">
            <el-form-item label="任务频率" prop="frequencyType">
              <el-select v-model="form.frequencyType" placeholder="请选择" clearable>
                <el-option label="每日" value="DAILY"/>
                <el-option label="每周" value="WEEKLY"/>
                <el-option label="每月" value="MONTHLY"/>
            <el-form-item label="任务频率"
                          prop="frequencyType">
              <el-select v-model="form.frequencyType"
                         placeholder="请选择"
                         clearable>
                <el-option label="每日"
                           value="DAILY" />
                <el-option label="每周"
                           value="WEEKLY" />
                <el-option label="每月"
                           value="MONTHLY" />
                <!-- <el-option label="季度" value="QUARTERLY"/> -->
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-time-picker v-model="form.frequencyDetail" placeholder="选择时间" format="HH:mm"
          <el-col :span="12"
                  v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-time-picker v-model="form.frequencyDetail"
                              placeholder="选择时间"
                              format="HH:mm"
                              value-format="HH:mm" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-select v-model="form.week" placeholder="请选择" clearable style="width: 50%">
                <el-option label="周一" value="MON"/>
                <el-option label="周二" value="TUE"/>
                <el-option label="周三" value="WED"/>
                <el-option label="周四" value="THU"/>
                <el-option label="周五" value="FRI"/>
                <el-option label="周六" value="SAT"/>
                <el-option label="周日" value="SUN"/>
          <el-col :span="12"
                  v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-select v-model="form.week"
                         placeholder="请选择"
                         clearable
                         style="width: 50%">
                <el-option label="周一"
                           value="MON" />
                <el-option label="周二"
                           value="TUE" />
                <el-option label="周三"
                           value="WED" />
                <el-option label="周四"
                           value="THU" />
                <el-option label="周五"
                           value="FRI" />
                <el-option label="周六"
                           value="SAT" />
                <el-option label="周日"
                           value="SUN" />
              </el-select>
              <el-time-picker v-model="form.time" placeholder="选择时间" format="HH:mm"
                              value-format="HH:mm"  style="width: 50%"/>
              <el-time-picker v-model="form.time"
                              placeholder="选择时间"
                              format="HH:mm"
                              value-format="HH:mm"
                              style="width: 50%" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="DD,HH:mm"
                  value-format="DD,HH:mm"
              />
          <el-col :span="12"
                  v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-date-picker v-model="form.frequencyDetail"
                              type="datetime"
                              clearable
                              placeholder="选择开始日期"
                              format="DD,HH:mm"
                              value-format="DD,HH:mm" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
            <el-form-item label="日期" prop="frequencyDetail">
              <el-date-picker
                  v-model="form.frequencyDetail"
                  type="datetime"
                  clearable
                  placeholder="选择开始日期"
                  format="MM,DD,HH:mm"
                  value-format="MM,DD,HH:mm"
              />
          <el-col :span="12"
                  v-if="form.frequencyType === 'QUARTERLY' && form.frequencyType">
            <el-form-item label="日期"
                          prop="frequencyDetail">
              <el-date-picker v-model="form.frequencyDetail"
                              type="datetime"
                              clearable
                              placeholder="选择开始日期"
                              format="MM,DD,HH:mm"
                              value-format="MM,DD,HH:mm" />
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="12"
                  v-if="form.frequencyType === 'DAILY' && form.frequencyType">
            <el-form-item label="时限(小时)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        type="number"
                        placeholder="请输入备注">
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12"
                  v-if="form.frequencyType === 'WEEKLY' && form.frequencyType">
            <el-form-item label="时限(天)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        placeholder="请输入备注"
                        type="number">
              </el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12"
                  v-if="form.frequencyType === 'MONTHLY' && form.frequencyType">
            <el-form-item label="时限(天)"
                          prop="inspectionDeadline">
              <el-input v-model="form.inspectionDeadline"
                        placeholder="请输入备注"
                        type="number">
              </el-input>
            </el-form-item>
          </el-col>
        </el-row>
@@ -92,7 +187,8 @@
      <template #footer>
        <div class="dialog-footer">
          <el-button @click="cancel">取消</el-button>
          <el-button type="primary" @click="submitForm">保存</el-button>
          <el-button type="primary"
                     @click="submitForm">保存</el-button>
        </div>
      </template>
    </el-dialog>
@@ -100,188 +196,205 @@
</template>
<script setup>
import {reactive, ref, getCurrentInstance, toRefs} from "vue";
import useUserStore from '@/store/modules/user'
import {addOrEditTimingTask} from "@/api/inspectionManagement/index.js";
import {userListNoPageByTenantId} from "@/api/system/user.js";
import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
  import { reactive, ref, getCurrentInstance, toRefs } from "vue";
  import useUserStore from "@/store/modules/user";
  import { addOrEditTimingTask } from "@/api/inspectionManagement/index.js";
  import { userListNoPageByTenantId } from "@/api/system/user.js";
  import { getDeviceLedger } from "@/api/equipmentManagement/ledger";
const { proxy } = getCurrentInstance()
const emit = defineEmits()
const userStore = useUserStore()
const dialogVisitable = ref(false);
const operationType = ref('add');
const deviceOptions = ref([]);
const data = reactive({
  form: {
    taskId: undefined,
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
  },
    rules: {
        taskId: [{ required: true, message: "请选择设备", trigger: "change" },],
        inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" },],
        dateStr: [{ required: true, message: "请选择登记时间", trigger: "change" }],
        frequencyType: [{ required: true, message: "请选择任务频率", trigger: "change" }],
        frequencyDetail: [
            {
                required: true,
                message: "请选择日期",
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (!form.value.frequencyType) {
                        callback()
                        return
                    }
                    if (form.value.frequencyType === 'WEEKLY') {
                        if (!form.value.week || !form.value.time) {
                            callback(new Error("请选择日期和时间"))
                        } else {
                            callback()
                        }
                    } else {
                        if (!value) {
                            callback(new Error("请选择日期"))
                        } else {
                            callback()
                        }
                    }
                }
            }
        ],
        week: [
            {
                required: true,
                message: "请选择星期",
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (form.value.frequencyType === 'WEEKLY' && !value) {
                        callback(new Error("请选择星期"))
                    } else {
                        callback()
                    }
                }
            }
        ],
        time: [
            {
                required: true,
                message: "请选择时间",
                trigger: "change",
                validator: (rule, value, callback) => {
                    if (form.value.frequencyType === 'WEEKLY' && !value) {
                        callback(new Error("请选择时间"))
                    } else {
                        callback()
                    }
                }
            }
        ]
    }
})
const { form, rules } = toRefs(data)
const userList = ref([])
const loadDeviceName = async () => {
  const { data } = await getDeviceLedger();
  deviceOptions.value = data;
};
const setDeviceModel = (id) => {
  const option = deviceOptions.value.find((item) => item.id === id);
  if (option) {
    form.value.taskName = option.deviceName;
  }
}
// æ‰“开弹框
const openDialog = async (type, row) => {
  dialogVisitable.value = true
  operationType.value = type
  // é‡ç½®è¡¨å•
  resetForm();
  // åŠ è½½ç”¨æˆ·åˆ—è¡¨
  userListNoPageByTenantId().then((res) => {
    userList.value = res.data;
  const { proxy } = getCurrentInstance();
  const emit = defineEmits();
  const userStore = useUserStore();
  const dialogVisitable = ref(false);
  const operationType = ref("add");
  const deviceOptions = ref([]);
  const data = reactive({
    form: {
      taskId: undefined,
      taskName: undefined,
      inspector: "",
      inspectorIds: "",
      remarks: "",
      frequencyType: "",
      frequencyDetail: "",
      week: "",
      time: "",
      takePhone: true,
      takeAlbum: false,
      inspectionDeadline: "",
    },
    rules: {
      // taskId: [{ required: true, message: "请选择设备", trigger: "change" }],
      taskName: [
        { required: true, message: "请输入巡检任务名称", trigger: "blur" },
      ],
      inspector: [{ required: true, message: "请输入巡检人", trigger: "blur" }],
      dateStr: [{ required: true, message: "请选择登记时间", trigger: "change" }],
      frequencyType: [
        { required: true, message: "请选择任务频率", trigger: "change" },
      ],
      frequencyDetail: [
        {
          required: true,
          message: "请选择日期",
          trigger: "change",
          validator: (rule, value, callback) => {
            if (!form.value.frequencyType) {
              callback();
              return;
            }
            if (form.value.frequencyType === "WEEKLY") {
              if (!form.value.week || !form.value.time) {
                callback(new Error("请选择日期和时间"));
              } else {
                callback();
              }
            } else {
              if (!value) {
                callback(new Error("请选择日期"));
              } else {
                callback();
              }
            }
          },
        },
      ],
      inspectionDeadline: [
        {
          required: true,
          message: "请输入时限",
          trigger: "blur",
        },
      ],
      week: [
        {
          required: true,
          message: "请选择星期",
          trigger: "change",
          validator: (rule, value, callback) => {
            if (form.value.frequencyType === "WEEKLY" && !value) {
              callback(new Error("请选择星期"));
            } else {
              callback();
            }
          },
        },
      ],
      time: [
        {
          required: true,
          message: "请选择时间",
          trigger: "change",
          validator: (rule, value, callback) => {
            if (form.value.frequencyType === "WEEKLY" && !value) {
              callback(new Error("请选择时间"));
            } else {
              callback();
            }
          },
        },
      ],
    },
  });
  // åŠ è½½è®¾å¤‡åˆ—è¡¨
  await loadDeviceName();
  if (type === 'edit' && row) {
    form.value = {...row}
    form.value.inspector = form.value.inspectorIds.split(',').map(Number)
    // å¦‚果有设备ID,自动设置设备信息
    if (form.value.taskId) {
      setDeviceModel(form.value.taskId);
  const { form, rules } = toRefs(data);
  const userList = ref([]);
  const loadDeviceName = async () => {
    const { data } = await getDeviceLedger();
    deviceOptions.value = data;
  };
  const setDeviceModel = id => {
    const option = deviceOptions.value.find(item => item.id === id);
    if (option) {
      form.value.taskName = option.deviceName;
    }
  }
}
  };
// å…³é—­å¯¹è¯æ¡†
const cancel = () => {
  resetForm()
  dialogVisitable.value = false
  emit('closeDia')
}
  // æ‰“开弹框
  const openDialog = async (type, row) => {
    dialogVisitable.value = true;
    operationType.value = type;
// é‡ç½®è¡¨å•函数
const resetForm = () => {
  if (proxy.$refs.formRef) {
    proxy.$refs.formRef.resetFields()
  }
  // é‡ç½®è¡¨å•数据确保设备信息正确重置
  form.value = {
    taskId: undefined,
    taskName: undefined,
    inspector: '',
    inspectorIds: '',
    remarks: '',
    frequencyType: '',
    frequencyDetail: '',
    week: '',
    time: ''
  }
}
    // é‡ç½®è¡¨å•
    resetForm();
// æäº¤è¡¨å•
const submitForm = () => {
  proxy.$refs["formRef"].validate(async valid => {
    if (valid) {
      try {
        form.value.inspectorIds = form.value.inspector.join(',')
        delete form.value.inspector
        if (form.value.frequencyType === 'WEEKLY') {
          let frequencyDetail = ''
          frequencyDetail = form.value.week + ',' + form.value.time
          form.value.frequencyDetail = frequencyDetail
    // åŠ è½½ç”¨æˆ·åˆ—è¡¨
    userListNoPageByTenantId().then(res => {
      userList.value = res.data;
    });
    // åŠ è½½è®¾å¤‡åˆ—è¡¨
    await loadDeviceName();
    if (type === "edit" && row) {
      form.value = { ...row };
      form.value.inspector = form.value.inspectorIds.split(",").map(Number);
      // å¦‚果有设备ID,自动设置设备信息
      // if (form.value.taskId) {
      //   setDeviceModel(form.value.taskId);
      // }
    }
  };
  // å…³é—­å¯¹è¯æ¡†
  const cancel = () => {
    resetForm();
    dialogVisitable.value = false;
    emit("closeDia");
  };
  // é‡ç½®è¡¨å•函数
  const resetForm = () => {
    if (proxy.$refs.formRef) {
      proxy.$refs.formRef.resetFields();
    }
    // é‡ç½®è¡¨å•数据确保设备信息正确重置
    form.value = {
      taskId: undefined,
      taskName: undefined,
      inspector: "",
      inspectorIds: "",
      remarks: "",
      frequencyType: "",
      frequencyDetail: "",
      week: "",
      time: "",
      takePhone: true,
      takeAlbum: false,
      inspectionDeadline: "",
    };
  };
  // æäº¤è¡¨å•
  const submitForm = () => {
    proxy.$refs["formRef"].validate(async valid => {
      if (valid) {
        try {
          form.value.inspectorIds = form.value.inspector.join(",");
          delete form.value.inspector;
          if (form.value.frequencyType === "WEEKLY") {
            let frequencyDetail = "";
            frequencyDetail = form.value.week + "," + form.value.time;
            form.value.frequencyDetail = frequencyDetail;
          }
          let res = await userStore.getInfo();
          form.value.registrantId = res.user.userId;
          await addOrEditTimingTask(form.value);
          cancel();
          proxy.$modal.msgSuccess("提交成功");
        } catch (error) {
          proxy.$modal.msgError("提交失败,请重试");
        }
        let res = await userStore.getInfo()
        form.value.registrantId = res.user.userId
        await addOrEditTimingTask(form.value)
        cancel()
        proxy.$modal.msgSuccess('提交成功')
      } catch (error) {
        proxy.$modal.msgError('提交失败,请重试')
      }
    }
  })
}
defineExpose({ openDialog })
    });
  };
  defineExpose({ openDialog });
</script>
<style scoped>
</style>
src/views/equipmentManagement/inspectionManagement/components/viewFiles.vue
@@ -1,83 +1,32 @@
<template>
  <div>
    <el-dialog title="查看附件"
               v-model="dialogVisitable" width="800px" @close="cancel">
               v-model="dialogVisitable"
               width="800px"
               @close="cancel">
      <div class="upload-container">
        <!-- ç”Ÿäº§å‰ -->
        <div class="form-container">
          <div class="title">生产前</div>
          <div class="title">附件列表</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in beforeProductionImgs" :key="index"
            <img v-for="(item, index) in beforeProductionImgs"
                 :key="index"
                 @click="showMedia(beforeProductionImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
                 :src="item"
                 style="max-width: 100px; height: 100px; margin: 5px;"
                 alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in beforeProductionVideos"
                :key="index"
                @click="showMedia(beforeProductionVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
            <div v-for="(videoUrl, index) in beforeProductionVideos"
                 :key="index"
                 @click="showMedia(beforeProductionVideos, index, 'video')"
                 style="position: relative; margin: 10px; cursor: pointer;">
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
          </div>
        </div>
        <!-- ç”Ÿäº§åŽ -->
        <div class="form-container">
          <div class="title">生产后</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in afterProductionImgs" :key="index"
                 @click="showMedia(afterProductionImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in afterProductionVideos"
                :key="index"
                @click="showMedia(afterProductionVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
          </div>
        </div>
        <!-- ç”Ÿäº§é—®é¢˜ -->
        <div class="form-container">
          <div class="title">生产问题</div>
          <!-- å›¾ç‰‡åˆ—表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <img v-for="(item, index) in productionIssuesImgs" :key="index"
                 @click="showMedia(productionIssuesImgs, index, 'image')"
                 :src="item" style="max-width: 100px; height: 100px; margin: 5px;" alt="">
          </div>
          <!-- è§†é¢‘列表 -->
          <div style="display: flex; flex-wrap: wrap;">
            <div
                v-for="(videoUrl, index) in productionIssuesVideos"
                :key="index"
                @click="showMedia(productionIssuesVideos, index, 'video')"
                style="position: relative; margin: 10px; cursor: pointer;"
            >
              <div style="width: 160px; height: 90px; background-color: #333; display: flex; align-items: center; justify-content: center;">
                <img src="@/assets/images/video.png" alt="播放" style="width: 30px; height: 30px; opacity: 0.8;" />
                <img src="@/assets/images/video.png"
                     alt="播放"
                     style="width: 30px; height: 30px; opacity: 0.8;" />
              </div>
              <div style="text-align: center; font-size: 12px; color: #666;">点击播放</div>
            </div>
@@ -85,220 +34,225 @@
        </div>
      </div>
    </el-dialog>
    <!-- ç»Ÿä¸€åª’体查看器 -->
    <div v-if="isMediaViewerVisible" class="media-viewer-overlay" @click.self="closeMediaViewer">
      <div class="media-viewer-content" @click.stop>
    <div v-if="isMediaViewerVisible"
         class="media-viewer-overlay"
         @click.self="closeMediaViewer">
      <div class="media-viewer-content"
           @click.stop>
        <!-- å›¾ç‰‡ -->
        <vue-easy-lightbox
            v-if="mediaType === 'image'"
            :visible="isMediaViewerVisible"
            :imgs="mediaList"
            :index="currentMediaIndex"
            @hide="closeMediaViewer"
        ></vue-easy-lightbox>
        <vue-easy-lightbox v-if="mediaType === 'image'"
                           :visible="isMediaViewerVisible"
                           :imgs="mediaList"
                           :index="currentMediaIndex"
                           @hide="closeMediaViewer"></vue-easy-lightbox>
        <!-- è§†é¢‘ -->
        <div v-else-if="mediaType === 'video'" style="position: relative;">
          <video
              :src="mediaList[currentMediaIndex]"
              autoplay
              controls
              style="max-width: 90vw; max-height: 80vh;"
          />
        <div v-else-if="mediaType === 'video'"
             style="position: relative;">
          <video :src="mediaList[currentMediaIndex]"
                 autoplay
                 controls
                 style="max-width: 90vw; max-height: 80vh;" />
        </div>
      </div>
    </div>
  </div>
</template>
<script setup>
import { ref } from 'vue';
import VueEasyLightbox from 'vue-easy-lightbox';
const { proxy } = getCurrentInstance();
  import { ref } from "vue";
  import VueEasyLightbox from "vue-easy-lightbox";
  const { proxy } = getCurrentInstance();
// æŽ§åˆ¶å¼¹çª—显示
const dialogVisitable = ref(false);
  // æŽ§åˆ¶å¼¹çª—显示
  const dialogVisitable = ref(false);
// å›¾ç‰‡æ•°ç»„
const beforeProductionImgs = ref([]);
const afterProductionImgs = ref([]);
const productionIssuesImgs = ref([]);
  // å›¾ç‰‡æ•°ç»„
  const beforeProductionImgs = ref([]);
  const afterProductionImgs = ref([]);
  const productionIssuesImgs = ref([]);
// è§†é¢‘数组
const beforeProductionVideos = ref([]);
const afterProductionVideos = ref([]);
const productionIssuesVideos = ref([]);
  // è§†é¢‘数组
  const beforeProductionVideos = ref([]);
  const afterProductionVideos = ref([]);
  const productionIssuesVideos = ref([]);
// åª’体查看器状态
const isMediaViewerVisible = ref(false);
const currentMediaIndex = ref(0);
const mediaList = ref([]); // å­˜å‚¨å½“前要查看的媒体列表(含图片和视频对象)
const mediaType = ref('image'); // image | video
const javaApi = proxy.javaApi;
  // åª’体查看器状态
  const isMediaViewerVisible = ref(false);
  const currentMediaIndex = ref(0);
  const mediaList = ref([]); // å­˜å‚¨å½“前要查看的媒体列表(含图片和视频对象)
  const mediaType = ref("image"); // image | video
  const javaApi = proxy.javaApi;
// å¤„理 URL:将 Windows è·¯å¾„转换为可访问的 URL
function processFileUrl(fileUrl) {
  if (!fileUrl) return '';
  // å¦‚æžœ URL æ˜¯ Windows è·¯å¾„格式(包含反斜杠),需要转换
  if (fileUrl && fileUrl.indexOf('\\') > -1) {
    // æŸ¥æ‰¾ uploads å…³é”®å­—的位置,从那里开始提取相对路径
    const uploadsIndex = fileUrl.toLowerCase().indexOf('uploads');
    if (uploadsIndex > -1) {
      // ä»Ž uploads å¼€å§‹æå–路径,并将反斜杠替换为正斜杠
      const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, '/');
      fileUrl = '/' + relativePath;
    } else {
      // å¦‚果没有找到 uploads,提取最后一个目录和文件名
      const parts = fileUrl.split('\\');
      const fileName = parts[parts.length - 1];
      fileUrl = '/uploads/' + fileName;
    }
  }
  // ç¡®ä¿æ‰€æœ‰éž http å¼€å¤´çš„ URL éƒ½æ‹¼æŽ¥ baseUrl
  if (fileUrl && !fileUrl.startsWith('http')) {
    // ç¡®ä¿è·¯å¾„以 / å¼€å¤´
    if (!fileUrl.startsWith('/')) {
      fileUrl = '/' + fileUrl;
    }
    // æ‹¼æŽ¥ baseUrl
    fileUrl = javaApi + fileUrl;
  }
  return fileUrl;
}
  // å¤„理 URL:将 Windows è·¯å¾„转换为可访问的 URL
  function processFileUrl(fileUrl) {
    if (!fileUrl) return "";
// å¤„理每一类数据:分离图片和视频
function processItems(items) {
  const images = [];
  const videos = [];
  // æ£€æŸ¥ items æ˜¯å¦å­˜åœ¨ä¸”为数组
  if (!items || !Array.isArray(items)) {
    return { images, videos };
  }
  items.forEach(item => {
    if (!item || !item.url) return;
    // å¤„理文件 URL
    const fileUrl = processFileUrl(item.url);
    // æ ¹æ®æ–‡ä»¶æ‰©å±•名判断是图片还是视频
    const urlLower = fileUrl.toLowerCase();
    if (urlLower.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/)) {
      images.push(fileUrl);
    } else if (urlLower.match(/\.(mp4|avi|mov|wmv|flv|mkv|webm)$/)) {
      videos.push(fileUrl);
    } else if (item.contentType) {
      // å¦‚果有 contentType,使用 contentType åˆ¤æ–­
      if (item.contentType.startsWith('image/')) {
        images.push(fileUrl);
      } else if (item.contentType.startsWith('video/')) {
        videos.push(fileUrl);
    // å¦‚æžœ URL æ˜¯ Windows è·¯å¾„格式(包含反斜杠),需要转换
    if (fileUrl && fileUrl.indexOf("\\") > -1) {
      // æŸ¥æ‰¾ uploads å…³é”®å­—的位置,从那里开始提取相对路径
      const uploadsIndex = fileUrl.toLowerCase().indexOf("uploads");
      if (uploadsIndex > -1) {
        // ä»Ž uploads å¼€å§‹æå–路径,并将反斜杠替换为正斜杠
        const relativePath = fileUrl.substring(uploadsIndex).replace(/\\/g, "/");
        fileUrl = "/" + relativePath;
      } else {
        // å¦‚果没有找到 uploads,提取最后一个目录和文件名
        const parts = fileUrl.split("\\");
        const fileName = parts[parts.length - 1];
        fileUrl = "/uploads/" + fileName;
      }
    }
  });
  return { images, videos };
}
// æ‰“开弹窗并加载数据
const openDialog = async (row) => {
  // ä½¿ç”¨æ­£ç¡®çš„字段名:commonFileListBefore, commonFileListAfter
  // productionIssues å¯èƒ½ä¸å­˜åœ¨ï¼Œä½¿ç”¨ç©ºæ•°ç»„
  const { images: beforeImgs, videos: beforeVids } = processItems(row.commonFileListBefore || []);
  const { images: afterImgs, videos: afterVids } = processItems(row.commonFileListAfter || []);
  const { images: issueImgs, videos: issueVids } = processItems(row.productionIssues || []);
  beforeProductionImgs.value = beforeImgs;
  beforeProductionVideos.value = beforeVids;
  afterProductionImgs.value = afterImgs;
  afterProductionVideos.value = afterVids;
  productionIssuesImgs.value = issueImgs;
  productionIssuesVideos.value = issueVids;
  dialogVisitable.value = true;
};
    // ç¡®ä¿æ‰€æœ‰éž http å¼€å¤´çš„ URL éƒ½æ‹¼æŽ¥ baseUrl
    if (fileUrl && !fileUrl.startsWith("http")) {
      // ç¡®ä¿è·¯å¾„以 / å¼€å¤´
      if (!fileUrl.startsWith("/")) {
        fileUrl = "/" + fileUrl;
      }
      // æ‹¼æŽ¥ baseUrl
      fileUrl = javaApi + fileUrl;
    }
// æ˜¾ç¤ºåª’体(图片 or è§†é¢‘)
function showMedia(mediaArray, index, type) {
  mediaList.value = mediaArray;
  currentMediaIndex.value = index;
  mediaType.value = type;
  isMediaViewerVisible.value = true;
}
    return fileUrl;
  }
// å…³é—­åª’体查看器
function closeMediaViewer() {
  isMediaViewerVisible.value = false;
  mediaList.value = [];
  mediaType.value = 'image';
}
  // å¤„理每一类数据:分离图片和视频
  function processItems(items) {
    const images = [];
    const videos = [];
// è¡¨å•关闭方法
const cancel = () => {
  dialogVisitable.value = false;
};
    // æ£€æŸ¥ items æ˜¯å¦å­˜åœ¨ä¸”为数组
    if (!items || !Array.isArray(items)) {
      return { images, videos };
    }
defineExpose({ openDialog });
    items.forEach(item => {
      if (!item || !item.url) return;
      // å¤„理文件 URL
      const fileUrl = processFileUrl(item.url);
      // æ ¹æ®æ–‡ä»¶æ‰©å±•名判断是图片还是视频
      const urlLower = fileUrl.toLowerCase();
      if (urlLower.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/)) {
        images.push(fileUrl);
      } else if (urlLower.match(/\.(mp4|avi|mov|wmv|flv|mkv|webm)$/)) {
        videos.push(fileUrl);
      } else if (item.contentType) {
        // å¦‚果有 contentType,使用 contentType åˆ¤æ–­
        if (item.contentType.startsWith("image/")) {
          images.push(fileUrl);
        } else if (item.contentType.startsWith("video/")) {
          videos.push(fileUrl);
        }
      }
    });
    return { images, videos };
  }
  // æ‰“开弹窗并加载数据
  const openDialog = async row => {
    // ä½¿ç”¨æ­£ç¡®çš„字段名:commonFileListBefore, commonFileListAfter
    // productionIssues å¯èƒ½ä¸å­˜åœ¨ï¼Œä½¿ç”¨ç©ºæ•°ç»„
    const { images: beforeImgs, videos: beforeVids } = processItems(
      row.commonFileListBefore || []
    );
    const { images: afterImgs, videos: afterVids } = processItems(
      row.commonFileListAfter || []
    );
    const { images: issueImgs, videos: issueVids } = processItems(
      row.productionIssues || []
    );
    beforeProductionImgs.value = beforeImgs;
    beforeProductionVideos.value = beforeVids;
    afterProductionImgs.value = afterImgs;
    afterProductionVideos.value = afterVids;
    productionIssuesImgs.value = issueImgs;
    productionIssuesVideos.value = issueVids;
    dialogVisitable.value = true;
  };
  // æ˜¾ç¤ºåª’体(图片 or è§†é¢‘)
  function showMedia(mediaArray, index, type) {
    mediaList.value = mediaArray;
    currentMediaIndex.value = index;
    mediaType.value = type;
    isMediaViewerVisible.value = true;
  }
  // å…³é—­åª’体查看器
  function closeMediaViewer() {
    isMediaViewerVisible.value = false;
    mediaList.value = [];
    mediaType.value = "image";
  }
  // è¡¨å•关闭方法
  const cancel = () => {
    dialogVisitable.value = false;
  };
  defineExpose({ openDialog });
</script>
<style scoped lang="scss">
.upload-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 20px;
  border: 1px solid #dcdfe6;
  box-sizing: border-box;
  .form-container {
    flex: 1;
    width: 100%;
  .upload-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px;
    border: 1px solid #dcdfe6;
    box-sizing: border-box;
    margin-bottom: 20px;
  }
}
.title {
  font-size: 14px;
  color: #165dff;
  line-height: 20px;
  font-weight: 600;
  padding-left: 10px;
  position: relative;
  margin: 6px 0;
  &::before {
    content: "";
    position: absolute;
    .form-container {
      flex: 1;
      width: 100%;
      margin-bottom: 20px;
    }
  }
  .title {
    font-size: 14px;
    color: #165dff;
    line-height: 20px;
    font-weight: 600;
    padding-left: 10px;
    position: relative;
    margin: 6px 0;
    &::before {
      content: "";
      position: absolute;
      left: 0;
      top: 3px;
      width: 4px;
      height: 14px;
      background-color: #165dff;
    }
  }
  .media-viewer-overlay {
    position: fixed;
    top: 0;
    left: 0;
    top: 3px;
    width: 4px;
    height: 14px;
    background-color: #165dff;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.8);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}
.media-viewer-overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.8);
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
}
.media-viewer-content {
  position: relative;
  max-width: 90vw;
  max-height: 90vh;
  overflow: hidden;
}
  .media-viewer-content {
    position: relative;
    max-width: 90vw;
    max-height: 90vh;
    overflow: hidden;
  }
</style>
src/views/equipmentManagement/inspectionManagement/index.vue
@@ -151,6 +151,78 @@
      },
    },
    {
      prop: "inspectionDeadlinetxt",
      label: "期限",
      minWidth: 150,
    },
    {
      prop: "inspectionStatus",
      label: "巡检状态",
      minWidth: 150,
      dataType: "tag",
      formatType: params => {
        const typeMap = {
          å·²å®Œæˆ: "info",
          æœªå·¡æ£€: "warning",
          è¶…期: "danger",
        };
        return typeMap[params] || "info";
      },
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
      formatter: (row, column, cellValue) => {
        // å…ˆåˆ¤æ–­æ˜¯å¦æ˜¯å­—符串
        if (typeof cellValue !== "string") return "";
        let val = cellValue;
        const replacements = {
          MON: "周一",
          TUE: "周二",
          WED: "周三",
          THU: "周四",
          FRI: "周五",
          SAT: "周六",
          SUN: "周日",
        };
        // ä½¿ç”¨æ­£åˆ™ä¸€æ¬¡æ€§æ›¿æ¢æ‰€æœ‰åŒ¹é…é¡¹
        return val.replace(
          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
          match => replacements[match]
        );
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "createTime", label: "登记日期", minWidth: 100 },
  ]);
  const columns1 = ref([
    { prop: "taskName", label: "巡检任务名称", minWidth: 160 },
    { prop: "remarks", label: "备注", minWidth: 150 },
    { prop: "inspector", label: "执行巡检人", minWidth: 150, slot: "inspector" },
    {
      prop: "frequencyType",
      label: "频次",
      minWidth: 150,
      // formatter: (_, __, val) => ({
      //   DAILY: "每日",
      //   WEEKLY: "每周",
      //   MONTHLY: "每月",
      //   QUARTERLY: "季度"
      // }[val] || "")
      formatData: params => {
        return params === "DAILY"
          ? "每日"
          : params === "WEEKLY"
          ? "每周"
          : params === "MONTHLY"
          ? "每月"
          : params === "QUARTERLY"
          ? "季度"
          : "";
      },
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
@@ -221,7 +293,7 @@
    if (value === "taskManage") {
      const operationColumn = getOperationColumn(["edit"]);
      tableColumns.value = [
        ...columns.value,
        ...columns1.value,
        ...(operationColumn ? [operationColumn] : []),
      ];
      operationsArr.value = ["edit"];
@@ -293,6 +365,13 @@
          return processedItem;
        });
        tableData.value.forEach(item => {
          item.inspectionStatus = getFileStatus(item);
          item.inspectionDeadlinetxt =
            item.frequencyType === "DAILY"
              ? item.inspectionDeadline + "小时"
              : item.inspectionDeadline + "天";
        });
        total.value = res.data.total || 0;
      })
      .finally(() => {
@@ -345,7 +424,61 @@
      })
      .catch(() => {});
  };
  const getFileStatus = record => {
    console.log(record);
    if (record.takePhone) {
      if (record.commonFileListBefore && record.commonFileListBefore.length) {
        return "已完成";
      }
      if (record.frequencyType == "DAILY") {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(小时)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const hoursDiff = (now - createTime) / (1000 * 60 * 60);
          if (hoursDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      } else {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(天)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24);
          if (daysDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      }
      return "未巡检";
    } else if (record.inspectionSubmitted) {
      return "已完成";
    } else {
      if (record.frequencyType == "DAILY") {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(小时)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const hoursDiff = (now - createTime) / (1000 * 60 * 60);
          if (hoursDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      } else {
        if (Number(record.inspectionDeadline) && record.createTime) {
          // è®¡ç®—时间差(天)
          const now = new Date().getTime();
          const createTime = new Date(record.createTime).getTime();
          const daysDiff = (now - createTime) / (1000 * 60 * 60 * 24);
          if (daysDiff > Number(record.inspectionDeadline)) {
            return "超期";
          }
        }
      }
      return "未巡检";
    }
  };
  // å¤šé€‰å˜æ›´
  const handleSelectionChange = selection => {
    selectedRows.value = selection;
src/views/equipmentManagement/repair/Modal/MaintainModal.vue
@@ -32,6 +32,16 @@
          style="width: 100%"
        />
      </el-form-item>
      <el-form-item label="设备备件">
        <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="请选择设备备件" multiple filterable>
          <el-option
              v-for="item in sparePartOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
      </el-form-item>
    </el-form>
  </FormDialog>
</template>
@@ -43,6 +53,7 @@
import useUserStore from "@/store/modules/user";
import dayjs from "dayjs";
import { ElMessage } from "element-plus";
import {getSparePartsOptions} from "@/api/equipmentManagement/spareParts.js";
defineOptions({
  name: "维修模态框",
@@ -61,7 +72,10 @@
  maintenanceResult: undefined, // ç»´ä¿®ç»“æžœ
  maintenanceTime: undefined, // ç»´ä¿®æ—¥æœŸ
  status: 0,
  sparePartsIds: undefined,
});
const sparePartOptions = ref([])
const loadingSparePartOptions = ref(true)
const setForm = (data) => {
  form.maintenanceName = data.maintenanceName ?? userStore.nickName;
@@ -71,12 +85,18 @@
      ? dayjs(data.maintenanceTime).format("YYYY-MM-DD HH:mm:ss")
      : dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.status = 1; // é»˜è®¤çŠ¶æ€ä¸ºå®Œç»“
  form.sparePartsIds = data.sparePartsIds;
};
const sendForm = async () => {
  loading.value = true;
  try {
    const { code } = await addMaintain({ id: repairId.value, ...form });
    const data = {
      id: repairId.value,
      ...form,
      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
    }
    const { code } = await addMaintain(data);
    if (code == 200) {
      ElMessage.success("维修成功");
      emits("ok");
@@ -87,6 +107,17 @@
    loading.value = false;
  }
};
const fetchSparePartOptions = (deviceLedgerId) => {
  loadingSparePartOptions.value = true;
  getSparePartsOptions({ deviceLedgerId: deviceLedgerId }).then((res) => {
    if (res.code == 200) {
      sparePartOptions.value = res.data || [];
    }
  }).finally(() => {
    loadingSparePartOptions.value = false;
  })
}
const handleCancel = () => {
  resetForm();
@@ -103,6 +134,7 @@
  visible.value = true;
  await nextTick();
  setForm(row);
  fetchSparePartOptions(row.deviceLedgerId)
};
defineExpose({
src/views/equipmentManagement/spareParts/index.vue
@@ -36,7 +36,6 @@
            <el-tag type="success" size="small">{{ row.status }}</el-tag>
          </template>
        </el-table-column>
        <el-table-column prop="price" label="ä»·æ ¼" width="140"></el-table-column>
        <el-table-column prop="quantity" label="数量" width="140"></el-table-column>
        <el-table-column prop="description" label="描述"></el-table-column>
        <el-table-column label="操作" width="150" fixed="right" align="center">
@@ -111,16 +110,6 @@
        <el-form-item label="描述" prop="description">
          <el-input v-model="form.description"></el-input>
        </el-form-item>
        <el-form-item label="ä»·æ ¼" prop="price">
          <el-input-number
            v-model="form.price"
            placeholder="请输入价格"
            :min="0"
            :step="0.01"
            :precision="2"
            style="width: 100%"
          ></el-input-number>
        </el-form-item>
      </el-form>
      <template #footer>
        <span class="dialog-footer">
@@ -173,7 +162,6 @@
  status: '',
  description: '',
  deviceLedgerIds: [],
  price: null
});
// è¡¨å•验证规则
@@ -298,7 +286,6 @@
  form.status = '';
  form.description = '';
  form.deviceLedgerIds = [];
  form.price = null;
  operationType.value = 'add'
  dialogVisible.value = true;
};
src/views/equipmentManagement/upkeep/Form/DetailDialog.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,219 @@
<template>
  <el-dialog v-model="dialogVisible"
             title="保养任务详情"
             width="600px"
             :close-on-click-modal="false"
             @close="handleClose">
    <el-form :model="formData"
             label-width="120px"
             class="detail-form">
      <el-form-item label="设备名称">
        <el-input v-model="formData.deviceName"
                  disabled />
      </el-form-item>
      <el-form-item label="规格型号">
        <el-input v-model="formData.deviceModel"
                  disabled />
      </el-form-item>
      <el-form-item label="计划保养日期">
        <el-input v-model="formData.maintenancePlanTime"
                  disabled />
      </el-form-item>
      <el-form-item label="录入人">
        <el-input v-model="formData.createUserName"
                  disabled />
      </el-form-item>
      <el-form-item label="实际保养人">
        <el-input v-model="formData.maintenanceActuallyName"
                  disabled />
      </el-form-item>
      <el-form-item label="实际保养日期">
        <el-input v-model="formData.maintenanceActuallyTime"
                  disabled />
      </el-form-item>
      <el-form-item label="保养结果">
        <el-input v-model="formData.maintenanceResult"
                  type="textarea"
                  :rows="3"
                  disabled />
      </el-form-item>
      <el-form-item label="状态">
        <el-tag v-if="formData.status === 2"
                type="danger">失败</el-tag>
        <el-tag v-else-if="formData.status === 1"
                type="success">完结</el-tag>
        <el-tag v-else-if="formData.status === 0"
                type="warning">待保养</el-tag>
        <span v-else>-</span>
      </el-form-item>
      <el-form-item label="设备备件">
        <span>{{formData.sparePartsNames}}</span>
      </el-form-item>
      <el-form-item label="图片列表">
        <div v-if="imageList.length > 0"
             class="image-list">
          <el-image v-for="(image, index) in imagesFile"
                    :key="index"
                    :src="image.url"
                    fit="cover"
                    class="image-item" />
        </div>
        <span v-else>-</span>
      </el-form-item>
    </el-form>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose">关闭</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script setup>
  import { ref, watch, computed } from "vue";
  import dayjs from "dayjs";
  const props = defineProps({
    visible: {
      type: Boolean,
      default: false,
    },
    row: {
      type: Object,
      default: () => ({}),
    },
  });
  const emit = defineEmits(["update:visible", "close"]);
  const dialogVisible = ref(false);
  const formData = ref({
    deviceName: "",
    deviceModel: "",
    maintenancePlanTime: "",
    createUserName: "",
    maintenanceActuallyName: "",
    maintenanceActuallyTime: "",
    maintenanceResult: "",
    status: "",
    sparePartsNames: "",
  });
  const imageList = ref([]);
  const sparePartsList = ref([]);
  // é¢„览图片列表
  const previewImageList = computed(() => {
    return imageList.value.map(image => image.url || image.fileUrl);
  });
  watch(
    () => props.visible,
    newVal => {
      dialogVisible.value = newVal;
    }
  );
  // ç›‘听 dialogVisible å˜åŒ–,通知父组件
  watch(
    () => dialogVisible.value,
    newVal => {
      emit("update:visible", newVal);
    }
  );
  watch(
    () => props.row,
    newRow => {
      if (newRow) {
        fillFormData(newRow);
      }
    },
    { deep: true }
  );
  const fillFormData = row => {
    formData.value = {
      deviceName: row.deviceName || "",
      deviceModel: row.deviceModel || "",
      maintenancePlanTime: row.maintenancePlanTime
        ? dayjs(row.maintenancePlanTime).format("YYYY-MM-DD")
        : "",
      createUserName: row.createUserName || "",
      maintenanceActuallyName: row.maintenanceActuallyName || "",
      maintenanceActuallyTime: row.maintenanceActuallyTime
        ? dayjs(row.maintenanceActuallyTime).format("YYYY-MM-DD HH:mm:ss")
        : "",
      maintenanceResult: row.maintenanceResult || "",
      status: row.status || 0,
      sparePartsNames: row.sparePartsNames || "",
    };
    // å¤„理图片列表
    if (row.imagesFile) {
      if (Array.isArray(row.imagesFile)) {
        imageList.value = row.imagesFile;
      } else if (typeof row.imagesFile === "string") {
        try {
          imageList.value = JSON.parse(row.imagesFile);
        } catch (error) {
          imageList.value = [];
        }
      } else {
        imageList.value = [];
      }
    } else {
      imageList.value = [];
    }
    console.log(imageList.value, "imageList");
    // å¤„理设备备件列表
    if (row.spareParts) {
      if (Array.isArray(row.spareParts)) {
        sparePartsList.value = row.spareParts;
      } else if (typeof row.spareParts === "string") {
        try {
          sparePartsList.value = JSON.parse(row.spareParts);
        } catch (error) {
          sparePartsList.value = [];
        }
      } else {
        sparePartsList.value = [];
      }
    } else {
      sparePartsList.value = [];
    }
  };
  const handleClose = () => {
    dialogVisible.value = false;
    emit("update:visible", false);
    emit("close");
  };
</script>
<style scoped>
  .detail-form {
    margin-top: 20px;
  }
  .dialog-footer {
    text-align: center;
  }
  .image-list {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 5px;
  }
  .image-item {
    width: 100px;
    height: 100px;
    cursor: pointer;
  }
  .el-table {
    margin-top: 5px;
  }
</style>
src/views/equipmentManagement/upkeep/Form/MaintenanceModal.vue
@@ -38,6 +38,16 @@
          placeholder="请输入保养结果"
          type="text" />
      </el-form-item>
      <el-form-item label="设备备件">
        <el-select v-model="form.sparePartsIds" :loading="loadingSparePartOptions" placeholder="请选择设备备件" multiple filterable>
          <el-option
              v-for="item in sparePartOptions"
              :key="item.id"
              :label="item.name"
              :value="item.id"
          />
        </el-select>
      </el-form-item>
    </el-form>
  </FormDialog>
</template>
@@ -45,6 +55,7 @@
<script setup>
import FormDialog from "@/components/Dialog/FormDialog.vue";
import { addMaintenance } from "@/api/equipmentManagement/upkeep";
import {getSparePartsOptions} from "@/api/equipmentManagement/spareParts.js";
import useFormData from "@/hooks/useFormData";
import dayjs from "dayjs";
import useUserStore from "@/store/modules/user";
@@ -67,7 +78,10 @@
  maintenanceActuallyTime: undefined, // å®žé™…保养日期
  maintenanceResult: undefined, // ä¿å…»ç»“æžœ
  status: 0, // ä¿å…»çŠ¶æ€
  sparePartsIds: undefined,
});
const sparePartOptions = ref([])
const loadingSparePartOptions = ref(true)
const setForm = (data) => {
  form.maintenanceActuallyName =
@@ -78,7 +92,19 @@
      : dayjs().format("YYYY-MM-DD HH:mm:ss");
  form.maintenanceResult = data.maintenanceResult;
  form.status = 1; // é»˜è®¤çŠ¶æ€ä¸ºå®Œç»“
  form.sparePartsIds = data.sparePartsIds;
};
const fetchSparePartOptions = (deviceLedgerId) => {
  loadingSparePartOptions.value = true;
  getSparePartsOptions({ deviceLedgerId: deviceLedgerId }).then((res) => {
    if (res.code == 200) {
      sparePartOptions.value = res.data || [];
    }
  }).finally(() => {
    loadingSparePartOptions.value = false;
  })
}
/**
 * @desc ä¿å­˜ä¿å…»
@@ -86,7 +112,12 @@
const sendForm = async () => {
  loading.value = true;
  try {
    const { code } = await addMaintenance({ id: planId.value, ...form });
    const data = {
      id: planId.value,
      ...form,
      sparePartsIds: form.sparePartsIds ? form.sparePartsIds.join(",") : "",
    }
    const { code } = await addMaintenance(data);
    if (code == 200) {
      ElMessage.success("保养成功");
      emits("ok");
@@ -113,6 +144,7 @@
  visible.value = true;
  await nextTick();
  setForm(row);
  fetchSparePartOptions(row.deviceLedgerId)
};
defineExpose({
src/views/equipmentManagement/upkeep/index.vue
@@ -1,694 +1,723 @@
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab" @tab-change="handleTabChange">
    <el-tabs v-model="activeTab"
             @tab-change="handleTabChange">
      <!-- å®šæ—¶ä»»åŠ¡ç®¡ç†tab -->
      <el-tab-pane label="定时任务管理" name="scheduled">
      <el-tab-pane label="定时任务管理"
                   name="scheduled">
        <div class="search_form">
          <el-form :model="scheduledFilters" :inline="true">
          <el-form :model="scheduledFilters"
                   :inline="true">
            <el-form-item label="任务名称">
              <el-input
                  v-model="scheduledFilters.taskName"
                  style="width: 240px"
                  placeholder="请输入任务名称"
                  clearable
                  :prefix-icon="Search"
                  @change="getScheduledTableData"
              />
              <el-input v-model="scheduledFilters.taskName"
                        style="width: 240px"
                        placeholder="请输入任务名称"
                        clearable
                        :prefix-icon="Search"
                        @change="getScheduledTableData" />
            </el-form-item>
            <el-form-item label="任务状态">
              <el-select v-model="scheduledFilters.status" placeholder="请选择任务状态" clearable style="width: 200px">
                <el-option label="启用" value="1" />
                <el-option label="停用" value="0" />
              <el-select v-model="scheduledFilters.status"
                         placeholder="请选择任务状态"
                         clearable
                         style="width: 200px">
                <el-option label="启用"
                           value="1" />
                <el-option label="停用"
                           value="0" />
              </el-select>
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="getScheduledTableData">搜索</el-button>
              <el-button type="primary"
                         @click="getScheduledTableData">搜索</el-button>
              <el-button @click="resetScheduledFilters">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">定时任务管理</el-text>
            <el-text class="mx-1"
                     size="large">定时任务管理</el-text>
            <div>
              <el-button type="primary" icon="Plus" @click="addScheduledTask">
              <el-button type="primary"
                         icon="Plus"
                         @click="addScheduledTask">
                æ–°å¢žä»»åŠ¡
              </el-button>
              <el-button
                type="danger"
                icon="Delete"
                :disabled="scheduledMultipleList.length <= 0"
                @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))"
              >
              <el-button type="danger"
                         icon="Delete"
                         :disabled="scheduledMultipleList.length <= 0"
                         @click="delScheduledTaskByIds(scheduledMultipleList.map((item) => item.id))">
                æ‰¹é‡åˆ é™¤
              </el-button>
            </div>
          </div>
          <PIMTable
            rowKey="id"
            isSelection
            :column="scheduledColumns"
            :tableData="scheduledDataList"
            :page="{
          <PIMTable rowKey="id"
                    isSelection
                    :column="scheduledColumns"
                    :tableData="scheduledDataList"
                    :page="{
              current: scheduledPagination.currentPage,
              size: scheduledPagination.pageSize,
              total: scheduledPagination.total,
            }"
            @selection-change="handleScheduledSelectionChange"
            @pagination="changeScheduledPage"
          >
                    @selection-change="handleScheduledSelectionChange"
                    @pagination="changeScheduledPage">
            <template #statusRef="{ row }">
              <el-tag v-if="row.status === 1" type="success">启用</el-tag>
              <el-tag v-if="row.status === 0" type="danger">停用</el-tag>
              <el-tag v-if="row.status === 1"
                      type="success">启用</el-tag>
              <el-tag v-if="row.status === 0"
                      type="danger">停用</el-tag>
            </template>
            <template #operation="{ row }">
              <el-button
                type="primary"
                link
                @click="editScheduledTask(row)"
              >
              <el-button type="primary"
                         link
                         @click="editScheduledTask(row)">
                ç¼–辑
              </el-button>
              <el-button
                type="danger"
                link
                @click="delScheduledTaskByIds(row.id)"
              >
              <el-button type="danger"
                         link
                         @click="delScheduledTaskByIds(row.id)">
                åˆ é™¤
              </el-button>
            </template>
          </PIMTable>
        </div>
      </el-tab-pane>
      <!-- ä»»åŠ¡è®°å½•tab(原设备保养页面) -->
      <el-tab-pane label="任务记录" name="record">
      <el-tab-pane label="任务记录"
                   name="record">
        <div class="search_form">
          <el-form :model="filters" :inline="true">
          <el-form :model="filters"
                   :inline="true">
            <el-form-item label="设备名称">
              <el-input
                  v-model="filters.deviceName"
                  style="width: 240px"
                  placeholder="请输入设备名称"
                  clearable
                  :prefix-icon="Search"
                  @change="getTableData"
              />
              <el-input v-model="filters.deviceName"
                        style="width: 240px"
                        placeholder="请输入设备名称"
                        clearable
                        :prefix-icon="Search"
                        @change="getTableData" />
            </el-form-item>
            <el-form-item label="计划保养日期">
              <el-date-picker
                  v-model="filters.maintenancePlanTime"
                  type="date"
                  placeholder="请选择计划保养日期"
                  size="default"
                  @change="(date) => handleDateChange(date,2)"
              />
              <el-date-picker v-model="filters.maintenancePlanTime"
                              type="date"
                              placeholder="请选择计划保养日期"
                              size="default"
                              @change="(date) => handleDateChange(date,2)" />
            </el-form-item>
            <el-form-item label="实际保养日期">
              <el-date-picker
                  v-model="filters.maintenanceActuallyTime"
                  type="date"
                  placeholder="请选择实际保养日期"
                  size="default"
                  @change="(date) => handleDateChange(date,1)"
              />
              <el-date-picker v-model="filters.maintenanceActuallyTime"
                              type="date"
                              placeholder="请选择实际保养日期"
                              size="default"
                              @change="(date) => handleDateChange(date,1)" />
            </el-form-item>
            <el-form-item label="实际保养人">
              <el-input
                  v-model="filters.maintenanceActuallyName"
                  style="width: 240px"
                  placeholder="请输入实际保养人"
                  clearable
                  :prefix-icon="Search"
                  @change="getTableData"
              />
              <el-input v-model="filters.maintenanceActuallyName"
                        style="width: 240px"
                        placeholder="请输入实际保养人"
                        clearable
                        :prefix-icon="Search"
                        @change="getTableData" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" @click="getTableData">搜索</el-button>
              <el-button type="primary"
                         @click="getTableData">搜索</el-button>
              <el-button @click="resetFilters">重置</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="table_list">
          <div class="actions">
            <el-text class="mx-1" size="large">任务记录</el-text>
            <el-text class="mx-1"
                     size="large">任务记录</el-text>
            <div>
              <el-button type="success" icon="Van" @click="addPlan">
              <el-button type="success"
                         icon="Van"
                         @click="addPlan">
                æ–°å¢žè®¡åˆ’
              </el-button>
              <el-button @click="handleOut">
                å¯¼å‡º
              </el-button>
              <el-button
                type="danger"
                icon="Delete"
                :disabled="multipleList.length <= 0 || hasFinishedStatus"
                @click="delRepairByIds(multipleList.map((item) => item.id))"
              >
              <el-button type="danger"
                         icon="Delete"
                         :disabled="multipleList.length <= 0 || hasFinishedStatus"
                         @click="delRepairByIds(multipleList.map((item) => item.id))">
                æ‰¹é‡åˆ é™¤
              </el-button>
            </div>
          </div>
         <PIMTable
        rowKey="id"
        isSelection
        :column="columns"
        :tableData="dataList"
        :page="{
          <PIMTable rowKey="id"
                    isSelection
                    :column="columns"
                    :tableData="dataList"
                    :page="{
          current: pagination.currentPage,
          size: pagination.pageSize,
          total: pagination.total,
        }"
        @selection-change="handleSelectionChange"
        @pagination="changePage"
      >
        <template #maintenanceResultRef="{ row }">
          <div>{{ row.maintenanceResult || '-' }}</div>
        </template>
        <template #statusRef="{ row }">
          <el-tag v-if="row.status === 2" type="danger">失败</el-tag>
          <el-tag v-if="row.status === 1" type="success">完结</el-tag>
          <el-tag v-if="row.status === 0" type="warning">待保养</el-tag>
        </template>
        <template #operation="{ row }">
          <!-- è¿™ä¸ªåŠŸèƒ½è·Ÿæ–°å¢žä¿å…»åŠŸèƒ½ä¸€æ¨¡ä¸€æ ·ï¼Œæœ‰å•¥æ„ä¹‰ï¼Ÿ -->
          <!-- <el-button
                    @selection-change="handleSelectionChange"
                    @pagination="changePage">
            <template #maintenanceResultRef="{ row }">
              <div>{{ row.maintenanceResult || '-' }}</div>
            </template>
            <template #statusRef="{ row }">
              <el-tag v-if="row.status === 2"
                      type="danger">失败</el-tag>
              <el-tag v-if="row.status === 1"
                      type="success">完结</el-tag>
              <el-tag v-if="row.status === 0"
                      type="warning">待保养</el-tag>
            </template>
            <template #operation="{ row }">
              <!-- è¿™ä¸ªåŠŸèƒ½è·Ÿæ–°å¢žä¿å…»åŠŸèƒ½ä¸€æ¨¡ä¸€æ ·ï¼Œæœ‰å•¥æ„ä¹‰ï¼Ÿ -->
              <!-- <el-button
              type="primary"
              text
              @click="addMaintain(row)"
          >
            æ–°å¢žä¿å…»
          </el-button> -->
          <el-button
            type="primary"
            link
            :disabled="row.status === 1"
            @click="editPlan(row.id)"
          >
            ç¼–辑
          </el-button>
          <el-button
            type="success"
            link
            :disabled="row.status === 1"
            @click="addMaintain(row)"
          >
            ä¿å…»
          </el-button>
          <el-button
            type="danger"
            link
            :disabled="row.status === 1"
            @click="delRepairByIds(row.id)"
          >
            åˆ é™¤
          </el-button>
          <el-button
            type="primary"
            link
            @click="openFileDialog(row)"
          >
            é™„ä»¶
          </el-button>
        </template>
      </PIMTable>
              <el-button type="primary"
                         link
                         :disabled="row.status === 1"
                         @click="editPlan(row.id)">
                ç¼–辑
              </el-button>
              <!-- <el-button type="success"
                         link
                         :disabled="row.status === 1"
                         @click="addMaintain(row)">
                ä¿å…»
              </el-button> -->
              <el-button type="danger"
                         link
                         :disabled="row.status === 1"
                         @click="delRepairByIds(row.id)">
                åˆ é™¤
              </el-button>
              <el-button type="primary"
                         link
                         @click="openFileDialog(row)">
                è¯¦æƒ…
              </el-button>
              <!-- <el-button type="primary"
                         link
                         @click="openAttachmentDialog(row)">
                é™„ä»¶
              </el-button> -->
            </template>
          </PIMTable>
        </div>
      </el-tab-pane>
    </el-tabs>
    <PlanModal ref="planModalRef" @ok="getTableData" />
        <MaintenanceModal ref="maintainModalRef" @ok="getTableData" />
        <FormDia ref="formDiaRef" @closeDia="getScheduledTableData" />
    <FileListDialog
      ref="fileListDialogRef"
      v-model="fileDialogVisible"
      :show-upload-button="true"
      :show-delete-button="true"
      :delete-method="handleAttachmentDelete"
      :name-column-label="'附件名称'"
      :rulesRegulationsManagementId="currentMaintenanceTaskId"
      @upload="handleAttachmentUpload" />
    <PlanModal ref="planModalRef"
               @ok="getTableData" />
    <MaintenanceModal ref="maintainModalRef"
                      @ok="getTableData" />
    <FormDia ref="formDiaRef"
             @closeDia="getScheduledTableData" />
    <DetailDialog ref="detailDialogRef"
                  v-model:visible="detailDialogVisible"
                  :row="currentDetailRow" />
    <FileListDialog ref="fileListDialogRef"
                    v-model="fileDialogVisible"
                    :show-upload-button="true"
                    :show-delete-button="true"
                    :delete-method="handleAttachmentDelete"
                    :name-column-label="'附件名称'"
                    :rulesRegulationsManagementId="currentMaintenanceTaskId"
                    @upload="handleAttachmentUpload" />
  </div>
</template>
<script setup>
import { ref, onMounted, reactive, getCurrentInstance, nextTick, computed } from 'vue'
import { Search } from '@element-plus/icons-vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import PlanModal from './Form/PlanModal.vue'
import MaintenanceModal from './Form/MaintenanceModal.vue'
import FormDia from './Form/formDia.vue'
import FileListDialog from '@/components/Dialog/FileListDialog.vue'
import {
  getUpkeepPage,
  delUpkeep,
  deviceMaintenanceTaskList,
  deviceMaintenanceTaskDel,
} from '@/api/equipmentManagement/upkeep'
import {
  listMaintenanceTaskFiles,
  addMaintenanceTaskFile,
  delMaintenanceTaskFile,
} from '@/api/equipmentManagement/maintenanceTaskFile'
import dayjs from 'dayjs'
  import {
    ref,
    onMounted,
    reactive,
    getCurrentInstance,
    nextTick,
    computed,
  } from "vue";
  import { Search } from "@element-plus/icons-vue";
  import { ElMessage, ElMessageBox } from "element-plus";
  import PlanModal from "./Form/PlanModal.vue";
  import MaintenanceModal from "./Form/MaintenanceModal.vue";
  import FormDia from "./Form/formDia.vue";
  import DetailDialog from "./Form/DetailDialog.vue";
  import FileListDialog from "@/components/Dialog/FileListDialog.vue";
  import {
    getUpkeepPage,
    delUpkeep,
    deviceMaintenanceTaskList,
    deviceMaintenanceTaskDel,
  } from "@/api/equipmentManagement/upkeep";
  import {
    listMaintenanceTaskFiles,
    addMaintenanceTaskFile,
    delMaintenanceTaskFile,
  } from "@/api/equipmentManagement/maintenanceTaskFile";
  import dayjs from "dayjs";
const { proxy } = getCurrentInstance()
  const { proxy } = getCurrentInstance();
// Tab相关
const activeTab = ref('scheduled')
  // Tab相关
  const activeTab = ref("scheduled");
// è®¡åˆ’弹窗控制器
const planModalRef = ref()
// ä¿å…»å¼¹çª—控制器
const maintainModalRef = ref()
// å®šæ—¶ä»»åŠ¡å¼¹çª—æŽ§åˆ¶å™¨
const formDiaRef = ref()
// é™„件弹窗
const fileListDialogRef = ref(null)
const fileDialogVisible = ref(false)
const currentMaintenanceTaskId = ref(null)
  // è®¡åˆ’弹窗控制器
  const planModalRef = ref();
  // ä¿å…»å¼¹çª—控制器
  const maintainModalRef = ref();
  // å®šæ—¶ä»»åŠ¡å¼¹çª—æŽ§åˆ¶å™¨
  const formDiaRef = ref();
  // è¯¦æƒ…弹窗
  const detailDialogRef = ref();
  const detailDialogVisible = ref(false);
  const currentDetailRow = ref(null);
  // é™„件弹窗
  const fileListDialogRef = ref(null);
  const fileDialogVisible = ref(false);
  const currentMaintenanceTaskId = ref(null);
// ä»»åŠ¡è®°å½•tab(原设备保养页面)相关变量
const filters = reactive({
  deviceName: '',
  maintenancePlanTime: '',
  maintenanceActuallyTime: '',
  maintenanceActuallyName: '',
})
  // ä»»åŠ¡è®°å½•tab(原设备保养页面)相关变量
  const filters = reactive({
    deviceName: "",
    maintenancePlanTime: "",
    maintenanceActuallyTime: "",
    maintenanceActuallyName: "",
  });
const dataList = ref([])
const pagination = ref({
  currentPage: 1,
  pageSize: 10,
  total: 0,
})
const multipleList = ref([])
  const dataList = ref([]);
  const pagination = ref({
    currentPage: 1,
    pageSize: 10,
    total: 0,
  });
  const multipleList = ref([]);
// å®šæ—¶ä»»åŠ¡ç®¡ç†tab相关变量
const scheduledFilters = reactive({
  taskName: '',
  status: '',
})
  // å®šæ—¶ä»»åŠ¡ç®¡ç†tab相关变量
  const scheduledFilters = reactive({
    taskName: "",
    status: "",
  });
const scheduledDataList = ref([])
const scheduledPagination = reactive({
  currentPage: 1,
  pageSize: 10,
  total: 0,
})
const scheduledMultipleList = ref([])
  const scheduledDataList = ref([]);
  const scheduledPagination = reactive({
    currentPage: 1,
    pageSize: 10,
    total: 0,
  });
  const scheduledMultipleList = ref([]);
// å®šæ—¶ä»»åŠ¡ç®¡ç†è¡¨æ ¼åˆ—é…ç½®
const scheduledColumns = ref([
    { prop: "taskName", label: "设备名称"},
    {
        label: "规格型号",
        prop: "deviceModel",
    },
    {
        prop: "frequencyType",
        label: "频次",
        minWidth: 150,
        // PIMTable ä½¿ç”¨çš„æ˜¯ formatData,而不是 Element-Plus çš„ formatter
        formatData: (cell) => ({
            DAILY: "每日",
            WEEKLY: "每周",
            MONTHLY: "每月",
            QUARTERLY: "季度"
        }[cell] || "")
    },
    {
        prop: "frequencyDetail",
        label: "开始日期与时间",
        minWidth: 150,
        // åŒæ ·æ”¹ç”¨ formatData,PIMTable å†…部会把单元格值传进来
        formatData: (cell) => {
            if (typeof cell !== 'string') return '';
            let val = cell;
            const replacements = {
                MON: '周一',
                TUE: '周二',
                WED: '周三',
                THU: '周四',
                FRI: '周五',
                SAT: '周六',
                SUN: '周日'
            };
            // ä½¿ç”¨æ­£åˆ™ä¸€æ¬¡æ€§æ›¿æ¢æ‰€æœ‰åŒ¹é…é¡¹
            return val.replace(/MON|TUE|WED|THU|FRI|SAT|SUN/g, match => replacements[match]);
        }
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "registrationDate", label: "登记日期", minWidth: 100 },
    {
        fixed: "right",
        label: "操作",
        dataType: "slot",
        slot: "operation",
        align: "center",
        width: "200px",
    },
])
  // å®šæ—¶ä»»åŠ¡ç®¡ç†è¡¨æ ¼åˆ—é…ç½®
  const scheduledColumns = ref([
    { prop: "taskName", label: "设备名称" },
    {
      label: "规格型号",
      prop: "deviceModel",
    },
    {
      prop: "frequencyType",
      label: "频次",
      minWidth: 150,
      // PIMTable ä½¿ç”¨çš„æ˜¯ formatData,而不是 Element-Plus çš„ formatter
      formatData: cell =>
        ({
          DAILY: "每日",
          WEEKLY: "每周",
          MONTHLY: "每月",
          QUARTERLY: "季度",
        }[cell] || ""),
    },
    {
      prop: "frequencyDetail",
      label: "开始日期与时间",
      minWidth: 150,
      // åŒæ ·æ”¹ç”¨ formatData,PIMTable å†…部会把单元格值传进来
      formatData: cell => {
        if (typeof cell !== "string") return "";
        let val = cell;
        const replacements = {
          MON: "周一",
          TUE: "周二",
          WED: "周三",
          THU: "周四",
          FRI: "周五",
          SAT: "周六",
          SUN: "周日",
        };
        // ä½¿ç”¨æ­£åˆ™ä¸€æ¬¡æ€§æ›¿æ¢æ‰€æœ‰åŒ¹é…é¡¹
        return val.replace(
          /MON|TUE|WED|THU|FRI|SAT|SUN/g,
          match => replacements[match]
        );
      },
    },
    { prop: "registrant", label: "登记人", minWidth: 100 },
    { prop: "registrationDate", label: "登记日期", minWidth: 100 },
    {
      fixed: "right",
      label: "操作",
      dataType: "slot",
      slot: "operation",
      align: "center",
      width: "200px",
    },
  ]);
// ä»»åŠ¡è®°å½•è¡¨æ ¼åˆ—é…ç½®ï¼ˆåŽŸè®¾å¤‡ä¿å…»è¡¨æ ¼åˆ—ï¼‰
const columns = ref([
    {
        label: "设备名称",
        align: "center",
        prop: "deviceName",
    },
    {
        label: "规格型号",
        align: "center",
        prop: "deviceModel",
    },
    {
        label: "计划保养日期",
        align: "center",
        prop: "maintenancePlanTime",
        formatData: (cell) => dayjs(cell).format("YYYY-MM-DD"),
    },
    {
        label: "录入人",
        align: "center",
        prop: "createUserName",
    },
    // {
    //   label: "录入日期",
    //   align: "center",
    //   prop: "createTime",
    //   formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
    //   width: 200,
    // },
    {
        label: "实际保养人",
        align: "center",
        prop: "maintenanceActuallyName",
    },
    {
        label: "实际保养日期",
        align: "center",
        prop: "maintenanceActuallyTime",
        formatData: (cell) =>
            cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-",
    },
    {
        label: "保养结果",
        align: "center",
        prop: "maintenanceResult",
        dataType: "slot",
        slot: "maintenanceResultRef",
    },
    {
        label: "状态",
        align: "center",
        prop: "status",
        dataType: "slot",
        slot: "statusRef",
    },
    {
        fixed: "right",
        label: "操作",
        dataType: "slot",
        slot: "operation",
        align: "center",
        width: "350px",
    },
])
  // ä»»åŠ¡è®°å½•è¡¨æ ¼åˆ—é…ç½®ï¼ˆåŽŸè®¾å¤‡ä¿å…»è¡¨æ ¼åˆ—ï¼‰
  const columns = ref([
    {
      label: "设备名称",
      align: "center",
      prop: "deviceName",
    },
    {
      label: "规格型号",
      align: "center",
      prop: "deviceModel",
    },
    {
      label: "计划保养日期",
      align: "center",
      prop: "maintenancePlanTime",
      formatData: cell => dayjs(cell).format("YYYY-MM-DD"),
    },
    {
      label: "录入人",
      align: "center",
      prop: "createUserName",
    },
    // {
    //   label: "录入日期",
    //   align: "center",
    //   prop: "createTime",
    //   formatData: (cell) => dayjs(cell).format("YYYY-MM-DD HH:mm:ss"),
    //   width: 200,
    // },
    {
      label: "实际保养人",
      align: "center",
      prop: "maintenanceActuallyName",
    },
    {
      label: "实际保养日期",
      align: "center",
      prop: "maintenanceActuallyTime",
      formatData: cell =>
        cell ? dayjs(cell).format("YYYY-MM-DD HH:mm:ss") : "-",
    },
    {
      label: "保养结果",
      align: "center",
      prop: "maintenanceResult",
      dataType: "slot",
      slot: "maintenanceResultRef",
    },
    {
      label: "状态",
      align: "center",
      prop: "status",
      dataType: "slot",
      slot: "statusRef",
    },
    {
      fixed: "right",
      label: "操作",
      dataType: "slot",
      slot: "operation",
      align: "center",
      width: "350px",
    },
  ]);
// Tab切换处理
const handleTabChange = (tabName) => {
  if (tabName === 'record') {
    getTableData()
  } else if (tabName === 'scheduled') {
    getScheduledTableData()
  }
}
// å®šæ—¶ä»»åŠ¡ç®¡ç†ç›¸å…³æ–¹æ³•
const getScheduledTableData = async () => {
  try {
    const params = {
      current: scheduledPagination.currentPage,
      size: scheduledPagination.pageSize,
      taskName: scheduledFilters.taskName || undefined,
      status: scheduledFilters.status || undefined,
  // Tab切换处理
  const handleTabChange = tabName => {
    if (tabName === "record") {
      getTableData();
    } else if (tabName === "scheduled") {
      getScheduledTableData();
    }
    const { code, data } = await deviceMaintenanceTaskList(params)
    if (code === 200) {
      scheduledDataList.value = data?.records || []
      scheduledPagination.total = data?.total || 0
  };
  // å®šæ—¶ä»»åŠ¡ç®¡ç†ç›¸å…³æ–¹æ³•
  const getScheduledTableData = async () => {
    try {
      const params = {
        current: scheduledPagination.currentPage,
        size: scheduledPagination.pageSize,
        taskName: scheduledFilters.taskName || undefined,
        status: scheduledFilters.status || undefined,
      };
      const { code, data } = await deviceMaintenanceTaskList(params);
      if (code === 200) {
        scheduledDataList.value = data?.records || [];
        scheduledPagination.total = data?.total || 0;
      }
    } catch (error) {
      ElMessage.error("获取定时任务列表失败");
    }
  } catch (error) {
    ElMessage.error('获取定时任务列表失败')
  }
}
  };
const resetScheduledFilters = () => {
  scheduledFilters.taskName = ''
  scheduledFilters.status = ''
  getScheduledTableData()
}
  const resetScheduledFilters = () => {
    scheduledFilters.taskName = "";
    scheduledFilters.status = "";
    getScheduledTableData();
  };
const handleScheduledSelectionChange = (selection) => {
  scheduledMultipleList.value = selection
}
  const handleScheduledSelectionChange = selection => {
    scheduledMultipleList.value = selection;
  };
const changeScheduledPage = (page) => {
  scheduledPagination.currentPage = page.page
  scheduledPagination.pageSize = page.limit
  getScheduledTableData()
}
  const changeScheduledPage = page => {
    scheduledPagination.currentPage = page.page;
    scheduledPagination.pageSize = page.limit;
    getScheduledTableData();
  };
const addScheduledTask = () => {
  nextTick(() => {
        formDiaRef.value?.openDialog('add');
    });
}
  const addScheduledTask = () => {
    nextTick(() => {
      formDiaRef.value?.openDialog("add");
    });
  };
const editScheduledTask = (row) => {
  if (row) {
        nextTick(() => {
            formDiaRef.value?.openDialog('edit', row);
        });
  }
}
  const editScheduledTask = row => {
    if (row) {
      nextTick(() => {
        formDiaRef.value?.openDialog("edit", row);
      });
    }
  };
const delScheduledTaskByIds = async (ids) => {
  try {
    await ElMessageBox.confirm('确定删除选中的定时任务吗?', '提示', {
      type: 'warning',
  const delScheduledTaskByIds = async ids => {
    try {
      await ElMessageBox.confirm("确定删除选中的定时任务吗?", "提示", {
        type: "warning",
      });
      const payload = Array.isArray(ids) ? ids : [ids];
      await deviceMaintenanceTaskDel(payload);
      ElMessage.success("删除定时任务成功");
      getScheduledTableData();
    } catch (error) {
      // ç”¨æˆ·å–消删除
    }
  };
  const handleScheduledOut = () => {
    ElMessage.info("导出定时任务功能待实现");
  };
  // ä»»åŠ¡è®°å½•ç›¸å…³æ–¹æ³•ï¼ˆåŽŸè®¾å¤‡ä¿å…»é¡µé¢æ–¹æ³•ï¼‰
  const getTableData = async () => {
    try {
      const params = {
        current: pagination.value.currentPage,
        size: pagination.value.pageSize,
        deviceName: filters.deviceName || undefined,
        maintenancePlanTime: filters.maintenancePlanTime
          ? dayjs(filters.maintenancePlanTime).format("YYYY-MM-DD")
          : undefined,
        maintenanceActuallyTime: filters.maintenanceActuallyTime
          ? dayjs(filters.maintenanceActuallyTime).format("YYYY-MM-DD")
          : undefined,
        maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
      };
      const { code, data } = await getUpkeepPage(params);
      if (code === 200) {
        dataList.value = data.records;
        pagination.value.total = data.total;
      }
    } catch (error) {
      console.log(error);
    }
  };
  const resetFilters = () => {
    filters.deviceName = "";
    filters.maintenancePlanTime = "";
    filters.maintenanceActuallyTime = "";
    filters.maintenanceActuallyName = "";
    getTableData();
  };
  const handleSelectionChange = selection => {
    multipleList.value = selection;
  };
  // æ£€æŸ¥é€‰ä¸­çš„记录中是否有完结状态的
  const hasFinishedStatus = computed(() => {
    return multipleList.value.some(item => item.status === 1);
  });
  const changePage = page => {
    pagination.value.currentPage = page.page;
    pagination.value.pageSize = page.limit;
    getTableData();
  };
  const addMaintain = row => {
    maintainModalRef.value.open(row.id, row);
  };
  const addPlan = () => {
    planModalRef.value.openModal();
  };
  const editPlan = id => {
    planModalRef.value.openEdit(id);
  };
  const delRepairByIds = async ids => {
    // æ£€æŸ¥æ˜¯å¦æœ‰å®Œç»“状态的记录
    const hasFinished = multipleList.value.some(item => item.status === 1);
    if (hasFinished) {
      ElMessage.warning("不能删除状态为完结的记录");
      return;
    }
    try {
      await ElMessageBox.confirm("确认删除保养数据, æ­¤æ“ä½œä¸å¯é€†?", "警告", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      });
      const { code } = await delUpkeep(ids);
      if (code === 200) {
        ElMessage.success("删除成功");
        getTableData();
      }
    } catch (error) {
      // ç”¨æˆ·å–消删除
    }
  };
  const handleOut = () => {
    ElMessageBox.confirm("选中的内容将被导出,是否确认导出?", "导出", {
      confirmButtonText: "确认",
      cancelButtonText: "取消",
      type: "warning",
    })
    const payload = Array.isArray(ids) ? ids : [ids]
    await deviceMaintenanceTaskDel(payload)
    ElMessage.success('删除定时任务成功')
    getScheduledTableData()
  } catch (error) {
    // ç”¨æˆ·å–消删除
  }
}
      .then(() => {
        proxy.download("/device/maintenance/export", {}, "设备保养.xlsx");
      })
      .catch(() => {
        ElMessage.info("已取消");
      });
  };
const handleScheduledOut = () => {
  ElMessage.info('导出定时任务功能待实现')
}
// ä»»åŠ¡è®°å½•ç›¸å…³æ–¹æ³•ï¼ˆåŽŸè®¾å¤‡ä¿å…»é¡µé¢æ–¹æ³•ï¼‰
const getTableData = async () => {
  try {
    const params = {
      current: pagination.value.currentPage,
      size: pagination.value.pageSize,
      deviceName: filters.deviceName || undefined,
      maintenancePlanTime: filters.maintenancePlanTime ? dayjs(filters.maintenancePlanTime).format('YYYY-MM-DD') : undefined,
      maintenanceActuallyTime: filters.maintenanceActuallyTime ? dayjs(filters.maintenanceActuallyTime).format('YYYY-MM-DD') : undefined,
      maintenanceActuallyName: filters.maintenanceActuallyName || undefined,
  const handleDateChange = (date, type) => {
    if (type === 1) {
      filters.maintenanceActuallyTime = date
        ? dayjs(date).format("YYYY-MM-DD")
        : "";
    } else {
      filters.maintenancePlanTime = date ? dayjs(date).format("YYYY-MM-DD") : "";
    }
    getTableData();
  };
    const { code, data } = await getUpkeepPage(params)
    if (code === 200) {
      dataList.value = data.records
      pagination.value.total = data.total
  // é™„件相关方法
  // æŸ¥è¯¢é™„件列表
  const fetchMaintenanceTaskFiles = async deviceMaintenanceId => {
    try {
      const params = {
        current: 1,
        size: 100,
        deviceMaintenanceId,
        rulesRegulationsManagementId: deviceMaintenanceId,
      };
      const res = await listMaintenanceTaskFiles(params);
      const records = res?.data?.records || [];
      const mapped = records.map(item => ({
        id: item.id,
        name: item.fileName || item.name,
        url: item.fileUrl || item.url,
        raw: item,
      }));
      fileListDialogRef.value?.setList(mapped);
    } catch (error) {
      ElMessage.error("获取附件列表失败");
    }
  } catch (error) {
    console.log(error);
  }
}
  };
const resetFilters = () => {
  filters.deviceName = ''
  filters.maintenancePlanTime = ''
  filters.maintenanceActuallyTime = ''
  filters.maintenanceActuallyName = ''
  getTableData()
}
  // æ‰“开详情弹窗
  const openFileDialog = row => {
    currentDetailRow.value = row;
    detailDialogVisible.value = true;
  };
const handleSelectionChange = (selection) => {
  multipleList.value = selection
}
  // æ‰“开附件弹窗
  const openAttachmentDialog = async row => {
    currentMaintenanceTaskId.value = row.id;
    fileDialogVisible.value = true;
    await fetchMaintenanceTaskFiles(row.id);
  };
// æ£€æŸ¥é€‰ä¸­çš„记录中是否有完结状态的
const hasFinishedStatus = computed(() => {
  return multipleList.value.some(item => item.status === 1)
})
  // åˆ·æ–°é™„件列表
  const refreshFileList = async () => {
    if (!currentMaintenanceTaskId.value) return;
    await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value);
  };
const changePage = (page) => {
  pagination.value.currentPage = page.page
  pagination.value.pageSize = page.limit
  getTableData()
}
const addMaintain = (row) => {
  maintainModalRef.value.open(row.id, row)
}
const addPlan = () => {
  planModalRef.value.openModal()
}
const editPlan = (id) => {
  planModalRef.value.openEdit(id)
}
const delRepairByIds = async (ids) => {
  // æ£€æŸ¥æ˜¯å¦æœ‰å®Œç»“状态的记录
  const hasFinished = multipleList.value.some(item => item.status === 1)
  if (hasFinished) {
    ElMessage.warning('不能删除状态为完结的记录')
    return
  }
  try {
    await ElMessageBox.confirm('确认删除保养数据, æ­¤æ“ä½œä¸å¯é€†?', '警告', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
    const { code } = await delUpkeep(ids)
    if (code === 200) {
      ElMessage.success('删除成功')
      getTableData()
  // ä¸Šä¼ é™„ä»¶
  const handleAttachmentUpload = async filePayload => {
    if (!currentMaintenanceTaskId.value) return;
    try {
      const payload = {
        name: filePayload?.fileName || filePayload?.name,
        url: filePayload?.fileUrl || filePayload?.url,
        deviceMaintenanceId: currentMaintenanceTaskId.value,
      };
      await addMaintenanceTaskFile(payload);
      ElMessage.success("文件上传成功");
      await refreshFileList();
    } catch (error) {
      ElMessage.error("文件上传失败");
    }
  } catch (error) {
    // ç”¨æˆ·å–消删除
  }
}
  };
const handleOut = () => {
  ElMessageBox.confirm('选中的内容将被导出,是否确认导出?', '导出', {
    confirmButtonText: '确认',
    cancelButtonText: '取消',
    type: 'warning',
  })
    .then(() => {
      proxy.download('/device/maintenance/export', {}, '设备保养.xlsx')
    })
    .catch(() => {
      ElMessage.info('已取消')
    })
}
const handleDateChange = (date, type) => {
  if (type === 1) {
    filters.maintenanceActuallyTime = date ? dayjs(date).format('YYYY-MM-DD') : ''
  } else {
    filters.maintenancePlanTime = date ? dayjs(date).format('YYYY-MM-DD') : ''
  }
  getTableData()
}
// é™„件相关方法
// æŸ¥è¯¢é™„件列表
const fetchMaintenanceTaskFiles = async (deviceMaintenanceId) => {
  try {
    const params = {
      current: 1,
      size: 100,
      deviceMaintenanceId,
      rulesRegulationsManagementId:deviceMaintenanceId
  // åˆ é™¤é™„ä»¶
  const handleAttachmentDelete = async row => {
    if (!row?.id) return false;
    try {
      await ElMessageBox.confirm("确认删除该附件?", "提示", { type: "warning" });
    } catch {
      return false;
    }
    const res = await listMaintenanceTaskFiles(params)
    const records = res?.data?.records || []
    const mapped = records.map(item => ({
      id: item.id,
      name: item.fileName || item.name,
      url: item.fileUrl || item.url,
      raw: item,
    }))
    fileListDialogRef.value?.setList(mapped)
  } catch (error) {
    ElMessage.error('获取附件列表失败')
  }
}
// æ‰“开附件弹窗
const openFileDialog = async (row) => {
  currentMaintenanceTaskId.value = row.id
  fileDialogVisible.value = true
  await fetchMaintenanceTaskFiles(row.id)
}
// åˆ·æ–°é™„件列表
const refreshFileList = async () => {
  if (!currentMaintenanceTaskId.value) return
  await fetchMaintenanceTaskFiles(currentMaintenanceTaskId.value)
}
// ä¸Šä¼ é™„ä»¶
const handleAttachmentUpload = async (filePayload) => {
  if (!currentMaintenanceTaskId.value) return
  try {
    const payload = {
      name: filePayload?.fileName || filePayload?.name,
      url: filePayload?.fileUrl || filePayload?.url,
      deviceMaintenanceId: currentMaintenanceTaskId.value,
    try {
      await delMaintenanceTaskFile(row.id);
      ElMessage.success("删除成功");
      await refreshFileList();
      return true;
    } catch (error) {
      ElMessage.error("删除失败");
      return false;
    }
    await addMaintenanceTaskFile(payload)
    ElMessage.success('文件上传成功')
    await refreshFileList()
  } catch (error) {
    ElMessage.error('文件上传失败')
  }
}
  };
// åˆ é™¤é™„ä»¶
const handleAttachmentDelete = async (row) => {
  if (!row?.id) return false
  try {
    await ElMessageBox.confirm('确认删除该附件?', '提示', { type: 'warning' })
  } catch {
    return false
  }
  try {
    await delMaintenanceTaskFile(row.id)
    ElMessage.success('删除成功')
    await refreshFileList()
    return true
  } catch (error) {
    ElMessage.error('删除失败')
    return false
  }
}
onMounted(() => {
  // æ ¹æ®é»˜è®¤æ¿€æ´»çš„ Tab è°ƒç”¨å¯¹åº”的查询接口
  if (activeTab.value === 'scheduled') {
    getScheduledTableData()
  } else {
    getTableData()
  }
})
  onMounted(() => {
    // æ ¹æ®é»˜è®¤æ¿€æ´»çš„ Tab è°ƒç”¨å¯¹åº”的查询接口
    if (activeTab.value === "scheduled") {
      getScheduledTableData();
    } else {
      getTableData();
    }
  });
</script>
<style lang="scss" scoped>
.table_list {
  margin-top: unset;
}
.actions {
  display: flex;
  justify-content: space-between;
  margin-bottom: 10px;
}
  .table_list {
    margin-top: unset;
  }
  .actions {
    display: flex;
    justify-content: space-between;
    margin-bottom: 10px;
  }
</style>
src/views/inventoryManagement/receiptManagement/Record.vue
@@ -83,6 +83,10 @@
            {{ getRecordType(scope.row.recordType) }}
          </template>
        </el-table-column>
        <el-table-column label="过磅日期"
                         prop="weighingDate"
                         v-if="type === '0'"
                         show-overflow-tooltip/>
      </el-table>
      <pagination v-show="total > 0"
                  :total="total"
src/views/inventoryManagement/stockManagement/New.vue
@@ -51,6 +51,30 @@
        >
          <el-input-number v-model="formState.warnNum" :step="1" :min="0" :max="formState.qualitity" style="width: 100%" />
        </el-form-item>
        <!-- productType === 0:原材料 -->
        <el-form-item
            v-if="type === 'qualified' && formState.productType === 0"
            label="过磅日期"
            prop="weighingDate"
        >
          <el-date-picker
              style="width: 100%"
              v-model="formState.weighingDate"
              value-format="YYYY-MM-DD HH:mm:ss"
              format="YYYY-MM-DD HH:mm:ss"
              type="datetime"
              placeholder="请选择过磅日期"
              clearable
          />
        </el-form-item>
        <el-form-item
            v-if="type === 'qualified' && formState.productType === 0"
            label="净重(吨)"
            prop="netWeight"
        >
          <el-input-number v-model="formState.netWeight" :step="0.01" :min="0" style="width: 100%" />
        </el-form-item>
        <el-form-item label="备注" prop="remark">
          <el-input v-model="formState.remark" type="textarea" />
@@ -101,8 +125,11 @@
  productName: "",
  productModelName: "",
  unit: "",
  weighingDate: undefined,
  productType: undefined,
  qualitity: 0,
  warnNum: 0,
  netWeight: undefined,
  remark: '',
});
@@ -133,6 +160,8 @@
// äº§å“é€‰æ‹©å¤„理
const handleProductSelect = async (products) => {
  formState.value.weighingDate = undefined;
  formState.value.netWeight = undefined;
  if (products && products.length > 0) {
    const product = products[0];
    formState.value.productId = product.productId;
@@ -140,6 +169,7 @@
    formState.value.productModelName = product.model;
    formState.value.productModelId = product.id;
    formState.value.unit = product.unit;
    formState.value.productType = product.productType;
    showProductSelectDialog.value = false;
    // è§¦å‘表单验证更新
    proxy.$refs["formRef"]?.validateField('productModelId');
src/views/inventoryManagement/stockManagement/Qualified.vue
@@ -23,12 +23,14 @@
        :row-class-name="tableRowClassName" height="calc(100vh - 18.5em)">
        <el-table-column align="center" type="selection" width="55" />
        <el-table-column align="center" label="序号" type="index" width="60" />
        <el-table-column label="产品类型" prop="parentName" show-overflow-tooltip />
        <el-table-column label="产品大类" prop="productName" show-overflow-tooltip />
        <el-table-column label="规格型号" prop="model" show-overflow-tooltip />
        <el-table-column label="单位" prop="unit" show-overflow-tooltip />
        <el-table-column label="库存数量" prop="qualitity" show-overflow-tooltip />
        <el-table-column label="冻结数量" prop="lockedQuantity" show-overflow-tooltip />
        <el-table-column label="库存预警数量" prop="warnNum"  show-overflow-tooltip />
        <el-table-column label="净重(吨)" prop="netWeight"  show-overflow-tooltip />
        <el-table-column label="备注" prop="remark"  show-overflow-tooltip />
        <el-table-column label="最近更新时间" prop="updateTime" show-overflow-tooltip />
        <el-table-column fixed="right" label="操作" min-width="60" align="center">