@10yun/cv-mobile-ui 0.5.20 → 0.5.21

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.
Files changed (69) hide show
  1. package/package.json +1 -1
  2. package/ui-cv/components/cv-grid-item/cv-grid-item.vue +1 -1
  3. package/uni-ui/lib/uni-badge/uni-badge.vue +150 -1
  4. package/uni-ui/lib/uni-breadcrumb/uni-breadcrumb.vue +37 -1
  5. package/uni-ui/lib/uni-breadcrumb-item/uni-breadcrumb-item.vue +83 -1
  6. package/uni-ui/lib/uni-calendar/uni-calendar-item.vue +122 -1
  7. package/uni-ui/lib/uni-calendar/uni-calendar.vue +366 -1
  8. package/uni-ui/lib/uni-card/uni-card.vue +124 -1
  9. package/uni-ui/lib/uni-col/uni-col.vue +1 -1
  10. package/uni-ui/lib/uni-collapse/uni-collapse.vue +135 -1
  11. package/uni-ui/lib/uni-collapse-item/uni-collapse-item.vue +266 -1
  12. package/uni-ui/lib/uni-combox/uni-combox.vue +1 -1
  13. package/uni-ui/lib/uni-countdown/uni-countdown.vue +239 -1
  14. package/uni-ui/lib/uni-data-checkbox/uni-data-checkbox.vue +487 -1
  15. package/uni-ui/lib/uni-data-picker/uni-data-picker.vue +530 -1
  16. package/uni-ui/lib/uni-data-pickerview/uni-data-picker.js +157 -150
  17. package/uni-ui/lib/uni-data-pickerview/uni-data-pickerview.vue +166 -1
  18. package/uni-ui/lib/uni-data-select/uni-data-select.vue +289 -1
  19. package/uni-ui/lib/uni-datetime-picker/calendar-item.vue +70 -1
  20. package/uni-ui/lib/uni-datetime-picker/calendar.vue +629 -1
  21. package/uni-ui/lib/uni-datetime-picker/time-picker.vue +741 -1
  22. package/uni-ui/lib/uni-datetime-picker/uni-datetime-picker.vue +847 -1
  23. package/uni-ui/lib/uni-drawer/uni-drawer.vue +115 -1
  24. package/uni-ui/lib/uni-easyinput/uni-easyinput.vue +515 -1
  25. package/uni-ui/lib/uni-fab/uni-fab.vue +257 -1
  26. package/uni-ui/lib/uni-fav/uni-fav.vue +123 -1
  27. package/uni-ui/lib/uni-file-picker/uni-file-picker.vue +642 -1
  28. package/uni-ui/lib/uni-file-picker/upload-file.vue +177 -1
  29. package/uni-ui/lib/uni-file-picker/upload-image.vue +176 -1
  30. package/uni-ui/lib/uni-forms/uni-forms.vue +375 -1
  31. package/uni-ui/lib/uni-forms-item/uni-forms-item.vue +429 -1
  32. package/uni-ui/lib/uni-goods-nav/uni-goods-nav.vue +129 -1
  33. package/uni-ui/lib/uni-grid/uni-grid.vue +115 -1
  34. package/uni-ui/lib/uni-grid-item/uni-grid-item.vue +78 -1
  35. package/uni-ui/lib/uni-group/uni-group.vue +85 -1
  36. package/uni-ui/lib/uni-icons/uni-icons.vue +85 -1
  37. package/uni-ui/lib/uni-indexed-list/uni-indexed-list-item.vue +68 -1
  38. package/uni-ui/lib/uni-indexed-list/uni-indexed-list.vue +294 -1
  39. package/uni-ui/lib/uni-list/uni-list.vue +81 -1
  40. package/uni-ui/lib/uni-list-ad/uni-list-ad.vue +77 -1
  41. package/uni-ui/lib/uni-list-chat/uni-list-chat.vue +294 -1
  42. package/uni-ui/lib/uni-list-item/uni-list-item.vue +346 -1
  43. package/uni-ui/lib/uni-load-more/uni-load-more.vue +172 -1
  44. package/uni-ui/lib/uni-nav-bar/uni-nav-bar.vue +205 -1
  45. package/uni-ui/lib/uni-nav-bar/uni-status-bar.vue +18 -1
  46. package/uni-ui/lib/uni-notice-bar/uni-notice-bar.vue +331 -1
  47. package/uni-ui/lib/uni-number-box/uni-number-box.vue +166 -1
  48. package/uni-ui/lib/uni-pagination/uni-pagination.vue +323 -1
  49. package/uni-ui/lib/uni-popup/uni-popup.vue +1 -1
  50. package/uni-ui/lib/uni-popup-dialog/uni-popup-dialog.vue +173 -1
  51. package/uni-ui/lib/uni-popup-message/uni-popup-message.vue +74 -1
  52. package/uni-ui/lib/uni-popup-share/uni-popup-share.vue +106 -1
  53. package/uni-ui/lib/uni-rate/uni-rate.vue +322 -1
  54. package/uni-ui/lib/uni-row/uni-row.vue +1 -1
  55. package/uni-ui/lib/uni-search-bar/uni-search-bar.vue +236 -1
  56. package/uni-ui/lib/uni-section/uni-section.vue +109 -1
  57. package/uni-ui/lib/uni-segmented-control/uni-segmented-control.vue +103 -1
  58. package/uni-ui/lib/uni-status-bar/uni-status-bar.vue +1 -1
  59. package/uni-ui/lib/uni-steps/uni-steps.vue +120 -1
  60. package/uni-ui/lib/uni-swipe-action-item/uni-swipe-action-item.vue +226 -3
  61. package/uni-ui/lib/uni-swiper-dot/uni-swiper-dot.vue +167 -1
  62. package/uni-ui/lib/uni-table/uni-table.vue +297 -1
  63. package/uni-ui/lib/uni-tag/uni-tag.vue +100 -1
  64. package/uni-ui/lib/uni-td/uni-td.vue +78 -1
  65. package/uni-ui/lib/uni-th/filter-dropdown.vue +1 -1
  66. package/uni-ui/lib/uni-th/uni-th.vue +224 -1
  67. package/uni-ui/lib/uni-thead/uni-thead.vue +77 -1
  68. package/uni-ui/lib/uni-tr/table-checkbox.vue +79 -1
  69. package/uni-ui/lib/uni-tr/uni-tr.vue +135 -1
@@ -1 +1,741 @@
1
- <template>
2
1
  <view class="uni-datetime-picker">
3
2
  <view @click="initTimePicker">
4
3
  <slot>
5
4
  <view
6
5
  class="uni-datetime-picker-timebox-pointer"
7
6
  :class="{ 'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border }"
8
7
  >
9
8
  <text class="uni-datetime-picker-text">{{ time }}</text>
10
9
  <view v-if="!time" class="uni-datetime-picker-time">
11
10
  <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
12
11
  </view>
13
12
  </view>
14
13
  </slot>
15
14
  </view>
16
15
  <view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
17
16
  <view
18
17
  v-if="visible"
19
18
  class="uni-datetime-picker-popup"
20
19
  :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
21
20
  :style="fixNvueBug"
22
21
  >
23
22
  <view class="uni-title">
24
23
  <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
25
24
  </view>
26
25
  <view v-if="dateShow" class="uni-datetime-picker__container-box">
27
26
  <picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd" @change="bindDateChange">
28
27
  <picker-view-column>
29
28
  <view class="uni-datetime-picker-item" v-for="(item, index) in years" :key="index">
