Sfoglia il codice sorgente

feat(电子二维码说明书):增加电子二维码说明书页面

Zhenghanjv 11 mesi fa
parent
commit
e65db2c2f5

+ 511 - 56
admin.ui.plus-master/package-lock.json

@@ -9,24 +9,30 @@
       "version": "2.2.3",
       "license": "MIT",
       "dependencies": {
+        "@element-plus/icons": "^0.0.11",
         "@element-plus/icons-vue": "^2.1.0",
+        "@types/date-fns": "^2.6.0",
         "@wangeditor/editor": "^5.1.23",
         "@wangeditor/editor-for-vue": "^5.1.12",
         "axios": "^1.4.0",
+        "clipboard": "^2.0.11",
         "countup.js": "^2.6.2",
         "cropperjs": "^1.5.13",
+        "date-fns": "^3.6.0",
         "echarts": "^5.4.2",
         "echarts-gl": "^2.0.9",
         "echarts-wordcloud": "^2.1.0",
         "element-plus": "^2.4.3",
         "exceljs": "^4.4.0",
         "file-saver": "^2.0.5",
+        "fs-extra": "^11.2.0",
         "js-cookie": "^3.0.5",
         "js-table2excel": "^1.1.2",
         "jsplumb": "^2.15.6",
         "lodash": "^4.17.21",
         "mitt": "^3.0.0",
         "nprogress": "^0.2.0",
+        "path": "^0.12.7",
         "pinia": "^2.1.4",
         "print-js": "^1.6.0",
         "qrcodejs2-fixes": "^0.0.2",
@@ -52,11 +58,12 @@
         "dotenv": "16.3.0",
         "eslint": "^8.43.0",
         "eslint-plugin-vue": "^9.14.1",
+        "fs": "^0.0.1-security",
         "prettier": "^2.8.8",
         "sass": "^1.63.4",
         "swagger-typescript-api": "12.0.4",
         "typescript": "^5.1.3",
-        "vite": "^4.3.9",
+        "vite": "^4.5.1",
         "vite-plugin-compression": "0.5.1",
         "vite-plugin-vue-setup-extend-plus": "^0.1.0",
         "vue-eslint-parser": "^9.3.1"
@@ -202,6 +209,12 @@
         "node": ">=10"
       }
     },
+    "node_modules/@element-plus/icons": {
+      "version": "0.0.11",
+      "resolved": "https://registry.npmmirror.com/@element-plus/icons/-/icons-0.0.11.tgz",
+      "integrity": "sha512-iKQXSxXu131Ai+I9Ymtcof9WId7kaXvB1+WRfAfpQCW7UiAMYgdNDqb/u0hgTo2Yq3MwC4MWJnNuTBEpG8r7+A==",
+      "deprecated": "Please use @element-plus/icons-vue instead."
+    },
     "node_modules/@element-plus/icons-vue": {
       "version": "2.3.1",
       "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz",
@@ -210,10 +223,346 @@
         "vue": "^3.2.0"
       }
     },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+      "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+      "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+      "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+      "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+      "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+      "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+      "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+      "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+      "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+      "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+      "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+      "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+      "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+      "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+      "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+      "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+      "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+      "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+      "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+      "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+      "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/@esbuild/win32-x64": {
-      "version": "0.17.15",
-      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.17.15.tgz",
-      "integrity": "sha512-DjDa9ywLUUmjhV2Y9wUTIF+1XsmuFGvZoCmOWkli1XcNAh5t25cc7fgsCx4Zi/Uurep3TTLyDiKATgGEg61pkA==",
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+      "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
       "cpu": [
         "x64"
       ],
@@ -644,6 +993,15 @@
       "resolved": "https://registry.npmmirror.com/@transloadit/prettier-bytes/-/prettier-bytes-0.0.7.tgz",
       "integrity": "sha512-VeJbUb0wEKbcwaSlj5n+LscBl9IPgLPkHVGBkh00cztv6X4L/TJXK58LzFuBKX7/GAfiGhIwH67YTLTlzvIzBA=="
     },
+    "node_modules/@types/date-fns": {
+      "version": "2.6.0",
+      "resolved": "https://registry.npmmirror.com/@types/date-fns/-/date-fns-2.6.0.tgz",
+      "integrity": "sha512-9DSw2ZRzV0Tmpa6PHHJbMcZn79HHus+BBBohcOaDzkK/G3zMjDUDYjJIWBFLbkh+1+/IOS0A59BpQfdr37hASg==",
+      "deprecated": "This is a stub types definition for date-fns (https://github.com/date-fns/date-fns). date-fns provides its own type definitions, so you don't need @types/date-fns installed!",
+      "dependencies": {
+        "date-fns": "*"
+      }
+    },
     "node_modules/@types/event-emitter": {
       "version": "0.3.3",
       "resolved": "https://registry.npmmirror.com/@types/event-emitter/-/event-emitter-0.3.3.tgz",
@@ -1793,6 +2151,15 @@
         "node": ">= 12"
       }
     },
