Bladeren bron

feat: 运行数据图表

lixiangrui 4 weken geleden
bovenliggende
commit
24e164b411

+ 1 - 0
src/hooks/useEcharts.js

@@ -26,6 +26,7 @@ export function useECharts(
26 26
     chartInstance.value = markRaw(echarts.init(containerRef.value, theme))
27 27
     
28 28
     chartInstance.value.setOption(options.value);
29
+    
29 30
     eventQueue = eventQueue.filter((handler) => {
30 31
       handler()
31 32
       return false

+ 110 - 0
src/views/portraitManagement/components/ChannelCheckChart.vue

@@ -0,0 +1,110 @@
1
+<template>
2
+  <Card title="每日通道过检率">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const hours = Array.from({length: 24}, (_, i) => `${i.toString().padStart(2, '0')}:00`)
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 60,
25
+      right: 60
26
+    },
27
+    xAxis: {
28
+      type: 'category',
29
+      data: hours,
30
+      axisLabel: { color: '#fff', fontSize: 14 },
31
+      axisLine: { lineStyle: { color: '#344067' } }
32
+    },
33
+    yAxis: [
34
+      {
35
+        type: 'value',
36
+        name: '过检率(%)',
37
+        position: 'left',
38
+        max: 100,
39
+        axisLabel: { color: '#fff', fontSize: 14 },
40
+        axisLine: {  lineStyle: { color: '#fff' } },
41
+        splitLine: { lineStyle: { color: '#344067' } }
42
+      },
43
+      {
44
+        type: 'value',
45
+        name: '数量',
46
+        position: 'right',
47
+        max: Math.max(...props.chartsData.map(item => item.num)) + 100,
48
+        axisLabel: { color: '#fff', fontSize: 14 },
49
+        axisLine: {  lineStyle: { color: '#fff' } },
50
+        splitLine: { show: false }
51
+      }
52
+    ],
53
+    series: [
54
+      {
55
+        name: '过检人数',
56
+        type: 'bar',
57
+        yAxisIndex: 1,
58
+        data: props.chartsData.map(item => item.num),
59
+        itemStyle: {
60
+          color: '#6DA6FE',
61
+          borderRadius: [2, 2, 0, 0],
62
+        },
63
+        barWidth: '20%'
64
+      },
65
+      {
66
+        name: '过检人数1',
67
+        type: 'bar',
68
+        yAxisIndex: 1,
69
+        data: props.chartsData.map(item => item.num1),
70
+        itemStyle: {
71
+          color: '#9963FB',
72
+          borderRadius: [2, 2, 0, 0],
73
+        },
74
+        barWidth: '20%'
75
+      },
76
+      {
77
+        name: '过检人数2',
78
+        type: 'bar',
79
+        yAxisIndex: 1,
80
+        data: props.chartsData.map(item => item.num2),
81
+        itemStyle: {
82
+          color: '#FCE661',
83
+          borderRadius: [2, 2, 0, 0],
84
+        },
85
+        barWidth: '20%'
86
+      },
87
+      {
88
+        name: '过检率',
89
+        type: 'line',
90
+        yAxisIndex: 0,
91
+        data: props.chartsData.map(item => item.rate),
92
+        smooth: true,
93
+        itemStyle: { color: '#F801FA' },
94
+        lineStyle: { color: '#F801FA' }
95
+      }
96
+    ],
97
+    tooltip: {
98
+      trigger: 'axis',
99
+      backgroundColor: 'rgba(13,80,122,1)',
100
+      borderColor: '#70CFE7',
101
+      textStyle: { color: '#fff' }
102
+    }
103
+  }
104
+})
105
+
106
+useECharts(bar, setChartsOptionsBar);
107
+
108
+</script>
109
+
110
+<style lang="scss" scoped></style>

+ 58 - 0
src/views/portraitManagement/components/EventItems.vue

@@ -0,0 +1,58 @@
1
+<template>
2
+  <Card title="不安全事件物品分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 200,
25
+      right: 0
26
+    },
27
+    tooltip: {
28
+      trigger: 'item',
29
+      backgroundColor: 'rgba(13,80,122,1)',
30
+      borderColor: '#70CFE7',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    legend: {
34
+      top: 'center',
35
+      left: '0%',
36
+      orient: 'vertical',
37
+      textStyle: { color: '#fff' }
38
+    },
39
+    series: [{
40
+      type: 'pie',
41
+      radius: ['40%', '60%'],
42
+      data: props.chartsData.map(item => {
43
+        return {
44
+          value: item.num,
45
+          name: item.name
46
+        }
47
+      }),
48
+      label: { show: true, color: '#fff', fontSize: 16, lineHeight: 20, formatter: '{b}\n{c}'  },
49
+      labelLine: { show: true }
50
+    }],
51
+  }
52
+})
53
+
54
+useECharts(bar, setChartsOptionsBar);
55
+
56
+</script>
57
+
58
+<style lang="scss" scoped></style>

