Compare commits

...

55 Commits

Author SHA1 Message Date
ZhangYong 58b4e1c618 产品选择组件 1 day ago
ZhangYong 3d98845145 新增付款币种组件 1 day ago
ZhangYong fd791b6f6a Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into zhangyong/milestone-20250913-现金管理 3 days ago
ZhangYong 3030d0b57c 收款相关弹窗 3 days ago
zhangrenyuan d40812ee74 style金币管理的1.0修改(背景颜色字体穿透) 1 week ago
ZhangYong 9ab4a4a4ce 9.30 1 week ago
zhangrenyuan e250039e1c Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into milestone-20250913-现金管理 1 week ago
zhangrenyuan b32346d57d fix金豆审核style 1 week ago
lihui 0d75574df8 fix:样式 1 week ago
lihui 8fd65196c9 Merge branch 'refs/heads/lihui/feature-20250915101448-现金管理' into milestone-20250913-现金管理 1 week ago
lihui 558be246d4 perf:优化代码 删除无用的样式,预留出地区负责人的页面,后面根据接口修改 1 week ago
zhangrenyuan 49b7f0cced Merge branch 'zhangrenyuan/feature-20250917134308-现金管理' into milestone-20250913-现金管理 1 week ago
zhangrenyuan c881b86bfb fix金币审核style 1 week ago
lihui ccbad9cf6c Merge branch 'refs/heads/lihui/feature-20250915101448-现金管理' into milestone-20250913-现金管理 1 week ago
lihui baede47f1b fix:柱状图部分内容:排名卡片 1 week ago
ZhangYong 512652f882 收款明细更新进度 1 week ago
ZhangYong 70a20d3635 删除打包文件 1 week ago
ZhangYong 57a95e2948 9.29收款明细进度更新 1 week ago
lihui eb50cbd01a fix:重复请求 1 week ago
zhangrenyuan 3f900444b3 Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into milestone-20250913-现金管理 1 week ago
zhangrenyuan f07b6986d5 fix工作台的类型卡片style 1 week ago
lihui 8b23e72b6f Merge branch 'refs/heads/lihui/feature-20250915101448-现金管理' into milestone-20250913-现金管理 1 week ago
lihui 793692b67e Merge branch 'refs/heads/master' into lihui/feature-20250915101448-现金管理 1 week ago
lihui beabec6da5 style:图例 右移一点点 1 week ago
zhangrenyuan 9bfa4aac55 style 优化 2 weeks ago
ZhangYong 214bbfb8cb 修改充值金额逻辑 2 weeks ago
zhangrenyuan a20142cebc 合并 2 weeks ago
zhangrenyuan 63a668beb2 cashmanagement style 2 weeks ago
ZhangYong c728df9d07 Merge branch 'milestone-20250913-现金管理' of http://39.101.133.168:8807/huangqizhen/gold-vue into zhangyong/milestone-20250913-现金管理 2 weeks ago
lihui 3acbf1c452 add:工作台左侧卡片,右侧卡片,底部柱状图,柱状图需要优化排名部分 按钮部分 2 weeks ago
zhangrenyuan db1a3dd803 cash-management 和 worspace 2 weeks ago
ZhangYong 88dc8998eb 拉代码 2 weeks ago
ZhangYong df5f91ae6c 9.26更新代码 2 weeks ago
ZhangYong 5ff3493269 权限控制 2 weeks ago
zhangrenyuan 7f73f8ab09 header 迁移 2 weeks ago
zhangrenyuan 5bdedf5667 Merge branch 'zhangrenyuan/feature-20250917134308-现金管理' into milestone-20250913-现金管理 2 weeks ago
zhangrenyuan 94e32e2048 背景样式基本完成,包括侧边栏,头部,中心区域背景,悬浮按钮等 2 weeks ago
ZhangYong 09d55d3ac0 收款明细 2 weeks ago
ZhangYong 5f424a62db 收款明细 2 weeks ago
zhangrenyuan b78141ba18 merge lh 2 weeks ago
zhangrenyuan 0b2099bbbe 背景样式的更改day1 2 weeks ago
lihui 2b4feb8fef add:工作台的一个卡片 2 weeks ago
ZhangYong 70fc4d1119 客服新增弹窗 2 weeks ago
zhangrenyuan 2cf5ee0ae8 背景样式 2 weeks ago
zhangrenyuan 2119ac35f0 Merge branch 'zhangrenyuan/feature-20250917161935-重构工作台' into zhangrenyuan/feature-20250917134308-现金管理 2 weeks ago
zhangrenyuan b1863fce0f Merge branch 'milestone-20250913-现金管理' into zhangrenyuan/feature-20250917134308-现金管理 2 weeks ago
ZhangYong edeb8c144d 现金管理,收款明细 2 weeks ago
lihuilin 66489ec66a 现金退款部分 2 weeks ago
zhangrenyuan 3bf91fe3d5 Merge branch 'milestone-20250913-现金管理' into zhangrenyuan/feature-20250917134308-现金管理 2 weeks ago
zhangrenyuan 448f96850d 工作台样式 3 weeks ago
zhangrenyuan 363570dc95 样式重构全局 3 weeks ago
zhangrenyuan 27fca44c30 Merge branch 'zhangrenyuan/feature-20250917134308-现金管理' into zhangrenyuan/feature-20250917161935-重构工作台 3 weeks ago
zhangrenyuan feea4e4f0c 重构工作台的样式 3 weeks ago
zhangrenyuan a698ca67af Merge branch 'milestone-20250913-现金管理' into zhangrenyuan/feature-20250917134308-现金管理 3 weeks ago
zhangrenyuan ee836f1780 fix本地优化 3 weeks ago
  1. 2
      .env.development
  2. 194
      package-lock.json
  3. 3
      package.json
  4. 14
      src/assets/SvgIcons/上升箭头.svg
  5. 14
      src/assets/SvgIcons/下降箭头.svg
  6. 10
      src/assets/SvgIcons/周同比.svg
  7. 38
      src/assets/SvgIcons/工作台.svg
  8. 30
      src/assets/SvgIcons/折合新币累计金额.svg
  9. 14
      src/assets/SvgIcons/持平.svg
  10. 30
      src/assets/SvgIcons/昨日充值人数.svg
  11. 19
      src/assets/SvgIcons/昨日新增消费.svg
  12. 30
      src/assets/SvgIcons/昨日新增金币.svg
  13. 18
      src/assets/SvgIcons/消耗.svg
  14. 29
      src/assets/SvgIcons/现金管理.svg
  15. 22
      src/assets/SvgIcons/设置.svg
  16. 27
      src/assets/SvgIcons/金币管理.svg
  17. 9
      src/assets/SvgIcons/金币系统LOGO.svg
  18. BIN
      src/assets/backgroundBlue.png
  19. BIN
      src/assets/半透明background.png
  20. BIN
      src/assets/收款明细撤回背景.png
  21. 336
      src/components/MoneyManage/CurrencySelect.vue
  22. 121
      src/components/MoneyManage/ProductSelect.vue
  23. 211
      src/components/workspace/CashManagement.vue
  24. 210
      src/components/workspace/CashManagementMarkets.vue
  25. 818
      src/components/workspace/GoldGraph.vue
  26. 818
      src/components/workspace/GoldGraphMarkets.vue
  27. 669
      src/components/workspace/GoldManagement.vue
  28. 26
      src/router/index.js
  29. 12
      src/utils/menuTreePermission.js
  30. 4
      src/utils/menuUtils.js
  31. 102
      src/views/audit/bean/beanAudit.vue
  32. 49
      src/views/audit/gold/rechargeAudit.vue
  33. 49
      src/views/audit/gold/refundAudit.vue
  34. 51
      src/views/consume/bean/articleVideo.vue
  35. 51
      src/views/consume/bean/dieHardFan.vue
  36. 51
      src/views/consume/bean/liveStream.vue
  37. 52
      src/views/consume/gold/coinConsumeDetail.vue
  38. 264
      src/views/home.vue
  39. 2
      src/views/moneyManage/executor/executor.vue
  40. 1244
      src/views/moneyManage/receiveDetail/receiveDetail.vue
  41. 471
      src/views/moneyManage/refundDetail/refundDetail.vue
  42. 39
      src/views/permissions/rolePermission.vue
  43. 37
      src/views/permissions/userPermission.vue
  44. 2
      src/views/recharge/bean/addBeanRecharge.vue
  45. 52
      src/views/recharge/bean/beanOnlineRecharge.vue
  46. 54
      src/views/recharge/bean/beanSystemRecharge.vue
  47. 24
      src/views/recharge/gold/addCoinRecharge.vue
  48. 50
      src/views/recharge/gold/coinRechargeDetail.vue
  49. 51
      src/views/refund/gold/coinRefundDetail.vue
  50. 51
      src/views/usergold/bean/userbean.vue
  51. 64
      src/views/usergold/gold/clientCountBalance.vue
  52. 51
      src/views/usergold/gold/clientCountDetail.vue
  53. 929
      src/views/workspace/index.vue
  54. 4949
      stats.html

2
.env.development

@ -13,4 +13,4 @@ VITE_UPLOAD_URL=http://39.101.133.168:8828/hljw/api/aws/upload
# 本地
#VITE_API_BASE='http://localhost:8081/'
# sunjiabei
# VITE_API_BASE='http://192.168.0.34:8081/'
# VITE_API_BASE='http://192.168.1.70:8081/'

194
package-lock.json

@ -14,9 +14,10 @@
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@tabler/icons-vue": "^3.34.0",
"axios": "^1.7.8",
"axios": "^1.12.2",
"dayjs": "^1.11.13",
"dayjs-plugin-utc": "^0.1.2",
"decimal.js": "^10.6.0",
"echarts": "^5.5.1",
"element-plus": "^2.8.8",
"js-cookie": "^3.0.5",
@ -3170,18 +3171,18 @@
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/asynckit/-/asynckit-0.4.0.tgz",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.7.8",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/axios/-/axios-1.7.8.tgz",
"integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==",
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.0",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
@ -3330,6 +3331,19 @@
"dev": true,
"license": "MIT"
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001699",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/caniuse-lite/-/caniuse-lite-1.0.30001699.tgz",
@ -3422,7 +3436,7 @@
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/combined-stream/-/combined-stream-1.0.8.tgz",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
@ -3551,9 +3565,9 @@
}
},
"node_modules/decimal.js": {
"version": "10.4.3",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/decimal.js/-/decimal.js-10.4.3.tgz",
"integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==",
"version": "10.6.0",
"resolved": "https://registry.npmmirror.com/decimal.js/-/decimal.js-10.6.0.tgz",
"integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==",
"license": "MIT"
},
"node_modules/define-lazy-prop": {
@ -3567,7 +3581,7 @@
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/delayed-stream/-/delayed-stream-1.0.0.tgz",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
@ -3599,6 +3613,20 @@
"integrity": "sha512-LN1gO7+u9xjU5oEScGFKvXhYf7Y/empUIIEAGBs1LzUq/rg5duiDrkuH5A2lQGd5jfMOb9X9usDa2oVXwJ0U/Q==",
"license": "MIT"
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/echarts": {
"version": "5.5.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/echarts/-/echarts-5.5.1.tgz",
@ -3660,6 +3688,24 @@
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-define-property": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-errors": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-module-lexer": {
"version": "1.6.0",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/es-module-lexer/-/es-module-lexer-1.6.0.tgz",
@ -3667,6 +3713,33 @@
"dev": true,
"license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": {
"version": "0.24.2",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/esbuild/-/esbuild-0.24.2.tgz",
@ -3785,13 +3858,15 @@
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
@ -3839,7 +3914,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@ -3862,6 +3936,43 @@
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/get-intrinsic": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/globals": {
"version": "11.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
@ -3871,11 +3982,49 @@
"node": ">=4"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
@ -4090,6 +4239,15 @@
"@jridgewell/sourcemap-codec": "^1.5.0"
}
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/mathjs": {
"version": "14.0.1",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/mathjs/-/mathjs-14.0.1.tgz",
@ -4161,7 +4319,7 @@
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/mime-db/-/mime-db-1.52.0.tgz",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
@ -4170,7 +4328,7 @@
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://mirrors.huaweicloud.com/repository/npm/mime-types/-/mime-types-2.1.35.tgz",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {

3
package.json

@ -18,9 +18,10 @@
"@fortawesome/free-solid-svg-icons": "^6.7.2",
"@fortawesome/vue-fontawesome": "^3.0.8",
"@tabler/icons-vue": "^3.34.0",
"axios": "^1.7.8",
"axios": "^1.12.2",
"dayjs": "^1.11.13",
"dayjs-plugin-utc": "^0.1.2",
"decimal.js": "^10.6.0",
"echarts": "^5.5.1",
"element-plus": "^2.8.8",
"js-cookie": "^3.0.5",

14
src/assets/SvgIcons/上升箭头.svg

@ -0,0 +1,14 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 14" class="design-iconfont">
<path d="M3.33333 14H6.66667V7.875V5.25H10L5 0L0 5.25H3.33333V7.875V14Z" fill="url(#9ch16kl2f__paint0_linear_454_32894)"/>
<path d="M6.54883 13.8828V5.13281H9.72656L5 0.170898L0.273438 5.13281H3.45117V13.8828H6.54883Z" stroke="url(#9ch16kl2f__paint1_linear_454_32894)" stroke-opacity=".63" stroke-width=".235129" stroke-miterlimit="10"/>
<defs>
<linearGradient id="9ch16kl2f__paint0_linear_454_32894" x1=".938339" y1="14" x2="12.7734" y2="9.25209" gradientUnits="userSpaceOnUse">
<stop stop-color="#F46C6C"/>
<stop offset="1" stop-color="#FCC4C5"/>
</linearGradient>
<linearGradient id="9ch16kl2f__paint1_linear_454_32894" x1=".975668" y1="14" x2="12.7608" y2="9.22824" gradientUnits="userSpaceOnUse">
<stop stop-color="#FCC4C5"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
</defs>
</svg>

14
src/assets/SvgIcons/下降箭头.svg

@ -0,0 +1,14 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 14" class="design-iconfont">
<path d="M3.33333 0H6.66667V6.125V8.75H10L5 14L0 8.75H3.33333V6.125V0Z" fill="url(#3jb4xovw8__paint0_linear_415_444599)"/>
<path d="M6.50977 0.157227V8.90723H9.63379L5 13.7725L0.366211 8.90723H3.49023V0.157227H6.50977Z" stroke="url(#3jb4xovw8__paint1_linear_415_444599)" stroke-opacity=".63" stroke-width=".313505" stroke-miterlimit="10"/>
<defs>
<linearGradient id="3jb4xovw8__paint0_linear_415_444599" x1=".938339" y1="-6.2e-7" x2="12.7734" y2="4.74791" gradientUnits="userSpaceOnUse">
<stop stop-color="#047CF5"/>
<stop offset="1" stop-color="#4CB9F9"/>
</linearGradient>
<linearGradient id="3jb4xovw8__paint1_linear_415_444599" x1=".975668" y1="4.4e-7" x2="12.7608" y2="4.77176" gradientUnits="userSpaceOnUse">
<stop stop-color="#4CB9F9"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
</defs>
</svg>

10
src/assets/SvgIcons/周同比.svg
File diff suppressed because it is too large
View File

38
src/assets/SvgIcons/工作台.svg

@ -0,0 +1,38 @@
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.83596 0.471662C11.7158 0.150229 15.1637 -0.182551 20.1364 0.471662C25.1091 1.12588 28.2723 3.89325 29.3265 7.22946C30.3807 10.5657 30.3042 17.0899 29.9158 20.3537C29.5969 24.2602 27.323 28.8843 21.8852 29.6899C16.4475 30.4954 9.76469 30.2806 7.08401 29.3261C4.40334 28.3715 0.853199 26.3391 0.389008 20.6463C-0.0751821 14.9534 -0.381919 7.313 2.51481 4.21499C4.52336 1.82858 7.95615 0.793096 9.83596 0.471662Z" fill="#C0F2FF"/>
<g filter="url(#filter0_d_352_61804)">
<path d="M23.9427 25.6281H6.38731C5.45216 25.6281 4.64453 24.8205 4.64453 23.8854C4.64453 22.9502 5.45216 22.1426 6.38731 22.1426H23.9001C24.8353 22.1426 25.6429 22.9502 25.6429 23.8854C25.6854 24.8205 24.8778 25.6281 23.9427 25.6281Z" fill="url(#paint0_linear_352_61804)"/>
</g>
<g filter="url(#filter1_d_352_61804)">
<path d="M23.9426 4.65332H6.38731C5.45216 4.65332 4.64453 5.46095 4.64453 6.3961V18.6806C4.64453 19.6157 5.45216 20.4234 6.38731 20.4234H23.9001C24.8353 20.4234 25.6429 19.6157 25.6429 18.6806V6.3961C25.6854 5.46095 24.8778 4.65332 23.9426 4.65332Z" fill="url(#paint1_linear_352_61804)"/>
</g>
<path fill-rule="evenodd" clip-rule="evenodd" d="M20.2742 9.7675C20.6171 10.0876 20.6357 10.6251 20.3156 10.968L16.6916 14.8509C16.5309 15.023 16.306 15.1207 16.0706 15.1207C15.8352 15.1207 15.6103 15.023 15.4497 14.8509L13.6546 12.9276L11.2555 15.4981C10.9354 15.841 10.3979 15.8595 10.055 15.5395C9.71205 15.2194 9.69352 14.6819 10.0136 14.339L13.0336 11.1032C13.1943 10.9311 13.4191 10.8334 13.6546 10.8334C13.89 10.8334 14.1149 10.9311 14.2755 11.1032L16.0706 13.0265L19.0737 9.8089C19.3938 9.46596 19.9313 9.44743 20.2742 9.7675Z" fill="white"/>
<defs>
<filter id="filter0_d_352_61804" x="3.64453" y="21.1426" width="23" height="5.48535" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.184314 0 0 0 0 0.717647 0 0 0 0 0.988235 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_352_61804"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_352_61804" result="shape"/>
</filter>
<filter id="filter1_d_352_61804" x="3.64453" y="3.65332" width="23" height="17.7705" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.184314 0 0 0 0 0.717647 0 0 0 0 0.988235 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_352_61804"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_352_61804" result="shape"/>
</filter>
<linearGradient id="paint0_linear_352_61804" x1="39.3932" y1="23.8854" x2="38.3491" y2="16.8465" gradientUnits="userSpaceOnUse">
<stop stop-color="#2FB7FC"/>
<stop offset="1" stop-color="#82DEFF"/>
</linearGradient>
<linearGradient id="paint1_linear_352_61804" x1="39.3932" y1="12.5383" x2="24.3333" y2="-9.90193" gradientUnits="userSpaceOnUse">
<stop stop-color="#2FB7FC"/>
<stop offset="1" stop-color="#82DEFF"/>
</linearGradient>
</defs>
</svg>

30
src/assets/SvgIcons/折合新币累计金额.svg
File diff suppressed because it is too large
View File

14
src/assets/SvgIcons/持平.svg

@ -0,0 +1,14 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 13 5" class="design-iconfont">
<rect x="1" y="1" width="11" height="3" rx=".6875" fill="url(#12pnzcg9o__paint0_linear_443_32365)" fill-opacity=".7"/>
<rect x=".838349" y=".838349" width="11.3233" height="3.3233" rx=".849151" stroke="url(#12pnzcg9o__paint1_linear_443_32365)" stroke-opacity=".63" stroke-width=".323302" stroke-miterlimit="10"/>
<defs>
<linearGradient id="12pnzcg9o__paint0_linear_443_32365" x1="2.03217" y1="1" x2="4.91594" y2="6.93872" gradientUnits="userSpaceOnUse">
<stop/>
<stop offset="1" stop-color="#8A8A8A"/>
</linearGradient>
<linearGradient id="12pnzcg9o__paint1_linear_443_32365" x1="2.07323" y1="1" x2="4.90949" y2="6.89506" gradientUnits="userSpaceOnUse">
<stop stop-color="#8A8A8A"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
</defs>
</svg>

30
src/assets/SvgIcons/昨日充值人数.svg

@ -0,0 +1,30 @@
<svg width="59" height="59" viewBox="0 0 59 59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_266_9164)">
<path d="M57 29.5C57 44.6878 44.6878 57 29.5 57C14.3122 57 2 44.6878 2 29.5C2 14.3122 14.3122 2 29.5 2C44.6878 2 57 14.3122 57 29.5ZM14.7183 29.5C14.7183 37.6637 21.3363 44.2817 29.5 44.2817C37.6637 44.2817 44.2817 37.6637 44.2817 29.5C44.2817 21.3363 37.6637 14.7183 29.5 14.7183C21.3363 14.7183 14.7183 21.3363 14.7183 29.5Z" fill="#65C9C9"/>
<g filter="url(#filter1_d_266_9164)">
<path d="M52.7209 21.6873C54.1319 25.8811 54.3808 30.3787 53.4412 34.7026C52.5016 39.0264 50.4086 43.0151 47.3844 46.2451C44.3602 49.4751 40.5177 51.8258 36.2649 53.0475C32.0121 54.2693 27.5079 54.3165 23.2304 53.1842C18.953 52.0519 15.062 49.7824 11.9707 46.6165C8.87944 43.4507 6.70321 39.5068 5.67313 35.2035C4.64305 30.9003 4.79759 26.3985 6.12032 22.176C7.44305 17.9536 9.8846 14.1682 13.1857 11.2218L18.0988 16.7263C15.7918 18.7854 14.0856 21.4308 13.1612 24.3817C12.2368 27.3325 12.1288 30.4786 12.8487 33.4859C13.5685 36.4932 15.0894 39.2494 17.2497 41.4618C19.4101 43.6743 22.1293 45.2603 25.1185 46.0516C28.1078 46.8429 31.2556 46.8099 34.2276 45.9561C37.1996 45.1023 39.885 43.4595 41.9984 41.2023C44.1119 38.945 45.5746 36.1575 46.2313 33.1358C46.8879 30.1141 46.7139 26.9709 45.7279 24.0401L52.7209 21.6873Z" fill="#9469D1"/>
</g>
</g>
<defs>
<filter id="filter0_d_266_9164" x="0" y="0" width="59" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_266_9164"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_266_9164" result="shape"/>
</filter>
<filter id="filter1_d_266_9164" x="4" y="11.2217" width="51" height="44.7783" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="0.5"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_266_9164"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_266_9164" result="shape"/>
</filter>
</defs>
</svg>

19
src/assets/SvgIcons/昨日新增消费.svg

@ -0,0 +1,19 @@
<svg width="59" height="59" viewBox="0 0 59 59" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_266_9159)">
<path d="M57 29.5C57 44.6878 44.6878 57 29.5 57C14.3122 57 2 44.6878 2 29.5C2 14.3122 14.3122 2 29.5 2C44.6878 2 57 14.3122 57 29.5ZM11.7063 29.5C11.7063 39.3272 19.6728 47.2937 29.5 47.2937C39.3272 47.2937 47.2937 39.3272 47.2937 29.5C47.2937 19.6728 39.3272 11.7063 29.5 11.7063C19.6728 11.7063 11.7063 19.6728 11.7063 29.5Z" fill="#65C9C9"/>
<path d="M51.708 21.8153C53.6527 27.4352 53.3944 33.5834 50.9852 39.0203C48.576 44.4573 44.1951 48.7787 38.7257 51.1133C33.2563 53.448 27.1052 53.6222 21.5124 51.6009C15.9197 49.5796 11.3012 45.5131 8.58813 40.2212C5.87507 34.9293 5.26918 28.8056 6.89262 23.0847C8.51606 17.3637 12.2481 12.471 17.3363 9.39292C22.4245 6.31482 28.4905 5.28026 34.3114 6.49782C40.1322 7.71537 45.275 11.0945 48.703 15.9539L42.9916 19.9828C40.5832 16.5687 36.97 14.1946 32.8804 13.3392C28.7908 12.4838 24.529 13.2106 20.9541 15.3732C17.3792 17.5358 14.7572 20.9733 13.6166 24.9927C12.476 29.0121 12.9017 33.3145 14.8078 37.0325C16.7139 40.7504 19.9588 43.6074 23.8881 45.0276C27.8175 46.4477 32.1391 46.3253 35.9818 44.685C39.8244 43.0448 42.9024 40.0087 44.595 36.1888C46.2876 32.3689 46.4691 28.0493 45.1028 24.1009L51.708 21.8153Z" fill="#9469D1"/>
<path d="M48.5076 15.6811C49.9077 17.607 51.0071 19.7345 51.7679 21.9906L45.0618 24.2521C44.5301 22.6754 43.7619 21.1886 42.7834 19.8427L48.5076 15.6811Z" fill="#96DB00"/>
</g>
<defs>
<filter id="filter0_d_266_9159" x="0" y="0" width="59" height="59" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="1"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_266_9159"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_266_9159" result="shape"/>
</filter>
</defs>
</svg>

30
src/assets/SvgIcons/昨日新增金币.svg

@ -0,0 +1,30 @@
<svg width="69" height="69" viewBox="0 0 69 69" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_352_61732)">
<path d="M66.0273 34.5C66.0273 51.897 51.9243 66 34.5273 66C17.1304 66 3.02734 51.897 3.02734 34.5C3.02734 17.103 17.1304 3 34.5273 3C51.9243 3 66.0273 17.103 66.0273 34.5ZM17.5956 34.5C17.5956 43.8512 25.1762 51.4318 34.5273 51.4318C43.8785 51.4318 51.4591 43.8512 51.4591 34.5C51.4591 25.1488 43.8785 17.5682 34.5273 17.5682C25.1762 17.5682 17.5956 25.1488 17.5956 34.5Z" fill="#80A6FF"/>
<g filter="url(#filter1_d_352_61732)">
<path d="M6.54257 32.4138C6.99533 26.3434 9.40963 20.5847 13.4214 16.0063C17.4331 11.428 22.8247 8.27814 28.7831 7.03191C34.7415 5.78567 40.9436 6.5106 46.4539 9.09737C51.9643 11.6841 56.4842 15.9925 59.3319 21.3726C62.1796 26.7528 63.2008 32.913 62.2414 38.9242C61.2819 44.9355 58.394 50.4718 54.013 54.6982C49.632 58.9246 43.9956 61.612 37.9538 62.3549C31.912 63.0979 25.7924 61.8563 20.518 58.8172L24.7373 51.4944C28.4233 53.6182 32.7 54.4859 36.9223 53.9667C41.1446 53.4474 45.0835 51.5694 48.1452 48.6158C51.2068 45.6622 53.225 41.7931 53.8955 37.5922C54.566 33.3913 53.8524 29.0862 51.8623 25.3263C49.8721 21.5664 46.7134 18.5556 42.8625 16.7478C39.0116 14.9401 34.6774 14.4334 30.5134 15.3044C26.3494 16.1753 22.5814 18.3765 19.7778 21.5761C16.9743 24.7757 15.287 28.8001 14.9706 33.0424L6.54257 32.4138Z" fill="#F7D47B"/>
</g>
</g>
<defs>
<filter id="filter0_d_352_61732" x="0.736435" y="0.709091" width="67.5818" height="67.5818" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="1.14545"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_352_61732"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_352_61732" result="shape"/>
</filter>
<filter id="filter1_d_352_61732" x="5.39751" y="6.4375" width="58.3417" height="58.4179" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1.14545"/>
<feGaussianBlur stdDeviation="0.572727"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_352_61732"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_352_61732" result="shape"/>
</filter>
</defs>
</svg>

