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

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 (71) hide show
  1. package/package.json +1 -1
  2. package/plugins/jumps.js +57 -12
  3. package/plugins/lbs.js +17 -8
  4. package/ui-cv/components/cv-grid-item/cv-grid-item.vue +1 -1
  5. package/uni-ui/lib/uni-badge/uni-badge.vue +150 -1
  6. package/uni-ui/lib/uni-breadcrumb/uni-breadcrumb.vue +37 -1
  7. package/uni-ui/lib/uni-breadcrumb-item/uni-breadcrumb-item.vue +83 -1
  8. package/uni-ui/lib/uni-calendar/uni-calendar-item.vue +122 -1
  9. package/uni-ui/lib/uni-calendar/uni-calendar.vue +366 -1
  10. package/uni-ui/lib/uni-card/uni-card.vue +124 -1
  11. package/uni-ui/lib/uni-col/uni-col.vue +1 -1
  12. package/uni-ui/lib/uni-collapse/uni-collapse.vue +135 -1
  13. package/uni-ui/lib/uni-collapse-item/uni-collapse-item.vue +266 -1
  14. package/uni-ui/lib/uni-combox/uni-combox.vue +1 -1
  15. package/uni-ui/lib/uni-countdown/uni-countdown.vue +239 -1
  16. package/uni-ui/lib/uni-data-checkbox/uni-data-checkbox.vue +487 -1
  17. package/uni-ui/lib/uni-data-picker/uni-data-picker.vue +530 -1
  18. package/uni-ui/lib/uni-data-pickerview/uni-data-picker.js +157 -150
  19. package/uni-ui/lib/uni-data-pickerview/uni-data-pickerview.vue +166 -1
  20. package/uni-ui/lib/uni-data-select/uni-data-select.vue +289 -1
  21. package/uni-ui/lib/uni-datetime-picker/calendar-item.vue +70 -1
  22. package/uni-ui/lib/uni-datetime-picker/calendar.vue +629 -1
  23. package/uni-ui/lib/uni-datetime-picker/time-picker.vue +741 -1
  24. package/uni-ui/lib/uni-datetime-picker/uni-datetime-picker.vue +847 -1
  25. package/uni-ui/lib/uni-drawer/uni-drawer.vue +115 -1
  26. package/uni-ui/lib/uni-easyinput/uni-easyinput.vue +515 -1
  27. package/uni-ui/lib/uni-fab/uni-fab.vue +257 -1
  28. package/uni-ui/lib/uni-fav/uni-fav.vue +123 -1
  29. package/uni-ui/lib/uni-file-picker/uni-file-picker.vue +642 -1
  30. package/uni-ui/lib/uni-file-picker/upload-file.vue +177 -1
  31. package/uni-ui/lib/uni-file-picker/upload-image.vue +176 -1
  32. package/uni-ui/lib/uni-forms/uni-forms.vue +375 -1
  33. package/uni-ui/lib/uni-forms-item/uni-forms-item.vue +429 -1
  34. package/uni-ui/lib/uni-goods-nav/uni-goods-nav.vue +129 -1
  35. package/uni-ui/lib/uni-grid/uni-grid.vue +115 -1
  36. package/uni-ui/lib/uni-grid-item/uni-grid-item.vue +78 -1
  37. package/uni-ui/lib/uni-group/uni-group.vue +85 -1
  38. package/uni-ui/lib/uni-icons/uni-icons.vue +85 -1
  39. package/uni-ui/lib/uni-indexed-list/uni-indexed-list-item.vue +68 -1
  40. package/uni-ui/lib/uni-indexed-list/uni-indexed-list.vue +294 -1
  41. package/uni-ui/lib/uni-list/uni-list.vue +81 -1
  42. package/uni-ui/lib/uni-list-ad/uni-list-ad.vue +77 -1
  43. package/uni-ui/lib/uni-list-chat/uni-list-chat.vue +294 -1
  44. package/uni-ui/lib/uni-list-item/uni-list-item.vue +346 -1
  45. package/uni-ui/lib/uni-load-more/uni-load-more.vue +172 -1
  46. package/uni-ui/lib/uni-nav-bar/uni-nav-bar.vue +205 -1
  47. package/uni-ui/lib/uni-nav-bar/uni-status-bar.vue +18 -1
  48. package/uni-ui/lib/uni-notice-bar/uni-notice-bar.vue +331 -1
  49. package/uni-ui/lib/uni-number-box/uni-number-box.vue +166 -1
  50. package/uni-ui/lib/uni-pagination/uni-pagination.vue +323 -1
  51. package/uni-ui/lib/uni-popup/uni-popup.vue +1 -1
  52. package/uni-ui/lib/uni-popup-dialog/uni-popup-dialog.vue +173 -1
  53. package/uni-ui/lib/uni-popup-message/uni-popup-message.vue +74 -1
  54. package/uni-ui/lib/uni-popup-share/uni-popup-share.vue +106 -1
  55. package/uni-ui/lib/uni-rate/uni-rate.vue +322 -1
  56. package/uni-ui/lib/uni-row/uni-row.vue +1 -1
  57. package/uni-ui/lib/uni-search-bar/uni-search-bar.vue +236 -1
  58. package/uni-ui/lib/uni-section/uni-section.vue +109 -1
  59. package/uni-ui/lib/uni-segmented-control/uni-segmented-control.vue +103 -1
  60. package/uni-ui/lib/uni-status-bar/uni-status-bar.vue +1 -1
  61. package/uni-ui/lib/uni-steps/uni-steps.vue +120 -1
  62. package/uni-ui/lib/uni-swipe-action-item/uni-swipe-action-item.vue +226 -3
  63. package/uni-ui/lib/uni-swiper-dot/uni-swiper-dot.vue +167 -1
  64. package/uni-ui/lib/uni-table/uni-table.vue +297 -1
  65. package/uni-ui/lib/uni-tag/uni-tag.vue +100 -1
  66. package/uni-ui/lib/uni-td/uni-td.vue +78 -1
  67. package/uni-ui/lib/uni-th/filter-dropdown.vue +1 -1
  68. package/uni-ui/lib/uni-th/uni-th.vue +224 -1
  69. package/uni-ui/lib/uni-thead/uni-thead.vue +77 -1
  70. package/uni-ui/lib/uni-tr/table-checkbox.vue +79 -1
  71. package/uni-ui/lib/uni-tr/uni-tr.vue +135 -1
@@ -1 +1,847 @@
1
- <template>
2
1
  <view class="uni-date">
3
2
  <view class="uni-date-editor" @click="show">
4
3
  <slot>
5
4
  <view class="uni-date-editor--x" :class="{ 'uni-date-editor--x__disabled': disabled, 'uni-date-x--border': border }">
6
5
  <view v-if="!isRange" class="uni-date-x uni-date-single">
7
6
  <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
8
7
  <view class="uni-date__x-input">{{ displayValue || singlePlaceholderText }}</view>
9
8
  </view>
10
9
  <view v-else class="uni-date-x uni-date-range">
11
10
  <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
12
11
  <view class="uni-date__x-input text-center">{{ displayRangeValue.startDate || startPlaceholderText }}</view>
13
12
  <view class="range-separator">{{ rangeSeparator }}</view>
14
13
  <view class="uni-date__x-input text-center">{{ displayRangeValue.endDate || endPlaceholderText }}</view>
15
14
  </view>
16
15
  <view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
17
16
  <uni-icons type="clear" color="#c0c4cc" size="22"></uni-icons>
18
17
  </view>
19
18
  </view>
20
19
  </slot>
21
20
  </view>
22
21
  <view v-show="pickerVisible" class="uni-date-mask--pc" @click="close"></view>
23
22
  <view v-if="!isPhone" v-show="pickerVisible" ref="datePicker" class="uni-date-picker__container">
24
23
  <view v-if="!isRange" class="uni-date-single--x" :style="pickerPositionStyle">
25
24
  <view class="uni-popper__arrow"></view>
26
25
  <view v-if="hasTime" class="uni-date-changed popup-x-header">
27
26
  <input class="uni-date__input text-center" type="text" v-model="inputDate" :placeholder="selectDateText" />
28
27
  <time-picker
29
28
  type="time"
30
29
  v-model="pickerTime"
31
30
  :border="false"
32
31
  :disabled="!inputDate"
33
32
  :start="timepickerStartTime"
34
33
  :end="timepickerEndTime"
35
34
  :hideSecond="hideSecond"
36
35
  style="width: 100%"
37
36
  >
38
37
  <input
39
38
  class="uni-date__input text-center"
40
39
  type="text"
41
40
  v-model="pickerTime"
42
41
  :placeholder="selectTimeText"
43
42
  :disabled="!inputDate"
44
43
  />
45
44
  </time-picker>
46
45
  </view>
47
46
  <Calendar
48
47
  ref="pcSingle"
49
48
  :showMonth="false"
50
49
  :start-date="calendarRange.startDate"
51
50
  :end-date="calendarRange.endDate"
52
51
  :date="calendarDate"
53
52
  @change="singleChange"
54
53
  :default-value="defaultValue"
55
54
  style="padding: 0 8px"
56
55
  />
57
56
  <view v-if="hasTime" class="popup-x-footer">
58
57
  <text class="confirm-text" @click="confirmSingleChange">{{ okText }}</text>
59
58
  </view>
