454 lines
13 KiB
Vue
454 lines
13 KiB
Vue
<template>
|
|
<div class="work-box-2">
|
|
<div class="box-1">
|
|
<div>
|
|
<Title1 title="今日工单" />
|
|
</div>
|
|
<div class="hd-list">
|
|
<img class="h-icon" src="@/assets/images/work-icon-1.png" />
|
|
<div class="item item1">
|
|
今日工单总条数 <span class="color1"><countup :end-val="totalData.total" /></span>
|
|
</div>
|
|
<div class="item item1">
|
|
工单完成数 <span class="color1"><countup :end-val="totalData.complete" /></span>
|
|
</div>
|
|
<div class="item item3">
|
|
紧急工单数 <span class=""><countup :end-val="totalData.warn" /></span>
|
|
</div>
|
|
<div class="item item2">
|
|
重要工单数 <span class=""><countup :end-val="totalData.important" /></span>
|
|
</div>
|
|
<div class="item item1">
|
|
普通工单数 <span class=""><countup :end-val="totalData.normal" /></span>
|
|
</div>
|
|
</div>
|
|
<div class="chart">
|
|
<div class="chart__wrapper mr-8">
|
|
<Title3 title="工单总数" />
|
|
<!-- <div class="check-label">
|
|
<span class="active">全部</span>
|
|
<span>已完成总数</span>
|
|
</div> -->
|
|
<Line :width="680" :height="320" :data="seriesData" :xAxisData="xAxisData" />
|
|
</div>
|
|
<div class="chart__wrapper">
|
|
<Title3 title="工单类型完成比例" />
|
|
<div class="progress">
|
|
<div class="progress-item">
|
|
<span class="progress-item__label">普通</span>
|
|
<div class="progress-item__inner">
|
|
<el-progress
|
|
:percentage="completeRateData.normal * 100"
|
|
:stroke-width="fitChartSize(24)"
|
|
stroke-linecap="square"
|
|
color="#2380FB"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="progress-item">
|
|
<span class="progress-item__label">紧急</span>
|
|
<div class="progress-item__inner">
|
|
<el-progress
|
|
:percentage="completeRateData.warn * 100"
|
|
:stroke-width="fitChartSize(24)"
|
|
stroke-linecap="square"
|
|
color="#D9011B"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div class="progress-item">
|
|
<span class="progress-item__label">重要</span>
|
|
<div class="progress-item__inner">
|
|
<el-progress
|
|
:percentage="completeRateData.important * 100"
|
|
:stroke-width="fitChartSize(24)"
|
|
stroke-linecap="square"
|
|
color="#FEAE00"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="box-2 mt-8">
|
|
<Title1 title="不同景区工单占比" />
|
|
<div class="chart">
|
|
<div class="chart__wrapper">
|
|
<Title3 title="景区工单占比" />
|
|
<div class="chart__inner">
|
|
<spotRate :dataList="spotRateData" :total="8888" />
|
|
<ul class="chart__legend">
|
|
<li class="chart__legend-item" v-for="(item, index) in spotRateData" :key="index">
|
|
<p class="dot" :style="{ background: colors[index] }" />
|
|
<p class="name">{{ item.name }}</p>
|
|
<p class="value">{{ item.value }}%</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
<div class="chart__wrapper">
|
|
<Title3 title="景区工单类型占比" />
|
|
<div class="chart__inner">
|
|
<spotRate :dataList="typeRateData" :total="8888" />
|
|
<ul class="chart__legend">
|
|
<li class="chart__legend-item" v-for="(item, index) in typeRateData" :key="index">
|
|
<p class="dot" :style="{ background: colors[index] }" />
|
|
<p class="name">{{ item.name }}</p>
|
|
<p class="value">{{ item.value }}%</p>
|
|
</li>
|
|
</ul>
|
|
<div v-if="pointRankData.length > 0" class="alarm">
|
|
<Title2 title="异常点位告警排名" />
|
|
<ul class="alarm__wrapper">
|
|
<li class="alarm-item" v-for="(item, index) in pointRankData" :key="index">
|
|
<p
|
|
class="alarm-item__rank"
|
|
:class="{
|
|
'alarm-item__rank--error': index == 0,
|
|
'alarm-item__rank--warning': index == 1,
|
|
'alarm-item__rank--primary': index == 2
|
|
}"
|
|
>
|
|
{{ index + 1 }}
|
|
</p>
|
|
<p class="alarm-item__content">{{ item.link_title }}</p>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import countup from 'vue-countup-v3'
|
|
import spotRate from './spotRate.vue'
|
|
import { fitChartSize } from '@/utils/dataUtil'
|
|
import {
|
|
getTotalApi,
|
|
getLineChartApi,
|
|
getCompleteRateApi,
|
|
getSpotRateApi,
|
|
getTypeRateApi
|
|
} from '@/api/workOrder'
|
|
import { getNewsPointRankApi } from '@/api/news'
|
|
|
|
const colors = ['#FDC40A', '#FF5232', '#50F0A6', '#5FDFFA']
|
|
let totalData = ref({
|
|
total: 0,
|
|
complete: 0,
|
|
urgent: 0,
|
|
important: 0,
|
|
normal: 0
|
|
})
|
|
let completeRateData = ref({ important: 0, normal: 0, warn: 0 })
|
|
let seriesData = ref([])
|
|
let xAxisData = ref([])
|
|
let typeRateData = ref([])
|
|
let spotRateData = ref([])
|
|
let pointRankData = ref([])
|
|
|
|
const getNewsPointRank = async () => {
|
|
let res = await getNewsPointRankApi()
|
|
pointRankData.value = res.data
|
|
}
|
|
const getTypeRate = async () => {
|
|
let res = await getTypeRateApi()
|
|
typeRateData.value = res.data.data
|
|
}
|
|
const getSpotRate = async () => {
|
|
let res = await getSpotRateApi()
|
|
spotRateData.value = res.data.data
|
|
}
|
|
const getCompleteRate = async () => {
|
|
let res = await getCompleteRateApi()
|
|
completeRateData.value = res.data
|
|
}
|
|
const getLineChart = async () => {
|
|
let res = await getLineChartApi()
|
|
seriesData.value = res.data.series
|
|
xAxisData.value = res.data.data
|
|
}
|
|
const getTotal = async () => {
|
|
let res = await getTotalApi()
|
|
totalData.value = res.data
|
|
}
|
|
onMounted(() => {
|
|
getTotal()
|
|
getLineChart()
|
|
getCompleteRate()
|
|
getTypeRate()
|
|
getSpotRate()
|
|
getNewsPointRank()
|
|
})
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
:deep(.el-progress-bar__outer) {
|
|
background: rgba(0, 150, 255, 0.15);
|
|
border-radius: 0;
|
|
}
|
|
:deep(.el-progress-bar__inner) {
|
|
border-radius: 0;
|
|
}
|
|
:deep(.el-progress__text) {
|
|
font-size: vw(14) !important;
|
|
color: #fff;
|
|
}
|
|
|
|
.chart-p {
|
|
position: relative;
|
|
.check-label {
|
|
position: absolute;
|
|
right: vw(20);
|
|
top: vh(-15);
|
|
span {
|
|
min-width: vw(55);
|
|
padding: vw(5);
|
|
background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%);
|
|
border-radius: vw(50);
|
|
margin-left: vw(5);
|
|
display: inline-block;
|
|
font-weight: 400;
|
|
font-size: vw(13);
|
|
color: #0084ff;
|
|
text-align: center;
|
|
font-style: normal;
|
|
text-transform: none;
|
|
}
|
|
.active {
|
|
background: linear-gradient(270deg, #37d8fc 0%, #0084ff 100%);
|
|
border-radius: vw(50);
|
|
border: 1px solid rgba(0, 114, 220, 0.3);
|
|
color: #fff;
|
|
}
|
|
}
|
|
}
|
|
.work-box-2 {
|
|
margin-top: vh(120);
|
|
margin-left: vw(8);
|
|
|
|
.box-1 {
|
|
padding: vw(1) 0;
|
|
box-sizing: border-box;
|
|
background: linear-gradient(to bottom, #0b2f64 0%, #062b57 100%);
|
|
.chart {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: vw(20) vw(15);
|
|
|
|
&__wrapper {
|
|
width: vw(740);
|
|
height: vh(370);
|
|
padding: 0 vw(20);
|
|
background-image: url('@/assets/images/bg-3.png');
|
|
background-size: 100% 100%;
|
|
.progress {
|
|
padding: vw(30);
|
|
padding-top: vh(40);
|
|
&-item {
|
|
display: flex;
|
|
width: 100%;
|
|
margin-top: vh(40);
|
|
align-items: center;
|
|
}
|
|
&-item__label {
|
|
font-weight: bold;
|
|
font-size: vw(14);
|
|
color: #ffffff;
|
|
text-align: left;
|
|
font-style: normal;
|
|
text-transform: none;
|
|
margin-right: vw(10);
|
|
}
|
|
&-item__inner {
|
|
flex: 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.hd-list {
|
|
display: flex;
|
|
justify-content: center;
|
|
position: relative;
|
|
.h-icon {
|
|
position: absolute;
|
|
left: vw(70);
|
|
top: 50%;
|
|
transform: translateY(-50%);
|
|
width: vw(74);
|
|
height: auto;
|
|
}
|
|
.item {
|
|
display: flex;
|
|
width: vw(210);
|
|
height: vh(58);
|
|
line-height: vh(58);
|
|
padding-left: vw(10);
|
|
text-align: center;
|
|
margin: 0 vw(15);
|
|
font-weight: 400;
|
|
font-size: vw(14);
|
|
color: rgba(255, 255, 255, 0.9);
|
|
text-align: left;
|
|
font-style: normal;
|
|
text-transform: none;
|
|
span {
|
|
font-size: vw(24);
|
|
position: relative;
|
|
top: vh(2);
|
|
margin-left: vw(5);
|
|
}
|
|
.color1 {
|
|
color: #02f9fa;
|
|
}
|
|
}
|
|
.item1 {
|
|
background-image: url('@/assets/images/work-n-bg-1.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
.item2 {
|
|
background-image: url('@/assets/images/work-n-bg-2.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
.item3 {
|
|
background-image: url('@/assets/images/work-n-bg-3.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
}
|
|
}
|
|
.box-2 {
|
|
padding: vw(1);
|
|
height: vh(442);
|
|
box-sizing: border-box;
|
|
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
|
|
|
|
.chart {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: vw(20) vw(15);
|
|
|
|
&__wrapper {
|
|
width: vw(740);
|
|
height: vh(370);
|
|
padding: 0 vw(20);
|
|
background-image: url('@/assets/images/bg-3.png');
|
|
background-size: 100% 100%;
|
|
}
|
|
|
|
&__inner {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
&__legend {
|
|
flex: 1;
|
|
|
|
&-item {
|
|
position: relative;
|
|
width: 100%;
|
|
height: vh(40);
|
|
display: flex;
|
|
align-items: center;
|
|
margin-bottom: vh(8);
|
|
background: linear-gradient(
|
|
90deg,
|
|
rgba(0, 150, 255, 0.34) 0%,
|
|
rgba(0, 150, 255, 0) 100%
|
|
);
|
|
|
|
&::before {
|
|
position: absolute;
|
|
content: '';
|
|
width: vw(4);
|
|
height: vh(40);
|
|
background-color: #0096ff;
|
|
}
|
|
|
|
.dot {
|
|
width: vw(4);
|
|
height: vw(4);
|
|
margin: 0 vw(16);
|
|
}
|
|
|
|
.name {
|
|
font-weight: 400;
|
|
font-size: vw(12);
|
|
color: #ffffff;
|
|
width: vw(130);
|
|
}
|
|
|
|
.value {
|
|
font-weight: bold;
|
|
font-size: vw(15);
|
|
color: #ffffff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
.alarm {
|
|
background: #0a4190;
|
|
|
|
&__wrapper {
|
|
flex: 1;
|
|
height: vh(270);
|
|
background: #054581; /* 滚动条整体样式 */
|
|
&::-webkit-scrollbar {
|
|
width: vw(4); /* 滚动条的宽度 */
|
|
}
|
|
/* 滚动条轨道 */
|
|
&::-webkit-scrollbar-track {
|
|
background: 'transparent'; /* 轨道的背景色 */
|
|
}
|
|
/* 滚动条滑块 */
|
|
&::-webkit-scrollbar-thumb {
|
|
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
|
|
border-radius: 5px; /* 滑块的圆角 */
|
|
}
|
|
overflow: auto;
|
|
}
|
|
|
|
&-item {
|
|
padding: 0 vw(12);
|
|
&:nth-child(2n) {
|
|
background: #054d8d;
|
|
}
|
|
height: vh(40);
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
&-item__rank {
|
|
width: vw(24);
|
|
height: vh(16);
|
|
font-size: vw(12);
|
|
color: #ffffff;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
background: #495c77;
|
|
}
|
|
&-item__rank--error {
|
|
background-color: #d9011b;
|
|
}
|
|
&-item__rank--warning {
|
|
background-color: #feae00;
|
|
}
|
|
&-item__rank--primary {
|
|
background-color: #2380fb;
|
|
}
|
|
&-item__content {
|
|
padding-left: vw(20);
|
|
font-weight: 400;
|
|
font-size: vw(14);
|
|
color: #ffffff;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</style>
|