18
src/assets/SvgIcons/消耗.svg

@ -0,0 +1,18 @@
<svg width="63" height="63" viewBox="0 0 63 63" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_d_266_9155)">
<path d="M59 31.5C59 38.0669 56.65 44.417 52.3751 49.4019C48.1002 54.3868 42.1825 57.6774 35.6924 58.6786C29.2023 59.6797 22.5681 58.3253 16.9897 54.8603C11.4114 51.3953 7.25713 46.0484 5.27827 39.7868C3.29941 33.5251 3.62661 26.762 6.20068 20.7206C8.77476 14.6793 13.4258 9.75842 19.3126 6.8481C25.1993 3.93778 31.9333 3.23011 38.2965 4.85308C44.6596 6.47605 50.232 10.3225 54.0058 15.6968L47.312 20.397C44.6607 16.6212 40.7457 13.9188 36.275 12.7785C31.8044 11.6382 27.0733 12.1354 22.9374 14.1802C18.8015 16.2249 15.5338 19.6821 13.7253 23.9267C11.9168 28.1712 11.6869 32.9228 13.0772 37.3221C14.4675 41.7214 17.3862 45.478 21.3054 47.9124C25.2247 50.3468 29.8857 51.2984 34.4455 50.595C39.0053 49.8916 43.1629 47.5798 46.1664 44.0775C49.1698 40.5752 50.8209 36.1138 50.8209 31.5H59Z" fill="#F7D47C"/>
<path d="M53.7429 15.329C57.8941 21.0388 59.6905 28.1264 58.7601 35.1242C57.8298 42.1219 54.244 48.4939 48.7452 52.9208C43.2464 57.3477 36.2558 59.4905 29.2207 58.9054C22.1857 58.3203 15.645 55.0522 10.9531 49.7777C6.26115 44.5033 3.77725 37.6264 4.01569 30.5711C4.25414 23.5158 7.19666 16.8224 12.234 11.8767C17.2714 6.93111 24.0177 4.11205 31.0762 4.00327C38.1347 3.89448 44.9648 6.5043 50.1521 11.2924L44.535 17.378C40.9098 14.0318 36.1367 12.208 31.2038 12.284C26.271 12.36 21.5564 14.3301 18.036 17.7864C14.5157 21.2426 12.4593 25.9203 12.2927 30.8509C12.1261 35.7814 13.8619 40.5873 17.1409 44.2733C20.4198 47.9594 24.9907 50.2433 29.9071 50.6521C34.8236 51.061 39.7089 49.5636 43.5518 46.4699C47.3946 43.3761 49.9005 38.9231 50.5507 34.0327C51.2008 29.1424 49.9454 24.1893 47.0444 20.199L53.7429 15.329Z" fill="#7DB7FA"/>
</g>
<defs>
<filter id="filter0_d_266_9155" x="0" y="0" width="63" height="63" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="2"/>
<feComposite in2="hardAlpha" operator="out"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.25 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_266_9155"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_266_9155" result="shape"/>
</filter>
</defs>
</svg>

29
src/assets/SvgIcons/现金管理.svg
File diff suppressed because it is too large
View File

22
src/assets/SvgIcons/设置.svg

@ -0,0 +1,22 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.5471 0.599735C18.5459 0.0869799 24.0461 -0.443875 31.9786 0.599735C39.9111 1.64335 44.9571 6.05789 46.6388 11.3799C48.3204 16.7019 48.1984 27.1094 47.5788 32.3158C47.07 38.5475 43.4427 45.924 34.7683 47.2091C26.0939 48.4941 15.4335 48.1514 11.1572 46.6287C6.88095 45.1059 1.21772 41.8638 0.477232 32.7825C-0.263252 23.7012 -0.752563 11.5131 3.86834 6.57115C7.07241 2.76432 12.5484 1.11249 15.5471 0.599735Z" fill="#D0DDFF"/>
<g filter="url(#filter0_d_402_35688)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M22.3024 5.17784C23.5385 4.46416 25.0615 4.46416 26.2976 5.17784L39.6024 12.8593C40.8385 13.573 41.6 14.892 41.6 16.3193V31.6823C41.6 33.1097 40.8385 34.4286 39.6024 35.1423L26.2976 42.8238C25.0615 43.5375 23.5385 43.5375 22.3024 42.8238L8.99763 35.1423C7.76149 34.4286 7 33.1097 7 31.6823V16.3193C7 14.892 7.76149 13.573 8.99763 12.8593L22.3024 5.17784Z" fill="url(#paint0_linear_402_35688)"/>
</g>
<path d="M34.5525 26.275C35.142 23.917 34.4935 22.378 34.4935 22.378L32.2381 22.2673C32.0404 21.5594 31.7509 20.8919 31.3832 20.2744L32.9047 18.5469C31.6542 16.4628 30.1074 15.8331 30.1074 15.8331L28.4321 17.3517C27.808 16.9886 27.1329 16.7074 26.4188 16.517L26.275 14.2476C23.9171 13.658 22.378 14.3066 22.378 14.3066L22.2709 16.488C21.5671 16.6649 20.8975 16.926 20.2785 17.2705L18.6927 15.8331C18.6927 15.8331 17.1458 16.4628 15.8953 18.5469C16.2928 18.9981 17.0748 19.5161 17.1218 20.1795C17.1333 20.3432 16.3691 22.2767 16.3361 22.2784L14.3065 22.378C14.3065 22.378 13.6581 23.917 14.2475 26.275L16.2589 26.4025C16.4489 27.2023 16.7537 27.9556 17.1573 28.6464L15.833 30.1074C15.833 30.1074 16.4628 31.6542 18.5469 32.9047L20.0562 31.5753C20.74 31.9847 21.4865 32.2965 22.2799 32.4951L22.378 34.4935C22.378 34.4935 23.9171 35.142 26.275 34.5525L26.4072 32.4668C27.2107 32.2538 27.9649 31.9246 28.6527 31.4951L30.2531 32.9047C32.3373 31.6543 32.967 30.1074 32.967 30.1074L31.5092 28.4991C31.8683 27.8537 32.1379 27.1538 32.3142 26.4168L34.5525 26.275ZM24.4 29.2449C21.7243 29.2449 19.5552 27.0758 19.5552 24.4C19.5552 21.7243 21.7243 19.5552 24.4 19.5552C27.0757 19.5552 29.2449 21.7243 29.2449 24.4C29.2449 27.0759 27.0757 29.2449 24.4 29.2449Z" fill="white"/>
<defs>
<filter id="filter0_d_402_35688" x="4" y="0.642578" width="42.6016" height="46.7168" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="1"/>
<feGaussianBlur stdDeviation="2"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.172549 0 0 0 0 0.360784 0 0 0 0 0.968627 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_402_35688"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_402_35688" result="shape"/>
</filter>
<linearGradient id="paint0_linear_402_35688" x1="57.4583" y1="24.0008" x2="19.4991" y2="-7.09544" gradientUnits="userSpaceOnUse">
<stop stop-color="#2C5CF7"/>
<stop offset="1" stop-color="#80A6FF"/>
</linearGradient>
</defs>
</svg>

27
src/assets/SvgIcons/金币管理.svg

@ -0,0 +1,27 @@
<svg width="31" height="31" viewBox="0 0 31 31" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.83596 0.876936C11.7158 0.555502 15.1637 0.222722 20.1364 0.876936C25.1091 1.53115 28.2723 4.29852 29.3265 7.63474C30.3807 10.971 30.3042 17.4952 29.9158 20.7589C29.5969 24.6654 27.323 29.2896 21.8852 30.0952C16.4475 30.9007 9.76469 30.6859 7.08401 29.7313C4.40334 28.7767 0.853199 26.7444 0.389008 21.0515C-0.0751821 15.3587 -0.381919 7.71828 2.51481 4.62027C4.52336 2.23386 7.95615 1.19837 9.83596 0.876936Z" fill="#FFF8D4"/>
<g filter="url(#filter0_d_352_61805)">
<path d="M7.66202 4H23.1458C25.0511 4 26.0032 4.95261 26.0032 6.85734V24.4109C26.0032 26.3161 25.0506 27.2682 23.1458 27.2682H7.66202C5.7568 27.2682 4.80469 26.3156 4.80469 24.4109V6.85734C4.80469 4.95261 5.7573 4 7.66202 4Z" fill="url(#paint0_linear_352_61805)"/>
</g>
<path d="M6.91658 10.8059H3.43517C3.05454 10.8059 2.6895 10.6547 2.42035 10.3855C2.1512 10.1164 2 9.75135 2 9.37072C2 8.99009 2.1512 8.62505 2.42035 8.3559C2.6895 8.08675 3.05454 7.93555 3.43517 7.93555H6.91708C7.29771 7.93555 7.66275 8.08675 7.9319 8.3559C8.20104 8.62505 8.35225 8.99009 8.35225 9.37072C8.35225 9.75135 8.20104 10.1164 7.9319 10.3855C7.66275 10.6547 7.29771 10.8059 6.91708 10.8059H6.91658ZM6.91658 17.0531H3.43517C3.05454 17.0531 2.6895 16.9019 2.42035 16.6328C2.1512 16.3636 2 15.9986 2 15.618C2 15.2373 2.1512 14.8723 2.42035 14.6031C2.6895 14.334 3.05454 14.1828 3.43517 14.1828H6.91708C7.29771 14.1828 7.66275 14.334 7.9319 14.6031C8.20104 14.8723 8.35225 15.2373 8.35225 15.618C8.35225 15.9986 8.20104 16.3636 7.9319 16.6328C7.66275 16.9019 7.29771 17.0531 6.91708 17.0531H6.91658ZM6.91658 23.3004H3.43517C3.05454 23.3004 2.6895 23.1491 2.42035 22.88C2.1512 22.6109 2 22.2458 2 21.8652C2 21.4846 2.1512 21.1195 2.42035 20.8504C2.6895 20.5812 3.05454 20.43 3.43517 20.43H6.91708C7.15314 20.4298 7.3856 20.4879 7.59383 20.5991C7.80206 20.7103 7.97962 20.8712 8.11076 21.0675C8.2419 21.2638 8.32256 21.4894 8.34558 21.7243C8.3686 21.9593 8.33327 22.1962 8.24273 22.4142C8.13406 22.6765 7.95007 22.9007 7.71403 23.0584C7.47798 23.2161 7.20047 23.3003 6.91658 23.3004Z" fill="url(#paint1_linear_352_61805)"/>
<path d="M20.123 18.3164C19.1741 18.8897 17.6962 19.2285 16 19.2285C14.3038 19.2285 12.8258 18.8898 11.877 18.3164V18.8652C11.9303 18.9713 12.0446 19.1022 12.2461 19.2412C12.4652 19.3922 12.7642 19.5399 13.1338 19.6689C13.8727 19.9269 14.8673 20.1025 16 20.1025C17.1327 20.1025 18.1273 19.9269 18.8662 19.6689C19.2358 19.5399 19.5349 19.3922 19.7539 19.2412C19.9554 19.1022 20.0697 18.9713 20.123 18.8652V18.3164ZM20.999 18.7852L21.248 18.7949C21.2104 19.6752 20.4237 20.2844 19.4668 20.6641C18.4874 21.0525 17.2197 21.25 16 21.25C14.7803 21.25 13.5129 21.0526 12.5332 20.6641C11.5758 20.2843 10.7878 19.6754 10.75 18.7949V12.2383C10.7682 11.3459 11.5549 10.7273 12.5146 10.3428C13.4967 9.94928 14.7725 9.75 16 9.75C17.2346 9.75 18.5185 9.95144 19.5029 10.3496C20.4649 10.7387 21.2498 11.3655 21.25 12.2686V12.2754L21.249 18.7852V18.7949L20.999 18.7852ZM20.123 16.209C19.1741 16.7823 17.6963 17.1211 16 17.1211C14.3037 17.1211 12.8258 16.7824 11.877 16.209V16.8086C11.915 16.9128 12.0126 17.0468 12.207 17.1924C12.4121 17.346 12.7012 17.4974 13.0674 17.6309C13.7991 17.8975 14.8107 18.0811 16 18.0811C17.1889 18.0811 18.1999 17.8973 18.9316 17.6309C19.2978 17.4975 19.5868 17.3459 19.792 17.1924C19.9867 17.0467 20.085 16.9129 20.123 16.8086V16.209ZM20.123 13.8857C19.677 14.147 19.1293 14.3487 18.5391 14.4941C17.7499 14.6886 16.8645 14.7881 16 14.7881C15.1355 14.7881 14.2501 14.6886 13.4609 14.4941C12.8707 14.3487 12.323 14.147 11.877 13.8857V14.7012C11.9149 14.8054 12.0125 14.9393 12.207 15.085C12.4121 15.2385 12.7013 15.39 13.0674 15.5234C13.7991 15.7901 14.8107 15.9746 16 15.9746C17.189 15.9746 18.1999 15.79 18.9316 15.5234C19.2979 15.39 19.5867 15.2385 19.792 15.085C19.9863 14.9396 20.0848 14.8064 20.123 14.7021V13.8857ZM16 10.8975C14.7633 10.8975 13.6919 11.1069 12.9385 11.4033C12.5608 11.5519 12.2736 11.7178 12.0859 11.8809C11.8935 12.0481 11.838 12.1825 11.8379 12.2686C11.8379 12.3546 11.8935 12.489 12.0859 12.6562C12.2736 12.8193 12.5609 12.9852 12.9385 13.1338C13.6919 13.4302 14.7633 13.6406 16 13.6406C17.2367 13.6406 18.3081 13.4302 19.0615 13.1338C19.439 12.9853 19.7254 12.8192 19.9131 12.6562C20.1058 12.4888 20.1621 12.3546 20.1621 12.2686C20.162 12.1825 20.1056 12.0481 19.9131 11.8809C19.7254 11.7179 19.4388 11.5518 19.0615 11.4033C18.3081 11.1069 17.2367 10.8975 16 10.8975Z" fill="white" stroke="white" stroke-width="0.5"/>
<defs>
<filter id="filter0_d_352_61805" x="3.80469" y="3" width="23.1992" height="25.2686" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="0.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 0.701961 0 0 0 0 0.101961 0 0 0 0.3 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_352_61805"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_352_61805" result="shape"/>
</filter>
<linearGradient id="paint0_linear_352_61805" x1="36.6024" y1="15.6341" x2="13.4348" y2="-5.47272" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFB31A"/>
<stop offset="1" stop-color="#FFD86B"/>
</linearGradient>
<linearGradient id="paint1_linear_352_61805" x1="11.5286" y1="15.618" x2="0.678436" y2="11.1321" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFB31A"/>
<stop offset="1" stop-color="#FFD86B"/>
</linearGradient>
</defs>
</svg>

9
src/assets/SvgIcons/金币系统LOGO.svg
File diff suppressed because it is too large
View File

BIN
src/assets/backgroundBlue.png

After

Width: 1440  |  Height: 810  |  Size: 1.3 MiB

BIN
src/assets/半透明background.png

After

Width: 1874  |  Height: 1054  |  Size: 10 KiB

BIN
src/assets/收款明细撤回背景.png

After

Width: 700  |  Height: 392  |  Size: 116 KiB

336
src/components/MoneyManage/CurrencySelect.vue

