vue_zhongyou 1.0.9 → 1.0.10
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
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
v-model="formData[field.field]"
|
|
9
9
|
:type="field.type === 'textarea' ? 'textarea' : 'text'"
|
|
10
10
|
:label="field.label"
|
|
11
|
+
:label-width="60"
|
|
11
12
|
:placeholder="field.placeholder || `请输入${field.label}`"
|
|
12
|
-
:rules="field.rules"
|
|
13
|
+
:rules="field.rules || []"
|
|
13
14
|
:maxlength="field.maxlength"
|
|
14
15
|
:rows="field.rows || (field.type === 'textarea' ? 3 : undefined)"
|
|
15
16
|
:autosize="field.type === 'textarea'"
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
/>
|
|
20
21
|
|
|
21
22
|
<!-- 单选 -->
|
|
22
|
-
<van-field v-else-if="field.type === 'radio'" name="radio" :label="field.label">
|
|
23
|
+
<van-field v-else-if="field.type === 'radio'" name="radio" :label="field.label" :rules="field.rules || []">
|
|
23
24
|
<template #input>
|
|
24
25
|
<van-radio-group
|
|
25
26
|
v-model="formData[field.field]"
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
|
|
41
42
|
|
|
42
43
|
<!-- 多选 -->
|
|
43
|
-
<van-field v-else-if="field.type === 'checkbox'" name="checkboxGroup" :label="field.label">
|
|
44
|
+
<van-field v-else-if="field.type === 'checkbox'" name="checkboxGroup" :label="field.label" :rules="field.rules || []">
|
|
44
45
|
<template #input>
|
|
45
46
|
<van-checkbox-group
|
|
46
47
|
v-model="formData[field.field]"
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
:label="field.label"
|
|
68
69
|
:placeholder="field.placeholder || `请选择${field.label}`"
|
|
69
70
|
:model-value="getSelectLabel(field)"
|
|
71
|
+
:rules="field.rules || []"
|
|
70
72
|
@click="openSelect(field)"
|
|
71
73
|
/>
|
|
72
74
|
|
|
@@ -77,10 +79,24 @@
|
|
|
77
79
|
readonly
|
|
78
80
|
:label="field.label"
|
|
79
81
|
:placeholder="field.placeholder || '请选择时间范围'"
|
|
82
|
+
:rules="field.rules || []"
|
|
80
83
|
:model-value="getDateRangeText(field)"
|
|
81
84
|
@click="openDateRange(field)"
|
|
82
85
|
/>
|
|
83
86
|
|
|
87
|
+
<!-- 日期时间范围 -->
|
|
88
|
+
<van-field
|
|
89
|
+
v-else-if="field.type === 'datetimeRange'"
|
|
90
|
+
is-link
|
|
91
|
+
readonly
|
|
92
|
+
:label="field.label"
|
|
93
|
+
:label-width="60"
|
|
94
|
+
:placeholder="field.placeholder || '请选择日期时间范围'"
|
|
95
|
+
:model-value="getDateTimeRangeText(field)"
|
|
96
|
+
:rules="field.rules || []"
|
|
97
|
+
@click="openDateTimeRange(field)"
|
|
98
|
+
/>
|
|
99
|
+
|
|
84
100
|
<!-- 地址选择 -->
|
|
85
101
|
<van-field
|
|
86
102
|
v-else-if="field.type === 'address'"
|
|
@@ -88,10 +104,12 @@
|
|
|
88
104
|
readonly
|
|
89
105
|
:label="field.label"
|
|
90
106
|
:placeholder="field.placeholder || '请选择地址'"
|
|
107
|
+
:rules="field.rules || []"
|
|
91
108
|
:model-value="getAddressText(field)"
|
|
92
109
|
@click="openAddressPicker(field)"
|
|
93
110
|
/>
|
|
94
111
|
|
|
112
|
+
|
|
95
113
|
<!-- 自定义内容 -->
|
|
96
114
|
<slot v-else :field="field" :value="formData[field.field]" />
|
|
97
115
|
</template>
|
|
@@ -122,6 +140,7 @@
|
|
|
122
140
|
@confirm="onSelectConfirm"
|
|
123
141
|
@cancel="closeSelect"
|
|
124
142
|
/>
|
|
143
|
+
|
|
125
144
|
</van-popup>
|
|
126
145
|
|
|
127
146
|
<!-- 时间范围 -->
|
|
@@ -135,6 +154,33 @@
|
|
|
135
154
|
@cancel="closeDateRange"
|
|
136
155
|
/>
|
|
137
156
|
|
|
157
|
+
<!-- 日期时间范围选择器 -->
|
|
158
|
+
<van-popup v-model:show="dateTimeRangePopup.visible" position="bottom" round>
|
|
159
|
+
<div class="datetime-range-popup">
|
|
160
|
+
<div class="popup-header">
|
|
161
|
+
<span class="cancel-btn" @click="closeDateTimeRange">取消</span>
|
|
162
|
+
<span class="confirm-btn" @click="confirmDateTimeRange">确定</span>
|
|
163
|
+
</div>
|
|
164
|
+
<div class="time_title">开始时间</div>
|
|
165
|
+
<nut-date-picker
|
|
166
|
+
v-model="dateTimeRangePopup.startTime"
|
|
167
|
+
type="datetime"
|
|
168
|
+
:show-toolbar="false"
|
|
169
|
+
:filter="startTimeFilter"
|
|
170
|
+
@change="(e)=>onDateTimeChange(e,'startTime')"
|
|
171
|
+
/>
|
|
172
|
+
<div class="time_title">结束时间</div>
|
|
173
|
+
<nut-date-picker
|
|
174
|
+
v-model="dateTimeRangePopup.endTime"
|
|
175
|
+
type="datetime"
|
|
176
|
+
:show-toolbar="false"
|
|
177
|
+
:filter="endTimeFilter"
|
|
178
|
+
@change="(e)=>onDateTimeChange(e,'endTime')"
|
|
179
|
+
/>
|
|
180
|
+
</div>
|
|
181
|
+
</van-popup>
|
|
182
|
+
|
|
183
|
+
|
|
138
184
|
<!-- 地址 -->
|
|
139
185
|
<van-popup v-model:show="addressPopup.visible" position="bottom" round>
|
|
140
186
|
<van-area
|
|
@@ -149,6 +195,8 @@
|
|
|
149
195
|
<script setup>
|
|
150
196
|
import { computed, reactive, ref, watch } from 'vue'
|
|
151
197
|
import { areaList } from '@vant/area-data'
|
|
198
|
+
import { showNotify } from 'vant';
|
|
199
|
+
|
|
152
200
|
const props = defineProps({
|
|
153
201
|
schema: {
|
|
154
202
|
type: Array,
|
|
@@ -188,6 +236,16 @@ const dateRangePopup = ref({
|
|
|
188
236
|
minDate: null,
|
|
189
237
|
maxDate: null
|
|
190
238
|
})
|
|
239
|
+
// 日期时间范围弹窗状态
|
|
240
|
+
const dateTimeRangePopup = ref({
|
|
241
|
+
visible: false, // 弹窗显示状态
|
|
242
|
+
field: null, // 当前操作的字段
|
|
243
|
+
startTime: new Date(), // 开始时间
|
|
244
|
+
endTime: new Date(), // 结束时间
|
|
245
|
+
currentDate: new Date(), // 当前选中日期
|
|
246
|
+
currentHour: '8' // 当前选择的小时值,默认为'12'
|
|
247
|
+
})
|
|
248
|
+
|
|
191
249
|
|
|
192
250
|
const addressPopup = ref({
|
|
193
251
|
visible: false,
|
|
@@ -196,6 +254,9 @@ const addressPopup = ref({
|
|
|
196
254
|
columnsPlaceholder: null
|
|
197
255
|
})
|
|
198
256
|
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
|
|
199
260
|
const normalizedSchema = computed(() =>
|
|
200
261
|
props.schema.map((item) => ({
|
|
201
262
|
...item,
|
|
@@ -206,6 +267,7 @@ const normalizedSchema = computed(() =>
|
|
|
206
267
|
const getDefaultValue = (type) => {
|
|
207
268
|
if (type === 'checkbox') return []
|
|
208
269
|
if (type === 'dateRange') return ['', '']
|
|
270
|
+
if (type === 'datetimeRange') return ['', '']
|
|
209
271
|
if (type === 'address') return { province: '', city: '', county: '', code: '' }
|
|
210
272
|
return ''
|
|
211
273
|
}
|
|
@@ -303,6 +365,125 @@ const closeDateRange = () => {
|
|
|
303
365
|
dateRangePopup.value.visible = false
|
|
304
366
|
}
|
|
305
367
|
|
|
368
|
+
// 打开日期时间范围选择
|
|
369
|
+
const openDateTimeRange = (field) => {
|
|
370
|
+
dateTimeRangePopup.value.visible = true
|
|
371
|
+
dateTimeRangePopup.value.field = field
|
|
372
|
+
|
|
373
|
+
// 设置默认时间:开始时间为当天8:30,结束时间为当天17:30
|
|
374
|
+
const today = new Date()
|
|
375
|
+
const defaultStartTime = new Date(today)
|
|
376
|
+
defaultStartTime.setHours(8, 30, 0, 0)
|
|
377
|
+
const defaultEndTime = new Date(today)
|
|
378
|
+
defaultEndTime.setHours(17, 30, 0, 0)
|
|
379
|
+
|
|
380
|
+
// 将field的startTime和endTime转换为日期时间格式
|
|
381
|
+
dateTimeRangePopup.value.startTime = typeof field.startTime === 'string' ? reverseFormatDateTime(field.startTime) : defaultStartTime
|
|
382
|
+
dateTimeRangePopup.value.endTime = typeof field.endTime === 'string' ? reverseFormatDateTime(field.endTime) : defaultEndTime
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const closeDateTimeRange = () => {
|
|
386
|
+
dateTimeRangePopup.value.visible = false
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// 日期时间选择器改变事件处理
|
|
390
|
+
const onDateTimeChange = (params,type) => {
|
|
391
|
+
|
|
392
|
+
// 更新当前选择的小时值
|
|
393
|
+
if (params && params.selectedValue && params.columnIndex === 3) {
|
|
394
|
+
// 更新小时值
|
|
395
|
+
// 根据小时值设置默认分钟值
|
|
396
|
+
if (['08', '17'].includes(params.selectedValue[3])) {
|
|
397
|
+
// 小时为08或17时,分钟设为30
|
|
398
|
+
if(type === 'startTime'){
|
|
399
|
+
dateTimeRangePopup.value.startTime.setMinutes(30)
|
|
400
|
+
}else{
|
|
401
|
+
dateTimeRangePopup.value.endTime.setMinutes(30)
|
|
402
|
+
}
|
|
403
|
+
} else if (['12', '13'].includes(params.selectedValue[3])) {
|
|
404
|
+
// 小时为12或13时,分钟设为00
|
|
405
|
+
if(type === 'startTime'){
|
|
406
|
+
dateTimeRangePopup.value.startTime.setMinutes(0)
|
|
407
|
+
}else{
|
|
408
|
+
dateTimeRangePopup.value.endTime.setMinutes(0)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if(type === 'startTime'){
|
|
412
|
+
dateTimeRangePopup.value.currentStartHour = params.selectedValue[3];
|
|
413
|
+
}else{
|
|
414
|
+
dateTimeRangePopup.value.currentEndHour = params.selectedValue[3];
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// 确认日期时间范围选择
|
|
421
|
+
const confirmDateTimeRange = () => {
|
|
422
|
+
if(!dateTimeRangePopup.value.startTime || !dateTimeRangePopup.value.endTime){
|
|
423
|
+
return
|
|
424
|
+
}
|
|
425
|
+
if(dateTimeRangePopup.value.startTime.getTime()>=dateTimeRangePopup.value.endTime.getTime()){
|
|
426
|
+
showNotify({ type: 'warning', message: '结束时间必须晚于开始时间' });
|
|
427
|
+
return
|
|
428
|
+
}
|
|
429
|
+
console.log(dateTimeRangePopup.value.startTime.getTime()<dateTimeRangePopup.value.endTime.getTime())
|
|
430
|
+
// 格式化日期时间范围
|
|
431
|
+
const startDateStr = formatDateTime(dateTimeRangePopup.value.startTime)
|
|
432
|
+
const endDateStr = formatDateTime(dateTimeRangePopup.value.endTime)
|
|
433
|
+
console.log('开始时间:', startDateStr);
|
|
434
|
+
console.log('结束时间:', endDateStr);
|
|
435
|
+
// 更新表单数据
|
|
436
|
+
if (dateTimeRangePopup.value.field) {
|
|
437
|
+
updateFieldValue(dateTimeRangePopup.value.field.field, [startDateStr, endDateStr])
|
|
438
|
+
}
|
|
439
|
+
// 关闭弹窗
|
|
440
|
+
closeDateTimeRange()
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
// 日期时间选择器筛选函数
|
|
444
|
+
const startTimeFilter = (type, options) => {
|
|
445
|
+
if (type === 'hour') {
|
|
446
|
+
return options.filter(option => ['08', '12', '13', '17'].includes(option.value))
|
|
447
|
+
} else if (type === 'minute') {
|
|
448
|
+
// 当小时位是'08'或者'12'时,分钟只保留'00'
|
|
449
|
+
if (['12','13'].includes(dateTimeRangePopup.value.currentStartHour)) {
|
|
450
|
+
return options.filter(option => ['00'].includes(option.value))
|
|
451
|
+
}else{
|
|
452
|
+
return options.filter(option => ['30'].includes(option.value))
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
return options
|
|
456
|
+
}
|
|
457
|
+
const endTimeFilter = (type, options) => {
|
|
458
|
+
if (type === 'hour') {
|
|
459
|
+
return options.filter(option => ['08', '12', '13', '17'].includes(option.value))
|
|
460
|
+
} else if (type === 'minute') {
|
|
461
|
+
// 当小时位是'08'或者'12'时,分钟只保留'00'
|
|
462
|
+
if (['12','13'].includes(dateTimeRangePopup.value.currentEndHour)) {
|
|
463
|
+
return options.filter(option => ['00'].includes(option.value))
|
|
464
|
+
}else{
|
|
465
|
+
return options.filter(option => ['30'].includes(option.value))
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return options
|
|
469
|
+
}
|
|
470
|
+
// 格式化日期时间为字符串
|
|
471
|
+
var formatDateTime = (date) => {
|
|
472
|
+
const y = date.getFullYear()
|
|
473
|
+
const m = `${date.getMonth() + 1}`.padStart(2, '0')
|
|
474
|
+
const d = `${date.getDate()}`.padStart(2, '0')
|
|
475
|
+
const h = `${date.getHours()}`.padStart(2, '0')
|
|
476
|
+
const min = `${date.getMinutes()}`.padStart(2, '0')
|
|
477
|
+
return `${y}-${m}-${d} ${h}:${min}`
|
|
478
|
+
}
|
|
479
|
+
// 解析字符串为日期时间对象
|
|
480
|
+
var reverseFormatDateTime = (dateStr) => {
|
|
481
|
+
const [datePart, timePart] = dateStr.split(' ')
|
|
482
|
+
const [y, m, d] = datePart.split('-')
|
|
483
|
+
const [h, min] = timePart.split(':')
|
|
484
|
+
return new Date(`${y}-${m}-${d}T${h}:${min}`)
|
|
485
|
+
}
|
|
486
|
+
|
|
306
487
|
const formatDate = (date) => {
|
|
307
488
|
const y = date.getFullYear()
|
|
308
489
|
const m = `${date.getMonth() + 1}`.padStart(2, '0')
|
|
@@ -328,6 +509,17 @@ const getDateRangeText = (field) => {
|
|
|
328
509
|
return ''
|
|
329
510
|
}
|
|
330
511
|
|
|
512
|
+
const getDateTimeRangeText = (field) => {
|
|
513
|
+
const value = formData[field.field]
|
|
514
|
+
if (Array.isArray(value) && value[0] && value[1]) {
|
|
515
|
+
// 只显示日期部分用于预览
|
|
516
|
+
const startDate = value[0]
|
|
517
|
+
const endDate = value[1]
|
|
518
|
+
return `${startDate} ~ ${endDate}`
|
|
519
|
+
}
|
|
520
|
+
return ''
|
|
521
|
+
}
|
|
522
|
+
|
|
331
523
|
// Address
|
|
332
524
|
const openAddressPicker = (field) => {
|
|
333
525
|
addressPopup.value = {
|
|
@@ -363,8 +555,11 @@ const getAddressText = (field) => {
|
|
|
363
555
|
const value = formData[field.field]
|
|
364
556
|
if (!value) return ''
|
|
365
557
|
const parts = [value.province, value.city, value.county].filter(Boolean)
|
|
366
|
-
return parts.join('
|
|
558
|
+
return parts.join('')
|
|
367
559
|
}
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
|
|
368
563
|
</script>
|
|
369
564
|
|
|
370
565
|
<style scoped lang="scss">
|
|
@@ -392,6 +587,49 @@ const getAddressText = (field) => {
|
|
|
392
587
|
}
|
|
393
588
|
}
|
|
394
589
|
|
|
590
|
+
.datetime-range-popup {
|
|
591
|
+
.popup-header {
|
|
592
|
+
display: flex;
|
|
593
|
+
justify-content: space-between;
|
|
594
|
+
align-items: center;
|
|
595
|
+
padding: 16px;
|
|
596
|
+
border-bottom: 1px solid #f0f0f0;
|
|
597
|
+
|
|
598
|
+
.cancel-btn, .confirm-btn {
|
|
599
|
+
font-size: 16px;
|
|
600
|
+
padding: 4px 8px;
|
|
601
|
+
cursor: pointer;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
.cancel-btn {
|
|
605
|
+
color: #666;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
.confirm-btn {
|
|
609
|
+
color: #1989fa;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.title {
|
|
613
|
+
font-size: 16px;
|
|
614
|
+
font-weight: 500;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.datetime-content {
|
|
619
|
+
padding: 20px 16px;
|
|
620
|
+
|
|
621
|
+
:deep(.van-picker-column__item--selected) {
|
|
622
|
+
font-weight: 500;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.time_title {
|
|
627
|
+
font-size: 14px;
|
|
628
|
+
color: #666;
|
|
629
|
+
text-align: center;
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
395
633
|
:deep(.van-cell) {
|
|
396
634
|
padding: 8px;
|
|
397
635
|
}
|