centaline-data-driven-v3 0.1.44 → 0.1.46
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 +78 -78
- package/package.json +1 -1
- package/src/components/web/Label.vue +1 -0
- package/src/components/web/TextBox.vue +1 -1
- package/src/components/web/Tree/Tree.vue +830 -408
- package/src/loader/src/Field.js +7 -5
- package/src/loader/src/Tree.js +319 -33
- package/src/main.js +3 -3
- package/src/utils/request.js +1 -1
- package/src/views/Form.vue +2 -2
|
@@ -1,24 +1,31 @@
|
|
|
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" :expand-on-click-node="false"
|
|
5
|
-
|
|
4
|
+
<el-tree class="tree-line" :props="defaultProps" :expand-on-click-node="false"
|
|
5
|
+
@node-click="handleNodeClick"
|
|
6
|
+
:filter-node-method="filterNode" lazy :load="loadNode" ref="refTree" @node-contextmenu="handleContextMenu"
|
|
6
7
|
node-key="code" current-node-key="currentNodeKey" :default-expanded-keys="defaultExpandedKeys">
|
|
7
8
|
<template #default="{ node, data }">
|
|
8
|
-
<span class="node_content">
|
|
9
|
+
<span class="node_content" @mouseenter="handleMouseEnter(data, node)" @mousemove="handleMouseMove">
|
|
9
10
|
<el-icon class="node-icon" :class="{ 'is-leaf': node.isLeaf }">
|
|
10
11
|
<Document v-if="node.isLeaf" :size="14" />
|
|
11
12
|
<Folder v-else-if="!node.expanded" :size="14" />
|
|
12
13
|
<FolderOpened v-else :size="14" />
|
|
13
14
|
</el-icon>
|
|
14
|
-
<span style="" :ref="(el: refItem) => handleSetInputMap(el, data)">
|
|
15
|
-
data.name }}
|
|
15
|
+
<span style="" :ref="(el: refItem) => handleSetInputMap(el, data)">
|
|
16
|
+
{{ data.name }}
|
|
17
|
+
</span>
|
|
16
18
|
<span @click.stop>
|
|
17
|
-
<el-popover placement="right" :virtual-ref="nodeRef" virtual-triggering
|
|
18
|
-
:
|
|
19
|
-
|
|
19
|
+
<el-popover placement="right" :show-arrow="false" :virtual-ref="nodeRef" virtual-triggering :visible="showPopover(data)" v-if="showPopover(data)" :show-after="0"
|
|
20
|
+
:hide-after="0" :popper-class="allIconsMode ? 'popper-transparent' : 'popper-menu'"
|
|
21
|
+
:popper-style="popoverStyle">
|
|
22
|
+
<div class="box-menu" :class="{ 'box-menu-icons': allIconsMode }">
|
|
20
23
|
<template v-for="(item, index) in allowedRoutes">
|
|
21
|
-
<
|
|
24
|
+
<template v-if="allIconsMode">
|
|
25
|
+
<img class="opertion" v-if="item.imgUrl" :src="item.imgUrl" :alt="item.controlLabel || ''"
|
|
26
|
+
:title="item.controlLabel" @click="routerClickHandler(item)" />
|
|
27
|
+
</template>
|
|
28
|
+
<div class="opertion" @click="routerClickHandler(item)" v-else>
|
|
22
29
|
<div>
|
|
23
30
|
<img v-if="item.imgUrl" :src="item.imgUrl" alt="" />
|
|
24
31
|
{{ item.controlLabel }}
|
|
@@ -90,6 +97,18 @@ const retryCount = ref(0);
|
|
|
90
97
|
const treeNodeRefMap = ref({});
|
|
91
98
|
const allowedRoutes = ref([]);
|
|
92
99
|
|
|
100
|
+
// 新增:鼠标悬停相关状态
|
|
101
|
+
const hoverTimer = ref(null)
|
|
102
|
+
const hoverNodeCode = ref('')
|
|
103
|
+
const isHoverMode = ref(false) // 是否是悬停模式
|
|
104
|
+
const isManualClose = ref(false) // 是否是手动关闭
|
|
105
|
+
const allIconsMode = ref(false) // 是否全是图标模式
|
|
106
|
+
// 新增:弹出框位置控制
|
|
107
|
+
const popoverStyle = ref({})
|
|
108
|
+
const currentMousePosition = ref({ x: 0, y: 0 }) // 当前鼠标位置
|
|
109
|
+
const lastNodeCode = ref('') // 上次显示菜单的节点code
|
|
110
|
+
const isPositionLockedForCurrentNode = ref(false) // 当前节点的位置是否已锁定
|
|
111
|
+
|
|
93
112
|
// 默认展开的节点key数组
|
|
94
113
|
const defaultExpandedKeys = ref([])
|
|
95
114
|
// 是否已设置默认展开
|
|
@@ -104,6 +123,11 @@ const fullTreeData = ref([])
|
|
|
104
123
|
const nodeCodeMap = ref(new Map())
|
|
105
124
|
|
|
106
125
|
const isExpandAll = ref(false);
|
|
126
|
+
const isLazyInitialized = ref(false) // 标记是否已经初始化过lazy值
|
|
127
|
+
|
|
128
|
+
// 新增:记录节点加载状态的Map
|
|
129
|
+
const nodeLoadedStatus = ref(new Map())
|
|
130
|
+
|
|
107
131
|
/** 动态设置Input Ref */
|
|
108
132
|
const handleSetInputMap = (el: refItem, item) => {
|
|
109
133
|
if (el) {
|
|
@@ -117,129 +141,292 @@ onBeforeUnmount(() => {
|
|
|
117
141
|
clearTimeout(qrtimer.value);
|
|
118
142
|
qrtimer.value = null;
|
|
119
143
|
}
|
|
144
|
+
if (hoverTimer.value) {
|
|
145
|
+
clearTimeout(hoverTimer.value);
|
|
146
|
+
hoverTimer.value = null;
|
|
147
|
+
}
|
|
120
148
|
})
|
|
121
149
|
|
|
122
|
-
|
|
123
|
-
|
|
150
|
+
// 检查allowedRoutes是否全是图标
|
|
151
|
+
function checkIfAllIcons(routes) {
|
|
152
|
+
if (!routes || routes.length === 0) return false;
|
|
153
|
+
return routes.every(item => item.imgUrl && item.imgUrl.trim() !== '');
|
|
154
|
+
}
|
|
124
155
|
|
|
125
|
-
|
|
126
|
-
|
|
156
|
+
// 显示弹出框的条件
|
|
157
|
+
function showPopover(data) {
|
|
158
|
+
if (isManualClose.value) {
|
|
159
|
+
return false;
|
|
127
160
|
}
|
|
128
161
|
|
|
129
|
-
const
|
|
130
|
-
|
|
162
|
+
const isCurrentNode = data.code === currentData.value.code;
|
|
163
|
+
const hasRoutes = allowedRoutes.value.length > 0;
|
|
164
|
+
if (isHoverMode.value) {
|
|
165
|
+
// 悬停模式:当前节点且有路由就显示
|
|
166
|
+
return isCurrentNode && hasRoutes && menuVisible.value;
|
|
167
|
+
} else {
|
|
168
|
+
// 右键模式:右键触发才显示
|
|
169
|
+
return isCurrentNode && hasRoutes && menuVisible.value;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
131
172
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
173
|
+
// 鼠标进入节点
|
|
174
|
+
function handleMouseEnter(data, node) {
|
|
175
|
+
// if (isManualClose.value) {
|
|
176
|
+
// isManualClose.value = false;
|
|
177
|
+
// return;
|
|
178
|
+
// }
|
|
179
|
+
// 检查当前节点的allowedRoutes是否全是图标
|
|
180
|
+
const routes = getAllowedRoutesForNode(data);
|
|
181
|
+
const allIcons = checkIfAllIcons(routes);
|
|
182
|
+
allIconsMode.value = allIcons;
|
|
183
|
+
if (allIcons) {
|
|
184
|
+
isHoverMode.value = true;
|
|
185
|
+
hoverNodeCode.value = data.code;
|
|
186
|
+
isManualClose.value = false;
|
|
187
|
+
|
|
188
|
+
if (hoverNodeCode.value === data.code) {
|
|
189
|
+
showNodeMenu(data, node, true);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// 鼠标移动事件
|
|
195
|
+
function handleMouseMove(event) {
|
|
196
|
+
// 更新鼠标位置
|
|
197
|
+
currentMousePosition.value = {
|
|
198
|
+
x: event.clientX,
|
|
199
|
+
y: event.clientY
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// 如果是悬停模式且全是图标,并且当前节点的位置尚未锁定,则更新位置
|
|
203
|
+
if (menuVisible.value && isHoverMode.value && allIconsMode.value && !isPositionLockedForCurrentNode.value) {
|
|
204
|
+
updatePopoverPosition();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// 更新弹出框位置(只对当前节点第一次调用时生效)
|
|
209
|
+
function updatePopoverPosition() {
|
|
210
|
+
// 如果当前节点的位置已锁定,不再更新
|
|
211
|
+
if (isPositionLockedForCurrentNode.value) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// 计算菜单位置,确保不会超出屏幕
|
|
216
|
+
const screenWidth = window.innerWidth;
|
|
217
|
+
const menuWidth = allIconsMode.value ? 150 : 200; // 预估菜单宽度
|
|
218
|
+
|
|
219
|
+
let left = currentMousePosition.value.x + 15;
|
|
220
|
+
|
|
221
|
+
// 检查是否超出右边界
|
|
222
|
+
if (left + menuWidth > screenWidth) {
|
|
223
|
+
left = currentMousePosition.value.x - menuWidth - 10;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// 只设置水平位置,垂直位置使用 Element UI 默认的
|
|
227
|
+
popoverStyle.value = {
|
|
228
|
+
left: `${left}px`
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// 设置当前节点的位置为已锁定
|
|
232
|
+
if (currentData.value.code) {
|
|
233
|
+
isPositionLockedForCurrentNode.value = true;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// 右键菜单事件
|
|
238
|
+
function handleContextMenu(event, object, node) {
|
|
239
|
+
event.preventDefault();
|
|
240
|
+
|
|
241
|
+
// 记录鼠标位置
|
|
242
|
+
currentMousePosition.value = {
|
|
243
|
+
x: event.clientX,
|
|
244
|
+
y: event.clientY
|
|
245
|
+
};
|
|
246
|
+
// 检查当前节点的allowedRoutes是否全是图标
|
|
247
|
+
const routes = getAllowedRoutesForNode(object);
|
|
248
|
+
const allIcons = checkIfAllIcons(routes);
|
|
249
|
+
|
|
250
|
+
// 如果全是图标,右键时不执行后面代码(不显示菜单)
|
|
251
|
+
if (allIcons) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
isManualClose.value = false;
|
|
255
|
+
showNodeMenu(object, node, false);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// 共用方法:显示节点菜单
|
|
259
|
+
function showNodeMenu(object, node, isHoverTrigger = false) {
|
|
260
|
+
// 检查是否是新的节点
|
|
261
|
+
const isNewNode = object.code !== lastNodeCode.value;
|
|
262
|
+
|
|
263
|
+
if (isNewNode) {
|
|
264
|
+
// 如果是新节点,重置位置锁定状态
|
|
265
|
+
isPositionLockedForCurrentNode.value = false;
|
|
266
|
+
lastNodeCode.value = object.code;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
nodeRef.value = treeNodeRefMap.value[`node_Ref_${object.code}`]
|
|
270
|
+
|
|
271
|
+
currentData.value = object
|
|
272
|
+
currentNode.value = node
|
|
273
|
+
|
|
274
|
+
allowedRoutes.value = getAllowedRoutesForNode(object);
|
|
275
|
+
|
|
276
|
+
if (allowedRoutes.value.length > 0) {
|
|
277
|
+
menuVisible.value = true;
|
|
278
|
+
|
|
279
|
+
// 使用nextTick确保DOM已更新,然后设置位置
|
|
280
|
+
nextTick(() => {
|
|
281
|
+
// 如果是右键触发,设置弹出框位置
|
|
282
|
+
if (!isHoverTrigger && !allIconsMode.value) {
|
|
283
|
+
updatePopoverPosition();
|
|
135
284
|
}
|
|
136
285
|
|
|
137
|
-
//
|
|
138
|
-
if (
|
|
139
|
-
|
|
286
|
+
// 如果是悬停模式且全是图标,设置跟随鼠标
|
|
287
|
+
if (isHoverTrigger && allIconsMode.value) {
|
|
288
|
+
updatePopoverPosition();
|
|
140
289
|
}
|
|
141
290
|
});
|
|
142
|
-
};
|
|
143
291
|
|
|
144
|
-
|
|
145
|
-
|
|
292
|
+
// 添加点击事件监听
|
|
293
|
+
document.addEventListener('click', closeMenuOnClick);
|
|
294
|
+
}
|
|
146
295
|
}
|
|
147
296
|
|
|
148
|
-
//
|
|
149
|
-
function
|
|
150
|
-
|
|
151
|
-
|
|
297
|
+
// 点击关闭菜单
|
|
298
|
+
function closeMenuOnClick(e) {
|
|
299
|
+
// 检查点击是否在菜单内部
|
|
300
|
+
const menu = document.querySelector('.box-menu');
|
|
301
|
+
if (menu && !menu.contains(e.target)) {
|
|
302
|
+
closeMenu();
|
|
152
303
|
}
|
|
304
|
+
}
|
|
153
305
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
306
|
+
//关闭菜单
|
|
307
|
+
function closeMenu() {
|
|
308
|
+
isManualClose.value = true;
|
|
309
|
+
menuVisible.value = false;
|
|
310
|
+
isHoverMode.value = false;
|
|
311
|
+
lastNodeCode.value = '';
|
|
312
|
+
isPositionLockedForCurrentNode.value = false;
|
|
158
313
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
314
|
+
hoverNodeCode.value = '';
|
|
315
|
+
nodeRef.value = null;
|
|
316
|
+
// 重置弹出框样式
|
|
317
|
+
popoverStyle.value = {};
|
|
163
318
|
|
|
164
|
-
|
|
319
|
+
// 移除事件监听
|
|
320
|
+
document.removeEventListener('click', closeMenuOnClick);
|
|
321
|
+
|
|
322
|
+
if (hoverTimer.value) {
|
|
323
|
+
clearTimeout(hoverTimer.value);
|
|
324
|
+
hoverTimer.value = null;
|
|
325
|
+
}
|
|
165
326
|
}
|
|
166
327
|
|
|
167
328
|
// 设置默认展开节点
|
|
168
329
|
function setDefaultExpandedNodes() {
|
|
169
|
-
if (!props.expandTwoLevels
|
|
330
|
+
if (!props.expandTwoLevels) {
|
|
170
331
|
return;
|
|
171
332
|
}
|
|
172
333
|
|
|
334
|
+
// 如果是懒加载模式,使用特定的展开逻辑
|
|
335
|
+
if (lazy.value) {
|
|
336
|
+
setLazyModeExpandedNodes();
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// 全量数据模式
|
|
173
341
|
if (isSearching.value) {
|
|
174
342
|
isExpandAll.value = true;
|
|
175
|
-
const allKeys = getAllNodeKeys(fullTreeData.value);
|
|
343
|
+
const allKeys = Tree.getAllNodeKeys(fullTreeData.value);
|
|
176
344
|
defaultExpandedKeys.value = allKeys;
|
|
177
345
|
} else {
|
|
178
346
|
isExpandAll.value = false;
|
|
179
347
|
// 检查是否有全展开搜索条件
|
|
180
348
|
const expandValue = findSearchFieldValue(screenPara.value, 'expanded', {
|
|
181
|
-
caseInsensitive: true,
|
|
182
|
-
keyFields: ['fieldName1', 'groupName', 'fieldLabel']
|
|
349
|
+
caseInsensitive: true,
|
|
350
|
+
keyFields: ['fieldName1', 'groupName', 'fieldLabel']
|
|
183
351
|
});
|
|
184
352
|
|
|
185
|
-
// 如果找到expanded=all的搜索条件,设置全展开
|
|
186
353
|
if (expandValue && expandValue.toString().toLowerCase() === 'all') {
|
|
187
354
|
isExpandAll.value = true;
|
|
188
|
-
const allKeys = getAllNodeKeys(fullTreeData.value);
|
|
355
|
+
const allKeys = Tree.getAllNodeKeys(fullTreeData.value);
|
|
189
356
|
defaultExpandedKeys.value = allKeys;
|
|
190
357
|
} else {
|
|
191
|
-
|
|
192
|
-
let expandLevel = 1; // 默认展开级别为1
|
|
358
|
+
let expandLevel = 1;
|
|
193
359
|
|
|
194
360
|
if (expandValue) {
|
|
195
361
|
const numericValue = Number(expandValue);
|
|
196
362
|
if (!isNaN(numericValue) && numericValue > 0) {
|
|
197
|
-
expandLevel = Math.max(0, numericValue - 1);
|
|
198
|
-
|
|
363
|
+
expandLevel = Math.max(0, numericValue - 1);
|
|
199
364
|
}
|
|
200
365
|
}
|
|
201
366
|
|
|
202
|
-
defaultExpandedKeys.value = getFirstNLevelKeys(fullTreeData.value, expandLevel);
|
|
367
|
+
defaultExpandedKeys.value = Tree.getFirstNLevelKeys(fullTreeData.value, expandLevel);
|
|
203
368
|
}
|
|
204
369
|
}
|
|
205
370
|
|
|
206
371
|
hasSetDefaultExpand.value = true;
|
|
207
372
|
}
|
|
208
373
|
|
|
209
|
-
//
|
|
210
|
-
function
|
|
211
|
-
|
|
374
|
+
// 修改:懒加载模式下的展开逻辑
|
|
375
|
+
function setLazyModeExpandedNodes() {
|
|
376
|
+
if (!fullTreeData.value || fullTreeData.value.length === 0) {
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
212
379
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (node.code) {
|
|
216
|
-
map.set(node.code, node);
|
|
217
|
-
}
|
|
380
|
+
// 获取所有非叶子节点(最后一层不展开)
|
|
381
|
+
const nonLeafKeys = [];
|
|
218
382
|
|
|
219
|
-
|
|
220
|
-
|
|
383
|
+
function traverse(nodes) {
|
|
384
|
+
nodes.forEach(node => {
|
|
385
|
+
// 关键判断:如果是叶子节点,就不展开
|
|
386
|
+
const isLeafNode = node.isLeaf === true ||
|
|
387
|
+
(!node.children || node.children.length === 0);
|
|
388
|
+
|
|
389
|
+
if (!isLeafNode) {
|
|
390
|
+
// 非叶子节点,可以展开
|
|
391
|
+
nonLeafKeys.push(node.code);
|
|
392
|
+
|
|
393
|
+
// 递归处理子节点
|
|
394
|
+
if (node.children && node.children.length > 0) {
|
|
395
|
+
traverse(node.children);
|
|
396
|
+
}
|
|
221
397
|
}
|
|
222
398
|
});
|
|
223
399
|
}
|
|
224
400
|
|
|
225
|
-
traverse(
|
|
226
|
-
|
|
227
|
-
|
|
401
|
+
traverse(fullTreeData.value);
|
|
402
|
+
|
|
403
|
+
defaultExpandedKeys.value = nonLeafKeys;
|
|
404
|
+
hasSetDefaultExpand.value = true;
|
|
228
405
|
|
|
229
|
-
//
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
406
|
+
// 延迟设置,确保树已渲染
|
|
407
|
+
nextTick(() => {
|
|
408
|
+
if (refTree.value && refTree.value.store) {
|
|
409
|
+
// 只展开已有的非叶子节点,不触发懒加载
|
|
410
|
+
nonLeafKeys.forEach(key => {
|
|
411
|
+
const node = refTree.value.getNode(key);
|
|
412
|
+
if (node && !node.expanded) {
|
|
413
|
+
// 安全地设置展开状态
|
|
414
|
+
node.expanded = true;
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
});
|
|
234
419
|
}
|
|
235
420
|
|
|
236
421
|
// 搜索(查询条件调用)
|
|
237
422
|
function search(m) {
|
|
238
|
-
const hasValidSearchConditions = checkHasValidSearchConditions(m);
|
|
423
|
+
const hasValidSearchConditions = Tree.checkHasValidSearchConditions(m);
|
|
239
424
|
|
|
240
425
|
isSearching.value = hasValidSearchConditions;
|
|
241
426
|
screenPara.value = m;
|
|
242
427
|
|
|
428
|
+
|
|
429
|
+
|
|
243
430
|
if (!lazy.value) {
|
|
244
431
|
filterFullTreeData(screenPara.value);
|
|
245
432
|
return;
|
|
@@ -264,111 +451,19 @@ function search(m) {
|
|
|
264
451
|
}, 200);
|
|
265
452
|
}
|
|
266
453
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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;
|
|
454
|
+
function collapseAllNodes() {
|
|
455
|
+
if (refTree.value && refTree.value.store) {
|
|
456
|
+
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
457
|
+
if (node) {
|
|
458
|
+
node.expanded = false;
|
|
313
459
|
}
|
|
314
|
-
}
|
|
460
|
+
});
|
|
315
461
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
});
|
|
462
|
+
// 清空默认展开的key
|
|
463
|
+
defaultExpandedKeys.value = [];
|
|
464
|
+
hasSetDefaultExpand.value = false;
|
|
465
|
+
}
|
|
370
466
|
}
|
|
371
|
-
|
|
372
467
|
// 修改:构建完整的过滤树,保持原始层级结构
|
|
373
468
|
function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
374
469
|
if (!matchedNodes || matchedNodes.length === 0) {
|
|
@@ -381,7 +476,7 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
381
476
|
// 第一步:创建所有匹配节点的副本
|
|
382
477
|
matchedNodes.forEach(node => {
|
|
383
478
|
if (!resultMap.has(node.code)) {
|
|
384
|
-
const clonedNode = cloneNode(node);
|
|
479
|
+
const clonedNode = Tree.cloneNode(node);
|
|
385
480
|
resultMap.set(node.code, clonedNode);
|
|
386
481
|
}
|
|
387
482
|
});
|
|
@@ -424,12 +519,11 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
424
519
|
if (!originalNode) continue;
|
|
425
520
|
|
|
426
521
|
// 创建节点副本
|
|
427
|
-
const clonedNode = cloneNode(originalNode);
|
|
522
|
+
const clonedNode = Tree.cloneNode(originalNode);
|
|
428
523
|
resultMap.set(currentCode, clonedNode);
|
|
429
524
|
|
|
430
525
|
// 如果是根节点,添加到根节点数组
|
|
431
526
|
if (i === 0) {
|
|
432
|
-
// 检查是否已经存在于根节点中
|
|
433
527
|
const existingRoot = rootNodes.find(n => n.code === currentCode);
|
|
434
528
|
if (!existingRoot) {
|
|
435
529
|
rootNodes.push(clonedNode);
|
|
@@ -442,7 +536,6 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
442
536
|
const parentNode = resultMap.get(parentCode);
|
|
443
537
|
|
|
444
538
|
if (parentNode) {
|
|
445
|
-
// 检查是否已经包含该子节点
|
|
446
539
|
const existingChild = parentNode.children.find(child => child.code === currentCode);
|
|
447
540
|
if (!existingChild) {
|
|
448
541
|
parentNode.children.push(clonedNode);
|
|
@@ -458,7 +551,6 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
458
551
|
const currentNode = resultMap.get(matchedNode.code);
|
|
459
552
|
|
|
460
553
|
if (parentNode && currentNode) {
|
|
461
|
-
// 检查是否已经包含该子节点
|
|
462
554
|
const existingChild = parentNode.children.find(child => child.code === matchedNode.code);
|
|
463
555
|
if (!existingChild) {
|
|
464
556
|
parentNode.children.push(currentNode);
|
|
@@ -469,11 +561,10 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
469
561
|
|
|
470
562
|
// 第三步:清理根节点,确保它们没有重复的父节点
|
|
471
563
|
const finalRootNodes = [];
|
|
472
|
-
const usedNodes = new Set();
|
|
473
564
|
|
|
474
565
|
function isNodeUsedInTree(node) {
|
|
475
566
|
for (const root of rootNodes) {
|
|
476
|
-
if (isNodeInChildren(root, node.code)) {
|
|
567
|
+
if (Tree.isNodeInChildren(root, node.code)) {
|
|
477
568
|
return true;
|
|
478
569
|
}
|
|
479
570
|
}
|
|
@@ -481,7 +572,6 @@ function buildFilteredTreeWithOriginalHierarchy(matchedNodes) {
|
|
|
481
572
|
}
|
|
482
573
|
|
|
483
574
|
rootNodes.forEach(rootNode => {
|
|
484
|
-
// 如果这个节点已经是其他节点的子节点,则不作为根节点
|
|
485
575
|
if (!isNodeUsedInTree(rootNode)) {
|
|
486
576
|
finalRootNodes.push(rootNode);
|
|
487
577
|
}
|
|
@@ -511,29 +601,6 @@ function findParentCodeInFullTree(nodeCode) {
|
|
|
511
601
|
return findParent(fullTreeData.value, nodeCode);
|
|
512
602
|
}
|
|
513
603
|
|
|
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
604
|
// 修改:过滤全量树数据,保持原始层级
|
|
538
605
|
function filterFullTreeData(filter) {
|
|
539
606
|
if (!fullTreeData.value.length) {
|
|
@@ -550,7 +617,7 @@ function filterFullTreeData(filter) {
|
|
|
550
617
|
searchConditions = filter.fields;
|
|
551
618
|
}
|
|
552
619
|
|
|
553
|
-
const validConditions = filterValidConditions(searchConditions);
|
|
620
|
+
const validConditions = Tree.filterValidConditions(searchConditions);
|
|
554
621
|
|
|
555
622
|
if (!validConditions || validConditions.length === 0) {
|
|
556
623
|
refTree.value.store.setData(fullTreeData.value);
|
|
@@ -559,7 +626,6 @@ function filterFullTreeData(filter) {
|
|
|
559
626
|
hasSetDefaultExpand.value = false;
|
|
560
627
|
defaultExpandedKeys.value = [];
|
|
561
628
|
|
|
562
|
-
// 先收起所有节点
|
|
563
629
|
if (refTree.value && refTree.value.store) {
|
|
564
630
|
Object.values(refTree.value.store.nodesMap).forEach((node: any) => {
|
|
565
631
|
if (node) {
|
|
@@ -575,7 +641,7 @@ function filterFullTreeData(filter) {
|
|
|
575
641
|
// 递归查找所有匹配的节点
|
|
576
642
|
const findMatchedNodes = (nodes, result = []) => {
|
|
577
643
|
nodes.forEach(node => {
|
|
578
|
-
const nodeMatches = nodeMatchesAllConditions(node, validConditions);
|
|
644
|
+
const nodeMatches = Tree.nodeMatchesAllConditions(node, validConditions);
|
|
579
645
|
|
|
580
646
|
if (nodeMatches) {
|
|
581
647
|
result.push(node);
|
|
@@ -590,18 +656,15 @@ function filterFullTreeData(filter) {
|
|
|
590
656
|
|
|
591
657
|
const matchedNodes = findMatchedNodes(fullTreeData.value);
|
|
592
658
|
|
|
593
|
-
// 构建保持原始层级的过滤树
|
|
594
659
|
let filteredData = [];
|
|
595
660
|
if (matchedNodes.length > 0) {
|
|
596
661
|
filteredData = buildFilteredTreeWithOriginalHierarchy(matchedNodes);
|
|
597
662
|
}
|
|
598
663
|
|
|
599
|
-
// 设置过滤后的数据
|
|
600
664
|
refTree.value.store.setData(filteredData);
|
|
601
665
|
|
|
602
|
-
// 搜索状态时展开所有节点
|
|
603
666
|
if (filteredData.length > 0 && isSearching.value) {
|
|
604
|
-
const allKeys = getAllNodeKeys(filteredData);
|
|
667
|
+
const allKeys = Tree.getAllNodeKeys(filteredData);
|
|
605
668
|
defaultExpandedKeys.value = allKeys;
|
|
606
669
|
|
|
607
670
|
nextTick(() => {
|
|
@@ -614,7 +677,6 @@ function filterFullTreeData(filter) {
|
|
|
614
677
|
}
|
|
615
678
|
});
|
|
616
679
|
|
|
617
|
-
// 默认选中第一个可选节点
|
|
618
680
|
const findFirstSelectableNode = (nodes) => {
|
|
619
681
|
for (const node of nodes) {
|
|
620
682
|
if (!node.children || node.children.length === 0) {
|
|
@@ -630,9 +692,10 @@ function filterFullTreeData(filter) {
|
|
|
630
692
|
if (firstNode && firstNode.code) {
|
|
631
693
|
nextTick(() => {
|
|
632
694
|
refTree.value.setCurrentKey(firstNode.code);
|
|
633
|
-
handleNodeClick(firstNode
|
|
695
|
+
handleNodeClick(firstNode);
|
|
634
696
|
});
|
|
635
697
|
}
|
|
698
|
+
|
|
636
699
|
}
|
|
637
700
|
|
|
638
701
|
} catch (error) {
|
|
@@ -642,74 +705,168 @@ function filterFullTreeData(filter) {
|
|
|
642
705
|
}
|
|
643
706
|
}
|
|
644
707
|
|
|
645
|
-
//
|
|
646
|
-
function
|
|
708
|
+
// 获取节点的allowedRoutes
|
|
709
|
+
function getAllowedRoutesForNode(data) {
|
|
710
|
+
if (!model.value || !model.value.actionRouter) return [];
|
|
647
711
|
|
|
648
|
-
|
|
649
|
-
const
|
|
650
|
-
|
|
712
|
+
return model.value.actionRouter.filter(v => {
|
|
713
|
+
const val = data[v.rightField];
|
|
714
|
+
const hit = val == '1' || val === undefined || val === null;
|
|
715
|
+
return hit;
|
|
716
|
+
});
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
// 修改:加载节点,保存节点Map
|
|
720
|
+
function loadNode(node, resolve) {
|
|
721
|
+
// 如果是根节点(level === 0),清空节点加载状态
|
|
722
|
+
if (node.level === 0) {
|
|
723
|
+
nodeLoadedStatus.value.clear();
|
|
724
|
+
}
|
|
725
|
+
// 如果节点已经加载过,直接返回子节点
|
|
726
|
+
if (nodeLoadedStatus.value.has(node.key) && nodeLoadedStatus.value.get(node.key) === 'loaded') {
|
|
727
|
+
if (node.data && node.data.children) {
|
|
728
|
+
resolve(node.data.children);
|
|
729
|
+
} else {
|
|
730
|
+
resolve([]);
|
|
731
|
+
}
|
|
732
|
+
return;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
// 如果节点已经有数据且不是懒加载模式,直接返回子节点
|
|
736
|
+
if (node.data && node.data.children && node.data.children.length > 0 && !lazy.value) {
|
|
737
|
+
resolve(node.data.children);
|
|
651
738
|
return;
|
|
652
739
|
}
|
|
653
740
|
|
|
654
|
-
|
|
741
|
+
// 懒加载模式:第一次加载或需要加载子节点
|
|
742
|
+
if (lazy.value && node.level === 0) {
|
|
655
743
|
loading.value = true;
|
|
656
|
-
rootNode.value = node
|
|
744
|
+
rootNode.value = node;
|
|
657
745
|
rootResolve.value = resolve;
|
|
658
|
-
|
|
746
|
+
|
|
659
747
|
return SearchTree(screenPara.value || undefined).then(data => {
|
|
660
748
|
loading.value = false;
|
|
749
|
+
// 重置前折叠所有节点
|
|
750
|
+
collapseAllNodes();
|
|
661
751
|
|
|
752
|
+
let lazyMode = lazy.value;
|
|
753
|
+
if (!isLazyInitialized.value) {
|
|
754
|
+
lazyMode = false;
|
|
755
|
+
}
|
|
662
756
|
|
|
663
|
-
const { tree, hasAnyLeaf } = buildDeptTreeByField(data.rows, {
|
|
757
|
+
const { tree, hasAnyLeaf } = Tree.buildDeptTreeByField(data.rows, {
|
|
664
758
|
pathKey: 'path',
|
|
665
|
-
separator: '.'
|
|
759
|
+
separator: '.',
|
|
760
|
+
lazyMode: lazyMode,
|
|
666
761
|
});
|
|
667
762
|
|
|
668
|
-
//
|
|
669
|
-
if (
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
setDefaultExpandedNodes();
|
|
677
|
-
});
|
|
763
|
+
// 只在第一次加载时初始化
|
|
764
|
+
if (!isLazyInitialized.value) {
|
|
765
|
+
isLazyInitialized.value = true;
|
|
766
|
+
|
|
767
|
+
if (hasAnyLeaf) {
|
|
768
|
+
lazy.value = !hasAnyLeaf;
|
|
769
|
+
fullTreeData.value = tree;
|
|
770
|
+
nodeCodeMap.value = Tree.buildNodeCodeMap(tree);
|
|
678
771
|
}
|
|
679
772
|
}
|
|
680
|
-
else {
|
|
681
|
-
resolve(data.rows);
|
|
682
|
-
}
|
|
683
|
-
lazy.value = !hasAnyLeaf;
|
|
684
773
|
|
|
774
|
+
// 无论是否第一次加载,都解析树数据
|
|
775
|
+
const resultData = hasAnyLeaf ? tree : data.rows;
|
|
776
|
+
resolve(resultData);
|
|
777
|
+
|
|
778
|
+
|
|
779
|
+
|
|
780
|
+
if (props.expandTwoLevels && hasAnyLeaf) {
|
|
781
|
+
fullTreeData.value = tree;
|
|
782
|
+
nextTick(() => {
|
|
783
|
+
hasSetDefaultExpand.value = false;
|
|
784
|
+
setDefaultExpandedNodes();
|
|
785
|
+
});
|
|
786
|
+
}
|
|
685
787
|
load(data, true);
|
|
788
|
+
|
|
686
789
|
}).catch(error => {
|
|
687
790
|
loading.value = false;
|
|
688
791
|
console.error('加载树数据失败:', error);
|
|
689
792
|
});
|
|
690
793
|
}
|
|
691
794
|
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
fields: [
|
|
698
|
-
...fields.fields,
|
|
699
|
-
...(screenPara.value?.searchData?.fields || [])
|
|
700
|
-
]
|
|
701
|
-
}
|
|
702
|
-
};
|
|
795
|
+
// 非懒加载模式或懒加载但已有数据
|
|
796
|
+
if (!lazy.value && node.data && node.data.children) {
|
|
797
|
+
resolve(node.data.children);
|
|
798
|
+
return;
|
|
799
|
+
}
|
|
703
800
|
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
801
|
+
// 懒加载模式加载子节点
|
|
802
|
+
// 懒加载模式加载子节点
|
|
803
|
+
if (node.level >= 1 && lazy.value) {
|
|
804
|
+
|
|
805
|
+
// 设置节点为加载中状态
|
|
806
|
+
if (node && node.key) {
|
|
807
|
+
nodeLoadedStatus.value.set(node.key, 'loading');
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
// 检查是否已经有子节点数据
|
|
811
|
+
if (node.data.children && node.data.children.length > 0) {
|
|
812
|
+
if (node && node.key) {
|
|
813
|
+
nodeLoadedStatus.value.set(node.key, 'loaded');
|
|
814
|
+
}
|
|
815
|
+
resolve(node.data.children);
|
|
816
|
+
return;
|
|
712
817
|
}
|
|
818
|
+
|
|
819
|
+
let fields = model.value.searchData("code", node.data.code, 9, 3);
|
|
820
|
+
let filter = {
|
|
821
|
+
"searchData": {
|
|
822
|
+
...(screenPara.value?.searchData || {}),
|
|
823
|
+
fields: [
|
|
824
|
+
...fields.fields,
|
|
825
|
+
...(screenPara.value?.searchData?.fields || [])
|
|
826
|
+
]
|
|
827
|
+
}
|
|
828
|
+
};
|
|
829
|
+
|
|
830
|
+
return SearchTree(filter).then(data => {
|
|
831
|
+
// 标记节点为已加载
|
|
832
|
+
if (node && node.key) {
|
|
833
|
+
nodeLoadedStatus.value.set(node.key, 'loaded');
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
// 关键:更新节点的数据,添加children属性
|
|
837
|
+
if (node.data) {
|
|
838
|
+
node.data.children = data.rows;
|
|
839
|
+
|
|
840
|
+
// 判断是否没有子节点
|
|
841
|
+
if (!data.rows || data.rows.length === 0) {
|
|
842
|
+
// 没有子节点,设置节点为叶子节点
|
|
843
|
+
node.data.isLeaf = true;
|
|
844
|
+
node.isLeaf = true;
|
|
845
|
+
} else {
|
|
846
|
+
// 有子节点,设置节点为非叶子节点
|
|
847
|
+
node.data.isLeaf = false;
|
|
848
|
+
node.isLeaf = false;
|
|
849
|
+
}
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
resolve(data.rows || []);
|
|
853
|
+
load(data, false);
|
|
854
|
+
}).catch(error => {
|
|
855
|
+
loading.value = false;
|
|
856
|
+
if (node && node.key) {
|
|
857
|
+
nodeLoadedStatus.value.delete(node.key);
|
|
858
|
+
}
|
|
859
|
+
console.error('加载子节点失败:', error);
|
|
860
|
+
|
|
861
|
+
// 加载失败时,如果没有子节点数据,也标记为叶子节点
|
|
862
|
+
if (node && node.data) {
|
|
863
|
+
node.data.isLeaf = true;
|
|
864
|
+
node.isLeaf = true;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
resolve([]);
|
|
868
|
+
});
|
|
869
|
+
}
|
|
713
870
|
}
|
|
714
871
|
|
|
715
872
|
// 加载数据
|
|
@@ -724,13 +881,26 @@ async function load(data, flagRootNode) {
|
|
|
724
881
|
|
|
725
882
|
if (flagRootNode) {
|
|
726
883
|
if (model.value.rows && model.value.rows[0]) {
|
|
727
|
-
handleNodeClick(model.value.rows[0]
|
|
884
|
+
handleNodeClick(model.value.rows[0]);
|
|
728
885
|
}
|
|
729
886
|
nextTick(() => {
|
|
730
887
|
if (model.value.rows && model.value.rows[0] && model.value.rows[0].code) {
|
|
731
888
|
refTree.value.setCurrentKey(model.value.rows[0].code)
|
|
732
889
|
}
|
|
733
890
|
});
|
|
891
|
+
} else {
|
|
892
|
+
// 对于子节点加载,检查是否有数据返回
|
|
893
|
+
const currentNodeCode = currentData.value?.code;
|
|
894
|
+
if (currentNodeCode) {
|
|
895
|
+
const treeNode = refTree.value.getNode(currentNodeCode);
|
|
896
|
+
if (treeNode && (!data.rows || data.rows.length === 0)) {
|
|
897
|
+
// 没有子节点数据,标记为叶子节点
|
|
898
|
+
treeNode.isLeaf = true;
|
|
899
|
+
if (treeNode.data) {
|
|
900
|
+
treeNode.data.isLeaf = true;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
}
|
|
734
904
|
}
|
|
735
905
|
}
|
|
736
906
|
|
|
@@ -750,6 +920,10 @@ function SearchTree(m) {
|
|
|
750
920
|
// 重置树到全量数据
|
|
751
921
|
function resetTree() {
|
|
752
922
|
isSearching.value = false;
|
|
923
|
+
|
|
924
|
+
// 重置前折叠所有节点
|
|
925
|
+
collapseAllNodes();
|
|
926
|
+
|
|
753
927
|
if (fullTreeData.value.length > 0) {
|
|
754
928
|
refTree.value.store.setData(fullTreeData.value);
|
|
755
929
|
hasSetDefaultExpand.value = false;
|
|
@@ -757,16 +931,8 @@ function resetTree() {
|
|
|
757
931
|
|
|
758
932
|
if (fullTreeData.value[0] && fullTreeData.value[0].code) {
|
|
759
933
|
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
934
|
refTree.value.setCurrentKey(fullTreeData.value[0].code);
|
|
769
|
-
handleNodeClick(fullTreeData.value[0]
|
|
935
|
+
handleNodeClick(fullTreeData.value[0]);
|
|
770
936
|
setDefaultExpandedNodes();
|
|
771
937
|
});
|
|
772
938
|
}
|
|
@@ -778,38 +944,78 @@ function clearSearch() {
|
|
|
778
944
|
screenPara.value = {};
|
|
779
945
|
isSearching.value = false;
|
|
780
946
|
|
|
781
|
-
|
|
782
|
-
|
|
947
|
+
// 清除前折叠所有节点
|
|
948
|
+
collapseAllNodes();
|
|
783
949
|
|
|
784
950
|
if (fullTreeData.value.length > 0) {
|
|
785
951
|
refTree.value.store.setData(fullTreeData.value);
|
|
786
952
|
|
|
787
953
|
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
954
|
setDefaultExpandedNodes();
|
|
797
955
|
|
|
798
956
|
if (fullTreeData.value[0] && fullTreeData.value[0].code) {
|
|
799
957
|
refTree.value.setCurrentKey(fullTreeData.value[0].code);
|
|
800
|
-
handleNodeClick(fullTreeData.value[0]
|
|
958
|
+
handleNodeClick(fullTreeData.value[0]);
|
|
801
959
|
}
|
|
802
960
|
});
|
|
803
961
|
}
|
|
804
962
|
}
|
|
805
963
|
|
|
806
|
-
|
|
807
|
-
function handleNodeClick(data
|
|
808
|
-
|
|
964
|
+
// 修改:节点点击事件,支持自动展开和懒加载
|
|
965
|
+
function handleNodeClick(data) {
|
|
966
|
+
|
|
809
967
|
closeMenu();
|
|
810
|
-
|
|
811
|
-
|
|
968
|
+
|
|
969
|
+
// 设置当前选中节点
|
|
970
|
+
if (data && data.code) {
|
|
971
|
+
refTree.value?.setCurrentKey(data.code);
|
|
972
|
+
|
|
973
|
+
// 如果是懒加载模式,检查节点是否需要加载子节点
|
|
974
|
+
if (lazy.value) {
|
|
975
|
+
const treeNode = refTree.value.getNode(data.code);
|
|
976
|
+
if (treeNode) {
|
|
977
|
+
// 如果节点不是叶子节点但尚未加载,触发加载
|
|
978
|
+
if (!treeNode.isLeaf && !treeNode.loaded && !treeNode.loading) {
|
|
979
|
+
loadNode(treeNode, (children) => {
|
|
980
|
+
if (children && children.length > 0) {
|
|
981
|
+
// 有子节点,展开节点
|
|
982
|
+
if (!treeNode.expanded) {
|
|
983
|
+
treeNode.expanded = true;
|
|
984
|
+
}
|
|
985
|
+
} else {
|
|
986
|
+
// 没有子节点,标记为叶子节点
|
|
987
|
+
treeNode.isLeaf = true;
|
|
988
|
+
treeNode.loaded = true;
|
|
989
|
+
|
|
990
|
+
// 更新原始数据中的 isLeaf 属性
|
|
991
|
+
if (treeNode.data) {
|
|
992
|
+
treeNode.data.isLeaf = true;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
// 如果有父节点,更新父节点的children数组
|
|
996
|
+
if (treeNode.parent && treeNode.parent.data) {
|
|
997
|
+
const parentData = treeNode.parent.data;
|
|
998
|
+
if (parentData.children) {
|
|
999
|
+
// 找到当前节点在父节点children中的索引
|
|
1000
|
+
const index = parentData.children.findIndex(child => child.code === data.code);
|
|
1001
|
+
if (index !== -1) {
|
|
1002
|
+
parentData.children[index].isLeaf = true;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
});
|
|
1008
|
+
} else if (treeNode.children && treeNode.children.length > 0 && !treeNode.expanded) {
|
|
1009
|
+
// 如果节点已经有子节点但未展开,展开节点
|
|
1010
|
+
treeNode.expanded = true;
|
|
1011
|
+
} else if (treeNode.loaded && treeNode.children && treeNode.children.length === 0) {
|
|
1012
|
+
// 节点已加载但没有子节点,确保标记为叶子节点
|
|
1013
|
+
treeNode.isLeaf = true;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
812
1017
|
}
|
|
1018
|
+
|
|
813
1019
|
if (LastClickNode.value != data) {
|
|
814
1020
|
LastClickNode.value = data;
|
|
815
1021
|
let rowRouter = model.value.rowSelectRouter;
|
|
@@ -833,40 +1039,10 @@ function handleNodeClick(data, formType) {
|
|
|
833
1039
|
}
|
|
834
1040
|
}
|
|
835
1041
|
|
|
836
|
-
//右键菜单
|
|
837
|
-
function rightClick(event, object, Node) {
|
|
838
|
-
nodeRef.value = treeNodeRefMap.value[`node_Ref_${object.code}`]
|
|
839
|
-
|
|
840
|
-
currentData.value = object
|
|
841
|
-
currentNode.value = Node
|
|
842
|
-
let actionIndex = 0;
|
|
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
|
-
|
|
855
|
-
if (menuVisible.value) {
|
|
856
|
-
document.addEventListener('click', closeMenu)
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
//关闭菜单
|
|
861
|
-
function closeMenu() {
|
|
862
|
-
menuVisible.value = false;
|
|
863
|
-
nodeRef.value = null
|
|
864
|
-
currentData.value = { ...currentData.value, code: "" }
|
|
865
|
-
document.removeEventListener('click', closeMenu)
|
|
866
|
-
}
|
|
867
1042
|
|
|
868
1043
|
// 菜单路由
|
|
869
1044
|
function routerClickHandler(field) {
|
|
1045
|
+
isManualClose.value = true;
|
|
870
1046
|
var submitData = {};
|
|
871
1047
|
field.submitFormField.forEach(v => {
|
|
872
1048
|
submitData[v] = currentData.value[v];
|
|
@@ -893,29 +1069,232 @@ function routerClickHandler(field) {
|
|
|
893
1069
|
})
|
|
894
1070
|
}
|
|
895
1071
|
|
|
896
|
-
//删除树节点
|
|
897
|
-
function removeNode(newData) {
|
|
898
|
-
getNextClickNode(currentNode.value)
|
|
899
|
-
refTree.value.remove(currentNode.value);
|
|
900
|
-
|
|
901
|
-
}
|
|
902
|
-
|
|
903
1072
|
//新增树节点
|
|
904
1073
|
function addNode(newData) {
|
|
905
|
-
|
|
906
|
-
|
|
1074
|
+
if (!lazy.value) {
|
|
1075
|
+
// 全量数据模式:手动更新全量数据和树显示
|
|
1076
|
+
const parentCode = currentData.value.code;
|
|
1077
|
+
const parentPath = currentData.value.path || '';
|
|
1078
|
+
|
|
1079
|
+
// 设置新节点的属性
|
|
1080
|
+
const newNode = {
|
|
1081
|
+
...newData,
|
|
1082
|
+
// 如果后端没有返回path,需要构建
|
|
1083
|
+
path: parentPath ? `${parentPath}.${newData.code}` : newData.code,
|
|
1084
|
+
// 确保children存在
|
|
1085
|
+
children: newData.children || [],
|
|
1086
|
+
// 标识是否为叶子节点
|
|
1087
|
+
isLeaf: true
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// 在全量数据中找到父节点并添加
|
|
1091
|
+
const findAndAdd = (nodes, parentCode) => {
|
|
1092
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1093
|
+
if (nodes[i].code === parentCode) {
|
|
1094
|
+
if (!nodes[i].children) {
|
|
1095
|
+
nodes[i].children = [];
|
|
1096
|
+
}
|
|
1097
|
+
nodes[i].children.push(newNode);
|
|
1098
|
+
nodes[i].isLeaf = false; // 父节点不再是叶子节点
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
if (nodes[i].children && nodes[i].children.length > 0) {
|
|
1103
|
+
if (findAndAdd(nodes[i].children, parentCode)) {
|
|
1104
|
+
return true;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
return false;
|
|
1109
|
+
};
|
|
1110
|
+
|
|
1111
|
+
// 更新全量数据
|
|
1112
|
+
findAndAdd(fullTreeData.value, parentCode);
|
|
1113
|
+
|
|
1114
|
+
// 更新nodeCodeMap
|
|
1115
|
+
nodeCodeMap.value.set(newNode.code, newNode);
|
|
1116
|
+
|
|
1117
|
+
// 如果是搜索状态,需要同时更新当前显示的数据
|
|
1118
|
+
if (isSearching.value && screenPara.value) {
|
|
1119
|
+
filterFullTreeData(screenPara.value);
|
|
1120
|
+
} else {
|
|
1121
|
+
// 非搜索状态,直接重新设置数据
|
|
1122
|
+
refTree.value.store.setData([...fullTreeData.value]);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
// 刷新树显示
|
|
1126
|
+
nextTick(() => {
|
|
1127
|
+
// 展开父节点
|
|
1128
|
+
const parentNode = refTree.value.getNode(parentCode);
|
|
1129
|
+
if (parentNode && !parentNode.expanded) {
|
|
1130
|
+
refTree.value.store.setCurrentNode(parentNode);
|
|
1131
|
+
parentNode.expanded = true;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
// 设置新节点为当前选中
|
|
1135
|
+
handleNodeClick(newNode);
|
|
1136
|
+
});
|
|
1137
|
+
} else {
|
|
1138
|
+
// 懒加载模式:使用原有方法
|
|
1139
|
+
refTree.value.append(newData, currentNode.value);
|
|
1140
|
+
handleNodeClick(newData);
|
|
1141
|
+
}
|
|
907
1142
|
}
|
|
908
1143
|
|
|
909
1144
|
//修改树节点
|
|
910
1145
|
function updateNode(newData) {
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
1146
|
+
if (!lazy.value) {
|
|
1147
|
+
// 全量数据模式:更新全量数据
|
|
1148
|
+
const updateInTree = (nodes, nodeCode) => {
|
|
1149
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1150
|
+
if (nodes[i].code === nodeCode) {
|
|
1151
|
+
// 合并数据
|
|
1152
|
+
nodes[i] = { ...nodes[i], ...newData };
|
|
1153
|
+
return true;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
if (nodes[i].children && nodes[i].children.length > 0) {
|
|
1157
|
+
if (updateInTree(nodes[i].children, nodeCode)) {
|
|
1158
|
+
return true;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
return false;
|
|
1163
|
+
};
|
|
1164
|
+
|
|
1165
|
+
// 更新全量数据
|
|
1166
|
+
updateInTree(fullTreeData.value, currentData.value.code);
|
|
1167
|
+
|
|
1168
|
+
// 更新nodeCodeMap
|
|
1169
|
+
nodeCodeMap.value.set(currentData.value.code, {
|
|
1170
|
+
...nodeCodeMap.value.get(currentData.value.code),
|
|
1171
|
+
...newData
|
|
1172
|
+
});
|
|
1173
|
+
|
|
1174
|
+
// 如果是搜索状态,重新过滤显示
|
|
1175
|
+
if (isSearching.value && screenPara.value) {
|
|
1176
|
+
filterFullTreeData(screenPara.value);
|
|
914
1177
|
} else {
|
|
915
|
-
|
|
1178
|
+
// 非搜索状态,直接重新设置数据
|
|
1179
|
+
refTree.value.store.setData([...fullTreeData.value]);
|
|
916
1180
|
}
|
|
1181
|
+
|
|
1182
|
+
// 刷新显示并保持选中状态
|
|
1183
|
+
nextTick(() => {
|
|
1184
|
+
refTree.value.setCurrentKey(currentData.value.code);
|
|
1185
|
+
handleNodeClick({ ...currentData.value, ...newData });
|
|
1186
|
+
});
|
|
1187
|
+
} else {
|
|
1188
|
+
// 懒加载模式:使用原有方法
|
|
1189
|
+
for (let key in newData) {
|
|
1190
|
+
if (typeof newData[key] === 'object') {
|
|
1191
|
+
currentData.value[key] = { ...currentData.value[key], ...newData[key] }
|
|
1192
|
+
} else {
|
|
1193
|
+
currentData.value[key] = newData[key];
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
handleNodeClick(newData);
|
|
917
1197
|
}
|
|
918
|
-
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
//删除树节点
|
|
1201
|
+
function removeNode(newData) {
|
|
1202
|
+
if (!lazy.value) {
|
|
1203
|
+
// 全量数据模式:从全量数据中删除
|
|
1204
|
+
let parentNode = null;
|
|
1205
|
+
let parentCode = null;
|
|
1206
|
+
|
|
1207
|
+
const removeFromTree = (nodes, nodeCode) => {
|
|
1208
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
1209
|
+
if (nodes[i].code === nodeCode) {
|
|
1210
|
+
// 记录父节点信息(如果是当前循环的节点)
|
|
1211
|
+
parentCode = findParentCodeInFullTree(nodeCode);
|
|
1212
|
+
if (parentCode) {
|
|
1213
|
+
const parent = findNodeByCode(fullTreeData.value, parentCode);
|
|
1214
|
+
if (parent) {
|
|
1215
|
+
parentNode = parent;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
// 删除节点
|
|
1220
|
+
nodes.splice(i, 1);
|
|
1221
|
+
nodeCodeMap.value.delete(nodeCode);
|
|
1222
|
+
return true;
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
if (nodes[i].children && nodes[i].children.length > 0) {
|
|
1226
|
+
if (removeFromTree(nodes[i].children, nodeCode)) {
|
|
1227
|
+
return true;
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
return false;
|
|
1232
|
+
};
|
|
1233
|
+
|
|
1234
|
+
// 从全量数据中删除
|
|
1235
|
+
removeFromTree(fullTreeData.value, currentData.value.code);
|
|
1236
|
+
|
|
1237
|
+
// 更新父节点的 isLeaf 状态
|
|
1238
|
+
if (parentCode && parentNode) {
|
|
1239
|
+
// 重新检查父节点是否还有子节点
|
|
1240
|
+
const hasChildren = parentNode.children && parentNode.children.length > 0;
|
|
1241
|
+
parentNode.isLeaf = !hasChildren;
|
|
1242
|
+
|
|
1243
|
+
// 同步更新 nodeCodeMap
|
|
1244
|
+
if (nodeCodeMap.value.has(parentCode)) {
|
|
1245
|
+
const updatedParent = nodeCodeMap.value.get(parentCode);
|
|
1246
|
+
updatedParent.isLeaf = !hasChildren;
|
|
1247
|
+
nodeCodeMap.value.set(parentCode, updatedParent);
|
|
1248
|
+
}
|
|
1249
|
+
} else {
|
|
1250
|
+
// 如果是根节点被删除,不需要更新 isLeaf
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
// 如果是搜索状态,重新过滤显示
|
|
1254
|
+
if (isSearching.value && screenPara.value) {
|
|
1255
|
+
filterFullTreeData(screenPara.value);
|
|
1256
|
+
} else {
|
|
1257
|
+
// 非搜索状态,直接重新设置数据
|
|
1258
|
+
refTree.value.store.setData([...fullTreeData.value]);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// 查找下一个可点击的节点
|
|
1262
|
+
getNextClickNode();
|
|
1263
|
+
} else {
|
|
1264
|
+
// 懒加载模式:使用原有方法
|
|
1265
|
+
getNextClickNode();
|
|
1266
|
+
refTree.value.remove(currentNode.value);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
// 根据 code 查找节点
|
|
1271
|
+
function findNodeByCode(nodes, targetCode) {
|
|
1272
|
+
for (const node of nodes) {
|
|
1273
|
+
if (node.code === targetCode) {
|
|
1274
|
+
return node;
|
|
1275
|
+
}
|
|
1276
|
+
|
|
1277
|
+
if (node.children && node.children.length > 0) {
|
|
1278
|
+
const found = findNodeByCode(node.children, targetCode);
|
|
1279
|
+
if (found) return found;
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
return null;
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// 查找节点的父节点(返回父节点本身,不只是code)
|
|
1286
|
+
function findParentNodeInFullTree(nodes, targetCode, parent = null) {
|
|
1287
|
+
for (const node of nodes) {
|
|
1288
|
+
if (node.code === targetCode) {
|
|
1289
|
+
return parent;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
if (node.children && node.children.length > 0) {
|
|
1293
|
+
const found = findParentNodeInFullTree(node.children, targetCode, node);
|
|
1294
|
+
if (found) return found;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
return null;
|
|
919
1298
|
}
|
|
920
1299
|
|
|
921
1300
|
function getNextClickNode() {
|
|
@@ -928,7 +1307,7 @@ function getNextClickNode() {
|
|
|
928
1307
|
} else if (node?.parent) {
|
|
929
1308
|
data = node.parent.data;
|
|
930
1309
|
}
|
|
931
|
-
handleNodeClick(data
|
|
1310
|
+
handleNodeClick(data)
|
|
932
1311
|
}
|
|
933
1312
|
|
|
934
1313
|
/** 过滤节点(全量数据模式下使用) */
|
|
@@ -937,98 +1316,21 @@ function filterNode(value, data) {
|
|
|
937
1316
|
return data.name.toLowerCase().includes(value.toLowerCase())
|
|
938
1317
|
}
|
|
939
1318
|
|
|
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 : pathKey;
|
|
950
|
-
|
|
951
|
-
// 按路径排序,确保父节点在前
|
|
952
|
-
const sortedList = [...flatList].sort((a, b) => {
|
|
953
|
-
const aPath = a[pathKey] || '';
|
|
954
|
-
const bPath = b[pathKey] || '';
|
|
955
|
-
return aPath.length - bPath.length || aPath.localeCompare(bPath);
|
|
956
|
-
});
|
|
957
|
-
|
|
958
|
-
const pathMap = new Map(); // path -> node
|
|
959
|
-
const root = [];
|
|
960
|
-
|
|
961
|
-
for (const item of sortedList) {
|
|
962
|
-
const path = item[pathKey];
|
|
963
|
-
if (!path) continue;
|
|
964
|
-
|
|
965
|
-
const node = {
|
|
966
|
-
...item,
|
|
967
|
-
children: [],
|
|
968
|
-
isLeaf: true // 默认为叶子节点,后续会更新
|
|
969
|
-
};
|
|
970
|
-
|
|
971
|
-
// 添加到路径映射
|
|
972
|
-
pathMap.set(path, node);
|
|
973
|
-
|
|
974
|
-
// 查找父节点
|
|
975
|
-
const lastDotIndex = path.lastIndexOf(separator);
|
|
976
|
-
if (lastDotIndex > -1) {
|
|
977
|
-
const parentPath = path.substring(0, lastDotIndex);
|
|
978
|
-
const parentNode = pathMap.get(parentPath);
|
|
979
|
-
|
|
980
|
-
if (parentNode) {
|
|
981
|
-
parentNode.children.push(node);
|
|
982
|
-
parentNode.isLeaf = false; // 有子节点,所以不是叶子
|
|
983
|
-
continue;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
// 没有找到父节点,或者没有父路径,则作为根节点
|
|
988
|
-
root.push(node);
|
|
989
|
-
}
|
|
990
|
-
|
|
991
|
-
// 排序:按 sortKey 或 path 排序
|
|
992
|
-
const sortTree = (nodes) => {
|
|
993
|
-
nodes.sort((a, b) => {
|
|
994
|
-
const aVal = a[actualSortKey] || a[pathKey] || '';
|
|
995
|
-
const bVal = b[actualSortKey] || b[pathKey] || '';
|
|
996
|
-
return String(aVal).localeCompare(String(bVal));
|
|
997
|
-
});
|
|
998
|
-
|
|
999
|
-
nodes.forEach(node => {
|
|
1000
|
-
if (node.children && node.children.length > 0) {
|
|
1001
|
-
sortTree(node.children);
|
|
1002
|
-
}
|
|
1003
|
-
});
|
|
1004
|
-
};
|
|
1005
|
-
|
|
1006
|
-
sortTree(root);
|
|
1007
|
-
|
|
1008
|
-
const hasAnyLeaf = root.some(n => !n.isLeaf);
|
|
1009
|
-
return { tree: root, hasAnyLeaf };
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
1319
|
function findSearchFieldValue(searchFields, targetKey, options = {}) {
|
|
1013
1320
|
const {
|
|
1014
|
-
keyFields = ['fieldName1', 'groupName'],
|
|
1015
|
-
valueField = 'searchValue1',
|
|
1321
|
+
keyFields = ['fieldName1', 'groupName'],
|
|
1322
|
+
valueField = 'searchValue1',
|
|
1016
1323
|
defaultValue = 2
|
|
1017
1324
|
} = options;
|
|
1018
1325
|
|
|
1019
|
-
// 检查数据结构
|
|
1020
1326
|
if (!searchFields?.searchData?.fields?.length) {
|
|
1021
1327
|
return defaultValue;
|
|
1022
1328
|
}
|
|
1023
1329
|
|
|
1024
|
-
// 遍历fields数组
|
|
1025
1330
|
for (const field of searchFields.searchData.fields) {
|
|
1026
|
-
// 检查所有可能的key字段
|
|
1027
1331
|
for (const keyField of keyFields) {
|
|
1028
1332
|
if (field[keyField] === targetKey) {
|
|
1029
|
-
// 找到了匹配的key,返回对应的值
|
|
1030
1333
|
const value = field[valueField];
|
|
1031
|
-
// 如果值为undefined、null或空字符串,返回默认值
|
|
1032
1334
|
return value !== undefined && value !== null && value !== ''
|
|
1033
1335
|
? value
|
|
1034
1336
|
: defaultValue;
|
|
@@ -1039,8 +1341,6 @@ function findSearchFieldValue(searchFields, targetKey, options = {}) {
|
|
|
1039
1341
|
return defaultValue;
|
|
1040
1342
|
}
|
|
1041
1343
|
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
1344
|
// 暴露方法
|
|
1045
1345
|
defineExpose({
|
|
1046
1346
|
search,
|
|
@@ -1099,6 +1399,8 @@ defineExpose({
|
|
|
1099
1399
|
.node_content {
|
|
1100
1400
|
display: flex;
|
|
1101
1401
|
align-items: center;
|
|
1402
|
+
position: relative;
|
|
1403
|
+
width: 100%;
|
|
1102
1404
|
}
|
|
1103
1405
|
|
|
1104
1406
|
.node-icon {
|
|
@@ -1109,20 +1411,140 @@ defineExpose({
|
|
|
1109
1411
|
.box-menu {
|
|
1110
1412
|
z-index: 1000;
|
|
1111
1413
|
background-color: #fff;
|
|
1112
|
-
|
|
1414
|
+
// box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
|
|
1415
|
+
border-radius: 4px;
|
|
1416
|
+
padding: 4px 0;
|
|
1113
1417
|
|
|
1114
1418
|
div {
|
|
1115
1419
|
cursor: pointer;
|
|
1420
|
+
|
|
1116
1421
|
}
|
|
1117
1422
|
}
|
|
1118
1423
|
|
|
1424
|
+
.box-menu.box-menu-icons {
|
|
1425
|
+
display: flex;
|
|
1426
|
+
flex-wrap: nowrap;
|
|
1427
|
+
padding: 8px 0px;
|
|
1428
|
+
gap: 0px;
|
|
1429
|
+
line-height: 15px;
|
|
1430
|
+
background: transparent !important;
|
|
1431
|
+
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
.box-menu-icons .opertion {
|
|
1435
|
+
width: 16px;
|
|
1436
|
+
height: 16px;
|
|
1437
|
+
padding: 0 !important;
|
|
1438
|
+
display: flex;
|
|
1439
|
+
align-items: center;
|
|
1440
|
+
justify-content: center;
|
|
1441
|
+
border-radius: 4px;
|
|
1442
|
+
margin: 0 2px !important;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
.box-menu-icons .opertion:hover {
|
|
1446
|
+
background-color: #f5f7fa;
|
|
1447
|
+
transform: translateY(-1px);
|
|
1448
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
.box-menu-icons .opertion img {
|
|
1452
|
+
width: 20px;
|
|
1453
|
+
height: 20px;
|
|
1454
|
+
margin: 0;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
.box-menu-icons .opertion div {
|
|
1458
|
+
display: flex;
|
|
1459
|
+
align-items: center;
|
|
1460
|
+
justify-content: center;
|
|
1461
|
+
width: 100%;
|
|
1462
|
+
height: 100%;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1119
1465
|
.box-menu .opertion {
|
|
1466
|
+
display: flex;
|
|
1467
|
+
align-items: center;
|
|
1468
|
+
padding: 4px;
|
|
1120
1469
|
cursor: pointer;
|
|
1121
|
-
|
|
1470
|
+
font-size: 14px;
|
|
1471
|
+
color: #606266;
|
|
1472
|
+
transition: all 0.2s ease;
|
|
1473
|
+
line-height: 20px;
|
|
1474
|
+
margin: 0 4px;
|
|
1475
|
+
border-radius: 6px;
|
|
1476
|
+
position: relative;
|
|
1477
|
+
overflow: hidden;
|
|
1478
|
+
|
|
1479
|
+
|
|
1122
1480
|
}
|
|
1123
1481
|
|
|
1124
1482
|
.box-menu .opertion:hover {
|
|
1125
1483
|
color: var(--btnHoverRed);
|
|
1126
|
-
background-color:
|
|
1484
|
+
background-color: #f5f7fa;
|
|
1485
|
+
transform: translateY(-1px);
|
|
1486
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
|
|
1487
|
+
}
|
|
1488
|
+
|
|
1489
|
+
.box-menu .opertion:active {
|
|
1490
|
+
transform: translateY(0);
|
|
1491
|
+
box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.1);
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
.box-menu .opertion:not(:last-child)::after {
|
|
1495
|
+
content: '';
|
|
1496
|
+
position: absolute;
|
|
1497
|
+
bottom: 0;
|
|
1498
|
+
left: 16px;
|
|
1499
|
+
right: 16px;
|
|
1500
|
+
height: 1px;
|
|
1501
|
+
background-color: #f0f0f0;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
.box-menu .opertion:last-child {
|
|
1505
|
+
margin-bottom: 0;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
.box-menu .opertion img {
|
|
1509
|
+
width: 16px;
|
|
1510
|
+
height: 16px;
|
|
1511
|
+
margin-right: 8px;
|
|
1512
|
+
vertical-align: middle;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
.box-menu .opertion div {
|
|
1516
|
+
display: flex;
|
|
1517
|
+
align-items: center;
|
|
1518
|
+
width: 100%;
|
|
1519
|
+
justify-content: center; // 垂直居中
|
|
1520
|
+
text-align: center;
|
|
1521
|
+
}
|
|
1522
|
+
|
|
1523
|
+
/* 菜单激活状态 */
|
|
1524
|
+
.box-menu .opertion.active {
|
|
1525
|
+
background-color: #ecf5ff;
|
|
1526
|
+
color: var(--centalineBlue);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
/* 悬停模式下的节点样式 */
|
|
1530
|
+
.node_content:hover {
|
|
1531
|
+
background-color: #f5f7fa;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
.popper-transparent {
|
|
1535
|
+
background: transparent !important;
|
|
1536
|
+
border: none !important;
|
|
1537
|
+
box-shadow: none !important;
|
|
1538
|
+
padding: 0 !important;
|
|
1539
|
+
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// .popper-transparent .el-popper__arrow::before,
|
|
1543
|
+
// .popper-menu .el-popper__arrow::before {
|
|
1544
|
+
// background: transparent !important;
|
|
1545
|
+
// }
|
|
1546
|
+
|
|
1547
|
+
.popper-menu {
|
|
1548
|
+
padding: 0 !important;
|
|
1127
1549
|
}
|
|
1128
1550
|
</style>
|