Просмотр исходного кода

Merge branch 'master' of http://39.97.59.228:8013/hrx/goaf-monitoring-system

lxh 5 месяцев назад
Родитель
Сommit
f644636289

+ 13 - 6
src/components/Configurable/preset/BlastDelta.vue

@@ -24,7 +24,7 @@
         <div class="item-name" v-for="item in legendList" :key="item">{{ item.name }}</div>
       </div> -->
     </div>
-    <div class="line-legend">
+    <div class="line-legend" :style="legendStyle">
       <div class="legend-box" v-for="(item, index) in legendList" :key="index">
         <span class="legend-icon"></span>
         <span class="legend-label">{{ item.name }}</span>
@@ -78,6 +78,10 @@
       type: String,
       default: '#fff',
     },
+    legendStyle: {
+      type: Object,
+      default: () => ({ left: '50%', top: '20px' }),
+    },
   });
 
   // 响应式数据
@@ -359,6 +363,9 @@
     position: relative;
     width: 100%;
     height: 100%;
+    padding-left: 20px;
+    padding-bottom: 20px;
+    box-sizing: border-box;
 
     // .blast-title {
     //   position: absolute;
@@ -435,13 +442,13 @@
 
     .coords {
       position: absolute;
-      left: 50%;
-      top: 50%;
+      left: 20px;
+      bottom: 20px;
       width: 90%;
       height: 80%;
       border-left: 1px solid #006c9d;
       border-bottom: 1px solid #006c9d;
-      transform: translate(-45%, -46%);
+      // transform: translate(-45%, -46%);
 
       .coord-lineY {
         position: absolute;
@@ -453,7 +460,7 @@
 
       .coord-labelY {
         position: absolute;
-        left: -25px;
+        left: -20px;
         top: -5px;
         width: 20px;
         height: 100%;
@@ -472,7 +479,7 @@
         display: flex;
         justify-content: flex-end;
         position: absolute;
-        bottom: -25px;
+        bottom: -20px;
         left: -5px;
         width: 100%;
         height: 20px;

+ 14 - 6
src/components/Form/src/jeecg/components/MineCascader/MineCascader.vue

@@ -1,9 +1,18 @@
 <template>
-  <Cascader :value="innerValue" :options="getDepartTree" placeholder="全部" :field-names="{
-    label: 'departName',
-    value: 'id',
-    children: 'childDepart',
-  }" :show-search="showSearch" :allow-clear="allowClear" :change-on-select="changeOnSelect" @change="handleChange">
+  <Cascader
+    :value="innerValue"
+    :options="options"
+    placeholder="全部"
+    :field-names="{
+      label: 'departName',
+      value: 'id',
+      children: 'childDepart',
+    }"
+    :show-search="showSearch"
+    :allow-clear="allowClear"
+    :change-on-select="changeOnSelect"
+    @change="handleChange"
+  >
     <template #displayRender="{ labels }">
       {{ labels[labels.length - 1] }}
     </template>
@@ -78,7 +87,6 @@ export default defineComponent({
       }
       return null;
     }
-    console.log(findNodeWithPath(getDepartTree.value, props.mineCode),'findNodeWithPath(getDepartTree.value, props.mineCode)')
     const defaultValue = computed(() => {
       if (props.mineCode) {
         return findNodeWithPath(getDepartTree.value, props.mineCode)

+ 4 - 0
src/design/ant/index.less

@@ -81,6 +81,10 @@
   }
   .ant-modal-content {
     padding: 0;
+
+    .ant-modal-footer {
+      padding: 16px;
+    }
   }
 }
 

+ 1 - 0
src/design/color.less

@@ -59,6 +59,7 @@ html {
 @header-light-bg-hover-color: #f6f6f6;
 @header-light-desc-color: #7c8087;
 @header-light-bottom-border-color: #eee;
+@header-static-bg-color: linear-gradient(90deg, #345991, #264471);
 // top-menu
 @top-menu-active-bg-color: var(--header-active-menu-bg-color);
 

+ 1 - 0
src/design/public.less

@@ -116,6 +116,7 @@
   padding: 0 12px 6px 12px;
   margin: 16px;
   border: 1px solid @border-color-base;
+  border-radius: 4px;
 }
 
 .action-btn {

+ 2 - 1
src/layouts/default/header/index.less

@@ -170,7 +170,8 @@
   }
 
   &--dark {
-    background-color: @header-dark-bg-color !important;
+    // background-color: @header-dark-bg-color !important;
+    background-image: @header-static-bg-color !important;
     // border-bottom: 1px solid @border-color-base;
     // update-begin--author:liaozhiyang---date:20250818---for:【issues/8709】LayoutContent样式多出1px
     // border-left: 1px solid @border-color-base;

+ 4 - 2
src/layouts/default/index.vue

@@ -94,9 +94,11 @@
 
     &-main {
       width: 100%;
-      border-top-right-radius: 10px;
-      border-bottom-right-radius: 10px;
+      border-top-right-radius: 4px;
+      border-bottom-right-radius: 4px;
       // background-color: #aaaaaa32;
+      // border: 1px solid @white;
+      box-shadow: inset 0 0 5px 0 @white;
       background: rgba(255, 255, 255, 0.2);
       backdrop-filter: blur(14px);
       // -webkit-backdrop-filter: blur(10px);

+ 1 - 1
src/settings/designSetting.ts

@@ -37,7 +37,7 @@ export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
 
 // sider preset color
 export const SIDE_BAR_BG_COLOR_LIST: string[] = [
-  '#304156',
+  '#202d3d',
   // '#212121',
   '#009688',
   '#273352',

+ 73 - 27
src/store/modules/mine.ts

@@ -4,7 +4,7 @@ import { ref, computed } from 'vue';
 import { getEnfMineTree } from '/@/api/sys/menu';
 import { getUserMinePermissionData } from '/@/components/Form/src/jeecg/components/MineCascader/mineData.api';
 import { findNode, findNodeAll, findPath, listToTree, treeToList } from '/@/utils/helper/treeHelper';
-import { isArray } from 'lodash';
+import { isArray, isFunction, isNil } from 'lodash';
 
 export interface MineDepartment {
   /** 唯一标识 */
@@ -37,7 +37,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
   const departTree = ref<MineDepartment[]>([]);
 
   /** 原始组织树(保存原始数据,用于恢复或重新过滤) */
-  const rawTree = ref<MineDepartment[]>([]);
+  // const rawTree = ref<MineDepartment[]>([]);
 
   // ==================== Getter 计算属性 ====================
 
@@ -52,7 +52,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
 
   /** 获取当前选中的部门在组织树中的访问路径 */
   const getDepartPath = computed(() => {
-    return findPath(departTree.value, (item) => item.id === getDepartId.value, DEFAULT_CONFIG) || [];
+    return calcDepartPathById(getDepartId.value, getDepartTree.value);
   });
 
   /**
@@ -63,15 +63,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
    */
   const getMineCode = computed(() => {
     const target = getDepartId.value ? [depart.value] : departTree.value;
-    const list = treeToList(target, DEFAULT_CONFIG);
-
-    if (isArray(list)) {
-      return list
-        .filter((item) => item.isLeaf && item.fax) // 只取叶子节点(矿井)且fax不为空
-        .map((item) => item.fax!) // 提取矿井编码
-        .join(','); // 用逗号分隔多个矿井编码
-    }
-    return '';
+    return calcMineCodeByDepart(target);
   });
 
   // ==================== Action 方法 ====================
@@ -80,7 +72,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
    * 设置当前选中的部门
    * @param dep - 部门对象
    */
-  function setDepart(dep: MineDepartment) {
+  function setDepart(dep?: MineDepartment) {
     // if (isNil(dep) || isEmpty(dep)) return;
     depart.value = dep;
   }
@@ -90,7 +82,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
    * @param id - 部门ID,默认为空字符串
    */
   function setDepartById(id: string = '') {
-    const node = findNode(departTree.value, (item) => item.id === id, DEFAULT_CONFIG);
+    const node = findDepartById(id, departTree.value);
     setDepart(node);
   }
 
@@ -120,7 +112,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
 
       departTree.value = tree;
       // 深拷贝保存原始数据,用于过滤后恢复
-      rawTree.value = JSON.parse(JSON.stringify(tree));
+      // rawTree.value = JSON.parse(JSON.stringify(tree));
 
       // 如果需要自动选中第一个叶子节点(矿井),可以取消注释以下代码
       /*
@@ -142,30 +134,83 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
   }
 
   /**
-   * 过滤组织树
+   * 清除选中的部门
+   */
+  function clearDepart() {
+    depart.value = undefined;
+  }
+
+  /**
+   * 工具函数,过滤组织树并返回,不改变组织树数据
    * @param fn - 过滤函数,返回true表示保留该节点
    */
   function filterDepartTree(fn: (node: MineDepartment) => boolean) {
     // 只有在有原始数据时才进行过滤
-    if (rawTree.value.length > 0) {
-      departTree.value = findNodeAll(rawTree.value, fn, DEFAULT_CONFIG);
+    if (departTree.value.length > 0) {
+      return findNodeAll(departTree.value, fn, DEFAULT_CONFIG);
     }
+    return [];
   }
 
   /**
-   * 恢复原始组织树(取消过滤)
+   * 工具函数,获取给出的部门下矿井编号的集合
    */
-  function restoreDepartTree() {
-    if (rawTree.value.length > 0) {
-      departTree.value = JSON.parse(JSON.stringify(rawTree.value));
+  function calcMineCodeByDepart(depart?: MineDepartment): string;
+  function calcMineCodeByDepart(depart?: (MineDepartment | undefined)[]): string;
+  function calcMineCodeByDepart(depart?: MineDepartment | (MineDepartment | undefined)[]): string {
+    if (!depart) return '';
+    if (!isArray(depart)) {
+      depart = [depart];
     }
+    const target = depart.filter((e) => !isNil(e));
+    const list = treeToList(target, DEFAULT_CONFIG);
+
+    if (isArray(list)) {
+      return list
+        .filter((item) => item.isLeaf && item.fax) // 只取叶子节点(矿井)且fax不为空
+        .map((item) => item.fax!) // 提取矿井编码
+        .join(','); // 用逗号分隔多个矿井编码
+    }
+    return '';
   }
 
   /**
-   * 清除选中的部门
+   * 工具函数,获取走到所选部门必要路径
    */
-  function clearDepart() {
-    depart.value = undefined;
+  function calcDepartPathById<T>(id?: string, depart?: MineDepartment, mapFn?: (node: MineDepartment) => T): T[];
+  function calcDepartPathById<T>(id?: string, depart?: (MineDepartment | undefined)[], mapFn?: (node: MineDepartment) => T): T[];
+  function calcDepartPathById<T>(id?: string, depart?: MineDepartment | (MineDepartment | undefined)[], mapFn?: (node: MineDepartment) => T) {
+    if (!id) return [];
+    if (!depart) return [];
+    if (!isArray(depart)) {
+      depart = [depart];
+    }
+    const target = depart.filter((e) => !isNil(e));
+    const path = findPath(target, (e) => e.id === id, DEFAULT_CONFIG);
+
+    if (!isArray(path)) {
+      return [];
+    }
+    if (isFunction(mapFn)) {
+      return path.map(mapFn);
+    }
+    return path;
+  }
+
+  function findDepartById(id?: string, depart?: MineDepartment): MineDepartment | undefined;
+  function findDepartById(id?: string, depart?: (MineDepartment | undefined)[]): MineDepartment | undefined;
+  function findDepartById(id?: string, depart?: MineDepartment | (MineDepartment | undefined)[]): MineDepartment | undefined {
+    if (!id) return;
+    if (!depart) return;
+    if (!isArray(depart)) {
+      depart = [depart];
+    }
+
+    const target = depart.filter((e) => !isNil(e));
+    const node = findNode(target, (e) => e.id === id, DEFAULT_CONFIG);
+
+    if (isNil(node)) return;
+    return node;
   }
 
   // ==================== 暴露的属性和方法 ====================
@@ -174,7 +219,6 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
     // --- State(可修改)---
     depart,
     departTree,
-    rawTree,
 
     // --- Getter(只读计算属性)---
     getDepart,
@@ -189,7 +233,9 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
     // setDepartTree,
     fetchDepartTree,
     filterDepartTree,
-    restoreDepartTree,
     clearDepart,
+    calcMineCodeByDepart,
+    calcDepartPathById,
+    findDepartById,
   };
 });

+ 28 - 13
src/views/monitor/sealedMonitor/components/RealtimeDetailsModal.vue

@@ -31,13 +31,18 @@
     <!-- 图表区域 -->
     <div class="chart-area">
       <div class="chart-item">
-        <div class="chart-title">爆炸三角形</div>
+        <div class="chart-title pl-20px">爆炸三角形</div>
         <div class="chart-placeholder">
-          <BlastDelta :posMonitor="dataRef" :canvasSize="{ width: '95%', height: '95%' }" text-color="#000" />
+          <BlastDelta
+            :posMonitor="dataRef"
+            :canvas-size="{ width: 311, height: 149 }"
+            :legendStyle="{ left: '50%', top: '10px' }"
+            text-color="#000"
+          />
         </div>
       </div>
       <div class="chart-item">
-        <div class="chart-title">气体浓度曲线</div>
+        <div class="chart-title pl-20px">气体浓度曲线</div>
         <div class="chart-placeholder">
           <CustomChart
             :chart-data="{ chartData: dataArray }"
@@ -52,7 +57,7 @@
         </div>
       </div>
       <div class="chart-item">
-        <div class="chart-title">内外压力及压差曲线</div>
+        <div class="chart-title pl-20px">内外压力及压差曲线</div>
         <div class="chart-placeholder">
           <CustomChart
             :chart-data="{ chartData: dataArray }"
@@ -133,7 +138,7 @@
 
       function fetchDetailData() {
         const { mineCode, goafId } = dataRef.value;
-        getGoafData({ mineCode, goafId }).then((r) => {
+        getGoafData({ mineCodeList: mineCode, goafId }).then((r) => {
           dataRef.value = last(r);
           push(dataRef.value);
           // push(dataRef.value)
@@ -191,7 +196,7 @@
   .label {
     color: #666;
     margin-right: 8px;
-    min-width: 80px;
+    min-width: 90px;
     flex-shrink: 0; /* 标签宽度不收缩 */
   }
   .value {
@@ -201,9 +206,10 @@
     text-overflow: ellipsis;
   }
   .data-cards {
-    display: grid;
-    grid-template-columns: repeat(8, 1fr);
-    gap: 16px;
+    display: flex;
+    // grid-template-columns: repeat(8, 1fr);
+    // gap: 16px;
+    justify-content: space-evenly;
     margin-bottom: 20px;
     padding: 20px;
     border: 1px solid @border-color-base;
@@ -230,7 +236,7 @@
   .chart-area {
     display: flex;
     flex-wrap: wrap;
-    gap: 16px;
+    gap: 20px;
     padding: 20px;
     border: 1px solid @border-color-base;
     border-radius: 10px;
@@ -239,17 +245,26 @@
   }
   .chart-item {
     flex: 1;
-    min-width: 200px;
+    // flex-basis: 6;
+    // flex-shrink: 1;
+    // min-width: 200px;
+    &:first-child {
+      // flex-basis: 380px;
+      flex: 0 0 380px;
+      // flex-shrink: 0;
+      // flex-grow: 1;
+    }
   }
   .chart-title {
     font-size: 14px;
     font-weight: 500;
     margin-bottom: 8px;
-    color: #333;
+    font-weight: bold;
+    color: @text-color-call-out;
   }
   .chart-placeholder {
     width: 100%;
-    height: 150px;
+    height: 200px;
     border-radius: 4px;
     overflow: hidden;
   }

+ 10 - 40
src/views/monitor/sealedMonitor/hooks/form.ts

@@ -3,61 +3,31 @@ import { ref } from 'vue';
 import { useRoute } from 'vue-router';
 import { getGoafSelectOption } from '../monitor.api';
 import { useMineDepartmentStore } from '/@/store/modules/mine';
-import { historicalFormSchema, searchFormSchema } from '../monitor.data';
-import { FormSchema } from '/@/components/Form';
 
 export function useInitForm() {
   const mineStore = useMineDepartmentStore();
   const route = useRoute();
-  const id = last(route.fullPath.split('/'));
+  const departId = last(route.fullPath.split('/'));
+  const code = route.params.mineCode;
+
+  if (code) {
+    mineStore.setDepartById(code as string);
+    initGoafOptions(code);
+  }
 
   // 采空区选择器
   const goafId = ref('');
   const goafOptions = ref<any[]>([]);
 
-  function initGoafOptions() {
-    getGoafSelectOption({ mineCode: mineStore.getMineCode }).then(({ options, defaultValue }) => {
+  function initGoafOptions(mineCode) {
+    return getGoafSelectOption({ mineCode }).then(({ options, defaultValue }) => {
       goafOptions.value = options;
       goafId.value = defaultValue;
     });
   }
-  initGoafOptions();
-
-  const realtimeSchemas: FormSchema[] = [
-    {
-      field: 'mineCodeList',
-      label: '煤矿名称',
-      component: 'MineCascader',
-      colProps: { span: 6 },
-      componentProps: {
-        resetOnDestroy: true,
-        rootId: id,
-      },
-    },
-    ...searchFormSchema,
-  ];
-
-  const historySchemas: FormSchema[] = [
-    {
-      field: 'mineCodeList',
-      label: '煤矿名称',
-      component: 'MineCascader',
-      colProps: { span: 6 },
-      required: true,
-      componentProps: {
-        resetOnDestroy: true,
-        rootId: id,
-        onChange() {
-          initGoafOptions();
-        },
-      },
-    },
-    ...historicalFormSchema,
-  ];
 
   return {
-    historySchemas,
-    realtimeSchemas,
+    departId,
     goafOptions,
     goafId,
     initGoafOptions,

+ 38 - 7
src/views/monitor/sealedMonitor/index.vue

@@ -42,7 +42,7 @@
   import { BasicTable } from '/@/components/Table';
   import { Tabs, TabPane, message } from 'ant-design-vue';
   // 引入模拟数据
-  import { columns, historicalColumns } from './monitor.data';
+  import { columns, historicalColumns, historicalFormSchema, searchFormSchema } from './monitor.data';
   import RealtimeDetailsModal from './components/RealtimeDetailsModal.vue';
   // import HistoricalDetailsModal from './components/HistoricalDetailsModal.vue';
   import { SvgIcon } from '/@/components/Icon';
@@ -56,7 +56,7 @@
   // 激活的Tab页签
 
   // 处理矿名选择器相关的逻辑
-  const { realtimeSchemas, historySchemas, goafOptions, goafId } = useInitForm();
+  const { departId, goafOptions, goafId, initGoafOptions } = useInitForm();
   const activeTab = ref('realtime');
 
   // 注册实时数据表格
@@ -65,7 +65,19 @@
       api: getGoafData,
       columns,
       formConfig: {
-        schemas: realtimeSchemas,
+        schemas: [
+          {
+            field: 'mineCodeList',
+            label: '煤矿名称',
+            component: 'MineCascader',
+            colProps: { span: 6 },
+            componentProps: {
+              syncToStore: false,
+              rootId: departId,
+            },
+          },
+          ...searchFormSchema,
+        ],
         schemaGroupNames: ['常规查询'],
       },
       showIndexColumn: false,
@@ -73,9 +85,9 @@
     },
     pagination: false,
   });
-  const [registerRealtimeTable, { reload }] = ctxRealtime;
+  const [registerRealtimeTable, realtimeTable] = ctxRealtime;
 
-  const { pause, resume } = useIntervalFn(() => reload({ silence: true }), 10000);
+  const { pause, resume } = useIntervalFn(() => realtimeTable.reload({ silence: true }), 10000);
 
   // 注册历史数据表格
   const { tableContext: ctxHistory, onExportXls } = useListPage({
@@ -90,7 +102,26 @@
       },
       columns: historicalColumns,
       formConfig: {
-        schemas: historySchemas, // 使用历史数据的搜索配置
+        schemas: [
+          {
+            field: 'mineCodeList',
+            label: '煤矿名称',
+            component: 'MineCascader',
+            colProps: { span: 6 },
+            required: true,
+            componentProps: {
+              syncToStore: false,
+              rootId: departId,
+              onChange(v) {
+                historyTable.setLoading(true);
+                initGoafOptions(v).finally(() => {
+                  historyTable.setLoading(false);
+                });
+              },
+            },
+          },
+          ...historicalFormSchema,
+        ], // 使用历史数据的搜索配置
         schemaGroupNames: ['常规查询'],
       },
       useSearchForm: true,
@@ -105,7 +136,7 @@
     },
     pagination: true,
   });
-  const [registerHistoryTable] = ctxHistory;
+  const [registerHistoryTable, historyTable] = ctxHistory;
 
   // 弹窗引用
   const [registerRealtimeModal, { openModal: openRealtimeModal }] = useModal();

+ 3 - 3
src/views/monitor/sealedMonitor/monitor.data.ts

@@ -178,7 +178,7 @@ export const modalDetailsData: {
     //   value: 'Ⅰ类容易自燃',
     // },
     {
-      label: '自然发火隐患等级',
+      label: '自然发火隐患',
       value: 'fireAlarm',
       tag: true,
     },
@@ -518,6 +518,6 @@ function getTagType(level: string) {
   }
 }
 export function tagCellRender(record: any) {
-  if (!record) return h(Tag, { bordered: false, color: 'default' }, '-');
-  return h(Tag, { bordered: false, color: getTagType(record.alarmLevel) }, record.alarmName);
+  if (!record) return h(Tag, { bordered: false, color: 'default' }, () => '-');
+  return h(Tag, { bordered: false, color: getTagType(record.alarmLevel) }, () => record.alarmName);
 }