Jelajahi Sumber

修改附件上传

zhangafei 1 bulan lalu
induk
melakukan
558ef6b607
42 mengubah file dengan 1145 tambahan dan 216 penghapusan
  1. 2 2
      .env.development
  2. 0 0
      src/assets/icons/device/el-device-allocate-transfer.svg
  3. 0 0
      src/assets/icons/device/el-device-base-info.svg
  4. 0 0
      src/assets/icons/device/el-device-equipment-disposal.svg
  5. 0 0
      src/assets/icons/device/el-device-events.svg
  6. 0 0
      src/assets/icons/device/el-device-information.svg
  7. 0 0
      src/assets/icons/device/el-device-maintain.svg
  8. 0 0
      src/assets/icons/device/el-device-maintenance.svg
  9. 0 0
      src/assets/icons/device/el-device-metering.svg
  10. 0 0
      src/assets/icons/device/el-device-point-inspection.svg
  11. 0 0
      src/assets/icons/device/el-device-spare-parts.svg
  12. 0 0
      src/assets/icons/device/el-device-verification.svg
  13. 1 0
      src/assets/icons/file/audio.svg
  14. 1 0
      src/assets/icons/file/excel.svg
  15. 1 0
      src/assets/icons/file/flash.svg
  16. 1 0
      src/assets/icons/file/html.svg
  17. 1 0
      src/assets/icons/file/other.svg
  18. 0 0
      src/assets/icons/file/pdf.svg
  19. 1 0
      src/assets/icons/file/ppt.svg
  20. 1 0
      src/assets/icons/file/text.svg
  21. 0 0
      src/assets/icons/file/video.svg
  22. 1 0
      src/assets/icons/file/word.svg
  23. 1 0
      src/assets/icons/file/zip.svg
  24. 12 12
      src/components/Form/src/jeecg/components/JUpload/JUpload.vue
  25. 2 0
      src/hooks/system/useJvxeMethods.ts
  26. 11 11
      src/views/equipmentLifecycle/device/list/components/DeviceBaseInfoDetailDrawer.vue
  27. 87 0
      src/views/equipmentLifecycle/manager/attachments/Attachments.api.ts
  28. 178 0
      src/views/equipmentLifecycle/manager/attachments/Attachments.data.ts
  29. 108 0
      src/views/equipmentLifecycle/manager/attachments/AttachmentsCard.vue
  30. 168 0
      src/views/equipmentLifecycle/manager/attachments/AttachmentsEditTable.vue
  31. 26 0
      src/views/equipmentLifecycle/manager/attachments/V20250423_1__menu_insert_Attachments.sql
  32. 70 0
      src/views/equipmentLifecycle/manager/attachments/components/AttachmentsForm.vue
  33. 76 0
      src/views/equipmentLifecycle/manager/attachments/components/AttachmentsModal.vue
  34. 208 0
      src/views/equipmentLifecycle/manager/attachments/index.vue
  35. 140 127
      src/views/equipmentLifecycle/supplier/accept/index.vue
  36. 5 1
      src/views/equipmentLifecycle/supplier/apply/list.vue
  37. 1 1
      src/views/equipmentLifecycle/supplier/list/index.vue
  38. 4 0
      src/views/equipmentLifecycle/supplier/plan/PurchasePlan.api.ts
  39. 7 28
      src/views/equipmentLifecycle/supplier/plan/PurchasePlan.data.ts
  40. 7 4
      src/views/equipmentLifecycle/supplier/plan/components/DetailDrawer.vue
  41. 23 29
      src/views/equipmentLifecycle/supplier/plan/components/PurchasePlanModal.vue
  42. 1 1
      src/views/equipmentLifecycle/supplier/plan/list.vue

+ 2 - 2
.env.development

@@ -6,10 +6,10 @@ VITE_PUBLIC_PATH = /
 
 
 # 跨域代理,您可以配置多个 ,请注意,没有换行符
-VITE_PROXY = [["/jeecgboot","http://192.168.1.6:9999"],["/upload","http://localhost:3300/upload"]]
+VITE_PROXY = [["/jeecgboot","http://192.168.1.53:9399"],["/upload","http://localhost:3300/upload"]]
 
 #后台接口全路径地址(必填)
-VITE_GLOB_DOMAIN_URL=http://192.168.1.6:9999
+VITE_GLOB_DOMAIN_URL=http://192.168.1.53:9399
 
 #后台接口父地址(必填)
 VITE_GLOB_API_URL=/jeecgboot

+ 0 - 0
src/assets/icons/el-device-allocate-transfer.svg → src/assets/icons/device/el-device-allocate-transfer.svg


+ 0 - 0
src/assets/icons/el-device-base-info.svg → src/assets/icons/device/el-device-base-info.svg


+ 0 - 0
src/assets/icons/el-device-equipment-disposal.svg → src/assets/icons/device/el-device-equipment-disposal.svg


+ 0 - 0
src/assets/icons/el-device-events.svg → src/assets/icons/device/el-device-events.svg


+ 0 - 0
src/assets/icons/el-device-information.svg → src/assets/icons/device/el-device-information.svg


+ 0 - 0
src/assets/icons/el-device-maintain.svg → src/assets/icons/device/el-device-maintain.svg


+ 0 - 0
src/assets/icons/el-device-maintenance.svg → src/assets/icons/device/el-device-maintenance.svg


+ 0 - 0
src/assets/icons/el-device-metering.svg → src/assets/icons/device/el-device-metering.svg


+ 0 - 0
src/assets/icons/el-device-point-inspection.svg → src/assets/icons/device/el-device-point-inspection.svg


+ 0 - 0
src/assets/icons/el-device-spare-parts.svg → src/assets/icons/device/el-device-spare-parts.svg


+ 0 - 0
src/assets/icons/el-device-verification.svg → src/assets/icons/device/el-device-verification.svg


+ 1 - 0
src/assets/icons/file/audio.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571541247" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1832" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M778.24 988.16H248.832c-84.48 0-153.6-69.632-153.6-154.624V190.464C95.232 105.472 164.352 35.84 248.832 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688l170.496 217.6c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 85.504-68.608 155.136-153.088 155.136z" fill="#E9FDEF" p-id="1833"></path><path d="M778.24 1024H248.832c-104.448 0-189.44-85.504-189.44-190.464V190.464C59.392 85.504 144.384 0 248.832 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM248.832 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#89F5A8" p-id="1834"></path><path d="M769.536 622.592h-56.832V508.928h56.832v113.664zM655.36 679.424h-56.832V452.096H655.36v227.328z m-113.664 85.504H484.864V366.592h56.832v398.336z m-113.664-85.504H371.2V452.096h56.832v227.328z m-113.664-56.832H257.536V508.928h56.832v113.664z" fill="#4DDB6B" p-id="1835"></path></svg>

+ 1 - 0
src/assets/icons/file/excel.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745569750313" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1766" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.704 985.6H247.296c-84.48 0-153.6-69.12-153.6-154.112V189.952C93.696 105.472 162.816 35.84 247.296 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688L901.12 303.616c18.432 23.552 28.672 52.736 28.672 82.432v444.928c0.512 84.992-68.608 154.624-153.088 154.624z" fill="#E9F6F3" p-id="1767"></path><path d="M776.704 1021.44H247.296c-104.448 0-189.44-84.992-189.44-189.952V189.952C57.856 84.992 142.848 0 247.296 0h378.88c52.224 0 100.352 23.552 132.608 64.512L929.28 281.6c23.552 29.696 36.352 66.56 36.352 104.96v444.928c0.512 104.96-84.48 189.952-188.928 189.952zM247.296 71.68c-65.024 0-117.76 52.736-117.76 118.272v641.536c0 65.024 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-52.736 117.76-118.272V386.56c0-21.504-7.168-43.008-20.992-60.416l-170.496-217.088c-18.432-23.552-46.592-36.864-76.288-36.864 0-0.512-378.88-0.512-378.88-0.512z" fill="#A3DBCC" p-id="1768"></path><path d="M595.456 749.056l-86.528-128-86.528 128H314.368l140.8-195.072-130.56-188.928h107.52l76.8 123.904 76.288-123.904h107.52l-130.56 188.928 140.8 195.072z" fill="#20A884" p-id="1769"></path></svg>

+ 1 - 0
src/assets/icons/file/flash.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571569570" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2832" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.704 988.16H247.296c-84.48 0-153.6-69.632-153.6-154.624V190.464C93.696 105.472 162.816 35.84 247.296 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688L901.12 304.64c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 84.992-68.608 154.624-153.088 154.624z" fill="#FFEEEF" p-id="2833"></path><path d="M776.704 1024H247.296c-104.448 0-189.44-85.504-189.44-190.464V190.464C57.856 85.504 142.848 0 247.296 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM247.296 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#FFB8BE" p-id="2834"></path><path d="M671.744 418.304c14.336-5.12 29.696-7.168 45.056-7.168V310.272c-68.608-2.048-134.144 28.672-176.128 82.944-17.408 22.528-32.256 47.104-44.032 73.728L464.384 547.84c-8.192 24.576-18.432 49.152-29.696 72.704-8.192 19.456-18.432 36.864-30.72 54.272a97.28 97.28 0 0 1-39.936 32.256c-17.408 8.192-36.864 12.288-56.32 12.288v102.4c68.608 2.048 133.632-28.672 176.128-82.944 13.312-18.432 25.6-37.888 35.84-58.368l27.648-64.512h139.264v-100.864H588.8c6.144-15.36 14.336-29.696 23.552-44.032 7.168-12.288 16.384-22.528 26.624-31.744 8.704-9.728 19.968-16.896 32.768-20.992z" fill="#FF5462" p-id="2835"></path></svg>

