@sy-common/organize-select-help 1.0.0-beta.63 → 1.0.0-beta.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sy-common/organize-select-help",
3
- "version": "1.0.0-beta.63",
3
+ "version": "1.0.0-beta.64",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "author": "lambo",
package/src/index.vue CHANGED
@@ -16,10 +16,14 @@
16
16
  <Tabs :value="tabName" @input="handleTabChange">
17
17
  <TabPane label="组织选择" name="org" v-if="name.includes('org')">
18
18
  <div class="tab">
19
- <span>组织搜索:</span>
20
- <Select v-model="orgSearch" filterable :remote-method="getOrgListBySearch" @on-change="getOrgOption" :loading="loadingOrg" placeholder="请输入组织名称" style="width: 600px;" clearable>
21
- <Option v-for="(option, index) in orgSearchList" :value="option.orgUnitId" :key="index">{{option.name}}</Option>
22
- </Select>
19
+ <div class="search-row">
20
+ <span class="search-label">组织搜索:</span>
21
+ <div class="search-input-wrapper">
22
+ <Select v-model="orgSearch" filterable :remote-method="getOrgListBySearch" @on-change="getOrgOption" :loading="loadingOrg" placeholder="请输入组织名称" style="width: 100%;" clearable>
23
+ <Option v-for="(option, index) in orgSearchList" :value="option.orgUnitId" :key="index">{{option.name}}</Option>
24
+ </Select>
25
+ </div>
26
+ </div>
23
27
  <div class="tag-content" v-if="isQuickOpen && orgTagList.length > 0">
24
28
  <span>快捷选择:</span>
25
29
  <div class="custom-select-wrapper">
@@ -49,7 +53,7 @@
49
53
  </div>
50
54
  </div>
51
55
  <div class="tree">
52
- <organizeTree @handleChange="getOrgList" ref="orgTree" :treeList="orgTree"></organizeTree>
56
+ <organizeTree v-if="orgTreeLoaded" @handleChange="getOrgList" ref="orgTree" :treeList="orgTree" :is-custom-tree="true" :disable-lazy-load="false"></organizeTree>
53
57
  </div>
54
58
  <div class="bottom-select">
55
59
  <CheckboxGroup v-model="includeLevelOrg">
@@ -75,10 +79,14 @@
75
79
  </div>
76
80
  </div>
77
81
  <div class="right">
78
- <span>组织搜索:</span>
79
- <Select v-model="postSearch" filterable :remote-method="getPostListBySearch" @on-change="getPostOption" placeholder="组织选择" :loading="loadingPost" clearable @on-clear="handlePostSearchClear" style="width: 365px;">
80
- <Option v-for="(option, index) in postSearchList" :value="option.orgUnitId" :key="index">{{option.name}}</Option>
81
- </Select>
82
+ <div class="search-row">
83
+ <span class="search-label">组织搜索:</span>
84
+ <div class="search-input-wrapper">
85
+ <Select v-model="postSearch" filterable :remote-method="getPostListBySearch" @on-change="getPostOption" placeholder="请输入组织名称" :loading="loadingPost" clearable @on-clear="handlePostSearchClear" style="width: 100%;">
86
+ <Option v-for="(option, index) in postSearchList" :value="option.orgUnitId" :key="index">{{option.name}}</Option>
87
+ </Select>
88
+ </div>
89
+ </div>
82
90
  <div class="tag-content" v-if="isQuickOpen && postTagList.length > 0">
83
91
  <span>快捷选择:</span>
84
92
  <div class="custom-select-wrapper">
@@ -108,7 +116,7 @@
108
116
  </div>
109
117
  </div>
110
118
  <div class="tree">
111
- <organizeTree @handleChange="getPostList" ref="postTree" :treeList="postTree"></organizeTree>
119
+ <organizeTree v-if="postTreeLoaded" @handleChange="getPostList" ref="postTree" :treeList="postTree" :is-custom-tree="true" :disable-lazy-load="false"></organizeTree>
112
120
  </div>
113
121
  <div class="bottom-select">
114
122
  <CheckboxGroup v-model="includeLevelPost">
@@ -129,6 +137,7 @@
129
137
  <div class="tree staff-org-tree">
130
138
  <div class="tree-scroll-force">
131
139
  <organizeTree
140
+ v-if="staffTreeLoaded"
132
141
  @handleChange="getStaffList"
133
142
  ref="staffTree"
134
143
  :treeList="staffTree"
@@ -143,7 +152,6 @@
143
152
  </div>
144
153
  </div>
145
154
  </div>
146
-
147
155
  <div class="staff-right-panel">
148
156
  <Input v-model="staffSearch" @on-enter="searchStaff" @on-search="searchStaff" search placeholder="搜索人员"/>
149
157
  <div style="position:relative;">
@@ -163,10 +171,10 @@
163
171
  </div>
164
172
  <Spin v-if="loadingStaff" size="large" fix />
165
173
  </div>
166
- <!-- <div class="bottom-select">-->
167
- <!-- <div>当前已选择 <span class="num">{{getCheckedStaff}}</span>人</div>-->
168
- <!-- <Button type="primary" icon="md-add" @click="addStaffList">添加人员</Button>-->
169
- <!-- </div>-->
174
+ <!-- <div class="bottom-select">-->
175
+ <!-- <div>当前已选择 <span class="num">{{getCheckedStaff}}</span>人</div>-->
176
+ <!-- <Button type="primary" icon="md-add" @click="addStaffList">添加人员</Button>-->
177
+ <!-- </div>-->
170
178
  </div>
171
179
  </div>
172
180
  </TabPane>
@@ -299,7 +307,14 @@ export default {
299
307
  selectedStaffOrgId: '', // 新增:选中的组织节点ID
300
308
  proStaffOrgList: [], // 新增:暂存选中的组织节点
301
309
  initialDefaultOrgUnitId: '', // 缓存初始defaultOrgUnitId
302
- staffTreeInited: false, // 组织树初始化完成标记(用于需求3)
310
+ // staffTreeInited: false, // 组织树初始化完成标记
311
+ // 树加载完成标记
312
+ orgTreeLoaded: false,
313
+ postTreeLoaded: false,
314
+ staffTreeLoaded: false,
315
+ // 缓存原始组织树/岗位树数据
316
+ originalOrgTree: [], // 组织Tab原始树缓存
317
+ originalPostTree: [], // 岗位Tab原始树缓存
303
318
  }
