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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vue_zhongyou",
3
- "version": "1.0.9",
3
+ "version": "1.0.10",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "keywords": [],
@@ -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
  }