@idooel/components 0.0.2-beta.12 → 0.0.2-beta.13

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 (111) hide show
  1. package/README.md +98 -98
  2. package/dist/@idooel/components.esm.js +960 -248
  3. package/dist/@idooel/components.umd.js +963 -251
  4. package/jsconfig.json +7 -7
  5. package/package.json +61 -61
  6. package/packages/alert/index.js +4 -4
  7. package/packages/alert/src/index.vue +45 -45
  8. package/packages/batch-export/index.js +4 -4
  9. package/packages/batch-export/src/index.vue +104 -104
  10. package/packages/business-components/modal-fsm/index.js +4 -4
  11. package/packages/business-components/modal-fsm/src/index.vue +163 -163
  12. package/packages/business-components/modal-import/index.js +4 -4
  13. package/packages/business-components/modal-import/src/index.vue +139 -139
  14. package/packages/business-components/modal-timeline/index.js +4 -4
  15. package/packages/business-components/modal-timeline/src/index.vue +77 -77
  16. package/packages/business-components/tabs-sub-center/index.js +4 -4
  17. package/packages/business-components/tabs-sub-center/src/index.vue +116 -116
  18. package/packages/button/index.js +4 -4
  19. package/packages/button/src/index.vue +65 -65
  20. package/packages/checkbox/index.js +4 -4
  21. package/packages/checkbox/src/index.vue +52 -52
  22. package/packages/composite-components/button-group/index.js +4 -4
  23. package/packages/composite-components/button-group/src/index.vue +151 -151
  24. package/packages/composite-components/form-attachment/src/index.vue +14 -14
  25. package/packages/composite-components/form-img-crop/index.js +4 -4
  26. package/packages/composite-components/form-img-crop/src/index.vue +131 -131
  27. package/packages/composite-components/modal-confirm/index.js +4 -4
  28. package/packages/composite-components/modal-confirm/src/index.vue +103 -103
  29. package/packages/composite-components/modal-form/index.js +4 -4
  30. package/packages/composite-components/modal-form/src/index.vue +230 -230
  31. package/packages/composite-components/modal-img-crop/index.js +4 -4
  32. package/packages/composite-components/modal-img-crop/src/index.vue +298 -298
  33. package/packages/composite-components/modal-table/index.js +4 -4
  34. package/packages/composite-components/modal-table/src/index.vue +155 -155
  35. package/packages/composite-components/modal-tree/index.js +4 -4
  36. package/packages/composite-components/modal-tree/src/index.vue +75 -75
  37. package/packages/composite-components/search-area/index.js +4 -4
  38. package/packages/composite-components/search-area/src/index.vue +238 -237
  39. package/packages/composite-components/search-area/src/label.vue +35 -35
  40. package/packages/composite-components/select-entity-modal-table/index.js +4 -4
  41. package/packages/composite-components/select-entity-modal-table/src/index.vue +171 -171
  42. package/packages/date/index.js +4 -4
  43. package/packages/date/src/index.vue +112 -112
  44. package/packages/date-range/index.js +4 -4
  45. package/packages/date-range/src/index.vue +47 -47
  46. package/packages/form/index.js +4 -4
  47. package/packages/form/src/index.vue +319 -319
  48. package/packages/icon/index.js +4 -4
  49. package/packages/icon/src/index.vue +31 -31
  50. package/packages/index.js +156 -153
  51. package/packages/input/index.js +4 -4
  52. package/packages/input/src/index.vue +35 -35
  53. package/packages/input-number/index.js +4 -4
  54. package/packages/input-number/src/index.vue +23 -23
  55. package/packages/loading/index.js +4 -4
  56. package/packages/loading/src/index.vue +36 -36
  57. package/packages/meta/provider.js +4 -0
  58. package/packages/modal/index.js +4 -4
  59. package/packages/modal/src/index.vue +184 -184
  60. package/packages/models/form-group-model/index.js +4 -4
  61. package/packages/models/form-group-model/src/index.vue +273 -273
  62. package/packages/models/form-model/index.js +4 -4
  63. package/packages/models/form-model/src/index.vue +236 -236
  64. package/packages/models/step-model/index.js +4 -4
  65. package/packages/models/step-model/src/index.vue +224 -224
  66. package/packages/models/tree-table-model/index.js +4 -4
  67. package/packages/models/tree-table-model/src/index.vue +806 -764
  68. package/packages/radio/index.js +4 -4
  69. package/packages/radio/src/index.vue +56 -56
  70. package/packages/select/index.js +4 -4
  71. package/packages/select/src/index.vue +105 -105
  72. package/packages/select-entity/index.js +4 -4
  73. package/packages/select-entity/src/index.vue +119 -119
  74. package/packages/table/index.js +4 -4
  75. package/packages/table/src/action.vue +172 -172
  76. package/packages/table/src/index.vue +339 -319
  77. package/packages/tabs/index.js +4 -4
  78. package/packages/tabs/src/index.vue +55 -55
  79. package/packages/text/index.js +4 -4
  80. package/packages/text/src/index.vue +47 -47
  81. package/packages/text-editor/index.js +4 -4
  82. package/packages/text-editor/src/index.vue +72 -72
  83. package/packages/textarea/index.js +4 -4
  84. package/packages/textarea/src/index.vue +57 -57
  85. package/packages/theme/form.scss +21 -21
  86. package/packages/theme/index.scss +43 -43
  87. package/packages/theme/overrid.scss +7 -7
  88. package/packages/theme/styleClass.scss +2 -2
  89. package/packages/theme/variables.scss +55 -55
  90. package/packages/timeline/index.js +4 -4
  91. package/packages/timeline/src/index.vue +257 -257
  92. package/packages/tpl/index.js +4 -4
  93. package/packages/tpl/src/index.vue +55 -55
  94. package/packages/tree/index.js +4 -4
  95. package/packages/tree/src/TreeNode.vue +29 -29
  96. package/packages/tree/src/index.vue +101 -101
  97. package/packages/tree-select/index.js +4 -4
  98. package/packages/tree-select/src/index.vue +142 -142
  99. package/packages/upload/index.js +4 -4
  100. package/packages/upload/src/index.vue +996 -996
  101. package/packages/utils/index.js +66 -62
  102. package/packages/utils/runtime-context/dataPoolAPI.js +501 -0
  103. package/packages/utils/runtime-context/globalDataPool.js +279 -0
  104. package/packages/utils/runtime-context/index.js +76 -0
  105. package/packages/utils/runtime-context/modelSchema.js +174 -0
  106. package/scripts/rollup.config.js +42 -42
  107. package/scripts/rollup.esm.config.js +11 -11
  108. package/scripts/rollup.umd.config.js +17 -17
  109. package/vitest.config.js +17 -17
  110. package/packages/utils/dataPool.js +0 -22
  111. package/packages/utils/treeTableDataPoolManager.js +0 -85