+    "node_modules/date-fns": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmmirror.com/date-fns/-/date-fns-3.6.0.tgz",
+      "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==",
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/kossnocorp"
+      }
+    },
     "node_modules/dayjs": {
       "version": "1.11.7",
       "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.7.tgz",
@@ -2041,9 +2408,9 @@
       }
     },
     "node_modules/esbuild": {
-      "version": "0.17.15",
-      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.17.15.tgz",
-      "integrity": "sha512-LBUV2VsUIc/iD9ME75qhT4aJj0r75abCVS0jakhFzOtR7TQsqQA5w0tZ+KTKnwl3kXE0MhskNdHDh/I5aCR1Zw==",
+      "version": "0.18.20",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.18.20.tgz",
+      "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
       "dev": true,
       "hasInstallScript": true,
       "bin": {
@@ -2053,28 +2420,28 @@
         "node": ">=12"
       },
       "optionalDependencies": {
-        "@esbuild/android-arm": "0.17.15",
-        "@esbuild/android-arm64": "0.17.15",
-        "@esbuild/android-x64": "0.17.15",
-        "@esbuild/darwin-arm64": "0.17.15",
-        "@esbuild/darwin-x64": "0.17.15",
-        "@esbuild/freebsd-arm64": "0.17.15",
-        "@esbuild/freebsd-x64": "0.17.15",
-        "@esbuild/linux-arm": "0.17.15",
-        "@esbuild/linux-arm64": "0.17.15",
-        "@esbuild/linux-ia32": "0.17.15",
-        "@esbuild/linux-loong64": "0.17.15",
-        "@esbuild/linux-mips64el": "0.17.15",
-        "@esbuild/linux-ppc64": "0.17.15",
-        "@esbuild/linux-riscv64": "0.17.15",
-        "@esbuild/linux-s390x": "0.17.15",
-        "@esbuild/linux-x64": "0.17.15",
-        "@esbuild/netbsd-x64": "0.17.15",
-        "@esbuild/openbsd-x64": "0.17.15",
-        "@esbuild/sunos-x64": "0.17.15",
-        "@esbuild/win32-arm64": "0.17.15",
-        "@esbuild/win32-ia32": "0.17.15",
-        "@esbuild/win32-x64": "0.17.15"
+        "@esbuild/android-arm": "0.18.20",
+        "@esbuild/android-arm64": "0.18.20",
+        "@esbuild/android-x64": "0.18.20",
+        "@esbuild/darwin-arm64": "0.18.20",
+        "@esbuild/darwin-x64": "0.18.20",
+        "@esbuild/freebsd-arm64": "0.18.20",
+        "@esbuild/freebsd-x64": "0.18.20",
+        "@esbuild/linux-arm": "0.18.20",
+        "@esbuild/linux-arm64": "0.18.20",
+        "@esbuild/linux-ia32": "0.18.20",
+        "@esbuild/linux-loong64": "0.18.20",
+        "@esbuild/linux-mips64el": "0.18.20",
+        "@esbuild/linux-ppc64": "0.18.20",
+        "@esbuild/linux-riscv64": "0.18.20",
+        "@esbuild/linux-s390x": "0.18.20",
+        "@esbuild/linux-x64": "0.18.20",
+        "@esbuild/netbsd-x64": "0.18.20",
+        "@esbuild/openbsd-x64": "0.18.20",
+        "@esbuild/sunos-x64": "0.18.20",
+        "@esbuild/win32-arm64": "0.18.20",
+        "@esbuild/win32-ia32": "0.18.20",
+        "@esbuild/win32-x64": "0.18.20"
       }
     },
     "node_modules/escalade": {
@@ -2532,23 +2899,28 @@
         "node": ">=12.20.0"
       }
     },