30
29
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
31
30
  </view>
32
31
  </picker-view-column>
33
32
  <picker-view-column>
34
33
  <view class="uni-datetime-picker-item" v-for="(item, index) in months" :key="index">
35
34
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
36
35
  </view>
37
36
  </picker-view-column>
38
37
  <picker-view-column>
39
38
  <view class="uni-datetime-picker-item" v-for="(item, index) in days" :key="index">
40
39
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
41
40
  </view>
42
41
  </picker-view-column>
43
42
  </picker-view>
44
43
  <!-- 兼容 nvue 不支持伪类 -->
45
44
  <text class="uni-datetime-picker-sign sign-left">-</text>
46
45
  <text class="uni-datetime-picker-sign sign-right">-</text>
47
46
  </view>
48
47
  <view v-if="timeShow" class="uni-datetime-picker__container-box">
49
48
  <picker-view
50
49
  class="uni-datetime-picker-view"
51
50
  :class="[hideSecond ? 'time-hide-second' : '']"
52
51
  :indicator-style="indicatorStyle"
53
52
  :value="hms"
54
53
  @change="bindTimeChange"
55
54
  >
56
55
  <picker-view-column>
57
56
  <view class="uni-datetime-picker-item" v-for="(item, index) in hours" :key="index">
58
57
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
59
58
  </view>
60
59
  </picker-view-column>
61
60
  <picker-view-column>
62
61
  <view class="uni-datetime-picker-item" v-for="(item, index) in minutes" :key="index">
63
62
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
64
63
  </view>
65
64
  </picker-view-column>
66
65
  <picker-view-column v-if="!hideSecond">
67
66
  <view class="uni-datetime-picker-item" v-for="(item, index) in seconds" :key="index">
68
67
  <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
69
68
  </view>
70
69
  </picker-view-column>
71
70
  </picker-view>
72
71
  <!-- 兼容 nvue 不支持伪类 -->
73
72
  <text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
74
73
  <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
75
74
  </view>
76
75
  <view class="uni-datetime-picker-btn">
77
76
  <view @click="clearTime">
78
77
  <text class="uni-datetime-picker-btn-text">{{ clearText }}</text>
79
78
  </view>
80
79
  <view class="uni-datetime-picker-btn-group">
81
80
  <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
82
81
  <text class="uni-datetime-picker-btn-text">{{ cancelText }}</text>
83
82
  </view>
84
83
  <view @click="setTime">
85
84
  <text class="uni-datetime-picker-btn-text">{{ okText }}</text>
86
85
  </view>
87
86
  </view>
88
87
  </view>
89
88
  </view>
90
89
  </view>
91
90
  * DatetimePicker 时间选择器
92
91
  * @description 可以同时选择日期和时间的选择器
93
92
  * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
94
93
  * @property {String} type = [datetime | date | time] 显示模式
95
94
  * @property {Boolean} multiple = [true|false] 是否多选
96
95
  * @property {String|Number} value 默认值
97
96
  * @property {String|Number} start 起始日期或时间
98
97
  * @property {String|Number} end 起始日期或时间
99
98
  * @property {String} return-type = [timestamp | string]
100
99
  * @event {Function} change 选中发生变化触发
101
100
  */
102
101
  name: 'UniDatetimePicker',
103
102
  data() {
104
103
  return {
105
104
  indicatorStyle: `height: 50px;`,
106
105
  visible: false,
107
106
  fixNvueBug: {},
108
107
  dateShow: true,
109
108
  timeShow: true,
110
109
  title: '日期和时间',
111
110
  // 输入框当前时间
112
111
  time: '',
113
112
  // 当前的年月日时分秒
114
113
  year: 1920,
115
114
  month: 0,
116
115
  day: 0,
117
116
  hour: 0,
118
117
  minute: 0,
119
118
  second: 0,
120
119
  // 起始时间
121
120
  startYear: 1920,
122
121
  startMonth: 1,
123
122
  startDay: 1,
124
123
  startHour: 0,
125
124
  startMinute: 0,
126
125
  startSecond: 0,
127
126
  // 结束时间
128
127
  endYear: 2120,
129
128
  endMonth: 12,
130
129
  endDay: 31,
131
130
  endHour: 23,
132
131
  endMinute: 59,
133
132
  endSecond: 59
134
133
  };
135
134
  },
136
135
  props: {
137
136
  type: {
138
137
  type: String,
139
138
  default: 'datetime'
140
139
  },
141
140
  value: {
142
141
  type: [String, Number],
143
142
  default: ''
144
143
  },
145
144
  modelValue: {
146
145
  type: [String, Number],
147
146
  default: ''
148
147
  },
149
148
  start: {
150
149
  type: [Number, String],
151
150
  default: ''
152
151
  },
153
152
  end: {
154
153
  type: [Number, String],
155
154
  default: ''
156
155
  },
157
156
  returnType: {
158
157
  type: String,
159
158
  default: 'string'
160
159
  },
161
160
  disabled: {
162
161
  type: [Boolean, String],
163
162
  default: false
164
163
  },
165
164
  border: {
166
165
  type: [Boolean, String],
167
166
  default: true
168
167
  },
169
168
  hideSecond: {
170
169
  type: [Boolean, String],
171
170
  default: false
172
171
  }
173
172
  },
174
173
  watch: {
175
174
  // #ifndef VUE3
176
175
  value: {
177
176
  handler(newVal) {
178
177
  if (newVal) {
179
178
  this.parseValue(fixIosDateFormat(newVal));
180
179
  this.initTime(false);
181
180
  } else {
182
181
  this.time = '';
183
182
  this.parseValue(Date.now());
184
183
  }
185
184
  },
186
185
  immediate: true
187
186
  },
188
187
  // #endif
189
188
  // #ifdef VUE3
190
189
  modelValue: {
191
190
  handler(newVal) {
192
191
  if (newVal) {
193
192
  this.parseValue(fixIosDateFormat(newVal));
194
193
  this.initTime(false);
195
194
  } else {
196
195
  this.time = '';
197
196
  this.parseValue(Date.now());
198
197
  }
199
198
  },
200
199
  immediate: true
201
200
  },
202
201
  // #endif
203
202
  type: {
204
203
  handler(newValue) {
205
204
  if (newValue === 'date') {
206
205
  this.dateShow = true;
207
206
  this.timeShow = false;
208
207
  this.title = '日期';
209
208
  } else if (newValue === 'time') {
210
209
  this.dateShow = false;
211
210
  this.timeShow = true;
212
211
  this.title = '时间';
213
212
  } else {
214
213
  this.dateShow = true;
215
214
  this.timeShow = true;
216
215
  this.title = '日期和时间';
217
216
  }
218
217
  },
219
218
  immediate: true
220
219
  },
221
220
  start: {
222
221
  handler(newVal) {
223
222
  this.parseDatetimeRange(fixIosDateFormat(newVal), 'start');
224
223
  },
225
224
  immediate: true
226
225
  },
227
226
  end: {
228
227
  handler(newVal) {
229
228
  this.parseDatetimeRange(fixIosDateFormat(newVal), 'end');
230
229
  },
231
230
  immediate: true
232
231
  },
233
232
  // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
234
233
  months(newVal) {
235
234
  this.checkValue('month', this.month, newVal);
236
235
  },
237
236
  days(newVal) {
238
237
  this.checkValue('day', this.day, newVal);
239
238
  },
240
239
  hours(newVal) {
241
240
  this.checkValue('hour', this.hour, newVal);
242
241
  },
243
242
  minutes(newVal) {
244
243
  this.checkValue('minute', this.minute, newVal);
245
244
  },
246
245
  seconds(newVal) {
247
246
  this.checkValue('second', this.second, newVal);
248
247
  }
249
248
  },