+ 1 - 0
src/assets/icons/file/html.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571529482" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1500" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M778.24 988.16H248.832c-84.48 0-153.6-69.632-153.6-154.624V190.464C95.232 105.472 164.352 35.84 248.832 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688l170.496 217.6c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 85.504-68.608 155.136-153.088 155.136z" fill="#E9FDEF" p-id="1501"></path><path d="M778.24 1024H248.832c-104.448 0-189.44-85.504-189.44-190.464V190.464C59.392 85.504 144.384 0 248.832 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM248.832 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#89F5A8" p-id="1502"></path><path d="M408.064 429.056c-12.288-12.8-32.768-13.312-45.056-1.024l-96.256 96.256c-12.288 12.288-12.288 32.768 0 45.056L362.496 665.6c12.288 11.776 32.256 11.776 44.544 0 12.8-12.288 13.312-32.768 1.024-45.056l-73.216-73.216 73.216-73.216c11.776-12.8 11.776-32.768 0-45.056zM759.808 524.288l-96.256-96.256c-12.288-11.776-32.256-11.776-44.544 0-12.8 12.288-13.312 32.768-1.024 45.056l73.216 73.216-73.216 73.216c-11.776 12.288-11.776 32.256 0 44.544 12.288 12.8 32.768 13.312 45.056 1.024l96.256-96.256c13.312-11.776 13.312-31.744 0.512-44.544zM573.952 406.016c-16.384-7.168-34.816 0-42.496 16.384L435.2 646.656c-6.656 15.872 0.512 34.304 16.384 41.472 16.384 7.168 34.816 0 42.496-16.384l96.256-224.256c7.168-15.872-0.512-34.304-16.384-41.472z" fill="#4DDB6B" p-id="1503"></path></svg>

+ 1 - 0
src/assets/icons/file/other.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571580773" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3000" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M783.36 988.16H253.952c-84.48 0-153.6-69.632-153.6-154.624V190.464C100.352 105.472 169.472 35.84 253.952 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688l170.496 217.6c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 85.504-68.608 155.136-153.088 155.136z" fill="#E6F1FF" p-id="3001"></path><path d="M783.36 1024H253.952c-104.448 0-189.44-85.504-189.44-190.464V190.464C64.512 85.504 149.504 0 253.952 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM253.952 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#96C6FF" p-id="3002"></path><path d="M741.376 531.968l-13.312-13.312c-5.12-5.12-11.264-7.68-18.432-7.68s-13.312 2.56-18.432 7.68L520.704 691.2l-2.56 2.56-148.992-148.992 143.36-143.36 57.856 57.856L497.152 532.48c-6.656 6.656-6.656 17.92 0 25.088l24.064 24.064c6.656 6.656 18.432 6.656 25.088 0L650.24 477.696c10.24-10.24 10.24-26.624 0-36.864L537.088 327.68c-10.24-10.24-26.624-10.24-36.864 0l-204.288 204.288c-5.12 5.12-7.68 11.264-7.68 18.432s2.56 13.312 7.68 18.432L500.224 773.12c5.12 5.12 11.776 7.68 18.432 7.68 6.656 0 13.312-2.56 18.432-7.68l204.288-204.288c10.24-10.24 10.24-26.624 0-36.864z" fill="#0075FF" p-id="3003"></path></svg>

File diff ditekan karena terlalu besar
+ 0 - 0
src/assets/icons/file/pdf.svg


+ 1 - 0
src/assets/icons/file/ppt.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571558439" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2498" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.704 988.16H247.296c-84.48 0-153.6-69.632-153.6-154.624V190.464C93.696 105.472 162.816 35.84 247.296 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688L901.12 304.64c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 84.992-68.608 154.624-153.088 154.624z" fill="#FFF0EB" p-id="2499"></path><path d="M776.704 1024H247.296c-104.448 0-189.44-85.504-189.44-190.464V190.464C57.856 85.504 142.848 0 247.296 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM247.296 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#FFC1AC" p-id="2500"></path><path d="M359.424 768V337.92h145.408c123.904 0 167.936 37.888 167.936 144.384 0 110.592-44.032 149.504-167.936 149.504H445.44V768H359.424zM445.44 565.248h46.08c69.12 0 92.672-20.48 92.672-80.384 0-58.88-25.088-80.384-92.672-80.384h-46.08v160.768z" fill="#FF6A38" p-id="2501"></path></svg>

+ 1 - 0
src/assets/icons/file/text.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571551525" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2164" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.704 988.16H247.296c-84.48 0-153.6-69.632-153.6-154.624V190.464C93.696 105.472 162.816 35.84 247.296 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688L901.12 304.64c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 84.992-68.608 154.624-153.088 154.624z" fill="#E6F5FC" p-id="2165"></path><path d="M776.704 1024H247.296c-104.448 0-189.44-85.504-189.44-190.464V190.464C57.856 85.504 142.848 0 247.296 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM247.296 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#96D6F4" p-id="2166"></path><path d="M708.608 427.52h-148.992v339.456H467.968V427.52H318.976V347.136h389.632v80.384z" fill="#009DE6" p-id="2167"></path></svg>

File diff ditekan karena terlalu besar
+ 0 - 0
src/assets/icons/file/video.svg


+ 1 - 0
src/assets/icons/file/word.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571547820" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1998" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.04389 985.695761H247.95611c-84.269327 0-153.216958-68.947631-153.216958-153.727681V192.03192c0-84.269327 68.947631-153.727681 153.216958-153.727681h377.935162c40.857855 0 79.162095 18.896758 104.187531 50.561596L900.149626 305.412469c18.386035 23.493267 28.600499 52.604489 28.600499 82.226434v443.818454c0.510723 84.78005-68.436908 154.238404-152.706235 154.238404z" fill="#E6F1FF" p-id="1999"></path><path d="M776.04389 1024H247.95611c-104.187531 0-188.967581-85.290773-188.967581-190.499751V190.499751C58.988529 85.290773 143.768579 0 247.95611 0h377.935162c52.093766 0 100.101746 23.493267 132.277307 64.861845l170.070822 217.56808c23.493267 29.621945 36.261347 66.904738 36.261347 105.208978v446.37207c0.510723 104.698254-84.269327 189.989027-188.456858 189.989027zM247.95611 72.01197c-64.861845 0-117.466334 53.115212-117.466334 118.487781v643.000498c0 65.372569 52.604489 118.487781 117.466334 118.487781h527.577057c64.861845 0 117.466334-53.115212 117.466334-118.487781V387.638903c0-21.450374-7.150125-43.411471-20.939651-60.77606l-170.070823-217.56808c-18.386035-23.493267-46.47581-37.282793-76.097755-37.282793h-377.935162z" fill="#96C6FF" p-id="2000"></path><path d="M292.389027 387.12818h76.608479l48.00798 247.190024h3.064339l51.07232-215.014463h84.78005l48.00798 215.014463h3.064339l49.029426-247.190024H731.610973l-76.608479 334.012967h-91.419452L512 509.191022h-3.064339l-52.604489 211.950125H364.911721L292.389027 387.12818z" fill="#0075FF" p-id="2001"></path></svg>

+ 1 - 0
src/assets/icons/file/zip.svg

@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1745571561263" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2666" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M776.704 988.16H247.296c-84.48 0-153.6-69.632-153.6-154.624V190.464C93.696 105.472 162.816 35.84 247.296 35.84h378.88c40.96 0 79.36 18.944 104.448 50.688L901.12 304.64c18.432 23.552 28.672 53.248 28.672 82.944v445.952c0.512 84.992-68.608 154.624-153.088 154.624z" fill="#F5ECEC" p-id="2667"></path><path d="M776.704 1024H247.296c-104.448 0-189.44-85.504-189.44-190.464V190.464C57.856 85.504 142.848 0 247.296 0h378.88c52.224 0 100.352 23.552 132.608 65.024l170.496 217.6c23.552 29.696 36.352 67.072 36.352 104.96v445.952c0.512 104.96-84.48 190.464-188.928 190.464zM247.296 72.192c-65.024 0-117.76 53.248-117.76 118.272v643.072c0 65.536 52.736 118.272 117.76 118.272h528.896c65.024 0 117.76-53.248 117.76-118.272V387.584c0-21.504-7.168-43.008-20.992-60.928l-170.496-217.6c-18.432-23.552-46.592-36.864-76.288-36.864h-378.88z" fill="#DBBDBD" p-id="2668"></path><path d="M332.8 744.96v-52.224L576.512 414.72H350.72V355.84h326.144v52.736L433.664 686.08H691.2v58.88z" fill="#BC8585" p-id="2669"></path></svg>

+ 12 - 12
src/components/Form/src/jeecg/components/JUpload/JUpload.vue

@@ -26,7 +26,7 @@
 </template>
 
 <script lang="ts" setup>
