af-mobile-client-vue3 1.0.82 → 1.0.84-1
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.
- package/package.json +1 -1
- package/src/components/data/XCellList/XCellList.md +275 -275
- package/src/components/data/XFormItem/index.vue +0 -2
- package/src/components/data/XReportGrid/XAddReport/XAddReport.vue +208 -0
- package/src/components/data/XReportGrid/XAddReport/index.js +3 -0
- package/src/components/data/XReportGrid/XAddReport/index.md +56 -0
- package/src/components/data/XReportGrid/XAddReport/index.ts +10 -0
- package/src/components/data/XReportGrid/XReport.vue +972 -0
- package/src/components/data/XReportGrid/XReportDemo.vue +33 -0
- package/src/components/data/XReportGrid/XReportDesign.vue +597 -0
- package/src/components/data/XReportGrid/XReportDrawer/XReportDrawer.vue +154 -0
- package/src/components/data/XReportGrid/XReportDrawer/index.js +3 -0
- package/src/components/data/XReportGrid/XReportDrawer/index.ts +10 -0
- package/src/components/data/XReportGrid/XReportJsonRender.vue +386 -0
- package/src/components/data/XReportGrid/XReportTrGroup.vue +589 -0
- package/src/components/data/XReportGrid/index.md +44 -0
- package/src/components/data/XReportGrid/index.ts +10 -0
- package/src/components/data/XReportGrid/print.js +184 -0
- package/src/router/routes.ts +13 -1
- package/src/views/component/XCellListView/index.vue +10 -18
- package/src/views/component/XFormGroupView/index.vue +6 -15
- package/src/views/component/XReportGridView/index.vue +14 -0
- package/src/views/component/index.vue +4 -0
- package/src/views/component/test/index.vue +52 -0
- package/tsconfig.json +43 -43
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, nextTick, onBeforeMount, onBeforeUnmount, onMounted, provide, ref, watch } from 'vue'
|
|
3
|
+
import { storeToRefs } from 'pinia'
|
|
4
|
+
import {
|
|
5
|
+
Button as VanButton,
|
|
6
|
+
Card as VanCard,
|
|
7
|
+
Icon as VanIcon,
|
|
8
|
+
RadioGroup as VanRadioGroup,
|
|
9
|
+
Radio as VanRadio,
|
|
10
|
+
Row as VanRow,
|
|
11
|
+
Col as VanCol,
|
|
12
|
+
Space as VanSpace,
|
|
13
|
+
Skeleton as VanSkeleton,
|
|
14
|
+
showDialog
|
|
15
|
+
} from 'vant'
|
|
16
|
+
import { getConfigByName, runLogic } from '@af-mobile-client-vue3/services/api/common'
|
|
17
|
+
import { executeStrFunctionByContext } from '@af-mobile-client-vue3/utils/runEvalFunction'
|
|
18
|
+
import { printElement } from '@af-mobile-client-vue3/components/data/XReportGrid/print'
|
|
19
|
+
import XReportDesign from '@af-mobile-client-vue3/components/data/XReportGrid/XReportDesign.vue'
|
|
20
|
+
import { useUserStore } from '@af-mobile-client-vue3/stores/modules/user'
|
|
21
|
+
|
|
22
|
+
// import HtmlToPdf from '@/utils/htmlToPDF'
|
|
23
|
+
|
|
24
|
+
// Props
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
files: {
|
|
27
|
+
type: Array,
|
|
28
|
+
default: () => [],
|
|
29
|
+
},
|
|
30
|
+
authority: {
|
|
31
|
+
type: String,
|
|
32
|
+
default: 'user',
|
|
33
|
+
},
|
|
34
|
+
editMode: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: true,
|
|
37
|
+
},
|
|
38
|
+
configName: {
|
|
39
|
+
type: String,
|
|
40
|
+
required: true,
|
|
41
|
+
},
|
|
42
|
+
activatedSlotName: {
|
|
43
|
+
type: String,
|
|
44
|
+
default: undefined,
|
|
45
|
+
},
|
|
46
|
+
localConfig: {
|
|
47
|
+
type: Object,
|
|
48
|
+
default: undefined,
|
|
49
|
+
},
|
|
50
|
+
dontFormat: {
|
|
51
|
+
type: Boolean,
|
|
52
|
+
default: true,
|
|
53
|
+
},
|
|
54
|
+
showImgInCell: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: false,
|
|
57
|
+
},
|
|
58
|
+
configData: {
|
|
59
|
+
type: Object,
|
|
60
|
+
default: undefined,
|
|
61
|
+
},
|
|
62
|
+
serverName: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: '',
|
|
65
|
+
},
|
|
66
|
+
env: {
|
|
67
|
+
type: String,
|
|
68
|
+
default: 'prod',
|
|
69
|
+
},
|
|
70
|
+
displayOnly: {
|
|
71
|
+
type: Boolean,
|
|
72
|
+
default: true,
|
|
73
|
+
},
|
|
74
|
+
noPadding: {
|
|
75
|
+
type: Boolean,
|
|
76
|
+
default: true,
|
|
77
|
+
},
|
|
78
|
+
noTopBorder: {
|
|
79
|
+
type: Boolean,
|
|
80
|
+
default: false,
|
|
81
|
+
},
|
|
82
|
+
showTitle: {
|
|
83
|
+
type: Boolean,
|
|
84
|
+
default: true,
|
|
85
|
+
},
|
|
86
|
+
showSaveButton: {
|
|
87
|
+
type: Boolean,
|
|
88
|
+
default: false,
|
|
89
|
+
},
|
|
90
|
+
registerMap: {
|
|
91
|
+
type: Array,
|
|
92
|
+
default: undefined,
|
|
93
|
+
},
|
|
94
|
+
isWidget: {
|
|
95
|
+
type: Boolean,
|
|
96
|
+
default: false,
|
|
97
|
+
},
|
|
98
|
+
useOssForImg: {
|
|
99
|
+
type: Boolean,
|
|
100
|
+
default: true,
|
|
101
|
+
},
|
|
102
|
+
imgPrefix: {
|
|
103
|
+
type: String,
|
|
104
|
+
default: undefined,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Emits
|
|
109
|
+
const emit = defineEmits(['updateImg', 'selectRow', 'cancel'])
|
|
110
|
+
|
|
111
|
+
// Store
|
|
112
|
+
const userStore = useUserStore()
|
|
113
|
+
// const { user: currUser } = storeToRefs(userStore)
|
|
114
|
+
|
|
115
|
+
// Refs
|
|
116
|
+
// const XReportDesign = ref()
|
|
117
|
+
const xAddReport = ref()
|
|
118
|
+
const xReportDrawer = ref()
|
|
119
|
+
|
|
120
|
+
// 状态
|
|
121
|
+
const showSkeleton = ref(true)
|
|
122
|
+
const config = ref()
|
|
123
|
+
const type = ref('design')
|
|
124
|
+
const onlyDisplay = ref(false)
|
|
125
|
+
const _maxColSpan = ref(12)
|
|
126
|
+
const scanFinish = ref(false)
|
|
127
|
+
const activeConfig = ref(null)
|
|
128
|
+
const originalConfig = ref(null)
|
|
129
|
+
const configFromWeb = ref({})
|
|
130
|
+
const timer = ref()
|
|
131
|
+
const hasImages = ref(false)
|
|
132
|
+
const imageList = ref([])
|
|
133
|
+
const dataCache = ref()
|
|
134
|
+
const diff = ref([])
|
|
135
|
+
const globalData = ref({})
|
|
136
|
+
|
|
137
|
+
// Computed
|
|
138
|
+
const widget = computed(() => props.isWidget)
|
|
139
|
+
|
|
140
|
+
// Provide
|
|
141
|
+
// provide('runLogic', runLogic)
|
|
142
|
+
// provide('openDialog', openDialog)
|
|
143
|
+
// provide('registerComponent', registerComponent)
|
|
144
|
+
// provide('getComponentByName', getComponentByName)
|
|
145
|
+
// provide('getParentComponentByName', getComponentByName)
|
|
146
|
+
// provide('getConfigByName', getConfigByName)
|
|
147
|
+
// provide('isWidget', widget)
|
|
148
|
+
// // provide('currUser', currUser)
|
|
149
|
+
// provide('getGlobalData', getGlobalData)
|
|
150
|
+
// provide('setGlobalData', setGlobalData)
|
|
151
|
+
|
|
152
|
+
// Methods
|
|
153
|
+
function slotRendered() {
|
|
154
|
+
if (config.value?.mountedFunction) {
|
|
155
|
+
let func = config.value.mountedFunction
|
|
156
|
+
if (func && func.startsWith('function')) {
|
|
157
|
+
func = func.replace('function', 'async function')
|
|
158
|
+
executeStrFunctionByContext(null, func, [])
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function registerComponent(componentName: string, component: any) {
|
|
164
|
+
console.log('内部注册', componentName)
|
|
165
|
+
if (XReportDesign.value)
|
|
166
|
+
XReportDesign.value[componentName] = component
|
|
167
|
+
|
|
168
|
+
console.log('内部注册完成')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// 数据处理方法
|
|
172
|
+
function transformArray(inputList: any[]) {
|
|
173
|
+
let operationIndex = 0
|
|
174
|
+
let operationList = []
|
|
175
|
+
const outputList = []
|
|
176
|
+
for (const lst of inputList) {
|
|
177
|
+
if (lst.length >= 1 && !lst.every(x => Array.isArray(x) || Array.isArray(lst[0]) || x.rowSpan === lst[0].rowSpan)) {
|
|
178
|
+
operationList = lst
|
|
179
|
+
break
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
operationIndex += 1
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let maxMergeRow = 0
|
|
187
|
+
|
|
188
|
+
if (operationList.length === 0) {
|
|
189
|
+
return inputList
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
const maxRow = Math.max(...operationList.map(item => item.rowSpan))
|
|
193
|
+
let mergeIndexCol = 0
|
|
194
|
+
for (let index = 0; index < operationList.length; index++) {
|
|
195
|
+
const row = operationList[index]
|
|
196
|
+
let rowSpan = row.rowSpan
|
|
197
|
+
let mergeIndexRow = operationIndex + 1
|
|
198
|
+
const rows = []
|
|
199
|
+
if (rowSpan < maxRow && mergeIndexRow < inputList.length)
|
|
200
|
+
rows.push([row])
|
|
201
|
+
|
|
202
|
+
while (rowSpan < maxRow && mergeIndexRow < inputList.length) {
|
|
203
|
+
rowSpan += inputList[mergeIndexRow][mergeIndexCol].rowSpan
|
|
204
|
+
rows.push([inputList[mergeIndexRow][mergeIndexCol]])
|
|
205
|
+
if (mergeIndexRow > maxMergeRow)
|
|
206
|
+
maxMergeRow = mergeIndexRow
|
|
207
|
+
|
|
208
|
+
mergeIndexRow++
|
|
209
|
+
}
|
|
210
|
+
if (rows.length !== 0)
|
|
211
|
+
operationList[index] = rows
|
|
212
|
+
|
|
213
|
+
if (row.rowSpan !== maxRow)
|
|
214
|
+
mergeIndexCol++
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let putindex = 0
|
|
219
|
+
while (operationIndex > 0) {
|
|
220
|
+
outputList.push(inputList[putindex])
|
|
221
|
+
putindex++
|
|
222
|
+
operationIndex -= 1
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
outputList.push(operationList)
|
|
226
|
+
|
|
227
|
+
while (maxMergeRow < inputList.length - 1) {
|
|
228
|
+
outputList.push(inputList[maxMergeRow + 1])
|
|
229
|
+
maxMergeRow += 1
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return transformArray(outputList)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// 组件操作方法
|
|
236
|
+
function getComponentByName(componentName: string) {
|
|
237
|
+
console.log('内部取组件', componentName)
|
|
238
|
+
return XReportDesign.value?.[componentName]
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const getGlobalData = () => globalData.value
|
|
242
|
+
|
|
243
|
+
function setGlobalData(obj: any) {
|
|
244
|
+
globalData.value = obj
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// 对话框操作
|
|
248
|
+
function openDialog(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
|
|
249
|
+
console.log('openDialog', configName, selectedId)
|
|
250
|
+
xAddReport.value?.init({
|
|
251
|
+
configName,
|
|
252
|
+
selectedId,
|
|
253
|
+
mixinData,
|
|
254
|
+
outEnv,
|
|
255
|
+
attr,
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function openDrawer(configName: string, selectedId: any, mixinData: any, outEnv = {}, attr = {}) {
|
|
260
|
+
console.log('openDrawer', configName, selectedId)
|
|
261
|
+
xReportDrawer.value?.init({
|
|
262
|
+
configName,
|
|
263
|
+
selectedId,
|
|
264
|
+
mixinData,
|
|
265
|
+
outEnv,
|
|
266
|
+
attr,
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// 数据导出和打印
|
|
271
|
+
function updateImg(data: any) {
|
|
272
|
+
emit('updateImg', data)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function exportData() {
|
|
276
|
+
let tempData
|
|
277
|
+
if (!activeConfig.value) {
|
|
278
|
+
tempData = originalConfig.value.data
|
|
279
|
+
}
|
|
280
|
+
else {
|
|
281
|
+
const tempDataKeys = Object.keys(activeConfig.value.tempData)
|
|
282
|
+
tempDataKeys.forEach((key) => {
|
|
283
|
+
changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
|
|
284
|
+
})
|
|
285
|
+
tempData = activeConfig.value.data
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
diff.value = []
|
|
289
|
+
compareProps(tempData, dataCache.value)
|
|
290
|
+
|
|
291
|
+
diff.value.forEach((eachDiff) => {
|
|
292
|
+
const arr = eachDiff.split('.')
|
|
293
|
+
let targetData = tempData[arr[0]]
|
|
294
|
+
if (arr.length !== 1) {
|
|
295
|
+
for (let i = 1; i < arr.length - 1; i++) {
|
|
296
|
+
const path = arr[i]
|
|
297
|
+
targetData = targetData[path]
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
targetData.update = true
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
return tempData
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function printDocument() {
|
|
307
|
+
const printContent = window.rawDocument.getElementById('printReady')
|
|
308
|
+
// printElement(printContent)
|
|
309
|
+
showDialog({ message: '操作成功!' })
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function exportPDF() {
|
|
313
|
+
const date = getDate()
|
|
314
|
+
let title = config.value.title
|
|
315
|
+
title = title.replace(/<[^>]+>/g, '')
|
|
316
|
+
const fileName = `${date}${title}`
|
|
317
|
+
// HtmlToPdf.getPdf(fileName, '#printReady')
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// 配置处理方法
|
|
321
|
+
function configInit() {
|
|
322
|
+
console.log('拼接完成', config.value)
|
|
323
|
+
originalConfig.value = Object.assign({}, config.value)
|
|
324
|
+
if (!props.dontFormat)
|
|
325
|
+
formatConfigRow(config.value)
|
|
326
|
+
|
|
327
|
+
activeConfig.value = config.value
|
|
328
|
+
showSkeleton.value = false
|
|
329
|
+
|
|
330
|
+
// 处理动态Index
|
|
331
|
+
activeConfig.value.columns.forEach((row: any[]) => {
|
|
332
|
+
row.forEach((cell) => {
|
|
333
|
+
if (cell.dynamicDataIndex === true) {
|
|
334
|
+
// eslint-disable-next-line no-eval
|
|
335
|
+
const func = eval(`(${cell.customFunctionForDynamicDataIndex})`)
|
|
336
|
+
cell.dataIndex = func(config.value)
|
|
337
|
+
}
|
|
338
|
+
if (['action', 'click'].includes(cell.eventType) && cell.customFunction && !cell.events) {
|
|
339
|
+
cell.events = []
|
|
340
|
+
cell.events.push({
|
|
341
|
+
type: cell.eventType,
|
|
342
|
+
customFunction: cell.customFunction,
|
|
343
|
+
})
|
|
344
|
+
}
|
|
345
|
+
})
|
|
346
|
+
})
|
|
347
|
+
|
|
348
|
+
activeConfig.value.tempData = {}
|
|
349
|
+
activeConfig.value.columns.forEach((row: any[]) => {
|
|
350
|
+
row.forEach((cell) => {
|
|
351
|
+
if (cell.dataIndex?.includes('@@@'))
|
|
352
|
+
activeConfig.value.tempData[cell.dataIndex] = getDeepObject(activeConfig.value.data, cell.dataIndex)
|
|
353
|
+
})
|
|
354
|
+
})
|
|
355
|
+
|
|
356
|
+
console.log('转换前配置', config.value)
|
|
357
|
+
originalConfig.value.columns = transformArray(JSON.parse(JSON.stringify(config.value.columns)))
|
|
358
|
+
console.log('转换后的列描述', originalConfig.value.columns)
|
|
359
|
+
|
|
360
|
+
scanFinish.value = true
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// 格式化配置行方法
|
|
364
|
+
function formatConfigRow(config: any) {
|
|
365
|
+
for (let i = 0; i < config.columns.length; i++) {
|
|
366
|
+
// 对原始数组进行递归,依次将该位置拆分为三个部分,当前处理位置之前的,当前处理位置,当前处理位置之后的
|
|
367
|
+
const before = config.columns.slice(0, i)
|
|
368
|
+
const after = config.columns.slice(i + 1, config.columns.length)
|
|
369
|
+
|
|
370
|
+
// 将当前处理的数组交给处理的方法
|
|
371
|
+
const x = checkRow(config.columns[i])
|
|
372
|
+
|
|
373
|
+
const newArr = []
|
|
374
|
+
|
|
375
|
+
// 拼接之前的数组
|
|
376
|
+
if (before.length > 0) {
|
|
377
|
+
if (before.length >= 1) {
|
|
378
|
+
before.forEach((item) => {
|
|
379
|
+
newArr.push(item)
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
newArr.push(before)
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// 拼接不需要更改当前节点处理完成的数组
|
|
388
|
+
newArr.push(x.old)
|
|
389
|
+
|
|
390
|
+
// 如果处理了新加的数据,拼接
|
|
391
|
+
if (x.add.length > 0) {
|
|
392
|
+
for (let j = 0; j < x.add.length; j++) {
|
|
393
|
+
if (x.add[j]) {
|
|
394
|
+
newArr.push(x.add[j])
|
|
395
|
+
i++
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// 拼接之后的数组
|
|
401
|
+
if (after.length > 0) {
|
|
402
|
+
if (after.length >= 1) {
|
|
403
|
+
after.forEach((item) => {
|
|
404
|
+
newArr.push(item)
|
|
405
|
+
})
|
|
406
|
+
}
|
|
407
|
+
else {
|
|
408
|
+
newArr.push(after)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
config.columns = newArr
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// 处理行数据
|
|
417
|
+
function checkRow(rowArr: any[]) {
|
|
418
|
+
// 不需要更改的数据
|
|
419
|
+
const original = []
|
|
420
|
+
// 需要更改新加的数据
|
|
421
|
+
const addArr = []
|
|
422
|
+
// 统计rowspan出现的总和
|
|
423
|
+
let count = 0
|
|
424
|
+
// 统计声明列需要的rowspan总数
|
|
425
|
+
let total = 0
|
|
426
|
+
// 是否为声明行
|
|
427
|
+
let titleCellFlag = false
|
|
428
|
+
// 是否为声明行后第一行
|
|
429
|
+
let firstSubLine = false
|
|
430
|
+
// 需要处理的行,新的index值
|
|
431
|
+
let subRowIndex = 0
|
|
432
|
+
// 新生成的行,临时存储
|
|
433
|
+
const waitForAddArr = []
|
|
434
|
+
// 用于记录声明行的colspan避免格式错误
|
|
435
|
+
let preColSpan = 0
|
|
436
|
+
// 用于统计循环次数,判断是否是最后一次
|
|
437
|
+
let forEachCount = 0
|
|
438
|
+
|
|
439
|
+
// 标记所有数据
|
|
440
|
+
rowArr.forEach((cell) => {
|
|
441
|
+
forEachCount++
|
|
442
|
+
// 如果该行没有rowspan则默认其为1,不要影响统计结果
|
|
443
|
+
if (!cell.rowSpan)
|
|
444
|
+
cell.rowSpan = 0
|
|
445
|
+
|
|
446
|
+
if (cell.text && total !== 0) { // 如果遇到了下一个声明行,证明rowspan少了一行,需要补充一个占位格
|
|
447
|
+
const nullObj = {
|
|
448
|
+
type: 'placeHolderColumn',
|
|
449
|
+
order: subRowIndex,
|
|
450
|
+
noBoarder: true,
|
|
451
|
+
needSplit: true,
|
|
452
|
+
colSpan: preColSpan,
|
|
453
|
+
dontShowRow: true,
|
|
454
|
+
}
|
|
455
|
+
subRowIndex++
|
|
456
|
+
waitForAddArr.push(nullObj)
|
|
457
|
+
total = 0
|
|
458
|
+
count = 0
|
|
459
|
+
titleCellFlag = false
|
|
460
|
+
firstSubLine = false
|
|
461
|
+
}
|
|
462
|
+
else if ((total !== count + cell.rowSpan) && forEachCount === rowArr.length) {
|
|
463
|
+
// 如果没有遇到了下一个声明行,但已经是当前行最后一个数据,也证明rowspan少了一行,需要补充一个占位格
|
|
464
|
+
const nullObj = {
|
|
465
|
+
type: 'placeHolderColumn',
|
|
466
|
+
order: subRowIndex,
|
|
467
|
+
noBoarder: true,
|
|
468
|
+
needSplit: true,
|
|
469
|
+
colSpan: preColSpan,
|
|
470
|
+
dontShowRow: true,
|
|
471
|
+
}
|
|
472
|
+
subRowIndex++
|
|
473
|
+
waitForAddArr.push(nullObj)
|
|
474
|
+
total = 0
|
|
475
|
+
count = 0
|
|
476
|
+
titleCellFlag = false
|
|
477
|
+
firstSubLine = false
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// 判断是否为声明行
|
|
481
|
+
if (cell.text && total === 0) {
|
|
482
|
+
// 将声明行声明的rowspan作为总数,判断下方rowspan相加是否等于声明行声明的数量
|
|
483
|
+
total = cell.rowSpan
|
|
484
|
+
titleCellFlag = false
|
|
485
|
+
firstSubLine = true
|
|
486
|
+
subRowIndex = 1
|
|
487
|
+
cell.show = true
|
|
488
|
+
cell.showRowSpan = total
|
|
489
|
+
}
|
|
490
|
+
else if (cell.rowSpan > 0 && !titleCellFlag && firstSubLine) { // 判断是否为声明行后首行,因为首行不需要移动
|
|
491
|
+
count += cell.rowSpan
|
|
492
|
+
firstSubLine = false
|
|
493
|
+
cell.noBoarder = true
|
|
494
|
+
cell.show = true
|
|
495
|
+
cell.showRowSpan = total
|
|
496
|
+
}
|
|
497
|
+
else if (cell.rowSpan > 0 && !titleCellFlag && !firstSubLine) { // 既非声明行,也非首行,需要移动
|
|
498
|
+
count += cell.rowSpan
|
|
499
|
+
cell.needSplit = true
|
|
500
|
+
cell.order = subRowIndex
|
|
501
|
+
cell.dontShowRow = true
|
|
502
|
+
subRowIndex++
|
|
503
|
+
|
|
504
|
+
// 如果之前添加过空行补充位置,刚好最后一位还有内容,将其互换
|
|
505
|
+
if (forEachCount === rowArr.length && !waitForAddArr[waitForAddArr.length - 1].dataIndex) {
|
|
506
|
+
waitForAddArr[waitForAddArr.length - 1].order += 1
|
|
507
|
+
cell.order -= 1
|
|
508
|
+
waitForAddArr.push(cell)
|
|
509
|
+
}
|
|
510
|
+
else {
|
|
511
|
+
waitForAddArr.push(cell)
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// 如果count和total相等了,证明已经处理完成。将计数器还原
|
|
516
|
+
if (count === total) {
|
|
517
|
+
total = 0
|
|
518
|
+
count = 0
|
|
519
|
+
titleCellFlag = false
|
|
520
|
+
firstSubLine = false
|
|
521
|
+
}
|
|
522
|
+
// 保存上一个的colspan,保持生成的格子与原格式一致
|
|
523
|
+
preColSpan = cell.colSpan
|
|
524
|
+
})
|
|
525
|
+
|
|
526
|
+
// 将所有不需要移动的放入original
|
|
527
|
+
rowArr.forEach((cell) => {
|
|
528
|
+
if (cell.needSplit !== true)
|
|
529
|
+
original.push(cell)
|
|
530
|
+
})
|
|
531
|
+
|
|
532
|
+
// 增加新的数组
|
|
533
|
+
waitForAddArr.forEach((cell) => {
|
|
534
|
+
const target = cell.order
|
|
535
|
+
cell.noBoarder = true
|
|
536
|
+
if (addArr[target] === undefined) {
|
|
537
|
+
const temp = []
|
|
538
|
+
temp.push(cell)
|
|
539
|
+
addArr[target] = temp
|
|
540
|
+
}
|
|
541
|
+
else if (addArr[target].length > 0) {
|
|
542
|
+
addArr[target].push(cell)
|
|
543
|
+
}
|
|
544
|
+
})
|
|
545
|
+
|
|
546
|
+
// 如果没有新增,将单元格边框设置为显示
|
|
547
|
+
if (addArr.length < 1) {
|
|
548
|
+
original.forEach((cell) => {
|
|
549
|
+
if (cell.type === 'input' || cell.type === 'inputs')
|
|
550
|
+
cell.noBoarder = false
|
|
551
|
+
})
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
return {
|
|
555
|
+
old: original,
|
|
556
|
+
add: addArr,
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
// 配置扫描方法
|
|
561
|
+
function checkSlotDefine(config: any) {
|
|
562
|
+
const slotsDeclare = config.slotsDeclare
|
|
563
|
+
const total = slotsDeclare.length
|
|
564
|
+
let count = 0
|
|
565
|
+
slotsDeclare.forEach((declare: string) => {
|
|
566
|
+
config.columns.forEach((row: any[]) => {
|
|
567
|
+
row.forEach((cell) => {
|
|
568
|
+
if (cell.slotConfig === declare) {
|
|
569
|
+
count++
|
|
570
|
+
}
|
|
571
|
+
})
|
|
572
|
+
})
|
|
573
|
+
})
|
|
574
|
+
return count === total
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function scanConfigName(config: any, result: string[]) {
|
|
578
|
+
if (config.slotsDeclare) {
|
|
579
|
+
config.slotsDeclare.forEach((name: string) => {
|
|
580
|
+
result.push(name)
|
|
581
|
+
})
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
function scanConfigSlot(config: any) {
|
|
586
|
+
const columnsArr = config.columns
|
|
587
|
+
for (let i = 0; i < columnsArr.length; i++) {
|
|
588
|
+
for (let j = 0; j < columnsArr[i].length; j++) {
|
|
589
|
+
if (columnsArr[i][j].type === 'slot') {
|
|
590
|
+
const targetName = columnsArr[i][j].slotConfig
|
|
591
|
+
if (!configFromWeb.value[targetName] || !configFromWeb.value[targetName].columns) {
|
|
592
|
+
console.error('无法找到目标插槽的配置!')
|
|
593
|
+
return
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
config.columns[i] = []
|
|
597
|
+
const before = config.columns.slice(0, i)
|
|
598
|
+
let after = config.columns.slice(i + 1, config.columns.length)
|
|
599
|
+
|
|
600
|
+
const addArr = []
|
|
601
|
+
for (let k = 0; k < configFromWeb.value[targetName].columns.length; k++) {
|
|
602
|
+
const temp = []
|
|
603
|
+
configFromWeb.value[targetName].columns[k].forEach((cell: any) => {
|
|
604
|
+
temp.push(cell)
|
|
605
|
+
})
|
|
606
|
+
addArr.push(temp)
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
const newArr = []
|
|
610
|
+
if (before.length > 0) {
|
|
611
|
+
before.forEach((item) => {
|
|
612
|
+
newArr.push(item)
|
|
613
|
+
})
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
addArr.forEach((arr) => {
|
|
617
|
+
newArr.push(arr)
|
|
618
|
+
})
|
|
619
|
+
|
|
620
|
+
if (after.length === 1) {
|
|
621
|
+
if (after[0].type === 'slot' || after[0][0].type === 'slot')
|
|
622
|
+
after = []
|
|
623
|
+
}
|
|
624
|
+
if (after.length > 0) {
|
|
625
|
+
after.forEach((item) => {
|
|
626
|
+
newArr.push(item)
|
|
627
|
+
})
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
config.columns = newArr
|
|
631
|
+
config.slotsDeclare = configFromWeb.value[targetName].slotsDeclare || []
|
|
632
|
+
|
|
633
|
+
if (config.data.images && configFromWeb.value[targetName].data.images) {
|
|
634
|
+
config.data.images = { ...config.data.images, ...configFromWeb.value[targetName].data.images }
|
|
635
|
+
delete configFromWeb.value[targetName].data.images
|
|
636
|
+
}
|
|
637
|
+
config.data = { ...config.data, ...configFromWeb.value[targetName].data }
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
config.value = config
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// 数据比较方法
|
|
645
|
+
function compareProps(obj1: any, obj2: any, path = '') {
|
|
646
|
+
for (const key in obj1) {
|
|
647
|
+
if (typeof obj2[key] === 'undefined') {
|
|
648
|
+
diff.value.push(path + key)
|
|
649
|
+
}
|
|
650
|
+
else if (Array.isArray(obj1) && Array.isArray(obj2)) {
|
|
651
|
+
if (obj1[key].length !== obj2[key].length)
|
|
652
|
+
diff.value.push(path + key)
|
|
653
|
+
}
|
|
654
|
+
else if (typeof obj1[key] === 'object' && typeof obj2[key] === 'object') {
|
|
655
|
+
compareProps(obj1[key], obj2[key], `${path + key}.`)
|
|
656
|
+
}
|
|
657
|
+
else if (obj1[key] !== obj2[key]) {
|
|
658
|
+
diff.value.push(path + key)
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// 数据处理辅助方法
|
|
664
|
+
function getDeepObject(obj: any, strPath: string) {
|
|
665
|
+
const arr = strPath.split('@@@')
|
|
666
|
+
let result = obj[arr[0]]
|
|
667
|
+
arr.shift()
|
|
668
|
+
try {
|
|
669
|
+
while (arr.length > 0) {
|
|
670
|
+
result = result[arr[0]]
|
|
671
|
+
arr.shift()
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
catch (e) {
|
|
675
|
+
result = undefined
|
|
676
|
+
}
|
|
677
|
+
return result
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function changeDeepObject(obj: any, strPath: string, newVal: any) {
|
|
681
|
+
const arr = strPath.split('@@@')
|
|
682
|
+
if (obj[arr[0]] === undefined)
|
|
683
|
+
obj = obj.images
|
|
684
|
+
|
|
685
|
+
if (arr.length === 1) {
|
|
686
|
+
obj[arr[0]] = newVal
|
|
687
|
+
}
|
|
688
|
+
else {
|
|
689
|
+
let result = obj[arr[0]]
|
|
690
|
+
arr.shift()
|
|
691
|
+
while (arr.length > 1) {
|
|
692
|
+
result = result[arr[0]]
|
|
693
|
+
arr.shift()
|
|
694
|
+
}
|
|
695
|
+
if (result)
|
|
696
|
+
result[arr[0]] = newVal
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
// 日期处理方法
|
|
701
|
+
function getDate() {
|
|
702
|
+
const currentDate = new Date()
|
|
703
|
+
const year = currentDate.getFullYear()
|
|
704
|
+
const month = String(currentDate.getMonth() + 1).padStart(2, '0')
|
|
705
|
+
const day = String(currentDate.getDate()).padStart(2, '0')
|
|
706
|
+
return `${year}_${month}_${day}`
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// 表格操作方法
|
|
710
|
+
function tabChanged(key: string) {
|
|
711
|
+
scanFinish.value = false
|
|
712
|
+
originalConfig.value.data = { ...originalConfig.value.data, ...config.value.data }
|
|
713
|
+
config.value.data = originalConfig.value.data
|
|
714
|
+
|
|
715
|
+
if (type.value === 'display') {
|
|
716
|
+
const tempDataKeys = Object.keys(activeConfig.value.tempData)
|
|
717
|
+
tempDataKeys.forEach((key) => {
|
|
718
|
+
changeDeepObject(activeConfig.value.data, key, activeConfig.value.tempData[key])
|
|
719
|
+
})
|
|
720
|
+
|
|
721
|
+
let count = 0
|
|
722
|
+
imageList.value = []
|
|
723
|
+
const keys = Object.keys(config.value.data.images)
|
|
724
|
+
keys.forEach((key) => {
|
|
725
|
+
if (config.value.data.images[key].length > 0) {
|
|
726
|
+
imageList.value = [...imageList.value, ...config.value.data.images[key]]
|
|
727
|
+
count++
|
|
728
|
+
}
|
|
729
|
+
})
|
|
730
|
+
hasImages.value = count > 0
|
|
731
|
+
}
|
|
732
|
+
else {
|
|
733
|
+
hasImages.value = false
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
scanFinish.value = true
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
function saveConfig() {
|
|
740
|
+
const funcStr = config.value.confirmFunction
|
|
741
|
+
executeStrFunctionByContext(null, funcStr, [])
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
function cancelConfig() {
|
|
745
|
+
emit('cancel')
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// 在其他方法后面添加
|
|
749
|
+
function jsonConfigInit() {
|
|
750
|
+
if (props.configData === undefined) {
|
|
751
|
+
console.error('未找到数据!')
|
|
752
|
+
return
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
originalConfig.value = Object.assign({}, config.value)
|
|
756
|
+
originalConfig.value.data = JSON.parse(JSON.stringify(props.configData))
|
|
757
|
+
type.value = 'display'
|
|
758
|
+
// onlyDisplay.value = true
|
|
759
|
+
showSkeleton.value = false
|
|
760
|
+
|
|
761
|
+
nextTick(() => {
|
|
762
|
+
scanFinish.value = true
|
|
763
|
+
})
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
// 生命周期
|
|
767
|
+
onBeforeMount(() => {
|
|
768
|
+
if (props.displayOnly) {
|
|
769
|
+
onlyDisplay.value = true
|
|
770
|
+
type.value = 'display'
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (props.localConfig) {
|
|
774
|
+
if (props.localConfig.designMode === 'json') {
|
|
775
|
+
config.value = props.localConfig
|
|
776
|
+
if (props.configData !== undefined)
|
|
777
|
+
config.value.data = props.configData
|
|
778
|
+
|
|
779
|
+
jsonConfigInit()
|
|
780
|
+
}
|
|
781
|
+
else {
|
|
782
|
+
config.value = props.localConfig
|
|
783
|
+
if (props.configData !== undefined)
|
|
784
|
+
config.value.data = props.configData
|
|
785
|
+
|
|
786
|
+
if (config.value.data.images === undefined)
|
|
787
|
+
config.value.data.images = {}
|
|
788
|
+
|
|
789
|
+
configInit()
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
else {
|
|
793
|
+
getConfigByName(props.configName, (res: any) => {
|
|
794
|
+
config.value = JSON.parse(JSON.stringify(res))
|
|
795
|
+
if (config.value.designMode === 'json') {
|
|
796
|
+
if (props.configData !== undefined)
|
|
797
|
+
config.value.data = props.configData
|
|
798
|
+
|
|
799
|
+
jsonConfigInit()
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
if (props.configData !== undefined)
|
|
803
|
+
config.value.data = props.configData
|
|
804
|
+
|
|
805
|
+
if (config.value.data.images === undefined)
|
|
806
|
+
config.value.data.images = {}
|
|
807
|
+
|
|
808
|
+
configInit()
|
|
809
|
+
}
|
|
810
|
+
}, props.serverName)
|
|
811
|
+
}
|
|
812
|
+
})
|
|
813
|
+
|
|
814
|
+
onMounted(() => {
|
|
815
|
+
if (props.registerMap !== undefined) {
|
|
816
|
+
props.registerMap.push({
|
|
817
|
+
exportData,
|
|
818
|
+
printDocument,
|
|
819
|
+
exportPDF,
|
|
820
|
+
})
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
if (props.configData)
|
|
824
|
+
dataCache.value = JSON.parse(JSON.stringify(props.configData))
|
|
825
|
+
else if (config.value?.data)
|
|
826
|
+
dataCache.value = JSON.parse(JSON.stringify(config.value.data))
|
|
827
|
+
})
|
|
828
|
+
|
|
829
|
+
onBeforeUnmount(() => {
|
|
830
|
+
clearInterval(timer.value)
|
|
831
|
+
})
|
|
832
|
+
|
|
833
|
+
// Watch
|
|
834
|
+
watch(() => props.configName, (val) => {
|
|
835
|
+
if (val) {
|
|
836
|
+
getConfigByName(props.configName, (res: any) => {
|
|
837
|
+
config.value = res
|
|
838
|
+
configInit()
|
|
839
|
+
}, props.serverName)
|
|
840
|
+
}
|
|
841
|
+
})
|
|
842
|
+
|
|
843
|
+
watch(() => props.localConfig, (val) => {
|
|
844
|
+
if (val) {
|
|
845
|
+
config.value = val
|
|
846
|
+
configInit()
|
|
847
|
+
}
|
|
848
|
+
})
|
|
849
|
+
|
|
850
|
+
// 暴露方法
|
|
851
|
+
defineExpose({
|
|
852
|
+
exportData,
|
|
853
|
+
printDocument,
|
|
854
|
+
exportPDF,
|
|
855
|
+
getComponentByName,
|
|
856
|
+
})
|
|
857
|
+
|
|
858
|
+
// 选择行方法
|
|
859
|
+
function selectRow(selectedRowKeys: any[], selectedRows: any[]) {
|
|
860
|
+
console.log('XReport selectRow')
|
|
861
|
+
emit('selectRow', selectedRowKeys, selectedRows)
|
|
862
|
+
}
|
|
863
|
+
</script>
|
|
864
|
+
|
|
865
|
+
<template>
|
|
866
|
+
<div>
|
|
867
|
+
<!-- 骨架屏 -->
|
|
868
|
+
<VanCard v-if="showSkeleton">
|
|
869
|
+
<VanSkeleton active />
|
|
870
|
+
</VanCard>
|
|
871
|
+
<template v-if="noPadding">
|
|
872
|
+
<!-- 主体表格 -->
|
|
873
|
+
<XReportDesign
|
|
874
|
+
v-if="scanFinish"
|
|
875
|
+
:show-img-in-cell="showImgInCell"
|
|
876
|
+
:img-prefix="imgPrefix"
|
|
877
|
+
:use-oss-for-img="useOssForImg"
|
|
878
|
+
:display-only="displayOnly"
|
|
879
|
+
:config="type === 'display' ? originalConfig : activeConfig"
|
|
880
|
+
:slot-config-name="type === 'display' ? undefined : activatedSlotName"
|
|
881
|
+
@update-img="updateImg"
|
|
882
|
+
:for-display="type === 'display'"
|
|
883
|
+
@select-row="selectRow"
|
|
884
|
+
ref="XReportDesign"
|
|
885
|
+
@slotRendered="slotRendered"
|
|
886
|
+
:server-name="serverName"
|
|
887
|
+
:env="env"
|
|
888
|
+
:show-title="showTitle"
|
|
889
|
+
:no-padding="noPadding"
|
|
890
|
+
:no-top-border="noTopBorder"
|
|
891
|
+
:show-images="hasImages"
|
|
892
|
+
:image-list="imageList"
|
|
893
|
+
/>
|
|
894
|
+
|
|
895
|
+
<VanRow v-if="showSaveButton" type="flex" justify="end">
|
|
896
|
+
<VanSpace>
|
|
897
|
+
<VanButton @click="saveConfig">
|
|
898
|
+
提交
|
|
899
|
+
</VanButton>
|
|
900
|
+
<VanButton @click="cancelConfig">
|
|
901
|
+
取消
|
|
902
|
+
</VanButton>
|
|
903
|
+
</VanSpace>
|
|
904
|
+
</VanRow>
|
|
905
|
+
</template>
|
|
906
|
+
<template v-else>
|
|
907
|
+
<!-- 用以包裹整个页面 -->
|
|
908
|
+
<div v-if="!showSkeleton">
|
|
909
|
+
<!-- 切换菜单 -->
|
|
910
|
+
<VanRadioGroup
|
|
911
|
+
v-show="!onlyDisplay && editMode"
|
|
912
|
+
v-model="type"
|
|
913
|
+
default-value="a"
|
|
914
|
+
button-style="solid"
|
|
915
|
+
@change="tabChanged"
|
|
916
|
+
>
|
|
917
|
+
<VanRadio v-if="!onlyDisplay" name="design">
|
|
918
|
+
设计
|
|
919
|
+
</VanRadio>
|
|
920
|
+
<VanRadio name="display" style="border-radius: 0">
|
|
921
|
+
预览
|
|
922
|
+
</VanRadio>
|
|
923
|
+
</VanRadioGroup>
|
|
924
|
+
|
|
925
|
+
<!-- 主体表格 -->
|
|
926
|
+
<XReportDesign
|
|
927
|
+
v-if="scanFinish"
|
|
928
|
+
:show-img-in-cell="showImgInCell"
|
|
929
|
+
:img-prefix="imgPrefix"
|
|
930
|
+
:use-oss-for-img="useOssForImg"
|
|
931
|
+
:display-only="displayOnly"
|
|
932
|
+
:config="type === 'display' ? originalConfig : activeConfig"
|
|
933
|
+
:slot-config-name="type === 'display' ? undefined : activatedSlotName"
|
|
934
|
+
:for-display="type === 'display'"
|
|
935
|
+
@update-img="updateImg"
|
|
936
|
+
:no-padding="noPadding"
|
|
937
|
+
@select-row="selectRow"
|
|
938
|
+
:no-top-border="noTopBorder"
|
|
939
|
+
@slotRendered="slotRendered"
|
|
940
|
+
:show-title="showTitle"
|
|
941
|
+
ref="XReportDesign"
|
|
942
|
+
:server-name="serverName"
|
|
943
|
+
:env="env"
|
|
944
|
+
:show-images="hasImages"
|
|
945
|
+
:image-list="imageList"
|
|
946
|
+
/>
|
|
947
|
+
</div>
|
|
948
|
+
</template>
|
|
949
|
+
|
|
950
|
+
<!-- 弹出框 -->
|
|
951
|
+
<!-- <x-add-report
|
|
952
|
+
ref="xAddReport"
|
|
953
|
+
:env="env"
|
|
954
|
+
/>-->
|
|
955
|
+
<!-- 弹出框 -->
|
|
956
|
+
<!-- <x-report-drawer
|
|
957
|
+
ref="xReportDrawer"
|
|
958
|
+
:env="env"
|
|
959
|
+
/> -->
|
|
960
|
+
</div>
|
|
961
|
+
</template>
|
|
962
|
+
|
|
963
|
+
<style lang="less" scoped>
|
|
964
|
+
.tools {
|
|
965
|
+
text-align: center;
|
|
966
|
+
cursor: pointer;
|
|
967
|
+
|
|
968
|
+
.toolsItem {
|
|
969
|
+
display: inline-block;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
</style>
|