Procházet zdrojové kódy

Merge branch 'dev-bxy' into 'dev'

refactor: 新增应急管理部分路由及页面,修改灾害防范部分样式

See merge request product-group-fe/sfy-safety-group/sfy-safety!103
陈昶 před 10 měsíci
rodič
revize
0092ff80a7

+ 1 - 0
package.json

@@ -26,6 +26,7 @@
     "deploy": "gh-pages -d dist"
   },
   "dependencies": {
+    "@antv/g6": "^5.0.48",
     "@element-plus/icons-vue": "2.0.9",
     "@vicons/antd": "0.12.0",
     "@vicons/ionicons5": "0.12.0",

+ 2 - 2
src/constant/nav.ts

@@ -45,8 +45,8 @@ export const NAV_LIST = [
     name: 'DisasterPrevention',
   },
   {
-    name: '应急管理',
-    path: '',
+    name: 'EmergencyManagement',
+    path: '/emergency-management',
     meta: {
       title: '应急管理',
     },

+ 65 - 0
src/router/full-routes.ts

@@ -503,6 +503,70 @@ export const disasterPreventionRoute = {
   redirect: '',
 };
 
+/** 应急管理 */
+export const emergencyManagementRoute = {
+  id: 2000,
+  parentId: -1,
+  name: 'EmergencyManagement',
+  path: '/emergency-management',
+  component: 'MENU_LAYOUT',
+  redirect: '',
+  meta: {
+    activeMenu: null,
+    alwaysShow: false,
+    frameSrc: '',
+    hidden: false,
+    icon: 'CameraOutlined',
+    isFrame: 0,
+    isRoot: false,
+    noCache: false,
+    query: '',
+    title: '应急管理',
+  },
+  children: [
+    {
+      id: 2001,
+      parentId: 2000,
+      name: 'emergency-management-overview',
+      path: 'overview',
+      component: '/emergency/overview/PageOverview',
+      redirect: '',
+      meta: {
+        activeMenu: null,
+        alwaysShow: false,
+        frameSrc: '',
+        hidden: false,
+        icon: 'OverviewIcon',
+        isFrame: 0,
+        isRoot: false,
+        noCache: false,
+        query: '',
+        title: '总览',
+      },
+    },
+    {
+      id: 2002,
+      parentId: 2000,
+      name: 'emergency-management-organization',
+      path: 'organization',
+      component: '/emergency/organization/PageOrganization',
+      redirect: '',
+      meta: {
+        activeMenu: null,
+        alwaysShow: false,
+        frameSrc: '',
+        hidden: false,
+        icon: 'OverviewIcon',
+        isFrame: 0,
+        isRoot: false,
+        noCache: false,
+        query: '',
+        title: '应急架构体系',
+      },
+    },
+  ],
+};
+
 /** 平台管理 */
 export const platformRoutes = {
   path: '/platform',
@@ -645,6 +709,7 @@ export const exceptionRouters =
 
 export const fullRoutes: AppRouteRecordRaw[] = [
   disasterPreventionRoute,
+  emergencyManagementRoute,
 
   // userRoutes,
 

+ 0 - 1
src/views/disaster/overview/PageOverview.vue

@@ -120,7 +120,6 @@
 
         .disaster-checking-lists {
           height: 65%;
-          // background-color: #fff;
           border-radius: 4px;
           margin-bottom: 10px;
         }

+ 16 - 10
src/views/disaster/overview/components/key-monitor-area/UpdateMonitorArea.vue

@@ -1,5 +1,11 @@
 <template>
-  <el-dialog v-model="visible" title="编辑监测区域相机" width="700px" @close="handleClose">
+  <el-dialog
+    v-model="visible"
+    title="编辑监测区域相机"
+    width="700px"
+    @close="handleClose"
+    class="update-monitor-dialog"
+  >
     <div class="camera-items">
       <el-input class="search-bar" v-model="searchQuery" placeholder="请输入搜索内容" clearable :prefix-icon="Search" />
       <div class="tree-container">
@@ -249,13 +255,13 @@
 </style>
 
 <style lang="scss">
-  // .el-dialog__header {
-  //   padding: 5px 5px 20px 6px;
-  // }
-
-  // .el-dialog__body {
-  //   min-height: 500px;
-  //   display: flex;
-  //   justify-content: space-evenly;
-  // }
+  .update-monitor-dialog .el-dialog__header {
+    padding: 5px 5px 20px 6px;
+  }
+
+  .update-monitor-dialog .el-dialog__body {
+    min-height: 500px;
+    display: flex;
+    justify-content: space-evenly;
+  }
 </style>

+ 166 - 0
src/views/emergency/components/OrgChart.vue

@@ -0,0 +1,166 @@
+<template>
+  <div class="org-chart-container" ref="container"></div>
+</template>
+
+<script setup lang="ts">
+  import { ref, onMounted, onBeforeUnmount, watch } from 'vue';
+  import { Graph, treeToGraphData } from '@antv/g6';
+
+  // 定义 props 接口
+  interface TreeData {
+    id: string;
+    label: string;
+    children?: TreeData[];
+  }
+
+  const props = defineProps<{
+    treeData: TreeData;
+  }>();
+
+  // 转换数据
+  const data = treeToGraphData(props.treeData);
+  // 图表容器引用
+  const container = ref<HTMLDivElement | null>(null);
+  let graph: any = null;
+
+  // 初始化图表
+  const initGraph = () => {
+    if (!container.value) return;
+
+    // 销毁旧实例
+    if (graph) {
+      graph.destroy();
+      graph = null;
+    }
+
+    // 创建新的 G6 实例
+    graph = new Graph({
+      container: container.value,
+      // width: window.innerWidth,
+      // height: window.innerHeight,
+      data,
+      layout: {
+        type: 'dagre',
+        rankdir: 'LR', // 水平方向布局
+        nodesep: 100,
+        ranksep: 120,
+        preventOverlap: true, // 防止节点重叠
+        nodeStrength: -50, // 节点之间的斥力
+        edgeStrength: 0.5, // 边的弹性系数
+        iterations: 200, // 迭代次数
+        animation: true, // 启用布局动画
+      },
+      behaviors: [
+        'drag-canvas',
+        {
+          type: 'zoom-canvas',
+          sensitivity: 1.5, // 配置灵敏度
+          key: 'zoom-behavior', // 为交互指定key,便于后续更新
+        },
+      ],
+      autoFit: {
+        type: 'view', // 自适应类型:'view' 或 'center'
+        options: {
+          // 仅适用于 'view' 类型
+          when: 'always', // 何时适配:'overflow'(仅当内容溢出时) 或 'always'(总是适配)
+          direction: 'both', // 适配方向:'x'、'y' 或 'both'
+        },
+        animation: {
+          // 自适应动画效果
+          duration: 1000, // 动画持续时间(毫秒)
+          easing: 'ease-in-out', // 动画缓动函数
+        },
+      },
+      node: {
+        type: 'circle', // 节点类型
+        style: {
+          fill: '#e6f7ff', // 填充色
+          stroke: '#91d5ff', // 边框色
+          lineWidth: 1, // 边框宽度
+          r: 20, // 半径
+          labelText: (d) => d.id, // 标签文本
+        },
+        // 节点状态样式
+        state: {
+          hover: {
+            lineWidth: 2,
+            stroke: '#69c0ff',
+          },
+          selected: {
+            fill: '#bae7ff',
+            stroke: '#1890ff',
+            lineWidth: 2,
+          },
+        },
+      },
+      edge: {
+        type: 'polyline', // 边类型
+        style: {
+          stroke: '#91d5ff', // 边的颜色
+          lineWidth: 2, // 边的宽度
+          endArrow: true, // 是否有箭头
+        },
+        // 边的状态样式
+        state: {
+          selected: {
+            stroke: '#1890ff',
+            lineWidth: 3,
+          },
+        },
+      },
+    });
+
+    // 渲染
+    graph.render();
+
+    // 添加交互效果
+    graph.on('node:mouseenter', (evt) => {
+      const node = evt.item;
+      graph.setItemState(node, 'hover', true);
+    });
+
+    graph.on('node:mouseleave', (evt) => {
+      const node = evt.item;
+      graph.setItemState(node, 'hover', false);
+    });
+
+    // 响应窗口大小变化
+    window.addEventListener('resize', handleResize);
+  };
+
+  // 处理窗口大小变化
+  const handleResize = () => {
+    if (graph.get('destroyed')) return;
+    if (container.value) {
+      graph.changeSize(container.value.clientWidth, container.value.clientHeight);
+    }
+  };
+
+  // 监听 treeData 变化
+  watch(
+    () => props.treeData,
+    () => {
+      initGraph();
+    },
+    { deep: true },
+  );
+
+  // 生命周期钩子
+  onMounted(() => {
+    initGraph();
+  });
+
+  onBeforeUnmount(() => {
+    window.removeEventListener('resize', handleResize);
+    if (graph) {
+      graph.destroy();
+    }
+  });
+</script>
+
+<style scoped>
+  .org-chart-container {
+    width: 100%;
+    height: 100%;
+  }
+</style>

+ 70 - 0
src/views/emergency/organization/PageOrganization.vue

@@ -0,0 +1,70 @@
+<template>
+  <div class="page-organization-container">
+    <div class="page-organization-header">
+      <div class="page-organization-header-title"> 应急架构体系 </div>
+    </div>
+    <div class="page-organization-content">
+      <OrgChart :treeData="treeData" />
+    </div>
+    <div class="page-organization-footer"> 编辑 </div>
+  </div>
+</template>
+
+<script setup lang="ts">
+  import OrgChart from '../components/OrgChart.vue';
+
+  const treeData = {
+    id: 'root',
+    label: '应急管理体系',
+    children: [
+      {
+        id: 'group1',
+        label: '应急领导小组',
+        children: [
+          { id: 'team1', label: '综合协调组' },
+          { id: 'team2', label: '抢险处置组' },
+          { id: 'team3', label: '应急抢修组' },
+          { id: 'team4', label: '救治保障组' },
+        ],
+      },
+    ],
+  };
+</script>
+
+<style scoped>
+  .page-organization-container {
+    width: 100%;
+    height: 100%;
+  }
+
+  .page-organization-header {
+    width: 100%;
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #f5f5f5;
+    border-bottom: 1px solid #e0e0e0;
+
+    .page-organization-header-title {
+      font-size: 20px;
+      font-weight: 500;
+      color: #333;
+    }
+  }
+
+  .page-organization-content {
+    width: 100%;
+    height: calc(100% - 120px);
+  }
+
+  .page-organization-footer {
+    width: 100%;
+    height: 60px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: #f5f5f5;
+    border-top: 1px solid #e0e0e0;
+  }
+</style>

+ 17 - 0
src/views/emergency/overview/PageOverview.vue

@@ -0,0 +1,17 @@
+<template>
+  <div class="page-organization"> 总览 </div>
+</template>
+
+<script setup lang="ts">
+  // 这里可以引入需要的模块和组件
+  import { ref } from 'vue';
+
+  // 示例:定义响应式变量
+  const message = ref('Hello PageOrganization');
+</script>
+
+<style scoped>
+  .page-organization {
+    padding: 24px;
+  }
+</style>