centaline-data-driven-v3 0.1.41 → 0.1.43
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/dist/centaline-data-driven-v3.umd.js +96 -96
- package/package.json +1 -1
- package/src/components/web/Form.vue +202 -49
- package/src/components/web/Tree/Tree.vue +838 -179
- package/src/loader/src/SearchScreen.js +1 -1
- package/src/main.js +3 -3
- package/src/utils/request.js +5 -6
- package/src/views/Form.vue +2 -2
- package/src/views/SearchList.vue +2 -2
- package/src/views/Tree.vue +2 -2
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div id="ct-tree" class="ct-tree" oncontextmenu="event.preventDefault()" style="overflow:auto;" v-loading="loading"
|
|
3
3
|
:style="{ height: props.treeHeight - 10 + 'px' }">
|
|
4
|
-
<el-tree class="tree-line" :props="defaultProps" :
|
|
5
|
-
|
|
6
|
-
current-node-key="currentNodeKey">
|
|
7
|
-
|
|
4
|
+
<el-tree class="tree-line" :props="defaultProps" :expand-on-click-node="false" @node-click="handleNodeClick"
|
|
5
|
+
:filter-node-method="filterNode" lazy :load="loadNode" ref="refTree" @node-contextmenu="rightClick"
|
|
6
|
+
node-key="code" current-node-key="currentNodeKey" :default-expanded-keys="defaultExpandedKeys">
|
|
8
7
|
<template #default="{ node, data }">
|
|
9
|
-
<span>
|
|
10
|
-
<
|
|
8
|
+
<span class="node_content">
|
|
9
|
+
<el-icon class="node-icon" :class="{ 'is-leaf': node.isLeaf }">
|
|
10
|
+
<Document v-if="node.isLeaf" :size="14" />
|
|
11
|
+
<Folder v-else-if="!node.expanded" :size="14" />
|
|
12
|
+
<FolderOpened v-else :size="14" />
|
|
13
|
+
</el-icon>
|
|
14
|
+
<span style="" :ref="(el: refItem) => handleSetInputMap(el, data)">{{
|
|
11
15
|
data.name }}</span>
|
|
12
16
|
<span @click.stop>
|
|
13
17
|
<el-popover placement="right" :virtual-ref="nodeRef" virtual-triggering
|
|
14
|
-
:visible="((data.code == currentData.code && menuVisible &&
|
|
18
|
+
:visible="((data.code == currentData.code && menuVisible && allowedRoutes?.length > 0))">
|
|
15
19
|
<div class="box-menu">
|
|
16
|
-
<template v-for="(item, index) in
|
|
20
|
+
<template v-for="(item, index) in allowedRoutes">
|
|
17
21
|
<div class="opertion" @click="routerClickHandler(item)">
|
|
18
22
|
<div>
|
|
19
23
|
<img v-if="item.imgUrl" :src="item.imgUrl" alt="" />
|
|
@@ -22,22 +26,21 @@
|
|
|
22
26
|
</div>
|
|
23
27
|
</template>
|
|
24
28
|
</div>
|
|
25
|
-
|
|
26
29
|
</el-popover>
|
|
27
30
|
</span>
|
|
28
31
|
</span>
|
|
29
32
|
</template>
|
|
30
33
|
</el-tree>
|
|
31
|
-
|
|
32
|
-
|
|
33
34
|
</div>
|
|
34
35
|
</template>
|
|
36
|
+
|
|
35
37
|
<script setup lang="ts">
|
|
36
|
-
import { ref, nextTick, ComponentPublicInstance, onBeforeUnmount } from 'vue'
|
|
38
|
+
import { ref, nextTick, ComponentPublicInstance, onBeforeUnmount, computed, watch } from 'vue'
|
|
37
39
|
import common from '../../../utils/common'
|
|
38
40
|
import { RouterClickHandler } from '../../../utils/mixins';
|
|
39
41
|
import Enum from '../../../utils/Enum'
|
|
40
42
|
import Tree from '../../../loader/src/Tree';
|
|
43
|
+
|
|
41
44
|
type refItem = Element | ComponentPublicInstance | null;
|
|
42
45
|
|
|
43
46
|
const emit = defineEmits(['loaded'])
|
|
@@ -54,8 +57,15 @@ const props = defineProps({
|
|
|
54
57
|
apiParam: {
|
|
55
58
|
type: Object,
|
|
56
59
|
default: () => { },
|
|
60
|
+
},
|
|
61
|
+
// 新增:是否默认展开两级
|
|
62
|
+
expandTwoLevels: {
|
|
63
|
+
type: Boolean,
|
|
64
|
+
default: true
|
|
57
65
|
}
|
|
58
66
|
})
|
|
67
|
+
|
|
68
|
+
const lazy = ref(true)
|
|
59
69
|
const refTree = ref()
|
|
60
70
|
const rootNode = ref();
|
|
61
71
|
const rootResolve = ref();
|
|
@@ -69,15 +79,31 @@ const defaultProps = ref({
|
|
|
69
79
|
})
|
|
70
80
|
const searchStatus = ref([])
|
|
71
81
|
const screenPara = ref(props.apiParam);
|
|
72
|
-
const menuVisible = ref(false)
|
|
73
|
-
const currentData = ref({ code: "" })
|
|
74
|
-
const currentNode = ref(null)
|
|
75
|
-
const loading = ref(false)
|
|
82
|
+
const menuVisible = ref(false)
|
|
83
|
+
const currentData = ref({ code: "" })
|
|
84
|
+
const currentNode = ref(null)
|
|
85
|
+
const loading = ref(false)
|
|
76
86
|
|
|
77
87
|
const model = ref(null)
|
|
78
88
|
const nodeRef = ref()
|
|
79
89
|
const retryCount = ref(0);
|
|
80
90
|
const treeNodeRefMap = ref({});
|
|
91
|
+
const allowedRoutes = ref([]);
|
|
92
|
+
|
|
93
|
+
// 默认展开的节点key数组
|
|
94
|
+
const defaultExpandedKeys = ref([])
|
|
95
|
+
// 是否已设置默认展开
|
|
96
|
+
const hasSetDefaultExpand = ref(false)
|
|
97
|
+
// 是否是搜索状态
|
|
98
|
+
const isSearching = ref(false)
|
|
99
|
+
|
|
100
|
+
// 全量数据缓存
|
|
101
|
+
const fullTreeData = ref([])
|
|
102
|
+
|
|
103
|
+
// 新增:缓存所有节点的Map,用于快速查找
|
|
104
|
+
const nodeCodeMap = ref(new Map())
|
|
105
|
+
|
|
106
|
+
const isExpandAll = ref(false);
|
|
81
107
|
/** 动态设置Input Ref */
|
|
82
108
|
const handleSetInputMap = (el: refItem, item) => {
|
|
83
109
|
if (el) {
|
|
@@ -93,11 +119,133 @@ onBeforeUnmount(() => {
|
|
|
93
119
|
}
|
|
94
120
|
})
|
|
95
121
|
|
|
96
|
-
|
|
122
|
+
function getFirstNLevelKeys(nodes, targetLevel = 1) {
|
|
123
|
+
const result = [];
|
|
124
|
+
|
|
125
|
+
if (!nodes || nodes.length === 0 || targetLevel < 0) {
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const traverse = (nodes, currentLevel) => {
|
|
130
|
+
if (currentLevel > targetLevel || !nodes) return;
|
|
131
|
+
|
|
132
|
+
nodes.forEach(node => {
|
|
133
|
+
if (node.code) {
|
|
134
|
+
result.push(node.code);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// 如果还有下一层且没超过目标层级,继续遍历
|
|
138
|
+
if (currentLevel < targetLevel && node.children && node.children.length > 0) {
|
|
139
|
+
traverse(node.children, currentLevel + 1);
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
traverse(nodes, 0);
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 递归获取所有节点的key(用于搜索时全展开)
|
|
149
|
+
function getAllNodeKeys(nodes, result = []) {
|
|
150
|
+
if (!nodes || nodes.length === 0) {
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
nodes.forEach(node => {
|
|
155
|
+
if (node.code) {
|
|
156
|
+
result.push(node.code);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (node.children && node.children.length > 0) {
|
|
160
|
+
getAllNodeKeys(node.children, result);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// 设置默认展开节点
|
|
168
|
+
function setDefaultExpandedNodes() {
|
|
169
|
+
if (!props.expandTwoLevels || !fullTreeData.value.length) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
if (isSearching.value) {
|
|
174
|
+
isExpandAll.value = true;
|
|
175
|
+
const allKeys = getAllNodeKeys(fullTreeData.value);
|
|
176
|
+
defaultExpandedKeys.value = allKeys;
|
|
177
|
+
} else {
|
|
178
|
+
isExpandAll.value = false;
|
|
179
|
+
// 检查是否有全展开搜索条件
|
|
180
|
+
const expandValue = findSearchFieldValue(screenPara.value, 'expanded', {
|
|
181
|
+
caseInsensitive: true, // 添加不区分大小写的选项
|
|
182
|
+
keyFields: ['fieldName1', 'groupName', 'fieldLabel'] // 扩展可能的key字段
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// 如果找到expanded=all的搜索条件,设置全展开
|
|
186
|
+
if (expandValue && expandValue.toString().toLowerCase() === 'all') {
|
|
187
|
+
isExpandAll.value = true;
|
|
188
|
+
const allKeys = getAllNodeKeys(fullTreeData.value);
|
|
189
|
+
defaultExpandedKeys.value = allKeys;
|
|
190
|
+
} else {
|
|
191
|
+
// 处理非'all'的情况
|
|
192
|
+
let expandLevel = 1; // 默认展开级别为1
|
|
193
|
+
|
|
194
|
+
if (expandValue) {
|
|
195
|
+
const numericValue = Number(expandValue);
|
|
196
|
+
if (!isNaN(numericValue) && numericValue > 0) {
|
|
197
|
+
expandLevel = Math.max(0, numericValue - 1); // 减1但最小为1
|
|
198
|
+
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
defaultExpandedKeys.value = getFirstNLevelKeys(fullTreeData.value, expandLevel);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
hasSetDefaultExpand.value = true;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 新增:构建节点Map,便于快速查找
|
|
210
|
+
function buildNodeCodeMap(nodes) {
|
|
211
|
+
const map = new Map();
|
|
212
|
+
|
|
213
|
+
function traverse(nodeList) {
|
|
214
|
+
nodeList.forEach(node => {
|
|
215
|
+
if (node.code) {
|
|
216
|
+
map.set(node.code, node);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (node.children && node.children.length > 0) {
|
|
220
|
+
traverse(node.children);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
traverse(nodes);
|
|
226
|
+
return map;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// 新增:复制节点(深拷贝)
|
|
230
|
+
function cloneNode(node) {
|
|
231
|
+
const cloned = { ...node };
|
|
232
|
+
cloned.children = [];
|
|
233
|
+
return cloned;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// 搜索(查询条件调用)
|
|
97
237
|
function search(m) {
|
|
238
|
+
const hasValidSearchConditions = checkHasValidSearchConditions(m);
|
|
239
|
+
|
|
240
|
+
isSearching.value = hasValidSearchConditions;
|
|
98
241
|
screenPara.value = m;
|
|
242
|
+
|
|
243
|
+
if (!lazy.value) {
|
|
244
|
+
filterFullTreeData(screenPara.value);
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
|
|
99
248
|
if (searchStatus.value.length == 0) {
|
|
100
|
-
// 重置计数器
|
|
101
249
|
retryCount.value = 0
|
|
102
250
|
if (qrtimer.value) clearTimeout(qrtimer.value);
|
|
103
251
|
searchStatus.value.push('a');
|
|
@@ -116,47 +264,465 @@ function search(m) {
|
|
|
116
264
|
}, 200);
|
|
117
265
|
}
|
|
118
266
|
}
|
|
119
|
-
|
|
267
|
+
|
|
268
|
+
// 检查是否有有效的搜索条件
|
|
269
|
+
function checkHasValidSearchConditions(filter) {
|
|
270
|
+
if (!filter) return false;
|
|
271
|
+
|
|
272
|
+
let searchConditions = [];
|
|
273
|
+
|
|
274
|
+
if (filter?.searchData?.fields) {
|
|
275
|
+
searchConditions = filter.searchData.fields;
|
|
276
|
+
} else if (filter?.fields) {
|
|
277
|
+
searchConditions = filter.fields;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const validConditions = filterValidConditions(searchConditions);
|
|
281
|
+
return validConditions && validConditions.length > 0;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
// 过滤掉 operation 为 1 的条件
|
|
287
|
+
function filterValidConditions(conditions) {
|
|
288
|
+
if (!conditions || !Array.isArray(conditions)) return [];
|
|
289
|
+
|
|
290
|
+
return conditions.filter(condition => {
|
|
291
|
+
return condition.operation !== 1;
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// 判断节点是否匹配所有搜索条件
|
|
296
|
+
function nodeMatchesAllConditions(node, conditions) {
|
|
297
|
+
const validConditions = filterValidConditions(conditions);
|
|
298
|
+
|
|
299
|
+
if (!validConditions || validConditions.length === 0) return true;
|
|
300
|
+
|
|
301
|
+
return validConditions.every(condition => {
|
|
302
|
+
const { fieldName1, operation, searchValue1, searchValue2, searchDataType } = condition;
|
|
303
|
+
let nodeValue = node[fieldName1];
|
|
304
|
+
|
|
305
|
+
if (nodeValue === undefined) {
|
|
306
|
+
const mappedField = Object.keys(node).find(key =>
|
|
307
|
+
key.toLowerCase() === fieldName1.toLowerCase()
|
|
308
|
+
);
|
|
309
|
+
if (mappedField) {
|
|
310
|
+
nodeValue = node[mappedField];
|
|
311
|
+
} else {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const strNodeValue = String(nodeValue || '').toLowerCase();
|
|
317
|
+
const strSearchValue = String(searchValue1 || '').toLowerCase();
|
|
318
|
+
|
|
319
|
+
switch (operation) {
|
|
320
|
+
case 2:
|
|
321
|
+
return strNodeValue === strSearchValue;
|
|
322
|
+
case 3:
|
|
323
|
+
return strNodeValue !== strSearchValue;
|
|
324
|
+
case 4:
|
|
325
|
+
return Number(nodeValue) > Number(searchValue1);
|
|
326
|
+
case 5:
|
|
327
|
+
return Number(nodeValue) >= Number(searchValue1);
|
|
328
|
+
case 6:
|
|
329
|
+
return Number(nodeValue) < Number(searchValue1);
|
|
330
|
+
case 7:
|
|
331
|
+
return Number(nodeValue) <= Number(searchValue1);
|
|
332
|
+
case 8:
|
|
333
|
+
return strNodeValue.includes(strSearchValue);
|
|
334
|
+
case 9:
|
|
335
|
+
return strNodeValue.startsWith(strSearchValue);
|
|
336
|
+
case 10:
|
|
337
|
+
return strNodeValue.endsWith(strSearchValue);
|
|
338
|
+
case 11:
|
|
339
|
+
return !strNodeValue.includes(strSearchValue);
|
|
340
|
+
case 12:
|
|
341
|
+
try {
|
|
342
|
+
const regex = new RegExp(searchValue1, 'i');
|
|
343
|
+
return regex.test(nodeValue);
|
|
344
|
+
} catch (e) {
|
|
345
|
+
console.warn('正则表达式错误:', e);
|
|
346
|
+
return false;
|
|
347
|
+
}
|
|
348
|
+
case 13:
|
|
349
|
+
if (!searchValue1) return false;
|
|
350
|
+
try {
|
|
351
|
+
const values = searchValue1.split(',').map(v => v.trim().toLowerCase());
|
|
352
|
+
return values.includes(strNodeValue);
|
|
353
|
+
} catch (e) {
|
|
354
|
+
console.warn('解析IN条件错误:', e);
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
case 14:
|
|
358
|
+
if (!searchValue1) return true;
|
|
359
|
+
try {
|
|
360
|
+
const values = searchValue1.split(',').map(v => v.trim().toLowerCase());
|
|
361
|
+
return !values.includes(strNodeValue);
|
|
362
|
+
} catch (e) {
|
|
363
|
+
console.warn('解析NotIN条件错误:', e);
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
default:
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
// 修改:构建完整的过滤树,保持原始层级结构
|
|
373
|
+
function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
374
|
+
if (!matchedNodes || matchedNodes.length === 0) {
|
|
375
|
+
return [];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
const resultMap = new Map();
|
|
379
|
+
const rootNodes = [];
|
|
380
|
+
|
|
381
|
+
// 第一步:创建所有匹配节点的副本
|
|
382
|
+
matchedNodes.forEach(node => {
|
|
383
|
+
if (!resultMap.has(node.code)) {
|
|
384
|
+
const clonedNode = cloneNode(node);
|
|
385
|
+
resultMap.set(node.code, clonedNode);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// 第二步:为每个匹配节点建立完整的父子关系链
|
|
390
|
+
matchedNodes.forEach(matchedNode => {
|
|
391
|
+
// 从全量数据中查找该节点的完整路径
|
|
392
|
+
const fullNode = nodeCodeMap.value.get(matchedNode.code);
|
|
393
|
+
if (!fullNode) return;
|
|
394
|
+
|
|
395
|
+
// 递归向上查找父节点链
|
|
396
|
+
function findParentChain(currentNode, chain = []) {
|
|
397
|
+
chain.unshift(currentNode.code);
|
|
398
|
+
|
|
399
|
+
// 在全量数据中查找父节点
|
|
400
|
+
const parentCode = findParentCodeInFullTree(currentNode.code);
|
|
401
|
+
if (parentCode) {
|
|
402
|
+
const parentNode = nodeCodeMap.value.get(parentCode);
|
|
403
|
+
if (parentNode) {
|
|
404
|
+
findParentChain(parentNode, chain);
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
return chain;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const parentChain = findParentChain(fullNode);
|
|
412
|
+
|
|
413
|
+
// 构建完整的树结构
|
|
414
|
+
for (let i = 0; i < parentChain.length; i++) {
|
|
415
|
+
const currentCode = parentChain[i];
|
|
416
|
+
|
|
417
|
+
// 如果节点已经存在,跳过
|
|
418
|
+
if (resultMap.has(currentCode)) {
|
|
419
|
+
continue;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// 从全量数据中获取节点
|
|
423
|
+
const originalNode = nodeCodeMap.value.get(currentCode);
|
|
424
|
+
if (!originalNode) continue;
|
|
425
|
+
|
|
426
|
+
// 创建节点副本
|
|
427
|
+
const clonedNode = cloneNode(originalNode);
|
|
428
|
+
resultMap.set(currentCode, clonedNode);
|
|
429
|
+
|
|
430
|
+
// 如果是根节点,添加到根节点数组
|
|
431
|
+
if (i === 0) {
|
|
432
|
+
// 检查是否已经存在于根节点中
|
|
433
|
+
const existingRoot = rootNodes.find(n => n.code === currentCode);
|
|
434
|
+
if (!existingRoot) {
|
|
435
|
+
rootNodes.push(clonedNode);
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// 连接到父节点
|
|
440
|
+
if (i > 0) {
|
|
441
|
+
const parentCode = parentChain[i - 1];
|
|
442
|
+
const parentNode = resultMap.get(parentCode);
|
|
443
|
+
|
|
444
|
+
if (parentNode) {
|
|
445
|
+
// 检查是否已经包含该子节点
|
|
446
|
+
const existingChild = parentNode.children.find(child => child.code === currentCode);
|
|
447
|
+
if (!existingChild) {
|
|
448
|
+
parentNode.children.push(clonedNode);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// 最后,确保当前匹配节点连接到其父节点
|
|
455
|
+
const parentCode = findParentCodeInFullTree(matchedNode.code);
|
|
456
|
+
if (parentCode && resultMap.has(parentCode)) {
|
|
457
|
+
const parentNode = resultMap.get(parentCode);
|
|
458
|
+
const currentNode = resultMap.get(matchedNode.code);
|
|
459
|
+
|
|
460
|
+
if (parentNode && currentNode) {
|
|
461
|
+
// 检查是否已经包含该子节点
|
|
462
|
+
const existingChild = parentNode.children.find(child => child.code === matchedNode.code);
|
|
463
|
+
if (!existingChild) {
|
|
464
|
+
parentNode.children.push(currentNode);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// 第三步:清理根节点,确保它们没有重复的父节点
|
|
471
|
+
const finalRootNodes = [];
|
|
472
|
+
const usedNodes = new Set();
|
|
473
|
+
|
|
474
|
+
function isNodeUsedInTree(node) {
|
|
475
|
+
for (const root of rootNodes) {
|
|
476
|
+
if (isNodeInChildren(root, node.code)) {
|
|
477
|
+
return true;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
rootNodes.forEach(rootNode => {
|
|
484
|
+
// 如果这个节点已经是其他节点的子节点,则不作为根节点
|
|
485
|
+
if (!isNodeUsedInTree(rootNode)) {
|
|
486
|
+
finalRootNodes.push(rootNode);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
return finalRootNodes;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// 新增:在全量树中查找父节点code
|
|
494
|
+
function findParentCodeInFullTree(nodeCode) {
|
|
495
|
+
function findParent(nodes, targetCode, parentCode = null) {
|
|
496
|
+
for (const node of nodes) {
|
|
497
|
+
if (node.code === targetCode) {
|
|
498
|
+
return parentCode;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (node.children && node.children.length > 0) {
|
|
502
|
+
const found = findParent(node.children, targetCode, node.code);
|
|
503
|
+
if (found !== null) {
|
|
504
|
+
return found;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
return findParent(fullTreeData.value, nodeCode);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// 新增:检查节点是否在子树中
|
|
515
|
+
function isNodeInChildren(parentNode, targetCode) {
|
|
516
|
+
if (parentNode.code === targetCode) {
|
|
517
|
+
return false; // 不检查自身
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (!parentNode.children || parentNode.children.length === 0) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
for (const child of parentNode.children) {
|
|
525
|
+
if (child.code === targetCode) {
|
|
526
|
+
return true;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (isNodeInChildren(child, targetCode)) {
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
return false;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// 修改:过滤全量树数据,保持原始层级
|
|
538
|
+
function filterFullTreeData(filter) {
|
|
539
|
+
if (!fullTreeData.value.length) {
|
|
540
|
+
return;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
loading.value = true;
|
|
544
|
+
try {
|
|
545
|
+
let searchConditions = [];
|
|
546
|
+
|
|
547
|
+
if (filter?.searchData?.fields) {
|
|
548
|
+
searchConditions = filter.searchData.fields;
|
|
549
|
+
} else if (filter?.fields) {
|
|
550
|
+
searchConditions = filter.fields;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const validConditions = filterValidConditions(searchConditions);
|
|
554
|
+
|
|
555
|
+
if (!validConditions || validConditions.length === 0) {
|
|
556
|
+
refTree.value.store.setData(fullTreeData.value);
|
|
557
|
+
loading.value = false;
|
|
558
|
+
isSearching.value = false;
|
|
559
|
+
hasSetDefaultExpand.value = false;
|
|
560
|
+
defaultExpandedKeys.value = [];
|
|
561
|
+
|
|
562
|
+
// 先收起所有节点
|
|
563
|
+
if (refTree.value && refTree.value.store) {
|
|
564
|
+
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
565
|
+
if (node) {
|
|
566
|
+
node.expanded = false;
|
|
567
|
+
}
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
setDefaultExpandedNodes();
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
// 递归查找所有匹配的节点
|
|
576
|
+
const findMatchedNodes = (nodes, result = []) => {
|
|
577
|
+
nodes.forEach(node => {
|
|
578
|
+
const nodeMatches = nodeMatchesAllConditions(node, validConditions);
|
|
579
|
+
|
|
580
|
+
if (nodeMatches) {
|
|
581
|
+
result.push(node);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
if (node.children && node.children.length > 0) {
|
|
585
|
+
findMatchedNodes(node.children, result);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
return result;
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
const matchedNodes = findMatchedNodes(fullTreeData.value);
|
|
592
|
+
|
|
593
|
+
// 构建保持原始层级的过滤树
|
|
594
|
+
let filteredData = [];
|
|
595
|
+
if (matchedNodes.length > 0) {
|
|
596
|
+
filteredData = buildFilteredTreeWithOriginalHierarchy(matchedNodes);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// 设置过滤后的数据
|
|
600
|
+
refTree.value.store.setData(filteredData);
|
|
601
|
+
|
|
602
|
+
// 搜索状态时展开所有节点
|
|
603
|
+
if (filteredData.length > 0 && isSearching.value) {
|
|
604
|
+
const allKeys = getAllNodeKeys(filteredData);
|
|
605
|
+
defaultExpandedKeys.value = allKeys;
|
|
606
|
+
|
|
607
|
+
nextTick(() => {
|
|
608
|
+
if (refTree.value && refTree.value.store) {
|
|
609
|
+
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
610
|
+
if (node) {
|
|
611
|
+
node.expanded = true;
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
|
|
617
|
+
// 默认选中第一个可选节点
|
|
618
|
+
const findFirstSelectableNode = (nodes) => {
|
|
619
|
+
for (const node of nodes) {
|
|
620
|
+
if (!node.children || node.children.length === 0) {
|
|
621
|
+
return node;
|
|
622
|
+
}
|
|
623
|
+
const childResult = findFirstSelectableNode(node.children);
|
|
624
|
+
if (childResult) return childResult;
|
|
625
|
+
}
|
|
626
|
+
return nodes[0];
|
|
627
|
+
};
|
|
628
|
+
|
|
629
|
+
const firstNode = findFirstSelectableNode(filteredData);
|
|
630
|
+
if (firstNode && firstNode.code) {
|
|
631
|
+
nextTick(() => {
|
|
632
|
+
refTree.value.setCurrentKey(firstNode.code);
|
|
633
|
+
handleNodeClick(firstNode, true);
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
} catch (error) {
|
|
639
|
+
console.error('过滤树数据失败:', error);
|
|
640
|
+
} finally {
|
|
641
|
+
loading.value = false;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// 修改:加载节点,保存节点Map
|
|
120
646
|
function loadNode(node, resolve) {
|
|
647
|
+
|
|
648
|
+
if (!lazy.value) {
|
|
649
|
+
const nodeData = node.data;
|
|
650
|
+
resolve(nodeData.children)
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
|
|
121
654
|
if (node.level === 0) {
|
|
122
655
|
loading.value = true;
|
|
123
656
|
rootNode.value = node
|
|
124
657
|
rootResolve.value = resolve;
|
|
658
|
+
|
|
125
659
|
return SearchTree(screenPara.value || undefined).then(data => {
|
|
126
660
|
loading.value = false;
|
|
127
|
-
|
|
128
|
-
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
const { tree, hasAnyLeaf } = buildDeptTreeByField(data.rows, {
|
|
664
|
+
pathKey: 'path',
|
|
665
|
+
separator: '.'
|
|
666
|
+
});
|
|
667
|
+
|
|
668
|
+
// 缓存全量数据并构建节点Map
|
|
669
|
+
if (hasAnyLeaf) {
|
|
670
|
+
fullTreeData.value = tree;
|
|
671
|
+
nodeCodeMap.value = buildNodeCodeMap(tree);
|
|
672
|
+
resolve(tree);
|
|
673
|
+
if (props.expandTwoLevels) {
|
|
674
|
+
nextTick(() => {
|
|
675
|
+
hasSetDefaultExpand.value = false;
|
|
676
|
+
setDefaultExpandedNodes();
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
else {
|
|
681
|
+
resolve(data.rows);
|
|
682
|
+
}
|
|
683
|
+
lazy.value = !hasAnyLeaf;
|
|
684
|
+
|
|
685
|
+
load(data, true);
|
|
686
|
+
}).catch(error => {
|
|
687
|
+
loading.value = false;
|
|
688
|
+
console.error('加载树数据失败:', error);
|
|
129
689
|
});
|
|
130
690
|
}
|
|
131
|
-
|
|
691
|
+
|
|
692
|
+
if (node.level >= 1 && lazy.value) {
|
|
132
693
|
let fields = model.value.searchData("code", node.data.code, 9, 3);
|
|
133
694
|
let filter = {
|
|
134
695
|
"searchData": {
|
|
135
|
-
// 先保留searchData的其他属性
|
|
136
696
|
...(screenPara.value?.searchData || {}),
|
|
137
|
-
// 再合并fields数组(将两个数组合并,而不是覆盖)
|
|
138
697
|
fields: [
|
|
139
698
|
...fields.fields,
|
|
140
699
|
...(screenPara.value?.searchData?.fields || [])
|
|
141
700
|
]
|
|
142
701
|
}
|
|
143
702
|
};
|
|
703
|
+
|
|
144
704
|
return SearchTree(filter).then(data => {
|
|
145
705
|
loading.value = false;
|
|
146
706
|
resolve(data.rows);
|
|
147
|
-
load(data, false)
|
|
707
|
+
load(data, false);
|
|
708
|
+
}).catch(error => {
|
|
709
|
+
loading.value = false;
|
|
710
|
+
console.error('加载子节点失败:', error);
|
|
148
711
|
});
|
|
149
712
|
}
|
|
150
713
|
}
|
|
151
|
-
|
|
152
|
-
|
|
714
|
+
|
|
715
|
+
// 加载数据
|
|
716
|
+
async function load(data, flagRootNode) {
|
|
153
717
|
model.value = data;
|
|
154
718
|
if (searchStatus.value.length > 0) {
|
|
155
719
|
searchStatus.value = searchStatus.value.slice(1)
|
|
156
720
|
}
|
|
721
|
+
|
|
157
722
|
loading.value = false;
|
|
158
723
|
menuVisible.value = false;
|
|
159
|
-
|
|
724
|
+
|
|
725
|
+
if (flagRootNode) {
|
|
160
726
|
if (model.value.rows && model.value.rows[0]) {
|
|
161
727
|
handleNodeClick(model.value.rows[0], true);
|
|
162
728
|
}
|
|
@@ -167,18 +733,79 @@ async function load(data, firstLoad) {
|
|
|
167
733
|
});
|
|
168
734
|
}
|
|
169
735
|
}
|
|
170
|
-
//查询数据
|
|
171
|
-
function SearchTree(m) {
|
|
172
736
|
|
|
737
|
+
// 查询数据
|
|
738
|
+
function SearchTree(m) {
|
|
173
739
|
return new Promise((resolve, reject) => {
|
|
174
740
|
if (typeof props.api !== 'undefined') {
|
|
175
|
-
|
|
176
|
-
|
|
741
|
+
Tree.loadSearchTreeApi(props.api, m)
|
|
742
|
+
.then(resolve)
|
|
743
|
+
.catch(reject);
|
|
744
|
+
} else {
|
|
745
|
+
reject(new Error('API未定义'));
|
|
177
746
|
}
|
|
178
747
|
});
|
|
179
748
|
}
|
|
180
|
-
|
|
749
|
+
|
|
750
|
+
// 重置树到全量数据
|
|
751
|
+
function resetTree() {
|
|
752
|
+
isSearching.value = false;
|
|
753
|
+
if (fullTreeData.value.length > 0) {
|
|
754
|
+
refTree.value.store.setData(fullTreeData.value);
|
|
755
|
+
hasSetDefaultExpand.value = false;
|
|
756
|
+
defaultExpandedKeys.value = [];
|
|
757
|
+
|
|
758
|
+
if (fullTreeData.value[0] && fullTreeData.value[0].code) {
|
|
759
|
+
nextTick(() => {
|
|
760
|
+
if (refTree.value && refTree.value.store) {
|
|
761
|
+
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
762
|
+
if (node) {
|
|
763
|
+
node.expanded = false;
|
|
764
|
+
}
|
|
765
|
+
});
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
refTree.value.setCurrentKey(fullTreeData.value[0].code);
|
|
769
|
+
handleNodeClick(fullTreeData.value[0], true);
|
|
770
|
+
setDefaultExpandedNodes();
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// 清除搜索条件
|
|
777
|
+
function clearSearch() {
|
|
778
|
+
screenPara.value = {};
|
|
779
|
+
isSearching.value = false;
|
|
780
|
+
|
|
781
|
+
defaultExpandedKeys.value = [];
|
|
782
|
+
hasSetDefaultExpand.value = false;
|
|
783
|
+
|
|
784
|
+
if (fullTreeData.value.length > 0) {
|
|
785
|
+
refTree.value.store.setData(fullTreeData.value);
|
|
786
|
+
|
|
787
|
+
nextTick(() => {
|
|
788
|
+
if (refTree.value && refTree.value.store) {
|
|
789
|
+
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
790
|
+
if (node) {
|
|
791
|
+
node.expanded = false;
|
|
792
|
+
}
|
|
793
|
+
});
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
setDefaultExpandedNodes();
|
|
797
|
+
|
|
798
|
+
if (fullTreeData.value[0] && fullTreeData.value[0].code) {
|
|
799
|
+
refTree.value.setCurrentKey(fullTreeData.value[0].code);
|
|
800
|
+
handleNodeClick(fullTreeData.value[0], true);
|
|
801
|
+
}
|
|
802
|
+
});
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
//节点点击事件
|
|
181
807
|
function handleNodeClick(data, formType) {
|
|
808
|
+
|
|
182
809
|
closeMenu();
|
|
183
810
|
if (data && formType) {
|
|
184
811
|
refTree.value.setCurrentKey(data.code)
|
|
@@ -192,35 +819,44 @@ function handleNodeClick(data, formType) {
|
|
|
192
819
|
SearchData[v] = data[v];
|
|
193
820
|
}
|
|
194
821
|
})
|
|
822
|
+
|
|
195
823
|
model.value.requestAction(rowRouter.action, SearchData, function (rowdata) {
|
|
196
824
|
var newdata = common.deepClone(data);
|
|
825
|
+
delete newdata.children;
|
|
826
|
+
|
|
197
827
|
if (rowdata) {
|
|
198
|
-
newdata.rowRouter = rowdata
|
|
828
|
+
newdata.rowRouter = rowdata;
|
|
199
829
|
}
|
|
200
830
|
newdata.title = model.value.source?.content?.title || '';
|
|
201
831
|
emit('loaded', newdata);
|
|
202
832
|
});
|
|
203
833
|
}
|
|
204
834
|
}
|
|
835
|
+
|
|
205
836
|
//右键菜单
|
|
206
|
-
function rightClick(event, object, Node) {
|
|
837
|
+
function rightClick(event, object, Node) {
|
|
207
838
|
nodeRef.value = treeNodeRefMap.value[`node_Ref_${object.code}`]
|
|
208
839
|
|
|
209
840
|
currentData.value = object
|
|
210
841
|
currentNode.value = Node
|
|
211
842
|
let actionIndex = 0;
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
843
|
+
|
|
844
|
+
allowedRoutes.value = (model.value.actionRouter || []).filter(v => {
|
|
845
|
+
const val = currentData.value[v.rightField]
|
|
846
|
+
const hit = val == '1' || val === undefined || val === null;
|
|
847
|
+
return hit;
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
allowedRoutes.value?.forEach(() => {
|
|
851
|
+
menuVisible.value = true
|
|
852
|
+
actionIndex += 1
|
|
853
|
+
})
|
|
854
|
+
|
|
220
855
|
if (menuVisible.value) {
|
|
221
|
-
document.addEventListener('click', closeMenu)
|
|
856
|
+
document.addEventListener('click', closeMenu)
|
|
222
857
|
}
|
|
223
858
|
}
|
|
859
|
+
|
|
224
860
|
//关闭菜单
|
|
225
861
|
function closeMenu() {
|
|
226
862
|
menuVisible.value = false;
|
|
@@ -228,6 +864,7 @@ function closeMenu() {
|
|
|
228
864
|
currentData.value = { ...currentData.value, code: "" }
|
|
229
865
|
document.removeEventListener('click', closeMenu)
|
|
230
866
|
}
|
|
867
|
+
|
|
231
868
|
// 菜单路由
|
|
232
869
|
function routerClickHandler(field) {
|
|
233
870
|
var submitData = {};
|
|
@@ -238,63 +875,193 @@ function routerClickHandler(field) {
|
|
|
238
875
|
|
|
239
876
|
RouterClickHandler(field, submitData, null, model.value, 'tree', function (newData) {
|
|
240
877
|
switch (field.actionType) {
|
|
241
|
-
case Enum.ActionType.Delete
|
|
242
|
-
case Enum.ActionType.CloseTabThenDelete
|
|
243
|
-
removeNode(newData)
|
|
878
|
+
case Enum.ActionType.Delete:
|
|
879
|
+
case Enum.ActionType.CloseTabThenDelete:
|
|
880
|
+
removeNode(newData);
|
|
244
881
|
break;
|
|
245
|
-
case Enum.ActionType.New
|
|
246
|
-
case Enum.ActionType.CloseTabThenNew
|
|
247
|
-
addNode(newData)
|
|
882
|
+
case Enum.ActionType.New:
|
|
883
|
+
case Enum.ActionType.CloseTabThenNew:
|
|
884
|
+
addNode(newData)
|
|
248
885
|
break;
|
|
249
|
-
case Enum.ActionType.Update
|
|
250
|
-
case Enum.ActionType.CloseTabThenUpdate
|
|
251
|
-
updateNode(newData)
|
|
886
|
+
case Enum.ActionType.Update:
|
|
887
|
+
case Enum.ActionType.CloseTabThenUpdate:
|
|
888
|
+
updateNode(newData)
|
|
252
889
|
break;
|
|
253
890
|
default:
|
|
254
891
|
break;
|
|
255
892
|
}
|
|
256
|
-
|
|
257
893
|
})
|
|
258
894
|
}
|
|
895
|
+
|
|
259
896
|
//删除树节点
|
|
260
897
|
function removeNode(newData) {
|
|
261
|
-
getNextClickNode()
|
|
898
|
+
getNextClickNode(currentNode.value)
|
|
262
899
|
refTree.value.remove(currentNode.value);
|
|
900
|
+
|
|
263
901
|
}
|
|
902
|
+
|
|
264
903
|
//新增树节点
|
|
265
904
|
function addNode(newData) {
|
|
266
905
|
refTree.value.append(newData, currentNode.value)
|
|
267
906
|
handleNodeClick(newData, true)
|
|
268
907
|
}
|
|
908
|
+
|
|
269
909
|
//修改树节点
|
|
270
910
|
function updateNode(newData) {
|
|
271
|
-
|
|
272
911
|
for (let key in newData) {
|
|
273
|
-
|
|
274
912
|
if (typeof newData[key] === 'object') {
|
|
275
913
|
currentData.value[key] = { ...currentData.value[key], ...newData[key] }
|
|
276
914
|
} else {
|
|
277
915
|
currentData.value[key] = newData[key];
|
|
278
916
|
}
|
|
279
|
-
|
|
280
917
|
}
|
|
281
918
|
handleNodeClick(newData, true)
|
|
282
919
|
}
|
|
920
|
+
|
|
283
921
|
function getNextClickNode() {
|
|
284
|
-
const node = refTree.value.getNode(currentData.value.code);
|
|
922
|
+
const node = refTree.value.getNode((currentData.value.code || currentNode.value.key));
|
|
285
923
|
let data = {};
|
|
286
|
-
if (node
|
|
924
|
+
if (node?.nextSibling) {
|
|
287
925
|
data = node.nextSibling.data;
|
|
288
926
|
} else if (node.previousSibling) {
|
|
289
927
|
data = node.previousSibling.data;
|
|
290
|
-
} else if (node
|
|
928
|
+
} else if (node?.parent) {
|
|
291
929
|
data = node.parent.data;
|
|
292
930
|
}
|
|
293
931
|
handleNodeClick(data, true)
|
|
294
932
|
}
|
|
295
|
-
|
|
933
|
+
|
|
934
|
+
/** 过滤节点(全量数据模式下使用) */
|
|
935
|
+
function filterNode(value, data) {
|
|
936
|
+
if (!value) return true
|
|
937
|
+
return data.name.toLowerCase().includes(value.toLowerCase())
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
function buildDeptTreeByField(flatList, opt = {}) {
|
|
941
|
+
const {
|
|
942
|
+
pathKey = 'path',
|
|
943
|
+
separator = '.',
|
|
944
|
+
sortKey = 'sort'
|
|
945
|
+
} = opt;
|
|
946
|
+
|
|
947
|
+
// 检查第一行是否有 sort 字段
|
|
948
|
+
const firstItem = flatList.length > 0 ? flatList[0] : null;
|
|
949
|
+
const actualSortKey = firstItem && firstItem.hasOwnProperty(sortKey) ? sortKey : 'path';
|
|
950
|
+
|
|
951
|
+
const createNode = (tplItem, path) => {
|
|
952
|
+
const node = { children: [] };
|
|
953
|
+
|
|
954
|
+
for (const key in tplItem) {
|
|
955
|
+
if (key !== 'children') {
|
|
956
|
+
node[key] = tplItem[key];
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
node[pathKey] = path;
|
|
961
|
+
return node;
|
|
962
|
+
};
|
|
963
|
+
|
|
964
|
+
const root = [];
|
|
965
|
+
const nodeMap = new Map();
|
|
966
|
+
|
|
967
|
+
for (const item of flatList) {
|
|
968
|
+
if (!item[pathKey]) {
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
const path = item[pathKey];
|
|
972
|
+
const levels = path.split(separator);
|
|
973
|
+
|
|
974
|
+
let curPath = '';
|
|
975
|
+
let parentPath = '';
|
|
976
|
+
|
|
977
|
+
levels.forEach((lvl, idx) => {
|
|
978
|
+
curPath = idx === 0 ? lvl : `${parentPath}${separator}${lvl}`;
|
|
979
|
+
let curNode = nodeMap.get(curPath);
|
|
980
|
+
|
|
981
|
+
if (!curNode) {
|
|
982
|
+
curNode = createNode(item, curPath);
|
|
983
|
+
nodeMap.set(curPath, curNode);
|
|
984
|
+
|
|
985
|
+
if (idx === 0) {
|
|
986
|
+
root.push(curNode);
|
|
987
|
+
} else {
|
|
988
|
+
const pNode = nodeMap.get(parentPath);
|
|
989
|
+
if (pNode) {
|
|
990
|
+
pNode.children.push(curNode);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
parentPath = curPath;
|
|
995
|
+
});
|
|
996
|
+
|
|
997
|
+
const lastNode = nodeMap.get(path);
|
|
998
|
+
for (const key in item) {
|
|
999
|
+
if (key !== 'children') {
|
|
1000
|
+
lastNode[key] = item[key];
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// 按实际排序键排序子节点
|
|
1006
|
+
for (const node of nodeMap.values()) {
|
|
1007
|
+
if (node.children && node.children.length > 0) {
|
|
1008
|
+
node.children.sort((a, b) => {
|
|
1009
|
+
const aVal = a[actualSortKey] || '';
|
|
1010
|
+
const bVal = b[actualSortKey] || '';
|
|
1011
|
+
return String(aVal).localeCompare(String(bVal));
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
node.isLeaf = node.children.length === 0;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
// 按实际排序键排序根节点
|
|
1018
|
+
root.sort((a, b) => {
|
|
1019
|
+
const aVal = a[actualSortKey] || '';
|
|
1020
|
+
const bVal = b[actualSortKey] || '';
|
|
1021
|
+
return String(aVal).localeCompare(String(bVal));
|
|
1022
|
+
});
|
|
1023
|
+
|
|
1024
|
+
const hasAnyLeaf = [...nodeMap.values()].some(n => n.isLeaf == false);
|
|
1025
|
+
return { tree: root, hasAnyLeaf };
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
function findSearchFieldValue(searchFields, targetKey, options = {}) {
|
|
1029
|
+
const {
|
|
1030
|
+
keyFields = ['fieldName1', 'groupName'], // 要查找的key字段列表
|
|
1031
|
+
valueField = 'searchValue1', // 要返回值的字段
|
|
1032
|
+
defaultValue = 2
|
|
1033
|
+
} = options;
|
|
1034
|
+
|
|
1035
|
+
// 检查数据结构
|
|
1036
|
+
if (!searchFields?.searchData?.fields?.length) {
|
|
1037
|
+
return defaultValue;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
// 遍历fields数组
|
|
1041
|
+
for (const field of searchFields.searchData.fields) {
|
|
1042
|
+
// 检查所有可能的key字段
|
|
1043
|
+
for (const keyField of keyFields) {
|
|
1044
|
+
if (field[keyField] === targetKey) {
|
|
1045
|
+
// 找到了匹配的key,返回对应的值
|
|
1046
|
+
const value = field[valueField];
|
|
1047
|
+
// 如果值为undefined、null或空字符串,返回默认值
|
|
1048
|
+
return value !== undefined && value !== null && value !== ''
|
|
1049
|
+
? value
|
|
1050
|
+
: defaultValue;
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
return defaultValue;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
// 暴露方法
|
|
296
1061
|
defineExpose({
|
|
297
|
-
search
|
|
1062
|
+
search,
|
|
1063
|
+
resetTree,
|
|
1064
|
+
clearSearch
|
|
298
1065
|
})
|
|
299
1066
|
</script>
|
|
300
1067
|
|
|
@@ -310,7 +1077,6 @@ defineExpose({
|
|
|
310
1077
|
|
|
311
1078
|
.ct-tree::-webkit-scrollbar-thumb {
|
|
312
1079
|
background-color: #bebebe;
|
|
313
|
-
/* 设置滚动条滑块颜色 */
|
|
314
1080
|
height: 5px;
|
|
315
1081
|
border-radius: 4px;
|
|
316
1082
|
display: block;
|
|
@@ -319,7 +1085,6 @@ defineExpose({
|
|
|
319
1085
|
.ct-tree::-webkit-scrollbar {
|
|
320
1086
|
width: 6px;
|
|
321
1087
|
height: 6px;
|
|
322
|
-
/* 设置滚动条高度 */
|
|
323
1088
|
background-color: #f1f1f1;
|
|
324
1089
|
display: block;
|
|
325
1090
|
}
|
|
@@ -347,121 +1112,14 @@ defineExpose({
|
|
|
347
1112
|
padding-right: 2px !important;
|
|
348
1113
|
}
|
|
349
1114
|
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
height: 100%;
|
|
354
|
-
width: 1px;
|
|
355
|
-
position: absolute;
|
|
356
|
-
left: 27px;
|
|
357
|
-
top: -1px;
|
|
358
|
-
border-width: 1px;
|
|
359
|
-
border-left: 1px dashed #52627C;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
.tree-line .el-tree-node:before:last-child {
|
|
363
|
-
top: -35px;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
.el-tree-node__children .el-tree-node::before {
|
|
367
|
-
content: "";
|
|
368
|
-
height: 100%;
|
|
369
|
-
width: 1px;
|
|
370
|
-
position: absolute;
|
|
371
|
-
left: 27px;
|
|
372
|
-
top: -2px;
|
|
373
|
-
border-width: 1px;
|
|
374
|
-
border-left: 1px dashed #52627C;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/* 当前最后一个接点的竖线高度 */
|
|
378
|
-
.el-tree-node:last-child::before {
|
|
379
|
-
height: 15px;
|
|
380
|
-
/*可以自己调整 */
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
/* 横线 */
|
|
384
|
-
.el-tree-node::after {
|
|
385
|
-
content: "";
|
|
386
|
-
width: 12px;
|
|
387
|
-
height: 20px;
|
|
388
|
-
position: absolute;
|
|
389
|
-
left: 27px;
|
|
390
|
-
top: 12px;
|
|
391
|
-
right: 2px;
|
|
392
|
-
border-width: 1px;
|
|
393
|
-
border-top: 1px dashed #52627C;
|
|
1115
|
+
.node_content {
|
|
1116
|
+
display: flex;
|
|
1117
|
+
align-items: center;
|
|
394
1118
|
}
|
|
395
1119
|
|
|
396
|
-
.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
.el-tree-node__expand-icon {
|
|
401
|
-
font-size: 16px;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/* 去掉顶层虚线 */
|
|
405
|
-
.tree>.el-tree-node:first-child::after {
|
|
406
|
-
border-top: none;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
.el-tree>.el-tree-node:first-child:before {
|
|
410
|
-
/* border-left: none; */
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
.tree>.is-leaf {
|
|
414
|
-
color: transparent;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
.el-tree .el-tree-node__expand-icon.expanded {
|
|
418
|
-
-webkit-transform: rotate(0deg);
|
|
419
|
-
transform: rotate(0deg);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
.el-tree .el-tree-node__expand-icon.expanded {
|
|
423
|
-
-webkit-transform: rotate(0deg);
|
|
424
|
-
transform: rotate(0deg);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
.el-tree .el-tree-node__expand-icon {
|
|
429
|
-
background: url("@/assets/images/node-collapse.png") no-repeat;
|
|
430
|
-
content: '';
|
|
431
|
-
display: block;
|
|
432
|
-
width: 12px;
|
|
433
|
-
height: 12px;
|
|
434
|
-
font-size: 12px;
|
|
435
|
-
background-size: 10px;
|
|
436
|
-
|
|
437
|
-
color: transparent;
|
|
438
|
-
background-position: left 6px top 6px;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
/*
|
|
442
|
-
//有子节点 且已展开*/
|
|
443
|
-
.el-tree .el-tree-node__expand-icon.expanded {
|
|
444
|
-
background: url("@/assets/images/node-expand.png") no-repeat;
|
|
445
|
-
content: '';
|
|
446
|
-
display: block;
|
|
447
|
-
width: 12px;
|
|
448
|
-
height: 12px;
|
|
449
|
-
font-size: 12px;
|
|
450
|
-
background-size: 10px;
|
|
451
|
-
|
|
452
|
-
color: transparent;
|
|
453
|
-
background-position: left 6px top 6px;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/* //没有子节点*/
|
|
457
|
-
.el-tree .el-tree-node__expand-icon.is-leaf::before {
|
|
458
|
-
background: transparent no-repeat 0 3px;
|
|
459
|
-
content: '';
|
|
460
|
-
display: block;
|
|
461
|
-
width: 12px;
|
|
462
|
-
height: 12px;
|
|
463
|
-
font-size: 12px;
|
|
464
|
-
background-size: 10px;
|
|
1120
|
+
.node-icon {
|
|
1121
|
+
margin-right: 5px;
|
|
1122
|
+
color: var(--el-color-warning);
|
|
465
1123
|
}
|
|
466
1124
|
|
|
467
1125
|
.box-menu {
|
|
@@ -481,5 +1139,6 @@ defineExpose({
|
|
|
481
1139
|
|
|
482
1140
|
.box-menu .opertion:hover {
|
|
483
1141
|
color: var(--btnHoverRed);
|
|
1142
|
+
background-color: var(--el-fill-color-light);
|
|
484
1143
|
}
|
|
485
|
-
</style>
|
|
1144
|
+
</style>
|