250
249
  computed: {
251
250
  // 当前年、月、日、时、分、秒选择范围
252
251
  years() {
253
252
  return this.getCurrentRange('year');
254
253
  },
255
254
  months() {
256
255
  return this.getCurrentRange('month');
257
256
  },
258
257
  days() {
259
258
  return this.getCurrentRange('day');
260
259
  },
261
260
  hours() {
262
261
  return this.getCurrentRange('hour');
263
262
  },
264
263
  minutes() {
265
264
  return this.getCurrentRange('minute');
266
265
  },
267
266
  seconds() {
268
267
  return this.getCurrentRange('second');
269
268
  },
270
269
  // picker 当前值数组
271
270
  ymd() {
272
271
  return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay];
273
272
  },
274
273
  hms() {
275
274
  return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond];
276
275
  },
277
276
  // 当前 date 是 start
278
277
  currentDateIsStart() {
279
278
  return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay;
280
279
  },
281
280
  // 当前 date 是 end
282
281
  currentDateIsEnd() {
283
282
  return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay;
284
283
  },
285
284
  // 当前年、月、日、时、分、秒的最小值和最大值
286
285
  minYear() {
287
286
  return this.startYear;
288
287
  },
289
288
  maxYear() {
290
289
  return this.endYear;
291
290
  },
292
291
  minMonth() {
293
292
  if (this.year === this.startYear) {
294
293
  return this.startMonth;
295
294
  } else {
296
295
  return 1;
297
296
  }
298
297
  },
299
298
  maxMonth() {
300
299
  if (this.year === this.endYear) {
301
300
  return this.endMonth;
302
301
  } else {
303
302
  return 12;
304
303
  }
305
304
  },
306
305
  minDay() {
307
306
  if (this.year === this.startYear && this.month === this.startMonth) {
308
307
  return this.startDay;
309
308
  } else {
310
309
  return 1;
311
310
  }
312
311
  },
313
312
  maxDay() {
314
313
  if (this.year === this.endYear && this.month === this.endMonth) {
315
314
  return this.endDay;
316
315
  } else {
317
316
  return this.daysInMonth(this.year, this.month);
318
317
  }
319
318
  },
320
319
  minHour() {
321
320
  if (this.type === 'datetime') {
322
321
  if (this.currentDateIsStart) {
323
322
  return this.startHour;
324
323
  } else {
325
324
  return 0;
326
325
  }
327
326
  }
328
327
  if (this.type === 'time') {
329
328
  return this.startHour;
330
329
  }
331
330
  },
332
331
  maxHour() {
333
332
  if (this.type === 'datetime') {
334
333
  if (this.currentDateIsEnd) {
335
334
  return this.endHour;
336
335
  } else {
337
336
  return 23;
338
337
  }
339
338
  }
340
339
  if (this.type === 'time') {
341
340
  return this.endHour;
342
341
  }
343
342
  },
344
343
  minMinute() {
345
344
  if (this.type === 'datetime') {
346
345
  if (this.currentDateIsStart && this.hour === this.startHour) {
347
346
  return this.startMinute;
348
347
  } else {
349
348
  return 0;
350
349
  }
351
350
  }
352
351
  if (this.type === 'time') {
353
352
  if (this.hour === this.startHour) {
354
353
  return this.startMinute;
355
354
  } else {
356
355
  return 0;
357
356
  }
358
357
  }
359
358
  },
360
359
  maxMinute() {
361
360
  if (this.type === 'datetime') {
362
361
  if (this.currentDateIsEnd && this.hour === this.endHour) {
363
362
  return this.endMinute;
364
363
  } else {
365
364
  return 59;
366
365
  }
367
366
  }
368
367
  if (this.type === 'time') {
369
368
  if (this.hour === this.endHour) {
370
369
  return this.endMinute;
371
370
  } else {
372
371
  return 59;
373
372
  }
374
373
  }
375
374
  },
376
375
  minSecond() {
377
376
  if (this.type === 'datetime') {
378
377
  if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
379
378
  return this.startSecond;
380
379
  } else {
381
380
  return 0;
382
381
  }
383
382
  }
384
383
  if (this.type === 'time') {
385
384
  if (this.hour === this.startHour && this.minute === this.startMinute) {
386
385
  return this.startSecond;
387
386
  } else {
388
387
  return 0;
389
388
  }
390
389
  }
391
390
  },
392
391
  maxSecond() {
393
392
  if (this.type === 'datetime') {
394
393
  if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
395
394
  return this.endSecond;
396
395
  } else {
397
396
  return 59;
398
397
  }
399
398
  }
400
399
  if (this.type === 'time') {
401
400
  if (this.hour === this.endHour && this.minute === this.endMinute) {
402
401
  return this.endSecond;
403
402
  } else {
404
403
  return 59;
405
404
  }
406
405
  }
407
406
  },
408
407
  /**
409
408
  * for i18n
410
409
  */
411
410
  selectTimeText() {
412
411
  return t('uni-datetime-picker.selectTime');
413
412
  },
414
413
  okText() {
415
414
  return t('uni-datetime-picker.ok');
416
415
  },
417
416
  clearText() {
418
417
  return t('uni-datetime-picker.clear');
419
418
  },
420
419
  cancelText() {
421
420
  return t('uni-datetime-picker.cancel');
422
421
  }
423
422
  },
424
423
  mounted() {
425
424
  // #ifdef APP-NVUE
426
425
  const res = uni.getSystemInfoSync();
427
426
  this.fixNvueBug = {
428
427
  top: res.windowHeight / 2,
429
428
  left: res.windowWidth / 2
430
429
  };
431
430
  // #endif
432
431
  },
433
432
  methods: {
434
433
  /**
435
434
  * @param {Object} item
436
435
  * 小于 10 在前面加个 0
437
436
  */
438
437
  lessThanTen(item) {
439
438
  return item < 10 ? '0' + item : item;
440
439
  },
441
440
  /**
442
441
  * 解析时分秒字符串,例如:00:00:00
443
442
  * @param {String} timeString
444
443
  */
445
444
  parseTimeType(timeString) {
446
445
  if (timeString) {
447
446
  let timeArr = timeString.split(':');
448
447
  this.hour = Number(timeArr[0]);
449
448
  this.minute = Number(timeArr[1]);
450
449
  this.second = Number(timeArr[2]);
451
450
  }
452
451
  },
453
452
  /**
454
453
  * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
455
454
  * @param {String | Number} datetime
456
455
  */
457
456
  initPickerValue(datetime) {
458
457
  let defaultValue = null;
459
458
  if (datetime) {
460
459
  defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end);
461
460
  } else {
462
461
  defaultValue = Date.now();
463
462
  defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end);
464
463
  }
465
464
  this.parseValue(defaultValue);
466
465
  },
467
466
  /**
468
467
  * 初始值规则:
469
468
  * - 用户设置初始值 value
470
469
  * - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
471
470
  * - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
472
471
  * - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
473
472
  * - 无起始终止时间,则初始值为 value
474
473
  * - 无初始值 value,则初始值为当前本地时间 Date.now()
475
474
  * @param {Object} value
476
475
  * @param {Object} dateBase
477
476
  */