-  import { ref, reactive, computed, watch, nextTick, createApp,unref } from 'vue';
+  import { ref, reactive, computed, watch, nextTick, createApp, unref } from 'vue';
   import { Icon } from '/@/components/Icon';
   import { getToken } from '/@/utils/auth';
   import { uploadUrl } from '/@/api/common/api';
@@ -82,18 +82,18 @@
   // 当前是否是上传图片模式
   const isImageMode = computed(() => props.fileType === UploadTypeEnum.image);
   // 上传按钮是否禁用
-  const buttonDisabled = computed(()=>{
-    if(props.disabled === true){
+  const buttonDisabled = computed(() => {
+    if (props.disabled === true) {
       return true;
     }
-    if(isMaxCount.value === true){
-      if(props.replaceLastOne === true){
-        return false
-      }else{
+    if (isMaxCount.value === true) {
+      if (props.replaceLastOne === true) {
+        return false;
+      } else {
         return true;
       }
     }
-    return false
+    return false;
   });
   // 合并 props 和 attrs
   const bindProps = computed(() => {
@@ -299,9 +299,9 @@
           }
           return file;
         });
-      }else{
-        successFileList = fileListTemp.filter(item=>{
-          return item.uid!=info.file.uid;
+      } else {
+        successFileList = fileListTemp.filter((item) => {
+          return item.uid != info.file.uid;
         });
         createMessage.error(`${info.file.name} 上传失败.`);
       }
@@ -328,7 +328,7 @@
               fileSize: item.size,
             };
             newFileList.push(fileJson);
-          }else{
+          } else {
             return;
           }
         }

+ 2 - 0
src/hooks/system/useJvxeMethods.ts

@@ -40,6 +40,7 @@ export function useJvxeMethod(requestAddOrEdit, classifyIntoFormData, tableRefs,
   }
   /** 确定按钮点击事件 */
   function handleSubmit() {
+    console.log('handleSubmit0000000000000000000');
     /** 触发表单验证 */
     getAllTable()
       .then((tables) => {
@@ -56,6 +57,7 @@ export function useJvxeMethod(requestAddOrEdit, classifyIntoFormData, tableRefs,
         }
         const formData = classifyIntoFormData(allValues);
         // 发起请求
+        console.log('777777777777777777777777777', formData);
         return requestAddOrEdit(formData);
       })
       .catch((e) => {

+ 11 - 11
src/views/equipmentLifecycle/device/list/components/DeviceBaseInfoDetailDrawer.vue

@@ -26,17 +26,17 @@
 
       // tab List
       const tabList = [
-        { key: '1', tab: '基本信息', icon: 'el-device-base-info', disabled: false, component: 'BaseInfo', size: '32' },
-        { key: '2', tab: '资料', icon: 'el-device-information', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '3', tab: '维修', icon: 'el-device-maintenance', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '4', tab: '保养', icon: 'el-device-maintain', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '5', tab: '点巡检', icon: 'el-device-point-inspection', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '6', tab: '调拨', icon: 'el-device-allocate-transfer', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '7', tab: '设备处置', icon: 'el-device-equipment-disposal', disabled: true, component: 'BaseInfo', size: '32' },
-        { key: '8', tab: '备件', icon: 'el-device-spare-parts', disabled: false, component: 'BaseInfo', size: '32' },
-        { key: '9', tab: '事件', icon: 'el-device-events', disabled: false, component: 'BaseInfo', size: '32' },
-        { key: '10', tab: '计量', icon: 'el-device-metering', disabled: false, component: 'BaseInfo', size: '32' },
-        { key: '11', tab: '检定', icon: 'el-device-verification', disabled: false, component: 'BaseInfo', size: '32' },
+        { key: '1', tab: '基本信息', icon: 'device-el-device-base-info', disabled: false, component: 'BaseInfo', size: '32' },
+        { key: '2', tab: '资料', icon: 'device-el-device-information', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '3', tab: '维修', icon: 'device-el-device-maintenance', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '4', tab: '保养', icon: 'device-el-device-maintain', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '5', tab: '点巡检', icon: 'device-el-device-point-inspection', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '6', tab: '调拨', icon: 'device-el-device-allocate-transfer', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '7', tab: '设备处置', icon: 'device-el-device-equipment-disposal', disabled: true, component: 'BaseInfo', size: '32' },
+        { key: '8', tab: '备件', icon: 'device-el-device-spare-parts', disabled: false, component: 'BaseInfo', size: '32' },
+        { key: '9', tab: '事件', icon: 'device-el-device-events', disabled: false, component: 'BaseInfo', size: '32' },
+        { key: '10', tab: '计量', icon: 'device-el-device-metering', disabled: false, component: 'BaseInfo', size: '32' },
+        { key: '11', tab: '检定', icon: 'device-el-device-verification', disabled: false, component: 'BaseInfo', size: '32' },
       ];
 
       // 抽屉注册及关闭方法,用于openDrawer方法中

+ 87 - 0
src/views/equipmentLifecycle/manager/attachments/Attachments.api.ts

@@ -0,0 +1,87 @@
+import { defHttp } from '/@/utils/http/axios';
+import { useMessage } from '/@/hooks/web/useMessage';
+
+const { createConfirm } = useMessage();
+
+enum Api {
+  list = '/attachments/attachments/list',
+  save = '/attachments/attachments/add',
+  edit = '/attachments/attachments/edit',
+  deleteOne = '/attachments/attachments/delete',
+  deleteBatch = '/attachments/attachments/deleteBatch',
+  importExcel = '/attachments/attachments/importExcel',
+  exportXls = '/attachments/attachments/exportXls',
+  // 批量添加或者修改
+  batchInsertOrUpdate = '/attachments/attachments/addAll',
+  // 根据主表删除
+  deleteByExtId = '/attachments/attachments/deleteByMainId',
+}
+/**
+ * 导出api
+ * @param params
+ */
+export const getExportUrl = Api.exportXls;
+/**
+ * 导入api
+ */
+export const getImportUrl = Api.importExcel;
+/**
+ * 列表接口
+ * @param params
+ */
+export const list = (params) => defHttp.get({ url: Api.list, params });
+
+/**
+ * 根据外键获取附件
+ */
+
+export const attachmentsByExtId = Api.list;
+
+/**
+ * 删除单个
+ */
+export const deleteOne = (params, handleSuccess) => {
+  return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+    handleSuccess();
+  });
+};
+/**
+ * 批量删除
+ * @param params
+ */
+export const batchDelete = (params, handleSuccess) => {
+  createConfirm({
+    iconType: 'warning',
+    title: '确认删除',
+    content: '是否删除选中数据',
+    okText: '确认',
+    cancelText: '取消',
+    onOk: () => {
+      return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+        handleSuccess();
+      });
+    },
+  });
+};
+
+export const batchEditTableDelete = (params) => {
+  return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true });
+};
+/**
+ * 保存或者更新
+ * @param params
+ */
+export const saveOrUpdate = (params, isUpdate) => {
+  const url = isUpdate ? Api.edit : Api.save;
+  return defHttp.post({ url: url, params });
+};
+
+// 批量添加或者修改
+export const batchInsertOrUpdate = (params) => {
+  return defHttp.post({ url: Api.batchInsertOrUpdate, params });
+};
+
+// 根据主表删除
+export const deleteByExtId = (params) => {
+  return defHttp.delete({ url: Api.deleteByExtId, params }, { joinParamsToUrl: true });
+};

+ 178 - 0
src/views/equipmentLifecycle/manager/attachments/Attachments.data.ts