304
319
  },
305
320
  mounted() {
@@ -307,79 +322,260 @@ export default {
307
322
  this.queryPositionList()
308
323
  // this.loadMore()
309
324
  this.initialDefaultOrgUnitId = this.defaultOrgUnitId || ''; // 缓存初始值
325
+ this.initOrgOrgTree()
326
+ this.initPostOrgTree()
310
327
  this.initStaffOrgTree()
311
328
  },
312
329
 
313
330
  methods:{
331
+ async initOrgOrgTree() {
332
+ try {
333
+ this.proOrgList = [];
334
+ this.orgSearch = '';
335
+ this.orgSearchList = [];
336
+ this.orgTreeLoaded = false;
337
+
338
+ const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
339
+ params: { orgUnitId: '' }
340
+ });
341
+
342
+ if (orgDetailRes.data.code !== 1 || !orgDetailRes.data.data) {
343
+ this.$Message.warning("未查询到组织根节点,显示空树");
344
+ this.orgTree = [];
345
+ this.originalOrgTree = []; // 缓存空数据
346
+ this.orgTreeLoaded = true;
347
+ return;
348
+ }
349
+
350
+ const rootOrgData = orgDetailRes.data.data;
351
+ const leafNode = await this.judgeNodeLeafe(rootOrgData.orgUnitId);
352
+ const rootNode = this.safeDeepCopy({
353
+ orgUnitId: rootOrgData.orgUnitId,
354
+ orgUnitName: rootOrgData.orgUnitName,
355
+ parentOrgUnitId: rootOrgData.parentOrgUnitId,
356
+ leafNode: leafNode,
357
+ title: rootOrgData.orgUnitName || `未命名组织(${rootOrgData.orgUnitId})`,
358
+ expand: true,
359
+ orgChildrenList: [],
360
+ children: []
361
+ });
362
+
363
+ let parentsList = [];
364
+ try {
365
+ parentsList = await this.getParentOrgNodesByOrgUnitId(rootOrgData.orgUnitId);
366
+ } catch (e) {
367
+ console.warn('父节点查询失败,仅显示根节点:', e);
368
+ parentsList = [];
369
+ }
370
+
371
+ const safeParents = this.safeDeepCopy(parentsList).map(node => ({
372
+ orgUnitId: node.orgUnitId,
373
+ orgUnitName: node.orgUnitName || node.name,
374
+ parentOrgUnitId: node.parentOrgUnitId || node.parentId,
375
+ leafNode: false,
376
+ title: node.orgUnitName || node.name || `未命名组织(${node.orgUnitId})`,
377
+ expand: true,
378
+ orgChildrenList: [],
379
+ children: []
380
+ }));
381
+
382
+ const treeSourceData = [...safeParents, rootNode].filter(Boolean);
383
+ this.orgTree = this.buildTree(treeSourceData);
384
+ // 缓存原始树数据
385
+ this.originalOrgTree = this.safeDeepCopy(this.orgTree);
386
+
387
+ if (this.orgTree.length === 0) {
388
+ this.orgTree = [rootNode];
389
+ this.originalOrgTree = [rootNode]; // 同步缓存
390
+ }
391
+
392
+ this.orgTreeLoaded = true;
393
+
394
+ } catch (e) {
395
+ console.error("组织选择Tab树初始化失败:", e);
396
+ this.orgTree = [];
397
+ this.originalOrgTree = []; // 缓存空数据
398
+ this.orgTreeLoaded = true;
399
+ this.$Message.error("组织树初始化失败,请刷新重试");
400
+ }
401
+ },
402
+ async initPostOrgTree() {
403
+ try {
404
+ this.proPostList = [];
405
+ this.postSearch = '';
406
+ this.postSearchList = [];
407
+ this.selectedPositionId = null;
408
+ this.postTreeLoaded = false;
409
+
410
+ const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
411
+ params: { orgUnitId: '' }
412
+ });
413
+
414
+ if (orgDetailRes.data.code !== 1 || !orgDetailRes.data.data) {
415
+ this.$Message.warning("未查询到组织根节点,显示空树");
416
+ this.postTree = [];
417
+ this.originalPostTree = []; // 缓存空数据
418
+ this.postTreeLoaded = true;
419
+ return;
420
+ }
421
+
422
+ const rootOrgData = orgDetailRes.data.data;
423
+ const leafNode = await this.judgeNodeLeafe(rootOrgData.orgUnitId);
424
+ const rootNode = this.safeDeepCopy({
425
+ orgUnitId: rootOrgData.orgUnitId,
426
+ orgUnitName: rootOrgData.orgUnitName,
427
+ parentOrgUnitId: rootOrgData.parentOrgUnitId,
428
+ leafNode: leafNode,
429
+ title: rootOrgData.orgUnitName || `未命名组织(${rootOrgData.orgUnitId})`,
430
+ expand: true,
431
+ orgChildrenList: [],
432
+ children: []
433
+ });
434
+
435
+ let parentsList = [];
436
+ try {
437
+ parentsList = await this.getParentOrgNodesByOrgUnitId(rootOrgData.orgUnitId);
438
+ } catch (e) {
439
+ console.warn('岗位Tab父节点查询失败:', e);
440
+ parentsList = [];
441
+ }
442
+
443
+ const safeParents = this.safeDeepCopy(parentsList).map(node => ({
444
+ orgUnitId: node.orgUnitId,
445
+ orgUnitName: node.orgUnitName || node.name,
446
+ parentOrgUnitId: node.parentOrgUnitId || node.parentId,
447
+ leafNode: false,
448
+ title: node.orgUnitName || node.name || `未命名组织(${node.orgUnitId})`,
449
+ expand: true,
450
+ orgChildrenList: [],
451
+ children: []
452
+ }));
453
+
454
+ const treeSourceData = [...safeParents, rootNode].filter(Boolean);
455
+ this.postTree = this.buildTree(treeSourceData);
456
+ // 缓存原始树数据
457
+ this.originalPostTree = this.safeDeepCopy(this.postTree);
458
+
459
+ if (this.postTree.length === 0) {
460
+ this.postTree = [rootNode];
461
+ this.originalPostTree = [rootNode]; // 同步缓存
462
+ }
463
+
464
+ this.postTreeLoaded = true;
465
+
466
+ } catch (e) {
467
+ console.error("岗位选择Tab树初始化失败:", e);
468
+ this.postTree = [];
469
+ this.originalPostTree = []; // 缓存空数据
470
+ this.postTreeLoaded = true;
471
+ this.$Message.error("岗位组织树初始化失败,请刷新重试");
472
+ }
473
+ },
474
+
314
475
  async initStaffOrgTree() {
315
476
  try {
316
- // 关键修复:初始化时重置选中状态
477
+ // 初始化时重置选中状态
317
478
  this.$set(this, 'selectedStaffOrgId', '');
318
479
  this.proStaffOrgList = [];
319
-
480
+ this.staffTreeLoaded = false;
320
481
  const rootOrgId = this.defaultOrgUnitId || '';
321
482
  let rootNode = null;
322
483
  let treeSourceData = []; // 存储树原始数据,避免后续覆盖
323
484
 
324
- if (rootOrgId) {
325
- const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
326
- params: { orgUnitId: rootOrgId }
485
+ // if (rootOrgId) {
486
+ // const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
487
+ // params: { orgUnitId: rootOrgId }
488
+ // });
489
+ // if (orgDetailRes.data.code === 1 && orgDetailRes.data.data) {
490
+ // const orgData = orgDetailRes.data.data;
491
+ // const leafNode = await this.judgeNodeLeafe(rootOrgId);
492
+ // rootNode = this.safeDeepCopy({
493
+ // ...orgData,
494
+ // orgNodeName: orgData.orgUnitName || '',
495
+ // title: orgData.orgUnitName || `未命名组织(${orgData.orgUnitId || ''})`,
496
+ // leafNode,
497
+ // expand: true,
498
+ // parentOrgUnitId: orgData.parentOrgUnitId || orgData.parentId,
499
+ // orgChildrenList: [], // 初始化自定义子节点字段
500
+ // children: [] // 初始化 Tree 组件识别的 children 字段
501
+ // });
502
+ // // 父节点列表同样同步初始化 children 字段
503
+ // let parentsList = await this.getParentOrgNodesByOrgUnitId(rootOrgId);
504
+ // const safeParents = this.safeDeepCopy(parentsList);
505
+ // safeParents.forEach(node => {
506
+ // node.expand = true;
507
+ // node.parentOrgUnitId = node.parentId;
508
+ // node.orgNodeName = node.orgUnitName || node.orgNodeName || '';
509
+ // node.title = node.orgUnitName || node.name || `未命名组织(${node.orgUnitId || ''})`;
510
+ // node.orgChildrenList = [];
511
+ // node.children = []; // 父节点也初始化 children 字段
512
+ // node.leafNode = false;
513
+ // });
514
+ // treeSourceData = [...safeParents, rootNode];
515
+ // } else {
516
+ // this.$Message.error("根据默认组织ID查询根节点失败!");
517
+ // return;
518
+ // }
519
+ // } else {
520
+ // // defaultOrgUnitId为空时,沿用原有接口/pub/personHelpBox/q/getOrgUnitList
521
+ // const res = await ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
522
+ // params: { containsCurLevel: true }
523
+ // });
524
+ // if (res.data.code === 1) {
525
+ // rootNode = res.data.data[0] || null;
526
+ // if (rootNode) {
527
+ // rootNode.expand = true;
528
+ // rootNode.parentOrgUnitId = rootNode.parentId;
529
+ // treeSourceData = [rootNode];
530
+ // }
531
+ // }
532
+ // }
533
+ const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
534
+ params: { orgUnitId: rootOrgId }
535
+ });
536
+ if (orgDetailRes.data.code === 1 && orgDetailRes.data.data) {
537
+ const orgData = orgDetailRes.data.data;
538
+ const leafNode = await this.judgeNodeLeafe(rootOrgId);
539
+ rootNode = this.safeDeepCopy({
540
+ ...orgData,
541
+ orgNodeName: orgData.orgUnitName || '',
542
+ title: orgData.orgUnitName || `未命名组织(${orgData.orgUnitId || ''})`,
543
+ leafNode,
544
+ expand: true,
545
+ parentOrgUnitId: orgData.parentOrgUnitId || orgData.parentId,
546
+ orgChildrenList: [], // 初始化自定义子节点字段
547
+ children: [] // 初始化 Tree 组件识别的 children 字段
327
548
  });
328
- if (orgDetailRes.data.code === 1 && orgDetailRes.data.data) {
329
- const orgData = orgDetailRes.data.data;
330
- const leafNode = await this.judgeNodeLeafe(rootOrgId);
331
- rootNode = this.safeDeepCopy({
332
- ...orgData,
333
- orgNodeName: orgData.orgUnitName || '',
334
- title: orgData.orgUnitName || `未命名组织(${orgData.orgUnitId || ''})`,
335
- leafNode,
336
- expand: true,
337
- parentOrgUnitId: orgData.parentOrgUnitId || orgData.parentId,
338
- orgChildrenList: [], // 初始化自定义子节点字段
339
- children: [] // 关键:初始化 Tree 组件识别的 children 字段
340
- });
341
- // 父节点列表同样同步初始化 children 字段
342
- let parentsList = await this.getParentOrgNodesByOrgUnitId(rootOrgId);
343
- const safeParents = this.safeDeepCopy(parentsList);
344
- safeParents.forEach(node => {
345
- node.expand = true;
346
- node.parentOrgUnitId = node.parentId;
347
- node.orgNodeName = node.orgUnitName || node.orgNodeName || '';
348
- node.title = node.orgUnitName || node.name || `未命名组织(${node.orgUnitId || ''})`;
349
- node.orgChildrenList = [];
350
- node.children = []; // 父节点也初始化 children 字段
351
- node.leafNode = false;
352
- });
353
- treeSourceData = [...safeParents, rootNode];
354
- } else {
355
- this.$Message.error("根据默认组织ID查询根节点失败!");
356
- return;
357
- }
358
- } else {
359
- // defaultOrgUnitId为空时,沿用原有接口/pub/personHelpBox/q/getOrgUnitList
360
- const res = await ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
361
- params: { containsCurLevel: true }
549
+ // 父节点列表同样同步初始化 children 字段
550
+ let parentsList = await this.getParentOrgNodesByOrgUnitId(rootOrgId);
551
+ const safeParents = this.safeDeepCopy(parentsList);
552
+ safeParents.forEach(node => {
553
+ node.expand = true;
554
+ node.parentOrgUnitId = node.parentId;
555
+ node.orgNodeName = node.orgUnitName || node.orgNodeName || '';
556
+ node.title = node.orgUnitName || node.name || `未命名组织(${node.orgUnitId || ''})`;
557
+ node.orgChildrenList = [];
558
+ node.children = []; // 父节点也初始化 children 字段
559
+ node.leafNode = false;
362
560
  });
363
- if (res.data.code === 1) {
364
- rootNode = res.data.data[0] || null;
365
- if (rootNode) {
366
- rootNode.expand = true;
367
- rootNode.parentOrgUnitId = rootNode.parentId;
368
- treeSourceData = [rootNode];
369
- }
370
- }
561
+ treeSourceData = [...safeParents, rootNode];
562
+ } else {
563
+ this.$Message.error("根据默认组织ID查询根节点失败!");
564
+ this.staffTreeLoaded = true;
565
+ return;
371
566
  }
372
-
373
- // 构建组织树,且仅赋值一次,避免后续覆盖(需求3)
567
+ // 构建组织树,且仅赋值一次,避免后续覆盖
374
568
  if (treeSourceData.length > 0) {
375
569
  const tree = this.buildTree(treeSourceData);
376
570
  this.staffTree = this.safeDeepCopy(tree);
377
- // 关键:标记树已初始化完成,防止后续重复构建覆盖
378
- this.staffTreeInited = true;
571
+ // 标记树已初始化完成,防止后续重复构建覆盖
572
+ // this.staffTreeInited = true;
573
+ this.staffTreeLoaded = true;
379
574
  }
380
575
  } catch (e) {
381
576
  this.$Message.error("人员选择组织树初始化失败!");
382
577
  console.error(e);
578
+ this.staffTreeLoaded = true;
383
579
  }