478
477
  compareValueWithStartAndEnd(value, start, end) {
479
478
  let winner = null;
480
479
  value = this.superTimeStamp(value);
481
480
  start = this.superTimeStamp(start);
482
481
  end = this.superTimeStamp(end);
483
482
  if (start && end) {
484
483
  if (value < start) {
485
484
  winner = new Date(start);
486
485
  } else if (value > end) {
487
486
  winner = new Date(end);
488
487
  } else {
489
488
  winner = new Date(value);
490
489
  }
491
490
  } else if (start && !end) {
492
491
  winner = start <= value ? new Date(value) : new Date(start);
493
492
  } else if (!start && end) {
494
493
  winner = value <= end ? new Date(value) : new Date(end);
495
494
  } else {
496
495
  winner = new Date(value);
497
496
  }
498
497
  return winner;
499
498
  },
500
499
  /**
501
500
  * 转换为可比较的时间戳,接受日期、时分秒、时间戳
502
501
  * @param {Object} value
503
502
  */
504
503
  superTimeStamp(value) {
505
504
  let dateBase = '';
506
505
  if (this.type === 'time' && value && typeof value === 'string') {
507
506
  const now = new Date();
508
507
  const year = now.getFullYear();
509
508
  const month = now.getMonth() + 1;
510
509
  const day = now.getDate();
511
510
  dateBase = year + '/' + month + '/' + day + ' ';
512
511
  }
513
512
  if (Number(value)) {
514
513
  value = parseInt(value);
515
514
  dateBase = 0;
516
515
  }
517
516
  return this.createTimeStamp(dateBase + value);
518
517
  },
519
518
  /**
520
519
  * 解析默认值 value,字符串、时间戳
521
520
  * @param {Object} defaultTime
522
521
  */
523
522
  parseValue(value) {
524
523
  if (!value) {
525
524
  return;
526
525
  }
527
526
  if (this.type === 'time' && typeof value === 'string') {
528
527
  this.parseTimeType(value);
529
528
  } else {
530
529
  let defaultDate = null;
531
530
  defaultDate = new Date(value);
532
531
  if (this.type !== 'time') {
533
532
  this.year = defaultDate.getFullYear();
534
533
  this.month = defaultDate.getMonth() + 1;
535
534
  this.day = defaultDate.getDate();
536
535
  }
537
536
  if (this.type !== 'date') {
538
537
  this.hour = defaultDate.getHours();
539
538
  this.minute = defaultDate.getMinutes();
540
539
  this.second = defaultDate.getSeconds();
541
540
  }
542
541
  }
543
542
  if (this.hideSecond) {
544
543
  this.second = 0;
545
544
  }
546
545
  },
547
546
  /**
548
547
  * 解析可选择时间范围 start、end,年月日字符串、时间戳
549
548
  * @param {Object} defaultTime
550
549
  */
551
550
  parseDatetimeRange(point, pointType) {
552
551
  // 时间为空,则重置为初始值
553
552
  if (!point) {
554
553
  if (pointType === 'start') {
555
554
  this.startYear = 1920;
556
555
  this.startMonth = 1;
557
556
  this.startDay = 1;
558
557
  this.startHour = 0;
559
558
  this.startMinute = 0;
560
559
  this.startSecond = 0;
561
560
  }
562
561
  if (pointType === 'end') {
563
562
  this.endYear = 2120;
564
563
  this.endMonth = 12;
565
564
  this.endDay = 31;
566
565
  this.endHour = 23;
567
566
  this.endMinute = 59;
568
567
  this.endSecond = 59;
569
568
  }
570
569
  return;
571
570
  }
572
571
  if (this.type === 'time') {
573
572
  const pointArr = point.split(':');
574
573
  this[pointType + 'Hour'] = Number(pointArr[0]);
575
574
  this[pointType + 'Minute'] = Number(pointArr[1]);
576
575
  this[pointType + 'Second'] = Number(pointArr[2]);
577
576
  } else {
578
577
  if (!point) {
579
578
  pointType === 'start' ? (this.startYear = this.year - 60) : (this.endYear = this.year + 60);
580
579
  return;
581
580
  }
582
581
  if (Number(point)) {
583
582
  point = parseInt(point);
584
583
  }
585
584
  // datetime 的 end 没有时分秒, 则不限制
586
585
  const hasTime = /[0-9]:[0-9]/;
587
586
  if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(point)) {
588
587
  point = point + ' 23:59:59';
589
588
  }
590
589
  const pointDate = new Date(point);
591
590
  this[pointType + 'Year'] = pointDate.getFullYear();
592
591
  this[pointType + 'Month'] = pointDate.getMonth() + 1;
593
592
  this[pointType + 'Day'] = pointDate.getDate();
594
593
  if (this.type === 'datetime') {
595
594
  this[pointType + 'Hour'] = pointDate.getHours();
596
595
  this[pointType + 'Minute'] = pointDate.getMinutes();
597
596
  this[pointType + 'Second'] = pointDate.getSeconds();
598
597
  }
599
598
  }
600
599
  },
601
600
  // 获取 年、月、日、时、分、秒 当前可选范围
602
601
  getCurrentRange(value) {
603
602
  const range = [];
604
603
  for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
605
604
  range.push(i);
606
605
  }
607
606
  return range;
608
607
  },
609
608
  // 字符串首字母大写
610
609
  capitalize(str) {
611
610
  return str.charAt(0).toUpperCase() + str.slice(1);
612
611
  },
613
612
  // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
614
613
  checkValue(name, value, values) {
615
614
  if (values.indexOf(value) === -1) {
616
615
  this[name] = values[0];
617
616
  }
618
617
  },
619
618
  // 每个月的实际天数
620
619
  daysInMonth(year, month) {
621
620
  // Use 1 for January, 2 for February, etc.
622
621
  return new Date(year, month, 0).getDate();
623
622
  },
624
623
  //兼容 iOS、safari 日期格式
625
624
  fixIosDateFormat(value) {
626
625
  if (typeof value === 'string') {
627
626
  value = value.replace(/-/g, '/');
628
627
  }
629
628
  return value;
630
629
  },
631
630
  /**
632
631
  * 生成时间戳
633
632
  * @param {Object} time
634
633
  */
635
634
  createTimeStamp(time) {
636
635
  if (!time) return;
637
636
  if (typeof time === 'number') {
638
637
  return time;
639
638
  } else {
640
639
  time = time.replace(/-/g, '/');
641
640
  if (this.type === 'date') {
642
641
  time = time + ' ' + '00:00:00';
643
642
  }
644
643
  return Date.parse(time);
645
644
  }
646
645
  },
647
646
  /**
648
647
  * 生成日期或时间的字符串
649
648
  */
650
649
  createDomSting() {
651
650
  const yymmdd = this.year + '-' + this.lessThanTen(this.month) + '-' + this.lessThanTen(this.day);
652
651
  let hhmmss = this.lessThanTen(this.hour) + ':' + this.lessThanTen(this.minute);
653
652
  if (!this.hideSecond) {
654
653
  hhmmss = hhmmss + ':' + this.lessThanTen(this.second);
655
654
  }
656
655
  if (this.type === 'date') {
657
656
  return yymmdd;
658
657
  } else if (this.type === 'time') {
659
658
  return hhmmss;
660
659
  } else {
661
660
  return yymmdd + ' ' + hhmmss;
662
661
  }
663
662
  },
664
663
  /**
665
664
  * 初始化返回值,并抛出 change 事件
666
665
  */
