af-mobile-client-vue3 1.1.6 → 1.1.7

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 (79) hide show
  1. package/.env +6 -6
  2. package/.env.development +4 -4
  3. package/.env.envoiceShow +6 -6
  4. package/.env.production +6 -6
  5. package/.husky/commit-msg +1 -1
  6. package/.husky/pre-commit +1 -1
  7. package/.vscode/settings.json +61 -61
  8. package/mock/modules/user.mock.ts +152 -152
  9. package/package.json +1 -1
  10. package/public/favicon.svg +4 -4
  11. package/public/safari-pinned-tab.svg +32 -32
  12. package/scripts/verifyCommit.js +19 -19
  13. package/src/App.vue +43 -43
  14. package/src/api/user/index.ts +40 -40
  15. package/src/bootstrap.ts +18 -18
  16. package/src/components/core/NavBar/index.vue +12 -12
  17. package/src/components/core/Tabbar/index.vue +38 -38
  18. package/src/components/core/XGridDropOption/index.vue +151 -151
  19. package/src/components/core/XMultiSelect/index.vue +183 -183
  20. package/src/components/data/XCellDetail/index.vue +106 -106
  21. package/src/components/data/XForm/index.vue +5 -0
  22. package/src/components/data/XFormItem/index.vue +3 -4
  23. package/src/components/data/XOlMap/README.md +0 -2
  24. package/src/components/data/XOlMap/XLocationPicker/index.vue +21 -9
  25. package/src/components/data/XOlMap/index.vue +81 -74
  26. package/src/components/data/XOlMap/types.ts +0 -4
  27. package/src/components/data/XOlMap/utils/wgs84ToGcj02.js +154 -154
  28. package/src/components/data/XReportForm/XReportFormJsonRender.vue +220 -220
  29. package/src/components/data/XReportForm/index.vue +1079 -1079
  30. package/src/components/data/XReportGrid/XAddReport/index.ts +1 -1
  31. package/src/components/data/XReportGrid/XReportDrawer/index.ts +1 -1
  32. package/src/components/data/XSignature/index.vue +285 -285
  33. package/src/components/data/XTag/index.vue +10 -10
  34. package/src/components/layout/NormalDataLayout/index.vue +70 -70
  35. package/src/components/layout/TabBarLayout/index.vue +40 -40
  36. package/src/components.d.ts +53 -53
  37. package/src/env.d.ts +16 -16
  38. package/src/font-style/font.css +3 -3
  39. package/src/hooks/useCommon.ts +9 -9
  40. package/src/locales/en-US.json +25 -25
  41. package/src/locales/zh-CN.json +25 -25
  42. package/src/plugins/AppData.ts +38 -38
  43. package/src/router/guards.ts +59 -59
  44. package/src/router/index.ts +61 -61
  45. package/src/router/invoiceRoutes.ts +33 -33
  46. package/src/services/api/common.ts +109 -109
  47. package/src/services/api/manage.ts +8 -8
  48. package/src/services/api/search.ts +16 -16
  49. package/src/services/restTools.ts +56 -56
  50. package/src/services/v3Api.ts +11 -11
  51. package/src/stores/modules/setting.ts +52 -52
  52. package/src/stores/mutation-type.ts +7 -7
  53. package/src/utils/authority-utils.ts +84 -84
  54. package/src/utils/crypto.ts +39 -39
  55. package/src/utils/i18n.ts +41 -41
  56. package/src/utils/indexedDB.ts +180 -180
  57. package/src/utils/mobileUtil.ts +26 -26
  58. package/src/utils/routerUtil.ts +271 -271
  59. package/src/utils/runEvalFunction.ts +13 -13
  60. package/src/utils/wechatUtil.ts +9 -9
  61. package/src/views/common/LoadError.vue +64 -64
  62. package/src/views/common/NotFound.vue +68 -68
  63. package/src/views/component/EvaluateRecordView/index.vue +40 -40
  64. package/src/views/component/XCellDetailView/index.vue +217 -217
  65. package/src/views/component/XOlMapView/XLocationPicker/index.vue +120 -120
  66. package/src/views/component/XOlMapView/index.vue +0 -1
  67. package/src/views/component/XReportFormIframeView/index.vue +47 -47
  68. package/src/views/component/XReportFormView/index.vue +13 -13
  69. package/src/views/component/XSignatureView/index.vue +50 -50
  70. package/src/views/component/menu.vue +117 -117
  71. package/src/views/component/notice.vue +46 -46
  72. package/src/views/component/topNav.vue +36 -36
  73. package/src/views/invoiceShow/index.vue +61 -61
  74. package/src/views/user/login/ForgetPasswordForm.vue +94 -94
  75. package/src/views/user/login/LoginTitle.vue +68 -68
  76. package/src/views/user/login/index.vue +22 -22
  77. package/src/views/user/my/index.vue +230 -230
  78. package/src/vue-router.d.ts +9 -9
  79. package/tsconfig.json +43 -43