60
59
  </view>
61
60
  <view v-else class="uni-date-range--x" :style="pickerPositionStyle">
62
61
  <view class="uni-popper__arrow"></view>
63
62
  <view v-if="hasTime" class="popup-x-header uni-date-changed">
64
63
  <view class="popup-x-header--datetime">
65
64
  <input
66
65
  class="uni-date__input uni-date-range__input"
67
66
  type="text"
68
67
  v-model="tempRange.startDate"
69
68
  :placeholder="startDateText"
70
69
  />
71
70
  <time-picker
72
71
  type="time"
73
72
  v-model="tempRange.startTime"
74
73
  :start="timepickerStartTime"
75
74
  :border="false"
76
75
  :disabled="!tempRange.startDate"
77
76
  :hideSecond="hideSecond"
78
77
  >
79
78
  <input
80
79
  class="uni-date__input uni-date-range__input"
81
80
  type="text"
82
81
  v-model="tempRange.startTime"
83
82
  :placeholder="startTimeText"
84
83
  :disabled="!tempRange.startDate"
85
84
  />
86
85
  </time-picker>
87
86
  </view>
88
87
  <uni-icons type="arrowthinright" color="#999" style="line-height: 40px"></uni-icons>
89
88
  <view class="popup-x-header--datetime">
90
89
  <input
91
90
  class="uni-date__input uni-date-range__input"
92
91
  type="text"
93
92
  v-model="tempRange.endDate"
94
93
  :placeholder="endDateText"
95
94
  />
96
95
  <time-picker
97
96
  type="time"
98
97
  v-model="tempRange.endTime"
99
98
  :end="timepickerEndTime"
100
99
  :border="false"
101
100
  :disabled="!tempRange.endDate"
102
101
  :hideSecond="hideSecond"
103
102
  >
104
103
  <input
105
104
  class="uni-date__input uni-date-range__input"
106
105
  type="text"
107
106
  v-model="tempRange.endTime"
108
107
  :placeholder="endTimeText"
109
108
  :disabled="!tempRange.endDate"
110
109
  />
111
110
  </time-picker>
112
111
  </view>
113
112
  </view>
114
113
  <view class="popup-x-body">
115
114
  <Calendar
116
115
  ref="left"
117
116
  :showMonth="false"
118
117
  :start-date="calendarRange.startDate"
119
118
  :end-date="calendarRange.endDate"
120
119
  :range="true"
121
120
  :pleStatus="endMultipleStatus"
122
121
  @change="leftChange"
123
122
  @firstEnterCale="updateRightCale"
124
123
  style="padding: 0 8px"
125
124
  />
126
125
  <Calendar
127
126
  ref="right"
128
127
  :showMonth="false"
129
128
  :start-date="calendarRange.startDate"
130
129
  :end-date="calendarRange.endDate"
131
130
  :range="true"
132
131
  @change="rightChange"
133
132
  :pleStatus="startMultipleStatus"
134
133
  @firstEnterCale="updateLeftCale"
135
134
  style="padding: 0 8px; border-left: 1px solid #f1f1f1"
136
135
  />
137
136
  </view>
138
137
  <view v-if="hasTime" class="popup-x-footer">
139
138
  <text @click="clear">{{ clearText }}</text>
140
139
  <text class="confirm-text" @click="confirmRangeChange">{{ okText }}</text>
141
140
  </view>
142
141
  </view>
143
142
  </view>
144
143
  <Calendar
145
144
  v-if="isPhone"
146
145
  ref="mobile"
147
146
  :clearDate="false"
148
147
  :date="calendarDate"
149
148
  :defTime="mobileCalendarTime"
150
149
  :start-date="calendarRange.startDate"
151
150
  :end-date="calendarRange.endDate"
152
151
  :selectableTimes="mobSelectableTime"
153
152
  :startPlaceholder="startPlaceholder"
154
153
  :endPlaceholder="endPlaceholder"
155
154
  :default-value="defaultValue"
156
155
  :pleStatus="endMultipleStatus"
157
156
  :showMonth="false"
158
157
  :range="isRange"
159
158
  :hasTime="hasTime"
160
159
  :insert="false"
161
160
  :hideSecond="hideSecond"
162
161
  @confirm="mobileChange"
163
162
  @maskClose="close"
164
163
  />
165
164
  </view>
166
165
  * DatetimePicker 时间选择器
167
166
  * @description 同时支持 PC 和移动端使用日历选择日期和日期范围
168
167
  * @tutorial https://ext.dcloud.net.cn/plugin?id=3962
169
168
  * @property {String} type 选择器类型
170
169
  * @property {String|Number|Array|Date} value 绑定值
171
170
  * @property {String} placeholder 单选择时的占位内容
172
171
  * @property {String} start 起始时间
173
172
  * @property {String} end 终止时间
174
173
  * @property {String} start-placeholder 范围选择时开始日期的占位内容
175
174
  * @property {String} end-placeholder 范围选择时结束日期的占位内容
176
175
  * @property {String} range-separator 选择范围时的分隔符
177
176
  * @property {Boolean} border = [true|false] 是否有边框
178
177
  * @property {Boolean} disabled = [true|false] 是否禁用
179
178
  * @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用)