667
666
  initTime(emit = true) {
668
667
  this.time = this.createDomSting();
669
668
  if (!emit) return;
670
669
  if (this.returnType === 'timestamp' && this.type !== 'time') {
671
670
  this.$emit('change', this.createTimeStamp(this.time));
672
671
  this.$emit('input', this.createTimeStamp(this.time));
673
672
  this.$emit('update:modelValue', this.createTimeStamp(this.time));
674
673
  } else {
675
674
  this.$emit('change', this.time);
676
675
  this.$emit('input', this.time);
677
676
  this.$emit('update:modelValue', this.time);
678
677
  }
679
678
  },
680
679
  /**
681
680
  * 用户选择日期或时间更新 data
682
681
  * @param {Object} e
683
682
  */
684
683
  bindDateChange(e) {
685
684
  const val = e.detail.value;
686
685
  this.year = this.years[val[0]];
687
686
  this.month = this.months[val[1]];
688
687
  this.day = this.days[val[2]];
689
688
  },
690
689
  bindTimeChange(e) {
691
690
  const val = e.detail.value;
692
691
  this.hour = this.hours[val[0]];
693
692
  this.minute = this.minutes[val[1]];
694
693
  this.second = this.seconds[val[2]];
695
694
  },
696
695
  /**
697
696
  * 初始化弹出层
698
697
  */
699
698
  initTimePicker() {
700
699
  if (this.disabled) return;
701
700
  const value = fixIosDateFormat(this.time);
702
701
  this.initPickerValue(value);
703
702
  this.visible = !this.visible;
704
703
  },
705
704
  /**
706
705
  * 触发或关闭弹框
707
706
  */
708
707
  tiggerTimePicker(e) {
709
708
  this.visible = !this.visible;
710
709
  },
711
710
  /**
712
711
  * 用户点击“清空”按钮,清空当前值
713
712
  */
714
713
  clearTime() {
715
714
  this.time = '';
716
715
  this.$emit('change', this.time);
717
716
  this.$emit('input', this.time);
718
717
  this.$emit('update:modelValue', this.time);
719
718
  this.tiggerTimePicker();
720
719
  },
721
720
  /**
722
721
  * 用户点击“确定”按钮
723
722
  */
724
723
  setTime() {
725
724
  this.initTime();
726
725
  this.tiggerTimePicker();
727
726
  }
728
727
  }