@@ -1,1079 +1,1079 @@
1
- <script setup lang="ts">
2
- import Uploader from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
3
- import XReportFormJsonRender from '@af-mobile-client-vue3/components/data/XReportForm/XReportFormJsonRender.vue'
4
- import XSignature from '@af-mobile-client-vue3/components/data/XSignature/index.vue'
5
- import { getConfigByNameWithoutIndexedDB } from '@af-mobile-client-vue3/services/api/common'
6
- import {
7
- Button as vanButton,
8
- Cell as vanCell,
9
- CellGroup as vanCellGroup,
10
- Collapse as vanCollapse,
11
- CollapseItem as vanCollapseItem,
12
- Field as vanField,
13
- Form as vanForm,
14
- NavBar as vanNavBar,
15
- Skeleton as vanSkeleton,
16
- } from 'vant'
17
- import { defineEmits, nextTick, reactive, ref, watch } from 'vue'
18
-
19
- // ------------------------- 类型定义 -------------------------
20
- interface configDefine {
21
- data?: any
22
- designMode?: string
23
- title?: string | undefined
24
- subTitle?: Array<cell> | undefined
25
- columns?: Array<any>
26
- slotsDeclare?: Array<string> | undefined
27
- tempData?: any
28
- }
29
-
30
- interface getConfigLock {
31
- status: boolean
32
- }
33
-
34
- interface cell {
35
- type: string
36
- dataIndex: string
37
- format: string | undefined
38
- }
39
-
40
- // ------------------------- 数据 -------------------------
41
- const props = defineProps({
42
- // 配置名
43
- configName: String,
44
- // 是否将动态行的label显示在标题上
45
- showInputColumnsLabelOnTitle: { default: false },
46
- slotName: String,
47
- showNav: { default: true },
48
- localConfig: { default: undefined },
49
- configData: { default: undefined },
50
- })
51
- const emit = defineEmits(['saveConfig'])
52
- // 原始配置
53
- const activatedConfig: configDefine = reactive({})
54
- // 激活的配置名
55
- const activatedConfigName = ref('')
56
- // 下载的配置
57
- const configFromWeb = reactive({})
58
- // 定时器
59
- let timer: NodeJS.Timeout
60
- // 控制组件渲染
61
- const scanFinish = ref(false)
62
- // 折叠面板当前激活的值
63
- const activeCollapseName = ref('副标题')
64
-
65
- watch(() => props.configName, () => {
66
- // 这里是你的处理逻辑
67
- initComponent()
68
- })
69
-
70
- // ------------------------- 方法 -------------------------
71
- // 为inputs类型的数据,整理格式,供form展示用
72
- function formatInputs(cell: cell): string[] {
73
- const format = cell.format
74
- const arr = format.split('{}')
75
- const result = []
76
- const reg = /[\u4E00-\u9FA5a-z]/gi
77
- arr.forEach((str) => {
78
- if (str.length >= 1 && str.match(reg)) {
79
- const strs = str.match(reg)
80
- result.push(strs.join(''))
81
- }
82
- })
83
- if (!activatedConfig.data[cell.dataIndex][result.length - 1]) {
84
- let dataKeySet = Object.keys(activatedConfig.data)
85
- dataKeySet = dataKeySet.filter((key) => {
86
- return key.startsWith(cell.dataIndex)
87
- })
88
- dataKeySet.sort()
89
- const target = dataKeySet[0]
90
- dataKeySet.shift()
91
- dataKeySet.forEach((key) => {
92
- activatedConfig.data[key].forEach((item) => {
93
- activatedConfig.data[target].push(item)
94
- })
95
- })
96
-
97
- for (let i = 0; i < result.length; i++) {
98
- if (!activatedConfig.data[cell.dataIndex][i])
99
- activatedConfig.data[cell.dataIndex][i] = undefined
100
- }
101
- }
102
- return result
103
- }
104
-
105
- // 左上角返回按钮
106
- function onClickLeft(): void {
107
- history.back()
108
- }
109
-
110
- // 提交按钮
111
- function onSubmit(): void {
112
- if (activatedConfig.tempData) {
113
- const keys = Object.keys(activatedConfig.tempData)
114
- keys.forEach((key) => {
115
- changeDeepObject(activatedConfig.data, key, activatedConfig.tempData[key])
116
- })
117
- }
118
- console.warn('保存', activatedConfig)
119
- emit('saveConfig', activatedConfig)
120
- }
121
-
122
- // // 动态行新增
123
- // function addInputColumns(dataIndex: string, define: Array<any>): void {
124
- // const temp = {}
125
- // define.forEach((def) => {
126
- // let begin = def.initialValue
127
- // if (def.type === 'increment') {
128
- // if (activatedConfig.data[dataIndex].length > 0) {
129
- // begin = activatedConfig.data[dataIndex][activatedConfig.data[dataIndex].length - 1][def.dataIndex]
130
- // begin = Number.parseInt(begin)
131
- // }
132
- // temp[def.dataIndex] = begin + def.step
133
- // }
134
- // else {
135
- // temp[def.dataIndex] = ''
136
- // }
137
- // })
138
- // activatedConfig.data[dataIndex].push(temp)
139
- // }
140
- //
141
- // // 动态行删除
142
- // function removeInputColumns(dataIndex: string) {
143
- // activatedConfig.data[dataIndex].pop()
144
- // }
145
-
146
- // 扫描所有插槽名
147
- function scanConfigName(config: configDefine, resut: Array<string>): void {
148
- if (config.slotsDeclare) {
149
- config.slotsDeclare.forEach((name) => {
150
- resut.push(name)
151
- })
152
- }
153
- }
154
-
155
- // 检查slot是否在配置文件中包含,如果没有包含,则视为非法获取
156
- function checkSlotDefine(config: configDefine): boolean {
157
- const slotsDeclare = config.slotsDeclare
158
- const total = slotsDeclare.length
159
- let count = 0
160
- slotsDeclare.forEach((declare) => {
161
- config.columns.forEach((row: Array<any>) => {
162
- row.forEach((cell) => {
163
- if (cell.slotConfig === declare)
164
- count++
165
- })
166
- })
167
- })
168
-
169
- return count === total
170
- }
171
-
172
- // 扫描配置,如果有插槽则拼接插槽
173
- function scanConfigSlot(config: configDefine): void {
174
- const columnsArr: Array<any> = config.columns
175
- for (let i = 0; i < columnsArr.length; i++) {
176
- for (let j = 0; j < columnsArr[i].length; j++) {
177
- // 如果发现type为slot,开始匹配对应的slot配置文件
178
- if (columnsArr[i][j].type === 'slot') {
179
- const targetName = columnsArr[i][j].slotConfig
180
- // 找不到目标插槽配置
181
- if (!configFromWeb[targetName] || !configFromWeb[targetName].columns)
182
- return
183
-
184
- // 替换columns,合并data
185
- config.columns[i] = []
186
- const before = config.columns.slice(0, i)
187
- let after = config.columns.slice(i + 1, config.columns.length)
188
-
189
- const addArr = []
190
-
191
- if (configFromWeb[targetName].cardMode === true) {
192
- const temp = [{
193
- type: 'card',
194
- content: [],
195
- label: configFromWeb[targetName].title,
196
- }]
197
- for (let k = 0; k < configFromWeb[targetName].columns.length; k++) {
198
- configFromWeb[targetName].columns[k].forEach((cell) => {
199
- temp[0].content.push(cell)
200
- })
201
- }
202
- addArr.push(temp)
203
- }
204
- else {
205
- for (let k = 0; k < configFromWeb[targetName].columns.length; k++) {
206
- const temp = []
207
- configFromWeb[targetName].columns[k].forEach((cell) => {
208
- temp.push(cell)
209
- })
210
- addArr.push(temp)
211
- }
212
- }
213
-
214
- const newArr = []
215
- // 拼接之前的数组
216
- if (before.length > 0) {
217
- if (before.length >= 1) {
218
- before.forEach((item) => {
219
- newArr.push(item)
220
- })
221
- }
222
- else {
223
- newArr.push(before)
224
- }
225
- }
226
-
227
- addArr.forEach((arr) => {
228
- newArr.push(arr)
229
- })
230
-
231
- // 拼接之后的数组
232
- if (after.length === 1) {
233
- if (after[0].type === 'slot' || after[0][0].type === 'slot')
234
- after = []
235
- }
236
- if (after.length > 0) {
237
- if (after.length >= 1) {
238
- after.forEach((item) => {
239
- newArr.push(item)
240
- })
241
- }
242
- else {
243
- newArr.push(after)
244
- }
245
- }
246
-
247
- config.columns = newArr
248
- if (configFromWeb[targetName].slotsDeclare)
249
- config.slotsDeclare = configFromWeb[targetName].slotsDeclare
250
-
251
- else
252
- config.slotsDeclare = []
253
-
254
- if (config.data.images && configFromWeb[targetName].data.images) {
255
- config.data.images = { ...config.data.images, ...configFromWeb[targetName].data.images }
256
- delete configFromWeb[targetName].data.images
257
- }
258
- config.data = { ...config.data, ...configFromWeb[targetName].data }
259
- }
260
- }
261
- }
262
- Object.assign(activatedConfig, config)
263
- }
264
-
265
- // 获取并拼装插槽
266
- function getConfigAndJoin(config: configDefine, outerLock: getConfigLock): void {
267
- // 检查主配置插槽声明是否合法
268
- const check = checkSlotDefine(config)
269
- const waitForDownloadSlotName = []
270
- if (check) {
271
- // 扫描主配置中声明的插槽名
272
- scanConfigName(config, waitForDownloadSlotName)
273
-
274
- const total = waitForDownloadSlotName.length
275
- let count = 0
276
-
277
- // 挨个获取插槽
278
- waitForDownloadSlotName.forEach((configName) => {
279
- getConfigByNameWithoutIndexedDB(configName).then((res) => {
280
- configFromWeb[configName] = res
281
- count++
282
- })
283
- })
284
-
285
- const timer = setInterval(() => {
286
- if (count >= total) {
287
- clearInterval(timer)
288
- scanConfigSlot(config)
289
- if (config.slotsDeclare.length > 0) {
290
- const lock: getConfigLock = { status: true }
291
- getConfigAndJoin(config, lock)
292
- const innerTimer = setInterval(() => {
293
- if (!lock.status) {
294
- clearInterval(innerTimer)
295
- outerLock.status = false
296
- }
297
- }, 100)
298
- }
299
- else {
300
- outerLock.status = false
301
- }
302
- }
303
- }, 100)
304
- }
305
- else {
306
- outerLock.status = false
307
- }
308
- }
309
-
310
- function deserializeFunctionAndRun(functionStr, value) {
311
- // eslint-disable-next-line no-eval
312
- const fun = eval(`(${functionStr})`)
313
- return fun(value, activatedConfig)
314
- }
315
-
316
- function deserializeFunctionAndRunWithConfig(functionStr) {
317
- // eslint-disable-next-line no-eval
318
- const fun = eval(`(${functionStr})`)
319
- return fun(activatedConfig)
320
- }
321
-
322
- // 将table配置的表格转换为适合Form展示的格式
323
- function formatConfigToForm(config: configDefine): void {
324
- const formColumns: Array<object> = []
325
- const labels: Array<string> = []
326
- for (let i = 0; i < config.columns.length; i++) {
327
- let tempObj: {
328
- customFunction?: any
329
- inputColumns?: boolean
330
- dataIndex: string
331
- label: string
332
- listType?: string
333
- listLength?: number
334
- valueText?: string
335
- type: string | undefined
336
- format?: string
337
- definition?: Array<any>
338
- editable?: boolean
339
- inputReadOnly?: boolean
340
- content?: Array<any>
341
- text?: string
342
- } = {
343
- label: '',
344
- type: undefined,
345
- dataIndex: '',
346
- }
347
-
348
- const row: Array<any> = config.columns[i]
349
- let listArr = []
350
- for (let j = 0; j < row.length; j++) {
351
- switch (row[j].type) {
352
- case 'column' :
353
- if (row[j].customFunctionForDynamicDataIndex)
354
- row[j].dataIndex = deserializeFunctionAndRunWithConfig(row[j].customFunctionForDynamicDataIndex)
355
- if (j === row.length - 1) {
356
- if (row[j].customFunction) {
357
- tempObj.customFunction = row[j].customFunction
358
- tempObj.label = deserializeFunctionAndRun(row[j].customFunction, row[j].dataIndex)
359
- }
360
- else {
361
- labels.push(tempObj.label)
362
- labels.push(row[j].text)
363
- tempObj = {
364
- label: '',
365
- type: undefined,
366
- dataIndex: '',
367
- }
368
- }
369
- }
370
- else if (tempObj.label && tempObj.dataIndex) {
371
- formColumns.push(tempObj)
372
- tempObj = {
373
- label: '',
374
- type: undefined,
375
- dataIndex: '',
376
- }
377
- }
378
- else if (tempObj.customFunction) {
379
- formColumns.push(tempObj)
380
- tempObj = {
381
- label: '',
382
- type: undefined,
383
- dataIndex: '',
384
- }
385
- }
386
- else if (tempObj.label && !tempObj.dataIndex) {
387
- labels.push(tempObj.label)
388
- tempObj = {
389
- label: '',
390
- type: undefined,
391
- dataIndex: '',
392
- }
393
- }
394
- if (row[j].customFunction) {
395
- tempObj.customFunction = row[j].customFunction
396
- tempObj.label = deserializeFunctionAndRun(row[j].customFunction, row[j].dataIndex)
397
- }
398
- else {
399
- tempObj.label = row[j].text
400
- }
401
- break
402
- case 'value' :
403
- tempObj.valueText = row[j].value
404
- tempObj.editable = false
405
- tempObj.type = 'showValue'
406
- break
407
- case 'input' :
408
- if (row[j].customFunctionForDynamicDataIndex)
409
- row[j].dataIndex = deserializeFunctionAndRunWithConfig(row[j].customFunctionForDynamicDataIndex)
410
- tempObj.dataIndex = row[j].dataIndex
411
- tempObj.type = 'input'
412
- if (row[j].inputReadOnly)
413
- tempObj.inputReadOnly = true
414
- break
415
- case 'curDateInput' :
416
- tempObj.dataIndex = row[j].dataIndex
417
- tempObj.text = row[j].text
418
- tempObj.type = 'curDateInput'
419
- break
420
- case 'signature' :
421
- tempObj.dataIndex = row[j].dataIndex
422
- tempObj.text = row[j].text
423
- tempObj.type = 'signature'
424
- break
425
- case 'inputs' :
426
- if (!tempObj.format)
427
- tempObj.format = ''
428
- if (!tempObj.dataIndex)
429
- tempObj.dataIndex = row[j].dataIndex
430
- tempObj.format += row[j].format
431
- tempObj.type = 'inputs'
432
- if (row[j].inputReadOnly)
433
- tempObj.inputReadOnly = true
434
- break
435
- case 'images' :
436
- tempObj.dataIndex = row[j].dataIndex
437
- tempObj.type = 'images'
438
- break
439
- case 'inputColumns' :
440
- tempObj.label = ''
441
- tempObj.dataIndex = row[j].dataIndex
442
- tempObj.definition = row[j].definition
443
- if (labels.length > 0) {
444
- for (let k = 0; k < tempObj.definition.length; k++) {
445
- if (labels[k].length > 1) {
446
- tempObj.definition[k].label = labels[k]
447
- if (props.showInputColumnsLabelOnTitle) { // 动态行label展示在标题
448
- if (k === tempObj.definition.length - 1)
449
- tempObj.label = `${tempObj.label} ${labels[k].replace(/\s*/g, '')}`
450
- else
451
- tempObj.label = `${tempObj.label} ${labels[k].replace(/\s*/g, '')} :`
452
- }
453
- else { // 动态行仅展示为’动态行‘
454
- tempObj.label = '动态行'
455
- }
456
- }
457
- else {
458
- tempObj.definition[k].label = ''
459
- }
460
- }
461
- }
462
- tempObj.type = 'inputColumns'
463
- break
464
- case 'list' :
465
- tempObj.valueText = row[j].listHead
466
- tempObj.type = 'list'
467
- tempObj.listType = row[j].listType
468
- tempObj.dataIndex = row[j].dataIndex
469
- if (row[j].content)
470
- tempObj.content = row[j].content
471
- tempObj.listLength = row[j].listLength
472
- listArr.push(tempObj)
473
- tempObj = {
474
- label: '',
475
- type: undefined,
476
- dataIndex: '',
477
- }
478
- }
479
- }
480
- if (listArr.length > 0)
481
- formColumns.push({ type: 'list', content: listArr })
482
- else if (tempObj.type || tempObj.label)
483
- formColumns.push(tempObj)
484
- listArr = []
485
- tempObj = {
486
- label: '',
487
- type: undefined,
488
- dataIndex: '',
489
- }
490
- }
491
- activatedConfig.columns = formColumns
492
- }
493
-
494
- // 获取子组件更新的file列表
495
- function updateFile(files, index) {
496
- files.forEach((file) => {
497
- if (file.content)
498
- delete file.content
499
- if (file.file)
500
- delete file.file
501
- if (file.objectUrl)
502
- delete file.objectUrl
503
- })
504
- if (index.includes('@@@'))
505
- changeDeepObjectDeepCopy(activatedConfig.data.images, index, files)
506
- else
507
- activatedConfig.data.images[index] = files
508
- }
509
-
510
- // function handleInputDeepChange(event, dataIndex) {
511
- // this.$forceUpdate()
512
- // }
513
- function getDeepObject(obj, strPath) {
514
- const arr = strPath.split('@@@')
515
- let result = obj[arr[0]]
516
- arr.shift()
517
- try {
518
- while (arr.length > 0) {
519
- result = result[arr[0]]
520
- arr.shift()
521
- }
522
- }
523
- catch {
524
- result = undefined
525
- }
526
- return result
527
- }
528
-
529
- function changeDeepObject(obj, strPath, newVal) {
530
- const arr = strPath.split('@@@')
531
- if (arr.length === 1) {
532
- obj[arr[0]] = newVal
533
- }
534
- else {
535
- let result = obj[arr[0]]
536
- arr.shift()
537
- while (arr.length > 1) {
538
- result = result[arr[0]]
539
- arr.shift()
540
- }
541
- result[arr[0]] = newVal
542
- }
543
- }
544
-
545
- function changeDeepObjectDeepCopy(obj, strPath, newVal) {
546
- const arr = strPath.split('@@@')
547
- if (arr.length === 1) {
548
- obj[arr[0]] = newVal
549
- }
550
- else {
551
- let result = obj[arr[0]]
552
- arr.shift()
553
- while (arr.length > 1) {
554
- result = result[arr[0]]
555
- arr.shift()
556
- }
557
- Object.assign(result[arr[0]], newVal)
558
- }
559
- }
560
-
561
- // ------------------------- 初始化 -------------------------
562
- initComponent()
563
-
564
- function initComponent() {
565
- if (props.localConfig !== undefined && Object.keys(props.localConfig).length > 0) {
566
- Object.assign(activatedConfig, props.localConfig)
567
-
568
- if (activatedConfig.designMode === 'json') {
569
- activatedConfig.data = {}
570
- Object.assign(activatedConfig.data, props.configData)
571
- nextTick(() => {
572
- scanFinish.value = true
573
- })
574
- return
575
- }
576
- else {
577
- const lock = { status: true }
578
- if (activatedConfig.slotsDeclare) {
579
- getConfigAndJoin(activatedConfig, lock)
580
- timer = setInterval(() => {
581
- if (!lock.status) {
582
- clearInterval(timer)
583
- // 将配置文件格式更改为更利于Form的组织形式
584
- formatConfigToForm(activatedConfig)
585
- nextTick(() => {
586
- scanFinish.value = true
587
- })
588
- }
589
- }, 100)
590
- }
591
- else {
592
- formatConfigToForm(activatedConfig)
593
- nextTick(() => {
594
- scanFinish.value = true
595
- })
596
- }
597
- if (props.configData !== undefined)
598
- Object.assign(activatedConfig.data, props.configData)
599
-
600
- activatedConfig.columns.forEach((row) => {
601
- row.forEach((item) => {
602
- if (item.dataIndex && item.dataIndex.includes('@@@')) {
603
- if (!activatedConfig.tempData) {
604
- activatedConfig.tempData = {}
605
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
606
- if (item.type === 'images')
607
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
608
- }
609
- else {
610
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
611
- if (item.type === 'images')
612
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
613
- }
614
- }
615
- })
616
- })
617
- console.warn('初始化完成,配置:', activatedConfig)
618
- }
619
- }
620
-
621
- if (props.slotName)
622
- activatedConfigName.value = props.slotName
623
-
624
- else
625
- activatedConfigName.value = props.configName
626
-
627
- getConfigByNameWithoutIndexedDB(activatedConfigName.value).then((result) => {
628
- Object.assign(activatedConfig, result)
629
- if (activatedConfig.designMode === 'json') {
630
- if (props.configData === undefined) {
631
- console.error('无法找到json配置的数据')
632
- }
633
- else {
634
- activatedConfig.data = {}
635
- Object.assign(activatedConfig.data, props.configData)
636
- nextTick(() => {
637
- scanFinish.value = true
638
- })
639
- }
640
- }
641
- else {
642
- const lock = { status: true }
643
- if (activatedConfig.slotsDeclare) {
644
- getConfigAndJoin(activatedConfig, lock)
645
- timer = setInterval(() => {
646
- if (!lock.status) {
647
- clearInterval(timer)
648
- // 将配置文件格式更改为更利于Form的组织形式
649
- formatConfigToForm(activatedConfig)
650
- nextTick(() => {
651
- scanFinish.value = true
652
- })
653
- }
654
- }, 100)
655
- }
656
- else {
657
- formatConfigToForm(activatedConfig)
658
- nextTick(() => {
659
- scanFinish.value = true
660
- })
661
- }
662
- if (props.configData !== undefined)
663
- Object.assign(activatedConfig.data, props.configData)
664
- }
665
-
666
- activatedConfig.columns.forEach((row) => {
667
- row.forEach((item) => {
668
- if (item.dataIndex && item.dataIndex.includes('@@@')) {
669
- if (!activatedConfig.tempData) {
670
- activatedConfig.tempData = {}
671
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
672
- if (item.type === 'images')
673
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
674
- }
675
- else {
676
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
677
- if (item.type === 'images')
678
- activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
679
- }
680
- }
681
- })
682
- })
683
- }).catch((e) => {
684
- console.error(e)
685
- })
686
- }
687
- function getNow() {
688
- const date = new Date()
689
- const year = date.getFullYear()
690
- const month = String(date.getMonth() + 1).padStart(2, '0')
691
- const day = String(date.getDate()).padStart(2, '0')
692
- const hours = String(date.getHours()).padStart(2, '0')
693
- const minutes = String(date.getMinutes()).padStart(2, '0')
694
- const seconds = String(date.getSeconds()).padStart(2, '0')
695
- return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
696
- }
697
- </script>
698
-
699
- <template>
700
- <!-- 标题栏 -->
701
- <van-nav-bar
702
- v-if="showNav"
703
- title="动态报表表单"
704
- left-text="返回"
705
- left-arrow
706
- @click-left="onClickLeft"
707
- />
708
- <div v-if="scanFinish" class="main">
709
- <template v-if="activatedConfig.designMode === 'json'">
710
- <XReportFormJsonRender :json-config="activatedConfig" />
711
- </template>
712
- <template v-else>
713
- <!-- 标题 -->
714
- <h2 v-if="activatedConfig.title" class="title" v-html="activatedConfig.title" />
715
- <!-- 副标题 -->
716
- <div v-if="activatedConfig.subTitle && activatedConfig.subTitle.length > 0" class="form_item">
717
- <van-collapse v-model="activeCollapseName" accordion>
718
- <van-collapse-item title="副标题" name="副标题">
719
- <van-form>
720
- <van-cell-group inset>
721
- <template v-for="(subCell, cellIndex) in activatedConfig.subTitle" :key="cellIndex">
722
- <template v-if="subCell.type === 'inputs'">
723
- <template v-for="(item, itemIndex) in formatInputs(subCell)" :key="itemIndex">
724
- <van-field
725
- v-model="activatedConfig.data[subCell.dataIndex][itemIndex]"
726
- :label="`${item}:`"
727
- clearable
728
- type="textarea"
729
- rows="1"
730
- autosize
731
- :placeholder="`请输入${item}`"
732
- />
733
- </template>
734
- </template>
735
- <template v-else>
736
- <van-field
737
- v-model="activatedConfig.data[subCell.dataIndex]"
738
- :label="`${subCell.format}:`"
739
- clearable
740
- type="textarea"
741
- rows="1"
742
- autosize
743
- :placeholder="`请输入${subCell.format}`"
744
- />
745
- </template>
746
- </template>
747
- </van-cell-group>
748
- </van-form>
749
- </van-collapse-item>
750
- </van-collapse>
751
- </div>
752
- <!-- 表单项 -->
753
- <div class="form_item">
754
- <van-collapse v-model="activeCollapseName" accordion>
755
- <van-collapse-item title="表单项" name="表单项">
756
- <van-form>
757
- <template v-for="(row, index) in activatedConfig.columns" :key="index">
758
- <!-- value属性 -->
759
- <van-cell-group v-if="row.type === 'showValue'" inset class="cell_group">
760
- <van-cell center :title="row.label" :value="row.valueText" />
761
- </van-cell-group>
762
- <!-- input -->
763
- <van-cell-group v-else-if="row.type === 'input'" inset class="cell_group" :title="row.label">
764
- <template v-if="row.inputReadOnly === true">
765
- <template v-if="row.dataIndex.includes('@@@')">
766
- <van-field
767
- v-model="activatedConfig.tempData[row.dataIndex]"
768
- :label="`${row.label}:`"
769
- :placeholder="`请输入${row.label}`"
770
- clearable
771
- type="textarea"
772
- rows="1"
773
- :disabled="true"
774
- autosize
775
- />
776
- </template>
777
- <template v-else>
778
- <van-field
779
- v-model="activatedConfig.data[row.dataIndex]"
780
- :label="`${row.label}:`"
781
- :placeholder="`请输入${row.label}`"
782
- clearable
783
- type="textarea"
784
- rows="1"
785
- :disabled="true"
786
- autosize
787
- />
788
- </template>
789
- </template>
790
- <template v-else>
791
- <template v-if="row.dataIndex.includes('@@@')">
792
- <van-field
793
- v-model="activatedConfig.tempData[row.dataIndex]"
794
- :label="`${row.label}:`"
795
- :placeholder="`请输入${row.label}`"
796
- clearable
797
- type="textarea"
798
- rows="1"
799
- autosize
800
- />
801
- </template>
802
- <template v-else>
803
- <van-field
804
- v-model="activatedConfig.data[row.dataIndex]"
805
- :label="`${row.label}:`"
806
- :placeholder="`请输入${row.label}`"
807
- clearable
808
- type="textarea"
809
- rows="1"
810
- autosize
811
- />
812
- </template>
813
- </template>
814
- </van-cell-group>
815
- <!-- curDateInput -->
816
- <van-cell-group v-else-if="row.type === 'curDateInput'" inset style="margin-top: 4vh">
817
- <van-field
818
- v-model="activatedConfig.data[row.dataIndex]"
819
- :label="row.valueText ? `${row.valueText}:` : ''"
820
- :placeholder="row.valueText ? `请点击右侧按钮设置${row.valueText}` : '请点击右侧按钮设置数据'"
821
- readonly
822
- type="textarea"
823
- rows="1"
824
- autosize
825
- >
826
- <template #button>
827
- <van-button v-if="!activatedConfig.data[row.dataIndex]" size="small" type="primary" @click="activatedConfig.data[row.dataIndex] = getNow()">
828
- {{ row.text }}
829
- </van-button>
830
- </template>
831
- </van-field>
832
- </van-cell-group>
833
- <!-- signature -->
834
- <van-cell-group v-else-if="row.type === 'signature'" inset style="margin-top: 4vh">
835
- <van-field
836
- :label="row.valueText ? `${row.valueText}:` : ''"
837
- readonly
838
- rows="1"
839
- autosize
840
- >
841
- <template #button>
842
- <XSignature v-model="activatedConfig.data[row.dataIndex]" />
843
- </template>
844
- </van-field>
845
- </van-cell-group>
846
- <!-- inputs -->
847
- <van-cell-group v-else-if="row.type === 'inputs'" inset :title="row.label">
848
- <template v-if="row.inputReadOnly === true">
849
- <template v-for="(item, _index) in formatInputs(row)" :key="_index">
850
- <van-field
851
- v-model="activatedConfig.data[row.dataIndex][_index]"
852
- :label="`${item}:`"
853
- :placeholder="`请输入${item}`"
854
- clearable
855
- type="textarea"
856
- rows="1"
857
- :disabled="true"
858
- autosize
859
- />
860
- </template>
861
- </template>
862
- <template v-else>
863
- <template v-for="(item, _index) in formatInputs(row)" :key="_index">
864
- <van-field
865
- v-model="activatedConfig.data[row.dataIndex][_index]"
866
- :label="`${item}:`"
867
- :placeholder="`请输入${item}`"
868
- clearable
869
- type="textarea"
870
- rows="1"
871
- autosize
872
- />
873
- </template>
874
- </template>
875
- </van-cell-group>
876
- <!-- images -->
877
- <van-cell-group v-else-if="row.type === 'images'" inset :title="row.label">
878
- <template v-if="row.dataIndex.includes('@@@')">
879
- <Uploader
880
- upload-mode="oss"
881
- :image-list="activatedConfig.tempData[row.dataIndex]"
882
- :outer-index="row.dataIndex"
883
- authority="admin"
884
- @update-file-list="updateFile"
885
- />
886
- </template>
887
- <template v-else>
888
- <Uploader
889
- upload-mode="oss"
890
- :image-list="activatedConfig.data.images[row.dataIndex]"
891
- :outer-index="row.dataIndex"
892
- authority="admin"
893
- @update-file-list="updateFile"
894
- />
895
- </template>
896
- </van-cell-group>
897
- <!-- 动态行 -->
898
- <template v-else-if="row.type === 'inputColumns'">
899
- <!-- <van-divider class="divider"> -->
900
- <!-- {{ row.label }} -->
901
- <!-- </van-divider> -->
902
- <van-cell-group inset :title="row.label" style="background-color: #eff2f5">
903
- <van-cell-group v-for="(_item, _index) in activatedConfig.data[row.dataIndex]" :key="_index" inset class="my-cell-group" style="margin: 0 0 10px 0">
904
- <div v-for="(def, defIndex) in row.definition" :key="defIndex">
905
- <van-field
906
- v-if="def.type === 'curDateInput'"
907
- v-model="activatedConfig.data[row.dataIndex][_index][def.dataIndex]"
908
- :label="`${def.label}:`"
909
- type="textarea"
910
- rows="1"
911
- autosize
912
- :placeholder="`请点击右侧按钮设置${def.label}`"
913
- readonly
914
- >
915
- <template #button>
916
- <van-button v-show="activatedConfig.data[row.dataIndex][_index][def.dataIndex] === ''" size="small" type="primary" @click="activatedConfig.data[row.dataIndex][_index][def.dataIndex] = getNow()">
917
- {{ def.text }}
918
- </van-button>
919
- </template>
920
- </van-field>
921
- <van-field
922
- v-else
923
- v-model="activatedConfig.data[row.dataIndex][_index][def.dataIndex]"
924
- :label="`${def.label}:`"
925
- type="textarea"
926
- rows="1"
927
- autosize
928
- :placeholder="`请输入${def.label}`"
929
- clearable
930
- />
931
- </div>
932
- </van-cell-group>
933
- </van-cell-group>
934
-
935
- <!-- <div class="button_group"> -->
936
- <!-- <van-button class="input_columns_button" plain type="primary" @click="addInputColumns(row.dataIndex, row.definition)"> -->
937
- <!-- <van-icon name="plus" /> -->
938
- <!-- </van-button> -->
939
- <!-- <van-button class="input_columns_button" plain type="primary" @click="removeInputColumns(row.dataIndex)"> -->
940
- <!-- <van-icon name="minus" /> -->
941
- <!-- </van-button> -->
942
- <!-- </div> -->
943
- </template>
944
- <!-- list -->
945
- <template v-else-if="row.type === 'list'">
946
- <template v-for="(listIndex) in row.content[0].listLength" :key="listIndex">
947
- <div style="margin-top: 3vh; margin-bottom: 3vh">
948
- <van-cell-group inset :title="row.label" style="background-color: #eff2f5">
949
- <template v-for="(_cell, cellIndex) in row.content" :key="listIndex + cellIndex">
950
- <template v-if="_cell.listType === 'input'">
951
- <van-field
952
- v-model="activatedConfig.data[_cell.dataIndex][listIndex]"
953
- :label="_cell.valueText"
954
- type="textarea"
955
- autosize
956
- />
957
- </template>
958
- <template v-else-if="_cell.listType === 'value'">
959
- <van-field
960
- :disabled="true"
961
- :label="_cell.valueText"
962
- type="textarea"
963
- :placeholder="_cell.content[listIndex - 1]"
964
- autosize
965
- />
966
- </template>
967
- </template>
968
- </van-cell-group>
969
- </div>
970
- </template>
971
- </template>
972
- </template>
973
- </van-form>
974
- </van-collapse-item>
975
- </van-collapse>
976
- </div>
977
- <!-- 提交按钮 -->
978
- <div class="submit_button">
979
- <van-button round block type="primary" native-type="submit" @click="onSubmit">
980
- 提交
981
- </van-button>
982
- </div>
983
- </template>
984
- </div>
985
- <!-- 骨架屏 -->
986
- <div v-else class="skeleton">
987
- <van-skeleton title :row="5" />
988
- </div>
989
- </template>
990
-
991
- <style scoped lang="less">
992
- .main{
993
- padding-top: 4vh;
994
- width: 100vw;
995
- height: 100vh;
996
- background-color: #eff2f5;
997
-
998
- .title{
999
- padding-bottom: 2vh;
1000
- color: rgb(50, 50, 51);
1001
- text-align: center;
1002
- margin: 0 0 3vh;
1003
- }
1004
-
1005
- .text_box{
1006
- margin-top: 2vh;
1007
- margin-bottom: 2vh;
1008
- }
1009
-
1010
- .main_text{
1011
- padding-left: 16px;
1012
- font-weight: 400;
1013
- line-height: 1.6;
1014
- margin: 0 0 40px;
1015
- color: #969799;
1016
- font-size: 14px;
1017
- }
1018
-
1019
- .show_value_item{
1020
- text-align: center;
1021
- font-size: 1.2em;
1022
- }
1023
-
1024
- .cell_group{
1025
- //margin-top: 2vh;
1026
- //margin-bottom: 2vh;
1027
- }
1028
-
1029
- .form_item{
1030
- margin-top: 2vh;
1031
- }
1032
-
1033
- .button_group{
1034
- text-align: center;
1035
- margin-top: 3vh;
1036
- margin-bottom: 3vh;
1037
- }
1038
-
1039
- .button_group>:first-child {
1040
- margin-right: 3vw;
1041
- }
1042
-
1043
- .divider{
1044
- color: #1989fa;
1045
- border-color: #1989fa;
1046
- padding: 0 16px
1047
- }
1048
-
1049
- .submit_button{
1050
- background-color: #eff2f5;
1051
- padding: 5vh;
1052
- }
1053
- }
1054
-
1055
- .skeleton{
1056
- margin-top: 5vh
1057
- }
1058
- .my-cell-group{
1059
- margin: 0 0 10px 0
1060
- }
1061
- :deep(.van-collapse-item__content) {
1062
- background-color: #eff2f5;
1063
- padding: 10px 0;
1064
- }
1065
- :deep(.van-cell-group__title){
1066
- padding-top: 10px;
1067
- padding-bottom: 10px;
1068
- }
1069
- :deep(.van-field__label) {
1070
- font-weight: 600;
1071
- }
1072
- :deep(.van-uploader__wrapper){
1073
- padding: 10px;
1074
- display: flex;
1075
- flex-wrap: wrap;
1076
- justify-content: space-between; /* 水平方向上左右分散对齐 */
1077
- align-items: center; /* 垂直方向上上下中心对齐 */
1078
- }
1079
- </style>
1
+ <script setup lang="ts">
2
+ import Uploader from '@af-mobile-client-vue3/components/core/Uploader/index.vue'
3
+ import XReportFormJsonRender from '@af-mobile-client-vue3/components/data/XReportForm/XReportFormJsonRender.vue'
4
+ import XSignature from '@af-mobile-client-vue3/components/data/XSignature/index.vue'
5
+ import { getConfigByNameWithoutIndexedDB } from '@af-mobile-client-vue3/services/api/common'
6
+ import {
7
+ Button as vanButton,
8
+ Cell as vanCell,
9
+ CellGroup as vanCellGroup,
10
+ Collapse as vanCollapse,
11
+ CollapseItem as vanCollapseItem,
12
+ Field as vanField,
13
+ Form as vanForm,
14
+ NavBar as vanNavBar,
15
+ Skeleton as vanSkeleton,
16
+ } from 'vant'
17
+ import { defineEmits, nextTick, reactive, ref, watch } from 'vue'
18
+
19
+ // ------------------------- 类型定义 -------------------------
20
+ interface configDefine {
21
+ data?: any
22
+ designMode?: string
23
+ title?: string | undefined
24
+ subTitle?: Array<cell> | undefined
25
+ columns?: Array<any>
26
+ slotsDeclare?: Array<string> | undefined
27
+ tempData?: any
28
+ }
29
+
30
+ interface getConfigLock {
31
+ status: boolean
32
+ }
33
+
34
+ interface cell {
35
+ type: string
36
+ dataIndex: string
37
+ format: string | undefined
38
+ }
39
+
40
+ // ------------------------- 数据 -------------------------
41
+ const props = defineProps({
42
+ // 配置名
43
+ configName: String,
44
+ // 是否将动态行的label显示在标题上
45
+ showInputColumnsLabelOnTitle: { default: false },
46
+ slotName: String,
47
+ showNav: { default: true },
48
+ localConfig: { default: undefined },
49
+ configData: { default: undefined },
50
+ })
51
+ const emit = defineEmits(['saveConfig'])
52
+ // 原始配置
53
+ const activatedConfig: configDefine = reactive({})
54
+ // 激活的配置名
55
+ const activatedConfigName = ref('')
56
+ // 下载的配置
57
+ const configFromWeb = reactive({})
58
+ // 定时器
59
+ let timer: NodeJS.Timeout
60
+ // 控制组件渲染
61
+ const scanFinish = ref(false)
62
+ // 折叠面板当前激活的值
63
+ const activeCollapseName = ref('副标题')
64
+
65
+ watch(() => props.configName, () => {
66
+ // 这里是你的处理逻辑
67
+ initComponent()
68
+ })
69
+
70
+ // ------------------------- 方法 -------------------------
71
+ // 为inputs类型的数据,整理格式,供form展示用
72
+ function formatInputs(cell: cell): string[] {
73
+ const format = cell.format
74
+ const arr = format.split('{}')
75
+ const result = []
76
+ const reg = /[\u4E00-\u9FA5a-z]/gi
77
+ arr.forEach((str) => {
78
+ if (str.length >= 1 && str.match(reg)) {
79
+ const strs = str.match(reg)
80
+ result.push(strs.join(''))
81
+ }
82
+ })
83
+ if (!activatedConfig.data[cell.dataIndex][result.length - 1]) {
84
+ let dataKeySet = Object.keys(activatedConfig.data)
85
+ dataKeySet = dataKeySet.filter((key) => {
86
+ return key.startsWith(cell.dataIndex)
87
+ })
88
+ dataKeySet.sort()
89
+ const target = dataKeySet[0]
90
+ dataKeySet.shift()
91
+ dataKeySet.forEach((key) => {
92
+ activatedConfig.data[key].forEach((item) => {
93
+ activatedConfig.data[target].push(item)
94
+ })
95
+ })
96
+
97
+ for (let i = 0; i < result.length; i++) {
98
+ if (!activatedConfig.data[cell.dataIndex][i])
99
+ activatedConfig.data[cell.dataIndex][i] = undefined
100
+ }
101
+ }
102
+ return result
103
+ }
104
+
105
+ // 左上角返回按钮
106
+ function onClickLeft(): void {
107
+ history.back()
108
+ }
109
+
110
+ // 提交按钮
111
+ function onSubmit(): void {
112
+ if (activatedConfig.tempData) {
113
+ const keys = Object.keys(activatedConfig.tempData)
114
+ keys.forEach((key) => {
115
+ changeDeepObject(activatedConfig.data, key, activatedConfig.tempData[key])
116
+ })
117
+ }
118
+ console.warn('保存', activatedConfig)
119
+ emit('saveConfig', activatedConfig)
120
+ }
121
+
122
+ // // 动态行新增
123
+ // function addInputColumns(dataIndex: string, define: Array<any>): void {
124
+ // const temp = {}
125
+ // define.forEach((def) => {
126
+ // let begin = def.initialValue
127
+ // if (def.type === 'increment') {
128
+ // if (activatedConfig.data[dataIndex].length > 0) {
129
+ // begin = activatedConfig.data[dataIndex][activatedConfig.data[dataIndex].length - 1][def.dataIndex]
130
+ // begin = Number.parseInt(begin)
131
+ // }
132
+ // temp[def.dataIndex] = begin + def.step
133
+ // }
134
+ // else {
135
+ // temp[def.dataIndex] = ''
136
+ // }
137
+ // })
138
+ // activatedConfig.data[dataIndex].push(temp)
139
+ // }
140
+ //
141
+ // // 动态行删除
142
+ // function removeInputColumns(dataIndex: string) {
143
+ // activatedConfig.data[dataIndex].pop()
144
+ // }
145
+
146
+ // 扫描所有插槽名
147
+ function scanConfigName(config: configDefine, resut: Array<string>): void {
148
+ if (config.slotsDeclare) {
149
+ config.slotsDeclare.forEach((name) => {
150
+ resut.push(name)
151
+ })
152
+ }
153
+ }
154
+
155
+ // 检查slot是否在配置文件中包含,如果没有包含,则视为非法获取
156
+ function checkSlotDefine(config: configDefine): boolean {
157
+ const slotsDeclare = config.slotsDeclare
158
+ const total = slotsDeclare.length
159
+ let count = 0
160
+ slotsDeclare.forEach((declare) => {
161
+ config.columns.forEach((row: Array<any>) => {
162
+ row.forEach((cell) => {
163
+ if (cell.slotConfig === declare)
164
+ count++
165
+ })
166
+ })
167
+ })
168
+
169
+ return count === total
170
+ }
171
+
172
+ // 扫描配置,如果有插槽则拼接插槽
173
+ function scanConfigSlot(config: configDefine): void {
174
+ const columnsArr: Array<any> = config.columns
175
+ for (let i = 0; i < columnsArr.length; i++) {
176
+ for (let j = 0; j < columnsArr[i].length; j++) {
177
+ // 如果发现type为slot,开始匹配对应的slot配置文件
178
+ if (columnsArr[i][j].type === 'slot') {
179
+ const targetName = columnsArr[i][j].slotConfig
180
+ // 找不到目标插槽配置
181
+ if (!configFromWeb[targetName] || !configFromWeb[targetName].columns)
182
+ return
183
+
184
+ // 替换columns,合并data
185
+ config.columns[i] = []
186
+ const before = config.columns.slice(0, i)
187
+ let after = config.columns.slice(i + 1, config.columns.length)
188
+
189
+ const addArr = []
190
+
191
+ if (configFromWeb[targetName].cardMode === true) {
192
+ const temp = [{
193
+ type: 'card',
194
+ content: [],
195
+ label: configFromWeb[targetName].title,
196
+ }]
197
+ for (let k = 0; k < configFromWeb[targetName].columns.length; k++) {
198
+ configFromWeb[targetName].columns[k].forEach((cell) => {
199
+ temp[0].content.push(cell)
200
+ })
201
+ }
202
+ addArr.push(temp)
203
+ }
204
+ else {
205
+ for (let k = 0; k < configFromWeb[targetName].columns.length; k++) {
206
+ const temp = []
207
+ configFromWeb[targetName].columns[k].forEach((cell) => {
208
+ temp.push(cell)
209
+ })
210
+ addArr.push(temp)
211
+ }
212
+ }
213
+
214
+ const newArr = []
215
+ // 拼接之前的数组
216
+ if (before.length > 0) {
217
+ if (before.length >= 1) {
218
+ before.forEach((item) => {
219
+ newArr.push(item)
220
+ })
221
+ }
222
+ else {
223
+ newArr.push(before)
224
+ }
225
+ }
226
+
227
+ addArr.forEach((arr) => {
228
+ newArr.push(arr)
229
+ })
230
+
231
+ // 拼接之后的数组
232
+ if (after.length === 1) {
233
+ if (after[0].type === 'slot' || after[0][0].type === 'slot')
234
+ after = []
235
+ }
236
+ if (after.length > 0) {
237
+ if (after.length >= 1) {
238
+ after.forEach((item) => {
239
+ newArr.push(item)
240
+ })
241
+ }
242
+ else {
243
+ newArr.push(after)
244
+ }
245
+ }
246
+
247
+ config.columns = newArr
248
+ if (configFromWeb[targetName].slotsDeclare)
249
+ config.slotsDeclare = configFromWeb[targetName].slotsDeclare
250
+
251
+ else
252
+ config.slotsDeclare = []
253
+
254
+ if (config.data.images && configFromWeb[targetName].data.images) {
255
+ config.data.images = { ...config.data.images, ...configFromWeb[targetName].data.images }
256
+ delete configFromWeb[targetName].data.images
257
+ }
258
+ config.data = { ...config.data, ...configFromWeb[targetName].data }
259
+ }
260
+ }
261
+ }
262
+ Object.assign(activatedConfig, config)
263
+ }
264
+
265
+ // 获取并拼装插槽
266
+ function getConfigAndJoin(config: configDefine, outerLock: getConfigLock): void {
267
+ // 检查主配置插槽声明是否合法
268
+ const check = checkSlotDefine(config)
269
+ const waitForDownloadSlotName = []
270
+ if (check) {
271
+ // 扫描主配置中声明的插槽名
272
+ scanConfigName(config, waitForDownloadSlotName)
273
+
274
+ const total = waitForDownloadSlotName.length
275
+ let count = 0
276
+
277
+ // 挨个获取插槽
278
+ waitForDownloadSlotName.forEach((configName) => {
279
+ getConfigByNameWithoutIndexedDB(configName).then((res) => {
280
+ configFromWeb[configName] = res
281
+ count++
282
+ })
283
+ })
284
+
285
+ const timer = setInterval(() => {
286
+ if (count >= total) {
287
+ clearInterval(timer)
288
+ scanConfigSlot(config)
289
+ if (config.slotsDeclare.length > 0) {
290
+ const lock: getConfigLock = { status: true }
291
+ getConfigAndJoin(config, lock)
292
+ const innerTimer = setInterval(() => {
293
+ if (!lock.status) {
294
+ clearInterval(innerTimer)
295
+ outerLock.status = false
296
+ }
297
+ }, 100)
298
+ }
299
+ else {
300
+ outerLock.status = false
301
+ }
302
+ }
303
+ }, 100)
304
+ }
305
+ else {
306
+ outerLock.status = false
307
+ }
308
+ }
309
+
310
+ function deserializeFunctionAndRun(functionStr, value) {
311
+ // eslint-disable-next-line no-eval
312
+ const fun = eval(`(${functionStr})`)
313
+ return fun(value, activatedConfig)
314
+ }
315
+
316
+ function deserializeFunctionAndRunWithConfig(functionStr) {
317
+ // eslint-disable-next-line no-eval
318
+ const fun = eval(`(${functionStr})`)
319
+ return fun(activatedConfig)
320
+ }
321
+
322
+ // 将table配置的表格转换为适合Form展示的格式
323
+ function formatConfigToForm(config: configDefine): void {
324
+ const formColumns: Array<object> = []
325
+ const labels: Array<string> = []
326
+ for (let i = 0; i < config.columns.length; i++) {
327
+ let tempObj: {
328
+ customFunction?: any
329
+ inputColumns?: boolean
330
+ dataIndex: string
331
+ label: string
332
+ listType?: string
333
+ listLength?: number
334
+ valueText?: string
335
+ type: string | undefined
336
+ format?: string
337
+ definition?: Array<any>
338
+ editable?: boolean
339
+ inputReadOnly?: boolean
340
+ content?: Array<any>
341
+ text?: string
342
+ } = {
343
+ label: '',
344
+ type: undefined,
345
+ dataIndex: '',
346
+ }
347
+
348
+ const row: Array<any> = config.columns[i]
349
+ let listArr = []
350
+ for (let j = 0; j < row.length; j++) {
351
+ switch (row[j].type) {
352
+ case 'column' :
353
+ if (row[j].customFunctionForDynamicDataIndex)
354
+ row[j].dataIndex = deserializeFunctionAndRunWithConfig(row[j].customFunctionForDynamicDataIndex)
355
+ if (j === row.length - 1) {
356
+ if (row[j].customFunction) {
357
+ tempObj.customFunction = row[j].customFunction
358
+ tempObj.label = deserializeFunctionAndRun(row[j].customFunction, row[j].dataIndex)
359
+ }
360
+ else {
361
+ labels.push(tempObj.label)
362
+ labels.push(row[j].text)
363
+ tempObj = {
364
+ label: '',
365
+ type: undefined,
366
+ dataIndex: '',
367
+ }
368
+ }
369
+ }
370
+ else if (tempObj.label && tempObj.dataIndex) {
371
+ formColumns.push(tempObj)
372
+ tempObj = {
373
+ label: '',
374
+ type: undefined,
375
+ dataIndex: '',
376
+ }
377
+ }
378
+ else if (tempObj.customFunction) {
379
+ formColumns.push(tempObj)
380
+ tempObj = {
381
+ label: '',
382
+ type: undefined,
383
+ dataIndex: '',
384
+ }
385
+ }
386
+ else if (tempObj.label && !tempObj.dataIndex) {
387
+ labels.push(tempObj.label)
388
+ tempObj = {
389
+ label: '',
390
+ type: undefined,
391
+ dataIndex: '',
392
+ }
393
+ }
394
+ if (row[j].customFunction) {
395
+ tempObj.customFunction = row[j].customFunction
396
+ tempObj.label = deserializeFunctionAndRun(row[j].customFunction, row[j].dataIndex)
397
+ }
398
+ else {
399
+ tempObj.label = row[j].text
400
+ }
401
+ break
402
+ case 'value' :
403
+ tempObj.valueText = row[j].value
404
+ tempObj.editable = false
405
+ tempObj.type = 'showValue'
406
+ break
407
+ case 'input' :
408
+ if (row[j].customFunctionForDynamicDataIndex)
409
+ row[j].dataIndex = deserializeFunctionAndRunWithConfig(row[j].customFunctionForDynamicDataIndex)
410
+ tempObj.dataIndex = row[j].dataIndex
411
+ tempObj.type = 'input'
412
+ if (row[j].inputReadOnly)
413
+ tempObj.inputReadOnly = true
414
+ break
415
+ case 'curDateInput' :
416
+ tempObj.dataIndex = row[j].dataIndex
417
+ tempObj.text = row[j].text
418
+ tempObj.type = 'curDateInput'
419
+ break
420
+ case 'signature' :
421
+ tempObj.dataIndex = row[j].dataIndex
422
+ tempObj.text = row[j].text
423
+ tempObj.type = 'signature'
424
+ break
425
+ case 'inputs' :
426
+ if (!tempObj.format)
427
+ tempObj.format = ''
428
+ if (!tempObj.dataIndex)
429
+ tempObj.dataIndex = row[j].dataIndex
430
+ tempObj.format += row[j].format
431
+ tempObj.type = 'inputs'
432
+ if (row[j].inputReadOnly)
433
+ tempObj.inputReadOnly = true
434
+ break
435
+ case 'images' :
436
+ tempObj.dataIndex = row[j].dataIndex
437
+ tempObj.type = 'images'
438
+ break
439
+ case 'inputColumns' :
440
+ tempObj.label = ''
441
+ tempObj.dataIndex = row[j].dataIndex
442
+ tempObj.definition = row[j].definition
443
+ if (labels.length > 0) {
444
+ for (let k = 0; k < tempObj.definition.length; k++) {
445
+ if (labels[k].length > 1) {
446
+ tempObj.definition[k].label = labels[k]
447
+ if (props.showInputColumnsLabelOnTitle) { // 动态行label展示在标题
448
+ if (k === tempObj.definition.length - 1)
449
+ tempObj.label = `${tempObj.label} ${labels[k].replace(/\s*/g, '')}`
450
+ else
451
+ tempObj.label = `${tempObj.label} ${labels[k].replace(/\s*/g, '')} :`
452
+ }
453
+ else { // 动态行仅展示为’动态行‘
454
+ tempObj.label = '动态行'
455
+ }
456
+ }
457
+ else {
458
+ tempObj.definition[k].label = ''
459
+ }
460
+ }
461
+ }
462
+ tempObj.type = 'inputColumns'
463
+ break
464
+ case 'list' :
465
+ tempObj.valueText = row[j].listHead
466
+ tempObj.type = 'list'
467
+ tempObj.listType = row[j].listType
468
+ tempObj.dataIndex = row[j].dataIndex
469
+ if (row[j].content)
470
+ tempObj.content = row[j].content
471
+ tempObj.listLength = row[j].listLength
472
+ listArr.push(tempObj)
473
+ tempObj = {
474
+ label: '',
475
+ type: undefined,
476
+ dataIndex: '',
477
+ }
478
+ }
479
+ }
480
+ if (listArr.length > 0)
481
+ formColumns.push({ type: 'list', content: listArr })
482
+ else if (tempObj.type || tempObj.label)
483
+ formColumns.push(tempObj)
484
+ listArr = []
485
+ tempObj = {
486
+ label: '',
487
+ type: undefined,
488
+ dataIndex: '',
489
+ }
490
+ }
491
+ activatedConfig.columns = formColumns
492
+ }
493
+
494
+ // 获取子组件更新的file列表
495
+ function updateFile(files, index) {
496
+ files.forEach((file) => {
497
+ if (file.content)
498
+ delete file.content
499
+ if (file.file)
500
+ delete file.file
501
+ if (file.objectUrl)
502
+ delete file.objectUrl
503
+ })
504
+ if (index.includes('@@@'))
505
+ changeDeepObjectDeepCopy(activatedConfig.data.images, index, files)
506
+ else
507
+ activatedConfig.data.images[index] = files
508
+ }
509
+
510
+ // function handleInputDeepChange(event, dataIndex) {
511
+ // this.$forceUpdate()
512
+ // }
513
+ function getDeepObject(obj, strPath) {
514
+ const arr = strPath.split('@@@')
515
+ let result = obj[arr[0]]
516
+ arr.shift()
517
+ try {
518
+ while (arr.length > 0) {
519
+ result = result[arr[0]]
520
+ arr.shift()
521
+ }
522
+ }
523
+ catch {
524
+ result = undefined
525
+ }
526
+ return result
527
+ }
528
+
529
+ function changeDeepObject(obj, strPath, newVal) {
530
+ const arr = strPath.split('@@@')
531
+ if (arr.length === 1) {
532
+ obj[arr[0]] = newVal
533
+ }
534
+ else {
535
+ let result = obj[arr[0]]
536
+ arr.shift()
537
+ while (arr.length > 1) {
538
+ result = result[arr[0]]
539
+ arr.shift()
540
+ }
541
+ result[arr[0]] = newVal
542
+ }
543
+ }
544
+
545
+ function changeDeepObjectDeepCopy(obj, strPath, newVal) {
546
+ const arr = strPath.split('@@@')
547
+ if (arr.length === 1) {
548
+ obj[arr[0]] = newVal
549
+ }
550
+ else {
551
+ let result = obj[arr[0]]
552
+ arr.shift()
553
+ while (arr.length > 1) {
554
+ result = result[arr[0]]
555
+ arr.shift()
556
+ }
557
+ Object.assign(result[arr[0]], newVal)
558
+ }
559
+ }
560
+
561
+ // ------------------------- 初始化 -------------------------
562
+ initComponent()
563
+
564
+ function initComponent() {
565
+ if (props.localConfig !== undefined && Object.keys(props.localConfig).length > 0) {
566
+ Object.assign(activatedConfig, props.localConfig)
567
+
568
+ if (activatedConfig.designMode === 'json') {
569
+ activatedConfig.data = {}
570
+ Object.assign(activatedConfig.data, props.configData)
571
+ nextTick(() => {
572
+ scanFinish.value = true
573
+ })
574
+ return
575
+ }
576
+ else {
577
+ const lock = { status: true }
578
+ if (activatedConfig.slotsDeclare) {
579
+ getConfigAndJoin(activatedConfig, lock)
580
+ timer = setInterval(() => {
581
+ if (!lock.status) {
582
+ clearInterval(timer)
583
+ // 将配置文件格式更改为更利于Form的组织形式
584
+ formatConfigToForm(activatedConfig)
585
+ nextTick(() => {
586
+ scanFinish.value = true
587
+ })
588
+ }
589
+ }, 100)
590
+ }
591
+ else {
592
+ formatConfigToForm(activatedConfig)
593
+ nextTick(() => {
594
+ scanFinish.value = true
595
+ })
596
+ }
597
+ if (props.configData !== undefined)
598
+ Object.assign(activatedConfig.data, props.configData)
599
+
600
+ activatedConfig.columns.forEach((row) => {
601
+ row.forEach((item) => {
602
+ if (item.dataIndex && item.dataIndex.includes('@@@')) {
603
+ if (!activatedConfig.tempData) {
604
+ activatedConfig.tempData = {}
605
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
606
+ if (item.type === 'images')
607
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
608
+ }
609
+ else {
610
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
611
+ if (item.type === 'images')
612
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
613
+ }
614
+ }
615
+ })
616
+ })
617
+ console.warn('初始化完成,配置:', activatedConfig)
618
+ }
619
+ }
620
+
621
+ if (props.slotName)
622
+ activatedConfigName.value = props.slotName
623
+
624
+ else
625
+ activatedConfigName.value = props.configName
626
+
627
+ getConfigByNameWithoutIndexedDB(activatedConfigName.value).then((result) => {
628
+ Object.assign(activatedConfig, result)
629
+ if (activatedConfig.designMode === 'json') {
630
+ if (props.configData === undefined) {
631
+ console.error('无法找到json配置的数据')
632
+ }
633
+ else {
634
+ activatedConfig.data = {}
635
+ Object.assign(activatedConfig.data, props.configData)
636
+ nextTick(() => {
637
+ scanFinish.value = true
638
+ })
639
+ }
640
+ }
641
+ else {
642
+ const lock = { status: true }
643
+ if (activatedConfig.slotsDeclare) {
644
+ getConfigAndJoin(activatedConfig, lock)
645
+ timer = setInterval(() => {
646
+ if (!lock.status) {
647
+ clearInterval(timer)
648
+ // 将配置文件格式更改为更利于Form的组织形式
649
+ formatConfigToForm(activatedConfig)
650
+ nextTick(() => {
651
+ scanFinish.value = true
652
+ })
653
+ }
654
+ }, 100)
655
+ }
656
+ else {
657
+ formatConfigToForm(activatedConfig)
658
+ nextTick(() => {
659
+ scanFinish.value = true
660
+ })
661
+ }
662
+ if (props.configData !== undefined)
663
+ Object.assign(activatedConfig.data, props.configData)
664
+ }
665
+
666
+ activatedConfig.columns.forEach((row) => {
667
+ row.forEach((item) => {
668
+ if (item.dataIndex && item.dataIndex.includes('@@@')) {
669
+ if (!activatedConfig.tempData) {
670
+ activatedConfig.tempData = {}
671
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
672
+ if (item.type === 'images')
673
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
674
+ }
675
+ else {
676
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data, item.dataIndex)
677
+ if (item.type === 'images')
678
+ activatedConfig.tempData[item.dataIndex] = getDeepObject(activatedConfig.data.images, item.dataIndex)
679
+ }
680
+ }
681
+ })
682
+ })
683
+ }).catch((e) => {
684
+ console.error(e)
685
+ })
686
+ }
687
+ function getNow() {
688
+ const date = new Date()
689
+ const year = date.getFullYear()
690
+ const month = String(date.getMonth() + 1).padStart(2, '0')
691
+ const day = String(date.getDate()).padStart(2, '0')
692
+ const hours = String(date.getHours()).padStart(2, '0')
693
+ const minutes = String(date.getMinutes()).padStart(2, '0')
694
+ const seconds = String(date.getSeconds()).padStart(2, '0')
695
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
696
+ }
697
+ </script>
698
+
699
+ <template>
700
+ <!-- 标题栏 -->
701
+ <van-nav-bar
702
+ v-if="showNav"
703
+ title="动态报表表单"
704
+ left-text="返回"
705
+ left-arrow
706
+ @click-left="onClickLeft"
707
+ />
708
+ <div v-if="scanFinish" class="main">
709
+ <template v-if="activatedConfig.designMode === 'json'">
710
+ <XReportFormJsonRender :json-config="activatedConfig" />
711
+ </template>
712
+ <template v-else>
713
+ <!-- 标题 -->
714
+ <h2 v-if="activatedConfig.title" class="title" v-html="activatedConfig.title" />
715
+ <!-- 副标题 -->
716
+ <div v-if="activatedConfig.subTitle && activatedConfig.subTitle.length > 0" class="form_item">
717
+ <van-collapse v-model="activeCollapseName" accordion>
718
+ <van-collapse-item title="副标题" name="副标题">
719
+ <van-form>
720
+ <van-cell-group inset>
721
+ <template v-for="(subCell, cellIndex) in activatedConfig.subTitle" :key="cellIndex">
722
+ <template v-if="subCell.type === 'inputs'">
723
+ <template v-for="(item, itemIndex) in formatInputs(subCell)" :key="itemIndex">
724
+ <van-field
725
+ v-model="activatedConfig.data[subCell.dataIndex][itemIndex]"
726
+ :label="`${item}:`"
727
+ clearable
728
+ type="textarea"
729
+ rows="1"
730
+ autosize
731
+ :placeholder="`请输入${item}`"
732
+ />
733
+ </template>
734
+ </template>
735
+ <template v-else>
736
+ <van-field
737
+ v-model="activatedConfig.data[subCell.dataIndex]"
738
+ :label="`${subCell.format}:`"
739
+ clearable
740
+ type="textarea"
741
+ rows="1"
742
+ autosize
743
+ :placeholder="`请输入${subCell.format}`"
744
+ />
745
+ </template>
746
+ </template>
747
+ </van-cell-group>
748
+ </van-form>
749
+ </van-collapse-item>
750
+ </van-collapse>
751
+ </div>
752
+ <!-- 表单项 -->
753
+ <div class="form_item">
754
+ <van-collapse v-model="activeCollapseName" accordion>
755
+ <van-collapse-item title="表单项" name="表单项">
756
+ <van-form>
757
+ <template v-for="(row, index) in activatedConfig.columns" :key="index">
758
+ <!-- value属性 -->
759
+ <van-cell-group v-if="row.type === 'showValue'" inset class="cell_group">
760
+ <van-cell center :title="row.label" :value="row.valueText" />
761
+ </van-cell-group>
762
+ <!-- input -->
763
+ <van-cell-group v-else-if="row.type === 'input'" inset class="cell_group" :title="row.label">
764
+ <template v-if="row.inputReadOnly === true">
765
+ <template v-if="row.dataIndex.includes('@@@')">
766
+ <van-field
767
+ v-model="activatedConfig.tempData[row.dataIndex]"
768
+ :label="`${row.label}:`"
769
+ :placeholder="`请输入${row.label}`"
770
+ clearable
771
+ type="textarea"
772
+ rows="1"
773
+ :disabled="true"
774
+ autosize
775
+ />
776
+ </template>
777
+ <template v-else>
778
+ <van-field
779
+ v-model="activatedConfig.data[row.dataIndex]"
780
+ :label="`${row.label}:`"
781
+ :placeholder="`请输入${row.label}`"
782
+ clearable
783
+ type="textarea"
784
+ rows="1"
785
+ :disabled="true"
786
+ autosize
787
+ />
788
+ </template>
789
+ </template>
790
+ <template v-else>
791
+ <template v-if="row.dataIndex.includes('@@@')">
792
+ <van-field
793
+ v-model="activatedConfig.tempData[row.dataIndex]"
794
+ :label="`${row.label}:`"
795
+ :placeholder="`请输入${row.label}`"
796
+ clearable
797
+ type="textarea"
798
+ rows="1"
799
+ autosize
800
+ />
801
+ </template>
802
+ <template v-else>
803
+ <van-field
804
+ v-model="activatedConfig.data[row.dataIndex]"
805
+ :label="`${row.label}:`"
806
+ :placeholder="`请输入${row.label}`"
807
+ clearable
808
+ type="textarea"
809
+ rows="1"
810
+ autosize
811
+ />
812
+ </template>
813
+ </template>
814
+ </van-cell-group>
815
+ <!-- curDateInput -->
816
+ <van-cell-group v-else-if="row.type === 'curDateInput'" inset style="margin-top: 4vh">
817
+ <van-field
818
+ v-model="activatedConfig.data[row.dataIndex]"
819
+ :label="row.valueText ? `${row.valueText}:` : ''"
820
+ :placeholder="row.valueText ? `请点击右侧按钮设置${row.valueText}` : '请点击右侧按钮设置数据'"
821
+ readonly
822
+ type="textarea"
823
+ rows="1"
824
+ autosize
825
+ >
826
+ <template #button>
827
+ <van-button v-if="!activatedConfig.data[row.dataIndex]" size="small" type="primary" @click="activatedConfig.data[row.dataIndex] = getNow()">
828
+ {{ row.text }}
829
+ </van-button>
830
+ </template>
831
+ </van-field>
832
+ </van-cell-group>
833
+ <!-- signature -->
834
+ <van-cell-group v-else-if="row.type === 'signature'" inset style="margin-top: 4vh">
835
+ <van-field
836
+ :label="row.valueText ? `${row.valueText}:` : ''"
837
+ readonly
838
+ rows="1"
839
+ autosize
840
+ >
841
+ <template #button>
842
+ <XSignature v-model="activatedConfig.data[row.dataIndex]" />
843
+ </template>
844
+ </van-field>
845
+ </van-cell-group>
846
+ <!-- inputs -->
847
+ <van-cell-group v-else-if="row.type === 'inputs'" inset :title="row.label">
848
+ <template v-if="row.inputReadOnly === true">
849
+ <template v-for="(item, _index) in formatInputs(row)" :key="_index">
850
+ <van-field
851
+ v-model="activatedConfig.data[row.dataIndex][_index]"
852
+ :label="`${item}:`"
853
+ :placeholder="`请输入${item}`"
854
+ clearable
855
+ type="textarea"
856
+ rows="1"
857
+ :disabled="true"
858
+ autosize
859
+ />
860
+ </template>
861
+ </template>
862
+ <template v-else>
863
+ <template v-for="(item, _index) in formatInputs(row)" :key="_index">
864
+ <van-field
865
+ v-model="activatedConfig.data[row.dataIndex][_index]"
866
+ :label="`${item}:`"
867
+ :placeholder="`请输入${item}`"
868
+ clearable
869
+ type="textarea"
870
+ rows="1"
871
+ autosize
872
+ />
873
+ </template>
874
+ </template>
875
+ </van-cell-group>
876
+ <!-- images -->
877
+ <van-cell-group v-else-if="row.type === 'images'" inset :title="row.label">
878
+ <template v-if="row.dataIndex.includes('@@@')">
879
+ <Uploader
880
+ upload-mode="oss"
881
+ :image-list="activatedConfig.tempData[row.dataIndex]"
882
+ :outer-index="row.dataIndex"
883
+ authority="admin"
884
+ @update-file-list="updateFile"
885
+ />
886
+ </template>
887
+ <template v-else>
888
+ <Uploader
889
+ upload-mode="oss"
890
+ :image-list="activatedConfig.data.images[row.dataIndex]"
891
+ :outer-index="row.dataIndex"
892
+ authority="admin"
893
+ @update-file-list="updateFile"
894
+ />
895
+ </template>
896
+ </van-cell-group>
897
+ <!-- 动态行 -->
898
+ <template v-else-if="row.type === 'inputColumns'">
899
+ <!-- <van-divider class="divider"> -->
900
+ <!-- {{ row.label }} -->
901
+ <!-- </van-divider> -->
902
+ <van-cell-group inset :title="row.label" style="background-color: #eff2f5">
903
+ <van-cell-group v-for="(_item, _index) in activatedConfig.data[row.dataIndex]" :key="_index" inset class="my-cell-group" style="margin: 0 0 10px 0">
904
+ <div v-for="(def, defIndex) in row.definition" :key="defIndex">
905
+ <van-field
906
+ v-if="def.type === 'curDateInput'"
907
+ v-model="activatedConfig.data[row.dataIndex][_index][def.dataIndex]"
908
+ :label="`${def.label}:`"
909
+ type="textarea"
910
+ rows="1"
911
+ autosize
912
+ :placeholder="`请点击右侧按钮设置${def.label}`"
913
+ readonly
914
+ >
915
+ <template #button>
916
+ <van-button v-show="activatedConfig.data[row.dataIndex][_index][def.dataIndex] === ''" size="small" type="primary" @click="activatedConfig.data[row.dataIndex][_index][def.dataIndex] = getNow()">
917
+ {{ def.text }}
918
+ </van-button>
919
+ </template>
920
+ </van-field>
921
+ <van-field
922
+ v-else
923
+ v-model="activatedConfig.data[row.dataIndex][_index][def.dataIndex]"
924
+ :label="`${def.label}:`"
925
+ type="textarea"
926
+ rows="1"
927
+ autosize
928
+ :placeholder="`请输入${def.label}`"
929
+ clearable
930
+ />
931
+ </div>
932
+ </van-cell-group>
933
+ </van-cell-group>
934
+
935
+ <!-- <div class="button_group"> -->
936
+ <!-- <van-button class="input_columns_button" plain type="primary" @click="addInputColumns(row.dataIndex, row.definition)"> -->
937
+ <!-- <van-icon name="plus" /> -->
938
+ <!-- </van-button> -->
939
+ <!-- <van-button class="input_columns_button" plain type="primary" @click="removeInputColumns(row.dataIndex)"> -->
940
+ <!-- <van-icon name="minus" /> -->
941
+ <!-- </van-button> -->
942
+ <!-- </div> -->
943
+ </template>
944
+ <!-- list -->
945
+ <template v-else-if="row.type === 'list'">
946
+ <template v-for="(listIndex) in row.content[0].listLength" :key="listIndex">
947
+ <div style="margin-top: 3vh; margin-bottom: 3vh">
948
+ <van-cell-group inset :title="row.label" style="background-color: #eff2f5">
949
+ <template v-for="(_cell, cellIndex) in row.content" :key="listIndex + cellIndex">
950
+ <template v-if="_cell.listType === 'input'">
951
+ <van-field
952
+ v-model="activatedConfig.data[_cell.dataIndex][listIndex]"
953
+ :label="_cell.valueText"
954
+ type="textarea"
955
+ autosize
956
+ />
957
+ </template>
958
+ <template v-else-if="_cell.listType === 'value'">
959
+ <van-field
960
+ :disabled="true"
961
+ :label="_cell.valueText"
962
+ type="textarea"
963
+ :placeholder="_cell.content[listIndex - 1]"
964
+ autosize
965
+ />
966
+ </template>
967
+ </template>
968
+ </van-cell-group>
969
+ </div>
970
+ </template>
971
+ </template>
972
+ </template>
973
+ </van-form>
974
+ </van-collapse-item>
975
+ </van-collapse>
976
+ </div>
977
+ <!-- 提交按钮 -->
978
+ <div class="submit_button">
979
+ <van-button round block type="primary" native-type="submit" @click="onSubmit">
980
+ 提交
981
+ </van-button>
982
+ </div>
983
+ </template>
984
+ </div>
985
+ <!-- 骨架屏 -->
986
+ <div v-else class="skeleton">
987
+ <van-skeleton title :row="5" />
988
+ </div>
989
+ </template>
990
+
991
+ <style scoped lang="less">
992
+ .main{
993
+ padding-top: 4vh;
994
+ width: 100vw;
995
+ height: 100vh;
996
+ background-color: #eff2f5;
997
+
998
+ .title{
999
+ padding-bottom: 2vh;
1000
+ color: rgb(50, 50, 51);
1001
+ text-align: center;
1002
+ margin: 0 0 3vh;
1003
+ }
1004
+
1005
+ .text_box{
1006
+ margin-top: 2vh;
1007
+ margin-bottom: 2vh;
1008
+ }
1009
+
1010
+ .main_text{
1011
+ padding-left: 16px;
1012
+ font-weight: 400;
1013
+ line-height: 1.6;
1014
+ margin: 0 0 40px;
1015
+ color: #969799;
1016
+ font-size: 14px;
1017
+ }
1018
+
1019
+ .show_value_item{
1020
+ text-align: center;
1021
+ font-size: 1.2em;
1022
+ }
1023
+
1024
+ .cell_group{
1025
+ //margin-top: 2vh;
1026
+ //margin-bottom: 2vh;
1027
+ }
1028
+
1029
+ .form_item{
1030
+ margin-top: 2vh;
1031
+ }
1032
+
1033
+ .button_group{
1034
+ text-align: center;
1035
+ margin-top: 3vh;
1036
+ margin-bottom: 3vh;
1037
+ }
1038
+
1039
+ .button_group>:first-child {
1040
+ margin-right: 3vw;
1041
+ }
1042
+
1043
+ .divider{
1044
+ color: #1989fa;
1045
+ border-color: #1989fa;
1046
+ padding: 0 16px
1047
+ }
1048
+
1049
+ .submit_button{
1050
+ background-color: #eff2f5;
1051
+ padding: 5vh;
1052
+ }
1053
+ }
1054
+
1055
+ .skeleton{
1056
+ margin-top: 5vh
1057
+ }
1058
+ .my-cell-group{
1059
+ margin: 0 0 10px 0
1060
+ }
1061
+ :deep(.van-collapse-item__content) {
1062
+ background-color: #eff2f5;
1063
+ padding: 10px 0;
1064
+ }
1065
+ :deep(.van-cell-group__title){
1066
+ padding-top: 10px;
1067
+ padding-bottom: 10px;
1068
+ }
1069
+ :deep(.van-field__label) {
1070
+ font-weight: 600;
1071
+ }
1072
+ :deep(.van-uploader__wrapper){
1073
+ padding: 10px;
1074
+ display: flex;
1075
+ flex-wrap: wrap;
1076
+ justify-content: space-between; /* 水平方向上左右分散对齐 */
1077
+ align-items: center; /* 垂直方向上上下中心对齐 */
1078
+ }
1079
+ </style>