Sfoglia il codice sorgente

[Pref 0000] 优化矿区级联选择器的数据流使其运行更为稳定

houzekong 3 mesi fa
parent
commit
b509f38d4e

+ 32 - 25
src/components/Form/src/jeecg/components/MineCascader/MineCascader.vue

@@ -1,7 +1,7 @@
 <template>
 <template>
   <Cascader
   <Cascader
     :value="innerValue"
     :value="innerValue"
-    :options="getDepartTree"
+    :options="options"
     placeholder="全部"
     placeholder="全部"
     :field-names="{
     :field-names="{
       label: 'departName',
       label: 'departName',
@@ -22,13 +22,19 @@
 
 
 <script lang="ts">
 <script lang="ts">
   import { last } from 'lodash';
   import { last } from 'lodash';
-  import { defineComponent, onUnmounted, h, ref } from 'vue';
+  import { defineComponent, ref } from 'vue';
   // import { useMessage } from '/@/hooks/web/useMessage';
   // import { useMessage } from '/@/hooks/web/useMessage';
   import { propTypes } from '/@/utils/propTypes';
   import { propTypes } from '/@/utils/propTypes';
   import { useMineDepartmentStore } from '/@/store/modules/mine';
   import { useMineDepartmentStore } from '/@/store/modules/mine';
-  import { storeToRefs } from 'pinia';
   import { Cascader } from 'ant-design-vue';
   import { Cascader } from 'ant-design-vue';
 
 
+  /**
+   * 矿区级联选择器,该组件会根据配置从store中获取初始数据
+   *
+   * 组件数据流梳理:初始化数据及选项 -> 更新数据 -> 同步STORE -> 计算组件内依赖
+   *
+   * 本组件在初始化后不再监听STORE中的数据变化,因为这样可能导致用户通过Tabs切换时出现数据混乱
+   */
   export default defineComponent({
   export default defineComponent({
     name: 'MineCascader',
     name: 'MineCascader',
     components: { Cascader },
     components: { Cascader },
@@ -37,6 +43,10 @@
       placeholder: propTypes.string.def('全部'),
       placeholder: propTypes.string.def('全部'),
       /** 根节点ID,如果传入,组件将过滤该节点下的节点 */
       /** 根节点ID,如果传入,组件将过滤该节点下的节点 */
       rootId: propTypes.string,
       rootId: propTypes.string,
+      /** 是否从已存储的信息中初始化组件值 */
+      initFromStore: propTypes.bool.def(true),
+      /** 是否从将值同步至STORE */
+      syncToStore: propTypes.bool.def(true),
       showSearch: propTypes.bool.def(true),
       showSearch: propTypes.bool.def(true),
       allowClear: propTypes.bool.def(true),
       allowClear: propTypes.bool.def(true),
       changeOnSelect: propTypes.bool.def(true),
       changeOnSelect: propTypes.bool.def(true),
@@ -46,7 +56,8 @@
     setup(props, { emit }) {
     setup(props, { emit }) {
       // const { createMessage } = useMessage();
       // const { createMessage } = useMessage();
       const mineStore = useMineDepartmentStore();
       const mineStore = useMineDepartmentStore();
-      const { getDepartTree, getMineCode } = storeToRefs(mineStore);
+      const innerValue = ref<string[]>([]);
+      const options = ref(mineStore.getDepartTree);
 
 
       // if (props.clearOnDestroy) {
       // if (props.clearOnDestroy) {
       //   const raw = getDepartId.value;
       //   const raw = getDepartId.value;
@@ -56,44 +67,40 @@
       // }
       // }
 
 
       if (props.rootId) {
       if (props.rootId) {
-        mineStore.clearDepart();
-        mineStore.filterDepartTree((e) => e.parentId === props.rootId);
-
-        onUnmounted(() => {
-          mineStore.restoreDepartTree();
-        });
+        options.value = mineStore.filterDepartTree((e) => e.parentId === props.rootId);
       }
       }
 
 
-      // const shownText = computed(() => getDepart.value.departName || '-');
-      const innerValue = ref<string[]>([]);
-      // const innerValue = computed(() => getDepartPath.value.map((e) => e.id));
-      const options = getDepartTree;
-
       /**
       /**
        * change事件
        * change事件
        * @param e
        * @param e
        */
        */
       function handleChange(value: any[]) {
       function handleChange(value: any[]) {
-        innerValue.value = value;
-        mineStore.setDepartById(last(value));
+        // innerValue.value = value;
+        const id = last(value);
 
 
-        const val = getMineCode.value;
+        const path = mineStore.calcDepartPathById(id, options.value, (e) => e.id);
+        const dep = mineStore.findDepartById(id, options.value);
+        const val = mineStore.calcMineCodeByDepart(dep ? [dep] : options.value);
+        innerValue.value = path;
         emit('update:value', val);
         emit('update:value', val);
         emit('change', val);
         emit('change', val);
-      }
 
 
-      handleChange([]);
+        if (props.syncToStore) {
+          mineStore.setDepartById(id);
+        }
+      }
 
 
-      onUnmounted(() => {
-        mineStore.clearDepart();
-      });
+      // 如果从STORE里初始化数据需要先检查合法性,毕竟rootId提供了选项过滤功能
+      if (props.initFromStore && mineStore.findDepartById(mineStore.getDepartId, options.value)) {
+        handleChange([mineStore.getDepartId]);
+      } else {
+        handleChange([]);
+      }
 
 
       return {
       return {
         innerValue,
         innerValue,
         options,
         options,
-        getDepartTree,
         handleChange,
         handleChange,
-        h,
       };
       };
     },
     },
   });
   });

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

@@ -4,7 +4,7 @@ import { ref, computed } from 'vue';
 import { getEnfMineTree } from '/@/api/sys/menu';
 import { getEnfMineTree } from '/@/api/sys/menu';
 import { getUserMinePermissionData } from '/@/components/Form/src/jeecg/components/MineCascader/mineData.api';
 import { getUserMinePermissionData } from '/@/components/Form/src/jeecg/components/MineCascader/mineData.api';
 import { findNode, findNodeAll, findPath, listToTree, treeToList } from '/@/utils/helper/treeHelper';
 import { findNode, findNodeAll, findPath, listToTree, treeToList } from '/@/utils/helper/treeHelper';
-import { isArray } from 'lodash';
+import { isArray, isFunction, isNil } from 'lodash';
 
 
 export interface MineDepartment {
 export interface MineDepartment {
   /** 唯一标识 */
   /** 唯一标识 */
@@ -37,7 +37,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
   const departTree = ref<MineDepartment[]>([]);
   const departTree = ref<MineDepartment[]>([]);
 
 
   /** 原始组织树(保存原始数据,用于恢复或重新过滤) */
   /** 原始组织树(保存原始数据,用于恢复或重新过滤) */
-  const rawTree = ref<MineDepartment[]>([]);
+  // const rawTree = ref<MineDepartment[]>([]);
 
 
   // ==================== Getter 计算属性 ====================
   // ==================== Getter 计算属性 ====================
 
 
@@ -52,7 +52,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
 
 
   /** 获取当前选中的部门在组织树中的访问路径 */
   /** 获取当前选中的部门在组织树中的访问路径 */
   const getDepartPath = computed(() => {
   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 getMineCode = computed(() => {
     const target = getDepartId.value ? [depart.value] : departTree.value;
     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 方法 ====================
   // ==================== Action 方法 ====================
@@ -80,7 +72,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
    * 设置当前选中的部门
    * 设置当前选中的部门
    * @param dep - 部门对象
    * @param dep - 部门对象
    */
    */
-  function setDepart(dep: MineDepartment) {
+  function setDepart(dep?: MineDepartment) {
     // if (isNil(dep) || isEmpty(dep)) return;
     // if (isNil(dep) || isEmpty(dep)) return;
     depart.value = dep;
     depart.value = dep;
   }
   }
@@ -90,7 +82,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
    * @param id - 部门ID,默认为空字符串
    * @param id - 部门ID,默认为空字符串
    */
    */
   function setDepartById(id: string = '') {
   function setDepartById(id: string = '') {
-    const node = findNode(departTree.value, (item) => item.id === id, DEFAULT_CONFIG);
+    const node = findDepartById(id, departTree.value);
     setDepart(node);
     setDepart(node);
   }
   }
 
 
@@ -120,7 +112,7 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
 
 
       departTree.value = tree;
       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表示保留该节点
    * @param fn - 过滤函数,返回true表示保留该节点
    */
    */
   function filterDepartTree(fn: (node: MineDepartment) => boolean) {
   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(可修改)---
     // --- State(可修改)---
     depart,
     depart,
     departTree,
     departTree,
-    rawTree,
 
 
     // --- Getter(只读计算属性)---
     // --- Getter(只读计算属性)---
     getDepart,
     getDepart,
@@ -189,7 +233,9 @@ export const useMineDepartmentStore = defineStore('mine-department-store', () =>
     // setDepartTree,
     // setDepartTree,
     fetchDepartTree,
     fetchDepartTree,
     filterDepartTree,
     filterDepartTree,
-    restoreDepartTree,
     clearDepart,
     clearDepart,
+    calcMineCodeByDepart,
+    calcDepartPathById,
+    findDepartById,
   };
   };
 });
 });