@@ -0,0 +1,178 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+// import { rules } from '/@/utils/helper/validator';
+// import { render } from '/@/utils/common/renderUtils';
+// import { getWeekMonthQuarterYear } from '/@/utils';
+import { JVxeTypes, JVxeColumn } from '/@/components/jeecg/JVxeTable/types';
+import dayjs from 'dayjs';
+import { getDictItemsByCode } from '/@/utils/dict/index';
+
+// 获取附件上传路径
+export const getUploadPath = ({ mainTable }) => `equipmentLifecycle/${mainTable}/${dayjs().format('YYYY/MM/DD')}`;
+
+// 获取附件扩展名
+export const getFileExtension = (fileName) => {
+  if (fileName) {
+    // 处理路径并获取文件名
+    const baseName = fileName.split(/[/\\]/).pop(); // 支持Windows和Unix路径
+    const lastDot = baseName.lastIndexOf('.');
+    // 确保存在点且不在文件名开头
+    return lastDot !== -1 ? baseName.slice(lastDot + 1) : 'other';
+  }
+  return 'other';
+};
+
+// 获取文件类型
+export const getFileType = (type: string): string => {
+  const fileTypeList = getDictItemsByCode('file_type') || [];
+  const fileTypeObj = fileTypeList.find((item) => item.value === type);
+  return fileTypeObj ? fileTypeObj.text : 'other';
+};
+
+//列表数据
+export const columns: BasicColumn[] = [
+  {
+    title: '文件名称',
+    align: 'left',
+    dataIndex: 'fileName',
+    slots: { customRender: 'fileName' },
+  },
+  {
+    title: '文件地址',
+    align: 'center',
+    dataIndex: 'fileAddress',
+  },
+  {
+    title: '附件关联模块',
+    align: 'center',
+    dataIndex: 'extTable',
+  },
+  {
+    title: '文件类型',
+    align: 'center',
+    dataIndex: 'type',
+  },
+  {
+    title: '文件大小',
+    align: 'center',
+    dataIndex: 'size',
+  },
+];
+//查询数据
+export const searchFormSchema: FormSchema[] = [];
+//表单数据
+export const formSchema: FormSchema[] = [
+  {
+    label: '文件名称',
+    field: 'fileName',
+    component: 'Input',
+  },
+  {
+    label: '文件地址',
+    field: 'fileAddress',
+    component: 'Input',
+  },
+  {
+    label: '附件关联表的id',
+    field: 'extId',
+    component: 'Input',
+  },
+  {
+    label: '附件关联表的名称',
+    field: 'extTable',
+    component: 'Input',
+  },
+  {
+    label: '文件类型',
+    field: 'type',
+    component: 'Input',
+  },
+  {
+    label: '文件大小',
+    field: 'size',
+    component: 'InputNumber',
+  },
+  // TODO 主键隐藏字段,目前写死为ID
+  {
+    label: '',
+    field: 'id',
+    component: 'Input',
+    show: false,
+  },
+];
+
+// 高级查询数据
+export const superQuerySchema = {
+  fileName: { title: '文件名称', order: 0, view: 'text', type: 'string' },
+  fileAddress: { title: '文件地址', order: 1, view: 'text', type: 'string' },
+  extId: { title: '附件关联表的id', order: 2, view: 'text', type: 'string' },
+  extTable: { title: '附件关联表的名称', order: 3, view: 'text', type: 'string' },
+  type: { title: '文件类型', order: 4, view: 'text', type: 'string' },
+  size: { title: '文件大小', order: 5, view: 'number', type: 'number' },
+};
+
+/**
+ * 流程表单调用这个方法获取formSchema
+ * @param param
+ */
+export function getBpmFormSchema(_formData): FormSchema[] {
+  // 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
+  return formSchema;
+}
+
+// 附件表字段
+export const getAttachmentsColumns = (options?: any): JVxeColumn[] => {
+  // const { extTable } = options || {};
+  console.log('getAttachmentsColumns', options);
+  return [
+    {
+      title: '文件地址',
+      key: 'fileAddress',
+      type: JVxeTypes.slot,
+      token: true,
+      action: '/jeecgboot/sys/common/upload',
+      responseName: 'message',
+      placeholder: '请输入${title}',
+      defaultValue: '',
+      slotName: 'fileAddress',
+      validateRules: [{ required: true, message: '文件不能' }],
+    },
+    {
+      title: '文件名称',
+      key: 'fileName',
+      type: JVxeTypes.input,
+      placeholder: '请输入${title}',
+      defaultValue: '',
+    },
+    {
+      title: '文件大小',
+      key: 'size',
+      type: JVxeTypes.input,
+      placeholder: '请输入${title}',
+      defaultValue: '',
+    },
+    {
+      title: '文件类型',
+      key: 'type',
+      type: JVxeTypes.input,
+      placeholder: '请输入${title}',
+      defaultValue: '',
+    },
+  ];
+};
+
+//查询数据
+export const editTableformSchema: FormSchema[] = [
+  {
+    label: '关联表',
+    field: 'extTable',
+    component: 'Input',
+    show: false,
+  },
+  {
+    label: '关联表id',
+    field: 'extId',
+    component: 'Input',
+    show: false,
+  },
+];

+ 108 - 0
src/views/equipmentLifecycle/manager/attachments/AttachmentsCard.vue

@@ -0,0 +1,108 @@
+<template>
+  <a-card style="width: 100%" :bodyStyle="{ padding: '10px', minHeight: '40px' }">
+    <a-spin :spinning="loading">
+      <a-row class="file-list" wrap :gutter="[16, 16]">
+        <a-col class="file-item" v-for="item in filesList" :key="item.id">
+          <div class="icon">
+            <template v-if="getFileType(item.type) === 'image'">
+              <a-image :width="120" :src="getFileAccessHttpUrl(item.fileAddress)" />
+            </template>
+            <template v-else>
+              <SvgIcon size="70" :name="`file-${getFileType(item.type)}`" />
+            </template>
+          </div>
+          <div class="file-name" :title="item.fileName">
+            <a-button class="line-1" type="link">{{ item.fileName }}</a-button>
+          </div>
+          <div class="file-size">
+            <a-button type="link">{{ calculateFileSize(item.size) }}</a-button>
+          </div>
+        </a-col>
+      </a-row>
+    </a-spin>
+  </a-card>
+</template>
+
+<script lang="ts" name="attachments-attachments" setup>
+  import { ref } from 'vue';
+  import { list } from './Attachments.api';
+  import { calculateFileSize } from '/@/utils/common/compUtils';
+  import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
+  import { Image as AImage } from 'ant-design-vue';
+  import { SvgIcon } from '/@/components/Icon';
+  import { getFileType } from './Attachments.data';
+
+  const props = defineProps({
+    extId: {
+      type: String,
+      default: '',
+    },
+    extTable: {
+      type: String,
+      default: '',
+    },
+  });
+
+  const loading = ref(false);
+  const filesList = ref<any[]>([]);
+
+  const getList = async () => {
+    try {
+      loading.value = true;
+      const res = await list({
+        extId: props.extId,
+        extTable: props.extTable,
+        pageNo: 1,
+        pageSize: 999,
+      });
+
+      console.log(res);
+      if (res.records) {
+        filesList.value = res.records;
+      }
+    } catch (e) {
+      console.log(e);
+    } finally {
+      loading.value = false;
+    }
+  };
+
+  defineExpose({
+    reload: getList,
+  });
+</script>
+
+<style lang="less" scoped>
+  .file-list {
+    width: 100%;
+
+    .file-item {
+      width: 136px;
+
+      .icon {
+        width: 120px;
+        height: 120px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        border: 1px solid #e5e7eb;
+        border-radius: 8px;
+        overflow: hidden;
+      }
+
+      .ant-btn {
+        width: 120px;
+        padding-left: 0;
+        padding-right: 0;
+        text-align: left;
+
+        :deep(span) {
+          width: 120px;
+          white-space: nowrap;
+          overflow: hidden;
+          text-overflow: ellipsis;
+        }
+      }
+    }
+  }
+</style>

+ 168 - 0
src/views/equipmentLifecycle/manager/attachments/AttachmentsEditTable.vue

@@ -0,0 +1,168 @@
+<template>
+  <BasicForm @register="registerForm" ref="formRef" name="PurchasePlanForm" />
+  <JVxeTable
+    keep-source
+    resizable
+    ref="attachmentsTableRef"
+    :loading="attachmentsTable.loading"
+    :columns="attachmentsTable.columns"
+    :dataSource="attachmentsTable.dataSource"
+    :height="340"
+    :rowNumber="true"
+    :rowSelection="true"
+    :disabled="formDisabled"
+    :toolbar="true"
+    class="attachments-edit-table"
+    @removed="handleUploadRemove"
+  >
+    <template #fileAddress="fileProps">
+      <JUpload
+        :value="fileProps.row && fileProps.row.fileAddress ? [{ fileName: fileProps.row.fileName }] : []"
+        :bizPath="getUploadPath({ mainTable })"
+        :returnUrl="false"
+        :buttonVisible="!fileProps.row.fileAddress"
+        :max-count="1"
+        @change="handleUploadChange($event, fileProps)"
+      />
+    </template>
+  </JVxeTable>
+  <a-button type="primary" @click="handleSubmit">保存</a-button>
+</template>
+<script lang="ts" setup>
+  import { reactive, ref } from 'vue';
+  import { BasicForm, useForm } from '/@/components/Form/index';
+  import { JVxeTable } from '/@/components/jeecg/JVxeTable';
+  import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods';
+  import JUpload from '/@/components/Form/src/jeecg/components/JUpload/JUpload.vue';
+  import { getAttachmentsColumns } from './Attachments.data';
+  import { getUploadPath, getFileExtension, editTableformSchema } from './Attachments.data';
+  import { attachmentsByExtId, batchEditTableDelete, batchInsertOrUpdate } from './Attachments.api';
+
+  const props = defineProps({
+    formDisabled: {
+      type: Boolean,
+      default: false,
+    },
+    mainTable: {
+      type: String,
+      default: 'default_file',
+    },
+    mainId: {
+      type: [String, Number],
+      default: '',
+    },
+  });
+
+  const attachmentsTableRef = ref();
+
+  const attachmentsTable = reactive({
+    loading: false,
+    dataSource: [],
+    columns: getAttachmentsColumns({
+      extId: props.mainId,
+      extTable: props.mainTable,
+    }),
+  });
+
+  //表单配置
+  const [registerForm, { resetFields, setFieldsValue }] = useForm({
+    labelWidth: 110,
+    schemas: editTableformSchema,
+    showActionButtonGroup: false,
+    baseColProps: { span: 24 },
+  });
+  // 方法配置
+  const activeKey = ref('attachmentsTable');
+  const refKeys = ref(['attachmentsTable']);
+  const tableRefs = { attachmentsTableRef };
+  const [, handleSubmit, requestSubTableData, formRef] = useJvxeMethod(
+    addOrEditFile,
+    (allValues) => {
+      let main = Object.assign({}, allValues.formValue);
+      return {
+        ...main, // 展开
+        attachmentsList: allValues.tablesValue[0].tableData,
+      };
+    },
+    tableRefs,
+    activeKey,
+    refKeys
+  );
+
+  // 上传
+  const handleUploadChange = (fileList: any, fileProps: any) => {
+    const fileArr = JSON.parse(fileList)[0] || {};
+    const { row } = fileProps;
+    const values = {
+      fileAddress: fileArr.filePath || '',
+      fileName: fileArr.fileName || '',
+      size: fileArr.fileSize || '',
+      type: getFileExtension(fileArr.fileName),
+    };
+    attachmentsTableRef.value.setValues([{ rowKey: row.id, values }]);
+  };
+
+  // 重置
+  const reset = () => {
+    attachmentsTable.dataSource = [];
+  };
+
+  // 填充数据
+  const requestFileTableData = async () => {
+    await resetFields();
+    await setFieldsValue({
+      extTable: props.mainTable,
+      extId: props.mainId,
+    });
+    if (typeof requestSubTableData === 'function') {
+      requestSubTableData(attachmentsByExtId, { extTable: props.mainTable, extId: props.mainId }, attachmentsTable);
+    }
+  };
+
+  // 保存附件或者编辑
+  async function addOrEditFile(values) {
+    try {
+      if (!values || !values.attachmentsList || !values.attachmentsList.length) return;
+      const params = values.attachmentsList.map((item) => {
+        return {
+          ...item,
+          extTable: props.mainTable,
+          extId: props.mainId,
+        };
+      });
+
+      await batchInsertOrUpdate(params);
+    } finally {
+    }
+  }
+
+  // 删除行
+  const handleUploadRemove = ({ deleteRows }) => {
+    console.log('11111111111111111111', deleteRows);
+    batchEditTableDelete({ ids: deleteRows.map((item) => item.id) })
+      .then((res) => {
+        console.log('res', res);
+      })
+      .catch((err) => {
+        console.log('err', err);
+        requestFileTableData();
+      });
+  };
+
+  defineExpose({
+    reset,
+    requestFileTableData,
+    sumbit: handleSubmit,
+  });
+</script>
+<style lang="less" scoped>
+  .attachments-edit-table {
+    width: 100%;
+
+    :deep(.ant-upload-wrapper) {
+      .ant-upload-list .ant-upload-list-item {
+        margin-top: 0;
+      }
+    }
+  }
+</style>

