@idooel/components 0.0.2-beta.3 → 0.0.2-beta.31

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