180
179
  * @property {[String} defaultValue 选择器打开时默认显示的时间
181
180
  * @event {Function} change 确定日期时触发的事件
182
181
  * @event {Function} maskClick 点击遮罩层触发的事件
183
182
  * @event {Function} show 打开弹出层
184
183
  * @event {Function} close 关闭弹出层
185
184
  * @event {Function} clear 清除上次选中的状态和值
186
185
  **/
187
186
  name: 'UniDatetimePicker',
188
187
  options: {
189
188
  virtualHost: true
190
189
  },
191
190
  components: {
192
191
  Calendar,
193
192
  TimePicker
194
193
  },
195
194
  data() {
196
195
  return {
197
196
  isRange: false,
198
197
  hasTime: false,
199
198
  displayValue: '',
200
199
  inputDate: '',
201
200
  calendarDate: '',
202
201
  pickerTime: '',
203
202
  calendarRange: {
204
203
  startDate: '',
205
204
  startTime: '',
206
205
  endDate: '',
207
206
  endTime: ''
208
207
  },
209
208
  displayRangeValue: {
210
209
  startDate: '',
211
210
  endDate: ''
212
211
  },
213
212
  tempRange: {
214
213
  startDate: '',
215
214
  startTime: '',
216
215
  endDate: '',
217
216
  endTime: ''
218
217
  },
219
218
  // 左右日历同步数据
220
219
  startMultipleStatus: {
221
220
  before: '',
222
221
  after: '',
223
222
  data: [],
224
223
  fulldate: ''
225
224
  },
226
225
  endMultipleStatus: {
227
226
  before: '',
228
227
  after: '',
229
228
  data: [],
230
229
  fulldate: ''
231
230
  },
232
231
  pickerVisible: false,
233
232
  pickerPositionStyle: null,
234
233
  isEmitValue: false,
235
234
  isPhone: false,
236
235
  isFirstShow: true,
237
236
  i18nT: () => {}
238
237
  };
239
238
  },
240
239
  props: {
241
240
  type: {
242
241
  type: String,
243
242
  default: 'datetime'
244
243
  },
245
244
  value: {
246
245
  type: [String, Number, Array, Date],
247
246
  default: ''
248
247
  },
249
248
  modelValue: {
250
249
  type: [String, Number, Array, Date],
251
250
  default: ''
252
251
  },
253
252
  start: {
254
253
  type: [Number, String],
255
254
  default: ''
256
255
  },
257
256
  end: {
258
257
  type: [Number, String],
259
258
  default: ''
260
259
  },
261
260
  returnType: {
262
261
  type: String,
263
262
  default: 'string'
264
263
  },
265
264
  placeholder: {
266
265
  type: String,
267
266
  default: ''
268
267
  },
269
268
  startPlaceholder: {
270
269
  type: String,
271
270
  default: ''
272
271
  },
273
272
  endPlaceholder: {
274
273
  type: String,
275
274
  default: ''
276
275
  },
277
276
  rangeSeparator: {
278
277
  type: String,
279
278
  default: '-'
280
279
  },
281
280
  border: {
282
281
  type: [Boolean],
283
282
  default: true
284
283
  },
285
284
  disabled: {
286
285
  type: [Boolean],
287
286
  default: false
288
287
  },
289
288
  clearIcon: {
290
289
  type: [Boolean],
291
290
  default: true
292
291
  },
293
292
  hideSecond: {
294
293
  type: [Boolean],
295
294
  default: false
296
295
  },
297
296
  defaultValue: {
298
297
  type: [String, Object, Array],
299
298
  default: ''
300
299
  }
301
300
  },
302
301
  watch: {
303
302
  type: {
304
303
  immediate: true,
305
304
  handler(newVal) {
306
305
  this.hasTime = newVal.indexOf('time') !== -1;
307
306
  this.isRange = newVal.indexOf('range') !== -1;
308
307
  }
309
308
  },
310
309
  // #ifndef VUE3
311
310
  value: {
312
311
  immediate: true,
313
312
  handler(newVal) {
314
313
  if (this.isEmitValue) {
315
314
  this.isEmitValue = false;
316
315
  return;
317
316
  }
318
317
  this.initPicker(newVal);
319
318
  }
320
319
  },
321
320
  // #endif
322
321
  // #ifdef VUE3
323
322
  modelValue: {
324
323
  immediate: true,
325
324
  handler(newVal) {
326
325
  if (this.isEmitValue) {
327
326
  this.isEmitValue = false;
328
327
  return;
329
328
  }
330
329
  this.initPicker(newVal);
331
330
  }
332
331
  },
333
332
  // #endif
334
333
  start: {
335
334
  immediate: true,
336
335
  handler(newVal) {
337
336
  if (!newVal) return;
338
337
  this.calendarRange.startDate = getDate(newVal);
339
338
  if (this.hasTime) {
340
339
  this.calendarRange.startTime = getTime(newVal);
341
340
  }
342
341
  }
343
342
  },
344
343
  end: {
345
344
  immediate: true,
346
345
  handler(newVal) {
347
346
  if (!newVal) return;
348
347
  this.calendarRange.endDate = getDate(newVal);
349
348
  if (this.hasTime) {
350
349
  this.calendarRange.endTime = getTime(newVal, this.hideSecond);
351
350
  }
352
351
  }
353
352
  }
354
353
  },
355
354
  computed: {
356
355
  timepickerStartTime() {
357
356
  const activeDate = this.isRange ? this.tempRange.startDate : this.inputDate;
358
357
  return activeDate === this.calendarRange.startDate ? this.calendarRange.startTime : '';
359
358
  },
360
359
  timepickerEndTime() {
361
360
  const activeDate = this.isRange ? this.tempRange.endDate : this.inputDate;
362
361
  return activeDate === this.calendarRange.endDate ? this.calendarRange.endTime : '';
363
362
  },
364
363
  mobileCalendarTime() {
365
364
  const timeRange = {
366
365
  start: this.tempRange.startTime,
367
366
  end: this.tempRange.endTime
368
367
  };
369
368
  return this.isRange ? timeRange : this.pickerTime;
370
369
  },
371
370
  mobSelectableTime() {
372
371
  return {
373
372
  start: this.calendarRange.startTime,
374
373
  end: this.calendarRange.endTime
375
374
  };
376
375
  },
377
376
  datePopupWidth() {
378
377
  // todo
379
378
  return this.isRange ? 653 : 301;
380
379
  },
381
380
  /**
382
381
  * for i18n
383
382
  */
384
383
  singlePlaceholderText() {
385
384
  return this.placeholder || (this.type === 'date' ? this.selectDateText : this.selectDateTimeText);
386
385
  },
387
386
  startPlaceholderText() {
388
387
  return this.startPlaceholder || this.startDateText;
389
388
  },
390
389
  endPlaceholderText() {
391
390
  return this.endPlaceholder || this.endDateText;
392
391
  },
393
392
  selectDateText() {
394
393
  return this.i18nT('uni-datetime-picker.selectDate');
395
394
  },
396
395
  selectDateTimeText() {
397
396
  return this.i18nT('uni-datetime-picker.selectDateTime');
398
397
  },
399
398
  selectTimeText() {
400
399
  return this.i18nT('uni-datetime-picker.selectTime');
401
400
  },
402
401
  startDateText() {
403
402
  return this.startPlaceholder || this.i18nT('uni-datetime-picker.startDate');
404
403
  },
405
404
  startTimeText() {
406
405
  return this.i18nT('uni-datetime-picker.startTime');
407
406
  },
408
407
  endDateText() {
409
408
  return this.endPlaceholder || this.i18nT('uni-datetime-picker.endDate');
410
409
  },
411
410
  endTimeText() {
412
411
  return this.i18nT('uni-datetime-picker.endTime');
413
412
  },
414
413
  okText() {
415
414
  return this.i18nT('uni-datetime-picker.ok');
416
415
  },
417
416
  clearText() {
418
417
  return this.i18nT('uni-datetime-picker.clear');
419
418
  },
420
419
  showClearIcon() {
421
420
  return (
422
421
  this.clearIcon &&
423
422
  !this.disabled &&
424
423
  (this.displayValue || (this.displayRangeValue.startDate && this.displayRangeValue.endDate))
425
424
  );
426
425
  }
427
426
  },
428
427
  created() {
429
428
  this.initI18nT();
430
429
  this.platform();
431
430
  },
432
431
  methods: {
433
432
  initI18nT() {
434
433
  const vueI18n = initVueI18n(i18nMessages);
435
434
  this.i18nT = vueI18n.t;
436
435
  },
437
436
  initPicker(newVal) {
438
437
  if ((!newVal && !this.defaultValue) || (Array.isArray(newVal) && !newVal.length)) {
439
438
  this.$nextTick(() => {
440
439
  this.clear(false);
441
440
  });
442
441
  return;
443
442
  }
444
443
  if (!Array.isArray(newVal) && !this.isRange) {
445
444
  if (newVal) {
446
445
  this.displayValue = this.inputDate = this.calendarDate = getDate(newVal);
447
446
  if (this.hasTime) {
448
447
  this.pickerTime = getTime(newVal, this.hideSecond);
449
448
  this.displayValue = `${this.displayValue} ${this.pickerTime}`;
450
449
  }
451
450
  } else if (this.defaultValue) {
452
451
  this.inputDate = this.calendarDate = getDate(this.defaultValue);
453
452
  if (this.hasTime) {
454
453
  this.pickerTime = getTime(this.defaultValue, this.hideSecond);
455
454
  }
456
455
  }
457
456
  } else {
458
457
  const [before, after] = newVal;
459
458
  if (!before && !after) return;
460
459
  const beforeDate = getDate(before);
461
460
  const beforeTime = getTime(before, this.hideSecond);
462
461
  const afterDate = getDate(after);
463
462
  const afterTime = getTime(after, this.hideSecond);
464
463
  const startDate = beforeDate;
465
464
  const endDate = afterDate;
466
465
  this.displayRangeValue.startDate = this.tempRange.startDate = startDate;
467
466
  this.displayRangeValue.endDate = this.tempRange.endDate = endDate;
468
467
  if (this.hasTime) {
469
468
  this.displayRangeValue.startDate = `${beforeDate} ${beforeTime}`;
470
469
  this.displayRangeValue.endDate = `${afterDate} ${afterTime}`;
471
470
  this.tempRange.startTime = beforeTime;
472
471
  this.tempRange.endTime = afterTime;
473
472
  }
474
473
  const defaultRange = {
475
474
  before: beforeDate,
476
475
  after: afterDate
477
476
  };
478
477
  this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
479
478
  which: 'right'
480
479
  });
481
480
  this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
482
481
  which: 'left'
483
482
  });
484
483
  }
485
484
  },
486
485
  updateLeftCale(e) {
487
486
  const left = this.$refs.left;
488
487
  // 设置范围选
489
488
  left.cale.setHoverMultiple(e.after);
490
489
  left.setDate(this.$refs.left.nowDate.fullDate);
491
490
  },
492
491
  updateRightCale(e) {
493
492
  const right = this.$refs.right;
494
493
  // 设置范围选
495
494
  right.cale.setHoverMultiple(e.after);
496
495
  right.setDate(this.$refs.right.nowDate.fullDate);
497
496
  },
498
497
  platform() {
499
498
  if (typeof navigator !== 'undefined') {
500
499
  this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1;
501
500
  return;
502
501
  }
503
502
  const { windowWidth } = uni.getSystemInfoSync();
504
503
  this.isPhone = windowWidth <= 500;
505
504
  this.windowWidth = windowWidth;
506
505
  },
507
506
  show() {
508
507
  if (this.disabled) {
509
508
  return;
510
509
  }
511
510
  this.platform();
512
511
  if (this.isPhone) {
513
512
  setTimeout(() => {
514
513
  this.$refs.mobile.open();
515
514
  }, 0);
516
515
  return;
517
516
  }
518
517
  this.pickerPositionStyle = {
519
518
  top: '10px'
520
519
  };
521
520
  const dateEditor = uni.createSelectorQuery().in(this).select('.uni-date-editor');
522
521
  dateEditor
523
522
  .boundingClientRect((rect) => {
524
523
  if (this.windowWidth - rect.left < this.datePopupWidth) {
525
524
  this.pickerPositionStyle.right = 0;
526
525
  }
527
526
  })
528
527
  .exec();
529
528
  setTimeout(() => {
530
529
  this.pickerVisible = !this.pickerVisible;
531
530
  if (!this.isPhone && this.isRange && this.isFirstShow) {
532
531
  this.isFirstShow = false;
533
532
  const { startDate, endDate } = this.calendarRange;
534
533
  if (startDate && endDate) {
535
534
  if (this.diffDate(startDate, endDate) < 30) {
536
535
  this.$refs.right.changeMonth('pre');
537
536
  }
538
537
  } else {
539
538
  this.$refs.right.changeMonth('next');
540
539
  this.$refs.right.cale.lastHover = false;
541
540
  }
542
541
  }
543
542
  }, 50);
544
543
  },
545
544
  close() {
546
545
  setTimeout(() => {
547
546
  this.pickerVisible = false;
548
547
  this.$emit('maskClick', this.value);
549
548
  this.$refs.mobile && this.$refs.mobile.close();
550
549
  }, 20);
551
550
  },
