소스 검색

reactor:兼容市州切换;

zhangchong 9 달 전
부모
커밋
0c4e842472

+ 5 - 3
.env.development

@@ -1,8 +1,10 @@
 # 本地环境
 VITE_MODE_NAME=development
-# #socket API
+# socket API
 VITE_API_SOCKET_URL=http://110.188.24.28:50300/hubs/hotline
-# # 基础请求地址
+# 基础请求地址
 VITE_API_URL=http://110.188.24.28:50300
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
-VITE_STORAGE_NAME=hotlineBS
+VITE_STORAGE_NAME=dev
+# 当前地州市
+VITE_CURRENT_CITY=zigong

+ 3 - 1
.env.production

@@ -5,4 +5,6 @@ VITE_API_SOCKET_URL=http://110.188.24.28:50100/hubs/hotline
 # # 基础请求地址
 VITE_API_URL=http://110.188.24.28:50100
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
-VITE_STORAGE_NAME=hotlineBS
+VITE_STORAGE_NAME=test
+# 当前地州市
+VITE_CURRENT_CITY=yibin

+ 3 - 1
.env.yibin

@@ -5,4 +5,6 @@ VITE_API_SOCKET_URL=http://218.6.151.146:50100/hubs/hotline
 # # 基础请求地址
 VITE_API_URL=http://218.6.151.146:50102
 # 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
-VITE_STORAGE_NAME=hotlineBS
+VITE_STORAGE_NAME=yibin
+# 当前地州市
+VITE_CURRENT_CITY=yibin

+ 10 - 0
.env.zigong

@@ -0,0 +1,10 @@
+# 自贡环境
+VITE_MODE_NAME=zigong
+# #socket API
+VITE_API_SOCKET_URL=http://218.6.151.146:50100/hubs/hotline
+# # 基础请求地址
+VITE_API_URL=http://218.6.151.146:50102
+# 防止部署多套系统到同一域名不同目录时,变量共用的问题 设置不同的前缀
+VITE_STORAGE_NAME=zigong
+# 当前地州市
+VITE_CURRENT_CITY=zigong

+ 3 - 0
README.md

@@ -10,4 +10,7 @@ npm run build
 
 # 打包发布宜宾分支
 npm run build:yibin
