@sy-common/organize-select-help 1.0.0-beta.25 → 1.0.0-beta.29
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 +1 -1
- package/src/index.vue +537 -149
- package/src/organize-tree.vue +241 -180
package/src/index.vue
CHANGED
|
@@ -121,32 +121,54 @@
|
|
|
121
121
|
</div>
|
|
122
122
|
</TabPane>
|
|
123
123
|
<TabPane label="选择人员" name="staff" v-if="name.includes('staff')">
|
|
124
|
-
<div class="tab">
|
|
125
|
-
|
|
126
|
-
<div
|
|
127
|
-
<div class="
|
|
128
|
-
|
|
129
|
-
<
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
124
|
+
<div class="tab staff-left-right-layout">
|
|
125
|
+
<!-- 左侧:组织选择区域(限制高度) -->
|
|
126
|
+
<div class="staff-left-panel">
|
|
127
|
+
<div class="panel-title">组织选择</div>
|
|
128
|
+
<div class="tree staff-org-tree">
|
|
129
|
+
<organizeTree
|
|
130
|
+
@handleChange="getStaffList"
|
|
131
|
+
ref="staffTree"
|
|
132
|
+
:treeList="staffTree"
|
|
133
|
+
:showCheckbox="true"
|
|
134
|
+
:checkStrictly="true"
|
|
135
|
+
:autoExpandParent="true"
|
|
136
|
+
:isSingleSelect="true"
|
|
137
|
+
></organizeTree>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<div class="staff-right-panel">
|
|
142
|
+
<Input v-model="staffSearch" @on-enter="searchStaff" @on-search="searchStaff" search placeholder="搜索人员"/>
|
|
143
|
+
<div style="position:relative;">
|
|
144
|
+
<div class="tree staff-content" @scroll="handleScroll">
|
|
145
|
+
<div :class="['gust-item',item.checked && 'staff-active']"
|
|
146
|
+
v-for="(item, index) in staffAllList"
|
|
147
|
+
:key="`staff_${index}_${item.id}`"
|
|
148
|
+
@click="handlestaff(item)">
|
|
149
|
+
<Checkbox
|
|
150
|
+
v-model="item.checked"
|
|
151
|
+
class="staff-checkbox"
|
|
152
|
+
@click.stop="() => handlestaff(item)"
|
|
153
|
+
></Checkbox>
|
|
154
|
+
<div class="left-panel">{{item.name && item.name.slice(0,1) || ''}}</div>
|
|
155
|
+
<div class="right-panel">
|
|
156
|
+
<p>{{item.name}}</p>
|
|
157
|
+
<p>{{item.orgNodeName || item.orgUnitName}}</p>
|
|
158
|
+
</div>
|
|
159
|
+
<!-- <div class="checked-icon" v-show="item.checked">✔</div>-->
|
|
160
|
+
</div>
|
|
161
|
+
<p v-if="staffEnding" style="color:#CCCCCC;text-align: center">---我也是有底线的---</p>
|
|
137
162
|
</div>
|
|
138
|
-
<
|
|
163
|
+
<Spin v-if="loadingStaff" size="large" fix />
|
|
164
|
+
</div>
|
|
165
|
+
<div class="bottom-select">
|
|
166
|
+
<div>当前已选择 <span class="num">{{getCheckedStaff}}</span>人</div>
|
|
167
|
+
<Button type="primary" icon="md-add" @click="addStaffList">添加人员</Button>
|
|
139
168
|
</div>
|
|
140
|
-
<p v-if="staffEnding" style="color:#CCCCCC;text-align: center">---我也是有底线的---</p>
|
|
141
169
|
</div>
|
|
142
|
-
<Spin v-if="loadingStaff" size="large" fix />
|
|
143
|
-
</div>
|
|
144
|
-
<div class="bottom-select">
|
|
145
|
-
<div>当前已选择 <span class="num">{{getCheckedStaff}}</span>人</div>
|
|
146
|
-
<Button type="primary" icon="md-add" @click="addStaffList">添加人员</Button>
|
|
147
170
|
</div>
|
|
148
|
-
|
|
149
|
-
</TabPane>
|
|
171
|
+
</TabPane>
|
|
150
172
|
</Tabs>
|
|
151
173
|
</div>
|
|
152
174
|
<div class="form-content">
|
|
@@ -264,14 +286,69 @@ export default {
|
|
|
264
286
|
selectedPositionId: null, // 新增:岗位单选的选中状态存储
|
|
265
287
|
selectedOrgTagKey: '', // 存储选中标签的唯一标识
|
|
266
288
|
selectedPostTagKey: '', // 存储选中标签的唯一标识
|
|
289
|
+
//人员选择
|
|
290
|
+
staffTree:[],
|
|
291
|
+
staffTagList:[],
|
|
292
|
+
staffOrgList:[],
|
|
293
|
+
staffSearchList:[],
|
|
294
|
+
selectedStaffOrgId: '', // 新增:选中的组织节点ID
|
|
295
|
+
proStaffOrgList: [] // 新增:暂存选中的组织节点
|
|
267
296
|
}
|
|
268
297
|
},
|
|
269
298
|
mounted() {
|
|
270
299
|
this.queryTagList()
|
|
271
300
|
this.queryPositionList()
|
|
272
|
-
this.loadMore()
|
|
301
|
+
// this.loadMore()
|
|
302
|
+
this.initStaffOrgTree()
|
|
273
303
|
},
|
|
274
304
|
methods:{
|
|
305
|
+
async initStaffOrgTree() {
|
|
306
|
+
try {
|
|
307
|
+
// 关键修复:初始化时重置选中状态
|
|
308
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
309
|
+
this.proStaffOrgList = [];
|
|
310
|
+
|
|
311
|
+
const rootOrgId = this.defaultOrgUnitId || '';
|
|
312
|
+
let rootNode = null;
|
|
313
|
+
|
|
314
|
+
if (rootOrgId) {
|
|
315
|
+
const leafNode = await this.judgeNodeLeafe(rootOrgId);
|
|
316
|
+
const orgDetail = await this.queryOrgNodeDetail(rootOrgId);
|
|
317
|
+
rootNode = this.safeDeepCopy({
|
|
318
|
+
...orgDetail,
|
|
319
|
+
orgNodeName: orgDetail.orgNodeName || orgDetail.name,
|
|
320
|
+
leafNode,
|
|
321
|
+
expand: true,
|
|
322
|
+
parentOrgUnitId: orgDetail.parentOrgUnitId || orgDetail.parentId
|
|
323
|
+
});
|
|
324
|
+
} else {
|
|
325
|
+
const res = await ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
|
|
326
|
+
params: { containsCurLevel: true }
|
|
327
|
+
});
|
|
328
|
+
if (res.data.code === 1) {
|
|
329
|
+
rootNode = res.data.data[0] || null;
|
|
330
|
+
if (rootNode) {
|
|
331
|
+
rootNode.expand = true;
|
|
332
|
+
rootNode.parentOrgUnitId = rootNode.parentId;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (rootNode) {
|
|
338
|
+
let parentsList = await this.getParentOrgNodesByOrgUnitId(rootNode.orgUnitId);
|
|
339
|
+
const safeParents = this.safeDeepCopy(parentsList);
|
|
340
|
+
safeParents.forEach(node => {
|
|
341
|
+
node.expand = true;
|
|
342
|
+
node.parentOrgUnitId = node.parentId;
|
|
343
|
+
});
|
|
344
|
+
const tree = this.buildTree([...safeParents, rootNode]);
|
|
345
|
+
this.staffTree = this.safeDeepCopy(tree);
|
|
346
|
+
}
|
|
347
|
+
} catch (e) {
|
|
348
|
+
this.$Message.error("人员选择组织树初始化失败!");
|
|
349
|
+
console.error(e);
|
|
350
|
+
}
|
|
351
|
+
},
|
|
275
352
|
handlePostTagSelect(quickPickKey) {
|
|
276
353
|
// 清空暂存列表
|
|
277
354
|
this.proPostList = [];
|
|
@@ -490,6 +567,30 @@ export default {
|
|
|
490
567
|
this.$Message.error("获取组织节点列表失败!");
|
|
491
568
|
}
|
|
492
569
|
},
|
|
570
|
+
async getStaffOption(val) {
|
|
571
|
+
this.staffOrgList = [];
|
|
572
|
+
if(!val) return this.$refs.staffTree.initData();
|
|
573
|
+
let item = this.staffSearchList.filter((item)=> item.orgUnitId === val).shift();
|
|
574
|
+
if (!item) return;
|
|
575
|
+
|
|
576
|
+
const leafNode = await this.judgeNodeLeafe(item.orgUnitId);
|
|
577
|
+
const ftem = this.safeDeepCopy({
|
|
578
|
+
...item,
|
|
579
|
+
orgNodeName: item.name,
|
|
580
|
+
parentOrgUnitId: item.parentId,
|
|
581
|
+
leafNode: leafNode
|
|
582
|
+
});
|
|
583
|
+
|
|
584
|
+
try{
|
|
585
|
+
let parentsList = await this.getParentOrgNodesByOrgUnitId(val);
|
|
586
|
+
// 对父节点列表进行安全拷贝
|
|
587
|
+
const safeParents = this.safeDeepCopy(parentsList);
|
|
588
|
+
let tree = this.buildTree([...safeParents, ftem]);
|
|
589
|
+
this.staffTree = this.safeDeepCopy(tree);
|
|
590
|
+
}catch(e){
|
|
591
|
+
this.$Message.error("获取组织节点列表失败!");
|
|
592
|
+
}
|
|
593
|
+
},
|
|
493
594
|
getParentOrgNodesByOrgUnitId(val){
|
|
494
595
|
return new Promise((resolve,reject)=>{
|
|
495
596
|
ajax.get('/pub-manage-server/pub/personHelpBox/q/getParentOrgNodesByOrgUnitId?orgUnitId='+val).then((res)=>{
|
|
@@ -552,28 +653,44 @@ export default {
|
|
|
552
653
|
|
|
553
654
|
searchStaff(){
|
|
554
655
|
this.staffEnding = false;
|
|
555
|
-
this.offset = 0
|
|
556
|
-
this.staffAllList = []
|
|
557
|
-
|
|
656
|
+
this.offset = 0;
|
|
657
|
+
this.staffAllList = [];
|
|
658
|
+
// 关键修复:50ms延迟,解决极端情况下的异步更新问题
|
|
659
|
+
setTimeout(() => {
|
|
660
|
+
this.loadMore();
|
|
661
|
+
}, 50);
|
|
558
662
|
},
|
|
559
|
-
queryAllStaffList(){
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
663
|
+
queryAllStaffList() {
|
|
664
|
+
const params = {
|
|
665
|
+
search: this.staffSearch,
|
|
666
|
+
offset: this.offset,
|
|
667
|
+
limit: 10
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// 关键优化:实时监测选中状态,未选中时显式传递空字符串(而非不传递)
|
|
671
|
+
if (this.selectedStaffOrgId && typeof this.selectedStaffOrgId === 'string' && this.selectedStaffOrgId.trim()) {
|
|
672
|
+
params.orgUnitId = this.selectedStaffOrgId.trim();
|
|
673
|
+
} else {
|
|
674
|
+
// 未选中任何节点时,显式设置orgUnitId为空字符串
|
|
675
|
+
params.orgUnitId = '';
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// 调试日志:查看最终传递的参数
|
|
679
|
+
console.log('人员查询接口参数:', params);
|
|
680
|
+
|
|
681
|
+
return new Promise((resolve, reject) => {
|
|
682
|
+
ajax.get('/pub-manage-server/pub/personHelpBox/q/queryAllStaffList', {
|
|
683
|
+
params: params
|
|
684
|
+
}).then((res) => {
|
|
685
|
+
if (res.data.code === 1) {
|
|
686
|
+
resolve(res.data.data);
|
|
687
|
+
} else {
|
|
688
|
+
reject(false);
|
|
689
|
+
}
|
|
690
|
+
}).catch((err) => {
|
|
691
|
+
reject(err);
|
|
692
|
+
});
|
|
693
|
+
});
|
|
577
694
|
},
|
|
578
695
|
handleScroll(e){
|
|
579
696
|
const { scrollTop, clientHeight, scrollHeight } = e.target;
|
|
@@ -603,45 +720,135 @@ export default {
|
|
|
603
720
|
console.log(e)
|
|
604
721
|
}
|
|
605
722
|
},
|
|
606
|
-
getOrgList(data){
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
723
|
+
getOrgList(data) {
|
|
724
|
+
// 过滤有效节点:仅要求orgUnitId(orgNodeName可选,用默认值兜底)
|
|
725
|
+
const validNodes = Array.isArray(data)
|
|
726
|
+
? data.filter(node => node.orgUnitId) // 仅校验orgUnitId(必选)
|
|
727
|
+
: [];
|
|
728
|
+
|
|
729
|
+
// 去重:基于orgUnitId避免重复
|
|
730
|
+
const uniqueNodes = validNodes.filter((node, index, self) =>
|
|
731
|
+
self.findIndex(item => item.orgUnitId === node.orgUnitId) === index
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
// 补全缺失字段,避免后续处理报错
|
|
735
|
+
const completeNodes = uniqueNodes.map(node => ({
|
|
736
|
+
...node,
|
|
737
|
+
orgNodeName: node.orgNodeName || node.name || `未命名组织(${node.orgUnitId})`,
|
|
738
|
+
orgUnitName: node.orgNodeName || node.name || `未命名组织(${node.orgUnitId})`
|
|
739
|
+
}));
|
|
612
740
|
|
|
741
|
+
// 安全深拷贝,确保数据响应式
|
|
742
|
+
this.proOrgList = this.safeDeepCopy(completeNodes);
|
|
613
743
|
},
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
744
|
+
|
|
745
|
+
getPostList(data) {
|
|
746
|
+
// 过滤有效节点:仅要求orgUnitId
|
|
747
|
+
const validNodes = Array.isArray(data)
|
|
748
|
+
? data.filter(node => node.orgUnitId)
|
|
749
|
+
: [];
|
|
750
|
+
|
|
751
|
+
// 去重:基于orgUnitId
|
|
752
|
+
const uniqueNodes = validNodes.filter((node, index, self) =>
|
|
753
|
+
self.findIndex(item => item.orgUnitId === node.orgUnitId) === index
|
|
754
|
+
);
|
|
755
|
+
|
|
756
|
+
// 补全缺失字段
|
|
757
|
+
const completeNodes = uniqueNodes.map(node => ({
|
|
758
|
+
...node,
|
|
759
|
+
orgNodeName: node.orgNodeName || node.name || `未命名组织(${node.orgUnitId})`,
|
|
760
|
+
orgUnitName: node.orgNodeName || node.name || `未命名组织(${node.orgUnitId})`
|
|
761
|
+
}));
|
|
762
|
+
|
|
763
|
+
// 覆盖暂存列表(而非concat,避免累积无效数据)
|
|
764
|
+
this.proPostList = this.safeDeepCopy(completeNodes);
|
|
765
|
+
},
|
|
766
|
+
getStaffList(data) {
|
|
767
|
+
if (!Array.isArray(data) || data.length === 0) {
|
|
768
|
+
this.proStaffOrgList = [];
|
|
769
|
+
// 强制清空并触发响应式更新
|
|
770
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
771
|
+
// 立即触发搜索,确保orgUnitId参数实时更新为空
|
|
772
|
+
this.$nextTick(() => this.searchStaff());
|
|
773
|
+
return;
|
|
619
774
|
}
|
|
775
|
+
|
|
776
|
+
// 关键修复1:过滤仅含有效orgUnitId的节点,排除无效数据
|
|
777
|
+
const validNodes = data.filter(node =>
|
|
778
|
+
node.orgUnitId && typeof node.orgUnitId === 'string' // 确保orgUnitId存在且为字符串
|
|
779
|
+
);
|
|
780
|
+
|
|
781
|
+
if (validNodes.length === 0) {
|
|
782
|
+
this.$Message.warning("所选节点无效,请重新选择");
|
|
783
|
+
this.proStaffOrgList = [];
|
|
784
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
785
|
+
// 立即触发搜索,更新参数为空
|
|
786
|
+
this.$nextTick(() => this.searchStaff());
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// 关键修复2:单选逻辑强化,仅保留最后一个有效选中节点
|
|
791
|
+
const currentNode = validNodes[validNodes.length - 1];
|
|
792
|
+
const currentOrgUnitId = currentNode.orgUnitId.trim(); // 去除空格,避免无效字符串
|
|
793
|
+
|
|
794
|
+
// 补全节点字段,确保orgUnitId绝对存在
|
|
795
|
+
const pureNode = this.safeDeepCopy({
|
|
796
|
+
...currentNode,
|
|
797
|
+
orgNodeName: currentNode.orgNodeName || currentNode.name || `未命名组织(${currentOrgUnitId})`,
|
|
798
|
+
orgUnitName: currentNode.orgNodeName || currentNode.name || `未命名组织(${currentOrgUnitId})`
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
// 清除子节点引用,避免循环引用导致的更新延迟
|
|
802
|
+
if (pureNode.orgChildrenList) pureNode.orgChildrenList = [];
|
|
803
|
+
if (pureNode.children) pureNode.children = [];
|
|
804
|
+
|
|
805
|
+
// 关键修复3:强制响应式更新,避免Vue数据延迟
|
|
806
|
+
this.$set(this, 'proStaffOrgList', [pureNode]);
|
|
807
|
+
this.$set(this, 'selectedStaffOrgId', currentOrgUnitId);
|
|
808
|
+
|
|
809
|
+
// 关键修复4:双重nextTick确保数据完全更新后再查询
|
|
810
|
+
this.$nextTick(() => {
|
|
811
|
+
if (this.selectedStaffOrgId !== currentOrgUnitId) {
|
|
812
|
+
this.$set(this, 'selectedStaffOrgId', currentOrgUnitId);
|
|
813
|
+
this.$nextTick(() => this.searchStaff());
|
|
814
|
+
} else {
|
|
815
|
+
this.searchStaff();
|
|
816
|
+
}
|
|
817
|
+
console.log('人员选择-当前选中orgUnitId:', this.selectedStaffOrgId); // 调试日志
|
|
818
|
+
});
|
|
620
819
|
},
|
|
820
|
+
|
|
621
821
|
addOrgList() {
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
822
|
+
// 过滤空节点(仅校验orgUnitId)
|
|
823
|
+
const validOrgList = this.proOrgList.filter(node => node.orgUnitId);
|
|
824
|
+
if (!validOrgList.length) return this.$Message.error("请先选择组织节点!");
|
|
825
|
+
|
|
826
|
+
let proOrgList = deepCopy(validOrgList);
|
|
827
|
+
proOrgList.forEach(item => {
|
|
828
|
+
// 用补全后的orgNodeName,避免空显示
|
|
829
|
+
item.title = this.includeLevelOrg.includes('01')
|
|
830
|
+
? `${item.orgNodeName}(包含下级组织节点)`
|
|
831
|
+
: item.orgNodeName;
|
|
832
|
+
item.id = this.includeLevelOrg.includes('01')
|
|
833
|
+
? (`01-${item.orgUnitId}`)
|
|
834
|
+
: (`00-${item.orgUnitId}`);
|
|
835
|
+
item.includeLevel = this.includeLevelOrg.includes('01');
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
// 去重合并
|
|
839
|
+
let list = this.orgList.concat(proOrgList);
|
|
630
840
|
let uniqueArray = list.filter((item, index, self) =>
|
|
631
|
-
|
|
632
|
-
t.id === item.id // 基于id属性去重
|
|
633
|
-
))
|
|
841
|
+
index === self.findIndex(t => t.id === item.id)
|
|
634
842
|
);
|
|
635
|
-
this.orgList = uniqueArray
|
|
843
|
+
this.orgList = uniqueArray;
|
|
636
844
|
|
|
637
|
-
//
|
|
845
|
+
// 清空选中状态
|
|
638
846
|
if (this.$refs.orgTree && this.$refs.orgTree.clearAllChecked) {
|
|
639
847
|
this.$refs.orgTree.clearAllChecked(this.$refs.orgTree.data);
|
|
640
|
-
this.$refs.orgTree.$emit('handleChange', []);
|
|
848
|
+
this.$refs.orgTree.$emit('handleChange', []);
|
|
641
849
|
}
|
|
642
|
-
|
|
643
|
-
this
|
|
644
|
-
this.proOrgList = []
|
|
850
|
+
this.$refs.orgTree.upDataTree();
|
|
851
|
+
this.proOrgList = [];
|
|
645
852
|
},
|
|
646
853
|
clearGroup(){
|
|
647
854
|
this.orgList = []
|
|
@@ -655,39 +862,42 @@ export default {
|
|
|
655
862
|
this.selectedPositionId = item.positionId
|
|
656
863
|
},
|
|
657
864
|
addPostList() {
|
|
658
|
-
|
|
659
|
-
|
|
865
|
+
// 过滤空节点
|
|
866
|
+
const validPostList = this.proPostList.filter(node => node.orgUnitId);
|
|
867
|
+
if (!validPostList.length) return this.$Message.error("请选择组织节点!");
|
|
868
|
+
|
|
660
869
|
let checkedPosition = this.positiontList.find(item => item.positionId === this.selectedPositionId);
|
|
661
|
-
if(!checkedPosition){return this.$Message.error("
|
|
662
|
-
|
|
663
|
-
let totalList = []
|
|
664
|
-
|
|
870
|
+
if (!checkedPosition) { return this.$Message.error("请选择岗位!"); }
|
|
871
|
+
|
|
872
|
+
let totalList = [];
|
|
873
|
+
validPostList.forEach(item => {
|
|
665
874
|
totalList.push({
|
|
666
875
|
...item,
|
|
667
876
|
...checkedPosition,
|
|
668
|
-
title
|
|
669
|
-
includeLevel:this.includeLevelPost.includes('01'),
|
|
670
|
-
id:this.includeLevelPost.includes('01')
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
877
|
+
title: `${this.includeLevelPost.length ? (item.orgNodeName + '(包含下级组织节点)') : item.orgNodeName}`,
|
|
878
|
+
includeLevel: this.includeLevelPost.includes('01'),
|
|
879
|
+
id: this.includeLevelPost.includes('01')
|
|
880
|
+
? (`01-${checkedPosition.positionId}-${item.orgUnitId}`)
|
|
881
|
+
: (`00-${checkedPosition.positionId}-${item.orgUnitId}`),
|
|
882
|
+
});
|
|
883
|
+
});
|
|
884
|
+
|
|
885
|
+
// 去重合并
|
|
886
|
+
let list = this.postList.concat(totalList);
|
|
674
887
|
let uniqueArray = list.filter((item, index, self) =>
|
|
675
|
-
|
|
676
|
-
t.id === item.id // 基于id属性去重
|
|
677
|
-
))
|
|
888
|
+
index === self.findIndex(t => t.id === item.id)
|
|
678
889
|
);
|
|
679
|
-
this.postList = uniqueArray
|
|
890
|
+
this.postList = uniqueArray;
|
|
680
891
|
|
|
681
|
-
//
|
|
892
|
+
// 清空选中状态
|
|
682
893
|
if (this.$refs.postTree && this.$refs.postTree.clearAllChecked) {
|
|
683
894
|
this.$refs.postTree.clearAllChecked(this.$refs.postTree.data);
|
|
684
|
-
this.$refs.postTree.$emit('handleChange', []);
|
|
895
|
+
this.$refs.postTree.$emit('handleChange', []);
|
|
685
896
|
}
|
|
686
|
-
|
|
687
|
-
this
|
|
688
|
-
this.
|
|
689
|
-
this.
|
|
690
|
-
this.$refs.postTree.initData()
|
|
897
|
+
this.$refs.postTree.upDataTree();
|
|
898
|
+
this.proPostList = [];
|
|
899
|
+
this.selectedPositionId = null;
|
|
900
|
+
// this.$refs.postTree.initData();
|
|
691
901
|
this.selectedPostTagKey = '';
|
|
692
902
|
},
|
|
693
903
|
clearPost(){
|
|
@@ -699,14 +909,18 @@ export default {
|
|
|
699
909
|
//staff
|
|
700
910
|
addStaffList(){
|
|
701
911
|
let staffList = this.staffAllList.filter((item)=>item.checked===true);
|
|
912
|
+
if (!staffList.length) {
|
|
913
|
+
this.$Message.error("请选择人员");
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
702
916
|
// 关键优化:基于item.id去重,不修改原数据字段,仅过滤重复项
|
|
703
917
|
let uniqueStaffList = staffList.filter(newItem =>
|
|
704
918
|
// 检查右侧条件区域(staffList)是否已有该人员,避免重复添加
|
|
705
919
|
!this.staffList.some(existItem => existItem.userId === newItem.userId)
|
|
706
920
|
);
|
|
707
|
-
//
|
|
921
|
+
// 合并去重后的列表
|
|
708
922
|
this.staffList = this.staffList.concat(uniqueStaffList);
|
|
709
|
-
//
|
|
923
|
+
// 清空选中状态
|
|
710
924
|
this.staffAllList.forEach(item => item.checked = false);
|
|
711
925
|
},
|
|
712
926
|
handlestaff(item){
|
|
@@ -726,14 +940,48 @@ export default {
|
|
|
726
940
|
}
|
|
727
941
|
this.$emit('confirm',deepCopy(v))
|
|
728
942
|
},
|
|
729
|
-
visibleChange(val){
|
|
730
|
-
this.$emit('input',val);
|
|
943
|
+
visibleChange(val) {
|
|
944
|
+
this.$emit('input', val);
|
|
945
|
+
// val 为 true 时表示帮助框打开,此时发起请求
|
|
946
|
+
if (val) {
|
|
947
|
+
this.initStaffList() // 新增初始化方法,统一处理打开后的请求逻辑
|
|
948
|
+
} else {
|
|
949
|
+
// 可选:关闭帮助框时重置人员列表相关状态,避免下次打开残留旧数据
|
|
950
|
+
this.staffEnding = false;
|
|
951
|
+
this.offset = 0;
|
|
952
|
+
this.staffAllList = [];
|
|
953
|
+
// 关闭时重置选中状态
|
|
954
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
955
|
+
}
|
|
956
|
+
},
|
|
957
|
+
initStaffList() {
|
|
958
|
+
this.staffEnding = false;
|
|
959
|
+
this.offset = 0;
|
|
960
|
+
this.staffAllList = [];
|
|
961
|
+
// 初始化时确保selectedStaffOrgId状态正确
|
|
962
|
+
if (this.tabName === 'staff' && (!this.selectedStaffOrgId || this.selectedStaffOrgId.trim())) {
|
|
963
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
964
|
+
}
|
|
965
|
+
this.loadMore(); // 打开帮助框后,再发起第一次请求
|
|
731
966
|
},
|
|
732
967
|
// 处理Tab切换,同步更新tabName
|
|
733
968
|
handleTabChange(tabName) {
|
|
734
969
|
this.tabName = tabName;
|
|
735
|
-
|
|
736
|
-
|
|
970
|
+
|
|
971
|
+
// 仅修改人员Tab相关逻辑,不影响其他Tab
|
|
972
|
+
if (tabName === 'staff') {
|
|
973
|
+
// 重置人员选择相关状态
|
|
974
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
975
|
+
this.proStaffOrgList = [];
|
|
976
|
+
// 清空树组件选中状态
|
|
977
|
+
if (this.$refs.staffTree) {
|
|
978
|
+
this.$refs.staffTree.clearAllChecked(this.$refs.staffTree.data);
|
|
979
|
+
this.$refs.staffTree.$emit('handleChange', []);
|
|
980
|
+
}
|
|
981
|
+
// 切换到人员tab时,立即触发一次搜索,确保orgUnitId参数正确
|
|
982
|
+
this.$nextTick(() => this.searchStaff());
|
|
983
|
+
} else if (tabName === 'post' && this.$refs.postTree && this.proPostList.length === 0) {
|
|
984
|
+
// 保留原有岗位Tab逻辑,不修改
|
|
737
985
|
this.proPostList = [];
|
|
738
986
|
this.$refs.postTree.initData();
|
|
739
987
|
}
|
|
@@ -1084,9 +1332,14 @@ export default {
|
|
|
1084
1332
|
return obj;
|
|
1085
1333
|
}
|
|
1086
1334
|
|
|
1087
|
-
//
|
|
1335
|
+
// 检测到循环引用时,保留核心字段(orgUnitId必选,其他字段尽可能保留)
|
|
1088
1336
|
if (hash.has(obj)) {
|
|
1089
|
-
const safeObj = {
|
|
1337
|
+
const safeObj = {
|
|
1338
|
+
orgUnitId: obj.orgUnitId,
|
|
1339
|
+
orgNodeName: obj.orgNodeName || obj.name || `未命名组织(${obj.orgUnitId || 'unknown'})`,
|
|
1340
|
+
orgUnitName: obj.orgUnitName || obj.orgNodeName || obj.name || `未命名组织(${obj.orgUnitId || 'unknown'})`,
|
|
1341
|
+
parentOrgUnitId: obj.parentOrgUnitId || obj.parentId || null
|
|
1342
|
+
};
|
|
1090
1343
|
hash.set(obj, safeObj);
|
|
1091
1344
|
return safeObj;
|
|
1092
1345
|
}
|
|
@@ -1103,14 +1356,15 @@ export default {
|
|
|
1103
1356
|
hash.set(obj, copy);
|
|
1104
1357
|
for (let key in obj) {
|
|
1105
1358
|
if (obj.hasOwnProperty(key)) {
|
|
1106
|
-
//
|
|
1107
|
-
if (['
|
|
1359
|
+
// 仅过滤vue内部字段,保留业务字段
|
|
1360
|
+
if (['__vue__', '__ob__', '$parent', '$children'].includes(key)) {
|
|
1108
1361
|
continue;
|
|
1109
1362
|
}
|
|
1110
|
-
//
|
|
1363
|
+
// 子节点数组特殊处理
|
|
1111
1364
|
if (['orgChildrenList', 'children'].includes(key) && Array.isArray(obj[key])) {
|
|
1112
1365
|
copy[key] = obj[key].map(child => this.safeDeepCopy(child, hash));
|
|
1113
1366
|
} else {
|
|
1367
|
+
// 保留所有业务字段,不额外过滤
|
|
1114
1368
|
copy[key] = this.safeDeepCopy(obj[key], hash);
|
|
1115
1369
|
}
|
|
1116
1370
|
}
|
|
@@ -1161,25 +1415,20 @@ export default {
|
|
|
1161
1415
|
return null;
|
|
1162
1416
|
}
|
|
1163
1417
|
|
|
1164
|
-
// 用队列实现广度优先搜索(BFS),避免递归栈溢出
|
|
1165
1418
|
const queue = [...treeData];
|
|
1166
1419
|
while (queue.length > 0) {
|
|
1167
|
-
const currentNode = queue.shift();
|
|
1168
|
-
//
|
|
1169
|
-
|
|
1420
|
+
const currentNode = queue.shift();
|
|
1421
|
+
// 兼容子组件可能的字段映射(orgUnitId可能存储在id字段)
|
|
1422
|
+
const nodeId = currentNode.orgUnitId || currentNode.id || '';
|
|
1423
|
+
if (nodeId === targetOrgUnitId) {
|
|
1170
1424
|
return currentNode;
|
|
1171
1425
|
}
|
|
1172
|
-
//
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
// 兼容子组件可能使用的children字段
|
|
1177
|
-
if (Array.isArray(currentNode.children) && currentNode.children.length > 0 && !currentNode.orgChildrenList) {
|
|
1178
|
-
queue.push(...currentNode.children);
|
|
1426
|
+
// 兼容children和orgChildrenList两种子节点字段
|
|
1427
|
+
const childNodes = currentNode.orgChildrenList || currentNode.children || [];
|
|
1428
|
+
if (childNodes.length > 0) {
|
|
1429
|
+
queue.push(...childNodes);
|
|
1179
1430
|
}
|
|
1180
1431
|
}
|
|
1181
|
-
|
|
1182
|
-
// 遍历完所有节点未找到
|
|
1183
1432
|
return null;
|
|
1184
1433
|
},
|
|
1185
1434
|
|
|
@@ -1301,6 +1550,146 @@ export default {
|
|
|
1301
1550
|
}
|
|
1302
1551
|
</script>
|
|
1303
1552
|
<style lang="less" scoped>
|
|
1553
|
+
// 新增checkbox样式
|
|
1554
|
+
.staff-checkbox {
|
|
1555
|
+
margin-right: 12px;
|
|
1556
|
+
flex-shrink: 0;
|
|
1557
|
+
|
|
1558
|
+
/deep/ .ivu-checkbox-wrapper {
|
|
1559
|
+
display: flex;
|
|
1560
|
+
align-items: center;
|
|
1561
|
+
cursor: pointer;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
/deep/ .ivu-checkbox {
|
|
1565
|
+
width: 18px;
|
|
1566
|
+
height: 18px;
|
|
1567
|
+
|
|
1568
|
+
&:checked {
|
|
1569
|
+
/deep/ .ivu-checkbox-inner {
|
|
1570
|
+
background-color: var(--primary-color);
|
|
1571
|
+
border-color: var(--primary-color);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
.staff-left-right-layout {
|
|
1577
|
+
display: flex;
|
|
1578
|
+
height: 600px;
|
|
1579
|
+
gap: 15px;
|
|
1580
|
+
padding: 0 5px;
|
|
1581
|
+
width: 100%;
|
|
1582
|
+
box-sizing: border-box;
|
|
1583
|
+
|
|
1584
|
+
.staff-left-panel {
|
|
1585
|
+
min-width: 300px;
|
|
1586
|
+
max-width: 350px;
|
|
1587
|
+
width: 320px;
|
|
1588
|
+
display: flex;
|
|
1589
|
+
flex-direction: column;
|
|
1590
|
+
box-sizing: border-box;
|
|
1591
|
+
flex-shrink: 0;
|
|
1592
|
+
|
|
1593
|
+
.panel-title {
|
|
1594
|
+
font-weight: 600;
|
|
1595
|
+
font-size: 15px;
|
|
1596
|
+
color: #1f2937;
|
|
1597
|
+
margin-bottom: 10px;
|
|
1598
|
+
height: 28px;
|
|
1599
|
+
display: flex;
|
|
1600
|
+
align-items: center;
|
|
1601
|
+
position: relative;
|
|
1602
|
+
padding-left: 18px; // 内边距同步加宽2px,保持视觉平衡
|
|
1603
|
+
// 调整竖线宽度为6px,更醒目且仍符合整体简约风格
|
|
1604
|
+
&::before {
|
|
1605
|
+
content: '';
|
|
1606
|
+
position: absolute;
|
|
1607
|
+
left: 0;
|
|
1608
|
+
top: 50%;
|
|
1609
|
+
transform: translateY(-50%);
|
|
1610
|
+
width: 6px; // 从3px调整为6px,加宽竖线
|
|
1611
|
+
height: 18px; // 高度同步微调至18px,比例更协调
|
|
1612
|
+
background-color: var(--primary-color);
|
|
1613
|
+
border-radius: 3px; // 圆角保持3px,视觉更柔和
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
.staff-org-tree {
|
|
1618
|
+
height: calc(100% - 38px) !important; // 对应title高度+margin-bottom调整
|
|
1619
|
+
overflow: auto;
|
|
1620
|
+
border: 1px solid #EAECF0;
|
|
1621
|
+
border-radius: 4px;
|
|
1622
|
+
padding: 8px;
|
|
1623
|
+
box-sizing: border-box;
|
|
1624
|
+
// 保持原有树节点样式
|
|
1625
|
+
/deep/ .ivu-tree-node-content {
|
|
1626
|
+
white-space: normal !important;
|
|
1627
|
+
line-height: 1.4;
|
|
1628
|
+
padding: 4px 0;
|
|
1629
|
+
}
|
|
1630
|
+
/deep/ .ivu-tree-node {
|
|
1631
|
+
padding-left: 4px !important;
|
|
1632
|
+
}
|
|
1633
|
+
/deep/ .ivu-tree-child-tree {
|
|
1634
|
+
padding-left: 16px !important;
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
.staff-right-panel {
|
|
1640
|
+
flex: 1 !important;
|
|
1641
|
+
min-width: 350px;
|
|
1642
|
+
width: calc(100% - 335px) !important;
|
|
1643
|
+
display: flex;
|
|
1644
|
+
flex-direction: column;
|
|
1645
|
+
box-sizing: border-box;
|
|
1646
|
+
gap: 8px;
|
|
1647
|
+
padding: 0 5px;
|
|
1648
|
+
flex-shrink: 0;
|
|
1649
|
+
|
|
1650
|
+
// 其他右侧样式保持不变...
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
// 其他原有样式保持不变
|
|
1655
|
+
/deep/ .ivu-tree {
|
|
1656
|
+
width: 100% !important;
|
|
1657
|
+
box-sizing: border-box;
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
/deep/ .ivu-tree-node-content {
|
|
1661
|
+
width: 100% !important;
|
|
1662
|
+
box-sizing: border-box;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
.gust-item {
|
|
1666
|
+
display: flex;
|
|
1667
|
+
align-items: center;
|
|
1668
|
+
width: 100% !important;
|
|
1669
|
+
padding: 12px 12px;
|
|
1670
|
+
margin-top: 8px;
|
|
1671
|
+
cursor: pointer;
|
|
1672
|
+
box-sizing: border-box;
|
|
1673
|
+
border: none !important; // 强制移除默认边框
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
// 恢复滚动条样式(确保滚动可见)
|
|
1677
|
+
.staff-content::-webkit-scrollbar {
|
|
1678
|
+
width: 8px !important;
|
|
1679
|
+
height: 8px;
|
|
1680
|
+
display: block !important;
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
.staff-content::-webkit-scrollbar-thumb {
|
|
1684
|
+
background-color: #ccc !important;
|
|
1685
|
+
border-radius: 4px !important;
|
|
1686
|
+
}
|
|
1687
|
+
|
|
1688
|
+
.staff-content::-webkit-scrollbar-track {
|
|
1689
|
+
background-color: #f9f9f9 !important;
|
|
1690
|
+
}
|
|
1691
|
+
|
|
1692
|
+
// 其他原有样式保持不变
|
|
1304
1693
|
.tab.post .left {
|
|
1305
1694
|
width: 200px;
|
|
1306
1695
|
height: 450px !important;
|
|
@@ -1310,38 +1699,35 @@ export default {
|
|
|
1310
1699
|
}
|
|
1311
1700
|
|
|
1312
1701
|
.scroll-container {
|
|
1313
|
-
height: 100% !important;
|
|
1314
|
-
overflow-y: auto !important;
|
|
1702
|
+
height: 100% !important;
|
|
1703
|
+
overflow-y: auto !important;
|
|
1315
1704
|
overflow-x: hidden !important;
|
|
1316
1705
|
padding: 8px 0;
|
|
1317
|
-
/* 消除可能的内边距/外边距影响 */
|
|
1318
1706
|
margin: 0;
|
|
1319
1707
|
box-sizing: border-box;
|
|
1320
1708
|
}
|
|
1321
1709
|
|
|
1322
|
-
/* 3. 强化滚动条样式,确保可见性(兼容webkit浏览器) */
|
|
1323
1710
|
.scroll-container::-webkit-scrollbar {
|
|
1324
|
-
width: 8px !important;
|
|
1711
|
+
width: 8px !important;
|
|
1325
1712
|
height: 8px;
|
|
1326
|
-
display: block !important;
|
|
1713
|
+
display: block !important;
|
|
1327
1714
|
}
|
|
1328
1715
|
|
|
1329
1716
|
.scroll-container::-webkit-scrollbar-thumb {
|
|
1330
|
-
background-color: #ccc !important;
|
|
1717
|
+
background-color: #ccc !important;
|
|
1331
1718
|
border-radius: 4px !important;
|
|
1332
1719
|
transition: background-color 0.2s;
|
|
1333
1720
|
}
|
|
1334
1721
|
|
|
1335
1722
|
.scroll-container::-webkit-scrollbar-thumb:hover {
|
|
1336
|
-
background-color: #999 !important;
|
|
1723
|
+
background-color: #999 !important;
|
|
1337
1724
|
}
|
|
1338
1725
|
|
|
1339
1726
|
.scroll-container::-webkit-scrollbar-track {
|
|
1340
|
-
background-color: #f9f9f9 !important;
|
|
1727
|
+
background-color: #f9f9f9 !important;
|
|
1341
1728
|
border-radius: 4px !important;
|
|
1342
1729
|
}
|
|
1343
1730
|
|
|
1344
|
-
/* 4. 保持position-item原有样式,确保布局正常 */
|
|
1345
1731
|
.position-item {
|
|
1346
1732
|
border: 1px solid #ddd;
|
|
1347
1733
|
margin: 5px 0;
|
|
@@ -1349,13 +1735,12 @@ export default {
|
|
|
1349
1735
|
border-radius: 2px;
|
|
1350
1736
|
cursor: pointer;
|
|
1351
1737
|
transition: background-color 0.2s;
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
overflow:
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
word-wrap: break-word; /* 兼容长英文/数字,强制换行(防止横向溢出) */
|
|
1738
|
+
white-space: normal !important;
|
|
1739
|
+
overflow: visible !important;
|
|
1740
|
+
text-overflow: clip !important;
|
|
1741
|
+
line-height: 1.4;
|
|
1742
|
+
min-height: 40px;
|
|
1743
|
+
word-wrap: break-word;
|
|
1359
1744
|
}
|
|
1360
1745
|
|
|
1361
1746
|
.position-item.active {
|
|
@@ -1366,45 +1751,42 @@ export default {
|
|
|
1366
1751
|
.position-item:hover:not(.active) {
|
|
1367
1752
|
background-color: #f5f5f5;
|
|
1368
1753
|
}
|
|
1754
|
+
|
|
1369
1755
|
.custom-select-wrapper {
|
|
1370
1756
|
position: relative;
|
|
1371
1757
|
|
|
1372
|
-
/* 优化清空按钮样式 */
|
|
1373
1758
|
/deep/ .ivu-select-clear {
|
|
1374
|
-
right: 32px;
|
|
1759
|
+
right: 32px;
|
|
1375
1760
|
color: #999;
|
|
1376
1761
|
font-size: 16px;
|
|
1377
|
-
opacity: 1 !important;
|
|
1762
|
+
opacity: 1 !important;
|
|
1378
1763
|
transition: all 0.2s ease;
|
|
1379
1764
|
|
|
1380
1765
|
&:hover {
|
|
1381
|
-
color: #ff4d4f;
|
|
1382
|
-
transform: scale(1.1);
|
|
1766
|
+
color: #ff4d4f;
|
|
1767
|
+
transform: scale(1.1);
|
|
1383
1768
|
}
|
|
1384
1769
|
}
|
|
1385
1770
|
|
|
1386
|
-
/* 调整下拉箭头位置 */
|
|
1387
1771
|
/deep/ .ivu-select-arrow {
|
|
1388
1772
|
right: 12px;
|
|
1389
1773
|
}
|
|
1390
1774
|
|
|
1391
|
-
/* 优化输入框内边距,避免文字被按钮遮挡 */
|
|
1392
1775
|
/deep/ .ivu-select-input {
|
|
1393
1776
|
padding-right: 45px !important;
|
|
1394
1777
|
}
|
|
1395
1778
|
|
|
1396
|
-
/* 选中选项样式 */
|
|
1397
1779
|
/deep/ .active-option {
|
|
1398
1780
|
background-color: #f2f8ff;
|
|
1399
1781
|
color: var(--primary-color);
|
|
1400
1782
|
}
|
|
1401
1783
|
|
|
1402
|
-
/* 无数据选项样式 */
|
|
1403
1784
|
/deep/ .ivu-select-option-disabled {
|
|
1404
1785
|
color: #ccc !important;
|
|
1405
1786
|
background: #f5f5f5 !important;
|
|
1406
1787
|
}
|
|
1407
1788
|
}
|
|
1789
|
+
|
|
1408
1790
|
.tag-select-container {
|
|
1409
1791
|
margin-left: 10px;
|
|
1410
1792
|
|
|
@@ -1424,6 +1806,7 @@ export default {
|
|
|
1424
1806
|
text-overflow: ellipsis;
|
|
1425
1807
|
}
|
|
1426
1808
|
}
|
|
1809
|
+
|
|
1427
1810
|
.modal-tree{
|
|
1428
1811
|
.header-text{
|
|
1429
1812
|
font-weight: bold;
|
|
@@ -1582,10 +1965,15 @@ export default {
|
|
|
1582
1965
|
font-size:18px;
|
|
1583
1966
|
}
|
|
1584
1967
|
}
|
|
1585
|
-
.staff-active{
|
|
1586
|
-
background
|
|
1587
|
-
|
|
1588
|
-
|
|
1968
|
+
.staff-active {
|
|
1969
|
+
background: transparent !important; // 彻底移除背景色
|
|
1970
|
+
border: none !important; // 彻底移除边框高亮
|
|
1971
|
+
border-radius: 0 !important; // 移除圆角
|
|
1972
|
+
|
|
1973
|
+
> .right-panel > p:first-child {
|
|
1974
|
+
color: inherit !important; // 可选:也移除文字颜色变化,仅保留Checkbox选中
|
|
1975
|
+
// 如果需要保留文字变色,删除上面这行,保留下面注释的行
|
|
1976
|
+
// color: var(--primary-color);
|
|
1589
1977
|
}
|
|
1590
1978
|
}
|
|
1591
1979
|
}
|