+ 26 - 0
src/views/equipmentLifecycle/manager/attachments/V20250423_1__menu_insert_Attachments.sql

@@ -0,0 +1,26 @@
+-- 注意:该页面对应的前台目录为views/attachments文件夹下
+-- 如果你想更改到其他目录,请修改sql中component字段对应的值
+
+
+INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external) 
+VALUES ('2025042303294350090', NULL, '相关附件', '/attachments/attachmentsList', 'attachments/AttachmentsList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0);
+
+-- 权限控制sql
+-- 新增
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350091', '2025042303294350090', '添加相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);
+-- 编辑
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350092', '2025042303294350090', '编辑相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);
+-- 删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350093', '2025042303294350090', '删除相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);
+-- 批量删除
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350094', '2025042303294350090', '批量删除相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);
+-- 导出excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350095', '2025042303294350090', '导出excel_相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);
+-- 导入excel
+INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
+VALUES ('2025042303294350096', '2025042303294350090', '导入excel_相关附件', NULL, NULL, 0, NULL, NULL, 2, 'attachments:sbsmzq_attachments:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-04-23 15:29:09', NULL, NULL, 0, 0, '1', 0);

+ 70 - 0
src/views/equipmentLifecycle/manager/attachments/components/AttachmentsForm.vue

@@ -0,0 +1,70 @@
+<template>
+    <div style="min-height: 400px">
+        <BasicForm @register="registerForm"></BasicForm>
+        <div style="width: 100%;text-align: center" v-if="!formDisabled">
+            <a-button @click="submitForm" pre-icon="ant-design:check" type="primary">提 交</a-button>
+        </div>
+    </div>
+</template>
+
+<script lang="ts">
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {computed, defineComponent} from 'vue';
+    import {defHttp} from '/@/utils/http/axios';
+    import { propTypes } from '/@/utils/propTypes';
+    import {getBpmFormSchema} from '../Attachments.data';
+    import {saveOrUpdate} from '../Attachments.api';
+    
+    export default defineComponent({
+        name: "AttachmentsForm",
+        components:{
+            BasicForm
+        },
+        props:{
+            formData: propTypes.object.def({}),
+            formBpm: propTypes.bool.def(true),
+        },
+        setup(props){
+            const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
+                labelWidth: 150,
+                schemas: getBpmFormSchema(props.formData),
+                showActionButtonGroup: false,
+                baseColProps: {span: 24}
+            });
+
+            const formDisabled = computed(()=>{
+                if(props.formData.disabled === false){
+                    return false;
+                }
+                return true;
+            });
+
+            let formData = {};
+            const queryByIdUrl = '/attachments/attachments/queryById';
+            async function initFormData(){
+                let params = {id: props.formData.dataId};
+                const data = await defHttp.get({url: queryByIdUrl, params});
+                formData = {...data}
+                //设置表单的值
+                await setFieldsValue(formData);
+                //默认是禁用
+                await setProps({disabled: formDisabled.value})
+            }
+
+            async function submitForm() {
+                let data = getFieldsValue();
+                let params = Object.assign({}, formData, data);
+                console.log('表单数据', params)
+                await saveOrUpdate(params, true)
+            }
+
+            initFormData();
+            
+            return {
+                registerForm,
+                formDisabled,
+                submitForm,
+            }
+        }
+    });
+</script>

+ 76 - 0
src/views/equipmentLifecycle/manager/attachments/components/AttachmentsModal.vue

@@ -0,0 +1,76 @@
+<template>
+  <BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
+      <BasicForm @register="registerForm" name="AttachmentsForm" />
+  </BasicModal>
+</template>
+
+<script lang="ts" setup>
+    import {ref, computed, unref} from 'vue';
+    import {BasicModal, useModalInner} from '/@/components/Modal';
+    import {BasicForm, useForm} from '/@/components/Form/index';
+    import {formSchema} from '../Attachments.data';
+    import {saveOrUpdate} from '../Attachments.api';
+    // Emits声明
+    const emit = defineEmits(['register','success']);
+    const isUpdate = ref(true);
+    const isDetail = ref(false);
+    //表单配置
+    const [registerForm, { setProps,resetFields, setFieldsValue, validate, scrollToField }] = useForm({
+        labelWidth: 150,
+        schemas: formSchema,
+        showActionButtonGroup: false,
+        baseColProps: {span: 24}
+    });
+    //表单赋值
+    const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
+        //重置表单
+        await resetFields();
+        setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
+        isUpdate.value = !!data?.isUpdate;
+        isDetail.value = !!data?.showFooter;
+        if (unref(isUpdate)) {
+            //表单赋值
+            await setFieldsValue({
+                ...data.record,
+            });
+        }
+        // 隐藏底部时禁用整个表单
+       setProps({ disabled: !data?.showFooter })
+    });
+    //设置标题
+    const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
+    //表单提交事件
+    async function handleSubmit(v) {
+        try {
+            let values = await validate();
+            setModalProps({confirmLoading: true});
+            //提交表单
+            await saveOrUpdate(values, isUpdate.value);
+            //关闭弹窗
+            closeModal();
+            //刷新列表
+            emit('success');
+        } catch ({ errorFields }) {
+           if (errorFields) {
+             const firstField = errorFields[0];
+             if (firstField) {
+               scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
+             }
+           }
+           return Promise.reject(errorFields);
+        } finally {
+            setModalProps({confirmLoading: false});
+        }
+    }
+</script>
+
+<style lang="less" scoped>
+	/** 时间和数字输入框样式 */
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+
+  :deep(.ant-calendar-picker) {
+    width: 100%;
+  }
+</style>

+ 208 - 0
src/views/equipmentLifecycle/manager/attachments/index.vue

