@sy-common/organize-select-help 1.0.0-beta.7 → 1.0.0-beta.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -2
- package/src/index.vue +3164 -149
- package/src/organize-tree.vue +624 -110
package/src/organize-tree.vue
CHANGED
|
@@ -1,158 +1,672 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div class="content">
|
|
3
3
|
<Spin fix v-if="loading"></Spin>
|
|
4
|
-
<
|
|
5
|
-
|
|
4
|
+
<div class="tree-inner">
|
|
5
|
+
<Tree
|
|
6
|
+
:data="data"
|
|
7
|
+
ref="tree"
|
|
8
|
+
:load-data="loadData"
|
|
9
|
+
:render="renderContent"
|
|
10
|
+
multiple
|
|
11
|
+
:check-strictly="true"
|
|
12
|
+
:cascade-check="false"
|
|
13
|
+
@on-select-change="handleChange"
|
|
14
|
+
></Tree>
|
|
15
|
+
</div>
|
|
6
16
|
</div>
|
|
7
17
|
</template>
|
|
18
|
+
|
|
8
19
|
<script>
|
|
9
|
-
import
|
|
20
|
+
import { deepCopy } from '@lambo-design/core/src/utils/assist';
|
|
21
|
+
import ajax from '@lambo-design/shared/utils/ajax';
|
|
22
|
+
|
|
10
23
|
export default {
|
|
11
|
-
props:{
|
|
12
|
-
disabled:{
|
|
24
|
+
props: {
|
|
25
|
+
disabled: {
|
|
26
|
+
type: Boolean,
|
|
27
|
+
default: false
|
|
28
|
+
},
|
|
29
|
+
treeList: {
|
|
30
|
+
type: Array,
|
|
31
|
+
default: () => []
|
|
32
|
+
},
|
|
33
|
+
isSingleSelect: {
|
|
34
|
+
type: Boolean,
|
|
35
|
+
default: false
|
|
36
|
+
},
|
|
37
|
+
// 新增1:接收父组件的 defaultOrgUnitId(自定义根节点ID)
|
|
38
|
+
defaultOrgUnitId: {
|
|
39
|
+
type: String,
|
|
40
|
+
default: ''
|
|
41
|
+
},
|
|
42
|
+
// 新增2:标记是否使用父组件构建的自定义树(禁用子组件自身的接口调用)
|
|
43
|
+
isCustomTree: {
|
|
44
|
+
type: Boolean,
|
|
45
|
+
default: false
|
|
46
|
+
},
|
|
47
|
+
// 新增3:禁用懒加载(避免触发子组件的旧接口)
|
|
48
|
+
disableLazyLoad: {
|
|
13
49
|
type: Boolean,
|
|
14
50
|
default: false
|
|
15
51
|
}
|
|
16
52
|
},
|
|
17
|
-
data(){
|
|
53
|
+
data() {
|
|
18
54
|
return {
|
|
19
|
-
data:[],
|
|
20
|
-
manageUnitId:'',
|
|
21
|
-
loading:true
|
|
22
|
-
|
|
55
|
+
data: [],
|
|
56
|
+
manageUnitId: '',
|
|
57
|
+
loading: true,
|
|
58
|
+
// 内部状态存储禁用懒加载的标识
|
|
59
|
+
isDisableLazyLoad: false
|
|
60
|
+
};
|
|
23
61
|
},
|
|
24
62
|
mounted() {
|
|
25
|
-
|
|
63
|
+
// 优先使用 props 的 disableLazyLoad,覆盖内部状态
|
|
64
|
+
this.isDisableLazyLoad = this.disableLazyLoad;
|
|
65
|
+
// 优先使用 props 的 isCustomTree,覆盖内部判断
|
|
66
|
+
this.isCustomTree = this.isCustomTree;
|
|
67
|
+
// 仅在未禁用懒加载且非自定义树时执行 initData
|
|
68
|
+
if (!this.isDisableLazyLoad && !this.isCustomTree) {
|
|
69
|
+
this.initData();
|
|
70
|
+
} else {
|
|
71
|
+
// 直接使用父组件传递的树数据
|
|
72
|
+
this.loading = false;
|
|
73
|
+
let tree = deepCopy(this.treeList);
|
|
74
|
+
this.initTree(tree);
|
|
75
|
+
this.data = tree;
|
|
76
|
+
}
|
|
77
|
+
|
|
26
78
|
},
|
|
27
|
-
methods:{
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
79
|
+
methods: {
|
|
80
|
+
setDisableLazyLoad(disabled) {
|
|
81
|
+
this.isDisableLazyLoad = disabled;
|
|
82
|
+
// 同时标记为自定义树,跳过子组件自身的 initData 逻辑
|
|
83
|
+
this.isCustomTree = disabled;
|
|
84
|
+
},
|
|
85
|
+
safeDeepCopy(obj, hash = new WeakMap()) {
|
|
86
|
+
if (obj === null || typeof obj !== 'object') {
|
|
87
|
+
return obj;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 检测循环引用,返回核心业务字段
|
|
91
|
+
if (hash.has(obj)) {
|
|
92
|
+
const safeObj = {
|
|
93
|
+
orgUnitId: obj.orgUnitId,
|
|
94
|
+
orgNodeName: obj.orgNodeName || obj.name || `未命名组织(${obj.orgUnitId || 'unknown'})`,
|
|
95
|
+
orgUnitName: obj.orgUnitName || obj.orgNodeName || obj.name || `未命名组织(${obj.orgUnitId || 'unknown'})`,
|
|
96
|
+
parentOrgUnitId: obj.parentOrgUnitId || obj.parentId || null
|
|
97
|
+
};
|
|
98
|
+
hash.set(obj, safeObj);
|
|
99
|
+
return safeObj;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
let copy;
|
|
103
|
+
if (obj instanceof Array) {
|
|
104
|
+
copy = [];
|
|
105
|
+
hash.set(obj, copy);
|
|
106
|
+
for (let i = 0; i < obj.length; i++) {
|
|
107
|
+
copy[i] = this.safeDeepCopy(obj[i], hash);
|
|
108
|
+
}
|
|
109
|
+
} else if (obj instanceof Object) {
|
|
110
|
+
copy = {};
|
|
111
|
+
hash.set(obj, copy);
|
|
112
|
+
for (let key in obj) {
|
|
113
|
+
if (obj.hasOwnProperty(key)) {
|
|
114
|
+
// 过滤Vue内部无效字段,保留业务字段
|
|
115
|
+
if (['__vue__', '__ob__', '$parent', '$children'].includes(key)) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// 子节点数组特殊处理
|
|
119
|
+
if (['orgChildrenList', 'children'].includes(key) && Array.isArray(obj[key])) {
|
|
120
|
+
copy[key] = obj[key].map(child => this.safeDeepCopy(child, hash));
|
|
121
|
+
} else {
|
|
122
|
+
copy[key] = this.safeDeepCopy(obj[key], hash);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
copy = obj;
|
|
128
|
+
}
|
|
129
|
+
return copy;
|
|
130
|
+
},
|
|
131
|
+
async initData() {
|
|
132
|
+
// 优先判断内部禁用状态,而非仅依赖 isCustomTree prop
|
|
133
|
+
if (this.isCustomTree || this.isDisableLazyLoad) {
|
|
134
|
+
this.loading = false;
|
|
135
|
+
let tree = deepCopy(this.treeList);
|
|
136
|
+
this.initTree(tree);
|
|
137
|
+
this.data = tree;
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
// 仅在非自定义/非禁用场景下执行原有逻辑
|
|
141
|
+
let data = await this.getOrgChildren();
|
|
142
|
+
this.loading = false;
|
|
31
143
|
this.data = data;
|
|
32
144
|
},
|
|
33
|
-
|
|
34
|
-
|
|
145
|
+
|
|
146
|
+
handleChange(data) {
|
|
147
|
+
// 仅处理复选框触发的选中数据,过滤空数据
|
|
148
|
+
if (!data || (Array.isArray(data) && data.length === 0)) {
|
|
149
|
+
this.$emit('handleChange', []);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let checkedData = Array.isArray(data)
|
|
154
|
+
? data.filter(item => item.checked)
|
|
155
|
+
: (data.checked ? [data] : []);
|
|
156
|
+
|
|
157
|
+
// 单选逻辑:仅保留最后一个选中的节点
|
|
158
|
+
if (this.isSingleSelect) {
|
|
159
|
+
checkedData = checkedData.length > 0 ? [checkedData[checkedData.length - 1]] : [];
|
|
160
|
+
// 清空其他节点的选中状态
|
|
161
|
+
this.clearOtherCheckedNodes(checkedData.map(item => item.orgUnitId));
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
this.syncAllNodeCheckedState(checkedData);
|
|
165
|
+
// 仅当有有效选中节点时才触发父组件事件
|
|
166
|
+
this.$emit('handleChange', checkedData);
|
|
35
167
|
},
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
168
|
+
clearOtherCheckedNodes(keepIds) {
|
|
169
|
+
if (!Array.isArray(this.data) || !Array.isArray(keepIds)) return;
|
|
170
|
+
|
|
171
|
+
const clearNodeState = (nodeList) => {
|
|
172
|
+
nodeList.forEach(node => {
|
|
173
|
+
if (!keepIds.includes(node.orgUnitId) && node.checked) {
|
|
174
|
+
this.$set(node, 'checked', false);
|
|
175
|
+
}
|
|
176
|
+
// 递归处理子节点(单选时也需要清空子节点的选中状态)
|
|
177
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
178
|
+
if (childNodes.length) {
|
|
179
|
+
clearNodeState(childNodes);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
clearNodeState(this.data);
|
|
40
185
|
},
|
|
41
|
-
|
|
42
|
-
|
|
186
|
+
|
|
187
|
+
syncAllNodeCheckedState(checkedData) {
|
|
188
|
+
if (!Array.isArray(this.data) || !Array.isArray(checkedData)) return;
|
|
189
|
+
|
|
190
|
+
const checkedIds = checkedData.map(item => item.orgUnitId);
|
|
191
|
+
const updateNodeState = (nodeList) => {
|
|
192
|
+
nodeList.forEach(node => {
|
|
193
|
+
// 仅更新当前节点,跳过子节点
|
|
194
|
+
const shouldBeChecked = checkedIds.includes(node.orgUnitId);
|
|
195
|
+
if (node.checked !== shouldBeChecked) {
|
|
196
|
+
this.$set(node, 'checked', shouldBeChecked);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
updateNodeState(this.data);
|
|
43
201
|
},
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
202
|
+
|
|
203
|
+
async loadData(item, callback) {
|
|
204
|
+
// 即使禁用懒加载,也允许加载已有子节点
|
|
205
|
+
if (this.disableLazyLoad) {
|
|
206
|
+
let children = item.orgChildrenList || item.children || [];
|
|
207
|
+
const formattedChildren = this.safeDeepCopy(children).map(child => ({
|
|
208
|
+
...child,
|
|
209
|
+
title: child.orgUnitName || child.orgNodeName || child.name || `未命名组织(${child.orgUnitId || child.id || ''})`,
|
|
210
|
+
checked: false,
|
|
211
|
+
expand: false,
|
|
212
|
+
leafNode: child.leafNode || false,
|
|
213
|
+
orgChildrenList: child.orgChildrenList || [],
|
|
214
|
+
children: child.children || []
|
|
215
|
+
}));
|
|
216
|
+
callback(formattedChildren);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 原有逻辑保持不变
|
|
221
|
+
if (this.isCustomTree) {
|
|
222
|
+
let children = item.orgChildrenList || item.children || [];
|
|
223
|
+
const formattedChildren = this.safeDeepCopy(children).map(child => ({
|
|
224
|
+
...child,
|
|
225
|
+
title: child.orgUnitName || child.orgNodeName || child.name || `未命名组织(${child.orgUnitId || child.id || ''})`,
|
|
226
|
+
checked: false,
|
|
227
|
+
expand: false,
|
|
228
|
+
leafNode: child.leafNode || false,
|
|
229
|
+
orgChildrenList: child.orgChildrenList || [],
|
|
230
|
+
children: child.children || []
|
|
231
|
+
}));
|
|
232
|
+
if (formattedChildren.length === 0 && item.orgUnitId) {
|
|
233
|
+
try {
|
|
234
|
+
const res = await ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
|
|
235
|
+
params: {
|
|
236
|
+
containsCurLevel: true,
|
|
237
|
+
orgUnitId: item.orgUnitId
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
if (res.data.code === 1) {
|
|
241
|
+
const apiChildren = res.data.data || [];
|
|
242
|
+
const initializedApiChildren = this.initTree(apiChildren);
|
|
243
|
+
const apiFormattedChildren = initializedApiChildren.map(child => ({
|
|
244
|
+
...child,
|
|
245
|
+
title: child.orgUnitName || child.orgNodeName || child.name || `未命名组织(${child.orgUnitId || ''})`,
|
|
246
|
+
checked: false,
|
|
247
|
+
expand: false,
|
|
248
|
+
leafNode: child.leafNode || false,
|
|
249
|
+
orgChildrenList: [],
|
|
250
|
+
children: []
|
|
251
|
+
}));
|
|
252
|
+
item.orgChildrenList = apiFormattedChildren;
|
|
253
|
+
item.children = apiFormattedChildren;
|
|
254
|
+
callback(apiFormattedChildren);
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
} catch (e) {
|
|
258
|
+
console.error("加载自定义树子节点失败:", e);
|
|
49
259
|
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
260
|
+
}
|
|
261
|
+
callback(formattedChildren);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let children = await this.getOrgChildren(item.orgUnitId);
|
|
266
|
+
const initializedChildren = this.initTree(children);
|
|
267
|
+
callback(initializedChildren);
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
getOrgChildren(orgUnitId = '') {
|
|
271
|
+
// 优先判断内部禁用状态
|
|
272
|
+
if (this.isDisableLazyLoad) {
|
|
273
|
+
return Promise.resolve([]);
|
|
274
|
+
}
|
|
275
|
+
if (this.isCustomTree) {
|
|
276
|
+
return Promise.resolve([]);
|
|
277
|
+
}
|
|
278
|
+
return new Promise((resolve, reject) => {
|
|
279
|
+
ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
|
|
280
|
+
params: {
|
|
281
|
+
containsCurLevel: true,
|
|
282
|
+
orgUnitId: orgUnitId
|
|
57
283
|
}
|
|
58
|
-
}).
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
list.forEach((item) => {
|
|
67
|
-
item.title=item.orgNodeName;
|
|
68
|
-
item.loading = false;
|
|
69
|
-
item.children = [];
|
|
70
|
-
item.expand = false;
|
|
71
|
-
item.checked = false;
|
|
72
|
-
if(item.leafNode){
|
|
73
|
-
delete item.loading;
|
|
74
|
-
delete item.children;
|
|
284
|
+
}).then((res) => {
|
|
285
|
+
if (res.data.code === 1) {
|
|
286
|
+
let treeList = res.data.data || [];
|
|
287
|
+
// 关键修改:调用重构后的 initTree,递归初始化所有层级节点
|
|
288
|
+
const initializedTree = this.initTree(treeList);
|
|
289
|
+
resolve(initializedTree);
|
|
290
|
+
} else {
|
|
291
|
+
resolve([]);
|
|
75
292
|
}
|
|
76
|
-
})
|
|
77
|
-
|
|
293
|
+
}).catch(err => {
|
|
294
|
+
console.log(err);
|
|
295
|
+
resolve([]);
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
setCheckedNodes(targets) {
|
|
301
|
+
if (!this.$refs.tree || !Array.isArray(targets)) {
|
|
302
|
+
this.clearAllChecked(this.data);
|
|
303
|
+
this.$emit('handleChange', []);
|
|
304
|
+
this.$nextTick(() => this.$refs.tree.$forceUpdate());
|
|
305
|
+
return;
|
|
78
306
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
307
|
+
|
|
308
|
+
// 单选,清空所有选中状态
|
|
309
|
+
this.clearAllChecked(this.data);
|
|
310
|
+
|
|
311
|
+
const targetList = this.isSingleSelect
|
|
312
|
+
? (targets.length > 0 ? [targets[targets.length - 1]] : [])
|
|
313
|
+
: targets;
|
|
314
|
+
|
|
315
|
+
// 转换为有效orgUnitId数组
|
|
316
|
+
const targetIds = targetList.map(item => {
|
|
317
|
+
if (typeof item === 'string') return item.trim();
|
|
318
|
+
return (item.orgUnitId || item.id || '').trim();
|
|
319
|
+
}).filter(id => id); // 过滤空ID
|
|
320
|
+
|
|
321
|
+
// 查找并选中目标节点
|
|
322
|
+
const findAndCheckNode = (treeData, targetId) => {
|
|
323
|
+
for (const node of treeData) {
|
|
324
|
+
const nodeId = (node.orgUnitId || node.id || '').trim();
|
|
325
|
+
if (nodeId === targetId) {
|
|
326
|
+
this.$set(node, 'checked', true);
|
|
327
|
+
this.expandToNode(node);
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
331
|
+
if (childNodes.length && findAndCheckNode(childNodes, targetId)) {
|
|
332
|
+
return true;
|
|
333
|
+
}
|
|
88
334
|
}
|
|
89
|
-
|
|
90
|
-
|
|
335
|
+
return false;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
targetIds.forEach(id => findAndCheckNode(this.data, id));
|
|
339
|
+
|
|
340
|
+
// 传递过滤后的有效节点
|
|
341
|
+
const checkedNodes = this.collectCurrentCheckedNodes(this.data);
|
|
342
|
+
this.$nextTick(() => {
|
|
343
|
+
this.$refs.tree.$forceUpdate();
|
|
344
|
+
this.$emit('handleChange', checkedNodes);
|
|
345
|
+
});
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
expandToNode(node) {
|
|
349
|
+
let current = node;
|
|
350
|
+
while (current && current.parent) {
|
|
351
|
+
if (typeof current.parent === 'object' && !Array.isArray(current.parent)) {
|
|
352
|
+
this.$set(current.parent, 'expand', true);
|
|
353
|
+
}
|
|
354
|
+
current = current.parent.orgUnitId
|
|
355
|
+
? this.findNodeInTree(this.data, current.parent.orgUnitId)
|
|
356
|
+
: null;
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
collectAllCheckedNodes(nodeList) {
|
|
361
|
+
let checkedNodes = [];
|
|
362
|
+
nodeList.forEach(node => {
|
|
363
|
+
if (node.checked) {
|
|
364
|
+
checkedNodes.push(node);
|
|
365
|
+
}
|
|
366
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
367
|
+
if (childNodes.length) {
|
|
368
|
+
checkedNodes = [...checkedNodes, ...this.collectAllCheckedNodes(childNodes)];
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
return checkedNodes;
|
|
372
|
+
},
|
|
373
|
+
|
|
374
|
+
clearAllChecked(treeData) {
|
|
375
|
+
if (!Array.isArray(treeData)) return;
|
|
376
|
+
treeData.forEach(node => {
|
|
377
|
+
if (node.checked) {
|
|
378
|
+
this.$set(node, 'checked', false);
|
|
91
379
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
380
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
381
|
+
if (childNodes.length) {
|
|
382
|
+
this.clearAllChecked(childNodes);
|
|
95
383
|
}
|
|
96
|
-
})
|
|
384
|
+
});
|
|
97
385
|
},
|
|
98
|
-
|
|
386
|
+
|
|
387
|
+
updateTreeData(newTreeData) {
|
|
388
|
+
if (!Array.isArray(newTreeData)) return;
|
|
389
|
+
const tree = deepCopy(newTreeData);
|
|
390
|
+
this.initTree(tree);
|
|
391
|
+
this.data = tree;
|
|
392
|
+
this.$nextTick(() => {
|
|
393
|
+
this.$refs.tree.$forceUpdate();
|
|
394
|
+
});
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
findNodeInTree(treeData, targetOrgUnitId) {
|
|
398
|
+
if (!treeData || !targetOrgUnitId) return null;
|
|
399
|
+
|
|
400
|
+
for (const node of treeData) {
|
|
401
|
+
if (!node.parent && treeData !== this.data) {
|
|
402
|
+
node.parent = treeData;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
if (node.orgUnitId === targetOrgUnitId) return node;
|
|
406
|
+
|
|
407
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
408
|
+
if (childNodes.length) {
|
|
409
|
+
const childNode = this.findNodeInTree(childNodes, targetOrgUnitId);
|
|
410
|
+
if (childNode) return childNode;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
initTree(treeList) {
|
|
417
|
+
// 递归处理节点的内部方法
|
|
418
|
+
const recursiveInitNode = (node) => {
|
|
419
|
+
node.title = node.orgUnitName || node.orgNodeName || node.name || `未命名组织(${node.orgUnitId || node.id || ''})`;
|
|
420
|
+
node.loading = false;
|
|
421
|
+
node.expand = false;
|
|
422
|
+
node.checked = false;
|
|
423
|
+
node.children = node.children || [];
|
|
424
|
+
node.orgChildrenList = node.orgChildrenList || node.children || [];
|
|
425
|
+
if (this.disabled) {
|
|
426
|
+
node.disabled = true;
|
|
427
|
+
}
|
|
428
|
+
if (node.leafNode) {
|
|
429
|
+
delete node.loading;
|
|
430
|
+
delete node.children;
|
|
431
|
+
delete node.orgChildrenList;
|
|
432
|
+
} else {
|
|
433
|
+
if (Array.isArray(node.orgChildrenList) && node.orgChildrenList.length > 0) {
|
|
434
|
+
node.children = node.orgChildrenList.map(child => recursiveInitNode(child));
|
|
435
|
+
node.expand = true;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
return node;
|
|
439
|
+
};
|
|
440
|
+
|
|
441
|
+
// 处理根节点列表
|
|
442
|
+
if (Array.isArray(treeList)) {
|
|
443
|
+
return treeList.map(node => recursiveInitNode(node));
|
|
444
|
+
}
|
|
445
|
+
return treeList;
|
|
446
|
+
},
|
|
447
|
+
|
|
448
|
+
renderContent(h, {root, node, data}) {
|
|
449
|
+
const nodeText = data.orgUnitName || data.title || data.orgNodeName || data.name || `未命名组织(${data.orgUnitId || data.id || ''})`;
|
|
99
450
|
return h('div', {
|
|
100
451
|
style: {
|
|
101
452
|
width: '100%',
|
|
102
|
-
overflow:'hidden',
|
|
103
|
-
display:'flex',
|
|
453
|
+
overflow: 'hidden',
|
|
454
|
+
display: 'flex',
|
|
104
455
|
alignItems: 'center',
|
|
456
|
+
cursor: 'default'
|
|
457
|
+
},
|
|
458
|
+
on: {
|
|
459
|
+
click: (e) => {
|
|
460
|
+
const isCheckbox = e.target.closest('.ivu-checkbox') || e.target.closest('.ivu-checkbox-icon');
|
|
461
|
+
if (!isCheckbox) {
|
|
462
|
+
e.stopPropagation();
|
|
463
|
+
e.preventDefault();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
105
466
|
}
|
|
106
467
|
}, [
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
on:{
|
|
124
|
-
click:()=>{
|
|
125
|
-
this.checkNode(data)
|
|
468
|
+
h('Checkbox', {
|
|
469
|
+
props: {
|
|
470
|
+
value: data.checked,
|
|
471
|
+
disabled: data.disabled || this.disabled,
|
|
472
|
+
indeterminate: false
|
|
473
|
+
},
|
|
474
|
+
style: {
|
|
475
|
+
marginRight: '8px',
|
|
476
|
+
cursor: 'pointer'
|
|
477
|
+
},
|
|
478
|
+
on: {
|
|
479
|
+
'on-change': (checked) => {
|
|
480
|
+
this.$set(data, 'checked', checked);
|
|
481
|
+
if (this.isSingleSelect && checked) {
|
|
482
|
+
this.clearOtherCheckedNodes([data.orgUnitId]);
|
|
126
483
|
}
|
|
484
|
+
const checkedNodes = this.isSingleSelect
|
|
485
|
+
? (checked ? [data] : [])
|
|
486
|
+
: this.collectCurrentCheckedNodes(this.data);
|
|
487
|
+
this.handleChange(checkedNodes);
|
|
127
488
|
}
|
|
128
|
-
}
|
|
489
|
+
}
|
|
490
|
+
}),
|
|
491
|
+
h('img', {
|
|
492
|
+
attrs: { src: require('./assets/icon.png') },
|
|
493
|
+
style: {
|
|
494
|
+
marginRight: '8px',
|
|
495
|
+
width: '14px',
|
|
496
|
+
height: '14px',
|
|
497
|
+
pointerEvents: 'none'
|
|
498
|
+
}
|
|
499
|
+
}),
|
|
500
|
+
h('span', {
|
|
501
|
+
style: {
|
|
502
|
+
flex: 1,
|
|
503
|
+
pointerEvents: 'none',
|
|
504
|
+
userSelect: 'none',
|
|
505
|
+
whiteSpace: 'normal',
|
|
506
|
+
wordWrap: 'break-word'
|
|
507
|
+
}
|
|
508
|
+
}, nodeText)
|
|
129
509
|
]);
|
|
130
510
|
},
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
511
|
+
collectCurrentCheckedNodes(nodeList) {
|
|
512
|
+
let checkedNodes = [];
|
|
513
|
+
nodeList.forEach(node => {
|
|
514
|
+
if (node.checked) {
|
|
515
|
+
const nodeId = node.orgUnitId || node.id || '';
|
|
516
|
+
if (nodeId && typeof nodeId === 'string' && nodeId.trim()) {
|
|
517
|
+
const validNode = {
|
|
518
|
+
...node,
|
|
519
|
+
orgUnitId: nodeId.trim(),
|
|
520
|
+
orgNodeName: node.orgNodeName || node.title || node.name || `未命名组织(${nodeId.trim()})`
|
|
521
|
+
};
|
|
522
|
+
checkedNodes.push(validNode);
|
|
137
523
|
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
|
|
524
|
+
}
|
|
525
|
+
// 递归处理子节点
|
|
526
|
+
const childNodes = node.children || node.orgChildrenList || [];
|
|
527
|
+
if (childNodes.length) {
|
|
528
|
+
checkedNodes = [...checkedNodes, ...this.collectCurrentCheckedNodes(childNodes)];
|
|
529
|
+
}
|
|
530
|
+
});
|
|
531
|
+
return checkedNodes;
|
|
532
|
+
},
|
|
533
|
+
upDataTree() {
|
|
534
|
+
const unCheck = (list) => {
|
|
535
|
+
list.forEach((item) => {
|
|
536
|
+
this.$set(item, 'checked', false);
|
|
537
|
+
});
|
|
538
|
+
};
|
|
539
|
+
unCheck(this.data);
|
|
141
540
|
}
|
|
142
541
|
},
|
|
143
|
-
|
|
542
|
+
watch: {
|
|
543
|
+
'treeList': {
|
|
544
|
+
handler(val) {
|
|
545
|
+
if (this.isCustomTree || this.isDisableLazyLoad) {
|
|
546
|
+
let tree = this.safeDeepCopy(val);
|
|
547
|
+
this.initTree(tree);
|
|
548
|
+
this.data = tree;
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
let tree = deepCopy(val);
|
|
552
|
+
this.initTree(tree);
|
|
553
|
+
this.data = tree;
|
|
554
|
+
},
|
|
555
|
+
deep: true
|
|
556
|
+
},
|
|
557
|
+
// 监听 isCustomTree 变化
|
|
558
|
+
isCustomTree(newVal) {
|
|
559
|
+
if (newVal) {
|
|
560
|
+
this.isDisableLazyLoad = true;
|
|
561
|
+
this.loading = false;
|
|
562
|
+
let tree = this.safeDeepCopy(this.treeList);
|
|
563
|
+
this.initTree(tree);
|
|
564
|
+
this.data = tree;
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
// 监听 disableLazyLoad 变化
|
|
568
|
+
disableLazyLoad(newVal) {
|
|
569
|
+
this.isDisableLazyLoad = newVal;
|
|
570
|
+
if (newVal) {
|
|
571
|
+
this.isCustomTree = true;
|
|
572
|
+
this.loading = false;
|
|
573
|
+
let tree = this.safeDeepCopy(this.treeList);
|
|
574
|
+
this.initTree(tree);
|
|
575
|
+
this.data = tree;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
};
|
|
144
580
|
</script>
|
|
581
|
+
|
|
145
582
|
<style lang="less" scoped>
|
|
146
|
-
.content{
|
|
147
|
-
width: 100
|
|
148
|
-
height: 100
|
|
149
|
-
overflow:
|
|
583
|
+
.content {
|
|
584
|
+
width: 100% !important;
|
|
585
|
+
height: 100% !important;
|
|
586
|
+
overflow: visible !important; /* 完全放开溢出限制 */
|
|
587
|
+
box-sizing: border-box;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/* 子组件内层容器强制宽度自适应 */
|
|
591
|
+
.tree-inner {
|
|
592
|
+
width: fit-content !important;
|
|
593
|
+
min-width: 100% !important;
|
|
594
|
+
height: 100% !important;
|
|
595
|
+
white-space: nowrap !important;
|
|
596
|
+
overflow: visible !important;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
/deep/ .ivu-tree-node {
|
|
600
|
+
white-space: nowrap !important;
|
|
601
|
+
width: auto !important;
|
|
602
|
+
min-width: 100% !important;
|
|
603
|
+
box-sizing: border-box;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/deep/ .ivu-tree-node-content {
|
|
607
|
+
cursor: default !important;
|
|
608
|
+
pointer-events: none !important;
|
|
609
|
+
padding-left: 0 !important;
|
|
610
|
+
width: 100% !important; /* 关键:节点内容宽度100% */
|
|
611
|
+
|
|
612
|
+
.ivu-checkbox, .ivu-tree-switcher {
|
|
613
|
+
pointer-events: auto !important;
|
|
614
|
+
cursor: pointer !important;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/deep/ .ivu-tree {
|
|
619
|
+
white-space: nowrap !important;
|
|
620
|
+
display: inline-block !important;
|
|
621
|
+
width: auto !important;
|
|
622
|
+
min-width: 100% !important;
|
|
623
|
+
box-sizing: border-box;
|
|
624
|
+
height: 100% !important; /* 关键:树组件高度100% */
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
|
|
628
|
+
/deep/ .ivu-tree-node,
|
|
629
|
+
/deep/ .ivu-tree-node *,
|
|
630
|
+
/deep/ .ivu-tree-node-content,
|
|
631
|
+
/deep/ .ivu-tree-title {
|
|
632
|
+
box-shadow: none !important;
|
|
633
|
+
text-shadow: none !important;
|
|
634
|
+
outline: none !important;
|
|
635
|
+
border: none !important;
|
|
636
|
+
background: transparent !important;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/deep/ .ivu-tree-node-selected,
|
|
640
|
+
/deep/ .ivu-tree-node-selected *,
|
|
641
|
+
/deep/ .ivu-tree-node-focus,
|
|
642
|
+
/deep/ .ivu-tree-node-focus *,
|
|
643
|
+
/deep/ .ivu-tree-node-hover,
|
|
644
|
+
/deep/ .ivu-tree-node-hover * {
|
|
645
|
+
box-shadow: none !important;
|
|
646
|
+
text-shadow: none !important;
|
|
647
|
+
background: transparent !important;
|
|
648
|
+
color: inherit !important;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/deep/ .ivu-tree-node-content {
|
|
652
|
+
padding-left: 0 !important;
|
|
150
653
|
}
|
|
151
|
-
|
|
152
|
-
|
|
654
|
+
|
|
655
|
+
/deep/ .ivu-tree::-webkit-scrollbar {
|
|
656
|
+
display: block !important;
|
|
153
657
|
}
|
|
154
|
-
|
|
155
|
-
|
|
658
|
+
|
|
659
|
+
/deep/ .ivu-tree-indent {
|
|
660
|
+
margin-right: 4px;
|
|
661
|
+
display: inline-block !important;
|
|
156
662
|
}
|
|
157
663
|
|
|
664
|
+
/deep/ .ivu-tree-node::before,
|
|
665
|
+
/deep/ .ivu-tree-node::after,
|
|
666
|
+
/deep/ .ivu-tree-title::before,
|
|
667
|
+
/deep/ .ivu-tree-title::after {
|
|
668
|
+
box-shadow: none !important;
|
|
669
|
+
text-shadow: none !important;
|
|
670
|
+
background: none !important;
|
|
671
|
+
}
|
|
158
672
|
</style>
|