@@ -1,764 +1,806 @@
1
- <template>
2
- <section class="ele model__tree-table">
3
- <section class="model__tree-table--container" v-if="showTree">
4
- <div class="model__tree--title"></div>
5
- <section :ref="modelTreeWrapper" class="model__tree--wrapper" :style="{height: `${treeWrapperHeight}px`}">
6
- <ele-tree
7
- :tree-data="treeData"
8
- :defaultExpandedKeys="defaultExpandedKeys"
9
- :defaultSelectedKeys="defaultSelectedKeys"
10
- @select="selectTreeNode"
11
- :replace-fields="mapFields">
12
- </ele-tree>
13
- </section>
14
- </section>
15
- <section class="model__table--container" :ref="modelTableContainerRef">
16
- <div class="model__table--title" v-if="title">
17
- <template v-if="titleMode">
18
- <div :class="[`model__table-title--${titleMode}`]"></div>
19
- </template>
20
- <template v-else>
21
- <div class="model__table-title--text">{{ title }}</div>
22
- </template>
23
- </div>
24
- <section :ref="modelTableWrapper" class="model__table--wrapper">
25
- <ele-search-area :ref="searchArea" @search="onSearch" :data-source="searchMeta.elements"></ele-search-area>
26
- <div class="button-row__area">
27
- <ele-button-group class="model-table__button-group" v-on="overrideButtonGroupEvent" :ref="buttonGroup" @click="handleClickButtonGroup" :data-source="getButtonGroupElements"></ele-button-group>
28
- <slot name="tags"></slot>
29
- <slot v-if="$slots['sub-center']" name="sub-center"></slot>
30
- </div>
31
- <ele-table
32
- v-on="overrideTableEvent"
33
- :ref="tableRef"
34
- :row-selection="rowSelection"
35
- :loading="loading"
36
- :columns="columns"
37
- :total="total"
38
- :x="x"
39
- :y="y"
40
- :bordered="setBorder"
41
- :height="tableHeight"
42
- :width="tableWidth"
43
- :actions="actions"
44
- :pageSize="pageSize"
45
- :pageSizeOptions="pageSizeOptions"
46
- :data-source="tableData"
47
- @change-page="onChangePage"
48
- ></ele-table>
49
- </section>
50
- </section>
51
- <ele-modal-form v-model="modalFormValue" v-on="overrideModalFormEvent" :meta="modalFormMeta"></ele-modal-form>
52
- <ele-modal-fsm v-model="showFsmModal" :contextProp="fsmContextProp" :meta="fsmMeta" @cancel="handleCloseFsmModal"></ele-modal-fsm>
53
- <ele-modal-table
54
- :meta="modalTableMeta"
55
- v-model="modalTableValue"
56
- v-on="overrideModalTableEvent"
57
- ></ele-modal-table>
58
- </section>
59
- </template>
60
-
61
- <script>
62
- import { type, net } from '@idooel/shared'
63
- import { v4 as uuidv4 } from 'uuid'
64
- import { BUILT_IN_EVENT_NAMES, RESERVE_EVENT_NAMES, parseFieldMap, BUILT_IN_TRIGGER, CONTEXT } from '../../../utils'
65
- import { TreeTableDataPoolManager } from '../../../utils/treeTableDataPoolManager'
66
- export default {
67
- name: 'ele-tree-table-model',
68
- props: {
69
- title: {
70
- type: [Object, String]
71
- },
72
- overHeight: {
73
- type: Number,
74
- default: 0
75
- },
76
- treeMeta: {
77
- type: Object,
78
- default: () => ({})
79
- },
80
- searchMeta: {
81
- type: Object,
82
- default: () => ({})
83
- },
84
- buttonGroupMeta: {
85
- typeof: Object,
86
- default: () => ({})
87
- },
88
- tableMeta: {
89
- type: Object,
90
- default: () => ({})
91
- },
92
- createMeta: {
93
- type: Object
94
- },
95
- editMeta: {
96
- type: Object
97
- }
98
- },
99
- provide () {
100
- return {
101
- requestTreeData: this.requestTreeData,
102
- requestTableData: this.requestTableData,
103
- [CONTEXT]: () => {
104
- return {
105
- exposed: this.exposed
106
- }
107
- }
108
- }
109
- },
110
- data () {
111
- return {
112
- tableHeight: 0,
113
- tableWidth: 0,
114
- modalFormMeta: {},
115
- modalFormValue: false,
116
- treeData: [],
117
- tableData: [],
118
- defaultExpandedKeys: [],
119
- defaultSelectedKeys: [],
120
- replaceFields: {
121
- title: 'title',
122
- children: 'children',
123
- key: 'id'
124
- },
125
- loading: false,
126
- total: 0,
127
- tableQuerys: {},
128
- resizeObserverModelTableWrapper: null,
129
- modelTableWrapperHeight: 0,
130
- currentTreeNodeData: {},
131
- currentRowData: {},
132
- treeWrapperHeight: 0,
133
- currentTableSelection: this.currentTableMode == 'radio' ? {} : [],
134
- showFsmModal: false,
135
- fsmMeta: {},
136
- fsmContextProp: {},
137
- modalTableValue: false,
138
- modalTableMeta: {},
139
- dataPoolManager: null
140
- }
141
- },
142
- computed: {
143
- setBorder () {
144
- return this.tableMeta.bordered === false ? false : true
145
- },
146
- rowSelection () {
147
- if (!this.currentTableMode) return void 0
148
- return {
149
- columnTitle: this.currentSelectionColumn.columnTitle,
150
- fixed: true,
151
- type: this.currentTableMode,
152
- onChange: this.onChangeTableSelection
153
- }
154
- },
155
- currentSelectionColumn () {
156
- const { multiple } = this.tableMeta
157
- const target = this.columns.find(item => Object.keys(item).includes('multiple'))
158
- const isGlobalExistMultiple = Object.keys(this.tableMeta).includes('multiple')
159
- if (target) {
160
- return target
161
- } else if (isGlobalExistMultiple) {
162
- return { multiple }
163
- }
164
- return void 0
165
- },
166
- x () {
167
- const { x } = this.tableMeta
168
- return x
169
- },
170
- y () {
171
- const { y } = this.tableMeta
172
- return y
173
- },
174
- currentTableMode () {
175
- if (!this.currentSelectionColumn) return void 0
176
- const { multiple } = this.currentSelectionColumn
177
- if (type.isBool(multiple)) {
178
- if (multiple) {
179
- return 'checkbox'
180
- } else {
181
- return 'radio'
182
- }
183
- } else {
184
- return void 0
185
- }
186
- },
187
- modelTableContainerRef () {
188
- return uuidv4()
189
- },
190
- titleMode () {
191
- if (type.isObject(this.title)) {
192
- const { mode = '' } = this.title
193
- return mode
194
- }
195
- return void 0
196
- },
197
- tableRef () {
198
- return uuidv4()
199
- },
200
- exposed () {
201
- return {
202
- showModalForm: this.showModalForm,
203
- closeModalForm: this.closeModalForm,
204
- showModalTable: this.showModalTable,
205
- closeModalTable: this.closeModalTable,
206
- currentTableSelection: this.currentTableSelection,
207
- currentTreeNode: this.currentTreeNodeData,
208
- requestTableData: this.requestTableData,
209
- refreshTreeData: this.refreshTreeData,
210
- querys: this.tableQuerys,
211
- currentRowData: this.getCurrentRowData(),
212
- getCurrentRowData: this.getCurrentRowData,
213
- setCurrentRowData: this.setCurrentRowData,
214
- setCurrentTableSelection: this.setCurrentTableSelection,
215
- getCurrentTableSelection: this.getCurrentTableSelection,
216
- cleanCurrentModelEffect: this.cleanCurrentModelEffect,
217
- route: this.$route,
218
- _route: this.$route.query,
219
- _routeMeta: this.$route.meta,
220
- dataPool: this.dataPoolManager.getDataPool(),
221
- dataPoolManager: this.dataPoolManager
222
- }
223
- },
224
- overrideTableEvent () {
225
- const events = this.actions.reduce((ret, action) => {
226
- ret[action.eventName || action.key] = (e) => {
227
- this.setCurrentRowData(e.exposed.currentRowData)
228
- const { target } = action
229
- const targetMeta = this.findMetaByKey(target)
230
- const { mode } = targetMeta
231
- mode && this.dispatchTrigger({ mode, record: e.exposed.currentRowData, modeMeta: targetMeta })
232
- this.$emit(action.eventName || action.key, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: { ...this.exposed, ...e.exposed } })
233
- }
234
- return ret
235
- }, {})
236
- return {
237
- ...this.$listeners,
238
- ...events,
239
- [BUILT_IN_EVENT_NAMES.EDIT]: this[BUILT_IN_EVENT_NAMES.EDIT],
240
- [BUILT_IN_EVENT_NAMES.SUBMIT]: this[BUILT_IN_EVENT_NAMES.SUBMIT]
241
- }
242
- },
243
- overrideModalFormEvent () {
244
- const { footerMeta } = this.modalFormMeta
245
- const { elements = [] } = footerMeta || {}
246
- const eles = type.isFunction(elements) ? elements.call(this) : elements
247
- const events = eles.reduce((ret, ele) => {
248
- ret[ele.eventName] = (e = {}) => {
249
- if (ele.eventName === 'cancel') {
250
- this.closeModalForm()
251
- } else {
252
- const { exposed = {} } = e
253
- this.$emit(`${ele.eventName || ele.key}`, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, exposed )})
254
- }
255
- }
256
- return ret
257
- }, {})
258
- return {
259
- ...events
260
- }
261
- },
262
- overrideModalTableEvent () {
263
- const { footerMeta } = this.modalTableMeta
264
- const { elements = [] } = footerMeta || {}
265
- const eles = type.isFunction(elements) ? elements.call(this) : elements
266
- const events = eles.reduce((ret, ele) => {
267
- ret[ele.eventName] = (e = {}) => {
268
- if (ele.eventName === 'cancel') {
269
- this.closeModalTable()
270
- } else {
271
- const { exposed = {} } = e
272
- this.$emit(`${ele.eventName || ele.key}`, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, exposed )})
273
- }
274
- }
275
- return ret
276
- }, {})
277
- return {
278
- ...events,
279
- exposed: this.exposed
280
- }
281
- },
282
- overrideButtonGroupEvent () {
283
- const events = this.getButtonGroupElements.reduce((ret, ele) => {
284
- ret[ele.eventName] = (e) => {
285
- this.$emit(ele.eventName || 'click', { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, e.exposed || {}, this.exposed)})
286
- }
287
- return ret
288
- }, {})
289
- return {
290
- ...this.$listeners,
291
- ...events,
292
- [BUILT_IN_EVENT_NAMES.CREATE]: this[BUILT_IN_EVENT_NAMES.CREATE],
293
- exposed: this.exposed
294
- }
295
- },
296
- showTree () {
297
- return !!Object.keys(this.treeMeta).length
298
- },
299
- buttonGroup () {
300
- return uuidv4()
301
- },
302
- searchArea () {
303
- return uuidv4()
304
- },
305
- modelTreeWrapper () {
306
- return uuidv4()
307
- },
308
- modelTableWrapper () {
309
- return uuidv4()
310
- },
311
- actions () {
312
- const { operations } = this.tableMeta
313
- if (operations) {
314
- return operations.elements
315
- } else {
316
- return []
317
- }
318
- },
319
- pageSize () {
320
- const { page = {} } = this.tableMeta
321
- return page.pageSize || 10
322
- },
323
- pageSizeOptions () {
324
- const { page = {} } = this.tableMeta
325
- return page.pageSizeOptions || ['10', '20', '30', '40']
326
- },
327
- columns () {
328
- const { columns, operations } = this.tableMeta
329
- if (type.get(columns) === 'array') {
330
- const columnsOptions = columns.map(item => {
331
- const { mode = 'text' } = item
332
- if (item.render) {
333
- return {
334
- ...item,
335
- customRender: (text, record, index) => {
336
- const { $createElement } = this
337
- return item.render.call(this,
338
- { h: $createElement, ctx: this },
339
- text ? typeof text == 'object' ? text[item.dataIndex] : text : '',
340
- record, index)
341
- }
342
- }
343
- } else if (mode !== BUILT_IN_TRIGGER.TEXT) {
344
- const { [`${mode}Meta`]: modeMeta } = item
345
- return {
346
- ...item,
347
- customRender: (text, record, index) => {
348
- return <span onClick={() => this.dispatchTrigger({ mode, record, modeMeta, index })} class={ mode }>{ text }</span>
349
- }
350
- }
351
- }
352
- return {
353
- ...item
354
- }
355
- })
356
- if (operations) {
357
- return [
358
- ...columnsOptions,
359
- {
360
- title: '操作',
361
- width: operations.width,
362
- key: 'action',
363
- fixed: 'right',
364
- scopedSlots: { customRender: 'action' }
365
- }
366
- ]
367
- }
368
- return columnsOptions
369
- } else {
370
- console.error('Error: columns is invalid, please check it')
371
- return []
372
- }
373
- },
374
- getButtonGroupElements () {
375
- const { elements } = this.buttonGroupMeta
376
- if (type.get(elements) === 'function') {
377
- return elements.call(this)
378
- } else if (type.get(elements) === 'array') {
379
- return elements
380
- } else {
381
- return []
382
- }
383
- },
384
- mapFields () {
385
- const { replaceFields = {} } = this.treeMeta
386
- const mapFields = type.isEmpty(replaceFields) ? this.replaceFields : replaceFields
387
- return mapFields
388
- }
389
- },
390
- async created () {
391
- // 初始化数据池管理器
392
- const instanceId = `treeTableModel_${uuidv4()}`
393
- this.dataPoolManager = new TreeTableDataPoolManager(instanceId)
394
-
395
- // 初始化 currentRowData(尝试从共享命名空间获取)
396
- this.initializeCurrentRowData()
397
-
398
- // 订阅数据池变化
399
- this.dataPoolManager.subscribe((event) => {
400
- this.currentRowData = event.value || {}
401
- this.$forceUpdate()
402
- })
403
-
404
- // 订阅共享数据变化
405
- this.dataPoolManager.subscribeShared((event) => {
406
- // 当有新的共享数据时,更新当前组件的 currentRowData
407
- if (event.value && Object.keys(event.value).length > 0) {
408
- this.setCurrentRowData(event.value)
409
- }
410
- })
411
-
412
- if (this.showTree) {
413
- this.treeData = await this.requestTreeData()
414
- const [defaultTreeNode = {}] = this.treeData
415
- this.defaultExpandedKeys = [defaultTreeNode[this.mapFields.key]]
416
- this.defaultSelectedKeys = [defaultTreeNode[this.mapFields.key]]
417
- this.currentTreeNodeData = defaultTreeNode
418
- }
419
-
420
- const { params = {}, fieldMap = {}, overrideInit = false } = this.tableMeta
421
- const currentRowData = this.getCurrentRowData()
422
- const ctx = {
423
- ...this.currentTreeNodeData,
424
- _route: this.$route.query,
425
- currentRowData: currentRowData
426
- }
427
-
428
- const initQuerys = Object.assign({}, params, parseFieldMap(fieldMap, ctx))
429
- if (overrideInit) {
430
- this.$emit(RESERVE_EVENT_NAMES.INIT, { ...this.exposed })
431
- } else {
432
- this.tableData = await this.requestTableData(initQuerys)
433
- }
434
- },
435
- methods: {
436
- initializeCurrentRowData () {
437
- // 检查是否有来自父组件的共享数据(比如 modal table 场景)
438
- const parentData = this.dataPoolManager.getSharedData()
439
-
440
- if (parentData && Object.keys(parentData).length > 0) {
441
- this.setCurrentRowData(parentData)
442
- return
443
- }
444
-
445
- // 可以根据路由参数、props 或其他来源设置初始的 currentRowData
446
- const { query } = this.$route
447
-
448
- // 示例:如果路由中有特定参数,可以设置为 currentRowData
449
- if (query.rowId || query.selectedId) {
450
- // 这里可以根据实际需求从服务端或其他地方获取数据
451
- // const presetData = { id: query.rowId, /* 其他字段 */ }
452
- // this.setCurrentRowData(presetData)
453
- }
454
-
455
- // 目前保持空对象,等待用户选择行数据
456
- },
457
- async refreshTreeData () {
458
- this.treeData = await this.requestTreeData()
459
- const [defaultTreeNode = {}] = this.treeData
460
- this.defaultExpandedKeys = [defaultTreeNode[this.mapFields.key]]
461
- this.defaultSelectedKeys = [defaultTreeNode[this.mapFields.key]]
462
- this.currentTreeNodeData = defaultTreeNode
463
- },
464
- dispatchTrigger ({ mode, record = {}, modeMeta = { } }) {
465
- switch (mode) {
466
- case BUILT_IN_TRIGGER.FSM:
467
- this[`${BUILT_IN_TRIGGER.FSM}Trigger`](record, modeMeta = type.isEmpty(modeMeta) ? {
468
- url: 'api-fsm/workbench/fsm/auditFlow',
469
- requestType: 'GET',
470
- fieldMap: {
471
- modelCode: 'modelCode',
472
- businessId: 'businessId'
473
- }
474
- } : modeMeta)
475
- break
476
- case BUILT_IN_TRIGGER.ELE_MODAL_FORM:
477
- this.modalFormMeta = modeMeta
478
- this.showModalForm(modeMeta)
479
- break
480
- case BUILT_IN_TRIGGER.ELE_MODAL_TABLE:
481
- this.modalTableMeta = modeMeta
482
- // 将当前行的 record 数据传递给 modal table
483
- this.showModalTable(modeMeta, record)
484
- break
485
- default:
486
- break
487
- }
488
- },
489
- handleCloseFsmModal () {
490
- this.showFsmModal = false
491
- },
492
- [`${BUILT_IN_TRIGGER.FSM}Trigger`] (record, meta) {
493
- this.fsmMeta = meta
494
- this.fsmContextProp = record
495
- this.showFsmModal = true
496
- },
497
- onChangeTableSelection (_, selectedRows = []) {
498
- if (this.currentTableMode === 'radio') {
499
- this.setCurrentTableSelection(selectedRows)
500
- this.$emit('on-change-table-selection', this.currentTableSelection)
501
- this.$emit('x:refresh-exposed', { exposed: this.exposed })
502
- } else {
503
- this.setCurrentTableSelection(selectedRows)
504
- this.$emit('on-change-table-selection', this.currentTableSelection)
505
- this.$emit('x:refresh-exposed', { exposed: this.exposed })
506
- }
507
- },
508
- setCurrentTableSelection (props = {}) {
509
- if (this.currentTableMode === 'radio') {
510
- this.$set(this, 'currentTableSelection', (type.isArray(props) && props.length > 0) ? props[0] : type.isObject(props) ? props : {})
511
- } else {
512
- this.$set(this, 'currentTableSelection', type.isArray(props) ? props : [])
513
- }
514
- },
515
- getCurrentTableSelection () {
516
- return this.currentTableSelection
517
- },
518
- setCurrentRowData (props = {}) {
519
- this.currentRowData = props
520
- this.dataPoolManager.setCurrentRowData(props)
521
- },
522
- getCurrentRowData () {
523
- return this.dataPoolManager.getCurrentRowData()
524
- },
525
- cleanCurrentModelEffect (clearRowData = true) {
526
- this.setCurrentTableSelection()
527
- if (clearRowData) {
528
- this.setCurrentRowData({})
529
- }
530
- },
531
- [BUILT_IN_EVENT_NAMES.SUBMIT] (props = {}) {
532
- this.cleanCurrentModelEffect()
533
- this.requestTableData()
534
- },
535
- [BUILT_IN_EVENT_NAMES.EDIT] (props = {}) {
536
- const { record = {} } = props
537
- this.setCurrentRowData(record)
538
- this.modalFormMeta = this.editMeta
539
- this.modalFormValue = true
540
- },
541
- [BUILT_IN_EVENT_NAMES.CREATE] () {
542
- this.modalFormMeta = this.createMeta
543
- this.modalFormValue = true
544
- },
545
- showModalForm (modeMeta = {}) {
546
- if (type.isStr(modeMeta)) {
547
- const targetMeta = this.findMetaByKey(modeMeta)
548
- this.modalFormMeta = targetMeta
549
- } else {
550
- this.modalFormMeta = modeMeta
551
- }
552
- this.modalFormValue = true
553
- },
554
- showModalTable (modeMeta = {}, record = null) {
555
- // 获取当前行数据并设置到共享命名空间
556
- const currentRowData = record || this.getCurrentRowData()
557
- this.dataPoolManager.setSharedData(currentRowData)
558
-
559
- let targetMeta = modeMeta
560
- if (type.isStr(modeMeta)) {
561
- targetMeta = this.findMetaByKey(modeMeta)
562
- }
563
-
564
- // 解析 fieldMap 参数,使用完整的上下文包括 currentRowData
565
- if (targetMeta && targetMeta.fieldMap) {
566
- const { fieldMap, params = {} } = targetMeta
567
-
568
- const ctx = {
569
- ...this.currentTreeNodeData,
570
- _route: this.$route.query,
571
- ...currentRowData
572
- }
573
- const parsedParams = parseFieldMap(fieldMap, ctx)
574
-
575
- // 将当前的 currentRowData 传递给 modal table,通过 params
576
- targetMeta = {
577
- ...targetMeta,
578
- params: {
579
- ...params,
580
- ...parsedParams
581
- }
582
- }
583
- }
584
-
585
- this.modalTableMeta = targetMeta
586
- this.modalTableValue = true
587
- },
588
- closeModalForm () {
589
- this.modalFormValue = false
590
- },
591
- closeModalTable () {
592
- this.modalTableValue = false
593
- },
594
- findMetaByKey (key) {
595
- return this.$attrs[key] || {}
596
- },
597
- handleClickButtonGroup (props) {
598
- const { eventName, target } = props
599
- const targetMeta = this.findMetaByKey(target)
600
- const { mode } = targetMeta
601
- mode && this.dispatchTrigger({ mode, modeMeta: targetMeta })
602
- this.$emit(eventName || 'click', { currentTreeNode: this.currentTreeNodeData })
603
- },
604
- async onSearch (props) {
605
- const { overrideInit = false } = this.tableMeta
606
- this.tableQuerys = Object.assign(this.tableQuerys, props)
607
- if (overrideInit) {
608
- this.$emit(RESERVE_EVENT_NAMES.TREE_CHANGE, { ...this.exposed })
609
- } else {
610
- this.tableData = await this.requestTableData()
611
- }
612
- },
613
- async selectTreeNode (selectedKeys, e) {
614
- const { fieldMap } = this.tableMeta
615
- this.currentTreeNodeData = e.node.$vnode.data.props.dataRef || {}
616
- //@deprecated '_' namespace is deprecated, please use 'exposed' instead
617
- const execFieldMapRet = parseFieldMap(fieldMap, { ...this.currentTreeNodeData, exposed: this.exposed, _route: this.exposed._route })
618
- const { overrideInit = false } = this.tableMeta
619
- if (overrideInit) {
620
- this.$emit(RESERVE_EVENT_NAMES.TREE_CHANGE, { ...this.exposed })
621
- } else {
622
- this.tableData = await this.requestTableData(execFieldMapRet)
623
- }
624
- },
625
- async requestTreeData () {
626
- const { url, requestType = 'GET', params = {}, fieldMap = {} } = this.treeMeta
627
- const fieldMapRet = parseFieldMap(fieldMap, { ...this.currentTreeNodeData, _route: this.$route.query })
628
- const ret = await net[requestType.toLowerCase()](
629
- url,
630
- { ...params, ...fieldMapRet }
631
- ).then(resp => {
632
- const { data } = resp || {}
633
- return data
634
- })
635
- return ret
636
- },
637
- async onChangePage (page, pageSize) {
638
- this.tableData = await this.requestTableData({ currentPage: page, pageSize })
639
- },
640
- async requestTableData (props = {}) {
641
- const { url, requestType = 'GET', page = {} } = this.tableMeta
642
- const { pageSize = 10 } = page
643
- this.tableQuerys = Object.assign(this.tableQuerys, { currentPage: 1, pageSize }, props)
644
- this.$emit(RESERVE_EVENT_NAMES.WATCH, { ...this.exposed })
645
- this.loading = true
646
- const ret = await net[requestType.toLowerCase()](
647
- url,
648
- this.tableQuerys
649
- ).then(resp => {
650
- const { data = [], count } = resp || {}
651
- this.total = count
652
- this.loading = false
653
- return (data || []).map(item => {
654
- delete item.children
655
- return {
656
- key: uuidv4(),
657
- ...item
658
- }
659
- })
660
- })
661
- this.cleanCurrentModelEffect(false) // 不清空 currentRowData,除非明确需要
662
- this.tableData = ret
663
- return ret
664
- },
665
- calculateTableHeight () {
666
- const currentViewportHeight = window.innerHeight
667
- const tableRef = this.$refs[this.tableRef]
668
- const { top: tableToTop, width } = tableRef.$el.getBoundingClientRect()
669
- this.tableWidth = width
670
- this.tableHeight = currentViewportHeight - tableToTop - this.overHeight
671
- },
672
- calculateTreeHeight () {
673
- if (!this.showTree) return
674
- const modelTableContainerRef = this.$refs[this.modelTableContainerRef]
675
- const { height } = modelTableContainerRef.getBoundingClientRect()
676
- this.treeWrapperHeight = height
677
- }
678
- },
679
- mounted () {
680
- this.calculateTableHeight()
681
- this.$nextTick(() => {
682
- this.calculateTreeHeight()
683
- })
684
- this.resizeObserverModelTableWrapper = new ResizeObserver(entries => {
685
- for (const _ of entries) {
686
- requestAnimationFrame(() => {
687
- this.calculateTableHeight()
688
- })
689
- }
690
- })
691
- this.resizeObserverModelTableWrapper.observe(this.$refs[this.modelTableWrapper])
692
- },
693
- destroyed () {
694
- this.resizeObserverModelTableWrapper.disconnect()
695
- if (this.dataPoolManager) {
696
- this.dataPoolManager.cleanup()
697
- }
698
- }
699
- }
700
- </script>
701
-
702
- <style lang="scss" scoped>
703
- .ele {
704
- &.model__tree-table {
705
- background: transparent;
706
- display: flex;
707
- flex-direction: row;
708
- width: 100%;
709
- .model__tree-table--container {
710
- .model__tree--wrapper {
711
- width: 240px;
712
- background: #fff;
713
- flex-shrink: 0;
714
- padding: 16px;
715
- box-sizing: border-box;
716
- margin-right: 16px;
717
- overflow-y: auto;
718
- }
719
- }
720
- .model__table--container {
721
- width: 100%;
722
- min-width: 0;
723
- background: #fff;
724
- .model__table--title {
725
- .model__table-title--bar {
726
- width: 100%;
727
- height: 8px;
728
- background: var(--idooel-primary-color);
729
- border-top-left-radius: 4px;
730
- border-top-right-radius: 4px;
731
- }
732
- .model__table-title--text {
733
- text-align: left;
734
- padding: 16px;
735
- font-size: 16px;
736
- font-weight: bold;
737
- background: #fff;
738
- border-bottom: 1px solid;
739
- border-color: var(--idoole-black-016);
740
- }
741
- }
742
- .model__table--wrapper {
743
- background: #fff;
744
- .button-row__area {
745
- width: 100%;
746
- display: flex;
747
- flex-direction: row;
748
- align-items: center;
749
- justify-content: space-between;
750
- padding-top: 16px;
751
- padding-bottom: 8px;
752
- padding-right: 16px;
753
- }
754
- .g-table__wrapper {
755
- .fsm {
756
- cursor: pointer;
757
- color: var(--idooel-primary-color);
758
- }
759
- }
760
- }
761
- }
762
- }
763
- }
764
- </style>
1
+ <template>
2
+ <section class="ele model__tree-table">
3
+ <section class="model__tree-table--container" v-if="showTree">
4
+ <div class="model__tree--title"></div>
5
+ <section :ref="modelTreeWrapper" class="model__tree--wrapper" :style="{height: `${treeWrapperHeight}px`}">
6
+ <ele-tree
7
+ :tree-data="treeData"
8
+ :defaultExpandedKeys="defaultExpandedKeys"
9
+ :defaultSelectedKeys="defaultSelectedKeys"
10
+ @select="selectTreeNode"
11
+ :replace-fields="mapFields">
12
+ </ele-tree>
13
+ </section>
14
+ </section>
15
+ <section class="model__table--container" :ref="modelTableContainerRef">
16
+ <div class="model__table--title" v-if="title">
17
+ <template v-if="titleMode">
18
+ <div :class="[`model__table-title--${titleMode}`]"></div>
19
+ </template>
20
+ <template v-else>
21
+ <div class="model__table-title--text">{{ title }}</div>
22
+ </template>
23
+ </div>
24
+ <section :ref="modelTableWrapper" class="model__table--wrapper">
25
+ <ele-search-area :ref="searchArea" @search="onSearch" :data-source="searchMeta.elements"></ele-search-area>
26
+ <div class="button-row__area">
27
+ <ele-button-group class="model-table__button-group" v-on="overrideButtonGroupEvent" :ref="buttonGroup" @click="handleClickButtonGroup" :data-source="getButtonGroupElements"></ele-button-group>
28
+ <slot name="tags"></slot>
29
+ <slot v-if="$slots['sub-center']" name="sub-center"></slot>
30
+ </div>
31
+ <ele-table
32
+ v-on="overrideTableEvent"
33
+ :ref="tableRef"
34
+ :row-selection="rowSelection"
35
+ :loading="loading"
36
+ :columns="columns"
37
+ :total="total"
38
+ :x="x"
39
+ :y="y"
40
+ :bordered="setBorder"
41
+ :height="tableHeight"
42
+ :width="tableWidth"
43
+ :actions="actions"
44
+ :pageSize="pageSize"
45
+ :pageSizeOptions="pageSizeOptions"
46
+ :data-source="tableData"
47
+ @change-page="onChangePage"
48
+ ></ele-table>
49
+ </section>
50
+ </section>
51
+ <ele-modal-form v-model="modalFormValue" v-on="overrideModalFormEvent" :meta="modalFormMeta"></ele-modal-form>
52
+ <ele-modal-fsm v-model="showFsmModal" :contextProp="fsmContextProp" :meta="fsmMeta" @cancel="handleCloseFsmModal"></ele-modal-fsm>
53
+ <ele-modal-table
54
+ :meta="modalTableMeta"
55
+ v-model="modalTableValue"
56
+ v-on="overrideModalTableEvent"
57
+ ></ele-modal-table>
58
+ </section>
59
+ </template>
60
+
61
+ <script>
62
+ import { type, net } from '@idooel/shared'
63
+ import { v4 as uuidv4 } from 'uuid'
64
+ import { BUILT_IN_EVENT_NAMES, RESERVE_EVENT_NAMES, parseFieldMap, BUILT_IN_TRIGGER, CONTEXT } from '../../../utils'
65
+ import { createTreeTableModel } from '../../../utils/runtime-context'
66
+ export default {
67
+ name: 'ele-tree-table-model',
68
+ props: {
69
+ title: {
70
+ type: [Object, String]
71
+ },
72
+ overHeight: {
73
+ type: Number,
74
+ default: 0
75
+ },
76
+ treeMeta: {
77
+ type: Object,
78
+ default: () => ({})
79
+ },
80
+ searchMeta: {
81
+ type: Object,
82
+ default: () => ({})
83
+ },
84
+ buttonGroupMeta: {
85
+ typeof: Object,
86
+ default: () => ({})
87
+ },
88
+ tableMeta: {
89
+ type: Object,
90
+ default: () => ({})
91
+ },
92
+ createMeta: {
93
+ type: Object
94
+ },
95
+ editMeta: {
96
+ type: Object
97
+ }
98
+ },
99
+ provide () {
100
+ return {
101
+ requestTreeData: this.requestTreeData,
102
+ requestTableData: this.requestTableData,
103
+ [CONTEXT]: () => {
104
+ return {
105
+ exposed: this.exposed
106
+ }
107
+ }
108
+ }
109
+ },
110
+ data () {
111
+ return {
112
+ tableHeight: 0,
113
+ tableWidth: 0,
114
+ modalFormMeta: {},
115
+ modalFormValue: false,
116
+ treeData: [],
117
+ tableData: [],
118
+ defaultExpandedKeys: [],
119
+ defaultSelectedKeys: [],
120
+ replaceFields: {
121
+ title: 'title',
122
+ children: 'children',
123
+ key: 'id'
124
+ },
125
+ loading: false,
126
+ total: 0,
127
+ tableQuerys: {},
128
+ resizeObserverModelTableWrapper: null,
129
+ modelTableWrapperHeight: 0,
130
+ currentTreeNodeData: {},
131
+ currentRowData: {},
132
+ treeWrapperHeight: 0,
133
+ currentTableSelection: this.currentTableMode == 'radio' ? {} : [],
134
+ showFsmModal: false,
135
+ fsmMeta: {},
136
+ fsmContextProp: {},
137
+ modalTableValue: false,
138
+ modalTableMeta: {},
139
+ dataPoolManager: null
140
+ }
141
+ },
142
+ computed: {
143
+ setBorder () {
144
+ return this.tableMeta.bordered === false ? false : true
145
+ },
146
+ rowSelection () {
147
+ if (!this.currentTableMode) return void 0
148
+ return {
149
+ columnTitle: this.currentSelectionColumn.columnTitle,
150
+ fixed: true,
151
+ type: this.currentTableMode,
152
+ onChange: this.onChangeTableSelection
153
+ }
154
+ },
155
+ currentSelectionColumn () {
156
+ const { multiple } = this.tableMeta
157
+ const target = this.columns.find(item => Object.keys(item).includes('multiple'))
158
+ const isGlobalExistMultiple = Object.keys(this.tableMeta).includes('multiple')
159
+ if (target) {
160
+ return target
161
+ } else if (isGlobalExistMultiple) {
162
+ return { multiple }
163
+ }
164
+ return void 0
165
+ },
166
+ x () {
167
+ const { x } = this.tableMeta
168
+ return x
169
+ },
170
+ y () {
171
+ const { y } = this.tableMeta
172
+ return y
173
+ },
174
+ currentTableMode () {
175
+ if (!this.currentSelectionColumn) return void 0
176
+ const { multiple } = this.currentSelectionColumn
177
+ if (type.isBool(multiple)) {
178
+ if (multiple) {
179
+ return 'checkbox'
180
+ } else {
181
+ return 'radio'
182
+ }
183
+ } else {
184
+ return void 0
185
+ }
186
+ },
187
+ modelTableContainerRef () {
188
+ return uuidv4()
189
+ },
190
+ titleMode () {
191
+ if (type.isObject(this.title)) {
192
+ const { mode = '' } = this.title
193
+ return mode
194
+ }
195
+ return void 0
196
+ },
197
+ tableRef () {
198
+ return uuidv4()
199
+ },
200
+ exposed () {
201
+ return {
202
+ showModalForm: this.showModalForm,
203
+ closeModalForm: this.closeModalForm,
204
+ showModalTable: this.showModalTable,
205
+ closeModalTable: this.closeModalTable,
206
+ currentTableSelection: this.currentTableSelection,
207
+ currentTreeNode: this.currentTreeNodeData,
208
+ requestTableData: this.requestTableData,
209
+ refreshTreeData: this.refreshTreeData,
210
+ querys: this.tableQuerys,
211
+ currentRowData: this.getCurrentRowData(),
212
+ getCurrentRowData: this.getCurrentRowData,
213
+ setCurrentRowData: this.setCurrentRowData,
214
+ setCurrentTableSelection: this.setCurrentTableSelection,
215
+ getCurrentTableSelection: this.getCurrentTableSelection,
216
+ cleanCurrentModelEffect: this.cleanCurrentModelEffect,
217
+ route: this.$route,
218
+ _route: this.$route.query,
219
+ _routeMeta: this.$route.meta,
220
+ dataPool: this.model ? this.model.getDataPool() : null,
221
+ dataPoolManager: this.model || null
222
+ }
223
+ },
224
+ overrideTableEvent () {
225
+ const events = this.actions.reduce((ret, action) => {
226
+ ret[action.eventName || action.key] = (e) => {
227
+ this.setCurrentRowData(e.exposed.currentRowData)
228
+ const { target } = action
229
+ const targetMeta = this.findMetaByKey(target)
230
+ const { mode } = targetMeta
231
+ mode && this.dispatchTrigger({ mode, record: e.exposed.currentRowData, modeMeta: targetMeta })
232
+ this.$emit(action.eventName || action.key, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: { ...this.exposed, ...e.exposed } })
233
+ }
234
+ return ret
235
+ }, {})
236
+ return {
237
+ ...this.$listeners,
238
+ ...events,
239
+ [BUILT_IN_EVENT_NAMES.EDIT]: this[BUILT_IN_EVENT_NAMES.EDIT],
240
+ [BUILT_IN_EVENT_NAMES.SUBMIT]: this[BUILT_IN_EVENT_NAMES.SUBMIT]
241
+ }
242
+ },
243
+ overrideModalFormEvent () {
244
+ const { footerMeta } = this.modalFormMeta
245
+ const { elements = [] } = footerMeta || {}
246
+ const eles = type.isFunction(elements) ? elements.call(this) : elements
247
+ const events = eles.reduce((ret, ele) => {
248
+ ret[ele.eventName] = (e = {}) => {
249
+ if (ele.eventName === 'cancel') {
250
+ this.closeModalForm()
251
+ } else {
252
+ const { exposed = {} } = e
253
+ this.$emit(`${ele.eventName || ele.key}`, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, exposed )})
254
+ }
255
+ }
256
+ return ret
257
+ }, {})
258
+ return {
259
+ ...events
260
+ }
261
+ },
262
+ overrideModalTableEvent () {
263
+ const { footerMeta } = this.modalTableMeta
264
+ const { elements = [] } = footerMeta || {}
265
+ const eles = type.isFunction(elements) ? elements.call(this) : elements
266
+ const events = eles.reduce((ret, ele) => {
267
+ ret[ele.eventName] = (e = {}) => {
268
+ if (ele.eventName === 'cancel') {
269
+ this.closeModalTable()
270
+ } else {
271
+ const { exposed = {} } = e
272
+ this.$emit(`${ele.eventName || ele.key}`, { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, exposed )})
273
+ }
274
+ }
275
+ return ret
276
+ }, {})
277
+ return {
278
+ ...events,
279
+ exposed: this.exposed
280
+ }
281
+ },
282
+ overrideButtonGroupEvent () {
283
+ const events = this.getButtonGroupElements.reduce((ret, ele) => {
284
+ ret[ele.eventName] = (e) => {
285
+ this.$emit(ele.eventName || 'click', { ...e, currentTreeNode: this.currentTreeNodeData, exposed: Object.assign({}, e.exposed || {}, this.exposed)})
286
+ }
287
+ return ret
288
+ }, {})
289
+ return {
290
+ ...this.$listeners,
291
+ ...events,
292
+ [BUILT_IN_EVENT_NAMES.CREATE]: this[BUILT_IN_EVENT_NAMES.CREATE],
293
+ exposed: this.exposed
294
+ }
295
+ },
296
+ showTree () {
297
+ return !!Object.keys(this.treeMeta).length
298
+ },
299
+ buttonGroup () {
300
+ return uuidv4()
301
+ },
302
+ searchArea () {
303
+ return uuidv4()
304
+ },
305
+ modelTreeWrapper () {
306
+ return uuidv4()
307
+ },
308
+ modelTableWrapper () {
309
+ return uuidv4()
310
+ },
311
+ actions () {
312
+ const { operations } = this.tableMeta
313
+ if (operations) {
314
+ return operations.elements
315
+ } else {
316
+ return []
317
+ }
318
+ },
319
+ pageSize () {
320
+ const { page = {} } = this.tableMeta
321
+ return page.pageSize || 10
322
+ },
323
+ pageSizeOptions () {
324
+ const { page = {} } = this.tableMeta
325
+ return page.pageSizeOptions || ['10', '20', '30', '40']
326
+ },
327
+ columns () {
328
+ const { columns, operations } = this.tableMeta
329
+ if (type.get(columns) === 'array') {
330
+ const columnsOptions = columns.map(item => {
331
+ const { mode = 'text' } = item
332
+ if (item.render) {
333
+ return {
334
+ ...item,
335
+ customRender: (text, record, index) => {
336
+ const { $createElement } = this
337
+ return item.render.call(this,
338
+ { h: $createElement, ctx: this },
339
+ text ? typeof text == 'object' ? text[item.dataIndex] : text : '',
340
+ record, index)
341
+ }
342
+ }
343
+ } else if (mode !== BUILT_IN_TRIGGER.TEXT) {
344
+ const { [`${mode}Meta`]: modeMeta } = item
345
+ return {
346
+ ...item,
347
+ customRender: (text, record, index) => {
348
+ return <span onClick={() => this.dispatchTrigger({ mode, record, modeMeta, index })} class={ mode }>{ text }</span>
349
+ }
350
+ }
351
+ }
352
+ return {
353
+ ...item
354
+ }
355
+ })
356
+ if (operations) {
357
+ return [
358
+ ...columnsOptions,
359
+ {
360
+ title: '操作',
361
+ width: operations.width,
362
+ key: 'action',
363
+ fixed: 'right',
364
+ scopedSlots: { customRender: 'action' }
365
+ }
366
+ ]
367
+ }
368
+ return columnsOptions
369
+ } else {
370
+ console.error('Error: columns is invalid, please check it')
371
+ return []
372
+ }
373
+ },
374
+ getButtonGroupElements () {
375
+ const { elements } = this.buttonGroupMeta
376
+ if (type.get(elements) === 'function') {
377
+ return elements.call(this)
378
+ } else if (type.get(elements) === 'array') {
379
+ return elements
380
+ } else {
381
+ return []
382
+ }
383
+ },
384
+ mapFields () {
385
+ const { replaceFields = {} } = this.treeMeta
386
+ const mapFields = type.isEmpty(replaceFields) ? this.replaceFields : replaceFields
387
+ return mapFields
388
+ }
389
+ },
390
+ async created () {
391
+ // 确保全局数据池已初始化
392
+ if (!window.__idooel_data_pool__) {
393
+ console.error('Global data pool not initialized. Please check if runtime-context/globalDataPool.js is properly imported.')
394
+ return
395
+ }
396
+
397
+ // 初始化数据池管理器(使用新的 runtime-context)
398
+ try {
399
+ this.model = createTreeTableModel('treeTableModel')
400
+
401
+ if (!this.model) {
402
+ throw new Error('Failed to create tree table model')
403
+ }
404
+ } catch (error) {
405
+ console.error('Error creating tree table model:', error)
406
+ this.model = null
407
+ return
408
+ }
409
+
410
+ // 初始化 currentRowData(尝试从共享命名空间获取)
411
+ this.initializeCurrentRowData()
412
+
413
+ // 订阅数据池变化
414
+ this.unsubscribe = this.model.subscribe('currentRowData', (event) => {
415
+ this.currentRowData = event.value || {}
416
+ this.$forceUpdate()
417
+ })
418
+
419
+ // 订阅共享数据变化
420
+ this.unsubscribeShared = this.model.subscribeShared((event) => {
421
+ // 当有新的共享数据时,更新当前组件的 currentRowData
422
+ if (event.value && Object.keys(event.value).length > 0) {
423
+ this.setCurrentRowData(event.value)
424
+ }
425
+ })
426
+
427
+ if (this.showTree) {
428
+ this.treeData = await this.requestTreeData()
429
+ const [defaultTreeNode = {}] = this.treeData
430
+ this.defaultExpandedKeys = [defaultTreeNode[this.mapFields.key]]
431
+ this.defaultSelectedKeys = [defaultTreeNode[this.mapFields.key]]
432
+ this.currentTreeNodeData = defaultTreeNode
433
+ }
434
+
435
+ const { params = {}, fieldMap = {}, overrideInit = false } = this.tableMeta
436
+ const currentRowData = this.getCurrentRowData()
437
+ const ctx = {
438
+ ...this.currentTreeNodeData,
439
+ _route: this.$route.query,
440
+ currentRowData: currentRowData
441
+ }
442
+
443
+ const initQuerys = Object.assign({}, params, parseFieldMap(fieldMap, ctx))
444
+ if (overrideInit) {
445
+ this.$emit(RESERVE_EVENT_NAMES.INIT, { ...this.exposed })
446
+ } else {
447
+ this.tableData = await this.requestTableData(initQuerys)
448
+ }
449
+ },
450
+ methods: {
451
+ initializeCurrentRowData () {
452
+ if (!this.model) {
453
+ console.warn('Model not initialized, skipping currentRowData initialization')
454
+ return
455
+ }
456
+
457
+ // 检查是否有来自父组件的共享数据(比如 modal table 场景)
458
+ const parentData = this.model.getSharedData()
459
+
460
+ if (parentData && Object.keys(parentData).length > 0) {
461
+ this.setCurrentRowData(parentData)
462
+ return
463
+ }
464
+
465
+ // 可以根据路由参数、props 或其他来源设置初始的 currentRowData
466
+ const { query } = this.$route
467
+
468
+ // 示例:如果路由中有特定参数,可以设置为 currentRowData
469
+ if (query.rowId || query.selectedId) {
470
+ // 这里可以根据实际需求从服务端或其他地方获取数据
471
+ // const presetData = { id: query.rowId, /* 其他字段 */ }
472
+ // this.setCurrentRowData(presetData)
473
+ }
474
+
475
+ // 目前保持空对象,等待用户选择行数据
476
+ },
477
+ async refreshTreeData () {
478
+ this.treeData = await this.requestTreeData()
479
+ const [defaultTreeNode = {}] = this.treeData
480
+ this.defaultExpandedKeys = [defaultTreeNode[this.mapFields.key]]
481
+ this.defaultSelectedKeys = [defaultTreeNode[this.mapFields.key]]
482
+ this.currentTreeNodeData = defaultTreeNode
483
+ },
484
+ dispatchTrigger ({ mode, record = {}, modeMeta = { } }) {
485
+ switch (mode) {
486
+ case BUILT_IN_TRIGGER.FSM:
487
+ this[`${BUILT_IN_TRIGGER.FSM}Trigger`](record, modeMeta = type.isEmpty(modeMeta) ? {
488
+ url: 'api-fsm/workbench/fsm/auditFlow',
489
+ requestType: 'GET',
490
+ fieldMap: {
491
+ modelCode: 'modelCode',
492
+ businessId: 'businessId'
493
+ }
494
+ } : modeMeta)
495
+ break
496
+ case BUILT_IN_TRIGGER.ELE_MODAL_FORM:
497
+ this.modalFormMeta = modeMeta
498
+ this.showModalForm(modeMeta)
499
+ break
500
+ case BUILT_IN_TRIGGER.ELE_MODAL_TABLE:
501
+ this.modalTableMeta = modeMeta
502
+ // 将当前行的 record 数据传递给 modal table
503
+ this.showModalTable(modeMeta, record)
504
+ break
505
+ default:
506
+ break
507
+ }
508
+ },
509
+ handleCloseFsmModal () {
510
+ this.showFsmModal = false
511
+ },
512
+ [`${BUILT_IN_TRIGGER.FSM}Trigger`] (record, meta) {
513
+ this.fsmMeta = meta
514
+ this.fsmContextProp = record
515
+ this.showFsmModal = true
516
+ },
517
+ onChangeTableSelection (_, selectedRows = []) {
518
+ if (this.currentTableMode === 'radio') {
519
+ this.setCurrentTableSelection(selectedRows)
520
+ this.$emit('on-change-table-selection', this.currentTableSelection)
521
+ this.$emit('x:refresh-exposed', { exposed: this.exposed })
522
+ } else {
523
+ this.setCurrentTableSelection(selectedRows)
524
+ this.$emit('on-change-table-selection', this.currentTableSelection)
525
+ this.$emit('x:refresh-exposed', { exposed: this.exposed })
526
+ }
527
+ },
528
+ setCurrentTableSelection (props = {}) {
529
+ if (this.currentTableMode === 'radio') {
530
+ this.$set(this, 'currentTableSelection', (type.isArray(props) && props.length > 0) ? props[0] : type.isObject(props) ? props : {})
531
+ } else {
532
+ this.$set(this, 'currentTableSelection', type.isArray(props) ? props : [])
533
+ }
534
+ },
535
+ getCurrentTableSelection () {
536
+ return this.currentTableSelection
537
+ },
538
+ setCurrentRowData (props = {}) {
539
+ this.currentRowData = props
540
+ if (this.model) {
541
+ this.model.setCurrentRowData(props)
542
+ } else {
543
+ console.warn('Model not initialized, cannot setCurrentRowData in model')
544
+ }
545
+ },
546
+ getCurrentRowData () {
547
+ if (this.model) {
548
+ return this.model.getCurrentRowData()
549
+ }
550
+ console.warn('Model not initialized, getCurrentRowData returning local data')
551
+ return this.currentRowData || {}
552
+ },
553
+ cleanCurrentModelEffect (clearRowData = true) {
554
+ this.setCurrentTableSelection()
555
+ if (clearRowData) {
556
+ this.setCurrentRowData({})
557
+ }
558
+ },
559
+ [BUILT_IN_EVENT_NAMES.SUBMIT] (props = {}) {
560
+ this.cleanCurrentModelEffect()
561
+ this.requestTableData()
562
+ },
563
+ [BUILT_IN_EVENT_NAMES.EDIT] (props = {}) {
564
+ const { record = {} } = props
565
+ this.setCurrentRowData(record)
566
+ this.modalFormMeta = this.editMeta
567
+ this.modalFormValue = true
568
+ },
569
+ [BUILT_IN_EVENT_NAMES.CREATE] () {
570
+ this.modalFormMeta = this.createMeta
571
+ this.modalFormValue = true
572
+ },
573
+ showModalForm (modeMeta = {}) {
574
+ if (type.isStr(modeMeta)) {
575
+ const targetMeta = this.findMetaByKey(modeMeta)
576
+ this.modalFormMeta = targetMeta
577
+ } else {
578
+ this.modalFormMeta = modeMeta
579
+ }
580
+ this.modalFormValue = true
581
+ },
582
+ showModalTable (modeMeta = {}, record = null) {
583
+ // 获取当前行数据并设置到共享命名空间
584
+ const currentRowData = record || this.getCurrentRowData()
585
+ if (this.model) {
586
+ this.model.setSharedData(currentRowData)
587
+ } else {
588
+ console.warn('Model not initialized, cannot setSharedData')
589
+ }
590
+
591
+ let targetMeta = modeMeta
592
+ if (type.isStr(modeMeta)) {
593
+ targetMeta = this.findMetaByKey(modeMeta)
594
+ }
595
+
596
+ // 解析 fieldMap 参数,使用完整的上下文包括 currentRowData
597
+ if (targetMeta && targetMeta.fieldMap) {
598
+ const { fieldMap, params = {} } = targetMeta
599
+
600
+ const ctx = {
601
+ ...this.currentTreeNodeData,
602
+ _route: this.$route.query,
603
+ ...currentRowData
604
+ }
605
+ const parsedParams = parseFieldMap(fieldMap, ctx)
606
+
607
+ // 将当前的 currentRowData 传递给 modal table,通过 params
608
+ targetMeta = {
609
+ ...targetMeta,
610
+ params: {
611
+ ...params,
612
+ ...parsedParams
613
+ }
614
+ }
615
+ }
616
+
617
+ this.modalTableMeta = targetMeta
618
+ this.modalTableValue = true
619
+ },
620
+ closeModalForm () {
621
+ this.modalFormValue = false
622
+ },
623
+ closeModalTable () {
624
+ this.modalTableValue = false
625
+ },
626
+ findMetaByKey (key) {
627
+ return this.$attrs[key] || {}
628
+ },
629
+ handleClickButtonGroup (props) {
630
+ const { eventName, target } = props
631
+ const targetMeta = this.findMetaByKey(target)
632
+ const { mode } = targetMeta
633
+ mode && this.dispatchTrigger({ mode, modeMeta: targetMeta })
634
+ this.$emit(eventName || 'click', { currentTreeNode: this.currentTreeNodeData })
635
+ },
636
+ async onSearch (props) {
637
+ const { overrideInit = false } = this.tableMeta
638
+ this.tableQuerys = Object.assign(this.tableQuerys, props)
639
+ if (overrideInit) {
640
+ this.$emit(RESERVE_EVENT_NAMES.TREE_CHANGE, { ...this.exposed })
641
+ } else {
642
+ this.tableData = await this.requestTableData()
643
+ }
644
+ },
645
+ async selectTreeNode (selectedKeys, e) {
646
+ const { fieldMap } = this.tableMeta
647
+ this.currentTreeNodeData = e.node.$vnode.data.props.dataRef || {}
648
+ //@deprecated '_' namespace is deprecated, please use 'exposed' instead
649
+ const execFieldMapRet = parseFieldMap(fieldMap, { ...this.currentTreeNodeData, exposed: this.exposed, _route: this.exposed._route })
650
+ const { overrideInit = false } = this.tableMeta
651
+ if (overrideInit) {
652
+ this.$emit(RESERVE_EVENT_NAMES.TREE_CHANGE, { ...this.exposed })
653
+ } else {
654
+ this.tableData = await this.requestTableData(execFieldMapRet)
655
+ }
656
+ },
657
+ async requestTreeData () {
658
+ const { url, requestType = 'GET', params = {}, fieldMap = {} } = this.treeMeta
659
+ const fieldMapRet = parseFieldMap(fieldMap, { ...this.currentTreeNodeData, _route: this.$route.query })
660
+ const ret = await net[requestType.toLowerCase()](
661
+ url,
662
+ { ...params, ...fieldMapRet }
663
+ ).then(resp => {
664
+ const { data } = resp || {}
665
+ return data
666
+ })
667
+ return ret
668
+ },
669
+ async onChangePage (page, pageSize) {
670
+ this.tableData = await this.requestTableData({ currentPage: page, pageSize })
671
+ },
672
+ async requestTableData (props = {}) {
673
+ const { url, requestType = 'GET', page = {} } = this.tableMeta
674
+ const { pageSize = 10 } = page
675
+ this.tableQuerys = Object.assign(this.tableQuerys, { currentPage: 1, pageSize }, props)
676
+ this.$emit(RESERVE_EVENT_NAMES.WATCH, { ...this.exposed })
677
+ this.loading = true
678
+ const ret = await net[requestType.toLowerCase()](
679
+ url,
680
+ this.tableQuerys
681
+ ).then(resp => {
682
+ const { data = [], count } = resp || {}
683
+ this.total = count
684
+ this.loading = false
685
+ return (data || []).map(item => {
686
+ delete item.children
687
+ return {
688
+ key: uuidv4(),
689
+ ...item
690
+ }
691
+ })
692
+ })
693
+ this.cleanCurrentModelEffect(false) // 不清空 currentRowData,除非明确需要
694
+ this.tableData = ret
695
+ return ret
696
+ },
697
+ calculateTableHeight () {
698
+ const currentViewportHeight = window.innerHeight
699
+ const tableRef = this.$refs[this.tableRef]
700
+ const { top: tableToTop, width } = tableRef.$el.getBoundingClientRect()
701
+ this.tableWidth = width
702
+ this.tableHeight = currentViewportHeight - tableToTop - this.overHeight
703
+ },
704
+ calculateTreeHeight () {
705
+ if (!this.showTree) return
706
+ const modelTableContainerRef = this.$refs[this.modelTableContainerRef]
707
+ const { height } = modelTableContainerRef.getBoundingClientRect()
708
+ this.treeWrapperHeight = height
709
+ }
710
+ },
711
+ mounted () {
712
+ this.calculateTableHeight()
713
+ this.$nextTick(() => {
714
+ this.calculateTreeHeight()
715
+ })
716
+ this.resizeObserverModelTableWrapper = new ResizeObserver(entries => {
717
+ for (const _ of entries) {
718
+ requestAnimationFrame(() => {
719
+ this.calculateTableHeight()
720
+ })
721
+ }
722
+ })
723
+ this.resizeObserverModelTableWrapper.observe(this.$refs[this.modelTableWrapper])
724
+ },
725
+ destroyed () {
726
+ this.resizeObserverModelTableWrapper.disconnect()
727
+ if (this.model) {
728
+ // 清理订阅
729
+ if (this.unsubscribe) {
730
+ this.unsubscribe()
731
+ }
732
+ if (this.unsubscribeShared) {
733
+ this.unsubscribeShared()
734
+ }
735
+ // 清理模型数据
736
+ if (this.model) {
737
+ this.model.cleanup()
738
+ }
739
+ }
740
+ }
741
+ }
742
+ </script>
743
+
744
+ <style lang="scss" scoped>
745
+ .ele {
746
+ &.model__tree-table {
747
+ background: transparent;
748
+ display: flex;
749
+ flex-direction: row;
750
+ width: 100%;
751
+ .model__tree-table--container {
752
+ .model__tree--wrapper {
753
+ width: 240px;
754
+ background: #fff;
755
+ flex-shrink: 0;
756
+ padding: 16px;
757
+ box-sizing: border-box;
758
+ margin-right: 16px;
759
+ overflow-y: auto;
760
+ }
761
+ }
762
+ .model__table--container {
763
+ width: 100%;
764
+ min-width: 0;
765
+ background: #fff;
766
+ .model__table--title {
767
+ .model__table-title--bar {
768
+ width: 100%;
769
+ height: 8px;
770
+ background: var(--idooel-primary-color);
771
+ border-top-left-radius: 4px;
772
+ border-top-right-radius: 4px;
773
+ }
774
+ .model__table-title--text {
775
+ text-align: left;
776
+ padding: 16px;
777
+ font-size: 16px;
778
+ font-weight: bold;
779
+ background: #fff;
780
+ border-bottom: 1px solid;
781
+ border-color: var(--idoole-black-016);
782
+ }
783
+ }
784
+ .model__table--wrapper {
785
+ background: #fff;
786
+ .button-row__area {
787
+ width: 100%;
788
+ display: flex;
789
+ flex-direction: row;
790
+ align-items: center;
791
+ justify-content: space-between;
792
+ padding-top: 16px;
793
+ padding-bottom: 8px;
794
+ padding-right: 16px;
795
+ }
796
+ .g-table__wrapper {
797
+ .fsm {
798
+ cursor: pointer;
799
+ color: var(--idooel-primary-color);
800
+ }
801
+ }
802
+ }
803
+ }
804
+ }
805
+ }
806
+ </style>