From 087daf26a99f673bbf5d05c2eb5034d427b558cb Mon Sep 17 00:00:00 2001 From: LiuJiaNan Date: Mon, 9 Jun 2025 11:33:46 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=B0=E8=B4=A6init?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- package-lock.json | 494 +++++++++++++++++- package.json | 9 +- src/assets/images/public/tx.png | Bin 0 -> 2365 bytes src/assets/js/aes_secret.js | 25 + src/assets/js/refreshToken.js | 17 + src/assets/js/utils.js | 480 +++++++++++++++++ src/components/verification/index.vue | 209 ++++++++ src/hooks/useFormValidate.js | 28 + src/hooks/useQueryCriteria.js | 54 ++ src/layout/breadcrumb/index.vue | 64 +++ .../header/components/change_password.vue | 70 +++ src/layout/header/index.vue | 125 +++++ src/layout/index.vue | 109 ++++ src/layout/menu/index.vue | 80 +++ src/main.js | 4 + src/pinia/miscellaneous.js | 24 + src/pinia/user.js | 33 ++ src/request/api.js | 8 + src/request/axios.js | 147 ++++++ src/router/index.js | 35 +- src/views/index/index.vue | 7 + src/views/login/index.vue | 185 +++++++ vite.config.js | 9 + 24 files changed, 2207 insertions(+), 11 deletions(-) create mode 100644 src/assets/images/public/tx.png create mode 100644 src/assets/js/aes_secret.js create mode 100644 src/assets/js/refreshToken.js create mode 100644 src/assets/js/utils.js create mode 100644 src/components/verification/index.vue create mode 100644 src/hooks/useFormValidate.js create mode 100644 src/hooks/useQueryCriteria.js create mode 100644 src/layout/breadcrumb/index.vue create mode 100644 src/layout/header/components/change_password.vue create mode 100644 src/layout/header/index.vue create mode 100644 src/layout/index.vue create mode 100644 src/layout/menu/index.vue create mode 100644 src/pinia/miscellaneous.js create mode 100644 src/pinia/user.js create mode 100644 src/request/api.js create mode 100644 src/request/axios.js create mode 100644 src/views/index/index.vue create mode 100644 src/views/login/index.vue diff --git a/.env.development b/.env.development index f8f9632..cfb6a7b 100644 --- a/.env.development +++ b/.env.development @@ -1,2 +1,2 @@ VITE_BASE=/ -VITE_BASE_URL= +VITE_BASE_URL=http://192.168.0.14:8060/qa_kangzai/ diff --git a/package-lock.json b/package-lock.json index 453e77e..3c9920e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,12 +8,16 @@ "name": "qa-kangzai-vue", "version": "0.0.0", "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@icon-park/vue-next": "^1.4.2", "@vueuse/core": "^13.3.0", "animate.css": "^4.1.1", "autofit.js": "^3.2.8", "axios": "^1.9.0", + "crypto-js": "^4.2.0", "dayjs": "^1.11.13", "echarts": "^5.6.0", + "element-plus": "^2.10.1", "lodash-es": "^4.17.21", "mitt": "^3.0.1", "normalize.css": "^8.0.1", @@ -22,7 +26,8 @@ "throttle-debounce": "^5.0.2", "v-viewer": "^3.0.21", "vue": "^3.5.13", - "vue-router": "^4.5.1" + "vue-router": "^4.5.1", + "vue3-puzzle-vcode": "^1.1.7" }, "devDependencies": { "@types/node": "^18.19.68", @@ -40,6 +45,8 @@ "eslint-plugin-vue": "^9.32.0", "prettier": "^2.8.8", "sass": "^1.83.0", + "unplugin-auto-import": "^19.3.0", + "unplugin-vue-components": "^28.7.0", "vite": "^6.3.5", "vite-plugin-env-parse": "^1.0.15", "vite-plugin-eslint": "^1.8.1", @@ -93,6 +100,24 @@ "node": ">=6.9.0" } }, + "node_modules/@ctrl/tinycolor": { + "version": "3.6.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", + "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/@element-plus/icons-vue/-/icons-vue-2.3.1.tgz", + "integrity": "sha512-XxVUZv48RZAd87ucGS48jPf6pKu0yV5UCg9f4FFwtrYxXOwWuVJo6wOvSLKEoMQKjv8GsX/mhP6UsC1lRwbUWg==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", "resolved": "https://repo.huaweicloud.com/repository/npm/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", @@ -591,6 +616,31 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/@floating-ui/core/-/core-1.7.1.tgz", + "integrity": "sha512-azI0DrjMMfIug/ExbBaeDVJXcY0a7EPvPjb2xAJPa4HeimBX+Z18HK8QQR3jb6356SnDDdxx+hinMLcJEDdOjw==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/@floating-ui/dom/-/dom-1.7.1.tgz", + "integrity": "sha512-cwsmW/zyw5ltYTUeeYJ60CnQuPqmGwuGVhG9w0PRaRKkAyi38BT5CKrpIbb+jtahSwUl04cWzSx9ZOIxeS6RsQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.1", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://repo.huaweicloud.com/repository/npm/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "license": "MIT" + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://repo.huaweicloud.com/repository/npm/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -629,6 +679,19 @@ "dev": true, "license": "BSD-3-Clause" }, + "node_modules/@icon-park/vue-next": { + "version": "1.4.2", + "resolved": "https://repo.huaweicloud.com/repository/npm/@icon-park/vue-next/-/vue-next-1.4.2.tgz", + "integrity": "sha512-+QklF255wkfBOabY+xw6FAI0Bwln/RhdwCunNy/9sKdKuChtaU67QZqU67KGAvZUTeeBgsL+yaHHxqfQeGZXEQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 8.0.0", + "npm": ">= 5.0.0" + }, + "peerDependencies": { + "vue": "3.x" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://repo.huaweicloud.com/repository/npm/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -1016,6 +1079,17 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.7", + "resolved": "https://repo.huaweicloud.com/repository/npm/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz", + "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, "node_modules/@rollup/pluginutils": { "version": "4.2.1", "resolved": "https://repo.huaweicloud.com/repository/npm/@rollup/pluginutils/-/pluginutils-4.2.1.tgz", @@ -1361,6 +1435,21 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/lodash": { + "version": "4.17.17", + "resolved": "https://repo.huaweicloud.com/repository/npm/@types/lodash/-/lodash-4.17.17.tgz", + "integrity": "sha512-RRVJ+J3J+WmyOTqnz3PiBLA501eKwXl2noseKOrNo/6+XEHjTAxO4xHvxQB6QuNm+s4WRbn6rSiap8+EA+ykFQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://repo.huaweicloud.com/repository/npm/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/node": { "version": "18.19.111", "resolved": "https://repo.huaweicloud.com/repository/npm/@types/node/-/node-18.19.111.tgz", @@ -1662,6 +1751,33 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://repo.huaweicloud.com/repository/npm/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://repo.huaweicloud.com/repository/npm/argparse/-/argparse-2.0.1.tgz", @@ -1801,6 +1917,12 @@ "node": ">= 0.4" } }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://repo.huaweicloud.com/repository/npm/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://repo.huaweicloud.com/repository/npm/asynckit/-/asynckit-0.4.0.tgz", @@ -1885,6 +2007,19 @@ "dev": true, "license": "MIT" }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/birpc": { "version": "2.3.0", "resolved": "https://repo.huaweicloud.com/repository/npm/birpc/-/birpc-2.3.0.tgz", @@ -1918,7 +2053,6 @@ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "fill-range": "^7.1.1" }, @@ -2202,6 +2336,12 @@ "node": ">= 8" } }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", + "license": "MIT" + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://repo.huaweicloud.com/repository/npm/cssesc/-/cssesc-3.0.0.tgz", @@ -2439,6 +2579,126 @@ "dev": true, "license": "ISC" }, + "node_modules/element-plus": { + "version": "2.10.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/element-plus/-/element-plus-2.10.1.tgz", + "integrity": "sha512-R+YM8b+s+3aQ3EeY33q0inn3ehRnunP42aDYoJxUtSZPgMPSXzYgmGEhIDP7Xg4NvY8raaSuO0/1fDLEfZ+nlA==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^3.4.1", + "@element-plus/icons-vue": "^2.3.1", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.14.182", + "@types/lodash-es": "^4.17.6", + "@vueuse/core": "^9.1.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.13", + "escape-html": "^1.0.3", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "lodash-unified": "^1.0.2", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/element-plus/node_modules/@types/web-bluetooth": { + "version": "0.0.16", + "resolved": "https://repo.huaweicloud.com/repository/npm/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz", + "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==", + "license": "MIT" + }, + "node_modules/element-plus/node_modules/@vueuse/core": { + "version": "9.13.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.16", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/core/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://repo.huaweicloud.com/repository/npm/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, + "node_modules/element-plus/node_modules/@vueuse/metadata": { + "version": "9.13.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/shared": { + "version": "9.13.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", + "license": "MIT", + "dependencies": { + "vue-demi": "*" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/element-plus/node_modules/@vueuse/shared/node_modules/vue-demi": { + "version": "0.14.10", + "resolved": "https://repo.huaweicloud.com/repository/npm/vue-demi/-/vue-demi-0.14.10.tgz", + "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "vue-demi-fix": "bin/vue-demi-fix.js", + "vue-demi-switch": "bin/vue-demi-switch.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@vue/composition-api": "^1.0.0-rc.1", + "vue": "^3.0.0-0 || ^2.6.0" + }, + "peerDependenciesMeta": { + "@vue/composition-api": { + "optional": true + } + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://repo.huaweicloud.com/repository/npm/entities/-/entities-4.5.0.tgz", @@ -2653,6 +2913,12 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://repo.huaweicloud.com/repository/npm/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, "node_modules/escape-string-regexp": { "version": "5.0.0", "resolved": "https://repo.huaweicloud.com/repository/npm/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", @@ -3254,7 +3520,6 @@ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3816,6 +4081,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/is-boolean-object": { "version": "1.2.2", "resolved": "https://repo.huaweicloud.com/repository/npm/is-boolean-object/-/is-boolean-object-1.2.2.tgz", @@ -3987,7 +4265,6 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.12.0" } @@ -4328,7 +4605,6 @@ "version": "4.17.21", "resolved": "https://repo.huaweicloud.com/repository/npm/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true, "license": "MIT" }, "node_modules/lodash-es": { @@ -4337,6 +4613,17 @@ "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==", "license": "MIT" }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://repo.huaweicloud.com/repository/npm/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://repo.huaweicloud.com/repository/npm/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4362,6 +4649,12 @@ "node": ">= 0.4" } }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://repo.huaweicloud.com/repository/npm/micromatch/-/micromatch-4.0.8.tgz", @@ -4523,6 +4816,16 @@ "dev": true, "license": "MIT" }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/normalize-range": { "version": "0.1.2", "resolved": "https://repo.huaweicloud.com/repository/npm/normalize-range/-/normalize-range-0.1.2.tgz", @@ -4533,6 +4836,12 @@ "node": ">=0.10.0" } }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, "node_modules/normalize.css": { "version": "8.0.1", "resolved": "https://repo.huaweicloud.com/repository/npm/normalize.css/-/normalize.css-8.0.1.tgz", @@ -5717,7 +6026,6 @@ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", - "optional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -5949,6 +6257,75 @@ "node": ">=18.12.0" } }, + "node_modules/unplugin-auto-import": { + "version": "19.3.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/unplugin-auto-import/-/unplugin-auto-import-19.3.0.tgz", + "integrity": "sha512-iIi0u4Gq2uGkAOGqlPJOAMI8vocvjh1clGTfSK4SOrJKrt+tirrixo/FjgBwXQNNdS7ofcr7OxzmOb/RjWxeEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "picomatch": "^4.0.2", + "unimport": "^4.2.0", + "unplugin": "^2.3.4", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^3.2.2", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-auto-import/node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://repo.huaweicloud.com/repository/npm/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/unplugin-auto-import/node_modules/unimport": { + "version": "4.2.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/unimport/-/unimport-4.2.0.tgz", + "integrity": "sha512-mYVtA0nmzrysnYnyb3ALMbByJ+Maosee2+WyE0puXl+Xm2bUwPorPaaeZt0ETfuroPOtG8jj1g/qeFZ6buFnag==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.1", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "pathe": "^2.0.3", + "picomatch": "^4.0.2", + "pkg-types": "^2.1.0", + "scule": "^1.3.0", + "strip-literal": "^3.0.0", + "tinyglobby": "^0.2.12", + "unplugin": "^2.2.2", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=18.12.0" + } + }, "node_modules/unplugin-utils": { "version": "0.2.4", "resolved": "https://repo.huaweicloud.com/repository/npm/unplugin-utils/-/unplugin-utils-0.2.4.tgz", @@ -5965,6 +6342,106 @@ "url": "https://github.com/sponsors/sxzz" } }, + "node_modules/unplugin-vue-components": { + "version": "28.7.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/unplugin-vue-components/-/unplugin-vue-components-28.7.0.tgz", + "integrity": "sha512-3SuWAHlTjOiZckqRBGXRdN/k6IMmKyt2Ch5/+DKwYaT321H0ItdZDvW4r8/YkEKQpN9TN3F/SZ0W342gQROC3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "debug": "^4.4.1", + "local-pkg": "^1.1.1", + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "tinyglobby": "^0.2.14", + "unplugin": "^2.3.4", + "unplugin-utils": "^0.2.4" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/unplugin-vue-components/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/unplugin-vue-components/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://repo.huaweicloud.com/repository/npm/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/unplugin-vue-components/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://repo.huaweicloud.com/repository/npm/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/unplugin-vue-components/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://repo.huaweicloud.com/repository/npm/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/untyped": { "version": "2.0.0", "resolved": "https://repo.huaweicloud.com/repository/npm/untyped/-/untyped-2.0.0.tgz", @@ -6240,6 +6717,11 @@ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, + "node_modules/vue3-puzzle-vcode": { + "version": "1.1.7", + "resolved": "https://repo.huaweicloud.com/repository/npm/vue3-puzzle-vcode/-/vue3-puzzle-vcode-1.1.7.tgz", + "integrity": "sha512-mW780dz7HKjrElnE60CeYSeHGidKBKHoMjTDYfqF21330rTkFOsfDK1FQKZ22MktgMtTEoS/imfpEDlM1cxY/g==" + }, "node_modules/webpack-virtual-modules": { "version": "0.6.2", "resolved": "https://repo.huaweicloud.com/repository/npm/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", diff --git a/package.json b/package.json index 8f0fa5e..90c6b35 100644 --- a/package.json +++ b/package.json @@ -9,12 +9,16 @@ "preview": "vite preview" }, "dependencies": { + "@element-plus/icons-vue": "^2.3.1", + "@icon-park/vue-next": "^1.4.2", "@vueuse/core": "^13.3.0", "animate.css": "^4.1.1", "autofit.js": "^3.2.8", "axios": "^1.9.0", + "crypto-js": "^4.2.0", "dayjs": "^1.11.13", "echarts": "^5.6.0", + "element-plus": "^2.10.1", "lodash-es": "^4.17.21", "mitt": "^3.0.1", "normalize.css": "^8.0.1", @@ -23,7 +27,8 @@ "throttle-debounce": "^5.0.2", "v-viewer": "^3.0.21", "vue": "^3.5.13", - "vue-router": "^4.5.1" + "vue-router": "^4.5.1", + "vue3-puzzle-vcode": "^1.1.7" }, "devDependencies": { "@types/node": "^18.19.68", @@ -41,6 +46,8 @@ "eslint-plugin-vue": "^9.32.0", "prettier": "^2.8.8", "sass": "^1.83.0", + "unplugin-auto-import": "^19.3.0", + "unplugin-vue-components": "^28.7.0", "vite": "^6.3.5", "vite-plugin-env-parse": "^1.0.15", "vite-plugin-eslint": "^1.8.1", diff --git a/src/assets/images/public/tx.png b/src/assets/images/public/tx.png new file mode 100644 index 0000000000000000000000000000000000000000..3f55e3037479fce0cac5804fc56ddddc6a9527d6 GIT binary patch literal 2365 zcmaJ@dpwi-AD>$Z6}hDgYeLIqo7-$m>_W;|3^S409xU6Q*~P7s9Z`}~Dwj_Da_bG5J(3E%El69kF`Z&t*xP7ADBFv zfEAAQA-a8yB|qU{ks=Wvi$KK2##+VNSb>5F1PX(}AduDwYimn6!crK|6EWf}c|zl5 z1tK713fO!R8{|Qk6d7TlScHSgGyS^+F8`Y>Px!S>@`fSe7<>fE3b|C$GLTIE|4=UX z8(Jvx0shJNe+mn!@q7T`0|-H}fGHnbxbadbK9(Q=7$Q(W1wqbo7b%gT2oy$wd?%kL>7(6E6LBzr2DpqVZ3yZWN5v);eM6`{o9STJvIiS&K z49OntV2iQC5NsTlxkQjD<^nv?GMDuam-Jokk{!5wd1N9WV8;L~Hv!0nekmKv{(dg_ z@9KT!vc8`S;k#UfJQ>8&aQ|!A%U5y-Ep5M9SAO_ret;);yg+X4&ov#X5QxfU527nI zu5aw;7od)xPHX46v!7A(2WrRZHT}GxM4esmTs?Xk5q?iuTiXSia&M*4*142Lg$)Hg zW`?gx#*H(Bd8X_3Ac+Ux>#wrS*4zFlM!lv)y?$U~VjI%y44oP5n14wTy!3_q4vhXpeusdfKS0%(S#S)25cEr}w8}W$i8I_}mrp*kS?W zxW>MP>Addq#&@L_xP|AkwHjl+v#%PH%d?w{Hu%44*Oo~ni(?<0=htpNIGfF^NS$hT zH|zXiHr^!va`|+?KFRsAPae~kwn;mOEA?|qFS_sR3wj*E8Jl3Fop58y8V(ePT%Q^^ zFZkp=|M}he`n=M>%F}<%ebg^=UMQ@gkB;mO&>z@P@8n~nT|L_`6gSU}b^A(mjTHy3 zS>T@%bk)%DLm%2qQmb?Vy}Z4yuFM}|Jsxb@ULNj>$}t;q*vbwM`S(rfi&EzPprZ)z&J%giq&mCCYSxq3_7f4SGFTx5R!wifn))bdt#RVpS3Q+zskQ;emqLTaugM;8Y4vY1))1p_iCIm< z>0=Vvwc?FDzvf<1J?;c!V7H#S9~jY56dc4ZEqwXDZsPe+9(q%K-Ysj~ju;!q=z0p3 zjE`(Gzjkk-{|S2Sw8-U>LCWA@%gf3{gY+YWHR>q=A19pYRr#UGp>#zR^(|ovzouX)cm-Fdb&o{P&^LTFmCbhNAAZ;L$R%b^!pW}G zkqd{@fUxdRlgK=_CgRS)(3T}Gv*`T3eZsR%Q)AYw}Nhad{(w>$Yv$k^$hj&v9{7Kr% zWzWO|b5CVbbF|+(7+%={fl z4OJKMBo#xn`1gbJ`>%}`W>0C>t74925_BfTt;JRaU5)Cr^FuGw9W8`&>P>|)<2|a3FcwP3SA)0XiDXu?6^-VfG z99~g>$89)2_pE=yiY>OL{BSC~ME0PKV(6?Tn=HLUpPG8TUXO&|YPd}|IVabQHvB9k z)lQ1Kcj6m1YU-$@v*FR~A~Ue=t|F}`|3R;=h6_`9 zowtin`$n)==$j8G7nQ=_x_0Hz5vnYW6-k8?y3>abpp*e zr})l$zZ-TzXXk8A!JtrnwC+)hLr?4;{a(FSaHi!n)nQ&~{R--Ug1LRpgW*{GHp+3{ z=Qst8>Jy$Z+BPrCc88uiR&|BkjE~km!5!Cquvp=fw5`3Onb@&9-QV!?qUCg0c}0~8 zCv1JMS{|BeT$b#eQx^@Q66);B92Eo z2fz(FU14jumNA{>?Zh;m_7n6bP2uo$fwILb7XlH~iF=~_1exuw! dxDquaq%b!l?!>O@=%pVT50V%03O@AEe*o*4-75e9 literal 0 HcmV?d00001 diff --git a/src/assets/js/aes_secret.js b/src/assets/js/aes_secret.js new file mode 100644 index 0000000..eb0fc29 --- /dev/null +++ b/src/assets/js/aes_secret.js @@ -0,0 +1,25 @@ +import CryptoJS from "crypto-js"; + +const key = CryptoJS.enc.Utf8.parse("daac3ae52eff4cec"); // 16位 + +const encrypt = (word) => { + let encrypted = ""; + if (typeof word === "string") { + const src = CryptoJS.enc.Utf8.parse(word); + encrypted = CryptoJS.AES.encrypt(src, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + } else if (typeof word === "object") { + // 对象格式的转成json字符串 + const data = JSON.stringify(word); + const src = CryptoJS.enc.Utf8.parse(data); + encrypted = CryptoJS.AES.encrypt(src, key, { + mode: CryptoJS.mode.ECB, + padding: CryptoJS.pad.Pkcs7, + }); + } + return encrypted.ciphertext.toString(CryptoJS.enc.Base64); +}; + +export { encrypt }; diff --git a/src/assets/js/refreshToken.js b/src/assets/js/refreshToken.js new file mode 100644 index 0000000..eb34068 --- /dev/null +++ b/src/assets/js/refreshToken.js @@ -0,0 +1,17 @@ +import dayjs from "dayjs"; +import { setRefreshToken } from "@/request/api.js"; +import { useUserStore } from "@/pinia/user.js"; +import pinia from "@/pinia/index.js"; +import router from "@/router/index.js"; + +export default async function () { + if (router.currentRoute.value.meta.isLogin) { + const userStore = useUserStore(pinia); + if (userStore.getTokenTime) { + if (dayjs().diff(dayjs(userStore.getTokenTime), "minute") >= 5) { + await userStore.setTokenTime(dayjs().format("YYYY-MM-DD HH:mm:ss")); + await setRefreshToken(); + } + } + } +} diff --git a/src/assets/js/utils.js b/src/assets/js/utils.js new file mode 100644 index 0000000..0ab922e --- /dev/null +++ b/src/assets/js/utils.js @@ -0,0 +1,480 @@ +import { ElMessage } from "element-plus"; +import dayjs from "dayjs"; + +/** + * @description 计算序号 + * @param {Object} pagination 分页数据对象 + * @param {number | string} pagination.currentPage 当前页 + * @param {number | string} pagination.pageSize 每页条数 + * @param {number} index 当页数据的索引值 + * @return {number} 序号 + **/ +export function serialNumber(pagination, index) { + return (pagination.currentPage - 1) * pagination.pageSize + (index + 1); +} + +/** + * @description 字符串数组转数组 + * @param {string} value 转换的字符串数组 + * @return {Array} 转换后的数组 + **/ +export function toArrayString(value) { + // eslint-disable-next-line no-eval + return value ? eval(value).map(String) : []; +} + +/** + * @description 判断文件后缀名是否符合 + * @param {string} name 文件名字 + * @param {string} suffix 文件后缀 + * @return {boolean} 是否符合 + **/ +export function interceptTheSuffix(name, suffix) { + return ( + name.substring(name.lastIndexOf("."), name.length).toLowerCase() === + suffix.toLowerCase() + ); +} + +/** + * @description 图片转base64 + * @param {string} imgUrl 图片地址 + * @return {Promise} Promise实例,then包含base64编码 + **/ +export function image2Base64(imgUrl) { + return new Promise((resolve) => { + const img = new Image(); + img.src = imgUrl; + img.crossOrigin = "Anonymous"; + img.onload = function () { + const canvas = document.createElement("canvas"); + canvas.width = img.width; + canvas.height = img.height; + const ctx = canvas.getContext("2d"); + ctx.drawImage(img, 0, 0, img.width, img.height); + const ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase(); + resolve(canvas.toDataURL("image/" + ext)); + }; + }); +} + +/** + * @description 判断图片是否可访问成功 + * @param {string} imgUrl 图片地址 + * @return {Promise} Promise实例 + **/ +export function checkImgExists(imgUrl) { + return new Promise((resolve, reject) => { + const ImgObj = new Image(); + ImgObj.src = imgUrl; + ImgObj.onload = function (res) { + resolve(res); + }; + ImgObj.onerror = function (err) { + reject(err); + }; + }); +} + +/** + * @description 获取数据类型 + * @param {any} data 数据 + * @return {string} 数据类型 + **/ +export function getDataType(data) { + return Object.prototype.toString.call(data).slice(8, -1); +} + +/** + * @description 数组去重 + * @param {Array} arr 去重的数组 + * @return {Array} 去重后的数组 + **/ +export function ArrayDeduplication(arr) { + return [...new Set(arr)]; +} + +/** + * @description 数组对象去重 + * @param {Array} arr 去重的数组 + * @param {string} name 去重的key + * @return {Array} 去重后的数组 + **/ +export function arrayObjectDeduplication(arr, name) { + const obj = {}; + arr = arr.reduce(function (previousValue, currentValue) { + if (!obj[currentValue[name]]) { + obj[currentValue[name]] = true; + previousValue.push(currentValue); + } + return previousValue; + }, []); + return arr; +} + +/** + * @description 查找字符串中指定的值第几次出现的位置 + * @param {Array} str 查找的字符串数组 + * @param {string} char 查找的值 + * @param {number} num 第几次出现 + * @return {number} 出现的位置 + **/ +export function findCharIndex(str, char, num) { + let index = str.indexOf(char); + if (index === -1) return -1; + for (let i = 0; i < num - 1; i++) { + index = str.indexOf(char, index + 1); + if (index === -1) return -1; + } + return index; +} + +/** + * @description 生成指定两个值之间的随机数 + * @param {number} min 最小值 + * @param {number} max 最大值 + * @return {number} 随机数 + **/ +export function randoms(min, max) { + return Math.random() * (max - min + 1) + min; +} + +/** + * @description 千位分隔符 + * @param {number | string} num 转换的值 + * @return {string} 转换后的值 + **/ +export function numFormat(num) { + if (num) { + const numArr = num.toString().split("."); + const arr = numArr[0].split("").reverse(); + let res = []; + for (let i = 0; i < arr.length; i++) { + if (i % 3 === 0 && i !== 0) { + res.push(","); + } + res.push(arr[i]); + } + res.reverse(); + if (numArr[1]) { + res = res.join("").concat("." + numArr[1]); + } else { + res = res.join(""); + } + return res; + } +} + +/** + * @description 验证是否为空 + * @param {any} value 验证的值 + * @return {boolean} 是否为空 + **/ +export function isEmpty(value) { + return ( + value === undefined || + value === null || + (typeof value === "object" && Object.keys(value).length === 0) || + (typeof value === "string" && value.trim().length === 0) + ); +} + +/** + * @description 获取url参数 + * @param {string} name 获取的key + * @return {string} 获取的值 + **/ +export function getUrlParam(name) { + const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); + const r = window.location.search.substr(1).match(reg); + if (r != null) return decodeURI(r[2]); + return ""; +} + +/** + * @description 数据分页 + * @param {Array} list 分页的数组 + * @param {number | string} currentPage 当前页 + * @param {number | string} pageSize 每页条数 + * @return {Array} 分页后的数组 + **/ +export function paging(list, currentPage, pageSize) { + return list.filter((item, index) => { + return ( + index < +currentPage * +pageSize && + index >= (+currentPage - 1) * +pageSize + ); + }); +} + +/** + * @description 获取文件后缀 + * @param {string} name 文件名 + * @return {string} 文件后缀 + **/ +export function getFileSuffix(name) { + return name.substring(name.lastIndexOf(".") + 1); +} + +/** + * @description 获取文件名称 + * @param {string} name 文件地址 + * @return {string} 文件名称 + **/ +export function getFileName(name) { + if (!name) return ""; + return name.substring(name.lastIndexOf("/") + 1); +} + +/** + * @description 读取txt文档 + * @param {string} filePah 文档路径 + * @return {resolve,string} 读取后的内容 + **/ +export function readTxtDocument(filePah) { + return new Promise((resolve) => { + const FILE_URL = import.meta.env.VITE_FILE_URL; + const file_url = FILE_URL + filePah; + const xhr = new XMLHttpRequest(); + xhr.open("get", file_url, true); + xhr.responseType = "blob"; + xhr.onload = function (event) { + const reader = new FileReader(); + reader.readAsText(event.target.response, "GB2312"); + reader.onload = function () { + resolve(reader.result); + }; + }; + xhr.send(); + }); +} + +/** + * @description 将秒转换成时分秒 + * @param {string,number} second 需要转换的秒数 + * @return {string} 转换后的时间 + **/ +export function secondConversion(second) { + if (!second) return 0; + const h = parseInt(second / 60 / 60, 10); + const m = parseInt((second / 60) % 60, 10); + const s = parseInt(second % 60, 10); + if (h) { + return h + "小时" + m + "分钟" + s + "秒"; + } else { + if (m) { + return m + "分钟" + s + "秒"; + } else { + return s + "秒"; + } + } +} + +/** + * @description 附件添加前缀 + * @param {Array} list 附件数组 + * @return {Array} 添加完的数组 + **/ +export function addingPrefixToFile(list) { + if (!list) return []; + const FILE_URL = import.meta.env.VITE_FILE_URL; + for (let i = 0; i < list.length; i++) { + list[i].url = FILE_URL + list[i].FILEPATH; + if (list[i].FILENAME) { + list[i].name = list[i].FILENAME; + } else { + list[i].name = getFileName(list[i].FILEPATH); + } + } + return list; +} + +/** + * @description 验证重复选择 + * @param {Array} list 验证的数组 + * @param {number} index 选择的索引 + * @param {string} key 验证的字段 + * @param {string} id 验证的值 + **/ +export async function verifyDuplicateSelection(list, index, key, id) { + return new Promise((resolve, reject) => { + if (list.some((item) => item[key] === id)) { + ElMessage.warning("不能重复选择"); + reject(new Error("不能重复选择")); + } else { + list[index][key] = id; + resolve(); + } + }); +} + +/** + * @description 翻译状态 + * @param {number | string} status 状态 + * @param {Array} list 翻译的数组 + * @param {String} idKey + * @param {String} nameKey + * @return {string} 翻译后的状态 + **/ +export function translationStatus( + status, + list, + idKey = "id", + nameKey = "name" +) { + for (let i = 0; i < list.length; i++) { + if (status === list[i][idKey]) { + return list[i][nameKey]; + } + } +} + +/** + * @description 计算文件大小 + * @param {number | string} size 文件kb + * @return {string} 计算后的文件大小 + **/ +export function calculateFileSize(size) { + return size > 1024 + ? (size / 1024 + "").substring(0, (size / 1024 + "").lastIndexOf(".") + 3) + + "MB" + : size + "KB"; +} + +/** + * @description 根据身份证号获取出生日期和性别 + * @param {String} idCard 身份证号 + * @return {Object} 出生日期和性别 date sex + **/ +export function idCardGetDateAndGender(idCard) { + const reg = + /^[1-9]\d{5}(18|19|([23]\d))\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\d{3}[0-9Xx]$/; + let sex = ""; + let date = ""; + if (reg.test(idCard)) { + const org_birthday = idCard.substring(6, 14); + const org_gender = idCard.substring(16, 17); + const birthday = + org_birthday.substring(0, 4) + + "-" + + org_birthday.substring(4, 6) + + "-" + + org_birthday.substring(6, 8); + const birthdays = new Date(birthday.replace(/-/g, "/")); + const Month = birthdays.getMonth() + 1; + let MonthDate; + const DayDate = birthdays.getDate(); + let Day; + if (Month < 10) MonthDate = "0" + Month; + else MonthDate = Month; + if (DayDate < 10) Day = "0" + DayDate; + else Day = DayDate; + sex = org_gender % 2 === 1 ? "1" : "0"; + date = birthdays.getFullYear() + "-" + MonthDate + "-" + Day; + } + return { sex, date }; +} + +/** + * @description 获取select的label + * @param {Array} list 获取的数组 + * @param {number | string} value 获取的值 + * @param {string?} idKey 获取的id + * @param {string?} labelKey 获取的label + * @return {string} 获取的label + **/ +export function getSelectLabel( + list, + value, + idKey = "bianma", + labelKey = "name" +) { + const result = list.find((item) => item[idKey] === value); + return result ? result[labelKey] : ""; +} + +/** + * @description 获取select中指定项组成的数组 + * @param {Array} list 获取的数组 + * @param {Array} value 获取的值 + * @param {string?} idKey 获取的id + * @return {Array} list中指定项组成的数组 + **/ +export function getSelectAppointItemList(list, value, idKey = "id") { + return list.filter((item) => value.includes(item[idKey])); +} + +/** + * @description dayjs改变日期格式 + * @param {date} date 传入的日期 + * @param {string} column 需要变成的日期格式 + * @return {string} 改变的日期格式 + **/ +export function formatDate(date, column) { + if (date) { + return dayjs(date).format(column); + } else { + return ""; + } +} + +/** + * @description json转换为树形结构 + * @param {Array} json 需要转换的json + * @param {string} idStr id字段 + * @param {string} pidStr 父级id字段 + * @param {string} chindrenStr 子级字段 + * @return {string} 转换完的树形结构 + **/ +export function listTransTree(json, idStr, pidStr, chindrenStr) { + const r = []; + const hash = {}; + const id = idStr; + const pid = pidStr; + const children = chindrenStr; + let i = 0; + let j = 0; + const len = json.length; + for (; i < len; i++) { + hash[json[i][id]] = json[i]; + } + for (; j < len; j++) { + const aVal = json[j]; + const hashVP = hash[aVal[pid]]; + if (hashVP) { + !hashVP[children] && (hashVP[children] = []); + hashVP[children].push(aVal); + } else { + r.push(aVal); + } + } + return r; +} + +/** + * @description 附件添加前缀 + * @param {Array} list 附件数组 + * @return {Array} 添加完的数组 + **/ +export function fileFeedback(list) { + if (!list) return []; + const FILE_URL = import.meta.env.VITE_FILE_URL; + for (let i = 0; i < list.length; i++) { + list[i].url = FILE_URL + list[i].filepath; + list[i].name = list[i].filepath || getFileName(list[i].filepath); + list[i].imgfilesId = getFileSuffix(list[i].imgfilesId); + } + return list; +} + +/** + * @description 获取文件路径前缀地址 + * @return {string} 文件路径前缀地址 + **/ +export function getFileUrl() { + return import.meta.env.VITE_FILE_URL; +} + +export function getBaseUrl() { + return import.meta.env[import.meta.env.DEV ? "VITE_PROXY" : "VITE_BASE_URL"]; +} diff --git a/src/components/verification/index.vue b/src/components/verification/index.vue new file mode 100644 index 0000000..81d3271 --- /dev/null +++ b/src/components/verification/index.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/src/hooks/useFormValidate.js b/src/hooks/useFormValidate.js new file mode 100644 index 0000000..9db28ca --- /dev/null +++ b/src/hooks/useFormValidate.js @@ -0,0 +1,28 @@ +import { ElMessage } from "element-plus"; +import { useTemplateRef } from "vue"; + +export default function useFormValidate() { + const formRef = useTemplateRef("formRef"); + const validate = (message = "请补全必填项!") => { + return new Promise((resolve, reject) => { + formRef.value.validate((valid) => { + if (valid) { + resolve(valid); + } else { + reject(valid); + ElMessage.warning(message); + setTimeout(() => { + const element = document.querySelectorAll( + ".el-form-item__error" + )[0]; + element.scrollIntoView({ + behavior: "smooth", + block: "center", + }); + }, 100); + } + }); + }); + }; + return { validate, formRef }; +} diff --git a/src/hooks/useQueryCriteria.js b/src/hooks/useQueryCriteria.js new file mode 100644 index 0000000..ef54ce3 --- /dev/null +++ b/src/hooks/useQueryCriteria.js @@ -0,0 +1,54 @@ +import { useMiscellaneousStore } from "@/pinia/miscellaneous.js"; + +export const getQueryCriteria = () => { + const miscellaneousStore = useMiscellaneousStore(); + const key = window.location.href; + let queryCriteria = miscellaneousStore.getQueryCriteria[key] || {}; + if (queryCriteria.tabsActiveName) { + queryCriteria = + miscellaneousStore.getQueryCriteria[ + key + "/" + queryCriteria.tabsActiveName + ] || {}; + } + const pagination = queryCriteria.pagination; + const searchForm = queryCriteria.searchForm; + const tabsActiveName = queryCriteria.tabsActiveName; + return { + pagination, + searchForm, + tabsActiveName, + }; +}; +export const setQueryCriteria = (data) => { + const miscellaneousStore = useMiscellaneousStore(); + let key = window.location.href; + if (data.tabsActiveName) { + miscellaneousStore.setQueryCriteria({ + ...miscellaneousStore.getQueryCriteria, + [key]: { + ...miscellaneousStore.getQueryCriteria[key], + tabsActiveName: data.tabsActiveName, + }, + }); + key = key + "/" + data.tabsActiveName; + } + miscellaneousStore.setQueryCriteria({ + ...miscellaneousStore.getQueryCriteria, + [key]: { + ...miscellaneousStore.getQueryCriteria[key], + ...data, + }, + }); +}; + +export const resetQueryCriteria = () => { + const miscellaneousStore = useMiscellaneousStore(); + miscellaneousStore.resetQueryCriteria(); +}; + +export const getTabsActiveName = () => { + const key = window.location.href; + const miscellaneousStore = useMiscellaneousStore(); + const queryCriteria = miscellaneousStore.getQueryCriteria[key] || {}; + return queryCriteria.tabsActiveName; +}; diff --git a/src/layout/breadcrumb/index.vue b/src/layout/breadcrumb/index.vue new file mode 100644 index 0000000..2aa8b34 --- /dev/null +++ b/src/layout/breadcrumb/index.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/src/layout/header/components/change_password.vue b/src/layout/header/components/change_password.vue new file mode 100644 index 0000000..9c3fa31 --- /dev/null +++ b/src/layout/header/components/change_password.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/layout/header/index.vue b/src/layout/header/index.vue new file mode 100644 index 0000000..a3e4315 --- /dev/null +++ b/src/layout/header/index.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/layout/index.vue b/src/layout/index.vue new file mode 100644 index 0000000..f81f7a3 --- /dev/null +++ b/src/layout/index.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/src/layout/menu/index.vue b/src/layout/menu/index.vue new file mode 100644 index 0000000..bfeca01 --- /dev/null +++ b/src/layout/menu/index.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/main.js b/src/main.js index c001e99..fbb0a65 100644 --- a/src/main.js +++ b/src/main.js @@ -9,8 +9,12 @@ import "normalize.css"; import "animate.css"; import "viewerjs/dist/viewer.css"; import VueViewer from "v-viewer"; +import { install } from "@icon-park/vue-next/es/all"; +import "element-plus/es/components/loading/style/css"; +import "element-plus/es/components/message/style/css"; const app = createApp(App); +install(app, "icon"); app .use(pinia) .use(router) diff --git a/src/pinia/miscellaneous.js b/src/pinia/miscellaneous.js new file mode 100644 index 0000000..2dc713c --- /dev/null +++ b/src/pinia/miscellaneous.js @@ -0,0 +1,24 @@ +import { defineStore } from "pinia"; + +export const useMiscellaneousStore = defineStore("miscellaneousStore", { + state: () => ({ + queryCriteria: {}, + }), + getters: { + getQueryCriteria() { + return this.queryCriteria; + }, + }, + actions: { + setQueryCriteria(data) { + this.queryCriteria = data; + }, + resetQueryCriteria() { + this.queryCriteria = {}; + }, + }, + persist: { + storage: window.sessionStorage, + paths: [""], + }, +}); diff --git a/src/pinia/user.js b/src/pinia/user.js new file mode 100644 index 0000000..801ed72 --- /dev/null +++ b/src/pinia/user.js @@ -0,0 +1,33 @@ +import { defineStore } from "pinia"; + +export const useUserStore = defineStore("userStore", { + state: () => ({ + userInfo: {}, + token: "", + tokenTime: "1", + permissions: [], + }), + getters: { + getUserInfo: (state) => state.userInfo, + getToken: (state) => state.token, + getTokenTime: (state) => state.tokenTime, + getPermissions: (state) => state.permissions, + }, + actions: { + setUserInfo(userInfo) { + this.userInfo = userInfo; + }, + async setToken(token) { + this.token = token; + }, + async setTokenTime(tokenTime) { + this.tokenTime = tokenTime; + }, + setPermissions(permissions) { + this.permissions = permissions; + }, + }, + persist: { + storage: window.sessionStorage, + }, +}); diff --git a/src/request/api.js b/src/request/api.js new file mode 100644 index 0000000..db7965b --- /dev/null +++ b/src/request/api.js @@ -0,0 +1,8 @@ +import { post } from "./axios"; + +export const Login = (params) => post("/sys/login", params); // 登录 +export const logout = (params) => post("/sys/logout", params); // 退出登录 +export const getUserInfo = (params) => post("/sys/user/info", params); // 获取用户信息 +export const setChangePassword = (params) => post("/sys/user/password", params); // 修改密码 +export const setRefreshToken = (params) => + post("/sys/refreshToken", { loading: false, ...params }); // 刷新token diff --git a/src/request/axios.js b/src/request/axios.js new file mode 100644 index 0000000..ef6ac83 --- /dev/null +++ b/src/request/axios.js @@ -0,0 +1,147 @@ +import axios from "axios"; +import { ElLoading, ElMessage } from "element-plus"; +import router from "../router"; +import pinia from "../pinia"; +import { useUserStore } from "@/pinia/user.js"; +import refreshToken from "@/assets/js/refreshToken.js"; +import { getBaseUrl } from "@/assets/js/utils.js"; + +let loading = null; +let isTipTokenFailure = false; +function startLoading() { + loading = ElLoading.service({ + lock: true, + text: "加载中...", + background: "rgba(0, 0, 0, 0.5)", + }); +} + +function endLoading() { + loading && loading.close(); +} + +axios.defaults.baseURL = getBaseUrl(); +axios.defaults.timeout = 1000 * 60 * 10; +// axios.defaults.withCredentials = true; +axios.interceptors.request.use( + async (config) => { + const userStore = useUserStore(pinia); + config.headers.Token = userStore.getToken; + if (config.method === "get" || config.method === "GET") { + if (config.params.loading !== false) startLoading(); + } + if (config.method === "post" || config.method === "POST") { + if (config.data.loading !== false) startLoading(); + } + return config; + }, + (error) => Promise.reject(error) +); + +axios.interceptors.response.use( + (config) => { + if (config.config.method === "get" || config.config.method === "GET") { + if (config.config.params.loading !== false) endLoading(); + } + if (config.config.method === "post" || config.config.method === "POST") { + if (config.config.headers["Content-Type"] === "multipart/form-data") { + endLoading(); + } else { + if (JSON.parse(config.config.data)?.loading !== false) endLoading(); + } + } + if (config.data.code === 401) { + if (!isTipTokenFailure) { + isTipTokenFailure = true; + ElMessage.error("登录失效,请重新登录"); + router.push("/login").then(); + isTipTokenFailure = false; + } + return Promise.reject(config.data.msg); + } else { + refreshToken(); + } + return config; + }, + (error) => { + if (error && error.response) { + error.message = `连接错误${error.response.status}`; + import.meta.env.DEV && + ElMessage.error(`连接错误${error.response.status}`); + } else { + error.message = "连接到服务器失败"; + ElMessage.error("连接到服务器失败"); + } + return Promise.reject(error.message); + } +); + +export function post(url, params = {}) { + const userStore = useUserStore(pinia); + return new Promise((resolve, reject) => { + axios + .post(url, { + corpinfoId: userStore.getUserInfo.corpinfoId, + userId: userStore.getUserInfo.userId, + ...params, + }) + .then((res) => { + if (res.data.result === "success") { + resolve(res.data); + } else { + ElMessage.error(res.data.msg || "系统开小差了"); + reject(res.data); + } + }) + .catch((err) => { + reject(err); + }); + }); +} + +export function get(url, params = {}) { + const userStore = useUserStore(pinia); + return new Promise((resolve, reject) => { + axios + .get(url, { + params: { + corpinfoId: userStore.getUserInfo.corpinfoId, + userId: userStore.getUserInfo.userId, + ...params, + }, + }) + .then((res) => { + if (res.data.result === "success") { + resolve(res.data); + } else { + ElMessage.error(res.data.msg || "系统开小差了"); + reject(res.data); + } + }) + .catch((err) => { + reject(err); + }); + }); +} + +export function upload(url, params = {}) { + return new Promise((resolve, reject) => { + axios + .post(url, params, { + headers: { + "Content-Type": "multipart/form-data", + }, + }) + .then((res) => { + if (res.data.result === "success") { + resolve(res.data); + } else { + ElMessage.error(res.data.msg || "系统开小差了"); + reject(res.data); + } + }) + .catch((err) => { + reject(err); + }); + }); +} diff --git a/src/router/index.js b/src/router/index.js index 3aef40a..1ac4a95 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -1,19 +1,25 @@ import { createRouter, createWebHashHistory } from "vue-router"; import children from "../components/children/index.vue"; +import loayout from "@/layout/index.vue"; const routes = [ + { + path: "/login", + name: "/login", + meta: { title: "登录", isLogin: false }, + component: () => import("@/views/login/index"), + }, { path: "/", name: "app", redirect: "/map", - meta: { title: "首页", isLogin: true }, + meta: { isLogin: true }, component: children, children: [ { path: "/map/:type?", - name: "/map", meta: { - title: "首页", + title: "地图", breadcrumb: false, isMenu: false, isSubMenu: false, @@ -22,6 +28,29 @@ const routes = [ }, component: () => import("@/views/map/index"), }, + { + path: "/backend", + name: "backend", + meta: { + breadcrumb: false, + isMenu: false, + isSubMenu: false, + isBack: false, + }, + component: loayout, + children: [ + { + path: "/backend/index", + meta: { title: "首页", isMenu: false }, + component: () => import("@/views/index/index"), + }, + { + path: "/backend/index111", + meta: { title: "首页" }, + component: () => import("@/views/index/index"), + }, + ], + }, ], }, { diff --git a/src/views/index/index.vue b/src/views/index/index.vue new file mode 100644 index 0000000..3b59031 --- /dev/null +++ b/src/views/index/index.vue @@ -0,0 +1,7 @@ + + + + + diff --git a/src/views/login/index.vue b/src/views/login/index.vue new file mode 100644 index 0000000..f9d42b9 --- /dev/null +++ b/src/views/login/index.vue @@ -0,0 +1,185 @@ + + + + + diff --git a/vite.config.js b/vite.config.js index 84bccd7..b33fd44 100644 --- a/vite.config.js +++ b/vite.config.js @@ -3,6 +3,9 @@ import vue from "@vitejs/plugin-vue"; import eslintPlugin from "vite-plugin-eslint"; import removeConsole from "vite-plugin-remove-console"; import { envParse } from "vite-plugin-env-parse"; +import AutoImport from "unplugin-auto-import/vite"; +import Components from "unplugin-vue-components/vite"; +import { ElementPlusResolver } from "unplugin-vue-components/resolvers"; export default ({ mode }) => { return defineConfig({ @@ -11,6 +14,12 @@ export default ({ mode }) => { vue(), envParse(), eslintPlugin(), + AutoImport({ + resolvers: [ElementPlusResolver()], + }), + Components({ + resolvers: [ElementPlusResolver()], + }), removeConsole({ includes: [ "assert",