vue2-client 1.12.26 → 1.12.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1107 +1,502 @@
1
- <template>
2
- <a-row id="has_row" type="flex" :gutter="gutter" :style="isWidget ? {margin: '0px'} : {'margin-bottom': '.5rem'}">
3
- <!-- 预览页展示 -->
4
- <template v-if="display">
5
- <template v-if="!inputColumns">
6
- <a-col
7
- name="trGroup"
8
- v-for="(cell, cellIndex) in columns"
9
- v-if="Array.isArray(cell) || !cell.dontShowRow"
10
- :key="cellIndex"
11
- :style="isWidget ? {padding: '0px 2px'} : (Array.isArray(cell) ? {} : determineCellStyle(cell))"
12
- :span="Array.isArray(cell) ? cell[0][0].colSpan * 2 : (cell.colSpan ? cell.colSpan * 2 : undefined)">
13
- <div id="report_widget" v-if="isWidget">
14
- <!-- 插槽渲染 -->
15
- <template v-if="Array.isArray(cell)">
16
- <!-- 处理 cell 是数组的情况 -->
17
- <div v-for="(item, index) in cell" :key="index">
18
- <x-report-tr-group
19
- @updateImg="updateImg"
20
- :show-img-in-cell="showImgInCell"
21
- :img-prefix="imgPrefix"
22
- :server-name="serverName"
23
- :env="env"
24
- :use-oss-for-img="useOssForImg"
25
- :key="index"
26
- :columns="recalculateItem(item)"
27
- :no-top-border="noTopBorder"
28
- :config-data="configData"
29
- :config="config"
30
- :display="true">
31
- </x-report-tr-group>
32
- </div>
33
- </template>
34
- <template v-else-if="cell.type === 'slot'">
35
- <template
36
- v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions'].includes(cell.slotType)">
37
- <component
38
- :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
39
- :key="cellIndex"
40
- :ref="`dynamicComponent_${ cell.slotRef || cellIndex}`"
41
- :serviceName="cell.serviceName"
42
- :serverName="cell.serviceName"
43
- v-on="getEventHandlers(cell)"
44
- @hook:mounted="(h)=>onComponentMounted(h,cell,cellIndex)"
45
- :queryParamsName="cell.slotConfig"
46
- :configName="cell.slotConfig"
47
- :countVisible="false"
48
- :env="env"
49
- />
50
- </template>
51
- </template>
52
- </div>
53
- <a-card v-else class="flexItem" :bordered="false" :body-style="flexItemBodyState">
54
- <!-- 插槽渲染 -->
55
- <template v-if="Array.isArray(cell)">
56
- <!-- 处理 cell 是数组的情况 -->
57
- <div v-for="(item, index) in cell" :key="index">
58
- <x-report-tr-group
59
- @updateImg="updateImg"
60
- :show-img-in-cell="showImgInCell"
61
- :img-prefix="imgPrefix"
62
- :server-name="serverName"
63
- :env="env"
64
- :use-oss-for-img="useOssForImg"
65
- :key="index"
66
- :columns="recalculateItem(item)"
67
- :no-top-border="noTopBorder"
68
- :config-data="configData"
69
- :config="config"
70
- :display="true">
71
- </x-report-tr-group>
72
- </div>
73
- </template>
74
- <template v-else-if="cell.type === 'slot'">
75
- <template
76
- v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse', 'x-h-descriptions'].includes(cell.slotType)">
77
- <component
78
- :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
79
- :key="cellIndex"
80
- :ref="`dynamicComponent_${ cell.slotRef || cellIndex}`"
81
- :serviceName="cell.serviceName"
82
- :serverName="cell.serviceName"
83
- v-on="getEventHandlers(cell)"
84
- @hook:mounted="(h)=>onComponentMounted(h,cell,cellIndex)"
85
- :queryParamsName="cell.slotConfig"
86
- :configName="cell.slotConfig"
87
- :countVisible="false"
88
- :env="env"
89
- />
90
- </template>
91
- </template>
92
- <!-- button 按钮渲染 -->
93
- <template v-else-if="cell.type === 'button'">
94
- <a-button v-on="getEventHandlers(cell)">
95
- {{ cell.buttonName }}
96
- </a-button>
97
- </template>
98
- <template v-else-if="cell.type === 'column'">
99
- <template v-if="cell.customFunction">
100
- {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
101
- </template>
102
- <template v-else>
103
- {{ cell.text }}
104
- </template>
105
- </template>
106
- <!-- 占位 -->
107
- <template v-else-if="cell.type === 'placeHolderColumn'">
108
- </template>
109
- <template v-else-if="cell.type === 'value'">
110
- <template v-if="cell.customFunction === undefined">
111
- {{ cell.value }}
112
- </template>
113
- <template v-else>
114
- {{ deserializeFunctionAndRun(cell.customFunction, cell.value, config) }}
115
- </template>
116
- </template>
117
- <template v-else-if="cell.type === 'input'">
118
- <template v-if="cell.customFunction === undefined">
119
- {{ getDeepObject(configData, cell.dataIndex) }}
120
- </template>
121
- <template v-else>
122
- {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
123
- </template>
124
- </template>
125
- <template v-else-if="cell.type === 'inputs'">
126
- <template v-if="cell.customFunction === undefined">
127
- {{ showSubRowValue(cell) }}
128
- </template>
129
- <template v-else>
130
- {{ deserializeFunctionAndRun(cell.customFunction, showSubRowValue(cell), config) }}
131
- </template>
132
- </template>
133
- <template v-else-if="cell.type === 'list'">
134
- <template v-if="listIndex === 0">
135
- <span style="font-weight: bold">{{ cell.listHead }}</span>
136
- </template>
137
- <template v-else-if="cell.listType === 'input'">
138
- {{ getDeepObject(configData, cell.dataIndex)[listIndex] }}
139
- </template>
140
- <template v-else-if="cell.listType === 'value'">
141
- {{ cell.content[listIndex] }}
142
- </template>
143
- <template v-else-if="cell.listType === 'variable'">
144
- {{ configData[cell.dataIndex][listIndex - 1][cell.listDataIndex] }}
145
- </template>
146
- </template>
147
- <template v-else-if="cell.type === 'images'">
148
- <template
149
- v-if="getDeepObject(configData.images, cell.dataIndex) === undefined || getDeepObject(configData.images, cell.dataIndex).length === 0">
150
- <template
151
- v-if="getDeepObject(configData, cell.dataIndex) === undefined || getDeepObject(configData, cell.dataIndex).length === 0">
152
- <span>无</span>
153
- </template>
154
- <template v-else>
155
- <template v-if="typeof getDeepObject(configData, cell.dataIndex) === 'object'">
156
- <div style="display: flex; align-items: end; justify-content: space-evenly; flex-wrap: wrap">
157
- <template v-for="(img,imgIndex) in getDeepObject(configData, cell.dataIndex)">
158
- <template v-if="showImgInCell">
159
- <div :key="imgIndex">
160
- <img :src="img.url" alt="图片"/>
161
- <p>{{ img.name }}</p>
162
- </div>
163
- </template>
164
- <template v-else>
165
- <span :key="imgIndex" style="margin-right: 5%">{{ img.name }}</span>
166
- </template>
167
- </template>
168
- </div>
169
- </template>
170
- <template v-else>
171
- <img :src="getDeepObject(configData, cell.dataIndex)" alt="图片"/>
172
- <p style="margin-right: 5%">{{ formatImgStr(getDeepObject(configData, cell.dataIndex))[0].name }}</p>
173
- </template>
174
- </template>
175
- </template>
176
- <span v-else v-for="(img,imgIndex) in getDeepObject(configData.images, cell.dataIndex)" :key="imgIndex" style="margin-right: 5%">{{ img.name }}</span>
177
- </template>
178
- </a-card>
179
- </a-col>
180
- </template>
181
- <template v-else>
182
- <a-col
183
- v-for="(cell, cellIndex) in columns"
184
- :key="cellIndex"
185
- :class=" calcTDBorder(cell.noBoarder) "
186
- :span="cell.colSpan ? cell.colSpan * 2 : undefined"
187
- :style="determineCellStyle(cell)"
188
- :rowspan="cell.rowSpan ? cell.rowSpan : undefined">
189
- <a-card class="flexItem" :bordered="false" :body-style="flexItemBodyState">
190
- <template v-if="cell.type === 'column'">
191
- {{ cell.text }}
192
- </template>
193
- <template v-else-if="cell.type === 'value'">
194
- <template v-if="cell.customFunction === undefined">
195
- {{ cell.value }}
196
- </template>
197
- <template v-else>
198
- {{ deserializeFunctionAndRun(cell.customFunction, cell.value, config) }}
199
- </template>
200
- </template>
201
- <template v-else-if="cell.type === 'increment'">
202
- <template v-if="cell.customFunction === undefined">
203
- {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
204
- </template>
205
- <template v-else>
206
- {{
207
- deserializeFunctionAndRun(cell.customFunction, configData.arr[inputColumnsDefinitionIndex][cell.dataIndex], config)
208
- }}
209
- </template>
210
- </template>
211
- <template v-else-if="cell.type === 'input'">
212
- <template v-if="cell.customFunction === undefined">
213
- {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
214
- </template>
215
- <template v-else>
216
- {{
217
- deserializeFunctionAndRun(cell.customFunction, configData.arr[inputColumnsDefinitionIndex][cell.dataIndex], config)
218
- }}
219
- </template>
220
- </template>
221
- <template v-else-if="cell.type === 'inputs'">
222
- <template v-if="cell.customFunction === undefined">
223
- {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
224
- </template>
225
- <template v-else>
226
- {{
227
- deserializeFunctionAndRun(cell.customFunction, configData.arr[inputColumnsDefinitionIndex][cell.dataIndex], config)
228
- }}
229
- </template>
230
- </template>
231
- </a-card>
232
- </a-col>
233
- </template>
234
- </template>
235
- <!-- 不是动态行 -->
236
- <template v-else-if="!inputColumns">
237
- <a-col
238
- v-for="(cell, cellIndex) in columns"
239
- :key="cellIndex"
240
- :class=" calcTDBorder(cell.noBoarder) "
241
- :span="cell.colSpan ? cell.colSpan * 2 : undefined"
242
- :style="determineCellStyle(cell)"
243
- :rowspan="cell.rowSpan ? cell.rowSpan : undefined">
244
- <a-card class="flexItem" :bordered="false" :body-style="flexItemBodyState">
245
- <template v-if="cell.type === 'column'">
246
- <template v-if="cell.customFunction">
247
- {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
248
- </template>
249
- <template v-else>
250
- {{ cell.text }}
251
- </template>
252
- </template>
253
- <template v-else-if="cell.type === 'placeHolderColumn'">
254
- <!-- 占位 -->
255
- </template>
256
- <template v-else-if="cell.type === 'value'">
257
- {{ cell.value }}
258
- </template>
259
- <template v-else-if="cell.type === 'curDateInput'">
260
- <a-button type="dashed" v-if="configData[cell.dataIndex]">
261
- {{ configData[cell.dataIndex] }}
262
- </a-button>
263
- <a-button
264
- v-if="!configData[cell.dataIndex]"
265
- type="primary"
266
- @click="getNowDate(cell.dataIndex)"
267
- >{{ cell.text || '确认' }}
268
- </a-button>
269
- </template>
270
- <template v-else-if="cell.type === 'input'">
271
- <template v-if="cell.inputReadOnly === true">
272
- <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
273
- <a-input
274
- @change="handleInputDeepChange($event, cell.dataIndex)"
275
- v-model="config.tempData[cell.dataIndex]"
276
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
277
- :disabled="true"/>
278
- </template>
279
- <template v-else>
280
- <a-input
281
- v-model="configData[cell.dataIndex]"
282
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
283
- :disabled="true"/>
284
- </template>
285
- </template>
286
- <template v-else>
287
- <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
288
- <a-input
289
- @change="handleInputDeepChange($event, cell.dataIndex)"
290
- v-model="config.tempData[cell.dataIndex]"
291
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
292
- </template>
293
- <template v-else>
294
- <a-input
295
- v-model="configData[cell.dataIndex]"
296
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
297
- </template>
298
- </template>
299
- </template>
300
- <template v-else-if="cell.type === 'inputs'">
301
- <template v-if="cell.inputReadOnly === true">
302
- <div class="inputsDiv">
303
- <div class="inputsDivItem" v-for="(num, index) of calcFormatInputNum(cell.format)" :key="index">
304
- <span class="inputsDivItemLabel">{{ displayFormatStartText(cell.format) }}</span>
305
- <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
306
- <a-input
307
- @change="handleInputDeepChange($event, cell.dataIndex)"
308
- v-model="config.tempData[cell.dataIndex][index]"
309
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
310
- :disabled="true"/>
311
- </template>
312
- <template v-else>
313
- <a-input
314
- v-model="configData[cell.dataIndex][index]"
315
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
316
- :disabled="true"/>
317
- </template>
318
- <span class="inputsDivItemLabel">{{ displayFormatText(cell.format, index) }}</span>
319
- </div>
320
- </div>
321
- </template>
322
- <template v-else>
323
- <div class="inputsDiv">
324
- <div class="inputsDivItem" v-for="(num, index) of calcFormatInputNum(cell.format)" :key="index">
325
- <span class="inputsDivItemLabel">{{ displayFormatStartText(cell.format) }}</span>
326
- <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
327
- <a-input
328
- @change="handleInputDeepChange($event, cell.dataIndex)"
329
- v-model="config.tempData[cell.dataIndex][index]"
330
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
331
- </template>
332
- <template v-else>
333
- <a-input
334
- v-model="configData[cell.dataIndex][index]"
335
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
336
- </template>
337
- <span class="inputsDivItemLabel">{{ displayFormatText(cell.format, index) }}</span>
338
- </div>
339
- </div>
340
- </template>
341
- </template>
342
- <template v-else-if="cell.type === 'list'">
343
- <template v-if="cell.listType === 'input'">
344
- <a-input
345
- v-model="configData[cell.dataIndex][listIndex]"
346
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
347
- </template>
348
- <template v-else-if="cell.listType === 'value'">
349
- {{ cell.content[listIndex] }}
350
- </template>
351
- </template>
352
- <template v-else-if="cell.type === 'images'">
353
- <div>
354
- <template v-if="configData.images[cell.dataIndex]?.length > 0">
355
- <upload
356
- :model="uploadParams"
357
- :img-prefix="imgPrefix"
358
- :service-name="serverName"
359
- :images="checkImg(cell.dataIndex, 'configData')"
360
- :outer-container-index="cell.dataIndex"
361
- @setFiles="(...args) => {setImages(args, 'configData')}"
362
- :upload-style="'simple'"
363
- />
364
- </template>
365
- <template v-else>
366
- <upload
367
- :model="uploadParams"
368
- :img-prefix="imgPrefix"
369
- :service-name="serverName"
370
- :images="checkImg(cell.dataIndex, 'config')"
371
- :outer-container-index="cell.dataIndex"
372
- @setFiles="(...args) => {setImages(args, 'config', cell.dataIndex)}"
373
- :upload-style="'simple'"
374
- />
375
- </template>
376
- </div>
377
- </template>
378
- </a-card>
379
- </a-col>
380
- </template>
381
- <!-- 动态行插入按钮 -->
382
- <template v-else-if="inputColumnsButton">
383
- <a-col :span="maxColSpan" :class="calcTDBorder()">
384
- <a-card class="flexItem" :bordered="false" :body-style="flexItemBodyState">
385
- <a-button-group>
386
- <a-button @click="addData(columns[0].dataIndex, columns)">
387
- <a-icon type="plus"/>
388
- </a-button>
389
- <a-button @click="removeData(columns[0].dataIndex)">
390
- <a-icon type="minus"/>
391
- </a-button>
392
- </a-button-group>
393
- </a-card>
394
- </a-col>
395
- </template>
396
- <!-- 其他行 -->
397
- <template v-else>
398
- <a-col
399
- v-for="(cell, cellIndex) in columns"
400
- :key="cellIndex"
401
- :class=" calcTDBorder(cell.noBoarder) "
402
- :span="cell.colSpan ? cell.colSpan * 2 : undefined"
403
- :style="determineCellStyle(cell)"
404
- :rowspan="cell.rowSpan ? cell.rowSpan : undefined">
405
- <a-card class="flexItem" :bordered="false" :body-style="flexItemBodyState">
406
- <template v-if="cell.type === 'column'">
407
- {{ cell.text }}
408
- </template>
409
- <template v-else-if="cell.type === 'value'">
410
- {{ cell.value }}
411
- </template>
412
- <template v-else-if="cell.type === 'curDateInput'">
413
- <a-button type="dashed" v-if="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]">
414
- {{ configData.arr[inputColumnsDefinitionIndex][cell.dataIndex] }}
415
- </a-button>
416
- <a-button
417
- v-if="!configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
418
- type="primary"
419
- @click="getNowDate(inputColumnsDefinitionIndex,cell.dataIndex)"
420
- >{{ cell.text || '确认' }}
421
- </a-button>
422
- </template>
423
- <template v-else-if="cell.type === 'increment'">
424
- {{ configData.arr[inputColumnsDefinitionIndex][cell.dataIndex] }}
425
- </template>
426
- <template v-else-if="cell.type === 'input'">
427
- <template v-if="cell.inputReadOnly === true">
428
- <a-input
429
- v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
430
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
431
- :disabled="true"/>
432
- </template>
433
- <template v-else>
434
- <a-input
435
- v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
436
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
437
- </template>
438
- </template>
439
- <template v-else-if="cell.type === 'inputs'">
440
- <template v-if="cell.inputReadOnly === true">
441
- <a-input
442
- v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
443
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
444
- :disabled="true"/>
445
- </template>
446
- <template v-else>
447
- <a-input
448
- v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
449
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
450
- </template>
451
- </template>
452
- </a-card>
453
- </a-col>
454
- </template>
455
- </a-row>
456
- </template>
457
-
458
- <script>
459
- import Upload from '@vue2-client/base-client/components/common/Upload'
460
- import { formatDate, getRealKeyData } from '@vue2-client/utils/util'
461
- import { nanoid } from 'nanoid'
462
- import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
463
- import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
464
- import { getMicroData, getWindow, isMicroAppEnv, microDispatch } from '@vue2-client/utils/microAppUtils'
465
-
466
- export default {
467
- name: 'XReportTrGroup',
468
- components: {
469
- Upload,
470
- XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
471
- XAddNativeForm: () => import('@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'),
472
- XFormGroup: () => import('@vue2-client/base-client/components/common/XFormGroup/XFormGroup.vue'),
473
- XTreePro: () => import('@vue2-client/base-client/components/common/XTree/XTreePro.vue'),
474
- XHisEditor: () => import('@vue2-client/base-client/components/his/XHisEditor/XHisEditor.vue'),
475
- XTab: () => import('@vue2-client/base-client/components/common/XTab/XTab.vue'),
476
- XReport: () => import('@vue2-client/base-client/components/common/XReport/XReport.vue'),
477
- XButtons: () => import('@vue2-client/base-client/components/common/XButtons/XButtons.vue'),
478
- XLabelSelect: () => import('@vue2-client/base-client/components/common/XLabelSelect/XLabelSelect.vue'),
479
- XConversation: () => import('@vue2-client/base-client/components/common/XConversation/XConversation.vue'),
480
- XCheckList: () => import('@vue2-client/base-client/components/common/XCheckList/XCheckList.vue'),
481
- XCardSet: () => import('@vue2-client/base-client/components/common/XCardSet/XCardSet.vue'),
482
- XCollapse: () => import('@vue2-client/base-client/components/common/XCollapse/XCollapse.vue'),
483
- XHDescriptions: () => import('@vue2-client/base-client/components/his/XHDescriptions/XHDescriptions.vue'),
484
- },
485
- props: {
486
- // 每一行的配置
487
- columns: {
488
- type: Array,
489
- required: true
490
- },
491
- showImgInCell: {
492
- type: Boolean,
493
- default: false
494
- },
495
- config: {
496
- type: Object,
497
- default: function () {
498
- return {}
499
- }
500
- },
501
- // 命名空间
502
- serverName: {
503
- type: String,
504
- default: 'af-system'
505
- },
506
- // 环境
507
- env: {
508
- type: String,
509
- default: 'prod'
510
- },
511
- // 原始配置
512
- configData: {
513
- type: Object,
514
- required: true
515
- },
516
- // 是否为动态行
517
- inputColumns: {
518
- type: Boolean,
519
- default: false
520
- },
521
- // 是否为动态行按钮
522
- inputColumnsButton: {
523
- type: Boolean,
524
- default: false
525
- },
526
- // 动态行的Index
527
- inputColumnsDefinitionIndex: {
528
- type: Number,
529
- default: undefined
530
- },
531
- // 是否为展示行
532
- display: {
533
- type: Boolean,
534
- default: false
535
- },
536
- // list类型的下标,用于遍历列表时,获取对应的数据
537
- listIndex: {
538
- type: Number,
539
- default: undefined
540
- },
541
- // 表格没有上边框
542
- noTopBorder: {
543
- type: Boolean,
544
- default: false
545
- },
546
- // 图片是否使用OSS来保存
547
- useOssForImg: {
548
- type: Boolean,
549
- default: true
550
- },
551
- // 图片上传后添加前缀
552
- imgPrefix: {
553
- type: String,
554
- default: undefined
555
- }
556
- },
557
- computed: {
558
- allSlotSum () {
559
- // 计算总共有多少个Slot
560
- let sum = 0
561
- this.columns.forEach((item) => {
562
- console.log('item', item)
563
- if (Array.isArray(item)) {
564
- item.forEach((cell) => {
565
- if (cell.type === 'slot') {
566
- sum++
567
- }
568
- })
569
- } else if (item.type && item.type === 'slot') {
570
- sum++
571
- }
572
- })
573
- console.log(`=总共有 ${sum} 个插槽栅格`)
574
- return sum
575
- }
576
- },
577
- data () {
578
- return {
579
- gutter: [8, { xs: 8, sm: 16, md: 24, lg: 32 }], // 设置水槽大小
580
- maxColSpan: 12,
581
- uploadParams: {
582
- type: 'image',
583
- accept: ['*'],
584
- resUploadStock: 1,
585
- pathKey: 'cs'
586
- },
587
- mixinData: {},
588
- flexItemBodyState: {},
589
- // 已经渲染得插槽得数量
590
- slotRendered: 0,
591
- // tableConfig: {}
592
- }
593
- },
594
- inject: ['openDialog', 'emitEvent', 'registerComponent', 'setGlobalData', 'getGlobalData', 'getComponentByName', 'runLogic', 'getMixinData', 'getSelectedId', 'isInAModal', 'getConfigByName', 'getSelectedData', 'getOutEnv', 'currUser', 'isWidget'],
595
- methods: {
596
- getWindow,
597
- isMicroAppEnv,
598
- microDispatch,
599
- getMicroData,
600
- getRealKeyData,
601
- onComponentMounted (h, cell, cellIndex) {
602
- this.slotRendered += 1
603
- if (this.slotRendered >= this.allSlotSum) {
604
- this.$emit('slotRendered')
605
- }
606
- if (this.getMixinData && this.getMixinData()) {
607
- this.mixinData = this.getMixinData()
608
- }
609
- if (cell.slotRef) {
610
- this.registerComponent(cell.slotRef, this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0])
611
- }
612
- // 传递给祖先组件
613
- console.log(`插槽组件已经初始化 slotType ${cell.slotType},ref= dynamicComponent_${cell.slotRef || cellIndex} , serviceName = ${cell.serviceName}`)
614
- const shouldInit = cell.shouldInit == null ? true : cell.shouldInit
615
- if (shouldInit) {
616
- if (cell.slotType === 'x-add-native-form') {
617
- // 简易表单需要主动调用初始化方法
618
- getConfigByName(cell.slotConfig, cell.serviceName, async (res) => {
619
- // 如果配置了 表单初始化logic
620
- // 调用 logic 获取参数
621
- let param = { ...this.mixinData }
622
- let selectedId
623
- if (res.paramLogicName) {
624
- if (!!this.getSelectedId) {
625
- selectedId = this.getSelectedId()
626
- if (typeof selectedId !== 'object') {
627
- selectedId = { selectedId: selectedId }
628
- }
629
- }
630
- param = Object.assign(param, await runLogic(res.paramLogicName, selectedId, cell.serviceName))
631
- }
632
- console.info('给表单赋值', res)
633
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
634
- serviceName: cell.serviceName,
635
- configName: cell.slotConfig,
636
- formItems: res.formJson,
637
- showSubmitBtn: !this.isInAModal,
638
- businessType: param.businessType || '新增',
639
- layout: res.xAddFormLayout,
640
- primaryKey: res.primaryKey,
641
- ...res,
642
- fixedAddForm: param,
643
- modifyModelData: {
644
- files: param.files,
645
- images: param.images
646
- }
647
- })
648
- }, this.env === 'dev')
649
- } else if (cell.slotType === 'x-form-group') {
650
- // 简易表单需要主动调用初始化方法
651
- getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
652
- // 如果配置了 表单初始化logic
653
- // 调用 logic 获取参数
654
- const param = { ...this.mixinData }
655
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
656
- ...res,
657
- serviceName: cell.serviceName,
658
- showSubmitBtn: !this.isInAModal,
659
- businessType: param.businessType || '新增',
660
- modifyModelData: param,
661
- showLeftTab: true,
662
- })
663
- }, this.env === 'dev')
664
- } else if (cell.slotType === 'x-buttons') {
665
- // 按钮组需要主动调用初始化方法
666
- getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
667
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
668
- ...res,
669
- serviceName: cell.serviceName,
670
- })
671
- }, this.env === 'dev')
672
- } else if (cell.slotType === 'x-label-select') {
673
- // 按钮组需要主动调用初始化方法
674
- getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
675
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
676
- ...res,
677
- serviceName: cell.serviceName,
678
- })
679
- }, this.env === 'dev')
680
- }
681
- }
682
- if (cell.slotType === 'x-report') {
683
- const param = { ...this.mixinData }
684
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init(param)
685
- }
686
- if (cell.slotType === 'x-conversation') {
687
- getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
688
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
689
- serviceName: cell.serviceName,
690
- ...res,
691
- })
692
- }, this.env === 'dev')
693
- }
694
- if (cell.slotType === 'x-check-list') {
695
- getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
696
- this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
697
- serviceName: cell.serviceName,
698
- ...res,
699
- })
700
- }, this.env === 'dev')
701
- }
702
- },
703
-
704
- // 对于嵌套情况,对colSpan重新分配
705
- recalculateItem (item) {
706
- const totalColSpan = item.reduce((sum, cell) => sum + (cell.colSpan || 1), 0) // 计算总的 colSpan
707
- return item.map(cell => {
708
- const newColSpan = Math.round((cell.colSpan || 1) / totalColSpan * 12) // 按比例重新分配 colSpan
709
- return {
710
- ...cell,
711
- colSpan: newColSpan // 更新 colSpan
712
- }
713
- })
714
- },
715
-
716
- getEventHandlers (cell) {
717
- const handlers = {}
718
- if (!cell?.events || cell?.events?.length === 0) {
719
- return handlers
720
- }
721
- cell.events.forEach(event => {
722
- handlers[event.type] = async (...args) => {
723
- console.info('Event handled:', event.type, args)
724
- let func = event.customFunction
725
- if (func && func.startsWith('function')) {
726
- func = func.replace('function', 'async function')
727
- }
728
- const result = await executeStrFunctionByContext(this, func, args)
729
- if (result instanceof Promise) {
730
- result.then((res) => {
731
- if (!res) return
732
- let messageType = 'success'
733
- // 如果传递了组件名字 自动调用刷新
734
- if (res?.name) {
735
- const waitRefreshRef = this.getComponentByName(res.name)
736
- if (waitRefreshRef) {
737
- waitRefreshRef.refresh()
738
- } else {
739
- console.warn(`未找到组件${res.name}无法刷新`)
740
- }
741
- }
742
- // 如果传递消息类型 自动调用消息
743
- if (res?.messageType) {
744
- messageType = res.messageType
745
- }
746
- // 如果传递了提示信息自动调用提示
747
- if (res?.message) {
748
- this.$message[messageType](res?.message)
749
- }
750
- })
751
- }
752
- }
753
- })
754
- return handlers
755
- },
756
- getComponentName (queryParamsName, serviceName, componentName) {
757
- // const config = await getConfigByName(queryParamsName, serviceName)
758
- // const componentName = config.$globalProp.type
759
- return componentName
760
- },
761
- updateImg (data) {
762
- this.$emit('updateImg', data)
763
- },
764
- formatImgStr (str) {
765
- const result = []
766
- if (str !== '') {
767
- const arr = str.split('/')
768
- result.push({
769
- uid: nanoid(6),
770
- url: str,
771
- name: arr[arr.length - 1],
772
- status: 'done'
773
- })
774
- }
775
- this.uploadParams.acceptCount = 1
776
- return result
777
- },
778
- checkImg (index, type) {
779
- let target
780
- if (type === 'configData') {
781
- target = this.configData.images[index]
782
- } else {
783
- target = this.config.tempData[index]
784
- }
785
- if (typeof target !== 'object') {
786
- return this.formatImgStr(target)
787
- }
788
- target.forEach(obj => {
789
- if (obj.uid === undefined) {
790
- obj.uid = obj.id.toString()
791
- }
792
- if (obj.url === undefined) {
793
- if (obj.path) {
794
- obj.url = obj.path
795
- }
796
- }
797
- if (obj.name === undefined) {
798
- const withOutEndFix = obj.url.split('.')[0]
799
- const temp = withOutEndFix.split('/')
800
- obj.name = temp[temp.length - 1]
801
- }
802
- if (obj.status === undefined) {
803
- obj.status = 'done'
804
- }
805
- })
806
- return target
807
- },
808
- // 判断单元格样式
809
- determineCellStyle (cell, color = '#000', borderWidth = '1px') {
810
- // 如果声明了borderColor
811
- if (this.config.style.borderColor) {
812
- color = this.config.style.borderColor
813
- }
814
- let result = {}
815
- // 如果表格也声明了样式,用表格样式将样式覆盖
816
- if (cell.style) {
817
- if (cell.noBorder) {
818
- result = { ...cell.style }
819
- } else {
820
- if (this.noTopBorder) {
821
- result = { ...cell.style }
822
- } else {
823
- result = { ...cell.style }
824
- }
825
- }
826
- return result
827
- }
828
- return result
829
- },
830
-
831
- // 表格中数据key含有@@@,需要手动触发更新
832
- handleInputDeepChange () {
833
- this.$forceUpdate()
834
- },
835
- // 路径中含有@@@的key,将其解析,并返回其数据
836
- getDeepObject (obj, strPath) {
837
- if (!strPath) {
838
- return ''
839
- }
840
- const arr = strPath.split('@@@')
841
- let result = obj[arr[0]]
842
- arr.shift()
843
- try {
844
- while (arr.length > 0) {
845
- result = result[arr[0]]
846
- arr.shift()
847
- }
848
- } catch (e) {
849
- result = undefined
850
- }
851
- return result
852
- },
853
- // 获取当前日期
854
- getNowDate (index1, index2) {
855
- if (index2) {
856
- // @click="getNowDate(configData.arr[inputColumnsDefinitionIndex][cell.dataIndex])"
857
- this.configData.arr[index1][index2] = formatDate('now')
858
- } else {
859
- this.configData[index1] = formatDate('now')
860
- }
861
- this.configData = Object.assign({}, this.configData)
862
- },
863
- // 反序列化函数并执行
864
- deserializeFunctionAndRun (functionStr, value) {
865
- // eslint-disable-next-line no-eval
866
- const fun = eval('(' + functionStr + ')')
867
- return fun(value, this.config)
868
- },
869
- // 基础上传组件,图片改动后触发
870
- setImages (args, type, index = undefined) {
871
- // 如果基础上传组件在初始化完成后,就调用emit了setImage,此时图片并没有变化,直接返回
872
- if (args[2] === 'created') {
873
- return
874
- }
875
- if (type === 'configData') {
876
- this.configData.images[args[1]] = args[0]
877
- } else {
878
- this.config.tempData[args[1]] = args[0]
879
- if (index) {
880
- this.$emit('updateImg', this.config.tempData[index])
881
- }
882
- }
883
- },
884
- // 动态行删除
885
- removeData (index) {
886
- if (this.configData[index].length === 0) {
887
- this.$message.warn('已经没有更多了')
888
- return
889
- }
890
- this.configData[index].pop()
891
- },
892
- // 添加一行
893
- addData (index, row) {
894
- // 获取定义
895
- const defs = row[0].definition
896
-
897
- // 获取外层对象名
898
- const dataName = row[0].dataIndex
899
- const temp = {}
900
-
901
- defs.forEach(def => {
902
- // 找到数组中最后一个数据的值
903
- let lastDataNo = 0
904
- if (this.configData[dataName][this.configData[dataName].length - 1]) {
905
- lastDataNo = this.configData[dataName][this.configData[dataName].length - 1][def.dataIndex]
906
- }
907
-
908
- // 如果没有值,检查是否声明了初始值
909
- if (lastDataNo === 0 && def.initialValue) {
910
- lastDataNo = def.initialValue
911
- }
912
-
913
- // 检查是否有步长
914
- let step = 1
915
- if (def.step) {
916
- step = def.step
917
- }
918
-
919
- // 如果单元格类型为increment,则进行自增
920
- if (def.type === 'increment') {
921
- temp[def.dataIndex] = lastDataNo + step
922
- }
923
- })
924
- this.configData[index].push(temp)
925
- },
926
- // 根据format计算需要多少个输入框
927
- calcFormatInputNum (formatStr) {
928
- let count = 0
929
- for (let i = 0; i < formatStr.length; i++) {
930
- if (formatStr[i] === '{') {
931
- count++
932
- }
933
- }
934
- return count
935
- },
936
- // 根据format计算输入框之后的文字显示
937
- displayFormatText (formatStr, num) {
938
- let start = 0
939
- let count = 0
940
- num++
941
- for (let i = 0; i < formatStr.length; i++) {
942
- if (formatStr[i] === '}') {
943
- start = i
944
- count++
945
- }
946
- if (count === num) {
947
- for (let j = start + 1; j < formatStr.length; j++) {
948
- if (formatStr[j] === '{') {
949
- return formatStr.slice(start + 1, j)
950
- }
951
- if (j === formatStr.length - 1 && formatStr[j] !== '}') {
952
- return formatStr[j]
953
- }
954
- }
955
- }
956
- }
957
- },
958
- calcTDBorder (cellNoBorder = false) {
959
- if (cellNoBorder) {
960
- return 'tdNoBorder'
961
- } else {
962
- if (this.noTopBorder) {
963
- return 'tdWithNoTopBorder'
964
- } else {
965
- return 'tdWithBorder'
966
- }
967
- }
968
- },
969
- // 根据format计算输入框之前的文字显示
970
- displayFormatStartText (formatStr) {
971
- let count = 0
972
- for (let i = 0; i < formatStr.length; i++) {
973
- if (formatStr[i] === '{') {
974
- break
975
- } else {
976
- count++
977
- }
978
- }
979
- return formatStr.slice(0, count)
980
- },
981
- // 拼接被自动拆分的单元格内容
982
- showSubRowValue (cell) {
983
- const dataName = cell.dataIndex
984
- const formatArr = []
985
- const dataArr = []
986
-
987
- // 从config中取出所有数据,根据dataIndex的开头内容进行拼接
988
- this.config.columns.forEach(row => row.forEach(cell => {
989
- if (cell.dataIndex && cell.dataIndex.startsWith(dataName)) {
990
- formatArr.push(cell.format)
991
- dataArr.push(this.configData[cell.dataIndex])
992
- }
993
- }))
994
-
995
- const text = []
996
- const data = []
997
-
998
- formatArr.forEach(word => {
999
- const temp = word.split('{}')
1000
- temp.forEach(char => {
1001
- if (char !== '') {
1002
- text.push(char)
1003
- }
1004
- })
1005
- })
1006
-
1007
- dataArr.forEach(item => {
1008
- item.forEach(num => {
1009
- data.push(num)
1010
- })
1011
- })
1012
-
1013
- let result = ''
1014
- for (let i = 0; i < data.length; i++) {
1015
- result += data[i]
1016
- result += text[i]
1017
- }
1018
-
1019
- return result
1020
- },
1021
- // 把用户定义的组件,传递到整个杉格中,方便调用
1022
- passComponentNamesToAncestor (refs) {
1023
- console.log('组件的keys', Object.entries(refs), refs)
1024
- // 遍历所有 refs
1025
- Object.entries(refs).forEach(([refKey, refValue]) => {
1026
- // 检查 ref 是否以 dynamicComponent_ 开头
1027
- if (refKey.startsWith('dynamicComponent_')) {
1028
- console.log('组件名存在')
1029
- const componentRef = refValue[0]
1030
- if (componentRef) {
1031
- // 去掉前缀并获取组件名字
1032
- const index = refKey.replace('dynamicComponent_', '') // 去掉前缀
1033
- console.log('注册组件', index)
1034
- // 传递给祖先组件
1035
- this.registerComponent(index, componentRef)
1036
- }
1037
- }
1038
- })
1039
- }
1040
- },
1041
- beforeMount () {
1042
- if (this.useOssForImg) {
1043
- this.uploadParams.resUploadMode = 'oss'
1044
- }
1045
- },
1046
- mounted () {
1047
- },
1048
- }
1049
-
1050
- </script>
1051
-
1052
- <style scoped lang="less">
1053
- .inputsDiv {
1054
- display: flex;
1055
- justify-content: space-between;
1056
-
1057
- .inputsDivItem {
1058
- display: flex;
1059
- align-items: center;
1060
- padding: 0 4px;
1061
- white-space: nowrap;
1062
-
1063
- .inputsDivItemLabel {
1064
- padding: 0 4px;
1065
- }
1066
- }
1067
- }
1068
-
1069
- .tdNoBorder {
1070
- border-left: 1px solid #000;
1071
- border-right: 1px solid #000;
1072
- padding: 8px;
1073
- }
1074
-
1075
- .tdWithBorder {
1076
- border: 1px solid #000;
1077
- padding: 8px;
1078
- }
1079
-
1080
- .tdWithNoTopBorder {
1081
- border-top-style: none;
1082
- border-left: 1px solid #000;
1083
- border-right: 1px solid #000;
1084
- border-bottom: 1px solid #000;
1085
- padding: 8px;
1086
- }
1087
-
1088
- .grid-content {
1089
- border-radius: 4px;
1090
- min-height: 36px;
1091
- text-align: center;
1092
- color: #fff;
1093
- background-color: #606266;
1094
- }
1095
-
1096
- .bg-purple {
1097
- background: #9254de;
1098
- }
1099
-
1100
- .bg-purple-light {
1101
- background: #b37feb;
1102
- }
1103
- .flexItem {
1104
- border-radius: 8px;
1105
- height: 100%;
1106
- }
1107
- </style>
1
+ <template>
2
+ <a-row id="has_row" type="flex" :gutter="gutter" :style="isWidget ? {margin: '0px'} : {'margin-bottom': '.5rem'}">
3
+ <!-- 预览页展示 -->
4
+ <a-col
5
+ name="trGroup"
6
+ v-for="(cell, cellIndex) in columns"
7
+ v-if="Array.isArray(cell) || !cell.dontShowRow"
8
+ :key="cellIndex"
9
+ :style="isWidget ? {padding: '0px 2px'} : (Array.isArray(cell) ? {} : determineCellStyle(cell))"
10
+ :span="Array.isArray(cell) ? cell[0][0].colSpan * 2 : (cell.colSpan ? cell.colSpan * 2 : undefined)">
11
+ <div id="report_widget" v-if="isWidget">
12
+ <!-- 插槽渲染 -->
13
+ <template v-if="Array.isArray(cell)">
14
+ <!-- 处理 cell 是数组的情况 -->
15
+ <div v-for="(item, index) in cell" :key="index">
16
+ <x-report-tr-group
17
+ :show-img-in-cell="showImgInCell"
18
+ :img-prefix="imgPrefix"
19
+ :server-name="serverName"
20
+ :env="env"
21
+ :use-oss-for-img="useOssForImg"
22
+ :key="index"
23
+ :columns="recalculateItem(item)"
24
+ :no-top-border="noTopBorder"
25
+ :config-data="configData"
26
+ :config="config"
27
+ :display="true">
28
+ </x-report-tr-group>
29
+ </div>
30
+ </template>
31
+ <template v-else-if="cell.type === 'slot'">
32
+ <template
33
+ v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse','x-h-descriptions'].includes(cell.slotType)">
34
+ <component
35
+ :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
36
+ :key="cellIndex"
37
+ :ref="`dynamicComponent_${ cell.slotRef || cellIndex}`"
38
+ :serviceName="cell.serviceName"
39
+ :serverName="cell.serviceName"
40
+ v-on="getEventHandlers(cell)"
41
+ @hook:mounted="(h)=>onComponentMounted(h,cell,cellIndex)"
42
+ :queryParamsName="cell.slotConfig"
43
+ :configName="cell.slotConfig"
44
+ :countVisible="false"
45
+ :env="env"
46
+ />
47
+ </template>
48
+ </template>
49
+ </div>
50
+ <a-card v-else class="flexItem" :bordered="false" :body-style="flexItemBodyState">
51
+ <!-- 插槽渲染 -->
52
+ <template v-if="Array.isArray(cell)">
53
+ <!-- 处理 cell 是数组的情况 -->
54
+ <div v-for="(item, index) in cell" :key="index">
55
+ <x-report-tr-group
56
+ :show-img-in-cell="showImgInCell"
57
+ :img-prefix="imgPrefix"
58
+ :server-name="serverName"
59
+ :env="env"
60
+ :use-oss-for-img="useOssForImg"
61
+ :key="index"
62
+ :columns="recalculateItem(item)"
63
+ :no-top-border="noTopBorder"
64
+ :config-data="configData"
65
+ :config="config"
66
+ :display="true">
67
+ </x-report-tr-group>
68
+ </div>
69
+ </template>
70
+ <template v-else-if="cell.type === 'slot'">
71
+ <template
72
+ v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-label-select', 'x-conversation', 'x-check-list', 'x-cardSet', 'x-collapse', 'x-h-descriptions'].includes(cell.slotType)">
73
+ <component
74
+ :is="getComponentName(cell.slotConfig, cell.serviceName, cell.slotType)"
75
+ :key="cellIndex"
76
+ :ref="`dynamicComponent_${ cell.slotRef || cellIndex}`"
77
+ :serviceName="cell.serviceName"
78
+ :serverName="cell.serviceName"
79
+ v-on="getEventHandlers(cell)"
80
+ @hook:mounted="(h)=>onComponentMounted(h,cell,cellIndex)"
81
+ :queryParamsName="cell.slotConfig"
82
+ :configName="cell.slotConfig"
83
+ :countVisible="false"
84
+ :env="env"
85
+ />
86
+ </template>
87
+ </template>
88
+ </a-card>
89
+ </a-col>
90
+ </a-row>
91
+ </template>
92
+
93
+ <script>
94
+ import Upload from '@vue2-client/base-client/components/common/Upload'
95
+ import { getRealKeyData } from '@vue2-client/utils/util'
96
+ import { executeStrFunctionByContext } from '@vue2-client/utils/runEvalFunction'
97
+ import { getConfigByName, runLogic } from '@vue2-client/services/api/common'
98
+ import { getMicroData, getWindow, isMicroAppEnv, microDispatch } from '@vue2-client/utils/microAppUtils'
99
+
100
+ export default {
101
+ name: 'XReportTrGroup',
102
+ components: {
103
+ Upload,
104
+ XFormTable: () => import('@vue2-client/base-client/components/common/XFormTable/XFormTable.vue'),
105
+ XAddNativeForm: () => import('@vue2-client/base-client/components/common/XAddNativeForm/XAddNativeForm.vue'),
106
+ XFormGroup: () => import('@vue2-client/base-client/components/common/XFormGroup/XFormGroup.vue'),
107
+ XTreePro: () => import('@vue2-client/base-client/components/common/XTree/XTreePro.vue'),
108
+ XHisEditor: () => import('@vue2-client/base-client/components/his/XHisEditor/XHisEditor.vue'),
109
+ XTab: () => import('@vue2-client/base-client/components/common/XTab/XTab.vue'),
110
+ XReport: () => import('@vue2-client/base-client/components/common/XReport/XReport.vue'),
111
+ XButtons: () => import('@vue2-client/base-client/components/common/XButtons/XButtons.vue'),
112
+ XLabelSelect: () => import('@vue2-client/base-client/components/common/XLabelSelect/XLabelSelect.vue'),
113
+ XConversation: () => import('@vue2-client/base-client/components/common/XConversation/XConversation.vue'),
114
+ XCheckList: () => import('@vue2-client/base-client/components/common/XCheckList/XCheckList.vue'),
115
+ XCardSet: () => import('@vue2-client/base-client/components/common/XCardSet/XCardSet.vue'),
116
+ XCollapse: () => import('@vue2-client/base-client/components/common/XCollapse/XCollapse.vue'),
117
+ XHDescriptions: () => import('@vue2-client/base-client/components/his/XHDescriptions/XHDescriptions.vue'),
118
+ },
119
+ props: {
120
+ // 每一行的配置
121
+ columns: {
122
+ type: Array,
123
+ required: true
124
+ },
125
+ showImgInCell: {
126
+ type: Boolean,
127
+ default: false
128
+ },
129
+ config: {
130
+ type: Object,
131
+ default: function () {
132
+ return {}
133
+ }
134
+ },
135
+ // 命名空间
136
+ serverName: {
137
+ type: String,
138
+ default: 'af-system'
139
+ },
140
+ // 环境
141
+ env: {
142
+ type: String,
143
+ default: 'prod'
144
+ },
145
+ // 原始配置
146
+ configData: {
147
+ type: Object,
148
+ required: true
149
+ },
150
+ // 是否为动态行
151
+ inputColumns: {
152
+ type: Boolean,
153
+ default: false
154
+ },
155
+ // 是否为动态行按钮
156
+ inputColumnsButton: {
157
+ type: Boolean,
158
+ default: false
159
+ },
160
+ // 动态行的Index
161
+ inputColumnsDefinitionIndex: {
162
+ type: Number,
163
+ default: undefined
164
+ },
165
+ // 是否为展示行
166
+ display: {
167
+ type: Boolean,
168
+ default: false
169
+ },
170
+ // list类型的下标,用于遍历列表时,获取对应的数据
171
+ listIndex: {
172
+ type: Number,
173
+ default: undefined
174
+ },
175
+ // 表格没有上边框
176
+ noTopBorder: {
177
+ type: Boolean,
178
+ default: false
179
+ },
180
+ // 图片是否使用OSS来保存
181
+ useOssForImg: {
182
+ type: Boolean,
183
+ default: true
184
+ },
185
+ // 图片上传后添加前缀
186
+ imgPrefix: {
187
+ type: String,
188
+ default: undefined
189
+ }
190
+ },
191
+ computed: {
192
+ allSlotSum () {
193
+ // 计算总共有多少个Slot
194
+ let sum = 0
195
+ this.columns.forEach((item) => {
196
+ console.log('item', item)
197
+ if (Array.isArray(item)) {
198
+ item.forEach((cell) => {
199
+ if (cell.type === 'slot') {
200
+ sum++
201
+ }
202
+ })
203
+ } else if (item.type && item.type === 'slot') {
204
+ sum++
205
+ }
206
+ })
207
+ console.log(`=总共有 ${sum} 个插槽栅格`)
208
+ return sum
209
+ }
210
+ },
211
+ data () {
212
+ return {
213
+ gutter: [8, { xs: 8, sm: 16, md: 24, lg: 32 }], // 设置水槽大小
214
+ maxColSpan: 12,
215
+ uploadParams: {
216
+ type: 'image',
217
+ accept: ['*'],
218
+ resUploadStock: 1,
219
+ pathKey: 'cs'
220
+ },
221
+ mixinData: {},
222
+ flexItemBodyState: {},
223
+ // 已经渲染得插槽得数量
224
+ slotRendered: 0,
225
+ // tableConfig: {}
226
+ }
227
+ },
228
+ inject: ['openDialog', 'emitEvent', 'registerComponent', 'setGlobalData', 'getGlobalData', 'getComponentByName', 'runLogic', 'getMixinData', 'getSelectedId', 'isInAModal', 'getConfigByName', 'getSelectedData', 'getOutEnv', 'currUser', 'isWidget'],
229
+ methods: {
230
+ getWindow,
231
+ isMicroAppEnv,
232
+ microDispatch,
233
+ getMicroData,
234
+ getRealKeyData,
235
+ onComponentMounted (h, cell, cellIndex) {
236
+ this.slotRendered += 1
237
+ if (this.slotRendered >= this.allSlotSum) {
238
+ this.$emit('slotRendered')
239
+ }
240
+ if (this.getMixinData && this.getMixinData()) {
241
+ this.mixinData = this.getMixinData()
242
+ }
243
+ if (cell.slotRef) {
244
+ this.registerComponent(cell.slotRef, this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0])
245
+ }
246
+ // 传递给祖先组件
247
+ console.log(`插槽组件已经初始化 slotType ${cell.slotType},ref= dynamicComponent_${cell.slotRef || cellIndex} , serviceName = ${cell.serviceName}`)
248
+ const shouldInit = cell.shouldInit == null ? true : cell.shouldInit
249
+ if (shouldInit) {
250
+ if (cell.slotType === 'x-add-native-form') {
251
+ // 简易表单需要主动调用初始化方法
252
+ getConfigByName(cell.slotConfig, cell.serviceName, async (res) => {
253
+ // 如果配置了 表单初始化logic
254
+ // 调用 logic 获取参数
255
+ let param = { ...this.mixinData }
256
+ let selectedId
257
+ if (res.paramLogicName) {
258
+ if (!!this.getSelectedId) {
259
+ selectedId = this.getSelectedId()
260
+ if (typeof selectedId !== 'object') {
261
+ selectedId = { selectedId: selectedId }
262
+ }
263
+ }
264
+ param = Object.assign(param, await runLogic(res.paramLogicName, selectedId, cell.serviceName))
265
+ }
266
+ console.info('给表单赋值', res)
267
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
268
+ serviceName: cell.serviceName,
269
+ configName: cell.slotConfig,
270
+ formItems: res.formJson,
271
+ showSubmitBtn: !this.isInAModal,
272
+ businessType: param.businessType || '新增',
273
+ layout: res.xAddFormLayout,
274
+ primaryKey: res.primaryKey,
275
+ ...res,
276
+ fixedAddForm: param,
277
+ modifyModelData: {
278
+ files: param.files,
279
+ images: param.images
280
+ }
281
+ })
282
+ }, this.env === 'dev')
283
+ } else if (cell.slotType === 'x-form-group') {
284
+ // 简易表单需要主动调用初始化方法
285
+ getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
286
+ // 如果配置了 表单初始化logic
287
+ // 调用 logic 获取参数
288
+ const param = { ...this.mixinData }
289
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
290
+ ...res,
291
+ serviceName: cell.serviceName,
292
+ showSubmitBtn: !this.isInAModal,
293
+ businessType: param.businessType || '新增',
294
+ modifyModelData: param,
295
+ showLeftTab: true,
296
+ })
297
+ }, this.env === 'dev')
298
+ } else if (cell.slotType === 'x-buttons') {
299
+ // 按钮组需要主动调用初始化方法
300
+ getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
301
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
302
+ ...res,
303
+ serviceName: cell.serviceName,
304
+ })
305
+ }, this.env === 'dev')
306
+ } else if (cell.slotType === 'x-label-select') {
307
+ // 按钮组需要主动调用初始化方法
308
+ getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
309
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
310
+ ...res,
311
+ serviceName: cell.serviceName,
312
+ })
313
+ }, this.env === 'dev')
314
+ }
315
+ }
316
+ if (cell.slotType === 'x-report') {
317
+ const param = { ...this.mixinData }
318
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init(param)
319
+ }
320
+ if (cell.slotType === 'x-conversation') {
321
+ getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
322
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
323
+ serviceName: cell.serviceName,
324
+ ...res,
325
+ })
326
+ }, this.env === 'dev')
327
+ }
328
+ if (cell.slotType === 'x-check-list') {
329
+ getConfigByName(cell.slotConfig, cell.serviceName, (res) => {
330
+ this.$refs[`dynamicComponent_${cell.slotRef || cellIndex}`][0].init({
331
+ serviceName: cell.serviceName,
332
+ ...res,
333
+ })
334
+ }, this.env === 'dev')
335
+ }
336
+ },
337
+
338
+ // 对于嵌套情况,对colSpan重新分配
339
+ recalculateItem (item) {
340
+ const totalColSpan = item.reduce((sum, cell) => sum + (cell.colSpan || 1), 0) // 计算总的 colSpan
341
+ return item.map(cell => {
342
+ const newColSpan = Math.round((cell.colSpan || 1) / totalColSpan * 12) // 按比例重新分配 colSpan
343
+ return {
344
+ ...cell,
345
+ colSpan: newColSpan // 更新 colSpan
346
+ }
347
+ })
348
+ },
349
+
350
+ getEventHandlers (cell) {
351
+ const handlers = {}
352
+ if (!cell?.events || cell?.events?.length === 0) {
353
+ return handlers
354
+ }
355
+ cell.events.forEach(event => {
356
+ handlers[event.type] = async (...args) => {
357
+ console.info('Event handled:', event.type, args)
358
+ let func = event.customFunction
359
+ if (func && func.startsWith('function')) {
360
+ func = func.replace('function', 'async function')
361
+ }
362
+ const result = await executeStrFunctionByContext(this, func, args)
363
+ if (result instanceof Promise) {
364
+ result.then((res) => {
365
+ if (!res) return
366
+ let messageType = 'success'
367
+ // 如果传递了组件名字 自动调用刷新
368
+ if (res?.name) {
369
+ const waitRefreshRef = this.getComponentByName(res.name)
370
+ if (waitRefreshRef) {
371
+ waitRefreshRef.refresh()
372
+ } else {
373
+ console.warn(`未找到组件${res.name}无法刷新`)
374
+ }
375
+ }
376
+ // 如果传递消息类型 自动调用消息
377
+ if (res?.messageType) {
378
+ messageType = res.messageType
379
+ }
380
+ // 如果传递了提示信息自动调用提示
381
+ if (res?.message) {
382
+ this.$message[messageType](res?.message)
383
+ }
384
+ })
385
+ }
386
+ }
387
+ })
388
+ return handlers
389
+ },
390
+ getComponentName (queryParamsName, serviceName, componentName) {
391
+ return componentName
392
+ },
393
+ // 判断单元格样式
394
+ determineCellStyle (cell, color = '#000', borderWidth = '1px') {
395
+ // 如果声明了borderColor
396
+ if (this.config.style.borderColor) {
397
+ color = this.config.style.borderColor
398
+ }
399
+ let result = {}
400
+ // 如果表格也声明了样式,用表格样式将样式覆盖
401
+ if (cell.style) {
402
+ if (cell.noBorder) {
403
+ result = { ...cell.style }
404
+ } else {
405
+ if (this.noTopBorder) {
406
+ result = { ...cell.style }
407
+ } else {
408
+ result = { ...cell.style }
409
+ }
410
+ }
411
+ return result
412
+ }
413
+ return result
414
+ },
415
+ // 把用户定义的组件,传递到整个杉格中,方便调用
416
+ passComponentNamesToAncestor (refs) {
417
+ console.log('组件的keys', Object.entries(refs), refs)
418
+ // 遍历所有 refs
419
+ Object.entries(refs).forEach(([refKey, refValue]) => {
420
+ // 检查 ref 是否以 dynamicComponent_ 开头
421
+ if (refKey.startsWith('dynamicComponent_')) {
422
+ console.log('组件名存在')
423
+ const componentRef = refValue[0]
424
+ if (componentRef) {
425
+ // 去掉前缀并获取组件名字
426
+ const index = refKey.replace('dynamicComponent_', '') // 去掉前缀
427
+ console.log('注册组件', index)
428
+ // 传递给祖先组件
429
+ this.registerComponent(index, componentRef)
430
+ }
431
+ }
432
+ })
433
+ }
434
+ },
435
+ beforeMount () {
436
+ if (this.useOssForImg) {
437
+ this.uploadParams.resUploadMode = 'oss'
438
+ }
439
+ },
440
+ mounted () {
441
+ },
442
+ }
443
+
444
+ </script>
445
+
446
+ <style scoped lang="less">
447
+ .inputsDiv {
448
+ display: flex;
449
+ justify-content: space-between;
450
+
451
+ .inputsDivItem {
452
+ display: flex;
453
+ align-items: center;
454
+ padding: 0 4px;
455
+ white-space: nowrap;
456
+
457
+ .inputsDivItemLabel {
458
+ padding: 0 4px;
459
+ }
460
+ }
461
+ }
462
+
463
+ .tdNoBorder {
464
+ border-left: 1px solid #000;
465
+ border-right: 1px solid #000;
466
+ padding: 8px;
467
+ }
468
+
469
+ .tdWithBorder {
470
+ border: 1px solid #000;
471
+ padding: 8px;
472
+ }
473
+
474
+ .tdWithNoTopBorder {
475
+ border-top-style: none;
476
+ border-left: 1px solid #000;
477
+ border-right: 1px solid #000;
478
+ border-bottom: 1px solid #000;
479
+ padding: 8px;
480
+ }
481
+
482
+ .grid-content {
483
+ border-radius: 4px;
484
+ min-height: 36px;
485
+ text-align: center;
486
+ color: #fff;
487
+ background-color: #606266;
488
+ }
489
+
490
+ .bg-purple {
491
+ background: #9254de;
492
+ }
493
+
494
+ .bg-purple-light {
495
+ background: #b37feb;
496
+ }
497
+
498
+ .flexItem {
499
+ border-radius: 8px;
500
+ height: 100%;
501
+ }
502
+ </style>