@ -0,0 +1,336 @@
<template>
<div class="dropdown" ref="dropdownRef">
<!-- 下拉框触发器 -->
<div class="dropdown-toggle" @click="toggleMenu" :class="{ 'active': isOpen }">
<span class="placeholder" :style="{ color: selectedItem ? '#333' : '#A8ABB2' }">
{{ selectedItem || placeholder }}
</span>
<span class="arrow">
<el-icon>
<ArrowDown />
</el-icon>
</span>
</div>
<!-- 下拉菜单 -->
<div class="dropdown-menu" v-if="isOpen">
<!-- 搜索框 -->
<div class="search">
<input type="text" v-model="searchData" class="search-input" placeholder="查询" @focus="handleSearchFocus"
@blur="handleSearchBlur">
<el-icon v-show="!searchData" class="search-icon">
<Search />
</el-icon>
<el-icon class="clear-icon" v-if="searchData" @click="clearSearch">
<CircleClose />
</el-icon>
</div>
<!-- 选项区域按钮样式 -->
<div class="menuContent">
<button class="dropdown-item" v-for="(item, index) in filteredItems" :key="index" @click="handleSelect(item)"
:class="{ 'selected': selectedItem === item }">
{{ item }}
</button>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watchEffect, onMounted } from 'vue';
const searchData = ref('')
const isOpen = ref(false)
const selectedItem = ref('')
const dropdownRef = ref(null)
const props = defineProps({
items: {
type: Array,
required: true,
default: () => []
},
placeholder: {
type: String,
default: '请选择支付方式'
},
modelValue: {
type: String,
default: ''
}
})
const emit = defineEmits(['update:modelValue', 'change'])
//
const toggleMenu = () => {
isOpen.value = !isOpen.value
searchData.value = ''
}
//
const clearSearch = () => {
searchData.value = ''
}
//
const handleSelect = (item) => {
selectedItem.value = item
isOpen.value = false
emit('update:modelValue', item)
emit('change', item)
}
//
const handleClickOutside = (event) => {
if (dropdownRef.value && !dropdownRef.value.contains(event.target)) {
isOpen.value = false
}
}
//
const handleSearchFocus = () => {
//
}
const handleSearchBlur = () => {
//
}
//
const filteredItems = computed(() => {
if (!searchData.value) return props.items
return props.items.filter(item =>
item.toLowerCase().includes(searchData.value.toLowerCase())
)
})
// /
onMounted(() => {
document.addEventListener('click', handleClickOutside)
return () => {
document.removeEventListener('click', handleClickOutside)
}
})
//
watchEffect(() => {
selectedItem.value = props.modelValue
})
</script>
<style scoped lang="scss">
//
.dropdown {
position: relative;
width: 268px;
font-family: 'Arial', sans-serif;
}
// /
.dropdown-toggle {
border: 1px solid #e5e7eb;
padding: 4px 12px;
/* 调整内边距以匹配按钮高度 */
height: 23px;
/* 调整高度以匹配按钮 */
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
border-radius: 6px;
transition: all 0.3s ease;
.placeholder {
flex: 1;
font-size: 14px;
line-height: 18px;
color: #A8ABB2;
}
}
// +
.dropdown-toggle.active {
border-color: #678BFF;
box-shadow: 0 0 0 2px rgba(103, 139, 255, 0.1);
}
//
.arrow {
margin-left: 8px;
color: #999;
transition: transform 0.3s ease;
}
.dropdown-toggle.active .arrow {
transform: rotate(180deg);
}
//
.dropdown-menu {
position: absolute;
top: 100%; //
left: 0;
width: 100%;
border: 1px solid #678BFF;
max-height: 300px;
background-color: #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-radius: 0 0 8px 8px; //
z-index: 1000;
margin-top: 15px; //
overflow: visible;
&::before {
content: "";
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%) scaleY(0.5);
width: 30px;
height: 16px;
background: #fff;
clip-path: polygon(0 100%, 100% 100%, 50% 0);
z-index: 1001;
border: none;
/* 移除原来的边框 */
}
&::after {
content: "";
position: absolute;
top: -9px;
/* 比 ::before 往下一点,制造边框效果 */
left: 50%;
transform: translateX(-50%) scaleY(0.5);
width: 30px;
height: 16px;
background: #678BFF;
clip-path: polygon(0 100%, 100% 100%, 50% 0);
z-index: 1000;
}
}
//
.search {
position: sticky;
top: 0;
background-color: #FFFFFF;
z-index: 1002;
padding: 10px 14px 0px 10px;
}
// +
.search-input {
width: 100%;
height: 27px;
padding: 0 12px 0 5px;
/* 左侧留出图标空间 */
border: 1px solid #dcdfe6;
border-radius: 10px;
box-sizing: border-box;
background-color: #f8f9fa;
/* 浅灰背景匹配参考图 */
outline: none;
font-size: 12px;
transition: border-color 0.3s ease;
&::placeholder {
color: #909399;
}
&:hover {
border-color: #c0c4cc;
}
&:focus {
border-color: #678BFF;
}
}
//
.search-icon {
position: absolute;
top: 62%;
left: 50px;
transform: translateY(-50%);
color: #909399;
z-index: 1003;
}
// + hover
.clear-icon {
position: absolute;
top: 62%;
right: 20px;
transform: translateY(-50%);
color: #909399;
cursor: pointer;
z-index: 1003;
&:hover {
color: #606266;
}
}
//
.menuContent {
max-height: 200px;
/* 减去搜索框高度和尖角高度 */
overflow-y: auto;
padding: 8px;
padding: 10px 14px 12px 10px;
}
// + hover/
.dropdown-item {
width: 100%;
height: 27px;
padding: 5px 12px 5px 5px;
text-align: center;
cursor: pointer;
border: none;
border-radius: 10px;
background-color: #fff;
font-size: 12px;
font-style: normal;
font-weight: 700;
line-height: 20px;
margin: 5px 0;
color: #040A2D;
transition: all 0.2s ease;
&:hover {
background-color: #F3FAFE;
/* hover浅灰 */
}
&.selected {
background-color: #E5EBFE;
/* 选中浅蓝 */
color: #2741DE;
/* 选中文字蓝色 */
}
}
//
.menuContent::-webkit-scrollbar {
width: 6px;
}
.menuContent::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.menuContent::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
&:hover {
background: #909399;
}
}
</style>

121
src/components/MoneyManage/ProductSelect.vue

@ -0,0 +1,121 @@
<template>
<div class="productContent">
<div class="selectBox" @click="handelMenu" :class="{ 'active': isOpen }">
<span class="placeholder" :style="{ color: selectedItem ? '#333' : '#A8ABB2' }">
{{ selectedItem || placeholder }}
</span>
<span class="arrow">
<el-icon>
<ArrowDown />
</el-icon>
</span>
</div>
<div class="menu" v-show="isOpen">
<div class="coin">
<div class="coinselect">
coin1
<span class="coin-arrow">
<el-icon>
<ArrowDown />
</el-icon>
</span>
</div>
<div class="coinoption">
coIn2
</div>
</div>
<div class="product">
22
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed, watchEffect, onMounted } from 'vue';
const searchData = ref('')
const isOpen = ref(false)
const selectedItem = ref('')
const dropdownRef = ref(null)
const placeholder = ref('请选择产品')
const handelMenu = () => {
isOpen.value = !isOpen.value
}
</script>
<style scoped lang="scss">
.productContent {
position: relative;
width: 268px;
font-family: 'Arial', sans-serif;
}
.selectBox {
border: 1px solid #e5e7eb;
padding: 4px 12px;
/* 调整内边距以匹配按钮高度 */
height: 23px;
/* 调整高度以匹配按钮 */
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
background-color: #fff;
border-radius: 6px;
transition: all 0.3s ease;
.placeholder {
flex: 1;
font-size: 14px;
line-height: 18px;
color: #A8ABB2;
}
}
//
.arrow {
margin-left: 8px;
color: #999;
transition: transform 0.3s ease;
}
.selectBox.active .arrow {
transform: rotate(180deg);
}
.menu {
position: absolute;
top: 100%; //
left: 0;
width: 130%;
max-height: 600px;
display: flex;
padding: 10px;
flex-direction: column;
align-items: flex-start;
gap: 10px;
flex-shrink: 0;
border-radius: 8px;
background: #E4F0FC;
box-shadow: 0 0 4px 0 #00000040;
z-index: 100;
.coin {
width: 100%;
.coinselect {
width: 100px;
height: 30px;
border: 1px solid #175BE5;
padding: 5px 0 5px 12px;
display: flex;
.coin-arrow {
margin-top: 8px;
color: #111;
}
}
}
}
</style>

211
src/components/workspace/CashManagement.vue

