Explorar o código

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

lxh hai 3 meses
pai
achega
320ccd31f9

+ 13 - 5
src/components/Form/src/components/FormGroup.vue

@@ -1,6 +1,3 @@
-<!--
- * @Description:It is troublesome to implement radio button group in the form. So it is extracted independently as a separate component
--->
 <template>
   <Space v-bind="attrs">
     <template v-for="(item, i) in groups" :key="`fmgrp${i}`">
@@ -13,12 +10,13 @@
   </Space>
 </template>
 <script lang="ts">
-  import { defineComponent, PropType } from 'vue';
+  import { defineComponent, PropType, watch } from 'vue';
   import { Space, Button } from 'ant-design-vue';
   import { useAttrs } from '/@/hooks/core/useAttrs';
+  import { first } from 'lodash';
 
   export default defineComponent({
-    name: 'RadioButtonGroup',
+    name: 'FormGroup',
     components: {
       Space,
       AButton: Button,
@@ -46,6 +44,16 @@
         }
       }
 
+      watch(
+        () => props.groups,
+        (nv) => {
+          !props.value && handleClick(first(nv));
+        },
+        {
+          immediate: true,
+        }
+      );
+
       return { attrs, handleClick };
     },
   });

+ 40 - 22
src/components/Form/src/jeecg/components/MineCascader/MineCascader.vue

@@ -1,14 +1,16 @@
 <template>
   <a-cascader
     :value="innerValue"
-    :options="getMineTree"
+    :options="getDepartTree"
     :placeholder="placeholder"
     :field-names="{
       label: 'departName',
       value: 'id',
       children: 'childDepart',
     }"
-    show-search
+    :show-search="showSearch"
+    :allow-clear="allowClear"
+    :change-on-select="changeOnSelect"
     @change="handleChange"
   >
     <template #displayRender="{ labels }">
@@ -19,8 +21,8 @@
 </template>
 
 <script lang="ts">
-  import { get, last } from 'lodash';
-  import { defineComponent, computed } from 'vue';
+  import { last } from 'lodash';
+  import { defineComponent, computed, onUnmounted } from 'vue';
   // import { useMessage } from '/@/hooks/web/useMessage';
   import { propTypes } from '/@/utils/propTypes';
   import { useMineStore } from '/@/store/modules/mine';
@@ -30,45 +32,61 @@
     name: 'MineCascader',
     props: {
       value: propTypes.string.def(''),
-      placeholder: propTypes.string.def('请选择矿名'),
-      /** 选择器选择深度,1即执法处,2即区县,3即矿区 */
-      level: propTypes.number.def(3),
-      /** 最后一级矿名选择时传递出去的值对应的字段 */
-      valueField: propTypes.string,
+      placeholder: propTypes.string.def('全部'),
+      /** 根节点ID,如果传入,组件将过滤该节点下的节点 */
+      rootId: propTypes.string,
+      showSearch: propTypes.bool.def(true),
+      allowClear: propTypes.bool.def(true),
+      changeOnSelect: propTypes.bool.def(true),
+      resetOnDestroy: propTypes.bool.def(true),
     },
     emits: ['change', 'update:value'],
     setup(props, { emit }) {
       // const { createMessage } = useMessage();
       const mineStore = useMineStore();
-      const { getMine, getMinePath, getMineTree, getMineId } = storeToRefs(mineStore);
+      const { getDepartPath, getDepartTree, getDepartId, getMineCode } = storeToRefs(mineStore);
 
-      // const shownText = computed(() => getMine.value.departName || '-');
-      const innerValue = computed(() => getMinePath.value.map((e) => e.id));
-      const options = getMineTree;
+      if (props.resetOnDestroy) {
+        const rawID = getDepartId.value;
+        onUnmounted(() => {
+          mineStore.clearDepart();
+          mineStore.setDepartById(rawID);
+        });
+      }
+
+      if (props.rootId) {
+        mineStore.filterDepartTree((e) => e.id === props.rootId);
+        mineStore.clearDepart();
+
+        onUnmounted(() => {
+          mineStore.restoreDepartTree();
+        });
+      }
+
+      // const shownText = computed(() => getDepart.value.departName || '-');
+      const innerValue = computed(() => getDepartPath.value.map((e) => e.id));
+      const options = getDepartTree;
 
       /**
        * change事件
        * @param e
        */
       function handleChange(value: any[]) {
-        mineStore.setMineById(last(value));
+        console.log('debug change', value, getMineCode.value);
+        mineStore.setDepartById(last(value));
+        console.log('debug aftter', value, getMineCode.value);
 
-        let val;
-        if (props.valueField) {
-          val = get(getMine.value, props.valueField);
-        } else {
-          val = getMineId.value;
-        }
+        const val = getMineCode.value;
         emit('update:value', val);
         emit('change', val);
       }
 
-      handleChange([mineStore.mineId]);
+      handleChange([getDepartId.value]);
 
       return {
         innerValue,
         options,
-        getMineTree,
+        getDepartTree,
         handleChange,
       };
     },

+ 1 - 1
src/main.ts

@@ -119,5 +119,5 @@ function setupProps(props?: MainAppProps) {
   appStore.setMainAppProps(props);
 
   const mineStore = useMineStore();
-  mineStore.fetchMineTree();
+  mineStore.fetchDepartTree();
 }

+ 179 - 81
src/store/modules/mine.ts

@@ -1,9 +1,10 @@
 import { defineStore } from 'pinia';
+import { ref, computed } from 'vue';
 
 import { getEnfMineTree } from '/@/api/sys/menu';
 import { getUserMinePermissionData } from '/@/components/Form/src/jeecg/components/MineCascader/mineData.api';
-import { findNode, findPath, listToTree } from '/@/utils/helper/treeHelper';
-import { isEmpty, isNil } from 'lodash';
+import { findNode, findNodeAll, findPath, listToTree, treeToList } from '/@/utils/helper/treeHelper';
+import { isArray, isEmpty, isNil } from 'lodash';
 
 export interface MineDepartment {
   /** 唯一标识 */
@@ -12,100 +13,197 @@ export interface MineDepartment {
   departName: string;
   /** 父部门ID */
   parentId: string | null;
-  /** 是否为叶子节点 */
+  /** 是否为叶子节点(矿井是叶子节点) */
   isLeaf: boolean;
   /** 子部门列表 */
   childDepart: MineDepartment[];
-  /** 传真,用作矿井编号 */
+  /** 传真,用作矿井编号(矿井编码) */
   fax: string | null;
 }
 
-export interface MineState {
-  mine?: MineDepartment;
-  /** 当前选中的矿井ID,可能为空 */
-  mineId?: MineDepartment['id'];
-  /** 当前选中的矿井编号,可能为空 */
-  // mineCode?: MineDepartment['fax'];
-  /** 当前选中的矿井在组织树中的访问路径 */
-  minePath: MineDepartment[];
-  /** 矿井组织树 */
-  mineTree: MineDepartment[];
-}
-
 const DEFAULT_CONFIG = {
   id: 'id',
   pid: 'parentId',
   children: 'childDepart',
 };
 
-export const useMineStore = defineStore({
-  id: 'mine-store',
-  state: (): MineState => ({
-    mine: undefined,
-    mineId: undefined,
-    // mineCode: undefined,
-    minePath: [],
-    mineTree: [],
-  }),
-  getters: {
-    getMine(): MineState['mine'] {
-      return this.mine;
-    },
-    getMineId(): MineState['mineId'] {
-      return this.getMine?.id;
-    },
-    // getMineCode(): MineState['mineCode'] {
-    //   return this.getMine?.fax;
-    // },
-    getMineTree(): MineState['mineTree'] {
-      return this.mineTree;
-    },
-    getMinePath(): MineState['minePath'] {
-      return this.minePath;
-    },
-  },
-  actions: {
-    /** 设置当前选中的矿井,并更新path项 */
-    setMine(mine?: MineDepartment) {
-      if (isNil(mine) || isEmpty(mine)) return;
-      this.mine = mine;
-      const path = findPath(this.getMineTree, (item) => item.id === mine.id, DEFAULT_CONFIG);
-      this.setMinePath(path);
-    },
-    /** 根据传入的id设置当前选中的矿井,更新id、code、path三项 */
-    setMineById(id: string = '') {
-      const node = findNode(this.getMineTree, (item) => item.id === id, DEFAULT_CONFIG);
-      this.setMine(node);
-    },
-    /** 根据传入的code设置当前选中的矿井,更新id、code、path三项 */
-    // setMineByCode(code: string = '') {
-    //   const node = findNode(this.getMineTree, (item) => item.fax === code, DEFAULT_CONFIG);
-    //   this.setMine(node);
-    // },
-    setMinePath(path: any[] = []) {
-      this.minePath = path;
-    },
-    setMineTree(tree: any[] = []) {
-      this.mineTree = tree;
-    },
-    async fetchMineTree() {
-      const r1 = await getEnfMineTree();
-      const r2 = await getUserMinePermissionData({});
-      r1.forEach((e) => (e.isLeaf = false));
-      r2.forEach((e) => {
-        e.isLeaf = true;
-        e.id = e.fax;
+export const useMineStore = defineStore('mine-store', () => {
+  // ==================== State 定义 ====================
+
+  /** 当前选中的部门,可能是执法处、区或者具体到矿井 */
+  const depart = ref<MineDepartment>();
+
+  /** 当前选中的部门ID,可能为空 */
+  const departId = ref<string>();
+
+  /** 组织树(经过过滤等处理后的树) */
+  const departTree = ref<MineDepartment[]>([]);
+
+  /** 原始组织树(保存原始数据,用于恢复或重新过滤) */
+  const rawTree = ref<MineDepartment[]>([]);
+
+  // ==================== Getter 计算属性 ====================
+
+  /** 获取当前选中的部门 */
+  const getDepart = computed(() => depart.value);
+
+  /** 获取当前选中的部门ID */
+  const getDepartId = computed(() => depart.value?.id);
+
+  /** 获取组织树 */
+  const getDepartTree = computed(() => departTree.value);
+
+  /** 获取当前选中的部门在组织树中的访问路径 */
+  const getDepartPath = computed(() => {
+    return findPath(departTree.value, (item) => item.id === departId.value, DEFAULT_CONFIG) || [];
+  });
+
+  /**
+   * 获取当前选中的矿井编号集合
+   * - 如果选择了具体的矿井节点,返回该矿井的编码
+   * - 如果选择了上级部门(如执法处),返回该部门下所有矿井的编码集合,用逗号分隔
+   * - 如果未选择任何节点,返回空字符串
+   */
+  const getMineCode = computed(() => {
+    const target = departId.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 '';
+  });
+
+  // ==================== Action 方法 ====================
+
+  /**
+   * 设置当前选中的部门
+   * @param dep - 部门对象
+   */
+  function setDepart(dep: MineDepartment) {
+    if (isNil(dep) || isEmpty(dep)) return;
+    depart.value = dep;
+    departId.value = dep.id;
+  }
+
+  /**
+   * 根据部门ID设置当前选中的部门
+   * @param id - 部门ID,默认为空字符串
+   */
+  function setDepartById(id: string = '') {
+    const node = findNode(departTree.value, (item) => item.id === id, DEFAULT_CONFIG);
+    setDepart(node);
+  }
+
+  /**
+   * 设置组织树并保存原始数据副本
+   * @param tree - 组织树数据
+   */
+  function setDepartTree(tree: MineDepartment[] = []) {
+    departTree.value = tree;
+    // 深拷贝保存原始数据,用于过滤后恢复
+    rawTree.value = JSON.parse(JSON.stringify(tree));
+  }
+
+  /**
+   * 获取组织树数据(异步)
+   * 从两个接口获取数据:
+   * 1. getEnfMineTree: 获取执法处、区等非叶子节点
+   * 2. getUserMinePermissionData: 获取矿井(叶子节点)数据
+   */
+  async function fetchDepartTree() {
+    try {
+      // 并行请求两个接口
+      const [r1, r2] = await Promise.all([
+        getEnfMineTree(), // 非叶子节点(执法处、区)
+        getUserMinePermissionData({}), // 叶子节点(矿井)
+      ]);
+
+      // 标记节点类型
+      r1.forEach((node) => (node.isLeaf = false)); // 非叶子节点
+      r2.forEach((node) => {
+        node.isLeaf = true; // 叶子节点(矿井)
+        node.id = node.fax || node.id; // 使用矿井编码作为ID
       });
+
+      // 合并数据并转换为树形结构
       const tree = listToTree([...r1, ...r2], DEFAULT_CONFIG);
-      // 使用查找方法而不是选中r2中第一个“叶节点”是因为:
-      // r2返回的矿名不具备权限控制,r1返回的父节点才有权限控制
 
-      this.setMineTree(tree);
+      setDepartTree(tree);
+
+      // 如果需要自动选中第一个叶子节点(矿井),可以取消注释以下代码
+      /*
+      if (!depart.value) {
+        const firstLeaf = findNode(
+          tree, 
+          (item) => item.isLeaf, 
+          DEFAULT_CONFIG
+        );
+        if (firstLeaf) {
+          setDepart(firstLeaf);
+        }
+      }
+      */
+    } catch (error) {
+      console.error('获取组织树数据失败:', error);
+      throw error;
+    }
+  }
+
+  /**
+   * 过滤组织树
+   * @param fn - 过滤函数,返回true表示保留该节点
+   */
+  function filterDepartTree(fn: (node: MineDepartment) => boolean) {
+    // 只有在有原始数据时才进行过滤
+    if (rawTree.value.length > 0) {
+      departTree.value = findNodeAll(rawTree.value, fn, DEFAULT_CONFIG);
+    }
+  }
+
+  /**
+   * 恢复原始组织树(取消过滤)
+   */
+  function restoreDepartTree() {
+    if (rawTree.value.length > 0) {
+      departTree.value = JSON.parse(JSON.stringify(rawTree.value));
+    }
+  }
+
+  /**
+   * 清除选中的部门
+   */
+  function clearDepart() {
+    depart.value = undefined;
+    departId.value = undefined;
+  }
+
+  // ==================== 暴露的属性和方法 ====================
+
+  return {
+    // --- State(可修改)---
+    depart,
+    departId,
+    departTree,
+    rawTree,
 
-      if (this.getMine) return;
+    // --- Getter(只读计算属性)---
+    getDepart,
+    getDepartId,
+    getDepartTree,
+    getDepartPath,
+    getMineCode,
 
-      const leaf = findNode(tree, (item) => item.isLeaf, DEFAULT_CONFIG);
-      this.setMine(leaf);
-    },
-  },
+    // --- Action(操作方法)---
+    setDepart,
+    setDepartById,
+    // setDepartTree,
+    fetchDepartTree,
+    filterDepartTree,
+    restoreDepartTree,
+    clearDepart,
+  };
 });