552
551
  setEmit(value) {
553
552
  if (this.returnType === 'timestamp' || this.returnType === 'date') {
554
553
  if (!Array.isArray(value)) {
555
554
  if (!this.hasTime) {
556
555
  value = value + ' ' + '00:00:00';
557
556
  }
558
557
  value = this.createTimestamp(value);
559
558
  if (this.returnType === 'date') {
560
559
  value = new Date(value);
561
560
  }
562
561
  } else {
563
562
  if (!this.hasTime) {
564
563
  value[0] = value[0] + ' ' + '00:00:00';
565
564
  value[1] = value[1] + ' ' + '00:00:00';
566
565
  }
567
566
  value[0] = this.createTimestamp(value[0]);
568
567
  value[1] = this.createTimestamp(value[1]);
569
568
  if (this.returnType === 'date') {
570
569
  value[0] = new Date(value[0]);
571
570
  value[1] = new Date(value[1]);
572
571
  }
573
572
  }
574
573
  }
575
574
  this.$emit('update:modelValue', value);
576
575
  this.$emit('input', value);
577
576
  this.$emit('change', value);
578
577
  this.isEmitValue = true;
579
578
  },
580
579
  createTimestamp(date) {
581
580
  date = fixIosDateFormat(date);
582
581
  return Date.parse(new Date(date));
583
582
  },
584
583
  singleChange(e) {
585
584
  this.calendarDate = this.inputDate = e.fulldate;
586
585
  if (this.hasTime) return;
587
586
  this.confirmSingleChange();
588
587
  },
589
588
  confirmSingleChange() {
590
589
  if (!checkDate(this.inputDate)) {
591
590
  const now = new Date();
592
591
  this.calendarDate = this.inputDate = getDate(now);
593
592
  this.pickerTime = getTime(now, this.hideSecond);
594
593
  }
595
594
  let startLaterInputDate = false;
596
595
  let startDate, startTime;
597
596
  if (this.start) {
598
597
  let startString = this.start;
599
598
  if (typeof this.start === 'number') {
600
599
  startString = getDateTime(this.start, this.hideSecond);
601
600
  }
602
601
  [startDate, startTime] = startString.split(' ');
603
602
  if (this.start && !dateCompare(startDate, this.inputDate)) {
604
603
  startLaterInputDate = true;
605
604
  this.inputDate = startDate;
606
605
  }
607
606
  }
608
607
  let endEarlierInputDate = false;
609
608
  let endDate, endTime;
610
609
  if (this.end) {
611
610
  let endString = this.end;
612
611
  if (typeof this.end === 'number') {
613
612
  endString = getDateTime(this.end, this.hideSecond);
614
613
  }
615
614
  [endDate, endTime] = endString.split(' ');
616
615
  if (this.end && !dateCompare(this.inputDate, endDate)) {
617
616
  endEarlierInputDate = true;
618
617
  this.inputDate = endDate;
619
618
  }
620
619
  }
621
620
  if (this.hasTime) {
622
621
  if (startLaterInputDate) {
623
622
  this.pickerTime = startTime || getDefaultSecond(this.hideSecond);
624
623
  }
625
624
  if (endEarlierInputDate) {
626
625
  this.pickerTime = endTime || getDefaultSecond(this.hideSecond);
627
626
  }
628
627
  if (!this.pickerTime) {
629
628
  this.pickerTime = getTime(Date.now(), this.hideSecond);
630
629
  }
631
630
  this.displayValue = `${this.inputDate} ${this.pickerTime}`;
632
631
  } else {
633
632
  this.displayValue = this.inputDate;
634
633
  }
635
634
  this.setEmit(this.displayValue);
636
635
  this.pickerVisible = false;
637
636
  },
638
637
  leftChange(e) {
639
638
  const { before, after } = e.range;
640
639
  this.rangeChange(before, after);
641
640
  const obj = {
642
641
  before: e.range.before,
643
642
  after: e.range.after,
644
643
  data: e.range.data,
645
644
  fulldate: e.fulldate
646
645
  };
647
646
  this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj);
648
647
  },
649
648
  rightChange(e) {
650
649
  const { before, after } = e.range;
651
650
  this.rangeChange(before, after);
652
651
  const obj = {
653
652
  before: e.range.before,
654
653
  after: e.range.after,
655
654
  data: e.range.data,
656
655
  fulldate: e.fulldate
657
656
  };
658
657
  this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj);
659
658
  },
660
659
  mobileChange(e) {
661
660
  if (this.isRange) {
662
661
  const { before, after } = e.range;
663
662
  if (!before || !after) {
664
663
  return;
665
664
  }
666
665
  this.handleStartAndEnd(before, after, true);
667
666
  if (this.hasTime) {
668
667
  const { startTime, endTime } = e.timeRange;
669
668
  this.tempRange.startTime = startTime;
670
669
  this.tempRange.endTime = endTime;
671
670
  }
672
671
  this.confirmRangeChange();
673
672
  } else {
674
673
  if (this.hasTime) {
675
674
  this.displayValue = e.fulldate + ' ' + e.time;
676
675
  } else {
677
676
  this.displayValue = e.fulldate;
678
677
  }
679
678
  this.setEmit(this.displayValue);
680
679
  }
681
680
  this.$refs.mobile.close();
682
681
  },
683
682
  rangeChange(before, after) {
684
683
  if (!(before && after)) return;
685
684
  this.handleStartAndEnd(before, after, true);
686
685
  if (this.hasTime) return;
687
686
  this.confirmRangeChange();
688
687
  },
689
688
  confirmRangeChange() {
690
689
  if (!this.tempRange.startDate || !this.tempRange.endDate) {
691
690
  this.pickerVisible = false;
692
691
  return;
693
692
  }
694
693
  if (!checkDate(this.tempRange.startDate)) {
695
694
  this.tempRange.startDate = getDate(Date.now());
696
695
  }
697
696
  if (!checkDate(this.tempRange.endDate)) {
698
697
  this.tempRange.endDate = getDate(Date.now());
699
698
  }
700
699
  let start, end;
701
700
  let startDateLaterRangeStartDate = false;
702
701
  let startDateLaterRangeEndDate = false;
703
702
  let startDate, startTime;
704
703
  if (this.start) {
705
704
  let startString = this.start;
706
705
  if (typeof this.start === 'number') {
707
706
  startString = getDateTime(this.start, this.hideSecond);
708
707
  }
709
708
  [startDate, startTime] = startString.split(' ');
710
709
  if (this.start && !dateCompare(this.start, this.tempRange.startDate)) {
711
710
  startDateLaterRangeStartDate = true;
712
711
  this.tempRange.startDate = startDate;
713
712
  }
714
713
  if (this.start && !dateCompare(this.start, this.tempRange.endDate)) {
715
714
  startDateLaterRangeEndDate = true;
716
715
  this.tempRange.endDate = startDate;
717
716
  }
718
717
  }
719
718
  let endDateEarlierRangeStartDate = false;
720
719
  let endDateEarlierRangeEndDate = false;
721
720
  let endDate, endTime;
722
721
  if (this.end) {
723
722
  let endString = this.end;
724
723
  if (typeof this.end === 'number') {
725
724
  endString = getDateTime(this.end, this.hideSecond);
726
725
  }
727
726
  [endDate, endTime] = endString.split(' ');
728
727
  if (this.end && !dateCompare(this.tempRange.startDate, this.end)) {
729
728
  endDateEarlierRangeStartDate = true;
730
729
  this.tempRange.startDate = endDate;
731
730
  }
732
731
  if (this.end && !dateCompare(this.tempRange.endDate, this.end)) {
733
732
  endDateEarlierRangeEndDate = true;
734
733
  this.tempRange.endDate = endDate;
735
734
  }
736
735
  }
737
736
  if (!this.hasTime) {
738
737
  start = this.displayRangeValue.startDate = this.tempRange.startDate;
739
738
  end = this.displayRangeValue.endDate = this.tempRange.endDate;
740
739
  } else {
741
740
  if (startDateLaterRangeStartDate) {
742
741
  this.tempRange.startTime = startTime || getDefaultSecond(this.hideSecond);
743
742
  } else if (endDateEarlierRangeStartDate) {
744
743
  this.tempRange.startTime = endTime || getDefaultSecond(this.hideSecond);
745
744
  }
746
745
  if (!this.tempRange.startTime) {
747
746
  this.tempRange.startTime = getTime(Date.now(), this.hideSecond);
748
747
  }
749
748
  if (startDateLaterRangeEndDate) {
750
749
  this.tempRange.endTime = startTime || getDefaultSecond(this.hideSecond);
751
750
  } else if (endDateEarlierRangeEndDate) {
752
751
  this.tempRange.endTime = endTime || getDefaultSecond(this.hideSecond);
753
752
  }
754
753
  if (!this.tempRange.endTime) {
755
754
  this.tempRange.endTime = getTime(Date.now(), this.hideSecond);
756
755
  }
757
756
  start = this.displayRangeValue.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`;
758
757
  end = this.displayRangeValue.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`;
759
758
  }
760
759
  if (!dateCompare(start, end)) {
761
760
  [start, end] = [end, start];
762
761
  }
763
762
  this.displayRangeValue.startDate = start;
764
763
  this.displayRangeValue.endDate = end;
765
764
  const displayRange = [start, end];
766
765
  this.setEmit(displayRange);
767
766
  this.pickerVisible = false;
768
767
  },
