feat(客户数据): 添加一键导出功能并集成xlsx库
- 在ProblemRanking组件中添加导出按钮和功能 - 新增导出API接口并修改axios基础URL - 添加xlsx依赖用于Excel文件生成 - 实现客户数据展平处理和Excel导出逻辑
This commit is contained in:
179
my-vue-app/package-lock.json
generated
179
my-vue-app/package-lock.json
generated
@@ -9,6 +9,7 @@
|
|||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@element-plus/icons-vue": "^2.3.1",
|
"@element-plus/icons-vue": "^2.3.1",
|
||||||
|
"@fullcalendar/core": "^6.1.19",
|
||||||
"axios": "^1.10.0",
|
"axios": "^1.10.0",
|
||||||
"chart.js": "^4.5.0",
|
"chart.js": "^4.5.0",
|
||||||
"dompurify": "^3.2.6",
|
"dompurify": "^3.2.6",
|
||||||
@@ -17,11 +18,12 @@
|
|||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"marked": "^16.1.1",
|
"marked": "^16.1.1",
|
||||||
"pinia": "^3.0.2",
|
"pinia": "^3.0.2",
|
||||||
"pnpm": "^10.15.0",
|
"pinia-plugin-persistedstate": "^4.5.0",
|
||||||
"vue": "^3.5.17",
|
"vue": "^3.5.17",
|
||||||
"vue-chartjs": "^5.3.2",
|
"vue-chartjs": "^5.3.2",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node22": "^22.0.1",
|
"@tsconfig/node22": "^22.0.1",
|
||||||
@@ -1211,6 +1213,15 @@
|
|||||||
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
"integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@fullcalendar/core": {
|
||||||
|
"version": "6.1.19",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fullcalendar/core/-/core-6.1.19.tgz",
|
||||||
|
"integrity": "sha512-z0aVlO5e4Wah6p6mouM0UEqtRf1MZZPt4mwzEyU6kusaNL+dlWQgAasF2cK23hwT4cmxkEmr4inULXgpyeExdQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"preact": "~10.12.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@humanfs/core": {
|
"node_modules/@humanfs/core": {
|
||||||
"version": "0.19.1",
|
"version": "0.19.1",
|
||||||
"resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz",
|
"resolved": "https://registry.npmmirror.com/@humanfs/core/-/core-0.19.1.tgz",
|
||||||
@@ -2823,6 +2834,15 @@
|
|||||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/adler-32": {
|
||||||
|
"version": "1.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
|
||||||
|
"integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ajv": {
|
"node_modules/ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
|
||||||
@@ -3031,6 +3051,19 @@
|
|||||||
],
|
],
|
||||||
"license": "CC-BY-4.0"
|
"license": "CC-BY-4.0"
|
||||||
},
|
},
|
||||||
|
"node_modules/cfb": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/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/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
|
"resolved": "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz",
|
||||||
@@ -3076,6 +3109,15 @@
|
|||||||
"url": "https://paulmillr.com/funding/"
|
"url": "https://paulmillr.com/funding/"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/codepage": {
|
||||||
|
"version": "1.15.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/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/color-convert": {
|
"node_modules/color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
@@ -3137,6 +3179,18 @@
|
|||||||
"url": "https://github.com/sponsors/mesqueeb"
|
"url": "https://github.com/sponsors/mesqueeb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/crc-32": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/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/cross-spawn": {
|
"node_modules/cross-spawn": {
|
||||||
"version": "7.0.6",
|
"version": "7.0.6",
|
||||||
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
"resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz",
|
||||||
@@ -3209,6 +3263,12 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/deep-pick-omit": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-pick-omit/-/deep-pick-omit-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-2J6Kc/m3irCeqVG42T+SaUMesaK7oGWaedGnQQK/+O0gYc+2SP5bKh/KKTE7d7SJ+GCA9UUE1GRzh6oDe0EnGw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/default-browser": {
|
"node_modules/default-browser": {
|
||||||
"version": "5.2.1",
|
"version": "5.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.2.1.tgz",
|
||||||
@@ -3252,6 +3312,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/defu": {
|
||||||
|
"version": "6.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/defu/-/defu-6.1.4.tgz",
|
||||||
|
"integrity": "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/delayed-stream": {
|
"node_modules/delayed-stream": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
@@ -3261,6 +3327,12 @@
|
|||||||
"node": ">=0.4.0"
|
"node": ">=0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/destr": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/detect-libc": {
|
"node_modules/detect-libc": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
|
"resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
@@ -3970,6 +4042,15 @@
|
|||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/frac": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fs-extra": {
|
"node_modules/fs-extra": {
|
||||||
"version": "11.3.1",
|
"version": "11.3.1",
|
||||||
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.1.tgz",
|
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.1.tgz",
|
||||||
@@ -5084,20 +5165,31 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pnpm": {
|
"node_modules/pinia-plugin-persistedstate": {
|
||||||
"version": "10.15.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmmirror.com/pnpm/-/pnpm-10.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-4.5.0.tgz",
|
||||||
"integrity": "sha512-SG68JZ0+mZpOhpHOA7XKxKccvso5Nyqbdiy1AM/fCHPiyxar49lRse4s8BJQPwJ7mLZYTk3yJSTgx0UNnseqew==",
|
"integrity": "sha512-QTkP1xJVyCdr2I2p3AKUZM84/e+IS+HktRxKGAIuDzkyaKKV48mQcYkJFVVDuvTxlI5j6X3oZObpqoVB8JnWpw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"dependencies": {
|
||||||
"pnpm": "bin/pnpm.cjs",
|
"deep-pick-omit": "^1.2.1",
|
||||||
"pnpx": "bin/pnpx.cjs"
|
"defu": "^6.1.4",
|
||||||
|
"destr": "^2.0.5"
|
||||||
},
|
},
|
||||||
"engines": {
|
"peerDependencies": {
|
||||||
"node": ">=18.12"
|
"@nuxt/kit": ">=3.0.0",
|
||||||
|
"@pinia/nuxt": ">=0.10.0",
|
||||||
|
"pinia": ">=3.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"peerDependenciesMeta": {
|
||||||
"url": "https://opencollective.com/pnpm"
|
"@nuxt/kit": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@pinia/nuxt": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"pinia": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss": {
|
"node_modules/postcss": {
|
||||||
@@ -5142,6 +5234,16 @@
|
|||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/preact": {
|
||||||
|
"version": "10.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/preact/-/preact-10.12.1.tgz",
|
||||||
|
"integrity": "sha512-l8386ixSsBdbreOAkqtrwqHwdvR35ID8c3rKPa8lCWuO86dBi32QWHV4vfsZK1utLLFMvw+Z5Ad4XLkZzchscg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/preact"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/prelude-ls": {
|
"node_modules/prelude-ls": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
"resolved": "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz",
|
||||||
@@ -5491,6 +5593,18 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ssf": {
|
||||||
|
"version": "0.11.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/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/strip-final-newline": {
|
"node_modules/strip-final-newline": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
|
||||||
@@ -6151,6 +6265,24 @@
|
|||||||
"node": ">= 8"
|
"node": ">= 8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/wmf": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/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.npmjs.org/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/word-wrap": {
|
"node_modules/word-wrap": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz",
|
"resolved": "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.5.tgz",
|
||||||
@@ -6177,6 +6309,27 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/xlsx": {
|
||||||
|
"version": "0.18.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/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"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/xml-name-validator": {
|
"node_modules/xml-name-validator": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
"resolved": "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz",
|
||||||
|
|||||||
@@ -23,7 +23,8 @@
|
|||||||
"vue": "^3.5.17",
|
"vue": "^3.5.17",
|
||||||
"vue-chartjs": "^5.3.2",
|
"vue-chartjs": "^5.3.2",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
"vue-router": "^4.5.0"
|
"vue-router": "^4.5.0",
|
||||||
|
"xlsx": "^0.18.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tsconfig/node22": "^22.0.1",
|
"@tsconfig/node22": "^22.0.1",
|
||||||
@@ -42,4 +43,4 @@
|
|||||||
"vite-plugin-vue-devtools": "^7.7.2",
|
"vite-plugin-vue-devtools": "^7.7.2",
|
||||||
"vue-tsc": "^2.2.8"
|
"vue-tsc": "^2.2.8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ export const cancelSwitchHistoryCampPeriod = (params) => {
|
|||||||
return https.post('/api/v1/level_four/overview/cancel_switch_history_camp_period', params)
|
return https.post('/api/v1/level_four/overview/cancel_switch_history_camp_period', params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 一键导出 api/v1/level_four/overview/export_customers
|
||||||
|
export const exportCustomers = (params) => {
|
||||||
|
return https.post('http://192.168.15.56:8890/api/v1/level_four/overview/export_customers', params)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import { useUserStore } from '@/stores/user'
|
|||||||
|
|
||||||
// 创建axios实例
|
// 创建axios实例
|
||||||
const service = axios.create({
|
const service = axios.create({
|
||||||
baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
// baseURL: 'https://mldash.nycjy.cn/' || '', // API基础路径,支持完整URL
|
||||||
// baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
baseURL: 'http://192.168.15.121:8890' || '', // API基础路径,支持完整URL
|
||||||
timeout: 100000, // 请求超时时间
|
timeout: 100000, // 请求超时时间
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json;charset=UTF-8'
|
'Content-Type': 'application/json;charset=UTF-8'
|
||||||
|
|||||||
@@ -19,9 +19,6 @@
|
|||||||
历史
|
历史
|
||||||
</button>
|
</button>
|
||||||
<button v-if="isViewingHistory" @click="returnToCurrentPeriod" class="current-btn">
|
<button v-if="isViewingHistory" @click="returnToCurrentPeriod" class="current-btn">
|
||||||
<svg viewBox="0 0 24 24" width="16" height="16">
|
|
||||||
<path fill="currentColor" d="M12,2A10,10 0 0,1 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2M12,4A8,8 0 0,0 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12A8,8 0 0,0 12,4M12,6A6,6 0 0,1 18,12A6,6 0 0,1 12,18A6,6 0 0,1 6,12A6,6 0 0,1 12,6M12,8A4,4 0 0,0 8,12A4,4 0 0,0 12,16A4,4 0 0,0 16,12A4,4 0 0,0 12,8Z"/>
|
|
||||||
</svg>
|
|
||||||
返回当前
|
返回当前
|
||||||
</button>
|
</button>
|
||||||
<button @click="nextMonth" class="nav-btn">
|
<button @click="nextMonth" class="nav-btn">
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<div class="chart-container">
|
<div class="chart-container">
|
||||||
<div class="chart-header">
|
<div class="chart-header">
|
||||||
<h3>客户迫切解决的问题排行榜</h3>
|
<h3>客户迫切解决的问题排行榜</h3>
|
||||||
|
<button @click="exportData">一键导出</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="chart-content">
|
<div class="chart-content">
|
||||||
<div v-if="sortedData.length > 0" class="problem-ranking">
|
<div v-if="sortedData.length > 0" class="problem-ranking">
|
||||||
@@ -33,7 +34,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed } from 'vue';
|
import { computed,onMounted } from 'vue';
|
||||||
|
import { exportCustomers } from '@/api/secondTop';
|
||||||
|
import { useUserStore } from "@/stores/user";
|
||||||
|
import { ElMessage } from 'element-plus';
|
||||||
|
import * as XLSX from 'xlsx';
|
||||||
|
// 用户store实例
|
||||||
|
const userStore = useUserStore();
|
||||||
|
|
||||||
// 定义Props,接收一个包含 { name: string, value: string | number } 的数组
|
// 定义Props,接收一个包含 { name: string, value: string | number } 的数组
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
@@ -73,6 +80,111 @@ const getRankingClass = (index) => {
|
|||||||
const getRankBadgeClass = (index) => {
|
const getRankBadgeClass = (index) => {
|
||||||
return ['badge-gold', 'badge-silver', 'badge-bronze'][index] || 'badge-default';
|
return ['badge-gold', 'badge-silver', 'badge-bronze'][index] || 'badge-default';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function exportData() {
|
||||||
|
const params = {
|
||||||
|
user_name: userStore.userInfo.username,
|
||||||
|
user_level: userStore.userInfo.user_level.toString(),
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
ElMessage.info('正在导出数据,请稍候...')
|
||||||
|
const res = await exportCustomers(params)
|
||||||
|
|
||||||
|
if (res.code === 200 && res.data && res.data.length > 0) {
|
||||||
|
// 处理数据,将复杂的嵌套对象展平
|
||||||
|
const exportData = res.data.map(customer => {
|
||||||
|
const flatData = {
|
||||||
|
'昵称': customer.nickname || '',
|
||||||
|
'性别': customer.gender || '',
|
||||||
|
'跟进人': customer.follow_up_name || '',
|
||||||
|
'手机号': customer.phone || '',
|
||||||
|
'是否入群': customer.is_in_group || '',
|
||||||
|
'用户ID': customer.mantis_user_id || '',
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理微信表单信息
|
||||||
|
if (customer.wechat_form) {
|
||||||
|
flatData['家长姓名'] = customer.wechat_form.name || ''
|
||||||
|
flatData['孩子姓名'] = customer.wechat_form.child_name || ''
|
||||||
|
flatData['孩子性别'] = customer.wechat_form.child_gender || ''
|
||||||
|
flatData['职业'] = customer.wechat_form.occupation || ''
|
||||||
|
flatData['孩子教育阶段'] = customer.wechat_form.child_education || ''
|
||||||
|
flatData['与孩子关系'] = customer.wechat_form.child_relation || ''
|
||||||
|
flatData['联系电话'] = customer.wechat_form.mobile || ''
|
||||||
|
flatData['地区'] = customer.wechat_form.territory || ''
|
||||||
|
flatData['创建时间'] = customer.wechat_form.created_at ? new Date(customer.wechat_form.created_at).toLocaleString() : ''
|
||||||
|
flatData['更新时间'] = customer.wechat_form.updated_at ? new Date(customer.wechat_form.updated_at).toLocaleString() : ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理到课情况
|
||||||
|
if (customer.live) {
|
||||||
|
flatData['课一到课情况'] = customer.live['课一'] || ''
|
||||||
|
flatData['课二到课情况'] = customer.live['课二'] || ''
|
||||||
|
flatData['课三到课情况'] = customer.live['课三'] || ''
|
||||||
|
flatData['课四到课情况'] = customer.live['课四'] || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理问卷调查信息
|
||||||
|
if (customer.wechat_form && customer.wechat_form.additional_info) {
|
||||||
|
customer.wechat_form.additional_info.forEach((item, index) => {
|
||||||
|
flatData[`问题${index + 1}`] = item.topic || ''
|
||||||
|
flatData[`答案${index + 1}`] = item.answer || ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return flatData
|
||||||
|
})
|
||||||
|
|
||||||
|
// 创建工作簿
|
||||||
|
const wb = XLSX.utils.book_new()
|
||||||
|
const ws = XLSX.utils.json_to_sheet(exportData)
|
||||||
|
|
||||||
|
// 设置列宽
|
||||||
|
const colWidths = [
|
||||||
|
{ wch: 10 }, // 昵称
|
||||||
|
{ wch: 6 }, // 性别
|
||||||
|
{ wch: 12 }, // 跟进人
|
||||||
|
{ wch: 15 }, // 手机号
|
||||||
|
{ wch: 10 }, // 是否入群
|
||||||
|
{ wch: 20 }, // 用户ID
|
||||||
|
{ wch: 12 }, // 家长姓名
|
||||||
|
{ wch: 12 }, // 孩子姓名
|
||||||
|
{ wch: 8 }, // 孩子性别
|
||||||
|
{ wch: 12 }, // 职业
|
||||||
|
{ wch: 12 }, // 孩子教育阶段
|
||||||
|
{ wch: 15 }, // 与孩子关系
|
||||||
|
{ wch: 15 }, // 联系电话
|
||||||
|
{ wch: 20 }, // 地区
|
||||||
|
{ wch: 20 }, // 创建时间
|
||||||
|
{ wch: 20 }, // 更新时间
|
||||||
|
]
|
||||||
|
ws['!cols'] = colWidths
|
||||||
|
|
||||||
|
// 添加工作表到工作簿
|
||||||
|
XLSX.utils.book_append_sheet(wb, ws, '客户数据')
|
||||||
|
|
||||||
|
// 生成文件名(包含当前时间)
|
||||||
|
const now = new Date()
|
||||||
|
const fileName = `客户数据导出_${now.getFullYear()}${(now.getMonth() + 1).toString().padStart(2, '0')}${now.getDate().toString().padStart(2, '0')}_${now.getHours().toString().padStart(2, '0')}${now.getMinutes().toString().padStart(2, '0')}.xlsx`
|
||||||
|
|
||||||
|
// 导出文件
|
||||||
|
XLSX.writeFile(wb, fileName)
|
||||||
|
|
||||||
|
ElMessage.success(`导出成功!共导出 ${exportData.length} 条数据`)
|
||||||
|
} else {
|
||||||
|
ElMessage.warning('暂无数据可导出')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('导出失败:', error)
|
||||||
|
ElMessage.error('导出失败,请稍后重试')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async ()=>{
|
||||||
|
await exportData()
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -89,12 +201,40 @@ const getRankBadgeClass = (index) => {
|
|||||||
.chart-header {
|
.chart-header {
|
||||||
padding: 20px 20px 16px;
|
padding: 20px 20px 16px;
|
||||||
border-bottom: 1px solid #ebeef5;
|
border-bottom: 1px solid #ebeef5;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: #303133;
|
color: #303133;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: linear-gradient(135deg, #409eff, #3a8ee6);
|
||||||
|
color: white;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: linear-gradient(135deg, #3a8ee6, #337ecc);
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 2px 4px rgba(64, 158, 255, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chart-content {
|
.chart-content {
|
||||||
|
|||||||
Reference in New Issue
Block a user