数据大屏
|
@ -82,7 +82,11 @@
|
||||||
"vxe-table-plugin-antd": "4.0.8",
|
"vxe-table-plugin-antd": "4.0.8",
|
||||||
"vxe-pc-ui": "4.6.12",
|
"vxe-pc-ui": "4.6.12",
|
||||||
"xe-utils": "3.5.26",
|
"xe-utils": "3.5.26",
|
||||||
"xss": "^1.0.15"
|
"xss": "^1.0.15",
|
||||||
|
"three": "^0.178.0",
|
||||||
|
"jquery": "^3.7.1",
|
||||||
|
"element-plus": "^2.10.4",
|
||||||
|
"@element-plus/icons-vue": "^2.3.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^18.6.1",
|
"@commitlint/cli": "^18.6.1",
|
||||||
|
|
14071
pnpm-lock.yaml
After Width: | Height: | Size: 1.0 MiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 39 KiB |
After Width: | Height: | Size: 5.2 KiB |
After Width: | Height: | Size: 5.6 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 5.2 KiB |
|
@ -0,0 +1,119 @@
|
||||||
|
|
||||||
|
/*
|
||||||
|
椭圆会使内部失真 transform: rotateX(50deg);
|
||||||
|
*/
|
||||||
|
.rotation3D{
|
||||||
|
position: relative; width: 800px; height: 750px; cursor: move; user-select: none;
|
||||||
|
margin: 0 auto; margin-top: -100px;
|
||||||
|
/*border: 1px solid white; border-radius: 100%;*/
|
||||||
|
}
|
||||||
|
.rotation3D .center{
|
||||||
|
display: none;
|
||||||
|
position: absolute; left: 50%; top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.rotation3D .itemList{ position: absolute; width: 100%; height: 100%; z-index: 20; }
|
||||||
|
.rotation3D .lineList{
|
||||||
|
position: absolute; width: 100%; height: 100%; z-index: 10;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*---------------------------点样式---------------------------*/
|
||||||
|
.rotation3D__item{
|
||||||
|
position: absolute; display: block; cursor: pointer; width: 161px; height: 188px;
|
||||||
|
text-align: center; line-height: 30px; font-size: 16px; color: white;
|
||||||
|
/*background: #2292ef; border-radius: 4px;*/
|
||||||
|
}
|
||||||
|
.rotation3D__item .scale{ position: absolute; top: 0; width: 100%; height: 100%; }
|
||||||
|
.rotation3D__item .cont{ position: relative; z-index: 2; }
|
||||||
|
.rotation3D__item .cont .iconfont { font-size: 28px; margin-top: 14px; margin-bottom: 0px; display: block; }
|
||||||
|
.rotation3D__item .cont p{ color: #fff; }
|
||||||
|
|
||||||
|
.rotation3D__item.blue{ color: #01e9fc; }
|
||||||
|
.rotation3D__item.green{ color: #02e943; }
|
||||||
|
.rotation3D__item.yellow{ color: #ffd200; }
|
||||||
|
|
||||||
|
/*底座*/
|
||||||
|
.rotation3D__item .baseImg{ position: absolute; width: 100%; height: 100%; z-index: 1; }
|
||||||
|
.rotation3D__item.blue .baseImg{ background: url("img/blue.png"); }
|
||||||
|
.rotation3D__item.green .baseImg{ background: url("img/green.png"); }
|
||||||
|
.rotation3D__item.yellow .baseImg{ background: url("img/yellow.png"); }
|
||||||
|
|
||||||
|
/*---------------------------
|
||||||
|
线样式
|
||||||
|
线高为总高的一般
|
||||||
|
---------------------------*/
|
||||||
|
.rotation3D__line{
|
||||||
|
position: absolute; left: 50%; top: 50%;
|
||||||
|
display: block; width: 2px; height: 50%;
|
||||||
|
padding-top: 60px; color: #fff; font-size: 50px;
|
||||||
|
/*background: #fff;*/
|
||||||
|
/*原点设置在中间*/
|
||||||
|
transform-origin: 50% 0;
|
||||||
|
transform-style: preserve-3d;
|
||||||
|
}
|
||||||
|
.rotation3D__line .pos{ position: absolute; top: 0; }
|
||||||
|
.rotation3D__line svg { position: absolute; top: 0; }
|
||||||
|
.rotation3D__line svg path {
|
||||||
|
stroke: #fff; fill: none;
|
||||||
|
stroke-width: 3;
|
||||||
|
animation: path-animation 100s linear 0s infinite normal;
|
||||||
|
}
|
||||||
|
@keyframes path-animation {
|
||||||
|
0% { stroke-dashoffset:500; }
|
||||||
|
100% { stroke-dashoffset:0; }
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot {
|
||||||
|
position: absolute; top: 0; left: 0; text-align: center;
|
||||||
|
/*width: 35px; height: 35px; font-size: 35px; */
|
||||||
|
width: 24px; height: 24px; font-size: 24px;
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot1,.rotation3D__line .dot3,.rotation3D__line .dot4{
|
||||||
|
animation: svg-path-animation 6s ease-in-out 0s infinite normal;
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot1{
|
||||||
|
offset-path: path("M0 400, 0 0"); offset-distance: 0%;
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot2{
|
||||||
|
offset-path: path("M0 200, 0 0"); offset-distance: 0%;
|
||||||
|
background: #ffd200; border-radius: 100%;
|
||||||
|
font-size: 22px; color: #000;
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot3{
|
||||||
|
offset-path: path("M20 400 S 0 200, 20 0"); offset-distance: 0%;
|
||||||
|
}
|
||||||
|
.rotation3D__line .dot4{
|
||||||
|
offset-path: path("M20 0 S 40 200, 20 400"); offset-distance: 0%;
|
||||||
|
}
|
||||||
|
@keyframes svg-path-animation {
|
||||||
|
from {offset-distance: 0%;}
|
||||||
|
to {offset-distance: 100%;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*颜色*/
|
||||||
|
.rotation3D__line.blue { color: #07b2f9; }
|
||||||
|
.rotation3D__line.green { color: #00ff5b; }
|
||||||
|
.rotation3D__line.yellow { color: #ffd500; }
|
||||||
|
|
||||||
|
.rotation3D__line.blue svg path { stroke: #07b2f9; }
|
||||||
|
.rotation3D__line.green svg path { stroke: #00ff5b; }
|
||||||
|
.rotation3D__line.yellow svg path { stroke: #ffd500; }
|
||||||
|
|
||||||
|
.rotation3D-baseMap{
|
||||||
|
position: absolute; left: 10px; right: 0; top: 126px; margin: auto;
|
||||||
|
width: 900px; height: 516px;
|
||||||
|
background: url("@/assets/img/baseMap.png") no-repeat;
|
||||||
|
background-position:center;
|
||||||
|
}
|
||||||
|
.rotation3D-baseMap::before{
|
||||||
|
position: absolute; left: 0px; right: 0; top: 0px; margin: auto; z-index: 99;
|
||||||
|
width: 342px; height: 318px; display: block; content: '';
|
||||||
|
background: url("@/assets/img/baseLogo.png") no-repeat;
|
||||||
|
animation: 10s bounceUpDown infinite;
|
||||||
|
background-size: 70%;
|
||||||
|
background-position: center ;
|
||||||
|
}
|
||||||
|
.mt-20{
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
|
@ -0,0 +1,164 @@
|
||||||
|
/* 全局样式 */
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||||
|
background-color: #0a192f;
|
||||||
|
color: #e6f1ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 滚动条样式 */
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
height: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-track {
|
||||||
|
background: rgba(100, 116, 139, 0.1);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background: rgba(148, 163, 184, 0.5);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb:hover {
|
||||||
|
background: rgba(148, 163, 184, 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 标题样式 */
|
||||||
|
.section-title {
|
||||||
|
position: relative;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding-left: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 4px;
|
||||||
|
background: linear-gradient(to bottom, #4ce7ff, #165dff);
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 数字动画 */
|
||||||
|
.number-counter {
|
||||||
|
font-family: 'Roboto Mono', monospace;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 渐变按钮 */
|
||||||
|
.gradient-btn {
|
||||||
|
background: linear-gradient(90deg, #4ce7ff 0%, #165dff 100%);
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-btn:hover {
|
||||||
|
transform: translateY(-1px);
|
||||||
|
box-shadow: 0 5px 15px rgba(22, 93, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.gradient-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
box-shadow: 0 2px 5px rgba(22, 93, 255, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 状态标签 */
|
||||||
|
.status-tag {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 2px 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.up {
|
||||||
|
background-color: rgba(16, 185, 129, 0.1);
|
||||||
|
color: #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-tag.down {
|
||||||
|
background-color: rgba(239, 68, 68, 0.1);
|
||||||
|
color: #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 骨架屏加载 */
|
||||||
|
.skeleton {
|
||||||
|
background: linear-gradient(90deg, rgba(255, 255, 255, 0.05) 25%, rgba(255, 255, 255, 0.1) 50%, rgba(255, 255, 255, 0.05) 75%);
|
||||||
|
background-size: 200% 100%;
|
||||||
|
animation: skeleton-loading 1.5s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes skeleton-loading {
|
||||||
|
0% {
|
||||||
|
background-position: 200% 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
background-position: -200% 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@font-face {
|
||||||
|
font-family: "unidreamLED";
|
||||||
|
src: url('@/assets/fonts/UnidreamLED.ttf');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "iconfont"; /* Project id 3045003 */
|
||||||
|
src: url('//at.alicdn.com/t/font_3045003_lkxtjaj4m6.woff2?t=1641286939195') format('woff2'),
|
||||||
|
url('//at.alicdn.com/t/font_3045003_lkxtjaj4m6.woff?t=1641286939195') format('woff'),
|
||||||
|
url('//at.alicdn.com/t/font_3045003_lkxtjaj4m6.ttf?t=1641286939195') format('truetype');
|
||||||
|
}
|
||||||
|
|
||||||
|
.iconfont {
|
||||||
|
font-family: "iconfont" !important;
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-liangchang:before {
|
||||||
|
content: "\e622";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-lumianshigong:before {
|
||||||
|
content: "\e623";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shiyanjiance:before {
|
||||||
|
content: "\e624";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-renyuanguanli:before {
|
||||||
|
content: "\e625";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-tanpuyashifuwu:before {
|
||||||
|
content: "\e626";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shujufuwuzhongxin:before {
|
||||||
|
content: "\e627";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-lujishigong2x:before {
|
||||||
|
content: "\e620";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-GPS:before {
|
||||||
|
content: "\e621";
|
||||||
|
}
|
After Width: | Height: | Size: 71 KiB |
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>
|
After Width: | Height: | Size: 496 B |
|
@ -64,5 +64,15 @@ export const TokenLoginRoute: AppRouteRecordRaw = {
|
||||||
ignoreAuth: true,
|
ignoreAuth: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const newScreenRoute: AppRouteRecordRaw = {
|
||||||
|
path: '/screen/screen',
|
||||||
|
name: 'screenIndex',
|
||||||
|
component: () => import('/@/views/screen/screen.vue'),
|
||||||
|
meta: {
|
||||||
|
title: t('routes.basic.login'),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Basic routing without permission
|
// Basic routing without permission
|
||||||
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute];
|
export const basicRoutes = [LoginRoute, RootRoute, ...mainOutRoutes, REDIRECT_ROUTE, PAGE_NOT_FOUND_ROUTE, TokenLoginRoute, Oauth2LoginRoute,newScreenRoute];
|
||||||
|
|
|
@ -0,0 +1,376 @@
|
||||||
|
import $ from 'jquery'
|
||||||
|
const cancelFrame = window.cancelAnimationFrame || window.cancelRequestAnimationFrame;
|
||||||
|
const requestFrame = window.requestAnimationFrame;
|
||||||
|
export let NumTile = "";
|
||||||
|
const time = !window.performance || !window.performance.now
|
||||||
|
? () => +new Date()
|
||||||
|
: () => performance.now();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计算两点距离
|
||||||
|
* @param points
|
||||||
|
* @returns {number}
|
||||||
|
* distance([{x:0,y:0},{x:1,y:1}]);
|
||||||
|
*/
|
||||||
|
const distance = (points) => {
|
||||||
|
const p1 = points[0];
|
||||||
|
const p2 = points[1];
|
||||||
|
const a = p2.x - p1.x;
|
||||||
|
const b = p2.y - p1.y;
|
||||||
|
return Math.sqrt(a * a + b * b);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 圆公式
|
||||||
|
* @param rotation 弧度
|
||||||
|
* 计算公式:
|
||||||
|
* Math.PI; //圆周率
|
||||||
|
* Math.sin(); //正弦 x -左 +右
|
||||||
|
* Math.cos; //余弦 y -下 +上
|
||||||
|
*/
|
||||||
|
const circleMath = {
|
||||||
|
/**
|
||||||
|
* 根据弧度计算角度
|
||||||
|
* @param rotation 弧度
|
||||||
|
* rotation, farScale, xs, xr, ys, yr, itemWidth
|
||||||
|
*/
|
||||||
|
parseRotate(rotation, self) {
|
||||||
|
const sin = Math.sin(rotation);
|
||||||
|
const cos = Math.cos(rotation);
|
||||||
|
const sin_cos = sin * cos; //得出偏移正负值,从0°向左依次 +-+-
|
||||||
|
let angle = (180 / Math.PI * rotation) - 180;
|
||||||
|
let lastAngle = angle;
|
||||||
|
|
||||||
|
lastAngle = angle + (self.yr * (sin_cos / (Math.PI + 1)));
|
||||||
|
|
||||||
|
return lastAngle;
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 计算scale,x,y
|
||||||
|
* scale 最小尺寸 + ((1 - 最小尺寸) * (sin正弦 + 1) * 0.5)
|
||||||
|
* x x起点 + (尺寸 * cos余弦 * x半径) - 元素宽度一半
|
||||||
|
* y y起点 + (尺寸 * sin正弦 * x半径) - 元素宽度一半
|
||||||
|
* farScale, xs, xr, ys, yr, itemWidth
|
||||||
|
*/
|
||||||
|
parseSXY(rotation, self) {
|
||||||
|
const { farScale, itemWidth, xs, xr, ys, yr } = self;
|
||||||
|
const sin = Math.sin(rotation);
|
||||||
|
const cos = Math.cos(rotation);
|
||||||
|
const scale = farScale + ((1 - farScale) * (sin + 1) * 0.5); //单个尺寸
|
||||||
|
|
||||||
|
// 使用压缩
|
||||||
|
const x = xs + (cos * xr) - (itemWidth * 0.5);
|
||||||
|
const y = ys + (sin * yr) - (itemWidth * 0.5);
|
||||||
|
const distanceNumber = distance([
|
||||||
|
{ x: self.$rotation.width() / 2 - self.$item.width() / 2, y: self.$rotation.height() / 2 - self.$item.height() / 2 },
|
||||||
|
{ x, y }
|
||||||
|
]);
|
||||||
|
|
||||||
|
return { x, y, scale, distanceNumber };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 3D旋转
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
export class Rotation3D {
|
||||||
|
constructor(_opts) {
|
||||||
|
const self = this;
|
||||||
|
this.$rotation = $(_opts.id);
|
||||||
|
this.$lineList = this.$rotation.find('.lineList');
|
||||||
|
this.$item = this.$rotation.find('.rotation3D__item');
|
||||||
|
this.$line = this.$rotation.find('.rotation3D__line');
|
||||||
|
this.itemWidth = this.$item.width();
|
||||||
|
this.itemHeight = this.$item.height();
|
||||||
|
this.length = this.$item.length;
|
||||||
|
|
||||||
|
// 圆计算
|
||||||
|
this.rotation = Math.PI / 2; //圆周率/2
|
||||||
|
this.destRotation = this.rotation;
|
||||||
|
|
||||||
|
const xr = this.$rotation.width() * 0.5;
|
||||||
|
const yr = this.$rotation.height() * 0.5;
|
||||||
|
const xRadius = _opts.xRadius || 0;
|
||||||
|
const yRadius = _opts.yRadius || 0;
|
||||||
|
|
||||||
|
const opts = Object.assign({
|
||||||
|
farScale: 1, // 最小尺寸
|
||||||
|
xs: xr, // x起点
|
||||||
|
ys: yr, // y起点
|
||||||
|
xr: xr - xRadius, // x半径-压缩
|
||||||
|
yr: yr - yRadius, // y半径-压缩
|
||||||
|
// 播放
|
||||||
|
autoPlay: false,
|
||||||
|
autoPlayDelay: 3000,
|
||||||
|
currenIndex: -1,
|
||||||
|
fps: 30,
|
||||||
|
speed: 4,
|
||||||
|
}, _opts);
|
||||||
|
Object.assign(this, opts);
|
||||||
|
|
||||||
|
// 遍历子元素
|
||||||
|
this.$item.each(function (index) {
|
||||||
|
if(NumTile == ''){
|
||||||
|
setTimeout(() => {
|
||||||
|
let num = self.$item[0].dataset.num;
|
||||||
|
let dw = self.$item[0].dataset.dw;
|
||||||
|
$('.rotation3DNum').html(num);
|
||||||
|
$('.dw').html(`(${dw})`);
|
||||||
|
}, 1500);
|
||||||
|
}
|
||||||
|
$(this).click(function () {
|
||||||
|
$(this).addClass('active').siblings().removeClass('active');
|
||||||
|
let num = $(this).attr('data-num');
|
||||||
|
let dw = $(this).attr('data-dw');
|
||||||
|
$('.dw').html(`(${dw})`);
|
||||||
|
$('.rotation3DNum').css('opacity', 0);
|
||||||
|
setTimeout(() => {
|
||||||
|
$('.rotation3DNum').html(num); // 更改数字内容
|
||||||
|
$('.rotation3DNum').css('opacity', 1);
|
||||||
|
}, 500);
|
||||||
|
self.goTo(index);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 当前控件进入离开
|
||||||
|
this.$rotation.mouseenter(function () {
|
||||||
|
clearInterval(self.autoPlayTimer);
|
||||||
|
});
|
||||||
|
this.$rotation.mouseleave(function () {
|
||||||
|
self.onAutoPlay();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.onAutoPlay();
|
||||||
|
this.onDrag();
|
||||||
|
this.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* item样式
|
||||||
|
* x x起点 + (尺寸 * 余弦 * x压缩) - 元素宽度一半
|
||||||
|
* y y起点 + (尺寸 * 正弦 * y压缩) - 元素宽度一半
|
||||||
|
*/
|
||||||
|
itemStyle($item, index, rotation) {
|
||||||
|
const parseSXY = circleMath.parseSXY(rotation, this);
|
||||||
|
const { scale, x, y } = parseSXY;
|
||||||
|
const $line = this.$lineList.find('.rotation3D__line').eq(index);
|
||||||
|
|
||||||
|
//设置当前子菜单的位置(left,top) = (x,y)
|
||||||
|
$item.find('.scale').css({
|
||||||
|
transform: `scale(${scale})`
|
||||||
|
});
|
||||||
|
$item.css({
|
||||||
|
position: 'absolute',
|
||||||
|
display: 'inline-block',
|
||||||
|
'z-index': parseInt(scale * 100),
|
||||||
|
'transform-origin': '0px 0px',
|
||||||
|
transform: `translate(${x}px, ${y}px)`
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 线样式
|
||||||
|
*/
|
||||||
|
$line.css({
|
||||||
|
height: parseSXY.distanceNumber
|
||||||
|
});
|
||||||
|
$line.find('svg').css({
|
||||||
|
height: parseSXY.distanceNumber
|
||||||
|
});
|
||||||
|
$line.find('.dot1').css({
|
||||||
|
'offset-path': `path("M0 ${parseSXY.distanceNumber}, 0 0")`
|
||||||
|
});
|
||||||
|
$line.find('#path1').attr({
|
||||||
|
d: `M0 ${parseSXY.distanceNumber}, 0 0`
|
||||||
|
});
|
||||||
|
|
||||||
|
$line.find('.dot2').css({
|
||||||
|
'offset-path': `path("M0 ${parseSXY.distanceNumber/2}, 0 0")`
|
||||||
|
});
|
||||||
|
$line.find('#path2').attr({
|
||||||
|
d: `M0 ${parseSXY.distanceNumber}, 0 0`
|
||||||
|
});
|
||||||
|
|
||||||
|
$line.find('.dot3').css({
|
||||||
|
'offset-path': `path("M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0")`
|
||||||
|
});
|
||||||
|
$line.find('#path3').attr({
|
||||||
|
d: `M20 ${parseSXY.distanceNumber} S 0 ${parseSXY.distanceNumber/2}, 20 0`
|
||||||
|
});
|
||||||
|
|
||||||
|
$line.find('.dot4').css({
|
||||||
|
'offset-path': `path("M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}")`
|
||||||
|
});
|
||||||
|
$line.find('#path4').attr({
|
||||||
|
d: `M20 0 S 40 ${parseSXY.distanceNumber/2}, 20 ${parseSXY.distanceNumber}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* line样式
|
||||||
|
*/
|
||||||
|
lineStyle($line, index, rotation) {
|
||||||
|
const rotate = circleMath.parseRotate(rotation, this);
|
||||||
|
$line.css({
|
||||||
|
transform: `rotate(${rotate}deg)`
|
||||||
|
});
|
||||||
|
this.$lineList.css({
|
||||||
|
// transform: `rotateX(${this.yRadius / 3}deg)`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 旋转至index
|
||||||
|
*/
|
||||||
|
goTo(index) {
|
||||||
|
const self = this;
|
||||||
|
this.currenIndex = index;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1.计算floatIndex,用于控死amdiff
|
||||||
|
*/
|
||||||
|
const itemsRotated = this.length * ((Math.PI / 2) - this.rotation) / (2 * Math.PI);
|
||||||
|
let floatIndex = itemsRotated % this.length;
|
||||||
|
if (floatIndex < 0) { floatIndex = floatIndex + this.length; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 2.计算diff,判断方向正反
|
||||||
|
*/
|
||||||
|
let diff = index - (floatIndex % this.length);
|
||||||
|
if (2 * Math.abs(diff) > this.length) {
|
||||||
|
diff -= (diff > 0) ? this.length : -this.length;
|
||||||
|
}
|
||||||
|
// 停止任何正在进行的旋转
|
||||||
|
this.destRotation += (2 * Math.PI / this.length) * -diff;
|
||||||
|
this.scheduleNextFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 定时器渐近旋转
|
||||||
|
*/
|
||||||
|
scheduleNextFrame() {
|
||||||
|
const self = this;
|
||||||
|
this.lastTime = time();
|
||||||
|
|
||||||
|
// 暂停
|
||||||
|
const pause = function () {
|
||||||
|
cancelFrame ? cancelFrame(this.timer) : clearTimeout(self.timer);
|
||||||
|
self.timer = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渐进播放
|
||||||
|
const playFrame = function () {
|
||||||
|
const rem = self.destRotation - self.rotation;
|
||||||
|
const now = time();
|
||||||
|
const dt = (now - self.lastTime) * 0.002;
|
||||||
|
self.lastTime = now;
|
||||||
|
|
||||||
|
if (Math.abs(rem) < 0.003) {
|
||||||
|
self.rotation = self.destRotation;
|
||||||
|
pause();
|
||||||
|
} else {
|
||||||
|
// 渐近地接近目的地
|
||||||
|
self.rotation = self.destRotation - rem / (1 + (self.speed * dt));
|
||||||
|
self.scheduleNextFrame();
|
||||||
|
}
|
||||||
|
self.render();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.timer = cancelFrame
|
||||||
|
? requestFrame(playFrame)
|
||||||
|
: setTimeout(playFrame, 1000 / this.fps);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*/
|
||||||
|
render() {
|
||||||
|
const self = this;
|
||||||
|
// 图形间隔:弧度
|
||||||
|
const spacing = 2 * Math.PI / this.$item.length;
|
||||||
|
let itemRotation = this.rotation;
|
||||||
|
let lineRotation = this.rotation + (Math.PI / 2);
|
||||||
|
this.$item.each(function (index) {
|
||||||
|
self.itemStyle($(this), index, itemRotation);
|
||||||
|
itemRotation += spacing;
|
||||||
|
});
|
||||||
|
this.$line.each(function (index) {
|
||||||
|
self.lineStyle($(this), index, lineRotation);
|
||||||
|
lineRotation += spacing;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 自动播放
|
||||||
|
*/
|
||||||
|
onAutoPlay() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
if (this.autoPlay) {
|
||||||
|
this.autoPlayTimer = setInterval(function () {
|
||||||
|
if (self.currenIndex < 0) {
|
||||||
|
self.currenIndex = self.length - 1;
|
||||||
|
}
|
||||||
|
self.goTo(self.currenIndex);
|
||||||
|
self.currenIndex--; //倒叙
|
||||||
|
}, this.autoPlayDelay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拖拽
|
||||||
|
*/
|
||||||
|
onDrag() {
|
||||||
|
const self = this;
|
||||||
|
let startX, startY, moveX, moveY, endX, endY;
|
||||||
|
|
||||||
|
// 拖拽:三个事件-按下 移动 抬起
|
||||||
|
//按下
|
||||||
|
this.$rotation.mousedown(function (e) {
|
||||||
|
startX = e.pageX;
|
||||||
|
startY = e.pageY;
|
||||||
|
|
||||||
|
// 移动
|
||||||
|
$(document).mousemove(function (e) {
|
||||||
|
endX = e.pageX;
|
||||||
|
endY = e.pageY;
|
||||||
|
moveX = endX - startX;
|
||||||
|
moveY = endY - startY;
|
||||||
|
});
|
||||||
|
|
||||||
|
// 抬起
|
||||||
|
$(document).mouseup(function (e) {
|
||||||
|
endX = e.pageX;
|
||||||
|
endY = e.pageY;
|
||||||
|
moveX = endX - startX;
|
||||||
|
moveY = endY - startY;
|
||||||
|
|
||||||
|
// 每40旋转一步
|
||||||
|
const moveIndex = parseInt(Math.abs(moveX) / 50);
|
||||||
|
if (moveIndex > 0) {
|
||||||
|
if (moveX < 0) { //向左
|
||||||
|
self.currenIndex = self.currenIndex - moveIndex;
|
||||||
|
play(moveIndex);
|
||||||
|
} else { //向右
|
||||||
|
self.currenIndex = self.currenIndex + moveIndex;
|
||||||
|
play(moveIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解绑
|
||||||
|
$(document).unbind("mousemove");
|
||||||
|
$(document).unbind("mouseup");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function play() {
|
||||||
|
if (self.currenIndex === 0) {
|
||||||
|
self.currenIndex = self.length - 1;
|
||||||
|
}
|
||||||
|
self.goTo(self.currenIndex % self.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//window.Rotation3D = Rotation3D;
|
||||||
|
//export default Rotation3D
|
|
@ -9,6 +9,7 @@ enum Api {
|
||||||
xqtd = '/zh/home/getXqtd',
|
xqtd = '/zh/home/getXqtd',
|
||||||
sbtd = '/zh/home/getSbtd',
|
sbtd = '/zh/home/getSbtd',
|
||||||
hytd = '/zh/home/getHytd',
|
hytd = '/zh/home/getHytd',
|
||||||
|
xqqy = '/zh/home/getXqqy',
|
||||||
sstd = '/zh/home/getSstd',
|
sstd = '/zh/home/getSstd',
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
@ -59,6 +60,12 @@ export const getSbtd = (params) => defHttp.get({ url: Api.sbtd, params }, { isTr
|
||||||
*/
|
*/
|
||||||
export const getHytd = (params) => defHttp.get({ url: Api.hytd, params }, { isTransformResponse: false });
|
export const getHytd = (params) => defHttp.get({ url: Api.hytd, params }, { isTransformResponse: false });
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小区清运
|
||||||
|
* @param params
|
||||||
|
*/
|
||||||
|
export const getXqqy = (params) => defHttp.get({ url: Api.xqqy, params }, { isTransformResponse: false });
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 实时投递
|
* 实时投递
|
||||||
* @param params
|
* @param params
|
||||||
|
|
|
@ -46,7 +46,15 @@
|
||||||
</a-row>
|
</a-row>
|
||||||
|
|
||||||
<a-row :gutter="16" style="padding:16px 0px 0px 16px;width: 100%">
|
<a-row :gutter="16" style="padding:16px 0px 0px 16px;width: 100%">
|
||||||
<a-col :span="6">
|
<a-col :span="4">
|
||||||
|
<a-card>
|
||||||
|
<div @click="openDataBigScreen">
|
||||||
|
<div class="space-between"><span>数据大屏</span></div>
|
||||||
|
<span style="font-size:45px;padding-left: 80px;"><fund-two-tone /></span>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="5">
|
||||||
<a-card>
|
<a-card>
|
||||||
<div>
|
<div>
|
||||||
<div class="space-between"><span>今日投递重量(T)</span><span>昨日</span></div>
|
<div class="space-between"><span>今日投递重量(T)</span><span>昨日</span></div>
|
||||||
|
@ -59,7 +67,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="5">
|
||||||
<a-card>
|
<a-card>
|
||||||
<div class="space-between"><span>今日投递次数(次)</span><span>昨日</span></div>
|
<div class="space-between"><span>今日投递次数(次)</span><span>昨日</span></div>
|
||||||
<div class="space-between"><span class="card-title">{{formData.tdcsT}}</span><span>{{formData.tdcsY}}</span></div>
|
<div class="space-between"><span class="card-title">{{formData.tdcsT}}</span><span>{{formData.tdcsY}}</span></div>
|
||||||
|
@ -70,7 +78,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="5">
|
||||||
<a-card>
|
<a-card>
|
||||||
<div class="space-between"><span>今日清运重量(T)</span><span>昨日</span></div>
|
<div class="space-between"><span>今日清运重量(T)</span><span>昨日</span></div>
|
||||||
<div class="space-between"><span class="card-title">{{formData.qyzlT}}</span><span>{{formData.qyzlY}}</span></div>
|
<div class="space-between"><span class="card-title">{{formData.qyzlT}}</span><span>{{formData.qyzlY}}</span></div>
|
||||||
|
@ -81,7 +89,7 @@
|
||||||
</div>
|
</div>
|
||||||
</a-card>
|
</a-card>
|
||||||
</a-col>
|
</a-col>
|
||||||
<a-col :span="6">
|
<a-col :span="5">
|
||||||
<a-card>
|
<a-card>
|
||||||
<div class="space-between"><span>今日新增会员(人)</span><span>昨日</span></div>
|
<div class="space-between"><span>今日新增会员(人)</span><span>昨日</span></div>
|
||||||
<div class="space-between"><span class="card-title">{{formData.hyrsT}}</span><span>{{formData.hyrsY}}</span></div>
|
<div class="space-between"><span class="card-title">{{formData.hyrsT}}</span><span>{{formData.hyrsY}}</span></div>
|
||||||
|
@ -161,13 +169,15 @@
|
||||||
</template>
|
</template>
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import {onMounted, reactive, ref} from 'vue';
|
import {onMounted, reactive, ref} from 'vue';
|
||||||
|
import { FundTwoTone } from '@ant-design/icons-vue';
|
||||||
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
import { BasicTable, useTable, TableAction } from '/@/components/Table';
|
||||||
import { useListPage } from '/@/hooks/system/useListPage';
|
import { useListPage } from '/@/hooks/system/useListPage';
|
||||||
import Pie from '/@/components/chart/Pie.vue';
|
import Pie from '/@/components/chart/Pie.vue';
|
||||||
import BarAndLine from '/@/components/chart/BarAndLine.vue';
|
import BarAndLine from '/@/components/chart/BarAndLine.vue';
|
||||||
import {getTotalInfo, getTodayInfo, getOrderTypeCn, getXqtd, getSbtd, getHytd, getSstd} from './api';
|
import {getTotalInfo, getTodayInfo, getOrderTypeCn, getXqtd, getSbtd, getHytd, getSstd, getXqqy} from './api';
|
||||||
import {orderColumns} from './data';
|
import {orderColumns} from './data';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
const router = useRouter();
|
||||||
const queryParam = reactive<any>({});
|
const queryParam = reactive<any>({});
|
||||||
//注册table数据
|
//注册table数据
|
||||||
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
const { prefixCls, tableContext, onExportXls, onImportXls } = useListPage({
|
||||||
|
@ -350,20 +360,42 @@
|
||||||
try {
|
try {
|
||||||
dataSource.value = [];
|
dataSource.value = [];
|
||||||
const res = await getSstd({});
|
const res = await getSstd({});
|
||||||
console.log(res);
|
|
||||||
dataSource.value = res.result;
|
dataSource.value = res.result;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
// 小区清运
|
||||||
|
async function loadXqqy(){
|
||||||
|
try {
|
||||||
|
const res = await getXqqy({});
|
||||||
|
console.log(res);
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadData(){
|
||||||
loadTotalData();
|
loadTotalData();
|
||||||
loadTodayData();
|
loadTodayData();
|
||||||
loadOrderTypeCn();
|
loadOrderTypeCn();
|
||||||
loadXqtd();
|
loadXqtd();
|
||||||
loadSbtd();
|
loadSbtd();
|
||||||
loadHytd();
|
loadHytd();
|
||||||
// loadSstd();
|
// loadXqqy();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
reload();
|
||||||
|
loadData();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
function openDataBigScreen(){
|
||||||
|
const url = router.resolve({ path: '/screen/screen' }).href
|
||||||
|
window.open(url, '_blank')
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadData();
|
||||||
})
|
})
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
<template>
|
||||||
|
<div class="rotation3D-baseMap"></div>
|
||||||
|
<div class="muflex">
|
||||||
|
<label class="rotation3DNum"></label><span class="dw"></span>
|
||||||
|
</div>
|
||||||
|
<!--旋转3D-->
|
||||||
|
<div id="rotation3D" class="rotation3D">
|
||||||
|
<div class="itemList">
|
||||||
|
<div class="rotation3D__item" :class="item.type" v-for="item in itemList" :data-num="item.num" :data-dw="item.dw">
|
||||||
|
<div class="scale">
|
||||||
|
<div class="baseImg"></div>
|
||||||
|
<div class="cont">
|
||||||
|
<!-- <i class="iconfont"> {{ item.num }} </i> -->
|
||||||
|
<i class="iconfont" :class="item.icon"></i>
|
||||||
|
<p class="item-name-overflow">{{item.name}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="lineList">
|
||||||
|
<div class="rotation3D__line" v-for="item in itemList" :class="item.type">
|
||||||
|
<div class="pos" v-if="item.type == 'blue'">
|
||||||
|
<svg width="10" height="400">
|
||||||
|
<path id="path1" d="M0 400, 0 0" stroke-dasharray="5,10"/>
|
||||||
|
</svg>
|
||||||
|
<div class="dot dot1 el-icon-caret-right"></div>
|
||||||
|
</div>
|
||||||
|
<div class="pos" v-if="item.type == 'yellow'">
|
||||||
|
<svg width="10" height="400">
|
||||||
|
<path id="path2" d="M0 400, 0 0" stroke-dasharray="5,10"/>
|
||||||
|
</svg>
|
||||||
|
<!-- <div class="dot dot2"><i class="el-icon-close"></i></div> -->
|
||||||
|
</div>
|
||||||
|
<div class="pos" style="left: -16px;" v-if="item.type == 'green'">
|
||||||
|
<svg width="50" height="400">
|
||||||
|
<path id="path3" d="M0 400, 0 0" stroke-dasharray="5,10"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup>
|
||||||
|
import {onMounted, ref} from 'vue';
|
||||||
|
import{ Rotation3D } from '@/utiles/index';
|
||||||
|
import { getTotalInfo } from "../../dashboard/Analysis/api";
|
||||||
|
|
||||||
|
const itemList = ref([
|
||||||
|
{ name:'总投递重量(T)', type:'blue', num:'0', icon:'icon-a-lujishigong2x', dw:'T'},
|
||||||
|
{ name:'总清运重量(T)', type:'green', num:'0', icon:'icon-a-lujishigong2x',dw:'T'},
|
||||||
|
{ name:'总会员(人)', type:'yellow', num:'0',icon:'icon-renyuanguanli', dw:'人' },
|
||||||
|
{ name:'总设备(台)', type:'blue', num:'0', icon:'icon-liangchang',dw:'台'},
|
||||||
|
{ name:'在线设备(台)', type:'green', num:'0', icon:'icon-tanpuyashifuwu', dw:'台'},
|
||||||
|
{ name:'离线设备(台)', type:'yellow', num:'0', icon:'icon-lumianshigong',dw:'台'},
|
||||||
|
{ name:'总区域(个)', type:'blue', num:'0', icon:'icon-GPS ',dw:'个' },
|
||||||
|
{ name:'总投递次数(次)', type:'green', num:'0', icon:'icon-shiyanjiance',dw:'次'},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const rotation3D = ref();
|
||||||
|
|
||||||
|
function createRotation3D(){
|
||||||
|
rotation3D.value = new Rotation3D({
|
||||||
|
id: '#rotation3D',
|
||||||
|
farScale: 0.6,
|
||||||
|
// farScale: 1,
|
||||||
|
xRadius: 0, //x半径压缩
|
||||||
|
yRadius: 220, //y半径压缩
|
||||||
|
// yRadius: 0, //y半径压缩
|
||||||
|
//autoPlay:true,
|
||||||
|
//autoPlayDelay:6000,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadTotalData() {
|
||||||
|
const resData = await getTotalInfo({});
|
||||||
|
const res = resData.result;
|
||||||
|
itemList.value = [];
|
||||||
|
itemList.value.push(
|
||||||
|
{
|
||||||
|
name: '总投递重量(T)',
|
||||||
|
type: 'blue',
|
||||||
|
num: res.tdzlA,
|
||||||
|
icon:'icon-a-lujishigong2x',
|
||||||
|
dw:'T'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '总清运重量(T)',
|
||||||
|
type: 'green',
|
||||||
|
num: res.qyzlA,
|
||||||
|
icon:'icon-a-lujishigong2x',
|
||||||
|
dw:'T'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '总会员(人)',
|
||||||
|
type: 'yellow',
|
||||||
|
num: res.hyrsA,
|
||||||
|
icon:'icon-renyuanguanli',
|
||||||
|
dw:'人'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '总设备(台)',
|
||||||
|
type: 'blue',
|
||||||
|
num: res.sbsA,
|
||||||
|
icon:'icon-liangchang',
|
||||||
|
dw:'台'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '在线设备(台)',
|
||||||
|
type: 'green',
|
||||||
|
num: res.zxsbsA,
|
||||||
|
icon:'icon-tanpuyashifuwu',
|
||||||
|
dw:'台'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '离线设备(台)',
|
||||||
|
type: 'yellow',
|
||||||
|
num: res.lxsbsA,
|
||||||
|
icon:'icon-lumianshigong',
|
||||||
|
dw:'台'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '总区域(个)',
|
||||||
|
type: 'blue',
|
||||||
|
num: res.qysA,
|
||||||
|
icon:'icon-GPS',
|
||||||
|
dw:'台'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '总投递次数(次)',
|
||||||
|
type: 'green',
|
||||||
|
num: res.tdcsA,
|
||||||
|
icon:'icon-shiyanjiance',
|
||||||
|
dw:'次'
|
||||||
|
},
|
||||||
|
);
|
||||||
|
// rotation3D.value.render();
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadTotalData();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
onMounted(()=>{
|
||||||
|
createRotation3D();
|
||||||
|
loadTotalData();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
@import url('@/assets/rotation3D.css');
|
||||||
|
.rotation3DNum{
|
||||||
|
font-size: 48px;
|
||||||
|
color: aqua;
|
||||||
|
font-family: 'unidreamLED';
|
||||||
|
transition: opacity 0.5s ease-out;
|
||||||
|
}
|
||||||
|
.dw{
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: aqua;
|
||||||
|
}
|
||||||
|
.muflex{
|
||||||
|
position: absolute;
|
||||||
|
left: 2%;
|
||||||
|
top: 10px;
|
||||||
|
}
|
||||||
|
.item-name-overflow{
|
||||||
|
word-wrap: break-word; /* 或使用 overflow-wrap: break-word; */
|
||||||
|
width: 60px; /* 设定一个宽度来观察效果 */
|
||||||
|
margin-left: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,301 @@
|
||||||
|
<template>
|
||||||
|
<div class="data-card" :id="id"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, onMounted, reactive} from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import {getXqtd} from "../../dashboard/Analysis/api";
|
||||||
|
// import { Info } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
data:{
|
||||||
|
type:String
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let quLabel = ref([]);
|
||||||
|
let quCn = ref([]);
|
||||||
|
let quWeight = ref([]);
|
||||||
|
let myChart = reactive({});
|
||||||
|
function tid(data){
|
||||||
|
quLabel.value = [];
|
||||||
|
quCn.value = [];
|
||||||
|
quWeight.value = [];
|
||||||
|
data.forEach((item)=>{
|
||||||
|
quLabel.value.push(item.housingestateName);
|
||||||
|
quCn.value.push(item.cn);
|
||||||
|
quWeight.value.push(item.weight)
|
||||||
|
})
|
||||||
|
const chartDom = document.getElementById(props.id);
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
// 科技风格配色
|
||||||
|
const colors = {
|
||||||
|
primary: 'rgba(66, 165, 245, 0.9)', // 主色调:科技蓝
|
||||||
|
secondary: 'rgba(129, 199, 132, 0.9)', // 辅助色:科技绿
|
||||||
|
gridLine: 'rgba(100, 150, 255, 0.1)', // 网格线
|
||||||
|
axisLine: 'rgba(100, 150, 255, 0.3)', // 坐标轴
|
||||||
|
textColor: '#a8b2d1', // 文本
|
||||||
|
tooltipBg: 'rgba(10, 25, 47, 0.8)', // 提示框背景
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渐变效果
|
||||||
|
const gradientPrimary = {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0, y: 0, x2: 0, y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{offset: 0, color: 'rgba(66, 165, 245, 0.9)'},
|
||||||
|
{offset: 1, color: 'rgba(66, 165, 245, 0.3)'}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const option = {
|
||||||
|
|
||||||
|
// 图例
|
||||||
|
legend: {
|
||||||
|
data: ['投递重量(T)','投递次数'],
|
||||||
|
textStyle: { color: colors.textColor },
|
||||||
|
icon: 'rect',
|
||||||
|
itemWidth: 14,
|
||||||
|
itemHeight: 8,
|
||||||
|
top: '3%'
|
||||||
|
},
|
||||||
|
|
||||||
|
// 网格(图表边距)
|
||||||
|
grid: {
|
||||||
|
left: '4%',
|
||||||
|
right: '2%',
|
||||||
|
bottom: '15%',
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// X轴配置
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: quLabel.value,
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: colors.axisLine }
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: colors.textColor,
|
||||||
|
interval: 0,
|
||||||
|
rotate: 45
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Y轴配置(左侧:访问量)
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递重量(T)',
|
||||||
|
nameTextStyle: { color: colors.primary },
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: colors.primary }
|
||||||
|
},
|
||||||
|
axisLabel: { color: colors.textColor },
|
||||||
|
splitLine: { show: false }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递次数',
|
||||||
|
nameTextStyle: { color: colors.secondary },
|
||||||
|
axisTick: { show: false },
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: colors.secondary }
|
||||||
|
},
|
||||||
|
axisLabel: { color: colors.textColor },
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: colors.gridLine }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// 系列数据(柱状图+折线图)
|
||||||
|
series: [
|
||||||
|
// 柱状图:访问量(科技蓝渐变)
|
||||||
|
{
|
||||||
|
name: '投递重量(T)',
|
||||||
|
type: 'bar',
|
||||||
|
yAxisIndex: 0,
|
||||||
|
barWidth: '35%',
|
||||||
|
data: quWeight.value,
|
||||||
|
itemStyle: { color: gradientPrimary },
|
||||||
|
emphasis: { itemStyle: { color: colors.primary } },
|
||||||
|
animationDelay: idx => idx * 10
|
||||||
|
},
|
||||||
|
// 折线图:转化率(紫色渐变)
|
||||||
|
{
|
||||||
|
name: '投递次数',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1, // 关联右侧Y轴
|
||||||
|
data: quCn.value,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: 8,
|
||||||
|
itemStyle: { color: colors.secondary },
|
||||||
|
lineStyle: {
|
||||||
|
color: colors.secondary,
|
||||||
|
width: 2,
|
||||||
|
type: 'solid'
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0, y: 0, x2: 0, y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{offset: 0, color: 'rgba(129, 199, 132, 0.4)'},
|
||||||
|
{offset: 1, color: 'rgba(129, 199, 132, 0.05)'}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animationDelay: idx => idx * 10 + 100
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// tooltip(提示框)样式优化
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
crossStyle: {
|
||||||
|
color: 'rgba(100, 255, 218, 0.7)',
|
||||||
|
width: 1,
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backgroundColor: colors.tooltipBg,
|
||||||
|
borderColor: 'rgba(100, 150, 255, 0.3)',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: { color: '#e6f1ff' },
|
||||||
|
},
|
||||||
|
|
||||||
|
// 背景色(与页面背景融合)
|
||||||
|
//backgroundColor: 'transparent'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置配置项并渲染
|
||||||
|
myChart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadXqtd() {
|
||||||
|
const resData = await getXqtd({});
|
||||||
|
const res = resData.result;
|
||||||
|
let xqu = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
xqu.push({
|
||||||
|
housingestateName: res[i].housingestateName,
|
||||||
|
cn: res[i].cn,
|
||||||
|
weight: res[i].weight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tid(xqu);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadXqtd();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
// 响应窗口大小变化
|
||||||
|
onMounted(()=>{
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
myChart.resize();
|
||||||
|
});
|
||||||
|
loadXqtd();
|
||||||
|
})
|
||||||
|
// const formattedValue = computed(() => {
|
||||||
|
// if (typeof props.value === 'number') {
|
||||||
|
// if (props.value >= 100000000) {
|
||||||
|
// return (props.value / 100000000).toFixed(2) + '亿'
|
||||||
|
// } else if (props.value >= 10000) {
|
||||||
|
// return (props.value / 10000).toFixed(2) + '万'
|
||||||
|
// } else {
|
||||||
|
// return props.value.toLocaleString()
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return props.value
|
||||||
|
// })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.data-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-display {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.number-counter {
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unit {
|
||||||
|
margin-left: 4px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-indicator {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.change-desc {
|
||||||
|
margin-left: 8px;
|
||||||
|
color: #94a3b8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-data .el-list-item {
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid rgba(100, 116, 139, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-item-content {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-name {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-value {
|
||||||
|
margin: 0 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-percentage {
|
||||||
|
min-width: 60px;
|
||||||
|
text-align: right;
|
||||||
|
} */
|
||||||
|
</style>
|
|
@ -0,0 +1,273 @@
|
||||||
|
<template>
|
||||||
|
<div class="data-card" :id="id"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { ref, reactive, onMounted } from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import {getHytd} from "../../dashboard/Analysis/api";
|
||||||
|
// import { Info } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let quLabel = ref([]);
|
||||||
|
let quCn = ref([]);
|
||||||
|
let quWeight = ref([]);
|
||||||
|
|
||||||
|
let myChart = reactive({});
|
||||||
|
function tid(data) {
|
||||||
|
quLabel.value = [];
|
||||||
|
quCn.value = [];
|
||||||
|
quWeight.value = [];
|
||||||
|
data.forEach((item) => {
|
||||||
|
quLabel.value.push(item.phone);
|
||||||
|
quCn.value.push(item.cn);
|
||||||
|
quWeight.value.push(item.weight)
|
||||||
|
})
|
||||||
|
const chartDom = document.getElementById(props.id);
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
// 图表配置
|
||||||
|
const option = {
|
||||||
|
|
||||||
|
// 图例
|
||||||
|
legend: {
|
||||||
|
data: ['投递重量(KG)','投递次数'],
|
||||||
|
top: '3%',
|
||||||
|
textStyle: { color: '#a8b2d1' }, // 图例文字颜色
|
||||||
|
icon: 'circle', // 圆形图例,更简洁
|
||||||
|
itemWidth: 8
|
||||||
|
},
|
||||||
|
|
||||||
|
// 网格(图表边距)
|
||||||
|
grid: {
|
||||||
|
left: '2%',
|
||||||
|
right: '3%',
|
||||||
|
bottom: '15%',
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// X轴配置
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: quLabel.value,
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: '#2d3748' } // X轴线颜色(深灰)
|
||||||
|
},
|
||||||
|
axisTick: { show: false }, // 隐藏刻度线
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a0aec0', // 刻度文字颜色
|
||||||
|
rotate: 45,
|
||||||
|
formatter: function (params) {
|
||||||
|
// return params.slice(-4);
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Y轴配置(左侧:访问量)
|
||||||
|
yAxis: [
|
||||||
|
// 右侧Y轴(转化率)
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递重量(KG)',
|
||||||
|
nameTextStyle: { color: 'rgba(129, 199, 132)' },
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(129, 199, 132)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: { show: false },
|
||||||
|
splitLine: { show: false }, // 右侧不显示网格线,避免冲突
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a8b2d1',
|
||||||
|
// formatter: '{value}%'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递次数',
|
||||||
|
nameTextStyle: { color: '#63b3ed' }, // 轴名称颜色
|
||||||
|
axisLine: { show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(66, 165, 245)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: { show: false },
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(74, 85, 104, 0.3)', // 网格线半透明
|
||||||
|
type: 'dashed' // 虚线网格,科技感
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a8b2d1',
|
||||||
|
// formatter: '{value}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
// 系列数据(柱状图+折线图)
|
||||||
|
series: [
|
||||||
|
// 柱状图:访问量(科技蓝渐变)
|
||||||
|
{
|
||||||
|
name: '投递重量(KG)',
|
||||||
|
type: 'bar',
|
||||||
|
data: quWeight.value,
|
||||||
|
// 柱子宽度
|
||||||
|
barWidth: 24,
|
||||||
|
// 圆角柱子
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: [6, 6, 0, 0], // 上圆角,下直角
|
||||||
|
// 蓝色渐变(科技感核心)
|
||||||
|
// 蓝色渐变(科技感核心)
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0, y: 0, x2: 0, y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{offset: 0, color: '#00FF9D'},
|
||||||
|
{offset: 1, color: 'rgba(0, 255, 157, 0.4)'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 柱子边框高亮
|
||||||
|
emphasis: {
|
||||||
|
itemStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{offset: 0, color: '#00FF9D'}, // 底部颜色
|
||||||
|
{offset: 1, color: 'rgba(0, 255, 157, 0.3)'} // 顶部颜色c
|
||||||
|
]),
|
||||||
|
boxShadow: '0 0 15px rgba(49, 130, 206, 0.6)' // 鼠标悬停发光
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 数值标签(顶部显示)
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
align: 'center',
|
||||||
|
color: '#e0e7ff',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 折线图:转化率(紫色渐变)
|
||||||
|
{
|
||||||
|
name: '投递次数',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1, // 关联右侧Y轴
|
||||||
|
data: quCn.value,
|
||||||
|
// 线样式
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
// color: '#165DFF', // 主色
|
||||||
|
color: '#16b9ff', // 主色
|
||||||
|
shadowBlur: 10,
|
||||||
|
// shadowColor: 'rgba(22, 93, 255, 0.7)' // 发光效果
|
||||||
|
shadowColor: 'rgba(22,139,255,0.7)' // 发光效果
|
||||||
|
},
|
||||||
|
// 拐点样式
|
||||||
|
symbol: 'circle', // 圆形拐点
|
||||||
|
symbolSize: 8, // 拐点大小
|
||||||
|
itemStyle: {
|
||||||
|
// color: '#805ad5',
|
||||||
|
// borderColor: '#fff',
|
||||||
|
color: '#16b9ff', // 主色
|
||||||
|
borderColor: '#16b9ff', // 主色
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
// 拐点高亮
|
||||||
|
emphasis: {
|
||||||
|
symbolSize: 12,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#d53f8c',
|
||||||
|
boxShadow: '0 0 10px rgba(213, 63, 140, 0.8)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 填充区域渐变
|
||||||
|
areaStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{offset: 0, color: 'rgba(22, 93, 255, 0.3)'},
|
||||||
|
{offset: 1, color: 'rgba(22, 93, 255, 0.05)'}
|
||||||
|
])
|
||||||
|
},
|
||||||
|
// 数值标签
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'bottom',
|
||||||
|
color: '#e9d8fd',
|
||||||
|
// formatter: '{value}%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// tooltip(提示框)样式优化
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
axisPointer: {
|
||||||
|
type: 'cross',
|
||||||
|
crossStyle: {
|
||||||
|
color: 'rgba(100, 255, 218, 0.7)',
|
||||||
|
width: 1,
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(17, 24, 39, 0.9)', // 半透明深色背景
|
||||||
|
borderColor: 'rgba(79, 70, 229, 0.5)',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: { color: '#e0e7ff' },
|
||||||
|
padding: 12,
|
||||||
|
// 提示框内网格线
|
||||||
|
extraCssText: 'box-shadow: 0 0 15px rgba(79, 70, 229, 0.3);',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// 背景色(与页面背景融合)
|
||||||
|
//backgroundColor: 'transparent'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置配置项并渲染
|
||||||
|
myChart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function loadHytd() {
|
||||||
|
const resData = await getHytd({});
|
||||||
|
const res = resData.result;
|
||||||
|
let Hy = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
Hy.push({
|
||||||
|
phone: res[i].phone,
|
||||||
|
cn: res[i].cn,
|
||||||
|
weight: res[i].weight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tid(Hy);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadHytd();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
// 响应窗口大小变化
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
myChart.resize();
|
||||||
|
});
|
||||||
|
loadHytd();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.data-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,178 @@
|
||||||
|
<template>
|
||||||
|
<div class="data-card" :id="id"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, onMounted, reactive} from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import {getXqqy} from "../../dashboard/Analysis/api";
|
||||||
|
// import { Info } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let quCn = ref([
|
||||||
|
]);
|
||||||
|
let quWeight = ref([]);
|
||||||
|
let myChart = reactive({});
|
||||||
|
function tid(data) {
|
||||||
|
quCn.value = [];
|
||||||
|
quWeight.value = [];
|
||||||
|
data.forEach((item, idx) => {
|
||||||
|
quCn.value.push({
|
||||||
|
name: item.housingestateName,
|
||||||
|
value: item.cn,
|
||||||
|
symbolSize: item.cn / 10,
|
||||||
|
count: item.cn,
|
||||||
|
weight: item.weight
|
||||||
|
});
|
||||||
|
|
||||||
|
quWeight.value.push({
|
||||||
|
source: '中心节点',
|
||||||
|
target: item.housingestateName,
|
||||||
|
value: item.weight,
|
||||||
|
lineStyle: {
|
||||||
|
width: item.weight / 20,
|
||||||
|
color: `rgba(100, 255, 218, ${item.weight / 3000 + 0.1})`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const chartDom = document.getElementById(props.id);
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
// 科技风格配色
|
||||||
|
const colors = {
|
||||||
|
primary: 'rgba(66, 165, 245, 0.9)', // 主色调:科技蓝
|
||||||
|
secondary: 'rgba(100, 255, 218, 0.9)', // 辅助色:科技青
|
||||||
|
accent: 'rgba(255, 102, 102, 0.9)', // 强调色:科技红
|
||||||
|
gridLine: 'rgba(100, 150, 255, 0.1)', // 网格线
|
||||||
|
axisLine: 'rgba(100, 150, 255, 0.3)', // 坐标轴
|
||||||
|
textColor: '#a8b2d1', // 文本
|
||||||
|
tooltipBg: 'rgba(10, 25, 47, 0.8)', // 提示框背景
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 图表配置
|
||||||
|
// 图表配置
|
||||||
|
const option = {
|
||||||
|
backgroundColor: 'transparent',
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: function (params) {
|
||||||
|
if (params.dataType === 'edge') {
|
||||||
|
return `
|
||||||
|
<div style="color:#64ffda;font-weight:bold">连接</div>
|
||||||
|
<div>投递重量(T): ${params.data.value}</div>
|
||||||
|
<div>${params.data.source} → ${params.data.target}</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return `
|
||||||
|
<div style="color:#64ffda;font-weight:bold">${params.data.name}</div>
|
||||||
|
<div>投递重量(T): ${params.data.weight}</div>
|
||||||
|
<div>投递次数: ${params.data.count}</div>
|
||||||
|
|
||||||
|
`;
|
||||||
|
},
|
||||||
|
backgroundColor: colors.tooltipBg,
|
||||||
|
borderColor: 'rgba(100, 150, 255, 0.3)',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: { color: '#e6f1ff' }
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'graph',
|
||||||
|
layout: 'force',
|
||||||
|
data: quCn.value,
|
||||||
|
links: quWeight.value,
|
||||||
|
roam: true,
|
||||||
|
focusNodeAdjacency: true,
|
||||||
|
draggable: true,
|
||||||
|
force: {
|
||||||
|
repulsion: 100,
|
||||||
|
edgeLength: [40, 100]
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'right',
|
||||||
|
color: colors.textColor
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: 'source',
|
||||||
|
curveness: 0.1
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
lineStyle: {
|
||||||
|
width: function (edge) {
|
||||||
|
return edge.value / 120;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: function (params) {
|
||||||
|
if (params.data.category === 0) {
|
||||||
|
return colors.primary;
|
||||||
|
}
|
||||||
|
// 根据次数调整颜色透明度
|
||||||
|
return `rgba(${params.data.count *0.15}, ${params.data.count *0.4}, ${params.data.count * 0.75}, ${params.data.count / 300 + 0.9})`;
|
||||||
|
},
|
||||||
|
shadowBlur: 50,
|
||||||
|
shadowColor: function (params) {
|
||||||
|
if (params.data.category === 0) {
|
||||||
|
return 'rgba(100, 255, 218, 0.7)';
|
||||||
|
}
|
||||||
|
return 'rgba(66, 165, 245, 0.5)';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animationDuration: 500,
|
||||||
|
animationEasing: 'elasticOut',
|
||||||
|
animationDelay: function (idx) {
|
||||||
|
return idx * 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// 设置配置项并渲染
|
||||||
|
myChart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 小区清运
|
||||||
|
async function loadXqqy(){
|
||||||
|
const resData = await getXqqy({});
|
||||||
|
const res = resData.result;
|
||||||
|
let Qy = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
Qy.push({
|
||||||
|
housingestateName: res[i].housingestateName,
|
||||||
|
cn: res[i].cn,
|
||||||
|
weight: res[i].weight,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
tid(Qy);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadXqqy();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
// 响应窗口大小变化
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
myChart.resize();
|
||||||
|
});
|
||||||
|
loadXqqy();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.data-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,267 @@
|
||||||
|
<template>
|
||||||
|
<div class="data-card" :id="id"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, onMounted, reactive} from 'vue'
|
||||||
|
import * as echarts from 'echarts'
|
||||||
|
import {getSbtd} from "../../dashboard/Analysis/api";
|
||||||
|
// import { Info } from '@element-plus/icons-vue'
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
type: String
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let quLabel = ref([]);
|
||||||
|
let quCn = ref([]);
|
||||||
|
let quWeight = ref([]);
|
||||||
|
let myChart = reactive({});
|
||||||
|
function tid(data) {
|
||||||
|
quLabel.value = [];
|
||||||
|
quCn.value = [];
|
||||||
|
quWeight.value = [];
|
||||||
|
data.forEach((item) => {
|
||||||
|
quLabel.value.push(`${item.housingestateName}-${item.content}`);
|
||||||
|
//quLabel.value.push(item.content);
|
||||||
|
quCn.value.push(item.cn);
|
||||||
|
quWeight.value.push(item.weight)
|
||||||
|
})
|
||||||
|
const chartDom = document.getElementById(props.id);
|
||||||
|
myChart = echarts.init(chartDom);
|
||||||
|
|
||||||
|
// 图表配置
|
||||||
|
const option = {
|
||||||
|
|
||||||
|
// 图例
|
||||||
|
legend: {
|
||||||
|
data: ['投递重量(T)','投递次数'],
|
||||||
|
top: '3%',
|
||||||
|
textStyle: { color: '#a8b2d1' }, // 图例文字颜色
|
||||||
|
icon: 'circle', // 圆形图例,更简洁
|
||||||
|
itemWidth: 8
|
||||||
|
},
|
||||||
|
|
||||||
|
// 网格(图表边距)
|
||||||
|
grid: {
|
||||||
|
left: '5%',
|
||||||
|
right: '2%',
|
||||||
|
bottom: '10%',
|
||||||
|
containLabel: true,
|
||||||
|
},
|
||||||
|
|
||||||
|
// X轴配置
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: quLabel.value,
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: { color: '#2d3748' } // X轴线颜色(深灰)
|
||||||
|
},
|
||||||
|
axisTick: { show: false }, // 隐藏刻度线
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a0aec0', // 刻度文字颜色
|
||||||
|
rotate: 45,
|
||||||
|
formatter: function (params) {
|
||||||
|
if (typeof params !== 'string') {
|
||||||
|
return ''; // 处理非字符串输入
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = params.lastIndexOf('-');
|
||||||
|
if (index === -1) {
|
||||||
|
return ''; // 没有找到破折号
|
||||||
|
}
|
||||||
|
return params.substring(index + 1).trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Y轴配置(左侧:访问量)
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递重量(T)',
|
||||||
|
nameTextStyle: { color: '#805ad5' }, // 轴名称颜色
|
||||||
|
axisLine: { show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgb(128,90,213)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: { show: false },
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(74, 85, 104, 0.3)', // 网格线半透明
|
||||||
|
type: 'dashed' // 虚线网格,科技感
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a8b2d1',
|
||||||
|
// formatter: '{value}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 右侧Y轴(转化率)
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
name: '投递次数',
|
||||||
|
nameTextStyle: { color: '#63b3ed' },
|
||||||
|
axisLine: { show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: 'rgba(66, 165, 245)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: { show: false },
|
||||||
|
splitLine: { show: false }, // 右侧不显示网格线,避免冲突
|
||||||
|
axisLabel: {
|
||||||
|
color: '#a8b2d1',
|
||||||
|
// formatter: '{value}%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// 系列数据(柱状图+折线图)
|
||||||
|
series: [
|
||||||
|
// 柱状图:访问量(科技蓝渐变)
|
||||||
|
{
|
||||||
|
name: '投递重量(T)',
|
||||||
|
type: 'bar',
|
||||||
|
data: quWeight.value,
|
||||||
|
// 柱子宽度
|
||||||
|
barWidth: 24,
|
||||||
|
// 圆角柱子
|
||||||
|
itemStyle: {
|
||||||
|
borderRadius: [6, 6, 0, 0], // 上圆角,下直角
|
||||||
|
// 蓝色渐变(科技感核心)
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0, y: 0, x2: 0, y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{offset: 0, color: '#9D4EDD'},
|
||||||
|
{offset: 1, color: 'rgba(22, 93, 255, 0.6)'}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// 柱子边框高亮
|
||||||
|
emphasis: {
|
||||||
|
itemStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{ offset: 0, color: '#63b3ed' }, // 高亮时更亮
|
||||||
|
{ offset: 1, color: '#3182ce' }
|
||||||
|
]),
|
||||||
|
boxShadow: '0 0 15px rgba(49, 130, 206, 0.6)' // 鼠标悬停发光
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 数值标签(顶部显示)
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
align: 'center',
|
||||||
|
color: '#e0e7ff',
|
||||||
|
fontSize: 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 折线图:转化率(紫色渐变)
|
||||||
|
{
|
||||||
|
name: '投递次数',
|
||||||
|
type: 'line',
|
||||||
|
yAxisIndex: 1, // 关联右侧Y轴
|
||||||
|
data: quCn.value,
|
||||||
|
// 线样式
|
||||||
|
lineStyle: {
|
||||||
|
width: 3,
|
||||||
|
color: '#00E5FF', // 线条颜色
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowColor: 'rgba(0, 229, 255, 0.5)' // 发光效果
|
||||||
|
},
|
||||||
|
// 拐点样式
|
||||||
|
symbol: 'circle', // 圆形拐点
|
||||||
|
symbolSize: 8, // 拐点大小
|
||||||
|
itemStyle: {
|
||||||
|
color: '#805ad5',
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 2
|
||||||
|
},
|
||||||
|
// 拐点高亮
|
||||||
|
emphasis: {
|
||||||
|
symbolSize: 12,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#d53f8c',
|
||||||
|
boxShadow: '0 0 10px rgba(213, 63, 140, 0.8)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 填充区域渐变
|
||||||
|
areaStyle: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||||
|
{ offset: 0, color: 'rgba(128, 90, 213, 0.3)' },
|
||||||
|
{ offset: 1, color: 'rgba(128, 90, 213, 0)' }
|
||||||
|
])
|
||||||
|
},
|
||||||
|
// 数值标签
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'bottom',
|
||||||
|
color: '#e9d8fd',
|
||||||
|
// formatter: '{value}%'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// tooltip(提示框)样式优化
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
backgroundColor: 'rgba(17, 24, 39, 0.9)', // 半透明深色背景
|
||||||
|
borderColor: 'rgba(79, 70, 229, 0.5)',
|
||||||
|
borderWidth: 1,
|
||||||
|
textStyle: { color: '#e0e7ff' },
|
||||||
|
padding: 12,
|
||||||
|
// 提示框内网格线
|
||||||
|
extraCssText: 'box-shadow: 0 0 15px rgba(79, 70, 229, 0.3);',
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// 背景色(与页面背景融合)
|
||||||
|
//backgroundColor: 'transparent'
|
||||||
|
};
|
||||||
|
|
||||||
|
// 设置配置项并渲染
|
||||||
|
myChart.setOption(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadSbtd() {
|
||||||
|
const resData = await getSbtd({});
|
||||||
|
const res = resData.result;
|
||||||
|
let Sb = [];
|
||||||
|
for (let i = 0; i < res.length; i++) {
|
||||||
|
Sb.push({
|
||||||
|
housingestateName: res[i].housingestateName,
|
||||||
|
content: res[i].content,
|
||||||
|
cn: res[i].cn,
|
||||||
|
weight: res[i].weight,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
tid(Sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadSbtd();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
// 响应窗口大小变化
|
||||||
|
onMounted(() => {
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
myChart.resize();
|
||||||
|
});
|
||||||
|
loadSbtd();
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.data-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,42 @@
|
||||||
|
<template>
|
||||||
|
<div class="page-header">
|
||||||
|
<div class="header-title">
|
||||||
|
<h1>{{ title }}</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
defineProps({
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
default: '吉林资环数据平台'
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.page-header {
|
||||||
|
display: flex;
|
||||||
|
height: 60px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
background-image: url('@/assets/titlebg.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-title h1 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 32px;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 10px;
|
||||||
|
background: linear-gradient(to top, #098fe9, #ffffff);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -0,0 +1,277 @@
|
||||||
|
<template>
|
||||||
|
<div class="dashboard-container">
|
||||||
|
<PageHeader />
|
||||||
|
<a-row :gutter="20" class="main-content">
|
||||||
|
<!-- 左侧面板 -->
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-card class="panel-card" :body-style="{'width':'100%','height':'100%','padding':'0', 'margin-top': '-34px'}">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-header">
|
||||||
|
<sliders-two-tone style="margin-right: 5px"/>
|
||||||
|
<span>小区排行</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<DataCard :id="`echart1`"/>
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card class="panel-card mt-20" :body-style="{'width':'100%','height':'100%','padding':'0','margin-top': '-34px'}">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-header">
|
||||||
|
<sliders-two-tone style="margin-right: 5px" />
|
||||||
|
<span>设备排行</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<DataCardSet :id="`echart2`" :data="Sb" />
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<!-- 中间面板 -->
|
||||||
|
<a-col :span="12">
|
||||||
|
<a-card class="mind-card" :body-style="{'padding':'0'}">
|
||||||
|
|
||||||
|
<ChartComponent
|
||||||
|
ref="mainChartRef"
|
||||||
|
:showControls="true"
|
||||||
|
:initialConfig="particleConfig"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div class="statistics-container">
|
||||||
|
<a-row :gutter="20">
|
||||||
|
<a-col :span="6" v-for="(item, index) in statistics" :key="index">
|
||||||
|
<div class="statistics-item">
|
||||||
|
<div class="title">{{ item.title }}</div>
|
||||||
|
<div class="flex justify-between items-center">
|
||||||
|
<div class="today-data">{{ item.today }}</div>
|
||||||
|
<div class="yesterday">昨日 {{ item.yesterday }}</div>
|
||||||
|
</div>
|
||||||
|
<div :style="{ color: item.rateColor }" class="rate">较昨日 {{ item.rate }}</div>
|
||||||
|
</div>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="6">
|
||||||
|
<a-card class="panel-card" :body-style="{'width':'100%','height':'100%','padding':'0', 'margin-top': '-34px'}">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-header">
|
||||||
|
<sliders-two-tone style="margin-right: 5px"/>
|
||||||
|
<span>会员排行</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<DataCardHy :id="`echart3`" :data="Hy" />
|
||||||
|
</a-card>
|
||||||
|
|
||||||
|
<a-card class="panel-card mt-20" :body-style="{'width':'100%','height':'100%','padding':'0','margin-top': '-34px'}">
|
||||||
|
<template #title>
|
||||||
|
<div class="card-header">
|
||||||
|
<sliders-two-tone style="margin-right: 5px"/>
|
||||||
|
<span>小区清运</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<DataCardQy :id="`echart4`" :data="Qy"/>
|
||||||
|
</a-card>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import {ref, onMounted, computed, reactive} from 'vue'
|
||||||
|
import {
|
||||||
|
SlidersTwoTone
|
||||||
|
} from '@ant-design/icons-vue';
|
||||||
|
import PageHeader from './components/PageHeader.vue'
|
||||||
|
import DataCard from './components/DataCard.vue'
|
||||||
|
import DataCardSet from './components/DataCardSet.vue'
|
||||||
|
import DataCardHy from './components/DataCardHy.vue'
|
||||||
|
import DataCardQy from './components/DataCardQy.vue'
|
||||||
|
import ChartComponent from './components/ChartComponent.vue'
|
||||||
|
import {getTodayInfo} from "../dashboard/Analysis/api";
|
||||||
|
|
||||||
|
const particleConfig = ref({
|
||||||
|
particleCount: 800,
|
||||||
|
radius: 30,
|
||||||
|
particleSize: 0.4,
|
||||||
|
animationSpeed: 0.015,
|
||||||
|
colorMode: 'group'
|
||||||
|
})
|
||||||
|
|
||||||
|
async function loadTodayData() {
|
||||||
|
statistics.value = [];
|
||||||
|
const resData = await getTodayInfo({});
|
||||||
|
const res = resData.result;
|
||||||
|
statistics.value.push(
|
||||||
|
{
|
||||||
|
title: '今日投递重量(T)',
|
||||||
|
today: res.tdzlT,
|
||||||
|
yesterday: res.tdzlY,
|
||||||
|
rate: res.tdzlR+"%",
|
||||||
|
rateColor: res.tdzlR>=0?'#ff3333':'#00FF9D'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '今日投递次数(次)',
|
||||||
|
today: res.tdcsT,
|
||||||
|
yesterday: res.tdcsY,
|
||||||
|
rate: res.tdcsR+"%",
|
||||||
|
rateColor: res.tdzlR>=0?'#ff3333':'#00FF9D'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '今日清运重量(T)',
|
||||||
|
today: res.qyzlT,
|
||||||
|
yesterday: res.qyzlY,
|
||||||
|
rate: res.qyzlR+"%",
|
||||||
|
rateColor: res.tdzlR>=0?'#ff3333':'#00FF9D'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '今日新增会员(人)',
|
||||||
|
today: res.hyrsT,
|
||||||
|
yesterday: res.hyrsY,
|
||||||
|
rate: res.hyrsR+"%",
|
||||||
|
rateColor: res.tdzlR>=0?'#ff3333':'#00FF9D'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟底部信息数据
|
||||||
|
const statistics = ref([])
|
||||||
|
|
||||||
|
// 图表引用
|
||||||
|
const mainChartRef = ref(null)
|
||||||
|
const budgetChartRef = ref(null)
|
||||||
|
const trendChartRef = ref(null)
|
||||||
|
|
||||||
|
setInterval(function() {
|
||||||
|
loadTodayData();
|
||||||
|
}, 30*60*1000);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
loadTodayData();
|
||||||
|
})
|
||||||
|
|
||||||
|
// 窗口大小变化时调整图表
|
||||||
|
const handleResize = () => {
|
||||||
|
if (mainChartRef.value) mainChartRef.value.resize()
|
||||||
|
if (budgetChartRef.value) budgetChartRef.value.resize()
|
||||||
|
if (trendChartRef.value) trendChartRef.value.resize()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="less">
|
||||||
|
|
||||||
|
.dashboard-container {
|
||||||
|
background-image: url('@/assets/bg.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
/*margin-top: 20px;*/
|
||||||
|
padding: 15px 15px 0px 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-card {
|
||||||
|
background: url('@/assets/borderbg.png') no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
border: 1px solid rgba(64, 158, 255, 0.2);
|
||||||
|
border-radius: 8px;
|
||||||
|
color: #fff;
|
||||||
|
height: 43vh;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
.mind-card{
|
||||||
|
background: transparent;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.card-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
height: 30px;
|
||||||
|
padding-left: 20px;
|
||||||
|
|
||||||
|
}
|
||||||
|
::v-deep(.ant-card-head-title){
|
||||||
|
background: url('@/assets/btbg.png') no-repeat center;
|
||||||
|
background-size: 100%;
|
||||||
|
height: 76px;
|
||||||
|
border: none;
|
||||||
|
padding: 5px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep(.ant-card-head){
|
||||||
|
margin-left: 0px!important;
|
||||||
|
margin-right: 0px!important;
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
.card-header i {
|
||||||
|
margin-right: 8px;
|
||||||
|
color: #409eff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-cards {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.small-card {
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-value {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #aaa;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics-item {
|
||||||
|
background: #0d0348;
|
||||||
|
border: 1px solid #064f8b;
|
||||||
|
padding: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
.title {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #99F2FF;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.today-data {
|
||||||
|
font-size: 36px;
|
||||||
|
color: #00FFFF;
|
||||||
|
font-weight: 700;
|
||||||
|
margin: 10px 0;
|
||||||
|
text-shadow: 0 0 8px rgba(0, 255, 255, 0.4);
|
||||||
|
}
|
||||||
|
.yesterday {
|
||||||
|
color: #B3FFFF;
|
||||||
|
font-size: 12px;
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
.rate {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.statistics-container{
|
||||||
|
//display: grid;
|
||||||
|
//grid-template-rows: auto 1fr auto;
|
||||||
|
//.ant-row{
|
||||||
|
// align-self: end;
|
||||||
|
//}
|
||||||
|
position: fixed;
|
||||||
|
bottom: 20px;
|
||||||
|
width: 49%;
|
||||||
|
}
|
||||||
|
</style>
|