@@ -0,0 +1,208 @@
+<template>
+  <div>
+    <!--引用表格-->
+    <BasicTable @register="registerTable" :rowSelection="rowSelection">
+      <!--插槽:table标题-->
+      <template #tableTitle>
+        <a-button type="primary" v-auth="'attachments:sbsmzq_attachments:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
+        <a-button type="primary" v-auth="'attachments:sbsmzq_attachments:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls">
+          导出</a-button
+        >
+        <j-upload-button
+          type="primary"
+          v-auth="'attachments:sbsmzq_attachments:importExcel'"
+          preIcon="ant-design:import-outlined"
+          @click="onImportXls"
+          >导入</j-upload-button
+        >
+        <a-dropdown v-if="selectedRowKeys.length > 0">
+          <template #overlay>
+            <a-menu>
+              <a-menu-item key="1" @click="batchHandleDelete">
+                <Icon icon="ant-design:delete-outlined" />
+                删除
+              </a-menu-item>
+            </a-menu>
+          </template>
+          <a-button v-auth="'attachments:sbsmzq_attachments:deleteBatch'"
+            >批量操作
+            <Icon icon="mdi:chevron-down" />
+          </a-button>
+        </a-dropdown>
+        <!-- 高级查询 -->
+        <super-query :config="superQueryConfig" @search="handleSuperQuery" />
+      </template>
+      <!--操作栏-->
+      <template #action="{ record }">
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
+      </template>
+      <!--字段回显插槽-->
+      <!-- <template v-slot:bodyCell="{ column, record, index, text }"> </template> -->
+      <template #fileName="{ text, record }">
+        <div class="flex items-center">
+          <template v-if="getFileType(record.type) === 'image'">
+            <a-image :width="32" :height="32" :src="getFileAccessHttpUrl(record.fileAddress)" />
+          </template>
+          <template v-else>
+            <SvgIcon size="32" :name="`file-${getFileType(record.type)}`" />
+          </template>
+          <a-button class="line-1" type="link">{{ text }}</a-button>
+        </div>
+      </template>
+    </BasicTable>
+    <!-- 表单区域 -->
+    <AttachmentsModal @register="registerModal" @success="handleSuccess" />
+  </div>
+</template>
+
+<script lang="ts" name="attachments-attachments" setup>
+  import { reactive } from 'vue';
+  import { BasicTable, TableAction } from '/@/components/Table';
+  import { useModal } from '/@/components/Modal';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import AttachmentsModal from './components/AttachmentsModal.vue';
+  import { columns, searchFormSchema, superQuerySchema, getFileType } from './Attachments.data';
+  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './Attachments.api';
+  import { getFileAccessHttpUrl } from '/@/utils/common/compUtils';
+  import { Image as AImage } from 'ant-design-vue';
+  import { SvgIcon } from '/@/components/Icon';
+  // import { downloadFile } from '/@/utils/common/renderUtils';
+
+  const queryParam = reactive<any>({});
+  //注册model
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { tableContext, onExportXls, onImportXls } = useListPage({
+    tableProps: {
+      title: '相关附件',
+      api: list,
+      columns,
+      canResize: false,
+      formConfig: {
+        //labelWidth: 120,
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+      },
+      actionColumn: {
+        width: 120,
+        fixed: 'right',
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, queryParam);
+      },
+    },
+    exportConfig: {
+      name: '相关附件',
+      url: getExportUrl,
+      params: queryParam,
+    },
+    importConfig: {
+      url: getImportUrl,
+      success: handleSuccess,
+    },
+  });
+
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
+
+  // 高级查询配置
+  const superQueryConfig = reactive(superQuerySchema);
+
+  /**
+   * 高级查询事件
+   */
+  function handleSuperQuery(params) {
+    Object.keys(params).map((k) => {
+      queryParam[k] = params[k];
+    });
+    reload();
+  }
+  /**
+   * 新增事件
+   */
+  function handleAdd() {
+    openModal(true, {
+      isUpdate: false,
+      showFooter: true,
+    });
+  }
+  /**
+   * 编辑事件
+   */
+  function handleEdit(record: Recordable) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+      showFooter: true,
+    });
+  }
+  /**
+   * 详情
+   */
+  function handleDetail(record: Recordable) {
+    openModal(true, {
+      record,
+      isUpdate: true,
+      showFooter: false,
+    });
+  }
+  /**
+   * 删除事件
+   */
+  async function handleDelete(record) {
+    await deleteOne({ id: record.id }, handleSuccess);
+  }
+  /**
+   * 批量删除事件
+   */
+  async function batchHandleDelete() {
+    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
+  }
+  /**
+   * 成功回调
+   */
+  function handleSuccess() {
+    (selectedRowKeys.value = []) && reload();
+  }
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '编辑',
+        onClick: handleEdit.bind(null, record),
+        auth: 'attachments:sbsmzq_attachments:edit',
+      },
+    ];
+  }
+  /**
+   * 下拉操作栏
+   */
+  function getDropDownAction(record) {
+    return [
+      {
+        label: '详情',
+        onClick: handleDetail.bind(null, record),
+      },
+      {
+        label: '删除',
+        popConfirm: {
+          title: '是否确认删除',
+          confirm: handleDelete.bind(null, record),
+          placement: 'topLeft',
+        },
+        auth: 'attachments:sbsmzq_attachments:delete',
+      },
+    ];
+  }
+</script>
+
+<style lang="less" scoped>
+  :deep(.ant-picker),
+  :deep(.ant-input-number) {
+    width: 100%;
+  }
+</style>

+ 140 - 127
src/views/equipmentLifecycle/supplier/accept/index.vue

@@ -1,35 +1,50 @@
 <template>
   <div>
     <!--引用表格-->
-   <BasicTable @register="registerTable" :rowSelection="rowSelection">
-     <!--插槽:table标题-->
+    <BasicTable @register="registerTable" :rowSelection="rowSelection">
+      <!--插槽:table标题-->
       <template #tableTitle>
-          <a-button type="primary" v-auth="'purchaseManage:sbsmzq_equipment_accept:add'"  @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
-          <a-button  type="primary" v-auth="'purchaseManage:sbsmzq_equipment_accept:exportXls'"  preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
-          <j-upload-button  type="primary" v-auth="'purchaseManage:sbsmzq_equipment_accept:importExcel'"  preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
-          <a-dropdown v-if="selectedRowKeys.length > 0">
-              <template #overlay>
-                <a-menu>
-                  <a-menu-item key="1" @click="batchHandleDelete">
-                    <Icon icon="ant-design:delete-outlined"></Icon>
-                    删除
-                  </a-menu-item>
-                </a-menu>
-              </template>
-              <a-button v-auth="'purchaseManage:sbsmzq_equipment_accept:deleteBatch'">批量操作
-                <Icon icon="mdi:chevron-down"></Icon>
-              </a-button>
+        <a-button type="primary" v-auth="'purchaseManage:sbsmzq_equipment_accept:add'" @click="handleAdd" preIcon="ant-design:plus-outlined">
+          新增</a-button
+        >
+        <a-button
+          type="primary"
+          v-auth="'purchaseManage:sbsmzq_equipment_accept:exportXls'"
+          preIcon="ant-design:export-outlined"
+          @click="onExportXls"
+        >
+          导出</a-button
+        >
+        <j-upload-button
+          type="primary"
+          v-auth="'purchaseManage:sbsmzq_equipment_accept:importExcel'"
+          preIcon="ant-design:import-outlined"
+          @click="onImportXls"
+          >导入</j-upload-button
+        >
+        <a-dropdown v-if="selectedRowKeys.length > 0">
+          <template #overlay>
+            <a-menu>
+              <a-menu-item key="1" @click="batchHandleDelete">
+                <Icon icon="ant-design:delete-outlined"></Icon>
+                删除
+              </a-menu-item>
+            </a-menu>
+          </template>
+          <a-button v-auth="'purchaseManage:sbsmzq_equipment_accept:deleteBatch'"
+            >批量操作
+            <Icon icon="mdi:chevron-down"></Icon>
+          </a-button>
         </a-dropdown>
         <!-- 高级查询 -->
         <super-query :config="superQueryConfig" @search="handleSuperQuery" />
       </template>
-       <!--操作栏-->
+      <!--操作栏-->
       <template #action="{ record }">
-        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
+        <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
       </template>
       <!--字段回显插槽-->
-      <template v-slot:bodyCell="{ column, record, index, text }">
-      </template>
+      <template v-slot:bodyCell="{ column, record, index, text }"> </template>
     </BasicTable>
     <!-- 表单区域 -->
     <EquipmentAcceptModal @register="registerModal" @success="handleSuccess"></EquipmentAcceptModal>
@@ -37,57 +52,55 @@
 </template>
 
 <script lang="ts" name="purchaseManage-equipmentAccept" setup>
-  import {ref, reactive, computed, unref} from 'vue';
-  import {BasicTable, useTable, TableAction} from '/@/components/Table';
-  import { useListPage } from '/@/hooks/system/useListPage'
-  import {useModal} from '/@/components/Modal';
-  import EquipmentAcceptModal from './components/EquipmentAcceptModal.vue'
-  import {columns, searchFormSchema, superQuerySchema} from './EquipmentAccept.data';
-  import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './EquipmentAccept.api';
-  import {downloadFile} from '/@/utils/common/renderUtils';
+  import { ref, reactive, computed, unref } from 'vue';
+  import { BasicTable, useTable, TableAction } from '/@/components/Table';
+  import { useListPage } from '/@/hooks/system/useListPage';
+  import { useModal } from '/@/components/Modal';
+  import EquipmentAcceptModal from './components/EquipmentAcceptModal.vue';
+  import { columns, searchFormSchema, superQuerySchema } from './EquipmentAccept.data';
+  import { list, deleteOne, batchDelete, getImportUrl, getExportUrl } from './EquipmentAccept.api';
+  import { downloadFile } from '/@/utils/common/renderUtils';
   import { useUserStore } from '/@/store/modules/user';
   const queryParam = reactive<any>({});
   const checkedKeys = ref<Array<string | number>>([]);
   const userStore = useUserStore();
   //注册model
