vue2-client 1.9.80 → 1.9.82
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/docs//345/207/275/346/225/260/344/275/277/347/224/250/347/233/270/345/205/263.md +1 -0
- package/package.json +1 -1
- package/src/base-client/components/common/Recording/Recording.vue +115 -31
- package/src/base-client/components/common/Recording/index.js +2 -2
- package/src/base-client/components/common/XForm/XFormItem.vue +5 -1
- package/src/base-client/components/common/XFormTable/XFormTable.vue +6 -0
- package/src/base-client/components/common/XReportGrid/XReport.vue +76 -29
- package/src/base-client/components/common/XReportGrid/XReportDemo.vue +2 -2
- package/src/base-client/components/common/XReportGrid/XReportDesign.vue +4 -3
- package/src/base-client/components/common/XReportGrid/XReportTrGroup.vue +37 -6
- package/src/base-client/components/common/XTable/XTable.vue +4 -0
- package/src/pages/Recording/index.vue +3 -2
|
@@ -31,6 +31,7 @@ this.openDialog('xxx', 5, {}, {}, {})
|
|
|
31
31
|
- refreshTable 重新查询
|
|
32
32
|
- clearRowKeys 清除选中的行
|
|
33
33
|
- getTableData() 获取全部数据
|
|
34
|
+
- setTableData(data) 设置表格内数据
|
|
34
35
|
- Object.assign(this.fixedQueryForm, data) 给查询条件传值
|
|
35
36
|
- 事件相关
|
|
36
37
|
- afterSubmit( type(新增/修改/擦和讯), id: (所操作的主键id), form: (请求的表单内容)) 提交后触发
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<button @click="startRecording" :disabled="isRecording">开始录音</button>
|
|
4
|
-
<button @click="stopRecording" :disabled="!isRecording">停止录音</button>
|
|
3
|
+
<a-button type="primary" @click="startRecording" :disabled="isRecording">开始录音</a-button>
|
|
4
|
+
<a-button type="primary" @click="stopRecording" :disabled="!isRecording">停止录音</a-button>
|
|
5
5
|
<!-- <audio v-if="audioUrl" :src="audioUrl" controls></audio>-->
|
|
6
6
|
</div>
|
|
7
7
|
</template>
|
|
@@ -20,8 +20,7 @@ export default {
|
|
|
20
20
|
config: {}
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
|
-
props: {
|
|
24
|
-
},
|
|
23
|
+
props: {},
|
|
25
24
|
watch: {},
|
|
26
25
|
components: {},
|
|
27
26
|
created () {
|
|
@@ -31,29 +30,30 @@ export default {
|
|
|
31
30
|
},
|
|
32
31
|
methods: {
|
|
33
32
|
async startRecording () {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
this.inputData = ''
|
|
34
|
+
this.audioChunks = []
|
|
35
|
+
const url = this.config.webSocketURL ? this.config.webSocketURL : 'ws://192.168.50.67:31090/websocket/bash' // WebSocket地址
|
|
36
|
+
this.setupWebSocket(url)
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
// 等待 WebSocket 连接成功
|
|
39
|
+
await this.waitForWebSocketConnection()
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
this.isRecording = true
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
// 初始化 AudioContext
|
|
44
|
+
this.audioContext = new (window.AudioContext || window.webkitAudioContext)()
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
'录音软件不支持您的浏览器!请使用现代浏览器或确保您正在使用 HTTPS。'
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
// 获取麦克风输入流
|
|
53
|
+
this.audioStream = await navigator.mediaDevices.getUserMedia({ audio: true })
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
// 设置音频处理流程
|
|
56
|
+
this.setupAudioProcessing()
|
|
57
57
|
},
|
|
58
58
|
setupWebSocket (url) {
|
|
59
59
|
this.ws = new WebSocket(url)
|
|
@@ -64,6 +64,10 @@ export default {
|
|
|
64
64
|
if (data.result !== undefined) {
|
|
65
65
|
this.inputData += data.result
|
|
66
66
|
}
|
|
67
|
+
if (!this.isRecording) {
|
|
68
|
+
this.ws.close()
|
|
69
|
+
this.resRecordingData()
|
|
70
|
+
}
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
this.ws.onclose = () => console.log('WebSocket closed.')
|
|
@@ -93,9 +97,13 @@ export default {
|
|
|
93
97
|
|
|
94
98
|
const inputData = e.inputBuffer.getChannelData(0)
|
|
95
99
|
|
|
100
|
+
// 收集音频数据块
|
|
101
|
+
|
|
96
102
|
// Resample to 16000 Hz if needed
|
|
97
103
|
const resampledData = this.resample(inputData, this.audioContext.sampleRate, 16000)
|
|
98
104
|
|
|
105
|
+
this.audioChunks.push(new Float32Array(resampledData))
|
|
106
|
+
|
|
99
107
|
// Convert to 16-bit PCM and send via WebSocket
|
|
100
108
|
const byteArray = this.convertTo16BitPCM(resampledData)
|
|
101
109
|
this.ws.send(byteArray)
|
|
@@ -108,24 +116,97 @@ export default {
|
|
|
108
116
|
throw error
|
|
109
117
|
}
|
|
110
118
|
},
|
|
119
|
+
|
|
111
120
|
stopRecording () {
|
|
112
121
|
this.isRecording = false
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.ws.onclose = () => {
|
|
116
|
-
console.log('WebSocket closed.')
|
|
117
|
-
// 这里可以添加WebSocket关闭后的清理工作
|
|
118
|
-
}
|
|
119
|
-
// 关闭WebSocket连接
|
|
120
|
-
this.ws.close()
|
|
121
|
-
}
|
|
122
|
+
|
|
123
|
+
// 停止麦克风流
|
|
122
124
|
if (this.audioStream) {
|
|
123
|
-
this.audioStream.getTracks().forEach(track => track.stop())
|
|
125
|
+
this.audioStream.getTracks().forEach((track) => track.stop())
|
|
124
126
|
}
|
|
127
|
+
|
|
128
|
+
// 合并音频数据块并保存为文件
|
|
129
|
+
// this.saveAudioFile()
|
|
130
|
+
|
|
131
|
+
// 关闭 WebSocket
|
|
132
|
+
// if (this.ws) {
|
|
133
|
+
// this.ws.close()
|
|
134
|
+
// }
|
|
135
|
+
|
|
125
136
|
if (this.audioContext) {
|
|
126
137
|
this.audioContext.close()
|
|
127
138
|
}
|
|
128
139
|
},
|
|
140
|
+
|
|
141
|
+
saveAudioFile () {
|
|
142
|
+
// 合并所有音频块
|
|
143
|
+
const audioBuffer = this.mergeAudioChunks(this.audioChunks)
|
|
144
|
+
|
|
145
|
+
// 转换为 WAV 格式
|
|
146
|
+
const wavBlob = this.encodeWAV(audioBuffer, 16000)
|
|
147
|
+
|
|
148
|
+
// 创建下载链接并触发下载
|
|
149
|
+
const url = URL.createObjectURL(wavBlob)
|
|
150
|
+
const a = document.createElement('a')
|
|
151
|
+
a.style.display = 'none'
|
|
152
|
+
a.href = url
|
|
153
|
+
a.download = 'recording.wav'
|
|
154
|
+
document.body.appendChild(a)
|
|
155
|
+
a.click()
|
|
156
|
+
window.URL.revokeObjectURL(url)
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
mergeAudioChunks (chunks) {
|
|
160
|
+
const length = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
161
|
+
const result = new Float32Array(length)
|
|
162
|
+
let offset = 0
|
|
163
|
+
for (const chunk of chunks) {
|
|
164
|
+
result.set(chunk, offset)
|
|
165
|
+
offset += chunk.length
|
|
166
|
+
}
|
|
167
|
+
return result
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
encodeWAV (samples, sampleRate) {
|
|
171
|
+
const buffer = new ArrayBuffer(44 + samples.length * 2) // 每个样本占2字节
|
|
172
|
+
const view = new DataView(buffer)
|
|
173
|
+
|
|
174
|
+
const writeString = (view, offset, string) => {
|
|
175
|
+
for (let i = 0; i < string.length; i++) {
|
|
176
|
+
view.setUint8(offset + i, string.charCodeAt(i))
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// WAV文件头
|
|
181
|
+
writeString(view, 0, 'RIFF') // ChunkID
|
|
182
|
+
view.setUint32(4, 36 + samples.length * 2, true) // ChunkSize
|
|
183
|
+
writeString(view, 8, 'WAVE') // Format
|
|
184
|
+
|
|
185
|
+
// fmt子块
|
|
186
|
+
writeString(view, 12, 'fmt ') // Subchunk1ID
|
|
187
|
+
view.setUint32(16, 16, true) // Subchunk1Size (PCM格式固定为16)
|
|
188
|
+
view.setUint16(20, 1, true) // AudioFormat (PCM为1)
|
|
189
|
+
view.setUint16(22, 1, true) // NumChannels (单声道为1)
|
|
190
|
+
view.setUint32(24, sampleRate, true) // SampleRate
|
|
191
|
+
view.setUint32(28, sampleRate * 2, true) // ByteRate (SampleRate * NumChannels * BitsPerSample/8)
|
|
192
|
+
view.setUint16(32, 2, true) // BlockAlign (NumChannels * BitsPerSample/8)
|
|
193
|
+
view.setUint16(34, 16, true) // BitsPerSample
|
|
194
|
+
|
|
195
|
+
// data子块
|
|
196
|
+
writeString(view, 36, 'data') // Subchunk2ID
|
|
197
|
+
view.setUint32(40, samples.length * 2, true) // Subchunk2Size
|
|
198
|
+
|
|
199
|
+
// 写入PCM数据
|
|
200
|
+
let offset = 44
|
|
201
|
+
for (let i = 0; i < samples.length; i++) {
|
|
202
|
+
const s = Math.max(-1, Math.min(1, samples[i])) // 限制范围为[-1, 1]
|
|
203
|
+
view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true) // 转换为16位PCM
|
|
204
|
+
offset += 2
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return new Blob([buffer], { type: 'audio/wav' })
|
|
208
|
+
},
|
|
209
|
+
|
|
129
210
|
resample (data, inputSampleRate, outputSampleRate) {
|
|
130
211
|
if (inputSampleRate === outputSampleRate) {
|
|
131
212
|
return data
|
|
@@ -148,6 +229,9 @@ export default {
|
|
|
148
229
|
},
|
|
149
230
|
getRecordingData () {
|
|
150
231
|
return this.inputData
|
|
232
|
+
},
|
|
233
|
+
resRecordingData () {
|
|
234
|
+
this.$emit('recordingData', this.inputData)
|
|
151
235
|
}
|
|
152
236
|
}
|
|
153
237
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import
|
|
1
|
+
import Recording from './Recording.vue'
|
|
2
2
|
|
|
3
|
-
export default
|
|
3
|
+
export default Recording
|
|
@@ -617,7 +617,7 @@
|
|
|
617
617
|
:flex="attr.flex">
|
|
618
618
|
<recording
|
|
619
619
|
ref="recording"
|
|
620
|
-
@
|
|
620
|
+
@recordingData="recordingData"
|
|
621
621
|
>
|
|
622
622
|
</recording>
|
|
623
623
|
</x-form-col>
|
|
@@ -1151,7 +1151,11 @@ export default {
|
|
|
1151
1151
|
// 获取 recording 转换后的数据
|
|
1152
1152
|
getRecodingData () {
|
|
1153
1153
|
return this.$refs.recording.getRecordingData()
|
|
1154
|
+
},
|
|
1155
|
+
recordingData (data) {
|
|
1156
|
+
this.emitFunc('recordingData', data)
|
|
1154
1157
|
}
|
|
1158
|
+
|
|
1155
1159
|
}
|
|
1156
1160
|
}
|
|
1157
1161
|
</script>
|
|
@@ -160,7 +160,7 @@ export default {
|
|
|
160
160
|
// 表格没有边距
|
|
161
161
|
noPadding: {
|
|
162
162
|
type: Boolean,
|
|
163
|
-
default:
|
|
163
|
+
default: true
|
|
164
164
|
},
|
|
165
165
|
// 表格没有上边框,与noPadding搭配可以实现连续表格
|
|
166
166
|
noTopBorder: {
|
|
@@ -275,34 +275,80 @@ export default {
|
|
|
275
275
|
console.log('内部注册完成', this.$refs)
|
|
276
276
|
},
|
|
277
277
|
|
|
278
|
-
transformArray (
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
278
|
+
transformArray (inputList) {
|
|
279
|
+
let operationIndex = 0
|
|
280
|
+
let operationList = []
|
|
281
|
+
const outputList = []
|
|
282
|
+
for (const lst of inputList) {
|
|
283
|
+
// 如果列表为空或只有一个元素,则所有元素相等。比较列表中每个元素是否与第一个元素相等
|
|
284
|
+
if (lst.length >= 1 && !lst.every(x => Array.isArray(x) || Array.isArray(lst[0]) || x.rowSpan === lst[0].rowSpan)) {
|
|
285
|
+
operationList = lst
|
|
286
|
+
break // 使用 break 退出整个循环
|
|
287
|
+
} else {
|
|
288
|
+
// 被操作的行
|
|
289
|
+
operationIndex += 1
|
|
290
|
+
}
|
|
291
|
+
}
|
|
282
292
|
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
293
|
+
let maxMergeRow = 0
|
|
294
|
+
|
|
295
|
+
// 没有需要合并的行,直接返回
|
|
296
|
+
if (operationList.length === 0) {
|
|
297
|
+
return inputList
|
|
298
|
+
} else {
|
|
299
|
+
// 当前行的最大值
|
|
300
|
+
const maxRow = Math.max(...operationList.map(item => item.rowSpan))
|
|
301
|
+
let mergeIndexCol = 0
|
|
302
|
+
for (let index = 0; index < operationList.length; index++) {
|
|
303
|
+
const row = operationList[index]
|
|
304
|
+
let rowSpan = row.rowSpan
|
|
305
|
+
// 需要合并的行
|
|
306
|
+
let mergeIndexRow = operationIndex + 1
|
|
307
|
+
// 存放合并后的行
|
|
308
|
+
const rows = []
|
|
309
|
+
// 添加当前行
|
|
310
|
+
if (rowSpan < maxRow && mergeIndexRow < inputList.length) {
|
|
311
|
+
rows.push([row])
|
|
312
|
+
}
|
|
313
|
+
// 当前需要被操作并且操作行没有超出列表的高度
|
|
314
|
+
while (rowSpan < maxRow && mergeIndexRow < inputList.length) {
|
|
315
|
+
rowSpan += inputList[mergeIndexRow][mergeIndexCol].rowSpan
|
|
316
|
+
// 放一行到合并结果
|
|
317
|
+
rows.push([inputList[mergeIndexRow][mergeIndexCol]])
|
|
318
|
+
if (mergeIndexRow > maxMergeRow) {
|
|
319
|
+
// 记录最多操作到了哪行
|
|
320
|
+
maxMergeRow = mergeIndexRow
|
|
321
|
+
}
|
|
322
|
+
mergeIndexRow++
|
|
323
|
+
}
|
|
324
|
+
// operation_list赋值, 没有变化的,不处理
|
|
325
|
+
if (rows.length !== 0) {
|
|
326
|
+
operationList[index] = rows
|
|
327
|
+
}
|
|
328
|
+
if (row.rowSpan !== maxRow) {
|
|
329
|
+
mergeIndexCol++ // 操作列转为下一列
|
|
330
|
+
}
|
|
295
331
|
}
|
|
296
|
-
|
|
297
|
-
})
|
|
332
|
+
}
|
|
298
333
|
|
|
299
|
-
//
|
|
300
|
-
|
|
301
|
-
|
|
334
|
+
// 组成outputlist, operation_list前部填入
|
|
335
|
+
let putindex = 0
|
|
336
|
+
while (operationIndex > 0) {
|
|
337
|
+
outputList.push(inputList[putindex])
|
|
338
|
+
putindex++
|
|
339
|
+
operationIndex -= 1
|
|
302
340
|
}
|
|
303
341
|
|
|
304
|
-
|
|
305
|
-
|
|
342
|
+
outputList.push(operationList)
|
|
343
|
+
|
|
344
|
+
// 组成outputlist, operation_list后部填入
|
|
345
|
+
while (maxMergeRow < inputList.length - 1) {
|
|
346
|
+
outputList.push(inputList[maxMergeRow + 1])
|
|
347
|
+
maxMergeRow += 1
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
console.log('转换完成了', outputList)
|
|
351
|
+
return this.transformArray(outputList)
|
|
306
352
|
},
|
|
307
353
|
|
|
308
354
|
// 根据名字从注册到组件中获取组件
|
|
@@ -887,14 +933,15 @@ export default {
|
|
|
887
933
|
}
|
|
888
934
|
})
|
|
889
935
|
})
|
|
890
|
-
this.$nextTick(() => {
|
|
891
|
-
this.scanFinish = true
|
|
892
|
-
})
|
|
893
936
|
|
|
894
937
|
// 对配置进行转换
|
|
895
938
|
console.log('转换前配置', this.config)
|
|
896
|
-
|
|
897
|
-
console.log('转换后的列描述',
|
|
939
|
+
this.originalConfig.columns = this.transformArray(this.config.columns)
|
|
940
|
+
console.log('转换后的列描述', this.originalConfig.columns)
|
|
941
|
+
|
|
942
|
+
this.$nextTick(() => {
|
|
943
|
+
this.scanFinish = true
|
|
944
|
+
})
|
|
898
945
|
},
|
|
899
946
|
// 初始化JSON配置
|
|
900
947
|
jsonConfigInit () {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
<!-- 大标题 -->
|
|
18
18
|
<h2 class="reportTitle" v-if="showTitle && activatedConfig.title" v-html="activatedConfig.title"></h2>
|
|
19
19
|
<!-- 小标题 / 介乎于标题与表格之间的内容 -->
|
|
20
|
-
<div class="subTitle" v-if="activatedConfig.subTitle">
|
|
20
|
+
<div class="subTitle" v-if="activatedConfig.subTitle && activatedConfig.subTitle.length">
|
|
21
21
|
<div class="subTitleItems" v-for="(item, itemIndex) in activatedConfig.subTitle" :key="itemIndex">
|
|
22
22
|
<template v-if="item.type === 'column'">
|
|
23
23
|
<span>{{ item.text }}</span>
|
|
@@ -270,7 +270,7 @@ export default {
|
|
|
270
270
|
// 表格没有边距
|
|
271
271
|
noPadding: {
|
|
272
272
|
type: Boolean,
|
|
273
|
-
default:
|
|
273
|
+
default: true
|
|
274
274
|
},
|
|
275
275
|
// 表格没有上边框,与noPadding搭配可以实现连续表格
|
|
276
276
|
noTopBorder: {
|
|
@@ -504,7 +504,8 @@ export default {
|
|
|
504
504
|
color: #000;
|
|
505
505
|
// background-color: #fff;
|
|
506
506
|
border-radius: 8px;
|
|
507
|
-
height:
|
|
507
|
+
height: auto;
|
|
508
|
+
min-height : 20vh;
|
|
508
509
|
overflow-y: auto;
|
|
509
510
|
overflow-x: hidden;
|
|
510
511
|
|
|
@@ -1,19 +1,37 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<a-row type="flex" :gutter="gutter" style="margin-bottom:
|
|
2
|
+
<a-row type="flex" :gutter="gutter" style="margin-bottom: .5rem;">
|
|
3
3
|
<!-- 预览页展示 -->
|
|
4
4
|
<template v-if="display">
|
|
5
5
|
<template v-if="!inputColumns">
|
|
6
6
|
<a-col
|
|
7
7
|
name="trGroup"
|
|
8
|
-
style="flex: 1;"
|
|
9
8
|
v-for="(cell, cellIndex) in columns"
|
|
10
|
-
v-if="!cell.dontShowRow"
|
|
9
|
+
v-if="Array.isArray(cell) || !cell.dontShowRow"
|
|
11
10
|
:key="cellIndex"
|
|
12
|
-
:style="determineCellStyle(cell)"
|
|
13
|
-
:span="cell.colSpan ? cell.colSpan * 2 : undefined">
|
|
11
|
+
:style="Array.isArray(cell) ? {} : determineCellStyle(cell)"
|
|
12
|
+
:span="Array.isArray(cell) ? cell[0][0].colSpan * 2 : (cell.colSpan ? cell.colSpan * 2 : undefined)">
|
|
14
13
|
<a-card class="flexItem" :bordered="false" :body-style="flexItemBodyState">
|
|
15
14
|
<!-- 插槽渲染 -->
|
|
16
|
-
<template v-if="cell
|
|
15
|
+
<template v-if="Array.isArray(cell)">
|
|
16
|
+
<!-- 处理 cell 是数组的情况 -->
|
|
17
|
+
<div v-for="(item, index) in cell" :key="index">
|
|
18
|
+
<x-report-tr-group
|
|
19
|
+
@updateImg="updateImg"
|
|
20
|
+
:show-img-in-cell="showImgInCell"
|
|
21
|
+
:img-prefix="imgPrefix"
|
|
22
|
+
:server-name="serverName"
|
|
23
|
+
:env="env"
|
|
24
|
+
:use-oss-for-img="useOssForImg"
|
|
25
|
+
:key="index"
|
|
26
|
+
:columns="recalculateItem(item)"
|
|
27
|
+
:no-top-border="noTopBorder"
|
|
28
|
+
:config-data="configData"
|
|
29
|
+
:config="config"
|
|
30
|
+
:display="true">
|
|
31
|
+
</x-report-tr-group>
|
|
32
|
+
</div>
|
|
33
|
+
</template>
|
|
34
|
+
<template v-else-if="cell.type === 'slot'">
|
|
17
35
|
<template
|
|
18
36
|
v-if="['x-form-table','x-add-native-form','x-tree-pro', 'x-his-editor', 'x-tab', 'x-form-group', 'x-report', 'x-buttons', 'x-conversation'].includes(cell.slotType)">
|
|
19
37
|
<component
|
|
@@ -592,6 +610,19 @@ export default {
|
|
|
592
610
|
}, this.env === 'dev')
|
|
593
611
|
}
|
|
594
612
|
},
|
|
613
|
+
|
|
614
|
+
// 对于嵌套情况,对colSpan重新分配
|
|
615
|
+
recalculateItem (item) {
|
|
616
|
+
const totalColSpan = item.reduce((sum, cell) => sum + (cell.colSpan || 1), 0) // 计算总的 colSpan
|
|
617
|
+
return item.map(cell => {
|
|
618
|
+
const newColSpan = Math.round((cell.colSpan || 1) / totalColSpan * 12) // 按比例重新分配 colSpan
|
|
619
|
+
return {
|
|
620
|
+
...cell,
|
|
621
|
+
colSpan: newColSpan // 更新 colSpan
|
|
622
|
+
}
|
|
623
|
+
})
|
|
624
|
+
},
|
|
625
|
+
|
|
595
626
|
getEventHandlers (cell) {
|
|
596
627
|
const handlers = {}
|
|
597
628
|
if (!cell?.events || cell?.events?.length === 0) {
|
|
@@ -1124,6 +1124,10 @@ export default {
|
|
|
1124
1124
|
getTableData () {
|
|
1125
1125
|
return this.$refs.table.localDataSource
|
|
1126
1126
|
},
|
|
1127
|
+
// 设置表格内数据
|
|
1128
|
+
setTableData (data) {
|
|
1129
|
+
Object.assign(this.$refs.table, { localDataSource: data })
|
|
1130
|
+
},
|
|
1127
1131
|
// 获取所有本地数据
|
|
1128
1132
|
getLocalData () {
|
|
1129
1133
|
return this.localEditModeDataSource
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div id="test" v-if="showReport">
|
|
3
|
-
<
|
|
3
|
+
<recording
|
|
4
4
|
@updateImg="updateImg"
|
|
5
5
|
ref="main"
|
|
6
6
|
:use-oss-for-img="false"
|
|
@@ -22,7 +22,8 @@ import { exportHTMLNodeToPDF } from '@vue2-client/utils/htmlToPDFApi'
|
|
|
22
22
|
export default {
|
|
23
23
|
name: 'Example',
|
|
24
24
|
components: {
|
|
25
|
-
XReport
|
|
25
|
+
XReport,
|
|
26
|
+
Recording: () => import('@vue2-client/base-client/components/common/Recording')
|
|
26
27
|
},
|
|
27
28
|
mounted () {
|
|
28
29
|
console.log(this.$route)
|