Compare commits

..
Author SHA1 Message Date
zxl 43b763bbce Revert "story#7062,供应商培训和财务发票上传挂钩--曹智龙"
This reverts commit 2c94eee160.
2025-08-21 17:24:20 +08:00
zxl c333298f82 Revert "story#7074,地图搜索位置改动为后台接口"
This reverts commit 1abb7ac605.
2025-08-21 17:24:18 +08:00
zxl 1bd67b4f28 Revert "story#7074,地图搜索位置改动为后台接口"
This reverts commit 60836e19da.
2025-08-21 17:24:17 +08:00
138 changed files with 711 additions and 231247 deletions
-2
View File
@@ -17,8 +17,6 @@ pnpm-debug.log*
# Editor directories and files
.idea
.vscode
.claude
.kimi-code
*.suo
*.ntvs*
*.njsproj
-3
View File
@@ -3,7 +3,4 @@
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
<component name="WebPackConfiguration">
<option name="mode" value="DISABLED" />
</component>
</project>
+35 -297
View File
@@ -15,10 +15,9 @@
"dayjs": "^1.8.14",
"decimal.js": "^10.4.3",
"echarts": "^5.2.2",
"element-ui": "^2.15.13",
"element-ui": "^2.15.9",
"less": "^4.1.3",
"less-loader": "^11.1.3",
"qrcode": "^1.5.4",
"qs": "^6.11.2",
"sass": "^1.65.1",
"sass-loader": "^13.3.2",
@@ -3351,6 +3350,7 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true,
"engines": {
"node": ">=8"
}
@@ -4801,15 +4801,6 @@
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/decimal.js": {
"version": "10.4.3",
"resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.4.3.tgz",
@@ -5029,12 +5020,6 @@
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
"dev": true
},
"node_modules/dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==",
"license": "MIT"
},
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -5225,7 +5210,8 @@
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"node_modules/emojis-list": {
"version": "3.0.0",
@@ -6229,6 +6215,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"dependencies": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@@ -6383,6 +6370,7 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true,
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
@@ -7004,6 +6992,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true,
"engines": {
"node": ">=8"
}
@@ -7419,6 +7408,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"dependencies": {
"p-locate": "^4.1.0"
},
@@ -8455,6 +8445,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"dependencies": {
"p-try": "^2.0.0"
},
@@ -8469,6 +8460,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"dependencies": {
"p-limit": "^2.2.0"
},
@@ -8493,6 +8485,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true,
"engines": {
"node": ">=6"
}
@@ -8589,6 +8582,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true,
"engines": {
"node": ">=8"
}
@@ -8669,15 +8663,6 @@
"node": ">=8"
}
},
"node_modules/pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==",
"license": "MIT",
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/portfinder": {
"version": "1.0.32",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
@@ -9409,131 +9394,6 @@
"node": ">=6"
}
},
"node_modules/qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"license": "MIT",
"dependencies": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"bin": {
"qrcode": "bin/qrcode"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/qrcode/node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/qrcode/node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/qrcode/node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"node_modules/qrcode/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/qrcode/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/qrcode/node_modules/wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
"license": "ISC"
},
"node_modules/qrcode/node_modules/yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"license": "MIT",
"dependencies": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
},
"engines": {
"node": ">=8"
}
},
"node_modules/qrcode/node_modules/yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"license": "ISC",
"dependencies": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/qs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
@@ -9783,6 +9643,7 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -9796,12 +9657,6 @@
"node": ">=0.10.0"
}
},
"node_modules/require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
"license": "ISC"
},
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -10178,12 +10033,6 @@
"node": ">= 0.8.0"
}
},
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"license": "ISC"
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -10475,6 +10324,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -10488,6 +10338,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -11851,12 +11702,6 @@
"which": "bin/which"
}
},
"node_modules/which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
"license": "ISC"
},
"node_modules/wildcard": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
@@ -14573,7 +14418,8 @@
"ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
@@ -15627,11 +15473,6 @@
}
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA=="
},
"decimal.js": {
"version": "10.4.3",
"resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.4.3.tgz",
@@ -15786,11 +15627,6 @@
"integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
"dev": true
},
"dijkstrajs": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/dijkstrajs/-/dijkstrajs-1.0.3.tgz",
"integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA=="
},
"dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -15947,7 +15783,8 @@
"emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"dev": true
},
"emojis-list": {
"version": "3.0.0",
@@ -16708,6 +16545,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
"dev": true,
"requires": {
"locate-path": "^5.0.0",
"path-exists": "^4.0.0"
@@ -16812,7 +16650,8 @@
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"dev": true
},
"get-intrinsic": {
"version": "1.2.1",
@@ -17249,7 +17088,8 @@
"is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"dev": true
},
"is-glob": {
"version": "4.0.3",
@@ -17559,6 +17399,7 @@
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
"dev": true,
"requires": {
"p-locate": "^4.1.0"
}
@@ -18343,6 +18184,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
@@ -18351,6 +18193,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
"dev": true,
"requires": {
"p-limit": "^2.2.0"
}
@@ -18368,7 +18211,8 @@
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
"dev": true
},
"param-case": {
"version": "3.0.4",
@@ -18448,7 +18292,8 @@
"path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
"dev": true
},
"path-is-absolute": {
"version": "1.0.1",
@@ -18505,11 +18350,6 @@
"find-up": "^4.0.0"
}
},
"pngjs": {
"version": "5.0.0",
"resolved": "https://registry.npmmirror.com/pngjs/-/pngjs-5.0.0.tgz",
"integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="
},
"portfinder": {
"version": "1.0.32",
"resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz",
@@ -18995,96 +18835,6 @@
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz",
"integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA=="
},
"qrcode": {
"version": "1.5.4",
"resolved": "https://registry.npmmirror.com/qrcode/-/qrcode-1.5.4.tgz",
"integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==",
"requires": {
"dijkstrajs": "^1.0.1",
"pngjs": "^5.0.0",
"yargs": "^15.3.1"
},
"dependencies": {
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"requires": {
"color-convert": "^2.0.1"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmmirror.com/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmmirror.com/cliui/-/cliui-6.0.0.tgz",
"integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
"requires": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.0",
"wrap-ansi": "^6.2.0"
}
},
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"wrap-ansi": {
"version": "6.2.0",
"resolved": "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
"integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
"requires": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
}
},
"y18n": {
"version": "4.0.3",
"resolved": "https://registry.npmmirror.com/y18n/-/y18n-4.0.3.tgz",
"integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
},
"yargs": {
"version": "15.4.1",
"resolved": "https://registry.npmmirror.com/yargs/-/yargs-15.4.1.tgz",
"integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
"requires": {
"cliui": "^6.0.0",
"decamelize": "^1.2.0",
"find-up": "^4.1.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^4.2.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^18.1.2"
}
},
"yargs-parser": {
"version": "18.1.3",
"resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-18.1.3.tgz",
"integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"qs": {
"version": "6.11.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
@@ -19271,7 +19021,8 @@
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"dev": true
},
"require-from-string": {
"version": "2.0.2",
@@ -19279,11 +19030,6 @@
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
"dev": true
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -19547,11 +19293,6 @@
"send": "0.18.0"
}
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw=="
},
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -19793,6 +19534,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"dev": true,
"requires": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -19803,6 +19545,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"dev": true,
"requires": {
"ansi-regex": "^5.0.1"
}
@@ -20781,11 +20524,6 @@
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/which-module/-/which-module-2.0.1.tgz",
"integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="
},
"wildcard": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz",
+1 -2
View File
@@ -16,10 +16,9 @@
"dayjs": "^1.8.14",
"decimal.js": "^10.4.3",
"echarts": "^5.2.2",
"element-ui": "^2.15.13",
"element-ui": "^2.15.9",
"less": "^4.1.3",
"less-loader": "^11.1.3",
"qrcode": "^1.5.4",
"qs": "^6.11.2",
"sass": "^1.65.1",
"sass-loader": "^13.3.2",
+3 -7
View File
@@ -31,14 +31,10 @@
}
</script>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=2.0&key=2560bbf04daef66c810c5e6a97e8c508&plugin=AMap.AutoComplete,AMap.PlaceSearch,AMap.Geolocation,AMap.Geocoder,AMap.Marker,AMap.Driving"></script>
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>
window.selfLink = window.location.href;
window.selfSearch = window.location.search;
</script>
<!-- <script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>-->
<script>
// VConsole 默认会挂载到 `window.VConsole` 上
let vConsole = new window.VConsole();
// let vConsole = new window.VConsole();
(function (doc, win) {
// console.log("==window.location.pathname===",window.location.pathname)
let docEl = doc.documentElement
@@ -56,7 +52,7 @@
if (isMobile) {// 是移动端不变
// console.log("是移动端不变")
}else{
if(window.location.pathname=='/h5/supplier/dispatch/kpiIndex' || window.location.pathname=='/h5/supplier/dispatch/kpiCaseNew'){
if(window.location.pathname=='/h5/supplier/dispatch/kpiIndex'){
// console.log("执行了执行了")
win.addEventListener(resizeEvt, recalc, false);
doc.addEventListener('DOMContentLoaded', recalc, false);
-160
View File
@@ -1,160 +0,0 @@
# 年终总结看板 Dashboard
道路救援服务年终数据可视化看板项目。
## 项目结构
```
dashboard-demo/
├── index.html # 主看板页面(支持URL参数动态加载数据)
├── data/
│ ├── 供应商年度KPI.xlsx # 服务商KPI数据(主数据源)
│ ├── 师傅案件top3.xlsx # 案件量TOP3师傅数据
│ ├── 师傅在线top3.xlsx # 在线时长TOP3师傅数据
│ ├── 拒单率最高地区.xlsx # 拒单率最高地区数据
│ └── 拒单率最高时段.xlsx # 拒单率最高时段数据
└── README.md # 项目说明
```
## 功能特性
- 深色主题数据可视化看板
- **直接读取Excel文件**,无需转换为JSON
- 支持通过URL参数 `?providerId=XXX` 切换不同服务商
- 右上角下拉框可实时切换服务商(自动从Excel读取服务商列表)
- 使用 Chart.js 实现饼状图和雷达图
- 使用 SheetJS (xlsx) 解析Excel文件
- 响应式布局,支持不同屏幕尺寸
- 数据与页面分离,便于维护
## 数据指标
看板展示以下数据指标:
1. **总案件量分布**(饼状图)
- 小修、困境、拖车三类案件占比
2. **年度聚合案件量**
3. **案件量TOP3师傅**
4. **车辆平均总在线时长**
5. **在线时长TOP3师傅**
6. **拒单率最高地区**
7. **拒单率最高时段**
8. **APP使用率**
- 年度APP使用率展示
## Excel数据结构
### 1. 供应商年度KPI.xlsx
| 列名 | 说明 |
|------|------|
| 服务商id | 服务商唯一标识 |
| 服务商 | 服务商名称 |
| 完成案件量 | 总案件数量 |
| 拖车完成量 | 拖车案件数 |
| 小修完成量 | 小修案件数 |
| 困境完成量 | 困境案件数 |
| 聚合案件量 | 聚合案件数量 |
| APP使用率. | APP使用率(小数形式,如0.998) |
| 年度车辆平均总在线时长(小时) | 车辆平均在线时长 |
### 2. 师傅案件top3.xlsx
| 列名 | 说明 |
|------|------|
| 服务商id | 服务商唯一标识 |
| 服务商 | 服务商名称 |
| 服务人员工号 | 师傅姓名/工号 |
| 完成案件量 | 该师傅完成的案件数 |
### 3. 师傅在线top3.xlsx
| 列名 | 说明 |
|------|------|
| 服务商名称 | 服务商名称 |
| 司机姓名 | 师傅姓名 |
| 年度总在线时长(小时) | 在线时长 |
### 4. 拒单率最高地区.xlsx
| 列名 | 说明 |
|------|------|
| 供应商名称 | 服务商名称 |
| 地区 | 拒单率最高的地区 |
| 拒单率 | 拒单率(小数形式) |
### 5. 拒单率最高时段.xlsx
| 列名 | 说明 |
|------|------|
| 供应商名称 | 服务商名称 |
| 时段 | 拒单率最高的时段 |
| 拒单率 | 拒单率(小数形式) |
## 使用方式
### 1. 启动本地服务器
由于页面使用 `fetch` 加载JSON数据,需要通过HTTP服务器访问:
```bash
cd C:\Users\Administrator\dashboard-demo
# 使用 Python
python -m http.server 8080
# 或使用 Node.js
npx serve .
# 或使用 PHP
php -S localhost:8080
```
### 2. 访问页面
- 默认服务商:`http://localhost:8080`(自动加载第一个服务商)
- 指定服务商:`http://localhost:8080?providerId=1128`(使用服务商id
- 切换服务商:使用页面右上角的下拉框
### 3. 更新数据
直接替换 `data/` 目录下的Excel文件即可,页面会自动读取最新数据。
服务商列表从Excel自动生成,无需手动配置。
## 技术栈
- HTML5 / CSS3
- JavaScript (ES6+)
- Chart.js - 图表库(饼图、雷达图)
- SheetJS (xlsx) - Excel文件解析
- CSS Grid / Flexbox - 布局
## 后续优化方向
- [ ] 添加更多图表类型(柱状图、折线图等)
- [ ] 支持时间范围筛选
- [ ] 添加数据导出功能
- [ ] 移动端适配优化
- [ ] 添加数据加载骨架屏
- [ ] 支持主题切换(深色/浅色)
## 更新日志
### 2025-01-21
- 改为直接读取Excel文件,无需JSON转换
- 服务商列表从Excel自动生成
- 将"AB段里程对比"改为"APP使用率"展示
- 新增服务商选择下拉框
### 2025-01-20
- 初始版本
- 实现基础看板布局
- 支持URL参数切换服务商
- 数据JSON化,与页面分离
-47
View File
@@ -1,47 +0,0 @@
{
"serviceProviderId": "SP001",
"serviceProviderName": "上海道路救援服务中心",
"year": 2025,
"summary": {
"totalCases": 100,
"caseBreakdown": {
"minorRepair": 20,
"predicament": 20,
"towing": 60
},
"aggregatedCases": 15
},
"topMastersByCases": [
{ "rank": 1, "name": "小王", "cases": 18 },
{ "rank": 2, "name": "小张", "cases": 16 },
{ "rank": 3, "name": "小李", "cases": 12 }
],
"onlineHours": {
"averageTotal": 2920,
"topMasters": [
{ "rank": 1, "name": "小王", "hours": 3230 },
{ "rank": 2, "name": "小张", "hours": 3028 },
{ "rank": 3, "name": "小李", "hours": 2996 }
]
},
"rejectionRate": {
"highestRegion": {
"name": "崇明",
"rate": 21.2
},
"highestTimeSlot": {
"period": "18:00-22:00",
"description": "晚高峰时段"
}
},
"abMileage": {
"highest": {
"region": "崇明",
"distance": 62
},
"lowest": {
"region": "黄浦",
"distance": 6
}
}
}
-47
View File
@@ -1,47 +0,0 @@
{
"serviceProviderId": "SP002",
"serviceProviderName": "浦东汽车救援有限公司",
"year": 2025,
"summary": {
"totalCases": 156,
"caseBreakdown": {
"minorRepair": 35,
"predicament": 41,
"towing": 80
},
"aggregatedCases": 22
},
"topMastersByCases": [
{ "rank": 1, "name": "老陈", "cases": 28 },
{ "rank": 2, "name": "大刘", "cases": 24 },
{ "rank": 3, "name": "阿强", "cases": 19 }
],
"onlineHours": {
"averageTotal": 3150,
"topMasters": [
{ "rank": 1, "name": "老陈", "hours": 3580 },
{ "rank": 2, "name": "大刘", "hours": 3420 },
{ "rank": 3, "name": "阿强", "hours": 3210 }
]
},
"rejectionRate": {
"highestRegion": {
"name": "奉贤",
"rate": 18.5
},
"highestTimeSlot": {
"period": "07:00-09:00",
"description": "早高峰时段"
}
},
"abMileage": {
"highest": {
"region": "金山",
"distance": 55
},
"lowest": {
"region": "静安",
"distance": 8
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-119
View File
@@ -1,119 +0,0 @@
{
"name": "data",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "data",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"xlsx": "^0.18.5"
}
},
"node_modules/adler-32": {
"version": "1.3.1",
"resolved": "https://registry.npmmirror.com/adler-32/-/adler-32-1.3.1.tgz",
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/cfb": {
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/cfb/-/cfb-1.2.2.tgz",
"integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"crc-32": "~1.2.0"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/codepage": {
"version": "1.15.0",
"resolved": "https://registry.npmmirror.com/codepage/-/codepage-1.15.0.tgz",
"integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/crc-32": {
"version": "1.2.2",
"resolved": "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz",
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"license": "Apache-2.0",
"bin": {
"crc32": "bin/crc32.njs"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/frac": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/frac/-/frac-1.1.2.tgz",
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/ssf": {
"version": "0.11.2",
"resolved": "https://registry.npmmirror.com/ssf/-/ssf-0.11.2.tgz",
"integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
"license": "Apache-2.0",
"dependencies": {
"frac": "~1.1.2"
},
"engines": {
"node": ">=0.8"
}
},
"node_modules/wmf": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/wmf/-/wmf-1.0.2.tgz",
"integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/word": {
"version": "0.3.0",
"resolved": "https://registry.npmmirror.com/word/-/word-0.3.0.tgz",
"integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==",
"license": "Apache-2.0",
"engines": {
"node": ">=0.8"
}
},
"node_modules/xlsx": {
"version": "0.18.5",
"resolved": "https://registry.npmmirror.com/xlsx/-/xlsx-0.18.5.tgz",
"integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==",
"license": "Apache-2.0",
"dependencies": {
"adler-32": "~1.3.0",
"cfb": "~1.2.1",
"codepage": "~1.15.0",
"crc-32": "~1.2.1",
"ssf": "~0.11.2",
"wmf": "~1.0.1",
"word": "~0.3.0"
},
"bin": {
"xlsx": "bin/xlsx.njs"
},
"engines": {
"node": ">=0.8"
}
}
}
}
@@ -1,16 +0,0 @@
{
"name": "data",
"version": "1.0.0",
"description": "",
"main": "read-excel.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"type": "commonjs",
"dependencies": {
"xlsx": "^0.18.5"
}
}
@@ -1,30 +0,0 @@
const XLSX = require('xlsx');
const fs = require('fs');
const path = require('path');
// Excel文件路径
const excelPath = 'C:\\Users\\chenhaid\\Documents\\WXWork\\1688858118476511\\Cache\\File\\2026-02\\供应商年度KPIv5.xlsx';
// 输出JSON文件路径
const outputPath = path.join(__dirname, 'kpi.json');
// 读取Excel文件
const workbook = XLSX.readFile(excelPath);
// 获取第一个工作表名称
const sheetName = workbook.SheetNames[0];
console.log('工作表列表:', workbook.SheetNames);
// 获取工作表
const worksheet = workbook.Sheets[sheetName];
// 转换为JSON
const jsonData = XLSX.utils.sheet_to_json(worksheet);
console.log('读取到', jsonData.length, '条数据');
console.log('第一条数据示例:', JSON.stringify(jsonData[0], null, 2));
// 写入JSON文件
fs.writeFileSync(outputPath, JSON.stringify(jsonData, null, 2), 'utf8');
console.log('已保存到:', outputPath);
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

-120
View File
@@ -1,120 +0,0 @@
import request from '@/utils/http'
// 根据订单 获取报备类型
/*export function getReportListByOrder(key){
return request({
url: '/order/baseDriverReportConfigs/getByOrderId',
method:'GET',
params: key
})
}*/
// 弹框
export function successPopup( data) {
return request({
url: '/returnOrder/wechatDriver/user/successPopup',
method:'POST',
contentType: 'application/x-www-form-urlencoded',
data
})
}
// 认证进度
export function infoVerifyProgress(data){
return request({
url: '/returnOrder/wechatDriver/user/infoVerifyProgress',
method:'POST',
contentType: 'application/json',
data
})
}
// 认证详情
export function driverInfoVerifyDetail(data) {
return request({
url:'/returnOrder/wechatDriver/user/driverInfoVerifyDetail',
method:'POST',
data: data,
contentType: 'application/json',
})
}
// 我的信息
export function getMyInfo(data) {
return request({
url:'/returnOrder/wechatDriver/user/driverDetail',
method:'POST',
data: data,
})
}
// ocr识别
export function ocrRecognize( data) {
return request( {
url:'/returnOrder/wechatDriver/user/ocrRecognize',
data: data,
method:'POST',
contentType: 'application/json'
})
}
// 认证
export function driverInfoVerify( data) {
return request({
url:'/returnOrder/wechatDriver/user/driverInfoVerify',
data: data,
method:'POST',
contentType: 'application/json'
})
}
// 实名认证
export function driverRealName( data) {
return request('/returnOrder/wechatDriver/user/driverRealNameAuth', {
data: data,
method:'POST',
contentType: 'application/json'
})
}
//获取需要确认的人员信息列表
export function getConfirmPerson(key){
return request({
url: '/supplierAppV2/dispatchApp/wechat/getNeedConfirmPersonInfo',
method:'GET',
params: key
})
}
//微信相关 获取联系我 二维码
export function getQrCode(key){
return request({
url: '/supplierAppV2/dispatchApp/wechat/getQrCode',
method:'GET',
params: key
})
}
//获取服务商的确认状态
export function getConfirmStatus(key){
return request({
url: '/supplierAppV2/dispatchApp/wechat/getSupplier',
method:'GET',
params: key
})
}
//确认已添加微信按钮
export function confirmAddWechat(key){
return request({
url: '/supplierAppV2/dispatchApp/wechat/confirmAddWechat',
method:'GET',
params: key
})
}
//确认无误
export function confirm(key){
return request({
url: '/supplierAppV2/dispatchApp/wechat/confirm',
method:'GET',
params: key
})
}
//提交审批
export function submitConfirm( data) {
return request('/supplierAppV2/dispatchApp/wechat/submitConfirm', {
data: data,
method:'POST',
contentType: 'application/json'
})
}
-14
View File
@@ -1,14 +0,0 @@
import request from '@/utils/http'
/**
* 查询 H5 损伤照片
* @param {Object} data - { userOrderId, taskOrderId }
*/
export function getDamagePhotos(data) {
return request({
url: '/api/h5-interface/damagePhotos',
method: 'POST',
contentType: 'application/json',
data
})
}
-10
View File
@@ -1,10 +0,0 @@
import request from '@/utils/http'
export function getBeforeDispatchImage(data) {
return request({
url: '/supplierAppV2/dispatchApp/order/getBeforeDispatchImage',
method: 'POST',
contentType: 'application/json',
data
})
}
-37
View File
@@ -82,40 +82,3 @@ export function getDriverName(key) {
}
});
}
export function getVehicleName(key) {
return request({
url: '/supplier/select/vehicle',
method: 'GET',
params: {
key: key ,
}
});
}
// 车辆 总览
export function vehicleTotalInfo(data) {
return request({
url: '/supplier/supplierKPI/querySupplierVehicleStatisticsKpi',
method: 'POST',
data
});
}
// 服务商维度查询车辆
export function vehicleInfoBySupplier(data) {
return request({
url: '/supplier/supplierKPI/querySupplierStatisticsKpiBySupplier',
method: 'POST',
data
});
}
// 车辆维度查询车辆
export function vehicleInfoByVehicle(data) {
return request({
url: '/supplier/supplierKPI/querySupplierVehicleKpi',
method: 'POST',
data
});
}
+2 -137
View File
@@ -18,34 +18,6 @@ export function saveVehicle(data){
data
})
}
//提交审批车辆信息
export function saveSupplierApproval(data){
return request({
url:'/supplier/approval/saveSupplierDriverVehicleApproval',
method:'POST',
contentType:'application/json',
data
})
}
/*车辆更改状态 /supplierAppV2/dispatchApp/user/enableVehicle*/
export function enableVehicle(data){
return request({
url:'/supplierAppV2/dispatchApp/user/enableVehicle',
method:'POST',
contentType:'application/json',
data
})
}
//编辑车辆信息
export function updateInsurance(data){
return request({
url:'/supplierAppV2/dispatchApp/user/updateInsurance',
method:'POST',
data
})
}
// 获取车辆信息(用于修改时回显的值,只需传vehicleId)
export function getInfoById(data){
return request({
@@ -72,87 +44,12 @@ export function vehicleTypeList(){
})
}
// 服务商服务能力
export function supplierServiceTree(data){
console.log('ddddddd0', data)
export function supplierServiceTree(){
return request({
url:'/supplierAppV2/dispatchApp/user/supplierServiceTree',
method:'POST',
data
method:'POST'
})
}
// 服务商服务能力
export function supplierServicePartTree(data){
return request({
url:'/supplier/approval/getSupplierServiceTree',
method:'POST',
data
})
}
// 申请加入
export function saveSupplier(data){
return request({
url:'/supplier/potential/save',
method:'POST',
data
})
}
// 申请加入
export function auditSupplier(data){
return request({
url:'/supplier/potential/audit',
method:'POST',
data
})
}
// 修改申请信息
export function getSupplierInfo(key){
return request({
url:'/supplier/potential/getById',
method:'GET',
params:key
})
}
// 根据id查询潜在服务商
export function supplierSelectById(params){
return request({
url:'/supplier/potential/supplierSelectById',
method:'GET',
params
})
}
// 获取企微二维码
export function getOrCodeInfo(data){
return request({
url:'/agg-api/wxcp/createContactQrCode',
method:'POST',
data
})
}
// 获取是否添加企微结果
export function getContactQrCodeResult(data){
return request({
url:'/agg-api/wxcp/getContactQrCodeResult',
method:'POST',
data
})
}
// 添加企微
export function updateWechatId(data){
return request({
url:'/supplier/potential/updateWechatId',
method:'POST',
data
})
}
//司机列表
export function driverList(data){
return request({
@@ -420,35 +317,3 @@ export function unifiedOCRWithCompress(data){
data
})
}
export function getArea(data){
return request({
url:'/base/area/tree',
method:'POST',
data
})
}
// 服务商是否培训
export function jumpPage(data){
return request({
url:'/supplierAppV2/dispatchApp/user/jumpPage',
method:'POST',
contentType:'application/json',
data
})
}
//发送确认参保
export function sendInsuranceEmail(){
return request({
url:'/supplierAppV2/dispatchApp/user/sendInsuranceEmail',
method:'POST',
})
}
// 判断服务商是否参保
export function isSendInsuranceEmail(){
return request({
url:'/supplierAppV2/dispatchApp/user/isSendInsuranceEmail',
method:'POST',
})
}
+1 -46
View File
@@ -23,7 +23,7 @@ export function toDoAudit(data){
data
})
}
//
// 工单详情
export function getOrderDetail(data){
return request({
url:'/supplierAppV2/dispatchApp/order/getOrderDetail',
@@ -77,15 +77,6 @@ export function updateOrderSettlement(data){
data
})
}
// 获取司机信息
export function getDriverInfo(data){
return request({
url:'/supplierAppV2/dispatchApp/order/getDriverInfo',
method:'POST',
contentType:'application/json',
data
})
}
// 电瓶数量列表
export function batteryCountList(){
return request({
@@ -160,40 +151,4 @@ export function dealWithAlarm(data) {
})
}
//获取当前任务信息
export function getConfigByCode(data){
return request({
url: '/base/baseConfig/getConfigByCode',
method:'POST',
data
})
}
//获取最新版本
export function getNewVersion(key){
return request({
url: '/driverApp/app/updateVersion',
method:'GET',
params: key
})
}
export function getLog(data){
// 添加log
return request({
url: '/ureport/pageView/save',
method:'POST',
contentType:'application/json',
data
})
}
//获取最新版本
export function getUserBO(){
return request({
url: '/base/user/getUserBO',
method:'POST',
})
}
+1 -11
View File
@@ -54,7 +54,7 @@ export function userFeedback(data){
data
})
}
//擦亮
//二手拖车信息擦亮
export function usedCarPolish(data){
return request({
url: `/toc-user/car-app/usedCarPolish/${data}`,
@@ -103,13 +103,3 @@ export function auditCarInfoAgain(data){
data
})
}
// 我的发布列表
export function getAddressForService(data){
return request({
url: '/base/gaodeMap/getPlaceByAddress',
method:'GET',
params: data,
})
}
-43
View File
@@ -1,43 +0,0 @@
import request from '@/utils/http'
/**
* 查询当前服务商分时段电话列表和审批状态
* @param {Object} params
* @param {number} params.supplierId 服务商 ID
*/
export function getSupplierPhoneList(params) {
return request({
url: '/supplierAppV2/dispatchApp/supplierPhone/list',
method: 'GET',
params
})
}
/**
* 查询当前服务商电话时段变更审批状态
* @param {Object} params
* @param {number} params.supplierId 服务商 ID
*/
export function getSupplierPhoneApprovalStatus(params) {
return request({
url: '/supplierAppV2/dispatchApp/supplierPhone/approvalStatus',
method: 'GET',
params
})
}
/**
* 提交服务商电话时段变更审批
* @param {Object} data
* @param {number} data.supplierId 服务商 ID
* @param {string} [data.modifyReason] 修改原因
* @param {Array} data.phoneList 电话时段草稿列表
*/
export function submitSupplierPhoneApproval(data) {
return request({
url: '/supplierAppV2/dispatchApp/supplierPhone/submit',
method: 'POST',
contentType: 'application/json',
data
})
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 277 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 803 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 795 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 868 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 915 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 251 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 870 B

-646
View File
@@ -1,646 +0,0 @@
<template>
<div class="cameraGuide" v-if="visible">
<!-- ===== 拍摄引导页 ===== -->
<div class="cameraPage" v-show="step==='guide'">
<video ref="video" class="cameraVideo" autoplay playsinline muted></video>
<div class="cameraNav">
<van-icon name="arrow-left" class="backBtn" @click="handleClose" />
<span class="navTitle">{{ navTitle }}</span>
</div>
<div class="guideLayer">
<!-- 顶部主指令卡 -->
<div class="guideHero">
<div class="guideHeroIcon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<rect x="3" y="5" width="18" height="14" rx="2"></rect>
<path d="M3 9h18"></path>
<circle cx="8" cy="13.5" r="1.6"></circle>
<path d="M11 12.5h7M11 15h5"></path>
</svg>
</div>
<div class="guideHeroText">
<div class="guideHeroTitle">{{ heroTitle }}</div>
<div class="guideHeroSub">从卡套内拿出避免反光</div>
</div>
</div>
<!-- 取景框 -->
<div class="guideFrameOuter">
<span class="corner tl"></span>
<span class="corner tr"></span>
<span class="corner bl"></span>
<span class="corner br"></span>
<div class="guideFrameBorder"></div>
<div class="guideHole">
<!-- 主页模板标题 + 印章 -->
<div v-if="type==='front'" class="licenseTemplate ltFrontPage">
<div class="ltInner">
<div class="ltTitle">
<div class="ltTitleLine">中华人民共和国机动车行驶证</div>
</div>
<div class="ltSeal">印章</div>
</div>
</div>
<!-- 副页模板条形码 + 编号 -->
<div v-else-if="type==='back'" class="licenseTemplate ltBackPage">
<div class="ltInner">
<div class="ltBarcodeArea">
<div class="ltBarcodeStrip">
<div v-for="(bar, i) in barcodeBars" :key="i" class="ltBar" :class="bar"></div>
</div>
<div class="ltBarcodeNum">3701001234567</div>
</div>
</div>
</div>
<!-- 车辆照片模板标题 + 车辆轮廓 -->
<div v-else class="licenseTemplate ltCarPage">
<div class="ltInner">
<div class="ltTitle">
<div class="ltTitleLine">车辆照片</div>
</div>
<div class="ltCarOutline">
<svg viewBox="0 0 140 70" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
<path d="M14 46 L20 26 Q22 20 30 19 L88 16 Q96 16 102 22 L116 34 Q126 36 128 42 L128 48 Q128 52 124 52 L116 52"></path>
<path d="M14 46 L14 50 Q14 52 18 52 L30 52"></path>
<circle cx="42" cy="52" r="9"></circle>
<circle cx="102" cy="52" r="9"></circle>
<path d="M51 52 L93 52"></path>
<path d="M58 19 L60 33 L34 34"></path>
<path d="M92 18 L94 32 L114 33"></path>
</svg>
</div>
</div>
</div>
</div>
</div>
<!-- 底部取景要点 -->
<div class="guideTips">
<div class="tipItem ok">
<span class="tipIco">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 8V4h4M16 4h4v4M20 16v4h-4M8 20H4v-4"></path>
</svg>
</span>
<span class="tipLabel">四角入框</span>
</div>
<div class="tipItem ok">
<span class="tipIco">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<path d="M4 12h16M7 7h10M7 17h10"></path>
</svg>
</span>
<span class="tipLabel">平放正向</span>
</div>
<div class="tipItem warn">
<span class="tipIco">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="4"></circle>
<path d="M12 2v3M12 19v3M2 12h3M19 12h3M5 5l2 2M17 17l2 2M19 5l-2 2M5 19l2-2"></path>
</svg>
</span>
<span class="tipLabel">避免反光</span>
</div>
</div>
</div>
<div class="shootBar">
<div class="shootBtn" @click="takePhoto"></div>
<div class="shootLabel">点击拍照</div>
</div>
</div>
<!-- ===== 预览确认页 ===== -->
<div class="previewPage" v-show="step==='preview'">
<div class="cameraNav">
<van-icon name="arrow-left" class="backBtn" @click="handlePreviewBack" />
<span class="navTitle">照片预览</span>
</div>
<div class="previewImgWrap">
<img class="previewImg" :src="previewDataURL" alt="预览" />
</div>
<div class="previewBtns">
<button class="previewBtn btnRetake" @click="retake">重拍</button>
<button class="previewBtn btnConfirm" @click="confirmPhoto">确认使用</button>
</div>
</div>
</div>
</template>
<script>
// 拍摄引导组件:WebRTC 取景 + 引导框 + 分页面证件模板 + 预览确认
// props: type(front/back/car), visible
// emit: confirm({blob, dataURL})、cancel、fallback(权限拒绝/相机不可用,父组件降级系统选择器)
export default {
name: 'CameraGuide',
props: {
type: {
type: String,
default: 'front'
},
visible: {
type: Boolean,
default: false
}
},
data() {
const heights = ['tall', 'short', 'medium wide', 'tall', 'short', 'medium', 'tall wide', 'short',
'medium', 'tall', 'short wide', 'medium', 'tall', 'short', 'medium wide', 'tall',
'short', 'medium', 'tall wide', 'short', 'medium', 'tall', 'short wide', 'medium',
'tall', 'short', 'medium wide', 'tall', 'short', 'medium', 'tall wide', 'short',
'medium', 'tall', 'short wide', 'medium', 'tall', 'short', 'medium wide', 'tall']
return {
step: 'guide', // guide 拍摄引导 | preview 预览确认
stream: null,
previewBlob: null,
previewDataURL: '',
barcodeBars: heights
}
},
computed: {
navTitle() {
return { front: '拍摄行驶证主页', back: '拍摄行驶证副页', car: '拍摄行驶证车辆照片' }[this.type] || '拍摄行驶证'
},
heroTitle() {
return { front: '请将主页对准取景框', back: '请将副页对准取景框', car: '请将车辆对准取景框' }[this.type] || '请将证件对准取景框'
}
},
watch: {
visible(val) {
if (val) {
this.step = 'guide'
this.previewBlob = null
this.previewDataURL = ''
this.$nextTick(() => this.startCamera())
} else {
this.stopCamera()
}
}
},
beforeDestroy() {
this.stopCamera()
},
methods: {
async startCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: 'environment' },
audio: false
})
// 等待期间组件已被关闭,立即释放
if (!this.visible) {
stream.getTracks().forEach(t => t.stop())
return
}
this.stream = stream
await this.$nextTick()
const video = this.$refs.video
if (video) {
video.srcObject = stream
video.play().catch(() => {})
}
} catch (e) {
// 权限拒绝或相机不可用 → 通知父组件降级为系统选择器
console.error('getUserMedia error:', e)
this.$emit('fallback')
}
},
stopCamera() {
if (this.stream) {
this.stream.getTracks().forEach(t => t.stop())
this.stream = null
}
},
takePhoto() {
const video = this.$refs.video
if (!video || !video.videoWidth) {
this.$toast('相机尚未就绪,请稍候')
return
}
const canvas = document.createElement('canvas')
canvas.width = video.videoWidth
canvas.height = video.videoHeight
canvas.getContext('2d').drawImage(video, 0, 0)
const dataURL = canvas.toDataURL('image/jpeg', 0.92)
canvas.toBlob(blob => {
if (!blob) {
this.$toast('拍摄失败,请重试')
return
}
this.previewBlob = blob
this.previewDataURL = dataURL
this.step = 'preview'
}, 'image/jpeg', 0.92)
},
retake() {
// 重拍回到引导页,相机流保持
this.step = 'guide'
},
confirmPhoto() {
this.$emit('confirm', { blob: this.previewBlob, dataURL: this.previewDataURL })
},
handleClose() {
this.$emit('cancel')
},
handlePreviewBack() {
// 预览页返回 = 放弃拍摄,关闭并释放相机流
this.$emit('cancel')
}
}
}
</script>
<style scoped lang="scss">
.cameraGuide {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 3000;
background: #F5F5F5;
}
.cameraPage {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(160deg, #F7F9FC 0%, #EEF1F6 50%, #E6EAF1 100%);
overflow: hidden;
}
.cameraVideo {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 1;
}
.cameraNav {
position: relative;
z-index: 10;
display: flex;
align-items: center;
height: 52px;
padding-left: 14px;
padding-top: env(safe-area-inset-top);
background: #2C395F;
color: #fff;
.backBtn {
font-size: 22px;
width: 36px;
flex-shrink: 0;
}
.navTitle {
flex: 1;
text-align: left;
font-size: 18px;
font-weight: bolder;
letter-spacing: .5px;
padding-left: 4px;
}
}
.guideLayer {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 5;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 80px;
padding-bottom: 100px;
pointer-events: none;
}
.guideHero {
display: flex;
align-items: center;
gap: 12px;
background: #FFFFFF;
border: 1px solid #E9E9EA;
border-radius: 6px;
padding: 12px 15px;
margin-bottom: 24px;
max-width: 322px;
width: calc(100% - 48px);
box-sizing: border-box;
box-shadow: 0 2px 10px rgba(20, 30, 50, .08);
.guideHeroIcon {
width: 42px;
height: 42px;
flex-shrink: 0;
border-radius: 6px;
background: rgba(53, 77, 147, .10);
display: flex;
align-items: center;
justify-content: center;
color: #354D93;
svg {
width: 23px;
height: 23px;
}
}
.guideHeroTitle {
color: #222;
font-size: 16px;
font-weight: 700;
line-height: 1.3;
letter-spacing: .3px;
}
.guideHeroSub {
color: #5B606E;
font-size: 12.5px;
margin-top: 4px;
line-height: 1.4;
}
}
/* 取景框:宽约为屏宽 80%,宽高比约 1.43:1 */
.guideFrameOuter {
position: relative;
width: 80%;
max-width: 340px;
padding-top: 69.93%; /* 宽高比约 1.43:1 */
flex-shrink: 0;
filter: drop-shadow(0 4px 16px rgba(20, 30, 50, .12));
}
.corner {
position: absolute;
width: 30px;
height: 30px;
border-color: #354D93;
border-style: solid;
z-index: 10;
animation: cornerFadeIn .45s ease both;
&.tl { top: -4px; left: -4px; border-width: 4px 0 0 4px; border-radius: 4px 0 0 0; }
&.tr { top: -4px; right: -4px; border-width: 4px 4px 0 0; border-radius: 0 4px 0 0; }
&.bl { bottom: -4px; left: -4px; border-width: 0 0 4px 4px; border-radius: 0 0 0 4px; }
&.br { bottom: -4px; right: -4px; border-width: 0 4px 4px 0; border-radius: 0 0 4px 0; }
}
@keyframes cornerFadeIn {
from { opacity: 0; transform: scale(1.15); }
to { opacity: 1; transform: scale(1); }
}
.guideFrameBorder {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 3px solid #C2C8D2;
border-radius: 8px;
pointer-events: none;
z-index: 9;
}
.guideHole {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
border-radius: 8px;
overflow: hidden;
}
/* 证件模板叠层(仅视觉辅助,不拦截事件) */
.licenseTemplate {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 6;
border: 1.5px solid rgba(53, 77, 147, .55);
border-radius: 4px;
overflow: hidden;
pointer-events: none;
background: rgba(53, 77, 147, .06);
}
.ltInner {
position: absolute;
top: 5px;
left: 5px;
right: 5px;
bottom: 5px;
display: flex;
flex-direction: column;
}
.ltTitle {
text-align: center;
margin-bottom: 4px;
}
.ltTitleLine {
font-size: 10px;
color: rgba(53, 77, 147, .9);
font-weight: bold;
letter-spacing: 1px;
white-space: nowrap;
}
.ltSeal {
position: absolute;
left: 10px;
bottom: 10px;
width: 34px;
height: 34px;
border: 1.5px dashed rgba(255, 85, 59, .85);
border-radius: 2px;
display: flex;
align-items: center;
justify-content: center;
font-size: 5.5px;
color: rgba(255, 85, 59, .85);
}
.ltFrontPage .ltInner {
justify-content: flex-start;
}
.ltBackPage .ltInner {
justify-content: flex-end;
}
.ltBarcodeArea {
display: flex;
flex-direction: column;
align-items: flex-end;
gap: 4px;
padding-bottom: 6px;
padding-right: 8px;
}
.ltBarcodeStrip {
display: flex;
align-items: flex-end;
height: 28px;
gap: 1px;
.ltBar {
background: rgba(53, 77, 147, .6);
width: 1.5px;
border-radius: 0.5px;
&.wide { width: 2.8px; }
&.short { height: 50%; }
&.medium { height: 70%; }
&.tall { height: 100%; }
}
}
.ltBarcodeNum {
font-size: 8px;
color: rgba(53, 77, 147, .9);
letter-spacing: 2px;
font-family: 'Courier New', monospace;
}
.ltCarPage .ltCarOutline {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 60%;
opacity: .6;
color: #354D93;
}
}
.guideTips {
display: flex;
gap: 10px;
margin-top: 22px;
padding: 0 14px;
max-width: 340px;
width: 100%;
box-sizing: border-box;
}
.tipItem {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
gap: 7px;
background: #FFFFFF;
border-radius: 6px;
padding: 11px 4px 9px;
border: 1px solid #E9E9EA;
box-shadow: 0 2px 8px rgba(20, 30, 50, .06);
.tipIco {
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
svg {
width: 17px;
height: 17px;
}
}
&.ok .tipIco {
background: rgba(53, 77, 147, .10);
color: #354D93;
}
&.warn .tipIco {
background: rgba(255, 85, 59, .12);
color: #FF553B;
}
.tipLabel {
color: #5B606E;
font-size: 11.5px;
line-height: 1.3;
text-align: center;
}
}
.shootBar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
z-index: 10;
display: flex;
flex-direction: column;
align-items: center;
padding-top: 12px;
padding-bottom: calc(32px + env(safe-area-inset-bottom));
background: #FFFFFF;
border-top: 1px solid #E9E9EA;
}
.shootBtn {
width: 72px;
height: 72px;
border-radius: 50%;
border: 4px solid #354D93;
background: #FFFFFF;
position: relative;
box-shadow: 0 0 0 2px rgba(53, 77, 147, .22), 0 6px 16px rgba(20, 30, 50, .18);
&:active {
transform: scale(.92);
}
&::after {
content: '';
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 58px;
height: 58px;
border-radius: 50%;
background: #354D93;
}
}
.shootLabel {
color: #5B606E;
font-size: 12px;
margin-top: 10px;
letter-spacing: 1px;
}
/* ===== 预览确认页 ===== */
.previewPage {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: #F5F5F5;
display: flex;
flex-direction: column;
z-index: 20;
}
.previewImgWrap {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
overflow: hidden;
}
.previewImg {
max-width: 100%;
max-height: 100%;
border-radius: 8px;
object-fit: contain;
}
.previewBtns {
display: flex;
gap: 16px;
padding: 0 20px 32px;
padding-bottom: calc(32px + env(safe-area-inset-bottom));
}
.previewBtn {
flex: 1;
height: 48px;
border-radius: 24px;
border: none;
font-size: 16px;
font-weight: 600;
&:active {
opacity: .8;
}
}
.btnRetake {
background: #FFFFFF;
color: #354D93;
border: 1px solid #354D93;
}
.btnConfirm {
background: #354D93;
color: #fff;
}
</style>
-136
View File
@@ -1,136 +0,0 @@
<template>
<div class="step-bar">
<div
v-for="(step, index) in steps"
:key="index"
class="step-item"
:class="getStepClass(index)"
>
<div class="step-circle" @click="onStepClick(index)">
<span v-if="getStatus(index) === 'finish'" class="step-check"></span>
<span v-else>{{ index + 1 }}</span>
</div>
<div class="step-label">{{ step }}</div>
<div v-if="index < steps.length - 1" class="step-line" :class="{'step-line-done': getStatus(index) === 'finish'}"></div>
</div>
</div>
</template>
<script>
export default {
name: 'StepBar',
props: {
current: {
type: Number,
default: 1
},
steps: {
type: Array,
default: () => ['基本信息', '添加企微', '车辆信息', '驾驶员信息']
}
},
methods: {
getStatus(index) {
const stepNum = index + 1;
if (stepNum < this.current) return 'finish';
if (stepNum === this.current) return 'process';
return 'wait';
},
getStepClass(index) {
return `step-${this.getStatus(index)}`;
},
onStepClick(index) {
const stepNum = index + 1;
if (this.getStatus(index) === 'finish') {
this.$emit('step-click', stepNum);
}
}
}
}
</script>
<style scoped lang="scss">
.step-bar {
display: flex;
align-items: flex-start;
justify-content: center;
padding: 14px 10px 10px;
background: #fff;
position: relative;
}
.step-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
position: relative;
}
.step-circle {
width: 26px;
height: 26px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 13px;
font-weight: bold;
z-index: 1;
position: relative;
}
.step-finish .step-circle {
background: #0E76F4;
color: #fff;
cursor: pointer;
}
.step-process .step-circle {
background: #0E76F4;
color: #fff;
box-shadow: 0 0 0 3px rgba(14, 118, 244, 0.2);
}
.step-wait .step-circle {
background: #e0e0e0;
color: #999;
}
.step-label {
font-size: 11px;
margin-top: 5px;
text-align: center;
white-space: nowrap;
}
.step-finish .step-label {
color: #0E76F4;
}
.step-process .step-label {
color: #0E76F4;
font-weight: bold;
}
.step-wait .step-label {
color: #999;
}
.step-line {
position: absolute;
top: 13px;
left: calc(50% + 13px);
right: calc(-50% + 13px);
height: 2px;
background: #e0e0e0;
}
.step-line-done {
background: #0E76F4;
}
.step-check {
font-size: 14px;
}
</style>
-51
View File
@@ -1,51 +0,0 @@
const authenticationRouter = [
{
path: '/auditList',
name: 'auditList',
component: () => import('@/views/rvDriverAuthentication/auditList.vue'),
meta:{
title: '小板运输司机认证',
}
},
{
path: '/personAudit',
name: 'personAudit',
component: () => import('@/views/rvDriverAuthentication/personAudit.vue'),
meta:{
title: '实名认证',
}
},
{
path: '/carAudit',
name: 'carAudit',
component: () => import('@/views/rvDriverAuthentication/carAudit.vue'),
meta:{
title: '驾驶证认证',
}
},
{
path: '/carInfoAudit',
name: 'carInfoAudit',
component: () => import('@/views/rvDriverAuthentication/carInfoAudit.vue'),
meta:{
title: '车辆信息认证',
}
},
{
path: '/bankInfo',
name: 'bankInfo',
component: () => import('@/views/rvDriverAuthentication/bankInfo.vue'),
meta:{
title: '银行卡信息认证',
}
},
{
path: '/personList',
name: 'personList',
component: () => import('@/views/mine/personList.vue'),
meta:{
title: '人员信息',
}
},
]
export default authenticationRouter
+1 -83
View File
@@ -5,60 +5,11 @@ import kpiRouter from './kpi-router'
import invoiceRouter from "@/router/invoice-router";
import secondHandRouter from "@/router/second-hand-router";
import reportRouter from "@/router/report-router"
import authenticationRouter from "@/router/authentication-router"
const routes = [
{
path: '/',
redirect: '/index'
},
{
path: '/supplierAdd',
name: 'supplierAdd',
component: () => import('@/views/index/supplierAdd'),
meta:{
title: '信息录入',
}
},
{
path: '/supplierAddResult',
name: 'supplierAddResult',
component: () => import('@/views/index/supplierAddResult'),
meta:{
title: '审核中',
}
},
{
path: '/addWechat',
name: 'addWechat',
component: () => import('@/views/index/addWechat'),
meta:{
title: '添加微信',
}
},
{
path: '/supplierInfo',
name: 'supplierInfo',
component: () => import('@/views/index/supplierInfo'),
meta:{
title: '信息查看',
}
},
{
path: '/supplierTimePhone',
name: 'supplierTimePhone',
component: () => import('@/views/index/supplierTimePhone'),
meta:{
title: '供应商时段电话',
}
},
{
path: '/supplierTimePhoneEdit',
name: 'supplierTimePhoneEdit',
component: () => import('@/views/index/supplierTimePhoneEdit'),
meta:{
title: '编辑时段电话',
}
},
{
path: '/toDoList',
name: 'toDoList',
@@ -180,22 +131,6 @@ const routes = [
title: '查看发票'
}
},
{
path: '/damagePhotos',
name: 'damagePhotoList',
component: () => import('@/views/damagePhoto/damagePhotoList.vue'),
meta: {
title: '损伤照片'
}
},
{
path: '/environmentPhotos',
name: 'environmentPhotoList',
component: () => import('@/views/environmentPhoto/environmentPhotoList.vue'),
meta: {
title: '环境照片'
}
},
{
path: "/vehicleManage",
name: 'vehicleManage',
@@ -212,14 +147,6 @@ const routes = [
title: '车辆新增或修改'
}
},
{
path: "/continueInsurance",
name: 'continueInsurance',
component: () => import('@/views/index/continueInsurance'),
meta: {
title: '续保更新'
}
},
{
path: '/driverManage',
name: 'driverManage',
@@ -364,19 +291,10 @@ const routes = [
title:'电瓶详情'
}
},
{
path: '/goToApp',
name: 'goToApp',
component:()=>import('@/views/goToApp/goToApp.vue'),
meta: {
title:'小板运输司机端'
}
},
...kpiRouter,
...invoiceRouter,
...secondHandRouter,
...reportRouter,
...authenticationRouter
...reportRouter
]
const router = new VueRouter({
-8
View File
@@ -7,13 +7,5 @@ const kpiRouter = [
title: 'kpi首页',
}
},
{
path: '/kpiCaseNew',
name: 'kpiCaseNew',
component: () => import('@/views/kpi/kpiCaseNew'),
meta:{
title: 'kpi服务商案件&车辆情况',
}
},
]
export default kpiRouter
-8
View File
@@ -17,13 +17,5 @@ const reportRouter = [
title: '道路救援',
}
},
{
path: '/insuredPage',
name: 'insuredPage',
component: () => import('@/views/liabilityInsurance/insuredPage'),
meta:{
title: '参保救援职业责任险',
}
},
]
export default reportRouter
-80
View File
@@ -47,84 +47,4 @@ select{
font-size: 14px;
color: #000000;
}
.text_center {
text-align: center;
}
//同意协议勾选
.protocol-list {
display: flex;
//align-items: top;
margin-top: 5px;
justify-content: center;
position: fixed;
bottom: 20px;
text-align: center;
width: 100%;
padding: 20px;
box-sizing: border-box;
.protocol-text {
font-size: 12px;
color: #203152;
line-height: 18px;
//text-align: left;
.linkColor {
color: #3364B7;
word-break: keep-all;
}
}
}
.icon_register {
width: 100%;
height: auto;
}
.mr15 {
margin-right: 15px;
}
.mt20 {
margin-top: 20px;
}
.flex_vertical_center {
display: flex;
align-items: center;
}
.flex {
display: flex;
}
.flex_between {
justify-content: space-between;
}
/*@mixin wh($w,$h) {
width: $w;
height: $h;
}
@mixin flex(){
display: flex;
}
@mixin alignCenter(){
@include flex();
align-items: center;
}
@mixin col(){
@include flex();
flex-direction: column;
}
@mixin colBothCenter(){
@include col();
justify-content: center;
align-items: center;
}
@mixin sizingPadding($t,$r,$b,$l) {
box-sizing: border-box;
padding: $t $r $b $l;
}*/
/*@mixin weigthSize($wei,$size){
font-weight:$wei ;
font-size: $size;
}
@mixin weigthSizeColor($wei,$size,$col){
@include weigthSize($wei,$size);
color: $col;
}*/
-11
View File
@@ -23,17 +23,6 @@
div {
padding-top: 8px;
}
.commonNum{
padding: 2px 5px;
background-color: #9C9C9C;
color: white;
border-radius: 3px;
font-size: 13px;
margin-left: 3px;
}
.notFinish{
background-color: red;
}
.active {
color: #3678FF;
position: relative;
+1 -1
View File
@@ -1,6 +1,6 @@
@import "@/styles/mixin.scss";
::v-deep .van-nav-bar__content{
//background-color: #3A3A3A !important;
background-color: #3A3A3A !important;
}
.wrap{
@include wh(100%,100%);
-43
View File
@@ -1,43 +0,0 @@
.carInfo{
margin-top: 10px;
box-sizing: border-box;
width: 100%;
min-height: 151px;
background: #FFFFFF;
padding:8px 23px 17px 30px ;
display: flex;
justify-content: space-between;
.left_wrap,.right_wrap{
display: flex;
flex-direction: column;
justify-content: space-around;
}
.title {
font-size: 14px;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #323643;
.mar_left{
margin-left: 8px;
}
.star {
color: red;
margin-right: 3px;
}
}
.right_wrap{
align-items: flex-end;
.phone{
font-size: 13px;
font-weight: 500;
color: #323643;
}
input{
font-size: 12px;
text-align: right;
&::-webkit-input-placeholder { /* WebKit browserswebkit内核浏览器 */
color: #A1A1A1;
}
}
}
}
-29
View File
@@ -105,32 +105,3 @@
color: $col;
line-height: $hei;
}
@mixin width_height($width,$height){
width: $width;
height: $height;
}
@mixin flex($row,$colum){
display: flex;
justify-content: $row;
align-items: $colum;
}
@mixin center(){
display: flex;
align-items: center;
}
@mixin direction($justify-content){
display: flex;
flex-direction: column;
justify-content: $justify-content;
}
@mixin iconImg($width,$height,$marginRight){
width: $width;
height: $height;
margin-right: $marginRight;
}
@mixin iconImgLeft($width,$height,$marginRight){
width: $width;
height: $height;
margin-left: $marginRight;
}
+1 -79
View File
@@ -42,89 +42,11 @@ const timeFormat=(data) =>{
return formattedDate;
}
// 认证状态
const verifyStatus=(id)=> {
const ids = String(id)
const status = {
'0': 1, // 个人信息认证
'-1': 1, // 已注册
'7': 1, // 已发送待认证
'1': 2, // 驾照信息认证
'2': 3, // 车辆信息审核
'3': 4, // 银行卡信息审核
'4': 5, // 认证中
'8': 6, // 审核中
'11': 6, // 审核失败
'12': 6 // 审核成功
}
return status[ids]
}
// 认证状态 简易版
const verifyStatusSimple=(id)=> {
const ids = String(id)
const status = {
'0': 1, // 个人信息认证
'-1': 1, // 已注册
'7': 1, // 已发送待认证
'1': 3, // 驾照信息认证
'2': 3, // 车辆信息审核
'3': 4, // 银行卡信息审核
'4': 5, // 认证中
'8': 6, // 审核中
'11': 6, // 审核失败
'12': 6 // 审核成功
}
return status[ids]
}
// 认证状态
const tipString=(id)=> {
const ids = String(id)
const status = {
'0': { // 个人信息认证
tip: '认证待提交',
button: '待认证'
},
'1': { // 驾照信息认证
tip: '认证待提交',
button: '待认证'
},
'2': { // 车辆信息审核
tip: '认证待提交',
button: '待认证'
},
'3': { // 银行卡信息审核
tip: '认证待提交',
button: '待认证'
},
'4': { // 认证中
tip: '认证待提交',
button: '待认证'
},
'8': { // 审核中
tip: '认证审核中',
button: '审核中'
},
'11': { // 审核失败
tip: '认证审核失败',
button: '审核失败'
},
'12': { // 审核成功
tip: '认证审核成功',
button: '审核成功'
},
}
return status[ids]
}
module.exports = {
formatNumber,
formatDate,
leftCopy,
timeFormat,
formatDate1,
verifyStatus,
verifyStatusSimple,
tipString
formatDate1
}
+1 -8
View File
@@ -19,7 +19,6 @@ if( token ) {
service.interceptors.request.use(
config => {
let reqUrl=config.url
// console.log('config',config)
config.data = config.contentType ? config.data : qs.stringify(config.data)
if (config.testFlag) {
config.data = qs.stringify(config.data, {arrayFormat: 'indices', allowDots: true})
@@ -28,17 +27,12 @@ service.interceptors.request.use(
let token = localStorage.getItem('token');
// let token='eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJBTkNIQU5HIiwidXNlcklkIjo0NTY3MSwibmFtZSI6IuWuieeVhSIsInVzZXJOYW1lIjoiQU5DSEFORyIsInN1cHBsaWVySWQiOjExMjgsImlzWmQiOjAsImV4cCI6MTc1NTQyMjUyNX0.xzDZhaANJFnbeViIHJA0SEtOyTv7Ja3rKmXqRKRuFkc'
// let token='eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJTSEhQWEIiLCJ1c2VySWQiOjU0NzI2LCJuYW1lIjoiI-a1i-ivleWwj-eZveeZvSIsInVzZXJOYW1lIjoiU0hIUFhCIiwic3VwcGxpZXJJZCI6MTAwMDE2NSwiZXhwIjoxNzQ0NTEwNzkwfQ.JPk0OA7slYJN3FIi_uhW4Y0CiWRvl6R1dK8MRTbyhD8'
// if(!(reqUrl=='/supplier/supplierTraining/trainingTask' || reqUrl=='/supplier/supplierTraining/normalList' || reqUrl=='/supplier/supplierTraining/trainingList')){
if ((reqUrl=='/supplier/supplierTraining/trainingList' || reqUrl=='/supplier/supplierTraining/normalList') && config?.params?.type==1){
console.log('司机app使用该请求不挂token')
} else {
if(!(reqUrl=='/supplier/supplierTraining/trainingTask' || reqUrl=='/supplier/supplierTraining/normalList' || reqUrl=='/supplier/supplierTraining/trainingList')){
if(token) {
config.headers['Authorization'] = `${token}`;
config.headers['token'] = `${token}`;
}
}
// }
return config
},
error => {
@@ -48,7 +42,6 @@ service.interceptors.request.use(
service.interceptors.response.use(
response => {
console.log('response', response.data)
const res = response.data
if ( res.code === 401 || res.code === 400 || res.code == 500) {
Toast(res.msg || 'Error')
-102
View File
@@ -1,102 +0,0 @@
import dayjs from "dayjs";
export const kpiMixins = {
data() {
return {
isMobile: false,
isZd: '',
current:'2024-10',
supplierId:'',
supplierName:'',
startMonthTime: '',
startTime: '',
endTime: '',
}
},
methods: {
applicateHandle() {
if (window.parent) {
const hasListener = window.parent.dispatchEvent(new Event('checkCloseDialog'));
if (hasListener) {
const data = {
action: 'closeDialog',
message: this.supplierId,
// 其他需要传递的参数
};
window.parent.postMessage(data, '*');
} else {
window.history.back();
}
}
},
toOnlineHours(minutes) {
let _hours = parseInt(minutes / 60);
let _minutes = parseInt(minutes % 60);
return _hours + '时' + _minutes + '分'
},
// 初始化获取当月日期
initDate() {
const today = dayjs(); // 获取当前日期
const currentDay = today.date(); // 获取今天是几号(1-31
let targetMonth = today; // 默认目标月份是当前月
if (currentDay === 1) {
targetMonth = today.subtract(1, 'month'); // 上个月
}
this.current = targetMonth.format('YYYY-MM');
this.startTime = targetMonth.startOf('month').format('YYYY-MM-DD HH:mm:ss');
let endTime;
if (targetMonth.isSame(today, 'month')) {
endTime = today.subtract(1, 'day').endOf('day');
} else {
endTime = targetMonth.endOf('month');
}
this.endTime = endTime.format('YYYY-MM-DD HH:mm:ss');
this.startMonthTime=this.getStartTimeFromEndTime(this.endTime)
},
//获取近四个月的开始时间
getStartTimeFromEndTime(endTimeStr) {
const startTime = dayjs(endTimeStr).subtract(3, 'month').startOf('month');
return startTime.format('YYYY-MM-DD HH:mm:ss');
},
padZero(num) {
return num < 10 ? `0${num}` : num;
},
checkMobile() {
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
this.isMobile = /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent);
},
// 通用函数,用于处理百分比数据
processPercentage(value) {
value *= 100;
if (value % 1 !== 0) {
value = value.toFixed(2);
}
return value;
},
formatPercentage(value) {
let result = value * 100;
if (Number.isInteger(result)) {
return result.toString() + '%';
} else {
return result.toFixed(2) + '%';
}
},
// 格式化承接案件量数据
formatCurrency(value) {
if (!value) return '';
let num = parseInt(value);
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
formatCurrency1(value) {
if (!value) return ''; // 如果值为空,返回空字符串
// 如果值已经包含逗号,直接返回原值
if (value.toString().includes(',')) {
return value;
}
// 否则,添加千分号
let num = parseInt(value);
if (isNaN(num)) return ''; // 如果转换失败,返回空字符串
return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
},
}
}
+2 -15
View File
@@ -1,4 +1,3 @@
import { getAddressForService } from "@/api/secondHandCar"
// 获取定位, 返回 经纬度
export function getLocal(mapContext) {
return new Promise((resolve, reject) => {
@@ -47,19 +46,7 @@ export function getAddress(mapContext, lnglat) {
// 输入提示
export function searchFun(mapContext, cityCode, keyword) {
return new Promise((resolve) => {
getAddressForService({
city: '',
address: keyword
}).then((res) => {
if(res.code == 200) {
resolve(res?.data?.pois || [])
} else {
resolve([])
}
}).catch(() => {
resolve([])
})
/*mapContext.plugin('AMap.AutoComplete', function(){
mapContext.plugin('AMap.AutoComplete', function(){
var autoOptions = {
city: cityCode || '全国',
};
@@ -74,7 +61,7 @@ export function searchFun(mapContext, cityCode, keyword) {
resolve([])
}
})
})*/
})
})
}
-15
View File
@@ -1,6 +1,3 @@
import { getLog } from "@/api/order"
let _setLogTimer = null
export const myMixins = {
data() {
@@ -8,17 +5,6 @@ export const myMixins = {
}
},
methods: {
setLogHandler(data) {
if (_setLogTimer) return
_setLogTimer = setTimeout(() => { _setLogTimer = null }, 1000)
getLog(data)
},
showFun() {
if( localStorage.getItem('infoVerify') == 8 || localStorage.getItem('infoVerify') == 12 ) {
return false
}
return true
},
goPage(page, query) {
this.$router.push({
name: page,
@@ -102,7 +88,6 @@ export const myMixins = {
isWebFunc(){
let res=false
var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
console.log('isMobile',isMobile)
if (!isMobile) {// 是移动端不变
res=true
}
-51
View File
@@ -1,51 +0,0 @@
/**
* 校验电话号码
* 支持:大陆手机号、大陆固话、400电话、港澳手机号
* @param {string} phone
* @returns {boolean}
*/
export function isValidPhone(phone) {
if (!phone) return false
// 大陆手机号
const mainlandMobile = /^1[3-9]\d{9}$/
// 大陆固话:区号(可选) + 7~8位号码
const mainlandLandline = /^(0\d{2,3}-?)\d{7,8}$/
// 400电话
const phone400 = /^400-?\d{3}-?\d{4}$/
// 港澳手机号(8位,首位5/6/8/9)
const hkMacaoMobile = /^[5689]\d{7}$/
// 港澳固话
const hkMacaoLandline = /^(\d{4}-?)?\d{4}$/
return (
mainlandMobile.test(phone) ||
mainlandLandline.test(phone) ||
phone400.test(phone) ||
hkMacaoMobile.test(phone) ||
hkMacaoLandline.test(phone)
)
}
/**
* 校验时段格式 HH:mm 及起止关系
* @param {string} startTime
* @param {string} endTime
* @returns {{valid: boolean, message?: string}}
*/
export function validateTimeRange(startTime, endTime) {
const timeRegex = /^([0-1]\d|2[0-3]):([0-5]\d)$/
if (!startTime || !endTime) {
return { valid: false, message: '请填写完整的起止时段' }
}
if (!timeRegex.test(startTime) || !timeRegex.test(endTime)) {
return { valid: false, message: '时段格式不正确,应为 00:00 ~ 23:59' }
}
const [startH, startM] = startTime.split(':').map(Number)
const [endH, endM] = endTime.split(':').map(Number)
const start = startH * 60 + startM
const end = endH * 60 + endM
if (start > end) {
return { valid: false, message: '开始时间不得晚于结束时间' }
}
return { valid: true }
}
-312
View File
@@ -1,312 +0,0 @@
<template>
<div class="wrap damage-photo-wrap">
<div class="navBar">
<van-nav-bar
title="损伤照片"
left-arrow
left-arrow-color="#FFFFFF"
:border="false"
:fixed="true"
:safe-area-inset-top="true"
@click-left="h5GoBack"
/>
</div>
<div class="content-wrap" v-if="loaded">
<!-- 案件信息 -->
<div class="info-card">
<div class="info-item">
<span class="info-label">案件号</span>
<span class="info-value">{{ info.caseNo || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">车辆标识</span>
<span class="info-value">{{ info.vehicleIdentity || '-' }}</span>
</div>
<div class="info-item">
<span class="info-label">起止路线</span>
<span class="info-value">{{ info.route || '-' }}</span>
</div>
</div>
<!-- 照片列表 -->
<div class="photo-list" v-if="photoList.length">
<div class="photo-card" v-for="(item, index) in photoList" :key="index">
<div class="photo-title">
<span>{{ item.title || '-' }}</span>
<span
v-if="item.replaced || (item.historyList && item.historyList.length)"
class="replaced-tag"
@click="showHistory(item)"
>被替换</span>
</div>
<div class="photo-image" @click="previewCurrent(item.currentUrl)">
<van-image
:src="item.currentUrl"
fit="cover"
width="100%"
height="160"
:error-icon="defaultImg"
error-icon-size="48"
/>
</div>
</div>
</div>
<!-- 空态 -->
<div class="empty-state" v-else>
<van-empty description="暂无损伤照片" />
</div>
</div>
<!-- 历史照片弹框 -->
<van-popup
v-model="historyShow"
position="bottom"
round
closeable
:style="{ height: '70%' }"
@closed="currentHistory = []"
>
<div class="history-popup">
<div class="history-title">历史照片</div>
<div class="history-list" v-if="currentHistory.length">
<div
class="history-item"
v-for="(item, index) in currentHistory"
:key="index"
@click="previewHistory(item.url)"
>
<van-image
:src="item.url"
fit="cover"
width="100%"
height="120"
:error-icon="defaultImg"
error-icon-size="48"
/>
<div class="history-time" v-if="item.replaceTime">替换时间{{ item.replaceTime }}</div>
</div>
</div>
<div class="history-empty" v-else>
<van-empty description="暂无历史照片" />
</div>
</div>
</van-popup>
</div>
</template>
<script>
import { getDamagePhotos } from '@/api/damagePhoto'
import { myMixins } from '@/utils/myMixins'
import { ImagePreview, Toast } from 'vant'
export default {
name: 'damagePhotoList',
mixins: [myMixins],
data() {
return {
loaded: false,
info: {
caseNo: '',
vehicleIdentity: '',
route: ''
},
photoList: [],
historyShow: false,
currentHistory: [],
defaultImg: require('@/assets/empty.png')
}
},
async mounted() {
await this.fetchDamagePhotos()
},
methods: {
async fetchDamagePhotos() {
const userOrderId = this.$route.query.userOrderId
const taskOrderId = this.$route.query.taskOrderId
if (!userOrderId || !taskOrderId) {
Toast('缺少必要参数')
this.loaded = true
return
}
Toast.loading({
message: '加载中...',
forbidClick: true,
duration: 0
})
try {
const res = await getDamagePhotos({
userOrderId: Number(userOrderId),
taskOrderId: Number(taskOrderId)
})
this.info = {
caseNo: res.data?.caseNo || '',
vehicleIdentity: res.data?.vehicleIdentity || '',
route: res.data?.route || ''
}
this.photoList = Array.isArray(res.data?.photos) ? res.data.photos : []
} finally {
Toast.clear()
this.loaded = true
}
},
previewCurrent(url) {
if (!url) return
ImagePreview({
images: [url],
startPosition: 0,
closeable: true
})
},
showHistory(item) {
this.currentHistory = Array.isArray(item.historyList) ? item.historyList : []
this.historyShow = true
},
previewHistory(url) {
if (!url) return
ImagePreview({
images: [url],
startPosition: 0,
closeable: true
})
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/mixin.scss";
@import "@/styles/common.scss";
.wrap {
@include wh(100%, 100%);
background-color: #F4F5F7;
overflow-y: auto;
}
.navBar {
height: 46px;
::v-deep .van-nav-bar--fixed {
z-index: 9999 !important;
}
}
.content-wrap {
padding: 10px 15px 20px;
}
.info-card {
background: #fff;
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
.info-item {
display: flex;
line-height: 24px;
font-size: 13px;
&:not(:last-child) {
margin-bottom: 8px;
}
.info-label {
color: rgba(0, 0, 0, 0.5);
width: 70px;
flex-shrink: 0;
}
.info-value {
color: #323643;
flex: 1;
word-break: break-all;
}
}
}
.photo-list {
.photo-card {
background: #fff;
border-radius: 8px;
padding: 12px 12px 15px;
margin-bottom: 10px;
.photo-title {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 14px;
font-weight: bold;
color: #323643;
margin-bottom: 10px;
.replaced-tag {
font-size: 12px;
font-weight: normal;
color: #fff;
background-color: #ee0a24;
padding: 2px 8px;
border-radius: 4px;
}
}
.photo-image {
width: 100%;
border-radius: 4px;
overflow: hidden;
}
}
}
.empty-state {
margin-top: 30px;
}
.history-popup {
height: 100%;
display: flex;
flex-direction: column;
.history-title {
font-size: 16px;
font-weight: bold;
color: #323643;
text-align: center;
padding: 15px 0;
border-bottom: 1px solid #E9E9EA;
}
.history-list {
flex: 1;
overflow-y: auto;
padding: 15px;
.history-item {
margin-bottom: 15px;
border-radius: 4px;
overflow: hidden;
.history-time {
font-size: 12px;
color: rgba(0, 0, 0, 0.5);
margin-top: 6px;
}
}
}
.history-empty {
flex: 1;
}
}
</style>
<style>
/* 确保图片预览及其遮罩层级高于底部弹框 */
.van-image-preview {
z-index: 10000000003 !important;
}
.van-overlay.van-image-preview__overlay {
z-index: 10000000002 !important;
}
</style>
+9 -74
View File
@@ -1,28 +1,6 @@
<template>
<div class="wrap">
<div class="navBar">
<van-nav-bar
left-arrow
left-arrow-color="#FFFFFF"
:border="false"
:fixed="true"
:safe-area-inset-top="true"
@click-left="goBack"
>
<template slot="title">
<div v-show="!show">培训文档</div>
<van-field v-model="keyword" placeholder="请输入关键词" v-show="show" @input="getTrainingList"/>
</template>
<template slot="right">
<div class="rightWrap" @click="show = !show">
<img src="@/assets/serach.png" class="img2" v-show="!show"/>
<img src="@/assets/delKey.png" class="img2" v-show="show" @click="initShow"/>
</div>
</template>
</van-nav-bar>
</div>
<!-- <div class="navBar">
<van-nav-bar
:border="false"
:fixed="true"
@@ -46,8 +24,7 @@
</template>
</van-nav-bar>
</div>
-->
<!-- <div class="statisticContainer">
<div class="statisticContainer">
<div class="statisticWrap">
<div class="line1">
<span>培训统计</span>
@@ -66,12 +43,11 @@
</div>
</div>
</div>
</div>-->
<div class="tab_wrap">
</div>
<div class="driver_tab_wrap">
<div v-for="(item, index) in tabArr" :key="index" :class="{'active' : activeIndex == index}"
@click="changeTab(index)">
{{ item.name }}<span v-if="item.count" :class="{'commonNum':true,'notFinish':index==2}">{{item.count}}</span>
<!-- {{ item.name }}-->
{{ item.name }}
</div>
</div>
<div class="contentWrap" v-show="!showEmpty">
@@ -108,14 +84,12 @@ export default {
mixins:[myMixins],
data(){
return{
tabArr: [{name: '全部文档', status: 1,count:0}, {name: '已培训', status:2,count:0},{name: '未培训', status: 3,count:0}],
// tabArr: [{name: '车型技术参数', status: 1}, {name: '中道服务规范', status:2},{name: '中道小课堂', status: 3}],
tabArr: [{name: '车型技术参数', status: 1}, {name: '中道服务规范', status:2},{name: '中道小课堂', status: 3}],
activeIndex: 0,
pageList:[],
totalList:[],
numInfo:'',
keyword:'',
serviceTypeName:'',
show:false,
showEmpty:false,
isLoading:false,
@@ -127,8 +101,7 @@ export default {
const urlParams = new URLSearchParams(window.location.search);
this.driverId = urlParams.get('driverId');
this.time=timeFormat(Date.now())
this.keyword=urlParams.get('keyword') || ''
this.serviceTypeName=urlParams.get('serviceTypeName') || ''
this.keyword=urlParams.get('keyWord') || ''
this.getTrainingList();
document.addEventListener('visibilitychange', async ( ) => {
let state = document.visibilityState
@@ -140,10 +113,6 @@ export default {
});
},
methods:{
initShow(){
this.keyword= ''
this.getTrainingList()
},
onRefresh() {
this.getTrainingList()
setTimeout(() => {
@@ -160,42 +129,21 @@ export default {
type:1,
id:this.driverId,
text:this.keyword || '',
serviceTypeName:this.serviceTypeName || ''
})
this.totalList=[]
this.pageList=[]
this.tabArr[0].count=0
this.tabArr[1].count=0
this.tabArr[2].count=0
this.numInfo=res.data
if(res.data.totalNum){
this.tabArr[0].count=res.data.totalNum
}
if(res.data.readNum){
this.tabArr[1].count=res.data.readNum
}
if(res.data.notReadNum){
this.tabArr[2].count=res.data.notReadNum
}
/* this.totalList=res.data.list
this.totalList=res.data.list
let result=[]
if(this.activeIndex === 0){
result=this.totalList?.filter(q => q.title === '车型技术参数');
}else if(this.activeIndex === 1){
result=this.totalList?.filter(q => q.title === '中道服务规范');
}else if(this.activeIndex === 2){
result=this.totalList?.filter(q => q.title === '中道小课堂');
}*/
let result=[]
this.totalList=res?.data?.list ? res?.data?.list[0]?.materials : []
if(this.activeIndex === 0){
result=this.totalList || []
}else if(this.activeIndex === 1){
result=this.totalList?.filter(item => item.alreadyRead==1) || []
}else if(this.activeIndex === 2){
result=this.totalList?.filter(item => item.alreadyRead!=1) || []
}
if(result){
this.pageList=result
this.pageList=result[0].materials
this.time=timeFormat(Date.now())
}
if(this.pageList?.length === 0){
@@ -212,19 +160,6 @@ export default {
@import "@/styles/mixin.scss";
@import "@/styles/docment.scss";
@import "@/styles/driverDocment.scss";
/*::v-deep .van-nav-bar__content{
background-color: #3A3A3A !important;
}*/
.tab_wrap {
.active:after {
width: 37px;
left: 0%;
transform: translateX(0%);
}
.active1:after {
width:48px !important;
}
}
.read{
padding: 2px 8px;
border-radius: 5px;
+11 -14
View File
@@ -36,6 +36,9 @@
v-model="keyword"
placeholder="名称/关键词/简介"
>
<!-- <template #button>
<van-icon class="search" name="search" size="20" @click="getTrainingList"/>
</template>-->
</van-field>
</template>
<template slot="left">
@@ -94,7 +97,6 @@ export default {
showEmpty:false,
supplierId:'',
driverId:'',
serviceTypeName:'',
}
},
mounted() {
@@ -102,36 +104,32 @@ export default {
this.supplierId = urlParams.get('supplierId');
this.driverId = urlParams.get('driverId');
if(this.driverId){
this.keyword=urlParams.get('keyword') || ''
this.keyword=urlParams.get('keyWord') || ''
}
this.serviceTypeName=urlParams.get('serviceTypeName') || ''
this.getNormalList()
},
methods:{
onRefresh() {
this.getNormalList()
if(!this.isLoading){
this.$toast('刷新成功');
}
/* setTimeout(() => {
setTimeout(() => {
this.$toast('刷新成功');
this.isLoading = false;
}, 1000);*/
}, 1000);
},
async changeTab(index) {
this.activeIndex = index
await this.getNormalList()
},
async getNormalList(){
this.isLoading = true;
this.totalList=[]
this.pageList=[]
let res= await getNormalList({
type:this.supplierId ? 2 : 1,
// type:2,
id: this.supplierId ? this.supplierId : this.driverId,
// id:this.supplierId,//33041,
text:this.keyword || '',
serviceTypeName:this.serviceTypeName || ''
})
this.totalList=[]
this.pageList=[]
this.totalList=res.data.list
let result=[]
if(this.activeIndex === 0){
@@ -151,10 +149,9 @@ export default {
}else {
this.showEmpty = false
}
this.isLoading = false
},
initShow(){
this.keyword= ''
this.keyword= '',
this.getNormalList()
}
}
+9 -46
View File
@@ -22,9 +22,9 @@
</van-nav-bar>
</div>
<div class="tab_wrap">
<div v-for="(item, index) in tabArr" :key="index" :class="{'active' : activeIndex == index,'active1':activeIndex==0}"
<div v-for="(item, index) in tabArr" :key="index" :class="{'active' : activeIndex == index}"
@click="changeTab(index)">
{{ item.name }}<span v-if="item.count" :class="{'commonNum':true,'notFinish':index==2}">{{item.count}}</span>
{{ item.name }}
</div>
</div>
<div class="contentWrap" v-show="!showEmpty">
@@ -61,30 +61,22 @@ export default {
mixins:[myMixins],
data(){
return{
tabArr: [{name: '全部文档', status: 1,count:0}, {name: '已培训', status:2,count:0},{name: '未培训', status: 3,count:0}],
tabArr: [{name: '车型技术参数', status: 1}, {name: '中道服务规范', status:2},{name: '中道小课堂', status: 3}],
activeIndex: 0,
pageNum:1,
pageSize:10,
pageList:[],
totalList:[],
keyword:'',
serviceTypeName:'',
show:false,
showEmpty:false,
isLoading:false,
supplierId:'',
numInfo:'',
}
},
activated() {
console.log('activated')
},
mounted() {
console.log('mounted')
const urlParams = new URLSearchParams(window.location.search);
this.supplierId = urlParams.get('supplierId');
this.keyword=urlParams.get('keyword') || ''
this.serviceTypeName=urlParams.get('serviceTypeName') || ''
this.getTrainingList();
document.addEventListener('visibilitychange', async ( ) => {
let state = document.visibilityState
@@ -112,39 +104,20 @@ export default {
type:2,
id: this.supplierId,
text:this.keyword || '',
serviceTypeName:this.serviceTypeName || ''
})
this.totalList=[]
this.pageList=[]
this.tabArr[0].count=0
this.tabArr[1].count=0
this.tabArr[2].count=0
this.totalList=res?.data?.list ? res?.data?.list[0]?.materials : []
this.numInfo=res.data
if(res.data.totalNum){
this.tabArr[0].count=res.data.totalNum
}
if(res.data.readNum){
this.tabArr[1].count=res.data.readNum
}
if(res.data.notReadNum){
this.tabArr[2].count=res.data.notReadNum
}
// console.log(' this.totalList',this.totalList)
console.log(' this.tabArr',this.tabArr)
this.totalList=res.data.list
let result=[]
if(this.activeIndex === 0){
result=this.totalList || []
// result=this.totalList?.filter(q => q.title === '车型技术参数');
result=this.totalList?.filter(q => q.title === '车型技术参数');
}else if(this.activeIndex === 1){
// result=this.totalList?.filter(q => q.title === '中道服务规范');
result=this.totalList?.filter(item => item.alreadyRead==1) || []
result=this.totalList?.filter(q => q.title === '中道服务规范');
}else if(this.activeIndex === 2){
result=this.totalList?.filter(item => item.alreadyRead!=1) || []
// result=this.totalList?.filter(q => q.title === '中道小课堂');
result=this.totalList?.filter(q => q.title === '中道小课堂');
}
if(result){
this.pageList=result
this.pageList=result[0].materials
}
if(this.pageList?.length === 0){
this.showEmpty = true
@@ -153,7 +126,7 @@ export default {
}
},
initShow(){
this.keyword= ''
this.keyword= '',
this.getTrainingList()
}
}
@@ -163,16 +136,6 @@ export default {
@import "@/styles/common.scss";
@import "@/styles/mixin.scss";
@import "@/styles/docment.scss";
.tab_wrap {
.active:after {
width: 37px;
left: 0%;
transform: translateX(0%);
}
.active1:after {
width:48px !important;
}
}
.read{
padding: 2px 8px;
border-radius: 5px;
@@ -1,118 +0,0 @@
<template>
<div class="wrap environment-photo-wrap">
<div v-if="loaded && photoList.length === 0" class="empty-tip">暂无环境照片</div>
<div v-for="(item, index) in photoList" :key="index" class="photo-item">
<div class="media-wrap">
<video
v-if="item.tag && item.tag.includes('video')"
:src="item.imageUrl"
controls
playsinline
class="media"
/>
<img
v-else-if="item.tag && item.tag.includes('img')"
:src="item.imageUrl"
class="media"
@click="previewImage(index)"
/>
</div>
<p v-if="item.title" class="photo-name">{{ item.title }}</p>
</div>
</div>
</template>
<script>
import { Toast, ImagePreview } from 'vant'
import { getBeforeDispatchImage } from '@/api/environmentPhoto'
export default {
name: 'EnvironmentPhotoList',
data() {
return {
photoList: [],
loaded: false
}
},
async mounted() {
await this.fetchPhotos()
},
methods: {
async fetchPhotos() {
const userOrderId = this.$route.query.userOrderId
if (!userOrderId) {
Toast('缺少必要参数')
this.loaded = true
return
}
Toast.loading({
message: '加载中...',
forbidClick: true,
duration: 0
})
try {
const res = await getBeforeDispatchImage({ userOrderId: Number(userOrderId) })
this.photoList = Array.isArray(res.data) ? res.data : []
} finally {
Toast.clear()
this.loaded = true
}
},
previewImage(index) {
const urls = this.photoList
.filter(item => item.tag && item.tag.includes('img'))
.map(item => item.imageUrl)
ImagePreview({ images: urls, startPosition: index })
}
}
}
</script>
<style scoped>.wrap {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #F4F5F7;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
}
.environment-photo-wrap {
padding: 12px;
}
.empty-tip {
text-align: center;
color: #999;
margin-top: 60px;
font-size: 14px;
}
.photo-item {
background: #fff;
border-radius: 6px;
margin-bottom: 12px;
overflow: hidden;
}
.media-wrap {
position: relative;
width: 100%;
padding-top: 56.25%;
}
.photo-item img,
.photo-item video {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
object-fit: cover;
}
.photo-name {
font-size: 13px;
color: #333;
padding: 8px 10px;
margin: 0;
}
</style>
-136
View File
@@ -1,136 +0,0 @@
<template>
<div class="wrap">
<div class="content">
<div class="goToBtn" @click="goAppHandler">立即打开</div>
<div class="content_tip">
<div class="font_cls">如未安装请点击 <span @click="downLoadHandler">立即下载</span></div>
</div>
</div>
<!-- 微信内置浏览器引导 -->
<div v-if="showGuide" class="guide-mask" @click.self="closeGuide">
<img class="guide-img" src="@/assets/sucai.png" alt="引导在浏览器打开" />
<div class="guide-btn" @click="closeGuide">我知道了</div>
</div>
</div>
</template>
<script>
import { getNewVersion, getLog } from "@/api/order"
export default {
name: "goToApp",
data() {
return {
showGuide: false
}
},
mounted() {
getLog({
source: 'App下载页',
event: '页面浏览',
page: '/h5/supplier/dispatch/goToApp'
})
this.showGuide = this.isWeixin()
},
methods: {
isWeixin() {
const ua = navigator.userAgent.toLowerCase()
return ua.indexOf('micromessenger') !== -1
},
closeGuide() {
this.showGuide = false
},
goAppHandler() {
getLog({
source: 'App下载页',
event: '直接打开',
page: '/h5/supplier/dispatch/goToApp'
})
window.location.href = "rvdriver://page/pagesLogin/phoneLogin?source=h5Link";
},
async downLoadHandler() {
getLog({
source: 'App下载页',
event: '立即下载',
page: '/h5/supplier/dispatch/goToApp'
});
getNewVersion({
appType: 5
}).then((res) => {
window.location.href = res?.result?.path
}).catch(() => {
this.$message.error('请求版本失败,请重试');
});
}
}
}
</script>
<style lang="scss" scoped>
.wrap {
width: 100%;
height: 100vh;
background-image: url('@/assets/toAppBg.png');
background-repeat: no-repeat;
background-size: 100% 100%;
}
.content {
width: 100%;
position: fixed;
top: 74vh;
}
.goToBtn {
width: 70%;
height: 45px;
margin-left: 15%;
background: linear-gradient( 270deg, #2347C0 0%, #72A3FF 100%);
border-radius: 23px;
//font-weight: bold;
font-size: 17px;
color: #FFFFFF;
letter-spacing: 2px;
line-height: 45px;
text-align: center;
}
.content_tip {
width: 100%;
margin-top: 15px;
.font_cls {
font-size: 14px;
color: #808080;
line-height: 20px;
text-align: center;
span {
color: #007BE9;
}
}
}
.guide-mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 999;
display: flex;
flex-direction: column;
align-items: center;
background: rgba(0, 0, 0, 0.85);
}
.guide-img {
width: 90%;
margin-top: 0;
object-fit: contain;
}
.guide-btn {
width: 140px;
height: 40px;
margin-top: 40px;
border: 1px solid #FFFFFF;
border-radius: 20px;
font-size: 15px;
color: #FFFFFF;
line-height: 40px;
text-align: center;
}
</style>
-183
View File
@@ -1,183 +0,0 @@
<template>
<div class="wrap">
<div class="top-wrap"></div>
<div class="center-info">
<div class="wei_code_wrap">
<div class="wei_title">请先添加企业微信保证申请流程正常进行</div>
<div class="wei_code_bg">
<img v-if="qrCodeUrl" :src="qrCodeUrl" alt="企业微信二维码" />
</div>
</div>
</div>
<div class="btn_wrap">
<div class="btn" @click="nextStep">下一步</div>
</div>
</div>
</template>
<script>
import QRCode from 'qrcode'
import {getOrCodeInfo, getContactQrCodeResult, saveSupplier} from "@/api/mine"
import {myMixins} from "@/utils/myMixins"
import {Toast, Dialog} from "vant";
export default {
name: "addWechat",
mixins: [myMixins],
data() {
return {
name: '',
potentialFlag: '',
formPayload: null,
qrCodeUrl: '',
qrCode: '',
configId: '',
wechatId: '',
clickFlag: true,
}
},
async mounted() {
const urlParams = new URLSearchParams(window.location.search);
this.potentialFlag = this.$route.query.potentialFlag || urlParams.get('potentialFlag') || '';
const cached = localStorage.getItem('supplierAddForm');
if (cached) {
this.formPayload = JSON.parse(cached);
this.wechatId = this.formPayload.wechatId;
this.name = this.formPayload.name;
}
if (this.name) {
await this.QrCodeHandler();
}
},
methods: {
async QrCodeHandler() {
await this.QrCodeInfo();
await this.getQrCode();
},
async QrCodeInfo() {
let res = await getOrCodeInfo({ name: this.name });
this.configId = res?.configId;
this.qrCode = res?.qrCode;
},
async getQrCode() {
try {
this.qrCodeUrl = await QRCode.toDataURL(this.qrCode, {
width: 150,
margin: 2,
color: { dark: '#000000', light: '#FFFFFF' },
});
} catch (error) {
console.error('生成二维码失败:', error);
}
},
async nextStep() {
if (!this.clickFlag) return;
if(!this.wechatId) {
let res = await getContactQrCodeResult({ configId: this.configId, name: this.name });
this.wechatId = res?.data?.wechatId;
}
if (!this.wechatId) {
Toast('请先添加企微再继续');
return;
}
try {
this.clickFlag = false;
const res = await saveSupplier({
...this.formPayload,
wechatId: this.wechatId,
});
if (res?.noToast) {
if (res?.code != 0) {
Dialog.alert({ title: '提示', message: '该服务商已存在,查看信息' }).then(() => {
localStorage.removeItem('supplierAddForm');
const target = { name: 'supplierInfo', query: { id: res?.code, potentialFlag: this.potentialFlag } };
localStorage.setItem('lastRoute', JSON.stringify(target));
this.goPage('supplierInfo', { id: res?.code, potentialFlag: this.potentialFlag });
});
} else {
Toast('该服务商已存在');
}
} else {
localStorage.removeItem('supplierAddForm');
const supplierId = res?.data;
const potentialFlag = this.potentialFlag;
const target = { name: 'supplierAddResult', query: { id: supplierId, potentialFlag } };
localStorage.setItem('lastRoute', JSON.stringify(target));
Dialog.confirm({
title: '提示',
message: '添加车辆和驾驶员会加快审核进度,是否去添加?',
confirmButtonText: '去添加',
cancelButtonText: '取消',
}).then(() => {
localStorage.setItem('lastRoute', JSON.stringify({ name: 'vehicleManage', query: { id: supplierId, potentialFlag } }));
this.goPage('vehicleManage', { id: supplierId, potentialFlag });
}).catch(() => {
localStorage.setItem('lastRoute', JSON.stringify({ name: 'supplierAddResult', query: { id: supplierId, potentialFlag } }));
this.goPage('supplierAddResult', { id: supplierId, potentialFlag });
});
}
} catch (e) {
Toast(e?.message || '提交失败');
} finally {
setTimeout(() => { this.clickFlag = true; }, 1000);
}
}
}
}
</script>
<style scoped lang="scss">
@import "@/styles/mixin.scss";
@import "@/styles/common.scss";
.wrap {
@include wh(100%, 100%);
box-sizing: border-box;
padding-bottom: 100px;
overflow-y: auto;
background: linear-gradient(180deg, #FBFDFE 0%, #F6FBFF 73%, #F0F7FF 100%);
backdrop-filter: blur(5.602678571428572px);
}
.top-wrap {
width: 100%;
height: 175px;
background: linear-gradient(180deg, #DAECFF 0%, rgba(233, 243, 255, 0) 100%);
}
.center-info {
text-align: center;
}
.wei_code_wrap {
margin-top: 10px;
.wei_title {
font-size: 15px;
color: #FF553B;
text-align: center;
}
.wei_code_bg {
width: 163px;
height: 173px;
background-image: url("~@/assets/supplier/weiCodeBg.png");
background-size: 100% 100%;
margin: 8px auto;
display: flex;
align-items: center;
justify-content: center;
}
}
.btn_wrap {
width: 100%;
padding: 15px 0;
position: fixed;
bottom: 10px;
z-index: 10000 !important;
.btn {
width: calc(100% - 80px);
margin-left: 40px;
height: 46px;
background: #0E76F4;
border-radius: 5px;
font-size: 15px;
color: #FFFFFF;
text-align: center;
line-height: 46px;
}
}
</style>

Some files were not shown because too many files have changed in this diff Show More