Jelajahi Sumber

feat: 院区安全弹窗

wyf 6 bulan lalu
induk
melakukan
5601ce3ad5

+ 2 - 0
package.json

@@ -49,8 +49,10 @@
     "form-data": "4.0.0",
     "html2canvas": "1.0.0",
     "lodash-es": "4.17.21",
+    "mitt": "3.0.1",
     "mockjs": "1.1.0",
     "mpegts.js": "1.7.3",
+    "notivue": "2.4.5",
     "nprogress": "0.2.0",
     "perfect-scrollbar": "1.5.5",
     "pinia": "2.0.16",

+ 3 - 0
src/views/institute-safety/modules/safety-company-home/CompanyHome.vue

@@ -16,6 +16,7 @@
   import SurveillanceList from './components/SurveillanceList.vue';
   import RealtimeSurveillance from './components/RealtimeSurveillance.vue';
   import QuestionList from '../safety-question-list/QuestionList.vue';
+  import useViolationNoticeCompany from './hooks/use-violation-notice-company';
 
   import { ref } from 'vue';
 
@@ -23,6 +24,8 @@
 
   const showSurveillanceList = ref(false);
   const showQuestionList = ref(false);
+
+  useViolationNoticeCompany();
 </script>
 
 <style scoped>

+ 31 - 2
src/views/institute-safety/modules/safety-company-home/apis/index.ts

@@ -1,6 +1,9 @@
 import { http } from '@/utils/http/axios';
+import type { QueryPageRequest, QueryPageResponse } from '@/types/basic-query';
 
-// 查询今日异常告警数量
+import type { IssueItem } from '../types';
+
+// 查询今日异常告警数量(评分)
 export function getTodayIssueNumber() {
   return http.request<number>({
     url: '/issue/queryTodayIssueCount',
@@ -8,4 +11,30 @@ export function getTodayIssueNumber() {
   });
 }
 
-// 查询重点监控区域
+// 查询分页异常告警问题列表
+export function getIssueList(data: QueryPageRequest<{ workshopCodeList: string[] }>) {
+  return http.request<QueryPageResponse<IssueItem>>({
+    url: '/issue/queryIssuePageByWorkshopCodes',
+    method: 'post',
+    data,
+  });
+}
+
+// 查询弹窗报警
+export function getNewIssueList() {
+  return http.request<IssueItem[]>({
+    url: '/issue/queryTodayNewIssueList',
+    method: 'get',
+  });
+}
+
+// 更新已读问题id
+export function updateReadIssueId(issueId: number) {
+  return http.request({
+    url: '/issue/updateLastReadIssueId',
+    method: 'post',
+    params: {
+      issueId,
+    },
+  });
+}

+ 83 - 0
src/views/institute-safety/modules/safety-company-home/hooks/use-violation-notice-company.ts

@@ -0,0 +1,83 @@
+// 报警消息实时提醒
+
+import { getNewIssueList, updateReadIssueId } from '../apis';
+import useViolationNoticeStore, { getPlace, emitter } from '../stores/use-violation-notice-store';
+import { onUnmounted, onMounted } from 'vue';
+import dayjs from 'dayjs';
+import { push } from 'notivue';
+
+const useViolationRealtimeCompany = () => {
+  /** 消息队列,最新的排在最前面,最老的排在最后面 */
+  // 报警消息最后返回数据的id
+  const violationStore = useViolationNoticeStore();
+
+  let apiTimer: number;
+  let isFirstLoad = true;
+  //弹出消息
+  const showNotice = () => {
+    const showItem = violationStore.getLastNotice();
+    // 从数组最末尾弹出消息
+    if (!showItem) return;
+
+    // 只显示当天的时分秒
+    const renderTime = dayjs(showItem.createdAt).format('HH:mm:ss');
+    const renderPlace = getPlace([showItem.workshopName, showItem.workspaceName]);
+    push.success({
+      props: {
+        thumbnail: showItem.pictures?.[0],
+        title: showItem.title,
+        message: `<div>
+      <div>地点:${renderPlace}</div>
+      <div>时间:${renderTime}</div>
+      </div>`,
+        onClick: () => {
+          // 这里打开问题列表
+        },
+      },
+      onAutoClear(item) {
+        showNotice();
+      },
+      onManualClear(item) {
+        showNotice();
+      },
+    });
+  };
+
+  emitter.on('showNotice', showNotice);
+
+  const getViolationsRealtime = () => {
+    getNewIssueList().then((res) => {
+      if (!res || res?.length === 0) return;
+      if (isFirstLoad) {
+        // 如果第一次加载,只显示第一条
+        violationStore.add([res[0]]);
+        isFirstLoad = false;
+      } else {
+        violationStore.add(res);
+      }
+      // 在此次调用更新id接口
+      updateReadIssueId(res[0].id);
+    });
+  };
+
+  /** 轮询api */
+  const pollingApi = () => {
+    getViolationsRealtime();
+    clearInterval(apiTimer);
+    apiTimer = window.setInterval(() => {
+      getViolationsRealtime();
+    }, 5000);
+  };
+
+  onMounted(() => {
+    violationStore.clear();
+    pollingApi();
+  });
+
+  onUnmounted(() => {
+    clearInterval(apiTimer);
+    violationStore.clear();
+  });
+};
+
+export default useViolationRealtimeCompany;

+ 45 - 0
src/views/institute-safety/modules/safety-company-home/stores/use-violation-notice-store.ts

@@ -0,0 +1,45 @@
+import { IssueItem } from '../types';
+import { NotificationHandle } from 'element-plus';
+import { defineStore } from 'pinia';
+import { ref } from 'vue';
+
+import mitt from 'mitt';
+
+export const getPlace = (arr: [string, string]): string => {
+  return arr.filter(Boolean).join('-');
+};
+export const emitter = mitt();
+
+/** 消息轮播的store */
+const useViolationNoticeStore = defineStore('violation-notice', () => {
+  const list = ref<IssueItem[]>([]);
+  let notiHandler: NotificationHandle | null = null;
+
+  /** 追加新消息 */
+  const add = (newList: IssueItem[]) => {
+    // 只有消息为空时,才需要去主动触发消息提示
+    if (list.value.length > 0) {
+      list.value = [...newList, ...list.value];
+    } else {
+      list.value = [...newList];
+      emitter.emit('showNotice');
+    }
+  };
+
+  const clear = () => {
+    // 清空的时候要把当前已有的也清空掉,同时关闭消息
+    list.value = [];
+    notiHandler?.close();
+  };
+
+  /** 获取最后一条消息(最旧的) */
+  const getLastNotice = () => {
+    if (list.value.length === 0) return null;
+    // 获取最后一条,同时原数据也要减去这一条
+    return list.value.pop()!;
+  };
+
+  return { list, add, clear, getLastNotice };
+});
+
+export default useViolationNoticeStore;

+ 72 - 0
src/views/institute-safety/modules/safety-company-home/types.ts

@@ -0,0 +1,72 @@
+export interface IssueItem {
+  /*问题单id */
+  id: number;
+  /*问题单标题 */
+  title: string;
+  /*问题单状态 */
+  issueState: number;
+  /*问题单来源 */
+  source: number;
+  /*一级分类类型 */
+  issueMainType: number;
+  /*问题算法类型(algo_id) */
+  issueType: number;
+  /*节点类型 */
+  flowNodeType: number;
+  /*问题严重等级 */
+  severityLevel: number;
+  /*优先级,0-未加急,1-加急 */
+  priority: number;
+  /*创建者id */
+  createdBy: number;
+  /*创建者名称 */
+  createdByName: string;
+  /*是否匿名 */
+  isAnonymous: boolean;
+  /*问题描述 */
+  description: string;
+  /*摄像头id */
+  cameraId: number;
+  /*摄像头code */
+  cameraCode: string;
+  /*车间id */
+  workshopId: number;
+  /*车间名称 */
+  workshopName: string;
+  /*工位id */
+  workspaceId: number;
+  /*工位名称 */
+  workspaceName: string;
+  /*坐标点 */
+  points: string;
+  /*负责人id */
+  personInCharge: number;
+  /*负责人名称 */
+  personNameInCharge: string;
+  /*创建时间 */
+  createdAt: string;
+  /*更新时间 */
+  updatedAt: string;
+  /*处理方式 */
+  handleMode: number;
+  /*处理人id */
+  handlerId: number;
+  /*处理人名称 */
+  handlerName: string;
+  /*问题描述图片url集合 */
+  pictures: string[];
+  /*问题视频uri集合 */
+  videos: string[];
+  /*0-未删除,大于0(时间戳)-已删除 */
+  isDeleted: number;
+  /*是否隐藏 */
+  isHide: boolean;
+  /*租户id */
+  tenantId: number;
+  /*是否在审核阶段改派 */
+  isReviewTransfer: number;
+  /*权限类型:1-查看 2-审核 3-处理 4-复核 */
+  permissionType: number;
+  /*超时状态:0-正常,1-超期,2-长期 */
+  timeoutType: number;
+}

+ 92 - 3
src/views/institute-safety/modules/safety-workshop-list/WorkshopList.vue

@@ -5,171 +5,260 @@
       <el-tooltip placement="top" :content="item.name">
         <div class="workshop-list-item-name">{{ item.name }}</div>
       </el-tooltip>
-      <img class="workshop-list-item-icon" v-if="true" src="@/assets/images/institute-safety/alert.png" alt="" />
+      <img class="workshop-list-item-icon" v-if="item.status" src="@/assets/images/institute-safety/alert.png" alt="" />
     </div>
   </div>
 </template>
 
 <script setup lang="ts">
+  import { onMounted, ref } from 'vue';
   import { ElTooltip } from 'element-plus';
-  const staticWorkshopList = [
+  import { getWorkshopTodayExceptionStatus } from './apis';
+
+  const staticWorkshopList = ref([
     {
       id: 1,
+      status: false,
+      workshopCode: 'R&DBuilding',
       name: '设计研发大楼',
     },
     {
       id: 2,
+      status: false,
+      workshopCode: 'ITCenter',
       name: '信息中心',
     },
     {
       id: 3,
+      status: false,
+      workshopCode: 'ArchivesCenter',
       name: '档案中心',
     },
     {
       id: 4,
+      status: false,
+      workshopCode: 'Canteen',
       name: '职工食堂1',
     },
     {
       id: 5,
+      status: false,
+      workshopCode: 'GeneralManagementBuilding',
       name: '综合楼',
     },
     {
       id: 6,
+      status: false,
+      workshopCode: 'ExecutiveBuilding',
       name: '行政办公楼',
     },
     {
       id: 7,
+      status: false,
+      workshopCode: 'ChiefDesignerBuilding',
       name: '总师楼',
     },
     {
       id: 8,
+      status: false,
+      workshopCode: 'CustomizationCenter&MultifunctionalPrototypeHangar',
       name: '客户选型中心及多功能样机库',
     },
     {
       id: 9,
+      status: false,
+      workshopCode: 'MiniCanteen',
       name: '职工食堂2',
     },
     {
       id: 10,
+      status: false,
+      workshopCode: 'C919SystemIntegrationLab',
       name: 'C919系统综合实验室',
     },
     {
       id: 11,
+      status: false,
+      workshopCode: '35VElectricityTransformerStation',
       name: '35KV变电站',
     },
     {
       id: 12,
+      status: false,
+      workshopCode: 'StressLab',
       name: '强度试验室',
     },
     {
       id: 13,
+      status: false,
+      workshopCode: 'GarbageStation',
       name: '垃圾房',
     },
     {
       id: 14,
+      status: false,
+      workshopCode: 'ElectricityDistributionStation3',
       name: '配电站3',
     },
     {
       id: 15,
+      status: false,
+      workshopCode: 'StructuralFunctionLab',
       name: '机构功能试验室',
     },
     {
       id: 16,
+      status: false,
+      workshopCode: 'EnvironmentalControlSystemLab',
       name: '环控试验室',
     },
     {
       id: 17,
+      status: false,
+      workshopCode: 'AirCompressionStation',
       name: '空压站',
     },
     {
       id: 18,
+      status: false,
+      workshopCode: 'FuelSystemLab',
       name: '燃油试验室',
     },
     {
       id: 19,
+      status: false,
+      workshopCode: 'FireProtectionSystemLab',
       name: '防火试验室',
     },
     {
       id: 20,
+      status: false,
+      workshopCode: 'KerodanePumpingStation',
       name: '煤油泵站',
     },
     {
       id: 21,
+      status: false,
+      workshopCode: 'StaffResidence',
       name: '单身公寓',
     },
     {
       id: 22,
+      status: false,
+      workshopCode: 'StaffActivityCenter',
       name: '职工活动中心',
     },
     {
       id: 23,
+      status: false,
+      workshopCode: 'TechnologyInnovationBuilding',
       name: '科技创新楼',
     },
     {
       id: 24,
+      status: false,
+      workshopCode: 'LogisticsManagementCenter',
       name: '综合保障管理中心',
     },
     {
       id: 25,
+      status: false,
+      workshopCode: 'E3Lab',
       name: '电磁环境效应试验室',
     },
     {
       id: 26,
+      status: false,
+      workshopCode: 'ElectricityDistributionStation1',
       name: '配电站1',
     },
     {
       id: 27,
+      status: false,
+      workshopCode: 'ElectricityDistributionStation2',
       name: '配电站2',
     },
     {
       id: 28,
+      status: false,
+      workshopCode: 'Library',
       name: '阅览中心',
     },
     {
       id: 29,
+      status: false,
+      workshopCode: 'RegionalJetSystemIntegrationLab',
       name: '支线客机系统综合试验室',
     },
     {
       id: 30,
+      status: false,
+      workshopCode: 'FlightControlSystemLab',
       name: '飞控系统试验室',
     },
     {
       id: 31,
+      status: false,
+      workshopCode: 'AvionicSystemLab',
       name: '航电系统试验室',
     },
     {
       id: 32,
+      status: false,
+      workshopCode: 'ElectricalSystemLab',
       name: '电气系统试验室',
     },
     {
       id: 33,
+      status: false,
+      workshopCode: 'CR929SystemIntegrationLab',
       name: 'CR929系统综合试验室',
     },
     {
       id: 34,
+      status: false,
+      workshopCode: 'AircraftIntegrationLab',
       name: '总体集成试验室',
     },
     {
       id: 35,
+      status: false,
+      workshopCode: 'DigitalSimulationLab',
       name: '数字仿真试验室',
     },
     {
       id: 36,
+      status: false,
+      workshopCode: 'AdvancedMaterialLab',
       name: '先进材料试验室',
     },
     {
       id: 37,
+      status: false,
+      workshopCode: 'ProgramDevelopmentCenter',
       name: '型号发展中心',
     },
     {
       id: 38,
+      status: false,
+      workshopCode: 'StructuralIntegrationLab',
       name: '结构综合试验室',
     },
     {
       id: 39,
+      status: false,
+      workshopCode: 'FundamentalTechnologyLab',
       name: '基础技术试验室',
     },
-  ];
+  ]);
+
+  onMounted(() => {
+    getWorkshopTodayExceptionStatus(staticWorkshopList.value.map((item) => item.workshopCode)).then((res) => {
+      staticWorkshopList.value.forEach((item) => {
+        item.status = res.find((x) => x.workshopCode === item.workshopCode)!.exceptionStatus;
+      });
+    });
+  });
 </script>
 
 <style scoped>

+ 17 - 0
src/views/institute-safety/modules/safety-workshop-list/apis/index.ts

@@ -0,0 +1,17 @@
+import { http } from '@/utils/http/axios';
+
+// 查询车间今日是否有异常状态
+export function getWorkshopTodayExceptionStatus(list: string[]) {
+  return http.request<
+    {
+      workshopCode: string;
+      exceptionStatus: boolean;
+    }[]
+  >({
+    url: '/issue/queryWorkshopTodayExceptionStatus',
+    method: 'post',
+    data: {
+      workshopCodeList: list,
+    },
+  });
+}