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

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