+
+# 打包发布自贡分支
+npm run build:zigong
 ```

+ 1 - 2
index.html

@@ -2,9 +2,8 @@
 <html lang="en" class="dark">
   <head>
     <meta charset="UTF-8" />
-    <link rel="icon" href="/favicon.ico" />
     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>宜宾市12345政务热线</title>
+    <title>市民热线服务系统</title>
   </head>
   <body>
     <div id="app"></div>

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
public/map-geojson/510300.json


+ 24 - 34
src/App.vue

@@ -1,25 +1,20 @@
 <template>
   <el-config-provider
-      :size="getGlobalComponentSize"
-      :locale="zhCn"
-      :message="messageConfig"
-      :button="buttonConfig"
+    :size="getGlobalComponentSize"
+    :locale="zhCn"
+    :message="messageConfig"
+    :button="buttonConfig"
   >
-    <el-watermark class="h100" :font="config.font" :content="config.content"
-                  :z-index="config.zIndex"
-                  :rotate="config.rotate"
-                  :gap="config.gap"
-                  :offset="config.offset">
-      <RouterView/>
-    </el-watermark>
+    <RouterView />
   </el-config-provider>
 </template>
 <script setup lang="ts">
-import {computed, reactive, watch} 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, useRoute} from "vue-router";
-import {useTitle} from "@/utils/tools";
+import { RouterView, useRoute } from "vue-router";
+import { getImageUrl, useTitle } from "@/utils/tools";
+import { useFavicon } from "@vueuse/core";
 //  signalR 初始化signalr
 signalR.init();
 signalR.joinGroup("BigScreen-DataShow"); //index
@@ -28,7 +23,7 @@ signalR.joinGroup("BigData-Screen"); // home
 signalR.joinGroup("BigData-Enforcement"); // judicial
 // 获取全局组件大小
 const getGlobalComponentSize = computed(() => {
-  return 'default';
+  return "default";
 });
 // 可同时显示的消息最大数量
 const messageConfig = reactive<any>({
@@ -38,27 +33,22 @@ const messageConfig = reactive<any>({
 const buttonConfig = reactive<any>({
   autoInsertSpace: false,
 });
-// 水印配置
-const config = reactive({
-  content: [''],
-  font: {
-    fontSize: 16,
-    color: 'rgba(0,0,0,.15)',
-  },
-  zIndex: 999999,
-  rotate: -22,
-  gap: [100, 100] as [number, number],
-  offset: [] as unknown as [number, number],
-})
+// 动态修改icon
+const icon = useFavicon();
+const currentCity = computed(() => {
+  return import.meta.env.VITE_CURRENT_CITY;
+});
+icon.value = getImageUrl(`${currentCity.value}/favicon.ico`); // 更改当前左上角角标
+console.log("当前城市", currentCity.value, icon.value);
 const route = useRoute();
 // 监听路由的变化,设置网站标题
 watch(
-    () => route.path,
-    () => {
-      useTitle();
-    },
-    {
-      deep: true,
-    }
+  () => route.path,
+  () => {
+    useTitle();
+  },
+  {
+    deep: true,
+  }
 );
 </script>

+ 0 - 0
public/favicon.ico → src/assets/img/yibin/favicon.ico


BIN
src/assets/img/zigong/you.png


+ 57 - 56
src/router/index.ts

@@ -1,68 +1,69 @@
-import {createRouter, createWebHistory} from 'vue-router'
-import type {RouteRecordRaw} from "vue-router"
+import { createRouter, createWebHistory } from "vue-router";
+import type { RouteRecordRaw } from "vue-router";
+import { getCurrentCityName } from "@/utils/constants";
 
 const routes: Array<RouteRecordRaw> = [
-    {
-        path: '/',
-        redirect: '/home',
+  {
+    path: "/",
+    redirect: "/home",
+  },
+  {
+    path: "/home",
+    name: "home",
+    component: () => import("@/views/home/index.vue"),
+    meta: {
+      title: "市民热线服务系统",
     },
-    {
-        path: '/home',
-        name: 'home',
-        component: () => import('@/views/home/index.vue'),
-        meta: {
-            title: '宜宾市12345政务服务便民热线',
-        }
+  },
+  {
+    path: "/home",
+    name: "home",
+    component: () => import("@/views/home/index.vue"),
+    meta: {
+      title: `${getCurrentCityName()}12345政务服务便民热线`,
     },
-    {
-        path: '/home',
-        name: 'home',
-        component: () => import('@/views/home/index.vue'),
-        meta: {
-            title: '宜宾市12345政务服务便民热线',
-        }
+  },
+  {
+    path: "/seats",
+    name: "seats",
+    component: () => import("@/views/seats/index.vue"),
+    meta: {
+      title: `${getCurrentCityName()}12345坐席监控中心`,
     },
-    {
-        path: '/seats',
-        name: 'seats',
-        component: () => import('@/views/seats/index.vue'),
-        meta: {
-            title: '宜宾市12345坐席监控中心',
-        }
+  },
+  {
+    path: "/judicial",
+    name: "judicial",
+    component: () => import("@/views/judicial/index.vue"),
+    meta: {
+      title: `${getCurrentCityName()}司法行政执法监督子系统`,
     },
-    {
-        path: '/judicial',
-        name: 'judicial',
-        component: () => import('@/views/judicial/index.vue'),
-        meta: {
-            title: '宜宾市司法行政执法监督子系统',
-        }
+  },
+  {
+    path: "/index",
+    name: "index",
+    component: () => import("@/views/index/index.vue"),
+    meta: {
+      title: `${getCurrentCityName()}12345数据大屏`,
     },
-    {
-        path: '/index',
-        name: 'index',
-        component: () => import('@/views/index/index.vue'),
-        meta: {
-            title: '宜宾市12345数据大屏',
-        }
+  },
+  {
+    path: "/:pathMatch(.*)",
+    name: "notFound",
+    component: () => import("@/views/error/404.vue"),
+    meta: {
+      title: "404",
+      isHide: true,
     },
-    {
-        path: '/:pathMatch(.*)',
-        name: 'notFound',
-        component: () => import('@/views/error/404.vue'),
-        meta: {
-            title: '404',
-            isHide: true,
-        },
-    },
-]
+  },
+];
 const router = createRouter({
-    history: createWebHistory(),
-    routes,
-})
+  history: createWebHistory(),
+  routes,
+});
 
 router.beforeEach((to, from, next) => {
-    next();
-})
+  next();
+});
 
-export default router
+export default router;

+ 91 - 68
src/utils/constants.ts

@@ -1,75 +1,98 @@
 export const loadingOptions = {
-    text: '加载中...',
-    color: '#c23531',
-    textColor: '#fff',
-    maskColor: 'rgba(0, 0, 0, 0.2)',
-    spinnerRadius: 10,
-    fontSize: 14,
-}
+  text: "加载中...",
+  color: "#c23531",
+  textColor: "#fff",
+  maskColor: "rgba(0, 0, 0, 0.2)",
+  spinnerRadius: 10,
+  fontSize: 14,
+};
 export const shortcuts = [
-    {
-        text: '近一周',
-        value: () => {
-            const end = new Date()
-            const start = new Date()
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
-            return [start, end]
-        },
+  {
+    text: "近一周",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+      return [start, end];
     },
-    {
-        text: '近一个月',
-        value: () => {
-            const end = new Date()
-            const start = new Date()
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
-            return [start, end]
-        },
-    }, {
-        text: '上季度',
-        value: () => {
-            let oDate = new Date();
-            let thisYear = oDate.getFullYear();
-            let thisMonth = oDate.getMonth() + 1;
-            let n = Math.ceil(thisMonth / 3); // 季度
-            let Month = n * 3 - 1;
-            let start = new Date(thisYear, Month - 2, 1);
-            let end = new Date();
-            return [start, end];
-        },
+  },
+  {
+    text: "近一个月",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+      return [start, end];
     },
-    {
-        text: '本季度',
-        value: () => {
-            const end = new Date();
-            const start = new Date();
-            start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
-            return [start, end];
-        },
+  },
+  {
+    text: "上季度",
+    value: () => {
+      let oDate = new Date();
+      let thisYear = oDate.getFullYear();
+      let thisMonth = oDate.getMonth() + 1;
+      let n = Math.ceil(thisMonth / 3); // 季度
+      let Month = n * 3 - 1;
+      let start = new Date(thisYear, Month - 2, 1);
+      let end = new Date();
+      return [start, end];
     },
-    {
-        text: '去年',
-        value: () => {
-            let oDate = new Date();
-            let prevYear = oDate.getFullYear() - 1;
-            const end = new Date();
-            const start = new Date();
-            start.setFullYear(prevYear);
-            start.setMonth(0);
-            start.setDate(1);
-            end.setFullYear(prevYear);
-            end.setMonth(11);
-            end.setDate(31);
-            return [start, end];
-        },
+  },
+  {
+    text: "本季度",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+      return [start, end];
     },
-    {
-        text: '今年',
-        value: () => {
-            const end = new Date();
-            const start = new Date();
-            start.setMonth(0);
-            start.setDate(1);
-            return [start, end];
-        },
+  },
+  {
+    text: "去年",
+    value: () => {
+      let oDate = new Date();
+      let prevYear = oDate.getFullYear() - 1;
+      const end = new Date();
+      const start = new Date();
+      start.setFullYear(prevYear);
+      start.setMonth(0);
+      start.setDate(1);
+      end.setFullYear(prevYear);
+      end.setMonth(11);
+      end.setDate(31);
+      return [start, end];
     },
-]
+  },
+  {
+    text: "今年",
+    value: () => {
+      const end = new Date();
+      const start = new Date();
+      start.setMonth(0);
+      start.setDate(1);
+      return [start, end];
+    },
+  },
+];
+// 获取当前市州中文
+export const getCurrentCityName = () => {
+  switch (import.meta.env.VITE_CURRENT_CITY) {
+    case "yibin":
+      return "宜宾市";
+    case "zigong":
+      return "自贡市";
+    default:
+      return "宜宾市";
+  }
+};
+// 获取当前市州地区编码
+export const getCurrentCityCode = () => {
+  switch (import.meta.env.VITE_CURRENT_CITY) {
+    case "yibin":
+      return "511500";
+    case "zigong":
+      return "510300";
+    default:
+      return "511500";
+  }
+};

+ 65 - 100
src/utils/tools.ts

@@ -1,5 +1,5 @@
 import axios from "axios";
-import { defineAsyncComponent, nextTick } from 'vue';
+import { defineAsyncComponent, nextTick } from "vue";
 import router from "@/router";
 /**
  * @description 防抖
@@ -8,15 +8,15 @@ import router from "@/router";
  * @param thisArg 功能函数内this的对象
  */
 export function debounce(func: Function, delay: number, thisArg?: any) {
-	let timer: number;
-	return function (...args: any[]) {
-		if (timer) {
-			window.clearTimeout(timer);
-		}
-		timer = window.setTimeout(function () {
-			func.apply(thisArg, args);
-		}, delay);
-	};
+  let timer: number;
+  return function (...args: any[]) {
+    if (timer) {
+      window.clearTimeout(timer);
+    }
+    timer = window.setTimeout(function () {
+      func.apply(thisArg, args);
+    }, delay);
+  };
 }
 /**
  * @description 节流(原理同上)
@@ -25,14 +25,14 @@ export function debounce(func: Function, delay: number, thisArg?: any) {
  * @param thisArg 功能函数内this的对象
  */
 export function throttle(func: Function, delay: number, thisArg?: any) {
-	let timeStamp: number;
-	return function (...args: any[]) {
-		const nowTimeStamp = Date.now();
-		if (!timeStamp || nowTimeStamp - timeStamp >= delay) {
-			func.apply(thisArg, args);
-			timeStamp = nowTimeStamp;
-		}
-	};
+  let timeStamp: number;
+  return function (...args: any[]) {
+    const nowTimeStamp = Date.now();
+    if (!timeStamp || nowTimeStamp - timeStamp >= delay) {
+      func.apply(thisArg, args);
+      timeStamp = nowTimeStamp;
+    }
+  };
 }
 /**
  *  @description vite引入图片
@@ -40,42 +40,30 @@ export function throttle(func: Function, delay: number, thisArg?: any) {
  * @returns {string} 返回处理后的文件地址
  */
 export function getImageUrl(name: string) {
-	return new URL(`../assets/img/${name}`, import.meta.url).href;
-}
-/**
- * 手机号脱敏处理
- * @param  { string} phoneNumber  手机号码
- * @returns {string} 返回处理后的手机号码
- */
-export function desensitizationPhone(phoneNumber: string) {
-	if (!phoneNumber) return '';
-	return phoneNumber.replace(/^(.{3})(\d+)(.{4})$/, '$1****$2');
-}
-/**
- * 姓名脱敏处理
- * @param {string} name  姓名
- * @returns {string} 返回处理后的姓名
- */
-export function desensitizationName(name: string) {
-	if (!name) return '';
-	const len = name.length;
-	return len <= 3
-		? '*' + name.substring(1, len)
-		: len > 3 && len <= 6
-		? '**' + name.substring(2, len)
-		: len > 6
-		? name.substring(0, 2) + '****' + name.substring(6, len)
-		: '';
+  return new URL(`../assets/img/${name}`, import.meta.url).href;
 }
 /**
  * @description 生成guid
  * @returns {string} 返回guid
  */
 export function guid(): string {
-	const S4 = (): string => {
-		return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
-	};
-	return S4() + S4() + '-' + S4() + '-' + S4() + '-' + S4() + '-' + S4() + S4() + S4();
+  const S4 = (): string => {
+    return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+  };
+  return (
+    S4() +
+    S4() +
+    "-" +
+    S4() +
+    "-" +
+    S4() +
+    "-" +
+    S4() +
+    "-" +
+    S4() +
+    S4() +
+    S4()
+  );
 }
 /**
  * 根据id排除自己(树形结构选择 修改时用)
@@ -84,43 +72,14 @@ export function guid(): string {
  * @returns {arr} 返回排除后的数组
  */
 export function excludeSelfById(arr: Array<any>, id: string) {
-	if (!arr) return [];
-	return arr.filter((v: any) => {
-		if (v.id === id) return false;
-		if (v.children && v.children.length) {
-			v.children = excludeSelfById(v.children, id);
-		}
-		return true;
-	});
-}
-/**
- * @description 下载文件
- * @param src 文件地址
- * @param filename 文件名
- */
-export function downloadFile(src: string, filename: string) {
-	if(!src) {
-		return
-	}
-	let fileName: string = filename || '' // 文件名
-	axios({
-		method: 'get',
-		url: src,
-		responseType: 'blob',
-		headers: { 'content-type': 'audio/mpeg' },
-	}).then((res: any) => {
-		let blob:Blob = new Blob([res.data], { type: res.data.type }) // 创建blob 设置blob文件类型 data 设置为后端返回的文件(例如mp3,jpeg) type:这里设置后端返回的类型 为 mp3
-		let down: HTMLAnchorElement = document.createElement('a') // 创建A标签
-		let href:string = window.URL.createObjectURL(blob) // 创建下载的链接
-		down.href = href // 下载地址
-		down.download = fileName // 下载文件名
-		document.body.appendChild(down)
-		down.click() // 模拟点击A标签
-		document.body.removeChild(down) // 下载完成移除元素
-		window.URL.revokeObjectURL(href) // 释放blob对象
-	}).catch(function (error) {
-		console.log(error)
-	})
+  if (!arr) return [];
+  return arr.filter((v: any) => {
+    if (v.id === id) return false;
+    if (v.children && v.children.length) {
+      v.children = excludeSelfById(v.children, id);
+    }
+    return true;
+  });
 }
 /**
  * @description 数组排序
@@ -129,14 +88,20 @@ export function downloadFile(src: string, filename: string) {
  * @param type 排序类型 默认降序 descending  升序 ascending
  * @returns {arr} 返回排序后的数组
  */
-export function arraySortByKey(arr: Array<any>, key: string, type= 'descending') {
-	return arr.sort((a: any, b: any) => {
-		if (type === 'descending') { // 降序
-			return b[key] - a[key];
-		} else { // 升序
-			return a[key] - b[key];
-		}
-	});
+export function arraySortByKey(
+  arr: Array<any>,
+  key: string,
+  type = "descending"
+) {
+  return arr.sort((a: any, b: any) => {
+    if (type === "descending") {
+      // 降序
+      return b[key] - a[key];
+    } else {
+      // 升序
+      return a[key] - b[key];
+    }
+  });
 }
 
 /**
@@ -144,10 +109,10 @@ export function arraySortByKey(arr: Array<any>, key: string, type= 'descending')
  * @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(() => {});
-}
+  nextTick(() => {
+    let webTitle: string;
+    const { meta } = router.currentRoute.value;
+    webTitle = <any>meta.title || "市民热线服务系统";
+    document.title = `${webTitle}`;
+  }).then(() => {});
+}

+ 40 - 34
src/views/home/center-map.vue

@@ -1,41 +1,48 @@
 <template>
   <div class="center-map">
     <v-chart
-        class="chart"
-        :option="option"
-        ref="centerMapRef"
-        :loading="loading"
-        :loading-options="loadingOptions"
+      class="chart"
+      :option="option"
+      ref="centerMapRef"
+      :loading="loading"
+      :loading-options="loadingOptions"
     />
   </div>
 </template>
 <script setup lang="ts">
-import {ref, onMounted, watch, nextTick} from "vue";
-import {registerMap, getMap} from "echarts/core";
-import {optionHandle} from "./center.map";
-import {loopShowTooltip} from "@/utils/tooltip-auto-show";
+import { ref, onMounted, watch, nextTick } from "vue";
+import { registerMap, getMap } from "echarts/core";
+import { optionHandle } from "./center.map";
+import { loopShowTooltip } from "@/utils/tooltip-auto-show";
 import axios from "axios";
-import {areaDetail} from "api/home";
+import { areaDetail } from "api/home";
 import dayjs from "dayjs";
-import {loadingOptions} from "@/utils/constants";
+import { getCurrentCityCode, loadingOptions } from "@/utils/constants";
 
 const props = defineProps({
   dateArray: {
     type: Array,
-    default: () => []
-  }
-})
+    default: () => [],
+  },
+});
 const date = ref([]);
-watch(() => props.dateArray, (val: any) => {
-  date.value = val;
-}, {immediate: true})
-
-watch(() => props.dateArray, (val: any) => {
-  getData();
-})
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    date.value = val;
+  },
+  { immediate: true }
+);
+
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    getData();
+  }
+);
 const loading = ref(false);
 const option = ref({});
-const code = ref("511500"); //100000 代表中国 其他地市是行政编码
+const code = ref(getCurrentCityCode()); //100000 代表中国 其他地市是行政编码
 const dataSetHandle = async (regionCode: string, list: object[]) => {
   code.value = regionCode;
   const geoJson: any = await getGeoJson(regionCode);
@@ -43,7 +50,7 @@ const dataSetHandle = async (regionCode: string, list: object[]) => {
   //获取当前地图每块行政区中心点
   geoJson.features.forEach((element: any) => {
     cityCenter[element.properties.name] =
-        element.properties.centroid || element.properties.center;
+      element.properties.centroid || element.properties.center;
   });
   option.value = optionHandle(regionCode, list);
 };
@@ -55,9 +62,9 @@ const getGeoJson = (regionCode: string) => {
       mapJson = mapJson.geoJSON;
       resolve(mapJson);
     } else {
-      mapJson = await axios.get(`./map-geojson/${regionCode}.json`).then(
-          (data) => data.data
-      );
+      mapJson = await axios
+        .get(`./map-geojson/${regionCode}.json`)
+        .then((data) => data.data);
       code.value = regionCode;
       registerMap(regionCode, {
         geoJSON: mapJson as any,
@@ -71,16 +78,16 @@ const getGeoJson = (regionCode: string) => {
 const getData = async () => {
   loading.value = true;
   try {
-    const {result} = await areaDetail({
-      StartTime: dayjs(date.value[0]).format('YYYY-MM-DD'),
-      EndTime: dayjs(date.value[1]).format('YYYY-MM-DD')
+    const { result } = await areaDetail({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
     });
     const regionData = result.map((item: any) => {
       return {
         name: item.areaName,
-        ...item
-      }
-    })
+        ...item,
+      };
+    });
     await dataSetHandle(code.value, regionData);
     loading.value = false;
   } catch (e) {
@@ -130,7 +137,7 @@ onMounted(async () => {
   .custom-tooltip-style {
     width: 355px;
     height: 219px;
-    background-image: url('@/assets/img/home/tool_tip_bg.png');
+    background-image: url("@/assets/img/home/tool_tip_bg.png");
     background-size: 100% 100%;
     color: #fff;
     padding: 30px;
@@ -212,7 +219,6 @@ onMounted(async () => {
           }
         }
       }
-
     }
   }
 }

+ 22 - 16
src/views/home/header.vue

@@ -2,15 +2,15 @@
   <div class="d-flex jc-center title_wrap">
     <div class="time-picker">
       <el-date-picker
-          v-model="timeValue"
-          type="daterange"
-          unlink-panels
-          range-separator="至"
-          start-placeholder="开始时间"
-          end-placeholder="结束时间"
-          :shortcuts="shortcuts"
-          :clearable="false"
-          @change="changeDate"
+        v-model="timeValue"
+        type="daterange"
+        unlink-panels
+        range-separator="至"
+        start-placeholder="开始时间"
+        end-placeholder="结束时间"
+        :shortcuts="shortcuts"
+        :clearable="false"
+        @change="changeDate"
       />
     </div>
     <div class="d-flex jc-center">
@@ -18,19 +18,17 @@
         <span class="title-text">{{ title }}</span>
       </div>
     </div>
-    <div class="timers">
-      {{ dateData.dateDay }} {{ dateData.dateWeek }}
-    </div>
+    <div class="timers">{{ dateData.dateDay }} {{ dateData.dateWeek }}</div>
   </div>
 </template>
 <script setup lang="ts">
-import {reactive, ref} from "vue";
+import { reactive, ref } from "vue";
 import dayjs from "dayjs";
-import {shortcuts} from '@/utils/constants';
+import { getCurrentCityName, shortcuts } from "@/utils/constants";
 
 const emit = defineEmits(["changeDate"]);
 
-const title = ref("宜宾市12345政务服务便民热线");
+const title = ref(`${getCurrentCityName()}12345政务服务便民热线`);
 const timeValue = ref<any>([
   dayjs().subtract(1, "month").toDate(),
   dayjs().toDate(),
@@ -46,7 +44,15 @@ const dateData = reactive<any>({
   timing: null as any,
 });
 
-const weekday = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
+const weekday = [
+  "星期天",
+  "星期一",
+  "星期二",
+  "星期三",
+  "星期四",
+  "星期五",
+  "星期六",
+];
 const timeFn = () => {
   dateData.timing = setInterval(() => {
     dateData.dateDay = dayjs().format("YYYY-MM-DD HH:mm:ss");

+ 199 - 162
src/views/home/left-bottom.vue

@@ -2,26 +2,36 @@
   <div class="left_bottom">
     <div class="left_bottom-title flex">
       <div class="flex items-center">
-        <img src="@/assets/img/home/title_arrow.png" alt="">
+        <img src="@/assets/img/home/title_arrow.png" alt="" />
         预警热点
       </div>
       <el-dropdown @command="handleCommand">
         <el-button link class="link-button">
           {{ areaText }}
           <el-icon class="el-icon--right">
-            <arrow-down/>
+            <arrow-down />
           </el-icon>
         </el-button>
         <template #dropdown>
           <el-dropdown-menu>
-            <el-dropdown-item v-for="item in areaList" :key="item.id" :command="item">{{ item.areaName }}</el-dropdown-item>
+            <el-dropdown-item
+              v-for="item in areaList"
+              :key="item.id"
+              :command="item"
+              >{{ item.areaName }}</el-dropdown-item
+            >
           </el-dropdown-menu>
         </template>
       </el-dropdown>
     </div>
     <div class="left_bottom-content">
       <template v-if="list.length">
-        <v-chart class="chart" :option="option" :loading="loading" :loading-options="loadingOptions"/>
+        <v-chart
+          class="chart"
+          :option="option"
+          :loading="loading"
+          :loading-options="loadingOptions"
+        />
       </template>
       <template v-else>
         <EmptyCom></EmptyCom>
@@ -30,41 +40,52 @@
   </div>
 </template>
 <script setup lang="ts">
-import {onMounted, ref, watch} from "vue";
-import {ArrowDown} from '@element-plus/icons-vue'
-import {getArea, hotSpot} from "@/api/home";
+import { onMounted, ref, watch } from "vue";
+import { ArrowDown } from "@element-plus/icons-vue";
+import { getArea, hotSpot } from "@/api/home";
 import dayjs from "dayjs";
 import EmptyCom from "@/components/empty-com";
-import {loadingOptions} from "@/utils/constants";
-import {graphic} from "echarts/core";
-import {arraySortByKey} from "@/utils/tools";
+import {
+  getCurrentCityCode,
+  getCurrentCityName,
+  loadingOptions,
+} from "@/utils/constants";
+import { graphic } from "echarts/core";
+import { arraySortByKey } from "@/utils/tools";
 
 const props = defineProps({
   dateArray: {
     type: Array,
-    default: () => []
-  }
-})
+    default: () => [],
+  },
+});
 const date = ref([]);
 const loading = ref(false);
 const option = ref<any>({});
-watch(() => props.dateArray, (val: any) => {
-  date.value = val;
-}, {immediate: true})
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    date.value = val;
+  },
+  { immediate: true }
+);
 
-watch(() => props.dateArray, () => {
-  getData();
-})
-const areaCode = ref('511500');
-const areaText = ref('宜宾市');
+watch(
+  () => props.dateArray,
+  () => {
+    getData();
+  }
+);
+const areaCode = ref(getCurrentCityCode());
+const areaText = ref(getCurrentCityName());
 const list = ref<any>([]);
 const getData = async () => {
   loading.value = true;
   try {
-    const {result} = await hotSpot({
-      StartTime: dayjs(date.value[0]).format('YYYY-MM-DD'),
-      EndTime: dayjs(date.value[1]).format('YYYY-MM-DD'),
-      AreaCode: areaCode.value
+    const { result } = await hotSpot({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
+      AreaCode: areaCode.value,
     });
     list.value = result;
     /*
@@ -76,67 +97,78 @@ const getData = async () => {
         })
     */
 
-    const category = arraySortByKey(result, 'sumCount',);
-    const charts = { // 按顺序排列从大到小
+    const category = arraySortByKey(result, "sumCount");
+    const charts = {
+      // 按顺序排列从大到小
       cityList: category.map((item: any) => item.hotspotName),
-      cityData: category.map((item: any) => item.sumCount)
+      cityData: category.map((item: any) => item.sumCount),
     };
     const top10CityList = charts.cityList;
 
     const top10CityData = charts.cityData;
-    const color = ['#ff9500', '#02d8f9', '#027fff'];
-    const color1 = ['#ffb349', '#70e9fc', '#4aa4ff'];
+    const color = ["#ff9500", "#02d8f9", "#027fff"];
+    const color1 = ["#ffb349", "#70e9fc", "#4aa4ff"];
 
-    let lineY = []
-    let lineT = []
+    let lineY = [];
+    let lineT = [];
     for (let i = 0; i < charts.cityList.length; i++) {
       let x = i;
       if (x > 1) {
-        x = 2
+        x = 2;
       }
       const data = {
         name: charts.cityList[i],
         color: color[x],
         value: top10CityData[i],
-        barGap: '-100%',
+        barGap: "-100%",
         itemStyle: {
           show: true,
-          color: new graphic.LinearGradient(0, 0, 1, 0, [{
-            offset: 0,
-            color: color[x]
-          }, {
-            offset: 1,
-            color: color1[x]
-          }], false),
+          color: new graphic.LinearGradient(
+            0,
+            0,
+            1,
+            0,
+            [
+              {
+                offset: 0,
+                color: color[x],
+              },
+              {
+                offset: 1,
+                color: color1[x],
+              },
+            ],
+            false
+          ),
           borderRadius: 10,
         },
         emphasis: {
           itemStyle: {
             shadowBlur: 15,
-            shadowColor: 'rgba(0, 0, 0, 0.1)'
-          }
-        }
+            shadowColor: "rgba(0, 0, 0, 0.1)",
+          },
+        },
       };
       const data1 = {
         value: top10CityData[0],
         itemStyle: {
-          color: '#001235',
-          borderRadius: 10
-        }
+          color: "#001235",
+          borderRadius: 10,
+        },
       };
-      lineY.push(data)
-      lineT.push(data1)
+      lineY.push(data);
+      lineT.push(data1);
     }
 
     option.value = {
-      backgroundColor: 'rgba(0, 0, 0, 0)',
+      backgroundColor: "rgba(0, 0, 0, 0)",
       title: {
-        show: false
+        show: false,
       },
       tooltip: {
-        trigger: 'axis',
+        trigger: "axis",
         axisPointer: {
-          type: 'shadow'
+          type: "shadow",
         },
         formatter: function (params: any) {
           let tar;
@@ -145,10 +177,10 @@ const getData = async () => {
           } else {
             tar = params[1];
           }
-          return tar.marker + tar.name + '<br/>' + ' 当前数量: ' + tar.value;
+          return tar.marker + tar.name + "<br/>" + " 当前数量: " + tar.value;
         },
 
-        enterable: true,//滚动条
+        enterable: true, //滚动条
         confine: true,
         extraCssText: "max-width:90%;max-height:83%;overflow:auto;",
         //改变提示框的位置 不超出屏幕显示
@@ -180,146 +212,151 @@ const getData = async () => {
             y = pointY - boxHeight;
           }
           return [x, y];
-        }
+        },
       },
       grid: {
         borderWidth: 0,
-        top: '5%',
-        left: '5%',
-        right: '15%',
-        bottom: '10%'
+        top: "5%",
+        left: "5%",
+        right: "15%",
+        bottom: "10%",
       },
       color: color,
-      yAxis: [{
-        type: 'category',
-        inverse: true,
-        axisTick: {
-          show: false
-        },
-        axisLine: {
-          show: false
-        },
-        axisLabel: {
-          show: false,
-          inside: false
-        },
-        data: top10CityList
-      }, {
-        type: 'category',
-        inverse: true,
-        axisLine: {
-          show: false
-        },
-        axisTick: {
-          show: false
-        },
-        axisLabel: {
-          show: true,
-          inside: false,
-          verticalAlign: 'middle',
-          lineHeight: '40',
-          color: '#fff',
-          fontSize: '14',
-          fontFamily: 'PingFangSC-Regular',
-          formatter: function (val) {
-            return `${val}`
-          }
-        },
-        splitArea: {
-          show: false
+      yAxis: [
+        {
+          type: "category",
+          inverse: true,
+          axisTick: {
+            show: false,
+          },
+          axisLine: {
+            show: false,
+          },
+          axisLabel: {
+            show: false,
+            inside: false,
+          },
+          data: top10CityList,
         },
-        splitLine: {
-          show: false
+        {
+          type: "category",
+          inverse: true,
+          axisLine: {
+            show: false,
+          },
+          axisTick: {
+            show: false,
+          },
+          axisLabel: {
+            show: true,
+            inside: false,
+            verticalAlign: "middle",
+            lineHeight: "40",
+            color: "#fff",
+            fontSize: "14",
+            fontFamily: "PingFangSC-Regular",
+            formatter: function (val) {
+              return `${val}`;
+            },
+          },
+          splitArea: {
+            show: false,
+          },
+          splitLine: {
+            show: false,
+          },
+          data: top10CityData,
         },
-        data: top10CityData
-      }],
+      ],
       xAxis: {
-        type: 'value',
+        type: "value",
         axisTick: {
-          show: false
+          show: false,
         },
         axisLine: {
-          show: false
+          show: false,
         },
         splitLine: {
-          show: false
+          show: false,
         },
         axisLabel: {
-          show: false
-        }
+          show: false,
+        },
       },
-      series: [{
-        type: 'bar',
-        zLevel: 2,
-        barWidth: '10px',
-        data: lineY,
-        label: {
-          color: '#b3ccf8',
-          show: true,
-          position: [0, '-18px'],
-          fontSize: 16,
-          width: 40,
-          formatter: function (a) {
-            let num = ''
-            let str = ''
-            if (a.dataIndex + 1 < 10) {
-              num = '0' + (a.dataIndex + 1);
-            } else {
-              num = (a.dataIndex + 1);
-            }
-            let names = '';
-            if (a.name.length > 25) {
-              names = a.name.slice(0, 25) + '...'
-            } else {
-              names = a.name;
-            }
-            if (a.dataIndex === 0) {
-              str = `{color1|${num}} {color4|${names}}`
-            } else if (a.dataIndex === 1) {
-              str = `{color2|${num}} {color4|${names}}`
-            } else {
-              str = `{color3|${num}} {color4|${names}}`
-            }
-            return str;
-          },
-          rich: {
-            color1: {
-              color: '#ff9500',
+      series: [
+        {
+          type: "bar",
+          zLevel: 2,
+          barWidth: "10px",
+          data: lineY,
+          label: {
+            color: "#b3ccf8",
+            show: true,
+            position: [0, "-18px"],
+            fontSize: 16,
+            width: 40,
+            formatter: function (a) {
+              let num = "";
+              let str = "";
+              if (a.dataIndex + 1 < 10) {
+                num = "0" + (a.dataIndex + 1);
+              } else {
+                num = a.dataIndex + 1;
+              }
+              let names = "";
+              if (a.name.length > 25) {
+                names = a.name.slice(0, 25) + "...";
+              } else {
+                names = a.name;
+              }
+              if (a.dataIndex === 0) {
+                str = `{color1|${num}} {color4|${names}}`;
+              } else if (a.dataIndex === 1) {
+                str = `{color2|${num}} {color4|${names}}`;
+              } else {
+                str = `{color3|${num}} {color4|${names}}`;
+              }
+              return str;
             },
-            color2: {
-              color: '#02d8f9',
+            rich: {
+              color1: {
+                color: "#ff9500",
+              },
+              color2: {
+                color: "#02d8f9",
+              },
+              color3: {
+                color: "#027fff",
+              },
+              color4: {
+                color: "#e5eaff",
+              },
             },
-            color3: {
-              color: '#027fff',
-            },
-            color4: {
-              color: '#e5eaff'
-            }
-          }
-        }
-      }],
-    }
+          },
+        },
+      ],
+    };
     loading.value = false;
   } catch (e) {
     console.log(e);
     loading.value = false;
   }
-}
+};
 // 选择省市区
 const handleCommand = (command: any) => {
   areaCode.value = command.id;
   areaText.value = command.areaName;
   getData();
-}
+};
 const areaList = ref([]);
 const getAreaData = async () => {
   try {
     const res = await getArea();
-    areaList.value = res.result ?? []
+    areaList.value = res.result ?? [];
   } catch (e) {
     console.log(e);
   }
-}
+};
 onMounted(() => {
   getData();
   getAreaData();
@@ -343,8 +380,8 @@ onMounted(() => {
 
 :deep(.link-button) {
   cursor: pointer;
-  color: #7DBDEC;
+  color: #7dbdec;
   display: flex;
   align-items: center;
 }
-</style>
+</style>

+ 8 - 7
src/views/index/center-map.vue

@@ -23,10 +23,11 @@ import { registerMap, getMap } from "echarts/core";
 import { optionHandle, regionCodes } from "./center.map";
 import BorderBox13 from "@/components/datav/border-box-13";
 import type { MapdataType } from "./center.map";
-import {loopShowTooltip } from "@/utils/tooltip-auto-show";
+import { loopShowTooltip } from "@/utils/tooltip-auto-show";
 import axios from "axios";
+import { getCurrentCityCode } from "@/utils/constants";
 const option = ref({});
-const code = ref("511500"); //100000 代表中国 其他地市是行政编码
+const code = ref(getCurrentCityCode()); //100000 代表中国 其他地市是行政编码
 withDefaults(
   defineProps<{
     // 结束数值
@@ -70,9 +71,9 @@ const getGeojson = (regionCode: string) => {
       mapjson = mapjson.geoJSON;
       resolve(mapjson);
     } else {
-      mapjson = await axios.get(`./map-geojson/${regionCode}.json`).then(
-        (data) => data.data
-      );
+      mapjson = await axios
+        .get(`./map-geojson/${regionCode}.json`)
+        .then((data) => data.data);
       code.value = regionCode;
       registerMap(regionCode, {
         geoJSON: mapjson as any,
@@ -84,7 +85,7 @@ const getGeojson = (regionCode: string) => {
 };
 const tooltipTimer = ref<any>(null);
 const centerMapRef = ref<any>(null);
-const tooltipMap = (myChart,option)=>{
+const tooltipMap = (myChart, option) => {
   tooltipTimer.value && tooltipTimer.value.clearLoop(); // this.tooltipTimer 在data里定义
   tooltipTimer.value = 0;
   // 调用轮播的方法
@@ -99,7 +100,7 @@ const tooltipMap = (myChart,option)=>{
   });
 };
 setTimeout(() => {
-  tooltipMap(centerMapRef.value!.chart,option.value);
+  tooltipMap(centerMapRef.value!.chart, option.value);
 }, 1000);
 onMounted(() => {
   getData(code.value);

+ 263 - 263
src/views/index/center.map.ts

@@ -1,283 +1,283 @@
-
-
 import Mock from "mockjs";
 //mapData数据结构
 export interface MapdataType {
-    name: string;
-    value: [number, number, number]; //x,y,value  第一个x 第二个y  第三个value
+  name: string;
+  value: [number, number, number]; //x,y,value  第一个x 第二个y  第三个value
 }
-export const optionHandle = (regionCode: string,
-    list: object[],
-    mapData: MapdataType[]) => {
-    let top = 45;
-    let zoom = ["511500"].includes(regionCode) ? 1.05 : 1;
-    return {
-        backgroundColor: "rgba(0,0,0,0)",
+export const optionHandle = (
+  regionCode: string,
+  list: object[],
+  mapData: MapdataType[]
+) => {
+  let top = 45;
+  let zoom = 1;
+  return {
+    backgroundColor: "rgba(0,0,0,0)",
+    tooltip: {
+      show: false,
+    },
+    legend: {
+      show: false,
+    },
+    visualMap: {
+      seriesIndex: 0,
+      left: 20,
+      bottom: 20,
+      pieces: [
+        { gte: 1000, label: "1000以上" }, // 不指定 max,表示 max 为无限大(Infinity)。
+        { gte: 600, lte: 999, label: "600-999" },
+        { gte: 200, lte: 599, label: "200-599" },
+        { gte: 50, lte: 199, label: "49-199" },
+        { gte: 10, lte: 49, label: "10-49" },
+        { lte: 9, label: "1-9" }, // 不指定 min,表示 min 为无限大(-Infinity)。
+      ],
+      inRange: {
+        // 渐变颜色,从小到大
+        // FFFFFF,EDF7FD,DBF0FA,C9E8F8,B7E1F6,A5D9F3,93D2F1,81CAEF,6FC2EC,5DBBEA,4AB3E8,38ACE5,26A4E3,1C9AD9,1A8DC7,
+        // 1781B5,
+        // 1573A2,136790,105A7E,0E4D6C,0C405A,093348,072636,051A24,020D12
+        color: [
+          // "#EDF7FD",
+          "rgba(237,247,253,.8)",
+          // "#B7E1F6",
+          "rgba(183,225,246,.9)",
+          // "#81CAEF",
+          "rgba(129,202,239,.9)",
+          // "#38ACE5",
+          "rgba(56,172,229,.9)",
+          // "#1781B5",
+          "rgba(23,129,181,.9)",
+          // "#105A7E",
+          "rgba(16,90,126,0.9)",
+        ],
+      },
+      textStyle: {
+        color: "#fff",
+      },
+    },
+    geo: {
+      map: regionCode,
+      roam: false,
+      selectedMode: false, //是否允许选中多个区域
+      zoom: zoom,
+      top: top,
+      // aspectScale: 0.78,
+      show: false,
+    },
+    series: [
+      {
+        name: "MAP",
+        type: "map",
+        map: regionCode,
+        // aspectScale: 0.78,
+        data: list,
+        // data: [1,100],
+        selectedMode: false, //是否允许选中多个区域
+        zoom: zoom,
+        geoIndex: 1,
+        top: top,
         tooltip: {
-            show: false,
-        },
-        legend: {
-            show: false,
-        },
-        visualMap: {
-            seriesIndex: 0,
-            left: 20,
-            bottom: 20,
-            pieces: [
-                { gte: 1000, label: "1000以上" }, // 不指定 max,表示 max 为无限大(Infinity)。
-                { gte: 600, lte: 999, label: "600-999" },
-                { gte: 200, lte: 599, label: "200-599" },
-                { gte: 50, lte: 199, label: "49-199" },
-                { gte: 10, lte: 49, label: "10-49" },
-                { lte: 9, label: "1-9" }, // 不指定 min,表示 min 为无限大(-Infinity)。
-            ],
-            inRange: {
-                // 渐变颜色,从小到大
-                // FFFFFF,EDF7FD,DBF0FA,C9E8F8,B7E1F6,A5D9F3,93D2F1,81CAEF,6FC2EC,5DBBEA,4AB3E8,38ACE5,26A4E3,1C9AD9,1A8DC7,
-                // 1781B5,
-                // 1573A2,136790,105A7E,0E4D6C,0C405A,093348,072636,051A24,020D12
-                color: [
-                    // "#EDF7FD",
-                    "rgba(237,247,253,.8)",
-                    // "#B7E1F6",
-                    "rgba(183,225,246,.9)",
-                    // "#81CAEF",
-                    "rgba(129,202,239,.9)",
-                    // "#38ACE5",
-                    "rgba(56,172,229,.9)",
-                    // "#1781B5",
-                    "rgba(23,129,181,.9)",
-                    // "#105A7E",
-                    "rgba(16,90,126,0.9)"
-                ],
-            },
-            textStyle: {
-                color: "#fff",
-            },
-        },
-        geo: {
-            map: regionCode,
-            roam: false,
-            selectedMode: false, //是否允许选中多个区域
-            zoom: zoom,
-            top: top,
-            // aspectScale: 0.78,
-            show: false,
-        },
-        series: [
-            {
-                name: "MAP",
-                type: "map",
-                map: regionCode,
-                // aspectScale: 0.78,
-                data: list,
-                // data: [1,100],
-                selectedMode: false, //是否允许选中多个区域
-                zoom: zoom,
-                geoIndex: 1,
-                top: top,
-                tooltip: {
-                    show: true,
-                    position: 'left',
-                    formatter: function (params: any) {
-                        if (params.data) {
-                            // console.log(params); //params是echarts的属性
-                            const res = params.data; //res等于params下的数据
-                            //return回调一个模板字符串,自定义提示框的形状
-                            return `
+          show: true,
+          position: "left",
+          formatter: function (params: any) {
+            if (params.data) {
+              // console.log(params); //params是echarts的属性
+              const res = params.data; //res等于params下的数据
+              //return回调一个模板字符串,自定义提示框的形状
+              return `
                             <div class="chartTooltip">
                                 <p class="dotTooltip">${res.name}</p>
                                 <p class="textTooltip">${res.value}件</p>
                             </div>`;
-                        } else {
-                            return params.name;
-                        }
-                    },
-                    background:'none',
-                    backgroundColor: "transparent",
-                    borderColor: "transparent",
-                    textStyle: {
-                        color: "#FFF",
-                    },
-                    padding:0,
-                },
-                label: {
-                    show: true,
-                    color: "#000",
-                    // position: [-10, 0],
-                    formatter: function (val: any) {
-                        if (val.data !== undefined) {
-                            return val.name.slice(0, 2);
-                        } else {
-                            return "";
-                        }
-                    },
-                    rich: {},
-                },
-                emphasis: {
-                    label: {
-                        show: false,
-                    },
-                    itemStyle: {
-                        // areaColor: "rgba(56,155,183,.7)",
-                        areaColor: {
-                            type: "radial",
-                            x: 0.5,
-                            y: 0.5,
-                            r: 0.8,
-                            colorStops: [
-                                {
-                                    offset: 0,
-                                    color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
-                                },
-                                {
-                                    offset: 1,
-                                    color: "rgba(56,155,183, .8)", // 100% 处的颜色
-                                },
-                            ],
-                            globalCoord: false, // 缺为 false
-                        },
-                        borderWidth: 1,
-                    },
+            } else {
+              return params.name;
+            }
+          },
+          background: "none",
+          backgroundColor: "transparent",
+          borderColor: "transparent",
+          textStyle: {
+            color: "#FFF",
+          },
+          padding: 0,
+        },
+        label: {
+          show: true,
+          color: "#000",
+          // position: [-10, 0],
+          formatter: function (val: any) {
+            if (val.data !== undefined) {
+              return val.name.slice(0, 2);
+            } else {
+              return "";
+            }
+          },
+          rich: {},
+        },
+        emphasis: {
+          label: {
+            show: false,
+          },
+          itemStyle: {
+            // areaColor: "rgba(56,155,183,.7)",
+            areaColor: {
+              type: "radial",
+              x: 0.5,
+              y: 0.5,
+              r: 0.8,
+              colorStops: [
+                {
+                  offset: 0,
+                  color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
                 },
-                itemStyle: {
-                    borderColor: "rgba(147, 235, 248, .8)",
-                    borderWidth: 1,
-                    areaColor: {
-                        type: "radial",
-                        x: 0.5,
-                        y: 0.5,
-                        r: 0.8,
-                        colorStops: [
-                            {
-                                offset: 0,
-                                color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
-                            },
-                            {
-                                offset: 1,
-                                color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
-                            },
-                        ],
-                        globalCoord: false, // 缺为 false
-                    },
-                    shadowColor: "rgba(128, 217, 248, .3)",
-                    shadowOffsetX: -2,
-                    shadowOffsetY: 2,
-                    shadowBlur: 10,
+                {
+                  offset: 1,
+                  color: "rgba(56,155,183, .8)", // 100% 处的颜色
                 },
+              ],
+              globalCoord: false, // 缺为 false
             },
-            {
-                data: mapData,
-                type: "effectScatter",
-                coordinateSystem: "geo",
-                symbolSize: function (val: any) {
-                    return 4;
-                    // return val[2] / 50;
-                },
-                legendHoverLink: true,
-                showEffectOn: "render",
-                rippleEffect: {
-                    // period: 4,
-                    scale: 6,
-                    color: "rgba(255,255,255, 1)",
-                    brushType: "fill",
-                },
-                tooltip: {
-                    show: true,
-                    position: 'left',
-                    formatter: function (params: any) {
-                        if (params.data) {
-                            const res = params.data; //res等于params下的数据
-                            //return回调一个模板字符串,自定义提示框的形状
-                            return `
+            borderWidth: 1,
+          },
+        },
+        itemStyle: {
+          borderColor: "rgba(147, 235, 248, .8)",
+          borderWidth: 1,
+          areaColor: {
+            type: "radial",
+            x: 0.5,
+            y: 0.5,
+            r: 0.8,
+            colorStops: [
+              {
+                offset: 0,
+                color: "rgba(147, 235, 248, 0)", // 0% 处的颜色
+              },
+              {
+                offset: 1,
+                color: "rgba(147, 235, 248, .2)", // 100% 处的颜色
+              },
+            ],
+            globalCoord: false, // 缺为 false
+          },
+          shadowColor: "rgba(128, 217, 248, .3)",
+          shadowOffsetX: -2,
+          shadowOffsetY: 2,
+          shadowBlur: 10,
+        },
+      },
+      {
+        data: mapData,
+        type: "effectScatter",
+        coordinateSystem: "geo",
+        symbolSize: function (val: any) {
+          return 4;
+          // return val[2] / 50;
+        },
+        legendHoverLink: true,
+        showEffectOn: "render",
+        rippleEffect: {
+          // period: 4,
+          scale: 6,
+          color: "rgba(255,255,255, 1)",
+          brushType: "fill",
+        },
+        tooltip: {
+          show: true,
+          position: "left",
+          formatter: function (params: any) {
+            if (params.data) {
+              const res = params.data; //res等于params下的数据
+              //return回调一个模板字符串,自定义提示框的形状
+              return `
                             <div class="chartTooltip">
                                 <p class="dotTooltip">${res.name}</p>
                                 <p class="textTooltip">${res.value[2]}件</p>
                             </div>`;
-                        } else {
-                            return params.name;
-                        }
-                    },
-                    background:'none',
-                    backgroundColor: "transparent",
-                    borderColor: "transparent",
-                    textStyle: {
-                        color: "#FFF",
-                    },
-                    padding:0,
-                },
-                label: {
-                    formatter: (param: any) => {
-                        return param.name.slice(0, 2);
-                    },
+            } else {
+              return params.name;
+            }
+          },
+          background: "none",
+          backgroundColor: "transparent",
+          borderColor: "transparent",
+          textStyle: {
+            color: "#FFF",
+          },
+          padding: 0,
+        },
+        label: {
+          formatter: (param: any) => {
+            return param.name.slice(0, 2);
+          },
 
-                    fontSize: 11,
-                    offset: [0, 2],
-                    position: "bottom",
-                    textBorderColor: "#fff",
-                    textShadowColor: "#000",
-                    textShadowBlur: 10,
-                    textBorderWidth: 0,
-                    color: "#FFF",
-                    show: true,
-                },
-                // colorBy: "data",
-                itemStyle: {
-                    color: "rgba(255,255,255,1)",
-                    borderColor: "rgba(2255,255,255,2)",
-                    borderWidth: 4,
-                    shadowColor: "#000",
-                    shadowBlur: 10,
-                },
-            },
-        ],
+          fontSize: 11,
+          offset: [0, 2],
+          position: "bottom",
+          textBorderColor: "#fff",
+          textShadowColor: "#000",
+          textShadowBlur: 10,
+          textBorderWidth: 0,
+          color: "#FFF",
+          show: true,
+        },
+        // colorBy: "data",
+        itemStyle: {
+          color: "rgba(255,255,255,1)",
+          borderColor: "rgba(2255,255,255,2)",
+          borderWidth: 4,
+          shadowColor: "#000",
+          shadowBlur: 10,
+        },
+      },
+    ],
 
-        //动画效果
-        // animationDuration: 1000,
-        // animationEasing: 'linear',
-        // animationDurationUpdate: 1000
-    };
-}
+    //动画效果
+    // animationDuration: 1000,
+    // animationEasing: 'linear',
+    // animationDurationUpdate: 1000
+  };
+};
 
 export const regionCodes: any = [
-    {
-        name: '翠屏区',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '南溪区',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '江安县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '长宁县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '高县',
-        value:Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '筠连县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '珙县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '兴文县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '屏山县',
-        value: Mock.mock('@integer(0, 1000)'),
-    },
-    {
-        name: '叙州区',
-        value: Mock.mock('@integer(0, 1000)'),
-    }
-]
+  {
+    name: "翠屏区",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "南溪区",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "江安县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "长宁县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "高县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "筠连县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "珙县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "兴文县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "屏山县",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+  {
+    name: "叙州区",
+    value: Mock.mock("@integer(0, 1000)"),
+  },
+];

+ 21 - 12
src/views/index/header.vue

@@ -5,31 +5,40 @@
     <div class="guang"></div>
     <div class="d-flex jc-center">
       <div class="title">
-        <span class="title-text">宜宾市12345政务热线</span>
+        <span class="title-text">{{ title }}</span>
       </div>
     </div>
     <div class="timers">
       {{ dateData.dateWeek }} {{ dateData.dateDay }}
       <div class="setting_icon" @click="setSettingShow(true)">
-        <img src="../../assets/img/headers/setting.png" alt="设置"/>
+        <img src="../../assets/img/headers/setting.png" alt="设置" />
       </div>
     </div>
   </div>
 </template>
 <script setup lang="ts">
-import {reactive} from "vue";
+import { reactive, ref } from "vue";
 import dayjs from "dayjs";
-import type {DateDataType} from "./index";
-import {useSettingStore} from "@/stores/setting";
+import type { DateDataType } from "./index";
+import { useSettingStore } from "@/stores/setting";
+import { getCurrentCityName } from "@/utils/constants";
 
 const dateData = reactive<DateDataType>({
   dateDay: "",
   dateWeek: "",
   timing: null as any,
 });
-
-const {setSettingShow} = useSettingStore();
-const weekday = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
+const title = ref(`${getCurrentCityName()}12345政务服务便民热线`);
+const { setSettingShow } = useSettingStore();
+const weekday = [
+  "星期天",
+  "星期一",
+  "星期二",
+  "星期三",
+  "星期四",
+  "星期五",
+  "星期六",
+];
 const timeFn = () => {
   dateData.timing = setInterval(() => {
     dateData.dateDay = dayjs().format("YYYY-MM-DD HH : mm : ss");
@@ -112,10 +121,10 @@ timeFn();
     letter-spacing: 6px;
     width: 100%;
     background: linear-gradient(
-            92deg,
-            #0072ff 0%,
-            #00eaff 48.8525390625%,
-            #01aaff 100%
+      92deg,
+      #0072ff 0%,
+      #00eaff 48.8525390625%,
+      #01aaff 100%
     );
     -webkit-background-clip: text;
     -webkit-text-fill-color: transparent;

+ 40 - 33
src/views/judicial/center-map.vue

@@ -1,49 +1,57 @@
 <template>
   <div class="center-map">
     <v-chart
-        class="chart"
-        :option="option"
-        ref="centerMapRef"
-        :loading="loading"
-        :loading-options="loadingOptions"
+      class="chart"
+      :option="option"
+      ref="centerMapRef"
+      :loading="loading"
+      :loading-options="loadingOptions"
     />
   </div>
 </template>
 <script setup lang="ts">
-import {ref, onMounted, watch, nextTick} from "vue";
-import {registerMap, getMap} from "echarts/core";
-import {optionHandle} from "./center.map";
-import {loopShowTooltip} from "@/utils/tooltip-auto-show";
+import { ref, onMounted, watch, nextTick } from "vue";
+import { registerMap, getMap } from "echarts/core";
+import { optionHandle } from "./center.map";
+import { loopShowTooltip } from "@/utils/tooltip-auto-show";
 import axios from "axios";
 import dayjs from "dayjs";
-import {loadingOptions} from "@/utils/constants";
-import {centerTopData} from "api/judicial";
+import { getCurrentCityCode, loadingOptions } from "@/utils/constants";
+import { centerTopData } from "api/judicial";
 
 const props = defineProps({
   dateArray: {
     type: Array,
-    default: () => []
-  }
-})
+    default: () => [],
+  },
+});
 const date = ref([]);
-watch(() => props.dateArray, (val: any) => {
-  date.value = val;
-}, {immediate: true})
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    date.value = val;
+  },
+  { immediate: true }
+);
 
-watch(() => props.dateArray, (val: any) => {
-  getData();
-})
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    getData();
+  }
+);
 const loading = ref(false);
 const option = ref({});
-const code = ref("511500"); //100000 代表中国 其他地市是行政编码
+const code = ref(getCurrentCityCode()); //100000 代表中国 其他地市是行政编码
 const dataSetHandle = async (regionCode: string, list: object[]) => {
+  console.log("val", list);
   code.value = regionCode;
   const geoJson: any = await getGeoJson(regionCode);
   let cityCenter: any = {};
   //获取当前地图每块行政区中心点
   geoJson.features.forEach((element: any) => {
     cityCenter[element.properties.name] =
-        element.properties.centroid || element.properties.center;
+      element.properties.centroid || element.properties.center;
   });
   option.value = optionHandle(regionCode, list);
 };
@@ -55,9 +63,9 @@ const getGeoJson = (regionCode: string) => {
       mapJson = mapJson.geoJSON;
       resolve(mapJson);
     } else {
-      mapJson = await axios.get(`./map-geojson/${regionCode}.json`).then(
-          (data) => data.data
-      );
+      mapJson = await axios
+        .get(`./map-geojson/${regionCode}.json`)
+        .then((data) => data.data);
       code.value = regionCode;
       registerMap(regionCode, {
         geoJSON: mapJson as any,
@@ -71,16 +79,16 @@ const getGeoJson = (regionCode: string) => {
 const getData = async () => {
   loading.value = true;
   try {
-    const {result} = await centerTopData({
-      StartTime: dayjs(date.value[0]).format('YYYY-MM-DD'),
-      EndTime: dayjs(date.value[1]).format('YYYY-MM-DD')
+    const { result } = await centerTopData({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
     });
     const regionData = result.map((item: any) => {
       return {
         name: item.areaName,
-        ...item
-      }
-    })
+        ...item,
+      };
+    });
     await dataSetHandle(code.value, regionData);
     loading.value = false;
   } catch (e) {
@@ -129,7 +137,7 @@ onMounted(async () => {
   .custom-tooltip-style {
     width: 355px;
     height: 219px;
-    background-image: url('@/assets/img/home/tool_tip_bg.png');
+    background-image: url("@/assets/img/home/tool_tip_bg.png");
     background-size: 100% 100%;
     color: #fff;
     padding: 20px 30px;
@@ -192,7 +200,6 @@ onMounted(async () => {
           }
         }
       }
-
     }
   }
 }

+ 22 - 16
src/views/judicial/header.vue

@@ -2,15 +2,15 @@
   <div class="d-flex jc-center title_wrap">
     <div class="time-picker">
       <el-date-picker
-          v-model="timeValue"
-          type="daterange"
-          unlink-panels
-          range-separator="至"
-          start-placeholder="开始时间"
-          end-placeholder="结束时间"
-          :shortcuts="shortcuts"
-          :clearable="false"
-          @change="changeDate"
+        v-model="timeValue"
+        type="daterange"
+        unlink-panels
+        range-separator="至"
+        start-placeholder="开始时间"
+        end-placeholder="结束时间"
+        :shortcuts="shortcuts"
+        :clearable="false"
+        @change="changeDate"
       />
     </div>
     <div class="d-flex jc-center">
@@ -18,19 +18,17 @@
         <span class="title-text">{{ title }}</span>
       </div>
     </div>
-    <div class="timers">
-      {{ dateData.dateDay }} {{ dateData.dateWeek }}
-    </div>
+    <div class="timers">{{ dateData.dateDay }} {{ dateData.dateWeek }}</div>
   </div>
 </template>
 <script setup lang="ts">
-import {reactive, ref} from "vue";
+import { reactive, ref } from "vue";
 import dayjs from "dayjs";
-import {shortcuts} from '@/utils/constants';
+import { getCurrentCityName, shortcuts } from "@/utils/constants";
 
 const emit = defineEmits(["changeDate"]);
 
-const title = ref("宜宾市司法行政执法监督子系统");
+const title = ref(`${getCurrentCityName()}司法行政执法监督子系统`);
 const timeValue = ref<any>([
   dayjs().subtract(1, "month").toDate(),
   dayjs().toDate(),
@@ -46,7 +44,15 @@ const dateData = reactive<any>({
   timing: null as any,
 });
 
-const weekday = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
+const weekday = [
+  "星期天",
+  "星期一",
+  "星期二",
+  "星期三",
+  "星期四",
+  "星期五",
+  "星期六",
+];
 const timeFn = () => {
   dateData.timing = setInterval(() => {
     dateData.dateDay = dayjs().format("YYYY-MM-DD HH:mm:ss");

+ 196 - 159
src/views/judicial/left-bottom.vue

@@ -2,26 +2,36 @@
   <div class="left_bottom">
     <div class="left_bottom-title flex">
       <div class="flex items-center">
-        <img src="@/assets/img/home/title_arrow.png" alt="">
+        <img src="@/assets/img/home/title_arrow.png" alt="" />
         高频事项分析
       </div>
       <el-dropdown @command="handleCommand">
         <el-button link class="link-button">
           {{ areaText }}
           <el-icon class="el-icon--right">
-            <arrow-down/>
+            <arrow-down />
           </el-icon>
         </el-button>
         <template #dropdown>
           <el-dropdown-menu>
-            <el-dropdown-item v-for="item in areaList" :key="item.id" :command="item">{{ item.areaName }}</el-dropdown-item>
+            <el-dropdown-item
+              v-for="item in areaList"
+              :key="item.id"
+              :command="item"
+              >{{ item.areaName }}</el-dropdown-item
+            >
           </el-dropdown-menu>
         </template>
       </el-dropdown>
     </div>
     <div class="left_bottom-content">
       <template v-if="list.length">
-        <v-chart class="chart" :option="option" :loading="loading" :loading-options="loadingOptions"/>
+        <v-chart
+          class="chart"
+          :option="option"
+          :loading="loading"
+          :loading-options="loadingOptions"
+        />
       </template>
       <template v-else>
         <EmptyCom></EmptyCom>
@@ -30,104 +40,126 @@
   </div>
 </template>
 <script setup lang="ts">
-import {onMounted, ref, watch} from "vue";
-import {ArrowDown} from '@element-plus/icons-vue'
-import {getArea} from "@/api/home";
+import { onMounted, ref, watch } from "vue";
+import { ArrowDown } from "@element-plus/icons-vue";
+import { getArea } from "@/api/home";
 import dayjs from "dayjs";
 import EmptyCom from "@/components/empty-com";
-import {loadingOptions} from "@/utils/constants";
-import {graphic} from "echarts/core";
-import {arraySortByKey} from "@/utils/tools";
-import {leftBottomData} from "api/judicial";
+import {
+  getCurrentCityCode,
+  getCurrentCityName,
+  loadingOptions,
+} from "@/utils/constants";
+import { graphic } from "echarts/core";
+import { arraySortByKey } from "@/utils/tools";
+import { leftBottomData } from "api/judicial";
 
 const props = defineProps({
   dateArray: {
     type: Array,
-    default: () => []
-  }
-})
+    default: () => [],
+  },
+});
 const date = ref([]);
 const loading = ref(false);
 const option = ref<any>({});
-watch(() => props.dateArray, (val: any) => {
-  date.value = val;
-}, {immediate: true})
+watch(
+  () => props.dateArray,
+  (val: any) => {
+    date.value = val;
+  },
+  { immediate: true }
+);
 
-watch(() => props.dateArray, () => {
-  getData();
-})
-const areaCode = ref('511500');
-const areaText = ref('宜宾市');
+watch(
+  () => props.dateArray,
+  () => {
+    getData();
+  }
+);
+const areaCode = ref(getCurrentCityCode());
+const areaText = ref(getCurrentCityName());
 const list = ref<any>([]);
 const getData = async () => {
   loading.value = true;
   try {
-    const {result} = await leftBottomData({
-      StartTime: dayjs(date.value[0]).format('YYYY-MM-DD'),
-      EndTime: dayjs(date.value[1]).format('YYYY-MM-DD'),
-      AreaCode: areaCode.value
+    const { result } = await leftBottomData({
+      StartTime: dayjs(date.value[0]).format("YYYY-MM-DD"),
+      EndTime: dayjs(date.value[1]).format("YYYY-MM-DD"),
+      AreaCode: areaCode.value,
     });
     list.value = result;
-    const category = arraySortByKey(result, 'sumCount',);
-    const charts = { // 按顺序排列从大到小
+    const category = arraySortByKey(result, "sumCount");
+    const charts = {
+      // 按顺序排列从大到小
       cityList: category.map((item: any) => item.eventTypeName),
-      cityData: category.map((item: any) => item.sumCount)
+      cityData: category.map((item: any) => item.sumCount),
     };
     const top10CityList = charts.cityList;
     const top10CityData = charts.cityData;
-    const color = ['#ff9500', '#02d8f9', '#027fff'];
-    const color1 = ['#ffb349', '#70e9fc', '#4aa4ff'];
+    const color = ["#ff9500", "#02d8f9", "#027fff"];
+    const color1 = ["#ffb349", "#70e9fc", "#4aa4ff"];
 
-    let lineY = []
-    let lineT = []
+    let lineY = [];
+    let lineT = [];
     for (let i = 0; i < charts.cityList.length; i++) {
       let x = i;
       if (x > 1) {
-        x = 2
+        x = 2;
       }
       const data = {
         name: charts.cityList[i],
         color: color[x],
         value: top10CityData[i],
-        barGap: '-100%',
+        barGap: "-100%",
         itemStyle: {
           show: true,
-          color: new graphic.LinearGradient(0, 0, 1, 0, [{
-            offset: 0,
-            color: color[x]
-          }, {
-            offset: 1,
-            color: color1[x]
-          }], false),
+          color: new graphic.LinearGradient(
+            0,
+            0,
+            1,
+            0,
+            [
+              {
+                offset: 0,
+                color: color[x],
+              },
+              {
+                offset: 1,
+                color: color1[x],
+              },
+            ],
+            false
+          ),
           borderRadius: 10,
         },
         emphasis: {
           itemStyle: {
             shadowBlur: 15,
-            shadowColor: 'rgba(0, 0, 0, 0.1)'
-          }
-        }
+            shadowColor: "rgba(0, 0, 0, 0.1)",
+          },
+        },
       };
       const data1 = {
         value: top10CityData[0],
         itemStyle: {
-          color: '#001235',
-          borderRadius: 10
-        }
+          color: "#001235",
+          borderRadius: 10,
+        },
       };
-      lineY.push(data)
-      lineT.push(data1)
+      lineY.push(data);
+      lineT.push(data1);
     }
 
     option.value = {
-      backgroundColor: 'rgba(0, 0, 0, 0)',
+      backgroundColor: "rgba(0, 0, 0, 0)",
       title: {
-        show: false
+        show: false,
       },
       tooltip: {
-        trigger: 'axis',
+        trigger: "axis",
         axisPointer: {
-          type: 'shadow'
+          type: "shadow",
         },
         formatter: function (params: any) {
           let tar;
@@ -136,10 +168,10 @@ const getData = async () => {
           } else {
             tar = params[1];
           }
-          return tar.marker + tar.name + '<br/>' + ' 当前数量: ' + tar.value;
+          return tar.marker + tar.name + "<br/>" + " 当前数量: " + tar.value;
         },
 
-        enterable: true,//滚动条
+        enterable: true, //滚动条
         confine: true,
         extraCssText: "max-width:90%;max-height:83%;overflow:auto;",
         //改变提示框的位置 不超出屏幕显示
@@ -171,142 +203,147 @@ const getData = async () => {
             y = pointY - boxHeight;
           }
           return [x, y];
-        }
+        },
       },
       grid: {
         borderWidth: 0,
-        top: '5%',
-        left: '5%',
-        right: '15%',
-        bottom: '10%'
+        top: "5%",
+        left: "5%",
+        right: "15%",
+        bottom: "10%",
       },
       color: color,
-      yAxis: [{
-        type: 'category',
-        inverse: true,
-        axisTick: {
-          show: false
-        },
-        axisLine: {
-          show: false
-        },
-        axisLabel: {
-          show: false,
-          inside: false
-        },
-        data: top10CityList
-      }, {
-        type: 'category',
-        inverse: true,
-        axisLine: {
-          show: false
-        },
-        axisTick: {
-          show: false
-        },
-        axisLabel: {
-          show: true,
-          inside: false,
-          verticalAlign: 'middle',
-          lineHeight: '40',
-          color: '#fff',
-          fontSize: '14',
-          fontFamily: 'PingFangSC-Regular',
-          formatter: function (val) {
-            return `${val}`
-          }
-        },
-        splitArea: {
-          show: false
+      yAxis: [
+        {
+          type: "category",
+          inverse: true,
+          axisTick: {
+            show: false,
+          },
+          axisLine: {
+            show: false,
+          },
+          axisLabel: {
+            show: false,
+            inside: false,
+          },
+          data: top10CityList,
         },
-        splitLine: {
-          show: false
+        {
+          type: "category",
+          inverse: true,
+          axisLine: {
+            show: false,
+          },
+          axisTick: {
+            show: false,
+          },
+          axisLabel: {
+            show: true,
+            inside: false,
+            verticalAlign: "middle",
+            lineHeight: "40",
+            color: "#fff",
+            fontSize: "14",
+            fontFamily: "PingFangSC-Regular",
+            formatter: function (val) {
+              return `${val}`;
+            },
+          },
+          splitArea: {
+            show: false,
+          },
+          splitLine: {
+            show: false,
+          },
+          data: top10CityData,
         },
-        data: top10CityData
-      }],
+      ],
       xAxis: {
-        type: 'value',
+        type: "value",
         axisTick: {
-          show: false
+          show: false,
         },
         axisLine: {
-          show: false
+          show: false,
         },
         splitLine: {
-          show: false
+          show: false,
         },
         axisLabel: {
-          show: false
-        }
+          show: false,
+        },
       },
-      series: [{
-        type: 'bar',
-        zLevel: 2,
-        barWidth: '10px',
-        data: lineY,
-        label: {
-          color: '#b3ccf8',
-          show: true,
-          position: [0, '-18px'],
-          fontSize: 16,
-          formatter: function (a) {
-            let num = ''
-            let str = ''
-            if (a.dataIndex + 1 < 10) {
-              num = '0' + (a.dataIndex + 1);
-            } else {
-              num = (a.dataIndex + 1);
-            }
-            if (a.dataIndex === 0) {
-              str = `{color1|${num}} {color4|${a.name}}`
-            } else if (a.dataIndex === 1) {
-              str = `{color2|${num}} {color4|${a.name}}`
-            } else {
-              str = `{color3|${num}} {color4|${a.name}}`
-            }
-            return str;
-          },
-          rich: {
-            color1: {
-              color: '#ff9500',
-              fontWeight: 700
+      series: [
+        {
+          type: "bar",
+          zLevel: 2,
+          barWidth: "10px",
+          data: lineY,
+          label: {
+            color: "#b3ccf8",
+            show: true,
+            position: [0, "-18px"],
+            fontSize: 16,
+            formatter: function (a) {
+              let num = "";
+              let str = "";
+              if (a.dataIndex + 1 < 10) {
+                num = "0" + (a.dataIndex + 1);
+              } else {
+                num = a.dataIndex + 1;
+              }
+              if (a.dataIndex === 0) {
+                str = `{color1|${num}} {color4|${a.name}}`;
+              } else if (a.dataIndex === 1) {
+                str = `{color2|${num}} {color4|${a.name}}`;
+              } else {
+                str = `{color3|${num}} {color4|${a.name}}`;
+              }
+              return str;
             },
-            color2: {
-              color: '#02d8f9',
-              fontWeight: 700
+            rich: {
+              color1: {
+                color: "#ff9500",
+                fontWeight: 700,
+              },
+              color2: {
+                color: "#02d8f9",
+                fontWeight: 700,
+              },
+              color3: {
+                color: "#027fff",
+                fontWeight: 700,
+              },
+              color4: {
+                color: "#e5eaff",
+              },
             },
-            color3: {
-              color: '#027fff',
-              fontWeight: 700
-            },
-            color4: {
-              color: '#e5eaff'
-            }
-          }
-        }
-      }],
-    }
+          },
+        },
+      ],
+    };
     loading.value = false;
   } catch (e) {
     console.log(e);
     loading.value = false;
   }
-}
+};
 // 选择省市区
 const handleCommand = (command: any) => {
   areaCode.value = command.id;
   areaText.value = command.areaName;
   getData();
-}
+};
 const areaList = ref([]);
 const getAreaData = async () => {
   try {
     const res = await getArea();
-    areaList.value = res.result ?? []
+    areaList.value = res.result ?? [];
   } catch (e) {
     console.log(e);
   }
-}
+};
 onMounted(() => {
   getData();
   getAreaData();
@@ -330,8 +367,8 @@ onMounted(() => {
 
 :deep(.link-button) {
   cursor: pointer;
-  color: #7DBDEC;
+  color: #7dbdec;
   display: flex;
   align-items: center;
 }
-</style>
+</style>

+ 44 - 31
src/views/seats/header.vue

@@ -1,43 +1,46 @@
 <template>
   <div class="title_wrap">
     <div class="title">
-      <span class="title-text">宜宾市12345坐席监控中心</span>
+      <span class="title-text">{{ title }}</span>
     </div>
     <div class="timers">
-      <span class="timers-text">{{ dateData.dateWeek }} {{ dateData.dateDay }}</span>
+      <span class="timers-text"
+        >{{ dateData.dateWeek }} {{ dateData.dateDay }}</span
+      >
     </div>
     <div class="guang"></div>
     <div class="left_icons">
       <el-badge :value="busyCount" :max="99" class="left_icons_item">
-        <img src="@/assets/img/seats/busy.png" alt="">通话中
+        <img src="@/assets/img/seats/busy.png" alt="" />通话中
       </el-badge>
       <el-badge :value="unreadyCount" :max="99" class="left_icons_item">
-        <img src="@/assets/img/seats/unready.png" alt="">小休
+        <img src="@/assets/img/seats/unready.png" alt="" />小休
       </el-badge>
       <el-badge :value="heldCount" :max="99" class="left_icons_item">
-        <img src="@/assets/img/seats/held.png" alt="">保持
+        <img src="@/assets/img/seats/held.png" alt="" />保持
       </el-badge>
       <el-badge :value="readyCount" :max="99" class="left_icons_item">
-        <img src="@/assets/img/seats/ready.png" alt="">示闲
+        <img src="@/assets/img/seats/ready.png" alt="" />示闲
       </el-badge>
     </div>
     <div class="right_icons">
       <el-badge :value="threeWayCount" :max="99" class="right_icons_item">
-        <img src="@/assets/img/seats/threeWay.png" alt="">三方会议
+        <img src="@/assets/img/seats/threeWay.png" alt="" />三方会议
       </el-badge>
       <el-badge :value="acwCount" :max="99" class="right_icons_item">
-        <img src="@/assets/img/seats/acw.png" alt="">话后整理
+        <img src="@/assets/img/seats/acw.png" alt="" />话后整理
       </el-badge>
       <el-badge :value="logoutCount" :max="99" class="right_icons_item">
-        <img src="@/assets/img/seats/logout.png" alt="">签出
+        <img src="@/assets/img/seats/logout.png" alt="" />签出
       </el-badge>
     </div>
   </div>
 </template>
 <script setup lang="ts">
-import {computed, reactive, ref, onMounted, onUnmounted, watch} from "vue";
+import { computed, reactive, ref, onMounted, onUnmounted, watch } from "vue";
 import dayjs from "dayjs";
 import signalR from "@/utils/signalR";
+import { getCurrentCityName } from "@/utils/constants";
 
 const props = defineProps({
   data: {
@@ -45,13 +48,22 @@ const props = defineProps({
     default: () => [],
   },
 });
+const title = ref(`${getCurrentCityName()}12345坐席监控中心`);
 const dateData = reactive<any>({
   dateDay: "",
   dateYear: "",
   dateWeek: "",
   timing: null as any,
 });
-const weekday = ["星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
+const weekday = [
+  "星期天",
+  "星期一",
+  "星期二",
+  "星期三",
+  "星期四",
+  "星期五",
+  "星期六",
+];
 const timeFn = () => {
   dateData.timing = setInterval(() => {
     dateData.dateDay = dayjs().format("YYYY-MM-DD HH:mm:ss");
@@ -61,43 +73,44 @@ const timeFn = () => {
 timeFn();
 // 通话数量
 const busyCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'busy').length;
+  return seatsList.value.filter((item: any) => item.state === "busy").length;
 });
 // 小休数量、
 const unreadyCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'unready').length;
+  return seatsList.value.filter((item: any) => item.state === "unready").length;
 });
 // 保持数量
 const heldCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'held').length;
+  return seatsList.value.filter((item: any) => item.state === "held").length;
 });
 // 空闲数量
 const readyCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'ready').length;
+  return seatsList.value.filter((item: any) => item.state === "ready").length;
 });
 // 三方会议数量
 const threeWayCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'threeWay').length;
+  return seatsList.value.filter((item: any) => item.state === "threeWay")
+    .length;
 });
 // 话后整理数量
 const acwCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'acw').length;
+  return seatsList.value.filter((item: any) => item.state === "acw").length;
 });
 // 签出数量
 const logoutCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state === 'logout').length;
+  return seatsList.value.filter((item: any) => item.state === "logout").length;
 });
-const seatsList = ref<any>([])
+const seatsList = ref<any>([]);
 watch(
-    () => props.data,
-    (newData: any) => {
-      seatsList.value = newData;
-    },
-    {immediate: true}
+  () => props.data,
+  (newData: any) => {
+    seatsList.value = newData;
+  },
+  { immediate: true }
 );
 onMounted(() => {
   // 接收消息
-  signalR.SR.on('SeatState', (res: any) => {
+  signalR.SR.on("SeatState", (res: any) => {
     const item = seatsList.value.find((item: any) => item.telNo === res.telNo);
     item.loading = true;
     if (item) {
@@ -109,7 +122,7 @@ onMounted(() => {
   });
 });
 onUnmounted(() => {
-  signalR.SR.off('SeatState');
+  signalR.SR.off("SeatState");
 });
 </script>
 
@@ -125,7 +138,7 @@ onUnmounted(() => {
   position: relative;
 
   &::after {
-    content: '.';
+    content: ".";
     position: absolute;
     bottom: 13px;
     background-image: radial-gradient(circle, #1b86d1 50%, #176bb5 50%);
@@ -168,10 +181,10 @@ onUnmounted(() => {
     letter-spacing: 6px;
     width: 100%;
     background: linear-gradient(
-            92deg,
-            #0072ff 0%,
-            #00eaff 48.8525390625%,
-            #01aaff 100%
+      92deg,
+      #0072ff 0%,
+      #00eaff 48.8525390625%,
+      #01aaff 100%
     );
     -webkit-background-clip: text;
     -webkit-text-fill-color: transparent;

+ 66 - 61
src/views/seats/left-bottom.vue

@@ -3,36 +3,36 @@
     <div class="left_number">
       <div>
         <span>登录坐席数量:</span>
-        <CountUp :endVal="loginCount"/>
+        <CountUp :endVal="loginCount" />
       </div>
       <div>
         <span>呼入接通数量:</span>
-        <CountUp :endVal="state.count.inOn"/>
+        <CountUp :endVal="state.count.inOn" />
       </div>
       <div>
         <span>有效接通数量:</span>
-        <CountUp :endVal="state.count.validOn"/>
+        <CountUp :endVal="state.count.validOn" />
       </div>
       <div>
         <span>未接通数量:</span>
-        <CountUp :endVal="state.count.inNoOn"/>
+        <CountUp :endVal="state.count.inNoOn" />
       </div>
       <div>
         <span>呼出接通数量:</span>
-        <CountUp :endVal="state.count.outOn"/>
+        <CountUp :endVal="state.count.outOn" />
       </div>
       <div>
         <span>队列挂断数量:</span>
-        <CountUp :endVal="state.count.inQueueNoOn"/>
+        <CountUp :endVal="state.count.inQueueNoOn" />
       </div>
     </div>
     <div class="right_chart">
-      <v-chart class="chart" :option="option"/>
+      <v-chart class="chart" :option="option" />
     </div>
   </div>
 </template>
 <script setup lang="ts">
-import {onMounted, reactive, ref, computed, onUnmounted, watch} from "vue";
+import { onMounted, reactive, ref, computed, onUnmounted, watch } from "vue";
 import CountUp from "@/components/count-up";
 import signalR from "@/utils/signalR";
 
@@ -43,8 +43,7 @@ const props = defineProps({
   },
   content: {
     type: Object,
-    default: () => {
-    },
+    default: () => {},
   },
 });
 const option = ref({});
@@ -55,7 +54,7 @@ const state = reactive<any>({
     inQueueNoOn: 0,
     outOn: 0,
     validOn: 0,
-  }
+  },
 });
 const setOption = async (newData: any) => {
   option.value = {
@@ -68,13 +67,13 @@ const setOption = async (newData: any) => {
       },
     },
     legend: {
-      data: ["呼入", "外呼", '外呼平均', '呼入平均'],
+      data: ["呼入", "外呼", "外呼平均", "呼入平均"],
       textStyle: {
         color: "#fff",
       },
       top: "0",
       left: "80px",
-      icon: 'roundRect',
+      icon: "roundRect",
       itemWidth: 16,
       itemHeight: 16,
       itemGap: 20,
@@ -98,7 +97,7 @@ const setOption = async (newData: any) => {
     },
     yAxis: [
       {
-        splitLine: {show: false},
+        splitLine: { show: false },
         axisLine: {
           lineStyle: {
             color: "#fff",
@@ -109,7 +108,7 @@ const setOption = async (newData: any) => {
         },
       },
       {
-        splitLine: {show: false},
+        splitLine: { show: false },
         axisLine: {
           lineStyle: {
             color: "#fff",
@@ -125,8 +124,9 @@ const setOption = async (newData: any) => {
         name: "呼入",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -138,8 +138,9 @@ const setOption = async (newData: any) => {
         name: "外呼",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -152,8 +153,9 @@ const setOption = async (newData: any) => {
         name: "呼入平均",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -166,8 +168,9 @@ const setOption = async (newData: any) => {
         name: "外呼平均",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -182,59 +185,62 @@ const setOption = async (newData: any) => {
 const seatsList = ref<any>([]);
 // 登录坐席数量
 const loginCount = computed(() => {
-  return seatsList.value.filter((item: any) => item.state !== 'logout').length;
+  return seatsList.value.filter((item: any) => item.state !== "logout").length;
 });
-watch(() => props.content, (val: any) => {
-  state.count = val.count[0];
-  let data = {
-    xData: [],
-    inData: [],
-    outData: [],
-    inAverageData: [],
-    outAverageData: [],
+watch(
+  () => props.content,
+  (val: any) => {
+    state.count = val.count[0];
+    let data = {
+      xData: [],
+      inData: [],
+      outData: [],
+      inAverageData: [],
+      outAverageData: [],
+    };
+    val.list.forEach((item: any) => {
+      data.xData.push(item.time);
+      data.inData.push(item.in);
+      data.outData.push(item.out);
+      data.inAverageData.push(item.inAverag);
+      data.outAverageData.push(item.outAverag);
+    });
+    setTimeout(() => {
+      setOption(data);
+    }, 100);
   }
-  val.list.forEach((item: any) => {
-    data.xData.push(item.time)
-    data.inData.push(item.in)
-    data.outData.push(item.out)
-    data.inAverageData.push(item.inAverag)
-    data.outAverageData.push(item.outAverag)
-  });
-  setTimeout(() => {
-    setOption(data);
-  }, 100);
-});
+);
 watch(
-    () => props.data,
-    (newData: any) => {
-      seatsList.value = newData;
-    },
-    {immediate: true}
+  () => props.data,
+  (newData: any) => {
+    seatsList.value = newData;
+  },
+  { immediate: true }
 );
 onMounted(() => {
-  signalR.SR.on('SeatState', (res: any) => {
+  signalR.SR.on("SeatState", (res: any) => {
     const item = seatsList.value.find((item: any) => item.telNo === res.telNo);
     if (item) {
       item.state = res.state;
     }
   });
-  signalR.SR.on('BsSeatStateDataShowArea3', (res: any) => {
+  signalR.SR.on("BsSeatStateDataShowArea3", (res: any) => {
     state.count = res[0];
   });
-  signalR.SR.on('BsSeatStateDataShowArea4', (res: any) => {
+  signalR.SR.on("BsSeatStateDataShowArea4", (res: any) => {
     let data = {
       xData: [],
       inData: [],
       outData: [],
       inAverageData: [],
       outAverageData: [],
-    }
+    };
     res.forEach((item: any) => {
-      data.xData.push(item.time)
-      data.inData.push(item.in)
-      data.outData.push(item.out)
-      data.inAverageData.push(item.inAverag)
-      data.outAverageData.push(item.outAverag)
+      data.xData.push(item.time);
+      data.inData.push(item.in);
+      data.outData.push(item.out);
+      data.inAverageData.push(item.inAverag);
+      data.outAverageData.push(item.outAverag);
     });
     setTimeout(() => {
       setOption(data);
@@ -242,9 +248,9 @@ onMounted(() => {
   });
 });
 onUnmounted(() => {
-  signalR.SR.off('SeatState');
-  signalR.SR.off('BsSeatStateDataShowArea3');
-  signalR.SR.off('BsSeatStateDataShowArea4');
+  signalR.SR.off("SeatState");
+  signalR.SR.off("BsSeatStateDataShowArea3");
+  signalR.SR.off("BsSeatStateDataShowArea4");
 });
 </script>
 <style scoped lang="scss">
@@ -272,7 +278,6 @@ onUnmounted(() => {
   .right_chart {
     flex: 1;
     height: 100%;
-
   }
 }
 </style>

+ 34 - 29
src/views/seats/left-top.vue

@@ -1,8 +1,8 @@
 <template>
-  <v-chart class="chart" :option="option"/>
+  <v-chart class="chart" :option="option" />
 </template>
 <script setup lang="ts">
-import {onMounted, ref, onUnmounted, watch} from "vue";
+import { onMounted, ref, onUnmounted, watch } from "vue";
 import signalR from "@/utils/signalR";
 
 const props = defineProps({
@@ -48,7 +48,7 @@ const setOption = async (newData: any) => {
     },
     yAxis: [
       {
-        splitLine: {show: false},
+        splitLine: { show: false },
         axisLine: {
           lineStyle: {
             color: "#fff",
@@ -59,7 +59,7 @@ const setOption = async (newData: any) => {
         },
       },
       {
-        splitLine: {show: false},
+        splitLine: { show: false },
         axisLine: {
           lineStyle: {
             color: "#fff",
@@ -75,8 +75,9 @@ const setOption = async (newData: any) => {
         name: "呼入",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -88,8 +89,9 @@ const setOption = async (newData: any) => {
         name: "外呼",
         type: "line",
         symbol: "circle", //数据交叉点样式
-        areaStyle: {   //添加背景颜色
-          opacity: 0.3,   //透明度
+        areaStyle: {
+          //添加背景颜色
+          opacity: 0.3, //透明度
         },
         itemStyle: {
           borderRadius: 5,
@@ -97,36 +99,39 @@ const setOption = async (newData: any) => {
         smooth: true,
         z: -12,
         data: newData.outData,
-      }
+      },
     ],
   };
 };
-watch(() => props.content, (val: any) => {
-  let data = {
-    xData: [],
-    inData: [],
-    outData: [],
+watch(
+  () => props.content,
+  (val: any) => {
+    let data = {
+      xData: [],
+      inData: [],
+      outData: [],
+    };
+    val.forEach((item: any) => {
+      data.xData.push(item.time);
+      data.inData.push(item.in);
+      data.outData.push(item.out);
+    });
+    setTimeout(() => {
+      setOption(data);
+    }, 100);
   }
-  val.forEach((item: any) => {
-    data.xData.push(item.time)
-    data.inData.push(item.in)
-    data.outData.push(item.out)
-  });
-  setTimeout(() => {
-    setOption(data);
-  }, 100);
-})
+);
 onMounted(() => {
-  signalR.SR.on('BsSeatStateDataShowArea1', (res: any) => {
+  signalR.SR.on("BsSeatStateDataShowArea1", (res: any) => {
     let data = {
       xData: [],
       inData: [],
       outData: [],
-    }
+    };
     res.forEach((item: any) => {
-      data.xData.push(item.time)
-      data.inData.push(item.in)
-      data.outData.push(item.out)
+      data.xData.push(item.time);
+      data.inData.push(item.in);
+      data.outData.push(item.out);
     });
     setTimeout(() => {
       setOption(data);
@@ -134,7 +139,7 @@ onMounted(() => {
   });
 });
 onUnmounted(() => {
-  signalR.SR.off('BsSeatStateDataShowArea1');
+  signalR.SR.off("BsSeatStateDataShowArea1");
 });
 </script>
 <style scoped lang="scss">

+ 132 - 52
src/views/seats/right.vue

@@ -1,14 +1,28 @@
 <template>
-  <div class="seats_box" v-loading="loading"
-       element-loading-text="加载中..."
-       element-loading-svg-view-box="-10, -10, 50, 50"
-       element-loading-background="rgba(122, 122, 122, 0.1)">
+  <div
+    class="seats_box"
+    v-loading="loading"
+    element-loading-text="加载中..."
+    element-loading-svg-view-box="-10, -10, 50, 50"
+    element-loading-background="rgba(122, 122, 122, 0.1)"
+  >
     <div class="seats_container">
-      <div v-for="(item,index) in seatsList" class="seats_item" ref="textRefs" @click="handleClick(index,item)">
-        <img src="@/assets/img/seats/service.png" alt="" class="seats_item_service">
+      <div
+        v-for="(item, index) in seatsList"
+        class="seats_item"
+        ref="textRefs"
+        @click="handleClick(index, item)"
+      >
+        <img
+          src="@/assets/img/seats/service.png"
+          alt=""
+          class="seats_item_service"
+        />
         <p class="seats_item_tel">{{ item.telNo }}</p>
-        <p class="seats_item_name" v-if="item.state === 'logout'"> 未登录</p>
-        <p class="seats_item_name" v-else> {{ item.workUserName ? item.workUserName : '&nbsp;' }}</p>
+        <p class="seats_item_name" v-if="item.state === 'logout'">未登录</p>
+        <p class="seats_item_name" v-else>
+          {{ item.workUserName ? item.workUserName : "&nbsp;" }}
+        </p>
         <!--        <el-dropdown @command="handleCommand($event,item)" class="seats_item_dropdown" trigger="click" v-if="item.state === 'busy'">
                   <el-icon class="seats_item_more" size="18">
                     <Operation/>
@@ -21,15 +35,24 @@
                   </template>
                 </el-dropdown>-->
         <div class="seats_item_state">
-          <img :src="getImageUrl('seats/'+item.state+'.png')" alt="">
-          <span class="seats_item_telNo"> {{ currentStatusText(item.state) }}</span>
+          <img :src="getImageUrl('seats/' + item.state + '.png')" alt="" />
+          <span class="seats_item_telNo">
+            {{ currentStatusText(item.state) }}</span
+          >
         </div>
       </div>
     </div>
 
-
-    <el-popover ref="popoverRef" :virtual-ref="textRef" :visible="hidePopover" virtual-triggering placement="right-start"
-                @hide="popoverHide" width="220" popper-class="call_popover_popper">
+    <el-popover
+      ref="popoverRef"
+      :virtual-ref="textRef"
+      :visible="hidePopover"
+      virtual-triggering
+      placement="right-start"
+      @hide="popoverHide"
+      width="220"
+      popper-class="call_popover_popper"
+    >
       <template #default>
         <div v-click-outside="onClickOutside" class="call_popover">
           <div class="call_popover_item">
@@ -42,7 +65,8 @@
             <span>通话时长:</span>{{ formatDuration(callTime) }}
           </div>
           <div class="call_popover_item">
-            <span>呼入类型:</span>{{ call.callDirection === 'inbound' ? '呼入' : '呼出' }}
+            <span>呼入类型:</span
+            >{{ call.callDirection === "inbound" ? "呼入" : "呼出" }}
           </div>
           <div class="call_popover_item">
             <span>电话号码:</span>{{ call.otherNumber }}
@@ -56,18 +80,24 @@
   </div>
 </template>
 <script setup lang="ts">
-import {onMounted, ref, onUnmounted, nextTick} from "vue";
-import {getImageUrl} from "@/utils/tools";
+import { onMounted, ref, nextTick, onBeforeUnmount, watch } from "vue";
+import { getImageUrl } from "@/utils/tools";
 import signalR from "@/utils/signalR";
-import {extensionPaged} from "api/home";
-import {ClickOutside as vClickOutside} from 'element-plus';
-import {Operation} from '@element-plus/icons-vue'
-import {formatDuration} from "../../utils/formatTime";
+import { extensionPaged } from "api/home";
+import { ClickOutside as vClickOutside } from "element-plus";
+import { formatDuration } from "@/utils/formatTime";
 import dayjs from "dayjs";
 
-const textRefs = ref([])
-const textRef = ref()
-const popoverRef = ref()
+const props = defineProps({
+  data: {
+    type: Array,
+    default: () => [],
+  },
+});
+
+const textRefs = ref([]);
+const textRef = ref();
+const popoverRef = ref();
 const hidePopover = ref(false);
 const call = ref({});
 // 开始签入时长
@@ -87,70 +117,120 @@ const startCallTimer = (second: any) => {
     }, 1000);
   }
 };
-const handleClick = (index: string | number, item: { state: string; }) => {
-  if (['busy', 'held'].includes(item.state)) {
+const handleClick = (index: string | number, item: { state: string }) => {
+  if (["busy", "held"].includes(item.state)) {
     textRef.value = textRefs.value[index];
     call.value = item;
     hidePopover.value = true;
     // 获取现在时间与签入时间的秒数
-    callTime.value = dayjs().diff(dayjs(item.answeredAt), 'second');
+    callTime.value = dayjs().diff(dayjs(item.answeredAt), "second");
     startCallTimer(callTime.value);
   }
-}
+};
 // 隐藏弹窗
 const popoverHide = () => {
   clearInterval(timer.value);
-}
+};
 const onClickOutside = () => {
   hidePopover.value = false;
-}
+};
 // 设置当前状态的值
 const currentStatusText = (state: string) => {
   const statusMap: any = {
-    logout: '签出',
-    login: '签入',
-    ready: '示闲',
-    unready: '小休',
-    busy: '通话中',
-    acw: '整理中',
-    held: '保持',
-    treeWay: '三方会议',
+    logout: "签出",
+    login: "签入",
+    ready: "示闲",
+    unready: "小休",
+    busy: "通话中",
+    acw: "整理中",
+    held: "保持",
+    treeWay: "三方会议",
   };
-  return statusMap[state] || '';
+  return statusMap[state] || "";
 };
 const seatsList = ref<any>([]);
+watch(
+  () => props.data,
+  (newData: any) => {
+    seatsList.value = newData;
+  },
+  { immediate: true }
+);
 const loading = ref(false);
 // 获取分机列表
 const getSeatsList = async () => {
   loading.value = true;
   try {
-    const {result} = await extensionPaged();
+    const { result } = await extensionPaged();
     seatsList.value = result ?? [];
     loading.value = false;
   } catch (e) {
-    console.log(e)
+    console.log(e);
     loading.value = false;
   }
 };
+// 对当前状态进行排序
+const sortSeatsList = () => {
+  // 通话中的排序
+  const busyData = seatsList.value.filter((item: any) => item.state === "busy");
+  // 话后整理
+  const acwData = seatsList.value.filter((item: any) => item.state === "acw");
+  // 保持
+  const heldData = seatsList.value.filter((item: any) => item.state === "held");
+  // 三方会议
+  const treeWayData = seatsList.value.filter(
+    (item: any) => item.state === "treeWay"
+  );
+  // 小休
+  const unreadyData = seatsList.value.filter(
+    (item: any) => item.state === "unready"
+  );
+  // 示闲
+  const readyData = seatsList.value.filter(
+    (item: any) => item.state === "ready"
+  );
+  // 签出
+  const logoutData = seatsList.value.filter(
+    (item: any) => item.state === "logout"
+  );
+  seatsList.value = [
+    ...busyData,
+    ...acwData,
+    ...heldData,
+    ...treeWayData,
+    ...unreadyData,
+    ...readyData,
+    ...logoutData,
+  ];
+};
 onMounted(async () => {
-  await nextTick()
-  await getSeatsList();
+  await nextTick();
+  // await getSeatsList();
   // 接收消息
-  signalR.SR.on('SeatState', () => {
-    getSeatsList();
+  signalR.SR.on("SeatState", (res: any) => {
+    const item = seatsList.value.find((item: any) => item.telNo === res.telNo);
+    item.loading = true;
+    if (item) {
+      setTimeout(() => {
+        item.state = res.state;
+        item.workUserName = res.workUserName;
+        item.workUserId = res.workUserId;
+        item.loading = false;
+        sortSeatsList();
+      }, 500);
+    }
+    console.log(seatsList.value);
   });
 });
 // 监听和插话消息
 const handleCommand = (command: string, item: any) => {
-  console.log(command, item)
-  if (command === 'listen') {
-
-  } else if (command === 'interject') {
-
+  console.log(command, item);
+  if (command === "listen") {
+  } else if (command === "interject") {
   }
 };
-onUnmounted(() => {
-  signalR.SR.off('SeatState');
+onBeforeUnmount(() => {
+  signalR.SR.off("SeatState");
 });
 </script>
 <style scoped lang="scss">
@@ -235,4 +315,4 @@ onUnmounted(() => {
     }
   }
 }
-</style>
+</style>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.