-  const [registerModal, {openModal}] = useModal();
-   //注册table数据
-  const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
-      tableProps:{
-           title: '设备验收',
-           api: list,
-           columns,
-           canResize:false,
-           formConfig: {
-                //labelWidth: 120,
-                schemas: searchFormSchema,
-                autoSubmitOnEnter:true,
-                showAdvancedButton:true,
-                fieldMapToNumber: [
-                ],
-                fieldMapToTime: [
-                ],
-            },
-           actionColumn: {
-               width: 120,
-               fixed:'right'
-           },
-           beforeFetch: (params) => {
-             return Object.assign(params, queryParam);
-           },
-        },
-        exportConfig: {
-            name:"设备验收",
-            url: getExportUrl,
-            params: queryParam,
-        },
-        importConfig: {
-            url: getImportUrl,
-            success: handleSuccess
-        },
-    })
+  const [registerModal, { openModal }] = useModal();
+  //注册table数据
+  const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
+    tableProps: {
+      title: '设备验收',
+      api: list,
+      columns,
+      canResize: false,
+      formConfig: {
+        //labelWidth: 120,
+        schemas: searchFormSchema,
+        autoSubmitOnEnter: true,
+        showAdvancedButton: true,
+        fieldMapToNumber: [],
+        fieldMapToTime: [],
+      },
+      actionColumn: {
+        width: 120,
+        fixed: 'right',
+      },
+      beforeFetch: (params) => {
+        return Object.assign(params, queryParam);
+      },
+    },
+    exportConfig: {
+      name: '设备验收',
+      url: getExportUrl,
+      params: queryParam,
+    },
+    importConfig: {
+      url: getImportUrl,
+      success: handleSuccess,
+    },
+  });
 
-  const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
+  const [registerTable, { reload }, { rowSelection, selectedRowKeys }] = tableContext;
 
   // 高级查询配置
   const superQueryConfig = reactive(superQuerySchema);
@@ -102,91 +115,91 @@
     reload();
   }
 
-   /**
-    * 新增事件
-    */
+  /**
+   * 新增事件
+   */
   function handleAdd() {
-     openModal(true, {
-       isUpdate: false,
-       showFooter: true,
-     });
+    openModal(true, {
+      isUpdate: false,
+      showFooter: true,
+    });
   }
-   /**
-    * 编辑事件
-    */
+  /**
+   * 编辑事件
+   */
   function handleEdit(record: Recordable) {
-     openModal(true, {
-       record,
-       isUpdate: true,
-       showFooter: true,
-     });
-   }
-   /**
-    * 详情
+    openModal(true, {
+      record,
+      isUpdate: true,
+      showFooter: true,
+    });
+  }
+  /**
+   * 详情
    */
   function handleDetail(record: Recordable) {
-     openModal(true, {
-       record,
-       isUpdate: true,
-       showFooter: false,
-     });
-   }
-   /**
-    * 删除事件
-    */
+    openModal(true, {
+      record,
+      isUpdate: true,
+      showFooter: false,
+    });
+  }
+  /**
+   * 删除事件
+   */
   async function handleDelete(record) {
-     await deleteOne({id: record.id}, handleSuccess);
-   }
-   /**
-    * 批量删除事件
-    */
+    await deleteOne({ id: record.id }, handleSuccess);
+  }
+  /**
+   * 批量删除事件
+   */
   async function batchHandleDelete() {
-     await batchDelete({ids: selectedRowKeys.value},handleSuccess);
-   }
-   /**
-    * 成功回调
-    */
+    await batchDelete({ ids: selectedRowKeys.value }, handleSuccess);
+  }
+  /**
+   * 成功回调
+   */
   function handleSuccess() {
-      (selectedRowKeys.value = []) && reload();
-   }
-   /**
-      * 操作栏
-      */
-  function getTableAction(record){
-       return [
-         {
-           label: '编辑',
-           onClick: handleEdit.bind(null, record),
-           auth: 'purchaseManage:sbsmzq_equipment_accept:edit'
-         }
-       ]
-   }
-
+    (selectedRowKeys.value = []) && reload();
+  }
+  /**
+   * 操作栏
+   */
+  function getTableAction(record) {
+    return [
+      {
+        label: '编辑',
+        onClick: handleEdit.bind(null, record),
+        auth: 'purchaseManage:sbsmzq_equipment_accept:edit',
+      },
+    ];
+  }
 
   /**
    * 下拉操作栏
    */
-  function getDropDownAction(record){
+  function getDropDownAction(record) {
     return [
       {
         label: '详情',
         onClick: handleDetail.bind(null, record),
-      }, {
+      },
+      {
         label: '删除',
         popConfirm: {
           title: '是否确认删除',
           confirm: handleDelete.bind(null, record),
-          placement: 'topLeft'
+          placement: 'topLeft',
         },
-        auth: 'purchaseManage:sbsmzq_equipment_accept:delete'
-      }
-    ]
+        auth: 'purchaseManage:sbsmzq_equipment_accept:delete',
+      },
+    ];
   }
-
 </script>
 
 <style lang="less" scoped>
-  :deep(.ant-picker),:deep(.ant-input-number){
+  :deep(.ant-picker),
+  :deep(.ant-input-number) {
     width: 100%;
   }
-</style>
+</style>

+ 5 - 1
src/views/equipmentLifecycle/supplier/apply/list.vue

@@ -45,7 +45,11 @@
         <TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)" />
       </template>
       <!--字段回显插槽-->
-      <!-- <template v-slot:bodyCell="{ column, record, index, text }"> </template> -->
+      <template #bodyCell="{ column, record, text }">
+        <template v-if="column.dataIndex === 'requestNo'">
+          <a-button type="link" size="small" @click="handleDetail(record)">{{ text }}</a-button>
+        </template>
+      </template>
     </BasicTable>
     <!-- 表单区域 -->
     <PurchaseApplicationModal @register="registerModal" @success="handleSuccess" />

+ 1 - 1
src/views/equipmentLifecycle/supplier/list/index.vue

@@ -42,7 +42,7 @@
       <!--字段回显插槽-->
       <!-- <template v-slot:bodyCell="{ column, record, index, text }"> </template> -->
       <template #supplierNumber="{ record }">
-        <a-button type="link" @click="handleDetail(record)">{{ record.supplierNumber }}</a-button>
+        <a-button type="link" size="small" @click="handleDetail(record)">{{ record.supplierNumber }}</a-button>
       </template>
       <template #disable="{ record }">
         <YOrN :yes="Number(record.disable) === 0" />

+ 4 - 0
src/views/equipmentLifecycle/supplier/plan/PurchasePlan.api.ts

@@ -1,5 +1,7 @@
 import { defHttp } from '/@/utils/http/axios';
 import { useMessage } from '/@/hooks/web/useMessage';
+import { deleteByExtId } from '/@/views/equipmentLifecycle/manager/attachments/Attachments.api';
+import { currentTable } from './PurchasePlan.data';
 
 const { createConfirm } = useMessage();
 
@@ -45,6 +47,7 @@ export const list = (params) => defHttp.get({ url: Api.list, params });
  */
 export const deleteOne = (params, handleSuccess) => {
   return defHttp.delete({ url: Api.deleteOne, params }, { joinParamsToUrl: true }).then(() => {
+    deleteByExtId({ extId: params.id, extTable: currentTable });
     handleSuccess();
   });
 };