@ -0,0 +1,211 @@
<template>
<div class="cash-management">
<div class="cash-title">
<div class="text1"> 现金管理
<span class="text1-update-time">最后更新时间{{
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
}}</span>
</div>
</div>
<div class="text2"><span class="text2-income">总营收{{ cashData.totalIncome }}</span></div>
<div class="chart-container">
<!-- 左侧数据列表 -->
<div class="market-data">
<div v-for="market in cashData.markets" :key="market.name" class="market-item">
<span class="market-name">{{ market.name }}:</span>
<span class="market-value">{{ market.value.toLocaleString() }}新币</span>
</div>
</div>
<!-- 图表区域 -->
<div ref="chartRef" class="chart"></div>
</div>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import {ref, onMounted} from 'vue'
//
const cashData = ref({
updateTime: '2025-09-24 12:00:00',
totalIncome: 1200000,
markets: [
{name: '北京', value: 450000},
{name: '上海', value: 300000},
{name: '广州', value: 200000},
{name: '深圳', value: 150000},
{name: '其他', value: 100000}
]
})
const chartRef = ref(null)
let chartInstance = null
const renderChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
}
const option = {
tooltip: {trigger: 'item'},
legend: {
bottom: 5, //
left: 'center'
},
series: [
{
label: {show: false},
type: 'pie',
radius: ['40%', '70%'],
data: cashData.value.markets,
center: ['60%', '45%'] //
}
]
}
chartInstance.setOption(option)
}
onMounted(() => {
renderChart()
})
</script>
<style scoped>
/* 背景卡片大小 */
.cash-management {
margin: 10px 5px;
width: 100%;
height: 50vh;
flex-shrink: 0;
border-radius: 8px;
background: #E7F4FD;
box-shadow: 0 2px 2px 0 #00000040;
display: flex;
flex-direction: column;
align-items: center;
}
/*
.cash-card {
width: 100%;
}
.chart {
width: 100%;
height: 200px;
} */
.cash-title {
width: 100%;
height: 5vh;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C6ADFF 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
.text1 {
color: #040a2d;
font-family: "PingFang SC";
font-size: 28px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
.text1-update-time {
width: 100%;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: 31.79px;
}
/* 总收入的渐变框 */
.text2 {
margin: 13px;
width: 95%;
height: 48px;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
/* 总收入字体 */
.text2-income {
width: 215px;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
/* 图表容器 */
.chart-container {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 10px;
}
/* 左侧数据列表,使用指定的样式 */
.market-data {
display: flex;
width: 180px;
flex-direction: column;
align-items: flex-start;
gap: 20px;
padding: 10px;
margin-left: 40px;
}
.market-item {
display: flex;
justify-content: space-between;
width: 100%;
font-family: "PingFang SC";
font-size: 16px;
color: #040a2d;
}
.market-name {
white-space: nowrap;
font-weight: 700;
}
.market-value {
font-weight: 500;
}
/* 图表样式 */
.chart {
flex: 1;
height: 300px;
margin-top: 10px;
}
</style>

210
src/components/workspace/CashManagementMarkets.vue

@ -0,0 +1,210 @@
<!--各地区的现金管理情况-->
<template>
<div class="cash-management">
<div class="cash-title">
<div class="text1"> 现金管理
<span class="text1-update-time">最后更新时间{{
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
}}</span>
</div>
</div>
<div class="text2"><span class="text2-income">总营收{{ cashData.totalIncome }}</span></div>
<div class="chart-container">
<!-- 左侧数据列表 -->
<div class="market-data">
<div v-for="market in cashData.markets" :key="market.name" class="market-item">
<span class="market-name">{{ market.name }}:</span>
<span class="market-value">{{ market.value.toLocaleString() }}</span>
</div>
</div>
<!-- 图表区域 -->
<div ref="chartRef" class="chart"></div>
</div>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import {ref, onMounted} from 'vue'
//
const cashData = ref({
updateTime: '2025-09-24 12:00:00',
totalIncome: 1200000,
markets: [
{name: '北京', value: 450000},
{name: '上海', value: 300000},
{name: '广州', value: 200000},
{name: '深圳', value: 150000},
{name: '其他', value: 100000}
]
})
const chartRef = ref(null)
let chartInstance = null
const renderChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
}
const option = {
tooltip: {trigger: 'item'},
legend: {
bottom: 5, //
left: 'center'
},
series: [
{
label: {show: false},
type: 'pie',
radius: ['40%', '70%'],
data: cashData.value.markets,
center: ['60%', '45%'] //
}
]
}
chartInstance.setOption(option)
}
onMounted(() => {
renderChart()
})
</script>
<style scoped>
/* 背景卡片大小 */
.cash-management {
margin: 10px 5px;
width: 100%;
height: 50vh;
flex-shrink: 0;
border-radius: 8px;
background: #E7F4FD;
box-shadow: 0 2px 2px 0 #00000040;
display: flex;
flex-direction: column;
align-items: center;
}
/*
.cash-card {
width: 100%;
}
.chart {
width: 100%;
height: 200px;
} */
.cash-title {
width: 100%;
height: 5vh;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C6ADFF 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
.text1 {
color: #040a2d;
font-family: "PingFang SC";
font-size: 28px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
.text1-update-time {
width: 100%;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: 31.79px;
}
/* 总收入的渐变框 */
.text2 {
margin: 13px;
width: 95%;
height: 48px;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
/* 总收入字体 */
.text2-income {
width: 215px;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
/* 图表容器 */
.chart-container {
display: flex;
align-items: center;
width: 100%;
height: 100%;
padding: 10px;
}
/* 左侧数据列表,使用您指定的样式 */
.market-data {
display: flex;
width: 179px;
flex-direction: column;
align-items: flex-start;
gap: 12px;
padding: 10px;
margin-left: 80px;
}
.market-item {
display: flex;
justify-content: space-between;
width: 100%;
font-family: "PingFang SC";
font-size: 16px;
color: #040a2d;
}
.market-name {
font-weight: 700;
}
.market-value {
font-weight: 500;
}
/* 图表样式 */
.chart {
flex: 1;
height: 300px;
margin-top: 10px;
}
</style>

818
src/components/workspace/GoldGraph.vue

@ -0,0 +1,818 @@
<template>
<div class="graph">
<el-card style="width:100%;" class="graph-card">
<div>
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane label="金币充值" name="recharge"></el-tab-pane>
<el-tab-pane label="金币消费" name="consume"></el-tab-pane>
</el-tabs>
</div>
<div class="condition">
<div class="stats">
<div v-if="activeTab === 'consume'">合计{{ sumConsume / 100 }}</div>&nbsp;&nbsp;
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }}&nbsp;&nbsp;
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }}&nbsp;&nbsp;
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }}&nbsp;&nbsp;
</div>
<div>
<el-button
:style="{ backgroundColor: activeTimeRange === 'yes' ? '#2741DE' : '#E5EBFE', color: activeTimeRange === 'yes' ? 'white' : '#666' }"
@click="getYes()" size="default">昨天
</el-button>
<el-button
:style="{ backgroundColor: activeTimeRange === 'today' ? '#2741DE' : '#E5EBFE', color: activeTimeRange === 'today' ? 'white' : '#666' }"
@click="getToday()" size="default">今天
</el-button>
<el-button
:style="{ backgroundColor: activeTimeRange === 'week' ? '#2741DE' : '#E5EBFE', color: activeTimeRange === 'week' ? 'white' : '#666' }"
@click="getWeek()" size="default">本周
</el-button>
<el-button
:style="{ backgroundColor: activeTimeRange === 'month' ? '#2741DE' : '#E5EBFE', color: activeTimeRange === 'month' ? 'white' : '#666' }"
@click="getMonth()" size="default">本月
</el-button>
<el-button
:style="{ backgroundColor: activeTimeRange === 'year' ? '#2741DE' : '#E5EBFE', color: activeTimeRange === 'year' ? 'white' : '#666' }"
@click="getYear()" size="default">本年
</el-button>
</div>
<div>
<el-date-picker size="small" v-model="dateRange" type="datetimerange" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
style="width:20vw;margin-left:0.5vw;" value-format="YYYY-MM-DD HH:mm:ss"
:default-time="defaultTime"
:disabled-date="disabledDate" @change="handleDatePickerChange"/>
<el-button type="primary" size="small" style="margin-left: 0.5vw" @click="getChartData">查询</el-button>
</div>
</div>
<div class="graph-content">
<div ref="chartRef" class="left"></div>
<div class="right">
<el-card class="graph-card-list">
<div class="card-large">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div>
<el-select class="card-select" v-model="selectedType" style="width: 100%; margin-bottom: 15px">
<el-option label="全部类型" value="all"></el-option>
<el-option label="永久金币" value="permanent"></el-option>
<el-option label="免费金币" value="free"></el-option>
<el-option label="任务金币" value="task"></el-option>
</el-select>
<el-table class="card-table" :data="tableData" height="320px">
<el-table-column prop="rank" label="排名" width="60" align="center"></el-table-column>
<el-table-column prop="market" label="地区" align="center">
<template #default="scope">
<span>{{ marketMapping[scope.row.market] || scope.row.market }}</span>
</template>
</el-table-column>
<el-table-column prop="coinAmount" label="金币数量" align="center">
<template #default="{ row }">
{{ row.coinAmount.toLocaleString() }}
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</div>
</el-card>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import {onMounted, onUnmounted, ref, watch} from 'vue'
import API from '@/util/http'
import {ElMessage} from 'element-plus'
import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc'
import {marketMapping} from "@/utils/marketMap.js";
dayjs.extend(utc)
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
//
const markets = ref([])
//
const dateRange = ref([])
const activeTab = ref('recharge')
const selectedType = ref('all')
const tableData = ref([])
const chartRef = ref(null)
let chartInstance = null
//
const sumRechargePermanent = ref(0)
const sumRechargeFree = ref(0)
const sumRechargeTask = ref(0)
const sumConsumePermanent = ref(0)
const sumConsumeFree = ref(0)
const sumConsumeTask = ref(0)
const sumConsume = ref(0)
//
const adminData = ref({})
//
const currentGold = ref(0)
const dailyChange = ref(0)
const currentPermanent = ref(0)
const currentFree = ref(0)
const currentFreeJune = ref(0)
const currentFreeDecember = ref(0)
const currentTask = ref(0)
const yearlyRecharge = ref(0)
const yearlyMoney = ref(0)
const recharge = ref(0)
const money = ref(0)
const yearlyReduce = ref(0)
const yearlyConsume = ref(0)
const yearlyRefund = ref(0)
const dailyReduce = ref(0)
const dailyConsume = ref(0)
const dailyRefund = ref(0)
const yearlyRechargeNum = ref(0)
const sumWow = ref(0)
const sumDaily = ref(0)
const rechargeNum = ref(0)
const ydayRechargeNum = ref(0)
const firstRecharge = ref(0)
const length = ref(0)
//
const chartLoading = ref(true)
const handleResize = () => {
if (chartInstance.value) {
try {
chartInstance.value.resize()
console.log('resize一下')
} catch (error) {
console.error('图表resize失败:', error)
}
}
}
//
const initChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
window.addEventListener('resize', handleResize)
}
}
//
const destroyChart = () => {
if (chartInstance.value) {
try {
chartInstance.value.dispose()
} catch (error) {
console.error('图表销毁失败:', error)
}
chartInstance.value = null
}
window.removeEventListener('resize', handleResize)
}
const formatDate = function (date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
//
const getYes = function () {
const yesterday = dayjs().subtract(1, 'day')
const startTime = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'yes' //
getChartData()
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'today' //
getChartData()
}
//
const getWeek = function () {
const today = dayjs();
// 01...6
const day = today.day();
// 6
let monday = today.subtract(day === 0 ? 6 : day - 1, 'day');
// (7 - day)
let sunday = today.add(day === 0 ? 0 : 7 - day, 'day');
//
const startTime = monday.startOf('day').format('YYYY-MM-DD HH:mm:ss');
const endTime = sunday.endOf('day').format('YYYY-MM-DD HH:mm:ss');
dateRange.value = [startTime, endTime];
console.log('本周时间范围(周一到周日):', dateRange.value);
activeTimeRange.value = 'week';
getChartData();
};
//
const getMonth = function () {
const today = dayjs()
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('month').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'month' //
getChartData()
}
//
const getYear = function () {
const today = dayjs()
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('year').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'year' //
getChartData()
}
// ( = + 6 + 12 + + )
const processData = (data) => {
const summary = {
currentGold: 0,
dailyChange: 0,
currentPermanent: 0,
currentFreeJune: 0,
currentFreeDecember: 0,
currentTask: 0,
currentFree: 0,
recharge: 0,
money: 0,
yearlyRecharge: 0,
yearlyMoney: 0,
consumePermanent: 0,
consumeFreeJune: 0,
consumeFreeDecember: 0,
consumeTask: 0,
refundPermanent: 0,
refundFreeJune: 0,
refundFreeDecember: 0,
refundTask: 0,
dailyReduce: 0,
yearlyConsume: 0,
yearlyRefund: 0,
yearlyReduce: 0,
rechargeNum: 0,
ydayRechargeNum: 0,
firstRecharge: 0,
sumWow: 0,
sumDaily: 0,
yearlyRechargeNum: 0
}
//
data.marketCards.forEach(market => {
for (const i in summary) {
if (market[i] !== undefined && market[i] !== null) { // number
summary[i] += market[i]
}
}
})
// wowdaily
length.value = data.markets.length
console.log(length.value)
// 退
const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
//
currentGold.value = summary.currentGold.toFixed(2)
dailyChange.value = summary.dailyChange.toFixed(2)
currentPermanent.value = summary.currentPermanent.toFixed(2)
currentFree.value = summary.currentFree.toFixed(2)
currentFreeJune.value = summary.currentFreeJune.toFixed(2)
currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
currentTask.value = summary.currentTask.toFixed(2)
yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
yearlyMoney.value = summary.yearlyMoney.toFixed(2)
recharge.value = summary.recharge.toFixed(2)
money.value = summary.money.toFixed(2)
yearlyReduce.value = summary.yearlyReduce.toFixed(2)
yearlyConsume.value = summary.yearlyConsume.toFixed(2)
yearlyRefund.value = summary.yearlyRefund.toFixed(2)
dailyReduce.value = summary.dailyReduce.toFixed(2)
dailyConsume.value = yesterdayConsume.toFixed(2)
dailyRefund.value = yesterdayRefund.toFixed(2)
yearlyRechargeNum.value = summary.yearlyRechargeNum
// //
// sumWow.value = (marketCards.sumWow / length.value).toFixed(2)
// //
// sumDaily.value = (marketCards.sumDaily / length.value).toFixed(2)
// rechargeNum.value = summary.rechargeNum
ydayRechargeNum.value = summary.ydayRechargeNum
firstRecharge.value = summary.firstRecharge
}
//
const disabledDate = (time) => {
const limitDate = new Date(2025, 0, 1);
return time.getTime() < limitDate.getTime();
}
//
const getMarkets = async () => {
console.log("adminData", adminData.value.account)
try {
const response = await API({
url: '/general/adminMarkets',
data: {
account: adminData.value.account
}
})
if (Array.isArray(response.data)) {
// markets.value = response.data.filter(data => data !== "1")
markets.value = response.data
console.log('市场列表获取成功:', markets.value)
} else {
console.error('获取市场列表失败', response)
ElMessage.error('获取市场列表失败')
}
} catch (error) {
console.error('获取市场列表失败:', error)
ElMessage.error('获取市场列表失败')
}
}
//
const getChartData = async () => {
try {
//
if (!markets.value || markets.value.length === 0) {
await getMarkets()
}
//
if (!dateRange.value || dateRange.value.length === 0) {
getYear()
}
const params = {
markets: markets.value,
startDate: dateRange.value[0],
endDate: dateRange.value[1]
};
const response = await API({
url: '/workbench/getGraph',
data: params
})
console.log('看看params', params)
if (Array.isArray(response.marketGraphs)) {
// const filteredGraphs = response.marketGraphs.filter(data => data.market !== "1");
//
processChartData(response.marketGraphs)
//
processRankingData(response.marketGraphs)
} else {
console.error('获取图表数据失败:', response)
ElMessage.error('获取图表数据失败')
}
} catch (error) {
console.error('获取图表数据失败:', error)
ElMessage.error('获取图表数据失败')
}
}
//
const processChartData = (marketCards) => {
const chartData = {
rechargePermanent: [],
rechargeFree: [],
rechargeTask: [],
consumePermanent: [],
consumeFree: [],
consumeTask: [],
sumConsume: []
}
//
const sumRechargePermanent1 = ref(0)
const sumRechargeFree1 = ref(0)
const sumRechargeTask1 = ref(0)
const sumConsumePermanent1 = ref(0)
const sumConsumeFree1 = ref(0)
const sumConsumeTask1 = ref(0)
const sumConsume1 = ref(0)
marketCards.forEach(market => {
chartData.rechargePermanent.push(market.sumRechargePermanent / 100 || 0)
chartData.rechargeFree.push(market.sumRechargeFree / 100 || 0)
chartData.rechargeTask.push(market.sumRechargeTask / 100 || 0)
chartData.consumePermanent.push(market.sumConsumePermanent / 100 || 0)
chartData.consumeFree.push(market.sumConsumeFree / 100 || 0)
chartData.consumeTask.push(market.sumConsumeTask / 100 || 0)
chartData.sumConsume.push(market.sumConsume / 100 || 0)
//
sumRechargePermanent1.value += (market.sumRechargePermanent || 0)
sumRechargeFree1.value += (market.sumRechargeFree || 0)
//sumRechargeTask1.value += (market.sumRechargeTask || 0)
sumConsumePermanent1.value += (market.sumConsumePermanent || 0)
sumConsumeFree1.value += (market.sumConsumeFree || 0)
sumConsumeTask1.value += (market.sumConsumeTask || 0)
sumConsume1.value += (market.sumConsume || 0)
})
sumRechargePermanent.value = sumRechargePermanent1.value
sumRechargeFree.value = sumRechargeFree1.value
sumRechargeTask.value = 0
sumConsumePermanent.value = sumConsumePermanent1.value
sumConsumeFree.value = sumConsumeFree1.value
sumConsumeTask.value = sumConsumeTask1.value
sumConsume.value = sumConsume1.value
updateChart(chartData)
}
const processRankingData = (marketCards) => {
//
const rankingData = marketCards.map(market => {
let coinAmount = 0;
if (activeTab.value === 'recharge') {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumRechargePermanent / 100 || 0) + (market.sumRechargeFree / 100 || 0) + (market.sumRechargeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumRechargePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumRechargeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumRechargeTask / 100 || 0;
break;
}
} else {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumConsumePermanent / 100 || 0) + (market.sumConsumeFree / 100 || 0) + (market.sumConsumeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumConsumePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumConsumeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumConsumeTask / 100 || 0;
break;
}
}
return {
market: market.market,
coinAmount: coinAmount
};
});
//
rankingData.sort((a, b) => b.coinAmount - a.coinAmount);
//
tableData.value = rankingData.map((item, index) => ({
rank: index + 1,
...item
}));
}
watch(selectedType, () => {
getChartData();
});
//
const updateChart = (chartData) => {
if (!chartInstance) {
initChart()
}
chartLoading.value = true
try {
let series = []
let legend = []
if (activeTab.value === 'recharge') {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargePermanent,
itemStyle: {color: '#5470c6'},
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeFree,
itemStyle: {color: '#91cc75'},
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeTask,
itemStyle: {color: '#fac858'},
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
} else {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'consume',
data: chartData.consumePermanent,
itemStyle: {color: '#5470c6'},
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeFree,
itemStyle: {color: '#91cc75'},
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeTask,
itemStyle: {color: '#fac858'},
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
}
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
let result = params[0].name + '<br/>'
let total = 0;
params.forEach(param => {
result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`;
total += param.value;
})
result += `${activeTab.value === 'recharge' ? '充值' : '消费'}: ${total.toLocaleString()}`;
return result
}
},
legend: {
data: legend,
bottom: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
},
xAxis: {
type: 'category',
data: markets.value,
axisLabel: {
interval: 0,
rotate: 0
}
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
type: 'dashed',
width: 1,
color: '#000000'
}
},
axisLabel: {
formatter: function (value) {
return value.toLocaleString()
}
},
},
series: series,
// dataZoom: [
// {
// type: 'slider',
// show: true,
// start: 0,
// end: 100,
// maxSpan: 100,
// minSpan: 100,
//
// height: 2,
// },
// ]
}
chartInstance.setOption(option)
} catch (error) {
console.error('图表更新失败:', error)
ElMessage.error('图表渲染失败')
} finally {
setTimeout(() => {
chartLoading.value = false
}, 300)
}
}
//
const handleTabChange = () => {
getChartData()
console.log('标签切换调用图表')
}
const getAdminData = async function () {
try {
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
onMounted(async () => {
await getAdminData()
await getMarkets()
getYear()
window.addEventListener('resize', () => {
chartInstance.resize()
})
})
onUnmounted(() => {
destroyChart()
})
</script>
<style scoped lang="scss">
/* 整个柱状图的图表样式 */
.graph {
.condition {
width: 100%;
height: 1%;
display: flex;
align-items: center;
.stats {
display: flex;
align-items: center;
width: 35vw;
font-size: 15px;
}
}
.graph-content {
flex: 1;
height: auto;
display: flex;
.left {
width: 70%;
height: auto;
}
.right {
flex: 1;
padding: 0.5vw 2vh;
}
}
}
.card-item {
width: 25%;
height: 28vh;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 0.25vw;
}
.card-title {
font-weight: bold;
margin-bottom: 1vh;
display: flex;
justify-content: center;
align-items: center;
}
.card-large {
font-weight: bold;
font-size: 16px;
text-align: center;
margin-bottom: 15px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.graph-card {
background: #F3FAFF;
box-shadow: 0 0 8px 0 #00000040;
}
.graph-card-list {
background: #E7F4FD;
box-shadow: 0 0 8px 0 #00000040;
padding: 12px;
.card-select {
:deep(.el-select__wrapper) {
background-color: #E7F4FD !important;
// :hover {
// background-color: red !important;
// }
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25) !important;
border: none !important;
}
:deep(.el-select-dropdown__item.selected) {
// :hover { background-color: red !important; }
background: red !important;
}
}
/* 表格整体背景:把表格容器设为卡片背景 */
:deep(.el-table) {
background-color: #E7F4FD !important;
box-shadow: none !important;
}
/* 表头/表体 wrapper 与 table body 单元格 */
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__body tr),
:deep(.el-table__body td) {
background-color: transparent !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #E7F4FD !important;
}
/* 针对表格 body 中的单元格底部边框 */
:deep(.el-table__body .el-table__cell) {
border-bottom: 1px solid #BBC0C9 !important;
}
}
/* tabs的样式 */
/* 选中 tab 的文字颜色 */
:deep(.el-tabs__item.is-active) {
color: #2741DE !important;
font-size: 18px;
font-weight: bold;
}
</style>

818
src/components/workspace/GoldGraphMarkets.vue

@ -0,0 +1,818 @@
<!--各地区的金币充值和消费情况柱状图-->
<template>
<div class="graph">
<el-card style="width:100%;" class="graph-card">
<div>
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane label="金币充值" name="recharge"></el-tab-pane>
<el-tab-pane label="金币消费" name="consume"></el-tab-pane>
</el-tabs>
</div>
<div class="condition">
<div class="stats">
<div v-if="activeTab === 'consume'">合计{{ sumConsume / 100 }}</div>&nbsp;&nbsp;
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }}&nbsp;&nbsp;
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }}&nbsp;&nbsp;
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }}&nbsp;&nbsp;
</div>
<div>
<el-button @click="getYes()" size="small" :type="activeTimeRange === 'yes' ? 'primary' : ''">昨天
</el-button>
<el-button @click="getToday()" size="small" :type="activeTimeRange === 'today' ? 'primary' : ''">今天
</el-button>
<el-button @click="getWeek()" size="small" :type="activeTimeRange === 'week' ? 'primary' : ''">本周
</el-button>
<el-button @click="getMonth()" size="small" :type="activeTimeRange === 'month' ? 'primary' : ''">本月
</el-button>
<el-button @click="getYear()" size="small" :type="activeTimeRange === 'year' ? 'primary' : ''">本年
</el-button>
</div>
<div>
<el-date-picker size="small" v-model="dateRange" type="datetimerange" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
style="width:20vw;margin-left:0.5vw;" value-format="YYYY-MM-DD HH:mm:ss"
:default-time="defaultTime"
:disabled-date="disabledDate" @change="handleDatePickerChange"/>
<el-button type="primary" size="small" style="margin-left: 0.5vw" @click="getChartData">查询</el-button>
</div>
</div>
<div class="graph-content">
<div ref="chartRef" class="left"></div>
<div class="right">
<el-card class="graph-card-list">
<div class="card-large">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div>
<el-select class="card-select" v-model="selectedType" style="width: 100%; margin-bottom: 15px">
<el-option label="全部类型" value="all"></el-option>
<el-option label="永久金币" value="permanent"></el-option>
<el-option label="免费金币" value="free"></el-option>
<el-option label="任务金币" value="task"></el-option>
</el-select>
<el-table class="card-table" :data="tableData" height="320px">
<el-table-column prop="rank" label="排名" width="60" align="center"></el-table-column>
<el-table-column prop="market" label="地区" align="center">
<template #default="scope">
<span>{{ marketMapping[scope.row.market] || scope.row.market }}</span>
</template>
</el-table-column>
<el-table-column prop="coinAmount" label="金币数量" align="center">
<template #default="{ row }">
{{ row.coinAmount.toLocaleString() }}
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</div>
</el-card>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import {onMounted, onUnmounted, ref, watch} from 'vue'
import API from '@/util/http'
import {ElMessage} from 'element-plus'
import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc'
import {marketMapping} from "@/utils/marketMap.js";
dayjs.extend(utc)
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
//
const markets = ref([])
//
const dateRange = ref([])
const activeTab = ref('recharge')
const selectedType = ref('all')
const tableData = ref([])
const chartRef = ref(null)
let chartInstance = null
//
const sumRechargePermanent = ref(0)
const sumRechargeFree = ref(0)
const sumRechargeTask = ref(0)
const sumConsumePermanent = ref(0)
const sumConsumeFree = ref(0)
const sumConsumeTask = ref(0)
const sumConsume = ref(0)
//
const adminData = ref({})
//
const currentGold = ref(0)
const dailyChange = ref(0)
const currentPermanent = ref(0)
const currentFree = ref(0)
const currentFreeJune = ref(0)
const currentFreeDecember = ref(0)
const currentTask = ref(0)
const yearlyRecharge = ref(0)
const yearlyMoney = ref(0)
const recharge = ref(0)
const money = ref(0)
const yearlyReduce = ref(0)
const yearlyConsume = ref(0)
const yearlyRefund = ref(0)
const dailyReduce = ref(0)
const dailyConsume = ref(0)
const dailyRefund = ref(0)
const yearlyRechargeNum = ref(0)
const sumWow = ref(0)
const sumDaily = ref(0)
const rechargeNum = ref(0)
const ydayRechargeNum = ref(0)
const firstRecharge = ref(0)
const length = ref(0)
//
const chartLoading = ref(true)
const handleResize = () => {
if (chartInstance.value) {
try {
chartInstance.value.resize()
console.log('resize一下')
} catch (error) {
console.error('图表resize失败:', error)
}
}
}
//
const initChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
window.addEventListener('resize', handleResize)
}
}
//
const destroyChart = () => {
if (chartInstance.value) {
try {
chartInstance.value.dispose()
} catch (error) {
console.error('图表销毁失败:', error)
}
chartInstance.value = null
}
window.removeEventListener('resize', handleResize)
}
const formatDate = function (date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
//
const getYes = function () {
const yesterday = dayjs().subtract(1, 'day')
const startTime = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'yes' //
getChartData()
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'today' //
getChartData()
}
//
const getWeek = function () {
const today = dayjs();
// 01...6
const day = today.day();
// 6
let monday = today.subtract(day === 0 ? 6 : day - 1, 'day');
// (7 - day)
let sunday = today.add(day === 0 ? 0 : 7 - day, 'day');
//
const startTime = monday.startOf('day').format('YYYY-MM-DD HH:mm:ss');
const endTime = sunday.endOf('day').format('YYYY-MM-DD HH:mm:ss');
dateRange.value = [startTime, endTime];
console.log('本周时间范围(周一到周日):', dateRange.value);
activeTimeRange.value = 'week';
getChartData();
};
//
const getMonth = function () {
const today = dayjs()
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('month').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'month' //
getChartData()
}
//
const getYear = function () {
const today = dayjs()
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('year').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'year' //
getChartData()
}
// ( = + 6 + 12 + + )
const processData = (data) => {
const summary = {
currentGold: 0,
dailyChange: 0,
currentPermanent: 0,
currentFreeJune: 0,
currentFreeDecember: 0,
currentTask: 0,
currentFree: 0,
recharge: 0,
money: 0,
yearlyRecharge: 0,
yearlyMoney: 0,
consumePermanent: 0,
consumeFreeJune: 0,
consumeFreeDecember: 0,
consumeTask: 0,
refundPermanent: 0,
refundFreeJune: 0,
refundFreeDecember: 0,
refundTask: 0,
dailyReduce: 0,
yearlyConsume: 0,
yearlyRefund: 0,
yearlyReduce: 0,
rechargeNum: 0,
ydayRechargeNum: 0,
firstRecharge: 0,
sumWow: 0,
sumDaily: 0,
yearlyRechargeNum: 0
}
//
data.marketCards.forEach(market => {
for (const i in summary) {
if (market[i] !== undefined && market[i] !== null) { // number
summary[i] += market[i]
}
}
})
// wowdaily
length.value = data.markets.length
console.log(length.value)
// 退
const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
//
currentGold.value = summary.currentGold.toFixed(2)
dailyChange.value = summary.dailyChange.toFixed(2)
currentPermanent.value = summary.currentPermanent.toFixed(2)
currentFree.value = summary.currentFree.toFixed(2)
currentFreeJune.value = summary.currentFreeJune.toFixed(2)
currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
currentTask.value = summary.currentTask.toFixed(2)
yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
yearlyMoney.value = summary.yearlyMoney.toFixed(2)
recharge.value = summary.recharge.toFixed(2)
money.value = summary.money.toFixed(2)
yearlyReduce.value = summary.yearlyReduce.toFixed(2)
yearlyConsume.value = summary.yearlyConsume.toFixed(2)
yearlyRefund.value = summary.yearlyRefund.toFixed(2)
dailyReduce.value = summary.dailyReduce.toFixed(2)
dailyConsume.value = yesterdayConsume.toFixed(2)
dailyRefund.value = yesterdayRefund.toFixed(2)
yearlyRechargeNum.value = summary.yearlyRechargeNum
// //
// sumWow.value = (marketCards.sumWow / length.value).toFixed(2)
// //
// sumDaily.value = (marketCards.sumDaily / length.value).toFixed(2)
// rechargeNum.value = summary.rechargeNum
ydayRechargeNum.value = summary.ydayRechargeNum
firstRecharge.value = summary.firstRecharge
}
//
const disabledDate = (time) => {
const limitDate = new Date(2025, 0, 1);
return time.getTime() < limitDate.getTime();
}
//
const getMarkets = async () => {
console.log("adminData", adminData.value.account)
try {
const response = await API({
url: '/general/adminMarkets',
data: {
account: adminData.value.account
}
})
if (Array.isArray(response.data)) {
// markets.value = response.data.filter(data => data !== "1")
markets.value = response.data
console.log('市场列表获取成功:', markets.value)
} else {
console.error('获取市场列表失败', response)
ElMessage.error('获取市场列表失败')
}
} catch (error) {
console.error('获取市场列表失败:', error)
ElMessage.error('获取市场列表失败')
}
}
//
const getChartData = async () => {
try {
//
if (!markets.value || markets.value.length === 0) {
await getMarkets()
}
//
if (!dateRange.value || dateRange.value.length === 0) {
getYear()
}
const params = {
markets: markets.value,
startDate: dateRange.value[0],
endDate: dateRange.value[1]
};
const response = await API({
url: '/workbench/getGraph',
data: params
})
console.log('看看params', params)
if (Array.isArray(response.marketGraphs)) {
// const filteredGraphs = response.marketGraphs.filter(data => data.market !== "1");
//
processChartData(response.marketGraphs)
//
processRankingData(response.marketGraphs)
} else {
console.error('获取图表数据失败:', response)
ElMessage.error('获取图表数据失败')
}
} catch (error) {
console.error('获取图表数据失败:', error)
ElMessage.error('获取图表数据失败')
}
}
//
const processChartData = (marketCards) => {
const chartData = {
rechargePermanent: [],
rechargeFree: [],
rechargeTask: [],
consumePermanent: [],
consumeFree: [],
consumeTask: [],
sumConsume: []
}
//
const sumRechargePermanent1 = ref(0)
const sumRechargeFree1 = ref(0)
const sumRechargeTask1 = ref(0)
const sumConsumePermanent1 = ref(0)
const sumConsumeFree1 = ref(0)
const sumConsumeTask1 = ref(0)
const sumConsume1 = ref(0)
marketCards.forEach(market => {
chartData.rechargePermanent.push(market.sumRechargePermanent / 100 || 0)
chartData.rechargeFree.push(market.sumRechargeFree / 100 || 0)
chartData.rechargeTask.push(market.sumRechargeTask / 100 || 0)
chartData.consumePermanent.push(market.sumConsumePermanent / 100 || 0)
chartData.consumeFree.push(market.sumConsumeFree / 100 || 0)
chartData.consumeTask.push(market.sumConsumeTask / 100 || 0)
chartData.sumConsume.push(market.sumConsume / 100 || 0)
//
sumRechargePermanent1.value += (market.sumRechargePermanent || 0)
sumRechargeFree1.value += (market.sumRechargeFree || 0)
//sumRechargeTask1.value += (market.sumRechargeTask || 0)
sumConsumePermanent1.value += (market.sumConsumePermanent || 0)
sumConsumeFree1.value += (market.sumConsumeFree || 0)
sumConsumeTask1.value += (market.sumConsumeTask || 0)
sumConsume1.value += (market.sumConsume || 0)
})
sumRechargePermanent.value = sumRechargePermanent1.value
sumRechargeFree.value = sumRechargeFree1.value
sumRechargeTask.value = 0
sumConsumePermanent.value = sumConsumePermanent1.value
sumConsumeFree.value = sumConsumeFree1.value
sumConsumeTask.value = sumConsumeTask1.value
sumConsume.value = sumConsume1.value
updateChart(chartData)
}
const processRankingData = (marketCards) => {
//
const rankingData = marketCards.map(market => {
let coinAmount = 0;
if (activeTab.value === 'recharge') {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumRechargePermanent / 100 || 0) + (market.sumRechargeFree / 100 || 0) + (market.sumRechargeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumRechargePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumRechargeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumRechargeTask / 100 || 0;
break;
}
} else {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumConsumePermanent / 100 || 0) + (market.sumConsumeFree / 100 || 0) + (market.sumConsumeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumConsumePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumConsumeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumConsumeTask / 100 || 0;
break;
}
}
return {
market: market.market,
coinAmount: coinAmount
};
});
//
rankingData.sort((a, b) => b.coinAmount - a.coinAmount);
//
tableData.value = rankingData.map((item, index) => ({
rank: index + 1,
...item
}));
}
watch(selectedType, () => {
getChartData();
});
//
const updateChart = (chartData) => {
if (!chartInstance) {
initChart()
}
chartLoading.value = true
try {
let series = []
let legend = []
if (activeTab.value === 'recharge') {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargePermanent,
itemStyle: {color: '#5470c6'},
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeFree,
itemStyle: {color: '#91cc75'},
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeTask,
itemStyle: {color: '#fac858'},
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
} else {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'consume',
data: chartData.consumePermanent,
itemStyle: {color: '#5470c6'},
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeFree,
itemStyle: {color: '#91cc75'},
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeTask,
itemStyle: {color: '#fac858'},
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
}
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
let result = params[0].name + '<br/>'
let total = 0;
params.forEach(param => {
result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`;
total += param.value;
})
result += `${activeTab.value === 'recharge' ? '充值' : '消费'}: ${total.toLocaleString()}`;
return result
}
},
legend: {
data: legend,
bottom: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
},
xAxis: {
type: 'category',
//
data: markets.value,
axisLabel: {
interval: 0,
rotate: 0
}
},
yAxis: {
type: 'value',
splitLine: {
lineStyle: {
type: 'dashed',
width: 1,
color: '#000000'
}
},
axisLabel: {
formatter: function (value) {
return value.toLocaleString()
}
},
},
series: series,
// dataZoom: [
// {
// type: 'slider',
// show: true,
// start: 0,
// end: 100,
// maxSpan: 100,
// minSpan: 100,
//
// height: 2,
// },
// ]
}
chartInstance.setOption(option)
} catch (error) {
console.error('图表更新失败:', error)
ElMessage.error('图表渲染失败')
} finally {
setTimeout(() => {
chartLoading.value = false
}, 300)
}
}
//
const handleTabChange = () => {
getChartData()
console.log('标签切换调用图表')
}
const getAdminData = async function () {
try {
const result = await API({url: '/admin/userinfo', data: {}})
adminData.value = result
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
onMounted(async () => {
await getAdminData()
await getMarkets()
getYear()
window.addEventListener('resize', () => {
chartInstance.resize()
})
})
onUnmounted(() => {
destroyChart()
})
</script>
<style scoped lang="scss">
.graph {
.condition {
width: 100%;
height: 1%;
display: flex;
align-items: center;
.stats {
display: flex;
align-items: center;
width: 35vw;
font-size: 15px;
}
}
.graph-content {
flex: 1;
height: auto;
display: flex;
.left {
width: 70%;
height: auto;
}
.right {
flex: 1;
padding: 0.5vw 2vh;
}
}
}
.center-card {
display: flex;
justify-content: center;
align-items: center;
}
.margin-bottom {
margin-bottom: 0.5vh;
}
.card-item {
width: 25%;
height: 28vh;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 0.25vw;
}
.card-title {
font-weight: bold;
margin-bottom: 1vh;
display: flex;
justify-content: center;
align-items: center;
}
.card-large {
font-weight: bold;
font-size: 16px;
text-align: center;
margin-bottom: 15px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.graph-card {
background: #F3FAFF;
box-shadow: 0 0 8px 0 #00000040;
}
.graph-card-list {
background: #F3FAFF;
box-shadow: 0 0 8px 0 #00000040;
padding: 12px;
.card-select {
:deep(.el-input__wrapper) {
background-color: #E7F4FD !important;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.25) !important;
border: none !important;
}
:deep(.el-input__inner) {
background-color: transparent !important;
}
:deep(.el-input__suffix) {
background-color: transparent !important;
}
}
/* 表格整体背景:把表格容器设为卡片背景 */
:deep(.el-table) {
background-color: #F3FAFF !important;
box-shadow: none !important;
}
/* 表头/表体 wrapper 与 table body 单元格 */
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__body),
:deep(.el-table__header),
:deep(.el-table__body tbody),
:deep(.el-table__body tr),
:deep(.el-table__row),
:deep(.el-table__cell),
:deep(.el-table__body td) {
background-color: transparent !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFF !important;
}
/* 行之间的分隔线(更像卡片内表格) */
:deep(.el-table .el-table__row):not(:last-child) {
border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}
}
</style>

669
src/components/workspace/GoldManagement.vue

@ -0,0 +1,669 @@
<template>
<div class="gold-management">
<div class="gold-title">
<div class="text1">
金币管理
<span class="text1-update-time">最后更新时间{{
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
}} </span>
</div>
</div>
<!-- 第一行包含两个横向格子 -->
<el-row>
<el-col :span="12">
<!-- 第一个卡片 -->
<div class="card-item-row1">
<div class="card-title">当前金币余量
<span style="font-weight: bold">{{
currentGold / 100
}}</span>&nbsp;&nbsp;&nbsp;&nbsp;较前一日
{{ dailyChange / 100 }}&nbsp;
<template v-if="dailyChange > 0">
<el-image :src="upArrow" style="width: 14px;"/>
</template>
<template v-else-if="dailyChange < 0">
<el-image :src="downArrow" style="width: 14px;"/>
</template>
<template v-else>
<el-image :src="pingArrow" style="width: 14px; padding-top: 12px"/>
</template>
</div>
<div>
<el-row>
<!-- 左边文本信息 -->
<el-col :span="12">
<div class="margin-bottom" style="white-space: nowrap;">
永久金币<b>{{ currentPermanent / 100 }}</b>
</div>
<div class="margin-bottom">&nbsp;</div>
<div class="margin-bottom">免费金币{{ currentFree / 100 }}</div>
<!-- <div class="margin-bottom">&nbsp</div>-->
<!-- <div class="margin-bottom">&nbsp</div>-->
<div class="margin-bottom">
[6月到期{{ currentFreeJune / 100 }}]
</div>
<div class="margin-bottom">&nbsp;</div>
<div class="margin-bottom">任务金币{{ currentTask / 100 }}</div>
</el-col>
<!-- 右边图表 -->
<el-col :span="12">
<!-- <div ref="goldTypeChart" style="width: 100%; height: 100px;"></div>-->
<div style="width: 100%; height: 60px;">&nbsp;</div>
<div class="margin-bottom">
[12月到期{{ currentFreeDecember / 100 }}]
</div>
</el-col>
</el-row>
</div>
</div>
</el-col>
<el-col :span="12">
<!-- 第二个卡片 -->
<div class="card-item-row1">
<div class="card-title">全年累计充值金币数{{ yearlyRecharge / 100 }}</div>
<el-row>
<el-col :span="12">
<div class="center-card">折合新币累计金额</div>
<el-image :src="svg1" style="width: 68px; display: block;margin: 0 auto;"/>
<div class="center-card">{{ yearlyMoney / 100 }}新币</div>
</el-col>
<el-col :span="12" style="border-left: 2px solid #CFE6FE; height: 120px">
<div class="center-card" style="white-space: nowrap;">昨日新增金币{{ recharge / 100 }}</div>
<div ref="rechargeGoldChart" style="width: 68px; height: 68px; display: block;margin: 0 auto;"></div>
<div class="center-card" style="white-space: nowrap;">其中永久金币{{ money / 100 }}</div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
<!-- 第二行包含两个横向格子 -->
<el-row>
<el-col :span="12">
<!-- 第三个卡片 -->
<div class="card-item">
<div class="card-title">全年累计消费金币数{{ yearlyReduce / 100 }}</div>
<el-row style="height: 200px;">
<el-col :span="12">
<div ref="consumeChart" style="width:100%; height: 68%;"></div>
</el-col>
<el-col :span="12">
<div ref="consumeDetailChart" style="width: 100%; height: 88%;"></div>
</el-col>
</el-row>
</div>
</el-col>
<el-col :span="12">
<!-- 第四个卡片 -->
<div class="card-item">
<div class="card-title">全年累计充值人头数{{ yearlyRechargeNum }}</div>
<el-row style="height: 200px;">
<el-col :span="12" style="border-right: 2px solid #CFE6FE; height: 150px">
<div class="chart5">
<el-image :src="svg2" style="width: 68px; display: block;margin: 0 auto;"/>
<div class="margin-bottom">
<div style="display: flex; gap: 10px; font-size: 14px;">周同比{{ sumWow }}%
<el-image v-if="sumWow > 0" :src="upArrow" style="width: 10px;"/>
<el-image v-else-if="sumWow < 0" :src="downArrow" style="width: 10px;"/>
<el-image v-else :src="pingArrow" style="width: 10px;"/>
</div>
<div style="display: flex; gap: 10px; font-size: 14px;">
日环比{{ sumDaily }}%
<el-image v-if="sumDaily > 0" :src="upArrow" style="width: 10px;"/>
<el-image v-else-if="sumDaily < 0" :src="downArrow" style="width: 10px;"/>
<el-image v-else :src="pingArrow" style="width: 10px; "/>
</div>
</div>
</div>
</el-col>
<!-- 新增的环形图容器 -->
<el-col :span="12">
<div ref="rechargePeopleChart" style="width:100%; height: 68%;"></div>
</el-col>
</el-row>
</div>
</el-col>
</el-row>
</div>
</template>
<script setup>
import {onMounted, ref, nextTick} from 'vue'
import * as echarts from 'echarts'
import API from '@/util/http'
import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc'
import {ArrowDownBold, ArrowUpBold, SemiSelect} from '@element-plus/icons-vue'
import svg1 from '@/assets/SvgIcons/折合新币累计金额.svg'
import svg2 from '@/assets/SvgIcons/周同比.svg'
import upArrow from '@/assets/SvgIcons/上升箭头.svg'
import downArrow from '@/assets/SvgIcons/下降箭头.svg'
import pingArrow from '@/assets/SvgIcons/持平.svg'
dayjs.extend(utc)
//
const adminData = ref({})
//
const currentGold = ref(0)
const dailyChange = ref(0)
const currentPermanent = ref(0)
const currentFree = ref(0)
const currentFreeJune = ref(0)
const currentFreeDecember = ref(0)
const currentTask = ref(0)
const yearlyRecharge = ref(0)
const yearlyMoney = ref(0)
const recharge = ref(0)
const money = ref(0)
const yearlyReduce = ref(0)
const yearlyConsume = ref(0)
const yearlyRefund = ref(0)
const dailyReduce = ref(0)
const dailyConsume = ref(0)
const dailyRefund = ref(0)
const yearlyRechargeNum = ref(0)
const sumWow = ref(0)
const sumDaily = ref(0)
const rechargeNum = ref(0)
const ydayRechargeNum = ref(0)
const firstRecharge = ref(0)
const length = ref(0)
// ECharts
const goldTypeChart = ref(null)
const rechargeGoldChart = ref(null)
const consumeChart = ref(null)
const consumeDetailChart = ref(null)
const rechargePeopleChart = ref(null)
// ( = + 6 + 12 + + )
const processData = (data) => {
const summary = {
currentGold: 0,
dailyChange: 0,
currentPermanent: 0,
currentFreeJune: 0,
currentFreeDecember: 0,
currentTask: 0,
currentFree: 0,
recharge: 0,
money: 0,
yearlyRecharge: 0,
yearlyMoney: 0,
consumePermanent: 0,
consumeFreeJune: 0,
consumeFreeDecember: 0,
consumeTask: 0,
refundPermanent: 0,
refundFreeJune: 0,
refundFreeDecember: 0,
refundTask: 0,
dailyReduce: 0,
yearlyConsume: 0,
yearlyRefund: 0,
yearlyReduce: 0,
rechargeNum: 0,
ydayRechargeNum: 0,
firstRecharge: 0,
sumWow: 0,
sumDaily: 0,
yearlyRechargeNum: 0
}
//
data.marketCards.forEach(market => {
for (const i in summary) {
if (market[i] !== undefined && market[i] !== null) {
summary[i] += market[i]
}
}
})
// wowdaily
length.value = data.markets.length
console.log(length.value)
// 退
const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
//
currentGold.value = summary.currentGold.toFixed(2)
dailyChange.value = summary.dailyChange.toFixed(2)
currentPermanent.value = summary.currentPermanent.toFixed(2)
currentFree.value = summary.currentFree.toFixed(2)
currentFreeJune.value = summary.currentFreeJune.toFixed(2)
currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
currentTask.value = summary.currentTask.toFixed(2)
yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
yearlyMoney.value = summary.yearlyMoney.toFixed(2)
recharge.value = summary.recharge.toFixed(2)
money.value = summary.money.toFixed(2)
yearlyReduce.value = summary.yearlyReduce.toFixed(2)
yearlyConsume.value = summary.yearlyConsume.toFixed(2)
yearlyRefund.value = summary.yearlyRefund.toFixed(2)
dailyReduce.value = summary.dailyReduce.toFixed(2)
dailyConsume.value = yesterdayConsume.toFixed(2)
dailyRefund.value = yesterdayRefund.toFixed(2)
yearlyRechargeNum.value = summary.yearlyRechargeNum
ydayRechargeNum.value = summary.ydayRechargeNum
firstRecharge.value = summary.firstRecharge
//
nextTick(() => {
// initGoldTypeChart();
initRechargeGoldChart();
initConsumeChart();
initConsumeDetailChart();
initRechargePeopleChart();
});
}
//
/*
const initGoldTypeChart = () => {
const myChart = echarts.init(goldTypeChart.value);
const option = {
tooltip: {
trigger: 'item',
formatter: function (params) {
let realValue = 0
if (params.name === '永久金币') realValue = currentPermanent.value / 100
else if (params.name === '免费金币') realValue = (currentFreeJune.value / 100 + currentFreeDecember.value / 100)
else realValue = currentTask.value / 100
return `${params.name}: ${realValue}`
}
},
toolbox: {
show: true,
feature: {}
},
series: [
{
name: 'Nightingale Chart',
type: 'pie',
radius: ['0%', '100%'],
center: ['50%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 5
},
data: [
{value: Math.log(currentPermanent.value / 100 + 1), name: '永久金币'},
{value: Math.log((currentFreeJune.value / 100 + currentFreeDecember.value / 100) + 1), name: '免费金币'},
{value: Math.log(currentTask.value / 100 + 1), name: '任务金币'}
],
labelLine: {show: false},
label: {show: false}
}
]
};
myChart.setOption(option);
}
*/
//
const initRechargeGoldChart = () => {
const myChart = echarts.init(rechargeGoldChart.value);
const option = {
series: [
{
type: 'pie',
radius: ['60%', '85%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: recharge.value / 100,
itemStyle: {color: '#80aaff'}
}
]
},
{
type: 'pie',
radius: ['60%', '75%'],
startAngle: 180,
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: money.value / 100,
itemStyle: {color: '#f2c97d'}
},
{
value: (recharge.value / 100 - money.value / 100),
itemStyle: {color: 'transparent'}
}
]
}
]
};
myChart.setOption(option);
}
// 退
const initConsumeChart = () => {
const myChart = echarts.init(consumeChart.value);
const option = {
legend: {
orient: 'vertical',
left: '10%',
top: '85',
icon: 'circle',
iconSize: 5,
textSize: 12,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['30%', '45%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: yearlyConsume.value / 100,
name: '消耗:' + yearlyConsume.value / 100,
// name: '' + 1234567890,
itemStyle: {color: '#7DB7FA'}
},
{
value: yearlyRefund.value / 100,
name: '退款:' + yearlyRefund.value / 100,
itemStyle: {color: '#F7D47C'}
}
],
}
]
};
myChart.setOption(option);
};
//
const initConsumeDetailChart = () => {
const myChart = echarts.init(consumeDetailChart.value);
const option = {
//
legend: {
orient: 'vertical',
left: '20%',
top: '85',
icon: 'circle',
iconSize: 5,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['25%', '40%'],
center: ['50%', '25%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: dailyConsume.value / 100,
name: '昨日新增消费:' + dailyConsume.value / 100,
itemStyle: {color: '#65C9C9'}
}
]
},
{
type: 'pie',
radius: ['25%', '35%'],
center: ['50%', '25%'],
startAngle: 180,
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: dailyReduce.value / 100,
name: '昨日新增消耗:' + dailyReduce.value / 100,
// name: '' + 1234567890,
itemStyle: {color: '#9469D1'}
},
{
value: dailyRefund.value / 100,
name: '昨日新增退款:' + dailyRefund.value / 100,
itemStyle: {color: '#B8DB6E'}
}
]
}
]
};
myChart.setOption(option);
};
//
const initRechargePeopleChart = () => {
const myChart = echarts.init(rechargePeopleChart.value);
const option = {
legend: {
orient: 'vertical',
left: '20%',
top: '85',
icon: 'circle',
iconSize: 5,
textSize: 18,
itemWidth: 7,
itemHeight: 7,
},
series: [
{
type: 'pie',
radius: ['30%', '50%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: ydayRechargeNum.value,
name: '昨日充值人数:' + ydayRechargeNum.value,
itemStyle: {color: '#65C9C9'}
},
],
},
{
type: 'pie',
radius: ['30%', '45%'],
center: ['50%', '35%'],
silent: true,
clockwise: true,
label: {show: false},
data: [
{
value: firstRecharge.value,
name: '其中首充:' + firstRecharge.value,
itemStyle: {color: '#9469D1'}
},
{
value: ydayRechargeNum.value - firstRecharge.value,
itemStyle: {color: 'transparent'}
}
],
}
]
};
myChart.setOption(option);
}
//
const getCardData = async () => {
try {
const response = await API({url: '/workbench/getCard', data: {}})
workDataUpdateTime.value = response.updateTime
//
sumWow.value = response.sumWow.toFixed(2)
//
sumDaily.value = response.sumDaily.toFixed(2)
if (response && response.data) {
processData(response.data)
} else if (Array.isArray(response?.marketCards)) {
processData(response)
} else {
console.error('无效的API响应结构:', response)
}
} catch (error) {
console.error('获取卡片数据失败:', error)
}
}
const workDataUpdateTime = ref(null)
onMounted(async () => {
await getCardData()
})
</script>
<style scoped lang="scss">
.center-card {
display: flex;
justify-content: center;
align-items: center;
}
.card-item-row1 {
height: 160px;
width: auto;
background: #E4F0FC;
box-shadow: 0 0 4px 0 #00000040;
border-radius: 10px;
margin-top: 20px;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -5px;
padding-bottom: 10px;
}
.card-item {
height: 200px;
width: auto;
background: #E4F0FC;
box-shadow: 0 0 4px 0 #00000040;
border-radius: 10px;
margin-top: 20px;
margin-left: 5px;
margin-right: 5px;
margin-bottom: -5px;
padding-bottom: 10px;
}
.card-title {
font-weight: bold;
height: 36px;
width: 100%;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #C1DCF8 50%, #E4F0FC 100%);
box-shadow: 0 0 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
margin-top: -5px;
margin-bottom: 10px;
}
.card-item .el-col {
overflow: visible;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.gold-title {
width: 100%;
height: 5vh;
flex-shrink: 0;
border-radius: 8px;
background: linear-gradient(90deg, #E4F0FC 0%, #FFF178 50%, #E4F0FC 100%);
box-shadow: 0 2px 2px 0 #00152940;
display: flex;
align-items: center;
justify-content: center;
}
.text1 {
color: #040a2d;
font-family: " PingFang SC ";
font-size: 28px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
}
.text1-update-time {
width: 100%;
height: 26px;
flex-shrink: 0;
color: #040a2d;
font-family: "PingFang SC";
font-size: 20px;
font-style: normal;
font-weight: 700;
line-height: 31.79px;
}
/* 背景卡片大小 */
.gold-management {
margin: 10px 5px;
width: 100%;
height: 50vh;
flex-shrink: 0;
border-radius: 8px;
background: #E7F4FD;
box-shadow: 0 2px 2px 0 #00000040;
flex-direction: column;
align-items: center;
}
.margin-bottom {
padding-left: 20px;
}
.chart5 {
margin-top: 15px;
.margin-bottom {
margin-top: 10px;
padding-left: 20px;
}
}
</style>

26
src/router/index.js

@ -300,13 +300,33 @@ const routes = [
]
},
{
path:'moneyManage',
path:'/moneyManage',
name:'moneyManage',
meta:{permissionId:4},
children:[
// 收款明细
{
path: 'receiveDetail',
name: "receiveDetail",
component: () => import("../views/moneyManage/receiveDetail/receiveDetail.vue"),
meta: { permissionId: 74 }
},
// 退款明细
{
path: 'refundDetail',
name: "refundDetail",
component: () => import("../views/moneyManage/refundDetail/refundDetail.vue"),
meta: { permissionId: 75 }
},
// 执行明细
{
path: 'executor',
name: "executor",
component: () => import("../views/moneyManage/executor/executor.vue"),
meta: { permissionId: 76 }
},
]
},
// 没有权限
{
path: '/noPermission',

12
src/utils/menuTreePermission.js

@ -40,14 +40,14 @@ export const permissionMapping = {
rechargeReject:31, // 充值审核已驳回
rechargeWait:32, // 充值审核待审核
rechargeWaitShow:33, // 充值审核待审核查看
rechargeWaitThough:34, // 充值审核通过
rechargeWaitReject:35, // 充值审核驳回
rechargeWaitThough:34, // 充值审核等待通过
rechargeWaitReject:35, // 充值审核等待驳回
refundThrough:36, // 退款审核已通过
refundReject:37, // 退款审核已驳回
refundWait:38, // 退款审核待审核
refundWaitShow:39, // 退款审核待审核查看
refundWaitThough:40, // 退款审核通过
refundWaitReject:41, // 退款审核驳回
refundWaitThough:40, // 退款审核等待通过
refundWaitReject:41, // 退款审核等待驳回
beanWait:42, // 金豆审核待审核
beanThrough:43, // 金豆审核已通过
@ -88,6 +88,10 @@ export const permissionMapping = {
roleManageShow:73, // 查看角色信息
addRoleInfo:71, // 新增角色信息
editRoleInfo:72, // 编辑角色信息
receiveDetail:74, // 收款明细
refundDetail:75, // 退款明细
executor:76, // 执行人
}
// 递归查找菜单中是否存在目标id

4
src/utils/menuUtils.js

@ -78,6 +78,10 @@ export const getRoutePath = (menu) => {
'用户管理': '/permissions/userPermission',
'角色管理': '/permissions/rolePermission',
'收款明细': '/moneyManage/receiveDetail',
'退款明细': '/moneyManage/refundDetail',
'执行人': '/moneyManage/executor/executor',
};
// 未匹配的菜单默认使用id作为路由(可根据实际需求调整)

102
src/views/audit/bean/beanAudit.vue

@ -1,35 +1,47 @@
<template>
<el-card style="margin-bottom: 0.5vh;width:82vw">
<div style="margin-bottom: 1vh">
<el-text size="large">精网号</el-text>
<el-card class="card1" style="margin-bottom: 0.5vh;">
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
<el-text class="text" size="large">精网号</el-text>
<el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width: 12vw;margin-right:1vw" clearable />
<el-text size="large">所属地区</el-text>
</div>
<div class="selectRow">
<el-text class="text" size="large">所属地区</el-text>
<el-cascader v-model="selectedMarkets" :options="marketOptions" placeholder="请选择所属地区" clearable
style="width: 12vw" @change="handleMarketChange" />
</div>
</div>
</el-col>
<el-col>
<el-text size="large" style="width: 80px" v-show="checkTab === 'pending'">提交时间</el-text>
<el-text size="large" style="width: 80px" v-show="checkTab === 'reject' || checkTab === 'pass'">审核时间</el-text>
<div class="select">
<div class="selectRow" style="width: 36vw;">
<el-text class="text" size="large" v-show="checkTab === 'pending'">提交时间</el-text>
<el-text size="large" style="width: 25vw;margin-right:1vw"
v-show="checkTab === 'reject' || checkTab === 'pass'">审核时间</el-text>
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="" start-placeholder="开始时间"
end-placeholder="结束时间" style="width: 25vw;margin-right:1vw" @change="handleDatePickerChange"
:default-time="defaultTime" />
<el-button @click="getToday()" :type="activeTimeRange === 'today' ? 'primary' : ''"></el-button>
<el-button @click="getYesterday()" :type="activeTimeRange === 'yesterday' ? 'primary' : ''"></el-button>
<el-button @click="get7Days()" :type="activeTimeRange === '7days' ? 'primary' : ''">近7天</el-button>
</div>
<div class="selectRow" style="justify-content: flex-start;">
<el-button type="success" @click="resetSearch">重置</el-button>
<el-button type="primary" @click="handleSearch">查询</el-button>
</div>
</div>
</el-col>
</el-card>
<el-card >
<el-card class="card2">
<el-tabs v-model="checkTab" type="card" @tab-click="handleClick">
<el-tab-pane label="待审核" name="pending" v-if="hasbeanWait && hasbeanWaitShow"></el-tab-pane>
<el-tab-pane label="已通过" name="pass" v-if="hasbeanThrough"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject" v-if="hasbeanReject"></el-tab-pane>
</el-tabs>
<div>
<div class="goldStatistics">
总条数{{ format3(stats.num) }}&nbsp;&nbsp;&nbsp;&nbsp;
总金豆数{{ format3(stats.beanNum) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆{{ format3(stats.permanentBean) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
@ -61,7 +73,8 @@
{{ row.auditTime ? moment(row.auditTime).format('YYYY-MM-DD HH:mm:ss') : '--' }}
</template>
</el-table-column>
<el-table-column v-if="checkTab === 'pending' &&(hasbeanWaitThough||hasbeanWaitReject)" fixed="right" prop="operation" label="操作" width="400px">
<el-table-column v-if="checkTab === 'pending' && (hasbeanWaitThough || hasbeanWaitReject)" fixed="right"
prop="operation" label="操作" width="400px">
<template #default="scope">
<div class="operation">
<el-popconfirm title="确定要通过此条记录吗?" @confirm="handleApprove(scope.row)">
@ -77,7 +90,8 @@
</el-button>
</template>
</el-popconfirm>
<el-button v-if="hasbeanWaitReject" :disabled="clicked || cancelClicked" type="primary" text @click="showRejectDialog(scope.row)">
<el-button v-if="hasbeanWaitReject" :disabled="clicked || cancelClicked" type="primary" text
@click="showRejectDialog(scope.row)">
驳回
</el-button>
</div>
@ -515,4 +529,68 @@ onMounted(async () => {
})
</script>
<style scoped></style>
<style scoped lang="scss">
/* 搜索的卡片样式 */
.card1 {
background: #F3FAFE;
}
/* 表单的卡片样式 */
.card2 {
background: #E7F4FD;
}
/* 充值新币总数等等 */
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
/* 表头/表体 wrapper 与 table body 单元格 */
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.select {
display: flex;
.selectRow {
width: 17vw;
display: flex;
align-items: center;
justify-content: center;
padding: 0 0.5vw;
.text {
width: 5vw;
font-size: 15px;
}
.selectContent {
flex: 1;
}
}
}
</style>

49
src/views/audit/gold/rechargeAudit.vue

@ -1,5 +1,5 @@
<template>
<el-card style="margin-bottom: 0.5vh;">
<el-card class="card1" style="margin-bottom: 0.5vh;">
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
@ -47,12 +47,12 @@
</div>
</el-col>
</el-card>
<el-card>
<el-card class="card2">
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tab-pane label="待审核" name="wait" v-if="hasrechargeWait&&hasrechargeWaitShow"></el-tab-pane>
<el-tab-pane label="已通过" name="pass" v-if="hasrechargeThrough"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject" v-if="hasrechargeReject"></el-tab-pane>
<div>
<div class="goldStatistics">
<!-- 总条数{{ format3(stats.totalNum) }}&nbsp;&nbsp;&nbsp;&nbsp;-->
充值新币{{ format3(stats.permanentGolds) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
@ -715,7 +715,7 @@ onMounted(async function () {
})
</script>
<style scoped>
<style scoped lang="scss">
.pagination {
display: flex;
margin-top: 0.5vh;
@ -725,6 +725,47 @@ onMounted(async function () {
display: flex;
}
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.select {
display: flex;

49
src/views/audit/gold/refundAudit.vue

@ -1,5 +1,5 @@
<template>
<el-card style="margin-bottom: 0.5vh;">
<el-card class="card1" style="margin-bottom: 0.5vh;">
<el-col style="margin-bottom: 1vh">
<div class="select">
<div class="selectRow">
@ -49,14 +49,14 @@
</el-col>
</el-card>
<el-card >
<el-card class="card2">
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tab-pane label="待审核" name="wait" v-if="hasrefundWait&&hasrefundWaitShow"></el-tab-pane>
<el-tab-pane label="已通过" name="pass" v-if="hasrefundThrough"></el-tab-pane>
<el-tab-pane label="已驳回" name="reject" v-if="hasrefundReject"></el-tab-pane>
</el-tabs>
<div>
<div class="goldStatistics">
退款总金币数{{ format3((stats.permanentGolds + stats.freeGolds + stats.taskGolds).toFixed(2))
}}金币&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(stats.permanentGolds.toFixed(2)) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
@ -629,7 +629,7 @@ onMounted(async () => {
})
</script>
<style scoped>
<style scoped lang="scss">
.pagination {
display: flex;
margin-top: 0.5vh;
@ -639,6 +639,47 @@ onMounted(async () => {
display: flex;
}
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.select {
display: flex;

51
src/views/consume/bean/articleVideo.vue

@ -463,7 +463,7 @@ const getTagText = (state) => {
</script>
<template>
<el-card style="margin-bottom: 1vh">
<el-card class="card1" style="margin-bottom: 1vh">
<el-col style="margin-bottom: 1vh; ">
<div style="display:flex">
<div style="width: 13vw; display:flex; align-items:center; justify-content: center;">
@ -516,8 +516,8 @@ const getTagText = (state) => {
</div>
</el-col>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
@ -600,7 +600,50 @@ const getTagText = (state) => {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;

51
src/views/consume/bean/dieHardFan.vue

@ -468,7 +468,7 @@ const getTagText = (state) => {
</script>
<template>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<el-col style="margin-bottom: 10px">
<el-text>精网号</el-text>
<el-input v-model="beanConsumeFan.jwcode" placeholder="请输入精网号" style="width: 200px;margin-right: 20px"
@ -499,8 +499,8 @@ const getTagText = (state) => {
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
</el-col>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
@ -573,7 +573,50 @@ const getTagText = (state) => {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;

51
src/views/consume/bean/liveStream.vue

@ -502,7 +502,7 @@ const getTagText = (state) => {
</script>
<template>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<div style="margin-bottom: 1vh;display: flex;">
<div style="width: 18vw;margin-right: 1vw;display: flex;align-items: center;">
<el-text>精网号</el-text>
@ -550,8 +550,8 @@ const getTagText = (state) => {
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(Math.abs(permanentBean + freeBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(Math.abs(permanentBean)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(Math.abs(freeBean)) }}
@ -623,7 +623,50 @@ const getTagText = (state) => {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
margin-top: 20px;

52
src/views/consume/gold/coinConsumeDetail.vue

@ -562,7 +562,7 @@ const getMarket = async function () {
</script>
<template>
<el-card style="margin-bottom: 0.5vh;">
<el-card class="card1" style="margin-bottom: 0.5vh;">
<div style="width:82vw;margin-bottom: 1vh;">
<el-text>精网号</el-text>
<el-input v-model="consumeUser.jwcode" placeholder="请输入精网号" style="width: 10vw;margin-right: 1vw;" clearable />
@ -605,8 +605,8 @@ const getMarket = async function () {
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
消耗新币{{ format3(Math.abs(permanentGolds)) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
总金币数{{ format3(Math.abs(permanentGolds + freeGolds + taskGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(Math.abs(permanentGolds)) }}&nbsp;&nbsp;&nbsp;&nbsp;
@ -713,7 +713,7 @@ const getMarket = async function () {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
.status {
display: flex;
}
@ -734,4 +734,48 @@ const getMarket = async function () {
display: flex;
margin-top: 1vh;
}
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
</style>

264
src/views/home.vue

@ -8,6 +8,8 @@ import ChangePassword from '@/components/changePassword.vue'
import { useAdminStore } from '@/store'
import { storeToRefs } from 'pinia'
import { filterMenu, getRoutePath } from "@/utils/menuUtils.js";
import SettingsIcon from '@/assets/blue.png';
//
const menuList = ref([])
@ -46,6 +48,10 @@ function findBestMatch(menuList, path) {
return bestMatch || path // fallback
}
// require
//
const activeMenu = computed(() => {
return findBestMatch(menuList.value, route.path)
@ -93,38 +99,55 @@ function logout() {
</script>
<template>
<div>
<el-container>
<el-aside >
<div class="main-container">
<!-- 背景毛玻璃层作为内容容器 -->
<div class="background-glass">
<!-- 侧边栏 -->
<div class="sidebar-container">
<el-aside class="sidebar-layout">
<div class="logo">
<img src="../assets/新logo.png" alt="logo" style="width: 9vh; height: 9vh" />
</div>
<div class="menu-scroll-container">
<el-menu :router="true" :default-active="activeMenu" style="min-height: 80vh;border:none;">
<!-- 递归渲染菜单层级 -->
<template v-for="menu in menuList" :key="menu.id">
<!-- 有子菜单的父级菜单menuType=2 且存在children -->
<el-sub-menu v-if="menu.children && menu.children.length > 0" :index="menu.id.toString()">
<template #title>
<el-icon>
<Folder />
</el-icon>
<img
:src="`/src/assets/SvgIcons/${menu.menuName}.svg`"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</template>
<!-- 子菜单 -->
<template v-for="child in menu.children" :key="child.id">
<!-- 子菜单为叶子节点无children -->
<el-menu-item v-if="!child.children || child.children.length === 0" :index="getRoutePath(child)">
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<span>{{ child.menuName }}</span>
</el-menu-item>
<!-- 子菜单有下级 -->
<el-sub-menu v-else :index="child.id.toString()">
<template #title>
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<span>{{ child.menuName }}</span>
</template>
<!-- 递归 下一级-->
<template v-for="grandChild in child.children" :key="grandChild.id">
<el-menu-item :index="getRoutePath(grandChild)">
<el-icon style="margin-right: 4px;">
<Folder />
</el-icon>
<span>{{ grandChild.menuName }}</span>
</el-menu-item>
</template>
@ -134,34 +157,54 @@ function logout() {
<!-- 无子菜单的一级菜单 -->
<el-menu-item v-else :index="getRoutePath(menu)">
<el-icon>
<Folder />
</el-icon>
<img
:src="`@/assets/SvgIcons/${menu.menuName}.svg`"
:alt="`${menu.menuName}图标`"
style="width: 4vh; height: 4vh; margin-right: 4px;"
>
<span>{{ menu.menuName }}</span>
</el-menu-item>
</template>
</el-menu>
</div>
<!-- 底部固定的设置中心 -->
<div class="settings-container">
<el-dropdown placement="top-start">
<span class="el-dropdown-link">
<img src="@/assets/SvgIcons/设置.svg" alt="设置" style="width: 4vh; height: 4vh" />
<span>设置中心</span>
<el-icon class="arrow-icon">
<ArrowUp />
</el-icon>
</span>
<template #dropdown>
<el-dropdown-menu>
<el-dropdown-item @click="message()">查看个人信息</el-dropdown-item>
<el-dropdown-item @click="openChangePassword">修改密码</el-dropdown-item>
<el-dropdown-item @click="logout">退出登录</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
</el-aside>
<el-container style="margin-left: 15vw;">
</div>
<!-- 右侧内容区域 -->
<div class="content-container">
<!-- 头部
<el-header class="header">
<el-menu class="el-menu-demo" mode="horizontal" :ellipsis="false">
<el-sub-menu index="1">
<template #title>
<el-image :src="imgrule1" style="width: 50px; height: 50px" />
<span style="margin-left: 10px">{{ adminData.name }}</span>
</template>
<el-menu-item @click="message()">查看个人信息</el-menu-item>
<el-menu-item @click="openChangePassword">修改密码</el-menu-item>
<el-menu-item @click="logout">退出登录</el-menu-item>
</el-sub-menu>
</el-menu>
</el-header>
<el-main style="margin-top: 6vh;height: auto;">
</el-header> -->
<!-- 主内容区域 -->
<div class="main-area">
<el-main>
<router-view></router-view>
</el-main>
</el-container>
</el-container>
</div>
</div>
</div>
<!-- 查看个人信息 -->
<el-dialog v-model="messageVisible" title="查看个人信息" width="500px">
@ -194,36 +237,173 @@ function logout() {
</template>
<style scoped>
.header {
/* 主容器,设置背景图并居中 */
.main-container {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 80;
background: white;
height: 8vh;
bottom: 0;
background-image: url('@/assets/backgroundBlue.png');
background-size: cover;
background-position: center center;
background-repeat: no-repeat;
overflow: hidden;
}
.message-font {
font-size: 16px;
font-weight: bold;
/* 背景毛玻璃层(作为内容容器) */
.background-glass {
position: absolute;
top: 1vh;
left: 1vh;
right: 1vh;
bottom: 1vh;
background-image: url('@/assets/半透明background.png');
background-size: cover;
z-index: 1;
display: flex;
flex-direction: row;
padding: 10px;
border-radius: 12px;
}
.el-aside {
width: 15vw;
position: fixed;
z-index: 100;
height: 90vh;
}
/* 侧边栏容器 */
.sidebar-container {
flex-shrink: 0;
}
.logo {
display: flex;
align-items: center;
justify-content: center;
height: 12vh;
}
/* 中间可滚动菜单容器 */
.menu-scroll-container {
flex: 1;
overflow-y: auto;
padding: 10px 0;
}
/* 底部设置中心样式 */
.settings-container {
padding: 10px 0 10px 20px; /* 上,右, 下,左 */
display: flex;
align-items: center; /* 垂直居中 */
}
/* 调整下拉菜单的样式,确保它向上弹出 */
.el-dropdown-link:focus {
/* 移除底部的异常效果 */
outline: none;
text-decoration: none;
}
.el-dropdown-link {
display: flex;
align-items: center;
cursor: pointer;
gap:10px; /* 图标和文字左右间距 */
}
.sidebar-layout {
width: 15vw;
height: 100%;
background: #E7F4FD; /* 浅蓝色背景 */
/* backdrop-filter: blur(5px); 毛玻璃效果 --消耗性能 */
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1); /* 添加阴影增强层次感 */
border-radius: 12px;
display: flex;
flex-direction: column;
position: relative;
transition: all 0.3s ease;
}
/* 内容区域容器 */
.content-container {
flex: 1;
display: flex;
flex-direction: column;
margin-left: 5px;
gap: 5px;
height: 100%;
overflow: hidden;
}
/* 主内容区域容器 */
.main-area {
flex: 1;
background: #E7F4FD;
/* 半透明浅色背景 */
/* backdrop-filter: blur(5px); */
/* 毛玻璃效果 */
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
/* 添加阴影增强层次感 */
overflow: hidden;
display: flex;
flex-direction: column;
}
/* 主内容区域样式 */
.el-main {
height: 100%;
padding: 20px;
background: transparent;
overflow-y: auto;
/* 应用自定义滚动条 */
}
/* 确保el-menu撑满容器 */
.sidebar-layout .el-menu {
width: 100%;
}
/* 侧边栏菜单样式 适配浅色背景 */
.el-menu {
background: transparent !important;
}
/* 工作台,金币管理,现金管理 */
::v-deep(.el-sub-menu__title:hover),
::v-deep(.el-menu-item:hover) {
background: #E5EBFE;
}
/* 子菜单展开时和背景同色 */
::v-deep(.el-sub-menu__title),
::v-deep(.el-menu-item) {
background: #E7F4FD;
}
.message-font {
/* 个人信息字体样式 */
font-size: 16px;
font-weight: bold;
}
/* 确保全局el-container适应容器 */
:deep(.el-container) {
/* vue3的深度选择器,用于覆盖element-plus的默认样式 */
min-height: 100%;
width: 100%;
background: transparent;
}
.el-menu-demo {
border: none;
padding: 0;
float: right;
/* 为侧边栏和主内容区域添加滚动条样式 */
.menu-scroll-container,
.el-main {
scrollbar-width: thin;
/* Firefox */
scrollbar-color: rgba(0, 0, 0, 0.3) rgba(255, 255, 255, 0.2);
/* Firefox滑块和轨道颜色 */
}
</style>

2
src/views/moneyManage/executor/executor.vue

@ -0,0 +1,2 @@
<template></template>
<script setup></script>

1244
src/views/moneyManage/receiveDetail/receiveDetail.vue
File diff suppressed because it is too large
View File

471
src/views/moneyManage/refundDetail/refundDetail.vue

@ -0,0 +1,471 @@
<template>
<el-card style="margin-bottom: 0.5vh;">
<div class="condition1">
<div class="condition-item">
<el-text size="large" style="width:4vw;">精网号</el-text>
<el-input v-model="searchForm.jwcode" placeholder="请输入精网号" style="width:10vw;" clearable />
</div>
<div class="condition-item">
<el-text size="large" style="width:4vw;">客户姓名</el-text>
<el-input v-model="searchForm.username" placeholder="请输入客户姓名" style="width:10vw;" clearable />
</div>
<div class="condition-item">
<el-text size="large" style="width:4vw;">所属地区</el-text>
<el-input v-model="searchForm.area" placeholder="请输入所属地区" style="width:10vw;" clearable />
</div>
<div class="condition-item">
<el-text size="large" style="width:4vw;">提交人</el-text>
<el-input v-model="searchForm.adminName" placeholder="请输入提交人" style="width:10vw;" clearable />
</div>
<div class="condition-item">
<el-text size="large" style="width:4vw;">支付方式</el-text>
<el-select v-model="searchForm.payType" style="width:10vw;">
<el-option v-for="item in payments" :key="item" :label="item" :value="item" />
</el-select>
</div>
</div>
<div class="condition1">
<div class="condition-item2">
<el-text size="large" style="width:4vw;">活动名称</el-text>
<el-input v-model="searchForm.activity" placeholder="请输入活动名称" style="width:10vw;" clearable />
</div>
<div class="condition-item2">
<el-text size="large" style="width:4vw;">产品名称</el-text>
<el-input v-model="searchForm.productName" placeholder="请输入产品名称" style="width:10vw;" clearable />
</div>
<div class="condition-item2" style="width: 30vw;">
<el-text size="large" style="width:4vw;">付款时间</el-text>
<el-date-picker v-model="dateRange" type="datetimerange" range-separator="" start-placeholder="起始时间"
end-placeholder="结束时间" style="width:22vw;" @change="handleDatePickerChange"
:disabled-date="disabledDate" />
</div>
<div>
<el-button type="success">重置</el-button>
<el-button type="primary">查询</el-button>
<el-button type="primary">导出excel</el-button>
<el-button type="primary">导出列表</el-button>
</div>
</div>
</el-card>
<div style="display: flex;">
<el-button type="primary" @click="showAdd = true">新增收款</el-button>
<el-button type="primary" @click="showAudit1 = true">新增收款</el-button>
<el-button type="primary" @click="showAudit2 = true">新增收款</el-button>
</div>
<el-card style="margin-top: 0.5vh;">
<el-table :data="tableData" style="height:64vh;width:82vw">
<el-table-column type="index" label="序号" width="60" fixed="left" />
<el-table-column prop="name" label="Homily ID" width="120" fixed="left" />
<el-table-column prop="jwcode" label="姓名" width="120" fixed="left" show-overflow-tooltip />
<el-table-column prop="market" label="所属地区" width="120" />
<el-table-column prop="orderCode" label="活动名称" width="120px" show-overflow-tooltip />
<el-table-column prop="refundType" label="产品名称" width="120" />
<el-table-column prop="refundType" label="退款类型" width="120" />
<el-table-column prop="refundType" label="提交人" width="120" />
<el-table-column prop="refundType" label="退款理由" width="120" />
<el-table-column prop="refundType" label="付款币种" width="120" />
<el-table-column prop="refundType" label="付款金额" width="120" />
<el-table-column prop="refundType" label="支付方式" width="120" />
<el-table-column prop="refundType" label="付款时间" width="120" />
<el-table-column prop="refundType" label="转账凭证" width="120" />
<el-table-column prop="remark" label="备注" width="150" show-overflow-tooltip />
<el-table-column prop="adminName" label="订单状态" width="120" />
<el-table-column prop="operation" label="操作" fixed="right" width="150px">
<template #default="scope">
<div class="operation">
<el-popconfirm title="确定要通过此条记录吗?" @confirm="handleApprove(scope.row)">
<template #reference>
<el-button v-if="hasrefundWaitThough" :disabled="clicked || cancelClicked"
type="primary" text>
通过
</el-button>
</template>
<template #actions="{ confirm, cancel }">
<el-button size="small" @click="cancel">取消</el-button>
<el-button type="primary" size="small" :disabled="clicked" @click="confirm">
确认
</el-button>
</template>
</el-popconfirm>
<el-button v-if="hasrefundWaitReject" :disabled="clicked || cancelClicked" type="primary" text
@click="showRejectDialog(scope.row)">
驳回
</el-button>
</div>
</template>
</el-table-column>
</el-table>
<el-pagination v-model:current-page="pagination.pageNum" v-model:page-size="pagination.pageSize"
layout="total, sizes, prev, pager, next, jumper" :total="pagination.total"
@size-change="handlePageSizeChange" @current-change="handleCurrentChange"
style="margin-top: 1vh;"></el-pagination>
</el-card>
<el-dialog v-model="showAdd" title="退款" class="addDialog" overflow draggable style="width: 40vw;">
<div style="display: flex;">
<div class="left">
<div class="dialog-item">
<el-text style="width:4vw;">精网号</el-text>
<el-input v-model="addForm.jwcode" placeholder="请输入精网号" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">客户姓名</el-text>
<el-input v-model="addForm.name" placeholder="请输入客户姓名" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">所属地区</el-text>
<el-input v-model="addForm.market" placeholder="请输入所属地区" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">活动名称</el-text>
<el-input v-model="addForm.orderCode" placeholder="请输入活动名称" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">产品名称</el-text>
<el-select v-model="addForm.refundType" placeholder="请选择产品名称" style="width:10vw;" clearable>
<el-option v-for="item in products" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="dialog-item">
<el-text style="width:4vw;">付款金额</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">付款币种</el-text>
<el-select v-model="addForm.refundCurrency" placeholder="请选择付款币种" style="width:10vw;" clearable>
<el-option v-for="item in currencies" :key="item.value" :label="item.label"
:value="item.value" />
</el-select>
</div>
<div class="dialog-item">
<el-text style="width:4vw;">支付方式</el-text>
<el-select v-model="addForm.paymentMethod" placeholder="请选择支付方式" style="width:10vw;">
<el-option v-for="item in payments" :key="item.value" :label="item.label" :value="item.value" />
</el-select>
</div>
<div class="dialog-item">
<el-text style="width:4vw;">转账凭证</el-text>
<el-form-item :rules="{ required: true, message: '请上传图片', trigger: 'change' }">
<el-upload ref="uploadRef" list-type="picture-card" :auto-upload="false"
:http-request="customUpload" :on-change="handleImageChange"
:on-success="handleUploadSuccess" :on-error="handleUploadError"
:before-upload="beforeUpload" :show-file-list="false">
<template #default>
<img v-if="addForm.imageUrl" :src="addForm.imageUrl"
style="width: 100%; height: 100%; object-fit: cover;">
<el-icon v-else>
<Plus />
</el-icon>
</template>
</el-upload>
</el-form-item>
</div>
<div class="dialog-item">
<el-text style="width:4vw;">备注</el-text>
<el-input v-model="addForm.remark" placeholder="请输入备注" style="width:10vw;" clearable />
</div>
</div>
<div class="right">
<div class="dialog-item">
<el-text style="width:4vw;">退款模式</el-text>
<el-radio-group v-model="addForm.refundMode">
<el-radio value="1">全部退款</el-radio>
<el-radio value="2">部分退款</el-radio>
</el-radio-group>
</div>
<div class="dialog-item">
<el-text style="width:4vw;">退款理由</el-text>
<el-input v-model="addForm.refundReason" placeholder="请输入退款理由" style="width:10vw;" :rows="5"
maxlength="100" show-word-limit type="textarea" />
</div>
<div style="display:flex;justify-content: center;margin-top: 5vh;">
<el-button type="primary" @click="">重置</el-button>
<el-button type="primary" @click="">提交</el-button>
</div>
</div>
</div>
</el-dialog>
<el-dialog v-model="showAudit1" title="审核" overflow draggable width="20vw">
<div class="audit1">
<div class="dialog-item">
<el-text style="width:4vw;">精网号</el-text>
<el-input v-model="addForm.jwcode" placeholder="请输入精网号" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">姓名</el-text>
<el-input v-model="addForm.name" placeholder="请输入客户姓名" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">所属地区</el-text>
<el-input v-model="addForm.market" placeholder="请输入所属地区" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">活动名称</el-text>
<el-input v-model="addForm.orderCode" placeholder="请输入活动名称" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">商品名称</el-text>
<el-input v-model="addForm.orderCode" placeholder="请输入活动名称" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">付款币种</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">付款金额</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">支付方式</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">付款时间</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
<div class="dialog-item">
<el-text style="width:4vw;">银行流水订单号</el-text>
<el-input v-model="addForm.refundAmount" placeholder="请输入付款金额" style="width:10vw;" clearable />
</div>
</div>
<div style="display:flex;justify-content: center;">
<el-button type="primary" @click="">驳回</el-button>
<el-button type="primary" @click="">通过</el-button>
</div>
</el-dialog>
<el-dialog v-model="showAudit2" title="审核">
<el-button type="primary" @click="">驳回</el-button>
</el-dialog>
</template>
<script setup>
import { ref } from 'vue'
import { ElMessage } from 'element-plus'
import API from '@/util/http.js'
const uploadUrl = 'https://api.homilychart.com/hljw/api/aws/upload'
const searchForm = ref({
jwcode: ''
})
const addForm = ref({
jwcode: ''
})
const pagination = ref({
pageNum: 1,
pageSize: 50,
total: 0
})
const tableData = ref([])
const showAdd = ref(false)
const showAudit1 = ref(false)
const showAudit2 = ref(false)
const uploadRef = ref(null)
const products = ref([
{
value: '1',
label: '产品1'
},
{
value: '2',
label: '产品2'
}
])
const currencies = ref([
{
value: 'CNY',
label: '人民币'
},
{
value: 'USD',
label: '美元'
}
])
const payments = ref([{
value: '银行转账',
label: '银行转账'
},
{
value: '现金',
label: '现金'
},
{
value: '支票',
label: '支票'
},
{
value: '刷卡',
label: '刷卡'
},
{
value: 'Grabpay',
label: 'Grabpay'
},
{
value: 'Nets',
label: 'Nets'
},
{
value: 'PayPal',
label: 'PayPal'
},
{
value: 'Stripe-链接收款',
label: 'Stripe-链接收款'
},
{
value: 'Ipay88-链接收款',
label: 'Ipay88-链接收款'
},
{
value: 'PaymentAsia-链接收款',
label: 'PaymentAsia-链接收款'
},
{
value: 'Stripe-Link平台',
label: 'Stripe-Link平台'
},
{
value: 'PaymentAsia-Link平台',
label: 'PaymentAsia-Link平台'
},
{
value: 'FirstData-Link平台-Link平台',
label: 'FirstData-Link平台-Link平台'
},
{
value: 'IOS-Link平台',
label: 'IOS-Link平台'
},
{
value: 'Ipay88-Link平台',
label: 'Ipay88-Link平台'
}
])
const handleImageChange = (file) => {
uploadRef.value.submit()
}
const beforeUpload = (file) => {
const isJPG = file.type === 'image/jpeg'
const isPNG = file.type === 'image/png'
const isLt1 = file.size / 1024 < 1024
if (!isJPG && !isPNG) {
ElMessage.error('上传图片只能是 JPG 或 PNG 格式')
return false
}
if (!isLt1) {
ElMessage.error('上传图片大小不能超过1MB')
return false
}
return true
}
const handleUploadSuccess = (response, file, fileList) => {
try {
addForm.value.imageUrl = response.data.url
console.log('==========================', response.data.url)
} catch (error) {
console.log('看看报错信息', error)
ElMessage.error(response.data.msg || '图片上传失败')
}
}
const handleUploadError = (error) => {
console.error('上传失败:', error)
addForm.value.imageUrl = null
ElMessage.error('图片上传失败,请重试')
}
const customUpload = async (options) => {
try {
const formData = new FormData()
formData.append('file', options.file)
const response = await API({
url: uploadUrl,
method: 'POST',
data: formData,
headers: {
'Content-Type': 'multipart/form-data'
}
})
if (response.code === 200 && response.data) {
handleUploadSuccess(response, options.file, [options.file])
ElMessage.success(response.msg || '上传成功')
} else {
ElMessage.error(response.msg || '上传失败')
}
} catch (error) {
console.error('上传错误:', error)
ElMessage.error(`上传失败: ${error.msg || error.message || '网络异常'}`)
}
}
</script>
<style scoped lang="scss">
.condition1 {
width: 82vw;
display: flex;
height: 4vh;
.condition-item {
width: 19%;
display: flex;
align-items: center;
margin-bottom: 1vh;
margin-right: 0.5vw;
}
.condition-item2 {
width: 19%;
display: flex;
align-items: center;
margin-right: 0.5vw;
}
}
.addDialog {
.left {
width: 50%;
height: 60vh;
.dialog-item {
display: flex;
align-items: center;
margin-bottom: 1vh;
}
}
.right {
width: 50%;
height: 50vh;
.dialog-item {
display: flex;
align-items: center;
margin-bottom: 1vh;
}
}
}
.audit1 {
height: 47vh;
.dialog-item {
display: flex;
align-items: center;
margin-bottom: 1vh;
}
.audit-btn {
display: flex;
justify-content: center;
align-items: center;
}
}
.audit2{
}
</style>

39
src/views/permissions/rolePermission.vue

@ -586,7 +586,7 @@ onMounted(async function () {
</script>
<template>
<div>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<div style="display: flex;">
<el-text size="large">角色名称</el-text>
<el-input v-model="role.name" style="width: 240px" placeholder="请输入角色名称" clearable />
@ -597,7 +597,7 @@ onMounted(async function () {
</div>
</el-card>
<el-card>
<el-card class="card2">
<div class="add-item">
<el-button style="color: #048efb; border: 1px solid #048efb" @click="permissionAddInit()" :disabled="!canAdd" v-if="canAdd">新增角色</el-button>
</div>
@ -739,7 +739,40 @@ onMounted(async function () {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.head-card {
display: flex;
}

37
src/views/permissions/userPermission.vue

@ -910,7 +910,7 @@ onMounted(async function () {
<template>
<div>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<div class="head-card">
<div class="head-card-element">
<el-text class="mx-1" size="large">OA号</el-text>
@ -935,7 +935,7 @@ onMounted(async function () {
</div>
</div>
</el-card>
<el-card>
<el-card class="card2">
<!-- 展示表单 -->
<div class="add-item">
<el-button style="color: #048efb; border: 1px solid #048efb" :disabled="!canAdd" v-if="canAdd" @click="userAddInit()">新增用户</el-button>
@ -1168,7 +1168,38 @@ onMounted(async function () {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
}

2
src/views/recharge/bean/addBeanRecharge.vue

@ -247,7 +247,7 @@ const handleAddForm = async () => {
</div>
</div>
</template>
<style scoped>
<style scoped lang="scss">
.userAndform {
width: 80vw;
height: 80vh;

52
src/views/recharge/bean/beanOnlineRecharge.vue

@ -349,7 +349,7 @@ onMounted(async function () {
})
</script>
<template>
<el-card style="margin-bottom: 0.5vh;">
<el-card class="card1" style="margin-bottom: 0.5vh;">
<div>
<el-text size="large">精网号</el-text>
<el-input v-model="selectData.jwcode" placeholder="请输入精网号" style="width: 10vw;margin-right: 1vw;" clearable />
@ -385,8 +385,8 @@ onMounted(async function () {
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
充值金豆数{{ format3(num) }}&nbsp;&nbsp;&nbsp;&nbsp;合计新币数{{ format3(money) }}
</div>
<!-- 设置表格容器的高度和滚动样式 -->
@ -459,4 +459,48 @@ onMounted(async function () {
</template>
</el-dialog>
</template>
<style scoped></style>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
</style>

54
src/views/recharge/bean/beanSystemRecharge.vue

@ -335,7 +335,7 @@ onMounted(async function () {
})
</script>
<template>
<el-card class="condition">
<el-card class="card1" style="margin-bottom: 0.5vh">
<div>
<el-text size="large">精网号</el-text>
<el-input v-model="selectData.jwcode" placeholder="请输入精网号" style="width: 9vw;margin-right:1vw" clearable />
@ -366,8 +366,8 @@ onMounted(async function () {
<el-button type="primary" style="width: 95px;" @click="openExportList">查看导出列表</el-button>
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金豆总数{{ format3(beanNum) }}&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(permanentBeans) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(freeBean) }}
@ -434,12 +434,56 @@ onMounted(async function () {
</template>
</el-dialog>
</template>
<style scoped>
.condition {
<style scoped lang="scss">
/* .condition {
height: 6vw;
margin-bottom: 0.5vh;
display: flex;
justify-content: space-between;
align-items: center;
} */
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
</style>

24
src/views/recharge/gold/addCoinRecharge.vue

@ -6,9 +6,9 @@ import axios from 'axios'
import API from '@/util/http.js'
import moment from 'moment'
import Cookies from 'js-cookie';
import Decimal from 'decimal.js';
// fixedAdminId
// const fixedAdminId = 1;
import Decimal from 'decimal.js';
//
const trimJwCode = () => {
@ -95,8 +95,6 @@ const add = async function () {
}
if (formattedRecharge.money) {
formattedRecharge.money = new Decimal(formattedRecharge.money).mul(100).toNumber();
// formattedRecharge.money = Number(formattedRecharge.money) * 100;
}
if (formattedRecharge.payTime) {
@ -597,13 +595,13 @@ const payModel = [
]
// // }
// function handleActivityChange(value) {
// //
// console.log('', value)
// // getActivityById(value)
// console.log('', recharge.value)
// }
function handleActivityChange(value) {
//
console.log('选中的值:', value)
// getActivityById(value)
console.log('看看', recharge.value)
}
//
const deleteRecharge = function () {
@ -919,10 +917,10 @@ p {
margin: 0px;
}
.batch-btn {
margin-top: 20px;
margin-left: auto;
}
// .batch-btn {
// margin-top: 20px;
// margin-left: auto;
// }
.field-label {
font-size: 14px;

50
src/views/recharge/gold/coinRechargeDetail.vue

@ -586,7 +586,7 @@ const getTagText = (state) => {
</script>
<template>
<el-card style="margin-bottom: 0.5vh">
<el-card class="card1" style="margin-bottom: 0.5vh">
<div style="margin-bottom: 0.5vh;">
<el-text size="large">精网号</el-text>
<el-input v-model="rechargeUser.jwcode" placeholder="请输入精网号" style="width: 10vw;margin-right: 1vw;" clearable />
@ -628,8 +628,8 @@ const getTagText = (state) => {
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
充值新币{{ format3(permanentGolds) }}新币&nbsp;&nbsp;&nbsp;&nbsp;
总金币数{{ format3(permanentGolds + freeGolds) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(permanentGolds) }}金币&nbsp;&nbsp;&nbsp;&nbsp;
@ -712,5 +712,47 @@ const getTagText = (state) => {
</template>
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
</style>

51
src/views/refund/gold/coinRefundDetail.vue

@ -499,7 +499,7 @@ const getMarket = async function () {
</script>
<template>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<div class="condition">
<div style="display: flex;align-items: center;width:18vw">
<el-text>精网号</el-text>
@ -552,8 +552,8 @@ const getMarket = async function () {
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
退款金币总数{{ format3(Math.abs(sumGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(Math.abs(permanentGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(Math.abs(freeGolds).toFixed(2)) }}&nbsp;&nbsp;&nbsp;&nbsp;
@ -637,7 +637,50 @@ const getMarket = async function () {
</el-dialog>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.condition{
display: flex;
width:82vw;

51
src/views/usergold/bean/userbean.vue

@ -1,5 +1,5 @@
<template>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<el-text size="large">精网号</el-text>
<el-input v-model="searchObj.jwcode" placeholder="请输入精网号" style="width: 240px" clearable />
<el-text size="large" style="margin-left:20px">地区</el-text>
@ -13,8 +13,8 @@
</div>
</el-card>
<el-card>
<div class="stats-card">
<el-card class="card2">
<div class="goldStatistics">
现有金豆数{{ format3(stats.sumBean) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
付费金豆数{{ format3(stats.permanentBean) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
免费金豆数{{ format3(stats.freeBean) }}金豆&nbsp;&nbsp;&nbsp;&nbsp;
@ -188,5 +188,48 @@ onMounted(() => {
})
</script>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
</style>

64
src/views/usergold/gold/clientCountBalance.vue

@ -382,7 +382,7 @@ const format3 = (num) => {
</script>
<template>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<div class="head-card">
<div class="head-card-element">
<el-text class="mx-1" size="large">精网号</el-text>
@ -390,14 +390,8 @@ const format3 = (num) => {
</div>
<div class="head-card-element">
<el-text class="mx-1" size="large">所属地区</el-text>
<el-cascader
v-model="selectedMarketPath"
:options="markets"
placeholder="请选择所属地区"
clearable
style="width:180px"
@change="handleMarketChange"
/>
<el-cascader v-model="selectedMarketPath" :options="markets" placeholder="请选择所属地区" clearable style="width:180px"
@change="handleMarketChange" />
</div>
<div class="head-card-element">
<el-checkbox v-model="showEmployeeData" @change="search()">员工数据</el-checkbox>
@ -409,8 +403,8 @@ const format3 = (num) => {
</div>
<!-- </div> -->
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金币总数{{ format3(goldtotal || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(permanentGold || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(freeGold || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
@ -418,7 +412,7 @@ const format3 = (num) => {
</div>
<!-- 设置表格容器的高度和滚动样式 -->
<div style="height: 60vh; overflow-y: auto">
<el-table :data="tableData" @cellClick="cellClick" style="width: 82vw;"height="60vh"
<el-table :data="tableData" @cellClick="cellClick" style="width: 82vw; height:60vh"
@sort-change="handleSortChange">
<el-table-column type="index" label="序号" width="100px" fixed="left">
<template #default="scope">
@ -512,8 +506,7 @@ const format3 = (num) => {
<!-- 分页 -->
<div class="pagination" style="margin-top: 20px">
<el-pagination background :page-size="getObj.pageSize" :page-sizes="[5, 10, 20, 50, 100]"
layout="total, sizes, prev, pager, next, jumper" :total="total"
@size-change="handlePageSizeChange"
layout="total, sizes, prev, pager, next, jumper" :total="total" @size-change="handlePageSizeChange"
@current-change="handleCurrentChange"></el-pagination>
</div>
</el-card>
@ -551,6 +544,49 @@ const format3 = (num) => {
</template>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.pagination {
display: flex;
}

51
src/views/usergold/gold/clientCountDetail.vue

@ -460,7 +460,7 @@ const format3 = (num) => {
</script>
<template>
<div>
<el-card style="margin-bottom: 1vh;">
<el-card class="card1" style="margin-bottom: 1vh;">
<el-row style="margin-bottom: 10px">
<el-col :span="5">
<div class="head-card-element">
@ -526,8 +526,8 @@ const format3 = (num) => {
<el-button type="primary" @click="openExportList">查看导出列表</el-button>
</div>
</el-card>
<el-card>
<div>
<el-card class="card2">
<div class="goldStatistics">
金币净变化{{ format3(totalGoldTotal || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
永久金币{{ format3(totalPermanentGold || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
免费金币{{ format3(totalFreeGold || 0) }}&nbsp;&nbsp;&nbsp;&nbsp;
@ -631,7 +631,50 @@ const format3 = (num) => {
</div>
</template>
<style scoped>
<style scoped lang="scss">
//
.card1 {
background: #F3FAFE;
}
//
.card2 {
background: #E7F4FD;
}
//
.goldStatistics {
margin-left: 1vw;
margin-bottom: 1vh;
color: #000000;
font-family: "PingFang SC";
font-size: 16px;
font-style: normal;
font-weight: 700;
line-height: 20px;
}
//
:deep(.el-table__header-wrapper),
:deep(.el-table__body-wrapper),
:deep(.el-table__cell),
/* 表格 */
:deep(.el-table__body td) {
background-color: #F3FAFE !important;
}
/* 表头 */
:deep(.el-table__header th) {
background-color: #F3FAFE !important;
}
/* 鼠标悬停 */
:deep(.el-table__row:hover > .el-table__cell) {
background-color: #E5EBFE !important;
}
.dialog-footer {
display: flex;
justify-content: flex-end;

929
src/views/workspace/index.vue

@ -1,911 +1,68 @@
<template>
<div class="top">
<el-card style="width:10vw" class="center-card">数据总览</el-card>
<span class="text">
最后更新时间{{
workDataUpdateTime && workDataUpdateTime !== '1970-01-01 08:00:00' ? workDataUpdateTime : '该地区暂无数据'
}}
</span>
</div>
<div class="card">
<!-- 第一个卡片 -->
<el-card class="card-item">
<template #header>
<div class="card-title">当前金币余量</div>
<div>
<span style="font-weight: bold">{{ currentGold / 100
}}</span>&nbsp;&nbsp;&nbsp;&nbsp;较前一日
{{ dailyChange / 100 }}
<template v-if="dailyChange > 0">
<el-icon style="color:red">
<ArrowUpBold />
</el-icon>
</template>
<template v-else-if="dailyChange < 0">
<el-icon style="color:forestgreen">
<ArrowDownBold />
</el-icon>
</template>
<template v-else>
<el-icon style="color:grey">
<SemiSelect />
</el-icon>
</template>
</div>
</template>
<div>
<div class="margin-bottom">永久金币{{ currentPermanent / 100 }}</div>
<div class="margin-bottom">免费金币{{ currentFree / 100 }}</div>
<div class="margin-bottom">[六月到期|{{ currentFreeJune / 100 }}]&nbsp;&nbsp;
[十二月到期|{{ currentFreeDecember / 100 }}]
</div>
<div>任务金币{{ currentTask / 100 }}</div>
</div>
</el-card>
<!-- 第二个卡片 -->
<el-card class="card-item">
<div class="card-title">全年累计充值金币数</div>
<div class="card-title">{{ yearlyRecharge / 100 }}</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</div>
<div class="center-card">折合新币累计金额:{{ yearlyMoney / 100 }}</div>
<template #footer>
<el-col class="margin-bottom center-card">昨日新增金币{{ recharge / 100 }}</el-col>
<el-col class="margin-bottom center-card">其中永久金币{{ money / 100 }}</el-col>
</template>
</el-card>
<!-- 第三个卡片 -->
<el-card class="card-item">
<div class="card-title">全年累计消费金币数</div>
<div class="card-title">{{ yearlyReduce / 100 }}</div>
<div style="padding-left: 30%;">消耗{{ yearlyConsume / 100 }}</div>
<div style="padding-left: 30%;">退款{{ yearlyRefund / 100 }}</div>
<template #footer>
<div style="margin-bottom:0.5%;padding-left: 30%;">昨日新增消费{{ dailyConsume / 100 }}</div>
<div style="margin-bottom:0.5%;padding-left: 30%;">昨日新增消耗{{ dailyReduce / 100 }}</div>
<div style="margin-bottom:0.5%;padding-left: 30%;">昨日新增退款{{ dailyRefund / 100 }}</div>
</template>
</el-card>
<!-- 第四个卡片 -->
<el-card class="card-item">
<el-col class="card-title">全年累计充值人头数</el-col>
<el-col class="card-title">{{ yearlyRechargeNum }}</el-col>
<el-col style="padding-left: 35%;">周同比:{{ sumWow }}%&nbsp;&nbsp;&nbsp;&nbsp;
<template v-if="sumWow > 0">
<el-icon style="color:red">
<ArrowUpBold />
</el-icon>
</template>
<template v-else-if="sumWow < 0">
<el-icon style="color:forestgreen">
<ArrowDownBold />
</el-icon>
</template>
<template v-else>
<el-icon style="color:grey">
<SemiSelect />
</el-icon>
</template>
<!-- 头部 -->
<el-header class="header">
<div class="title">数据总览</div>
</el-header>
<div style="height: 100vh;">
<el-row class="cards" >
<el-col :span="14">
<GoldManagement/>
</el-col>
<el-col style="padding-left: 35%;">日环比:{{ sumDaily }}%&nbsp;&nbsp;&nbsp;&nbsp;
<template v-if="sumDaily > 0">
<el-icon style="color:red">
<ArrowUpBold />
</el-icon>
</template>
<template v-else-if="sumDaily < 0">
<el-icon style="color:forestgreen">
<ArrowDownBold />
</el-icon>
</template>
<template v-else>
<el-icon style="color:grey">
<SemiSelect />
</el-icon>
</template>
<!-- 右上格子占12列 -->
<el-col :span="10">
<CashManagement />
</el-col>
<template #footer>
<el-col style="padding-left: 35%;margin-bottom:0.5%">昨日充值人数{{ ydayRechargeNum }}</el-col>
<el-col style="padding-left: 35%;">其中首充{{ firstRecharge }}</el-col>
</template>
</el-card>
</div>
<div class="graph">
<el-card style="width:84vw;">
<div>
<el-tabs v-model="activeTab" @tab-change="handleTabChange">
<el-tab-pane label="金币充值" name="recharge"></el-tab-pane>
<el-tab-pane label="金币消费" name="consume"></el-tab-pane>
</el-tabs>
</div>
<div class="condition">
<div class="stats">
<div v-if="activeTab === 'consume'">合计{{ sumConsume / 100 }}</div>&nbsp;&nbsp;
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }}&nbsp;&nbsp;
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }}&nbsp;&nbsp;
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }}&nbsp;&nbsp;
</div>
<div>
<el-button @click="getYes()" size="small" :type="activeTimeRange === 'yes' ? 'primary' : ''">昨天
</el-button>
<el-button @click="getToday()" size="small" :type="activeTimeRange === 'today' ? 'primary' : ''">今天
</el-button>
<el-button @click="getWeek()" size="small" :type="activeTimeRange === 'week' ? 'primary' : ''">本周
</el-button>
<el-button @click="getMonth()" size="small" :type="activeTimeRange === 'month' ? 'primary' : ''">本月
</el-button>
<el-button @click="getYear()" size="small" :type="activeTimeRange === 'year' ? 'primary' : ''">本年
</el-button>
</div>
<div>
<el-date-picker size="small" v-model="dateRange" type="datetimerange" range-separator=""
start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss"
style="width:20vw;margin-left:0.5vw;" value-format="YYYY-MM-DD HH:mm:ss" :default-time="defaultTime"
:disabled-date="disabledDate" @change="handleDatePickerChange" />
<el-button type="primary" size="small" style="margin-left: 0.5vw" @click="getChartData">查询</el-button>
</div>
</div>
<div class="graph-content">
<div ref="chartRef" class="left"></div>
<div class="right">
<el-card>
<div class="card-large">金币{{ activeTab === 'recharge' ? '充值' : '消费' }}排名</div>
<el-select v-model="selectedType" style="width: 100%; margin-bottom: 15px">
<el-option label="全部类型" value="all"></el-option>
<el-option label="永久金币" value="permanent"></el-option>
<el-option label="免费金币" value="free"></el-option>
<el-option label="任务金币" value="task"></el-option>
</el-select>
<el-table :data="tableData" height="320px">
<el-table-column prop="rank" label="排名" width="60" align="center"></el-table-column>
<el-table-column prop="market" label="地区" align="center">
<template #default="scope">
<span>{{ marketMapping[scope.row.market] || scope.row.market }}</span>
</template>
</el-table-column>
<el-table-column prop="coinAmount" label="金币数量" align="center">
<template #default="{ row }">
{{ row.coinAmount.toLocaleString() }}
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</div>
</el-card>
</el-row>
<el-row class="graphs">
<el-col :span="24">
<GoldGraph/>
</el-col>
</el-row>
</div>
</template>
<script setup>
import * as echarts from 'echarts'
import { ref, onMounted, nextTick, watch, onUnmounted } from 'vue'
import { ref, onMounted } from 'vue'
import API from '@/util/http'
import { ElMessage } from 'element-plus'
import dayjs from 'dayjs';
import utc from 'dayjs-plugin-utc'
import weekday from 'dayjs/plugin/weekday'
dayjs.extend(utc)
import { ArrowUpBold, ArrowDownBold, SemiSelect } from '@element-plus/icons-vue'
import { marketMapping } from "@/utils/marketMap.js";
const defaultTime = [
new Date(2000, 1, 1, 0, 0, 0),
new Date(2000, 2, 1, 23, 59, 59),
]
//
const markets = ref([])
//
const dateRange = ref([])
const activeTab = ref('recharge')
const selectedType = ref('all')
const tableData = ref([])
const chartRef = ref(null)
let chartInstance = null
//
const sumRechargePermanent = ref(0)
const sumRechargeFree = ref(0)
const sumRechargeTask = ref(0)
const sumConsumePermanent = ref(0)
const sumConsumeFree = ref(0)
const sumConsumeTask = ref(0)
const sumConsume = ref(0)
//
const adminData = ref({})
//
const currentGold = ref(0)
const dailyChange = ref(0)
const currentPermanent = ref(0)
const currentFree = ref(0)
const currentFreeJune = ref(0)
const currentFreeDecember = ref(0)
const currentTask = ref(0)
const yearlyRecharge = ref(0)
const yearlyMoney = ref(0)
const recharge = ref(0)
const money = ref(0)
const yearlyReduce = ref(0)
const yearlyConsume = ref(0)
const yearlyRefund = ref(0)
const dailyReduce = ref(0)
const dailyConsume = ref(0)
const dailyRefund = ref(0)
const yearlyRechargeNum = ref(0)
const sumWow = ref(0)
const sumDaily = ref(0)
const rechargeNum = ref(0)
const ydayRechargeNum = ref(0)
const firstRecharge = ref(0)
const length = ref(0)
//
const chartLoading = ref(true)
const handleResize = () => {
if (chartInstance.value) {
try {
chartInstance.value.resize()
console.log('resize一下')
} catch (error) {
console.error('图表resize失败:', error)
}
}
}
//
const initChart = () => {
if (!chartInstance && chartRef.value) {
chartInstance = echarts.init(chartRef.value)
window.addEventListener('resize', handleResize)
}
}
//
const destroyChart = () => {
if (chartInstance.value) {
try {
chartInstance.value.dispose()
} catch (error) {
console.error('图表销毁失败:', error)
}
chartInstance.value = null
}
window.removeEventListener('resize', handleResize)
}
const formatDate = function (date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}
//
const getYes = function () {
const yesterday = dayjs().subtract(1, 'day')
const startTime = yesterday.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = yesterday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'yes' //
getChartData()
}
//
const getToday = function () {
const today = dayjs()
const startTime = today.startOf('day').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('day').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'day').startOf('day').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'today' //
getChartData()
}
//
const getWeek = function () {
const today = dayjs();
// 01...6
const day = today.day();
// 6
let monday = today.subtract(day === 0 ? 6 : day - 1, 'day');
// (7 - day)
let sunday = today.add(day === 0 ? 0 : 7 - day, 'day');
//
const startTime = monday.startOf('day').format('YYYY-MM-DD HH:mm:ss');
const endTime = sunday.endOf('day').format('YYYY-MM-DD HH:mm:ss');
dateRange.value = [startTime, endTime];
console.log('本周时间范围(周一到周日):', dateRange.value);
activeTimeRange.value = 'week';
getChartData();
};
//
const getMonth = function () {
const today = dayjs()
const startTime = today.startOf('month').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'month').startOf('month').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('month').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'month' //
getChartData()
}
//
const getYear = function () {
const today = dayjs()
const startTime = today.startOf('year').format('YYYY-MM-DD HH:mm:ss')
const endTime = today.endOf('year').format('YYYY-MM-DD HH:mm:ss')
// const endTime = today.add(1, 'year').startOf('year').format('YYYY-MM-DD HH:mm:ss')
dateRange.value = [startTime, endTime]
console.log('看看dateRange', dateRange.value)
activeTimeRange.value = 'year' //
getChartData()
}
// ( = + 6 + 12 + + )
const processData = (data) => {
const summary = {
currentGold: 0,
dailyChange: 0,
currentPermanent: 0,
currentFreeJune: 0,
currentFreeDecember: 0,
currentTask: 0,
currentFree: 0,
recharge: 0,
money: 0,
yearlyRecharge: 0,
yearlyMoney: 0,
consumePermanent: 0,
consumeFreeJune: 0,
consumeFreeDecember: 0,
consumeTask: 0,
refundPermanent: 0,
refundFreeJune: 0,
refundFreeDecember: 0,
refundTask: 0,
dailyReduce: 0,
yearlyConsume: 0,
yearlyRefund: 0,
yearlyReduce: 0,
rechargeNum: 0,
ydayRechargeNum: 0,
firstRecharge: 0,
sumWow: 0,
sumDaily: 0,
yearlyRechargeNum: 0
}
//
data.marketCards.forEach(market => {
for (const i in summary) {
if (market[i] !== undefined && market[i] !== null) { // number
summary[i] += market[i]
}
}
})
// wowdaily
length.value = data.markets.length
console.log(length.value)
// 退
const yesterdayConsume = summary.consumePermanent + summary.consumeFreeJune + summary.consumeFreeDecember + summary.consumeTask
const yesterdayRefund = summary.refundPermanent + summary.refundFreeJune + summary.refundFreeDecember + summary.refundTask
//
currentGold.value = summary.currentGold.toFixed(2)
dailyChange.value = summary.dailyChange.toFixed(2)
currentPermanent.value = summary.currentPermanent.toFixed(2)
currentFree.value = summary.currentFree.toFixed(2)
currentFreeJune.value = summary.currentFreeJune.toFixed(2)
currentFreeDecember.value = summary.currentFreeDecember.toFixed(2)
currentTask.value = summary.currentTask.toFixed(2)
yearlyRecharge.value = summary.yearlyRecharge.toFixed(2)
yearlyMoney.value = summary.yearlyMoney.toFixed(2)
recharge.value = summary.recharge.toFixed(2)
money.value = summary.money.toFixed(2)
yearlyReduce.value = summary.yearlyReduce.toFixed(2)
yearlyConsume.value = summary.yearlyConsume.toFixed(2)
yearlyRefund.value = summary.yearlyRefund.toFixed(2)
dailyReduce.value = summary.dailyReduce.toFixed(2)
dailyConsume.value = yesterdayConsume.toFixed(2)
dailyRefund.value = yesterdayRefund.toFixed(2)
yearlyRechargeNum.value = summary.yearlyRechargeNum
// //
// sumWow.value = (marketCards.sumWow / length.value).toFixed(2)
// //
// sumDaily.value = (marketCards.sumDaily / length.value).toFixed(2)
// rechargeNum.value = summary.rechargeNum
ydayRechargeNum.value = summary.ydayRechargeNum
firstRecharge.value = summary.firstRecharge
}
//
const disabledDate = (time) => {
const limitDate = new Date(2025, 0, 1);
return time.getTime() < limitDate.getTime();
}
//
const getMarkets = async () => {
console.log("adminData", adminData.value.account)
try {
const response = await API({
url: '/general/adminMarkets',
data: {
account: adminData.value.account
}
})
if (Array.isArray(response.data)) {
// markets.value = response.data.filter(data => data !== "1")
markets.value = response.data
console.log('市场列表获取成功:', markets.value)
} else {
console.error('获取市场列表失败', response)
ElMessage.error('获取市场列表失败')
}
} catch (error) {
console.error('获取市场列表失败:', error)
ElMessage.error('获取市场列表失败')
}
}
//
const getChartData = async () => {
try {
//
if (!markets.value || markets.value.length === 0) {
await getMarkets()
}
//
if (!dateRange.value || dateRange.value.length === 0) {
getYear()
}
const params = {
markets: markets.value,
startDate: dateRange.value[0],
endDate: dateRange.value[1]
};
const response = await API({
url: '/workbench/getGraph',
data: params
})
console.log('看看params', params)
if (Array.isArray(response.marketGraphs)) {
// const filteredGraphs = response.marketGraphs.filter(data => data.market !== "1");
//
processChartData(response.marketGraphs)
//
processRankingData(response.marketGraphs)
} else {
console.error('获取图表数据失败:', response)
ElMessage.error('获取图表数据失败')
}
} catch (error) {
console.error('获取图表数据失败:', error)
ElMessage.error('获取图表数据失败')
}
}
//
const processChartData = (marketCards) => {
const chartData = {
rechargePermanent: [],
rechargeFree: [],
rechargeTask: [],
consumePermanent: [],
consumeFree: [],
consumeTask: [],
sumConsume: []
}
//
const sumRechargePermanent1 = ref(0)
const sumRechargeFree1 = ref(0)
const sumRechargeTask1 = ref(0)
const sumConsumePermanent1 = ref(0)
const sumConsumeFree1 = ref(0)
const sumConsumeTask1 = ref(0)
const sumConsume1 = ref(0)
marketCards.forEach(market => {
chartData.rechargePermanent.push(market.sumRechargePermanent / 100 || 0)
chartData.rechargeFree.push(market.sumRechargeFree / 100 || 0)
chartData.rechargeTask.push(market.sumRechargeTask / 100 || 0)
chartData.consumePermanent.push(market.sumConsumePermanent / 100 || 0)
chartData.consumeFree.push(market.sumConsumeFree / 100 || 0)
chartData.consumeTask.push(market.sumConsumeTask / 100 || 0)
chartData.sumConsume.push(market.sumConsume / 100 || 0)
//
sumRechargePermanent1.value += (market.sumRechargePermanent || 0)
sumRechargeFree1.value += (market.sumRechargeFree || 0)
//sumRechargeTask1.value += (market.sumRechargeTask || 0)
sumConsumePermanent1.value += (market.sumConsumePermanent || 0)
sumConsumeFree1.value += (market.sumConsumeFree || 0)
sumConsumeTask1.value += (market.sumConsumeTask || 0)
sumConsume1.value += (market.sumConsume || 0)
})
sumRechargePermanent.value = sumRechargePermanent1.value
sumRechargeFree.value = sumRechargeFree1.value
sumRechargeTask.value = 0
sumConsumePermanent.value = sumConsumePermanent1.value
sumConsumeFree.value = sumConsumeFree1.value
sumConsumeTask.value = sumConsumeTask1.value
sumConsume.value = sumConsume1.value
updateChart(chartData)
}
const processRankingData = (marketCards) => {
//
const rankingData = marketCards.map(market => {
let coinAmount = 0;
if (activeTab.value === 'recharge') {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumRechargePermanent / 100 || 0) + (market.sumRechargeFree / 100 || 0) + (market.sumRechargeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumRechargePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumRechargeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumRechargeTask / 100 || 0;
break;
}
} else {
//
switch (selectedType.value) {
case 'all':
coinAmount = (market.sumConsumePermanent / 100 || 0) + (market.sumConsumeFree / 100 || 0) + (market.sumConsumeTask / 100 || 0);
break;
case 'permanent':
coinAmount = market.sumConsumePermanent / 100 || 0;
break;
case 'free':
coinAmount = market.sumConsumeFree / 100 || 0;
break;
case 'task':
coinAmount = market.sumConsumeTask / 100 || 0;
break;
}
}
return {
market: market.market,
coinAmount: coinAmount
};
});
//
rankingData.sort((a, b) => b.coinAmount - a.coinAmount);
//
tableData.value = rankingData.map((item, index) => ({
rank: index + 1,
...item
}));
}
watch(selectedType, () => {
getChartData();
});
//
const updateChart = (chartData) => {
if (!chartInstance) {
initChart()
}
chartLoading.value = true
try {
let series = []
let legend = []
if (activeTab.value === 'recharge') {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargePermanent,
itemStyle: { color: '#5470c6' },
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeFree,
itemStyle: { color: '#91cc75' },
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'recharge',
data: chartData.rechargeTask,
itemStyle: { color: '#fac858' },
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
} else {
series = [
{
name: '永久金币',
type: 'bar',
stack: 'consume',
data: chartData.consumePermanent,
itemStyle: { color: '#5470c6' },
barWidth: 30
},
{
name: '免费金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeFree,
itemStyle: { color: '#91cc75' },
barWidth: 30
},
{
name: '任务金币',
type: 'bar',
stack: 'consume',
data: chartData.consumeTask,
itemStyle: { color: '#fac858' },
barWidth: 30
}
]
legend = ['永久金币', '免费金币', '任务金币']
}
import GoldManagement from "@/components/workspace/GoldManagement.vue"
import CashManagement from "@/components/workspace/CashManagement.vue"
import GoldGraph from "@/components/workspace/GoldGraph.vue"
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params) {
let result = params[0].name + '<br/>'
let total = 0;
params.forEach(param => {
result += `${param.seriesName}: ${param.value.toLocaleString()}<br/>`;
total += param.value;
})
result += `${activeTab.value === 'recharge' ? '充值' : '消费'}: ${total.toLocaleString()}`;
return result
}
},
legend: {
data: legend,
bottom: 10
},
grid: {
left: '3%',
right: '4%',
bottom: '10%',
containLabel: true
},
xAxis: {
type: 'category',
data: markets.value,
axisLabel: {
interval: 0,
rotate: 30
}
},
yAxis: {
type: 'value',
axisLabel: {
formatter: function (value) {
return value.toLocaleString()
}
}
},
series: series,
// dataZoom: [
// {
// type: 'slider',
// show: true,
// start: 0,
// end: 100,
// maxSpan: 100,
// minSpan: 100,
//
// height: 2,
// },
// ]
}
chartInstance.setOption(option)
} catch (error) {
console.error('图表更新失败:', error)
ElMessage.error('图表渲染失败')
} finally {
setTimeout(() => {
chartLoading.value = false
}, 300)
}
}
//
const handleTabChange = () => {
getChartData()
console.log('标签切换调用图表')
}
const getAdminData = async function () {
try {
const result = await API({ url: '/admin/userinfo', data: {} })
adminData.value = result
console.log('用户信息', adminData.value)
} catch (error) {
console.log('请求失败', error)
}
}
//
const getCardData = async () => {
try {
const response = await API({ url: '/workbench/getCard', data: {} })
workDataUpdateTime.value = response.updateTime
//
sumWow.value = response.sumWow.toFixed(2)
//
sumDaily.value = response.sumDaily.toFixed(2)
if (response && response.data) {
processData(response.data)
} else if (Array.isArray(response?.marketCards)) {
processData(response)
} else {
console.error('无效的API响应结构:', response)
}
} catch (error) {
console.error('获取卡片数据失败:', error)
}
}
const workDataUpdateTime = ref(null)
//
const activeTimeRange = ref('')
//
const handleDatePickerChange = () => {
activeTimeRange.value = ''
}
onMounted(async () => {
await getAdminData()
await getCardData()
await getMarkets()
getYear()
window.addEventListener('resize', () => {
chartInstance.resize()
})
})
onUnmounted(() => {
destroyChart()
})
</script>
<style scoped>
.top {
height: 5.5vh;
width: 80vw;
display: flex;
margin-bottom: 0.5vh;
.text {
margin-left: 2vw;
width: 20vw;
.header {
/* 将纯色背景替换为线性渐变 */
background: linear-gradient(
90deg,
rgba(228, 240, 252, 1) 20%,
rgba(190, 218, 247, 1) 50%,
rgba(228, 240, 252, 1) 100%
);
height: 6vh;
border-radius: 12px;
margin-bottom: 4px;
box-shadow: 0 2px 5px rgba(8, 4, 4, 0.1);
/* 添加阴影增强层次感 */
z-index: 80;
display: flex;
align-items: center;
font-size: 18px;
}
}
.card {
height: 28vh;
margin-bottom: 0.5vh;
display: flex;
justify-content: center;
}
.graph {
width: 100%;
display: flex;
height: 64%;
.condition {
width: 100%;
height: 1%;
display: flex;
align-items: center;
.stats {
display: flex;
align-items: center;
width: 35vw;
font-size: 15px;
}
}
.graph-content {
flex: 1;
height: auto;
display: flex;
.left {
width: 70%;
height: auto;
}
.right {
flex: 1;
padding: 0.5vw 2vh;
}
}
}
.center-card {
display: flex;
justify-content: center;
align-items: center;
}
.margin-bottom {
margin-bottom: 0.5vh;
}
.card-item {
width: 25%;
height: 28vh;
display: flex;
flex-direction: column;
justify-content: center;
margin-right: 0.25vw;
}
.card-title {
font-weight: bold;
margin-bottom: 1vh;
display: flex;
justify-content: center;
align-items: center;
}
.card-large {
font-weight: bold;
font-size: 16px;
.title {
width: 136px;
color: #040a2d;
font-family: "PingFang SC";
font-size: 34px;
font-style: normal;
font-weight: 900;
line-height: 31.79px;
text-align: center;
margin-bottom: 15px;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>

4949
stats.html
File diff suppressed because it is too large
View File

Loading…
Cancel
Save