+ 58 - 0
src/views/portraitManagement/components/EventType.vue

@@ -0,0 +1,58 @@
1
+<template>
2
+  <Card title="不安全事件类型分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 200,
25
+      right: 0
26
+    },
27
+    tooltip: {
28
+      trigger: 'item',
29
+      backgroundColor: 'rgba(13,80,122,1)',
30
+      borderColor: '#70CFE7',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    legend: {
34
+      top: 'center',
35
+      left: '0%',
36
+      orient: 'vertical',
37
+      textStyle: { color: '#fff' }
38
+    },
39
+    series: [{
40
+      type: 'pie',
41
+      radius: ['40%', '60%'],
42
+      data: props.chartsData.map(item => {
43
+        return {
44
+          value: item.num,
45
+          name: item.name
46
+        }
47
+      }),
48
+      label: { show: true, color: '#fff', fontSize: 16, lineHeight: 20, formatter: '{b}\n{c}'  },
49
+      labelLine: { show: true }
50
+    }],
51
+  }
52
+})
53
+
54
+useECharts(bar, setChartsOptionsBar);
55
+
56
+</script>
57
+
58
+<style lang="scss" scoped></style>

+ 80 - 0
src/views/portraitManagement/components/EventWorkArea.vue

@@ -0,0 +1,80 @@
1
+<template>
2
+  <Card title="不安全事件查获岗位分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const labels = props.chartsData.map(item => item.name)
20
+  return {
21
+    grid: {
22
+      top: 50,
23
+      bottom: 40,
24
+      left: 60,
25
+      right: 20
26
+    },
27
+    legend: {
28
+      top: '10',
29
+      left: '30',
30
+      // orient: 'vertical',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    xAxis: {
34
+      type: 'category',
35
+      data: labels,
36
+      axisLabel: { color: '#fff', fontSize: 14 },
37
+      axisLine: { lineStyle: { color: '#344067' } }
38
+    },
39
+    yAxis: [
40
+      {
41
+        type: 'value',
42
+        position: 'left',
43
+        axisLabel: { color: '#fff', fontSize: 14 },
44
+        axisLine: {  lineStyle: { color: '#fff' } },
45
+        splitLine: { lineStyle: { color: '#344067' } }
46
+      },
47
+    ],
48
+    series: [
49
+      {
50
+        name: '查获数量',
51
+        type: 'bar',
52
+        data: props.chartsData.map(item => item.num),
53
+        itemStyle: {
54
+          borderRadius: [5, 5, 0, 0],
55
+          color: '#6DA6FE',
56
+        },
57
+        label: {
58
+          show: true,
59
+          position: 'top',
60
+          color: '#6DA6FE',
61
+          fontSize: 14,
62
+          fontWeight: 500
63
+        },
64
+        barWidth: '40%'
65
+      },
66
+    ],
67
+    tooltip: {
68
+      trigger: 'axis',
69
+      backgroundColor: 'rgba(13,80,122,1)',
70
+      borderColor: '#70CFE7',
71
+      textStyle: { color: '#fff' }
72
+    }
73
+  }
74
+})
75
+
76
+useECharts(bar, setChartsOptionsBar);
77
+
78
+</script>
79
+
80
+<style lang="scss" scoped></style>

+ 75 - 0
src/views/portraitManagement/components/InterceptionDistribution.vue

@@ -0,0 +1,75 @@
1
+<template>
2
+  <Card title="实时质控拦截物品分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const countryColors = ['#6DA6FE', '#9963FB', '#FCE661', '#F801FA', '#95E530', '#22C2CC', '#F76723']
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 10,
23
+      bottom: 30,
24
+      left: 80,
25
+      right: 40
26
+    },
27
+    xAxis: {
28
+      max: 'dataMax',
29
+      axisLabel: { color: '#fff', fontSize: 14 },
30
+    },
31
+    dataset: {
32
+      source: props.chartsData.map(item => {
33
+        return [item.name, item.num ]
34
+      })
35
+    },
36
+    yAxis: {
37
+      type: 'category',
38
+      position: 'left',
39
+      axisLabel: { color: '#fff', fontSize: 14 },
40
+      splitLine: { lineStyle: { color: '#344067' } }
41
+    },
42
+    series: [
43
+      {
44
+        realtimeSort: true,
45
+        seriesLayoutBy: 'column',
46
+        type: 'bar',
47
+        itemStyle: {
48
+          borderRadius: [0, 5, 5, 0],
49
+          color: function (param) {
50
+            return countryColors[param.dataIndex % countryColors.length]
51
+          }
52
+        },
53
+        label: {
54
+          show: true,
55
+          position: 'right',
56
+          color: '#FFF',
57
+          fontSize: 14,
58
+          fontWeight: 500
59
+        },
60
+      }
61
+    ],
62
+    tooltip: {
63
+      trigger: 'axis',
64
+      backgroundColor: 'rgba(13,80,122,1)',
65
+      borderColor: '#70CFE7',
66
+      textStyle: { color: '#fff' }
67
+    }
68
+  }
69
+})
70
+
71
+useECharts(bar, setChartsOptionsBar);
72
+
73
+</script>
74
+
75
+<style lang="scss" scoped></style>

