vue2-client 1.14.67 → 1.14.69

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue2-client",
3
- "version": "1.14.67",
3
+ "version": "1.14.69",
4
4
  "private": false,
5
5
  "scripts": {
6
6
  "serve": "SET NODE_OPTIONS=--openssl-legacy-provider && vue-cli-service serve --no-eslint",
@@ -247,7 +247,17 @@ export default {
247
247
  this.$emit('updateImg', data)
248
248
  },
249
249
  // 导出数据,某些外部需要统一控制数据的变动
250
- exportData () {
250
+ exportData (skipValidation = false) {
251
+ // 如果不跳过校验,先进行必填字段校验
252
+ if (!skipValidation) {
253
+ const validation = this.validateRequiredFields()
254
+ if (!validation.isValid) {
255
+ const errorMessages = validation.errors.map(error => error.message).join(';')
256
+ console.warn(`数据导出警告:存在必填字段未填写 - ${errorMessages}`)
257
+ // 在导出时只警告,不阻止导出
258
+ }
259
+ }
260
+
251
261
  // 获取当前修改后的数据
252
262
  let tempData
253
263
  if (this.activeConfig === undefined || this.activeConfig === null) {
@@ -296,8 +306,68 @@ export default {
296
306
  }
297
307
  }
298
308
  },
309
+ // 验证必填字段
310
+ validateRequiredFields () {
311
+ const errors = []
312
+ const config = this.type === 'display' ? this.originalConfig : this.activeConfig
313
+
314
+ if (!config || !config.columns) {
315
+ return { isValid: true, errors: [] }
316
+ }
317
+
318
+ // 遍历所有配置项检查必填字段
319
+ config.columns.forEach((row, rowIndex) => {
320
+ row.forEach((cell, cellIndex) => {
321
+ if (cell.required && cell.dataIndex) {
322
+ let value
323
+ if (cell.dataIndex.indexOf('@@@') !== -1) {
324
+ // 处理深层嵌套数据
325
+ // const arr = cell.dataIndex.split('@@@')
326
+ value = config.tempData && config.tempData[cell.dataIndex]
327
+ } else {
328
+ value = config.data[cell.dataIndex]
329
+ }
330
+
331
+ // 检查值是否为空
332
+ if (!value || (typeof value === 'string' && value.trim() === '')) {
333
+ const message = cell.requiredMessage || this.getDefaultRequiredMessage(cell.type)
334
+ errors.push({
335
+ dataIndex: cell.dataIndex,
336
+ message: message,
337
+ rowIndex: rowIndex,
338
+ cellIndex: cellIndex,
339
+ type: cell.type
340
+ })
341
+ }
342
+ }
343
+ })
344
+ })
345
+
346
+ return {
347
+ isValid: errors.length === 0,
348
+ errors: errors
349
+ }
350
+ },
351
+ // 获取默认的必填提示信息
352
+ getDefaultRequiredMessage (fieldType) {
353
+ const defaultMessages = {
354
+ datePicker: '请选择日期',
355
+ timePicker: '请选择日期时间',
356
+ input: '请填写此字段',
357
+ inputs: '请填写此字段'
358
+ }
359
+ return defaultMessages[fieldType] || '此字段为必填项'
360
+ },
299
361
  // 正常的保存方法,当前修改内容会直接全部导出到外部
300
362
  saveConfig () {
363
+ // 先进行必填字段校验
364
+ const validation = this.validateRequiredFields()
365
+ if (!validation.isValid) {
366
+ const errorMessages = validation.errors.map(error => error.message).join(';')
367
+ this.$message.error(`保存失败:${errorMessages}`)
368
+ return false
369
+ }
370
+
301
371
  if (this.activeConfig === undefined || this.activeConfig === null) {
302
372
  return this.originalConfig.data
303
373
  } else {
@@ -306,6 +376,7 @@ export default {
306
376
  this.changeDeepObject(this.activeConfig.data, key, this.activeConfig.tempData[key])
307
377
  })
308
378
  this.$emit('saveConfig', this.$refs.XReportDesign.activatedConfig)
379
+ return true
309
380
  }
310
381
  },
311
382
  // 通过@@@分割临时变量,找到对应的key,并修改它的值
@@ -4,9 +4,8 @@
4
4
  @updateImg="updateImg"
5
5
  ref="main"
6
6
  :use-oss-for-img="false"
7
- config-name="ceshi1"
7
+ config-name="用户户内通气点火工艺流程"
8
8
  server-name="af-system"
9
- :config-data="{aaa:'data:image/png;base64,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115LdHotwujfv7+JFURlIIGUgLUeH3/8sfd7qH306dPHdO+KykECSQjWgyMNGLy9du1a7/exbfT0009X71WFIYEkxFoP37Z2wHocc8wxUb9+/VSfqDAkkARgPWhnp3CXxHpQwGP//f7775/e4kQqSCAJoO7x1ltvRR9++KH3ewjODzzwQBOca+dg5SGBeGKr5s8//7x35gqwHoMGDTJ7z0XlIYF4QLvHmjVrTGD+ySefeL/PWg8EwgwwUXlIIB7QsctmqBdffNF7xyBgPQYMGGB2DorKRAIpAtZjyZIl0dNPP212Dfpircd5550Xde7cOcUVijSRQIpAYE6r+TvvvJPofTb2OOGEE1JamcgCCcSBPXl2woQJXhuWLFgP9nyQ2pX1qGwkkH8B12rZsmXRU089lailBEjnXnDBBdGxxx6b0upEVkgg/8L69evNEdWTJk1KFJhTKWcYw4UXXqjMVREovDLwIs9oR+E2IGs1Z86caNy4caZr1xc2RO2+++7R8OHD1ZRYBCw03Qg8gDgHnfvFURh5G4MkgWwFHxxTSp588snErhU9VwxjIPZQS3txEAj3mfuNO8qkSYSCBWZrQKgzQVoigbQAcXDwDb1WSV0rAnN6rbAenPkh3HCvub+4sl988YU5T6Wmpua/Oy7pPEAoCIYZxjx8QiCBtIAP7P33348eeeSRaPHixYnei2tAYE5Luzp2i4NASKEztaXlvxmfRLcC8dvhhx9upr8ccsghptiKaJhlnOX9lUD+hrjj008/jcaOHRt9/fXXid7LB8YHedlll5kYRPjBPd+WlbaTXGgKZVsBYuH+nn322eY0riz31CiLFf0v7qDe8e677yZ6L4E5/vK1116rUaIJsS6WCysWWn2mT5+eedarzQvEDn977rnnEscdgGtFOwkvtbP7Y4fiUWvygQdRbW2t2ZmZJW1eIPi9r7/+evTwww8njjsIHGklueaaazRnNyEIhDNVkgy9YCJ+1pmtNi0QG5Tfd999iRoRwWat8Il9xoiKf2Izhr5gQXbbbbfM6yRtViCI44MPPojuv//+RIOnLQSOzMEdOHBgLvL1lYbdY+MLDySC86zTvW1SILZSfvfddycOygFBkM698sorjV8skoNAigXoLbGHDmVNmxMIHboUpkjn0sKeNCi3J9PedNNNaidpBaVYEAqGWdOmBGKPSnvwwQej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'}"
10
9
  :show-img-in-cell="true"
11
10
  :edit-mode="false"
12
11
  :show-save-button="false"
@@ -37,6 +37,22 @@
37
37
  {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
38
38
  </template>
39
39
  </template>
40
+ <template v-else-if="cell.type === 'datePicker'">
41
+ <template v-if="cell.customFunction === undefined">
42
+ {{ getDeepObject(configData, cell.dataIndex) }}
43
+ </template>
44
+ <template v-else>
45
+ {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
46
+ </template>
47
+ </template>
48
+ <template v-else-if="cell.type === 'timePicker'">
49
+ <template v-if="cell.customFunction === undefined">
50
+ {{ getDeepObject(configData, cell.dataIndex) }}
51
+ </template>
52
+ <template v-else>
53
+ {{ deserializeFunctionAndRun(cell.customFunction, configData[cell.dataIndex], config) }}
54
+ </template>
55
+ </template>
40
56
  <template v-else-if="cell.type === 'inputs'">
41
57
  <template v-if="cell.customFunction === undefined">
42
58
  {{ showSubRowValue(cell) }}
@@ -131,6 +147,26 @@
131
147
  }}
132
148
  </template>
133
149
  </template>
150
+ <template v-else-if="cell.type === 'datePicker'">
151
+ <template v-if="cell.customFunction === undefined">
152
+ {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
153
+ </template>
154
+ <template v-else>
155
+ {{
156
+ deserializeFunctionAndRun(cell.customFunction, configData.arr[inputColumnsDefinitionIndex][cell.dataIndex], config)
157
+ }}
158
+ </template>
159
+ </template>
160
+ <template v-else-if="cell.type === 'timePicker'">
161
+ <template v-if="cell.customFunction === undefined">
162
+ {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
163
+ </template>
164
+ <template v-else>
165
+ {{
166
+ deserializeFunctionAndRun(cell.customFunction, configData.arr[inputColumnsDefinitionIndex][cell.dataIndex], config)
167
+ }}
168
+ </template>
169
+ </template>
134
170
  <template v-else-if="cell.type === 'inputs'">
135
171
  <template v-if="cell.customFunction === undefined">
136
172
  {{ getDeepObject(configData.arr[inputColumnsDefinitionIndex], cell.dataIndex) }}
@@ -178,39 +214,61 @@
178
214
  >{{ cell.text || '确认' }}
179
215
  </a-button>
180
216
  </template>
217
+ <template v-else-if="cell.type === 'datePicker'">
218
+ <div>
219
+ <a-date-picker
220
+ @change="handleDatePickerChange($event, cell.dataIndex, cell)"
221
+ :value="formatDateValue(configData[cell.dataIndex])"
222
+ format="YYYY-MM-DD"
223
+ :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
224
+ :disabled="cell.inputReadOnly===true"
225
+ :class="{'required-field-error': isFieldRequired(cell) && !configData[cell.dataIndex]}"/>
226
+ <div v-if="isFieldRequired(cell) && !configData[cell.dataIndex]" class="required-message">
227
+ {{ getRequiredMessage(cell, 'datePicker') }}
228
+ </div>
229
+ </div>
230
+ </template>
231
+ <template v-else-if="cell.type === 'timePicker'">
232
+ <div>
233
+ <a-date-picker
234
+ @change="handleTimePickerChange($event, cell.dataIndex, cell)"
235
+ :value="formatDateValue(configData[cell.dataIndex])"
236
+ format="YYYY-MM-DD HH:mm:ss"
237
+ show-time
238
+ :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
239
+ :disabled="cell.inputReadOnly===true"
240
+ :class="{'required-field-error': isFieldRequired(cell) && !configData[cell.dataIndex]}"/>
241
+ <div v-if="isFieldRequired(cell) && !configData[cell.dataIndex]" class="required-message">
242
+ {{ getRequiredMessage(cell, 'timePicker') }}
243
+ </div>
244
+ </div>
245
+ </template>
181
246
  <template v-else-if="cell.type === 'signature'">
182
247
  <img :src="configData[cell.dataIndex]" alt="签名加载失败" style="max-height: 2rem">
183
248
  <a-button v-if="!configData[cell.dataIndex]" type="dashed" >需要在手机端签名 </a-button>
184
249
  </template>
185
250
  <template v-else-if="cell.type === 'input'">
186
- <template v-if="cell.inputReadOnly === true">
251
+ <div>
187
252
  <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
188
253
  <a-input
189
- @change="handleInputDeepChange($event, cell.dataIndex)"
254
+ @change="handleInputDeepChange($event, cell.dataIndex, cell)"
190
255
  v-model="config.tempData[cell.dataIndex]"
191
256
  :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
192
- :disabled="true"/>
257
+ :disabled="cell.inputReadOnly === true"
258
+ :class="{'required-field-error': isFieldRequired(cell) && !config.tempData[cell.dataIndex]}"/>
193
259
  </template>
194
260
  <template v-else>
195
261
  <a-input
262
+ @change="handleInputChange($event, cell.dataIndex, cell)"
196
263
  v-model="configData[cell.dataIndex]"
197
264
  :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
198
- :disabled="true"/>
265
+ :disabled="cell.inputReadOnly === true"
266
+ :class="{'required-field-error': isFieldRequired(cell) && !configData[cell.dataIndex]}"/>
199
267
  </template>
200
- </template>
201
- <template v-else>
202
- <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
203
- <a-input
204
- @change="handleInputDeepChange($event, cell.dataIndex)"
205
- v-model="config.tempData[cell.dataIndex]"
206
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
207
- </template>
208
- <template v-else>
209
- <a-input
210
- v-model="configData[cell.dataIndex]"
211
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
212
- </template>
213
- </template>
268
+ <div v-if="isFieldRequired(cell) && !getInputValue(cell)" class="required-message">
269
+ {{ getRequiredMessage(cell, 'input') }}
270
+ </div>
271
+ </div>
214
272
  </template>
215
273
  <template v-else-if="cell.type === 'inputs'">
216
274
  <template v-if="cell.inputReadOnly === true">
@@ -219,7 +277,7 @@
219
277
  <span class="inputsDivItemLabel">{{ displayFormatStartText(cell.format) }}</span>
220
278
  <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
221
279
  <a-input
222
- @change="handleInputDeepChange($event, cell.dataIndex)"
280
+ @change="handleInputDeepChange($event, cell.dataIndex, cell)"
223
281
  v-model="config.tempData[cell.dataIndex][index]"
224
282
  :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
225
283
  :disabled="true"/>
@@ -240,7 +298,7 @@
240
298
  <span class="inputsDivItemLabel">{{ displayFormatStartText(cell.format) }}</span>
241
299
  <template v-if="cell.dataIndex.indexOf('@@@') !== -1">
242
300
  <a-input
243
- @change="handleInputDeepChange($event, cell.dataIndex)"
301
+ @change="handleInputDeepChange($event, cell.dataIndex, cell)"
244
302
  v-model="config.tempData[cell.dataIndex][index]"
245
303
  :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
246
304
  </template>
@@ -337,6 +395,35 @@
337
395
  >{{ cell.text || '确认' }}
338
396
  </a-button>
339
397
  </template>
398
+ <template v-else-if="cell.type === 'datePicker'">
399
+ <div>
400
+ <a-date-picker
401
+ @change="handleArrayDatePickerChange($event, inputColumnsDefinitionIndex, cell.dataIndex, cell)"
402
+ :value="formatDateValue(configData.arr[inputColumnsDefinitionIndex][cell.dataIndex])"
403
+ format="YYYY-MM-DD"
404
+ :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
405
+ :disabled="cell.inputReadOnly === true"
406
+ :class="{'required-field-error': isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]}"/>
407
+ <div v-if="isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]" class="required-message">
408
+ {{ getRequiredMessage(cell, 'datePicker') }}
409
+ </div>
410
+ </div>
411
+ </template>
412
+ <template v-else-if="cell.type === 'timePicker'">
413
+ <div>
414
+ <a-date-picker
415
+ @change="handleArrayTimePickerChange($event, inputColumnsDefinitionIndex, cell.dataIndex, cell)"
416
+ :value="formatDateValue(configData.arr[inputColumnsDefinitionIndex][cell.dataIndex])"
417
+ format="YYYY-MM-DD HH:mm:ss"
418
+ show-time
419
+ :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
420
+ :disabled="cell.inputReadOnly === true"
421
+ :class="{'required-field-error': isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]}"/>
422
+ <div v-if="isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]" class="required-message">
423
+ {{ getRequiredMessage(cell, 'timePicker') }}
424
+ </div>
425
+ </div>
426
+ </template>
340
427
  <template v-else-if="cell.type === 'signature'">
341
428
  <img :src="configData[cell.dataIndex]" alt="签名加载失败" style="max-height: 2rem">
342
429
  <a-button v-if="!configData[cell.dataIndex]" type="dashed" >需要在手机端签名</a-button>
@@ -345,17 +432,17 @@
345
432
  {{ configData.arr[inputColumnsDefinitionIndex][cell.dataIndex] }}
346
433
  </template>
347
434
  <template v-else-if="cell.type === 'input'">
348
- <template v-if="cell.inputReadOnly === true">
435
+ <div>
349
436
  <a-input
437
+ @change="handleArrayInputChange($event, inputColumnsDefinitionIndex, cell.dataIndex, cell)"
350
438
  v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
351
439
  :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"
352
- :disabled="true"/>
353
- </template>
354
- <template v-else>
355
- <a-input
356
- v-model="configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]"
357
- :style="'width:' + (cell.inputWidth ? cell.inputWidth : '100') + '%'"/>
358
- </template>
440
+ :disabled="cell.inputReadOnly === true"
441
+ :class="{'required-field-error': isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]}"/>
442
+ <div v-if="isFieldRequired(cell) && !configData.arr[inputColumnsDefinitionIndex][cell.dataIndex]" class="required-message">
443
+ {{ getRequiredMessage(cell, 'input') }}
444
+ </div>
445
+ </div>
359
446
  </template>
360
447
  <template v-else-if="cell.type === 'inputs'">
361
448
  <template v-if="cell.inputReadOnly === true">
@@ -379,6 +466,7 @@
379
466
  import Upload from '@vue2-client/base-client/components/common/Upload'
380
467
  import { formatDate } from '@vue2-client/utils/util'
381
468
  import { nanoid } from 'nanoid'
469
+ import moment from 'moment'
382
470
 
383
471
  export default {
384
472
  name: 'XReportTrGroup',
@@ -582,9 +670,35 @@ export default {
582
670
  return result
583
671
  },
584
672
  // 表格中数据key含有@@@,需要手动触发更新
585
- handleInputDeepChange () {
673
+ handleInputDeepChange (event, dataIndex, cell = null) {
674
+ // 如果字段必填且有值,触发重新渲染以移除错误样式
675
+ if (cell && this.isFieldRequired(cell) && event.target.value) {
676
+ this.$forceUpdate()
677
+ }
586
678
  this.$forceUpdate()
587
679
  },
680
+ // 处理普通input变化
681
+ handleInputChange (event, dataIndex, cell = null) {
682
+ // 如果字段必填且有值,触发重新渲染以移除错误样式
683
+ if (cell && this.isFieldRequired(cell) && event.target.value) {
684
+ this.$forceUpdate()
685
+ }
686
+ },
687
+ // 处理动态行中input变化
688
+ handleArrayInputChange (event, arrayIndex, dataIndex, cell = null) {
689
+ // 如果字段必填且有值,触发重新渲染以移除错误样式
690
+ if (cell && this.isFieldRequired(cell) && event.target.value) {
691
+ this.$forceUpdate()
692
+ }
693
+ },
694
+ // 获取input的值,用于必填校验
695
+ getInputValue (cell) {
696
+ if (cell.dataIndex.indexOf('@@@') !== -1) {
697
+ return this.config.tempData[cell.dataIndex]
698
+ } else {
699
+ return this.configData[cell.dataIndex]
700
+ }
701
+ },
588
702
  // 路径中含有@@@的key,将其解析,并返回其数据
589
703
  getDeepObject (obj, strPath) {
590
704
  const arr = strPath.split('@@@')
@@ -610,6 +724,69 @@ export default {
610
724
  }
611
725
  this.configData = Object.assign({}, this.configData)
612
726
  },
727
+ // 通用的日期时间选择器变化处理方法
728
+ handleDateTimePickerChange (date, dataIndex, format, arrayIndex = null, cell = null) {
729
+ const dateStr = date ? moment(date).format(format) : ''
730
+
731
+ if (arrayIndex !== null) {
732
+ // 处理动态行中的日期时间选择器
733
+ this.configData.arr[arrayIndex][dataIndex] = dateStr
734
+ } else if (dataIndex.indexOf('@@@') !== -1) {
735
+ // 处理深层嵌套的数据
736
+ this.handleInputDeepChange({ target: { value: dateStr } }, dataIndex, cell)
737
+ } else {
738
+ // 处理普通的数据
739
+ this.configData[dataIndex] = dateStr
740
+ }
741
+
742
+ // 如果字段必填且有值,触发重新渲染以移除错误样式
743
+ if (cell && this.isFieldRequired(cell) && dateStr) {
744
+ this.$forceUpdate()
745
+ }
746
+
747
+ this.configData = Object.assign({}, this.configData)
748
+ },
749
+ // 日期选择器变化处理(YYYY-MM-DD格式)
750
+ handleDatePickerChange (date, dataIndex, cell = null) {
751
+ this.handleDateTimePickerChange(date, dataIndex, 'YYYY-MM-DD', null, cell)
752
+ },
753
+ // 时间选择器变化处理(YYYY-MM-DD HH:mm:ss格式)
754
+ handleTimePickerChange (date, dataIndex, cell = null) {
755
+ this.handleDateTimePickerChange(date, dataIndex, 'YYYY-MM-DD HH:mm:ss', null, cell)
756
+ },
757
+ // 动态行中日期选择器变化处理
758
+ handleArrayDatePickerChange (date, arrayIndex, dataIndex, cell = null) {
759
+ this.handleDateTimePickerChange(date, dataIndex, 'YYYY-MM-DD', arrayIndex, cell)
760
+ },
761
+ // 动态行中时间选择器变化处理
762
+ handleArrayTimePickerChange (date, arrayIndex, dataIndex, cell = null) {
763
+ this.handleDateTimePickerChange(date, dataIndex, 'YYYY-MM-DD HH:mm:ss', arrayIndex, cell)
764
+ },
765
+ // 判断字段是否必填
766
+ isFieldRequired (cell) {
767
+ return cell && cell.required === true
768
+ },
769
+ // 获取必填字段的提示信息
770
+ getRequiredMessage (cell, fieldType) {
771
+ if (cell.requiredMessage) {
772
+ return cell.requiredMessage
773
+ }
774
+
775
+ // 默认提示信息
776
+ const defaultMessages = {
777
+ datePicker: '请选择日期',
778
+ timePicker: '请选择日期时间',
779
+ input: '请填写此字段'
780
+ }
781
+
782
+ return defaultMessages[fieldType] || '此字段为必填项'
783
+ },
784
+ // 格式化日期值,用于日期选择器的value
785
+ formatDateValue (dateStr) {
786
+ if (!dateStr) return null
787
+ const date = moment(dateStr)
788
+ return date.isValid() ? date : null
789
+ },
613
790
  // 反序列化函数并执行
614
791
  deserializeFunctionAndRun (functionStr, value) {
615
792
  // eslint-disable-next-line no-eval
@@ -813,4 +990,16 @@ export default {
813
990
  border-bottom: 1px solid #000;
814
991
  padding: 8px;
815
992
  }
993
+
994
+ .required-field-error {
995
+ border-color: #ff4d4f !important;
996
+ box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.2) !important;
997
+ }
998
+
999
+ .required-message {
1000
+ color: #ff4d4f;
1001
+ font-size: 12px;
1002
+ margin-top: 4px;
1003
+ line-height: 1.2;
1004
+ }
816
1005
  </style>
@@ -36,9 +36,68 @@ export default {
36
36
  ```vue
37
37
  <XReport :config-name="'test_tableConfig'" :activated-slot-name="'test_tableConfig_slot'"/>
38
38
  ```
39
+
40
+ ## 支持的表单项目类型
41
+
42
+ | 类型 | 说明 | 输出格式 | 备注 |
43
+ |-----------------|------|-------|-----------|
44
+ | input | 文本输入框 | 字符串 | 标准文本输入 |
45
+ | datePicker| 日期选择器 | YYYY-MM-DD | 日期格式 |
46
+ | timePicker | 时间选择器 | YYYY-MM-DD HH:mm:ss | 日期时间格式 |
47
+ | curDateInput | 当前日期按钮 | YYYY-MM-DD HH:mm:ss | 点击获取当前时间|
48
+ | signature | 签名框 | 图片URL | 需要在手机端操作|
49
+ | images | 图片上传 | 图片数组 | 支持多图片上传|
50
+
51
+ ## 配置例子
52
+
53
+ ### 日期选择器配置
54
+ ```json
55
+ {
56
+ "type": "datePicker",
57
+ "dataIndex": "selectedDate",
58
+ "inputWidth": "100%",
59
+ "inputReadOnly": false,
60
+ "required": true,
61
+ "requiredMessage": "请选择操作日期"
62
+ }
63
+ ```
64
+
65
+ ### 时间选择器配置
66
+ ```json
67
+ {
68
+ "type": "timePicker",
69
+ "dataIndex": "selectedDateTime",
70
+ "inputWidth": "100%",
71
+ "inputReadOnly": false,
72
+ "required": true,
73
+ "requiredMessage": "请选择具体时间"
74
+ }
75
+ ```
76
+
77
+ ### 必填字段配置说明
78
+
79
+ | 参数 | 说明 | 类型 | 默认值 |
80
+ |-----------------|------|-------|-----------|
81
+ | required | 是否必填 | Boolean | false |
82
+ | requiredMessage| 必填提示信息 | String | 根据字段类型自动生成 |
83
+
84
+ **默认提示信息:**
85
+ - datePicker: "请选择日期"
86
+ - timePicker: "请选择日期时间"
87
+ - input: "请填写此字段"
88
+ - 其他类型: "此字段为必填项"
89
+
90
+ **必填校验特性:**
91
+ - 必填字段为空时会显示红色边框和错误提示
92
+ - 保存时会自动校验所有必填字段,校验失败会阻止保存并显示错误信息
93
+ - 导出数据时会进行校验提醒,但不会阻止导出
94
+
39
95
  ## 注意事项
40
96
 
41
97
  > 在某些情况下,比如手机端,只需要输入表格中一部分的内容。
42
98
  > 可以将这部分内容作为插槽,并在activatedSlotName中填写插槽名。
43
99
  > 则会在设计页面仅展示插槽中的输入项,并在预览窗口中,根据configName中的配置,
44
100
  > 渲染出来完整的表格
101
+
102
+ > 新增的datePicker和timePicker支持在普通行、动态行中使用,
103
+ > 会自动格式化为指定的日期时间格式并保存到配置数据中。支持必填校验功能。
@@ -1,28 +1,55 @@
1
1
  <template>
2
2
  <div class="list-wrapper">
3
3
  <a-list size="large" :data-source="data" itemLayout="horizontal" class="list-container" ref="listRef">
4
- <a-list-item slot="renderItem" slot-scope="item, index" class="list-item" @click="handleClick(index)">
5
- <i
6
- v-if="icon"
7
- class="icon-menu"
8
- :style="getIconStyle(item)"
9
- ></i>
10
- <span
11
- class="item-text">
12
- {{ item.number }} {{ item.name }}
13
- </span>
14
-
15
- <div v-if="button" class="button-group">
16
- <a-button
17
- v-for="(name, idx) in buttonNames"
18
- :key="idx"
19
- type="link"
20
- :class="['confirm-btn', buttonMode ? 'hover-btn' : '']"
21
- @click.stop="click(index, idx)"
4
+ <a-list-item
5
+ slot="renderItem"
6
+ slot-scope="item, index"
7
+ class="list-item"
8
+ @click="handleClick(index)"
9
+ @mouseenter="enableHoverOptions && handleMouseEnter(index)"
10
+ @mouseleave="handleMouseLeave"
11
+ :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index }"
12
+ >
13
+ <i
14
+ v-if="icon"
15
+ class="icon-menu"
16
+ :style="getIconStyle(item)"
17
+ ></i>
18
+ <span
19
+ class="item-text">
20
+ {{ item.number }} {{ item.name }}
21
+ </span>
22
+
23
+ <div v-if="button" class="button-group">
24
+ <a-button
25
+ v-for="(name, idx) in buttonNames"
26
+ :key="idx"
27
+ type="link"
28
+ :class="['confirm-btn', buttonMode ? 'hover-btn' : '']"
29
+ @click.stop="click(index, idx)"
30
+ >
31
+ <span :class="{ 'hover-active': enableHoverOptions && hoveredIndex === index }">{{ name }}</span>
32
+ </a-button>
33
+ </div>
34
+
35
+ <!-- 悬浮选项框 -->
36
+ <div
37
+ v-show="enableHoverOptions && hoveredIndex === index"
38
+ class="hover-options"
39
+ @mouseenter="handleOptionsEnter"
40
+ @mouseleave="handleOptionsLeave"
22
41
  >
23
- {{ name }}
24
- </a-button>
25
- </div>
42
+ <div class="hover-options-content">
43
+ <div
44
+ v-for="(item, idx) in select_options"
45
+ :key="idx"
46
+ class="option-item"
47
+ @click="handleOptionClick(index, item)"
48
+ >
49
+ {{ item }}
50
+ </div>
51
+ </div>
52
+ </div>
26
53
  </a-list-item>
27
54
  </a-list>
28
55
  </div>
@@ -42,6 +69,10 @@ export default {
42
69
  fixedQueryForm: {
43
70
  type: Object,
44
71
  default: { condition: '1=1' }
72
+ },
73
+ enableHoverOptions: {
74
+ type: Boolean,
75
+ default: true
45
76
  }
46
77
  },
47
78
  inject: ['getComponentByName'],
@@ -51,7 +82,12 @@ export default {
51
82
  button: false,
52
83
  icon: false,
53
84
  buttonNames: [],
54
- buttonMode: false
85
+ buttonMode: false,
86
+ hoveredIndex: -1,
87
+ isOptionsHovered: false,
88
+ hoverTimer: null,
89
+ leaveTimer: null,
90
+ select_options: []
55
91
  }
56
92
  },
57
93
  created () {
@@ -65,6 +101,10 @@ export default {
65
101
  that.icon = res.icon
66
102
  that.buttonNames = res.buttonNames || []
67
103
  that.buttonMode = res.buttonMode || false
104
+ this.enableHoverOptions = res.enableHoverOptions || false
105
+ if (this.enableHoverOptions) {
106
+ this.select_options = res.select_options
107
+ }
68
108
  runLogic(res.data, param, 'af-his').then(ress => {
69
109
  that.data = ress
70
110
  })
@@ -88,6 +128,42 @@ export default {
88
128
  runLogic(this.queryParamsName, par, 'af-his').then(res => {
89
129
  this.data = res.data
90
130
  })
131
+ },
132
+ handleMouseEnter (index) {
133
+ this.clearAllTimers()
134
+ this.hoveredIndex = index
135
+ this.isOptionsHovered = true
136
+ },
137
+ handleMouseLeave () {
138
+ this.clearAllTimers()
139
+ this.leaveTimer = setTimeout(() => {
140
+ this.isOptionsHovered = false
141
+ this.hoveredIndex = -1
142
+ }, 100)
143
+ },
144
+ handleOptionsEnter () {
145
+ this.clearAllTimers()
146
+ this.isOptionsHovered = true
147
+ },
148
+ handleOptionsLeave () {
149
+ this.clearAllTimers()
150
+ this.leaveTimer = setTimeout(() => {
151
+ this.isOptionsHovered = false
152
+ this.hoveredIndex = -1
153
+ }, 100)
154
+ },
155
+ clearAllTimers () {
156
+ if (this.hoverTimer) {
157
+ clearTimeout(this.hoverTimer)
158
+ this.hoverTimer = null
159
+ }
160
+ if (this.leaveTimer) {
161
+ clearTimeout(this.leaveTimer)
162
+ this.leaveTimer = null
163
+ }
164
+ },
165
+ handleOptionClick (index, action) {
166
+ this.$emit('optionClick', { data: this.data[index], action })
91
167
  }
92
168
  },
93
169
  watch: {
@@ -97,6 +173,9 @@ export default {
97
173
  this.refreshList(val)
98
174
  }
99
175
  }
176
+ },
177
+ beforeDestroy () {
178
+ this.clearAllTimers()
100
179
  }
101
180
  }
102
181
  </script>
@@ -124,6 +203,8 @@ export default {
124
203
  border: 1px solid #D9D9D9;
125
204
  box-sizing: border-box;
126
205
  margin-bottom: 8px !important;
206
+ position: relative;
207
+ transition: background-color 0.3s ease;
127
208
  }
128
209
 
129
210
  .icon-menu {
@@ -170,4 +251,56 @@ export default {
170
251
  .list-wrapper::-webkit-scrollbar-track {
171
252
  background-color: #f0f0f0;
172
253
  }
254
+
255
+ .hover-active {
256
+ color: white;
257
+ }
258
+
259
+ .list-item.hover-active {
260
+ background-color: rgb(0, 87, 254) !important;
261
+ color: white;
262
+ border: 1px solid black;
263
+ }
264
+
265
+ .hover-options {
266
+ position: absolute;
267
+ left: 0;
268
+ right: 0;
269
+ top: 100%;
270
+ background: white;
271
+ border: 1px solid #d9d9d9;
272
+ border-radius: 4px;
273
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
274
+ z-index: 1000;
275
+ margin-top: 4px;
276
+ width: 100%;
277
+ box-sizing: border-box;
278
+ pointer-events: auto;
279
+ }
280
+
281
+ .hover-options-content {
282
+ padding: 4px 0;
283
+ display: flex;
284
+ flex-direction: column;
285
+ width: 100%;
286
+ }
287
+
288
+ .option-item {
289
+ padding: 8px 12px;
290
+ cursor: pointer;
291
+ transition: all 0.3s ease;
292
+ color: #333;
293
+ font-size: 14px;
294
+ display: flex;
295
+ align-items: center;
296
+ }
297
+
298
+ .option-item:hover {
299
+ background-color: #f5f5f5;
300
+ color: #1890ff;
301
+ }
302
+
303
+ .option-item:active {
304
+ background-color: #e6f7ff;
305
+ }
173
306
  </style>
@@ -339,6 +339,65 @@ async function handleSubmit (formData) {
339
339
  }
340
340
  }
341
341
 
342
+ // 处理表单数据
343
+ function mergeAndTransformData (records, patientInfo, id, date, operateDate) {
344
+ // 提取records中的数据
345
+ const temperatureList = records.map(record => record.temperature).join(',')
346
+ const sphygmusList = records.map(record => record.sphygmus).join(',')
347
+ const breathList = records.map(record => record.breath).join(',')
348
+ const heartList = records.map(record => record.heart).join(',')
349
+ const notesList = records.map(record => record.notes).join(',')
350
+ const painList = records.map(record => record.pain).join(',')
351
+ const data1List = records.map(record => {
352
+ const [systolic, diastolic] = record.data1.split('|')
353
+ return `${systolic}/${diastolic}`
354
+ }).join(',')
355
+ const data2List = records.map(record => record.data2).join(',')
356
+ const data3List = records.map(record => record.data3).join(',')
357
+ const data4List = records.map(record => record.data4).join(',')
358
+ const data5List = records.map(record => record.data5).join(',')
359
+ const data6List = records.map(record => record.data6).join(',')
360
+ const data7List = records.map(record => record.data7).join(',')
361
+ const tempTypeList = records.map(record => record.temptype).join(',')
362
+
363
+ // 提取patientInfo中的数据
364
+ const name = patientInfo.name || ''
365
+ const dept = patientInfo.dept || ''
366
+ const bed = patientInfo.bed || ''
367
+ const inDate = patientInfo.indate || ''
368
+ const diag = patientInfo.diag || ''
369
+
370
+ // 生成合并后的对象
371
+ const mergedData = {
372
+ bed: bed.toString(),
373
+ sphygmus: sphygmusList,
374
+ notes: notesList,
375
+ medicalNo: id, // 示例中的固定值
376
+ diag: diag,
377
+ type: 'normal', // 示例中的固定值
378
+ breath: breathList,
379
+ temperature: temperatureList,
380
+ id: id, // 示例中的固定值
381
+ tempType: tempTypeList,
382
+ data7: data7List,
383
+ pain: painList,
384
+ data6: data6List,
385
+ data5: data5List,
386
+ data4: data4List,
387
+ data3: data3List,
388
+ data2: data2List,
389
+ inDate: inDate.split(' ')[0], // 只取日期部分
390
+ data1: data1List,
391
+ dept: dept,
392
+ heart: heartList,
393
+ labels: '血压(mmHg)|入水量(ml)|出水量(ml)|大便(次)|小便(次)|身高(cm)|体重(kg)', // 示例中的固定值
394
+ name: name,
395
+ begin: date, // 只取日期部分
396
+ operateDate: operateDate // 只取日期部分
397
+ }
398
+ return mergedData
399
+ }
400
+
342
401
  // 生命周期钩子
343
402
  onMounted(() => {
344
403
  window.addEventListener('message', (event) => {
@@ -373,7 +432,9 @@ defineExpose({
373
432
  vitalSignsId.value = id
374
433
  },
375
434
  // 创建体温单 参数:(Object) data
376
- handleSubmit
435
+ handleSubmit,
436
+ // 获取表单数据
437
+ mergeAndTransformData
377
438
  })
378
439
  </script>
379
440
 
@@ -37,7 +37,7 @@
37
37
  <a-tab-pane key="0" tab="步骤详情">
38
38
  <a-card :bordered="false" :loading="loadingHistory">
39
39
  <!-- 当前步骤历史记录 -->
40
- <template v-if="formCompletedDataPreview && formCompletedDataPreview.data.length > 0">
40
+ <template v-if="formCompletedDataPreview">
41
41
  <a-descriptions
42
42
  v-show="formCompletedDataPreview.data"
43
43
  :column="{ xxl: 4, xl: 3, lg: 3, md: 3, sm: 2, xs: 1 }"