ocpview-plus 1.3.15 → 1.3.17

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.
Files changed (213) hide show
  1. package/README.md +55 -43
  2. package/dist/ocpviewplus.min.esm.js +574 -482
  3. package/dist/ocpviewplus.min.js +9 -9
  4. package/dist/style.css +1 -1
  5. package/dist/styles/efviewplus.css +1 -1
  6. package/package.json +146 -146
  7. package/src/components/base/ContractPrintMixins.js +30 -30
  8. package/src/components/base/controlbase.vue +190 -190
  9. package/src/components/base/controlbox.vue +102 -102
  10. package/src/components/base/index.js +2 -2
  11. package/src/components/base/load.js +19 -19
  12. package/src/components/base/probase.js +220 -220
  13. package/src/components/base/size.js +78 -78
  14. package/src/components/billbox/billbox.vue +67 -67
  15. package/src/components/billbox/index.js +1 -1
  16. package/src/components/cascaderbox/cascaderbox.vue +184 -184
  17. package/src/components/cascaderbox/index.js +2 -2
  18. package/src/components/checkbox/checkbox.vue +75 -75
  19. package/src/components/checkbox/checkgroupbox.vue +103 -103
  20. package/src/components/checkbox/index.js +2 -2
  21. package/src/components/colorbox/colorbox.vue +43 -43
  22. package/src/components/colorbox/index.js +1 -1
  23. package/src/components/combobox/combobox.vue +219 -219
  24. package/src/components/combobox/index.js +1 -1
  25. package/src/components/conditionbox/conditionbase.vue +194 -194
  26. package/src/components/conditionbox/conditionbox.vue +62 -62
  27. package/src/components/conditionbox/conditionfilterbox.vue +479 -479
  28. package/src/components/conditionbox/conditionselectorbox.vue +237 -237
  29. package/src/components/conditionbox/index.js +4 -4
  30. package/src/components/conditionbox/queryconditionbox.vue +25 -25
  31. package/src/components/conditionbox/queryconditionboxbase.vue +123 -123
  32. package/src/components/conditionbox/searchconditionbox.vue +113 -113
  33. package/src/components/conditionbox/searchgrid.vue +391 -391
  34. package/src/components/datebox/DateBoxV1.vue +22 -22
  35. package/src/components/datebox/datebox.vue +129 -129
  36. package/src/components/datebox/daterangebox.vue +154 -154
  37. package/src/components/datebox/index.js +5 -5
  38. package/src/components/form/baseform.vue +676 -676
  39. package/src/components/form/detailsbox.vue +487 -487
  40. package/src/components/form/formbox.vue +28 -28
  41. package/src/components/form/formcardbox.vue +267 -267
  42. package/src/components/form/formcardbox2.vue +228 -228
  43. package/src/components/form/formcardgroupbox.vue +251 -251
  44. package/src/components/form/formcompro.js +18 -18
  45. package/src/components/form/formdetail.vue +128 -128
  46. package/src/components/form/formdetailtwo.vue +302 -302
  47. package/src/components/form/index.js +9 -9
  48. package/src/components/form/toolanchor.js +45 -45
  49. package/src/components/form/workform.vue +167 -167
  50. package/src/components/grid/basegrid.vue +1062 -1062
  51. package/src/components/grid/editgrid.vue +51 -51
  52. package/src/components/grid/editgridbase.vue +1062 -1062
  53. package/src/components/grid/editgridcard.vue +193 -193
  54. package/src/components/grid/expandrow.vue +137 -137
  55. package/src/components/grid/index.js +5 -5
  56. package/src/components/grid/viewgrid.vue +121 -121
  57. package/src/components/grid/viewgridbase.vue +1286 -1286
  58. package/src/components/icon/common-icon.vue +53 -53
  59. package/src/components/icon/eicon.vue +28 -28
  60. package/src/components/icon/icons.vue +42 -42
  61. package/src/components/icon/index.js +1 -1
  62. package/src/components/label/index.js +2 -2
  63. package/src/components/label/showtext.vue +94 -94
  64. package/src/components/load/loadcartoon.vue +227 -227
  65. package/src/components/map/index.js +1 -1
  66. package/src/components/map/mapbox.vue +348 -348
  67. package/src/components/masterplate/RewriteBillListDetails/BillInfoPanel.vue +184 -184
  68. package/src/components/masterplate/RewriteBillListDetails/BillInfoPanelEditTable.vue +838 -838
  69. package/src/components/masterplate/RewriteBillListDetails/BillInfoPanelEditTableControlbox.vue +126 -126
  70. package/src/components/masterplate/RewriteBillListDetails/BillInfoPanelEditTableControlboxNumberbox.vue +27 -27
  71. package/src/components/masterplate/RewriteBillListDetails/BillListPanel.vue +126 -126
  72. package/src/components/masterplate/RewriteBillListDetails/BillListPanelQueryBar.vue +280 -280
  73. package/src/components/masterplate/RewriteBillListDetails/BillListPanelTable.vue +346 -346
  74. package/src/components/masterplate/RewriteBillListDetails/index.vue +325 -325
  75. package/src/components/masterplate/RewriteBillListDetails/mixins/useVxeGridEditTypeKeydownEventHook.js +251 -251
  76. package/src/components/masterplate/RewriteListdetails/BillListPanelV2.vue +115 -115
  77. package/src/components/masterplate/RewriteListdetails/BillListPanelV2QueryBar.vue +24 -24
  78. package/src/components/masterplate/RewriteListdetails/BillListPanelV3.vue +121 -121
  79. package/src/components/masterplate/RewriteListdetails/BillListPanelV3QueryBar.vue +275 -275
  80. package/src/components/masterplate/RewriteListdetails/indexV2.vue +320 -320
  81. package/src/components/masterplate/RewriteListdetails/indexV3.vue +331 -331
  82. package/src/components/masterplate/appendix.vue +586 -586
  83. package/src/components/masterplate/approval.vue +863 -863
  84. package/src/components/masterplate/base.vue +1028 -1028
  85. package/src/components/masterplate/billasyncimport.vue +614 -614
  86. package/src/components/masterplate/billconditionbox.vue +223 -223
  87. package/src/components/masterplate/billconditionsbox.vue +427 -427
  88. package/src/components/masterplate/billdetailform.vue +1028 -1028
  89. package/src/components/masterplate/billimport.vue +301 -301
  90. package/src/components/masterplate/billquerygrid.vue +391 -391
  91. package/src/components/masterplate/billsinglegrid.vue +234 -234
  92. package/src/components/masterplate/birtreport.vue +185 -185
  93. package/src/components/masterplate/contractappendix.vue +688 -688
  94. package/src/components/masterplate/detailbtntoolbar.vue +311 -311
  95. package/src/components/masterplate/detailsbox.vue +386 -386
  96. package/src/components/masterplate/editgridcard.vue +292 -292
  97. package/src/components/masterplate/editgridcard2.vue +127 -127
  98. package/src/components/masterplate/formcard.vue +105 -105
  99. package/src/components/masterplate/formcardgroupbox.vue +167 -167
  100. package/src/components/masterplate/formdetailtwo.vue +366 -366
  101. package/src/components/masterplate/gridcolset.vue +226 -226
  102. package/src/components/masterplate/index.js +54 -54
  103. package/src/components/masterplate/layouttemplate.vue +51 -51
  104. package/src/components/masterplate/leftlistrightdetails.vue +581 -581
  105. package/src/components/masterplate/leftlistrightlist.vue +464 -464
  106. package/src/components/masterplate/lefttreerightdetails.vue +636 -636
  107. package/src/components/masterplate/levelreport.vue +510 -510
  108. package/src/components/masterplate/listbtntoolbar.vue +276 -276
  109. package/src/components/masterplate/listdetails.vue +768 -768
  110. package/src/components/masterplate/operlog.vue +272 -272
  111. package/src/components/masterplate/options.vue +110 -110
  112. package/src/components/masterplate/page.vue +102 -102
  113. package/src/components/masterplate/promptmessage.vue +73 -73
  114. package/src/components/masterplate/querybar.vue +490 -490
  115. package/src/components/masterplate/report.vue +357 -357
  116. package/src/components/masterplate/rowbtntoolbar.vue +126 -126
  117. package/src/components/masterplate/simpletree.vue +137 -137
  118. package/src/components/masterplate/simpleviewgrid.vue +144 -144
  119. package/src/components/mychart/bar/bar.vue +201 -201
  120. package/src/components/mychart/basechart.vue +190 -190
  121. package/src/components/mychart/complexmychart/barline.vue +153 -153
  122. package/src/components/mychart/gauge/gauge.vue +82 -82
  123. package/src/components/mychart/index.js +8 -8
  124. package/src/components/mychart/line/line.vue +201 -201
  125. package/src/components/mychart/liquidfill/liquidfill.vue +108 -108
  126. package/src/components/mychart/pie/pie.vue +95 -95
  127. package/src/components/mychart/radar/radar.vue +121 -121
  128. package/src/components/mychart/scatter/scatter.vue +75 -75
  129. package/src/components/numberbox/NumberBoxV1.vue +39 -39
  130. package/src/components/numberbox/append.js +11 -11
  131. package/src/components/numberbox/index.js +4 -4
  132. package/src/components/numberbox/numberbox.vue +302 -302
  133. package/src/components/numberbox/numberrangebox.vue +422 -422
  134. package/src/components/picturebox/filebox.vue +369 -369
  135. package/src/components/picturebox/index.js +2 -2
  136. package/src/components/picturebox/picturebox.vue +541 -541
  137. package/src/components/picturebox/uploadbox.vue +164 -164
  138. package/src/components/poptagbox/index.js +1 -1
  139. package/src/components/poptagbox/poptagbox.vue +388 -388
  140. package/src/components/poptextbox/index.js +1 -1
  141. package/src/components/poptextbox/poptextbox.vue +624 -624
  142. package/src/components/radiobox/index.js +1 -1
  143. package/src/components/radiobox/radiogroupbox.vue +75 -75
  144. package/src/components/richtextbox/editor.vue +150 -150
  145. package/src/components/richtextbox/index.js +1 -1
  146. package/src/components/richtextbox/richtextbox.vue +448 -448
  147. package/src/components/textbox/index.js +1 -1
  148. package/src/components/textbox/textbox.vue +97 -97
  149. package/src/components/timebox/index.js +1 -1
  150. package/src/components/timebox/timebox.vue +75 -75
  151. package/src/components/toolbar/ebutton.vue +169 -169
  152. package/src/components/toolbar/index.js +3 -3
  153. package/src/components/toolbar/toolbar.vue +445 -445
  154. package/src/components/tree/CompatTree.vue +297 -297
  155. package/src/components/tree/basetree.vue +1098 -1098
  156. package/src/components/tree/index.js +2 -2
  157. package/src/components/tree/treedata.vue +53 -53
  158. package/src/components/tree/treedatabase.vue +189 -189
  159. package/src/components/upload/billimport.vue +233 -233
  160. package/src/components/upload/index.js +1 -1
  161. package/src/components/videobox/index.js +1 -1
  162. package/src/components/videobox/uploadbox.vue +148 -148
  163. package/src/components/videobox/videobox.vue +503 -503
  164. package/src/components/wrichtextbox/editor.vue +219 -219
  165. package/src/components/wrichtextbox/index.js +1 -1
  166. package/src/components/wrichtextbox/wrichtextbox.vue +62 -62
  167. package/src/index.js +231 -231
  168. package/src/locale/format.js +51 -51
  169. package/src/locale/index.js +63 -63
  170. package/src/locale/lang/zh-CN.js +123 -123
  171. package/src/locale/lang/zh-TW.js +114 -114
  172. package/src/locale/lang/zh-UG.js +115 -115
  173. package/src/locale/lang.js +15 -15
  174. package/src/method/case/case.js +1274 -1274
  175. package/src/method/config/queryconfig.js +24 -24
  176. package/src/method/const/const.js +815 -815
  177. package/src/method/index.js +7 -7
  178. package/src/plugins/theme/theme-variable.css +114 -114
  179. package/src/plugins/vxeTable/index.js +241 -241
  180. package/src/plugins/vxeTable/renderer/components/TableFilterInput.vue +51 -51
  181. package/src/plugins/vxeTable/renderer/filter.js +32 -32
  182. package/src/static/excel/exportexcel.js +626 -626
  183. package/src/static/iview/coustom.js +462 -462
  184. package/src/store/index.js +18 -18
  185. package/src/store/modules/app.js +53 -53
  186. package/src/styles/README.md +3 -3
  187. package/src/styles/common.less +80 -80
  188. package/src/styles/components/anchor.less +74 -74
  189. package/src/styles/components/approval.less +135 -135
  190. package/src/styles/components/button.less +208 -208
  191. package/src/styles/components/card.less +51 -51
  192. package/src/styles/components/content.less +38 -38
  193. package/src/styles/components/font.less +313 -313
  194. package/src/styles/components/form.less +71 -71
  195. package/src/styles/components/iconfont/fonts/iconfont.less +1384 -1384
  196. package/src/styles/components/iconfont/fonts/iconfont.svg +703 -703
  197. package/src/styles/components/index.less +16 -16
  198. package/src/styles/components/input.less +290 -290
  199. package/src/styles/components/modal.less +203 -203
  200. package/src/styles/components/page.less +340 -340
  201. package/src/styles/components/select.less +361 -361
  202. package/src/styles/components/steps.less +367 -367
  203. package/src/styles/components/table.less +544 -544
  204. package/src/styles/components/tabs.less +249 -249
  205. package/src/styles/components/upload.less +82 -82
  206. package/src/styles/custom.less +67 -67
  207. package/src/styles/index.less +6 -6
  208. package/src/styles/pack.less +6 -6
  209. package/src/utils/EfuMessenger.js +155 -155
  210. package/src/utils/assist.js +353 -353
  211. package/src/utils/index.js +1 -1
  212. package/src/utils/random_str.js +10 -10
  213. package/src/components/masterplate/detailgridbox.vue +0 -386