+ 175 - 0
src/views/portraitManagement/components/SeizedInfo.vue

@@ -0,0 +1,175 @@
1
+<template>
2
+  <Card title="查获信息展示">
3
+    <div class="content">
4
+      <div class="svgIcon">
5
+        <Svg></Svg>
6
+        <div class="svgContent">
7
+          <div class="value">1658</div>
8
+          <div class="tips">
9
+            <span>查获总数</span>
10
+            <span>(所有人员)</span>
11
+          </div>
12
+        </div>
13
+      </div>
14
+      <div class="charts">
15
+        <div ref="bar" style="width: 100%; height: 100%;"></div>
16
+      </div>
17
+    </div>
18
+  </Card>
19
+</template>
20
+
21
+<script setup>
22
+import { computed } from 'vue';
23
+import Card from './card.vue';
24
+import { useECharts } from '@/hooks/useEcharts.js';
25
+import Svg from './Svg.vue';
26
+const bar = ref(null)
27
+const props = defineProps({
28
+  chartsData: {
29
+    type: Object,
30
+    default: () => ([])
31
+  }
32
+})
33
+
34
+const colors = [
35
+  {
36
+    type: 'linear',
37
+    x: 0,
38
+    y: 0,
39
+    x2: 0,
40
+    y2: 1,
41
+    colorStops: [{
42
+      offset: 0, color: '#A674FC'
43
+    }, {
44
+      offset: 1, color: '#2C2B53'
45
+    }],
46
+    global: false
47
+  },
48
+  {
49
+    type: 'linear',
50
+    x: 0,
51
+    y: 0,
52
+    x2: 0,
53
+    y2: 1,
54
+    colorStops: [{
55
+      offset: 0, color: '#71A3FC'
56
+    }, {
57
+      offset: 1, color: '#1E2144'
58
+    }],
59
+    global: false
60
+  },
61
+  {
62
+    type: 'linear',
63
+    x: 0,
64
+    y: 0,
65
+    x2: 0,
66
+    y2: 1,
67
+    colorStops: [{
68
+      offset: 0, color: '#F462CC'
69
+    }, {
70
+      offset: 1, color: '#2C244B'
71
+    }],
72
+    global: false
73
+  },
74
+]
75
+
76
+const setChartsOptionsBar = computed(() => {
77
+  const hours = ['等级1', '等级2', '等级3']
78
+  return {
79
+    grid: {
80
+      top: 30,
81
+      bottom: 40,
82
+      left: 60,
83
+      right: 30
84
+    },
85
+    xAxis: {
86
+      type: 'category',
87
+      data: hours,
88
+      axisLabel: { color: '#fff', fontSize: 14 },
89
+      axisLine: { lineStyle: { color: '#344067' } }
90
+    },
91
+    yAxis: [
92
+      {
93
+        type: 'value',
94
+        position: 'left',
95
+        max: Math.max(...props.chartsData.map(item => item.num)) + 100,
96
+        axisLabel: { color: '#fff', fontSize: 14 },
97
+        axisLine: {  lineStyle: { color: '#fff' } },
98
+        splitLine: { show: false }
99
+      }
100
+    ],
101
+    series: [
102
+      {
103
+        name: '人数',
104
+        type: 'bar',
105
+        data: props.chartsData.map(item => item.num),
106
+        itemStyle: {
107
+          color: (params) => {
108
+            return colors[params.dataIndex % colors.length]
109
+          },
110
+          borderRadius: [5, 5, 0, 0],
111
+        },
112
+        barWidth: '40px'
113
+      },
114
+    ],
115
+    tooltip: {
116
+      trigger: 'axis',
117
+      backgroundColor: 'rgba(13,80,122,1)',
118
+      borderColor: '#70CFE7',
119
+      textStyle: { color: '#fff' }
120
+    }
121
+  }
122
+})
123
+
124
+useECharts(bar, setChartsOptionsBar);
125
+</script>
126
+
127
+<style lang="scss" scoped>
128
+.content {
129
+  display: flex;
130
+  width: 100%;
131
+  height: 100%;
132
+  column-gap: 30px;
133
+  .svgIcon {
134
+    width: 280px;
135
+    box-sizing: border-box;
136
+    padding: 20px;
137
+    position: relative;
138
+    .svgContent {
139
+      position: absolute;
140
+      width: 175px;
141
+      height: 175px;
142
+      inset: 0;
143
+      margin: auto;
144
+      border-radius: 50%;
145
+      display: flex;
146
+      flex-direction: column;
147
+      align-items: center;
148
+      justify-content: center;
149
+      background: radial-gradient(
150
+        circle at center,
151
+        transparent 0%,
152
+        transparent 50%,
153
+        #a19dd2 100%
154
+      );
155
+      color: #fff;
156
+      .value {
157
+        font-size: 48px;
158
+        font-weight: 500;
159
+        text-shadow: 2px 2px 1px #BBA7E2;
160
+        color: #fff;
161
+      }
162
+      .tips {
163
+        display: flex;
164
+        flex-direction: column;
165
+        font-size: 14px;
166
+        font-weight: 500;
167
+        color: #BBA7E2;
168
+      }
169
+    }
170
+  }
171
+  .charts {
172
+    flex: 1;
173
+  }
174
+}
175
+</style>

+ 58 - 0
src/views/portraitManagement/components/SeizedItems.vue

@@ -0,0 +1,58 @@
1
+<template>
2
+  <Card title="查获物品分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 60,
25
+      right: 20
26
+    },
27
+    tooltip: {
28
+      trigger: 'item',
29
+      backgroundColor: 'rgba(13,80,122,1)',
30
+      borderColor: '#70CFE7',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    legend: {
34
+      top: 'center',
35
+      left: '0%',
36
+      orient: 'vertical',
37
+      textStyle: { color: '#fff' }
38
+    },
39
+    series: [{
40
+      type: 'pie',
41
+      radius: ['40%', '70%'],
42
+      data: props.chartsData.map(item => {
43
+        return {
44
+          value: item.num,
45
+          name: item.name
46
+        }
47
+      }),
48
+      label: { show: true, color: '#fff', fontSize: 16, lineHeight: 20, formatter: '{b}\n{c}'  },
49
+      labelLine: { show: true }
50
+    }],
51
+  }
52
+})
53
+
54
+useECharts(bar, setChartsOptionsBar);
55
+
56
+</script>
57
+
58
+<style lang="scss" scoped></style>

+ 119 - 0
src/views/portraitManagement/components/SeizedNum.vue

@@ -0,0 +1,119 @@
1
+<template>
2
+  <Card title="每日查获数量(个人对比)">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  return {
20
+    grid: {
21
+      top: 40,
22
+      bottom: 30,
23
+      left: 60,
24
+      right: 20
25
+    },
26
+    xAxis: {
27
+      type: 'category',
28
+      axisLabel: { show: false },
29
+      axisLine: { show: false },
30
+      boundaryGap: false
31
+    },
32
+    yAxis: [
33
+      {
34
+        type: 'value',
35
+        position: 'left',
36
+        axisLabel: { color: '#fff', fontSize: 14 },
37
+        axisLine: {  lineStyle: { color: '#fff' } },
38
+        splitLine: { lineStyle: { color: '#344067' } }
39
+      },
40
+    ],
41
+    series: [
42
+      {
43
+        name: '数量1',
44
+        type: 'line',
45
+        data: props.chartsData.map(item => item.num),
46
+        smooth: true,
47
+        itemStyle: { color: '#71B138' },
48
+        lineStyle: { color: '#71B138' },
49
+        areaStyle: { color: {
50
+          type: 'linear',
51
+          x: 0,
52
+          y: 0,
53
+          x2: 0,
54
+          y2: 1,
55
+          colorStops: [{
56
+            offset: 0, color: '#71B138'
57
+          }, {
58
+            offset: 1, color: '#71B13800'
59
+          }],
60
+          global: false
61
+        }}
62
+      },
63
+      {
64
+        name: '数量2',
65
+        type: 'line',
66
+        data: props.chartsData.map(item => item.num1),
67
+        smooth: true,
68
+        itemStyle: { color: '#F801FA' },
69
+        lineStyle: { color: '#F801FA' },
70
+        areaStyle: { color: {
71
+          type: 'linear',
72
+          x: 0,
73
+          y: 0,
74
+          x2: 0,
75
+          y2: 1,
76
+          colorStops: [{
77
+            offset: 0, color: '#F801FA'
78
+          }, {
79
+            offset: 1, color: '#F801FA00'
80
+          }],
81
+          global: false
82
+        }}
83
+      },
84
+      {
85
+        name: '数量3',
86
+        type: 'line',
87
+        data: props.chartsData.map(item => item.num2),
88
+        smooth: true,
89
+        itemStyle: { color: '#6DA6FE' },
90
+        lineStyle: { color: '#6DA6FE' },
91
+        areaStyle: { color: {
92
+          type: 'linear',
93
+          x: 0,
94
+          y: 0,
95
+          x2: 0,
96
+          y2: 1,
97
+          colorStops: [{
98
+            offset: 0, color: '#6DA6FE'
99
+          }, {
100
+            offset: 1, color: '#6DA6FE00'
101
+          }],
102
+          global: false
103
+        }}
104
+      }
105
+    ],
106
+    tooltip: {
107
+      trigger: 'axis',
108
+      backgroundColor: 'rgba(13,80,122,1)',
109
+      borderColor: '#70CFE7',
110
+      textStyle: { color: '#fff' }
111
+    }
112
+  }
113
+})
114
+
115
+useECharts(bar, setChartsOptionsBar);
116
+
117
+</script>
118
+
119
+<style lang="scss" scoped></style>

+ 65 - 0
src/views/portraitManagement/components/SeizedNumAll.vue

@@ -0,0 +1,65 @@
1
+<template>
2
+  <Card title="每日查获数量(总表)">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const hours = Array.from({length: 24}, (_, i) => `${i.toString().padStart(2, '0')}:00`)
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 30,
24
+      left: 60,
25
+      right: 30
26
+    },
27
+    xAxis: {
28
+      type: 'category',
29
+      axisLabel: { show: false },
30
+      axisLine: { show: false },
31
+      boundaryGap: false
32
+    },
33
+    yAxis: [
34
+      {
35
+        type: 'value',
36
+        position: 'left',
37
+        axisLabel: { color: '#fff', fontSize: 14 },
38
+        axisLine: {  lineStyle: { color: '#fff' } },
39
+        splitLine: { lineStyle: { color: '#344067' } }
40
+      }
41
+    ],
42
+    series: [
43
+      {
44
+        name: '查获数',
45
+        type: 'line',
46
+        data: props.chartsData.map(item => item.num),
47
+        smooth: true,
48
+        itemStyle: { color: '#71B138' },
49
+        lineStyle: { color: '#71B138' }
50
+      }
51
+    ],
52
+    tooltip: {
53
+      trigger: 'axis',
54
+      backgroundColor: 'rgba(13,80,122,1)',
55
+      borderColor: '#70CFE7',
56
+      textStyle: { color: '#fff' }
57
+    }
58
+  }
59
+})
60
+
61
+useECharts(bar, setChartsOptionsBar);
62
+
63
+</script>
64
+
65
+<style lang="scss" scoped></style>

+ 73 - 0
src/views/portraitManagement/components/SeizedWorkArea.vue

@@ -0,0 +1,73 @@
1
+<template>
2
+  <Card title="查获工作区域分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const labels = props.chartsData.map(item => item.name)
20
+  return {
21
+    grid: {
22
+      top: 50,
23
+      bottom: 40,
24
+      left: 60,
25
+      right: 20
26
+    },
27
+    legend: {
28
+      top: '10',
29
+      left: '30',
30
+      // orient: 'vertical',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    xAxis: {
34
+      type: 'category',
35
+      data: labels,
36
+      axisLabel: { color: '#fff', fontSize: 14 },
37
+      axisLine: { lineStyle: { color: '#344067' } }
38
+    },
39
+    yAxis: [
40
+      {
41
+        type: 'value',
42
+        position: 'left',
43
+        axisLabel: { color: '#fff', fontSize: 14 },
44
+        axisLine: {  lineStyle: { color: '#fff' } },
45
+        splitLine: { lineStyle: { color: '#344067' } }
46
+      },
47
+    ],
48
+    series: [
49
+      {
50
+        name: '查获数量',
51
+        type: 'bar',
52
+        data: props.chartsData.map(item => item.num),
53
+        itemStyle: {
54
+          borderRadius: [5, 5, 0, 0],
55
+          color: '#95E530',
56
+        },
57
+        barWidth: '40%'
58
+      },
59
+    ],
60
+    tooltip: {
61
+      trigger: 'axis',
62
+      backgroundColor: 'rgba(13,80,122,1)',
63
+      borderColor: '#70CFE7',
64
+      textStyle: { color: '#fff' }
65
+    }
66
+  }
67
+})
68
+
69
+useECharts(bar, setChartsOptionsBar);
70
+
71
+</script>
72
+
73
+<style lang="scss" scoped></style>

+ 81 - 0
src/views/portraitManagement/components/SupervisionDistribution.vue

@@ -0,0 +1,81 @@
1
+<template>
2
+  <Card title="各岗位监察问题分布">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const labels = props.chartsData.map(item => item.name)
20
+  return {
21
+    grid: {
22
+      top: 50,
23
+      bottom: 60,
24
+      left: 60,
25
+      right: 20
26
+    },
27
+    legend: {
28
+      bottom: '10',
29
+      left: 'center',
30
+      // orient: 'vertical',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    xAxis: {
34
+      type: 'category',
35
+      data: labels,
36
+      axisLabel: { color: '#fff', fontSize: 14 },
37
+      axisLine: { lineStyle: { color: '#344067' } }
38
+    },
39
+    yAxis: [
40
+      {
41
+        name: '人数',
42
+        type: 'value',
43
+        position: 'left',
44
+        axisLabel: { color: '#fff', fontSize: 14 },
45
+        axisLine: {  lineStyle: { color: '#fff' } },
46
+        splitLine: { lineStyle: { color: '#344067' } }
47
+      },
48
+    ],
49
+    series: [
50
+      {
51
+        name: '查获数量',
52
+        type: 'bar',
53
+        data: props.chartsData.map(item => item.num),
54
+        itemStyle: {
55
+          borderRadius: [5, 5, 0, 0],
56
+          color: '#F462CC',
57
+        },
58
+        label: {
59
+          show: true,
60
+          position: 'top',
61
+          color: '#F462CC',
62
+          fontSize: 14,
63
+          fontWeight: 500
64
+        },
65
+        barWidth: '40%'
66
+      },
67
+    ],
68
+    tooltip: {
69
+      trigger: 'axis',
70
+      backgroundColor: 'rgba(13,80,122,1)',
71
+      borderColor: '#70CFE7',
72
+      textStyle: { color: '#fff' }
73
+    }
74
+  }
75
+})
76
+
77
+useECharts(bar, setChartsOptionsBar);
78
+
79
+</script>
80
+
81
+<style lang="scss" scoped></style>

+ 73 - 0
src/views/portraitManagement/components/Svg.vue

@@ -0,0 +1,73 @@
1
+<template>
2
+  <svg
3
+    width="100%"
4
+    height="100%"
5
+    viewBox="0 0 500 500"
6
+    xmlns="http://www.w3.org/2000/svg"
7
+  >
8
+    <defs>
9
+      <!-- 外圈渐变 #e0e0e0-透明-#e0e0e0-透明 -->
10
+      <linearGradient id="grad1">
11
+        <stop offset="0%" stop-color="#e0e0e0"/>
12
+        <stop offset="45%" stop-color="transparent"/>
13
+        <stop offset="55%" stop-color="transparent"/>
14
+        <stop offset="100%" stop-color="#e0e0e0"/>
15
+      </linearGradient>
16
+      <!-- 弧条渐变 0f46fa → bd03fb -->
17
+      <linearGradient id="grad2">
18
+        <stop offset="0%" stop-color="#0f46fa"/>
19
+        <stop offset="100%" stop-color="#bd03fb"/>
20
+      </linearGradient>
21
+    </defs>
22
+    <!-- 最外层点状圆环 -->
23
+    <circle
24
+      cx="250"
25
+      cy="250"
26
+      r="250"
27
+      fill="none"
28
+      stroke="url(#grad1)"
29
+      stroke-width="1"
30
+    />
31
+
32
+    <!-- 内层红色底环 -->
33
+    <circle
34
+      cx="250"
35
+      cy="250"
36
+      r="202"
37
+      fill="none"
38
+      stroke="#838390"
39
+      stroke-width="2"
40
+    />
41
+
42
+    <!-- 可旋转的两段刻度弧(位置已修正对称) -->
43
+    <g>
44
+      <!-- 刻度段 -->
45
+      <path
46
+        d="M 448 210 A 199 199 0 0 0 290 52"
47
+        fill="none"
48
+        stroke="url(#grad2)"
49
+        stroke-width="4"
50
+      />
51
+      <path
52
+        d="M 210 448 A 199 199 0 0 1 52 290"
53
+        fill="none"
54
+        stroke="url(#grad2)"
55
+        stroke-width="4"
56
+      />
57
+      <animateTransform
58
+        attributeName="transform"
59
+        type="rotate"
60
+        from="0 250 250"
61
+        to="360 250 250"
62
+        dur="12s"
63
+        repeatCount="indefinite"
64
+        calcMode="linear"
65
+      />
66
+    </g>
67
+  </svg>
68
+</template>
69
+
70
+<script>
71
+</script>
72
+
73
+<style lang="scss" scoped></style>

+ 80 - 0
src/views/portraitManagement/components/TestArea.vue

@@ -0,0 +1,80 @@
1
+<template>
2
+  <Card title="安保测试区域情况">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+const setChartsOptionsBar = computed(() => {
19
+  const labels = props.chartsData.map(item => item.name)
20
+  return {
21
+    grid: {
22
+      top: 50,
23
+      bottom: 40,
24
+      left: 60,
25
+      right: 20
26
+    },
27
+    legend: {
28
+      top: '10',
29
+      left: '30',
30
+      // orient: 'vertical',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    xAxis: {
34
+      type: 'category',
35
+      data: labels,
36
+      axisLabel: { color: '#fff', fontSize: 14 },
37
+      axisLine: { lineStyle: { color: '#344067' } }
38
+    },
39
+    yAxis: [
40
+      {
41
+        type: 'value',
42
+        position: 'left',
43
+        axisLabel: { color: '#fff', fontSize: 14 },
44
+        axisLine: {  lineStyle: { color: '#fff' } },
45
+        splitLine: { lineStyle: { color: '#344067' } }
46
+      },
47
+    ],
48
+    series: [
49
+      {
50
+        name: '查获数量',
51
+        type: 'bar',
52
+        data: props.chartsData.map(item => item.num),
53
+        itemStyle: {
54
+          borderRadius: [5, 5, 0, 0],
55
+          color: '#9963FB',
56
+        },
57
+        label: {
58
+          show: true,
59
+          position: 'top',
60
+          color: '#9963FB',
61
+          fontSize: 14,
62
+          fontWeight: 500
63
+        },
64
+        barWidth: '40%'
65
+      },
66
+    ],
67
+    tooltip: {
68
+      trigger: 'axis',
69
+      backgroundColor: 'rgba(13,80,122,1)',
70
+      borderColor: '#70CFE7',
71
+      textStyle: { color: '#fff' }
72
+    }
73
+  }
74
+})
75
+
76
+useECharts(bar, setChartsOptionsBar);
77
+
78
+</script>
79
+
80
+<style lang="scss" scoped></style>

+ 62 - 0
src/views/portraitManagement/components/TestItems.vue

@@ -0,0 +1,62 @@
1
+<template>
2
+  <Card title="安保测试物品分类">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 200,
25
+      right: 0
26
+    },
27
+    tooltip: {
28
+      trigger: 'item',
29
+      backgroundColor: 'rgba(13,80,122,1)',
30
+      borderColor: '#70CFE7',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    legend: {
34
+      top: 'center',
35
+      left: '0%',
36
+      orient: 'vertical',
37
+      textStyle: { color: '#fff' }
38
+    },
39
+    series: [{
40
+      type: 'pie',
41
+      radius: ['0%', '60%'],
42
+      data: props.chartsData.map(item => {
43
+        return {
44
+          value: item.num,
45
+          name: item.name
46
+        }
47
+      }),
48
+      itemStyle: {
49
+        borderRadius: 5,
50
+        borderWidth: 0
51
+      },
52
+      label: { show: true, color: '#fff', fontSize: 16, lineHeight: 20, formatter: '{b}\n{c}'  },
53
+      labelLine: { show: true }
54
+    }],
55
+  }
56
+})
57
+
58
+useECharts(bar, setChartsOptionsBar);
59
+
60
+</script>
61
+
62
+<style lang="scss" scoped></style>

+ 62 - 0
src/views/portraitManagement/components/TestResult.vue

@@ -0,0 +1,62 @@
1
+<template>
2
+  <Card title="安保测试通过结果">
3
+    <div ref="bar" style="width: 100%; height: 100%;"></div>
4
+  </Card>
5
+</template>
6
+
7
+<script setup>
8
+import { computed } from 'vue';
9
+import Card from './card.vue';
10
+import { useECharts } from '@/hooks/useEcharts.js';
11
+const bar = ref(null)
12
+const props = defineProps({
13
+  chartsData: {
14
+    type: Object,
15
+    default: () => ([])
16
+  }
17
+})
18
+
19
+const setChartsOptionsBar = computed(() => {
20
+  return {
21
+    grid: {
22
+      top: 40,
23
+      bottom: 40,
24
+      left: 200,
25
+      right: 0
26
+    },
27
+    tooltip: {
28
+      trigger: 'item',
29
+      backgroundColor: 'rgba(13,80,122,1)',
30
+      borderColor: '#70CFE7',
31
+      textStyle: { color: '#fff' }
32
+    },
33
+    legend: {
34
+      top: 'center',
35
+      left: '0%',
36
+      orient: 'vertical',
37
+      textStyle: { color: '#fff' }
38
+    },
39
+    series: [{
40
+      type: 'pie',
41
+      radius: ['0%', '60%'],
42
+      data: props.chartsData.map(item => {
43
+        return {
44
+          value: item.num,
45
+          name: item.name
46
+        }
47
+      }),
48
+      itemStyle: {
49
+        borderRadius: 5,
50
+        borderWidth: 0
51
+      },
52
+      label: { show: true, color: '#fff', fontSize: 16, lineHeight: 20, formatter: '{b}\n{c}'  },
53
+      labelLine: { show: true }
54
+    }],
55
+  }
56
+})
57
+
58
+useECharts(bar, setChartsOptionsBar);
59
+
60
+</script>
61
+
62
+<style lang="scss" scoped></style>

+ 2 - 2
src/views/portraitManagement/employeeProfile/index.vue

@@ -219,10 +219,10 @@ import Page from '../components/page.vue'
219 219
 import Card from '../components/card.vue'
220 220
 import SearchBar from '../components/SearchBar.vue'
221 221
 import { getEmployeePortrait } from '@/api/score/index'
222
-import { onMounted, onUnmounted, ref } from 'vue'
222
+import { onMounted, reactive, ref } from 'vue'
223 223
 import { useDict } from '@/utils/dict'
224 224
 import { useECharts } from '@/hooks/useEcharts'
225
-import { reactive } from 'vue'
225
+
226 226
 
227 227
 const { sys_user_schooling } = useDict('sys_user_schooling')
228 228
 const visible = ref(false)

+ 129 - 6
src/views/portraitManagement/groupProfile/component/runData.vue

@@ -1,20 +1,143 @@
1 1
 <template>
2 2
   <div class="operation-data">
3
-    <div class="placeholder">运行数据页面</div>
3
+    <div class="row">
4
+      <ChannelCheckChart :chartsData="chartsData" />
5
+    </div>
6
+    <div class="row">
7
+      <div class="col">
8
+        <SeizedInfo :chartsData="chartsData"/>
9
+      </div>
10
+      <div class="col">
11
+        <SeizedItems :chartsData="chartsData" />
12
+      </div>
13
+    </div>
14
+    <div class="row">
15
+      <div class="col">
16
+        <SeizedNumAll :chartsData="chartsData"/>
17
+      </div>
18
+      <div class="col">
19
+        <SeizedNum :chartsData="chartsData" />
20
+      </div>
21
+    </div>
22
+    <div class="row">
23
+      <SeizedWorkArea :chartsData="chartsData" />
24
+    </div>
25
+    <div class="row">
26
+      <div class="col">
27
+        <EventItems :chartsData="chartsData"  />
28
+      </div>
29
+      <div class="col">
30
+        <EventType :chartsData="chartsData"  />
31
+      </div>
32
+      <div class="col">
33
+        <EventWorkArea :chartsData="chartsData"  />
34
+      </div>
35
+    </div>
36
+    <div class="row">
37
+      <div class="col">
38
+        <TestItems :chartsData="chartsData"  />
39
+      </div>
40
+      <div class="col">
41
+        <TestResult :chartsData="chartsData"  />
42
+      </div>
43
+      <div class="col">
44
+        <TestArea :chartsData="chartsData"  />
45
+      </div>
46
+    </div>
47
+    <div class="row">
48
+      <div class="col">
49
+        <SupervisionDistribution :chartsData="chartsData"/>
50
+      </div>
51
+      <div class="col">
52
+        <InterceptionDistribution :chartsData="chartsData" />
53
+      </div>
54
+    </div>
4 55
   </div>
5 56
 </template>
6 57
 
7 58
 <script setup>
59
+import ChannelCheckChart from '../../components/ChannelCheckChart.vue';
60
+import SeizedInfo from '../../components/SeizedInfo.vue';
61
+import SeizedItems from '../../components/SeizedItems.vue';
62
+import SeizedNumAll from '../../components/SeizedNumAll.vue';
63
+import SeizedNum from '../../components/SeizedNum.vue';
64
+import SeizedWorkArea from '../../components/SeizedWorkArea.vue';
65
+import EventItems from '../../components/EventItems.vue';
66
+import EventType from '../../components/EventType.vue';
67
+import EventWorkArea from '../../components/EventWorkArea.vue';
68
+import TestItems from '../../components/TestItems.vue';
69
+import TestResult from '../../components/TestResult.vue';
70
+import TestArea from '../../components/TestArea.vue';
71
+import SupervisionDistribution from '../../components/SupervisionDistribution.vue';
72
+import InterceptionDistribution from '../../components/InterceptionDistribution.vue';
73
+
74
+
75
+const chartsData = ref([
76
+  {
77
+    num: 370,
78
+    num1: 330,
79
+    num2: 120,
80
+    num3: 470,
81
+    num4: 570,
82
+    rate: 30,
83
+    name: '打火机'
84
+  },
85
+  {
86
+    num: 330,
87
+    num1: 430,
88
+    num2: 420,
89
+    num3: 430,
90
+    num4: 150,
91
+    rate: 60,
92
+    name: '火柴'
93
+  },
94
+  {
95
+    num: 410,
96
+    num1: 310,
97
+    num2: 220,
98
+    num3: 370,
99
+    num4: 510,
100
+    rate: 35,
101
+    name: '刀具'
102
+  },
103
+  {
104
+    num: 570,
105
+    num1: 440,
106
+    num2: 420,
107
+    num3: 410,
108
+    num4: 470,
109
+    rate: 80,
110
+    name: '充电宝'
111
+  },
112
+  {
113
+    num: 340,
114
+    num1: 330,
115
+    num2: 620,
116
+    num3: 370,
117
+    num4: 170,
118
+    rate: 60,
119
+    name: '烟火'
120
+  },
121
+])
122
+  
123
+
8 124
 </script>
9 125
 
10 126
 <style lang="scss" scoped>
11 127
 .operation-data {
12 128
   padding: 20px;
13
-  .placeholder {
14
-    color: #fff;
15
-    font-size: 24px;
16
-    text-align: center;
17
-    padding: 100px 0;
129
+  .row {
130
+    display: flex;
131
+    column-gap: 15px;
132
+    height: 360px;
133
+    margin-bottom: 15px;
134
+    .col {
135
+      flex: 1;
136
+      height: 100%;
137
+      :deep(.info-card) {
138
+        height: 100%;
139
+      }
140
+    }
18 141
   }
19 142
 }
20 143
 </style>