+    "node_modules/fs": {
+      "version": "0.0.1-security",
+      "resolved": "https://registry.npmmirror.com/fs/-/fs-0.0.1-security.tgz",
+      "integrity": "sha512-3XY9e1pP0CVEUCdj5BmfIZxRBTSDycnbqhIOGec9QYtmVH2fbLpj86CFWkrNOkt/Fvty4KZG5lTglL9j/gJ87w==",
+      "dev": true
+    },
     "node_modules/fs-constants": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
       "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
     },
     "node_modules/fs-extra": {
-      "version": "10.1.0",
-      "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
-      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
-      "dev": true,
+      "version": "11.2.0",
+      "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.2.0.tgz",
+      "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
       "dependencies": {
         "graceful-fs": "^4.2.0",
         "jsonfile": "^6.0.1",
         "universalify": "^2.0.0"
       },
       "engines": {
-        "node": ">=12"
+        "node": ">=14.14"
       }
     },
     "node_modules/fs.realpath": {
@@ -2556,6 +2928,20 @@
       "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz",
       "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
     },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
     "node_modules/fstream": {
       "version": "1.0.12",
       "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
@@ -2962,7 +3348,6 @@
       "version": "6.1.0",
       "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz",
       "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-      "dev": true,
       "dependencies": {
         "universalify": "^2.0.0"
       },
@@ -3361,9 +3746,15 @@
       "integrity": "sha512-N/sMKHniSDJBjfrkbS/tpkPj4RAbvW3mr8UAzvlMHyun93XEm83IAvhWtJVHo+RHn/oO8Job5YN4b+wRjSVp5g=="
     },
     "node_modules/nanoid": {
-      "version": "3.3.6",
-      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz",
-      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+      "version": "3.3.7",
+      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz",
+      "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
       "bin": {
         "nanoid": "bin/nanoid.cjs"
       },
@@ -3612,6 +4003,15 @@
         "node": ">=8"
       }
     },
+    "node_modules/path": {
+      "version": "0.12.7",
+      "resolved": "https://registry.npmmirror.com/path/-/path-0.12.7.tgz",
+      "integrity": "sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==",
+      "dependencies": {
+        "process": "^0.11.1",
+        "util": "^0.10.3"
+      }
+    },
     "node_modules/path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz",
@@ -3684,13 +4084,27 @@
       }
     },
     "node_modules/postcss": {
-      "version": "8.4.23",
-      "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.23.tgz",
-      "integrity": "sha512-bQ3qMcpF6A/YjR55xtoTr0jGOlnPOKAIMdOWiv0EIT6HVPEaJiJB4NLljSbiHoC2RX7DN5Uvjtpbg1NPdwv1oA==",
+      "version": "8.4.38",
+      "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.4.38.tgz",
+      "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
       "dependencies": {
-        "nanoid": "^3.3.6",
+        "nanoid": "^3.3.7",
         "picocolors": "^1.0.0",
-        "source-map-js": "^1.0.2"
+        "source-map-js": "^1.2.0"
       },
       "engines": {
         "node": "^10 || ^12 || >=14"
@@ -3748,6 +4162,14 @@
         "node": ">=6"
       }
     },
+    "node_modules/process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmmirror.com/process/-/process-0.11.10.tgz",
+      "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
     "node_modules/process-nextick-args": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
@@ -3892,9 +4314,9 @@
       }
     },
     "node_modules/rollup": {
-      "version": "3.21.5",
-      "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.21.5.tgz",
-      "integrity": "sha512-a4NTKS4u9PusbUJcfF4IMxuqjFzjm6ifj76P54a7cKnvVzJaG12BLVR+hgU2YDGHzyMMQNxLAZWuALsn8q2oQg==",
+      "version": "3.29.4",
+      "resolved": "https://registry.npmmirror.com/rollup/-/rollup-3.29.4.tgz",
+      "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==",
       "dev": true,
       "bin": {
         "rollup": "dist/bin/rollup"
@@ -4141,9 +4563,9 @@
       }
     },
     "node_modules/source-map-js": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz",
-      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.0.tgz",
+      "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
       "engines": {
         "node": ">=0.10.0"
       }
@@ -4463,7 +4885,6 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz",
       "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
-      "dev": true,
       "engines": {
         "node": ">= 10.0.0"
       }
@@ -4521,11 +4942,24 @@
         "punycode": "^2.1.0"
       }
     },
+    "node_modules/util": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmmirror.com/util/-/util-0.10.4.tgz",
+      "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
+      "dependencies": {
+        "inherits": "2.0.3"
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
     },
