浏览代码

feat:不同页面设置不同的浏览器标题;

zhangchong 1 年之前
父节点
当前提交
834b6f5225

+ 14 - 4
src/App.vue

@@ -15,10 +15,11 @@
   </el-config-provider>
 </template>
 <script setup lang="ts">
-import { computed,reactive } from "vue";
+import { computed,reactive,watch } from "vue";
 import zhCn from "element-plus/es/locale/lang/zh-cn";
 import signalR from "@/utils/signalR";
-import { RouterView } from "vue-router";
+import {RouterView, useRoute} from "vue-router";
+import { useTitle } from "@/utils/tools";
 //  signalR 初始化signalr
 signalR.init();
 signalR.joinGroup("BigScreen-DataShow");
@@ -47,6 +48,15 @@ const config = reactive({
   gap: [100, 100] as [number, number],
   offset: [] as unknown as [number, number],
 })
+const route = useRoute();
+// 监听路由的变化,设置网站标题
+watch(
+    () => route.path,
+    () => {
+      useTitle();
+    },
+    {
+      deep: true,
+    }
+);
 </script>
-
-<style scoped></style>

+ 14 - 0
src/router/index.ts

@@ -9,11 +9,25 @@ const routes: Array<RouteRecordRaw> = [
     path: '/index',
     name: 'index',
     component: () => import('@/views/index/index.vue'),
+    meta: {
+      title: '',
+    }
   },
   {
     path: '/seats',
     name: 'seats',
     component: () => import('@/views/seats/index.vue'),
+    meta: {
+      title: '宜宾市12345坐席监控中心',
+    }
+  },
+  {
+    path: '/statistics',
+    name: 'statistics',
+    component: () => import('@/views/statistics/index.vue'),
+    meta: {
+      title: '',
+    }
   },
 ]
 const router = createRouter({

+ 15 - 0
src/utils/tools.ts

@@ -1,4 +1,6 @@
 import axios from "axios";
+import { defineAsyncComponent, nextTick } from 'vue';
+import router from "@/router";
 /**
  * @description 防抖
  * @param func    功能函数(即要防抖的函数)
@@ -135,4 +137,17 @@ export function arraySortByKey(arr: Array<any>, key: string, type= 'descending')
 			return a[key] - b[key];
 		}
 	});
+}
+
+/**
+ * @description 设置浏览器标题
+ * @method const title = useTitle(); ==> title()
+ */
+export function useTitle() {
+	nextTick(() => {
+		let webTitle: string;
+		const {  meta } = router.currentRoute.value;
+		webTitle = <any>meta.title || '宜宾市12345政务热线';
+		document.title = `${webTitle}`
+	}).then(() => {});
 }

+ 0 - 2
src/views/index/index.vue

@@ -14,7 +14,6 @@
     <div class="content_wrap">
       <Headers />
       <Container />
-      <RouterView />
       <MessageContent />
     </div>
   </scale-screen>
@@ -22,7 +21,6 @@
 </template>
 <script setup lang="ts" name="index">
 import { defineAsyncComponent } from "vue";
-import { RouterView } from "vue-router";
 import { useSettingStore } from "@/stores/setting";
 import { storeToRefs } from "pinia";
 

+ 1 - 3
src/views/seats/index.vue

@@ -14,15 +14,13 @@
     <div class="content_wrap">
       <Headers />
       <Container />
-      <RouterView />
       <MessageContent />
     </div>
   </scale-screen>
   <Setting />
 </template>
 <script setup lang="ts" name="seats">
-import { defineAsyncComponent } from "vue";
-import { RouterView } from "vue-router";
+import {defineAsyncComponent, onMounted} from "vue";
 import { useSettingStore } from "@/stores/setting";
 import { storeToRefs } from "pinia";
 

+ 106 - 0
src/views/statistics/bar.vue

@@ -0,0 +1,106 @@
+
+<template>
+  <v-chart
+      class="chart"
+      :option="option"
+      v-if="JSON.stringify(option) != '{}'"
+  />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { graphic } from "echarts/core";
+import Mock from "mockjs";
+const option = ref({});
+const getData = () => {
+  let num = 10
+  const data = Mock.mock({
+    category: ['其他','表扬','咨询','建议','投诉','举报','求助','意见','惠民帮助','大气污染举报'],
+    ["barData|" + num]: ["@integer(10, 100)"],
+  })
+  let lineData = [], rateData = [];
+  for (let index = 0; index < num; index++) {
+    let lineNum = Mock.mock('@integer(10, 100)') + data.barData[index]
+    lineData.push(lineNum)
+    let rate = data.barData[index] / lineNum;
+    rateData.push((rate * 100).toFixed(0))
+  }
+  data.lineData = lineData
+  data.rateData = rateData
+  setTimeout(() => {
+    setOption(data);
+  }, 100);
+}
+const setOption = async (newData: any) => {
+  option.value = {
+    title: {
+      left: "center",
+      top:'10',
+      text: '渠道来源',
+      textStyle: {
+        fontSize: 24,
+      },
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+    },
+    legend: {
+      data: ["已完成"],
+      textStyle: {
+        fontSize: 16,
+      },
+      bottom: "0",
+    },
+    grid: {
+      left: "50px",
+      right: "50px",
+      bottom: "50px",
+      top: "20px",
+    },
+    xAxis: {
+      data: newData.category,
+      axisLine: {
+        lineStyle: {
+          color: "#333",
+          fontSize: 16,
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: [
+      {
+        splitLine: { show: false },
+        axisLine: {
+          lineStyle: {
+            color: "#333",
+            fontSize: 16,
+          },
+        },
+
+        axisLabel: {
+          formatter: "{value}",
+        },
+      }
+    ],
+    series: [
+      {
+        name: "已完成",
+        type: "bar",
+        itemStyle: {
+
+        },
+        data: newData.barData,
+      }
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>

+ 104 - 0
src/views/statistics/bar2.vue

@@ -0,0 +1,104 @@
+
+<template>
+  <v-chart
+      class="chart"
+      :option="option"
+      v-if="JSON.stringify(option) != '{}'"
+  />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { graphic } from "echarts/core";
+import Mock from "mockjs";
+const option = ref({});
+const getData = () => {
+  const data = Mock.mock({
+    category: ['咨询','投诉','求助','其他'],
+    lastYear: [535543,122266,195830,2877],
+    thisYear: [545348,165464,249227,3096],
+  })
+  setTimeout(() => {
+    setOption(data);
+  }, 100);
+}
+const setOption = async (newData: any) => {
+  option.value = {
+    title: {
+      left: "center",
+      top:'10',
+      text: '近两年12345热线主要受理情况',
+      textStyle: {
+        fontSize: 24,
+      },
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+    },
+    legend: {
+      data: ["2022", "2023"],
+      textStyle: {
+        color: "#333",
+      },
+      bottom: "0",
+    },
+    grid: {
+      left: "80px",
+      right: "50px",
+      bottom: "50px",
+      top: "20px",
+    },
+    xAxis: {
+      data: newData.category,
+      axisLine: {
+        lineStyle: {
+          color: "#333",
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+    },
+    yAxis: [
+      {
+        splitLine: { show: false },
+        axisLine: {
+          lineStyle: {
+            color: "#333",
+          },
+        },
+        axisLabel: {
+          formatter: "{value}",
+        },
+      }
+    ],
+    series: [
+      {
+        name: "2022",
+        type: "bar",
+        barWidth: 40,
+        itemStyle: {
+
+        },
+        data: newData.lastYear,
+      },
+      {
+        name: "2023",
+        type: "bar",
+        barWidth: 40,
+        itemStyle: {
+
+        },
+        data: newData.thisYear,
+      }
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>

+ 200 - 0
src/views/statistics/bar3.vue

@@ -0,0 +1,200 @@
+
+<template>
+  <v-chart
+      class="chart"
+      :option="option"
+      v-if="JSON.stringify(option) != '{}'"
+  />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { graphic } from "echarts/core";
+import Mock from "mockjs";
+const option = ref({});
+const getData = () => {
+  let num = 3
+  const data = Mock.mock({
+    category: ['求助','投诉','咨询'],
+    ["barData|" + num]: ["@integer(10, 100)"],
+    ["barData2|" + num]: ["@integer(10, 100)"],
+    ["barData3|" + num]: ["@integer(10, 100)"],
+    ["barData4|" + num]: ["@integer(10, 100)"],
+  })
+  let lineData = [], rateData = [];
+  for (let index = 0; index < num; index++) {
+    let lineNum = Mock.mock('@integer(10, 100)') + data.barData[index]
+    lineData.push(lineNum)
+    let rate = data.barData[index] / lineNum;
+    rateData.push((rate * 100).toFixed(0))
+  }
+  data.lineData = lineData
+  data.rateData = rateData
+  setTimeout(() => {
+    setOption(data);
+  }, 100);
+}
+const setOption = async (newData: any) => {
+  option.value = {
+    title: {
+      left: "center",
+      top:'10',
+      text: '2023主要受理类型满意率',
+      textStyle: {
+        fontSize: 24,
+      },
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+      formatter: function (params: any) {
+        // 添加单位
+        let result = params[0].name + "<br>";
+        params.forEach(function (item: any) {
+          if (item.value) {
+            if (item.seriesName == "满意度") {
+              result +=
+                  item.marker +
+                  " " +
+                  item.seriesName +
+                  " : " +
+                  item.value +
+                  "%</br>";
+            } else {
+              result +=
+                  item.marker +
+                  " " +
+                  item.seriesName +
+                  " : " +
+                  item.value +
+                  "件</br>";
+            }
+          } else {
+            result += item.marker + " " + item.seriesName + " :  - </br>";
+          }
+        });
+        return result;
+      },
+    },
+    legend: {
+      data: ["非常满意", "满意", "视为满意","不满意","满意度"],
+      textStyle: {
+        color: "#333",
+      },
+      bottom: "0",
+    },
+    grid: {
+      left: "50px",
+      right: "50px",
+      bottom: "50px",
+      top: "40px",
+    },
+    xAxis: {
+      data: newData.category,
+      axisLine: {
+        lineStyle: {
+          color: "#333",
+          fontSize: 16,
+        },
+      },
+      axisTick: {
+        show: false,
+      },
+      axisLabel: {
+        // color: "#7EB7FD",
+        fontWeight: "500",
+        fontSize: 16,
+      },
+    },
+    yAxis: [
+      {
+        splitLine: { show: false },
+        axisLine: {
+          lineStyle: {
+            color: "#333",
+          },
+        },
+
+        axisLabel: {
+          formatter: "{value}",
+        },
+      },
+      {
+        splitLine: { show: false },
+        axisLine: {
+          lineStyle: {
+            color: "#333",
+          },
+        },
+        axisLabel: {
+          formatter: "{value}% ",
+        },
+      },
+    ],
+    series: [
+      {
+        name: "非常满意",
+        type: "bar",
+        barWidth: '20%',
+        stack: 'x',
+        itemStyle: {
+
+        },
+        data: newData.barData,
+      },
+      {
+        name: "满意",
+        type: "bar",
+        barWidth: '20%',
+        stack: 'x',
+        z: -1,
+        itemStyle: {
+
+        },
+        data: newData.barData2,
+      },
+      {
+        name: "视为满意",
+        type: "bar",
+        barWidth: '20%',
+        stack: 'x',
+        z: -2,
+        itemStyle: {
+
+        },
+        data: newData.barData3,
+      },
+      {
+        name: "不满意",
+        type: "bar",
+        barWidth: '20%',
+        stack: 'x',
+        z: -3,
+        itemStyle: {
+
+        },
+        data: newData.barData4,
+      },
+      {
+        name: "满意度",
+        type: "line",
+        smooth: false,
+        showAllSymbol: true,
+        symbol: "emptyCircle",
+        symbolSize: 8,
+        yAxisIndex: 1,
+        itemStyle: {
+          color: "#F02FC2",
+        },
+        data: newData.rateData,
+      },
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>

+ 62 - 0
src/views/statistics/container.vue

@@ -0,0 +1,62 @@
+<template>
+  <div class="index-box">
+    <div class="center_right">
+      <el-radio-group v-model="radio" @change="change" class="mt-10 mb-10">
+        <el-radio-button label="Pie" >Pie</el-radio-button>
+        <el-radio-button label="Bar">Bar</el-radio-button>
+        <el-radio-button label="Bar2">Bar2</el-radio-button>
+        <el-radio-button label="Bar3">Bar3</el-radio-button>
+        <el-radio-button label="Line">Line</el-radio-button>
+        <el-radio-button label="Line2">Line2</el-radio-button>
+      </el-radio-group>
+      <component :is="currentComponent"></component>
+    </div>
+  </div>
+</template>
+<script setup lang="ts">
+import { ref,shallowRef } from "vue";
+import Pie from "@/views/statistics/pie.vue";
+import Bar from "@/views/statistics/bar.vue";
+import Bar2 from "@/views/statistics/bar2.vue";
+import Bar3 from "@/views/statistics/bar3.vue";
+import Line from "@/views/statistics/line.vue";
+import Line2 from "@/views/statistics/line2.vue";
+const currentComponent = shallowRef(Pie);
+const radio = ref("Pie");
+const change = (val: string) => {
+  radio.value = val;
+  switch (val) {
+    case "Pie":
+      currentComponent.value = Pie;
+      break;
+    case "Bar":
+      currentComponent.value = Bar;
+      break;
+    case "Bar2":
+      currentComponent.value = Bar2;
+      break;
+    case "Bar3":
+      currentComponent.value = Bar3;
+      break;
+    case "Line":
+      currentComponent.value = Line;
+      break;
+    case "Line2":
+      currentComponent.value = Line2;
+      break;
+  }
+};
+</script>
+<style scoped lang="scss">
+.index-box {
+  width: 100%;
+  display: flex;
+  min-height: 100%;
+}
+.center_right{
+  height: 800px;
+  width: 50%;
+  padding: 0 20px;
+  box-sizing: border-box;
+}
+</style>

+ 42 - 0
src/views/statistics/index.vue

@@ -0,0 +1,42 @@
+<template>
+  <scale-screen
+      width="1920"
+      height="1080"
+      :delay="500"
+      :fullScreen="true"
+      :boxStyle="{
+      background: '#fff',
+      overflow: isScale ? 'hidden' : 'auto',
+    }"
+      :wrapperStyle="wrapperStyle"
+      :autoScale="isScale"
+  >
+    <div class="content_wrap">
+      <Container />
+      <MessageContent />
+    </div>
+  </scale-screen>
+  <Setting />
+</template>
+<script setup lang="ts" name="statistics">
+import { defineAsyncComponent } from "vue";
+import { useSettingStore } from "@/stores/setting";
+import { storeToRefs } from "pinia";
+
+const ScaleScreen = defineAsyncComponent(() => import('@/components/scale-screen'));
+const Container = defineAsyncComponent(() => import('@/views/statistics/container.vue'));
+const Setting = defineAsyncComponent(() => import('@/views/index/setting.vue'));
+const MessageContent = defineAsyncComponent(() => import('@/components/Plugins/MessageContent'));
+
+const settingStore = useSettingStore();
+const { isScale } = storeToRefs(settingStore);
+const wrapperStyle = {};
+</script>
+<style lang="scss" scoped>
+.content_wrap {
+  width: 100%;
+  height: 100%;
+  box-sizing: border-box;
+  color: var(--el-text-color-regular) !important;
+}
+</style>

+ 238 - 0
src/views/statistics/line.vue

@@ -0,0 +1,238 @@
+<template>
+  <v-chart
+      class="chart"
+      :option="option"
+      v-if="JSON.stringify(option) != '{}'"
+  />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { graphic } from "echarts/core";
+import Mock from "mockjs";
+const option = ref({});
+const getData = () => {
+  // window["$message"]({
+  //   text: res.msg,
+  //   type: "warning",
+  // });
+  const data = Mock.mock({
+    xdata: ['2023-07', '2023-08', '2023-09', '2023-10', '2023-11', "2023-12"],
+    "yData|6": ["@integer(0, 1000)"],
+    "yData2|6": ["@integer(0, 1000)"],
+  })
+  setTimeout(() => {
+    setOption(data);
+  }, 100);
+}
+const setOption = async (data:any) => {
+  option.value = {
+    title: {
+      text: "话务量",
+      left:'center',
+      top:'10',
+      textStyle: {
+        fontSize:24,
+      },
+    },
+    xAxis: {
+      type: "category",
+      data: data.xdata,
+      boundaryGap: false, // 不留白,从原点开始
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: "rgba(31,99,163,.2)",
+        },
+      },
+      axisLine: {
+        // show:false,
+        lineStyle: {
+          color: "rgba(31,99,163,.1)",
+        },
+      },
+      axisLabel: {
+        color: "#7EB7FD",
+        fontWeight: "500",
+      },
+    },
+    yAxis: {
+      type: "value",
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: "rgba(31,99,163,.2)",
+        },
+      },
+      axisLine: {
+        lineStyle: {
+          color: "rgba(31,99,163,.1)",
+        },
+      },
+      axisLabel: {
+        color: "#7EB7FD",
+        fontWeight: "500",
+      },
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+    },
+    grid: {
+      //布局
+      show: false,
+      left: "10px",
+      right: "30px",
+      bottom: "10px",
+      top: "52px",
+      containLabel: true,
+      borderColor: "#1F63A3",
+    },
+    series: [
+      {
+        data: data.yData,
+        type: "line",
+        smooth: true,
+        stack: 'x',
+        symbol: "none", //去除点
+        name: "最高1次数",
+        color: "rgba(252,144,16,.7)",
+        areaStyle: {
+          //右,下,左,上
+          color: new graphic.LinearGradient(
+              0,
+              0,
+              0,
+              1,
+              [
+                {
+                  offset: 0,
+                  color: "rgba(252,144,16,.7)",
+                },
+                {
+                  offset: 1,
+                  color: "rgba(252,144,16,.0)",
+                },
+              ],
+              false
+          ),
+        },
+        markPoint: {
+          data: [
+            {
+              name: "最大值",
+              type: "max",
+              valueDim: "y",
+              symbol: "rect",
+              symbolSize: [60, 26],
+              symbolOffset: [0, -20],
+              itemStyle: {
+                color: "rgba(0,0,0,0)",
+              },
+              label: {
+                color: "#FC9010",
+                backgroundColor: "rgba(252,144,16,0.1)",
+                borderRadius: 6,
+                padding: [7, 14],
+                borderWidth: 0.5,
+                borderColor: "rgba(252,144,16,.5)",
+                formatter: "峰值1:{c}",
+              },
+            },
+            {
+              name: "最大值",
+              type: "max",
+              valueDim: "y",
+              symbol: "circle",
+              symbolSize: 6,
+              itemStyle: {
+                color: "#FC9010",
+                shadowColor: "#FC9010",
+                shadowBlur: 8,
+              },
+              label: {
+                formatter: "",
+              },
+            },
+          ],
+        },
+      },
+      {
+        data: data.yData2,
+        type: "line",
+        smooth: true,
+        symbol: "none", //去除点
+        name: "最高2次数",
+        stack: 'x',
+        color: "rgba(9,202,243,.7)",
+        areaStyle: {
+          //右,下,左,上
+          color: new graphic.LinearGradient(
+              0,
+              0,
+              0,
+              1,
+              [
+                {
+                  offset: 0,
+                  color: "rgba(9,202,243,.7)",
+                },
+                {
+                  offset: 1,
+                  color: "rgba(9,202,243,.0)",
+                },
+              ],
+              false
+          ),
+        },
+        markPoint: {
+          data: [
+            {
+              name: "最大值",
+              type: "max",
+              valueDim: "y",
+              symbol: "rect",
+              symbolSize: [60, 26],
+              symbolOffset: [0, -20],
+              itemStyle: {
+                color: "rgba(0,0,0,0)",
+              },
+              label: {
+                color: "#09CAF3",
+                backgroundColor: "rgba(9,202,243,0.1)",
+
+                borderRadius: 6,
+                borderColor: "rgba(9,202,243,.5)",
+                padding: [7, 14],
+                formatter: "峰值2:{c}",
+                borderWidth: 0.5,
+              },
+            },
+            {
+              name: "最大值",
+              type: "max",
+              valueDim: "y",
+              symbol: "circle",
+              symbolSize: 6,
+              itemStyle: {
+                color: "#09CAF3",
+                shadowColor: "#09CAF3",
+                shadowBlur: 8,
+              },
+              label: {
+                formatter: "",
+              },
+            },
+          ],
+        },
+      },
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>

+ 198 - 0
src/views/statistics/line2.vue

@@ -0,0 +1,198 @@
+<template>
+  <v-chart
+      class="chart"
+      :option="option"
+      v-if="JSON.stringify(option) != '{}'"
+  />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import { graphic } from "echarts/core";
+import Mock from "mockjs";
+const option = ref({});
+const getData = () => {
+  // window["$message"]({
+  //   text: res.msg,
+  //   type: "warning",
+  // });
+  const data = Mock.mock({
+    xdata: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
+    total: [66035,
+      76707,
+      83229,
+      73998,
+      77083,
+      78343,
+      81537,
+      74994,
+      82399,
+      87391,
+      90588,
+      90831
+    ],
+    reportData: [9932,
+      11412,
+      13571,
+      13626,
+      13767,
+      14671,
+      14360,
+      13561,
+      14403,
+      15551,
+      15803,
+      14807
+    ],
+    adviceData: [36228,
+      48940,
+      50356,
+      41581,
+      42984,
+      42752,
+      44721,
+      39139,
+      45565,
+      50532,
+      51340,
+      51210
+    ],
+    resortData: [19712,
+      16185,
+      19083,
+      18588,
+      20096,
+      20684,
+      22228,
+      22039,
+      22141,
+      20950,
+      23132,
+      24389,
+
+    ],
+  })
+  setTimeout(() => {
+    setOption(data);
+  }, 100);
+}
+const setOption = async (data:any) => {
+  option.value = {
+    title: {
+      text: "2023年群众反应问题每月变化趋势图",
+      left:'center',
+      top:'10',
+      textStyle: {
+        fontSize:24,
+      },
+    },
+    legend: {
+      data: ["反应总量", "投诉量", "咨询量", "求助量"],
+      textStyle: {
+        color: "#333",
+        fontSize: 16,
+      },
+      top: "50px",
+    },
+    grid: {
+      //布局
+      show: false,
+      left: "10px",
+      right: "40px",
+      bottom: "40px",
+      top: "100px",
+      containLabel: true,
+      borderColor: "#1F63A3",
+    },
+    xAxis: {
+      type: "category",
+      data: data.xdata,
+      boundaryGap: true, // 不留白,从原点开始
+      splitLine: {
+        show: false,
+        lineStyle: {
+          color: "rgba(31,99,163,.5)",
+        },
+      },
+      axisLine: {
+        // show:false,
+        lineStyle: {
+          color: "rgba(31,99,163,.5)",
+        },
+      },
+      axisLabel: {
+        color: "#333",
+        fontWeight: "500",
+        fontSize: 16,
+      },
+    },
+    yAxis: {
+      type: "value",
+      splitLine: {
+        show: true,
+        lineStyle: {
+          color: "rgba(31,99,163,.5)",
+        },
+      },
+      axisLine: {
+        show:true,
+        symbol: ['none', 'arrow'],
+        lineStyle: {
+          color: "rgba(31,99,163,.5)",
+        },
+      },
+      axisLabel: {
+        color: "#333",
+        fontSize: 16,
+        fontWeight: "500",
+      },
+    },
+    tooltip: {
+      trigger: "axis",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+    },
+    series: [
+      {
+        data: data.total,
+        type: "line",
+        name: "反应总量",
+        symbol: "circle",
+        symbolSize: 14,
+        label: {
+
+        },
+      },
+      {
+        data: data.reportData,
+        type: "line",
+        name: "投诉量",
+        symbol: "rect",
+        symbolSize: 14,
+        label: {
+
+        },
+      },
+      {
+        data: data.adviceData,
+        type: "line",
+        name: "咨询量",
+        symbol: "triangle",
+        symbolSize: 14,
+      },
+        {
+        data: data.resortData,
+        type: "line",
+        name: "求助量",
+        symbol: "pin",
+          symbolSize: 14,
+      },
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>

+ 108 - 0
src/views/statistics/pie.vue

@@ -0,0 +1,108 @@
+<template>
+  <v-chart class="chart" :option="option" />
+</template>
+<script setup lang="ts">
+import { ref, onMounted } from "vue";
+import Mock from "mockjs";
+
+let colors = ["#0BFC7F", "#A0A0A0", "#F48C02", "#F4023C"];
+const option = ref({});
+const totalNum = ref(0)
+const getData = () => {
+  const  data = [
+    {
+      "name": "安置",
+      "value": Mock.mock('@integer(1, 100)'),
+    },
+    {
+      "name": "拆迁",
+      "value":Mock.mock('@integer(1, 100)')
+    },
+    {
+      "name": "征收",
+      "value": Mock.mock('@integer(1, 100)')
+    },
+    {
+      "name": "赔偿",
+      "value": Mock.mock('@integer(1, 100)')
+    },
+  ]
+  totalNum.value = data.reduce((total, item) => {
+    return total + item.value;
+  }, 0);
+  setOption(data);
+};
+const setOption = (data:any) => {
+  option.value = {
+    title: {
+      left: "center",
+      top:'0',
+      text: '2023土地征收反映问题',
+      textStyle: {
+       fontSize: 32,
+        color: "#333",
+      },
+    },
+    tooltip: {
+      trigger: "item",
+      backgroundColor: "rgba(0,0,0,.6)",
+      borderColor: "rgba(147, 235, 248, .8)",
+      textStyle: {
+        color: "#FFF",
+      },
+    },
+    series: [
+      {
+        name: "",
+        type: "pie",
+        // avoidLabelOverlap: false,
+        itemStyle: {
+          borderRadius: 6,
+          borderColor: "rgba(255,255,255,0)",
+          borderWidth: 2,
+        },
+        color: colors,
+        label: {
+          show: true,
+          formatter: "{b|{b}}  \n {c|{c}件}  {per|{d}%}",
+          //   position: "outside",
+          rich: {
+            b: {
+              color: "inherit",
+              fontSize: 24,
+              lineHeight: 40,
+            },
+            c: {
+              color: "inherit",
+              fontSize: 14,
+            },
+            per: {
+              color: "#31ABE3",
+              fontSize: 14,
+            },
+          },
+        },
+        emphasis: {
+          show: false,
+        },
+        legend: {
+          show: false
+        },
+        tooltip: { show: false },
+        labelLine: {
+          show: true,
+          length: 20, // 第一段线 长度
+          length2: 36, // 第二段线 长度
+          smooth: 0.2,
+          lineStyle: {},
+        },
+        data:data
+      },
+    ],
+  };
+};
+onMounted(() => {
+  getData();
+});
+</script>
+<style scoped lang="scss"></style>