384
580
  },
385
581
  handlePostTagSelect(quickPickKey) {
@@ -504,7 +700,6 @@ export default {
504
700
  this.loadingPost = false;
505
701
  if (res.data.code === 1) {
506
702
  let resp = res.data.data?.items ?? [];
507
- // 修复:岗位搜索结果深拷贝,避免引用污染
508
703
  this.postSearchList = this.safeDeepCopy(resp);
509
704
  } else {
510
705
  this.postSearchList = [];
@@ -512,13 +707,15 @@ export default {
512
707
  }
513
708
  });
514
709
  } else {
515
- // 修复:清空搜索时,同时清空树数据和暂存列表(与组织Tab一致)
710
+ // 仅清空搜索结果,不重置树数据
516
711
  this.postSearchList = [];
712
+ // 仅重置选中状态,保留树结构
517
713
  if (this.$refs.postTree) {
518
- this.$refs.postTree.initData();
714
+ this.$refs.postTree.initData(); // 清空选中状态
715
+ this.proPostList = []; // 清空暂存列表
519
716
  }
520
- this.proPostList = []; // 清空岗位暂存列表
521
- this.$set(this, 'postTree', []); // 清空岗位树数据
717
+ // 移除清空树数据的代码
718
+ // this.$set(this, 'postTree', []);
522
719
  }