+    "node_modules/util/node_modules/inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw=="
+    },
     "node_modules/uuid": {
       "version": "8.3.2",
       "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
@@ -4535,14 +4969,14 @@
       }
     },
     "node_modules/vite": {
-      "version": "4.3.9",
-      "resolved": "https://registry.npmmirror.com/vite/-/vite-4.3.9.tgz",
-      "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==",
+      "version": "4.5.3",
+      "resolved": "https://registry.npmmirror.com/vite/-/vite-4.5.3.tgz",
+      "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
       "dev": true,
       "dependencies": {
-        "esbuild": "^0.17.5",
-        "postcss": "^8.4.23",
-        "rollup": "^3.21.0"
+        "esbuild": "^0.18.10",
+        "postcss": "^8.4.27",
+        "rollup": "^3.27.1"
       },
       "bin": {
         "vite": "bin/vite.js"
@@ -4550,12 +4984,16 @@
       "engines": {
         "node": "^14.18.0 || >=16.0.0"
       },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
       "optionalDependencies": {
         "fsevents": "~2.3.2"
       },
       "peerDependencies": {
         "@types/node": ">= 14",
         "less": "*",
+        "lightningcss": "^1.21.0",
         "sass": "*",
         "stylus": "*",
         "sugarss": "*",
@@ -4568,6 +5006,9 @@
         "less": {
           "optional": true
         },
+        "lightningcss": {
+          "optional": true
+        },
         "sass": {
           "optional": true
         },
@@ -4596,6 +5037,20 @@
         "vite": ">=2.0.0"
       }
     },
+    "node_modules/vite-plugin-compression/node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
     "node_modules/vite-plugin-vue-setup-extend-plus": {
       "version": "0.1.0",
       "resolved": "https://registry.npmmirror.com/vite-plugin-vue-setup-extend-plus/-/vite-plugin-vue-setup-extend-plus-0.1.0.tgz",

+ 77 - 0
admin.ui.plus-master/src/api/admin/productionManagement/QRBookDto.ts

@@ -0,0 +1,77 @@
+/**
+ *  * 生产管理 - 电子二维码说明书
+ *  数据对象的Dto
+ */
+
+/**
+ * 查询过滤
+ */
+export interface QRBookFilter {
+    /** 上传人 */ 
+    Author?: string
+    /** 说明书文件名 */
+    FileName?: string
+    /** 开始查询时间 */
+    StartTime?: string | null
+    /** 结束查询时间 */
+    EndTime?: string | null
+}
+
+/**
+ * 分页查询请求
+ */
+export interface QRBookPageSearchRequest {
+    /**
+   * 当前页标
+   * @format int32
+   */
+  CurrentPage?: number
+  /**
+   * 每页大小
+   * @format int32
+   */
+  PageSize?: number
+  Filter?: QRBookFilter
+}
+
+/**
+ * 表数据
+ */
+export interface QRBookTableInfo {
+    /** 文件信息id */
+    id: number
+    /** 文件guid */
+    guid:string
+    /** 说明书文件名 */
+    fileName:string
+    /** 说明书后缀名 */
+    extension:string
+    /** 状态 */
+    status: number
+    /** 上传人 */
+    author:string
+    /** 备注 */
+    remark:string
+    /**上传时间 */
+    uploadTime:string
+    /**修改时间 */
+    updateTime:string
+}
+
+/**
+ * 分页查询响应
+ */
+export interface QRBookPageSearchResponse {
+    total:number,
+    list: QRBookTableInfo[]
+}
+
+/**
+ * 上传/修改文件信息
+ */
+export interface QRBookFileInfoRequset {
+    fileName?:string
+    status:number
+    author?:string
+    remark?:string
+}

+ 7 - 1
admin.ui.plus-master/src/api/admin/productionManagement/README.md

@@ -36,4 +36,10 @@
 
 #### groupLogoKeyDto.ts
 
-	生产管理 - 团标密钥 数据对象的DTO
+	生产管理 - 团标密钥 数据对象的DTO
+
+#### qrBookApi.ts
+	生产管理 - 电子二维码说明书后端请求
+
+#### QRBookDto.ts
+	生产管理 - 电子二维码说明书 数据对象DTO

+ 71 - 0
admin.ui.plus-master/src/api/admin/productionManagement/qrBookApi.ts

@@ -0,0 +1,71 @@
+import { storeToRefs } from "pinia";
+import { QRBookFileInfoRequset } from "./QRBookDto";
+import {ContentType, HttpClient, RequestParams} from "/@/api/admin/http-client";
+import {AxiosResponse} from "axios";
+import { useUserInfo } from "/@/stores/userInfo";
+import { number } from "echarts";
+
+export class QRBookApi<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
+    /**
+     * 分页查询
+     * @param data 
+     * @returns 
+     */
+    getPage = (query:any ,params: RequestParams = {}) : any  => 
+        this.request<AxiosResponse,any>({
+            path:'/api/app/qr-book/get-page',
+            method: 'GET',
+            query:query,
+            secure: true,
+            format: 'json',
+            ...params
+          })
+    
+
+    /**
+     * 上传/修改文件信息
+     * @param data 
+     * @returns 
+     */
+    uploadFile = (data:QRBookFileInfoRequset) => 
+        this.request<AxiosResponse,any>({
+            path: `/api/app/qr-book/upload`,
+            method: 'POST',
+            body: data,
+            secure: true,
+            type: ContentType.Json,
+            format: 'json',
+        })
+
+    /**
+     * 下载文件
+     * @param id 下载文件对应 id
+     * @param type 下载类型—— 0:文件;1:二维码
+     * @param FileName 下载文件名
+     */
+    donwloadFile = (id:string, type:number,fileName:string) => {
+        const { userInfos } = storeToRefs(useUserInfo());
+        const accessToken = userInfos.value.token
+        const token = `Bearer ${accessToken}`
+        var myHeaders = new Headers();
+        myHeaders.append("Authorization", token);
+
+        const requestOptions: RequestInit = {
+            method: 'GET',
+            headers: myHeaders,
+            redirect: 'follow', // 此处使用枚举值 'follow'
+        };
+
+        const fileUrl = import.meta.env.VITE_API_URL +'/api/app/qr-book/download?id='+id+'&type='+type; // 替换为实际文件URL
+        fetch(fileUrl,requestOptions)
+            .then(response => response.blob())
+            .then(blob => {
+                const link = document.createElement('a');
+                link.href = URL.createObjectURL(blob);
+                link.download = fileName;
+                link.click();
+            }).catch(error => {
+                console.error('下载失败:', error);
+            });
+    }
+}

+ 2 - 1
admin.ui.plus-master/src/stores/globalCacheStore.ts

@@ -18,7 +18,8 @@ const arr =
     'softwareType',
     'equipmentType',
     'softwarePackageStatus',
-    'oilEngineStatus'
+    'oilEngineStatus',
+    'qrBookFileStatus'
   ]
 
 export const useGlobalCacheStore = defineStore('globalCacheStore', {

+ 141 - 0
admin.ui.plus-master/src/views/admin/product/qrBook/components/qrbook-edit.vue

@@ -0,0 +1,141 @@
+<template>
+    <div class="admin-authorize-editInfo">
+      <el-dialog :title="formData.titleText" v-model="formData.isShowDialog" draggable width="769px">
+        <el-form :model="formData.editData"
+                 :rules="rules"
+                 ref="formRef"
+                 v-loading="formData.loading"
+                 size="default"
+                 label-width="80px">
+          <el-row :gutter="35">
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+              <el-form-item label="文件名" prop="fileName">
+                <el-input v-model="formData.editData.fileName" placeholder="上传文件会自动填写文件名" clearable></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+              <el-form-item label="上传人" prop="author">
+                <el-input v-model="formData.editData.author" placeholder="请输入上传人" clearable></el-input>
+              </el-form-item>
+            </el-col>
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+            <el-form-item label="状态" prop="status">
+              <el-select  v-model="formData.editData.status" placeholder="请设置文件状态" >
+                <el-option v-for="(value, key) in statusType" :key="key" :label="value[1].name"  :value="Number(value[1].value)" />
+              </el-select>
+            </el-form-item>
+          </el-col>
+            <el-col :xs="24" :sm="12" :md="12" :lg="12" :xl="12" class="mb20">
+              <el-form-item label="备注" prop="remark">
+                <el-input v-model="formData.editData.remark" placeholder="请输入备注" rows="6" clearable type="textarea"></el-input>
+              </el-form-item>
+            </el-col>
+          </el-row>
+          <QRBookUpload v-model="formData.fileValue" ref="uploadFileRef" :file="{fileName:formData.editData.fileName}" @onUpload="onUpload"/>
+        </el-form>
+        <template #footer>
+          <span class="dialog-footer">
+            <el-button @click="onCancel" icon="ele-CircleClose" size="default">取 消</el-button>
+            <el-button type="primary" :icon="formData.editIcon" @click="onSubmit" size="default">{{formData.buttonText}}</el-button>
+          </span>
+        </template>
+      </el-dialog>
+    </div>
+  </template>
+  
+  <script setup lang="ts">
+  import {defineAsyncComponent, reactive, ref, watch} from "vue";
+  import {FormRules} from "element-plus";
+  import {useGlobalCacheStore} from "/@/stores/globalCacheStore";
+  import { QRBookFileInfoRequset, QRBookTableInfo } from "/@/api/admin/productionManagement/QRBookDto";
+  import { QRBookApi } from "/@/api/admin/productionManagement/qrBookApi";
+  import eventBus from "/@/utils/mitt";
+  
+  /** 引入组件 */
+  const QRBookUpload = defineAsyncComponent(() => import('./qrbook-upload.vue'))
+  
+  /** 获取全局缓存 */
+  const globalCacheStore = useGlobalCacheStore()
+  /** 获取文件状态 */
+  const statusType = ref(globalCacheStore.getGlobalStore().get('qrBookFileStatus'))
+  
+  /**数据对象 */
+  const formData = reactive({
+    loading: false,
+    titleText:'',
+    editIcon:'',
+    buttonText:'',
+    isShowDialog: false,
+    editData:{} as QRBookTableInfo,
+    fileValue: null
+  })
+
+  /**表单校验*/
+  const rules = reactive<FormRules>({
+    fileName: [
+      { required: true, message: '请输入文件名', trigger: 'blur' },
+    ]
+  })
+  
+  /**
+   * 表单对象
+   */
+  const formRef = ref()
+  
+  const openDialog = (val) => {
+    formData.isShowDialog = true
+    if(val){
+      formData.editData = JSON.parse(JSON.stringify(val))
+      formData.titleText = '更新说明书'
+      formData.buttonText = '更新'
+      formData.editIcon = 'ele-Refresh'
+    }else {
+      formData.editData = {} as QRBookTableInfo
+      formData.titleText = '添加说明书'
+      formData.buttonText = '添加'
+      formData.editData.status = 1
+      formData.editIcon = 'ele-CirclePlus'
+    }
+  }
+  
+  const onCancel = () => {
+    formData.editData = {} as QRBookTableInfo
+    formData.isShowDialog = false
+  }
+  
+  /***监听弹窗关   闭表单验证*/
+  watch(() => formData.isShowDialog,(newVal) => {
+    if(newVal) formRef.value?.resetFields()
+  })
+  
+  const onUpload = (val) => {
+    formData.editData.guid = val.guid
+    formData.editData.fileName = val.fileName + val.extension
+    formData.editData.extension = val.extension
+  }
+  
+  const uploadFileRef = ref(null);
+  
+  const onSubmit =  () => {
+    formRef.value.validate(async (valid: boolean) =>{
+      if(!valid) return
+  
+      formData.loading = true
+      let request = JSON.parse(JSON.stringify(formData.editData)) 
+      let res = await new QRBookApi().uploadFile(request as QRBookFileInfoRequset)
+      if(res?.data?.value) eventBus.emit('refreshView')
+
+      formData.editData = {} as QRBookTableInfo
+      formData.isShowDialog = false
+      formData.loading = false
+    })
+  }
+  
+  defineExpose({
+    openDialog,
+  })
+  </script>
+  <style scoped lang="scss">
+  
+  </style>
+  

+ 79 - 0
admin.ui.plus-master/src/views/admin/product/qrBook/components/qrbook-upload.vue

@@ -0,0 +1,79 @@
+<template>
+    <el-upload
+      class="upload-demo"
+      v-model:file-list="fileList"
+      drag
+      :headers="{ Authorization:  'Bearer ' + useUserInfoStores.getToken()}"
+      :action='baseUrl+"/api/app/qr-book/upload-file"'
+      :on-success="handleAvatarSuccess"
+      :before-upload="beforeAvatarUpload"
+    >
+      <el-icon class="el-icon--upload"><upload-filled /></el-icon>
+      <div class="el-upload__text">
+        将文件拖到此处/<em>点击上传</em>
+      </div>
+      <template #tip>
+        <div class="el-upload__tip">
+          说明书上传
+        </div>
+      </template>
+    </el-upload>
+  </template>
+  
+  <script setup lang="ts">
+  import { UploadFilled} from "@element-plus/icons-vue";
+  import { useUserInfo } from '/@/stores/userInfo'
+  import {ElMessage, UploadProps, UploadUserFile} from "element-plus";
+  import { onMounted, ref, watch } from "vue";
+  
+  const useUserInfoStores = useUserInfo()
+  
+  const emits = defineEmits(['onUpload'])
+
+  const fileList = ref<UploadUserFile[]>([])
+
+  const baseUrl = import.meta.env.VITE_API_URL
+  
+  //接受父组件的传值
+  const props = defineProps({
+    file:{} as any
+  })
+  const file = ref(props.file)
+
+  // watch(() => props.file.fileUrl, (val)=> {
+  //   file.value.fileUrl = val
+  //   if(file.value.fileUrl) {
+  //     fileList.value = [{name:file.value.fileName,url:file.value.fileUrl} as UploadUserFile]
+  //   }else{
+  //     fileList.value = []
+  //   }
+  // })
+  watch(() => props.file.fileName, (val)=> {
+    file.value.fileName = val
+    if(val) fileList.value = [{name:val}]
+  })
+  
+  const handleAvatarSuccess: UploadProps['onSuccess'] = (
+    response,
+  ) => {
+    const res = response?.data
+    fileList.value = [{name:res.fileName+res.extension}]
+    file.value.guid = res.guid
+    file.value.fileName = res.fileName,
+    file.value.extension = res.extension
+    emits('onUpload',file.value)
+  }
+  
+  const beforeAvatarUpload: UploadProps['beforeUpload'] = (rawFile) => {
+    if (rawFile.size / 1024 / 1024 > 10) {
+      ElMessage.error('文件超过10MB!')
+      return false
+    }
+    return true
+  }
+  
+  onMounted(()=>{
+    if(file.value.fileName) fileList.value = [{name:file.value.fileName} as UploadUserFile]
+  })
+  </script>
+  

+ 238 - 0
admin.ui.plus-master/src/views/admin/product/qrBook/index.vue

@@ -0,0 +1,238 @@
+<template>
+    <div class="layout-pd">
+        <el-row>
+            <!-- 操作 -->
+            <el-col :xs="24">
+                <el-card class="mt8" shadow="hover">
+                    <el-form :model="qrBookData.Filter" :inline="true" @submit.stop.prevent>
+                        <el-form-item prop="name" style="width: 100%;">
+                            <el-col :xs="15" :sm="6" :md="5" :lg="5" class="mb20">
+                                <el-form-item label="上传人">
+                                    <el-input v-model="qrBookData.Filter.Author" placeholder="单行输入" clearable></el-input>
+                                </el-form-item>
+                            </el-col>
+                        
+                            <el-col :xs="24" :sm="12" :md="8" :lg="8" class="mb20">
+                                <el-form-item label="说明书名称">
+                                    <el-input v-model="qrBookData.Filter.FileName" placeholder="单行输入" clearable></el-input>
+                                </el-form-item>
+                            </el-col>
+
+                            <el-col :xs="24" :md="8" :lg="8" :xl="4" class="mb20">
+                                <el-form-item label="选择时间">
+                                    <el-date-picker
+                                        v-model="qrBookData.time"
+                                        type="datetimerange"
+                                        value-format="YYYY-MM-DD HH:mm:ss"
+                                        range-separator="To"
+                                        start-placeholder="Start date"
+                                        end-placeholder="End date" />
+                                </el-form-item>
+                            </el-col>
+
+                            <el-col :xs="24" :md="8" :lg="8" :xl="4" class="mb20">
+                                <el-form-item>
+                                    <el-button type="primary" icon="ele-Search" @click="getData()">查询</el-button>
+                                    <el-button type="primary" plain icon="ele-RefreshRight" @click="clear()">清空</el-button>
+                                </el-form-item>
+                            </el-col>
+                        </el-form-item>
+                        
+                        <div class="my-flex my-flex-end">
+                            <el-button type="primary" icon="ele-CirclePlus" @click="uploadDialog">上传说明书</el-button>
+                        </div>
+                    </el-form>
+                </el-card>
+            </el-col>
+
+            <!-- 表格 -->
+             <el-col :xs="24">
+                <el-card style="height: 70vh;" class="my-fill mt8" shadow="hover">
+                    <el-table v-loading="qrBookData.loading" stripe :data="qrBookData.tableModel" row-key="id" style="width: 100%;">
+                        <el-table-column v-for="column in qrBookData.dynamicColumns" :key="column.prop" :prop="column.prop" :label="column.label">
+                            <template #default="{row}">
+                                <span :style="getColor(column.prop,row)">
+                                    {{getName(column.prop,row)}}
+                                </span>
+                            </template>
+                        </el-table-column>
+                        <el-table-column label="操作" fixed="right" align="center" header-align="center" class="right-operation" width="140">
+                            <template #default="{row}">
+                                <el-link class="my-el-link mr12 ml12" type="primary" :underline="false" target="_blank" icon="ele-Edit" @click="editDialog(row)">编辑</el-link>
+                                <el-link class="my-el-link mr12 ml12"  type="primary" :underline="false" target="_blank" icon="ele-Download" @click="download(row,0)">下载文件</el-link>
+                                <el-link class="my-el-link mr12 ml12"  type="primary" :underline="false" target="_blank" icon="ele-Download" @click="download(row,1)">下载二维码</el-link>
+                            </template>
+                        </el-table-column>
+                    </el-table>
+                    <div class="my-flex my-flex-end" style="margin-top: 20px">
+                        <el-pagination
+                            v-model:currentPage="qrBookData.PageInput.CurrentPage"
+                            v-model:page-size="qrBookData.PageInput.PageSize"
+                            :total="qrBookData.total"
+                            :page-sizes="[10, 20, 50, 100]"
+                            small
+                            background
+                            @size-change="onSizeChange"
+                            @current-change="onCurrentChange"
+                            layout="total, sizes, prev, pager, next, jumper"/>
+                    </div>
+                    <template>
+                        <a ref="downloadLink" style="display: none;"></a>
+                    </template>
+                </el-card>
+             </el-col>
+        </el-row>
+        <FileEditDialog ref="fileEditRef"></FileEditDialog>
+    </div>
+    
+</template>
+
+<script setup lang="ts">
+import { defineAsyncComponent, onBeforeMount, onMounted, reactive, ref, watch } from "vue";
+import { QRBookFilter, QRBookPageSearchResponse } from "/@/api/admin/productionManagement/QRBookDto";
+import { pageInput } from "/@/api/admin/shareDto/shareDto";
+import { QRBookApi } from "/@/api/admin/productionManagement/qrBookApi";
+import eventBus from "/@/utils/mitt";
+import { useGlobalCacheStore } from "/@/stores/globalCacheStore";
+
+/**引入组件*/
+const FileEditDialog = defineAsyncComponent(() => import('./components/qrbook-edit.vue'))
+const fileEditRef = ref()
+
+/** 获取全局缓存 */
+const globalCacheStore = useGlobalCacheStore()
+  /** 获取文件状态 */
+  const statusType = ref(globalCacheStore.getGlobalStore().get('qrBookFileStatus'))
+
+const downloadLink = ref()
+
+const qrBookData = reactive({
+    // 是否加载
+    loading : false,
+    time:'',
+    // 查询条件
+    Filter:{
+        Author:"",
+        FileName:"",
+        StartTime: null,
+        EndTime: null
+    } as QRBookFilter,
+    // 表数据
+    tableModel:[] as QRBookPageSearchResponse[],
+    // 表头
+    dynamicColumns: [
+        { prop: 'fileName', label: '说明书文件名' },
+        { prop: 'author', label: '上传人' },
+        { prop: 'status', label: '状态' },
+        { prop: 'uploadTime', label: '上传时间' },
+        { prop: 'updateTime', label: '修改时间' },
+        { prop: 'remark', label: '备注' }
+    ],
+    /**分页标识 */
+    PageInput:{
+        CurrentPage: 1,
+        PageSize: 10,
+  } as pageInput,
+  /**分页总数 */
+  total: 0
+})
+
+//获取数据
+const getData = async () => {
+    qrBookData.loading = true
+    let res = await new QRBookApi().getPage({
+        ...qrBookData.PageInput,
+        "Filter.Author":qrBookData.Filter.Author,
+        "Filter.FileName":qrBookData.Filter.FileName,
+        "Filter.StartTime":qrBookData.Filter.StartTime,
+        "Filter.EndTime":qrBookData.Filter.EndTime
+    })
+    qrBookData.tableModel = res?.data?.list ?? []
+    qrBookData.total = res?.data?.total ?? 0
+    qrBookData.loading = false
+}
+
+//清除查询条件
+const clear = () => {
+    qrBookData.Filter = {
+        author:"",
+        fileName:"",
+        startTime: null,
+        endTime: null
+    } as QRBookFilter
+
+}
+
+//下载
+const download = async (row,type) => {
+    let fileName = ""
+    switch(type) {
+        case 0:
+            fileName = removeExtension(row.fileName) + row.extension
+            break
+        case 1:
+            fileName = removeExtension(row.fileName) + ".PNG"
+            break
+    }
+    let res = await new QRBookApi().donwloadFile(row.id,type,fileName)
+    
+}
+//去除文件名后缀
+const removeExtension = (filename:string) => {
+    const dotIndex = filename.lastIndexOf('.');  
+    if (dotIndex < 0) {  
+        // 如果没有找到'.',则返回原始文件名  
+        return filename;  
+    }  
+    // 返回去除最后一个'.'及其之后的所有字符的字符串  
+    return filename.slice(0, dotIndex);  
+}
+
+//打开上传文件弹窗
+const uploadDialog = () => {
+    fileEditRef.value.openDialog()
+}
+//打开编辑文件弹窗
+const editDialog = (row) => {
+    fileEditRef.value.openDialog(row)
+}
+
+const onSizeChange = () => {
+    getData()
+}
+
+const onCurrentChange = () => {
+    getData()
+}
+
+//获取颜色值
+const getColor = (val,row) => {
+    if(val === "status") return {color: statusType.value.get(String(row[val])).color}
+    return {}
+}
+
+//获取名称值
+const getName = (val,row) => {
+    if(val === "status") return statusType.value.get(String(row[val])).name
+    return row[val]
+}
+
+watch(() => qrBookData.time,(val) => {
+    if(val?.length === 0) return
+    qrBookData.Filter.StartTime = val?.[0].toString()
+    qrBookData.Filter.EndTime = val?.[1].toString()
+})
+
+onMounted(() => {
+    getData()
+    eventBus.off('refreshView')
+    eventBus.on('refreshView', async () => {
+        await getData()
+    })
+})
+
+onBeforeMount(() => {
+    eventBus.off('refreshView')
+})
+
+</script>