|
@@ -6,7 +6,15 @@
|
|
|
</div>
|
|
</div>
|
|
|
<el-divider />
|
|
<el-divider />
|
|
|
<div style="flex-grow: 1; display: flex">
|
|
<div style="flex-grow: 1; display: flex">
|
|
|
- <v-chart class="chart" :option="option" />
|
|
|
|
|
|
|
+ <v-chart
|
|
|
|
|
+ ref="myChart"
|
|
|
|
|
+ class="chart"
|
|
|
|
|
+ :option="option"
|
|
|
|
|
+ @highlight="handleHighlight"
|
|
|
|
|
+ @downplay="handleDownPlay"
|
|
|
|
|
+ @click="handleClickChart"
|
|
|
|
|
+ @mouseover="handleMouseOver"
|
|
|
|
|
+ @mouseout="handleMouseOut" />
|
|
|
<el-divider direction="vertical" border-style="solid" />
|
|
<el-divider direction="vertical" border-style="solid" />
|
|
|
<div class="stat-show">
|
|
<div class="stat-show">
|
|
|
<ViolationStatItem :data="getVioStatData(0)" class="stat-data" />
|
|
<ViolationStatItem :data="getVioStatData(0)" class="stat-data" />
|
|
@@ -20,7 +28,7 @@
|
|
|
</template>
|
|
</template>
|
|
|
|
|
|
|
|
<script setup lang="ts">
|
|
<script setup lang="ts">
|
|
|
- import { computed, ref,onMounted } from 'vue';
|
|
|
|
|
|
|
+ import { computed, ref, onMounted } from 'vue';
|
|
|
import CensusTabs from './AlgoCensusTabs.vue';
|
|
import CensusTabs from './AlgoCensusTabs.vue';
|
|
|
import ViolationStatItem from './ViolationStatItem.vue';
|
|
import ViolationStatItem from './ViolationStatItem.vue';
|
|
|
import { TimeTabEnum, violationHandleCounts } from '../types';
|
|
import { TimeTabEnum, violationHandleCounts } from '../types';
|
|
@@ -49,26 +57,12 @@
|
|
|
};
|
|
};
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
- console.log(newData);
|
|
|
|
|
-
|
|
|
|
|
return newData;
|
|
return newData;
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
const algoLegendData = computed(() => {
|
|
const algoLegendData = computed(() => {
|
|
|
return algoData.value.map((item) => item.name);
|
|
return algoData.value.map((item) => item.name);
|
|
|
});
|
|
});
|
|
|
- // [
|
|
|
|
|
- // { value: 335, name: "人员闯入" },
|
|
|
|
|
- // { value: 310, name: "未穿反光背心" },
|
|
|
|
|
- // { value: 2, name: "明火烟雾" },
|
|
|
|
|
- // { value: 135, name: "机翼保护垫" },
|
|
|
|
|
- // { value: 148, name: "工装未归位" },
|
|
|
|
|
- // { value: 335, name: "人员闯入1" },
|
|
|
|
|
- // { value: 310, name: "未穿反光背心1" },
|
|
|
|
|
- // { value: 2, name: "明火烟雾1" },
|
|
|
|
|
- // { value: 135, name: "机翼保护垫1" },
|
|
|
|
|
- // { value: 148, name: "工装未归位1" },
|
|
|
|
|
- // ];
|
|
|
|
|
|
|
|
|
|
const statData = computed(() => props.data.statusCountList);
|
|
const statData = computed(() => props.data.statusCountList);
|
|
|
|
|
|
|
@@ -85,107 +79,114 @@
|
|
|
return { ...violationHandleCounts[index], count };
|
|
return { ...violationHandleCounts[index], count };
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
- // const option = computed(() => {
|
|
|
|
|
- // return {
|
|
|
|
|
- // tooltip: {
|
|
|
|
|
- // trigger: 'item',
|
|
|
|
|
- // formatter: '{a} <br/>{b} : {c} ({d}%)',
|
|
|
|
|
- // },
|
|
|
|
|
- // legend: {
|
|
|
|
|
- // orient: 'horizontial',
|
|
|
|
|
- // x: 'center',
|
|
|
|
|
- // y: 'bottom',
|
|
|
|
|
- // icon: 'circle',
|
|
|
|
|
- // width: '80%',
|
|
|
|
|
- // height: '28%',
|
|
|
|
|
- // type: 'scroll',
|
|
|
|
|
- // data: algoData.value.map((item) => item.name),
|
|
|
|
|
- // formatter: function (name) {
|
|
|
|
|
- // let total = 0;
|
|
|
|
|
- // let target;
|
|
|
|
|
- // for (let i = 0; i < algoData.value.length; i++) {
|
|
|
|
|
- // total += algoData.value[i].value;
|
|
|
|
|
- // if (algoData.value[i].name === name) {
|
|
|
|
|
- // target = algoData.value[i].value;
|
|
|
|
|
- // }
|
|
|
|
|
- // }
|
|
|
|
|
- // var arr = [
|
|
|
|
|
- // '{a|' + name + '}',
|
|
|
|
|
- // '{b|' + ' | ' + ((target / total) * 100).toFixed(0) + '%}\n',
|
|
|
|
|
- // ];
|
|
|
|
|
- // return arr.join(' ');
|
|
|
|
|
- // },
|
|
|
|
|
- // textStyle: {
|
|
|
|
|
- // padding: [8, 0, 0, 0],
|
|
|
|
|
- // fontSize: 14,
|
|
|
|
|
- // rich: {
|
|
|
|
|
- // a: {
|
|
|
|
|
- // fontSize: 15,
|
|
|
|
|
- // },
|
|
|
|
|
- // b: {
|
|
|
|
|
- // fontSize: 15,
|
|
|
|
|
- // color: '#c1c1c1',
|
|
|
|
|
- // },
|
|
|
|
|
- // },
|
|
|
|
|
- // },
|
|
|
|
|
- // },
|
|
|
|
|
- // series: [
|
|
|
|
|
- // {
|
|
|
|
|
- // name: '违规统计',
|
|
|
|
|
- // type: 'pie',
|
|
|
|
|
- // radius: ['40%', '65%'],
|
|
|
|
|
- // center: ['50%', '40%'],
|
|
|
|
|
- // labelLine: {
|
|
|
|
|
- // show: false,
|
|
|
|
|
- // },
|
|
|
|
|
|
|
+ // const titleLeft = ref('');
|
|
|
|
|
+ const myChart = ref();
|
|
|
|
|
+ let timer;
|
|
|
|
|
+ const index = ref(0);
|
|
|
|
|
+
|
|
|
|
|
+ onMounted(() => {
|
|
|
|
|
+ // const contentChart = document.querySelector('.echarts.chart') as HTMLDivElement;
|
|
|
|
|
+ // titleLeft.value = contentChart?.offsetWidth * 0.3 + 'px';
|
|
|
|
|
+ if (myChart.value) startAutoPlay();
|
|
|
|
|
+ });
|
|
|
|
|
|
|
|
- // label: {
|
|
|
|
|
- // show: false,
|
|
|
|
|
- // position: 'center',
|
|
|
|
|
- // },
|
|
|
|
|
- // data: algoData.value,
|
|
|
|
|
- // itemStyle: {
|
|
|
|
|
- // borderColor: '#fff',
|
|
|
|
|
- // borderWidth: 5,
|
|
|
|
|
- // },
|
|
|
|
|
- // emphasis: {
|
|
|
|
|
- // label: {
|
|
|
|
|
- // show: true,
|
|
|
|
|
- // fontSize: 20,
|
|
|
|
|
- // fontWeight: 'bold',
|
|
|
|
|
- // },
|
|
|
|
|
- // itemStyle: {
|
|
|
|
|
- // shadowBlur: 10,
|
|
|
|
|
- // shadowOffsetX: 0,
|
|
|
|
|
- // shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
|
|
|
- // },
|
|
|
|
|
- // },
|
|
|
|
|
- // },
|
|
|
|
|
- // ],
|
|
|
|
|
- // };
|
|
|
|
|
- // });
|
|
|
|
|
|
|
+ function startAutoPlay() {
|
|
|
|
|
+ stopAutoPlay();
|
|
|
|
|
+ timer = setInterval(function () {
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'highlight',
|
|
|
|
|
+ dataIndex: index.value,
|
|
|
|
|
+ });
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'downplay',
|
|
|
|
|
+ dataIndex: index.value === 0 ? algoData.value.length - 1 : index.value - 1,
|
|
|
|
|
+ });
|
|
|
|
|
+ index.value++;
|
|
|
|
|
|
|
|
|
|
+ if (index.value === algoData.value.length) {
|
|
|
|
|
+ index.value = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 2500);
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- const titleLeft=ref('')
|
|
|
|
|
- onMounted(()=>{
|
|
|
|
|
- const contentChart = document.querySelector('.chart') as HTMLDivElement;
|
|
|
|
|
- titleLeft.value = contentChart?.offsetWidth * 0.3 - 43 +'px'
|
|
|
|
|
|
|
+ function stopAutoPlay() {
|
|
|
|
|
+ clearInterval(timer);
|
|
|
|
|
+ let length = algoData.value.length;
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'downplay',
|
|
|
|
|
+ dataIndex: Array.from({ length }, (_, i) => i),
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- })
|
|
|
|
|
|
|
+ function pauseAutoPlay(argIndex) {
|
|
|
|
|
+ if (myChart.value) {
|
|
|
|
|
+ let length = algoData.value.length;
|
|
|
|
|
+ index.value = argIndex;
|
|
|
|
|
+ stopAutoPlay();
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'highlight',
|
|
|
|
|
+ dataIndex: index.value,
|
|
|
|
|
+ });
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'downplay',
|
|
|
|
|
+ dataIndex: Array.from({ length }, (_, i) => i).filter((item) => item !== index.value),
|
|
|
|
|
+ });
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ function continueAutoPlay(argIndex) {
|
|
|
|
|
+ if (myChart.value) {
|
|
|
|
|
+ let length = algoData.value.length;
|
|
|
|
|
+ myChart.value.dispatchAction({
|
|
|
|
|
+ type: 'downplay',
|
|
|
|
|
+ dataIndex: argIndex,
|
|
|
|
|
+ });
|
|
|
|
|
+ index.value = argIndex + 1 === length ? 0 : argIndex + 1;
|
|
|
|
|
+ startAutoPlay();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const handleHighlight = (event) => {
|
|
|
|
|
+ if ('name' in event) {
|
|
|
|
|
+ const tempIndex = algoData.value.findIndex((item) => item.name === event.name);
|
|
|
|
|
+ if (myChart.value) pauseAutoPlay(tempIndex);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleDownPlay = (event) => {
|
|
|
|
|
+ if ('name' in event) {
|
|
|
|
|
+ const tempIndex = algoData.value.findIndex((item) => item.name === event.name);
|
|
|
|
|
+ if (myChart.value) continueAutoPlay(tempIndex);
|
|
|
|
|
+ }
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleClickChart = (event) => {
|
|
|
|
|
+ const { dataIndex } = event;
|
|
|
|
|
+ if (myChart.value) pauseAutoPlay(dataIndex);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleMouseOver = (event) => {
|
|
|
|
|
+ const { dataIndex } = event;
|
|
|
|
|
+ if (myChart.value) pauseAutoPlay(dataIndex);
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ const handleMouseOut = (event) => {
|
|
|
|
|
+ const { dataIndex } = event;
|
|
|
|
|
+ if (myChart.value) continueAutoPlay(dataIndex);
|
|
|
|
|
+ };
|
|
|
|
|
|
|
|
const option = computed(() => {
|
|
const option = computed(() => {
|
|
|
return {
|
|
return {
|
|
|
title: {
|
|
title: {
|
|
|
- text: '算法占比', // 设置标题文本
|
|
|
|
|
- left: titleLeft.value, // 标题居中对齐
|
|
|
|
|
- top: 'center',
|
|
|
|
|
|
|
+ text: '问题占比', // 设置标题文本
|
|
|
|
|
+ // left: titleLeft.value, // 标题居中对齐
|
|
|
|
|
+ left: '32.5%',
|
|
|
|
|
+ top: '37%',
|
|
|
|
|
+ textAlign: 'center',
|
|
|
textStyle: {
|
|
textStyle: {
|
|
|
fontSize: 20,
|
|
fontSize: 20,
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
- // tooltip: {
|
|
|
|
|
- // trigger: 'item',
|
|
|
|
|
- // },
|
|
|
|
|
grid: {
|
|
grid: {
|
|
|
left: '10px',
|
|
left: '10px',
|
|
|
right: '4%',
|
|
right: '4%',
|
|
@@ -207,11 +208,20 @@
|
|
|
},
|
|
},
|
|
|
data: algoLegendData.value,
|
|
data: algoLegendData.value,
|
|
|
formatter: function (name) {
|
|
formatter: function (name) {
|
|
|
|
|
+ let maxNameLength = 0;
|
|
|
|
|
+ algoData.value.forEach((item) => {
|
|
|
|
|
+ if (item.name.length > maxNameLength) maxNameLength = item.name.length;
|
|
|
|
|
+ });
|
|
|
if (algoData.value && algoData.value.length) {
|
|
if (algoData.value && algoData.value.length) {
|
|
|
for (var i = 0; i < algoData.value.length; i++) {
|
|
for (var i = 0; i < algoData.value.length; i++) {
|
|
|
if (name === algoData.value[i].name) {
|
|
if (name === algoData.value[i].name) {
|
|
|
return (
|
|
return (
|
|
|
- '' + name + ' | ' + ' ' + (algoData.value[i].value * 100).toFixed(2) + '%'
|
|
|
|
|
|
|
+ '' +
|
|
|
|
|
+ name +
|
|
|
|
|
+ ' '.repeat(maxNameLength - name.length) +
|
|
|
|
|
+ ' ' +
|
|
|
|
|
+ (algoData.value[i].value * 100).toFixed(2) +
|
|
|
|
|
+ '%'
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -219,19 +229,29 @@
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
|
-
|
|
|
|
|
series: [
|
|
series: [
|
|
|
{
|
|
{
|
|
|
- // name: 'Access From',
|
|
|
|
|
- center: ['30%', '50%'],
|
|
|
|
|
type: 'pie',
|
|
type: 'pie',
|
|
|
- radius: ['50%', '70%'],
|
|
|
|
|
|
|
+ radius: ['44%', '55%'],
|
|
|
|
|
+ center: ['33%', '40%'],
|
|
|
avoidLabelOverlap: false,
|
|
avoidLabelOverlap: false,
|
|
|
label: {
|
|
label: {
|
|
|
show: false,
|
|
show: false,
|
|
|
- // position: 'center',
|
|
|
|
|
|
|
+ position: 'outside',
|
|
|
|
|
+ fontSize: 16,
|
|
|
|
|
+ color: '#000',
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLine: {
|
|
|
|
|
+ show: false,
|
|
|
|
|
+ },
|
|
|
|
|
+ labelLayout() {
|
|
|
|
|
+ return {
|
|
|
|
|
+ x: '33%',
|
|
|
|
|
+ y: '86%',
|
|
|
|
|
+ verticalAlign: 'bottom',
|
|
|
|
|
+ align: 'center',
|
|
|
|
|
+ };
|
|
|
},
|
|
},
|
|
|
-
|
|
|
|
|
emphasis: {
|
|
emphasis: {
|
|
|
label: {
|
|
label: {
|
|
|
show: true,
|
|
show: true,
|
|
@@ -240,14 +260,13 @@
|
|
|
formatter: '{b}: {d}%',
|
|
formatter: '{b}: {d}%',
|
|
|
},
|
|
},
|
|
|
itemStyle: {
|
|
itemStyle: {
|
|
|
|
|
+ borderColor: '#f3f3f3',
|
|
|
|
|
+ borderWidth: 3,
|
|
|
shadowBlur: 10,
|
|
shadowBlur: 10,
|
|
|
shadowOffsetX: 0,
|
|
shadowOffsetX: 0,
|
|
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
- labelLine: {
|
|
|
|
|
- show: false,
|
|
|
|
|
- },
|
|
|
|
|
data: algoData.value,
|
|
data: algoData.value,
|
|
|
},
|
|
},
|
|
|
],
|
|
],
|
|
@@ -259,6 +278,8 @@
|
|
|
const onCheckTab = (info: { tab: TimeTabEnum; data: string[] }) => {
|
|
const onCheckTab = (info: { tab: TimeTabEnum; data: string[] }) => {
|
|
|
timeTab.value = info.tab;
|
|
timeTab.value = info.tab;
|
|
|
props.getViolations(info.data);
|
|
props.getViolations(info.data);
|
|
|
|
|
+ index.value = 0;
|
|
|
|
|
+ startAutoPlay();
|
|
|
};
|
|
};
|
|
|
</script>
|
|
</script>
|
|
|
|
|
|