@sy-common/organize-select-help 1.0.0-beta.4 → 1.0.0-beta.42

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.
@@ -1,158 +1,425 @@
1
1
  <template>
2
2
  <div class="content">
3
3
  <Spin fix v-if="loading"></Spin>
4
- <Tree :data="data" ref="tree" :load-data="loadData" :render="renderContent" check-directly
5
- @on-select-change ="handleChange" multiple></Tree>
4
+ <Tree
5
+ :data="data"
6
+ ref="tree"
7
+ :load-data="loadData"
8
+ :render="renderContent"
9
+ multiple
10
+ :check-strictly="true"
11
+ :cascade-check="false"
12
+ @on-select-change="handleChange"
13
+ ></Tree>
6
14
  </div>
7
15
  </template>
16
+
8
17
  <script>
9
- import ajax from '@lambo-design/shared/utils/ajax'
18
+ import { deepCopy } from '@lambo-design/core/src/utils/assist';
19
+ import ajax from '@lambo-design/shared/utils/ajax';
20
+
10
21
  export default {
11
- props:{
12
- disabled:{
22
+ props: {
23
+ disabled: {
24
+ type: Boolean,
25
+ default: false
26
+ },
27
+ treeList: {
28
+ type: Array,
29
+ default: () => []
30
+ },
31
+ isSingleSelect: {
13
32
  type: Boolean,
14
33
  default: false
15
34
  }
16
35
  },
17
- data(){
36
+ data() {
18
37
  return {
19
- data:[],
20
- manageUnitId:'',
21
- loading:true
22
- }
38
+ data: [],
39
+ manageUnitId: '',
40
+ loading: true
41
+ };
23
42
  },
24
43
  mounted() {
25
- this.initData()
44
+ this.initData();
26
45
  },
27
- methods:{
28
- async initData(){
29
- let data = await this.getOrgChildren()
30
- this.loading = false
46
+ methods: {
47
+ async initData() {
48
+ let data = await this.getOrgChildren();
49
+ this.loading = false;
31
50
  this.data = data;
32
51
  },
33
- handleChange(data){
34
- this.$emit('handleChange',data)
52
+
53
+ handleChange(data) {
54
+ let checkedData = Array.isArray(data)
55
+ ? data.filter(item => item.checked)
56
+ : (data.checked ? [data] : []);
57
+
58
+ // 单选逻辑:仅保留最后一个选中的节点
59
+ if (this.isSingleSelect) {
60
+ checkedData = checkedData.length > 0 ? [checkedData[checkedData.length - 1]] : [];
61
+ // 清空其他节点的选中状态
62
+ this.clearOtherCheckedNodes(checkedData.map(item => item.orgUnitId));
63
+ }
64
+
65
+ this.syncAllNodeCheckedState(checkedData);
66
+ this.$emit('handleChange', checkedData);
67
+ },
68
+ clearOtherCheckedNodes(keepIds) {
69
+ if (!Array.isArray(this.data) || !Array.isArray(keepIds)) return;
70
+
71
+ const clearNodeState = (nodeList) => {
72
+ nodeList.forEach(node => {
73
+ if (!keepIds.includes(node.orgUnitId) && node.checked) {
74
+ this.$set(node, 'checked', false);
75
+ }
76
+ // 递归处理子节点(单选时也需要清空子节点的选中状态)
77
+ const childNodes = node.children || node.orgChildrenList || [];
78
+ if (childNodes.length) {
79
+ clearNodeState(childNodes);
80
+ }
81
+ });
82
+ };
83
+
84
+ clearNodeState(this.data);
85
+ },
86
+
87
+ syncAllNodeCheckedState(checkedData) {
88
+ if (!Array.isArray(this.data) || !Array.isArray(checkedData)) return;
89
+
90
+ const checkedIds = checkedData.map(item => item.orgUnitId);
91
+ const updateNodeState = (nodeList) => {
92
+ nodeList.forEach(node => {
93
+ // 仅更新当前节点,跳过子节点
94
+ const shouldBeChecked = checkedIds.includes(node.orgUnitId);
95
+ if (node.checked !== shouldBeChecked) {
96
+ this.$set(node, 'checked', shouldBeChecked);
97
+ }
98
+ // 彻底删除子节点递归逻辑
99
+ });
100
+ };
101
+ updateNodeState(this.data);
35
102
  },
36
- async loadData(item, callback){
37
- // 模拟异步获取数据
38
- let children = await this.getOrgChildren(item.orgUnitId)
39
- callback(children); // 调用callback传入子节点数据
103
+
104
+ async loadData(item, callback) {
105
+ let children = await this.getOrgChildren(item.orgUnitId);
106
+ callback(children);
40
107
  },
41
- checkNode(data){
42
- // console.log(data,'data')
108
+
109
+ getOrgChildren(orgUnitId = '') {
110
+ return new Promise((resolve, reject) => {
111
+ ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', {
112
+ params: {
113
+ containsCurLevel: true,
114
+ orgUnitId: orgUnitId
115
+ }
116
+ }).then((res) => {
117
+ if (res.data.code === 1) {
118
+ let treeList = res.data.data;
119
+ this.initTree(treeList);
120
+ resolve(treeList);
121
+ } else {
122
+ resolve([]);
123
+ }
124
+ }).catch(err => {
125
+ console.log(err);
126
+ resolve([]);
127
+ });
128
+ });
43
129
  },
44
- getOrgChildren(orgUnitId){
45
- return new Promise((resolve,reject)=>{
46
- ajax.get('/pub-manage-server/pub/personHelpBox/q/getOrgUnitList', { params:{
47
- containsCurLevel:true,
48
- orgUnitId:orgUnitId,
130
+
131
+ setCheckedNodes(targets) {
132
+ if (!this.$refs.tree || !Array.isArray(targets)) {
133
+ this.clearAllChecked(this.data);
134
+ this.$emit('handleChange', []);
135
+ this.$nextTick(() => this.$refs.tree.$forceUpdate());
136
+ return;
137
+ }
138
+
139
+ // 单选逻辑强化:清空所有选中状态
140
+ this.clearAllChecked(this.data);
141
+
142
+ const targetList = this.isSingleSelect
143
+ ? (targets.length > 0 ? [targets[targets.length - 1]] : [])
144
+ : targets;
145
+
146
+ // 转换为有效orgUnitId数组
147
+ const targetIds = targetList.map(item => {
148
+ if (typeof item === 'string') return item.trim();
149
+ return (item.orgUnitId || item.id || '').trim();
150
+ }).filter(id => id); // 过滤空ID
151
+
152
+ // 查找并选中目标节点
153
+ const findAndCheckNode = (treeData, targetId) => {
154
+ for (const node of treeData) {
155
+ const nodeId = (node.orgUnitId || node.id || '').trim();
156
+ if (nodeId === targetId) {
157
+ this.$set(node, 'checked', true);
158
+ this.expandToNode(node);
159
+ return true;
49
160
  }
50
- }).then((res)=>{
51
- if(res.data.code === 1){
52
- let treeList = res.data.data
53
- this.initTree(treeList)
54
- resolve(treeList)
55
- }else{
56
- resolve([])
161
+ const childNodes = node.children || node.orgChildrenList || [];
162
+ if (childNodes.length && findAndCheckNode(childNodes, targetId)) {
163
+ return true;
57
164
  }
58
- }).catch(err=>{
59
- console.log(err)
60
- })
61
- })
62
- },
63
- initTree(treeList){
64
- const defineTree = function(list){
65
- if(!list)return
165
+ }
166
+ return false;
167
+ };
168
+
169
+ targetIds.forEach(id => findAndCheckNode(this.data, id));
170
+
171
+ // 传递过滤后的有效节点
172
+ const checkedNodes = this.collectCurrentCheckedNodes(this.data);
173
+ this.$nextTick(() => {
174
+ this.$refs.tree.$forceUpdate();
175
+ this.$emit('handleChange', checkedNodes);
176
+ });
177
+ },
178
+
179
+ expandToNode(node) {
180
+ let current = node;
181
+ while (current && current.parent) {
182
+ if (typeof current.parent === 'object' && !Array.isArray(current.parent)) {
183
+ this.$set(current.parent, 'expand', true);
184
+ }
185
+ current = current.parent.orgUnitId
186
+ ? this.findNodeInTree(this.data, current.parent.orgUnitId)
187
+ : null;
188
+ }
189
+ },
190
+
191
+ collectAllCheckedNodes(nodeList) {
192
+ let checkedNodes = [];
193
+ nodeList.forEach(node => {
194
+ if (node.checked) {
195
+ checkedNodes.push(node);
196
+ }
197
+ const childNodes = node.children || node.orgChildrenList || [];
198
+ if (childNodes.length) {
199
+ checkedNodes = [...checkedNodes, ...this.collectAllCheckedNodes(childNodes)];
200
+ }
201
+ });
202
+ return checkedNodes;
203
+ },
204
+
205
+ clearAllChecked(treeData) {
206
+ if (!Array.isArray(treeData)) return;
207
+ treeData.forEach(node => {
208
+ if (node.checked) {
209
+ this.$set(node, 'checked', false);
210
+ }
211
+ const childNodes = node.children || node.orgChildrenList || [];
212
+ if (childNodes.length) {
213
+ this.clearAllChecked(childNodes);
214
+ }
215
+ });
216
+ },
217
+
218
+ updateTreeData(newTreeData) {
219
+ if (!Array.isArray(newTreeData)) return;
220
+ const tree = deepCopy(newTreeData);
221
+ this.initTree(tree);
222
+ this.data = tree;
223
+ this.$nextTick(() => {
224
+ this.$refs.tree.$forceUpdate();
225
+ });
226
+ },
227
+
228
+ findNodeInTree(treeData, targetOrgUnitId) {
229
+ if (!treeData || !targetOrgUnitId) return null;
230
+
231
+ for (const node of treeData) {
232
+ if (!node.parent && treeData !== this.data) {
233
+ node.parent = treeData;
234
+ }
235
+
236
+ if (node.orgUnitId === targetOrgUnitId) return node;
237
+
238
+ const childNodes = node.children || node.orgChildrenList || [];
239
+ if (childNodes.length) {
240
+ const childNode = this.findNodeInTree(childNodes, targetOrgUnitId);
241
+ if (childNode) return childNode;
242
+ }
243
+ }
244
+ return null;
245
+ },
246
+
247
+ initTree(treeList) {
248
+ const defineTree = function (list) {
249
+ if (!list) return;
66
250
  list.forEach((item) => {
67
- item.title=item.orgNodeName;
251
+ item.title = item.orgNodeName;
68
252
  item.loading = false;
69
253
  item.children = [];
70
254
  item.expand = false;
71
- item.checked = false;
72
- if(item.leafNode){
255
+ item.checked = false; // 确保checked属性初始化
256
+ if (item.leafNode) {
73
257
  delete item.loading;
74
258
  delete item.children;
75
259
  }
76
- })
77
- return list
78
- }
79
- treeList.forEach(item=>{
80
- item.title=item.orgNodeName;
260
+ if (item.orgChildrenList && item.orgChildrenList.length) {
261
+ item.children = defineTree(item.orgChildrenList);
262
+ item.expand = true;
263
+ }
264
+ });
265
+ return list;
266
+ };
267
+ treeList.forEach(item => {
268
+ item.title = item.orgNodeName;
81
269
  item.loading = false;
82
270
  item.children = [];
83
271
  item.expand = false;
84
- item.checked = false;
85
- if(item.orgChildrenList && item.orgChildrenList.length){
272
+ item.checked = false; // 初始化Checkbox绑定的checked属性
273
+ if (item.orgChildrenList && item.orgChildrenList.length) {
86
274
  item.children = defineTree(item.orgChildrenList);
87
275
  item.expand = true;
88
276
  }
89
- if(this.disabled){
277
+ if (this.disabled) {
90
278
  item.disabled = true;
91
279
  }
92
- if(item.leafNode){
280
+ if (item.leafNode) {
93
281
  delete item.loading;
94
282
  delete item.children;
95
283
  }
96
- })
284
+ });
97
285
  },
98
- renderContent(h, { root, node, data }){
286
+
287
+ //renderContent添加Checkbox组件
288
+ renderContent(h, {root, node, data}) {
99
289
  return h('div', {
100
290
  style: {
101
291
  width: '100%',
102
- overflow:'hidden',
103
- display:'flex',
292
+ overflow: 'hidden',
293
+ display: 'flex',
104
294
  alignItems: 'center',
295
+ cursor: 'pointer'
105
296
  }
106
297
  }, [
107
- h('img', {
108
- attrs: {
109
- src: require('./assets/icon.png'),
110
- },
111
- style: {
112
- marginRight: '8px',
113
- width:'14px',
114
- height:'14px',
115
- }
116
- }),
117
- h('span',{
118
- style: {
119
- overflow: 'hidden',
120
- textOverflow:'ellipsis',
121
- flex:1
122
- },
123
- on:{
124
- click:()=>{
125
- this.checkNode(data)
298
+ h('Checkbox', {
299
+ props: {
300
+ value: data.checked,
301
+ disabled: data.disabled || this.disabled,
302
+ indeterminate: false
303
+ },
304
+ style: {
305
+ marginRight: '8px'
306
+ },
307
+ on: {
308
+ 'on-change': (checked) => {
309
+ this.$set(data, 'checked', checked);
310
+
311
+ // 单选逻辑:勾选当前节点时,清空其他所有节点
312
+ if (this.isSingleSelect && checked) {
313
+ this.clearOtherCheckedNodes([data.orgUnitId]);
126
314
  }
315
+
316
+ // 收集选中节点(单选时仅返回当前节点)
317
+ const checkedNodes = this.isSingleSelect
318
+ ? (checked ? [data] : [])
319
+ : this.collectCurrentCheckedNodes(this.data);
320
+
321
+ this.handleChange(checkedNodes);
127
322
  }
128
- }, data.title)
323
+ }
324
+ }),
325
+ h('img', {
326
+ attrs: { src: require('./assets/icon.png') },
327
+ style: { marginRight: '8px', width: '14px', height: '14px' }
328
+ }),
329
+ h('span', {
330
+ style: { overflow: 'hidden', textOverflow: 'ellipsis', flex: 1 }
331
+ }, data.title)
129
332
  ]);
130
333
  },
131
- upDataTree(){
132
- const unCheck = (list)=>{
133
- list.forEach((item)=>{
134
- this.$set(item, 'selected', false);
135
- if(item.children && item.children.length){
136
- unCheck(item.children)
334
+ collectCurrentCheckedNodes(nodeList) {
335
+ let checkedNodes = [];
336
+ nodeList.forEach(node => {
337
+ if (node.checked) {
338
+ // 强制补全orgUnitId,过滤无效节点
339
+ const nodeId = node.orgUnitId || node.id || '';
340
+ if (nodeId && typeof nodeId === 'string' && nodeId.trim()) {
341
+ const validNode = {
342
+ ...node,
343
+ orgUnitId: nodeId.trim(),
344
+ orgNodeName: node.orgNodeName || node.title || node.name || `未命名组织(${nodeId.trim()})`
345
+ };
346
+ checkedNodes.push(validNode);
137
347
  }
138
- })
139
- }
140
- unCheck(this.data)
348
+ }
349
+ // 递归处理子节点
350
+ const childNodes = node.children || node.orgChildrenList || [];
351
+ if (childNodes.length) {
352
+ checkedNodes = [...checkedNodes, ...this.collectCurrentCheckedNodes(childNodes)];
353
+ }
354
+ });
355
+ return checkedNodes;
356
+ },
357
+ upDataTree() {
358
+ const unCheck = (list) => {
359
+ list.forEach((item) => {
360
+ this.$set(item, 'checked', false);
361
+ });
362
+ };
363
+ unCheck(this.data);
141
364
  }
142
365
  },
143
- }
366
+ watch: {
367
+ 'treeList': {
368
+ handler(val) {
369
+ let tree = deepCopy(val);
370
+ this.initTree(tree);
371
+ this.data = tree;
372
+ },
373
+ deep: true
374
+ }
375
+ }
376
+ };
144
377
  </script>
378
+
145
379
  <style lang="less" scoped>
146
- .content{
380
+ .content {
147
381
  width: 100%;
148
382
  height: 100%;
149
383
  overflow: auto;
150
384
  }
151
- /deep/.ivu-tree ul li{
152
- overflow: hidden;
385
+
386
+ /deep/ .ivu-tree-node,
387
+ /deep/ .ivu-tree-node *,
388
+ /deep/ .ivu-tree-node-content,
389
+ /deep/ .ivu-tree-title {
390
+ box-shadow: none !important;
391
+ text-shadow: none !important;
392
+ outline: none !important;
393
+ border: none !important;
394
+ background: transparent !important;
395
+ }
396
+
397
+ /deep/ .ivu-tree-node-selected,
398
+ /deep/ .ivu-tree-node-selected *,
399
+ /deep/ .ivu-tree-node-focus,
400
+ /deep/ .ivu-tree-node-focus *,
401
+ /deep/ .ivu-tree-node-hover,
402
+ /deep/ .ivu-tree-node-hover * {
403
+ box-shadow: none !important;
404
+ text-shadow: none !important;
405
+ background: transparent !important;
406
+ color: inherit !important;
153
407
  }
154
- /deep/.ivu-tree-title{
155
- width: calc(100% - 20px);
408
+
409
+ /deep/ .ivu-tree-node-content {
410
+ padding-left: 0 !important;
156
411
  }
157
412
 
158
- </style>
413
+ /deep/ .ivu-tree-indent {
414
+ margin-right: 4px;
415
+ }
416
+
417
+ /deep/ .ivu-tree-node::before,
418
+ /deep/ .ivu-tree-node::after,
419
+ /deep/ .ivu-tree-title::before,
420
+ /deep/ .ivu-tree-title::after {
421
+ box-shadow: none !important;
422
+ text-shadow: none !important;
423
+ background: none !important;
424
+ }
425
+ </style>