@sy-common/organize-select-help 1.0.0-beta.26 → 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 +521 -148
- 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
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
|
+
}));
|
|
740
|
+
|
|
741
|
+
// 安全深拷贝,确保数据响应式
|
|
742
|
+
this.proOrgList = this.safeDeepCopy(completeNodes);
|
|
743
|
+
},
|
|
612
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);
|
|
613
765
|
},
|
|
614
|
-
|
|
615
|
-
if (
|
|
616
|
-
this.
|
|
617
|
-
|
|
618
|
-
this
|
|
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,8 +940,8 @@ 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);
|
|
731
945
|
// val 为 true 时表示帮助框打开,此时发起请求
|
|
732
946
|
if (val) {
|
|
733
947
|
this.initStaffList() // 新增初始化方法,统一处理打开后的请求逻辑
|
|
@@ -736,19 +950,38 @@ export default {
|
|
|
736
950
|
this.staffEnding = false;
|
|
737
951
|
this.offset = 0;
|
|
738
952
|
this.staffAllList = [];
|
|
953
|
+
// 关闭时重置选中状态
|
|
954
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
739
955
|
}
|
|
740
956
|
},
|
|
741
957
|
initStaffList() {
|
|
742
958
|
this.staffEnding = false;
|
|
743
959
|
this.offset = 0;
|
|
744
960
|
this.staffAllList = [];
|
|
961
|
+
// 初始化时确保selectedStaffOrgId状态正确
|
|
962
|
+
if (this.tabName === 'staff' && (!this.selectedStaffOrgId || this.selectedStaffOrgId.trim())) {
|
|
963
|
+
this.$set(this, 'selectedStaffOrgId', '');
|
|
964
|
+
}
|
|
745
965
|
this.loadMore(); // 打开帮助框后,再发起第一次请求
|
|
746
966
|
},
|
|
747
967
|
// 处理Tab切换,同步更新tabName
|
|
748
968
|
handleTabChange(tabName) {
|
|
749
969
|
this.tabName = tabName;
|
|
750
|
-
|
|
751
|
-
|
|
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逻辑,不修改
|
|
752
985
|
this.proPostList = [];
|
|
753
986
|
this.$refs.postTree.initData();
|
|
754
987
|
}
|
|
@@ -1099,9 +1332,14 @@ export default {
|
|
|
1099
1332
|
return obj;
|
|
1100
1333
|
}
|
|
1101
1334
|
|
|
1102
|
-
//
|
|
1335
|
+
// 检测到循环引用时,保留核心字段(orgUnitId必选,其他字段尽可能保留)
|
|
1103
1336
|
if (hash.has(obj)) {
|
|
1104
|
-
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
|
+
};
|
|
1105
1343
|
hash.set(obj, safeObj);
|
|
1106
1344
|
return safeObj;
|
|
1107
1345
|
}
|
|
@@ -1118,14 +1356,15 @@ export default {
|
|
|
1118
1356
|
hash.set(obj, copy);
|
|
1119
1357
|
for (let key in obj) {
|
|
1120
1358
|
if (obj.hasOwnProperty(key)) {
|
|
1121
|
-
//
|
|
1122
|
-
if (['
|
|
1359
|
+
// 仅过滤vue内部字段,保留业务字段
|
|
1360
|
+
if (['__vue__', '__ob__', '$parent', '$children'].includes(key)) {
|
|
1123
1361
|
continue;
|
|
1124
1362
|
}
|
|
1125
|
-
//
|
|
1363
|
+
// 子节点数组特殊处理
|
|
1126
1364
|
if (['orgChildrenList', 'children'].includes(key) && Array.isArray(obj[key])) {
|
|
1127
1365
|
copy[key] = obj[key].map(child => this.safeDeepCopy(child, hash));
|
|
1128
1366
|
} else {
|
|
1367
|
+
// 保留所有业务字段,不额外过滤
|
|
1129
1368
|
copy[key] = this.safeDeepCopy(obj[key], hash);
|
|
1130
1369
|
}
|
|
1131
1370
|
}
|
|
@@ -1176,25 +1415,20 @@ export default {
|
|
|
1176
1415
|
return null;
|
|
1177
1416
|
}
|
|
1178
1417
|
|
|
1179
|
-
// 用队列实现广度优先搜索(BFS),避免递归栈溢出
|
|
1180
1418
|
const queue = [...treeData];
|
|
1181
1419
|
while (queue.length > 0) {
|
|
1182
|
-
const currentNode = queue.shift();
|
|
1183
|
-
//
|
|
1184
|
-
|
|
1420
|
+
const currentNode = queue.shift();
|
|
1421
|
+
// 兼容子组件可能的字段映射(orgUnitId可能存储在id字段)
|
|
1422
|
+
const nodeId = currentNode.orgUnitId || currentNode.id || '';
|
|
1423
|
+
if (nodeId === targetOrgUnitId) {
|
|
1185
1424
|
return currentNode;
|
|
1186
1425
|
}
|
|
1187
|
-
//
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
// 兼容子组件可能使用的children字段
|
|
1192
|
-
if (Array.isArray(currentNode.children) && currentNode.children.length > 0 && !currentNode.orgChildrenList) {
|
|
1193
|
-
queue.push(...currentNode.children);
|
|
1426
|
+
// 兼容children和orgChildrenList两种子节点字段
|
|
1427
|
+
const childNodes = currentNode.orgChildrenList || currentNode.children || [];
|
|
1428
|
+
if (childNodes.length > 0) {
|
|
1429
|
+
queue.push(...childNodes);
|
|
1194
1430
|
}
|
|
1195
1431
|
}
|
|
1196
|
-
|
|
1197
|
-
// 遍历完所有节点未找到
|
|
1198
1432
|
return null;
|
|
1199
1433
|
},
|
|
1200
1434
|
|
|
@@ -1316,6 +1550,146 @@ export default {
|
|
|
1316
1550
|
}
|
|
1317
1551
|
</script>
|
|
1318
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
|
+
// 其他原有样式保持不变
|
|
1319
1693
|
.tab.post .left {
|
|
1320
1694
|
width: 200px;
|
|
1321
1695
|
height: 450px !important;
|
|
@@ -1325,38 +1699,35 @@ export default {
|
|
|
1325
1699
|
}
|
|
1326
1700
|
|
|
1327
1701
|
.scroll-container {
|
|
1328
|
-
height: 100% !important;
|
|
1329
|
-
overflow-y: auto !important;
|
|
1702
|
+
height: 100% !important;
|
|
1703
|
+
overflow-y: auto !important;
|
|
1330
1704
|
overflow-x: hidden !important;
|
|
1331
1705
|
padding: 8px 0;
|
|
1332
|
-
/* 消除可能的内边距/外边距影响 */
|
|
1333
1706
|
margin: 0;
|
|
1334
1707
|
box-sizing: border-box;
|
|
1335
1708
|
}
|
|
1336
1709
|
|
|
1337
|
-
/* 3. 强化滚动条样式,确保可见性(兼容webkit浏览器) */
|
|
1338
1710
|
.scroll-container::-webkit-scrollbar {
|
|
1339
|
-
width: 8px !important;
|
|
1711
|
+
width: 8px !important;
|
|
1340
1712
|
height: 8px;
|
|
1341
|
-
display: block !important;
|
|
1713
|
+
display: block !important;
|
|
1342
1714
|
}
|
|
1343
1715
|
|
|
1344
1716
|
.scroll-container::-webkit-scrollbar-thumb {
|
|
1345
|
-
background-color: #ccc !important;
|
|
1717
|
+
background-color: #ccc !important;
|
|
1346
1718
|
border-radius: 4px !important;
|
|
1347
1719
|
transition: background-color 0.2s;
|
|
1348
1720
|
}
|
|
1349
1721
|
|
|
1350
1722
|
.scroll-container::-webkit-scrollbar-thumb:hover {
|
|
1351
|
-
background-color: #999 !important;
|
|
1723
|
+
background-color: #999 !important;
|
|
1352
1724
|
}
|
|
1353
1725
|
|
|
1354
1726
|
.scroll-container::-webkit-scrollbar-track {
|
|
1355
|
-
background-color: #f9f9f9 !important;
|
|
1727
|
+
background-color: #f9f9f9 !important;
|
|
1356
1728
|
border-radius: 4px !important;
|
|
1357
1729
|
}
|
|
1358
1730
|
|
|
1359
|
-
/* 4. 保持position-item原有样式,确保布局正常 */
|
|
1360
1731
|
.position-item {
|
|
1361
1732
|
border: 1px solid #ddd;
|
|
1362
1733
|
margin: 5px 0;
|
|
@@ -1364,13 +1735,12 @@ export default {
|
|
|
1364
1735
|
border-radius: 2px;
|
|
1365
1736
|
cursor: pointer;
|
|
1366
1737
|
transition: background-color 0.2s;
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
overflow:
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
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;
|
|
1374
1744
|
}
|
|
1375
1745
|
|
|
1376
1746
|
.position-item.active {
|
|
@@ -1381,45 +1751,42 @@ export default {
|
|
|
1381
1751
|
.position-item:hover:not(.active) {
|
|
1382
1752
|
background-color: #f5f5f5;
|
|
1383
1753
|
}
|
|
1754
|
+
|
|
1384
1755
|
.custom-select-wrapper {
|
|
1385
1756
|
position: relative;
|
|
1386
1757
|
|
|
1387
|
-
/* 优化清空按钮样式 */
|
|
1388
1758
|
/deep/ .ivu-select-clear {
|
|
1389
|
-
right: 32px;
|
|
1759
|
+
right: 32px;
|
|
1390
1760
|
color: #999;
|
|
1391
1761
|
font-size: 16px;
|
|
1392
|
-
opacity: 1 !important;
|
|
1762
|
+
opacity: 1 !important;
|
|
1393
1763
|
transition: all 0.2s ease;
|
|
1394
1764
|
|
|
1395
1765
|
&:hover {
|
|
1396
|
-
color: #ff4d4f;
|
|
1397
|
-
transform: scale(1.1);
|
|
1766
|
+
color: #ff4d4f;
|
|
1767
|
+
transform: scale(1.1);
|
|
1398
1768
|
}
|
|
1399
1769
|
}
|
|
1400
1770
|
|
|
1401
|
-
/* 调整下拉箭头位置 */
|
|
1402
1771
|
/deep/ .ivu-select-arrow {
|
|
1403
1772
|
right: 12px;
|
|
1404
1773
|
}
|
|
1405
1774
|
|
|
1406
|
-
/* 优化输入框内边距,避免文字被按钮遮挡 */
|
|
1407
1775
|
/deep/ .ivu-select-input {
|
|
1408
1776
|
padding-right: 45px !important;
|
|
1409
1777
|
}
|
|
1410
1778
|
|
|
1411
|
-
/* 选中选项样式 */
|
|
1412
1779
|
/deep/ .active-option {
|
|
1413
1780
|
background-color: #f2f8ff;
|
|
1414
1781
|
color: var(--primary-color);
|
|
1415
1782
|
}
|
|
1416
1783
|
|
|
1417
|
-
/* 无数据选项样式 */
|
|
1418
1784
|
/deep/ .ivu-select-option-disabled {
|
|
1419
1785
|
color: #ccc !important;
|
|
1420
1786
|
background: #f5f5f5 !important;
|
|
1421
1787
|
}
|
|
1422
1788
|
}
|
|
1789
|
+
|
|
1423
1790
|
.tag-select-container {
|
|
1424
1791
|
margin-left: 10px;
|
|
1425
1792
|
|
|
@@ -1439,6 +1806,7 @@ export default {
|
|
|
1439
1806
|
text-overflow: ellipsis;
|
|
1440
1807
|
}
|
|
1441
1808
|
}
|
|
1809
|
+
|
|
1442
1810
|
.modal-tree{
|
|
1443
1811
|
.header-text{
|
|
1444
1812
|
font-weight: bold;
|
|
@@ -1597,10 +1965,15 @@ export default {
|
|
|
1597
1965
|
font-size:18px;
|
|
1598
1966
|
}
|
|
1599
1967
|
}
|
|
1600
|
-
.staff-active{
|
|
1601
|
-
background
|
|
1602
|
-
|
|
1603
|
-
|
|
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);
|
|
1604
1977
|
}
|
|
1605
1978
|
}
|
|
1606
1979
|
}
|