af-mobile-client-vue3 1.0.84 → 1.0.86

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 (25) hide show
  1. package/package.json +1 -1
  2. package/src/components/data/XCellList/index.vue +5 -2
  3. package/src/components/data/XCellListFilter/index.vue +1 -1
  4. package/src/components/data/XFormItem/index.vue +16 -2
  5. package/src/components/data/XReportGrid/XAddReport/XAddReport.vue +202 -0
  6. package/src/components/data/XReportGrid/XAddReport/index.js +3 -0
  7. package/src/components/data/XReportGrid/XAddReport/index.md +56 -0
  8. package/src/components/data/XReportGrid/XAddReport/index.ts +10 -0
  9. package/src/components/data/XReportGrid/XReport.vue +973 -0
  10. package/src/components/data/XReportGrid/XReportDemo.vue +33 -0
  11. package/src/components/data/XReportGrid/XReportDesign.vue +597 -0
  12. package/src/components/data/XReportGrid/XReportDrawer/XReportDrawer.vue +148 -0
  13. package/src/components/data/XReportGrid/XReportDrawer/index.js +3 -0
  14. package/src/components/data/XReportGrid/XReportDrawer/index.ts +10 -0
  15. package/src/components/data/XReportGrid/XReportJsonRender.vue +386 -0
  16. package/src/components/data/XReportGrid/XReportTrGroup.vue +592 -0
  17. package/src/components/data/XReportGrid/index.md +44 -0
  18. package/src/components/data/XReportGrid/print.js +184 -0
  19. package/src/layout/GridView/index.vue +16 -0
  20. package/src/layout/PageLayout.vue +5 -4
  21. package/src/router/routes.ts +18 -0
  22. package/src/views/component/XCellListView/index.vue +5 -5
  23. package/src/views/component/XFormGroupView/index.vue +2 -2
  24. package/src/views/component/XReportGridView/index.vue +18 -0
  25. package/src/views/component/index.vue +4 -0