728
+ <template>
729
+ <view class="uni-datetime-picker">
730
+ <view @click="initTimePicker">
731
+ <slot>
732
+ <view
733
+ class="uni-datetime-picker-timebox-pointer"
734
+ :class="{ 'uni-datetime-picker-disabled': disabled, 'uni-datetime-picker-timebox': border }"
735
+ >
736
+ <text class="uni-datetime-picker-text">{{ time }}</text>
737
+ <view v-if="!time" class="uni-datetime-picker-time">
738
+ <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
739
+ </view>
740
+ </view>
741
+ </slot>
742
+ </view>
743
+ <view v-if="visible" id="mask" class="uni-datetime-picker-mask" @click="tiggerTimePicker"></view>
744
+ <view
745
+ v-if="visible"
746
+ class="uni-datetime-picker-popup"
747
+ :class="[dateShow && timeShow ? '' : 'fix-nvue-height']"
748
+ :style="fixNvueBug"
749
+ >
750
+ <view class="uni-title">
751
+ <text class="uni-datetime-picker-text">{{ selectTimeText }}</text>
752
+ </view>
753
+ <view v-if="dateShow" class="uni-datetime-picker__container-box">
754
+ <picker-view class="uni-datetime-picker-view" :indicator-style="indicatorStyle" :value="ymd" @change="bindDateChange">
755
+ <picker-view-column>
756
+ <view class="uni-datetime-picker-item" v-for="(item, index) in years" :key="index">
757
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
758
+ </view>
759
+ </picker-view-column>
760
+ <picker-view-column>
761
+ <view class="uni-datetime-picker-item" v-for="(item, index) in months" :key="index">
762
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
763
+ </view>
764
+ </picker-view-column>
765
+ <picker-view-column>
766
+ <view class="uni-datetime-picker-item" v-for="(item, index) in days" :key="index">
767
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
768
+ </view>
769
+ </picker-view-column>
770
+ </picker-view>
771
+ <!-- 兼容 nvue 不支持伪类 -->
772
+ <text class="uni-datetime-picker-sign sign-left">-</text>
773
+ <text class="uni-datetime-picker-sign sign-right">-</text>
774
+ </view>
775
+ <view v-if="timeShow" class="uni-datetime-picker__container-box">
776
+ <picker-view
777
+ class="uni-datetime-picker-view"
778
+ :class="[hideSecond ? 'time-hide-second' : '']"
779
+ :indicator-style="indicatorStyle"
780
+ :value="hms"
781
+ @change="bindTimeChange"
782
+ >
783
+ <picker-view-column>
784
+ <view class="uni-datetime-picker-item" v-for="(item, index) in hours" :key="index">
785
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
786
+ </view>
787
+ </picker-view-column>
788
+ <picker-view-column>
789
+ <view class="uni-datetime-picker-item" v-for="(item, index) in minutes" :key="index">
790
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
791
+ </view>
792
+ </picker-view-column>
793
+ <picker-view-column v-if="!hideSecond">
794
+ <view class="uni-datetime-picker-item" v-for="(item, index) in seconds" :key="index">
795
+ <text class="uni-datetime-picker-item">{{ lessThanTen(item) }}</text>
796
+ </view>
797
+ </picker-view-column>
798
+ </picker-view>
799
+ <!-- 兼容 nvue 不支持伪类 -->
800
+ <text class="uni-datetime-picker-sign" :class="[hideSecond ? 'sign-center' : 'sign-left']">:</text>
801
+ <text v-if="!hideSecond" class="uni-datetime-picker-sign sign-right">:</text>
802
+ </view>
803
+ <view class="uni-datetime-picker-btn">
804
+ <view @click="clearTime">
805
+ <text class="uni-datetime-picker-btn-text">{{ clearText }}</text>
806
+ </view>
807
+ <view class="uni-datetime-picker-btn-group">
808
+ <view class="uni-datetime-picker-cancel" @click="tiggerTimePicker">
809
+ <text class="uni-datetime-picker-btn-text">{{ cancelText }}</text>
810
+ </view>
811
+ <view @click="setTime">
812
+ <text class="uni-datetime-picker-btn-text">{{ okText }}</text>
813
+ </view>
814
+ </view>
815
+ </view>
816
+ </view>
817
+ </view>
818
+ </template>
819
+ <script>
820
+ import { initVueI18n } from '@dcloudio/uni-i18n';
821
+ import i18nMessages from './i18n/index.js';
822
+ const { t } = initVueI18n(i18nMessages);
823
+ import { fixIosDateFormat } from './util';
824
+ /**
825
+ * DatetimePicker 时间选择器
826
+ * @description 可以同时选择日期和时间的选择器
827
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=xxx
828
+ * @property {String} type = [datetime | date | time] 显示模式
829
+ * @property {Boolean} multiple = [true|false] 是否多选
830
+ * @property {String|Number} value 默认值
831
+ * @property {String|Number} start 起始日期或时间
832
+ * @property {String|Number} end 起始日期或时间
833
+ * @property {String} return-type = [timestamp | string]
834
+ * @event {Function} change 选中发生变化触发
835
+ */
836
+ export default {
837
+ name: 'UniDatetimePicker',
838
+ data() {
839
+ return {
840
+ indicatorStyle: `height: 50px;`,
841
+ visible: false,
842
+ fixNvueBug: {},
843
+ dateShow: true,
844
+ timeShow: true,
845
+ title: '日期和时间',
846
+ // 输入框当前时间
847
+ time: '',
848
+ // 当前的年月日时分秒
849
+ year: 1920,
850
+ month: 0,
851
+ day: 0,
852
+ hour: 0,
853
+ minute: 0,
854
+ second: 0,
855
+ // 起始时间
856
+ startYear: 1920,
857
+ startMonth: 1,
858
+ startDay: 1,
859
+ startHour: 0,
860
+ startMinute: 0,
861
+ startSecond: 0,
862
+ // 结束时间
863
+ endYear: 2120,
864
+ endMonth: 12,
865
+ endDay: 31,
866
+ endHour: 23,
867
+ endMinute: 59,
868
+ endSecond: 59
869
+ };
870
+ },
871
+ props: {
872
+ type: {
873
+ type: String,
874
+ default: 'datetime'
875
+ },
876
+ value: {
877
+ type: [String, Number],
878
+ default: ''
879
+ },
880
+ modelValue: {
881
+ type: [String, Number],
882
+ default: ''
883
+ },
884
+ start: {
885
+ type: [Number, String],
886
+ default: ''
887
+ },
888
+ end: {
889
+ type: [Number, String],
890
+ default: ''
891
+ },
892
+ returnType: {
893
+ type: String,
894
+ default: 'string'
895
+ },
896
+ disabled: {
897
+ type: [Boolean, String],
898
+ default: false
899
+ },
900
+ border: {
901
+ type: [Boolean, String],
902
+ default: true
903
+ },
904
+ hideSecond: {
905
+ type: [Boolean, String],
906
+ default: false
907
+ }
908
+ },
909
+ watch: {
910
+ // #ifndef VUE3
911
+ value: {
912
+ handler(newVal) {
913
+ if (newVal) {
914
+ this.parseValue(fixIosDateFormat(newVal));
915
+ this.initTime(false);
916
+ } else {
917
+ this.time = '';
918
+ this.parseValue(Date.now());
919
+ }
920
+ },
921
+ immediate: true
922
+ },
923
+ // #endif
924
+ // #ifdef VUE3
925
+ modelValue: {
926
+ handler(newVal) {
927
+ if (newVal) {
928
+ this.parseValue(fixIosDateFormat(newVal));
929
+ this.initTime(false);
930
+ } else {
931
+ this.time = '';
932
+ this.parseValue(Date.now());
933
+ }
934
+ },
935
+ immediate: true
936
+ },
937
+ // #endif
938
+ type: {
939
+ handler(newValue) {
940
+ if (newValue === 'date') {
941
+ this.dateShow = true;
942
+ this.timeShow = false;
943
+ this.title = '日期';
944
+ } else if (newValue === 'time') {
945
+ this.dateShow = false;
946
+ this.timeShow = true;
947
+ this.title = '时间';
948
+ } else {
949
+ this.dateShow = true;
950
+ this.timeShow = true;
951
+ this.title = '日期和时间';
952
+ }
953
+ },
954
+ immediate: true
955
+ },
956
+ start: {
957
+ handler(newVal) {
958
+ this.parseDatetimeRange(fixIosDateFormat(newVal), 'start');
959
+ },
960
+ immediate: true
961
+ },
962
+ end: {
963
+ handler(newVal) {
964
+ this.parseDatetimeRange(fixIosDateFormat(newVal), 'end');
965
+ },
966
+ immediate: true
967
+ },
968
+ // 月、日、时、分、秒可选范围变化后,检查当前值是否在范围内,不在则当前值重置为可选范围第一项
969
+ months(newVal) {
970
+ this.checkValue('month', this.month, newVal);
971
+ },
972
+ days(newVal) {
973
+ this.checkValue('day', this.day, newVal);
974
+ },
975
+ hours(newVal) {
976
+ this.checkValue('hour', this.hour, newVal);
977
+ },
978
+ minutes(newVal) {
979
+ this.checkValue('minute', this.minute, newVal);
980
+ },
981
+ seconds(newVal) {
982
+ this.checkValue('second', this.second, newVal);
983
+ }
984
+ },
985
+ computed: {
986
+ // 当前年、月、日、时、分、秒选择范围
987
+ years() {
988
+ return this.getCurrentRange('year');
989
+ },
990
+ months() {
991
+ return this.getCurrentRange('month');
992
+ },
993
+ days() {
994
+ return this.getCurrentRange('day');
995
+ },
996
+ hours() {
997
+ return this.getCurrentRange('hour');
998
+ },
999
+ minutes() {
1000
+ return this.getCurrentRange('minute');
1001
+ },
1002
+ seconds() {
1003
+ return this.getCurrentRange('second');
1004
+ },
1005
+ // picker 当前值数组
1006
+ ymd() {
1007
+ return [this.year - this.minYear, this.month - this.minMonth, this.day - this.minDay];
1008
+ },
1009
+ hms() {
1010
+ return [this.hour - this.minHour, this.minute - this.minMinute, this.second - this.minSecond];
1011
+ },
1012
+ // 当前 date 是 start
1013
+ currentDateIsStart() {
1014
+ return this.year === this.startYear && this.month === this.startMonth && this.day === this.startDay;
1015
+ },
1016
+ // 当前 date 是 end
1017
+ currentDateIsEnd() {
1018
+ return this.year === this.endYear && this.month === this.endMonth && this.day === this.endDay;
1019
+ },
1020
+ // 当前年、月、日、时、分、秒的最小值和最大值
1021
+ minYear() {
1022
+ return this.startYear;
1023
+ },
1024
+ maxYear() {
1025
+ return this.endYear;
1026
+ },
1027
+ minMonth() {
1028
+ if (this.year === this.startYear) {
1029
+ return this.startMonth;
1030
+ } else {
1031
+ return 1;
1032
+ }
1033
+ },
1034
+ maxMonth() {
1035
+ if (this.year === this.endYear) {
1036
+ return this.endMonth;
1037
+ } else {
1038
+ return 12;
1039
+ }
1040
+ },
1041
+ minDay() {
1042
+ if (this.year === this.startYear && this.month === this.startMonth) {
1043
+ return this.startDay;
1044
+ } else {
1045
+ return 1;
1046
+ }
1047
+ },
1048
+ maxDay() {
1049
+ if (this.year === this.endYear && this.month === this.endMonth) {
1050
+ return this.endDay;
1051
+ } else {
1052
+ return this.daysInMonth(this.year, this.month);
1053
+ }
1054
+ },
1055
+ minHour() {
1056
+ if (this.type === 'datetime') {
1057
+ if (this.currentDateIsStart) {
1058
+ return this.startHour;
1059
+ } else {
1060
+ return 0;
1061
+ }
1062
+ }
1063
+ if (this.type === 'time') {
1064
+ return this.startHour;
1065
+ }
1066
+ },
1067
+ maxHour() {
1068
+ if (this.type === 'datetime') {
1069
+ if (this.currentDateIsEnd) {
1070
+ return this.endHour;
1071
+ } else {
1072
+ return 23;
1073
+ }
1074
+ }
1075
+ if (this.type === 'time') {
1076
+ return this.endHour;
1077
+ }
1078
+ },
1079
+ minMinute() {
1080
+ if (this.type === 'datetime') {
1081
+ if (this.currentDateIsStart && this.hour === this.startHour) {
1082
+ return this.startMinute;
1083
+ } else {
1084
+ return 0;
1085
+ }
1086
+ }
1087
+ if (this.type === 'time') {
1088
+ if (this.hour === this.startHour) {
1089
+ return this.startMinute;
1090
+ } else {
1091
+ return 0;
1092
+ }
1093
+ }
1094
+ },
1095
+ maxMinute() {
1096
+ if (this.type === 'datetime') {
1097
+ if (this.currentDateIsEnd && this.hour === this.endHour) {
1098
+ return this.endMinute;
1099
+ } else {
1100
+ return 59;
1101
+ }
1102
+ }
1103
+ if (this.type === 'time') {
1104
+ if (this.hour === this.endHour) {
1105
+ return this.endMinute;
1106
+ } else {
1107
+ return 59;
1108
+ }
1109
+ }
1110
+ },
1111
+ minSecond() {
1112
+ if (this.type === 'datetime') {
1113
+ if (this.currentDateIsStart && this.hour === this.startHour && this.minute === this.startMinute) {
1114
+ return this.startSecond;
1115
+ } else {
1116
+ return 0;
1117
+ }
1118
+ }
1119
+ if (this.type === 'time') {
1120
+ if (this.hour === this.startHour && this.minute === this.startMinute) {
1121
+ return this.startSecond;
1122
+ } else {
1123
+ return 0;
1124
+ }
1125
+ }
1126
+ },
1127
+ maxSecond() {
1128
+ if (this.type === 'datetime') {
1129
+ if (this.currentDateIsEnd && this.hour === this.endHour && this.minute === this.endMinute) {
1130
+ return this.endSecond;
1131
+ } else {
1132
+ return 59;
1133
+ }
1134
+ }
1135
+ if (this.type === 'time') {
1136
+ if (this.hour === this.endHour && this.minute === this.endMinute) {
1137
+ return this.endSecond;
1138
+ } else {
1139
+ return 59;
1140
+ }
1141
+ }
1142
+ },
1143
+ /**
1144
+ * for i18n
1145
+ */
1146
+ selectTimeText() {
1147
+ return t('uni-datetime-picker.selectTime');
1148
+ },
1149
+ okText() {
1150
+ return t('uni-datetime-picker.ok');
1151
+ },
1152
+ clearText() {
1153
+ return t('uni-datetime-picker.clear');
1154
+ },
1155
+ cancelText() {
1156
+ return t('uni-datetime-picker.cancel');
1157
+ }
1158
+ },
1159
+ mounted() {
1160
+ // #ifdef APP-NVUE
1161
+ const res = uni.getSystemInfoSync();
1162
+ this.fixNvueBug = {
1163
+ top: res.windowHeight / 2,
1164
+ left: res.windowWidth / 2
1165
+ };
1166
+ // #endif
1167
+ },
1168
+ methods: {
1169
+ /**
1170
+ * @param {Object} item
1171
+ * 小于 10 在前面加个 0
1172
+ */
1173
+ lessThanTen(item) {
1174
+ return item < 10 ? '0' + item : item;
1175
+ },
1176
+ /**
1177
+ * 解析时分秒字符串,例如:00:00:00
1178
+ * @param {String} timeString
1179
+ */
1180
+ parseTimeType(timeString) {
1181
+ if (timeString) {
1182
+ let timeArr = timeString.split(':');
1183
+ this.hour = Number(timeArr[0]);
1184
+ this.minute = Number(timeArr[1]);
1185
+ this.second = Number(timeArr[2]);
1186
+ }
1187
+ },
1188
+ /**
1189
+ * 解析选择器初始值,类型可以是字符串、时间戳,例如:2000-10-02、'08:30:00'、 1610695109000
1190
+ * @param {String | Number} datetime
1191
+ */
1192
+ initPickerValue(datetime) {
1193
+ let defaultValue = null;
1194
+ if (datetime) {
1195
+ defaultValue = this.compareValueWithStartAndEnd(datetime, this.start, this.end);
1196
+ } else {
1197
+ defaultValue = Date.now();
1198
+ defaultValue = this.compareValueWithStartAndEnd(defaultValue, this.start, this.end);
1199
+ }
1200
+ this.parseValue(defaultValue);
1201
+ },
1202
+ /**
1203
+ * 初始值规则:
1204
+ * - 用户设置初始值 value
1205
+ * - 设置了起始时间 start、终止时间 end,并 start < value < end,初始值为 value, 否则初始值为 start
1206
+ * - 只设置了起始时间 start,并 start < value,初始值为 value,否则初始值为 start
1207
+ * - 只设置了终止时间 end,并 value < end,初始值为 value,否则初始值为 end
1208
+ * - 无起始终止时间,则初始值为 value
1209
+ * - 无初始值 value,则初始值为当前本地时间 Date.now()
1210
+ * @param {Object} value
1211
+ * @param {Object} dateBase
1212
+ */
1213
+ compareValueWithStartAndEnd(value, start, end) {
1214
+ let winner = null;
1215
+ value = this.superTimeStamp(value);
1216
+ start = this.superTimeStamp(start);
1217
+ end = this.superTimeStamp(end);
1218
+ if (start && end) {
1219
+ if (value < start) {
1220
+ winner = new Date(start);
1221
+ } else if (value > end) {
1222
+ winner = new Date(end);
1223
+ } else {
1224
+ winner = new Date(value);
1225
+ }
1226
+ } else if (start && !end) {
1227
+ winner = start <= value ? new Date(value) : new Date(start);
1228
+ } else if (!start && end) {
1229
+ winner = value <= end ? new Date(value) : new Date(end);
1230
+ } else {
1231
+ winner = new Date(value);
1232
+ }
1233
+ return winner;
1234
+ },
1235
+ /**
1236
+ * 转换为可比较的时间戳,接受日期、时分秒、时间戳
1237
+ * @param {Object} value
1238
+ */
1239
+ superTimeStamp(value) {
1240
+ let dateBase = '';
1241
+ if (this.type === 'time' && value && typeof value === 'string') {
1242
+ const now = new Date();
1243
+ const year = now.getFullYear();
1244
+ const month = now.getMonth() + 1;
1245
+ const day = now.getDate();
1246
+ dateBase = year + '/' + month + '/' + day + ' ';
1247
+ }
1248
+ if (Number(value)) {
1249
+ value = parseInt(value);
1250
+ dateBase = 0;
1251
+ }
1252
+ return this.createTimeStamp(dateBase + value);
1253
+ },
1254
+ /**
1255
+ * 解析默认值 value,字符串、时间戳
1256
+ * @param {Object} defaultTime
1257
+ */
1258
+ parseValue(value) {
1259
+ if (!value) {
1260
+ return;
1261
+ }
1262
+ if (this.type === 'time' && typeof value === 'string') {
1263
+ this.parseTimeType(value);
1264
+ } else {
1265
+ let defaultDate = null;
1266
+ defaultDate = new Date(value);
1267
+ if (this.type !== 'time') {
1268
+ this.year = defaultDate.getFullYear();
1269
+ this.month = defaultDate.getMonth() + 1;
1270
+ this.day = defaultDate.getDate();
1271
+ }
1272
+ if (this.type !== 'date') {
1273
+ this.hour = defaultDate.getHours();
1274
+ this.minute = defaultDate.getMinutes();
1275
+ this.second = defaultDate.getSeconds();
1276
+ }
1277
+ }
1278
+ if (this.hideSecond) {
1279
+ this.second = 0;
1280
+ }
1281
+ },
1282
+ /**
1283
+ * 解析可选择时间范围 start、end,年月日字符串、时间戳
1284
+ * @param {Object} defaultTime
1285
+ */
1286
+ parseDatetimeRange(point, pointType) {
1287
+ // 时间为空,则重置为初始值
1288
+ if (!point) {
1289
+ if (pointType === 'start') {
1290
+ this.startYear = 1920;
1291
+ this.startMonth = 1;
1292
+ this.startDay = 1;
1293
+ this.startHour = 0;
1294
+ this.startMinute = 0;
1295
+ this.startSecond = 0;
1296
+ }
1297
+ if (pointType === 'end') {
1298
+ this.endYear = 2120;
1299
+ this.endMonth = 12;
1300
+ this.endDay = 31;
1301
+ this.endHour = 23;
1302
+ this.endMinute = 59;
1303
+ this.endSecond = 59;
1304
+ }
1305
+ return;
1306
+ }
1307
+ if (this.type === 'time') {
1308
+ const pointArr = point.split(':');
1309
+ this[pointType + 'Hour'] = Number(pointArr[0]);
1310
+ this[pointType + 'Minute'] = Number(pointArr[1]);
1311
+ this[pointType + 'Second'] = Number(pointArr[2]);
1312
+ } else {
1313
+ if (!point) {
1314
+ pointType === 'start' ? (this.startYear = this.year - 60) : (this.endYear = this.year + 60);
1315
+ return;
1316
+ }
1317
+ if (Number(point)) {
1318
+ point = parseInt(point);
1319
+ }
1320
+ // datetime 的 end 没有时分秒, 则不限制
1321
+ const hasTime = /[0-9]:[0-9]/;
1322
+ if (this.type === 'datetime' && pointType === 'end' && typeof point === 'string' && !hasTime.test(point)) {
1323
+ point = point + ' 23:59:59';
1324
+ }
1325
+ const pointDate = new Date(point);
1326
+ this[pointType + 'Year'] = pointDate.getFullYear();
1327
+ this[pointType + 'Month'] = pointDate.getMonth() + 1;
1328
+ this[pointType + 'Day'] = pointDate.getDate();
1329
+ if (this.type === 'datetime') {
1330
+ this[pointType + 'Hour'] = pointDate.getHours();
1331
+ this[pointType + 'Minute'] = pointDate.getMinutes();
1332
+ this[pointType + 'Second'] = pointDate.getSeconds();
1333
+ }
1334
+ }
1335
+ },
1336
+ // 获取 年、月、日、时、分、秒 当前可选范围
1337
+ getCurrentRange(value) {
1338
+ const range = [];
1339
+ for (let i = this['min' + this.capitalize(value)]; i <= this['max' + this.capitalize(value)]; i++) {
1340
+ range.push(i);
1341
+ }
1342
+ return range;
1343
+ },
1344
+ // 字符串首字母大写
1345
+ capitalize(str) {
1346
+ return str.charAt(0).toUpperCase() + str.slice(1);
1347
+ },
1348
+ // 检查当前值是否在范围内,不在则当前值重置为可选范围第一项
1349
+ checkValue(name, value, values) {
1350
+ if (values.indexOf(value) === -1) {
1351
+ this[name] = values[0];
1352
+ }
1353
+ },
1354
+ // 每个月的实际天数
1355
+ daysInMonth(year, month) {
1356
+ // Use 1 for January, 2 for February, etc.
1357
+ return new Date(year, month, 0).getDate();
1358
+ },
1359
+ //兼容 iOS、safari 日期格式
1360
+ fixIosDateFormat(value) {
1361
+ if (typeof value === 'string') {
1362
+ value = value.replace(/-/g, '/');
1363
+ }
1364
+ return value;
1365
+ },
1366
+ /**
1367
+ * 生成时间戳
1368
+ * @param {Object} time
1369
+ */
1370
+ createTimeStamp(time) {
1371
+ if (!time) return;
1372
+ if (typeof time === 'number') {
1373
+ return time;
1374
+ } else {
1375
+ time = time.replace(/-/g, '/');
1376
+ if (this.type === 'date') {
1377
+ time = time + ' ' + '00:00:00';
1378
+ }
1379
+ return Date.parse(time);
1380
+ }
1381
+ },
1382
+ /**
1383
+ * 生成日期或时间的字符串
1384
+ */
1385
+ createDomSting() {
1386
+ const yymmdd = this.year + '-' + this.lessThanTen(this.month) + '-' + this.lessThanTen(this.day);
1387
+ let hhmmss = this.lessThanTen(this.hour) + ':' + this.lessThanTen(this.minute);
1388
+ if (!this.hideSecond) {
1389
+ hhmmss = hhmmss + ':' + this.lessThanTen(this.second);
1390
+ }
1391
+ if (this.type === 'date') {
1392
+ return yymmdd;
1393
+ } else if (this.type === 'time') {
1394
+ return hhmmss;
1395
+ } else {
1396
+ return yymmdd + ' ' + hhmmss;
1397
+ }
1398
+ },
1399
+ /**
1400
+ * 初始化返回值,并抛出 change 事件
1401
+ */
1402
+ initTime(emit = true) {
1403
+ this.time = this.createDomSting();
1404
+ if (!emit) return;
1405
+ if (this.returnType === 'timestamp' && this.type !== 'time') {
1406
+ this.$emit('change', this.createTimeStamp(this.time));
1407
+ this.$emit('input', this.createTimeStamp(this.time));
1408
+ this.$emit('update:modelValue', this.createTimeStamp(this.time));
1409
+ } else {
1410
+ this.$emit('change', this.time);
1411
+ this.$emit('input', this.time);
1412
+ this.$emit('update:modelValue', this.time);
1413
+ }
1414
+ },
1415
+ /**
1416
+ * 用户选择日期或时间更新 data
1417
+ * @param {Object} e
1418
+ */
1419
+ bindDateChange(e) {
1420
+ const val = e.detail.value;
1421
+ this.year = this.years[val[0]];
1422
+ this.month = this.months[val[1]];
1423
+ this.day = this.days[val[2]];
1424
+ },
1425
+ bindTimeChange(e) {
1426
+ const val = e.detail.value;
1427
+ this.hour = this.hours[val[0]];
1428
+ this.minute = this.minutes[val[1]];
1429
+ this.second = this.seconds[val[2]];
1430
+ },
1431
+ /**
1432
+ * 初始化弹出层
1433
+ */
1434
+ initTimePicker() {
1435
+ if (this.disabled) return;
1436
+ const value = fixIosDateFormat(this.time);
1437
+ this.initPickerValue(value);
1438
+ this.visible = !this.visible;
1439
+ },
1440
+ /**
1441
+ * 触发或关闭弹框
1442
+ */
1443
+ tiggerTimePicker(e) {
1444
+ this.visible = !this.visible;
1445
+ },
1446
+ /**
1447
+ * 用户点击“清空”按钮,清空当前值
1448
+ */
1449
+ clearTime() {
1450
+ this.time = '';
1451
+ this.$emit('change', this.time);
1452
+ this.$emit('input', this.time);
1453
+ this.$emit('update:modelValue', this.time);
1454
+ this.tiggerTimePicker();
1455
+ },
1456
+ /**
1457
+ * 用户点击“确定”按钮
1458
+ */
1459
+ setTime() {
1460
+ this.initTime();
1461
+ this.tiggerTimePicker();
1462
+ }
1463
+ }
1464
+ };
1465
+ </script>
1466
+ <style>
1467
+ @import 'style.css';
1468
+ </style>