@@ -61,6 +64,7 @@ export const batchDelete = (params, handleSuccess) => {
     cancelText: '取消',
     onOk: () => {
       return defHttp.delete({ url: Api.deleteBatch, data: params }, { joinParamsToUrl: true }).then(() => {
+        deleteByExtId({ extId: params.ids.join(','), extTable: currentTable });
         handleSuccess();
       });
     },

+ 7 - 28
src/views/equipmentLifecycle/supplier/plan/PurchasePlan.data.ts

@@ -5,6 +5,7 @@ import { render } from '/@/utils/common/renderUtils';
 import { JVxeTypes, JVxeColumn } from '/@/components/jeecg/JVxeTable/types';
 import dayjs from 'dayjs';
 
+export const currentTable = 'purchasePlan';
 //列表数据
 export const columns: BasicColumn[] = [
   {
@@ -130,10 +131,9 @@ export const formSchema: FormSchema[] = [
     field: 'applicationTime',
     component: 'DatePicker',
     componentProps: {
-      showTime: true,
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD',
     },
-    defaultValue: dayjs().format('YYYY-MM-DD HH:mm:ss'),
+    defaultValue: dayjs().format('YYYY-MM-DD'),
     colProps: { span: 12 },
     rules: [{ required: true, message: '请选择申请时间' }],
   },
@@ -175,10 +175,9 @@ export const formSchema: FormSchema[] = [
     field: 'approvalEndTime',
     component: 'DatePicker',
     componentProps: {
-      showTime: true,
-      valueFormat: 'YYYY-MM-DD HH:mm:ss',
+      valueFormat: 'YYYY-MM-DD',
     },
-    defaultValue: dayjs().add(1, 'month').format('YYYY-MM-DD HH:mm:ss'),
+    defaultValue: dayjs().add(1, 'month').format('YYYY-MM-DD'),
     colProps: { span: 12 },
   },
   {
@@ -195,26 +194,6 @@ export const formSchema: FormSchema[] = [
   },
 ];
 //子表单数据
-//子表表格配置
-export const purchaseAttachmentsColumns: JVxeColumn[] = [
-  {
-    title: '文件地址',
-    key: 'fileAddress',
-    type: JVxeTypes.upload,
-    token: true,
-    action: '/jeecgboot/sys/common/upload',
-    responseName: 'message',
-    placeholder: '请输入${title}',
-    defaultValue: '',
-  },
-  {
-    title: '文件名称',
-    key: 'fileName',
-    type: JVxeTypes.input,
-    placeholder: '请输入${title}',
-    defaultValue: '',
-  },
-];
 export const purchasePlanInfoColumns: JVxeColumn[] = [
   {
     title: '编号',
@@ -248,7 +227,7 @@ export const purchasePlanInfoColumns: JVxeColumn[] = [
     key: 'amount',
     dataIndex: 'amount',
     type: JVxeTypes.inputNumber,
-    width: '60px',
+    width: '100px',
     placeholder: '请输入${title}',
     defaultValue: '',
   },
@@ -266,7 +245,7 @@ export const purchasePlanInfoColumns: JVxeColumn[] = [
     key: 'unit',
     dataIndex: 'unit',
     type: JVxeTypes.select,
-    width: '70px',
+    width: '100px',
     placeholder: '请输入${title}',
     defaultValue: '',
     allowSearch: true,

+ 7 - 4
src/views/equipmentLifecycle/supplier/plan/components/DetailDrawer.vue

@@ -18,7 +18,7 @@
 
       <div class="dtl-wrapper">
         <div class="title">相关附件</div>
-        <!-- <BasicTable @register="registerTable" /> -->
+        <AttachmentsCard ref="attachmentsContext" :ext-id="info.id" :ext-table="currentTable" />
       </div>
 
       <div class="dtl-wrapper">
@@ -39,16 +39,18 @@
   import { BasicTable, BasicColumn } from '/@/components/Table';
   import { useListPage } from '/@/hooks/system/useListPage';
   import { getPurchasePlanInfo } from '../PurchasePlan.api';
-  import { purchasePlanInfoColumns } from '../PurchasePlan.data';
+  import { currentTable, purchasePlanInfoColumns } from '../PurchasePlan.data';
   import ApplyTableList from '../../apply/list.vue';
   import { render } from '/@/utils/common/renderUtils';
   import { mapTableTotalSummary } from '/@/utils/common/compUtils';
+  import AttachmentsCard from '../../../manager/attachments/AttachmentsCard.vue';
 
   export default defineComponent({
-    components: { BasicDrawer, BasicTable, ApplyTableList },
+    components: { BasicDrawer, BasicTable, ApplyTableList, AttachmentsCard },
     setup() {
       const info = ref<Recordable>({});
       const applyTableContext = ref();
+      const attachmentsContext = ref();
 
       // 抽屉注册及关闭方法,用于openDrawer方法中
       // 注册抽屉,用于openDrawer调用
@@ -56,6 +58,7 @@
         info.value = data;
 
         reload();
+        attachmentsContext.value && attachmentsContext.value.reload();
         applyTableContext.value && applyTableContext.value.reload();
       });
 
@@ -87,7 +90,7 @@
 
       const [registerTable, { reload }] = tableSubContext;
 
-      return { register, closeDrawer, info, registerTable, reload, applyTableContext, render };
+      return { register, closeDrawer, info, registerTable, reload, applyTableContext, attachmentsContext, render, currentTable };
     },
   });
 </script>

+ 23 - 29
src/views/equipmentLifecycle/supplier/plan/components/PurchasePlanModal.vue

@@ -11,20 +11,8 @@
     <BasicForm @register="registerForm" ref="formRef" name="PurchasePlanForm" />
     <!-- 子表单区域 -->
     <a-tabs v-model:activeKey="activeKey" animated @change="handleChangeTabs">
-      <a-tab-pane tab="采购计划相关附件" key="purchaseAttachments" :forceRender="true">
-        <JVxeTable
-          keep-source
-          resizable
-          ref="purchaseAttachments"
-          :loading="purchaseAttachmentsTable.loading"
-          :columns="purchaseAttachmentsTable.columns"
-          :dataSource="purchaseAttachmentsTable.dataSource"
-          :height="340"
-          :rowNumber="true"
-          :rowSelection="true"
-          :disabled="formDisabled"
-          :toolbar="true"
-        />
+      <a-tab-pane tab="采购计划附件" key="purchaseAttachments" :forceRender="true">
+        <AttachmentsEditTable :formDisabled="formDisabled" ref="attachmentsTable" :mainId="info.id" :mainTable="currentTable" />
       </a-tab-pane>
       <a-tab-pane tab="采购计划信息" key="purchasePlanInfo" :forceRender="true">
         <JVxeTable
@@ -50,7 +38,7 @@
               :showSearch="true"
               :pageConfig="{
                 isPage: true,
-                //如果和默认的分页字段一致,请忽略以下配置
+                // 如果和默认的分页字段一致,请忽略以下配置
                 pageField: 'pageNo',
                 pageSizeField: 'pageSize',
                 totalField: 'total',
@@ -71,26 +59,23 @@
   import { BasicForm, useForm } from '/@/components/Form/index';
   import { JVxeTable } from '/@/components/jeecg/JVxeTable';
   import { useJvxeMethod } from '/@/hooks/system/useJvxeMethods';
-  import { formSchema, purchaseAttachmentsColumns, purchasePlanInfoColumns } from '../PurchasePlan.data';
-  import { saveOrUpdate, purchaseAttachmentsList, purchasePlanInfoList } from '../PurchasePlan.api';
+  import { formSchema, purchasePlanInfoColumns, currentTable } from '../PurchasePlan.data';
+  import { saveOrUpdate, purchasePlanInfoList } from '../PurchasePlan.api';
   import ApiSelect from '/@/components/Form/src/components/ApiSelect.vue';
   import { list as supplierList } from '/@/views/equipmentLifecycle/supplier/list/SupplierManage.api';
+  import AttachmentsEditTable from '/@/views/equipmentLifecycle/manager/attachments/AttachmentsEditTable.vue';
 
   // import { VALIDATE_FAILED } from '/@/utils/common/vxeUtils';
   // Emits声明
   const emit = defineEmits(['register', 'success']);
   const isUpdate = ref(true);
   const formDisabled = ref(false);
-  const refKeys = ref(['purchaseAttachments', 'purchasePlanInfo']);
+  const refKeys = ref(['purchasePlanInfo']);
   const activeKey = ref('purchaseAttachments');
-  const purchaseAttachments = ref();
+  const attachmentsTable = ref();
   const purchasePlanInfo = ref();
-  const tableRefs = { purchaseAttachments, purchasePlanInfo };
-  const purchaseAttachmentsTable = reactive({
-    loading: false,
-    dataSource: [],
-    columns: purchaseAttachmentsColumns,
-  });
+  const tableRefs = { purchasePlanInfo };
+
   const purchasePlanInfoTable = reactive({
     loading: false,
     dataSource: [],
@@ -103,6 +88,8 @@
     showActionButtonGroup: false,
     baseColProps: { span: 24 },
   });
+
+  const info = ref<any>({});
   //表单赋值
   const [registerModal, { setModalProps, closeModal }] = useModalInner(async (data) => {
     //重置表单
@@ -110,13 +97,17 @@
     setModalProps({ confirmLoading: false, showCancelBtn: data?.showFooter, showOkBtn: data?.showFooter });
     isUpdate.value = !!data?.isUpdate;
     formDisabled.value = !data?.showFooter;
+
+    info.value = data.record;
     if (unref(isUpdate)) {
       //表单赋值
       await setFieldsValue({
         ...data.record,
       });
+
+      // 设置附件表格
+      attachmentsTable.value.requestFileTableData();
       if (typeof requestSubTableData === 'function') {
-        requestSubTableData(purchaseAttachmentsList, { id: data?.record?.id }, purchaseAttachmentsTable);
         requestSubTableData(purchasePlanInfoList, { id: data?.record?.id }, purchasePlanInfoTable);
       }
     }
@@ -138,15 +129,15 @@
   async function reset() {
     await resetFields();
     activeKey.value = 'purchaseAttachments';
-    purchaseAttachmentsTable.dataSource = [];
+    // 附件表格重置
+    attachmentsTable.value.reset();
     purchasePlanInfoTable.dataSource = [];
   }
   function classifyIntoFormData(allValues) {
     let main = Object.assign({}, allValues.formValue);
     return {
       ...main, // 展开
-      purchaseAttachmentsList: allValues.tablesValue[0].tableData,
-      purchasePlanInfoList: allValues.tablesValue[1].tableData,
+      purchasePlanInfoList: allValues.tablesValue[0].tableData,
     };
   }
   //表单提交事件
@@ -155,6 +146,9 @@
       setModalProps({ confirmLoading: true });
       //提交表单
       await saveOrUpdate(values, isUpdate.value);
+
+      // 保存附件
+      await attachmentsTable.value.sumbit();
       //关闭弹窗
       closeModal();
       //刷新列表

+ 1 - 1
src/views/equipmentLifecycle/supplier/plan/list.vue

@@ -41,7 +41,7 @@
     <!--字段回显插槽-->
     <!-- <template v-slot:bodyCell="{ column, record, index, text }"> </template> -->
     <template #planNumber="{ record }">
-      <a-button type="link" @click="handleDetail(record)">{{ record.planNumber }}</a-button>
+      <a-button type="link" size="small" @click="handleDetail(record)">{{ record.planNumber }}</a-button>
     </template>
   </BasicTable>
   <!-- 表单区域 -->

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini