|
@@ -1,6 +1,12 @@
|
|
|
<template>
|
|
<template>
|
|
|
|
|
|
|
|
- <div class="common_tree_wrapper common_tree">
|
|
|
|
|
|
|
+ <div
|
|
|
|
|
+ class="common_tree_wrapper common_tree"
|
|
|
|
|
+ v-loading="loading"
|
|
|
|
|
+ element-loading-text="加载中……"
|
|
|
|
|
+ element-loading-spinner="el-icon-loading"
|
|
|
|
|
+ element-loading-background="#ffffff"
|
|
|
|
|
+ >
|
|
|
<el-tree
|
|
<el-tree
|
|
|
ref="commonTree"
|
|
ref="commonTree"
|
|
|
class="tree_container"
|
|
class="tree_container"
|
|
@@ -167,6 +173,12 @@ export default {
|
|
|
type: Boolean,
|
|
type: Boolean,
|
|
|
default: false,
|
|
default: false,
|
|
|
},
|
|
},
|
|
|
|
|
+
|
|
|
|
|
+ /** 树数据加载中(父组件请求期间传 true) */
|
|
|
|
|
+ loading: {
|
|
|
|
|
+ type: Boolean,
|
|
|
|
|
+ default: false,
|
|
|
|
|
+ },
|
|
|
},
|
|
},
|
|
|
inject: ["openAiRobot"], //注入Ai机器人组件调用方法
|
|
inject: ["openAiRobot"], //注入Ai机器人组件调用方法
|
|
|
// ==================== 数据状态 ====================
|
|
// ==================== 数据状态 ====================
|
|
@@ -187,10 +199,7 @@ export default {
|
|
|
// ==================== 生命周期 ====================
|
|
// ==================== 生命周期 ====================
|
|
|
mounted() {
|
|
mounted() {
|
|
|
if (Array.isArray(this.treeData) && this.treeData.length > 0) {
|
|
if (Array.isArray(this.treeData) && this.treeData.length > 0) {
|
|
|
- clearTimeout(this._defaultSelectTimer);
|
|
|
|
|
- this._defaultSelectTimer = setTimeout(() => {
|
|
|
|
|
- this.applyDefaultFirstNode(this.treeData);
|
|
|
|
|
- }, 100);
|
|
|
|
|
|
|
+ this.scheduleDefaultFirstNode(this.treeData);
|
|
|
}
|
|
}
|
|
|
},
|
|
},
|
|
|
|
|
|
|
@@ -202,22 +211,13 @@ export default {
|
|
|
watch: {
|
|
watch: {
|
|
|
treeData: {
|
|
treeData: {
|
|
|
handler(newVal) {
|
|
handler(newVal) {
|
|
|
- if (!Array.isArray(newVal) || newVal.length === 0) return;
|
|
|
|
|
- // 用 setTimeout 确保 el-tree 内部节点已完全渲染
|
|
|
|
|
- clearTimeout(this._defaultSelectTimer);
|
|
|
|
|
- this._defaultSelectTimer = setTimeout(() => {
|
|
|
|
|
- // 如果已有手动勾选的节点,在新数据上重新应用状态
|
|
|
|
|
- if (this.manuallyCheckedKeys.length > 0 && this.showCheckbox) {
|
|
|
|
|
- this._isUpdating = true;
|
|
|
|
|
- this.reapplyCheckStates();
|
|
|
|
|
- this.$nextTick(() => {
|
|
|
|
|
- this._isUpdating = false;
|
|
|
|
|
- });
|
|
|
|
|
- } else {
|
|
|
|
|
- // 没有手动勾选节点时,执行默认选中第一个节点
|
|
|
|
|
- this.applyDefaultFirstNode(newVal);
|
|
|
|
|
- }
|
|
|
|
|
- }, 100);
|
|
|
|
|
|
|
+ // 数据切换(换人/换科目/重新筛选)时,清空旧勾选并重新默认勾选+展开第一个节点
|
|
|
|
|
+ this.manuallyCheckedKeys = [];
|
|
|
|
|
+ if (!Array.isArray(newVal) || newVal.length === 0) {
|
|
|
|
|
+ this.clearChecked();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ this.scheduleDefaultFirstNode(newVal);
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
|
},
|
|
},
|
|
@@ -433,27 +433,57 @@ export default {
|
|
|
this.$refs.commonTree.setCurrentKey(key);
|
|
this.$refs.commonTree.setCurrentKey(key);
|
|
|
},
|
|
},
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 延迟执行默认勾选/展开,确保 el-tree 内部节点已渲染完成
|
|
|
|
|
+ * @param {Array} data - 树形数据
|
|
|
|
|
+ */
|
|
|
|
|
+ scheduleDefaultFirstNode(data) {
|
|
|
|
|
+ clearTimeout(this._defaultSelectTimer);
|
|
|
|
|
+ this._defaultSelectTimer = setTimeout(() => {
|
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
|
+ this.applyDefaultFirstNode(data);
|
|
|
|
|
+ });
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+ },
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 默认勾选并展开第一个一级节点
|
|
* 默认勾选并展开第一个一级节点
|
|
|
- * 新逻辑:只勾选第一个节点本身(手动勾选),其祖先和后代自动勾选+置灰
|
|
|
|
|
|
|
+ * - 无论树只有 1 个节点还是多个节点,都勾选第一个顶层节点
|
|
|
|
|
+ * - 展开该节点下全部子孙节点
|
|
|
* @param {Array} data - 树形数据
|
|
* @param {Array} data - 树形数据
|
|
|
|
|
+ * @param {Number} retry - 内部重试次数(树尚未渲染完时)
|
|
|
*/
|
|
*/
|
|
|
- applyDefaultFirstNode(data) {
|
|
|
|
|
|
|
+ applyDefaultFirstNode(data, retry = 0) {
|
|
|
if (!data || data.length === 0) return;
|
|
if (!data || data.length === 0) return;
|
|
|
const treeRef = this.$refs.commonTree;
|
|
const treeRef = this.$refs.commonTree;
|
|
|
- if (!treeRef || !treeRef.store || !treeRef.store.root) return;
|
|
|
|
|
-
|
|
|
|
|
- // 1. 获取第一个顶层节点实例
|
|
|
|
|
- const rootNode = treeRef.store.root;
|
|
|
|
|
- const childNodes = rootNode.childNodes;
|
|
|
|
|
- if (!childNodes || childNodes.length === 0) return;
|
|
|
|
|
|
|
+ const childNodes =
|
|
|
|
|
+ treeRef && treeRef.store && treeRef.store.root
|
|
|
|
|
+ ? treeRef.store.root.childNodes
|
|
|
|
|
+ : null;
|
|
|
|
|
+
|
|
|
|
|
+ // 树尚未渲染出节点时短暂重试,避免切换数据后漏勾选/漏展开
|
|
|
|
|
+ if (!childNodes || childNodes.length === 0) {
|
|
|
|
|
+ if (retry < 8) {
|
|
|
|
|
+ clearTimeout(this._defaultSelectTimer);
|
|
|
|
|
+ this._defaultSelectTimer = setTimeout(() => {
|
|
|
|
|
+ this.applyDefaultFirstNode(data, retry + 1);
|
|
|
|
|
+ }, 50);
|
|
|
|
|
+ }
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
const firstNodeInstance = childNodes[0];
|
|
const firstNodeInstance = childNodes[0];
|
|
|
if (!firstNodeInstance) return;
|
|
if (!firstNodeInstance) return;
|
|
|
|
|
|
|
|
- // 2. 默认勾选第一个节点(手动勾选,只传该节点 key)
|
|
|
|
|
|
|
+ const firstKey =
|
|
|
|
|
+ firstNodeInstance.key != null
|
|
|
|
|
+ ? firstNodeInstance.key
|
|
|
|
|
+ : firstNodeInstance.data && firstNodeInstance.data[this.nodeKey];
|
|
|
|
|
+ if (firstKey == null || firstKey === "") return;
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 默认勾选第一个节点(含「只有一个节点」的场景)
|
|
|
if (this.showCheckbox) {
|
|
if (this.showCheckbox) {
|
|
|
- this.manuallyCheckedKeys = [firstNodeInstance.key];
|
|
|
|
|
|
|
+ this.manuallyCheckedKeys = [firstKey];
|
|
|
this._isUpdating = true;
|
|
this._isUpdating = true;
|
|
|
this.reapplyCheckStates();
|
|
this.reapplyCheckStates();
|
|
|
this.$nextTick(() => {
|
|
this.$nextTick(() => {
|
|
@@ -461,10 +491,10 @@ export default {
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 3. 默认高亮选中第一个节点
|
|
|
|
|
- treeRef.setCurrentKey(firstNodeInstance.key);
|
|
|
|
|
|
|
+ // 2. 默认高亮选中第一个节点
|
|
|
|
|
+ treeRef.setCurrentKey(firstKey);
|
|
|
|
|
|
|
|
- // 4. 默认展开第一个节点及其全部子节点(所有层级)
|
|
|
|
|
|
|
+ // 3. 默认展开第一个节点及其全部子节点(所有层级;单节点叶子也设 expanded)
|
|
|
const expandAllChildren = (node) => {
|
|
const expandAllChildren = (node) => {
|
|
|
if (!node) return;
|
|
if (!node) return;
|
|
|
node.expanded = true;
|
|
node.expanded = true;
|
|
@@ -475,7 +505,7 @@ export default {
|
|
|
};
|
|
};
|
|
|
expandAllChildren(firstNodeInstance);
|
|
expandAllChildren(firstNodeInstance);
|
|
|
|
|
|
|
|
- // 5. 只传递手动勾选的节点 key(即第一个节点本身)
|
|
|
|
|
|
|
+ // 4. 回传手动勾选的节点 key(即第一个节点本身)
|
|
|
if (this.showCheckbox) {
|
|
if (this.showCheckbox) {
|
|
|
this.$emit("nodeCheck", [...this.manuallyCheckedKeys]);
|
|
this.$emit("nodeCheck", [...this.manuallyCheckedKeys]);
|
|
|
}
|
|
}
|