523
720
  },
524
721
  getOrgUnitBySearchTerm(query,callback){
@@ -526,78 +723,138 @@ export default {
526
723
  },
527
724
  async getOrgOption(val) {
528
725
  this.selectedOrgTagKey = '';
529
- this.orgTagList.forEach(tag => {
530
- tag.checked = false;
531
- });
726
+ this.orgTagList.forEach(tag => tag.checked = false);
532
727
  this.proOrgList = [];
533
- if(!val) return this.$refs.orgTree.initData();
534
- let item = this.orgSearchList.filter((item)=> item.orgUnitId === val).shift();
535
- if (!item) return;
728
+ if (!val) {
729
+ // 清空搜索时恢复原始树数据,而非置空
730
+ this.orgTree = this.safeDeepCopy(this.originalOrgTree);
731
+ // 同步更新子组件数据
732
+ this.$nextTick(() => {
733
+ if (this.$refs.orgTree) {
734
+ this.$refs.orgTree.data = this.safeDeepCopy(this.orgTree);
735
+ // 重置树选中状态,但保留树结构
736
+ this.$refs.orgTree.initData();
737
+ }
738
+ });
739
+ return;
740
+ }
741
+ const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
742
+ params: { orgUnitId: val }
743
+ });
536
744
 
537
- const leafNode = await this.judgeNodeLeafe(item.orgUnitId);
538
- const ftem = this.safeDeepCopy({
539
- ...item,
540
- orgNodeName: item.name,
541
- parentOrgUnitId: item.parentId,
542
- leafNode: leafNode
745
+ if (orgDetailRes.data.code !== 1 || !orgDetailRes.data.data) {
746
+ this.$Message.error("获取组织节点详情失败!");
747
+ return;
748
+ }
749
+
750
+ const nodeData = orgDetailRes.data.data;
751
+ const currentNode = this.safeDeepCopy({
752
+ orgUnitId: nodeData.orgUnitId,
753
+ orgUnitName: nodeData.orgUnitName,
754
+ parentOrgUnitId: nodeData.parentOrgUnitId,
755
+ leafNode: nodeData.leafNode || await this.judgeNodeLeafe(nodeData.orgUnitId),
756
+ title: nodeData.orgUnitName || `未命名组织(${nodeData.orgUnitId})`,
757
+ expand: true,
758
+ orgChildrenList: [],
759
+ children: []
543
760
  });
544
761
 
545
- try{
762
+ try {
546
763
  let parentsList = await this.getParentOrgNodesByOrgUnitId(val);
547
- // 对父节点列表进行安全拷贝
548
- const safeParents = this.safeDeepCopy(parentsList);
549
- let tree = this.buildTree([...safeParents, ftem]);
550
- this.orgTree = this.safeDeepCopy(tree);
551
- }catch(e){
552
- this.$Message.error("获取组织节点列表失败!");
764
+ const safeParents = this.safeDeepCopy(parentsList).map(node => ({
765
+ orgUnitId: node.orgUnitId,
766
+ orgUnitName: node.orgUnitName || node.name,
767
+ parentOrgUnitId: node.parentOrgUnitId || node.parentId,
768
+ leafNode: false,
769
+ title: node.orgUnitName || node.name || `未命名组织(${node.orgUnitId})`,
770
+ expand: true,
771
+ orgChildrenList: [],
772
+ children: []
773
+ }));
774
+
775
+ const treeSourceData = [...safeParents, currentNode].filter(Boolean);
776
+ this.orgTree = this.buildTree(treeSourceData);
777
+
778
+ // 强制更新子组件数据
779
+ this.$nextTick(() => {
780
+ if (this.$refs.orgTree) {
781
+ this.$refs.orgTree.data = this.safeDeepCopy(this.orgTree);
782
+ }
783
+ });
784
+ } catch (e) {
785
+ this.$Message.error("更新组织树失败!");
553
786
  }
554
787
  },
555
788
  async getPostOption(val) {
556
- // 1. 重置选中的标签key
557
789
  this.selectedPostTagKey = '';
790
+ this.postTagList.forEach(tag => tag.checked = false);
558
791
 
559
- // 2. 重置所有标签的选中状态
560
- this.postTagList.forEach(tag => {
561
- tag.checked = false;
562
- });
563
792
  if (!val) {
564
- // 修复:岗位树清空时,同时清空暂存列表和搜索框
565
- if (this.$refs.postTree) {
566
- this.$refs.postTree.initData();
567
- }
568
- this.proPostList = []; // 清空岗位暂存列表(与组织Tab保持一致)
569
- this.postSearch = ''; // 清空搜索框
793
+ // 清空搜索时恢复原始树数据
794
+ this.postTree = this.safeDeepCopy(this.originalPostTree);
795
+ this.proPostList = [];
796
+ this.postSearch = '';
797
+ // 同步更新子组件数据
798
+ this.$nextTick(() => {
799
+ if (this.$refs.postTree) {
800
+ this.$refs.postTree.data = this.safeDeepCopy(this.postTree);
801
+ // 重置树选中状态,但保留树结构
802
+ this.$refs.postTree.initData();
803
+ }
804
+ });
570
805
  return;
571
806
  }
572
807
 
573
- let item = this.postSearchList.filter(item => item.orgUnitId === val).shift();
574
- if (!item) return;
808
+ // 原有逻辑保持不变
809
+ const orgDetailRes = await ajax.get(`/pub-manage-server/pub/organ/q/queryOrg`, {
810
+ params: { orgUnitId: val }
811
+ });
575
812
 
576
- const leafNode = await this.judgeNodeLeafe(item.orgUnitId);
577
- // 修复:岗位节点深拷贝,避免引用污染
578
- const ftem = this.safeDeepCopy({
579
- ...item,
580
- orgNodeName: item.name || `未命名组织(${item.orgUnitId})`,
581
- parentOrgUnitId: item.parentId,
582
- leafNode: leafNode
813
+ if (orgDetailRes.data.code !== 1 || !orgDetailRes.data.data) {
814
+ this.$Message.error("获取组织节点详情失败!");
815
+ return;
816
+ }
817
+
818
+ const nodeData = orgDetailRes.data.data;
819
+ const currentNode = this.safeDeepCopy({
820
+ orgUnitId: nodeData.orgUnitId,
821
+ orgUnitName: nodeData.orgUnitName,
822
+ parentOrgUnitId: nodeData.parentOrgUnitId,
823
+ leafNode: nodeData.leafNode || await this.judgeNodeLeafe(nodeData.orgUnitId),
824
+ title: nodeData.orgUnitName || `未命名组织(${nodeData.orgUnitId})`,
825
+ expand: true,
826
+ orgChildrenList: [],
827
+ children: []
583
828
  });
584
829
 
585
830
  try {
586
831
  let parentsList = await this.getParentOrgNodesByOrgUnitId(val);
587
- const safeParents = this.safeDeepCopy(parentsList);
588
- let tree = this.buildTree([...safeParents, ftem]);
589
- // 修复:用$set确保岗位树数据响应式更新
590
- this.$set(this, 'postTree', this.safeDeepCopy(tree));
832
+ const safeParents = this.safeDeepCopy(parentsList).map(node => ({
833
+ orgUnitId: node.orgUnitId,
834
+ orgUnitName: node.orgUnitName || node.name,
835
+ parentOrgUnitId: node.parentOrgUnitId || node.parentId,
836
+ leafNode: false,
837
+ title: node.orgUnitName || node.name || `未命名组织(${node.orgUnitId})`,
838
+ expand: true,
839
+ orgChildrenList: [],
840
+ children: []
841
+ }));
842
+
843
+ const treeSourceData = [...safeParents, currentNode].filter(Boolean);
844
+ this.postTree = this.buildTree(treeSourceData);
591
845
 
592
- // 修复:设置节点展开和选中(与组织Tab逻辑一致)
593
846
  this.$nextTick(() => {
594
847
  if (this.$refs.postTree && this.$refs.postTree.setCheckedNodes) {
595
- this.$refs.postTree.setCheckedNodes([val]); // 选中当前节点
596
- this.proPostList = [ftem]; // 同步暂存列表
848
+ this.$refs.postTree.setCheckedNodes([val]);
849
+ this.proPostList = [currentNode];
850
+ }
851
+ // 强制更新子组件数据
852
+ if (this.$refs.postTree) {
853
+ this.$refs.postTree.data = this.safeDeepCopy(this.postTree);
597
854
  }
598
855
  });
599
856
  } catch (e) {
600
- this.$Message.error("获取组织节点列表失败!");
857
+ this.$Message.error("更新岗位组织树失败!");
601
858
  }
602
859
  },
603
860
  async getStaffOption(val) {
@@ -624,67 +881,84 @@ export default {
624
881
  this.$Message.error("获取组织节点列表失败!");
625
882
  }
626
883
  },
627
- getParentOrgNodesByOrgUnitId(val){
628
- return new Promise((resolve,reject)=>{
629
- ajax.get('/pub-manage-server/pub/personHelpBox/q/getParentOrgNodesByOrgUnitId?orgUnitId='+val).then((res)=>{
630
- if(res.data.code === 1){
631
- let parentsList = res.data?.data?.items??[]
632
- resolve(parentsList)
633
- }else{
634
- reject(false)
635
- }
636
- })
637
- })
884
+ getParentOrgNodesByOrgUnitId(val) {
885
+ return new Promise((resolve) => {
886
+ ajax.get('/pub-manage-server/pub/personHelpBox/q/getParentOrgNodesByOrgUnitId?orgUnitId='+val)
887
+ .then((res) => {
888
+ if (res.data.code === 1) {
889
+ const parentsList = res.data?.data?.items ?? [];
890
+ resolve(parentsList); // 接口正常返回则取数据
891
+ } else {
892
+ resolve([]); // 接口报错返回空数组
893
+ }
894
+ })
895
+ .catch(() => {
896
+ resolve([]); // 网络/请求失败返回空数组
897
+ });
898
+ });
638
899
  },
639
- judgeNodeLeafe(orgUnitId){
640
- return new Promise((resolve,reject)=>{
641
- ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', { params:{
642
- containsCurLevel:true,
643
- orgUnitId:orgUnitId,
900
+ judgeNodeLeafe(orgUnitId) {
901
+ return new Promise((resolve) => {
902
+ ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
903
+ params: {
904
+ containsCurLevel: true,
905
+ orgUnitId: orgUnitId,
644
906
  }
645
- }).then((res)=>{
646
- if(res.data.code === 1){
647
- let treeList = res.data.data
648
- if(treeList && treeList.length){
649
- resolve(false)
650
- }else{
651
- resolve(true)
652
- }
653
- }else{
654
- resolve(false)
907
+ }).then((res) => {
908
+ if (res.data.code === 1) {
909
+ const treeList = res.data.data || [];
910
+ resolve(treeList.length === 0);
911
+ } else {
912
+ resolve(false); // 接口失败默认非叶子节点
655
913
  }
656
- })
657
- })
914
+ }).catch(() => {
915
+ resolve(false); // 网络错误默认非叶子节点
916
+ });
917
+ });
658
918
  },
659
919
  buildTree(items) {
660
- const map = {};
920
+ if (!Array.isArray(items) || items.length === 0) {
921
+ console.warn('构建树入参为空,返回空数组');
922
+ return [];
923
+ }
924
+
925
+ const map = new Map();
661
926
  const roots = [];
662
927
  const copiedItems = this.safeDeepCopy(items);
663
928
 
664
929
  copiedItems.forEach(item => {
665
930
  if (!item.orgUnitId) return;
666
- map[item.orgUnitId] = this.safeDeepCopy({
667
- ...item,
668
- orgChildrenList: [],
669
- children: [], // 强制初始化 children 空数组
670
- title: item.orgUnitName || item.orgNodeName || item.name || `未命名组织(${item.orgUnitId || ''})`
671
- });
931
+ map.set(item.orgUnitId, this.safeDeepCopy({
932
+ orgUnitId: item.orgUnitId,
933
+ orgUnitName: item.orgUnitName,
934
+ parentOrgUnitId: item.parentOrgUnitId,
935
+ leafNode: item.leafNode || false,
936
+ title: item.title || item.orgUnitName || `未命名组织(${item.orgUnitId})`,
937
+ expand: item.expand || true, // 保留展开状态
938
+ orgChildrenList: item.orgChildrenList || [],
939
+ children: item.children || []
940
+ }));
672
941
  });
673
942
 
674
943
  copiedItems.forEach(item => {
675
- if (!item.orgUnitId || !map[item.orgUnitId]) return;
944
+ if (!item.orgUnitId || !map.has(item.orgUnitId)) return;
676
945
 
677
- const node = map[item.orgUnitId];
678
- if (!item.parentOrgUnitId || !map[item.parentOrgUnitId]) {
946
+ const node = map.get(item.orgUnitId);
947
+ if (!item.parentOrgUnitId || !map.has(item.parentOrgUnitId)) {
679
948
  roots.push(node);
680
949
  } else {
681
- const parent = map[item.parentOrgUnitId];
950
+ const parent = map.get(item.parentOrgUnitId);
682
951
  parent.orgChildrenList.push(node);
683
- parent.children.push(node); // 同步 children 字段
684
- parent.leafNode = false;
685
- parent.expand = true;
952
+ parent.children.push(node);
953
+ parent.leafNode = false; // 有子节点则强制非叶子节点
954
+ parent.expand = true; // 有子节点则强制展开
686
955
  }
687
956
  });
957
+
958
+ if (roots.length === 0 && map.size > 0) {
959
+ roots.push(Array.from(map.values())[0]);
960
+ }
961
+
688
962
  return roots;
689
963
  },
690
964
 
@@ -692,7 +966,7 @@ export default {
692
966
  this.staffEnding = false;
693
967
  this.offset = 0;
694
968
  this.staffAllList = [];
695
- // 关键修复:50ms延迟,解决极端情况下的异步更新问题
969
+ // 50ms延迟,解决极端情况下的异步更新问题
696
970
  setTimeout(() => {
697
971
  this.loadMore();
698
972
  }, 50);
@@ -807,7 +1081,7 @@ export default {
807
1081
  return;
808
1082
  }
809
1083
 
810
- // 关键修复1:过滤仅含有效orgUnitId的节点,排除无效数据
1084
+ // 过滤仅含有效orgUnitId的节点,排除无效数据
811
1085
  const validNodes = data.filter(node =>
812
1086
  node.orgUnitId && typeof node.orgUnitId === 'string' // 确保orgUnitId存在且为字符串
813
1087
  );
@@ -821,7 +1095,7 @@ export default {
821
1095
  return;
822
1096
  }
823
1097
 
824
- // 关键修复2:单选逻辑强化,仅保留最后一个有效选中节点
1098
+ // 单选逻辑强化,仅保留最后一个有效选中节点
825
1099
  const currentNode = validNodes[validNodes.length - 1];
826
1100
  const currentOrgUnitId = currentNode.orgUnitId.trim(); // 去除空格,避免无效字符串
827
1101
 
@@ -836,11 +1110,11 @@ export default {
836
1110
  if (pureNode.orgChildrenList) pureNode.orgChildrenList = [];
837
1111
  if (pureNode.children) pureNode.children = [];
838
1112
 
839
- // 关键修复3:强制响应式更新,避免Vue数据延迟
1113
+ // 强制响应式更新,避免Vue数据延迟
840
1114
  this.$set(this, 'proStaffOrgList', [pureNode]);
841
1115
  this.$set(this, 'selectedStaffOrgId', currentOrgUnitId);
842
1116
 
843
- // 关键修复4:双重nextTick确保数据完全更新后再查询
1117
+ // 双重nextTick确保数据完全更新后再查询
844
1118
  this.$nextTick(() => {
845
1119
  if (this.selectedStaffOrgId !== currentOrgUnitId) {
846
1120
  this.$set(this, 'selectedStaffOrgId', currentOrgUnitId);
@@ -1050,15 +1324,14 @@ export default {
1050
1324
  this.offset = 0;
1051
1325
  this.staffAllList = [];
1052
1326
  this.loadingStaff = false;
1053
- this.loadMore().catch(err => console.log("同步加载失败:", err));
1054
- this.$nextTick(() => {
1055
- setTimeout(() => {
1056
- this.loadMore();
1057
- }, 100);
1058
- });
1059
- } else if (tabName === 'post' && this.$refs.postTree && this.proPostList.length === 0) {
1327
+ // 仅当树未初始化时才加载
1328
+ if (!this.staffTreeLoaded || this.staffTree.length === 0) {
1329
+ this.loadMore().catch(err => console.log("同步加载失败:", err));
1330
+ }
1331
+ } else if (tabName === 'post' && this.proPostList.length === 0) {
1060
1332
  this.proPostList = [];
1061
- this.$refs.postTree.initData();
1333
+ // 移除initData调用,避免重置树数据
1334
+ // this.$refs.postTree.initData();
1062
1335
  }
1063
1336
  },
1064
1337
  initStaffList() {
@@ -1082,7 +1355,8 @@ export default {
1082
1355
  const proListKey = 'proOrgList';
1083
1356
  const treeDataKey = 'orgTree';
1084
1357
  this[proListKey] = [];
1085
- if (treeRef) await treeRef.initData();
1358
+ // 移除initData调用
1359
+ // if (treeRef) await treeRef.initData();
1086
1360
  if (!treeRef) {
1087
1361
  this.$Message.error("组织树组件未初始化,请稍后再试");
1088
1362
  item.checked = !item.checked;
@@ -1126,7 +1400,8 @@ export default {
1126
1400
 
1127
1401
  this[proListKey] = [];
1128
1402
  const isCurrentlyChecked = item.checked;
1129
- if (treeRef) await treeRef.initData();
1403
+ // 移除initData调用,避免重置树数据
1404
+ // if (treeRef) await treeRef.initData();
1130
1405
 
1131
1406
  // 2. 清空岗位 Tab 标签选中状态(仅操作 postTagList)
1132
1407
  this.postTagList.forEach(tag => {
@@ -1323,7 +1598,6 @@ export default {
1323
1598
  }
1324
1599
  }
1325
1600
 
1326
- // 最终数据赋值(根据Tab类型区分,核心统一逻辑)
1327
1601
 
1328
1602
  if (matchedNodes.length > 0) {
1329
1603
  // 同步暂存列表(组织proOrgList/岗位proPostList)
@@ -1418,7 +1692,6 @@ export default {
1418
1692
  return obj;
1419
1693
  }
1420
1694
 
1421
- // 检测到循环引用时,保留核心字段(orgUnitId必选,其他字段尽可能保留)
1422
1695
  if (hash.has(obj)) {
1423
1696
  const safeObj = {
1424
1697
  orgUnitId: obj.orgUnitId,
@@ -1536,7 +1809,7 @@ export default {
1536
1809
  if (res.data.code === 1 && res.data.data && res.data.data.orgUnitId) {
1537
1810
  // 深拷贝并清理无效字段
1538
1811
  const node = this.safeDeepCopy(res.data.data);
1539
- // 核心修复:确保节点名称有默认值,避免空显示
1812
+ // 确保节点名称有默认值,避免空显示
1540
1813
  const nodeName = node.orgNodeName || node.orgUnitName || node.name || `未命名组织(${orgUnitId})`;
1541
1814
  node.orgNodeName = nodeName;
1542
1815
  node.orgUnitName = nodeName; // 同步更新orgUnitName,确保所有使用场景都有值
@@ -1835,8 +2108,16 @@ export default {
1835
2108
  }
1836
2109
  }
1837
2110
 
2111
+
1838
2112
  .tab-content-pro {
1839
2113
  .tab {
2114
+ .search-row {
2115
+ display: flex;
2116
+ align-items: center;
2117
+ flex-wrap: nowrap; // 禁止换行
2118
+ width: 100%;
2119
+ gap: 8px; // 文字和搜索框之间的间距
2120
+ }
1840
2121
  .tree {
1841
2122
  // 全屏 使用百分比高度 + 最小高度
1842
2123
  height: calc(100vh - 340px) !important; // 从300px增加到340px,缩减40px高度
@@ -1882,6 +2163,18 @@ export default {
1882
2163
  color:var(--primary-color);
1883
2164
  }
1884
2165
  }
2166
+ // 搜索标签样式(固定宽度,不换行)
2167
+ .search-label {
2168
+ white-space: nowrap; // 文字不换行
2169
+ flex-shrink: 0; // 不被压缩
2170
+ font-size: 14px;
2171
+ color: #333;
2172
+ }
2173
+ // 搜索框容器样式(自适应剩余宽度)
2174
+ .search-input-wrapper {
2175
+ flex: 1; // 占满剩余宽度
2176
+ min-width: 0; // 允许搜索框收缩
2177
+ }
1885
2178
  }
1886
2179
  }
1887
2180
 
@@ -54,13 +54,34 @@ export default {
54
54
  return {
55
55
  data: [],
56
56
  manageUnitId: '',
57
- loading: true
57
+ loading: true,
58
+ // 内部状态存储禁用懒加载的标识
59
+ isDisableLazyLoad: false
58
60
  };
59
61
  },
60
62
  mounted() {
61
- this.initData();
63
+ // 优先使用 props 的 disableLazyLoad,覆盖内部状态
64
+ this.isDisableLazyLoad = this.disableLazyLoad;
65
+ // 优先使用 props 的 isCustomTree,覆盖内部判断
66
+ this.isCustomTree = this.isCustomTree;
67
+ // 仅在未禁用懒加载且非自定义树时执行 initData
68
+ if (!this.isDisableLazyLoad && !this.isCustomTree) {
69
+ this.initData();
70
+ } else {
71
+ // 直接使用父组件传递的树数据
72
+ this.loading = false;
73
+ let tree = deepCopy(this.treeList);
74
+ this.initTree(tree);
75
+ this.data = tree;
76
+ }
77
+
62
78
  },
63
79
  methods: {
80
+ setDisableLazyLoad(disabled) {
81
+ this.isDisableLazyLoad = disabled;
82
+ // 同时标记为自定义树,跳过子组件自身的 initData 逻辑
83
+ this.isCustomTree = disabled;
84
+ },
64
85
  safeDeepCopy(obj, hash = new WeakMap()) {
65
86
  if (obj === null || typeof obj !== 'object') {
66
87
  return obj;
@@ -108,14 +129,15 @@ export default {
108
129
  return copy;
109
130
  },
110
131
  async initData() {
111
- if (this.isCustomTree) {
132
+ // 优先判断内部禁用状态,而非仅依赖 isCustomTree prop
133
+ if (this.isCustomTree || this.isDisableLazyLoad) {
112
134
  this.loading = false;
113
135
  let tree = deepCopy(this.treeList);
114
136
  this.initTree(tree);
115
137
  this.data = tree;
116
138
  return;
117
139
  }
118
- // 仅在非自定义树场景下生效
140
+ // 仅在非自定义/非禁用场景下执行原有逻辑
119
141
  let data = await this.getOrgChildren();
120
142
  this.loading = false;
121
143
  this.data = data;
@@ -179,7 +201,23 @@ export default {
179
201
  },
180
202
 
181
203
  async loadData(item, callback) {
182
- // 自定义树场景(defaultOrgUnitId 不为空):原有逻辑不变
204
+ // 核心修改:即使禁用懒加载,也允许加载已有子节点
205
+ if (this.disableLazyLoad) {
206
+ let children = item.orgChildrenList || item.children || [];
207
+ const formattedChildren = this.safeDeepCopy(children).map(child => ({
208
+ ...child,
209
+ title: child.orgUnitName || child.orgNodeName || child.name || `未命名组织(${child.orgUnitId || child.id || ''})`,
210
+ checked: false,
211
+ expand: false,
212
+ leafNode: child.leafNode || false,
213
+ orgChildrenList: child.orgChildrenList || [],
214
+ children: child.children || []
215
+ }));
216
+ callback(formattedChildren);
217
+ return;
218
+ }
219
+
220
+ // 原有逻辑保持不变
183
221
  if (this.isCustomTree) {
184
222
  let children = item.orgChildrenList || item.children || [];
185
223
  const formattedChildren = this.safeDeepCopy(children).map(child => ({
@@ -201,7 +239,6 @@ export default {
201
239
  });
202
240
  if (res.data.code === 1) {
203
241
  const apiChildren = res.data.data || [];
204
- // 关键:对接口返回的二级节点进行 initTree 初始化
205
242
  const initializedApiChildren = this.initTree(apiChildren);
206
243
  const apiFormattedChildren = initializedApiChildren.map(child => ({
207
244
  ...child,
@@ -225,18 +262,16 @@ export default {
225
262
  return;
226
263
  }
227
264
 
228
- // 非自定义树场景(defaultOrgUnitId 为空):补充子节点初始化
229
- if (this.disableLazyLoad) {
230
- callback([]);
231
- return;
232
- }
233
- // 加载子节点后,先经过 initTree 处理再返回
234
265
  let children = await this.getOrgChildren(item.orgUnitId);
235
266
  const initializedChildren = this.initTree(children);
236
267
  callback(initializedChildren);
237
268
  },
238
269
 
239
270
  getOrgChildren(orgUnitId = '') {
271
+ // 优先判断内部禁用状态
272
+ if (this.isDisableLazyLoad) {
273
+ return Promise.resolve([]);
274
+ }
240
275
  if (this.isCustomTree) {
241
276
  return Promise.resolve([]);
242
277
  }
@@ -517,18 +552,38 @@ export default {
517
552
  'treeList': {
518
553
  handler(val) {
519
554
  // 自定义树场景:直接使用父组件传递的树数据,不初始化旧接口
520
- if (this.isCustomTree) {
521
- let tree = deepCopy(val);
555
+ if (this.isCustomTree || this.isDisableLazyLoad) {
556
+ let tree = this.safeDeepCopy(val);
522
557
  this.initTree(tree);
523
558
  this.data = tree;
524
559
  return;
525
560
  }
526
- // 原有逻辑
527
561
  let tree = deepCopy(val);
528
562
  this.initTree(tree);
529
563
  this.data = tree;
530
564
  },
531
565
  deep: true
566
+ },
567
+ // 监听 isCustomTree 变化
568
+ isCustomTree(newVal) {
569
+ if (newVal) {
570
+ this.isDisableLazyLoad = true;
571
+ this.loading = false;
572
+ let tree = this.safeDeepCopy(this.treeList);
573
+ this.initTree(tree);
574
+ this.data = tree;
575
+ }
576
+ },
577
+ // 监听 disableLazyLoad 变化
578
+ disableLazyLoad(newVal) {
579
+ this.isDisableLazyLoad = newVal;
580
+ if (newVal) {
581
+ this.isCustomTree = true;
582
+ this.loading = false;
583
+ let tree = this.safeDeepCopy(this.treeList);
584
+ this.initTree(tree);
585
+ this.data = tree;
586
+ }
532
587
  }
533
588
  }
534
589
  };
@@ -624,4 +679,4 @@ export default {
624
679
  text-shadow: none !important;
625
680
  background: none !important;
626
681
  }
627
- </style>
682
+ </style>