Browse Source
Merge branch 'milestone-20250913-现金管理' into lihuilin/feature-20250923114949-现金
lihuilin/feature-20250923114949-现金
Merge branch 'milestone-20250913-现金管理' into lihuilin/feature-20250923114949-现金
lihuilin/feature-20250923114949-现金
35 changed files with 4365 additions and 5973 deletions
-
2.env.development
-
7package-lock.json
-
1package.json
-
14src/assets/SvgIcons/上升箭头.svg
-
14src/assets/SvgIcons/下降箭头.svg
-
10src/assets/SvgIcons/周同比.svg
-
38src/assets/SvgIcons/工作台.svg
-
30src/assets/SvgIcons/折合新币累计金额.svg
-
14src/assets/SvgIcons/持平.svg
-
30src/assets/SvgIcons/昨日充值人数.svg
-
19src/assets/SvgIcons/昨日新增消费.svg
-
30src/assets/SvgIcons/昨日新增金币.svg
-
18src/assets/SvgIcons/消耗.svg
-
29src/assets/SvgIcons/现金管理.svg
-
22src/assets/SvgIcons/设置.svg
-
27src/assets/SvgIcons/金币管理.svg
-
9src/assets/SvgIcons/金币系统LOGO.svg
-
BINsrc/assets/backgroundBlue.png
-
BINsrc/assets/半透明background.png
-
211src/components/workspace/CashManagement.vue
-
210src/components/workspace/CashManagementMarkets.vue
-
818src/components/workspace/GoldGraph.vue
-
818src/components/workspace/GoldGraphMarkets.vue
-
669src/components/workspace/GoldManagement.vue
-
8src/utils/menuTreePermission.js
-
2src/utils/menuUtils.js
-
183src/views/audit/gold/rechargeAudit.vue
-
2src/views/audit/gold/refundAudit.vue
-
276src/views/home.vue
-
922src/views/moneyManage/receiveDetail/receiveDetail.vue
-
2src/views/moneyManage/refundDetail/refundDetail.vue
-
23src/views/recharge/gold/addCoinRecharge.vue
-
2src/views/usergold/gold/clientCountBalance.vue
-
929src/views/workspace/index.vue
-
4949stats.html
@ -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> |
@ -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
File diff suppressed because it is too large
View File
@ -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
File diff suppressed because it is too large
View File
@ -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> |
@ -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> |
@ -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> |
@ -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> |
@ -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
File diff suppressed because it is too large
View File
@ -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> |
@ -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
File diff suppressed because it is too large
View File
After Width: 1440 | Height: 810 | Size: 1.3 MiB |
After Width: 1874 | Height: 1054 | Size: 10 KiB |
@ -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> |
@ -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> |
@ -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> |
||||
|
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }} |
||||
|
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }} |
||||
|
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }} |
||||
|
</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(); |
||||
|
// 获取今天是星期几(0是周日,1是周一,...,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] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// wow和daily除一下 |
||||
|
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> |
@ -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> |
||||
|
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }} |
||||
|
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }} |
||||
|
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }} |
||||
|
</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(); |
||||
|
// 获取今天是星期几(0是周日,1是周一,...,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] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// wow和daily除一下 |
||||
|
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> |
@ -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> 较前一日 |
||||
|
{{ dailyChange / 100 }} |
||||
|
<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"> </div> |
||||
|
|
||||
|
<div class="margin-bottom">免费金币:{{ currentFree / 100 }}</div> |
||||
|
<!-- <div class="margin-bottom"> </div>--> |
||||
|
<!-- <div class="margin-bottom"> </div>--> |
||||
|
<div class="margin-bottom"> |
||||
|
[6月到期:{{ currentFreeJune / 100 }}] |
||||
|
</div> |
||||
|
<div class="margin-bottom"> </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;"> </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] |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
|
||||
|
// wow和daily除一下 |
||||
|
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> |
@ -1,2 +1,920 @@ |
|||||
<template></template> |
|
||||
<script setup></script> |
|
||||
|
<template> |
||||
|
<div class="content"> |
||||
|
<div class="card1"> |
||||
|
<el-card style="margin-bottom: 0.5vh; min-height: 110px;"> |
||||
|
<div class="row"> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">精网号</el-text> |
||||
|
<el-input placeholder="请输入精网号" style="width:10vw;" clearable></el-input> |
||||
|
</div> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">客户姓名</el-text> |
||||
|
<el-input placeholder="请输入客户姓名" style="width:10vw;" clearable></el-input> |
||||
|
</div> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">所属地区</el-text> |
||||
|
<el-select placeholder="请选择所属地区" style="width:10vw;" clearable></el-select> |
||||
|
</div> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">订单状态</el-text> |
||||
|
<el-select placeholder="请选择订单状态" style="width: 10vw;" clearable></el-select> |
||||
|
</div> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">支付方式</el-text> |
||||
|
<el-select placeholder="请选择支付方式" style="width: 10vw;" clearable></el-select> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="row" style="margin-top: 10px;"> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">活动名称</el-text> |
||||
|
<el-select placeholdert="请选择活动方式" style="width: 10vw;" clearable></el-select> |
||||
|
</div> |
||||
|
<div class="rowItem"> |
||||
|
<el-text style="width: 4vw;">产品名称</el-text> |
||||
|
<el-select placeholder="请选择产品名称" style="width: 10vw;" clearable></el-select> |
||||
|
</div> |
||||
|
<div class="rowItem" style="width: 30vw"> |
||||
|
<el-text style="width: 4vw; margin-left: 0.5vw;">付款时间</el-text> |
||||
|
<el-date-picker v-model="getTime" type="datetimerange" range-separator="至" |
||||
|
start-placeholder="起始时间" end-placeholder="结束时间" style="width: 22vw; " |
||||
|
@change="handleDatePickerChange" :default-time="defaultTime" |
||||
|
:disabled-date="disabledDate" /> |
||||
|
</div> |
||||
|
</div> |
||||
|
<div class="row" style="margin-top: 10px;"> |
||||
|
<div class="buttons"> |
||||
|
<el-button type="primary">查询</el-button> |
||||
|
<el-button type="success">重置</el-button> |
||||
|
<el-button type="primary">导出excel</el-button> |
||||
|
<el-button type="primary" style="background-color: #5870FF;">导出列表</el-button> |
||||
|
<el-button type="primary" @click="checkKefu">切换客服</el-button> |
||||
|
<el-button type="success" @click="checkCaiwu">切换财务</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</div> |
||||
|
|
||||
|
|
||||
|
<div class="card2"> |
||||
|
<el-card> |
||||
|
<div class="btns"> |
||||
|
<div class="tabs" v-if="caiwu"> |
||||
|
<el-button-group> |
||||
|
<el-button class="btnItem" |
||||
|
:style="{ backgroundColor: activeTab === 'wait' ? '#2741DE' : '#E5EBFE', color: activeTab === 'wait' ? 'white' : '#666' }" |
||||
|
@click="navigateTo('wait')"> |
||||
|
待审核 |
||||
|
</el-button> |
||||
|
<el-button class="btnItem" |
||||
|
:style="{ backgroundColor: activeTab === 'pass' ? '#2741DE' : '#E5EBFE', color: activeTab === 'pass' ? 'white' : '#666' }" |
||||
|
@click="navigateTo('pass')"> |
||||
|
已通过 |
||||
|
</el-button> |
||||
|
<el-button class="btnItem" |
||||
|
:style="{ backgroundColor: activeTab === 'reject' ? '#2741DE' : '#E5EBFE', color: activeTab === 'reject' ? 'white' : '#666' }" |
||||
|
@click="navigateTo('reject')"> |
||||
|
已驳回 |
||||
|
</el-button> |
||||
|
</el-button-group> |
||||
|
</div> |
||||
|
<div class="btnAdd"> |
||||
|
<el-button @click="openAddForm" type="success" v-if="kefu">添加收款</el-button> |
||||
|
</div> |
||||
|
</div> |
||||
|
|
||||
|
<div class="table"> |
||||
|
<el-table :data="tableData" style="width: 80vw;height:54vh;" @sort-change="handleSortChange" |
||||
|
:row-style="{ height: '60px' }" :header-cell-style="{ textAlign: 'center' }" |
||||
|
:cell-style="{ textAlign: 'center' }"> |
||||
|
<el-table-column type="index" label="序号" width="100px" fixed="left"> |
||||
|
<template #default="scope"> |
||||
|
<span>{{ scope.$index + 1 + (pageInfo.pageNum - 1) * pageInfo.pageSize }}</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column fixed="left" prop="jwcode" label="Homily ID" width="110px" /> |
||||
|
<el-table-column fixed="left" prop="name" label="姓名" width="110px" /> |
||||
|
<el-table-column prop="market" label="所属地区" width="80px" /> |
||||
|
<el-table-column prop="activity" label="活动名称" width="120px" /> |
||||
|
<el-table-column prop="rateName" label="产品名称" width="120px" /> |
||||
|
<el-table-column prop="money" label="付款币种" width="100px"> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="permanentGold" label="付款金额" width="120px"> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="moneyType" label="到账币种" v-if="caiwu && activeTab == 'pass'" width="150px" ></el-table-column> |
||||
|
<el-table-column prop="getMoney" label="到账金额" v-if="caiwu && activeTab == 'pass'" width="150px" > |
||||
|
<template #default="scope"> |
||||
|
<div v-if="!scope.row.getMoney"> |
||||
|
<text style="color: #FA5A1E;">待补充</text> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="shouxufei" label="手续费" v-if="caiwu && activeTab == 'pass'" width="150px" > |
||||
|
<template #default="scope"> |
||||
|
<div v-if="!scope.row.shouxufei"> |
||||
|
<text style="color: #FA5A1E;">待补充</text> |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="pastType" label="支付方式" width="110px"> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="remark" label="付款时间" width="100px" /> |
||||
|
<el-table-column prop="payModel" label="转账凭证" width="110px"> |
||||
|
<template #default="scope"> |
||||
|
<div v-if="scope.row.voucher" |
||||
|
style="display: flex; justify-content: center; align-items: center; cursor: pointer;" |
||||
|
@click="previewImage(scope.row.voucher)"> |
||||
|
<img :src="scope.row.payModel" alt="支付凭证" style="width: auto; height: 40px;"> |
||||
|
</div> |
||||
|
<div v-else |
||||
|
style="display: flex; justify-content: center; align-items: center; height: 40px;"> |
||||
|
-- |
||||
|
</div> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
<el-table-column prop="bankOrder" label="银行流水订单号" v-if="caiwu && activeTab == 'pass'" width="150px" show-overflow-tooltip></el-table-column> |
||||
|
<el-table-column prop="submiter" label="提交人" width="150px" show-overflow-tooltip></el-table-column> |
||||
|
<el-table-column prop="auditor" label="审核人" v-if="caiwu && activeTab == 'pass'" width="150px" show-overflow-tooltip></el-table-column> |
||||
|
<el-table-column prop="mask" label="备注" width="150px" show-overflow-tooltip></el-table-column> |
||||
|
<el-table-column prop="getMoneyTime" label="到账时间" v-if="caiwu && activeTab == 'pass'" width="150px" show-overflow-tooltip> |
||||
|
</el-table-column> |
||||
|
<el-table-column v-if="kefu" fixed="right" prop="orderStatus" label="订单状态" width="100px" /> |
||||
|
<el-table-column fixed="right" label="操作" width="100px" v-if="activeTab != 'reject'"> |
||||
|
<template #default=scope> |
||||
|
<span v-if="kefu && scope.row.orderStatus == '已通过'" style="color: #FA5A1E;">退款</span> |
||||
|
<span v-else-if="kefu && scope.row.orderStatus == '已撤回'" |
||||
|
style="color: #2741DE;">编辑</span> |
||||
|
<span v-else-if="kefu && scope.row.orderStatus == '待审核'" |
||||
|
style="color: #FA5A1E;">撤回</span> |
||||
|
<span v-else-if="activeTab == 'wait' && !kefu" style="color: #2741DE;" |
||||
|
@click="openAuditForm">审核</span> |
||||
|
<span v-else-if="activeTab == 'pass' && !kefu" style="color: #2741DE;" |
||||
|
@click="openEditForm(scope.row)">编辑</span> |
||||
|
</template> |
||||
|
</el-table-column> |
||||
|
</el-table> |
||||
|
</div> |
||||
|
<div class="pagination"> |
||||
|
<el-pagination :page-size="pageInfo.pageSize" :page-sizes="[5, 10, 20, 50, 100]" |
||||
|
layout="total, sizes, prev, pager, next, jumper" :total="total" |
||||
|
@size-change="handlePagination('size', $event)" |
||||
|
@current-change="handlePagination('page', $event)"></el-pagination> |
||||
|
</div> |
||||
|
</el-card> |
||||
|
</div> |
||||
|
<el-dialog class="adddialog" v-model="addFormisible" width="20vw" :before-close="closeAddForm"> |
||||
|
<el-form class="addForm" label-width="4vw" label-position="left"> |
||||
|
<el-form-item label="精网号" required> |
||||
|
<el-input v-model="addFormData.jwcode" placeholder="请输入驳回理由" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="客户姓名" required> |
||||
|
<el-input v-model="addFormData.userName" placeholder="请输入客户姓名" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="所属地区" required> |
||||
|
<el-input disabled="true" v-model="addFormData.market" placeholder="请输入所属地区" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="活动名称" required> |
||||
|
<el-input v-model="addFormData.jwcode" placeholder="请输入活动名称" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="产品名称" required> |
||||
|
<el-select placeholder="请选择产品名称" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款币种" required> |
||||
|
<el-select placeholder="请选择付款币种" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款金额" required> |
||||
|
<el-input v-model="addFormData.jwcode" placeholder="请输入付款金额" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="支付方式" required> |
||||
|
<el-select placeholder="请选择支付方式" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款时间" required> |
||||
|
<el-time-picker v-model="addFormData.time" placeholder="请选择付款时间" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="转账凭证" required> |
||||
|
<el-upload ref="uploadRef" class="uploader" :show-file-list="false" list-type="picture-card" |
||||
|
:auto-upload="false" :before-upload="beforeUpload" :on-error="handelImgErr" |
||||
|
:on-change="handleImageChange" :http-request="customUpload"> |
||||
|
<img v-if="addFormData.imageUrl" :src="addFormData.imageUrl" class="avatar" |
||||
|
style="height: 100%; width: 100%; object-fit: cover;" /> |
||||
|
<el-icon v-else class="avatar-uploader-icon"> |
||||
|
<Plus /> |
||||
|
</el-icon> |
||||
|
</el-upload> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="备注" required> |
||||
|
<el-input v-model="addFormData.mask" type="textarea" :rows="4" placeholder="请输入备注" maxlength="100" |
||||
|
show-word-limit /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<span class="dialog-footer"> |
||||
|
<el-button style="background-color: #7E91FF;" @click="closeAddForm">取消</el-button> |
||||
|
<el-button style="background-color: #2741DE; margin-left: 2.5vw;" type="primary" |
||||
|
@click="handleReject">确定</el-button> |
||||
|
</span> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
<!-- 审核弹窗 --> |
||||
|
<el-dialog class="adddialog" v-model="auditFormisible" width="20vw" :before-close="closeAuditForm"> |
||||
|
<el-form class="addForm" label-width="4vw" label-position="left"> |
||||
|
<el-form-item label="精网号"> |
||||
|
<el-input v-model="auditFormData.jwcode" placeholder="请输入驳回理由" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="客户姓名"> |
||||
|
<el-input v-model="auditFormData.userName" placeholder="请输入客户姓名" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="所属地区"> |
||||
|
<el-input disabled="true" v-model="auditFormData.market" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="活动名称"> |
||||
|
<el-input v-model="auditFormData.jwcode" placeholder="请输入活动名称" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="产品名称"> |
||||
|
<el-select placeholder="请选择产品名称" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款币种"> |
||||
|
<el-select placeholder="请选择付款币种" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款金额"> |
||||
|
<el-input v-model="auditFormData.jwcode" placeholder="请输入付款金额" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="支付方式"> |
||||
|
<el-select placeholder="请选择支付方式" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款时间"> |
||||
|
<el-time-picker v-model="auditFormData.time" placeholder="请选择付款时间" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="转账凭证"> |
||||
|
<div class="pic"> |
||||
|
<el-upload ref="uploadRef" class="uploader" :show-file-list="false" list-type="picture-card" |
||||
|
:auto-upload="false" :before-upload="beforeUpload" :on-error="handelImgErr" |
||||
|
:on-change="handleImageChange" :http-request="customUpload"> |
||||
|
<img v-if="auditFormData.imageUrl" :src="auditFormData.imageUrl" class="avatar" |
||||
|
style="height: 100%; width: 100%; object-fit: cover;" /> |
||||
|
<el-icon v-else class="avatar-uploader-icon"> |
||||
|
<Plus /> |
||||
|
</el-icon> |
||||
|
</el-upload> |
||||
|
<el-text class="picText"> |
||||
|
仅支持.jpg .png格式文件≤ 1 MB |
||||
|
</el-text> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="备注"> |
||||
|
<el-input v-model="auditFormData.mask" type="textarea" :rows="3" placeholder="请输入备注" maxlength="100" |
||||
|
show-word-limit /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="驳回理由" v-if="ifReject" required> |
||||
|
<el-input v-model="auditFormData.mask" type="textarea" :rows="3" placeholder="请输入驳回理由" |
||||
|
maxlength="100" show-word-limit /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<template #footer> |
||||
|
<span class="dialog-footer" v-if="!ifReject"> |
||||
|
<el-button style="background-color: #7E91FF;" @click="ifReject = true">驳回</el-button> |
||||
|
<el-button :style="{ |
||||
|
backgroundColor: isBtnDisabled ? '#E5E5E5FF' : '#2741DEFF', |
||||
|
marginLeft: '60px', |
||||
|
color: isBtnDisabled ? '#8A8A8A' : '#F3FAFE' |
||||
|
}" @click="handleReject" :disabled="isBtnDisabled">{{ btnText }}</el-button> |
||||
|
</span> |
||||
|
<span class="dialog-footer" v-if="ifReject"> |
||||
|
<el-button style="background-color: #7E91FF;" @click="closeAuditForm">取消</el-button> |
||||
|
<el-button style="background-color: #2741DE; margin-left: 2.5vw;" type="primary" |
||||
|
@click="handleReject">确定</el-button> |
||||
|
</span> |
||||
|
</template> |
||||
|
</el-dialog> |
||||
|
<!-- 编辑弹窗 --> |
||||
|
<el-dialog class="editdialog" v-model="editFormisible" width="20vw" :before-close="closeEditForm"> |
||||
|
<div class="content"> |
||||
|
<div class="left"> |
||||
|
<el-form class="editForm" label-width="4.5vw" label-position="left"> |
||||
|
<el-form-item label="精网号"> |
||||
|
<el-input v-model="editFormData.jwcode" placeholder="请输入驳回理由" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="客户姓名"> |
||||
|
<el-input v-model="editFormData.userName" placeholder="请输入客户姓名" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="所属地区"> |
||||
|
<el-input disabled="true" v-model="editFormData.market" placeholder="请输入所属地区" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="活动名称"> |
||||
|
<el-input v-model="editFormData.jwcode" placeholder="请输入活动名称" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="产品名称"> |
||||
|
<el-select placeholder="请选择产品名称" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款币种"> |
||||
|
<el-select placeholder="请选择付款币种" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款金额"> |
||||
|
<el-input v-model="editFormData.jwcode" placeholder="请输入付款金额" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="支付方式"> |
||||
|
<el-select placeholder="请选择支付方式" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="付款时间"> |
||||
|
<el-time-picker v-model="editFormData.time" placeholder="请选择付款时间" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="转账凭证"> |
||||
|
<div class="pic"> |
||||
|
<el-upload ref="uploadRef" class="uploader" :show-file-list="false" |
||||
|
list-type="picture-card" :auto-upload="false" :before-upload="beforeUpload" |
||||
|
:on-error="handelImgErr" :on-change="handleImageChange" |
||||
|
:http-request="customUpload"> |
||||
|
<img v-if="editFormData.imageUrl" :src="editFormData.imageUrl" class="avatar" |
||||
|
style="height: 100%; width: 100%; object-fit: cover;" /> |
||||
|
<el-icon v-else class="avatar-uploader-icon"> |
||||
|
<Plus /> |
||||
|
</el-icon> |
||||
|
</el-upload> |
||||
|
<el-text class="picText"> |
||||
|
仅支持.jpg .png格式文件≤ 1 MB |
||||
|
</el-text> |
||||
|
</div> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="驳回理由"> |
||||
|
<el-input v-model="addFormData.mask" type="textarea" :rows="4" placeholder="请输入驳回理由" |
||||
|
maxlength="100" show-word-limit /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
</div> |
||||
|
<div class="right"> |
||||
|
<el-form class="editFormRighrt" label-width="4.5vw" label-position="left"> |
||||
|
<el-form-item label="到账货币"> |
||||
|
<el-select placeholder="请选择产品名称" clearable></el-select> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="到账金额"> |
||||
|
<el-input v-model="addFormData.userName" placeholder="请输入到账金额" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="手续费"> |
||||
|
<el-input disabled="true" v-model="addFormData.market" placeholder="请输入手续费" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="银行流水订单号"> |
||||
|
<el-input v-model="addFormData.jwcode" placeholder="请输入银行流水订单号" /> |
||||
|
</el-form-item> |
||||
|
<el-form-item label="到账时间"> |
||||
|
<el-input v-model="addFormData.jwcode" placeholder="请输入到账时间" /> |
||||
|
</el-form-item> |
||||
|
</el-form> |
||||
|
<span class="editBtns"> |
||||
|
<button class="editBtn1"> |
||||
|
<text class="txt"> |
||||
|
取消 |
||||
|
</text> |
||||
|
</button> |
||||
|
<button class="editBtn2"> |
||||
|
<text class="txt"> |
||||
|
提交 |
||||
|
</text> |
||||
|
</button> |
||||
|
</span> |
||||
|
</div> |
||||
|
</div> |
||||
|
</el-dialog> |
||||
|
</div> |
||||
|
</template> |
||||
|
<script setup> |
||||
|
import { ref, watch } from 'vue'; |
||||
|
import { ElMessage } from 'element-plus' |
||||
|
import API from '@/util/http.js' |
||||
|
import { color } from 'echarts'; |
||||
|
import { template } from 'lodash'; |
||||
|
|
||||
|
//==================== 标签切换 ========================= |
||||
|
const activeTab = ref('wait') |
||||
|
|
||||
|
const navigateTo = (tab) => { |
||||
|
if (tab === 'wait') { |
||||
|
activeTab.value = 'wait' |
||||
|
} else if (tab === 'pass') { |
||||
|
activeTab.value = 'pass' |
||||
|
} |
||||
|
else if (tab === 'reject') { |
||||
|
activeTab.value = 'reject' |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const kefu = ref(true) |
||||
|
const caiwu = ref(true) |
||||
|
const checkKefu = () => { |
||||
|
kefu.value = true |
||||
|
caiwu.value = false |
||||
|
} |
||||
|
const checkCaiwu = () => { |
||||
|
kefu.value = false |
||||
|
caiwu.value = true |
||||
|
} |
||||
|
//================= 客服新增弹窗 ================== |
||||
|
const addFormData = ref({ |
||||
|
|
||||
|
}) |
||||
|
const addFormisible = ref(false) |
||||
|
|
||||
|
|
||||
|
const uploadRef = ref() |
||||
|
const openAddForm = () => { |
||||
|
addFormisible.value = true |
||||
|
} |
||||
|
const closeAddForm = () => { |
||||
|
addFormisible.value = false |
||||
|
addFormData.value = {} |
||||
|
} |
||||
|
|
||||
|
const handleImgSuccess = (response, uploadFile) => { |
||||
|
try { |
||||
|
console.log('11', response) |
||||
|
addFormData.value.imageUrl = response.data.url |
||||
|
console.log('22', response.data.url) |
||||
|
} catch (error) { |
||||
|
console.log('报错信息', error) |
||||
|
ElMessage.error(response.msg || '图片上传失败') |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
const handelImgErr = (err) => { |
||||
|
console.log(err); |
||||
|
addFormData.value.imageUrl = null |
||||
|
ElMessage.error("图片上传失败") |
||||
|
} |
||||
|
const beforeUpload = (rawFile) => { |
||||
|
if (rawFile.type !== 'image/jpeg' && rawFile.type !== 'image/png') { |
||||
|
ElMessage.error('图片必须是jpg或png类型!') |
||||
|
return false |
||||
|
} else if (rawFile.size / 1024 / 1024 > 1) { |
||||
|
ElMessage.error('图片大小不能超过 1MB!') |
||||
|
return false |
||||
|
} |
||||
|
return true |
||||
|
} |
||||
|
const handleImageChange = (file) => { |
||||
|
uploadRef.value.submit() |
||||
|
} |
||||
|
|
||||
|
const customUpload = async (options) => { |
||||
|
try { |
||||
|
const formData = new FormData() |
||||
|
formData.append('file', options.file) |
||||
|
|
||||
|
const response = await API({ |
||||
|
url: 'https://api.homilychart.com/hljw/api/aws/upload', |
||||
|
method: 'POST', |
||||
|
data: formData, |
||||
|
headers: { |
||||
|
'Content-Type': 'multipart/form-data' |
||||
|
} |
||||
|
}) |
||||
|
if (response.code === 100 && response.data) { |
||||
|
handleImgSuccess(response, options.file) |
||||
|
ElMessage.success(response.msg || '上传成功') |
||||
|
} else { |
||||
|
options.onError(response) |
||||
|
ElMessage.error(response.msg || '上传失败') |
||||
|
} |
||||
|
} catch (error) { |
||||
|
console.error('上传错误:', error) |
||||
|
ElMessage.error(`上传失败: ${error.msg || error.message || '网络异常'}`) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
//================== 财务编辑相关 ========================= |
||||
|
const editFormData = ref({ |
||||
|
|
||||
|
}) |
||||
|
const editFormisible = ref(false) |
||||
|
const openEditForm = (row) => { |
||||
|
console.log('编辑时该行数据:',row); |
||||
|
editFormData.value = row |
||||
|
editFormisible.value = true |
||||
|
} |
||||
|
const closeEditForm = () => { |
||||
|
editFormisible.value = false |
||||
|
editFormData.value = {} |
||||
|
} |
||||
|
//================== 审核相关 ========================= |
||||
|
const auditFormData = ref({ |
||||
|
|
||||
|
}) |
||||
|
const auditFormisible = ref(false) |
||||
|
//判断弹窗中是否展示驳回 |
||||
|
const ifReject = ref(false) |
||||
|
const openAuditForm = () => { |
||||
|
auditFormisible.value = true |
||||
|
} |
||||
|
const countdown = ref(0); // 倒计时秒数(示例设为 5 秒) |
||||
|
const isBtnDisabled = ref(false); // 按钮是否禁用 |
||||
|
const btnText = ref('通过(3)'); // 按钮显示的文字(含倒计时) |
||||
|
const closeAuditForm = () => { |
||||
|
ifReject.value = false |
||||
|
auditFormisible.value = false |
||||
|
auditFormData.value = {} |
||||
|
} |
||||
|
//倒计时控制通过按钮 |
||||
|
watch(auditFormisible, (val) => { |
||||
|
if (val) { |
||||
|
countdown.value = 3 |
||||
|
isBtnDisabled.value = true |
||||
|
btnText.value = `通过(${countdown.value})` |
||||
|
|
||||
|
const timer = setInterval(() => { |
||||
|
countdown.value-- |
||||
|
btnText.value = `通过(${countdown.value})` |
||||
|
console.log(btnText.value); |
||||
|
|
||||
|
if (countdown.value <= 0) { |
||||
|
isBtnDisabled.value = false |
||||
|
clearInterval(timer) |
||||
|
btnText.value = '通过' |
||||
|
} |
||||
|
}, 1000); |
||||
|
} |
||||
|
|
||||
|
}) |
||||
|
//========================分页相关================== |
||||
|
const pageInfo = ref({ |
||||
|
pageSize: 10, |
||||
|
pageNum: 1 |
||||
|
}) |
||||
|
|
||||
|
|
||||
|
const total = ref(0) |
||||
|
const tableData = [ |
||||
|
{ |
||||
|
"jwcode": "HM2024001", |
||||
|
"name": "张三", |
||||
|
"market": "华东区", |
||||
|
"activity": "2024春季促销活动", |
||||
|
"rateName": "年度会员套餐A", |
||||
|
"money": "人民币", |
||||
|
"permanentGold": 2980.00, |
||||
|
"moneyType": "人民币", |
||||
|
"getMoney": 2980.00, |
||||
|
"shouxufei": 59.60, |
||||
|
"pastType": "支付宝转账", |
||||
|
"remark": "2024-05-10 09:23", |
||||
|
"voucher": "https://example.com/voucher/1.jpg", |
||||
|
"payModel": "https://example.com/icon/alipay.png", |
||||
|
"bankOrder": "ALIPAY2024051000001", |
||||
|
"submiter": "李四(运营部)", |
||||
|
"auditor": "王五(财务部)", |
||||
|
"mask": "客户主动购买,无特殊备注", |
||||
|
"getMoneyTime": "2024-05-10 10:05", |
||||
|
"orderStatus": "已通过" |
||||
|
}, |
||||
|
{ |
||||
|
"jwcode": "HM2024002", |
||||
|
"name": "李四", |
||||
|
"market": "华北区", |
||||
|
"activity": "新客首单优惠", |
||||
|
"rateName": "季度体验套餐B", |
||||
|
"money": "美元", |
||||
|
"permanentGold": 99.00, |
||||
|
"moneyType": "人民币", |
||||
|
"getMoney": 712.00, |
||||
|
"shouxufei": 14.24, |
||||
|
"pastType": "PayPal", |
||||
|
"remark": "2024-05-11 14:56", |
||||
|
"voucher": "https://example.com/voucher/2.jpg", |
||||
|
"payModel": "https://example.com/icon/paypal.png", |
||||
|
"bankOrder": "PAYPAL2024051100002", |
||||
|
"submiter": "赵六(国际部)", |
||||
|
"auditor": "孙七(财务部)", |
||||
|
"mask": "跨境支付,汇率按当日中间价计算", |
||||
|
"getMoneyTime": "2024-05-12 08:30", |
||||
|
"orderStatus": "待审核" |
||||
|
}, |
||||
|
{ |
||||
|
"jwcode": "HM2024003", |
||||
|
"name": "王五", |
||||
|
"market": "华南区", |
||||
|
"activity": "老客召回活动", |
||||
|
"rateName": "月度续费套餐C", |
||||
|
"money": "人民币", |
||||
|
"permanentGold": 399.00, |
||||
|
"moneyType": "人民币", |
||||
|
"getMoney": null, |
||||
|
"shouxufei": null, |
||||
|
"pastType": "微信支付", |
||||
|
"remark": "2024-05-12 11:18", |
||||
|
"voucher": "https://example.com/voucher/3.jpg", |
||||
|
"payModel": "https://example.com/icon/wechat.png", |
||||
|
"bankOrder": "WECHAT2024051200003", |
||||
|
"submiter": "钱八(客服部)", |
||||
|
"auditor": null, |
||||
|
"mask": "到账信息待财务补充", |
||||
|
"getMoneyTime": null, |
||||
|
"orderStatus": "已撤回" |
||||
|
}, |
||||
|
{ |
||||
|
"jwcode": "HM2024004", |
||||
|
"name": "赵六", |
||||
|
"market": "西区", |
||||
|
"activity": "企业团购活动", |
||||
|
"rateName": "企业定制套餐D", |
||||
|
"money": "人民币", |
||||
|
"permanentGold": 15800.00, |
||||
|
"moneyType": "人民币", |
||||
|
"getMoney": 15800.00, |
||||
|
"shouxufei": 316.00, |
||||
|
"pastType": "银行对公转账", |
||||
|
"remark": "2024-05-13 09:45", |
||||
|
"voucher": "https://example.com/voucher/4.jpg", |
||||
|
"payModel": "https://example.com/icon/bank.png", |
||||
|
"bankOrder": "BANK2024051300004", |
||||
|
"submiter": "周九(销售部)", |
||||
|
"auditor": "吴十(财务部)", |
||||
|
"mask": "10人企业团单,享受95折优惠", |
||||
|
"getMoneyTime": "2024-05-13 11:20", |
||||
|
"orderStatus": "已通过" |
||||
|
}, |
||||
|
{ |
||||
|
"jwcode": "HM2024005", |
||||
|
"name": "孙七", |
||||
|
"market": "东北区", |
||||
|
"activity": "节日特惠活动", |
||||
|
"rateName": "年度会员套餐A", |
||||
|
"money": "人民币", |
||||
|
"permanentGold": 2780.00, |
||||
|
"moneyType": "人民币", |
||||
|
"getMoney": 2780.00, |
||||
|
"shouxufei": 55.60, |
||||
|
"pastType": "银联支付", |
||||
|
"remark": "2024-05-14 15:30", |
||||
|
"voucher": null, |
||||
|
"payModel": null, |
||||
|
"bankOrder": "UNIONPAY2024051400005", |
||||
|
"submiter": "郑一(市场部)", |
||||
|
"auditor": "王二(财务部)", |
||||
|
"mask": "凭证暂未上传,已提醒客户补充", |
||||
|
"getMoneyTime": "2024-05-14 16:45", |
||||
|
"orderStatus": "待审核" |
||||
|
} |
||||
|
] |
||||
|
</script> |
||||
|
<style scoped lang="scss"> |
||||
|
.content { //整体内容 |
||||
|
height: 100%; |
||||
|
width: 83vw; |
||||
|
|
||||
|
.card1 { // 筛选框 |
||||
|
width: 100%; |
||||
|
|
||||
|
.row { |
||||
|
height: 4vh; |
||||
|
width: 80vw; |
||||
|
display: flex; |
||||
|
min-height: 40px; |
||||
|
|
||||
|
.rowItem { |
||||
|
display: flex; |
||||
|
width: 15vw; |
||||
|
align-items: center; |
||||
|
justify-content: center; |
||||
|
margin-right: 0.5vw; |
||||
|
} |
||||
|
|
||||
|
.buttons { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
.card2 { // 下方数据展示card |
||||
|
width: 100%; |
||||
|
|
||||
|
margin-top: 2vh; |
||||
|
|
||||
|
.btns { //切换标签 |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
justify-content: space-between; |
||||
|
padding-bottom: 10px; |
||||
|
|
||||
|
.tabs { |
||||
|
min-width: 300px; |
||||
|
|
||||
|
.btnItem { |
||||
|
margin-left: 10px; |
||||
|
border-radius: 5px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.btnAdd { |
||||
|
margin-right: 5vw; |
||||
|
padding-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
.table { |
||||
|
margin: 10px 3vw; |
||||
|
border-radius: 20px; |
||||
|
} |
||||
|
|
||||
|
.pagination { |
||||
|
margin-top: 10px; |
||||
|
padding: 10px 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:deep(.adddialog) { //客服新增弹窗 |
||||
|
min-width: 500px; |
||||
|
background-color: #F3FAFE !important; |
||||
|
margin-top: 8vh; |
||||
|
border-radius: 8px; |
||||
|
|
||||
|
.addForm { |
||||
|
padding: 0 60px 1vh 60px; |
||||
|
|
||||
|
.el-date-editor { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
.pic { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.uploader { |
||||
|
height: 80px; |
||||
|
width: 80px; |
||||
|
|
||||
|
.el-upload { |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.picText { |
||||
|
color: #999999; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 10px; |
||||
|
font-style: normal; |
||||
|
font-weight: 400; |
||||
|
line-height: 20px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
.dialog-footer { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
padding-bottom: 1.5vh; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
:deep(.editdialog) { //编辑弹窗 |
||||
|
min-width: 990px; |
||||
|
background-color: #F3FAFE !important; |
||||
|
margin-top: 8vh; |
||||
|
border-radius: 8px; |
||||
|
|
||||
|
.editForm { |
||||
|
padding: 0 60px 1vh 60px; |
||||
|
|
||||
|
.el-date-editor { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.pic { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.uploader { |
||||
|
height: 80px; |
||||
|
width: 80px; |
||||
|
|
||||
|
.el-upload { |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.picText { |
||||
|
color: #999999; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 10px; |
||||
|
font-style: normal; |
||||
|
font-weight: 400; |
||||
|
line-height: 20px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
.content { //编辑弹窗内容 |
||||
|
display: flex; |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
|
||||
|
.left { |
||||
|
min-width: 500px; |
||||
|
} |
||||
|
|
||||
|
.right { |
||||
|
flex: 1; |
||||
|
|
||||
|
.editFormRighrt { |
||||
|
padding: 0 60px 0 40px; |
||||
|
|
||||
|
.el-date-editor { |
||||
|
display: flex; |
||||
|
flex: 1; |
||||
|
} |
||||
|
|
||||
|
.pic { |
||||
|
display: flex; |
||||
|
align-items: center; |
||||
|
|
||||
|
.uploader { |
||||
|
height: 80px; |
||||
|
width: 80px; |
||||
|
|
||||
|
.el-upload { |
||||
|
height: 100%; |
||||
|
width: 100%; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.picText { |
||||
|
color: #999999; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 10px; |
||||
|
font-style: normal; |
||||
|
font-weight: 400; |
||||
|
line-height: 20px; |
||||
|
margin-left: 10px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
.editBtns { |
||||
|
display: flex; |
||||
|
justify-content: center; |
||||
|
margin-top: 60px; |
||||
|
|
||||
|
.txt { |
||||
|
color: #f3fafe; |
||||
|
text-align: center; |
||||
|
font-family: "PingFang SC"; |
||||
|
font-size: 14px; |
||||
|
font-style: normal; |
||||
|
font-weight: 700; |
||||
|
line-height: 22px; |
||||
|
} |
||||
|
|
||||
|
.editBtn1 { |
||||
|
min-width: 80px; |
||||
|
padding: 5px 12px; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
gap: 4px; |
||||
|
border-radius: 4px; |
||||
|
background: #7E91FF; |
||||
|
border: none; |
||||
|
box-shadow: 0 0 4px 0 #00000040; |
||||
|
} |
||||
|
|
||||
|
.editBtn2 { |
||||
|
display: flex; |
||||
|
width: 80px; |
||||
|
min-width: 80px; |
||||
|
padding: 5px 12px; |
||||
|
justify-content: center; |
||||
|
align-items: center; |
||||
|
gap: 4px; |
||||
|
border-radius: 4px; |
||||
|
background: #2741DE; |
||||
|
border: none; |
||||
|
box-shadow: 0 0 4px 0 #00000040; |
||||
|
margin-left: 60px; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
|
|
||||
|
:deep(.adddialog .el-form-item__label) { //设置新增弹窗表头 |
||||
|
min-width: 80px; |
||||
|
width: auto; |
||||
|
font-weight: 800; |
||||
|
padding-bottom: 15px; |
||||
|
} |
||||
|
} |
||||
|
</style> |
@ -1,911 +1,68 @@ |
|||||
<template> |
<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> 较前一日 |
|
||||
{{ 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 }}] |
|
||||
[十二月到期|{{ 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> </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 }}% |
|
||||
<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> |
||||
<el-col style="padding-left: 35%;">日环比:{{ sumDaily }}% |
|
||||
<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> |
</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> |
|
||||
永久金币: {{ activeTab === 'recharge' ? sumRechargePermanent / 100 : sumConsumePermanent / 100 }} |
|
||||
免费金币: {{ activeTab === 'recharge' ? sumRechargeFree / 100 : sumConsumeFree / 100 }} |
|
||||
任务金币: {{ activeTab === 'recharge' ? sumRechargeTask / 100 : sumConsumeTask / 100 }} |
|
||||
</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> |
</div> |
||||
</template> |
</template> |
||||
|
|
||||
<script setup> |
<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 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(); |
|
||||
// 获取今天是星期几(0是周日,1是周一,...,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] |
|
||||
} |
|
||||
} |
|
||||
}) |
|
||||
|
|
||||
// wow和daily除一下 |
|
||||
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) |
|
||||
|
|
||||
|
import GoldManagement from "@/components/workspace/GoldManagement.vue" |
||||
|
import CashManagement from "@/components/workspace/CashManagement.vue" |
||||
|
import GoldGraph from "@/components/workspace/GoldGraph.vue" |
||||
|
|
||||
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: 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> |
</script> |
||||
|
|
||||
<style scoped> |
<style scoped> |
||||
.top { |
|
||||
height: 5.5vh; |
|
||||
width: 80vw; |
|
||||
display: flex; |
|
||||
margin-bottom: 0.5vh; |
|
||||
|
|
||||
.text { |
|
||||
margin-left: 2vw; |
|
||||
width: 20vw; |
|
||||
display: flex; |
|
||||
align-items: center; |
|
||||
font-size: 18px; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
.card { |
|
||||
height: 28vh; |
|
||||
margin-bottom: 0.5vh; |
|
||||
|
.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; |
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; |
align-items: center; |
||||
} |
|
||||
|
|
||||
.margin-bottom { |
|
||||
margin-bottom: 0.5vh; |
|
||||
} |
|
||||
|
|
||||
.card-item { |
|
||||
width: 25%; |
|
||||
height: 28vh; |
|
||||
display: flex; |
|
||||
flex-direction: column; |
|
||||
justify-content: center; |
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; |
text-align: center; |
||||
margin-bottom: 15px; |
|
||||
} |
} |
||||
|
|
||||
@keyframes spin { |
|
||||
0% { |
|
||||
transform: rotate(0deg); |
|
||||
} |
|
||||
|
|
||||
100% { |
|
||||
transform: rotate(360deg); |
|
||||
} |
|
||||
} |
|
||||
</style> |
</style> |
4949
stats.html
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue