Quellcode durchsuchen

feat: 保密总览人员管理图

wyf vor 6 Monaten
Ursprung
Commit
4f38200ec7

+ 170 - 0
src/views/security-confidentiality/overview/charts/OuterPersonChart.vue

@@ -0,0 +1,170 @@
+<template>
+  <div :id="props.id" :style="{ width: '100%' }" class="pieChart"></div>
+</template>
+<script setup lang="ts">
+  import * as echarts from 'echarts/core';
+  import { TooltipComponent, LegendComponent, GraphicComponent } from 'echarts/components';
+  import { PieChart } from 'echarts/charts';
+  import { CanvasRenderer } from 'echarts/renderers';
+  import { onMounted, ref, watch } from 'vue';
+  import type { PieChartData } from './types';
+
+  const props = defineProps<{
+    data: PieChartData[];
+    id: string;
+  }>();
+
+  echarts.use([TooltipComponent, LegendComponent, PieChart, GraphicComponent, CanvasRenderer]);
+
+  const sum = ref(props.data.reduce((acc, cur) => acc + cur.value, 0));
+  let doughnut;
+
+  onMounted(() => {
+    doughnut = echarts.init(document.getElementById(props.id as string)!);
+    if (doughnut) {
+      initDoughnut(doughnut);
+      drawDoughnut(doughnut);
+    }
+  });
+
+  const drawDoughnut = (doughnut) => {
+    const doughnutOption = {
+      series: [
+        {
+          data: props.data,
+        },
+      ],
+    };
+    doughnut.setOption(doughnutOption);
+  };
+
+  const initDoughnut = (doughnut) => {
+    const doughnutOption = {
+      graphic: [
+        {
+          type: 'group',
+          width: '60%',
+          children: [
+            {
+              type: 'text',
+              left: 'center',
+              top: '90px',
+              z: 10,
+              style: {
+                text: `${sum.value}`,
+                fill: '#1777ff',
+                fontSize: 25,
+                fontWeight: 'bold',
+              },
+            },
+            {
+              type: 'text',
+              left: 'center',
+              top: '125px',
+              z: 10,
+              style: {
+                text: '总人数',
+                fill: '#1777ff',
+                fontSize: 14,
+              },
+            },
+          ],
+        },
+
+        {
+          type: 'text',
+          left: '5%',
+          bottom: '5px',
+          z: 10,
+          style: {
+            text: '说明:常驻外部人员及临时项目报备人员除外',
+            fill: '#CCCDD0',
+            fontSize: 14,
+          },
+        },
+      ],
+      // legend: {
+      //   orient: 'vertical',
+      //   top: 'center',
+      //   right: '20%',
+      //   icon: 'circle',
+      //   formatter: (name) => {
+      //     const item = props.data.find((item) => item.name === name);
+      //     return `{a|${name}} ` + (item?.id === 1 ? `{b|${item.value}} ` : `{c|${item?.value}} `) + `{a|人}`;
+      //   },
+      //   textStyle: {
+      //     rich: {
+      //       a: {
+      //         fontSize: 14,
+      //         color: '#8B8B8B',
+      //       },
+      //       b: {
+      //         fontSize: 14,
+      //         color: '#3777FD',
+      //       },
+      //       c: {
+      //         fontSize: 14,
+      //         color: '#F1C7A3',
+      //       },
+      //     },
+      //   },
+      // },
+      series: [
+        {
+          type: 'pie',
+          radius: ['50%', '70%'],
+          center: ['30%', '50%'],
+          clockwise: true,
+          avoidLabelOverlap: false,
+          padAngle: 5,
+          label: {
+            show: false,
+          },
+          emphasis: {
+            itemStyle: {
+              borderColor: '#f3f3f3',
+              borderWidth: 5,
+            },
+          },
+          data: props.data,
+          itemStyle: {
+            normal: {
+              color: function (params) {
+                const colorList = [
+                  ['#3777FD', '#52A8FF'],
+                  ['#F1C7A3', '#F19570'],
+                ];
+                const index = params.dataIndex;
+                return new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+                  {
+                    offset: 0,
+                    color: colorList[index][0],
+                  },
+                  {
+                    offset: 1,
+                    color: colorList[index][1],
+                  },
+                ]);
+              },
+            },
+          },
+        },
+      ],
+    };
+    doughnut.setOption(doughnutOption);
+  };
+
+  watch(
+    () => props.data,
+    () => {
+      sum.value = props.data.reduce((acc, cur) => acc + cur.value, 0);
+      drawDoughnut(doughnut);
+    },
+  );
+</script>
+
+<style scoped lang="scss">
+  .pieChart {
+    height: 100%;
+  }
+</style>

+ 37 - 0
src/views/security-confidentiality/overview/charts/OuterPersonChartLegend.vue

@@ -0,0 +1,37 @@
+<template>
+  <div style="cursor: default">
+    <div class="legend-item" v-for="item in props.data" :key="item.id">
+      <div class="icon" :style="{ backgroundColor: item.color }"></div>
+      <span class="name">{{ item.name }}</span>
+      <span class="value" :style="{ color: item.color }">{{ item.value }}</span>
+      <span class="unit">人</span>
+    </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import type { PieChartData } from './types';
+
+  const props = defineProps<{
+    data: PieChartData[];
+  }>();
+</script>
+
+<style scoped>
+  .legend-item {
+    display: flex;
+    align-items: center;
+    margin-bottom: 10px;
+  }
+  .icon {
+    width: 20px;
+    height: 20px;
+    border-radius: 50%;
+    border: 5px solid #fff;
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.2);
+    margin-right: 10px;
+  }
+  .name {
+    color: #6e6f6e;
+  }
+</style>

+ 6 - 0
src/views/security-confidentiality/overview/charts/types.ts

@@ -0,0 +1,6 @@
+export interface PieChartData {
+  name: string;
+  value: number;
+  id: number;
+  color: string;
+}

+ 18 - 2
src/views/security-confidentiality/overview/components/OuterPerson.vue

@@ -4,11 +4,20 @@
       <span class="line"></span>
       <span class="title">外部人员管理</span>
     </div>
-    <div class="chart-container"></div>
+    <OuterPersonChart class="chart-container" id="OuterPersonChart" :data="pieData"></OuterPersonChart>
+    <OuterPersonChartLegend class="chart-legend" :data="pieData"></OuterPersonChartLegend>
   </div>
 </template>
 
-<script setup lang="ts"></script>
+<script setup lang="ts">
+  import OuterPersonChart from '../charts/OuterPersonChart.vue';
+  import OuterPersonChartLegend from '../charts/OuterPersonChartLegend.vue';
+
+  const pieData = [
+    { value: 90, name: '非外籍访客', id: 1, color: '#3777FD' },
+    { value: 200, name: '外籍访客', id: 2, color: '#F1C7A3' },
+  ];
+</script>
 
 <style scoped lang="scss">
   .container-title {
@@ -35,10 +44,17 @@
     width: 100%;
     height: 100%;
     padding-top: 14px;
+    position: relative;
   }
 
   .chart-container {
     width: 100%;
     height: calc(100% - 24px);
   }
+
+  .chart-legend {
+    position: absolute;
+    top: 120px;
+    left: 55%;
+  }
 </style>