@@ -0,0 +1,33 @@
1
+ <script setup lang="ts">
2
+ import { onMounted, ref } from 'vue'
3
+ import XReport from './XReport.vue'
4
+
5
+ const mainRef = ref()
6
+
7
+ onMounted(() => {
8
+ // 初始化逻辑
9
+ })
10
+ </script>
11
+
12
+ <template>
13
+ <div id="test">
14
+ <van-card :bordered="false">
15
+ <XReport
16
+ ref="mainRef"
17
+ :use-oss-for-img="false"
18
+ config-name="nurseWorkstationCover"
19
+ server-name="af-his"
20
+ :show-img-in-cell="true"
21
+ :display-only="true"
22
+ :edit-mode="false"
23
+ :show-save-button="false"
24
+ :no-padding="true"
25
+ :dont-format="true"
26
+ />
27
+ </van-card>
28
+ </div>
29
+ </template>
30
+
31
+ <style scoped>
32
+
33
+ </style>
@@ -0,0 +1,597 @@
1
+ <script setup lang="ts">
2
+ import { computed, onMounted, ref, watch } from 'vue'
3
+
4
+ import { getConfigByName } from '@af-mobile-client-vue3/services/api/common'
5
+ import XReportTrGroup from './XReportTrGroup.vue'
6
+ import XReportJsonRender from './XReportJsonRender.vue'
7
+
8
+ // Props 类型定义
9
+ interface Props {
10
+ config: {
11
+ data: Record<string, any>
12
+ designMode?: string
13
+ width?: number
14
+ title?: string
15
+ style?: Record<string, string>
16
+ columns?: any[][]
17
+ subTitle?: Array<{
18
+ type: string
19
+ text?: string
20
+ format?: string
21
+ dataIndex?: string
22
+ inputWidth?: number
23
+ inputReadOnly?: boolean
24
+ }>
25
+ }
26
+ showImgInCell?: boolean
27
+ forDisplay?: boolean
28
+ serverName?: string
29
+ env?: string
30
+ displayOnly?: boolean
31
+ slotConfigName?: string
32
+ showImages?: boolean
33
+ imageList?: any[]
34
+ noPadding?: boolean
35
+ noTopBorder?: boolean
36
+ showTitle?: boolean
37
+ useOssForImg?: boolean
38
+ imgPrefix?: string
39
+ }
40
+
41
+ // Props
42
+ const props = withDefaults(defineProps<Props>(), {
43
+ serverName: 'af-system',
44
+ env: 'prod',
45
+ displayOnly: false,
46
+ noPadding: true,
47
+ noTopBorder: false,
48
+ showTitle: true,
49
+ useOssForImg: true,
50
+ })
51
+
52
+ // Emits
53
+ const emit = defineEmits(['updateImg', 'selectRow', 'slotRendered'])
54
+
55
+ // 注入
56
+ const isWidget = false // inject('isWidget', false)
57
+
58
+ // 状态
59
+ const data = ref(props.config.data || {})
60
+ const slotConfig = ref<any>()
61
+ const render = ref(false)
62
+ const activatedConfig = ref<any>({})
63
+
64
+ // 计算属性
65
+ const flexItemBodyState = computed(() => ({
66
+ padding: isWidget ? '0px' : '24px',
67
+ }))
68
+
69
+ // 方法
70
+ function slotRendered() {
71
+ emit('slotRendered')
72
+ }
73
+
74
+ function updateImg(data: any) {
75
+ emit('updateImg', data)
76
+ }
77
+
78
+ function selectRow(selectedRowKeys: any[], selectedRows: any[]) {
79
+ console.log('XReportDesign')
80
+ emit('selectRow', selectedRowKeys, selectedRows)
81
+ }
82
+
83
+ // 格式化相关方法
84
+ function calcFormatInputNum(formatStr: string) {
85
+ let count = 0
86
+ for (let i = 0; i < formatStr.length; i++) {
87
+ if (formatStr[i] === '{')
88
+ count++
89
+ }
90
+ return count
91
+ }
92
+
93
+ function displayFormatText(formatStr: string, num: number) {
94
+ let start = 0
95
+ let count = 0
96
+ num++
97
+ for (let i = 0; i < formatStr.length; i++) {
98
+ if (formatStr[i] === '}') {
99
+ start = i
100
+ count++
101
+ }
102
+ if (count === num) {
103
+ for (let j = start + 1; j < formatStr.length; j++) {
104
+ if (formatStr[j] === '{')
105
+ return formatStr.slice(start + 1, j)
106
+
107
+ if (j === formatStr.length - 1 && formatStr[j] !== '}')
108
+ return formatStr[j]
109
+ }
110
+ }
111
+ }
112
+ }
113
+
114
+ function displayFormatStartText(formatStr: string) {
115
+ let count = 0
116
+ for (let i = 0; i < formatStr.length; i++) {
117
+ if (formatStr[i] === '{')
118
+ break
119
+ count++
120
+ }
121
+ return formatStr.slice(0, count)
122
+ }
123
+
124
+ // 生命周期
125
+ onMounted(() => {
126
+ console.log('>>>> xreportdesign 渲染')
127
+ if (props.slotConfigName) {
128
+ getConfigByName(props.slotConfigName, (res: any) => {
129
+ slotConfig.value = res
130
+ res.data = { ...res.data, ...data.value }
131
+ props.config.data = res.data
132
+ activatedConfig.value = res
133
+ render.value = true
134
+ }, props.serverName)
135
+ }
136
+ else {
137
+ activatedConfig.value = props.config
138
+ render.value = true
139
+ }
140
+
141
+ if (activatedConfig.value.designMode !== 'json') {
142
+ activatedConfig.value.columns?.forEach((row: any[]) => {
143
+ if (row[0]?.type === 'list' && row[0]?.listLength === 1) {
144
+ row.forEach((cell) => {
145
+ cell.listLength = activatedConfig.value.data[cell.dataIndex].length
146
+ })
147
+ }
148
+ })
149
+ }
150
+ })
151
+
152
+ // 监听
153
+ watch(() => props.config, (newVal) => {
154
+ // 配置变化时的处理
155
+ }, { deep: true })
156
+
157
+ watch(() => activatedConfig.value, (val) => {
158
+ console.log('>>>> activatedConfig: ', val)
159
+ })
160
+ </script>
161
+
162
+ <template>
163
+ <div id="xreportdesign">
164
+ <template v-if="activatedConfig.designMode === 'json'">
165
+ <XReportJsonRender
166
+ :img-prefix="imgPrefix"
167
+ :server-name="serverName"
168
+ :display-only="displayOnly"
169
+ :show-title="showTitle"
170
+ :no-padding="noPadding"
171
+ :no-top-border="noTopBorder"
172
+ :config="activatedConfig"
173
+ @update-img="updateImg"
174
+ @select-row="selectRow"
175
+ />
176
+ </template>
177
+ <template v-else-if="isWidget">
178
+ <template v-for="(row, rowIndex) in activatedConfig.columns">
179
+ <!-- 插槽展示 -->
180
+ <template v-if="row[0].type === 'slot'">
181
+ <XReportTrGroup
182
+ :show-img-in-cell="showImgInCell"
183
+ :img-prefix="imgPrefix"
184
+ :server-name="serverName"
185
+ :env="env"
186
+ :key="rowIndex"
187
+ :use-oss-for-img="useOssForImg"
188
+ :columns="row"
189
+ @update-img="updateImg"
190
+ :no-top-border="noTopBorder"
191
+ @selectRow="selectRow"
192
+ :config-data="activatedConfig.data"
193
+ :config="activatedConfig"
194
+ :display="true"
195
+ />
196
+ </template>
197
+ <!-- 普通行 -->
198
+ <template v-else>
199
+ <template v-if="!forDisplay">
200
+ <XReportTrGroup
201
+ :show-img-in-cell="showImgInCell"
202
+ :img-prefix="imgPrefix"
203
+ :server-name="serverName"
204
+ :env="env"
205
+ :key="rowIndex"
206
+ :use-oss-for-img="useOssForImg"
207
+ :columns="row"
208
+ @update-img="updateImg"
209
+ :no-top-border="noTopBorder"
210
+ @selectRow="selectRow"
211
+ :config-data="activatedConfig.data"
212
+ :config="activatedConfig"
213
+ />
214
+ </template>
215
+ <template v-else>
216
+ <XReportTrGroup
217
+ :show-img-in-cell="showImgInCell"
218
+ :img-prefix="imgPrefix"
219
+ :server-name="serverName"
220
+ :env="env"
221
+ :use-oss-for-img="useOssForImg"
222
+ :config="activatedConfig"
223
+ :key="rowIndex"
224
+ @update-img="updateImg"
225
+ :columns="row"
226
+ @selectRow="selectRow"
227
+ :no-top-border="noTopBorder"
228
+ :config-data="activatedConfig.data"
229
+ :display="true"
230
+ />
231
+ </template>
232
+ </template>
233
+ </template>
234
+ </template>
235
+ <template v-else>
236
+ <div :class=" noPadding ? 'reportMainNoPadding' : 'reportMain'" :style="activatedConfig.width > 0 ? (`width:${activatedConfig.width}px`) : undefined">
237
+ <!-- 大标题 -->
238
+ <h2 v-if="showTitle && activatedConfig.title" class="reportTitle" v-html="activatedConfig.title" />
239
+ <!-- 小标题 / 介乎于标题与表格之间的内容 -->
240
+ <div v-if="activatedConfig.subTitle && activatedConfig.subTitle.length" class="subTitle">
241
+ <div v-for="(item, itemIndex) in activatedConfig.subTitle" :key="itemIndex" class="subTitleItems">
242
+ <template v-if="item.type === 'column'">
243
+ <span>{{ item.text }}</span>
244
+ </template>
245
+ <template v-else-if="item.type === 'inputs'">
246
+ <div class="inputsDiv">
247
+ <div v-for="(num, index) of calcFormatInputNum(item.format)" :key="index" class="inputsDivItem">
248
+ <span class="inputsDivItemLabel">{{ displayFormatStartText(item.format) }}</span>
249
+ <template v-if="!forDisplay">
250
+ <template v-if="item.inputReadOnly === true">
251
+ <a-input v-model="data[item.dataIndex][index]" :style="`width:${item.inputWidth ? item.inputWidth : '100'}%`" :disabled="true" />
252
+ </template>
253
+ <template v-else>
254
+ <a-input v-model="data[item.dataIndex][index]" :style="`width:${item.inputWidth ? item.inputWidth : '100'}%`" />
255
+ </template>
256
+ </template>
257
+ <template v-else>
258
+ {{ activatedConfig.data[item.dataIndex][index] }}
259
+ </template>
260
+ <span class="inputsDivItemLabel">{{ displayFormatText(item.format, index) }}</span>
261
+ </div>
262
+ </div>
263
+ </template>
264
+ </div>
265
+ </div>
266
+ <!-- 主体表格 -->
267
+ <table v-if="render" class="reportTable" :style="activatedConfig.style ? activatedConfig.style : undefined">
268
+ <tbody class="reportTable">
269
+ <template v-for="(row, rowIndex) in activatedConfig.columns">
270
+ <!-- 插槽展示 -->
271
+ <template v-if="row[0].type === 'slot'">
272
+ <XReportTrGroup
273
+ :show-img-in-cell="showImgInCell"
274
+ :img-prefix="imgPrefix"
275
+ :server-name="serverName"
276
+ :env="env"
277
+ :use-oss-for-img="useOssForImg"
278
+ @update-img="updateImg"
279
+ :key="rowIndex"
280
+ @select-row="selectRow"
281
+ :columns="row"
282
+ @slot-rendered="slotRendered"
283
+ :no-top-border="noTopBorder"
284
+ :config-data="activatedConfig.data"
285
+ :config="activatedConfig"
286
+ :display="true"
287
+ />
288
+ </template>
289
+ <!-- 列表 list -->
290
+ <template v-else-if="row[0].type === 'list'">
291
+ <template v-for="(num, listIndex) in row[0].listLength + 1">
292
+ <template v-if="!forDisplay">
293
+ <XReportTrGroup
294
+ :show-img-in-cell="showImgInCell"
295
+ :img-prefix="imgPrefix"
296
+ :server-name="serverName"
297
+ :env="env"
298
+ :use-oss-for-img="useOssForImg"
299
+ @slot-rendered="slotRendered"
300
+ :config="activatedConfig"
301
+ @update-img="updateImg"
302
+ :key="rowIndex + listIndex"
303
+ @select-row="selectRow"
304
+ :columns="row"
305
+ :no-top-border="noTopBorder"
306
+ :config-data="activatedConfig.data"
307
+ :list-index="listIndex"
308
+ />
309
+ </template>
310
+ <template v-else>
311
+ <XReportTrGroup
312
+ :show-img-in-cell="showImgInCell"
313
+ :img-prefix="imgPrefix"
314
+ :server-name="serverName"
315
+ :env="env"
316
+ :use-oss-for-img="useOssForImg"
317
+ @slot-rendered="slotRendered"
318
+ :config="activatedConfig"
319
+ @update-img="updateImg"
320
+ :key="rowIndex + listIndex"
321
+ @select-row="selectRow"
322
+ :columns="row"
323
+ :no-top-border="noTopBorder"
324
+ :config-data="activatedConfig.data"
325
+ :list-index="listIndex"
326
+ :display="true"
327
+ />
328
+ </template>
329
+ </template>
330
+ </template>
331
+ <!-- 动态行 inputColumns -->
332
+ <template v-else-if="row[0].type === 'inputColumns'">
333
+ <template v-if="forDisplay">
334
+ <XReportTrGroup
335
+ :show-img-in-cell="showImgInCell"
336
+ :img-prefix="imgPrefix"
337
+ :server-name="serverName"
338
+ :env="env"
339
+ :use-oss-for-img="useOssForImg"
340
+ @slot-rendered="slotRendered"
341
+ :config="activatedConfig"
342
+ @update-img="updateImg"
343
+ :columns="row[0].definition"
344
+ @select-row="selectRow"
345
+ :config-data="{ arr: activatedConfig.data[row[0].dataIndex] }"
346
+ :input-columns="true"
347
+ :no-top-border="noTopBorder"
348
+ v-for="(item, definitionIndex) in activatedConfig.data[row[0].dataIndex]"
349
+ :input-columns-definition-index="definitionIndex"
350
+ :display="true"
351
+ :key="row[0].dataIndex + definitionIndex + rowIndex"
352
+ />
353
+ </template>
354
+ <template v-if="!forDisplay">
355
+ <XReportTrGroup
356
+ :show-img-in-cell="showImgInCell"
357
+ :img-prefix="imgPrefix"
358
+ :server-name="serverName"
359
+ :env="env"
360
+ :use-oss-for-img="useOssForImg"
361
+ @slot-rendered="slotRendered"
362
+ :config="activatedConfig"
363
+ @update-img="updateImg"
364
+ :columns="row[0].definition"
365
+ @select-row="selectRow"
366
+ :config-data="{ arr: activatedConfig.data[row[0].dataIndex] }"
367
+ :input-columns="true"
368
+ :no-top-border="noTopBorder"
369
+ v-for="(item, definitionIndex) in activatedConfig.data[row[0].dataIndex]"
370
+ :input-columns-definition-index="definitionIndex"
371
+ :key="row[0].dataIndex + definitionIndex + rowIndex"
372
+ />
373
+ <!-- 动态行交互按钮 -->
374
+ <XReportTrGroup
375
+ :show-img-in-cell="showImgInCell"
376
+ :img-prefix="imgPrefix"
377
+ :server-name="serverName"
378
+ :env="env"
379
+ :use-oss-for-img="useOssForImg"
380
+ @slot-rendered="slotRendered"
381
+ :config="activatedConfig"
382
+ @update-img="updateImg"
383
+ :key="rowIndex"
384
+ @select-row="selectRow"
385
+ :columns="row"
386
+ :no-top-border="noTopBorder"
387
+ :config-data="activatedConfig.data"
388
+ :input-columns-button="true"
389
+ :input-columns="true"
390
+ />
391
+ </template>
392
+ </template>
393
+ <!-- 普通行 -->
394
+ <template v-else>
395
+ <template v-if="!forDisplay">
396
+ <XReportTrGroup
397
+ :show-img-in-cell="showImgInCell"
398
+ :img-prefix="imgPrefix"
399
+ :server-name="serverName"
400
+ :env="env"
401
+ :use-oss-for-img="useOssForImg"
402
+ @slot-rendered="slotRendered"
403
+ :key="rowIndex"
404
+ @update-img="updateImg"
405
+ :columns="row"
406
+ @select-row="selectRow"
407
+ :no-top-border="noTopBorder"
408
+ :config-data="activatedConfig.data"
409
+ :config="activatedConfig"
410
+ />
411
+ </template>
412
+ <template v-else>
413
+ <XReportTrGroup
414
+ :show-img-in-cell="showImgInCell"
415
+ :img-prefix="imgPrefix"
416
+ :server-name="serverName"
417
+ :env="env"
418
+ :use-oss-for-img="useOssForImg"
419
+ @slot-rendered="slotRendered"
420
+ :config="activatedConfig"
421
+ @update-img="updateImg"
422
+ :key="rowIndex"
423
+ @select-row="selectRow"
424
+ :columns="row"
425
+ :no-top-border="noTopBorder"
426
+ :config-data="activatedConfig.data"
427
+ :display="true"
428
+ />
429
+ </template>
430
+ </template>
431
+ </template>
432
+ </tbody>
433
+ </table>
434
+ <div v-if="showImages" style="margin-top: 5%; display: flex;margin-bottom: 5%">
435
+ <p>图片:</p>
436
+ <div v-for="(img, imgIndex) in imageList" :key="imgIndex" style="margin-left: 3%;width: 200px">
437
+ <img :src="img.url" class="img" :alt="img.name">
438
+ <p style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;width: 100%;">
439
+ {{ img.name }}
440
+ </p>
441
+ </div>
442
+ </div>
443
+ </div>
444
+ </template>
445
+ </div>
446
+ </template>
447
+
448
+ <style lang="less" scoped>
449
+ .img{
450
+ width: 95%;
451
+ height: 180px;
452
+ object-fit: cover;
453
+ }
454
+ .reportMain {
455
+ text-align: center;
456
+ margin: 0 auto;
457
+ font-size: 16px;
458
+ color: #000;
459
+ background-color: #fff;
460
+ border-radius: 8px;
461
+
462
+ .reportTitle {
463
+ font-weight: bold;
464
+ }
465
+
466
+ .subTitle {
467
+ display: flex;
468
+ justify-content: space-between;
469
+ margin-bottom: 1%;
470
+
471
+ .subTitleItems {
472
+ max-width: 30%;
473
+ }
474
+ }
475
+
476
+ .inputsDiv {
477
+ display: flex;
478
+ justify-content: space-between;
479
+ .inputsDivItem {
480
+ display: flex;
481
+ align-items: center;
482
+ padding: 0 4px;
483
+ white-space: nowrap;
484
+ .inputsDivItemLabel {
485
+ padding: 0 4px;
486
+ }
487
+ }
488
+ }
489
+
490
+ .reportTable {
491
+ width: 100%;
492
+ border-collapse: collapse;
493
+ table-layout:fixed;
494
+ word-break:break-all;
495
+ }
496
+ }
497
+ .reportMainForDisplay {
498
+ text-align: center;
499
+ margin: 10% auto;
500
+ font-size: 16px;
501
+ color: #000;
502
+ background-color: #fff;
503
+ border-radius: 8px;
504
+
505
+ .reportTitle {
506
+ font-weight: bold;
507
+ }
508
+
509
+ .subTitle {
510
+ display: flex;
511
+ justify-content: space-between;
512
+
513
+ .subTitleItems {
514
+ max-width: 30%;
515
+ }
516
+ }
517
+
518
+ .inputsDiv {
519
+ display: flex;
520
+ justify-content: space-around;
521
+ .inputsDivItem {
522
+ display: flex;
523
+ align-items: center;
524
+ padding: 0 4px;
525
+ white-space: nowrap;
526
+ .inputsDivItemLabel {
527
+ padding: 0 4px;
528
+ }
529
+ }
530
+ }
531
+
532
+ .reportTable {
533
+ width: 100%;
534
+ border-collapse: collapse;
535
+ table-layout:fixed;
536
+ word-break:break-all;
537
+ }
538
+ }
539
+ .reportMainNoPadding {
540
+ // text-align: center;
541
+ margin: 0 auto;
542
+ font-size: 16px;
543
+ color: #000;
544
+ // background-color: #fff;
545
+ border-radius: 8px;
546
+ height: auto;
547
+ min-height : 20vh;
548
+ overflow-y: auto;
549
+ overflow-x: hidden;
550
+
551
+ .reportTitle {
552
+ font-weight: bold;
553
+ }
554
+
555
+ .subTitle {
556
+ display: flex;
557
+ justify-content: space-between;
558
+
559
+ .subTitleItems {
560
+ max-width: 30%;
561
+ }
562
+ }
563
+
564
+ .inputsDiv {
565
+ display: flex;
566
+ justify-content: space-between;
567
+ .inputsDivItem {
568
+ display: flex;
569
+ align-items: center;
570
+ padding: 0 4px;
571
+ white-space: nowrap;
572
+ .inputsDivItemLabel {
573
+ padding: 0 4px;
574
+ }
575
+ }
576
+ }
577
+
578
+ .reportTable {
579
+ width: 100%;
580
+ border-collapse: collapse;
581
+ table-layout:fixed;
582
+ word-break:break-all;
583
+ }
584
+ }
585
+ .tools{
586
+ position: fixed;
587
+ right: 2%;
588
+ text-align: right;
589
+ width: 60%;
590
+ cursor: pointer;
591
+ .toolsItem{
592
+ width: 15%;
593
+ margin-right: 3%;
594
+ display: inline-block;
595
+ }
596
+ }
597
+ </style>