769
768
  handleStartAndEnd(before, after, temp = false) {
770
769
  if (!(before && after)) return;
771
770
  const type = temp ? 'tempRange' : 'range';
772
771
  const isStartEarlierEnd = dateCompare(before, after);
773
772
  this[type].startDate = isStartEarlierEnd ? before : after;
774
773
  this[type].endDate = isStartEarlierEnd ? after : before;
775
774
  },
776
775
  /**
777
776
  * 比较时间大小
778
777
  */
779
778
  dateCompare(startDate, endDate) {
780
779
  // 计算截止时间
781
780
  startDate = new Date(startDate.replace('-', '/').replace('-', '/'));
782
781
  // 计算详细项的截止时间
783
782
  endDate = new Date(endDate.replace('-', '/').replace('-', '/'));
784
783
  return startDate <= endDate;
785
784
  },
786
785
  /**
787
786
  * 比较时间差
788
787
  */
789
788
  diffDate(startDate, endDate) {
790
789
  // 计算截止时间
791
790
  startDate = new Date(startDate.replace('-', '/').replace('-', '/'));
792
791
  // 计算详细项的截止时间
793
792
  endDate = new Date(endDate.replace('-', '/').replace('-', '/'));
794
793
  const diff = (endDate - startDate) / (24 * 60 * 60 * 1000);
795
794
  return Math.abs(diff);
796
795
  },
797
796
  clear(needEmit = true) {
798
797
  if (!this.isRange) {
799
798
  this.displayValue = '';
800
799
  this.inputDate = '';
801
800
  this.pickerTime = '';
802
801
  if (this.isPhone) {
803
802
  this.$refs.mobile && this.$refs.mobile.clearCalender();
804
803
  } else {
805
804
  this.$refs.pcSingle && this.$refs.pcSingle.clearCalender();
806
805
  }
807
806
  if (needEmit) {
808
807
  this.$emit('change', '');
809
808
  this.$emit('input', '');
810
809
  this.$emit('update:modelValue', '');
811
810
  }
812
811
  } else {
813
812
  this.displayRangeValue.startDate = '';
814
813
  this.displayRangeValue.endDate = '';
815
814
  this.tempRange.startDate = '';
816
815
  this.tempRange.startTime = '';
817
816
  this.tempRange.endDate = '';
818
817
  this.tempRange.endTime = '';
819
818
  if (this.isPhone) {
820
819
  this.$refs.mobile && this.$refs.mobile.clearCalender();
821
820
  } else {
822
821
  this.$refs.left && this.$refs.left.clearCalender();
823
822
  this.$refs.right && this.$refs.right.clearCalender();
824
823
  this.$refs.right && this.$refs.right.changeMonth('next');
825
824
  }
826
825
  if (needEmit) {
827
826
  this.$emit('change', []);
828
827
  this.$emit('input', []);
829
828
  this.$emit('update:modelValue', []);
830
829
  }
831
830
  }
832
831
  }
833
832
  }