@@ -1,1098 +1,1098 @@
1
- <script>
2
- import size from '@/components/base/size';
3
- import { resolveComponent } from 'vue';
4
- export default {
5
- mixins: [size],
6
- name:'baseTree',
7
- data () {
8
- return {
9
- globalConfig: {
10
- emptyText: '暂无数据',
11
- multiSelect: false,
12
- resources: '',
13
- method: '',
14
- response: '',
15
- selectkey: '',
16
- idField:'',
17
- parentField:'',
18
- idClass:'',
19
- searchParam: null,
20
- readOnly: false,
21
- showIcon:false,
22
- keepExpand:false,
23
- expandData:[],
24
- showIconList:[],
25
- showCheckBox: false,
26
- showRootNode:false,
27
- showTitle:true,
28
- expand:true,
29
- rootNode:{},
30
- setNodeDisabled:'',
31
- bordered:true,
32
- disHover:false,
33
- selectedRoot:false,
34
- className:'efutre-tree-node'
35
- },
36
- myConfig: {
37
-
38
- },
39
- gridConfig:{
40
-
41
- },
42
- showCondition:true,
43
- data:[],
44
- oldData:[],
45
- selectedData:[],
46
- conditionSearchParam:{},
47
- searchBeforeSearchParam:{},
48
- rootNode:{},
49
- showTree:true,
50
- showGrid:false,
51
- extraHeight:0,
52
- outsideHeight:0,
53
- treeData:[],
54
- asyncLoad:false,
55
- _autoExpandId: '',
56
-
57
- };
58
- },
59
- created () {
60
- this.init();
61
- },
62
- props:{
63
- config: {
64
- type: Object,
65
- default: () => {
66
- return {};
67
- }
68
- },
69
- dictData: {
70
- type: Object,
71
- default:null
72
- }
73
- },
74
- methods:{
75
- init() {
76
- //获取初期默认值
77
- this.myConfig = Object.assign({}, this.globalConfig, this.myConfig);
78
-
79
- //获取配置
80
- if (this.config) {
81
- this.myConfig = Object.assign({}, this.myConfig, this.config);
82
- }
83
-
84
- let rootCode = '0';
85
- let rootName = '根节点';
86
- if (this.myConfig.showRootNode) {
87
- if (this.myConfig.rootNode !== undefined && this.myConfig.rootNode.code !== undefined) {
88
- rootCode = this.myConfig.rootNode.code;
89
- }
90
- if (this.myConfig.rootNode !== undefined && this.myConfig.rootNode.name !== undefined) {
91
- rootName = this.myConfig.rootNode.name;
92
- }
93
- }
94
- if (this.myConfig.responseId === undefined) {
95
- this.myConfig.responseId = this.myConfig.responseCode;
96
- }
97
- this.rootNode[this.myConfig.idField] = rootCode + '';
98
- this.rootNode[this.myConfig.responseId] = rootCode + '';
99
- this.rootNode[this.myConfig.responseCode] = rootCode + '';
100
- this.rootNode[this.myConfig.responseName] = rootName;
101
- if (this.myConfig.idClass !== undefined) {
102
- this.rootNode[this.myConfig.idClass] = 0;
103
- }
104
- //多选 才允许出现复选框
105
- if (this.myConfig.multiSelect !== true) {
106
- this.myConfig.showCheckBox = false;
107
- }
108
- this.setSizeConfig(this.myConfig);
109
-
110
- if (this.myConfig.asyncLoad) {
111
- this.asyncLoad = true;
112
- }
113
- //特定化处理
114
- if (this.customInit) {
115
- this.customInit();
116
- }
117
-
118
- },
119
- setIcon(data) {
120
- let nodeClass = data[this.myConfig.idClass];
121
- if (!nodeClass) {
122
- nodeClass = 0;
123
- } else {
124
- nodeClass = Number(nodeClass);
125
- }
126
- if (!this.myConfig.showRootNode) {
127
- if (nodeClass && nodeClass !== 0) {
128
- nodeClass = nodeClass - 1;
129
- }
130
- }
131
- if (nodeClass >= this.myConfig.showIconList.length) {
132
- nodeClass = this.myConfig.showIconList.length - 1;
133
- }
134
-
135
- const icon = this.myConfig.showIconList[nodeClass];
136
- data.icon = icon.type;
137
- if (icon.size) {
138
- data.iconSize = icon.size;
139
- }
140
- if (icon.color) {
141
- data.iconColor = icon.color;
142
- }
143
- return data;
144
- },
145
- iconRender(h, params) {
146
-
147
- let icon = params.data.icon
148
- let size = params.data.iconSize
149
- let color = params.data.iconColor
150
-
151
- const hasChildren =
152
- params.data.children &&
153
- params.data.children.length > 0
154
-
155
- if (!icon) {
156
- if (hasChildren) {
157
- icon = params.data.expand
158
- ? '_base_mulu'
159
- : '_base_close_mulu'
160
- } else {
161
- icon = '_base_wenjian'
162
- }
163
- }
164
-
165
- if (!size) {
166
- size = 14
167
- }
168
-
169
- let para = {
170
- type: icon,
171
- size,
172
- color
173
- }
174
-
175
- if (this.myConfig.setTreeNodeIcon) {
176
- para = this.myConfig.setTreeNodeIcon(params, para)
177
- } else if (this.setTreeNodeIcon) {
178
- para = this.setTreeNodeIcon(params, para)
179
- }
180
-
181
- // 处理自定义 iconfont
182
- if (para.type && para.type.startsWith('_')) {
183
- const resultIcon =
184
- 'iconfont icon-' + para.type.substring(1)
185
-
186
- para.custom = resultIcon
187
- delete para.type
188
- }
189
-
190
- let nodeClass = 'efuture-treenode'
191
-
192
- if (this.myConfig.setNodeClass) {
193
- nodeClass = this.myConfig.setNodeClass(params)
194
- }
195
-
196
- return h(
197
- 'div',
198
- {
199
- class: { [nodeClass]: true },
200
- style: {
201
- display: 'flex',
202
- userSelect: 'none'
203
- },
204
- onDblclick: () => {
205
- this.$nextTick(() => {
206
- this.setExpend(params.data)
207
- })
208
- this.$emit('dbclick', params.data)
209
- }
210
- },
211
- [
212
- h(
213
- 'div',
214
- {
215
- style: { paddingLeft: '5px' }
216
- },
217
- [
218
- h(resolveComponent('Icon'), para)
219
- ]
220
- ),
221
-
222
- h(resolveComponent('ShowText'), {
223
- label: params.data.title,
224
- contentAlign: 'left'
225
- })
226
- ]
227
- )
228
- },
229
- iconRenderOld(h,params) {
230
- let icon = params.data.icon;
231
- let size = params.data.iconSize;
232
- let color = params.data.iconColor;
233
- if (!icon) {
234
- if (params.node && params.node.children && params.node.children.length > 0) {
235
- if (params.data.expand) {
236
- icon = '_base_mulu';
237
- } else {
238
- icon = '_base_close_mulu';
239
- }
240
-
241
- } else {
242
- icon = '_base_wenjian';
243
- }
244
- }
245
- if (!size) {
246
- size = 14;
247
- }
248
- let para = {
249
- type:icon,
250
- size:size,
251
- color:color
252
- }
253
- if (this.myConfig.setTreeNodeIcon) {
254
- para = this.myConfig.setTreeNodeIcon(params,para);
255
- } else if (this.setTreeNodeIcon) {
256
- para = this.setTreeNodeIcon(params,para);
257
- }
258
- if (para.type.indexOf('_') === 0) {
259
- let resulIcon = para.type.substring(1,para.type.length);
260
- resulIcon = 'iconfont icon-' + resulIcon;
261
- para.custom = resulIcon;
262
- delete para.type;
263
- }
264
- let nodeClass = 'efuture-treenode';
265
- if (this.myConfig.setNodeClass) {
266
- nodeClass =this.myConfig.setNodeClass(params)
267
- }
268
- let classstyle = {};
269
- classstyle[nodeClass] = true;
270
- return h(
271
- 'div',
272
- {
273
- style: {
274
- display: 'flex',
275
- userSelect: 'none'
276
- },
277
- class:classstyle,
278
- onDblclick:() => {
279
- this.$nextTick(() => {
280
- this.setExpend(params.data);
281
- });
282
- this.$emit('dbclick', params.data);
283
- }
284
- },
285
- [
286
- h(
287
- 'div',
288
- {
289
- style: {
290
- 'padding-left':'5px'
291
- }
292
- },
293
- [
294
- h(resolveComponent('Icon'), para)
295
- ]
296
- ),
297
- h(resolveComponent('ShowText'), {
298
- label:params.data.title,
299
- contentAlign:'left'
300
- })
301
- ]);
302
- },
303
- toTreeData(expandMap = new Set(), selectedId = null) {
304
- let pos = {};
305
- let tree = [];
306
- let i = 0;
307
-
308
- const idField = this.myConfig.idField;
309
- const parentField = this.myConfig.parentField;
310
- const rootId = this.rootNode[idField];
311
-
312
- const focusId = (selectedId !== null && selectedId !== undefined)
313
- ? selectedId
314
- : this._autoExpandId;
315
-
316
- let autoExpandParents = new Set();
317
-
318
- // 根据 focusId 反查父链(并防环)
319
- if (focusId !== null && focusId !== undefined) {
320
- let current = this.data.find(item => item[idField] === focusId);
321
- const visited = new Set();
322
-
323
- while (current) {
324
- const cid = current[idField];
325
- if (visited.has(cid)) {
326
- console.warn('[toTreeData] parent chain cycle detected:', cid);
327
- break;
328
- }
329
- visited.add(cid);
330
-
331
- autoExpandParents.add(cid); // 选中节点本身 + 全部祖先都加入展开集合
332
-
333
- const pid = current[parentField];
334
- if (pid == null) break; // 注意:不要写 !pid,避免 0 被误判
335
-
336
- current = this.data.find(item => item[idField] === pid);
337
- }
338
- }
339
-
340
-
341
- let data = this.$Method.copy(this.data);
342
- data.forEach(el => {
343
- this.setSelected(el); // 保留你原逻辑
344
- });
345
- let tempData = this.$Method.copy(data);
346
-
347
- // 统一状态赋值(避免到处重复写漏)
348
- const applyNodeState = (node) => {
349
- const nid = node[idField];
350
-
351
- // 展开:外部传入 expandMap 或者 focusId 的祖先链
352
- if (expandMap.has(nid) || autoExpandParents.has(nid)) {
353
- node.expand = true;
354
- }
355
-
356
- // 选中:focusId 命中
357
- node.selected = (focusId !== null && focusId !== undefined && nid === focusId);
358
- };
359
-
360
- // 防死循环控制
361
- let guard = 0;
362
- const maxGuard = data.length * 5 + 20;
363
- let movedInRound = 0;
364
-
365
- while (data.length !== 0) {
366
- const current = data[i];
367
- const currentId = current[idField];
368
- const parentId = current[parentField];
369
-
370
- // 父是否存在于原始数据(判断孤儿)
371
- const index = tempData.findIndex(item => item[idField] === parentId);
372
-
373
- if (parentId === rootId || index < 0) {
374
- applyNodeState(current);
375
-
376
- tree.push(current);
377
- pos[currentId] = [tree.length - 1];
378
- data.splice(i, 1);
379
- i--;
380
- movedInRound++;
381
- } else {
382
- const posArr = pos[parentId];
383
- if (posArr) {
384
- let obj = tree[posArr[0]];
385
- for (let j = 1; j < posArr.length; j++) {
386
- obj = obj.children[posArr[j]];
387
- }
388
-
389
- applyNodeState(current);
390
-
391
- obj.children.push(current);
392
- pos[currentId] = posArr.concat([obj.children.length - 1]);
393
- data.splice(i, 1);
394
- i--;
395
- movedInRound++;
396
- }
397
- }
398
-
399
- i++;
400
- if (i > data.length - 1) {
401
- // 一轮下来没挂上任何节点 -> 环/坏链路,兜底退出
402
- if (movedInRound === 0 && data.length > 0) {
403
- console.warn('[toTreeData] unresolved/cyclic nodes, force attach to root level:', data);
404
-
405
- data.forEach(node => {
406
- applyNodeState(node);
407
- const nid = node[idField];
408
- tree.push(node);
409
- pos[nid] = [tree.length - 1];
410
- });
411
-
412
- data = [];
413
- break;
414
- }
415
-
416
- movedInRound = 0;
417
- i = 0;
418
-
419
- guard++;
420
- if (guard > maxGuard) {
421
- console.warn('[toTreeData] safety break triggered');
422
- break;
423
- }
424
- }
425
- }
426
-
427
-
428
- if (this.myConfig.showRootNode) {
429
- let root = {
430
- title: ' ' + this.myConfig.rootNode.name,
431
- expand: true,
432
- disabled: this.myConfig.readOnly,
433
- children: tree,
434
- selected: false
435
- };
436
-
437
- if (this.myConfig.rootNode.disabled !== undefined) {
438
- root.disabled = this.myConfig.rootNode.disabled;
439
- }
440
- Object.assign(root, this.rootNode);
441
-
442
- if (this.myConfig.showIcon) {
443
- if (this.myConfig.idClass && this.myConfig.showIconList && this.myConfig.showIconList.length > 0) {
444
- root[this.myConfig.idClass] = 0;
445
- root = this.setIcon(root);
446
- }
447
- }
448
-
449
- root.render = this.myConfig.nodeRender ? this.myConfig.nodeRender : this.iconRender;
450
-
451
- this._autoExpandId = null;
452
- return [root];
453
- } else {
454
- this._autoExpandId = null;
455
- return tree;
456
- }
457
- },
458
- setSelected (reTemp) {
459
- if (this.myConfig.expand) {
460
- reTemp.expand = this.myConfig.expand;
461
- }
462
- if (this.asyncLoad) {
463
- if (Number(reTemp[this.myConfig.idClass]) !== Number(this.myConfig.maxClass)) {
464
- reTemp.loading = false;
465
- }
466
- }
467
- /*if (this.myConfig.keepExpand) {
468
- let index = this.myConfig.expandData.findIndex(el => el === reTemp[this.myConfig.responseId]);
469
- if (index > -1) {
470
- reTemp.expand = true;
471
- }
472
- }*/
473
- if (this.myConfig.showCodeWithName) {
474
- reTemp.title = ' [' + reTemp[this.myConfig.responseCode] + '] ' + reTemp[this.myConfig.responseName];
475
- } else {
476
- reTemp.title = ' ' + reTemp[this.myConfig.responseName];
477
- }
478
- if (this.myConfig.readOnly) {
479
- reTemp.disabled = true;
480
- } else {
481
- reTemp.disabled = false;
482
- }
483
- if (this.myConfig.setNodeDisabled) {
484
- reTemp.disabled = this.myConfig.setNodeDisabled(reTemp);
485
- }
486
- if (this.myConfig.showIcon) {
487
- if (this.myConfig.idClass && this.myConfig.showIconList && this.myConfig.showIconList.length > 0) {
488
- reTemp = this.setIcon(reTemp);
489
- }
490
- }
491
-
492
- if (this.myConfig.nodeRender) {
493
- reTemp.render = this.myConfig.nodeRender;
494
- } else{
495
- reTemp.render = this.iconRender;
496
- }
497
- if (reTemp.children === undefined) {
498
- reTemp.children= [];
499
- } else {
500
- let children = [];
501
- reTemp.children.forEach(el => {
502
- children.push(this.setSelected(el));
503
- });
504
- reTemp.children = children;
505
- }
506
- return reTemp;
507
- },
508
- refurbish(para) {
509
- if(!para) {
510
- para = {};
511
- }
512
- if (this.asyncLoad) {
513
- para[this.myConfig.idClass] = 1;
514
- }
515
- let self = this;
516
- self.synchroPost(self.myConfig.resources, self.myConfig.method, self.getSearchParam(para), function(data) {
517
- let root = [];
518
- if (data && data[self.myConfig.response]) {
519
- if (self.checkData(data[self.myConfig.response])) {
520
- root = data[self.myConfig.response];
521
- } else {
522
- return false;
523
- }
524
- }
525
- if (self.myConfig.customData && self.myConfig.customData.length > 0) {
526
- root = self.myConfig.customData.concat(root);
527
- }
528
- self.data = root;
529
- self.treeData = self.toTreeData();
530
- if (self.myConfig.selectedRoot) {
531
- if (self.selectedData && self.selectedData.length === 0) {
532
- self.selectedData.push(self.rootNode);
533
- }
534
- }
535
- },null);
536
- },
537
- getAsyncNode(para){
538
- let self = this;
539
- let asyncData = [];
540
- self.synchroPost(self.myConfig.resources, self.myConfig.method, self.getSearchParam(para), function(data) {
541
- if (data && data[self.myConfig.response]) {
542
- if (self.checkData(data[self.myConfig.response])) {
543
- asyncData = data[self.myConfig.response];
544
- }
545
- }
546
- },null);
547
- return asyncData;
548
- },
549
- checkData(data) {
550
- let index = data.findIndex(el => el[this.myConfig.idField] === el[this.myConfig.parentField]);
551
- if (index > -1) {
552
- this.alert('存在' + this.myConfig.idField +'与' + this.myConfig.parentField+'都为[' + data[index][this.myConfig.idField]+']的数据,请检查',null,2);
553
- return false;
554
- }
555
- return true;
556
- },
557
- setReadOnly(flag) {
558
- this.myConfig = Object.assign({},this.myConfig,{readOnly:flag});
559
- },
560
- getRootNode () {
561
- return this.$Method.copy(this.rootNode);
562
- },
563
-
564
- getData() {
565
- if (!this.treeData) return []
566
-
567
- return this.myConfig.showCheckBox
568
- ? this.getNodesByKey('checked', this.treeData)
569
- : this.getNodesByKey('selected', this.treeData)
570
- },
571
- // getNodesByKey(key, data, result = []) {
572
- // data.forEach(item => {
573
- // if (item[key]) {
574
- // result.push(item)
575
- // }
576
- // if (Array.isArray(item.children)) {
577
- // this.getNodesByKey(key, item.children, result)
578
- // }
579
- // })
580
- // return result
581
- // },
582
-
583
- getNodesByKey(key, data, result = []) {
584
- data.forEach(item => {
585
- if (item[key]) {
586
- result.push(item)
587
- }
588
- if (Array.isArray(item.children) && item.children.length > 0) {
589
- this.getNodesByKey(key, item.children, result)
590
- }
591
- })
592
- return result
593
- },
594
-
595
-
596
- setData(data) {
597
- this.selectedData = this.$Method.copy(data);
598
- this.oldData = this.$Method.copy(data);
599
- },
600
- setDisplayData(data) {
601
- if (this.checkData(data)) {
602
- this.data = this.$Method.copy(data);
603
- this.treeData = this.toTreeData();
604
- }
605
- },
606
- clearExpand() {
607
- this.myConfig.expandData = [];
608
- },
609
- setPro(data) {
610
- if (data) {
611
- this.myConfig = Object.assign({},this.myConfig,data);
612
- }
613
- },
614
- getPro(name) {
615
- return this.myConfig[name];
616
- },
617
- onSelectChange: function(res,node) { //点击树节点时触发返回当前已选中的节点数组
618
- this.$emit('onSelectChange', res, node);
619
- },
620
- onCheckChange: function(res,node) { //勾选树节点时触发返回当前已勾选的节点数组
621
- if (this.myConfig.showCheckBox) {
622
- let obj = [];
623
- res.forEach(el => {
624
- let temp = {};
625
- temp[this.myConfig.responseId] = el[this.myConfig.responseId];
626
- obj.push(temp);
627
- });
628
- this.selectedData = this.$Method.copy(obj);
629
- }
630
- this.$emit('onCheckChange', res,node);
631
- },
632
- onToggleExpand: function(res) { //展开和收起子列表时触发返回当前节点的数据
633
- /*if (res.expand) {
634
- // 去重
635
- let index = this.myConfig.expandData.findIndex(el => el === res[this.myConfig.responseId]);
636
- if (index === -1) {
637
- this.myConfig.expandData.push(res[this.myConfig.responseId])
638
- }
639
- } else {
640
- let children = [];
641
- this.getChildren(res,children);
642
- // 收起当前节点
643
- children.push(res[this.myConfig.responseId]);
644
- children.forEach(el => {
645
- let index2 = this.myConfig.expandData.findIndex(el2 => el === el2);
646
- if (index2 > -1) {
647
- this.myConfig.expandData.splice(index2, 1);
648
- }
649
- });
650
- }*/
651
- this.$emit('onToggleExpand', res);
652
- },
653
- getChildren(res,childrens) {
654
- this.data.forEach(el => {
655
- if (el[this.myConfig.parentField] === res[this.myConfig.idField]) {
656
- childrens.push(el[this.myConfig.responseId]);
657
- this.getChildren(el, childrens);
658
- }
659
- });
660
- },
661
- popValueChanged (para) {
662
- let reData = [];
663
- let self = this;
664
- let searchParam = Object.assign({},self.getSearchParam(),para);
665
- self.synchroPost(self.myConfig.resources,self.myConfig.method,searchParam,function(data) {
666
- if (data && data[self.myConfig.response]) {
667
- reData = data[self.myConfig.response];
668
- }
669
- },null);
670
- return reData;
671
- },
672
- clearData() {
673
- this.data = [];
674
- this.oldData = [];
675
- this.selectedData =[];
676
- this.treeData = [];
677
- this.conditionSearchParam = {};
678
- this.myConfig.expandData = [];
679
- },
680
- getSelectedNodes() {
681
- return this.$refs.tree.getSelectedNodes();
682
- },
683
-
684
- getCheckedNodes() {
685
- if (!this.treeData) return []
686
- return this.getNodesByKey('checked', this.treeData)
687
- },
688
-
689
- getCheckedAndIndeterminateNodes() {
690
- return this.$refs.tree.getCheckedAndIndeterminateNodes();
691
- },
692
- isChange() {
693
- // 初期值为空时,结果是否有值
694
- let data = this.getData();
695
- if (this.oldData.length === 0) {
696
- if (data.length > 0) {
697
- return true;
698
- } else {
699
- return false;
700
- }
701
- }
702
- // 判断初期值是否在结果中
703
- let resultFlag = false;
704
- let tempflag = false;
705
- this.oldData.forEach(el => {
706
- tempflag = false;
707
- data.forEach(el2 => {
708
- if (el[this.myConfig.idField] === el2[this.myConfig.idField]) {
709
- tempflag = true;
710
- return;
711
- }
712
- });
713
- if (!tempflag) {
714
- resultFlag = true;
715
- return;
716
- }
717
- });
718
- if (resultFlag) {
719
- return true;
720
- }
721
- // 初期值全部在结果中,是否多了新值
722
- let num = 0;
723
- data.forEach(el => {
724
- if (el.children === undefined || (el.children && el.children.length === 0)) {
725
- num++;
726
- }
727
- });
728
- if (this.oldData.length !== num) {
729
- return true;
730
- } else {
731
- return false;
732
- }
733
- },
734
- setSearchBeforeSearchParam(obj) {
735
- this.searchBeforeSearchParam = Object.assign({},{},obj);
736
- },
737
- clearSearchBeforeSearchParam() {
738
- this.searchBeforeSearchParam = {};
739
- },
740
- getFatherNode(node) {
741
- if (!node || !node[this.myConfig.parentField]) {
742
- return {};
743
- }
744
- if (this.data && this.data.length > 0) {
745
- const index = this.data.findIndex(el => el[this.myConfig.idField] === node[this.myConfig.parentField]);
746
- if (index > -1) {
747
- return this.$Method.copy(this.data[index]);
748
- } else {
749
- return {};
750
- }
751
- }
752
- },
753
- isChildren (node) {
754
- let flag = false;
755
- if (this.data && this.data.length > 0) {
756
- const index = this.data.findIndex(el => el[this.myConfig.parentField] === node[this.myConfig.idField]);
757
- if (index > -1) {
758
- flag = true;
759
- }
760
- }
761
- return flag;
762
- },
763
- setExtraHeight () {
764
- let height = 0;
765
- if (this.$refs.condition) {
766
- height = this.$refs.condition.offsetHeight;
767
- }
768
- this.extraHeight = height;
769
- },
770
- setOutsideHeight(value) {
771
- this.outsideHeight = value;
772
- },
773
- setAllNode(name, value) {
774
- let tempName = name;
775
- if (name === 'readOnly') {
776
- tempName = 'disabled';
777
- } else if (name === 'selected') {
778
- if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
779
- tempName ='checked';
780
- } else {
781
- tempName = 'selected';
782
- }
783
- }
784
- const updateNode = (nodes) => {
785
- if (!nodes) return
786
-
787
- nodes.forEach(node => {
788
- if (node[tempName] !== value) {
789
- node[tempName] = value
790
- }
791
-
792
- if (node.children && node.children.length > 0) {
793
- updateNode(node.children)
794
- }
795
- })
796
- }
797
-
798
- updateNode(this.data)
799
-
800
- },
801
-
802
- setNodes(data, name, value) {
803
- let tempName = name;
804
- if (name === 'readOnly') {
805
- tempName = 'disabled';
806
- } else if (name === 'selected') {
807
- if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
808
- tempName ='checked';
809
- } else {
810
- tempName = 'selected';
811
- }
812
- }
813
- let responseId = this.myConfig.responseId;
814
- this.$refs.tree.flatState.forEach(el => {
815
- let index = data.findIndex(
816
- el2 => el.node[responseId] === el2[responseId]
817
- );
818
- if (index > -1) {
819
- if (el.node[tempName] !== value) {
820
- let obj ={};
821
- obj[tempName] = value;
822
- Object.assign(el.node,obj);
823
- }
824
- } else {
825
- if (el.node[tempName] !== !value) {
826
- let obj ={};
827
- obj[tempName] = !value;
828
- Object.assign(el.node,obj);
829
- }
830
- }
831
- });
832
- },
833
-
834
- setNodese(data = [], name, value) {
835
- let tempName = name;
836
- if (name === 'readOnly') {
837
- tempName = 'disabled';
838
- } else if (name === 'selected') {
839
- tempName = (this.myConfig.multiSelect && this.myConfig.showCheckBox) ? 'checked' : 'selected';
840
- }
841
-
842
- const responseId = this.myConfig.idField || this.myConfig.responseId;
843
-
844
- // 统一字符串,避免 1 / "1" 不匹配
845
- const idSet = new Set(
846
- (data || []).map(item => String(item?.[responseId]))
847
- );
848
-
849
- // 确认真实渲染源
850
- const source = Array.isArray(this.data)
851
- ? this.data
852
- : (Array.isArray(this.treeData) ? this.treeData : []);
853
-
854
- let hitCount = 0;
855
-
856
- const updateNode = (nodes) => {
857
- if (!Array.isArray(nodes)) return;
858
-
859
- nodes.forEach(node => {
860
- const exists = idSet.has(String(node?.[responseId]));
861
- if (exists) hitCount++;
862
-
863
- let newValue;
864
-
865
- // 只有“选中=true”时,才清空其他节点(单选常见需求)
866
- if (name === 'selected' && value === true) {
867
- newValue = exists;
868
- } else if (exists) {
869
- // 其他场景只改命中节点
870
- newValue = value;
871
- } else {
872
- newValue = node[tempName];
873
- }
874
-
875
- if (node[tempName] !== newValue) {
876
- // Vue2: 动态键必须用 $set 才响应
877
- // this.$set(node, tempName, newValue);
878
- node[tempName] = newValue;
879
- }
880
-
881
- if (node.children && node.children.length > 0) {
882
- updateNode(node.children);
883
- }
884
- });
885
- };
886
-
887
- updateNode(source);
888
-
889
- // 兜底触发视图更新
890
- if (source === this.data) this.data = [...source];
891
- if (source === this.treeData) this.treeData = [...source];
892
-
893
- console.log('[setNodes]', { tempName, responseId, targetIds: [...idSet], hitCount });
894
- return hitCount;
895
- },
896
- setNodes2(data, name, value) {
897
- let tempName = name;
898
- if (name === 'readOnly') {
899
- tempName = 'disabled';
900
- } else if (name === 'selected') {
901
- if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
902
- tempName ='checked';
903
- } else {
904
- tempName = 'selected';
905
- }
906
- }
907
- let responseId = this.myConfig.idField || this.myConfig.responseId;
908
- // 把目标列表变成 Set,提高查找效率
909
- const idSet = new Set(
910
- data.map(item => item[responseId])
911
- )
912
-
913
- const updateNode = (nodes) => {
914
- if (!nodes) return
915
-
916
- nodes.forEach(node => {
917
-
918
- const exists = idSet.has(node[responseId])
919
-
920
- const newValue = exists ? value : !value
921
-
922
- if (node[tempName] !== newValue) {
923
- node[tempName] = newValue
924
- }
925
-
926
- if (node.children && node.children.length > 0) {
927
- updateNode(node.children)
928
- }
929
-
930
- })
931
- }
932
-
933
- updateNode(this.data)
934
- },
935
- saveExpandState() {
936
- const expandSet = new Set();
937
-
938
- const loop = (nodes) => {
939
- if (!nodes) return;
940
-
941
- nodes.forEach(node => {
942
- if (node.expand) {
943
- expandSet.add(node[this.myConfig.idField]);
944
- }
945
- if (node.children && node.children.length) {
946
- loop(node.children);
947
- }
948
- });
949
- };
950
-
951
- loop(this.treeData);
952
-
953
- return expandSet;
954
- },
955
- updateNode(data, flag) {
956
- const idField = this.myConfig.idField
957
- const parentField = this.myConfig.parentField
958
- const targetId = data[idField]
959
-
960
- // ① 保存当前展开状态
961
- const expandSet = this.saveExpandState()
962
- // ② 数据更新
963
- const index = this.data.findIndex(
964
- el => el[idField] === targetId
965
- )
966
-
967
- if (flag === 'U') {
968
- if (index > -1) {
969
- Object.assign(this.data[index], data)
970
- } else {
971
- this.data.push(data)
972
-
973
- // ===== 新增时自动展开父链 =====
974
- let parentId = data[parentField]
975
-
976
- while (parentId) {
977
- expandSet.add(parentId)
978
-
979
- const parent = this.data.find(
980
- el => el[idField] === parentId
981
- )
982
-
983
- if (!parent) break
984
-
985
- parentId = parent[parentField]
986
- }
987
- }
988
- }
989
-
990
- if (flag === 'D') {
991
- if (index > -1) {
992
- this.data.splice(index, 1)
993
- }
994
- }
995
- // ③ 重建树(带展开状态)
996
- this.treeData = this.toTreeData(expandSet, targetId)
997
- },
998
- updateNodeod(data,flag) {
999
- let tmp = data;
1000
- if(flag !== 'D') {
1001
- tmp = this.setSelected(data);
1002
- }
1003
- tmp.selected = true;
1004
- if (this.$refs.tree && this.$refs.tree.flatState) {
1005
- let index = -1;
1006
- if (flag === 'U') {
1007
- index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.idField]);
1008
- if (index > -1) {
1009
- if (this.$refs.tree.flatState[index].node.children && this.$refs.tree.flatState[index].node.children.length > 0) {
1010
- delete tmp.children;
1011
- }
1012
- Object.assign(this.$refs.tree.flatState[index].node,tmp);
1013
- } else {
1014
- index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.parentField]);
1015
- if (index > -1) {
1016
- if (!this.$refs.tree.flatState[index].node.children){
1017
- this.$refs.tree.flatState[index].node.children = [];
1018
- }
1019
- this.$refs.tree.flatState[index].node.children.forEach(el2 => {
1020
- let tmpIndex = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === el2[this.myConfig.idField] && el.node.selected);
1021
- if (tmpIndex > -1) {
1022
- Object.assign(this.$refs.tree.flatState[tmpIndex].node,{selected:false});
1023
- }
1024
- });
1025
- Object.assign(this.$refs.tree.flatState[index].node,{selected:false, expand:true});
1026
- this.$refs.tree.flatState[index].node.children.push(tmp)
1027
- }
1028
- }
1029
- }
1030
- if (flag === 'D') {
1031
- index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.parentField]);
1032
- if (index > -1) {
1033
- let tmpIndex = this.$refs.tree.flatState[index].node.children.findIndex(el => el[this.myConfig.idField] === tmp[this.myConfig.idField]);
1034
- if (tmpIndex > -1) {
1035
- this.$refs.tree.flatState[index].node.children.splice(tmpIndex, 1);
1036
- if (this.$refs.tree.flatState[index].node.children.length === 0) {
1037
- Object.assign(this.$refs.tree.flatState[index].node,{expand:false});
1038
- }
1039
- }
1040
- }
1041
- }
1042
- }
1043
- this.treeData = [...this.treeData];
1044
- },
1045
- setExpend(data) {
1046
- let index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === data[this.myConfig.idField]);
1047
- if (index > -1) {
1048
- let tmp = {expand:!this.$refs.tree.flatState[index].node.expand};
1049
- if (tmp.expand && this.asyncLoad) {
1050
- if (!this.$refs.tree.flatState[index].node.loading && this.$refs.tree.flatState[index].node.children.length === 0) {
1051
- tmp.loading = true;
1052
- };
1053
- let callback = (data) => {
1054
- data.forEach(el => {
1055
- el.selected = false;
1056
- this.$refs.tree.flatState[index].node.children.push(el);
1057
- })
1058
- Object.assign(this.$refs.tree.flatState[index].node,{loading:false});
1059
- }
1060
- if (this.$refs.tree.flatState[index].node.children.length === 0){
1061
- this.loadData(data,callback);
1062
- }
1063
-
1064
- }
1065
- Object.assign(this.$refs.tree.flatState[index].node,tmp);
1066
- }
1067
- },
1068
- loadData (item, callback) {
1069
- let para = {};
1070
- para[this.myConfig.parentField] = item[this.myConfig.idField];
1071
- let data = this.getAsyncNode(para);
1072
- setTimeout(() => {
1073
- data.forEach(el => {
1074
- this.setSelected(el);
1075
- });
1076
- callback(data);
1077
- }, 200);
1078
- }
1079
- },
1080
- mounted () {
1081
- //this._setCustomHeight(this.clientHeight);
1082
- },
1083
- watch: {
1084
- 'myConfig.readOnly':function(val){
1085
- this.setAllNode('readOnly', val);
1086
- },
1087
- selectedData:function (val) {
1088
- this.setNodes(val,'selected', true);
1089
- }
1090
- }
1091
- };
1092
- </script>
1093
- <style>
1094
- .efutre-tree-node .ivu-tree-title{
1095
- width: 95%;
1096
- padding-left: 2px;
1097
- }
1098
- </style>
1
+ <script>
2
+ import size from '@/components/base/size';
3
+ import { resolveComponent } from 'vue';
4
+ export default {
5
+ mixins: [size],
6
+ name:'baseTree',
7
+ data () {
8
+ return {
9
+ globalConfig: {
10
+ emptyText: '暂无数据',
11
+ multiSelect: false,
12
+ resources: '',
13
+ method: '',
14
+ response: '',
15
+ selectkey: '',
16
+ idField:'',
17
+ parentField:'',
18
+ idClass:'',
19
+ searchParam: null,
20
+ readOnly: false,
21
+ showIcon:false,
22
+ keepExpand:false,
23
+ expandData:[],
24
+ showIconList:[],
25
+ showCheckBox: false,
26
+ showRootNode:false,
27
+ showTitle:true,
28
+ expand:true,
29
+ rootNode:{},
30
+ setNodeDisabled:'',
31
+ bordered:true,
32
+ disHover:false,
33
+ selectedRoot:false,
34
+ className:'efutre-tree-node'
35
+ },
36
+ myConfig: {
37
+
38
+ },
39
+ gridConfig:{
40
+
41
+ },
42
+ showCondition:true,
43
+ data:[],
44
+ oldData:[],
45
+ selectedData:[],
46
+ conditionSearchParam:{},
47
+ searchBeforeSearchParam:{},
48
+ rootNode:{},
49
+ showTree:true,
50
+ showGrid:false,
51
+ extraHeight:0,
52
+ outsideHeight:0,
53
+ treeData:[],
54
+ asyncLoad:false,
55
+ _autoExpandId: '',
56
+
57
+ };
58
+ },
59
+ created () {
60
+ this.init();
61
+ },
62
+ props:{
63
+ config: {
64
+ type: Object,
65
+ default: () => {
66
+ return {};
67
+ }
68
+ },
69
+ dictData: {
70
+ type: Object,
71
+ default:null
72
+ }
73
+ },
74
+ methods:{
75
+ init() {
76
+ //获取初期默认值
77
+ this.myConfig = Object.assign({}, this.globalConfig, this.myConfig);
78
+
79
+ //获取配置
80
+ if (this.config) {
81
+ this.myConfig = Object.assign({}, this.myConfig, this.config);
82
+ }
83
+
84
+ let rootCode = '0';
85
+ let rootName = '根节点';
86
+ if (this.myConfig.showRootNode) {
87
+ if (this.myConfig.rootNode !== undefined && this.myConfig.rootNode.code !== undefined) {
88
+ rootCode = this.myConfig.rootNode.code;
89
+ }
90
+ if (this.myConfig.rootNode !== undefined && this.myConfig.rootNode.name !== undefined) {
91
+ rootName = this.myConfig.rootNode.name;
92
+ }
93
+ }
94
+ if (this.myConfig.responseId === undefined) {
95
+ this.myConfig.responseId = this.myConfig.responseCode;
96
+ }
97
+ this.rootNode[this.myConfig.idField] = rootCode + '';
98
+ this.rootNode[this.myConfig.responseId] = rootCode + '';
99
+ this.rootNode[this.myConfig.responseCode] = rootCode + '';
100
+ this.rootNode[this.myConfig.responseName] = rootName;
101
+ if (this.myConfig.idClass !== undefined) {
102
+ this.rootNode[this.myConfig.idClass] = 0;
103
+ }
104
+ //多选 才允许出现复选框
105
+ if (this.myConfig.multiSelect !== true) {
106
+ this.myConfig.showCheckBox = false;
107
+ }
108
+ this.setSizeConfig(this.myConfig);
109
+
110
+ if (this.myConfig.asyncLoad) {
111
+ this.asyncLoad = true;
112
+ }
113
+ //特定化处理
114
+ if (this.customInit) {
115
+ this.customInit();
116
+ }
117
+
118
+ },
119
+ setIcon(data) {
120
+ let nodeClass = data[this.myConfig.idClass];
121
+ if (!nodeClass) {
122
+ nodeClass = 0;
123
+ } else {
124
+ nodeClass = Number(nodeClass);
125
+ }
126
+ if (!this.myConfig.showRootNode) {
127
+ if (nodeClass && nodeClass !== 0) {
128
+ nodeClass = nodeClass - 1;
129
+ }
130
+ }
131
+ if (nodeClass >= this.myConfig.showIconList.length) {
132
+ nodeClass = this.myConfig.showIconList.length - 1;
133
+ }
134
+
135
+ const icon = this.myConfig.showIconList[nodeClass];
136
+ data.icon = icon.type;
137
+ if (icon.size) {
138
+ data.iconSize = icon.size;
139
+ }
140
+ if (icon.color) {
141
+ data.iconColor = icon.color;
142
+ }
143
+ return data;
144
+ },
145
+ iconRender(h, params) {
146
+
147
+ let icon = params.data.icon
148
+ let size = params.data.iconSize
149
+ let color = params.data.iconColor
150
+
151
+ const hasChildren =
152
+ params.data.children &&
153
+ params.data.children.length > 0
154
+
155
+ if (!icon) {
156
+ if (hasChildren) {
157
+ icon = params.data.expand
158
+ ? '_base_mulu'
159
+ : '_base_close_mulu'
160
+ } else {
161
+ icon = '_base_wenjian'
162
+ }
163
+ }
164
+
165
+ if (!size) {
166
+ size = 14
167
+ }
168
+
169
+ let para = {
170
+ type: icon,
171
+ size,
172
+ color
173
+ }
174
+
175
+ if (this.myConfig.setTreeNodeIcon) {
176
+ para = this.myConfig.setTreeNodeIcon(params, para)
177
+ } else if (this.setTreeNodeIcon) {
178
+ para = this.setTreeNodeIcon(params, para)
179
+ }
180
+
181
+ // 处理自定义 iconfont
182
+ if (para.type && para.type.startsWith('_')) {
183
+ const resultIcon =
184
+ 'iconfont icon-' + para.type.substring(1)
185
+
186
+ para.custom = resultIcon
187
+ delete para.type
188
+ }
189
+
190
+ let nodeClass = 'efuture-treenode'
191
+
192
+ if (this.myConfig.setNodeClass) {
193
+ nodeClass = this.myConfig.setNodeClass(params)
194
+ }
195
+
196
+ return h(
197
+ 'div',
198
+ {
199
+ class: { [nodeClass]: true },
200
+ style: {
201
+ display: 'flex',
202
+ userSelect: 'none'
203
+ },
204
+ onDblclick: () => {
205
+ this.$nextTick(() => {
206
+ this.setExpend(params.data)
207
+ })
208
+ this.$emit('dbclick', params.data)
209
+ }
210
+ },
211
+ [
212
+ h(
213
+ 'div',
214
+ {
215
+ style: { paddingLeft: '5px' }
216
+ },
217
+ [
218
+ h(resolveComponent('Icon'), para)
219
+ ]
220
+ ),
221
+
222
+ h(resolveComponent('ShowText'), {
223
+ label: params.data.title,
224
+ contentAlign: 'left'
225
+ })
226
+ ]
227
+ )
228
+ },
229
+ iconRenderOld(h,params) {
230
+ let icon = params.data.icon;
231
+ let size = params.data.iconSize;
232
+ let color = params.data.iconColor;
233
+ if (!icon) {
234
+ if (params.node && params.node.children && params.node.children.length > 0) {
235
+ if (params.data.expand) {
236
+ icon = '_base_mulu';
237
+ } else {
238
+ icon = '_base_close_mulu';
239
+ }
240
+
241
+ } else {
242
+ icon = '_base_wenjian';
243
+ }
244
+ }
245
+ if (!size) {
246
+ size = 14;
247
+ }
248
+ let para = {
249
+ type:icon,
250
+ size:size,
251
+ color:color
252
+ }
253
+ if (this.myConfig.setTreeNodeIcon) {
254
+ para = this.myConfig.setTreeNodeIcon(params,para);
255
+ } else if (this.setTreeNodeIcon) {
256
+ para = this.setTreeNodeIcon(params,para);
257
+ }
258
+ if (para.type.indexOf('_') === 0) {
259
+ let resulIcon = para.type.substring(1,para.type.length);
260
+ resulIcon = 'iconfont icon-' + resulIcon;
261
+ para.custom = resulIcon;
262
+ delete para.type;
263
+ }
264
+ let nodeClass = 'efuture-treenode';
265
+ if (this.myConfig.setNodeClass) {
266
+ nodeClass =this.myConfig.setNodeClass(params)
267
+ }
268
+ let classstyle = {};
269
+ classstyle[nodeClass] = true;
270
+ return h(
271
+ 'div',
272
+ {
273
+ style: {
274
+ display: 'flex',
275
+ userSelect: 'none'
276
+ },
277
+ class:classstyle,
278
+ onDblclick:() => {
279
+ this.$nextTick(() => {
280
+ this.setExpend(params.data);
281
+ });
282
+ this.$emit('dbclick', params.data);
283
+ }
284
+ },
285
+ [
286
+ h(
287
+ 'div',
288
+ {
289
+ style: {
290
+ 'padding-left':'5px'
291
+ }
292
+ },
293
+ [
294
+ h(resolveComponent('Icon'), para)
295
+ ]
296
+ ),
297
+ h(resolveComponent('ShowText'), {
298
+ label:params.data.title,
299
+ contentAlign:'left'
300
+ })
301
+ ]);
302
+ },
303
+ toTreeData(expandMap = new Set(), selectedId = null) {
304
+ let pos = {};
305
+ let tree = [];
306
+ let i = 0;
307
+
308
+ const idField = this.myConfig.idField;
309
+ const parentField = this.myConfig.parentField;
310
+ const rootId = this.rootNode[idField];
311
+
312
+ const focusId = (selectedId !== null && selectedId !== undefined)
313
+ ? selectedId
314
+ : this._autoExpandId;
315
+
316
+ let autoExpandParents = new Set();
317
+
318
+ // 根据 focusId 反查父链(并防环)
319
+ if (focusId !== null && focusId !== undefined) {
320
+ let current = this.data.find(item => item[idField] === focusId);
321
+ const visited = new Set();
322
+
323
+ while (current) {
324
+ const cid = current[idField];
325
+ if (visited.has(cid)) {
326
+ console.warn('[toTreeData] parent chain cycle detected:', cid);
327
+ break;
328
+ }
329
+ visited.add(cid);
330
+
331
+ autoExpandParents.add(cid); // 选中节点本身 + 全部祖先都加入展开集合
332
+
333
+ const pid = current[parentField];
334
+ if (pid == null) break; // 注意:不要写 !pid,避免 0 被误判
335
+
336
+ current = this.data.find(item => item[idField] === pid);
337
+ }
338
+ }
339
+
340
+
341
+ let data = this.$Method.copy(this.data);
342
+ data.forEach(el => {
343
+ this.setSelected(el); // 保留你原逻辑
344
+ });
345
+ let tempData = this.$Method.copy(data);
346
+
347
+ // 统一状态赋值(避免到处重复写漏)
348
+ const applyNodeState = (node) => {
349
+ const nid = node[idField];
350
+
351
+ // 展开:外部传入 expandMap 或者 focusId 的祖先链
352
+ if (expandMap.has(nid) || autoExpandParents.has(nid)) {
353
+ node.expand = true;
354
+ }
355
+
356
+ // 选中:focusId 命中
357
+ node.selected = (focusId !== null && focusId !== undefined && nid === focusId);
358
+ };
359
+
360
+ // 防死循环控制
361
+ let guard = 0;
362
+ const maxGuard = data.length * 5 + 20;
363
+ let movedInRound = 0;
364
+
365
+ while (data.length !== 0) {
366
+ const current = data[i];
367
+ const currentId = current[idField];
368
+ const parentId = current[parentField];
369
+
370
+ // 父是否存在于原始数据(判断孤儿)
371
+ const index = tempData.findIndex(item => item[idField] === parentId);
372
+
373
+ if (parentId === rootId || index < 0) {
374
+ applyNodeState(current);
375
+
376
+ tree.push(current);
377
+ pos[currentId] = [tree.length - 1];
378
+ data.splice(i, 1);
379
+ i--;
380
+ movedInRound++;
381
+ } else {
382
+ const posArr = pos[parentId];
383
+ if (posArr) {
384
+ let obj = tree[posArr[0]];
385
+ for (let j = 1; j < posArr.length; j++) {
386
+ obj = obj.children[posArr[j]];
387
+ }
388
+
389
+ applyNodeState(current);
390
+
391
+ obj.children.push(current);
392
+ pos[currentId] = posArr.concat([obj.children.length - 1]);
393
+ data.splice(i, 1);
394
+ i--;
395
+ movedInRound++;
396
+ }
397
+ }
398
+
399
+ i++;
400
+ if (i > data.length - 1) {
401
+ // 一轮下来没挂上任何节点 -> 环/坏链路,兜底退出
402
+ if (movedInRound === 0 && data.length > 0) {
403
+ console.warn('[toTreeData] unresolved/cyclic nodes, force attach to root level:', data);
404
+
405
+ data.forEach(node => {
406
+ applyNodeState(node);
407
+ const nid = node[idField];
408
+ tree.push(node);
409
+ pos[nid] = [tree.length - 1];
410
+ });
411
+
412
+ data = [];
413
+ break;
414
+ }
415
+
416
+ movedInRound = 0;
417
+ i = 0;
418
+
419
+ guard++;
420
+ if (guard > maxGuard) {
421
+ console.warn('[toTreeData] safety break triggered');
422
+ break;
423
+ }
424
+ }
425
+ }
426
+
427
+
428
+ if (this.myConfig.showRootNode) {
429
+ let root = {
430
+ title: ' ' + this.myConfig.rootNode.name,
431
+ expand: true,
432
+ disabled: this.myConfig.readOnly,
433
+ children: tree,
434
+ selected: false
435
+ };
436
+
437
+ if (this.myConfig.rootNode.disabled !== undefined) {
438
+ root.disabled = this.myConfig.rootNode.disabled;
439
+ }
440
+ Object.assign(root, this.rootNode);
441
+
442
+ if (this.myConfig.showIcon) {
443
+ if (this.myConfig.idClass && this.myConfig.showIconList && this.myConfig.showIconList.length > 0) {
444
+ root[this.myConfig.idClass] = 0;
445
+ root = this.setIcon(root);
446
+ }
447
+ }
448
+
449
+ root.render = this.myConfig.nodeRender ? this.myConfig.nodeRender : this.iconRender;
450
+
451
+ this._autoExpandId = null;
452
+ return [root];
453
+ } else {
454
+ this._autoExpandId = null;
455
+ return tree;
456
+ }
457
+ },
458
+ setSelected (reTemp) {
459
+ if (this.myConfig.expand) {
460
+ reTemp.expand = this.myConfig.expand;
461
+ }
462
+ if (this.asyncLoad) {
463
+ if (Number(reTemp[this.myConfig.idClass]) !== Number(this.myConfig.maxClass)) {
464
+ reTemp.loading = false;
465
+ }
466
+ }
467
+ /*if (this.myConfig.keepExpand) {
468
+ let index = this.myConfig.expandData.findIndex(el => el === reTemp[this.myConfig.responseId]);
469
+ if (index > -1) {
470
+ reTemp.expand = true;
471
+ }
472
+ }*/
473
+ if (this.myConfig.showCodeWithName) {
474
+ reTemp.title = ' [' + reTemp[this.myConfig.responseCode] + '] ' + reTemp[this.myConfig.responseName];
475
+ } else {
476
+ reTemp.title = ' ' + reTemp[this.myConfig.responseName];
477
+ }
478
+ if (this.myConfig.readOnly) {
479
+ reTemp.disabled = true;
480
+ } else {
481
+ reTemp.disabled = false;
482
+ }
483
+ if (this.myConfig.setNodeDisabled) {
484
+ reTemp.disabled = this.myConfig.setNodeDisabled(reTemp);
485
+ }
486
+ if (this.myConfig.showIcon) {
487
+ if (this.myConfig.idClass && this.myConfig.showIconList && this.myConfig.showIconList.length > 0) {
488
+ reTemp = this.setIcon(reTemp);
489
+ }
490
+ }
491
+
492
+ if (this.myConfig.nodeRender) {
493
+ reTemp.render = this.myConfig.nodeRender;
494
+ } else{
495
+ reTemp.render = this.iconRender;
496
+ }
497
+ if (reTemp.children === undefined) {
498
+ reTemp.children= [];
499
+ } else {
500
+ let children = [];
501
+ reTemp.children.forEach(el => {
502
+ children.push(this.setSelected(el));
503
+ });
504
+ reTemp.children = children;
505
+ }
506
+ return reTemp;
507
+ },
508
+ refurbish(para) {
509
+ if(!para) {
510
+ para = {};
511
+ }
512
+ if (this.asyncLoad) {
513
+ para[this.myConfig.idClass] = 1;
514
+ }
515
+ let self = this;
516
+ self.synchroPost(self.myConfig.resources, self.myConfig.method, self.getSearchParam(para), function(data) {
517
+ let root = [];
518
+ if (data && data[self.myConfig.response]) {
519
+ if (self.checkData(data[self.myConfig.response])) {
520
+ root = data[self.myConfig.response];
521
+ } else {
522
+ return false;
523
+ }
524
+ }
525
+ if (self.myConfig.customData && self.myConfig.customData.length > 0) {
526
+ root = self.myConfig.customData.concat(root);
527
+ }
528
+ self.data = root;
529
+ self.treeData = self.toTreeData();
530
+ if (self.myConfig.selectedRoot) {
531
+ if (self.selectedData && self.selectedData.length === 0) {
532
+ self.selectedData.push(self.rootNode);
533
+ }
534
+ }
535
+ },null);
536
+ },
537
+ getAsyncNode(para){
538
+ let self = this;
539
+ let asyncData = [];
540
+ self.synchroPost(self.myConfig.resources, self.myConfig.method, self.getSearchParam(para), function(data) {
541
+ if (data && data[self.myConfig.response]) {
542
+ if (self.checkData(data[self.myConfig.response])) {
543
+ asyncData = data[self.myConfig.response];
544
+ }
545
+ }
546
+ },null);
547
+ return asyncData;
548
+ },
549
+ checkData(data) {
550
+ let index = data.findIndex(el => el[this.myConfig.idField] === el[this.myConfig.parentField]);
551
+ if (index > -1) {
552
+ this.alert('存在' + this.myConfig.idField +'与' + this.myConfig.parentField+'都为[' + data[index][this.myConfig.idField]+']的数据,请检查',null,2);
553
+ return false;
554
+ }
555
+ return true;
556
+ },
557
+ setReadOnly(flag) {
558
+ this.myConfig = Object.assign({},this.myConfig,{readOnly:flag});
559
+ },
560
+ getRootNode () {
561
+ return this.$Method.copy(this.rootNode);
562
+ },
563
+
564
+ getData() {
565
+ if (!this.treeData) return []
566
+
567
+ return this.myConfig.showCheckBox
568
+ ? this.getNodesByKey('checked', this.treeData)
569
+ : this.getNodesByKey('selected', this.treeData)
570
+ },
571
+ // getNodesByKey(key, data, result = []) {
572
+ // data.forEach(item => {
573
+ // if (item[key]) {
574
+ // result.push(item)
575
+ // }
576
+ // if (Array.isArray(item.children)) {
577
+ // this.getNodesByKey(key, item.children, result)
578
+ // }
579
+ // })
580
+ // return result
581
+ // },
582
+
583
+ getNodesByKey(key, data, result = []) {
584
+ data.forEach(item => {
585
+ if (item[key]) {
586
+ result.push(item)
587
+ }
588
+ if (Array.isArray(item.children) && item.children.length > 0) {
589
+ this.getNodesByKey(key, item.children, result)
590
+ }
591
+ })
592
+ return result
593
+ },
594
+
595
+
596
+ setData(data) {
597
+ this.selectedData = this.$Method.copy(data);
598
+ this.oldData = this.$Method.copy(data);
599
+ },
600
+ setDisplayData(data) {
601
+ if (this.checkData(data)) {
602
+ this.data = this.$Method.copy(data);
603
+ this.treeData = this.toTreeData();
604
+ }
605
+ },
606
+ clearExpand() {
607
+ this.myConfig.expandData = [];
608
+ },
609
+ setPro(data) {
610
+ if (data) {
611
+ this.myConfig = Object.assign({},this.myConfig,data);
612
+ }
613
+ },
614
+ getPro(name) {
615
+ return this.myConfig[name];
616
+ },
617
+ onSelectChange: function(res,node) { //点击树节点时触发返回当前已选中的节点数组
618
+ this.$emit('onSelectChange', res, node);
619
+ },
620
+ onCheckChange: function(res,node) { //勾选树节点时触发返回当前已勾选的节点数组
621
+ if (this.myConfig.showCheckBox) {
622
+ let obj = [];
623
+ res.forEach(el => {
624
+ let temp = {};
625
+ temp[this.myConfig.responseId] = el[this.myConfig.responseId];
626
+ obj.push(temp);
627
+ });
628
+ this.selectedData = this.$Method.copy(obj);
629
+ }
630
+ this.$emit('onCheckChange', res,node);
631
+ },
632
+ onToggleExpand: function(res) { //展开和收起子列表时触发返回当前节点的数据
633
+ /*if (res.expand) {
634
+ // 去重
635
+ let index = this.myConfig.expandData.findIndex(el => el === res[this.myConfig.responseId]);
636
+ if (index === -1) {
637
+ this.myConfig.expandData.push(res[this.myConfig.responseId])
638
+ }
639
+ } else {
640
+ let children = [];
641
+ this.getChildren(res,children);
642
+ // 收起当前节点
643
+ children.push(res[this.myConfig.responseId]);
644
+ children.forEach(el => {
645
+ let index2 = this.myConfig.expandData.findIndex(el2 => el === el2);
646
+ if (index2 > -1) {
647
+ this.myConfig.expandData.splice(index2, 1);
648
+ }
649
+ });
650
+ }*/
651
+ this.$emit('onToggleExpand', res);
652
+ },
653
+ getChildren(res,childrens) {
654
+ this.data.forEach(el => {
655
+ if (el[this.myConfig.parentField] === res[this.myConfig.idField]) {
656
+ childrens.push(el[this.myConfig.responseId]);
657
+ this.getChildren(el, childrens);
658
+ }
659
+ });
660
+ },
661
+ popValueChanged (para) {
662
+ let reData = [];
663
+ let self = this;
664
+ let searchParam = Object.assign({},self.getSearchParam(),para);
665
+ self.synchroPost(self.myConfig.resources,self.myConfig.method,searchParam,function(data) {
666
+ if (data && data[self.myConfig.response]) {
667
+ reData = data[self.myConfig.response];
668
+ }
669
+ },null);
670
+ return reData;
671
+ },
672
+ clearData() {
673
+ this.data = [];
674
+ this.oldData = [];
675
+ this.selectedData =[];
676
+ this.treeData = [];
677
+ this.conditionSearchParam = {};
678
+ this.myConfig.expandData = [];
679
+ },
680
+ getSelectedNodes() {
681
+ return this.$refs.tree.getSelectedNodes();
682
+ },
683
+
684
+ getCheckedNodes() {
685
+ if (!this.treeData) return []
686
+ return this.getNodesByKey('checked', this.treeData)
687
+ },
688
+
689
+ getCheckedAndIndeterminateNodes() {
690
+ return this.$refs.tree.getCheckedAndIndeterminateNodes();
691
+ },
692
+ isChange() {
693
+ // 初期值为空时,结果是否有值
694
+ let data = this.getData();
695
+ if (this.oldData.length === 0) {
696
+ if (data.length > 0) {
697
+ return true;
698
+ } else {
699
+ return false;
700
+ }
701
+ }
702
+ // 判断初期值是否在结果中
703
+ let resultFlag = false;
704
+ let tempflag = false;
705
+ this.oldData.forEach(el => {
706
+ tempflag = false;
707
+ data.forEach(el2 => {
708
+ if (el[this.myConfig.idField] === el2[this.myConfig.idField]) {
709
+ tempflag = true;
710
+ return;
711
+ }
712
+ });
713
+ if (!tempflag) {
714
+ resultFlag = true;
715
+ return;
716
+ }
717
+ });
718
+ if (resultFlag) {
719
+ return true;
720
+ }
721
+ // 初期值全部在结果中,是否多了新值
722
+ let num = 0;
723
+ data.forEach(el => {
724
+ if (el.children === undefined || (el.children && el.children.length === 0)) {
725
+ num++;
726
+ }
727
+ });
728
+ if (this.oldData.length !== num) {
729
+ return true;
730
+ } else {
731
+ return false;
732
+ }
733
+ },
734
+ setSearchBeforeSearchParam(obj) {
735
+ this.searchBeforeSearchParam = Object.assign({},{},obj);
736
+ },
737
+ clearSearchBeforeSearchParam() {
738
+ this.searchBeforeSearchParam = {};
739
+ },
740
+ getFatherNode(node) {
741
+ if (!node || !node[this.myConfig.parentField]) {
742
+ return {};
743
+ }
744
+ if (this.data && this.data.length > 0) {
745
+ const index = this.data.findIndex(el => el[this.myConfig.idField] === node[this.myConfig.parentField]);
746
+ if (index > -1) {
747
+ return this.$Method.copy(this.data[index]);
748
+ } else {
749
+ return {};
750
+ }
751
+ }
752
+ },
753
+ isChildren (node) {
754
+ let flag = false;
755
+ if (this.data && this.data.length > 0) {
756
+ const index = this.data.findIndex(el => el[this.myConfig.parentField] === node[this.myConfig.idField]);
757
+ if (index > -1) {
758
+ flag = true;
759
+ }
760
+ }
761
+ return flag;
762
+ },
763
+ setExtraHeight () {
764
+ let height = 0;
765
+ if (this.$refs.condition) {
766
+ height = this.$refs.condition.offsetHeight;
767
+ }
768
+ this.extraHeight = height;
769
+ },
770
+ setOutsideHeight(value) {
771
+ this.outsideHeight = value;
772
+ },
773
+ setAllNode(name, value) {
774
+ let tempName = name;
775
+ if (name === 'readOnly') {
776
+ tempName = 'disabled';
777
+ } else if (name === 'selected') {
778
+ if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
779
+ tempName ='checked';
780
+ } else {
781
+ tempName = 'selected';
782
+ }
783
+ }
784
+ const updateNode = (nodes) => {
785
+ if (!nodes) return
786
+
787
+ nodes.forEach(node => {
788
+ if (node[tempName] !== value) {
789
+ node[tempName] = value
790
+ }
791
+
792
+ if (node.children && node.children.length > 0) {
793
+ updateNode(node.children)
794
+ }
795
+ })
796
+ }
797
+
798
+ updateNode(this.data)
799
+
800
+ },
801
+
802
+ setNodes(data, name, value) {
803
+ let tempName = name;
804
+ if (name === 'readOnly') {
805
+ tempName = 'disabled';
806
+ } else if (name === 'selected') {
807
+ if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
808
+ tempName ='checked';
809
+ } else {
810
+ tempName = 'selected';
811
+ }
812
+ }
813
+ let responseId = this.myConfig.responseId;
814
+ this.$refs.tree.flatState.forEach(el => {
815
+ let index = data.findIndex(
816
+ el2 => el.node[responseId] === el2[responseId]
817
+ );
818
+ if (index > -1) {
819
+ if (el.node[tempName] !== value) {
820
+ let obj ={};
821
+ obj[tempName] = value;
822
+ Object.assign(el.node,obj);
823
+ }
824
+ } else {
825
+ if (el.node[tempName] !== !value) {
826
+ let obj ={};
827
+ obj[tempName] = !value;
828
+ Object.assign(el.node,obj);
829
+ }
830
+ }
831
+ });
832
+ },
833
+
834
+ setNodese(data = [], name, value) {
835
+ let tempName = name;
836
+ if (name === 'readOnly') {
837
+ tempName = 'disabled';
838
+ } else if (name === 'selected') {
839
+ tempName = (this.myConfig.multiSelect && this.myConfig.showCheckBox) ? 'checked' : 'selected';
840
+ }
841
+
842
+ const responseId = this.myConfig.idField || this.myConfig.responseId;
843
+
844
+ // 统一字符串,避免 1 / "1" 不匹配
845
+ const idSet = new Set(
846
+ (data || []).map(item => String(item?.[responseId]))
847
+ );
848
+
849
+ // 确认真实渲染源
850
+ const source = Array.isArray(this.data)
851
+ ? this.data
852
+ : (Array.isArray(this.treeData) ? this.treeData : []);
853
+
854
+ let hitCount = 0;
855
+
856
+ const updateNode = (nodes) => {
857
+ if (!Array.isArray(nodes)) return;
858
+
859
+ nodes.forEach(node => {
860
+ const exists = idSet.has(String(node?.[responseId]));
861
+ if (exists) hitCount++;
862
+
863
+ let newValue;
864
+
865
+ // 只有“选中=true”时,才清空其他节点(单选常见需求)
866
+ if (name === 'selected' && value === true) {
867
+ newValue = exists;
868
+ } else if (exists) {
869
+ // 其他场景只改命中节点
870
+ newValue = value;
871
+ } else {
872
+ newValue = node[tempName];
873
+ }
874
+
875
+ if (node[tempName] !== newValue) {
876
+ // Vue2: 动态键必须用 $set 才响应
877
+ // this.$set(node, tempName, newValue);
878
+ node[tempName] = newValue;
879
+ }
880
+
881
+ if (node.children && node.children.length > 0) {
882
+ updateNode(node.children);
883
+ }
884
+ });
885
+ };
886
+
887
+ updateNode(source);
888
+
889
+ // 兜底触发视图更新
890
+ if (source === this.data) this.data = [...source];
891
+ if (source === this.treeData) this.treeData = [...source];
892
+
893
+ console.log('[setNodes]', { tempName, responseId, targetIds: [...idSet], hitCount });
894
+ return hitCount;
895
+ },
896
+ setNodes2(data, name, value) {
897
+ let tempName = name;
898
+ if (name === 'readOnly') {
899
+ tempName = 'disabled';
900
+ } else if (name === 'selected') {
901
+ if (this.myConfig.multiSelect && this.myConfig.showCheckBox) {
902
+ tempName ='checked';
903
+ } else {
904
+ tempName = 'selected';
905
+ }
906
+ }
907
+ let responseId = this.myConfig.idField || this.myConfig.responseId;
908
+ // 把目标列表变成 Set,提高查找效率
909
+ const idSet = new Set(
910
+ data.map(item => item[responseId])
911
+ )
912
+
913
+ const updateNode = (nodes) => {
914
+ if (!nodes) return
915
+
916
+ nodes.forEach(node => {
917
+
918
+ const exists = idSet.has(node[responseId])
919
+
920
+ const newValue = exists ? value : !value
921
+
922
+ if (node[tempName] !== newValue) {
923
+ node[tempName] = newValue
924
+ }
925
+
926
+ if (node.children && node.children.length > 0) {
927
+ updateNode(node.children)
928
+ }
929
+
930
+ })
931
+ }
932
+
933
+ updateNode(this.data)
934
+ },
935
+ saveExpandState() {
936
+ const expandSet = new Set();
937
+
938
+ const loop = (nodes) => {
939
+ if (!nodes) return;
940
+
941
+ nodes.forEach(node => {
942
+ if (node.expand) {
943
+ expandSet.add(node[this.myConfig.idField]);
944
+ }
945
+ if (node.children && node.children.length) {
946
+ loop(node.children);
947
+ }
948
+ });
949
+ };
950
+
951
+ loop(this.treeData);
952
+
953
+ return expandSet;
954
+ },
955
+ updateNode(data, flag) {
956
+ const idField = this.myConfig.idField
957
+ const parentField = this.myConfig.parentField
958
+ const targetId = data[idField]
959
+
960
+ // ① 保存当前展开状态
961
+ const expandSet = this.saveExpandState()
962
+ // ② 数据更新
963
+ const index = this.data.findIndex(
964
+ el => el[idField] === targetId
965
+ )
966
+
967
+ if (flag === 'U') {
968
+ if (index > -1) {
969
+ Object.assign(this.data[index], data)
970
+ } else {
971
+ this.data.push(data)
972
+
973
+ // ===== 新增时自动展开父链 =====
974
+ let parentId = data[parentField]
975
+
976
+ while (parentId) {
977
+ expandSet.add(parentId)
978
+
979
+ const parent = this.data.find(
980
+ el => el[idField] === parentId
981
+ )
982
+
983
+ if (!parent) break
984
+
985
+ parentId = parent[parentField]
986
+ }
987
+ }
988
+ }
989
+
990
+ if (flag === 'D') {
991
+ if (index > -1) {
992
+ this.data.splice(index, 1)
993
+ }
994
+ }
995
+ // ③ 重建树(带展开状态)
996
+ this.treeData = this.toTreeData(expandSet, targetId)
997
+ },
998
+ updateNodeod(data,flag) {
999
+ let tmp = data;
1000
+ if(flag !== 'D') {
1001
+ tmp = this.setSelected(data);
1002
+ }
1003
+ tmp.selected = true;
1004
+ if (this.$refs.tree && this.$refs.tree.flatState) {
1005
+ let index = -1;
1006
+ if (flag === 'U') {
1007
+ index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.idField]);
1008
+ if (index > -1) {
1009
+ if (this.$refs.tree.flatState[index].node.children && this.$refs.tree.flatState[index].node.children.length > 0) {
1010
+ delete tmp.children;
1011
+ }
1012
+ Object.assign(this.$refs.tree.flatState[index].node,tmp);
1013
+ } else {
1014
+ index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.parentField]);
1015
+ if (index > -1) {
1016
+ if (!this.$refs.tree.flatState[index].node.children){
1017
+ this.$refs.tree.flatState[index].node.children = [];
1018
+ }
1019
+ this.$refs.tree.flatState[index].node.children.forEach(el2 => {
1020
+ let tmpIndex = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === el2[this.myConfig.idField] && el.node.selected);
1021
+ if (tmpIndex > -1) {
1022
+ Object.assign(this.$refs.tree.flatState[tmpIndex].node,{selected:false});
1023
+ }
1024
+ });
1025
+ Object.assign(this.$refs.tree.flatState[index].node,{selected:false, expand:true});
1026
+ this.$refs.tree.flatState[index].node.children.push(tmp)
1027
+ }
1028
+ }
1029
+ }
1030
+ if (flag === 'D') {
1031
+ index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === tmp[this.myConfig.parentField]);
1032
+ if (index > -1) {
1033
+ let tmpIndex = this.$refs.tree.flatState[index].node.children.findIndex(el => el[this.myConfig.idField] === tmp[this.myConfig.idField]);
1034
+ if (tmpIndex > -1) {
1035
+ this.$refs.tree.flatState[index].node.children.splice(tmpIndex, 1);
1036
+ if (this.$refs.tree.flatState[index].node.children.length === 0) {
1037
+ Object.assign(this.$refs.tree.flatState[index].node,{expand:false});
1038
+ }
1039
+ }
1040
+ }
1041
+ }
1042
+ }
1043
+ this.treeData = [...this.treeData];
1044
+ },
1045
+ setExpend(data) {
1046
+ let index = this.$refs.tree.flatState.findIndex(el => el.node[this.myConfig.idField] === data[this.myConfig.idField]);
1047
+ if (index > -1) {
1048
+ let tmp = {expand:!this.$refs.tree.flatState[index].node.expand};
1049
+ if (tmp.expand && this.asyncLoad) {
1050
+ if (!this.$refs.tree.flatState[index].node.loading && this.$refs.tree.flatState[index].node.children.length === 0) {
1051
+ tmp.loading = true;
1052
+ };
1053
+ let callback = (data) => {
1054
+ data.forEach(el => {
1055
+ el.selected = false;
1056
+ this.$refs.tree.flatState[index].node.children.push(el);
1057
+ })
1058
+ Object.assign(this.$refs.tree.flatState[index].node,{loading:false});
1059
+ }
1060
+ if (this.$refs.tree.flatState[index].node.children.length === 0){
1061
+ this.loadData(data,callback);
1062
+ }
1063
+
1064
+ }
1065
+ Object.assign(this.$refs.tree.flatState[index].node,tmp);
1066
+ }
1067
+ },
1068
+ loadData (item, callback) {
1069
+ let para = {};
1070
+ para[this.myConfig.parentField] = item[this.myConfig.idField];
1071
+ let data = this.getAsyncNode(para);
1072
+ setTimeout(() => {
1073
+ data.forEach(el => {
1074
+ this.setSelected(el);
1075
+ });
1076
+ callback(data);
1077
+ }, 200);
1078
+ }
1079
+ },
1080
+ mounted () {
1081
+ //this._setCustomHeight(this.clientHeight);
1082
+ },
1083
+ watch: {
1084
+ 'myConfig.readOnly':function(val){
1085
+ this.setAllNode('readOnly', val);
1086
+ },
1087
+ selectedData:function (val) {
1088
+ this.setNodes(val,'selected', true);
1089
+ }
1090
+ }
1091
+ };
1092
+ </script>
1093
+ <style>
1094
+ .efutre-tree-node .ivu-tree-title{
1095
+ width: 95%;
1096
+ padding-left: 2px;
1097
+ }
1098
+ </style>