feat: 页面编写
|
|
@ -4,9 +4,6 @@
|
|||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
|
||||
<!-- WX JS SDK 微信小程序一定要引入这个文件 可以自己去官方下载最新的-->
|
||||
<script type="text/javascript" src="/js/jweixin-1.6.0.js"></script>
|
||||
<script type="text/javascript" src="/js/uni.webview.1.5.6.js" defer></script>
|
||||
<title></title>
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
"crypto-js": "^4.2.0",
|
||||
"echarts": "^5.6.0",
|
||||
"echarts-gl": "^2.0.9",
|
||||
"gsap": "^3.13.0",
|
||||
"pinia": "^2.3.0",
|
||||
"pinia-plugin-persistedstate": "^4.1.3",
|
||||
"semver": "^7.6.3",
|
||||
|
|
@ -30,6 +31,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@iconify-json/carbon": "^1.2.8",
|
||||
"@types/gsap": "^3.0.0",
|
||||
"@types/qs": "^6.9.17",
|
||||
"@unocss/preset-wind": "^0.65.2",
|
||||
"@vitejs/plugin-basic-ssl": "^1.2.0",
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ importers:
|
|||
echarts-gl:
|
||||
specifier: ^2.0.9
|
||||
version: 2.0.9(echarts@5.6.0)
|
||||
gsap:
|
||||
specifier: ^3.13.0
|
||||
version: 3.13.0
|
||||
pinia:
|
||||
specifier: ^2.3.0
|
||||
version: 2.3.0(typescript@5.6.3)(vue@3.5.13(typescript@5.6.3))
|
||||
|
|
@ -57,6 +60,9 @@ importers:
|
|||
'@iconify-json/carbon':
|
||||
specifier: ^1.2.8
|
||||
version: 1.2.8
|
||||
'@types/gsap':
|
||||
specifier: ^3.0.0
|
||||
version: 3.0.0
|
||||
'@types/qs':
|
||||
specifier: ^6.9.17
|
||||
version: 6.9.17
|
||||
|
|
@ -637,6 +643,10 @@ packages:
|
|||
'@types/estree@1.0.6':
|
||||
resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==}
|
||||
|
||||
'@types/gsap@3.0.0':
|
||||
resolution: {integrity: sha512-BbWLi4WRHGze4C8NV7U7yRevuBFiPkPZZyGa0rryanvh/9HPUFXTNBXsGQxJZJq7Ix7j4RXMYodP3s+OsqCErg==}
|
||||
deprecated: This is a stub types definition. gsap provides its own type definitions, so you do not need this installed.
|
||||
|
||||
'@types/node@22.10.1':
|
||||
resolution: {integrity: sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==}
|
||||
|
||||
|
|
@ -1321,6 +1331,9 @@ packages:
|
|||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
gsap@3.13.0:
|
||||
resolution: {integrity: sha512-QL7MJ2WMjm1PHWsoFrAQH/J8wUeqZvMtHO58qdekHpCfhvhSL4gSiz6vJf5EeMP0LOn3ZCprL2ki/gjED8ghVw==}
|
||||
|
||||
gzip-size@6.0.0:
|
||||
resolution: {integrity: sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==}
|
||||
engines: {node: '>=10'}
|
||||
|
|
@ -3035,6 +3048,10 @@ snapshots:
|
|||
|
||||
'@types/estree@1.0.6': {}
|
||||
|
||||
'@types/gsap@3.0.0':
|
||||
dependencies:
|
||||
gsap: 3.13.0
|
||||
|
||||
'@types/node@22.10.1':
|
||||
dependencies:
|
||||
undici-types: 6.20.0
|
||||
|
|
@ -3954,6 +3971,8 @@ snapshots:
|
|||
|
||||
gopd@1.2.0: {}
|
||||
|
||||
gsap@3.13.0: {}
|
||||
|
||||
gzip-size@6.0.0:
|
||||
dependencies:
|
||||
duplexer: 0.1.2
|
||||
|
|
|
|||
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="8.005532264709473" height="9.987500190734863" viewBox="0 0 8.005532264709473 9.987500190734863"><g><path d="M7.23431,5.99L6.02431,5.99C6.02431,5.98,6.02431,5.98,6.02431,5.97L6.02431,1C6.02431,0.45,5.57431,0,5.02431,0L2.99431,0C2.44431,0,1.99431,0.45,1.99431,1L1.99431,5.97C1.99431,5.98,1.99431,5.98,1.99431,5.99L0.77431,5.99C0.0843096,5.99,-0.25569,6.69,0.224309,7.09L3.45431,9.8C3.75431,10.05,4.24431,10.05,4.54431,9.8L7.77431,7.09C8.26431,6.69,7.92431,5.99,7.23431,5.99Z" fill="#FF4E4E" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>
|
||||
|
After Width: | Height: | Size: 668 B |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="8.005532785518852" height="9.987500608192311" viewBox="0 0 8.005532785518852 9.987500608192311"><g transform="matrix(-1,-5.2146120310681e-8,5.2146120310681e-8,-1,16.011064008609537,19.97500163384207)"><path d="M15.239842264709473,15.977500608192312L14.029842264709472,15.977500608192312C14.029842264709472,15.967500608192312,14.029842264709472,15.967500608192312,14.029842264709472,15.957500608192312L14.029842264709472,10.987500608192311C14.029842264709472,10.43750060819231,13.579842264709473,9.987500608192311,13.029842264709472,9.987500608192311L10.999842264709473,9.987500608192311C10.449842264709472,9.987500608192311,9.999842264709473,10.43750060819231,9.999842264709473,10.987500608192311L9.999842264709473,15.957500608192312C9.999842264709473,15.967500608192312,9.999842264709473,15.967500608192312,9.999842264709473,15.977500608192312L8.779842264709472,15.977500608192312C8.089841864709472,15.977500608192312,7.749842264709473,16.67750060819231,8.229841264709473,17.07750060819231L11.459842264709472,19.78750060819231C11.759842264709473,20.03750060819231,12.249842264709471,20.03750060819231,12.549842264709472,19.78750060819231L15.779842264709472,17.07750060819231C16.269842264709474,16.67750060819231,15.929842264709473,15.977500608192312,15.239842264709473,15.977500608192312Z" fill="#4AFFA2" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></svg>
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 86 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="14.13671875" height="17.787841796875" viewBox="0 0 14.13671875 17.787841796875"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_110_5610"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="51.01040005683899%" stop-color="#97BBFF" stop-opacity="1"/><stop offset="52.34435796737671%" stop-color="#1168FF" stop-opacity="1"/><stop offset="100%" stop-color="#1185FF" stop-opacity="1"/></linearGradient><linearGradient x1="0.24648989737033844" y1="0" x2="0.3002182700303045" y2="0.8341024570154847" id="master_svg1_110_5613"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="1"/><stop offset="100%" stop-color="#2D8CFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg2_110_5623"><stop offset="0%" stop-color="#66E0FF" stop-opacity="0"/><stop offset="100%" stop-color="#1164FF" stop-opacity="0.5"/></linearGradient></defs><g><g style="opacity:0.30000001192092896;"><path d="M0.5,2.60546875L13.1633,10.46999875L0.5,17.78786875L0.5,15.87376875L5.18962,10.46999875L0.5,4.66468875L0.5,2.60546875Z" fill-rule="evenodd" fill="#044BB8" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0.5,0.8990478515625L13.1633,8.7635778515625L0.5,16.0814478515625L0.5,14.1673478515625L5.18962,8.7635778515625L0.5,2.9582678515625L0.5,0.8990478515625Z" fill-rule="evenodd" fill="url(#master_svg0_110_5610)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0,0L0,2.95833L0,3.13506L4.53757,8.75214L0,13.9807L0,16.948L14.1359,8.77909L0,0ZM1,2.78161L5.84168,8.77514L1,14.3541L1,15.2151L12.1907,8.74819L1,1.79821L1,2.78161Z" fill-rule="evenodd" fill="url(#master_svg1_110_5613)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g><g><path d="M0.5,0.89892578125L13.1633,8.76345578125L5.18962,8.76345578125L0.5,2.95814578125L0.5,0.89892578125Z" fill-rule="evenodd" fill="url(#master_svg2_110_5623)" fill-opacity="1" style="mix-blend-mode:passthrough"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_95_7905"><stop offset="0%" stop-color="#23518C" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#17439D" stop-opacity="0.10000000149011612"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_95_7906" gradientTransform="translate(272.25 210.25) rotate(90) scale(33.016276359558105 293.6848504078262)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.10000000149011612"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg2_95_7907" gradientTransform="translate(272.25 210.25) rotate(90) scale(7.3813605308532715 170.33950726831247)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_95_7908" gradientTransform="translate(272.25 210.25) rotate(90) scale(3.5998570919036865 121.80235547062695)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0.05106060206890106" x2="0.5" y2="1" id="master_svg4_81_5443"><stop offset="0%" stop-color="#525DFF" stop-opacity="0"/><stop offset="100%" stop-color="#525DFF" stop-opacity="0.47999998927116394"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg5_13_2169" gradientTransform="translate(248.49790859222412 1.25) rotate(0) scale(5.699835777282715 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_13_2170"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient></defs><g><g><path d="M0.25,0.25L544.25,0.25L544.25,210.25L0.25,210.25L0.25,0.25Z" fill-rule="evenodd" fill="#000000" fill-opacity="0.25"/><path d="M0.25,0.25L544.25,0.25L544.25,210.25L0.25,210.25L0.25,0.25Z" fill-rule="evenodd" fill="url(#master_svg0_95_7905)" fill-opacity="1"/><path d="M0.25,0.25L544.25,0.25L544.25,210.25L0.25,210.25L0.25,0.25Z" fill-rule="evenodd" fill="url(#master_svg1_95_7906)" fill-opacity="1"/><path d="M0.25,0.25L544.25,0.25L544.25,210.25L0.25,210.25L0.25,0.25Z" fill-rule="evenodd" fill="url(#master_svg2_95_7907)" fill-opacity="1"/><path d="M0.25,0.25L544.25,0.25L544.25,210.25L0.25,210.25L0.25,0.25Z" fill-rule="evenodd" fill="url(#master_svg3_95_7908)" fill-opacity="1"/><path d="M544.5,0L0,0L0,210.5L544.5,210.5L544.5,0ZM0.5,210L0.5,0.5L544,0.5L544,210L0.5,210Z" fill-rule="evenodd" fill="url(#master_svg4_81_5443)" fill-opacity="1"/></g><g style="opacity:0.44999998807907104;"><path d="M478.25,1.75L287.725,1.75L243.498,1.75L62.25,1.75L62.25,0.75L243.498,0.75L287.725,0.75L478.25,0.75L478.25,1.75Z" fill-rule="evenodd" fill="url(#master_svg5_13_2169)" fill-opacity="1"/><path d="M478.25,1.75L287.725,1.75L243.498,1.75L62.25,1.75L62.25,0.75L243.498,0.75L287.725,0.75L478.25,0.75L478.25,1.75Z" fill-rule="evenodd" fill="url(#master_svg6_13_2170)" fill-opacity="1"/></g></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 544.5 210.75"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_95_7905"><stop offset="0%" stop-color="#23518C" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#17439D" stop-opacity="0.10000000149011612"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_95_7906" gradientTransform="translate(272.25 210.5) rotate(90) scale(33.016276359558105 293.6848504078262)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.10000000149011612"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg2_95_7907" gradientTransform="translate(272.25 210.5) rotate(90) scale(7.3813605308532715 170.33950726831247)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_95_7908" gradientTransform="translate(272.25 210.5) rotate(90) scale(3.5998570919036865 121.80235547062695)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0.05106060206890106" x2="0.5" y2="1" id="master_svg4_81_5443"><stop offset="0%" stop-color="#525DFF" stop-opacity="0"/><stop offset="100%" stop-color="#525DFF" stop-opacity="0.47999998927116394"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg5_13_2169" gradientTransform="translate(250.49790859222412 0.5) rotate(0) scale(5.699835777282715 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_13_2170"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient></defs><g><g><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="#000000" fill-opacity="0.25"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg0_95_7905)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg1_95_7906)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg2_95_7907)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" fill="url(#master_svg3_95_7908)" fill-opacity="1"/><path d="M0.25 0.5C0.25 0.5 0.25 0.5 0.25 0.5L544.25 0.5C544.25 0.5 544.25 0.5 544.25 0.5L544.25 210.5C544.25 210.5 544.25 210.5 544.25 210.5L0.25 210.5C0.25 210.5 0.25 210.5 0.25 210.5Z" stroke="url(#master_svg4_81_5443)" fill-opacity="0" fill="none" stroke-width="0.5"/></g><g style="opacity:0.44999998807907104;"><path d="M480.25,1L289.725,1L245.498,1L64.25,1L64.25,0L245.498,0L289.725,0L480.25,0L480.25,1Z" fill-rule="evenodd" fill="url(#master_svg5_13_2169)" fill-opacity="1"/><path d="M480.25,1L289.725,1L245.498,1L64.25,1L64.25,0L245.498,0L289.725,0L480.25,0L480.25,1Z" fill-rule="evenodd" fill="url(#master_svg6_13_2170)" fill-opacity="1"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 4.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 188 36"><defs><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg0_110_5669"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.4000000059604645"/><stop offset="23.317307233810425%" stop-color="#2773FF" stop-opacity="0.25"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.05999999865889549"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_110_4138" gradientTransform="translate(132.2986946851015 34.756103515625) rotate(76.51046439419082) scale(17.356884100084887 29.26667369717238)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_4139"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient></defs><g><g><path d="M0,1L177.338,1L138.238,30.561L0,30.561L0,1Z" fill-rule="evenodd" fill="url(#master_svg0_110_5669)" fill-opacity="1"/></g><g><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4138)" fill-opacity="1"/><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg2_110_4139)" fill-opacity="1"/></g><g><g><path d="M182.97852,1L294.145,1L288.074,6.2439L176,6.2439L182.97852,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5664)" fill-opacity="1"/></g><g><path d="M182.999984375,1L263.919784375,1L251.97318437500002,11.4878L169.146484375,11.4878L182.999984375,1Z" fill-rule="evenodd" fill="url(#master_svg4_110_5643)" fill-opacity="1"/></g><g style="opacity:0.5;"><g><path d="M184.1035,1L295.464,1L295.464,23.0244L155,23.0244L184.1035,1Z" fill-rule="evenodd" fill="url(#master_svg5_110_5664)" fill-opacity="1"/></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 255 36"><defs><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg0_110_5669"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.4000000059604645"/><stop offset="23.317307233810425%" stop-color="#2773FF" stop-opacity="0.25"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.05999999865889549"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_110_4537" gradientTransform="translate(114.16638627648354 34.756103515625) rotate(78.3045141357308) scale(17.2358897800393 25.079449849220687)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1.578010082244873" y1="0.6616930961608887" x2="-0.00028524507193582627" y2="0.6588591327853952" id="master_svg2_110_4538"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_110_5566" gradientTransform="translate(538.6601538022733 1) rotate(0) scale(9.584570288854593 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5567"><stop offset="0%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#27AEFF" stop-opacity="1"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0.06541949510574341" y2="0.5" id="master_svg7_110_5455"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient></defs><g><g><g><path d="M0,1L217.337,1L178.239,30.561L0,30.561L0,1Z" fill-rule="evenodd" fill="url(#master_svg0_110_5669)" fill-opacity="1"/></g><g><path d="M225.643,1.5L255,1.5L255,0.5L225.305,0.5L181.079,34.2561L0,34.2561L0,35.2561L181.417,35.2561L225.643,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4537)" fill-opacity="1"/><path d="M225.643,1.5L255,1.5L255,0.5L225.305,0.5L181.079,34.2561L0,34.2561L0,35.2561L181.417,35.2561L225.643,1.5Z" fill-rule="evenodd" fill="url(#master_svg2_110_4538)" fill-opacity="1"/></g></g><g><g><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg3_110_5566)" fill-opacity="1"/><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg4_110_5567)" fill-opacity="1"/></g><g><path d="M225.97852,1L924.145,1L918.074,6.2439L219,6.2439L225.97852,1Z" fill-rule="evenodd" fill="url(#master_svg5_110_5664)" fill-opacity="1"/></g><g><path d="M225.3535,1L893.92,1L881.973,11.4878L211.5,11.4878L225.3535,1Z" fill-rule="evenodd" fill="url(#master_svg6_110_5643)" fill-opacity="1"/></g><g><path d="M225.1035,0L924.964,0L924.964,22.0244L197,22.0244L225.1035,0Z" fill-rule="evenodd" fill="url(#master_svg7_110_5455)" fill-opacity="1"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 4.0 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="188 0 108 36"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_110_4138" gradientTransform="translate(132.2986946851015 34.756103515625) rotate(76.51046439419082) scale(17.356884100084887 29.26667369717238)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg1_110_4139"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg4_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="0.9886833429336548" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5647"><stop offset="0%" stop-color="#02DBFF" stop-opacity="0"/><stop offset="100%" stop-color="#01B5FF" stop-opacity="1"/></linearGradient></defs><g><g><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg0_110_4138)" fill-opacity="1"/><path d="M183.644,1.5L295.5,1.5L295.5,0.5L183.306,0.5L139.079,34.2561L0,34.2561L0,35.2561L139.417,35.2561L183.644,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_4139)" fill-opacity="1"/></g><g><g><path d="M182.97852,1L294.145,1L288.074,6.2439L176,6.2439L182.97852,1Z" fill-rule="evenodd" fill="url(#master_svg2_110_5664)" fill-opacity="1"/></g><g><path d="M182.999984375,1L263.919784375,1L251.97318437500002,11.4878L169.146484375,11.4878L182.999984375,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5643)" fill-opacity="1"/></g><g style="opacity:0.5;"><g><path d="M184.1035,1L295.464,1L295.464,23.0244L155,23.0244L184.1035,1Z" fill-rule="evenodd" fill="url(#master_svg4_110_5664)" fill-opacity="1"/></g><g><g><path d="M268.89489541992185,5.195068359375L263.72240541992187,10.438968359375L260.8193054199219,10.438968359375L265.9917854199219,5.195068359375L268.89489541992185,5.195068359375ZM274.9515054199219,5.195068359375L269.78065541992186,10.438968359375L266.8759454199219,10.438968359375L272.0493054199219,5.195068359375L274.9515054199219,5.195068359375ZM281.00820541992186,5.195068359375L275.83480541992185,10.438968359375L272.93260541992186,10.438968359375L278.10600541992187,5.195068359375L281.00820541992186,5.195068359375ZM287.06480541992187,5.195068359375L281.89140541992185,10.438968359375L278.98920541992186,10.438968359375L284.1601054199219,5.195068359375L287.06480541992187,5.195068359375ZM286.9392054199219,10.438968359375L292.11170541992186,5.195068359375L289.20860541992187,5.195068359375L284.03610541992185,10.438968359375L286.9392054199219,10.438968359375Z" fill-rule="evenodd" fill="url(#master_svg5_110_5647)" fill-opacity="1"/></g></g></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="256 0 669 36"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_110_5566" gradientTransform="translate(538.6601538022733 1) rotate(0) scale(9.584570288854593 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg1_110_5567"><stop offset="0%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#27AEFF" stop-opacity="1"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg2_110_5664"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg3_110_5643"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/><stop offset="18.59523504972458%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></linearGradient><linearGradient x1="1" y1="0.5" x2="0.06541949510574341" y2="0.5" id="master_svg4_110_5455"><stop offset="0%" stop-color="#2773FF" stop-opacity="0"/><stop offset="81.4047634601593%" stop-color="#2773FF" stop-opacity="0.21617308259010315"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0.30000001192092896"/></linearGradient><linearGradient x1="0.9886833429336548" y1="0.5" x2="0" y2="0.5" id="master_svg5_110_5647"><stop offset="0%" stop-color="#02DBFF" stop-opacity="0"/><stop offset="100%" stop-color="#01B5FF" stop-opacity="1"/></linearGradient></defs><g><g><g><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg0_110_5566)" fill-opacity="1"/><path d="M925.000609375,1.5L225.474609375,1.5L225.474609375,0.5L925.000609375,0.5L925.000609375,1.5Z" fill-rule="evenodd" fill="url(#master_svg1_110_5567)" fill-opacity="1"/></g><g><path d="M225.97852,1L924.145,1L918.074,6.2439L219,6.2439L225.97852,1Z" fill-rule="evenodd" fill="url(#master_svg2_110_5664)" fill-opacity="1"/></g><g><path d="M225.3535,1L893.92,1L881.973,11.4878L211.5,11.4878L225.3535,1Z" fill-rule="evenodd" fill="url(#master_svg3_110_5643)" fill-opacity="1"/></g><g><path d="M225.1035,0L924.964,0L924.964,22.0244L197,22.0244L225.1035,0Z" fill-rule="evenodd" fill="url(#master_svg4_110_5455)" fill-opacity="1"/></g><g><path d="M898.3959025,4.195068359375L893.2234125,9.438968359375L890.3203125,9.438968359375L895.4927925,4.195068359375L898.3959025,4.195068359375ZM904.4525125,4.195068359375L899.2816625,9.438968359375L896.3769525,9.438968359375L901.5503125,4.195068359375L904.4525125,4.195068359375ZM910.5092125,4.195068359375L905.3358125,9.438968359375L902.4336125,9.438968359375L907.6070125,4.195068359375L910.5092125,4.195068359375ZM916.5658125,4.195068359375L911.3924125,9.438968359375L908.4902125,9.438968359375L913.6611125,4.195068359375L916.5658125,4.195068359375ZM916.4402125,9.438968359375L921.6127125,4.195068359375L918.7096125,4.195068359375L913.5371125,9.438968359375L916.4402125,9.438968359375Z" fill-rule="evenodd" fill="url(#master_svg5_110_5647)" fill-opacity="1"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.4 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 14 22"><defs><pattern x="1.9090908765792847" y="3" width="10.181818008422852" height="16" patternUnits="userSpaceOnUse" id="master_svg0_120_993"><image x="0" y="0" width="42" height="66" transform="scale(0.2424242382957822,0.24242424242424243)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACoAAABCCAYAAAAhZERsAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAOFSURBVGiB7dk/bBN3FMDx77vYlH9qJFKwQQIkaLsUIXXoAgssDIEyVIz8ERJ0AaXAUrUm7YnYAfEnXZspVZmqDqUIZgSICYQU/qwUKSj2ORJDqColuPcYEreWdbbPd7/f7xbedu89nT96z3e+k+F9OI6JGV2VtQHA69Uw/wGDF6r6hQtMt+gJ9TdIzfP4tFLVvS5AqWOspr9lie050f8ahREVprLCxoaWChIgnFXhVhbY2FCA8wX5A+H3LLB9QQEaOUaAOdfYvqH+kMx7yjFgpUts31CA7zfKXVV+Ala7wiaCAgz+TQl4hiNsYujIJ7IQCoeBRRxgE0MBfijINPDj8qFVbCooQKPAZYUHy4fWsGLiJBcD3favMg2sXU79I8qB0ka5Y+L8YGCiAN8V5IXA2ZaU8ckamWgzyjW9CXzZkjI2WSMTbUYDTgBzLSljkzUK9YtSV+HrtrQRrFEowGhBbgBTbenUWONQgPwA3wAv29KpsFag366XN4QcA8K2UmKsFSjA+U1yT4VrEaVEWGtQgMF5RoGnEaW+sUbvo1FRCXSnKg+BFRHl2PdZqxMFKBXkCcpoh3LsyVqHAjSKXFXhfodyLKwTqC8SsvT68qZDS0+sEyjAaFH+EjjTpaUr1vrF1B6Vmv6pcLBLS+QF5myizXgLJ4F6l5bIyTqH+kWpK4z3aFutwk1/Rtc1E86hV2q6RuB0j7ZQhFP+ZnndTDiHLsI14OMuLaEIx0sF+bU16fRiGqvqsAi3u7REIsEhdPyVDoU5ngHFDi0dkeBw9ZrnZxIiwRG0HOgRVQ51KPdEgoPVX5rVLQ2PJ8BgRDkWEixPVFWl4fELKZFgGVoOOANE/Xb3hQSLq79Q1c884RGwsq3UNxIsTXRSNe/BdQwhwRJ0LsBH+LwtnRgJFlZfDnQXyj1goCWdCgmGoVdqumYBpoHtLenUSDC8+gWYwAISDE60UtX9KtxqSRlDgiGoP6sf5Tye8v9vuVEkGFp9XpjEIhIMQCuBHlXhq+VDK0hIufryrG5l6YHjQywiIcVEVVVYeuCwjoQU0PE654A9OEBCwtVXarpD4RGQd4GEJH+DP9cVuvTA4QwJCaADQ/jATpfIvmM80N3lmi5WAj3q+rNjf0f9uq7NhTwWoZzFJHNxG/MhV8kIGTvGqjpcDvRI1o6u4c/ourFA92Xt6BmXXmvUq+776BTvAA46hzw7ExF1AAAAAElFTkSuQmCC"/></pattern></defs><g><g><rect x="1.9090908765792847" y="3" width="10.181818008422852" height="16" rx="0" fill="url(#master_svg0_120_993)" fill-opacity="1"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
|
@ -1 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 127 130.5"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_85_02406" gradientTransform="translate(62.63833460211754 260.6206922531128) rotate(90) scale(129.7585763875395 128.02340110725947)"><stop offset="0%" stop-color="#4EAAFF" stop-opacity="1"/><stop offset="36.93000078201294%" stop-color="#0066FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#000000" stop-opacity="0"/></radialGradient></defs><g><g transform="matrix(1,0,0,-1,0,261)" style="opacity:0.10000000149011612;"><path d="M63.5,130.5C28.4311,130.5,0,188.7103,0,260.5C0,260.5,127,260.5,127,260.5C127,188.6801,98.5743,130.5,63.5,130.5C63.5,130.5,63.5,130.5,63.5,130.5Z" fill="url(#master_svg0_85_02406)" fill-opacity="1"/></g><g style="opacity:0.20000000298023224;"><path d="M127,102L1,102L1,101L127,101L127,102Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M126,1L0,1L0,0L126,0L126,1Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M12,1L0,1L0,0L12,0L12,1Z" fill-rule="evenodd" fill="#00AAFF" fill-opacity="1"/></g></g></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="127" height="104" viewBox="0 0 127 104"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_85_02406" gradientTransform="translate(62.63833460211754 261.1206922531128) rotate(90) scale(129.7585763875395 128.02340110725947)"><stop offset="0%" stop-color="#4EAAFF" stop-opacity="1"/><stop offset="36.93000078201294%" stop-color="#0066FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#000000" stop-opacity="0"/></radialGradient></defs><g><g transform="matrix(1,0,0,-1,0,262)" style="opacity:0.10000000149011612;"><path d="M63.5,131C28.4311,131,0,189.2103,0,261C0,261,127,261,127,261C127,189.1801,98.5743,131,63.5,131C63.5,131,63.5,131,63.5,131Z" fill="url(#master_svg0_85_02406)" fill-opacity="1"/></g><g style="opacity:0.20000000298023224;"><path d="M127,102.5L1,102.5L1,101.5L127,101.5L127,102.5Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M126,1.5L0,1.5L0,0.5L126,0.5L126,1.5Z" fill-rule="evenodd" fill="#0867A2" fill-opacity="1"/></g><g><path d="M12,1.5L0,1.5L0,0.5L12,0.5L12,1.5Z" fill-rule="evenodd" fill="#00AAFF" fill-opacity="1"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 55 121"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_85_7578"><stop offset="0%" stop-color="#0085FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#0047FF" stop-opacity="0"/></linearGradient><linearGradient x1="0.49977484345436096" y1="0.9948660731315613" x2="0.49977484345436096" y2="0.000026565079679130577" id="master_svg1_73_6481"><stop offset="0%" stop-color="#0058FF" stop-opacity="0"/><stop offset="100%" stop-color="#00AAFF" stop-opacity="0.5"/></linearGradient><linearGradient x1="0" y1="0.5" x2="1.0000001192092896" y2="0.5" id="master_svg2_73_6482"><stop offset="0%" stop-color="#0066FF" stop-opacity="1"/><stop offset="12.5%" stop-color="#0066FF" stop-opacity="1"/><stop offset="49.73750710487366%" stop-color="#87D4FF" stop-opacity="1"/><stop offset="91.14583134651184%" stop-color="#0075FF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg3_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg4_13_2583"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="0"/><stop offset="100%" stop-color="#FFFFFF" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg5_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5000787973403931" y1="0.9994168281555176" x2="0.5000787973403931" y2="0" id="master_svg6_85_5542"><stop offset="0%" stop-color="#00C9FF" stop-opacity="1"/><stop offset="100%" stop-color="#0072DD" stop-opacity="1"/></linearGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg7_13_2583"><stop offset="0%" stop-color="#FFFFFF" stop-opacity="0"/><stop offset="100%" stop-color="#FFFFFF" stop-opacity="1"/></linearGradient></defs><g><g style="opacity:0.30000001192092896;"><path d="M1,111C1,113.761,3.23858,116,6,116L49,116C51.7614,116,54,113.761,54,111L54,4L1,4L1,111Z" fill="url(#master_svg0_85_7578)" fill-opacity="1"/></g><g><rect x="1" y="85" width="53" height="30" rx="0" fill="url(#master_svg1_73_6481)" fill-opacity="1" id="pw1" /><rect id="pw2" x="1" y="85" width="53" height="30" rx="0" fill="url(#master_svg2_73_6482)" fill-opacity="0.6000000238418579"/></g><g><ellipse cx="27.5" cy="5" rx="26.5" ry="5" fill="url(#master_svg3_85_5542)" fill-opacity="1"/></g><g><path d="M53.3333,5C53.3333,5.498801,52.8377,6.0743100000000005,51.576,6.68445C50.3307,7.28672,48.4753,7.85205,46.1077,8.33633C41.3823,9.30283,34.8033,9.909089999999999,27.5,9.909089999999999C27.5,9.909089999999999,27.5,11,27.5,11C34.924,11,41.6783,10.38521,46.6047,9.37758C49.063,8.87476,51.1127,8.26474,52.5663,7.56187C54.0033,6.86686,55,6.00743,55,5C55,5,53.3333,5,53.3333,5C53.3333,5,53.3333,5,53.3333,5ZM27.5,9.909089999999999C20.1965,9.909089999999999,13.6176,9.30283,8.89237,8.33633C6.52483,7.85205,4.6695,7.28672,3.42413,6.68445C2.16246,6.0743100000000005,1.66667,5.498801,1.66667,5C1.66667,5,0,5,0,5C0,6.00743,0.996595,6.86686,2.43374,7.56187C3.88718,8.26474,5.9371,8.87476,8.39527,9.37758C13.3215,10.38521,20.0759,11,27.5,11C27.5,11,27.5,9.909089999999999,27.5,9.909089999999999C27.5,9.909089999999999,27.5,9.909089999999999,27.5,9.909089999999999Z" fill="url(#master_svg4_13_2583)" fill-opacity="1"/></g><g><ellipse id="ellipse1" cx="27.5" cy="85" rx="26.5" ry="5" fill="url(#master_svg5_85_5542)" fill-opacity="1"/></g><g><ellipse cx="27.5" cy="115" rx="26.5" ry="5" fill="url(#master_svg6_85_5542)" fill-opacity="1"/></g><g><path d="M53.3333,115C53.3333,115.498801,52.8377,116.07431,51.576,116.68445C50.3307,117.28672,48.4753,117.85205,46.1077,118.33633C41.3823,119.30283,34.8033,119.90909,27.5,119.90909C27.5,119.90909,27.5,121,27.5,121C34.924,121,41.6783,120.38521,46.6047,119.37758C49.063,118.87476,51.1127,118.26474,52.5663,117.56187C54.0033,116.86686,55,116.00743,55,115C55,115,53.3333,115,53.3333,115C53.3333,115,53.3333,115,53.3333,115ZM27.5,119.90909C20.1965,119.90909,13.6176,119.30283,8.89237,118.33633C6.52483,117.85205,4.6695,117.28672,3.42413,116.68445C2.16246,116.07431,1.66667,115.498801,1.66667,115C1.66667,115,0,115,0,115C0,116.00743,0.996595,116.86686,2.43374,117.56187C3.88718,118.26474,5.9371,118.87476,8.39527,119.37758C13.3215,120.38521,20.0759,121,27.5,121C27.5,121,27.5,119.90909,27.5,119.90909C27.5,119.90909,27.5,119.90909,27.5,119.90909Z" fill="url(#master_svg7_13_2583)" fill-opacity="1"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="312.5" height="210.75" viewBox="0 0 312.5 210.75"><defs><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg0_95_7905"><stop offset="0%" stop-color="#23518C" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#17439D" stop-opacity="0.10000000149011612"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg1_95_7906" gradientTransform="translate(156.25 210.5) rotate(90) scale(33.016276359558105 168.4368994986062)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.10000000149011612"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg2_95_7907" gradientTransform="translate(156.25 210.5) rotate(90) scale(7.3813605308532715 97.69471740388508)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.20000000298023224"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg3_95_7908" gradientTransform="translate(156.25 210.5) rotate(90) scale(3.5998570919036865 69.85723328462429)"><stop offset="0%" stop-color="#2773FF" stop-opacity="0.5"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0.05106060206890106" x2="0.5" y2="1" id="master_svg4_81_5443"><stop offset="0%" stop-color="#525DFF" stop-opacity="0"/><stop offset="100%" stop-color="#525DFF" stop-opacity="0.47999998927116394"/></linearGradient><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg5_13_2169" gradientTransform="translate(139.9359314441681 0.5) rotate(0) scale(4.274876832962036 Infinity)"><stop offset="0%" stop-color="#4FE4FF" stop-opacity="1"/><stop offset="100%" stop-color="#2773FF" stop-opacity="0"/></radialGradient><linearGradient x1="1" y1="0.5" x2="0" y2="0.5" id="master_svg6_13_2170"><stop offset="0%" stop-color="#36C8FF" stop-opacity="0"/><stop offset="53.635478019714355%" stop-color="#27AEFF" stop-opacity="1"/><stop offset="100%" stop-color="#1997FF" stop-opacity="0.20000000298023224"/></linearGradient></defs><g><g><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="#000000" fill-opacity="0.25"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg0_95_7905)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg1_95_7906)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg2_95_7907)" fill-opacity="1"/><path d="M0.25,0.5L312.25,0.5L312.25,210.5L0.25,210.5L0.25,0.5Z" fill-rule="evenodd" fill="url(#master_svg3_95_7908)" fill-opacity="1"/><path d="M312.5,0.25L0,0.25L0,210.75L312.5,210.75L312.5,0.25ZM0.5,210.25L0.5,0.75L312,0.75L312,210.25L0.5,210.25Z" fill-rule="evenodd" fill="url(#master_svg4_81_5443)" fill-opacity="1"/></g><g style="opacity:0.4000000059604645;"><path d="M312.25,1L220.432,1L177.243,1L0.25,1L0.25,0L177.243,0L220.432,0L312.25,0L312.25,1Z" fill-rule="evenodd" fill="url(#master_svg5_13_2169)" fill-opacity="1"/><path d="M312.25,1L220.432,1L177.243,1L0.25,1L0.25,0L177.243,0L220.432,0L312.25,0L312.25,1Z" fill-rule="evenodd" fill="url(#master_svg6_13_2170)" fill-opacity="1"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
|
@ -1,5 +0,0 @@
|
|||
<template>
|
||||
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup></script>
|
||||
|
|
@ -1,315 +0,0 @@
|
|||
<template>
|
||||
<div class="chart-container" v-echartResize>
|
||||
<div class="chart" ref="chartRef"></div>
|
||||
<!-- 底座背景 -->
|
||||
<div class="bg"></div>
|
||||
<!-- 中间文字 -->
|
||||
<div class="center-text">
|
||||
<div class="value">{{ totalValue }}</div>
|
||||
<div class="unit">人</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, onBeforeUnmount, reactive, computed } from 'vue'
|
||||
import { getPie3D, getParametricEquation } from '@/composables/useEchart'
|
||||
import * as echarts from 'echarts'
|
||||
import 'echarts-gl' // 3d图表库
|
||||
import { fitChartSize } from '@/utils/echartData'
|
||||
import { vEchartResize } from '@/directives/chart-resize'
|
||||
|
||||
const color = ['#5AF3B8', '#93DBFF']
|
||||
|
||||
const props = defineProps({
|
||||
optionData: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
})
|
||||
|
||||
// refs
|
||||
const chartRef = ref(null)
|
||||
let statusChart = ref(null)
|
||||
|
||||
// 计算数据总和
|
||||
const totalValue = computed(() => {
|
||||
return props.optionData.reduce((sum, item) => sum + item.value, 0)
|
||||
})
|
||||
|
||||
const option = reactive({})
|
||||
|
||||
// 初始化label样式
|
||||
const setLabel = () => {
|
||||
props.optionData.forEach((item, index) => {
|
||||
item.itemStyle = {
|
||||
color: color[index]
|
||||
}
|
||||
item.label = {
|
||||
show: true,
|
||||
color: color[index],
|
||||
formatter: '{b} {d}%', // 简化格式化字符串,避免使用数组join和富文本
|
||||
rich: {
|
||||
b: {
|
||||
color: color[index],
|
||||
lineHeight: 25,
|
||||
align: 'left',
|
||||
fontSize: 12,
|
||||
},
|
||||
d: {
|
||||
color: color[index],
|
||||
align: 'left',
|
||||
fontSize: 12
|
||||
}
|
||||
}
|
||||
}
|
||||
item.labelLine = {
|
||||
lineStyle: {
|
||||
width: 1,
|
||||
color: color[index]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 图表初始化
|
||||
const initChart = () => {
|
||||
statusChart.value = echarts.init(chartRef.value)
|
||||
// 传入数据生成 option, 构建3d饼状图, 参数工具文件已经备注的很详细
|
||||
Object.assign(option, getPie3D(props.optionData, 0.8, 240, 36, 13, 0.5))
|
||||
statusChart.value.setOption(option)
|
||||
// 是否需要label指引线,如果要就添加一个透明的2d饼状图并调整角度使得labelLine和3d的饼状图对齐,并再次setOption
|
||||
option.series.push({
|
||||
name: '', //自己根据场景修改
|
||||
backgroundColor: 'transparent',
|
||||
type: 'pie',
|
||||
label: {
|
||||
opacity: 1,
|
||||
fontSize: 12,
|
||||
},
|
||||
startAngle: -40, // 起始角度,支持范围[0, 360]。
|
||||
clockwise: false, // 饼图的扇区是否是顺时针排布。上述这两项配置主要是为了对齐3d的样式
|
||||
radius: ['20%', '50%'],
|
||||
center: ['50%', '50%'],
|
||||
data: props.optionData,
|
||||
itemStyle: {
|
||||
opacity: 0 //这里必须是0,不然2d的图会覆盖在表面
|
||||
}
|
||||
})
|
||||
statusChart.value.setOption(option)
|
||||
bindListen(statusChart.value)
|
||||
}
|
||||
|
||||
// 监听鼠标事件,实现饼图选中效果(单选),近似实现高亮(放大)效果。
|
||||
// optionName是防止有多个图表进行定向option传递,单个图表可以不传,默认是opiton
|
||||
const bindListen = (myChart) => {
|
||||
let selectedIndex = ''
|
||||
let hoveredIndex = ''
|
||||
// 监听点击事件,实现选中效果(单选)
|
||||
myChart.on('click', (params) => {
|
||||
// 确保params.seriesIndex有效且对应的对象存在
|
||||
if (params.seriesIndex === undefined || !option.series[params.seriesIndex] || !option.series[params.seriesIndex].pieStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 从 option.series 中读取重新渲染扇形所需的参数,将是否选中取反。
|
||||
const isSelected = !option.series[params.seriesIndex].pieStatus.selected
|
||||
const isHovered = option.series[params.seriesIndex].pieStatus.hovered
|
||||
const k = option.series[params.seriesIndex].pieStatus.k
|
||||
const startRatio = option.series[params.seriesIndex].pieData.startRatio
|
||||
const endRatio = option.series[params.seriesIndex].pieData.endRatio
|
||||
// 如果之前选中过其他扇形,将其取消选中(对 option 更新)
|
||||
if (selectedIndex !== '' && selectedIndex !== params.seriesIndex &&
|
||||
option.series[selectedIndex] && option.series[selectedIndex].pieStatus) {
|
||||
option.series[selectedIndex].parametricEquation = getParametricEquation(
|
||||
option.series[selectedIndex].pieData.startRatio,
|
||||
option.series[selectedIndex].pieData.endRatio,
|
||||
false,
|
||||
false,
|
||||
k,
|
||||
option.series[selectedIndex].pieData.value
|
||||
)
|
||||
option.series[selectedIndex].pieStatus.selected = false
|
||||
}
|
||||
// 对当前点击的扇形,执行选中/取消选中操作(对 option 更新)
|
||||
option.series[params.seriesIndex].parametricEquation = getParametricEquation(
|
||||
startRatio,
|
||||
endRatio,
|
||||
isSelected,
|
||||
isHovered,
|
||||
k,
|
||||
option.series[params.seriesIndex].pieData.value
|
||||
)
|
||||
option.series[params.seriesIndex].pieStatus.selected = isSelected
|
||||
// 如果本次是选中操作,记录上次选中的扇形对应的系列号 seriesIndex
|
||||
selectedIndex = isSelected ? params.seriesIndex : null
|
||||
// 使用更新后的 option,渲染图表
|
||||
myChart.setOption(option)
|
||||
})
|
||||
|
||||
// 监听 mouseover,近似实现高亮(放大)效果
|
||||
myChart.on('mouseover', (params) => {
|
||||
// 准备重新渲染扇形所需的参数
|
||||
let isSelected
|
||||
let isHovered
|
||||
let startRatio
|
||||
let endRatio
|
||||
let k
|
||||
// 如果触发 mouseover 的扇形当前已高亮,则不做操作
|
||||
if (hoveredIndex === params.seriesIndex) {
|
||||
// 否则进行高亮及必要的取消高亮操作
|
||||
} else {
|
||||
// 如果当前有高亮的扇形,取消其高亮状态(对 option 更新)
|
||||
if (hoveredIndex !== '' && option.series[hoveredIndex] && option.series[hoveredIndex].pieStatus) {
|
||||
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 false。
|
||||
isSelected = option.series[hoveredIndex].pieStatus.selected
|
||||
isHovered = false
|
||||
startRatio = option.series[hoveredIndex].pieData.startRatio
|
||||
endRatio = option.series[hoveredIndex].pieData.endRatio
|
||||
k = option.series[hoveredIndex].pieStatus.k
|
||||
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
|
||||
option.series[hoveredIndex].parametricEquation = getParametricEquation(
|
||||
startRatio,
|
||||
endRatio,
|
||||
isSelected,
|
||||
isHovered,
|
||||
k,
|
||||
option.series[hoveredIndex].pieData.value
|
||||
)
|
||||
option.series[hoveredIndex].pieStatus.hovered = isHovered
|
||||
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
|
||||
hoveredIndex = ''
|
||||
}
|
||||
// 如果触发 mouseover 的扇形不是透明圆环,将其高亮(对 option 更新)
|
||||
if (
|
||||
params.seriesName !== 'mouseoutSeries' &&
|
||||
params.seriesName !== 'pie2d' &&
|
||||
params.seriesIndex !== undefined &&
|
||||
option.series[params.seriesIndex] &&
|
||||
option.series[params.seriesIndex].pieStatus
|
||||
) {
|
||||
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
|
||||
isSelected = option.series[params.seriesIndex].pieStatus.selected
|
||||
isHovered = true
|
||||
startRatio = option.series[params.seriesIndex].pieData.startRatio
|
||||
endRatio = option.series[params.seriesIndex].pieData.endRatio
|
||||
k = option.series[params.seriesIndex].pieStatus.k
|
||||
// 对当前点击的扇形,执行高亮操作(对 option 更新)
|
||||
option.series[params.seriesIndex].parametricEquation = getParametricEquation(
|
||||
startRatio,
|
||||
endRatio,
|
||||
isSelected,
|
||||
isHovered,
|
||||
k,
|
||||
option.series[params.seriesIndex].pieData.value + 60
|
||||
)
|
||||
option.series[params.seriesIndex].pieStatus.hovered = isHovered
|
||||
// 记录上次高亮的扇形对应的系列号 seriesIndex
|
||||
hoveredIndex = params.seriesIndex
|
||||
}
|
||||
// 使用更新后的 option,渲染图表
|
||||
myChart.setOption(option)
|
||||
}
|
||||
})
|
||||
|
||||
// 修正取消高亮失败的 bug
|
||||
myChart.on('globalout', () => {
|
||||
// 准备重新渲染扇形所需的参数
|
||||
let isSelected
|
||||
let isHovered
|
||||
let startRatio
|
||||
let endRatio
|
||||
let k
|
||||
if (hoveredIndex !== '' && option.series[hoveredIndex] && option.series[hoveredIndex].pieStatus) {
|
||||
// 从 option.series 中读取重新渲染扇形所需的参数,将是否高亮设置为 true。
|
||||
isSelected = option.series[hoveredIndex].pieStatus.selected
|
||||
isHovered = false
|
||||
k = option.series[hoveredIndex].pieStatus.k
|
||||
startRatio = option.series[hoveredIndex].pieData.startRatio
|
||||
endRatio = option.series[hoveredIndex].pieData.endRatio
|
||||
// 对当前点击的扇形,执行取消高亮操作(对 option 更新)
|
||||
option.series[hoveredIndex].parametricEquation = getParametricEquation(
|
||||
startRatio,
|
||||
endRatio,
|
||||
isSelected,
|
||||
isHovered,
|
||||
k,
|
||||
option.series[hoveredIndex].pieData.value
|
||||
)
|
||||
option.series[hoveredIndex].pieStatus.hovered = isHovered
|
||||
// 将此前记录的上次选中的扇形对应的系列号 seriesIndex 清空
|
||||
hoveredIndex = ''
|
||||
}
|
||||
// 使用更新后的 option,渲染图表
|
||||
myChart.setOption(option)
|
||||
})
|
||||
}
|
||||
|
||||
// 自适应宽高
|
||||
// const changeSize = () => {
|
||||
// statusChart.value?.resize()
|
||||
// }
|
||||
|
||||
// 生命周期钩子
|
||||
onMounted(() => {
|
||||
setLabel()
|
||||
initChart()
|
||||
|
||||
// 根据窗口变化自动调节图表大小
|
||||
// window.addEventListener('resize', changeSize)
|
||||
})
|
||||
|
||||
// onBeforeUnmount(() => {
|
||||
// window.removeEventListener('resize', changeSize)
|
||||
// })
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.chart-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
.chart,
|
||||
.bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.bg {
|
||||
position: absolute;
|
||||
bottom: 50px;
|
||||
left: 50%;
|
||||
z-index: -1;
|
||||
width: 180px;
|
||||
height: 73px;
|
||||
background: no-repeat center;
|
||||
background-image: url('/images/particles-bg.png');
|
||||
background-size: 100% 100%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
|
||||
.center-text {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 10;
|
||||
text-align: center;
|
||||
|
||||
.value {
|
||||
display: inline-block;
|
||||
font-size: 24px;
|
||||
font-weight: 500;
|
||||
color: #8FC8FF;
|
||||
}
|
||||
|
||||
.unit {
|
||||
display: inline-block;
|
||||
font-size: 18px;
|
||||
font-weight: 500;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div class="w-full overflow-x-auto ranking-table">
|
||||
<table :style="tableStyle">
|
||||
<!-- 表头插槽 -->
|
||||
<thead v-if="$slots.header">
|
||||
<tr>
|
||||
<th :colspan="columns.length">
|
||||
<slot name="header"></slot>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<!-- 列标题 -->
|
||||
<thead :class="`${headerClass}`">
|
||||
<tr>
|
||||
<th v-for="col in columns" :key="col.field" :style="getWidthStyle(col)">
|
||||
<div :class="`cell-content ${col.align}`">
|
||||
{{ col.header }}
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody :class="`${bodyClass}`">
|
||||
<tr v-for="(row, rowIndex) in value" :key="rowIndex">
|
||||
<td v-for="col in columns" :key="col.field" :style="getWidthStyle(col)" :class="`${col.align}`">
|
||||
<div :class="`cell-content ${col.align}`">
|
||||
<slot :name="col.field" :data="row" :index="rowIndex">
|
||||
{{ row[col.field] }}
|
||||
</slot>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<!-- 表尾插槽 -->
|
||||
<tfoot v-if="$slots.footer">
|
||||
<tr>
|
||||
<td :colspan="columns.length">
|
||||
<slot name="footer"></slot>
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
interface Column {
|
||||
field: string;
|
||||
header: string;
|
||||
width?: string;
|
||||
minWidth?: string;
|
||||
maxWidth?: string;
|
||||
align?: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
value: any[];
|
||||
columns: Column[];
|
||||
tableStyle?: string;
|
||||
headerClass?: string;
|
||||
bodyClass?:string;
|
||||
}
|
||||
|
||||
defineProps<Props>();
|
||||
|
||||
const getWidthStyle = (col: Column) => {
|
||||
const style: Record<string, string> = {};
|
||||
if (col.width) style.width = col.width;
|
||||
if (col.minWidth) style.minWidth = col.minWidth;
|
||||
if (col.maxWidth) style.maxWidth = col.maxWidth;
|
||||
return style;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.cell-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
|
||||
/* 自定义滚动条样式 */
|
||||
.ranking-table::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.ranking-table::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.ranking-table::-webkit-scrollbar-track {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
</style>
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
|
||||
html {
|
||||
line-height: 1.15;
|
||||
line-height: 1;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
body {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
.border-image {
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
#217ac600,
|
||||
#227cc8,
|
||||
#217ac600
|
||||
)
|
||||
1 1;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div class="w-[926px] h-[358px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">咨询学段</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[255px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[669px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px]">
|
||||
<AskSectionChart />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import AskSectionChart from "@/views/components/chartsComponents/AskSectionChart.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
<template>
|
||||
<div class="border-container">
|
||||
<div class="border-glow"></div>
|
||||
<div class="border-inner p-[2px]">
|
||||
<slot></slot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "BackgroundColor",
|
||||
data() {
|
||||
return {
|
||||
animationFrame: null,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
this.startAnimation();
|
||||
},
|
||||
beforeUnmount() {
|
||||
if (this.animationFrame) {
|
||||
cancelAnimationFrame(this.animationFrame);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startAnimation() {
|
||||
const borderGlow = document.querySelector(".border-glow");
|
||||
let angle = 0;
|
||||
|
||||
const animate = () => {
|
||||
angle = (angle + 1) % 360;
|
||||
if (borderGlow) {
|
||||
borderGlow.style.background = `conic-gradient(
|
||||
from ${angle}deg,
|
||||
hsla(0, 0%, 0%, 0.25),
|
||||
hsla(214, 60%, 34%, 0.2),
|
||||
hsla(220, 74%, 35%, 0.1),
|
||||
hsla(219, 100%, 58%, 0.1),
|
||||
hsla(219, 100%, 58%, 0.2),
|
||||
hsla(219, 100%, 58%, 0.5),
|
||||
hsla(219, 100%, 58%, 0)
|
||||
)`;
|
||||
}
|
||||
this.animationFrame = requestAnimationFrame(animate);
|
||||
};
|
||||
|
||||
animate();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.border-container {
|
||||
position: relative;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.border-glow {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
width: auto;
|
||||
height: auto;
|
||||
background: conic-gradient(
|
||||
from 0deg,
|
||||
hsla(0, 0%, 0%, 0.25),
|
||||
hsla(214, 60%, 34%, 0.2),
|
||||
hsla(220, 74%, 35%, 0.1),
|
||||
hsla(219, 100%, 58%, 0.1),
|
||||
hsla(219, 100%, 58%, 0.2),
|
||||
hsla(219, 100%, 58%, 0.5),
|
||||
hsla(219, 100%, 58%, 0)
|
||||
);
|
||||
border-radius: inherit;
|
||||
filter: blur(2px);
|
||||
pointer-events: none;
|
||||
mix-blend-mode: plus-lighter;
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
.border-inner {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 0.5px solid hsla(236, 100%, 66%, 0.48);
|
||||
border-radius: inherit;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 内容区域样式 */
|
||||
.border-container > :not(.border-glow):not(.border-inner) {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">收费排行榜</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col relative">
|
||||
<div class="absolute right-[0] flex items-center justify-end mr-[13px] transform-translate-y-[-50%]">
|
||||
<div class="text-[15px] text-[#84E8FF]">更多</div>
|
||||
<SvgComponent :content="moreArrowSvg" class="w-[14px] h-[22px]" />
|
||||
</div>
|
||||
<div class="mt-[26px] mx-[16px]">
|
||||
<RankingTable :value="products" :columns="columns" header-class="custom-table-header" body-class="custom-table-body">
|
||||
<template #rank="{ index }">
|
||||
<SvgComponent :content="goldMedalSvg" class="w-[34px] h-[20px]" v-if="index === 0" />
|
||||
<SvgComponent :content="silverMedalSvg" class="w-[34px] h-[20px]" v-if="index === 1" />
|
||||
<SvgComponent :content="bronzeMedalSvg" class="w-[34px] h-[20px]" v-if="index === 2" />
|
||||
<span class="text-[14px] font-600" v-if="index > 2">{{ index + 1 }}</span>
|
||||
</template>
|
||||
<template #name="{ data }">
|
||||
<span class="text-[#C0EEFF] text-[14px]">{{ data.name }}</span>
|
||||
</template>
|
||||
</RankingTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import RankingTable from "@/components/table/RankingTable.vue";
|
||||
|
||||
const columns = [
|
||||
{ field: "rank", header: "名次", align: "justify-center", width: "68px" },
|
||||
{ field: "name", header: "姓名", align: "justify-left", width: "100px" },
|
||||
{ field: "Status", header: "获客人数", align: "justify-center", width: "96px" },
|
||||
];
|
||||
|
||||
const products = [{ name: "张三" }, { name: "张三" }, { name: "张三" }, { name: "张三" }, { name: "张三" }];
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const moreArrowSvg = ref("");
|
||||
const getMoreArrowSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/more-arrow.svg?raw");
|
||||
moreArrowSvg.value = svg;
|
||||
};
|
||||
|
||||
const goldMedalSvg = ref("");
|
||||
const getGoldMedalSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/gold-medal.svg?raw");
|
||||
goldMedalSvg.value = svg;
|
||||
};
|
||||
|
||||
const silverMedalSvg = ref("");
|
||||
const getSilverMedalSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/silver-medal.svg?raw");
|
||||
silverMedalSvg.value = svg;
|
||||
};
|
||||
|
||||
const bronzeMedalSvg = ref("");
|
||||
const getBronzeMedalSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/bronze-medal.svg?raw");
|
||||
bronzeMedalSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
|
||||
getMoreArrowSvg();
|
||||
|
||||
getGoldMedalSvg();
|
||||
getSilverMedalSvg();
|
||||
getBronzeMedalSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
:deep(.custom-table-header) {
|
||||
tr {
|
||||
background-color: rgb(14, 39, 97);
|
||||
th {
|
||||
padding: 13px 10px;
|
||||
color: #44c1ef;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.custom-table-body) {
|
||||
tr {
|
||||
td {
|
||||
padding: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
<template>
|
||||
<div class="w-max h-max relative">
|
||||
<SvgComponent :content="groupSvg" class="w-[312px] h-[210px]" />
|
||||
<div class="w-full h-full absolute top-0 left-0 pt-[31px] pb-[21px] pl-[14px] pr-[19px] flex items-center">
|
||||
<div class="w-[144px]">
|
||||
<div class="relative w-[144px] h-[113px] flex items-center flex-col">
|
||||
<div class="text-[#44C1EF] italic text-[20px] font-700">今日获客</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent mb-[15px] z-10">
|
||||
<span class="text-[34px] italic">125</span>
|
||||
<span class="text-[18px]">人</span>
|
||||
</div>
|
||||
<SvgComponent :content="hexagonalBoxSvg" class="box-light absolute" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="relative ml-[12px]">
|
||||
<SvgComponent :content="paymentBorderSvg" class="w-[127px] h-[104px] z-1" />
|
||||
<div class="w-[127px] h-[104px] top-0 left-0 z-1 absolute pl-[14px] flex flex-col justify-center">
|
||||
<p class="text-[#C0EEFF] text-[12px]">昨日获客人数</p>
|
||||
<p class="text-[#C0EEFF] text-[16px] font-500 mt-[18px] mb-[9px]">177人</p>
|
||||
<div class="text-[#FF4E4E] text-[12px] flex items-center">
|
||||
<span class="">今日较昨日</span>
|
||||
<SvgIcon name="arrow-up" class="text-[9px]" />
|
||||
<span>12人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
|
||||
|
||||
|
||||
|
||||
const groupSvg = ref("");
|
||||
const getGroupBackgroundSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/short-background.svg?raw");
|
||||
groupSvg.value = svg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const hexagonalBoxSvg = ref("");
|
||||
const getLightningBoxSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/hexagonal-light.svg?raw");
|
||||
hexagonalBoxSvg.value = svg;
|
||||
};
|
||||
|
||||
const paymentBorderSvg = ref("");
|
||||
const getPaymentChartSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/payment-border.svg?raw");
|
||||
paymentBorderSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getGroupBackgroundSvg();
|
||||
getLightningBoxSvg();
|
||||
getPaymentChartSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/text-color.scss";
|
||||
|
||||
.border-image {
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
#217ac600,
|
||||
#227cc8,
|
||||
#217ac600
|
||||
)
|
||||
1 1;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.rotate-animation {
|
||||
animation: rotate-animation 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate-animation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.box-light) {
|
||||
.lightning-flashing {
|
||||
animation: lightning-flashing 1s infinite;
|
||||
}
|
||||
@keyframes lightning-flashing {
|
||||
0% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
50% {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
100% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
<template>
|
||||
<div class="w-max h-max relative">
|
||||
<SvgComponent :content="groupSvg" class="w-[312px] h-[210px]" />
|
||||
<div class="w-full h-full absolute top-0 left-0 pt-[31px] pb-[21px] pl-[14px] pr-[19px] flex items-center">
|
||||
<div class="w-[144px]">
|
||||
<div class="relative w-[144px] h-[113px] flex items-center flex-col">
|
||||
<div class="text-[#44C1EF] italic text-[20px] font-700">总获客</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent mb-[15px] z-10">
|
||||
<span class="text-[34px] italic">125</span>
|
||||
<span class="text-[18px]">人</span>
|
||||
</div>
|
||||
<SvgComponent :content="hexagonalBoxSvg" class="box-light absolute" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="relative ml-[37px] flex flex-col items-center">
|
||||
<span class="text-[#C0EEFF] text-[12px]">目标值2W</span>
|
||||
<SvgComponent :content="powerSvg" class="w-[55px] h-[121px] z-1 my-[4px]" />
|
||||
<span class="text-[#769CBF] text-[12px]">当前值0.5W</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
|
||||
const groupSvg = ref("");
|
||||
const getGroupBackgroundSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/short-background.svg?raw");
|
||||
groupSvg.value = svg;
|
||||
};
|
||||
|
||||
const hexagonalBoxSvg = ref("");
|
||||
const getLightningBoxSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/hexagonal-light.svg?raw");
|
||||
hexagonalBoxSvg.value = svg;
|
||||
};
|
||||
|
||||
const powerFlag = ref(false)
|
||||
const powerSvg = ref("");
|
||||
const getPaymentChartSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/process.svg?raw");
|
||||
powerSvg.value = svg;
|
||||
powerFlag.value = true;
|
||||
};
|
||||
|
||||
const setChargePercentageByPath = (percent: number) => {
|
||||
// 图形宽55 高121 以此建立用户坐标系
|
||||
|
||||
// 这个图形的原本数据为 y="85" height="30"
|
||||
const pw1 = document.querySelector("g rect#pw1");
|
||||
const pw2 = document.querySelector("g rect#pw2");
|
||||
const ellipse1 = document.querySelector("g ellipse#ellipse1");
|
||||
if(pw1 && pw2 && ellipse1) {
|
||||
let rectY = percent / 100 * (85 + 30)
|
||||
|
||||
pw1.setAttribute("y", `${85 + 30 - rectY} `)
|
||||
pw1.setAttribute("height", `${rectY}`)
|
||||
pw2.setAttribute("y", `${85 + 30 - rectY}`)
|
||||
pw2.setAttribute("height", `${rectY}`)
|
||||
ellipse1.setAttribute("cy", `${85 + 30 - rectY}`)
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
watch(powerFlag, () => {
|
||||
nextTick(() => {
|
||||
setChargePercentageByPath(80);
|
||||
});
|
||||
});
|
||||
|
||||
onBeforeMount(() => {
|
||||
getGroupBackgroundSvg();
|
||||
getLightningBoxSvg();
|
||||
getPaymentChartSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/text-color.scss";
|
||||
|
||||
.border-image {
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(90deg, #217ac600, #227cc8, #217ac600) 1 1;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.rotate-animation {
|
||||
animation: rotate-animation 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate-animation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.box-light) {
|
||||
.lightning-flashing {
|
||||
animation: lightning-flashing 1s infinite;
|
||||
}
|
||||
@keyframes lightning-flashing {
|
||||
0% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
50% {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
100% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
<template>
|
||||
<div class="w-max h-max relative">
|
||||
<SvgComponent :content="groupSvg" class="w-[312px] h-[210px]" />
|
||||
<div class="w-full h-full absolute top-0 left-0 pt-[31px] pb-[21px] pl-[14px] pr-[19px] flex items-center">
|
||||
<div class="w-[144px]">
|
||||
<div class="relative w-[144px] h-[113px] flex items-center flex-col">
|
||||
<div class="text-[#44C1EF] italic text-[20px] font-700">今日流失</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent mb-[15px] z-10">
|
||||
<span class="text-[34px] italic">125</span>
|
||||
<span class="text-[18px]">人</span>
|
||||
</div>
|
||||
<SvgComponent :content="hexagonalBoxSvg" class="box-light absolute" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="relative ml-[12px]">
|
||||
<SvgComponent :content="paymentBorderSvg" class="w-[127px] h-[104px] z-1" />
|
||||
<div class="w-[127px] h-[104px] top-0 left-0 z-1 absolute pl-[14px] flex flex-col justify-center">
|
||||
<p class="text-[#C0EEFF] text-[12px]">总流失人数</p>
|
||||
<p class="text-[#C0EEFF] text-[16px] font-500 mt-[18px] mb-[9px]">177人</p>
|
||||
<div class="text-[#FF4E4E] text-[12px] flex items-center">
|
||||
<span class="">今日较昨日</span>
|
||||
<SvgIcon name="arrow-up" class="text-[9px]" />
|
||||
<span>12人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
|
||||
|
||||
|
||||
|
||||
const groupSvg = ref("");
|
||||
const getGroupBackgroundSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/short-background.svg?raw");
|
||||
groupSvg.value = svg;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const hexagonalBoxSvg = ref("");
|
||||
const getLightningBoxSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/hexagonal-light.svg?raw");
|
||||
hexagonalBoxSvg.value = svg;
|
||||
};
|
||||
|
||||
const paymentBorderSvg = ref("");
|
||||
const getPaymentChartSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/payment-border.svg?raw");
|
||||
paymentBorderSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getGroupBackgroundSvg();
|
||||
getLightningBoxSvg();
|
||||
getPaymentChartSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/text-color.scss";
|
||||
|
||||
.border-image {
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
#217ac600,
|
||||
#227cc8,
|
||||
#217ac600
|
||||
)
|
||||
1 1;
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.rotate-animation {
|
||||
animation: rotate-animation 1s infinite;
|
||||
}
|
||||
|
||||
@keyframes rotate-animation {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.box-light) {
|
||||
.lightning-flashing {
|
||||
animation: lightning-flashing 1s infinite;
|
||||
}
|
||||
@keyframes lightning-flashing {
|
||||
0% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
50% {
|
||||
fill-opacity: 1;
|
||||
}
|
||||
100% {
|
||||
fill-opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">线下详情</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col">
|
||||
<div class="ml-[22px] relative mt-[13px]">
|
||||
<div class="flex items-center justify-center">
|
||||
<ProportionCharts :chart-data="chartData" class="z-2 relative" />
|
||||
<SvgComponent :content="paymentChartSvg" class="w-[143px] h-[143px] absolute top-0 left-[50%] z-1 transform-translate-x-[-50%]" />
|
||||
</div>
|
||||
<div class="leading-[1] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-3 flex items-center flex-col font-700 italic">
|
||||
<div
|
||||
class=" bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent flex items-baseline">
|
||||
<div class="text-[25px] ">
|
||||
690
|
||||
</div>
|
||||
<div class="text-[20px]">人</div>
|
||||
</div>
|
||||
<div class="text-[#FFFFFF] text-[16px] text-shadow-[0px_2px_2px_rgba(12,32,72,0.42)] mt-[7px]">线下</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="px-[24px] grid grid-cols-2 gap-x-[20px] gap-y-[16px] mt-[20px] leading-[1]">
|
||||
<li class="flex items-center flex-col" v-for="item in chartData" :key="item.name">
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="w-[6px] h-[6px] rounded-full" :style="{ backgroundColor: item.color }"></div>
|
||||
<div class="flex-1 flex items-center text-[#C0EEFF] text-[12px] justify-between">
|
||||
<span class="ml-[4px] mr-[9px]">{{ item.name }}</span>
|
||||
<span>{{ item.value }}人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-image w-full mt-[6px]"></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import ProportionCharts from "@/views/components/chartsComponents/ProportionCharts.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const paymentChartSvg = ref("");
|
||||
const getPaymentChartSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/payment-chart.svg?raw");
|
||||
paymentChartSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
const chartData = ref([
|
||||
{ name: "类型A", value: 250, color: "#0783FA" },
|
||||
{ name: "类型B", value: 274, color: "#07D1FA" },
|
||||
{ name: "类型C", value: 310, color: "#20E6A4" },
|
||||
{ name: "类型D", value: 135, color: "#FFD15C" },
|
||||
{ name: "其他", value: 135, color: "#07D1FA" },
|
||||
]);
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
getPaymentChartSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/custom-border.scss";
|
||||
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">线上详情</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col">
|
||||
<div class="ml-[22px] relative mt-[13px]">
|
||||
<div class="flex items-center justify-center">
|
||||
<ProportionCharts :chart-data="chartData" class="z-2 relative" />
|
||||
<SvgComponent :content="paymentChartSvg" class="w-[143px] h-[143px] absolute top-0 left-[50%] z-1 transform-translate-x-[-50%]" />
|
||||
</div>
|
||||
<div class="leading-[1] absolute top-[50%] left-[50%] translate-x-[-50%] translate-y-[-50%] z-3 flex items-center flex-col font-700 italic">
|
||||
<div
|
||||
class=" bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent flex items-baseline">
|
||||
<div class="text-[25px] ">
|
||||
690
|
||||
</div>
|
||||
<div class="text-[20px]">人</div>
|
||||
</div>
|
||||
<div class="text-[#FFFFFF] text-[16px] text-shadow-[0px_2px_2px_rgba(12,32,72,0.42)] mt-[7px]">线上</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="px-[24px] grid grid-cols-2 gap-x-[20px] gap-y-[16px] mt-[20px] leading-[1]">
|
||||
<li class="flex items-center flex-col" v-for="item in chartData" :key="item.name">
|
||||
<div class="flex items-center justify-between w-full">
|
||||
<div class="w-[6px] h-[6px] rounded-full" :style="{ backgroundColor: item.color }"></div>
|
||||
<div class="flex-1 flex items-center text-[#C0EEFF] text-[12px] justify-between">
|
||||
<span class="ml-[4px] mr-[9px]">{{ item.name }}</span>
|
||||
<span>{{ item.value }}人</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border-image w-full m-[6px]"></div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import ProportionCharts from "@/views/components/chartsComponents/ProportionCharts.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const paymentChartSvg = ref("");
|
||||
const getPaymentChartSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/payment-chart.svg?raw");
|
||||
paymentChartSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
const chartData = ref([
|
||||
{ name: "类型A", value: 250, color: "#0783FA" },
|
||||
{ name: "类型B", value: 274, color: "#07D1FA" },
|
||||
{ name: "类型C", value: 310, color: "#20E6A4" },
|
||||
{ name: "类型D", value: 135, color: "#FFD15C" },
|
||||
]);
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
getPaymentChartSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/custom-border.scss";
|
||||
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<div class="w-[926px] h-[358px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">经营趋势</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[255px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[669px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px]">
|
||||
<OperatingTrendsChart />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import OperatingTrendsChart from "@/views/components/chartsComponents/OperatingTrendsChart.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -50,7 +50,7 @@
|
|||
<script lang="ts" setup>
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import YProgress from "@/components/progress/YProgress.vue";
|
||||
import ProportionCharts from "@/views/components/ProportionCharts.vue";
|
||||
import ProportionCharts from "@/views/components/chartsComponents/ProportionCharts.vue";
|
||||
|
||||
const groupSvg = ref("");
|
||||
const getGroupBackgroundSvg = async () => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,77 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">六纬志愿</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col relative">
|
||||
<div class="absolute right-[0] flex items-center justify-end mr-[13px] transform-translate-y-[-50%]">
|
||||
<div class="text-[15px] text-[#84E8FF]">更多</div>
|
||||
<SvgComponent :content="moreArrowSvg" class="w-[14px] h-[22px]"/>
|
||||
</div>
|
||||
<div class="flex items-baseline leading-[1] mt-[29px] mx-[27px]">
|
||||
<div class="text-[#44C1EF] italic text-[20px] font-700">总获客</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[40px] font-700 italic pr-[4px]">189</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[18px] font-700">人</div>
|
||||
<SvgIcon name="arrow-up" class="text-[9px] text-[#4AFFA2] ml-[9px]" />
|
||||
</div>
|
||||
<SixStatisticsChart />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
|
||||
import SixStatisticsChart from "@/views/components/chartsComponents/SixStatisticsChart.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const moreArrowSvg = ref("");
|
||||
const getMoreArrowSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/more-arrow.svg?raw");
|
||||
moreArrowSvg.value = svg;
|
||||
};
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
|
||||
getMoreArrowSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">学生来源</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col">
|
||||
<StudentSourceChart
|
||||
class="w-full h-full"
|
||||
:chartData="[
|
||||
{ name: '线下', value: 240, itemStyle: { color: 'rgba(147, 219, 255, 1)' } },
|
||||
{ name: '线上', value: 600, itemStyle: { color: 'rgb(79, 214, 169)' } },
|
||||
]"
|
||||
:ringSize="0.8" />
|
||||
<div class="flex items-center justify-between mx-[20px] my-[33px]">
|
||||
<div class="flex items-center">
|
||||
<SvgComponent :content="onlineSvg" class="w-[53px] h-[38px]" />
|
||||
<div class="flex flex-col ml-[9px] items-center">
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent font-700">
|
||||
<span class="text-[18px]">240</span>
|
||||
<span class="text-[14px]">人</span>
|
||||
</div>
|
||||
<span class="text-[#C7F0FF] text-[12px]">线上来源</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<SvgComponent :content="offlineSvg" class="w-[53px] h-[38px]" />
|
||||
<div class="flex flex-col ml-[9px] items-center">
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent font-700">
|
||||
<span class="text-[18px]">240</span>
|
||||
<span class="text-[14px]">人</span>
|
||||
</div>
|
||||
<span class="text-[#C7F0FF] text-[12px]">线下来源</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import StudentSourceChart from "@/views/components/chartsComponents/StudentSourceChart.vue";
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const onlineSvg = ref("")
|
||||
const offlineSvg = ref("")
|
||||
const getOfflineSvg = async () => {
|
||||
const {default: svg} = await import('/src/assets/svg-img/offline.svg?raw')
|
||||
offlineSvg.value = svg
|
||||
}
|
||||
const getOnlineSvg = async () => {
|
||||
const {default: svg} = await import('/src/assets/svg-img/online.svg?raw')
|
||||
onlineSvg.value = svg
|
||||
}
|
||||
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
|
||||
getOfflineSvg();
|
||||
getOnlineSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
<template>
|
||||
<div class="w-max h-max relative">
|
||||
<SvgComponent :content="groupSvg" class="w-[544px] h-[210px]" />
|
||||
<SvgComponent :content="groupSvg" class="w-[312px] h-[210px]" />
|
||||
<div class="w-full h-full absolute top-0 left-0 pt-[31px] pb-[21px] pl-[14px] pr-[19px] flex items-center">
|
||||
<div class="w-[216px]">
|
||||
<div class="w-[144px]">
|
||||
<div class="relative w-[144px] h-[113px] flex items-center flex-col">
|
||||
<div class="text-[#44C1EF] italic text-[20px] font-700">今日缴费</div>
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent mb-[15px] z-10">
|
||||
|
|
@ -11,34 +11,33 @@
|
|||
</div>
|
||||
<SvgComponent :content="hexagonalBoxSvg" class="box-light absolute" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="flex items-center justify-between text-[12px]">
|
||||
<div class="text-[#6B89BC]">当前值1265人</div>
|
||||
<div class="text-[#69D4FF]">
|
||||
计划:
|
||||
<span class="text-[15px]">4000</span>
|
||||
<span class="text-[13px]">人</span>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="relative ml-[12px]">
|
||||
<SvgComponent :content="paymentBorderSvg" class="w-[127px] h-[104px] z-1" />
|
||||
<div class="w-[127px] h-[104px] top-0 left-0 z-1 absolute pl-[14px] flex flex-col justify-center">
|
||||
<p class="text-[#C0EEFF] text-[12px]">昨日缴费人数</p>
|
||||
<p class="text-[#C0EEFF] text-[16px] font-500 mt-[18px] mb-[9px]">177人</p>
|
||||
<div class="text-[#FF4E4E] text-[12px] flex items-center">
|
||||
<span class="">今日较昨日</span>
|
||||
<SvgIcon name="arrow-up" class="text-[9px]" />
|
||||
<span>12人</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="ml-[22px] relative">
|
||||
<SvgComponent :content="paymentBorderSvg" class="w-[127px] h-[130px] top-0 left-0 z-1" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
|
||||
|
||||
|
||||
|
||||
const groupSvg = ref("");
|
||||
const getGroupBackgroundSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/group-background.svg?raw");
|
||||
const { default: svg } = await import("/src/assets/svg-img/short-background.svg?raw");
|
||||
groupSvg.value = svg;
|
||||
};
|
||||
|
||||
|
|
@ -65,18 +64,7 @@
|
|||
|
||||
<style scoped lang="scss">
|
||||
@use "@/styles/text-color.scss";
|
||||
|
||||
.border-image {
|
||||
border: 1px solid;
|
||||
border-image: linear-gradient(
|
||||
90deg,
|
||||
#217ac600,
|
||||
#227cc8,
|
||||
#217ac600
|
||||
)
|
||||
1 1;
|
||||
opacity: 0.3;
|
||||
}
|
||||
@use "@/styles/custom-border.scss";
|
||||
|
||||
.rotate-animation {
|
||||
animation: rotate-animation 1s infinite;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
<template>
|
||||
<div class="w-[296px] h-[320px] relative bg-[#082059]">
|
||||
<div class="flex h-full custom-border absolute top-0 left-0">
|
||||
<div class="relative h-[36px]">
|
||||
<div class="absolute top-[50%] translate-y-[-50%] left-[15px] flex items-center">
|
||||
<SvgComponent :content="arrowLeftSvg" class="w-[15px] h-[18px]" />
|
||||
<div class="bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent text-[20px] ml-[9px] font-700">获客排行榜</div>
|
||||
</div>
|
||||
<SvgComponent :content="headerLeftSvg" class="w-[188px] h-[36px]" />
|
||||
</div>
|
||||
<SvgComponent :content="headerRightSvg" class="w-[108px] h-[36px]" />
|
||||
</div>
|
||||
<div class="w-full h-[calc(100%-36px)] mt-[36px] flex flex-col relative">
|
||||
<div class="absolute right-[0] flex items-center justify-end mr-[13px] transform-translate-y-[-50%]">
|
||||
<div class="text-[15px] text-[#84E8FF]">更多</div>
|
||||
<SvgComponent :content="moreArrowSvg" class="w-[14px] h-[22px]" />
|
||||
</div>
|
||||
<div class="mt-[26px] mx-[16px]">
|
||||
<RankingTable :value="products" :columns="columns" header-class="custom-table-header" body-class="custom-table-body">
|
||||
<template #rank="{index }">
|
||||
<SvgComponent :content="goldMedalSvg" class="w-[34px] h-[20px]" v-if="index===0"/>
|
||||
<SvgComponent :content="silverMedalSvg" class="w-[34px] h-[20px]" v-if="index===1"/>
|
||||
<SvgComponent :content="bronzeMedalSvg" class="w-[34px] h-[20px]" v-if="index===2"/>
|
||||
<span class="text-[14px] font-600" v-if="index > 2">{{ index + 1 }}</span>
|
||||
</template>
|
||||
|
||||
<template #name="{data}">
|
||||
<span class="text-[#C0EEFF] text-[14px]">{{ data.name }}</span>
|
||||
</template>
|
||||
|
||||
</RankingTable>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import RankingTable from "@/components/table/RankingTable.vue";
|
||||
|
||||
const columns = [
|
||||
{ field: "rank", header: "名次", align: "justify-center",width:'68px' },
|
||||
{ field: "name", header: "姓名", align: "justify-left",width:'100px' },
|
||||
{ field: "Status", header: "获客人数", align: "justify-center",width:'96px' },
|
||||
];
|
||||
|
||||
const products = [{ name: "张三" },{ name: "张三" },{ name: "张三" },{ name: "张三" },{ name: "张三" }];
|
||||
|
||||
const headerLeftSvg = ref("");
|
||||
const headerRightSvg = ref("");
|
||||
|
||||
const getHeaderLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-left-sort.svg?raw");
|
||||
headerLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const getHeaderRightSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/header-bg-right-sort.svg?raw");
|
||||
headerRightSvg.value = svg;
|
||||
};
|
||||
|
||||
const arrowLeftSvg = ref("");
|
||||
const getArrowLeftSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/arrow-left.svg?raw");
|
||||
arrowLeftSvg.value = svg;
|
||||
};
|
||||
|
||||
const moreArrowSvg = ref("");
|
||||
const getMoreArrowSvg = async () => {
|
||||
const { default: svg } = await import("/src/assets/svg-img/more-arrow.svg?raw");
|
||||
moreArrowSvg.value = svg;
|
||||
};
|
||||
|
||||
const goldMedalSvg = ref("")
|
||||
const getGoldMedalSvg = async () => {
|
||||
const {default: svg} = await import("/src/assets/svg-img/gold-medal.svg?raw");
|
||||
goldMedalSvg.value = svg
|
||||
}
|
||||
|
||||
const silverMedalSvg = ref("")
|
||||
const getSilverMedalSvg = async () => {
|
||||
const {default: svg} = await import("/src/assets/svg-img/silver-medal.svg?raw");
|
||||
silverMedalSvg.value = svg
|
||||
}
|
||||
|
||||
const bronzeMedalSvg = ref("")
|
||||
const getBronzeMedalSvg = async () => {
|
||||
const {default: svg} = await import("/src/assets/svg-img/bronze-medal.svg?raw");
|
||||
bronzeMedalSvg.value = svg
|
||||
}
|
||||
|
||||
onBeforeMount(() => {
|
||||
getHeaderLeftSvg();
|
||||
getHeaderRightSvg();
|
||||
getArrowLeftSvg();
|
||||
|
||||
getMoreArrowSvg();
|
||||
|
||||
getGoldMedalSvg();
|
||||
getSilverMedalSvg();
|
||||
getBronzeMedalSvg();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.custom-border {
|
||||
border-image-slice: 27 27 27 27;
|
||||
border-image-width: 1px 1px 2px 1px;
|
||||
border-image-outset: 0px 0px 0px 0px;
|
||||
border-image-repeat: stretch stretch;
|
||||
border-image-source: url("src/assets/svg-img/border-image.png");
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
:deep(.custom-table-header) {
|
||||
tr{
|
||||
background-color: rgb(14, 39, 97);
|
||||
th{
|
||||
padding: 13px 10px;
|
||||
color:#44C1EF;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.custom-table-body){
|
||||
tr{
|
||||
td{
|
||||
padding: 10px;
|
||||
line-height: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
<template>
|
||||
<div ref="chartDom" class="w-full h-full"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import * as echarts from "echarts";
|
||||
import { ref, onMounted, onUnmounted } from "vue";
|
||||
|
||||
const renderItem = (params: any, api: { coord: (arg0: any[]) => any[]; value: (arg0: number) => any; style: () => any }) => {
|
||||
// 柱子索引值
|
||||
const { seriesIndex } = params;
|
||||
|
||||
// 基础坐标
|
||||
const basicsCoord = api.coord([api.value(seriesIndex), api.value(1)]);
|
||||
// 顶部基础 y 轴
|
||||
const topBasicsYAxis = basicsCoord[1];
|
||||
// 基础 x 轴
|
||||
const basicsXAxis = basicsCoord[0];
|
||||
// 底部 y 轴
|
||||
const bottomYAxis = api.coord([api.value(seriesIndex), 0])[1];
|
||||
return {
|
||||
type: "group",
|
||||
children: [
|
||||
{
|
||||
type: "leftShape",
|
||||
shape: {
|
||||
topBasicsYAxis,
|
||||
basicsXAxis,
|
||||
bottomYAxis,
|
||||
},
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(0, 147, 221, 1)" },
|
||||
{ offset: 1, color: "rgba(0, 88, 255, 0.20)" },
|
||||
]), // 覆盖基础样式
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "rightShape",
|
||||
shape: {
|
||||
topBasicsYAxis,
|
||||
basicsXAxis,
|
||||
bottomYAxis,
|
||||
},
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(0, 147, 221, 1)" },
|
||||
{ offset: 1, color: "rgba(0, 88, 255, 0.20)" },
|
||||
]), // 覆盖基础样式
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "topShape",
|
||||
shape: {
|
||||
topBasicsYAxis,
|
||||
basicsXAxis,
|
||||
bottomYAxis,
|
||||
},
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(143, 231, 255, 1)" },
|
||||
{ offset: 1, color: "rgba(0, 132, 255, 1)" },
|
||||
]), // 覆盖基础样式
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "middleShape",
|
||||
shape: {
|
||||
topBasicsYAxis,
|
||||
basicsXAxis,
|
||||
bottomYAxis,
|
||||
},
|
||||
style: {
|
||||
fill: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: "rgba(143, 231, 255, 1)" },
|
||||
{ offset: 1, color: "rgba(0, 132, 255, 0)" },
|
||||
]), // 覆盖基础样式
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
const chartDom = ref(null);
|
||||
let myChart: echarts.ECharts | null = null;
|
||||
|
||||
const initChart = () => {
|
||||
if (chartDom.value) {
|
||||
myChart = echarts.init(chartDom.value);
|
||||
// 侧面宽度
|
||||
const WIDTH = 10;
|
||||
// 斜角高度
|
||||
const OBLIQUE_ANGLE_HEIGHT = 3.5;
|
||||
const leftShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx, shape) {
|
||||
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape;
|
||||
|
||||
const p1 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT];
|
||||
const p2 = [basicsXAxis - WIDTH, bottomYAxis];
|
||||
const p3 = [basicsXAxis, bottomYAxis];
|
||||
const p4 = [basicsXAxis, topBasicsYAxis];
|
||||
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.lineTo(p3[0], p3[1]);
|
||||
ctx.lineTo(p4[0], p4[1]);
|
||||
},
|
||||
});
|
||||
|
||||
const rightShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx, shape) {
|
||||
const { topBasicsYAxis, bottomYAxis, basicsXAxis } = shape;
|
||||
|
||||
const p1 = [basicsXAxis, topBasicsYAxis];
|
||||
const p2 = [basicsXAxis, bottomYAxis];
|
||||
const p3 = [basicsXAxis + WIDTH, bottomYAxis];
|
||||
const p4 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT];
|
||||
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.lineTo(p3[0], p3[1]);
|
||||
ctx.lineTo(p4[0], p4[1]);
|
||||
},
|
||||
});
|
||||
|
||||
const topShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx, shape) {
|
||||
const { topBasicsYAxis, basicsXAxis } = shape;
|
||||
|
||||
const p1 = [basicsXAxis, topBasicsYAxis];
|
||||
const p2 = [basicsXAxis + WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT];
|
||||
const p3 = [basicsXAxis, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT * 2];
|
||||
const p4 = [basicsXAxis - WIDTH, topBasicsYAxis - OBLIQUE_ANGLE_HEIGHT];
|
||||
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.lineTo(p3[0], p3[1]);
|
||||
ctx.lineTo(p4[0], p4[1]);
|
||||
},
|
||||
});
|
||||
const middleShape = echarts.graphic.extendShape({
|
||||
buildPath(ctx, shape) {
|
||||
const { topBasicsYAxis, basicsXAxis, bottomYAxis } = shape;
|
||||
|
||||
const p1 = [basicsXAxis - 0.5, topBasicsYAxis];
|
||||
const p2 = [basicsXAxis - 0.5, bottomYAxis];
|
||||
const p3 = [basicsXAxis + 0.5, bottomYAxis];
|
||||
const p4 = [basicsXAxis + 0.5, topBasicsYAxis];
|
||||
|
||||
ctx.moveTo(p1[0], p1[1]);
|
||||
ctx.lineTo(p2[0], p2[1]);
|
||||
ctx.lineTo(p3[0], p3[1]);
|
||||
ctx.lineTo(p4[0], p4[1]);
|
||||
},
|
||||
});
|
||||
|
||||
echarts.graphic.registerShape("leftShape", leftShape);
|
||||
echarts.graphic.registerShape("rightShape", rightShape);
|
||||
echarts.graphic.registerShape("topShape", topShape);
|
||||
echarts.graphic.registerShape("middleShape", middleShape);
|
||||
|
||||
const options = {
|
||||
grid: {
|
||||
top: "12%",
|
||||
left: "5%",
|
||||
right: "3%",
|
||||
bottom: "15%",
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: [1, 2, 3, 4, 5],
|
||||
axisLabel: {
|
||||
formatter: (value: any) => value,
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
name: "人数",
|
||||
nameLocation: "end",
|
||||
data: [100, 200, 300, 400],
|
||||
nameTextStyle: {
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
padding: [0, 5, 0, 0],
|
||||
align: "right",
|
||||
},
|
||||
type: "value",
|
||||
min: 0,
|
||||
max: 500,
|
||||
interval: 100,
|
||||
axisLabel: {
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
color: "#308EFF",
|
||||
width: 1,
|
||||
opacity: 0.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "custom",
|
||||
renderItem: renderItem,
|
||||
color: "blue",
|
||||
data: [100, 200, 300, 400],
|
||||
},
|
||||
{
|
||||
type: "bar",
|
||||
label: {
|
||||
show: true,
|
||||
position: "top",
|
||||
fontSize: 12,
|
||||
color: "rgba(192, 238, 255, 1)",
|
||||
},
|
||||
tooltip: {
|
||||
show: false,
|
||||
},
|
||||
itemStyle: {
|
||||
color: "transparent",
|
||||
},
|
||||
data: [100, 200, 300, 400],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
myChart.setOption(options);
|
||||
|
||||
window.addEventListener("resize", handleResize);
|
||||
}
|
||||
};
|
||||
|
||||
const handleResize = () => {
|
||||
myChart?.resize();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener("resize", handleResize);
|
||||
myChart?.dispose();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss"></style>
|
||||
|
|
@ -0,0 +1,595 @@
|
|||
<template>
|
||||
<div ref="chartDom" class="w-full h-full"></div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, ref } from "vue";
|
||||
import * as echarts from "echarts";
|
||||
|
||||
const chartDom = ref(null);
|
||||
let myChart: echarts.ECharts | null = null;
|
||||
|
||||
// 图表数据
|
||||
const chartData = ref({
|
||||
dates: ["5.24", "5.25", "5.26", "5.27", "5.28", "5.29", "5.30"],
|
||||
seriesData: [
|
||||
{ name: "获客", data: [180, 230, 200, 280, 250, 300, 350], color: "#20E6A4" },
|
||||
{ name: "缴费", data: [150, 210, 180, 240, 200, 260, 320], color: "#0783FA" },
|
||||
{ name: "流失", data: [120, 380, 220, 350, 300, 280, 400], color: "#FFD15C" },
|
||||
],
|
||||
});
|
||||
|
||||
const currentMode = ref("week");
|
||||
|
||||
const legendIcons = ref<{ [key: string]: string }>({});
|
||||
|
||||
// 生成SVG图标
|
||||
const generateSvgIcon = (color: string) => {
|
||||
return encodeURIComponent(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 16 16">
|
||||
<g><g><path d="M0,2L0,14C0,15.1046,0.89543,16,2,16L14,16C15.1046,16,16,15.1046,16,14L16,2C16,0.89543,15.1046,0,14,0L2,0C0.89543,0,0,0.89543,0,2ZM13.949,6.32574L7.64171,11.99Q7.35295,12.25,6.94914,12.25Q6.54551,12.25,6.25625,11.9902L2.05119,8.2139Q1.75,7.94411,1.75,7.55595Q1.75,7.16798,2.05072,6.89792Q2.33947,6.63794,2.74329,6.63794Q3.14692,6.63794,3.43617,6.89771L6.94886,10.0523L12.5636,5.00998Q12.8523,4.75,13.2562,4.75Q13.6598,4.75,13.9488,5.00955Q14.25,5.27935,14.25,5.66751Q14.25,6.05547,13.949,6.32574Z" fill-rule="evenodd" fill="${color}" fill-opacity="1"/></g></g></svg>`);
|
||||
};
|
||||
|
||||
// 初始化图例图标
|
||||
const initLegendIcons = () => {
|
||||
chartData.value.seriesData.forEach((item) => {
|
||||
legendIcons.value[item.name] = generateSvgIcon(item.color);
|
||||
});
|
||||
};
|
||||
|
||||
// 获取图例图标
|
||||
const getLegendIcon = (name: string, isSelected = true) => {
|
||||
const seriesItem = chartData.value.seriesData.find((item) => item.name === name);
|
||||
const color = isSelected ? seriesItem?.color || "#555" : "#555";
|
||||
return `image://data:image/svg+xml;charset=utf-8,${generateSvgIcon(color)}`;
|
||||
};
|
||||
|
||||
// 更新图例图标颜色
|
||||
const updateLegendIcons = (selected: Record<string, boolean>) => {
|
||||
if (!myChart) return;
|
||||
|
||||
const option = myChart.getOption() as any;
|
||||
const legendData = option.legend[0].data as any[];
|
||||
|
||||
// 更新每个图例项的图标
|
||||
const updatedLegendData = legendData.map((item: any) => {
|
||||
const isSelected = selected[item.name] !== false;
|
||||
return {
|
||||
...item,
|
||||
icon: getLegendIcon(item.name, isSelected),
|
||||
};
|
||||
});
|
||||
|
||||
// 更新图表配置
|
||||
myChart.setOption({
|
||||
legend: {
|
||||
data: updatedLegendData,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 生成图表系列的函数
|
||||
const generateSeries = (seriesData: any) => {
|
||||
return seriesData.map((item: any,) => {
|
||||
const series = {
|
||||
name: item.name,
|
||||
type: "line",
|
||||
data: item.data,
|
||||
symbol: "circle",
|
||||
symbolSize: 8,
|
||||
itemStyle: {
|
||||
color: "#111", // 中心填充颜色
|
||||
borderColor: item.color, // 边框颜色
|
||||
borderWidth: 2,
|
||||
},
|
||||
lineStyle: {
|
||||
width: 3,
|
||||
color: item.color,
|
||||
},
|
||||
};
|
||||
return series;
|
||||
});
|
||||
};
|
||||
|
||||
// 切换周/月显示
|
||||
const switchDisplayMode = (mode: string) => {
|
||||
currentMode.value = mode;
|
||||
|
||||
// 这里可以根据不同模式加载不同数据
|
||||
if (mode === "week") {
|
||||
// 周数据 (默认)
|
||||
chartData.value.dates = ["5.24", "5.25", "5.26", "5.27", "5.28", "5.29", "5.30"];
|
||||
} else {
|
||||
// 月数据
|
||||
chartData.value.dates = ["1月", "2月", "3月", "4月", "5月", "6月", "7月"];
|
||||
}
|
||||
|
||||
// 重新渲染图表
|
||||
initChart();
|
||||
};
|
||||
|
||||
const initChart = () => {
|
||||
if (!myChart) {
|
||||
myChart = echarts.init(chartDom.value);
|
||||
}
|
||||
|
||||
// 初始化图例图标
|
||||
initLegendIcons();
|
||||
|
||||
// 按钮的SVG背景 - 使用Base64编码
|
||||
const buttonSvgBase64 = encodeURIComponent(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="72" height="28" viewBox="0 0 72 28"><defs><filter id="master_svg0_104_04023" filterUnits="objectBoundingBox" color-interpolation-filters="sRGB" x="0" y="0" width="1" height="1"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feColorMatrix in="SourceAlpha" type="matrix" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="8" dx="0"/><feGaussianBlur stdDeviation="6"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.08237092196941376 0 0 0 0 0.17847032845020294 0 0 0 1 0"/><feBlend mode="normal" in2="shape" result="effect1_innerShadow"/><feColorMatrix in="SourceAlpha" type="matrix" result="hardAlpha" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/><feOffset dy="-8" dx="0"/><feGaussianBlur stdDeviation="6"/><feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/><feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0.08235294371843338 0 0 0 0 0.18039216101169586 0 0 0 1 0"/><feBlend mode="normal" in2="effect1_innerShadow" result="effect2_innerShadow"/></filter></defs><g><g filter="url(#master_svg0_104_04023)"><path d="M0,14.5113C0,8.31958,0,6.07937,0.871948,4.36808C1.63894,2.86278,2.86278,1.63893,4.36808,0.871948C6.07937,0,8.31958,0,14.5113,0L72,0L72,13.4887C72,19.6804,72,21.9206,71.1281,23.6319C70.3611,25.1372,69.1372,26.3611,67.6319,27.1281C65.9206,28,63.6804,28,57.4887,28L0,28L0,14.5113Z" fill="#061E3A" fill-opacity="1"/></g><g><path d="M0,14.5113C0,8.31958,0,6.07937,0.871948,4.36808C1.63894,2.86278,2.86278,1.63893,4.36808,0.871948C6.07937,0,8.31958,0,14.5113,0L72,0L72,13.4887C72,19.6804,72,21.9206,71.1281,23.6319C70.3611,25.1372,69.1372,26.3611,67.6319,27.1281C65.9206,28,63.6804,28,57.4887,28L0,28L0,14.5113ZM14.5113,1L71,1L71,13.4887Q71,18.6574,70.8935,20.1702Q70.753,22.1653,70.237,23.1779Q69.2045,25.2045,67.1779,26.237Q66.1653,26.753,64.1702,26.8935Q62.6574,27,57.4887,27L1,27L1,14.5113Q1,9.34262,1.10652,7.82977Q1.247,5.83468,1.76295,4.82207Q2.79553,2.79553,4.82207,1.76295Q5.83468,1.247,7.82977,1.10652Q9.34262,1,14.5113,1Z" fill-rule="evenodd" fill="#2A8EFE" fill-opacity="1"/></g></g></svg>
|
||||
`);
|
||||
|
||||
// 定义选中状态的SVG背景
|
||||
const activeButtonSvgBase64 = encodeURIComponent(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" width="72" height="28" viewBox="0 0 72 28"><defs><radialGradient cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" id="master_svg0_85_00187" gradientTransform="translate(36 28) rotate(90) scale(16.125258922576904 182.11454980862436)"><stop offset="0%" stop-color="#FFCE4F" stop-opacity="0.5749016404151917"/><stop offset="99.90439414978027%" stop-color="#E0BF00" stop-opacity="0"/></radialGradient><linearGradient x1="0.5" y1="0" x2="0.5" y2="1" id="master_svg1_85_00188"><stop offset="0%" stop-color="#E0BF00" stop-opacity="0.4000000059604645"/><stop offset="100%" stop-color="#E0BF00" stop-opacity="0"/></linearGradient><linearGradient x1="0.5" y1="1" x2="0.5" y2="1.9133386611938477" id="master_svg2_85_00190"><stop offset="0%" stop-color="#FFF7A6" stop-opacity="1"/><stop offset="100%" stop-color="#046172" stop-opacity="0"/></linearGradient></defs><g><g><path d="M0,14.5113C0,8.31958,0,6.07937,0.871948,4.36808C1.63894,2.86278,2.86278,1.63893,4.36808,0.871948C6.07937,0,8.31958,0,14.5113,0L72,0L72,13.4887C72,19.6804,72,21.9206,71.1281,23.6319C70.3611,25.1372,69.1372,26.3611,67.6319,27.1281C65.9206,28,63.6804,28,57.4887,28L0,28L0,14.5113Z" fill="url(#master_svg0_85_00187)" fill-opacity="1"/><path d="M0,14.5113C0,8.31958,0,6.07937,0.871948,4.36808C1.63894,2.86278,2.86278,1.63893,4.36808,0.871948C6.07937,0,8.31958,0,14.5113,0L72,0L72,13.4887C72,19.6804,72,21.9206,71.1281,23.6319C70.3611,25.1372,69.1372,26.3611,67.6319,27.1281C65.9206,28,63.6804,28,57.4887,28L0,28L0,14.5113Z" fill="url(#master_svg1_85_00188)" fill-opacity="1"/></g><g><path d="M0,14.5113C0,8.31958,0,6.07937,0.871948,4.36808C1.63894,2.86278,2.86278,1.63893,4.36808,0.871948C6.07937,0,8.31958,0,14.5113,0L72,0L72,13.4887C72,19.6804,72,21.9206,71.1281,23.6319C70.3611,25.1372,69.1372,26.3611,67.6319,27.1281C65.9206,28,63.6804,28,57.4887,28L0,28L0,14.5113ZM14.5113,1L71,1L71,13.4887Q71,18.6574,70.8935,20.1702Q70.753,22.1653,70.237,23.1779Q69.2045,25.2045,67.1779,26.237Q66.1653,26.753,64.1702,26.8935Q62.6574,27,57.4887,27L1,27L1,14.5113Q1,9.34262,1.10652,7.82977Q1.247,5.83468,1.76295,4.82207Q2.79553,2.79553,4.82207,1.76295Q5.83468,1.247,7.82977,1.10652Q9.34262,1,14.5113,1Z" fill-rule="evenodd" fill="url(#master_svg2_85_00190)" fill-opacity="1"/></g></g></svg>
|
||||
`);
|
||||
|
||||
const option = {
|
||||
grid: {
|
||||
top: "14%",
|
||||
left: "5%",
|
||||
right: "3%",
|
||||
bottom: "15%",
|
||||
},
|
||||
legend: {
|
||||
type: "plain",
|
||||
itemWidth: 16,
|
||||
itemHeight: 16,
|
||||
top: 3,
|
||||
left: "center",
|
||||
itemGap: 40,
|
||||
textStyle: {
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
lineHeight: 16,
|
||||
},
|
||||
data: chartData.value.seriesData.map((item) => ({
|
||||
name: item.name,
|
||||
icon:
|
||||
"image://data:image/svg+xml;charset=utf-8," +
|
||||
encodeURIComponent(`
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" fill="none" version="1.1" viewBox="0 0 16 16">
|
||||
<g><g><path d="M0,2L0,14C0,15.1046,0.89543,16,2,16L14,16C15.1046,16,16,15.1046,16,14L16,2C16,0.89543,15.1046,0,14,0L2,0C0.89543,0,0,0.89543,0,2ZM13.949,6.32574L7.64171,11.99Q7.35295,12.25,6.94914,12.25Q6.54551,12.25,6.25625,11.9902L2.05119,8.2139Q1.75,7.94411,1.75,7.55595Q1.75,7.16798,2.05072,6.89792Q2.33947,6.63794,2.74329,6.63794Q3.14692,6.63794,3.43617,6.89771L6.94886,10.0523L12.5636,5.00998Q12.8523,4.75,13.2562,4.75Q13.6598,4.75,13.9488,5.00955Q14.25,5.27935,14.25,5.66751Q14.25,6.05547,13.949,6.32574Z" fill-rule="evenodd" fill="${item.color}" fill-opacity="1"/></g></g></svg>`),
|
||||
textStyle: {
|
||||
color: "#C0EEFF",
|
||||
verticalAlign: "middle",
|
||||
},
|
||||
})),
|
||||
selectedMode: true,
|
||||
inactiveColor: "#555",
|
||||
itemStyle: {
|
||||
borderWidth: 0,
|
||||
},
|
||||
},
|
||||
// 使用graphic组件添加自定义按钮
|
||||
graphic: [
|
||||
// 按周按钮
|
||||
{
|
||||
type: "group",
|
||||
right: 97,
|
||||
top: 0,
|
||||
z: 100,
|
||||
children: [
|
||||
{
|
||||
type: "image",
|
||||
z: 100,
|
||||
style: {
|
||||
image: `data:image/svg+xml;charset=utf-8,${currentMode.value === "week" ? activeButtonSvgBase64 : buttonSvgBase64}`,
|
||||
width: 72,
|
||||
height: 28,
|
||||
},
|
||||
cursor: "pointer",
|
||||
onclick: () => switchDisplayMode("week"),
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
z: 100,
|
||||
style: {
|
||||
text: "按周",
|
||||
x: 36,
|
||||
y: 14,
|
||||
textAlign: "center",
|
||||
textVerticalAlign: "middle",
|
||||
fill: `${currentMode.value === "week" ? "#F8EA21" : "#DBF7FF"}`,
|
||||
fontSize: 14,
|
||||
},
|
||||
cursor: "pointer",
|
||||
onclick: () => switchDisplayMode("week"),
|
||||
},
|
||||
],
|
||||
},
|
||||
// 按月按钮
|
||||
{
|
||||
type: "group",
|
||||
right: 15,
|
||||
top: 0,
|
||||
z: 100,
|
||||
children: [
|
||||
{
|
||||
type: "image",
|
||||
z: 100,
|
||||
style: {
|
||||
image: `data:image/svg+xml;charset=utf-8,${currentMode.value === "month" ? activeButtonSvgBase64 : buttonSvgBase64}`,
|
||||
width: 72,
|
||||
height: 28,
|
||||
},
|
||||
cursor: "pointer",
|
||||
onclick: () => switchDisplayMode("month"),
|
||||
},
|
||||
{
|
||||
type: "text",
|
||||
z: 100,
|
||||
style: {
|
||||
text: "按月",
|
||||
x: 36,
|
||||
y: 14,
|
||||
textAlign: "center",
|
||||
textVerticalAlign: "middle",
|
||||
fill: `${currentMode.value === "month" ? "#F8EA21" : "#DBF7FF"}`,
|
||||
fontSize: 14,
|
||||
},
|
||||
cursor: "pointer",
|
||||
onclick: () => switchDisplayMode("month"),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
renderMode: "html",
|
||||
padding: 0,
|
||||
borderWidth: 0,
|
||||
extraCssText: "background-color: transparent;",
|
||||
formatter: (params: any) => {
|
||||
const date = params[0].name;
|
||||
const seriesData = params
|
||||
.map(
|
||||
(item: any) => `<div class="tip-content">
|
||||
<div class="tip-content-left">
|
||||
<div class="tip-icon" style="background-color: ${item.borderColor};"></div>
|
||||
<div class="tip-text">${item.seriesName}</div>
|
||||
</div>
|
||||
<div class="tip-content-right">
|
||||
<div class="tip-text">${item.value}人</div>
|
||||
</div>
|
||||
</div>`,
|
||||
)
|
||||
.join("");
|
||||
return `<div style="" class='tool-tip-wrapper'>
|
||||
<div class="tool-tip-header">
|
||||
<span class="tip-date">${date}</span>
|
||||
<div class="tip-graphic">
|
||||
<div class="qua-group">
|
||||
<div class="qua-item"></div>
|
||||
<div class="qua-item"></div>
|
||||
<div class="qua-item"></div>
|
||||
<div class="qua-item"></div>
|
||||
<div class="qua-item"></div>
|
||||
</div>
|
||||
<div class="rect-group">
|
||||
<div class="rect-item"></div>
|
||||
<div class="rect-item"></div>
|
||||
<div class="rect-item"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tip-content-wrapper">
|
||||
${seriesData}
|
||||
</div>
|
||||
</div>`;
|
||||
},
|
||||
axisPointer: {
|
||||
id: "xPointer",
|
||||
type: "line", // 直线指示器
|
||||
lineStyle: {
|
||||
color: "#4760FF",
|
||||
width: 2,
|
||||
type: "dashed",
|
||||
},
|
||||
},
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: chartData.value.dates,
|
||||
axisLabel: {
|
||||
formatter: (value: any) => value,
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
name: "人数",
|
||||
nameLocation: "end",
|
||||
nameTextStyle: {
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
padding: [0, 5, 0, 0],
|
||||
align: "right",
|
||||
},
|
||||
type: "value",
|
||||
min: 0,
|
||||
max: 500,
|
||||
interval: 100,
|
||||
axisLabel: {
|
||||
color: "#C0EEFF",
|
||||
fontSize: 14,
|
||||
},
|
||||
axisLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: "#243174",
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: "dashed",
|
||||
color: "#308EFF",
|
||||
width: 1,
|
||||
opacity: 0.2,
|
||||
},
|
||||
},
|
||||
},
|
||||
series: [
|
||||
...generateSeries(chartData.value.seriesData),
|
||||
{
|
||||
type: "bar",
|
||||
id: "axisOverlayBar",
|
||||
zlevel: 1,
|
||||
silent: false,
|
||||
barWidth: "100%",
|
||||
data: chartData.value.dates.map(() => 500), // 使用y轴的最大值
|
||||
itemStyle: {
|
||||
color: "transparent",
|
||||
},
|
||||
tooltip: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
myChart.setOption(option, true);
|
||||
|
||||
// 跟踪鼠标指示器状态
|
||||
const hoverBarId = 'mouseHoverBar';
|
||||
|
||||
|
||||
myChart.on("mouseover", { seriesId: "axisOverlayBar" }, (params) => {
|
||||
if (!myChart) return;
|
||||
|
||||
// 获取当前数据索引
|
||||
const dataIndex = params.dataIndex;
|
||||
|
||||
// 获取当前option配置
|
||||
const _option = myChart.getOption() as any;
|
||||
|
||||
// 检查是否已存在高亮条
|
||||
let seriesIndex = -1;
|
||||
if (_option.series && Array.isArray(_option.series)) {
|
||||
_option.series.forEach((series: any, index: number) => {
|
||||
if (series.id === hoverBarId) {
|
||||
seriesIndex = index;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 构建高亮条配置
|
||||
const hoverBarOption = {
|
||||
id: hoverBarId,
|
||||
type: 'bar',
|
||||
barWidth: 40,
|
||||
barGap: '-100%',
|
||||
zlevel: 10,
|
||||
silent: true,
|
||||
animation: true,
|
||||
data: chartData.value.dates.map((_: any, index: number) => {
|
||||
return index === dataIndex ? 500 : '-'
|
||||
}),
|
||||
itemStyle: {
|
||||
color: {
|
||||
type: 'linear',
|
||||
x: 0,
|
||||
y: 0,
|
||||
x2: 0,
|
||||
y2: 1,
|
||||
colorStops: [
|
||||
{
|
||||
offset: 0,
|
||||
color: '#fff' // 开始颜色
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: '#0783FA' // 结束颜色
|
||||
}
|
||||
],
|
||||
global: false
|
||||
},
|
||||
opacity: 0.3,
|
||||
},
|
||||
tooltip: {
|
||||
show: false
|
||||
}
|
||||
};
|
||||
|
||||
if (seriesIndex === -1) {
|
||||
// 如果不存在则添加新的高亮条
|
||||
if (_option.series && Array.isArray(_option.series)) {
|
||||
_option.series.push(hoverBarOption);
|
||||
}
|
||||
} else {
|
||||
// 如果已存在则更新位置
|
||||
if (_option.series && Array.isArray(_option.series)) {
|
||||
_option.series[seriesIndex].data = hoverBarOption.data;
|
||||
}
|
||||
}
|
||||
|
||||
// 更新图表
|
||||
myChart.setOption(_option, false);
|
||||
});
|
||||
|
||||
// 鼠标移出图表时移除高亮条
|
||||
myChart.on("mouseout", { seriesId: "axisOverlayBar" }, () => {
|
||||
|
||||
if (!myChart) return;
|
||||
const _option = myChart.getOption() as any;
|
||||
const hoverBarExists = _option.series.find((series: any) => series.id && series.id === hoverBarId);
|
||||
|
||||
if (hoverBarExists) {
|
||||
try {
|
||||
// 检查series是否存在
|
||||
if (_option.series && Array.isArray(_option.series)) {
|
||||
// 查找并删除高亮条
|
||||
const newSeries = _option.series.filter((series: any) => {
|
||||
return series.id !== hoverBarId;
|
||||
});
|
||||
|
||||
// 直接设置新的series数组
|
||||
_option.series = newSeries;
|
||||
// 更新图表
|
||||
myChart.setOption(_option, true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("删除高亮条出错:", err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
myChart.on("legendselectchanged", (params: any) => {
|
||||
// 更新图例图标
|
||||
updateLegendIcons(params.selected);
|
||||
});
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener("resize", () => myChart?.resize());
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
:deep(.tool-tip-wrapper) {
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
width: 184px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0px 4px 10px 0px #0d3472;
|
||||
overflow: hidden;
|
||||
padding: 10px;
|
||||
background-color: rgb(3, 33, 64);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 2px solid transparent;
|
||||
border-image: linear-gradient(rgb(3, 33, 64), rgba(0, 170, 255, 0.3)) 2;
|
||||
}
|
||||
|
||||
.tool-tip-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
.tip-date {
|
||||
font-size: 14px;
|
||||
color: #c0eeff;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.tip-graphic {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.qua-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 4px;
|
||||
.qua-item {
|
||||
width: 2px;
|
||||
height: 8px;
|
||||
color: rgba(255, 255, 255, 1);
|
||||
text-align: center;
|
||||
transform: skewX(-40deg);
|
||||
background: linear-gradient(360deg, #0085ff 0%, rgba(0, 133, 255, 0) 93%, rgba(0, 133, 255, 0) 100%);
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.rect-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.rect-item {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
background-color: #00c2ff;
|
||||
transform: rotate(45deg);
|
||||
margin-left: 5px;
|
||||
animation: colorChange 1.5s infinite;
|
||||
|
||||
&:nth-child(1) {
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
&:nth-child(2) {
|
||||
animation-delay: 0.5s;
|
||||
}
|
||||
|
||||
&:nth-child(3) {
|
||||
animation-delay: 1s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tip-content {
|
||||
padding: 6px 7px 6px 10px;
|
||||
border-radius: 4px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: rgb(4, 50, 89);
|
||||
font-size: 14px;
|
||||
color: #b9ddfd;
|
||||
.tip-content-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.tip-icon {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tip-content-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes colorChange {
|
||||
0%,
|
||||
100% {
|
||||
background-color: #00c2ff;
|
||||
}
|
||||
50% {
|
||||
background-color: #0085ff;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -52,7 +52,8 @@ const initChart = () => {
|
|||
color: '#fff',
|
||||
fontSize: 10
|
||||
},
|
||||
formatter: '{b}: {d}%'
|
||||
formatter: '{b}: {d}%',
|
||||
|
||||
},
|
||||
series: [
|
||||
{
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
<template>
|
||||
<div ref="chartRef" class="chart-container"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from "echarts/core";
|
||||
import { LineChart } from "echarts/charts";
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent
|
||||
} from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
|
||||
echarts.use([
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
GridComponent,
|
||||
LegendComponent,
|
||||
LineChart,
|
||||
CanvasRenderer
|
||||
]);
|
||||
|
||||
const chartRef = useTemplateRef("chartRef")
|
||||
let chart: echarts.ECharts | null = null;
|
||||
|
||||
const initChart = () => {
|
||||
if(!chartRef.value) return;
|
||||
chart = echarts.init(chartRef.value)
|
||||
const options = {
|
||||
tooltip: {
|
||||
trigger: 'axis'
|
||||
},
|
||||
grid: {
|
||||
top:"3%",
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '3%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
boundaryGap: false,
|
||||
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'],
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
show: false
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '数据1',
|
||||
type: 'line',
|
||||
smooth: true,
|
||||
data: [120, 132, 101, 134, 90, 230, 210],
|
||||
lineStyle: {
|
||||
color: 'rgba(41, 241, 250, 1)',
|
||||
width: 2
|
||||
},
|
||||
itemStyle: {
|
||||
color: 'rgba(41, 241, 250, 1)',
|
||||
},
|
||||
symbol:"none",
|
||||
areaStyle: {
|
||||
opacity: 0.3,
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{
|
||||
offset: 0,
|
||||
color: 'rgb(9, 86, 128)'
|
||||
},
|
||||
{
|
||||
offset: 1,
|
||||
color: 'rgb(6, 37, 99)'
|
||||
}
|
||||
])
|
||||
}
|
||||
},
|
||||
]
|
||||
};
|
||||
|
||||
chart.setOption(options);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
window.addEventListener('resize', () => {
|
||||
chart?.resize();
|
||||
});
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
chart?.dispose();
|
||||
window.removeEventListener('resize', () => {
|
||||
chart?.resize();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.chart-container {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -0,0 +1,429 @@
|
|||
<template>
|
||||
<div class="flex flex-col">
|
||||
<div class="relative flex-1">
|
||||
<div ref="chartRef" class="w-full h-full"></div>
|
||||
<div
|
||||
class="absolute left-50% top-50% transform-translate-x-[-50%] transform-translate-y-[-50%] bg-gradient-to-b from-[#8FC8FF] to-white bg-clip-text text-transparent flex items-end leading-[1] z-[2]">
|
||||
<span class="text-[24px] font-700">{{ total }}</span>
|
||||
<span class="text-[16px] font-700">人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import * as echarts from "echarts/core";
|
||||
import { TooltipComponent } from "echarts/components";
|
||||
import { CanvasRenderer } from "echarts/renderers";
|
||||
import { SurfaceChart } from "echarts-gl/charts";
|
||||
import { Grid3DComponent } from "echarts-gl/components";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
|
||||
echarts.use([TooltipComponent, Grid3DComponent, SurfaceChart, CanvasRenderer]);
|
||||
|
||||
type DefaultProps = {
|
||||
chartData: any;
|
||||
ringSize: number;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<DefaultProps>(), {
|
||||
chartData: [
|
||||
{ name: "线下", value: 310, itemStyle: { color: "rgba(147, 219, 255, 1)" } },
|
||||
{ name: "线上", value: 335, itemStyle: { color: "rgb(79, 214, 169)" } },
|
||||
],
|
||||
ringSize: 1,
|
||||
});
|
||||
|
||||
const chartRef = ref<HTMLElement | null>(null);
|
||||
let chart: echarts.ECharts | null = null;
|
||||
|
||||
interface SeriesItem {
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
// 获取3D饼图的最高扇区的高度
|
||||
const getHeight3D = (series: any[], height: number) => {
|
||||
series.sort((a, b) => {
|
||||
return b.pieData.value - a.pieData.value;
|
||||
});
|
||||
return (height * 35) / series[0].pieData.value;
|
||||
};
|
||||
|
||||
// 生成扇形的曲面参数方程
|
||||
const getParametricEquation = (startRatio: number, endRatio: number, isSelected: boolean, isHovered: boolean, k: number, h: number) => {
|
||||
const midRatio = (startRatio + endRatio) / 2;
|
||||
const startRadian = startRatio * Math.PI * 2;
|
||||
const endRadian = endRatio * Math.PI * 2;
|
||||
const midRadian = midRatio * Math.PI * 2;
|
||||
|
||||
if (startRatio === 0 && endRatio === 1) {
|
||||
isSelected = false;
|
||||
}
|
||||
|
||||
k = typeof k !== "undefined" ? k : 1 / 3;
|
||||
const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
|
||||
const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
|
||||
const hoverRate = isHovered ? 1.05 : 1;
|
||||
|
||||
return {
|
||||
u: {
|
||||
min: -Math.PI,
|
||||
max: Math.PI * 3,
|
||||
step: Math.PI / 32,
|
||||
},
|
||||
v: {
|
||||
min: 0,
|
||||
max: Math.PI * 2,
|
||||
step: Math.PI / 20,
|
||||
},
|
||||
x: (u: number, v: number) => {
|
||||
if (u < startRadian) {
|
||||
return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
}
|
||||
if (u > endRadian) {
|
||||
return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
}
|
||||
return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
},
|
||||
y: (u: number, v: number) => {
|
||||
if (u < startRadian) {
|
||||
return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
}
|
||||
if (u > endRadian) {
|
||||
return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
}
|
||||
return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
|
||||
},
|
||||
z: (u: number, v: number) => {
|
||||
if (u < -Math.PI * 0.5) {
|
||||
return Math.sin(u);
|
||||
}
|
||||
if (u > Math.PI * 2.5) {
|
||||
return Math.sin(u) * h * 0.1;
|
||||
}
|
||||
return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
// 构建3D饼图配置
|
||||
const getPie3D = (pieData: any[], internalDiameterRatio: number): any => {
|
||||
const series: SeriesItem[] = [];
|
||||
let sumValue = 0;
|
||||
let startValue = 0;
|
||||
let endValue = 0;
|
||||
const legendData: any[] = [];
|
||||
const k = 1 - internalDiameterRatio;
|
||||
|
||||
pieData.sort((a, b) => b.value - a.value);
|
||||
|
||||
// 为每个饼图数据生成series-surface配置
|
||||
for (let i = 0; i < pieData.length; i++) {
|
||||
sumValue += pieData[i].value;
|
||||
const seriesItem: SeriesItem = {
|
||||
name: pieData[i].name || `series${i}`,
|
||||
type: "surface",
|
||||
parametric: true,
|
||||
wireframe: {
|
||||
show: false,
|
||||
},
|
||||
pieData: pieData[i],
|
||||
pieStatus: {
|
||||
selected: false,
|
||||
hovered: false,
|
||||
k: k,
|
||||
},
|
||||
animation: true,
|
||||
zlevel: 1,
|
||||
};
|
||||
|
||||
if (pieData[i].itemStyle) {
|
||||
seriesItem.itemStyle = {
|
||||
color: pieData[i].itemStyle.color,
|
||||
opacity: 0.6,
|
||||
};
|
||||
}
|
||||
series.push(seriesItem);
|
||||
}
|
||||
|
||||
// 计算每个扇形的参数方程
|
||||
for (let i = 0; i < series.length; i++) {
|
||||
endValue = startValue + series[i].pieData.value;
|
||||
series[i].pieData.startRatio = startValue / sumValue;
|
||||
series[i].pieData.endRatio = endValue / sumValue;
|
||||
series[i].parametricEquation = getParametricEquation(series[i].pieData.startRatio, series[i].pieData.endRatio, false, false, k, series[i].pieData.value);
|
||||
startValue = endValue;
|
||||
legendData.push(series[i].name);
|
||||
}
|
||||
|
||||
const boxHeight = getHeight3D(series, 26);
|
||||
|
||||
return {
|
||||
tooltip: {
|
||||
formatter: (params: any) => {
|
||||
if (params.seriesName !== "mouseoutSeries" && params.seriesName !== "pie2d") {
|
||||
const bfb = ((series[params.seriesIndex].pieData.endRatio - series[params.seriesIndex].pieData.startRatio) * 100).toFixed(2);
|
||||
return `${params.seriesName}<br/>${bfb}%`;
|
||||
}
|
||||
},
|
||||
},
|
||||
xAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
yAxis3D: {
|
||||
min: -1,
|
||||
max: 1,
|
||||
},
|
||||
zAxis3D: {
|
||||
min: -4,
|
||||
max: 4,
|
||||
},
|
||||
grid3D: {
|
||||
show: false,
|
||||
boxHeight: boxHeight,
|
||||
viewControl: {
|
||||
alpha: 30,
|
||||
distance: 160,
|
||||
rotateSensitivity: 1,
|
||||
zoomSensitivity: 1,
|
||||
panSensitivity: 1,
|
||||
autoRotate: false,
|
||||
},
|
||||
},
|
||||
series: series,
|
||||
graphic: [
|
||||
{
|
||||
id: "backgroundImg",
|
||||
elements: [
|
||||
{
|
||||
type: "image",
|
||||
left: "center",
|
||||
top: "33%",
|
||||
style: {
|
||||
image: "/images/particleBase.png",
|
||||
width: 254,
|
||||
height: 106,
|
||||
},
|
||||
z: 0,
|
||||
origin: [127, 53],
|
||||
keyframeAnimation: [
|
||||
{
|
||||
duration: 1600,
|
||||
loop: true,
|
||||
keyframes: [
|
||||
{
|
||||
percent: 0,
|
||||
scaleX: 1.1,
|
||||
scaleY: 1.1,
|
||||
},
|
||||
{
|
||||
percent: 0.3,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
},
|
||||
{
|
||||
percent: 1,
|
||||
scaleX: 1.1,
|
||||
scaleY: 1.1,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
||||
// 初始化图表
|
||||
const initChart = () => {
|
||||
if (!chartRef.value) return;
|
||||
|
||||
chart = echarts.init(chartRef.value);
|
||||
const option = getPie3D(props.chartData, props.ringSize);
|
||||
|
||||
option.series.push({
|
||||
name: "pie2d",
|
||||
type: "pie",
|
||||
labelLine: {
|
||||
length: 18,
|
||||
length2: 18,
|
||||
smooth: true,
|
||||
minTurnAngle: 20,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: "outside",
|
||||
color: "inherit",
|
||||
rich: {
|
||||
a: {
|
||||
width: 5,
|
||||
height: 5,
|
||||
borderRadius: 50,
|
||||
backgroundColor: "inherit",
|
||||
},
|
||||
b: {
|
||||
fontSize: 12,
|
||||
},
|
||||
c: {
|
||||
fontSize: 12,
|
||||
},
|
||||
},
|
||||
formatter: "{a|} {b|{b}}{d|{d}}%",
|
||||
},
|
||||
startAngle: -30,
|
||||
clockwise: false,
|
||||
radius: ["30%", "60%"],
|
||||
padAngle: 360,
|
||||
center: ["50%", "50%"],
|
||||
data: props.chartData,
|
||||
itemStyle: {
|
||||
opacity: 1,
|
||||
borderWidth: 0,
|
||||
},
|
||||
z: 1,
|
||||
});
|
||||
|
||||
chart.setOption(option);
|
||||
bindEvents();
|
||||
};
|
||||
|
||||
// 绑定事件
|
||||
const bindEvents = () => {
|
||||
if (!chart) return;
|
||||
|
||||
// let selectedIndex = "";
|
||||
// let hoveredIndex = "";
|
||||
|
||||
// chart.on("click", (params: any) => {
|
||||
// if (!chart) return;
|
||||
|
||||
// const option = chart.getOption() as any;
|
||||
// const isSelected = !option.series[params.seriesIndex].pieStatus.selected;
|
||||
// const isHovered = option.series[params.seriesIndex].pieStatus.hovered;
|
||||
// const k = option.series[params.seriesIndex].pieStatus.k;
|
||||
// const startRatio = option.series[params.seriesIndex].pieData.startRatio;
|
||||
// const endRatio = option.series[params.seriesIndex].pieData.endRatio;
|
||||
|
||||
// if (selectedIndex !== "" && selectedIndex !== params.seriesIndex) {
|
||||
// option.series[selectedIndex].parametricEquation = getParametricEquation(
|
||||
// option.series[selectedIndex].pieData.startRatio,
|
||||
// option.series[selectedIndex].pieData.endRatio,
|
||||
// false,
|
||||
// false,
|
||||
// k,
|
||||
// option.series[selectedIndex].pieData.value,
|
||||
// );
|
||||
// option.series[selectedIndex].pieStatus.selected = false;
|
||||
// }
|
||||
|
||||
// option.series[params.seriesIndex].parametricEquation = getParametricEquation(
|
||||
// startRatio,
|
||||
// endRatio,
|
||||
// isSelected,
|
||||
// isHovered,
|
||||
// k,
|
||||
// option.series[params.seriesIndex].pieData.value,
|
||||
// );
|
||||
// option.series[params.seriesIndex].pieStatus.selected = isSelected;
|
||||
|
||||
// isSelected ? (selectedIndex = params.seriesIndex) : null;
|
||||
// chart.setOption(option);
|
||||
// });
|
||||
|
||||
// 鼠标悬停事件
|
||||
// chart.on("mouseover", (params: any) => {
|
||||
// if (!chart) return;
|
||||
|
||||
// const option = chart.getOption() as any;
|
||||
// if (hoveredIndex === params.seriesIndex) return;
|
||||
|
||||
// if (hoveredIndex !== "") {
|
||||
// const isSelected = option.series[hoveredIndex].pieStatus.selected;
|
||||
// const isHovered = false;
|
||||
// const k = option.series[hoveredIndex].pieStatus.k;
|
||||
// const startRatio = option.series[hoveredIndex].pieData.startRatio;
|
||||
// const endRatio = option.series[hoveredIndex].pieData.endRatio;
|
||||
|
||||
// option.series[hoveredIndex].parametricEquation = getParametricEquation(
|
||||
// startRatio,
|
||||
// endRatio,
|
||||
// isSelected,
|
||||
// isHovered,
|
||||
// k,
|
||||
// option.series[hoveredIndex].pieData.value,
|
||||
// );
|
||||
// option.series[hoveredIndex].pieStatus.hovered = isHovered;
|
||||
// hoveredIndex = "";
|
||||
// }
|
||||
|
||||
// if (params.seriesName !== "mouseoutSeries" && params.seriesName !== "pie2d") {
|
||||
// const isSelected = option.series[params.seriesIndex].pieStatus.selected;
|
||||
// const isHovered = true;
|
||||
// const k = option.series[params.seriesIndex].pieStatus.k;
|
||||
// const startRatio = option.series[params.seriesIndex].pieData.startRatio;
|
||||
// const endRatio = option.series[params.seriesIndex].pieData.endRatio;
|
||||
|
||||
// option.series[params.seriesIndex].parametricEquation = getParametricEquation(
|
||||
// startRatio,
|
||||
// endRatio,
|
||||
// isSelected,
|
||||
// isHovered,
|
||||
// k,
|
||||
// option.series[params.seriesIndex].pieData.value + 5,
|
||||
// );
|
||||
// option.series[params.seriesIndex].pieStatus.hovered = isHovered;
|
||||
// hoveredIndex = params.seriesIndex;
|
||||
// }
|
||||
|
||||
// chart.setOption(option);
|
||||
// });
|
||||
|
||||
// // 鼠标移出事件
|
||||
// chart.on("globalout", () => {
|
||||
// if (!chart) return;
|
||||
|
||||
// const option = chart.getOption() as any;
|
||||
// if (hoveredIndex !== "") {
|
||||
// const isSelected = option.series[hoveredIndex].pieStatus.selected;
|
||||
// const isHovered = false;
|
||||
// const k = option.series[hoveredIndex].pieStatus.k;
|
||||
// const startRatio = option.series[hoveredIndex].pieData.startRatio;
|
||||
// const endRatio = option.series[hoveredIndex].pieData.endRatio;
|
||||
|
||||
// option.series[hoveredIndex].parametricEquation = getParametricEquation(
|
||||
// startRatio,
|
||||
// endRatio,
|
||||
// isSelected,
|
||||
// isHovered,
|
||||
// k,
|
||||
// option.series[hoveredIndex].pieData.value,
|
||||
// );
|
||||
// option.series[hoveredIndex].pieStatus.hovered = isHovered;
|
||||
// hoveredIndex = "";
|
||||
// }
|
||||
|
||||
// chart.setOption(option);
|
||||
// });
|
||||
};
|
||||
|
||||
const total = computed(() => props.chartData.reduce((sum: number, item: any) => sum + item.value, 0));
|
||||
|
||||
// 监听数据变化
|
||||
watch(
|
||||
() => props.chartData,
|
||||
() => {
|
||||
initChart();
|
||||
},
|
||||
{ deep: true },
|
||||
);
|
||||
|
||||
// 组件挂载时初始化
|
||||
onMounted(() => {
|
||||
initChart();
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div class="main-bg aspect-[16/9]">
|
||||
<div class="main-bg flex flex-col scrollbar-hide h-screen overflow-auto ">
|
||||
<header class="relative flex items-center">
|
||||
<SvgComponent :content="headerSvg" class="w-full h-[98px]" />
|
||||
<SvgComponent :content="titleSvg" class="w-[50%] h-[69px] absolute top-0 left-50% translate-x-[-50%]" />
|
||||
|
|
@ -8,16 +8,32 @@
|
|||
<DigitalWatch class="ml-[10px]" />
|
||||
</div>
|
||||
</header>
|
||||
<div class="flex items-center justify-end pr-[24px] cursor-pointer">
|
||||
<div class="flex items-center justify-end pr-[24px] cursor-pointer mb-[13px]">
|
||||
<SvgIcon name="circle" class="text-[14px] text-[#C0EEFF] hover:rotate-90 transition-all duration-300" />
|
||||
<div class="text-[#C0EEFF] text-[12px] ml-[5px]">数据更新时间:6.12 12:00:00</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center px-[24px]">
|
||||
<PaymentTotal />
|
||||
<TodayPayment class="ml-[20px]" />
|
||||
<div class="grid grid-rows-[210px_358px_320px] gap-y-5 w-full min-h-[928px] gap-[20px] flex-1 overflow-auto mb-[27px]">
|
||||
<div class="flex items-center px-[24px] justify-start">
|
||||
<PaymentTotal />
|
||||
<TodayPayment class="ml-[20px]" />
|
||||
<GainTotal class="ml-[20px]" />
|
||||
<GainToday class="ml-[20px]" />
|
||||
<LossStatic class="ml-[20px]" />
|
||||
</div>
|
||||
<div class="flex items-center px-[24px] justify-start">
|
||||
<OperatingTrends class=""/>
|
||||
<AskSection class="ml-[20px]"/>
|
||||
</div>
|
||||
<div class="flex items-center px-[24px] overflow-x-auto">
|
||||
<StudentSource />
|
||||
<OnLineStatus class="ml-[20px]"/>
|
||||
<OfflineStatus class="ml-[20px]" />
|
||||
<SixStatistics class="ml-[20px]"/>
|
||||
<ChargingRanking class="ml-[20px]" />
|
||||
<WinCustomer class="ml-[20px]" />
|
||||
</div>
|
||||
</div>
|
||||
<!-- <TDCharts :optionData="chartData" /> -->
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
@ -25,12 +41,21 @@
|
|||
import SvgComponent from "@/components/SvgComponent.vue";
|
||||
import SvgIcon from "@/components/svg-icon/SvgIcon.vue";
|
||||
|
||||
import TDCharts from "@/components/ease-charts/TDCharts.vue";
|
||||
import DigitalWatch from "@/components/watch/DigitalWatch.vue";
|
||||
import PaymentTotal from "@/views/components/PaymentTotal.vue";
|
||||
import TodayPayment from "@/views/components/TodayPayment.vue";
|
||||
|
||||
|
||||
import GainTotal from "@/views/components/GainTotal.vue";
|
||||
import GainToday from "@/views/components/GainToday.vue";
|
||||
import LossStatic from "@/views/components/LossStatic.vue";
|
||||
import OperatingTrends from "@/views/components/OperatingTrends.vue";
|
||||
import AskSection from "@/views/components/AskSection.vue";
|
||||
import StudentSource from "@/views/components/StudentSource.vue";
|
||||
import OnLineStatus from "@/views/components/OnlineStatus.vue";
|
||||
import OfflineStatus from "@/views/components/OfflineStatus.vue";
|
||||
import SixStatistics from "@/views/components/SixStatistics.vue";
|
||||
import ChargingRanking from "./components/ChargingRanking.vue";
|
||||
import WinCustomer from "./components/WinCustomer.vue";
|
||||
|
||||
import { useDate } from "@/composables/useDate";
|
||||
|
||||
|
||||
|
|
@ -56,11 +81,7 @@
|
|||
|
||||
});
|
||||
|
||||
// 示例数据
|
||||
const chartData = ref([
|
||||
{ name: "线上", value: 335, itemStyle: { color: "#d62728" } },
|
||||
{ name: "线下", value: 310, itemStyle: { color: "#ffcc5c" } },
|
||||
]);
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
|
|
@ -69,6 +90,7 @@
|
|||
background-size: 100% 100%;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
interface Window {
|
||||
|
||||
}
|
||||
|
||||
declare module 'echarts-gl/charts';
|
||||
declare module 'echarts-gl/components';
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { defineConfig, presetIcons,presetUno } from "unocss";
|
||||
import presetWind from "@unocss/preset-wind";
|
||||
// import presetWind from "@unocss/preset-wind";
|
||||
import { presetScrollbarHide } from 'unocss-preset-scrollbar-hide'
|
||||
// import { presetPxToViewport } from "unocss-preset-px-to-vw-or-vh";
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ export default defineConfig({
|
|||
// keyToVw: ["font-size"],
|
||||
// }),
|
||||
presetUno(),
|
||||
presetWind(),
|
||||
// presetWind(),
|
||||
presetScrollbarHide(),
|
||||
presetIcons({
|
||||
scale: 1,
|
||||
|
|
|
|||