833
+ <template>
834
+ <view class="uni-date">
835
+ <view class="uni-date-editor" @click="show">
836
+ <slot>
837
+ <view class="uni-date-editor--x" :class="{ 'uni-date-editor--x__disabled': disabled, 'uni-date-x--border': border }">
838
+ <view v-if="!isRange" class="uni-date-x uni-date-single">
839
+ <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
840
+ <view class="uni-date__x-input">{{ displayValue || singlePlaceholderText }}</view>
841
+ </view>
842
+ <view v-else class="uni-date-x uni-date-range">
843
+ <uni-icons class="icon-calendar" type="calendar" color="#c0c4cc" size="22"></uni-icons>
844
+ <view class="uni-date__x-input text-center">{{ displayRangeValue.startDate || startPlaceholderText }}</view>
845
+ <view class="range-separator">{{ rangeSeparator }}</view>
846
+ <view class="uni-date__x-input text-center">{{ displayRangeValue.endDate || endPlaceholderText }}</view>
847
+ </view>
848
+ <view v-if="showClearIcon" class="uni-date__icon-clear" @click.stop="clear">
849
+ <uni-icons type="clear" color="#c0c4cc" size="22"></uni-icons>
850
+ </view>
851
+ </view>
852
+ </slot>
853
+ </view>
854
+ <view v-show="pickerVisible" class="uni-date-mask--pc" @click="close"></view>
855
+ <view v-if="!isPhone" v-show="pickerVisible" ref="datePicker" class="uni-date-picker__container">
856
+ <view v-if="!isRange" class="uni-date-single--x" :style="pickerPositionStyle">
857
+ <view class="uni-popper__arrow"></view>
858
+ <view v-if="hasTime" class="uni-date-changed popup-x-header">
859
+ <input class="uni-date__input text-center" type="text" v-model="inputDate" :placeholder="selectDateText" />
860
+ <time-picker
861
+ type="time"
862
+ v-model="pickerTime"
863
+ :border="false"
864
+ :disabled="!inputDate"
865
+ :start="timepickerStartTime"
866
+ :end="timepickerEndTime"
867
+ :hideSecond="hideSecond"
868
+ style="width: 100%"
869
+ >
870
+ <input
871
+ class="uni-date__input text-center"
872
+ type="text"
873
+ v-model="pickerTime"
874
+ :placeholder="selectTimeText"
875
+ :disabled="!inputDate"
876
+ />
877
+ </time-picker>
878
+ </view>
879
+ <Calendar
880
+ ref="pcSingle"
881
+ :showMonth="false"
882
+ :start-date="calendarRange.startDate"
883
+ :end-date="calendarRange.endDate"
884
+ :date="calendarDate"
885
+ @change="singleChange"
886
+ :default-value="defaultValue"
887
+ style="padding: 0 8px"
888
+ />
889
+ <view v-if="hasTime" class="popup-x-footer">
890
+ <text class="confirm-text" @click="confirmSingleChange">{{ okText }}</text>
891
+ </view>
892
+ </view>
893
+ <view v-else class="uni-date-range--x" :style="pickerPositionStyle">
894
+ <view class="uni-popper__arrow"></view>
895
+ <view v-if="hasTime" class="popup-x-header uni-date-changed">
896
+ <view class="popup-x-header--datetime">
897
+ <input
898
+ class="uni-date__input uni-date-range__input"
899
+ type="text"
900
+ v-model="tempRange.startDate"
901
+ :placeholder="startDateText"
902
+ />
903
+ <time-picker
904
+ type="time"
905
+ v-model="tempRange.startTime"
906
+ :start="timepickerStartTime"
907
+ :border="false"
908
+ :disabled="!tempRange.startDate"
909
+ :hideSecond="hideSecond"
910
+ >
911
+ <input
912
+ class="uni-date__input uni-date-range__input"
913
+ type="text"
914
+ v-model="tempRange.startTime"
915
+ :placeholder="startTimeText"
916
+ :disabled="!tempRange.startDate"
917
+ />
918
+ </time-picker>
919
+ </view>
920
+ <uni-icons type="arrowthinright" color="#999" style="line-height: 40px"></uni-icons>
921
+ <view class="popup-x-header--datetime">
922
+ <input
923
+ class="uni-date__input uni-date-range__input"
924
+ type="text"
925
+ v-model="tempRange.endDate"
926
+ :placeholder="endDateText"
927
+ />
928
+ <time-picker
929
+ type="time"
930
+ v-model="tempRange.endTime"
931
+ :end="timepickerEndTime"
932
+ :border="false"
933
+ :disabled="!tempRange.endDate"
934
+ :hideSecond="hideSecond"
935
+ >
936
+ <input
937
+ class="uni-date__input uni-date-range__input"
938
+ type="text"
939
+ v-model="tempRange.endTime"
940
+ :placeholder="endTimeText"
941
+ :disabled="!tempRange.endDate"
942
+ />
943
+ </time-picker>
944
+ </view>
945
+ </view>
946
+ <view class="popup-x-body">
947
+ <Calendar
948
+ ref="left"
949
+ :showMonth="false"
950
+ :start-date="calendarRange.startDate"
951
+ :end-date="calendarRange.endDate"
952
+ :range="true"
953
+ :pleStatus="endMultipleStatus"
954
+ @change="leftChange"
955
+ @firstEnterCale="updateRightCale"
956
+ style="padding: 0 8px"
957
+ />
958
+ <Calendar
959
+ ref="right"
960
+ :showMonth="false"
961
+ :start-date="calendarRange.startDate"
962
+ :end-date="calendarRange.endDate"
963
+ :range="true"
964
+ @change="rightChange"
965
+ :pleStatus="startMultipleStatus"
966
+ @firstEnterCale="updateLeftCale"
967
+ style="padding: 0 8px; border-left: 1px solid #f1f1f1"
968
+ />
969
+ </view>
970
+ <view v-if="hasTime" class="popup-x-footer">
971
+ <text @click="clear">{{ clearText }}</text>
972
+ <text class="confirm-text" @click="confirmRangeChange">{{ okText }}</text>
973
+ </view>
974
+ </view>
975
+ </view>
976
+ <Calendar
977
+ v-if="isPhone"
978
+ ref="mobile"
979
+ :clearDate="false"
980
+ :date="calendarDate"
981
+ :defTime="mobileCalendarTime"
982
+ :start-date="calendarRange.startDate"
983
+ :end-date="calendarRange.endDate"
984
+ :selectableTimes="mobSelectableTime"
985
+ :startPlaceholder="startPlaceholder"
986
+ :endPlaceholder="endPlaceholder"
987
+ :default-value="defaultValue"
988
+ :pleStatus="endMultipleStatus"
989
+ :showMonth="false"
990
+ :range="isRange"
991
+ :hasTime="hasTime"
992
+ :insert="false"
993
+ :hideSecond="hideSecond"
994
+ @confirm="mobileChange"
995
+ @maskClose="close"
996
+ />
997
+ </view>
998
+ </template>
999
+ <script>
1000
+ /**
1001
+ * DatetimePicker 时间选择器
1002
+ * @description 同时支持 PC 和移动端使用日历选择日期和日期范围
1003
+ * @tutorial https://ext.dcloud.net.cn/plugin?id=3962
1004
+ * @property {String} type 选择器类型
1005
+ * @property {String|Number|Array|Date} value 绑定值
1006
+ * @property {String} placeholder 单选择时的占位内容
1007
+ * @property {String} start 起始时间
1008
+ * @property {String} end 终止时间
1009
+ * @property {String} start-placeholder 范围选择时开始日期的占位内容
1010
+ * @property {String} end-placeholder 范围选择时结束日期的占位内容
1011
+ * @property {String} range-separator 选择范围时的分隔符
1012
+ * @property {Boolean} border = [true|false] 是否有边框
1013
+ * @property {Boolean} disabled = [true|false] 是否禁用
1014
+ * @property {Boolean} clearIcon = [true|false] 是否显示清除按钮(仅PC端适用)
1015
+ * @property {[String} defaultValue 选择器打开时默认显示的时间
1016
+ * @event {Function} change 确定日期时触发的事件
1017
+ * @event {Function} maskClick 点击遮罩层触发的事件
1018
+ * @event {Function} show 打开弹出层
1019
+ * @event {Function} close 关闭弹出层
1020
+ * @event {Function} clear 清除上次选中的状态和值
1021
+ **/
1022
+ import Calendar from './calendar.vue';
1023
+ import TimePicker from './time-picker.vue';
1024
+ import { initVueI18n } from '@dcloudio/uni-i18n';
1025
+ import i18nMessages from './i18n/index.js';
1026
+ import { getDateTime, getDate, getTime, getDefaultSecond, dateCompare, checkDate, fixIosDateFormat } from './util';
1027
+ export default {
1028
+ name: 'UniDatetimePicker',
1029
+ options: {
1030
+ virtualHost: true
1031
+ },
1032
+ components: {
1033
+ Calendar,
1034
+ TimePicker
1035
+ },
1036
+ data() {
1037
+ return {
1038
+ isRange: false,
1039
+ hasTime: false,
1040
+ displayValue: '',
1041
+ inputDate: '',
1042
+ calendarDate: '',
1043
+ pickerTime: '',
1044
+ calendarRange: {
1045
+ startDate: '',
1046
+ startTime: '',
1047
+ endDate: '',
1048
+ endTime: ''
1049
+ },
1050
+ displayRangeValue: {
1051
+ startDate: '',
1052
+ endDate: ''
1053
+ },
1054
+ tempRange: {
1055
+ startDate: '',
1056
+ startTime: '',
1057
+ endDate: '',
1058
+ endTime: ''
1059
+ },
1060
+ // 左右日历同步数据
1061
+ startMultipleStatus: {
1062
+ before: '',
1063
+ after: '',
1064
+ data: [],
1065
+ fulldate: ''
1066
+ },
1067
+ endMultipleStatus: {
1068
+ before: '',
1069
+ after: '',
1070
+ data: [],
1071
+ fulldate: ''
1072
+ },
1073
+ pickerVisible: false,
1074
+ pickerPositionStyle: null,
1075
+ isEmitValue: false,
1076
+ isPhone: false,
1077
+ isFirstShow: true,
1078
+ i18nT: () => {}
1079
+ };
1080
+ },
1081
+ props: {
1082
+ type: {
1083
+ type: String,
1084
+ default: 'datetime'
1085
+ },
1086
+ value: {
1087
+ type: [String, Number, Array, Date],
1088
+ default: ''
1089
+ },
1090
+ modelValue: {
1091
+ type: [String, Number, Array, Date],
1092
+ default: ''
1093
+ },
1094
+ start: {
1095
+ type: [Number, String],
1096
+ default: ''
1097
+ },
1098
+ end: {
1099
+ type: [Number, String],
1100
+ default: ''
1101
+ },
1102
+ returnType: {
1103
+ type: String,
1104
+ default: 'string'
1105
+ },
1106
+ placeholder: {
1107
+ type: String,
1108
+ default: ''
1109
+ },
1110
+ startPlaceholder: {
1111
+ type: String,
1112
+ default: ''
1113
+ },
1114
+ endPlaceholder: {
1115
+ type: String,
1116
+ default: ''
1117
+ },
1118
+ rangeSeparator: {
1119
+ type: String,
1120
+ default: '-'
1121
+ },
1122
+ border: {
1123
+ type: [Boolean],
1124
+ default: true
1125
+ },
1126
+ disabled: {
1127
+ type: [Boolean],
1128
+ default: false
1129
+ },
1130
+ clearIcon: {
1131
+ type: [Boolean],
1132
+ default: true
1133
+ },
1134
+ hideSecond: {
1135
+ type: [Boolean],
1136
+ default: false
1137
+ },
1138
+ defaultValue: {
1139
+ type: [String, Object, Array],
1140
+ default: ''
1141
+ }
1142
+ },
1143
+ watch: {
1144
+ type: {
1145
+ immediate: true,
1146
+ handler(newVal) {
1147
+ this.hasTime = newVal.indexOf('time') !== -1;
1148
+ this.isRange = newVal.indexOf('range') !== -1;
1149
+ }
1150
+ },
1151
+ // #ifndef VUE3
1152
+ value: {
1153
+ immediate: true,
1154
+ handler(newVal) {
1155
+ if (this.isEmitValue) {
1156
+ this.isEmitValue = false;
1157
+ return;
1158
+ }
1159
+ this.initPicker(newVal);
1160
+ }
1161
+ },
1162
+ // #endif
1163
+ // #ifdef VUE3
1164
+ modelValue: {
1165
+ immediate: true,
1166
+ handler(newVal) {
1167
+ if (this.isEmitValue) {
1168
+ this.isEmitValue = false;
1169
+ return;
1170
+ }
1171
+ this.initPicker(newVal);
1172
+ }
1173
+ },
1174
+ // #endif
1175
+ start: {
1176
+ immediate: true,
1177
+ handler(newVal) {
1178
+ if (!newVal) return;
1179
+ this.calendarRange.startDate = getDate(newVal);
1180
+ if (this.hasTime) {
1181
+ this.calendarRange.startTime = getTime(newVal);
1182
+ }
1183
+ }
1184
+ },
1185
+ end: {
1186
+ immediate: true,
1187
+ handler(newVal) {
1188
+ if (!newVal) return;
1189
+ this.calendarRange.endDate = getDate(newVal);
1190
+ if (this.hasTime) {
1191
+ this.calendarRange.endTime = getTime(newVal, this.hideSecond);
1192
+ }
1193
+ }
1194
+ }
1195
+ },
1196
+ computed: {
1197
+ timepickerStartTime() {
1198
+ const activeDate = this.isRange ? this.tempRange.startDate : this.inputDate;
1199
+ return activeDate === this.calendarRange.startDate ? this.calendarRange.startTime : '';
1200
+ },
1201
+ timepickerEndTime() {
1202
+ const activeDate = this.isRange ? this.tempRange.endDate : this.inputDate;
1203
+ return activeDate === this.calendarRange.endDate ? this.calendarRange.endTime : '';
1204
+ },
1205
+ mobileCalendarTime() {
1206
+ const timeRange = {
1207
+ start: this.tempRange.startTime,
1208
+ end: this.tempRange.endTime
1209
+ };
1210
+ return this.isRange ? timeRange : this.pickerTime;
1211
+ },
1212
+ mobSelectableTime() {
1213
+ return {
1214
+ start: this.calendarRange.startTime,
1215
+ end: this.calendarRange.endTime
1216
+ };
1217
+ },
1218
+ datePopupWidth() {
1219
+ // todo
1220
+ return this.isRange ? 653 : 301;
1221
+ },
1222
+ /**
1223
+ * for i18n
1224
+ */
1225
+ singlePlaceholderText() {
1226
+ return this.placeholder || (this.type === 'date' ? this.selectDateText : this.selectDateTimeText);
1227
+ },
1228
+ startPlaceholderText() {
1229
+ return this.startPlaceholder || this.startDateText;
1230
+ },
1231
+ endPlaceholderText() {
1232
+ return this.endPlaceholder || this.endDateText;
1233
+ },
1234
+ selectDateText() {
1235
+ return this.i18nT('uni-datetime-picker.selectDate');
1236
+ },
1237
+ selectDateTimeText() {
1238
+ return this.i18nT('uni-datetime-picker.selectDateTime');
1239
+ },
1240
+ selectTimeText() {
1241
+ return this.i18nT('uni-datetime-picker.selectTime');
1242
+ },
1243
+ startDateText() {
1244
+ return this.startPlaceholder || this.i18nT('uni-datetime-picker.startDate');
1245
+ },
1246
+ startTimeText() {
1247
+ return this.i18nT('uni-datetime-picker.startTime');
1248
+ },
1249
+ endDateText() {
1250
+ return this.endPlaceholder || this.i18nT('uni-datetime-picker.endDate');
1251
+ },
1252
+ endTimeText() {
1253
+ return this.i18nT('uni-datetime-picker.endTime');
1254
+ },
1255
+ okText() {
1256
+ return this.i18nT('uni-datetime-picker.ok');
1257
+ },
1258
+ clearText() {
1259
+ return this.i18nT('uni-datetime-picker.clear');
1260
+ },
1261
+ showClearIcon() {
1262
+ return (
1263
+ this.clearIcon &&
1264
+ !this.disabled &&
1265
+ (this.displayValue || (this.displayRangeValue.startDate && this.displayRangeValue.endDate))
1266
+ );
1267
+ }
1268
+ },
1269
+ created() {
1270
+ this.initI18nT();
1271
+ this.platform();
1272
+ },
1273
+ methods: {
1274
+ initI18nT() {
1275
+ const vueI18n = initVueI18n(i18nMessages);
1276
+ this.i18nT = vueI18n.t;
1277
+ },
1278
+ initPicker(newVal) {
1279
+ if ((!newVal && !this.defaultValue) || (Array.isArray(newVal) && !newVal.length)) {
1280
+ this.$nextTick(() => {
1281
+ this.clear(false);
1282
+ });
1283
+ return;
1284
+ }
1285
+ if (!Array.isArray(newVal) && !this.isRange) {
1286
+ if (newVal) {
1287
+ this.displayValue = this.inputDate = this.calendarDate = getDate(newVal);
1288
+ if (this.hasTime) {
1289
+ this.pickerTime = getTime(newVal, this.hideSecond);
1290
+ this.displayValue = `${this.displayValue} ${this.pickerTime}`;
1291
+ }
1292
+ } else if (this.defaultValue) {
1293
+ this.inputDate = this.calendarDate = getDate(this.defaultValue);
1294
+ if (this.hasTime) {
1295
+ this.pickerTime = getTime(this.defaultValue, this.hideSecond);
1296
+ }
1297
+ }
1298
+ } else {
1299
+ const [before, after] = newVal;
1300
+ if (!before && !after) return;
1301
+ const beforeDate = getDate(before);
1302
+ const beforeTime = getTime(before, this.hideSecond);
1303
+ const afterDate = getDate(after);
1304
+ const afterTime = getTime(after, this.hideSecond);
1305
+ const startDate = beforeDate;
1306
+ const endDate = afterDate;
1307
+ this.displayRangeValue.startDate = this.tempRange.startDate = startDate;
1308
+ this.displayRangeValue.endDate = this.tempRange.endDate = endDate;
1309
+ if (this.hasTime) {
1310
+ this.displayRangeValue.startDate = `${beforeDate} ${beforeTime}`;
1311
+ this.displayRangeValue.endDate = `${afterDate} ${afterTime}`;
1312
+ this.tempRange.startTime = beforeTime;
1313
+ this.tempRange.endTime = afterTime;
1314
+ }
1315
+ const defaultRange = {
1316
+ before: beforeDate,
1317
+ after: afterDate
1318
+ };
1319
+ this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, defaultRange, {
1320
+ which: 'right'
1321
+ });
1322
+ this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, defaultRange, {
1323
+ which: 'left'
1324
+ });
1325
+ }
1326
+ },
1327
+ updateLeftCale(e) {
1328
+ const left = this.$refs.left;
1329
+ // 设置范围选
1330
+ left.cale.setHoverMultiple(e.after);
1331
+ left.setDate(this.$refs.left.nowDate.fullDate);
1332
+ },
1333
+ updateRightCale(e) {
1334
+ const right = this.$refs.right;
1335
+ // 设置范围选
1336
+ right.cale.setHoverMultiple(e.after);
1337
+ right.setDate(this.$refs.right.nowDate.fullDate);
1338
+ },
1339
+ platform() {
1340
+ if (typeof navigator !== 'undefined') {
1341
+ this.isPhone = navigator.userAgent.toLowerCase().indexOf('mobile') !== -1;
1342
+ return;
1343
+ }
1344
+ const { windowWidth } = uni.getSystemInfoSync();
1345
+ this.isPhone = windowWidth <= 500;
1346
+ this.windowWidth = windowWidth;
1347
+ },
1348
+ show() {
1349
+ if (this.disabled) {
1350
+ return;
1351
+ }
1352
+ this.platform();
1353
+ if (this.isPhone) {
1354
+ setTimeout(() => {
1355
+ this.$refs.mobile.open();
1356
+ }, 0);
1357
+ return;
1358
+ }
1359
+ this.pickerPositionStyle = {
1360
+ top: '10px'
1361
+ };
1362
+ const dateEditor = uni.createSelectorQuery().in(this).select('.uni-date-editor');
1363
+ dateEditor
1364
+ .boundingClientRect((rect) => {
1365
+ if (this.windowWidth - rect.left < this.datePopupWidth) {
1366
+ this.pickerPositionStyle.right = 0;
1367
+ }
1368
+ })
1369
+ .exec();
1370
+ setTimeout(() => {
1371
+ this.pickerVisible = !this.pickerVisible;
1372
+ if (!this.isPhone && this.isRange && this.isFirstShow) {
1373
+ this.isFirstShow = false;
1374
+ const { startDate, endDate } = this.calendarRange;
1375
+ if (startDate && endDate) {
1376
+ if (this.diffDate(startDate, endDate) < 30) {
1377
+ this.$refs.right.changeMonth('pre');
1378
+ }
1379
+ } else {
1380
+ this.$refs.right.changeMonth('next');
1381
+ this.$refs.right.cale.lastHover = false;
1382
+ }
1383
+ }
1384
+ }, 50);
1385
+ },
1386
+ close() {
1387
+ setTimeout(() => {
1388
+ this.pickerVisible = false;
1389
+ this.$emit('maskClick', this.value);
1390
+ this.$refs.mobile && this.$refs.mobile.close();
1391
+ }, 20);
1392
+ },
1393
+ setEmit(value) {
1394
+ if (this.returnType === 'timestamp' || this.returnType === 'date') {
1395
+ if (!Array.isArray(value)) {
1396
+ if (!this.hasTime) {
1397
+ value = value + ' ' + '00:00:00';
1398
+ }
1399
+ value = this.createTimestamp(value);
1400
+ if (this.returnType === 'date') {
1401
+ value = new Date(value);
1402
+ }
1403
+ } else {
1404
+ if (!this.hasTime) {
1405
+ value[0] = value[0] + ' ' + '00:00:00';
1406
+ value[1] = value[1] + ' ' + '00:00:00';
1407
+ }
1408
+ value[0] = this.createTimestamp(value[0]);
1409
+ value[1] = this.createTimestamp(value[1]);
1410
+ if (this.returnType === 'date') {
1411
+ value[0] = new Date(value[0]);
1412
+ value[1] = new Date(value[1]);
1413
+ }
1414
+ }
1415
+ }
1416
+ this.$emit('update:modelValue', value);
1417
+ this.$emit('input', value);
1418
+ this.$emit('change', value);
1419
+ this.isEmitValue = true;
1420
+ },
1421
+ createTimestamp(date) {
1422
+ date = fixIosDateFormat(date);
1423
+ return Date.parse(new Date(date));
1424
+ },
1425
+ singleChange(e) {
1426
+ this.calendarDate = this.inputDate = e.fulldate;
1427
+ if (this.hasTime) return;
1428
+ this.confirmSingleChange();
1429
+ },
1430
+ confirmSingleChange() {
1431
+ if (!checkDate(this.inputDate)) {
1432
+ const now = new Date();
1433
+ this.calendarDate = this.inputDate = getDate(now);
1434
+ this.pickerTime = getTime(now, this.hideSecond);
1435
+ }
1436
+ let startLaterInputDate = false;
1437
+ let startDate, startTime;
1438
+ if (this.start) {
1439
+ let startString = this.start;
1440
+ if (typeof this.start === 'number') {
1441
+ startString = getDateTime(this.start, this.hideSecond);
1442
+ }
1443
+ [startDate, startTime] = startString.split(' ');
1444
+ if (this.start && !dateCompare(startDate, this.inputDate)) {
1445
+ startLaterInputDate = true;
1446
+ this.inputDate = startDate;
1447
+ }
1448
+ }
1449
+ let endEarlierInputDate = false;
1450
+ let endDate, endTime;
1451
+ if (this.end) {
1452
+ let endString = this.end;
1453
+ if (typeof this.end === 'number') {
1454
+ endString = getDateTime(this.end, this.hideSecond);
1455
+ }
1456
+ [endDate, endTime] = endString.split(' ');
1457
+ if (this.end && !dateCompare(this.inputDate, endDate)) {
1458
+ endEarlierInputDate = true;
1459
+ this.inputDate = endDate;
1460
+ }
1461
+ }
1462
+ if (this.hasTime) {
1463
+ if (startLaterInputDate) {
1464
+ this.pickerTime = startTime || getDefaultSecond(this.hideSecond);
1465
+ }
1466
+ if (endEarlierInputDate) {
1467
+ this.pickerTime = endTime || getDefaultSecond(this.hideSecond);
1468
+ }
1469
+ if (!this.pickerTime) {
1470
+ this.pickerTime = getTime(Date.now(), this.hideSecond);
1471
+ }
1472
+ this.displayValue = `${this.inputDate} ${this.pickerTime}`;
1473
+ } else {
1474
+ this.displayValue = this.inputDate;
1475
+ }
1476
+ this.setEmit(this.displayValue);
1477
+ this.pickerVisible = false;
1478
+ },
1479
+ leftChange(e) {
1480
+ const { before, after } = e.range;
1481
+ this.rangeChange(before, after);
1482
+ const obj = {
1483
+ before: e.range.before,
1484
+ after: e.range.after,
1485
+ data: e.range.data,
1486
+ fulldate: e.fulldate
1487
+ };
1488
+ this.startMultipleStatus = Object.assign({}, this.startMultipleStatus, obj);
1489
+ },
1490
+ rightChange(e) {
1491
+ const { before, after } = e.range;
1492
+ this.rangeChange(before, after);
1493
+ const obj = {
1494
+ before: e.range.before,
1495
+ after: e.range.after,
1496
+ data: e.range.data,
1497
+ fulldate: e.fulldate
1498
+ };
1499
+ this.endMultipleStatus = Object.assign({}, this.endMultipleStatus, obj);
1500
+ },
1501
+ mobileChange(e) {
1502
+ if (this.isRange) {
1503
+ const { before, after } = e.range;
1504
+ if (!before || !after) {
1505
+ return;
1506
+ }
1507
+ this.handleStartAndEnd(before, after, true);
1508
+ if (this.hasTime) {
1509
+ const { startTime, endTime } = e.timeRange;
1510
+ this.tempRange.startTime = startTime;
1511
+ this.tempRange.endTime = endTime;
1512
+ }
1513
+ this.confirmRangeChange();
1514
+ } else {
1515
+ if (this.hasTime) {
1516
+ this.displayValue = e.fulldate + ' ' + e.time;
1517
+ } else {
1518
+ this.displayValue = e.fulldate;
1519
+ }
1520
+ this.setEmit(this.displayValue);
1521
+ }
1522
+ this.$refs.mobile.close();
1523
+ },
1524
+ rangeChange(before, after) {
1525
+ if (!(before && after)) return;
1526
+ this.handleStartAndEnd(before, after, true);
1527
+ if (this.hasTime) return;
1528
+ this.confirmRangeChange();
1529
+ },
1530
+ confirmRangeChange() {
1531
+ if (!this.tempRange.startDate || !this.tempRange.endDate) {
1532
+ this.pickerVisible = false;
1533
+ return;
1534
+ }
1535
+ if (!checkDate(this.tempRange.startDate)) {
1536
+ this.tempRange.startDate = getDate(Date.now());
1537
+ }
1538
+ if (!checkDate(this.tempRange.endDate)) {
1539
+ this.tempRange.endDate = getDate(Date.now());
1540
+ }
1541
+ let start, end;
1542
+ let startDateLaterRangeStartDate = false;
1543
+ let startDateLaterRangeEndDate = false;
1544
+ let startDate, startTime;
1545
+ if (this.start) {
1546
+ let startString = this.start;
1547
+ if (typeof this.start === 'number') {
1548
+ startString = getDateTime(this.start, this.hideSecond);
1549
+ }
1550
+ [startDate, startTime] = startString.split(' ');
1551
+ if (this.start && !dateCompare(this.start, this.tempRange.startDate)) {
1552
+ startDateLaterRangeStartDate = true;
1553
+ this.tempRange.startDate = startDate;
1554
+ }
1555
+ if (this.start && !dateCompare(this.start, this.tempRange.endDate)) {
1556
+ startDateLaterRangeEndDate = true;
1557
+ this.tempRange.endDate = startDate;
1558
+ }
1559
+ }
1560
+ let endDateEarlierRangeStartDate = false;
1561
+ let endDateEarlierRangeEndDate = false;
1562
+ let endDate, endTime;
1563
+ if (this.end) {
1564
+ let endString = this.end;
1565
+ if (typeof this.end === 'number') {
1566
+ endString = getDateTime(this.end, this.hideSecond);
1567
+ }
1568
+ [endDate, endTime] = endString.split(' ');
1569
+ if (this.end && !dateCompare(this.tempRange.startDate, this.end)) {
1570
+ endDateEarlierRangeStartDate = true;
1571
+ this.tempRange.startDate = endDate;
1572
+ }
1573
+ if (this.end && !dateCompare(this.tempRange.endDate, this.end)) {
1574
+ endDateEarlierRangeEndDate = true;
1575
+ this.tempRange.endDate = endDate;
1576
+ }
1577
+ }
1578
+ if (!this.hasTime) {
1579
+ start = this.displayRangeValue.startDate = this.tempRange.startDate;
1580
+ end = this.displayRangeValue.endDate = this.tempRange.endDate;
1581
+ } else {
1582
+ if (startDateLaterRangeStartDate) {
1583
+ this.tempRange.startTime = startTime || getDefaultSecond(this.hideSecond);
1584
+ } else if (endDateEarlierRangeStartDate) {
1585
+ this.tempRange.startTime = endTime || getDefaultSecond(this.hideSecond);
1586
+ }
1587
+ if (!this.tempRange.startTime) {
1588
+ this.tempRange.startTime = getTime(Date.now(), this.hideSecond);
1589
+ }
1590
+ if (startDateLaterRangeEndDate) {
1591
+ this.tempRange.endTime = startTime || getDefaultSecond(this.hideSecond);
1592
+ } else if (endDateEarlierRangeEndDate) {
1593
+ this.tempRange.endTime = endTime || getDefaultSecond(this.hideSecond);
1594
+ }
1595
+ if (!this.tempRange.endTime) {
1596
+ this.tempRange.endTime = getTime(Date.now(), this.hideSecond);
1597
+ }
1598
+ start = this.displayRangeValue.startDate = `${this.tempRange.startDate} ${this.tempRange.startTime}`;
1599
+ end = this.displayRangeValue.endDate = `${this.tempRange.endDate} ${this.tempRange.endTime}`;
1600
+ }
1601
+ if (!dateCompare(start, end)) {
1602
+ [start, end] = [end, start];
1603
+ }
1604
+ this.displayRangeValue.startDate = start;
1605
+ this.displayRangeValue.endDate = end;
1606
+ const displayRange = [start, end];
1607
+ this.setEmit(displayRange);
1608
+ this.pickerVisible = false;
1609
+ },
1610
+ handleStartAndEnd(before, after, temp = false) {
1611
+ if (!(before && after)) return;
1612
+ const type = temp ? 'tempRange' : 'range';
1613
+ const isStartEarlierEnd = dateCompare(before, after);
1614
+ this[type].startDate = isStartEarlierEnd ? before : after;
1615
+ this[type].endDate = isStartEarlierEnd ? after : before;
1616
+ },
1617
+ /**
1618
+ * 比较时间大小
1619
+ */
1620
+ dateCompare(startDate, endDate) {
1621
+ // 计算截止时间
1622
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'));
1623
+ // 计算详细项的截止时间
1624
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'));
1625
+ return startDate <= endDate;
1626
+ },
1627
+ /**
1628
+ * 比较时间差
1629
+ */
1630
+ diffDate(startDate, endDate) {
1631
+ // 计算截止时间
1632
+ startDate = new Date(startDate.replace('-', '/').replace('-', '/'));
1633
+ // 计算详细项的截止时间
1634
+ endDate = new Date(endDate.replace('-', '/').replace('-', '/'));
1635
+ const diff = (endDate - startDate) / (24 * 60 * 60 * 1000);
1636
+ return Math.abs(diff);
1637
+ },
1638
+ clear(needEmit = true) {
1639
+ if (!this.isRange) {
1640
+ this.displayValue = '';
1641
+ this.inputDate = '';
1642
+ this.pickerTime = '';
1643
+ if (this.isPhone) {
1644
+ this.$refs.mobile && this.$refs.mobile.clearCalender();
1645
+ } else {
1646
+ this.$refs.pcSingle && this.$refs.pcSingle.clearCalender();
1647
+ }
1648
+ if (needEmit) {
1649
+ this.$emit('change', '');
1650
+ this.$emit('input', '');
1651
+ this.$emit('update:modelValue', '');
1652
+ }
1653
+ } else {
1654
+ this.displayRangeValue.startDate = '';
1655
+ this.displayRangeValue.endDate = '';
1656
+ this.tempRange.startDate = '';
1657
+ this.tempRange.startTime = '';
1658
+ this.tempRange.endDate = '';
1659
+ this.tempRange.endTime = '';
1660
+ if (this.isPhone) {
1661
+ this.$refs.mobile && this.$refs.mobile.clearCalender();
1662
+ } else {
1663
+ this.$refs.left && this.$refs.left.clearCalender();
1664
+ this.$refs.right && this.$refs.right.clearCalender();
1665
+ this.$refs.right && this.$refs.right.changeMonth('next');
1666
+ }
1667
+ if (needEmit) {
1668
+ this.$emit('change', []);
1669
+ this.$emit('input', []);
1670
+ this.$emit('update:modelValue', []);
1671
+ }
1672
+ }
1673
+ }
1674
+ }
1675
+ };
1676
+ </script>
1677
+ <style>
1678
+ @import 'style.css';
1679
+ </style>