Blame view

uni_modules/uview-plus/components/u-cascader/u-cascader.vue 29.9 KB
252962bb   刘淇   uni_modu
1
  <template>
9441e28e   刘淇   考勤打卡
2
3
4
5
6
7
8
9
10
11
12
13
  	<u-popup
  		:show="show"
  		mode="bottom"
  		:overlay="overlay"
  		:duration="duration"
  		:overlayStyle="overlayStyle"
  		:overlayOpacity="overlayOpacity"
  		:zIndex="zIndex"
  		:safeAreaInsetBottom="safeAreaInsetBottom"
  		:safeAreaInsetTop="safeAreaInsetTop"
  		:bgColor="bgColor"
  		:closeable="!pageInline"
ecbfbe06   刘淇   树巡检记录
14
  		@close="close"
9441e28e   刘淇   考勤打卡
15
16
17
18
  		@closed="$emit('closed')"
  		:round="round"
  		:pageInline="pageInline"
  		:closeOnClickOverlay="closeOnClickOverlay"
ecbfbe06   刘淇   树巡检记录
19
  	>
9441e28e   刘淇   考勤打卡
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
  		<view class="u-calendar">
  			<uHeader
  				:title="title"
  				:subtitle="subtitle"
  				:showSubtitle="showSubtitle"
  				:showTitle="showTitle"
  				:weekText="weekText"
  				:showSwitch="monthSwitch"
  				:showToday="showToday"
  				:todayText="todayText"
  				:todayDisabled="todayDisabled"
  				:prevDisabled="switchPrevDisabled"
  				:nextDisabled="switchNextDisabled"
  				:prevYearDisabled="switchPrevYearDisabled"
  				:nextYearDisabled="switchNextYearDisabled"
  				@prev="prevMonth"
  				@next="nextMonth"
  				@prevYear="prevYear"
  				@nextYear="nextYear"
  				@today="jumpToToday"
  			></uHeader>
  			<view v-if="showTimePanel" class="u-calendar__time-panel">
  				<view v-if="mode === 'single'" class="u-calendar__time-row">
  					<text class="u-calendar__time-date">{{ singleDateLabel }}</text>
  					<view class="u-calendar__time-trigger" @click="openTimePicker('single')">
  						<text class="u-calendar__time-text">{{ singleTime }}</text>
  					</view>
  				</view>
  				<view v-else-if="mode === 'range' && rangeResultMode === 'boundary'">
  					<view class="u-calendar__time-row">
  						<text class="u-calendar__time-date">{{ rangeStartDateLabel }}</text>
  						<view class="u-calendar__time-trigger" @click="openTimePicker('start')">
  							<text class="u-calendar__time-text">{{ rangeStartTime }}</text>
  						</view>
  					</view>
  					<view class="u-calendar__time-row">
  						<text class="u-calendar__time-date">{{ rangeEndDateLabel }}</text>
  						<view class="u-calendar__time-trigger" @click="openTimePicker('end')">
  							<text class="u-calendar__time-text">{{ rangeEndTime }}</text>
252962bb   刘淇   uni_modu
59
60
  						</view>
  					</view>
9441e28e   刘淇   考勤打卡
61
  				</view>
252962bb   刘淇   uni_modu
62
  			</view>
9441e28e   刘淇   考勤打卡
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  			<scroll-view
  				v-if="!monthSwitch"
  				:style="{
                      height: addUnit(listHeight, 'px')
                  }"
  				scroll-y
  				@scroll="onScroll"
  				:scroll-top="scrollTop"
  				:scrollIntoView="scrollIntoView"
  			>
  				<uMonth
  					:color="color"
  					:rowHeight="rowHeight"
  					:showMark="showMark"
  					:months="months"
  					:mode="mode"
  					:maxCount="maxCount"
  					:startText="startText"
  					:endText="endText"
  					:defaultDate="defaultDate"
  					:minDate="innerMinDate"
  					:maxDate="innerMaxDate"
  					:maxMonth="monthNum"
  					:readonly="readonly"
  					:maxRange="maxRange"
  					:rangePrompt="rangePrompt"
  					:showRangePrompt="showRangePrompt"
  					:allowSameDay="allowSameDay"
  					:forbidDays="forbidDays"
  					:forbidDaysToast="forbidDaysToast"
  					:monthFormat="monthFormat"
  					:todayDate="todayDate"
  					:todayColor="todayColor"
  					ref="month"
  					@monthSelected="monthSelected"
  					@updateMonthTop="onUpdateMonthTop"
  				></uMonth>
  			</scroll-view>
  			<view
  				v-else
  				:style="{
                      height: addUnit(listHeight, 'px')
                  }"
  			>
  				<uMonth
  					:color="color"
  					:rowHeight="rowHeight"
  					:showMark="showMark"
  					:months="currentMonths"
  					:mode="mode"
  					:maxCount="maxCount"
  					:startText="startText"
  					:endText="endText"
  					:defaultDate="defaultDate"
  					:minDate="innerMinDate"
  					:maxDate="innerMaxDate"
  					:maxMonth="monthNum"
  					:readonly="readonly"
  					:maxRange="maxRange"
  					:rangePrompt="rangePrompt"
  					:showRangePrompt="showRangePrompt"
  					:allowSameDay="allowSameDay"
  					:forbidDays="forbidDays"
  					:forbidDaysToast="forbidDaysToast"
  					:monthFormat="monthFormat"
  					:todayDate="todayDate"
  					:todayColor="todayColor"
  					ref="month"
  					@monthSelected="monthSelected"
  					@updateMonthTop="onUpdateMonthTop"
  				></uMonth>
252962bb   刘淇   uni_modu
134
  			</view>
9441e28e   刘淇   考勤打卡
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  			<slot name="footer" v-if="showConfirm">
  				<view class="u-calendar__confirm">
  					<u-button
  						shape="circle"
  						:text="
                              buttonDisabled ? confirmDisabledText : confirmText
                          "
  						:color="color"
  						@click="confirm"
  						:disabled="buttonDisabled"
  					></u-button>
  				</view>
  			</slot>
  		</view>
  	</u-popup>
  	<u-popup
  		:show="timePickerShow"
  		mode="center"
  		:round="8"
  		:closeOnClickOverlay="true"
  		@close="closeTimePicker"
  	>
  		<view class="u-calendar__time-picker">
  			<view class="u-calendar__time-picker__header">
  				<text class="u-calendar__time-picker__cancel" @click="closeTimePicker">取消</text>
  				<text class="u-calendar__time-picker__title">选择时间</text>
  				<text class="u-calendar__time-picker__confirm" @click="confirmTimePicker">确定</text>
252962bb   刘淇   uni_modu
162
  			</view>
9441e28e   刘淇   考勤打卡
163
164
165
166
167
168
169
170
171
172
173
  			<picker-view class="u-calendar__time-picker__body" :value="timePickerValue" @change="onTimePickerChange">
  				<picker-view-column>
  					<view v-for="(item, index) in hourOptions" :key="`h-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
  				</picker-view-column>
  				<picker-view-column v-if="timePrecision !== 'hour'">
  					<view v-for="(item, index) in minuteOptions" :key="`m-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
  				</picker-view-column>
  				<picker-view-column v-if="timePrecision === 'second'">
  					<view v-for="(item, index) in secondOptions" :key="`s-${index}`" class="u-calendar__time-picker__item">{{ item }}</view>
  				</picker-view-column>
  			</picker-view>
252962bb   刘淇   uni_modu
174
  		</view>
9441e28e   刘淇   考勤打卡
175
  	</u-popup>
252962bb   刘淇   uni_modu
176
177
178
  </template>
  
  <script>
9441e28e   刘淇   考勤打卡
179
180
181
182
183
184
185
186
187
188
  import uHeader from './header.vue'
  import uMonth from './month.vue'
  import { props } from './props.js'
  import util from './util.js'
  import dayjs from '../u-datetime-picker/dayjs.esm.min.js';
  import Calendar from '../../libs/util/calendar.js'
  import { mpMixin } from '../../libs/mixin/mpMixin.js'
  import { mixin } from '../../libs/mixin/mixin.js'
  import { addUnit, getPx, range, error, padZero } from '../../libs/function/index';
  import test from '../../libs/function/test';
ecbfbe06   刘淇   树巡检记录
189
  import { t } from '../../libs/i18n'
9441e28e   刘淇   考勤打卡
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
  /**
   * Calendar 日历
   * @description  此组件用于单个选择日期,范围选择日期等,日历被包裹在底部弹起的容器中.
   * @tutorial https://uview-plus.jiangruyi.com/components/calendar.html
   *
   * @property {String}				title				标题内容 (默认 日期选择 )
   * @property {Boolean}				showTitle			是否显示标题  (默认 true )
   * @property {Boolean}				showSubtitle		是否显示副标题	(默认 true )
   * @property {String}				mode				日期类型选择  single-选择单个日期,multiple-可以选择多个日期,range-选择日期范围 ( 默认 'single' )
   * @property {String}				startText			mode=range时,第一个日期底部的提示文字  (默认 '开始' )
   * @property {String}				endText				mode=range时,最后一个日期底部的提示文字 (默认 '结束' )
   * @property {Array}				customList			自定义列表
   * @property {String}				color				主题色,对底部按钮和选中日期有效  (默认 ‘#3c9cff' )
   * @property {String | Number}		minDate				最小的可选日期	 (默认 0 )
   * @property {String | Number}		maxDate				最大可选日期  (默认 0 )
   * @property {Array | String| Date}	defaultDate			默认选中的日期,mode为multiple或range是必须为数组格式
   * @property {String | Number}		maxCount			mode=multiple时,最多可选多少个日期  (默认 	Number.MAX_SAFE_INTEGER  )
   * @property {String | Number}		rowHeight			日期行高 (默认 56 )
   * @property {Function}				formatter			日期格式化函数
   * @property {Boolean}				showLunar			是否显示农历  (默认 false )
   * @property {Boolean}				showMark			是否显示月份背景色 (默认 true )
   * @property {String}				confirmText			确定按钮的文字 (默认 '确定' )
   * @property {String}				confirmDisabledText	确认按钮处于禁用状态时的文字 (默认 '确定' )
   * @property {Boolean}				show				是否显示日历弹窗 (默认 false )
   * @property {Boolean}				overlay				是否显示遮罩 (默认 true )
   * @property {String | Number}		duration			动画时长,单位ms (默认 300 )
   * @property {Object | String}		overlayStyle		自定义遮罩的样式
   * @property {Number | String}		overlayOpacity		遮罩透明度,0-1之间 (默认 0.5 )
   * @property {String | Number}		zIndex				弹出层的z-index值 (默认 10075 )
   * @property {Boolean}				safeAreaInsetBottom	是否留出底部安全距离 (默认 true )
   * @property {Boolean}				safeAreaInsetTop	是否留出顶部安全距离(状态栏高度) (默认 false )
   * @property {String}				bgColor				弹窗背景色,设置为transparent可去除白色背景
   * @property {Boolean}				closeOnClickOverlay	是否允许点击遮罩关闭日历 (默认 false )
   * @property {Boolean}				readonly	        是否为只读状态,只读状态下禁止选择日期 (默认 false )
   * @property {String | Number}		maxRange	        日期区间最多可选天数,默认无限制,mode = range时有效
   * @property {String}				rangePrompt	        范围选择超过最多可选天数时的提示文案,mode = range时有效
   * @property {Boolean}				showRangePrompt	    范围选择超过最多可选天数时,是否展示提示文案,mode = range时有效 (默认 true )
   * @property {Boolean}				allowSameDay	    是否允许日期范围的起止时间为同一天,mode = range时有效 (默认 false )
   * @property {String}				rangeResultMode	    区间模式下确认返回值格式,all-返回区间内所有日期,boundary-仅返回起止日期 (默认 'all' )
   * @property {Boolean}				enableTime			是否开启时分秒选择 (默认 false )
   * @property {String}				timePrecision		时间精度,hour-仅时,minute-时分,second-时分秒 (默认 'minute' )
   * @property {String}				defaultTime			默认时间,支持HH/HH:mm/HH:mm:ss,不传则按00:00补齐
   * @property {Number|String}	    round				圆角值,默认无圆角  (默认 0 )
   * @property {Number|String}	    monthNum			最多展示的月份数量  (默认 3 )
   * @property {Boolean}	            monthSwitch			是否启用非滚动的单月切换模式  (默认 false )
   * @property {String}	            todayColor			今天日期的独立高亮颜色,默认跟随主题色
   * @property {Array}	            weekText			星期文案  (默认 ['一', '二', '三', '四', '五', '六', '日'] )
   *
   * @event {Function()} confirm 		点击确定按钮时触发		选择日期相关的返回参数
   * @event {Function()} close 		日历关闭时触发			可定义页面关闭时的回调事件
   * @event {Function()} closed 	日历已关闭(离场动画结束、弹窗真正消失后)触发
   * @example <u-calendar  :defaultDate="defaultDateMultiple" :show="show" mode="multiple" @confirm="confirm">
  	</u-calendar>
   * */
ecbfbe06   刘淇   树巡检记录
244
  export default {
9441e28e   刘淇   考勤打卡
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
  	name: 'u-calendar',
  	mixins: [mpMixin, mixin, props],
  	components: {
  		uHeader,
  		uMonth
  	},
  	data() {
  		return {
  			// 需要显示的月份的数组
  			months: [],
  			// 在月份滚动区域中,当前视图中月份的index索引
  			monthIndex: 0,
  			// 月份滚动区域的高度
  			listHeight: 0,
  			// month组件中选择的日期数组
  			selected: [],
  			scrollIntoView: '',
  			scrollIntoViewScroll: '',
  			scrollTop:0,
  			timePickerShow: false,
  			timePickerTarget: 'single',
  			timePickerValue: [0, 0, 0],
  			hourOptions: [],
  			minuteOptions: [],
  			secondOptions: [],
  			singleTime: '00:00',
  			rangeStartTime: '00:00',
  			rangeEndTime: '00:00',
  			// 过滤处理方法
  			innerFormatter: (value) => value
  		}
  	},
  	watch: {
  		scrollIntoView: {
  			immediate: true,
  			handler(n) {
  				// console.log('scrollIntoView', n)
  			}
  		},
  		selectedChange: {
  			immediate: true,
  			handler(n) {
  				this.setMonth()
  			}
  		},
  		timePrecision() {
  			this.initTimeOptions()
  			this.initTimeValues()
  		},
  		defaultTime() {
  			this.initTimeValues()
  		},
  		// 打开弹窗时,设置月份数据
ecbfbe06   刘淇   树巡检记录
298
  		show: {
9441e28e   刘淇   考勤打卡
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
  			immediate: true,
  			handler(n) {
  				if (n) {
  					this.setMonth()
  					// 弹层每次打开都会重新挂载并滚动回默认月份,副标题指向的月份索引要一起复位,
  					// 否则会沿用上一次关闭前滚动到的月份,导致副标题与日历内容对应不上。
  					// 页面内模式的内容一直挂载着,滚动位置不会重置,所以不做处理
  					if (!this.pageInline) {
  						this.monthIndex = this.getDefaultMonthIndex()
  					}
  				} else {
  					// 关闭时重置scrollIntoView,否则会出现二次打开日历,当前月份数据显示不正确。
  					// scrollIntoView需要有一个值变动过程,才会产生作用。
  					this.scrollIntoView = ''
  				}
  			}
  		}
  	},
  	computed: {
  		// 由于maxDate和minDate可以为字符串(2021-10-10),或者数值(时间戳),但是dayjs如果接受字符串形式的时间戳会有问题,这里进行处理
  		innerMaxDate() {
  			return test.number(this.maxDate)
  				? Number(this.maxDate)
  				: this.maxDate
ecbfbe06   刘淇   树巡检记录
323
  		},
9441e28e   刘淇   考勤打卡
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
  		innerMinDate() {
  			return test.number(this.minDate)
  				? Number(this.minDate)
  				: this.minDate
  		},
  		todayDate() {
  			return dayjs().format('YYYY-MM-DD')
  		},
  		todayText() {
  			return t('up.calendar.today')
  		},
  		todayDisabled() {
  			const today = dayjs(this.todayDate)
  			const minDate = this.innerMinDate
  				? dayjs(this.innerMinDate)
  				: null
  			const maxDate = this.innerMaxDate
  				? dayjs(this.innerMaxDate)
  				: null
  			if (minDate && today.isBefore(minDate, 'day')) {
  				return true
  			}
  			if (maxDate && today.isAfter(maxDate, 'day')) {
  				return true
  			}
  			return false
  		},
  		// 多个条件的变化,会引起选中日期的变化,这里统一管理监听
  		selectedChange() {
  			return [this.innerMinDate, this.innerMaxDate, this.defaultDate]
  		},
  		subtitle() {
  			// 初始化时,this.months为空数组,所以需要特别判断处理
  			if (this.months.length) {
  				if (uni.getLocale() == 'zh-Hans' || uni.getLocale() == 'zh-Hant') {
  					return this.months[this.monthIndex].year + '年' + (this.months[this.monthIndex].month < 10 ? '0' + this.months[this.monthIndex].month : this.months[this.monthIndex].month) + '月'
  				} else {
  					return (this.months[this.monthIndex].month < 10 ? '0' + this.months[this.monthIndex].month : this.months[this.monthIndex].month) + '/' + this.months[this.monthIndex].year
  				}
  			} else {
  				return ''
252962bb   刘淇   uni_modu
365
366
  			}
  		},
9441e28e   刘淇   考勤打卡
367
368
369
  		currentMonths() {
  			if (this.monthSwitch && this.months.length) {
  				return [this.months[this.monthIndex]]
252962bb   刘淇   uni_modu
370
  			}
9441e28e   刘淇   考勤打卡
371
  			return this.months
252962bb   刘淇   uni_modu
372
  		},
9441e28e   刘淇   考勤打卡
373
374
  		switchPrevDisabled() {
  			return this.monthIndex <= 0
ecbfbe06   刘淇   树巡检记录
375
  		},
9441e28e   刘淇   考勤打卡
376
377
  		switchNextDisabled() {
  			return this.monthIndex >= this.months.length - 1
ecbfbe06   刘淇   树巡检记录
378
  		},
9441e28e   刘淇   考勤打卡
379
380
  		switchPrevYearDisabled() {
  			return this.monthIndex - 12 < 0
ecbfbe06   刘淇   树巡检记录
381
  		},
9441e28e   刘淇   考勤打卡
382
383
  		switchNextYearDisabled() {
  			return this.monthIndex + 12 > this.months.length - 1
ecbfbe06   刘淇   树巡检记录
384
  		},
9441e28e   刘淇   考勤打卡
385
386
387
388
389
390
391
  		showTimePanel() {
  			if (!this.enableTime) return false
  			if (this.mode === 'single') return true
  			if (this.mode === 'range' && this.rangeResultMode === 'boundary') {
  				return true
  			}
  			return false
ecbfbe06   刘淇   树巡检记录
392
  		},
9441e28e   刘淇   考勤打卡
393
394
  		singleDateLabel() {
  			return this.selected[0] || '--'
ecbfbe06   刘淇   树巡检记录
395
  		},
9441e28e   刘淇   考勤打卡
396
397
  		rangeStartDateLabel() {
  			return this.selected[0] || '--'
ecbfbe06   刘淇   树巡检记录
398
  		},
9441e28e   刘淇   考勤打卡
399
400
401
402
403
  		rangeEndDateLabel() {
  			if (this.selected.length >= 2) {
  				return this.selected[this.selected.length - 1]
  			}
  			return '--'
ecbfbe06   刘淇   树巡检记录
404
  		},
9441e28e   刘淇   考勤打卡
405
406
407
408
409
410
411
412
413
414
415
  		buttonDisabled() {
  			// 如果为range类型,且选择的日期个数不足1个时,让底部的按钮出于disabled状态
  			if (this.mode === 'range') {
  				if (this.selected.length <= 1) {
  					return true
  				} else {
  					return false
  				}
  			} else {
  				return false
  			}
ecbfbe06   刘淇   树巡检记录
416
417
  		}
  	},
9441e28e   刘淇   考勤打卡
418
419
420
  	mounted() {
  		this.start = Date.now()
  		this.init()
ecbfbe06   刘淇   树巡检记录
421
  	},
9441e28e   刘淇   考勤打卡
422
423
424
425
426
  	emits: ["confirm", "close", "closed"],
  	methods: {
  		addUnit,
  		padTime(num) {
  			return String(num).padStart(2, '0')
ecbfbe06   刘淇   树巡检记录
427
  		},
9441e28e   刘淇   考勤打卡
428
429
430
431
432
433
434
435
436
437
438
439
  		initTimeOptions() {
  			this.hourOptions = Array.from({ length: 24 }, (_, i) => this.padTime(i))
  			this.minuteOptions = Array.from({ length: 60 }, (_, i) => this.padTime(i))
  			this.secondOptions = Array.from({ length: 60 }, (_, i) => this.padTime(i))
  		},
  		parseTimeValue(value = '') {
  			const raw = String(value || '').trim()
  			const parts = raw.length ? raw.split(':') : []
  			const getNumber = (index, max) => {
  				const current = Number(parts[index] || 0)
  				if (Number.isNaN(current)) return 0
  				return Math.max(0, Math.min(max, current))
252962bb   刘淇   uni_modu
440
  			}
9441e28e   刘淇   考勤打卡
441
442
443
444
  			const hour = getNumber(0, 23)
  			const minute = getNumber(1, 59)
  			const second = getNumber(2, 59)
  			return [hour, minute, second]
252962bb   刘淇   uni_modu
445
  		},
9441e28e   刘淇   考勤打卡
446
447
448
449
450
451
452
453
454
  		getDefaultTimeValue() {
  			const [hour, minute, second] = this.parseTimeValue(this.defaultTime)
  			if (this.timePrecision === 'hour') {
  				return this.padTime(hour)
  			}
  			if (this.timePrecision === 'second') {
  				return `${this.padTime(hour)}:${this.padTime(minute)}:${this.padTime(second)}`
  			}
  			return `${this.padTime(hour)}:${this.padTime(minute)}`
ecbfbe06   刘淇   树巡检记录
455
  		},
9441e28e   刘淇   考勤打卡
456
457
458
459
460
  		initTimeValues() {
  			const value = this.getDefaultTimeValue()
  			this.singleTime = value
  			this.rangeStartTime = value
  			this.rangeEndTime = value
ecbfbe06   刘淇   树巡检记录
461
  		},
9441e28e   刘淇   考勤打卡
462
463
464
465
466
467
468
469
470
471
  		timeToPickerValue(value = '') {
  			const [hour, minute, second] = this.parseTimeValue(value)
  			return [hour, minute, second]
  		},
  		pickerValueToTime(value = []) {
  			const hour = Number(value[0] || 0)
  			const minute = Number(value[1] || 0)
  			const second = Number(value[2] || 0)
  			if (this.timePrecision === 'hour') {
  				return this.padTime(hour)
ecbfbe06   刘淇   树巡检记录
472
  			}
9441e28e   刘淇   考勤打卡
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  			if (this.timePrecision === 'second') {
  				return `${this.padTime(hour)}:${this.padTime(minute)}:${this.padTime(second)}`
  			}
  			return `${this.padTime(hour)}:${this.padTime(minute)}`
  		},
  		openTimePicker(target) {
  			this.timePickerTarget = target
  			let currentValue = this.singleTime
  			if (target === 'start') currentValue = this.rangeStartTime
  			if (target === 'end') currentValue = this.rangeEndTime
  			this.timePickerValue = this.timeToPickerValue(currentValue)
  			this.timePickerShow = true
  		},
  		onTimePickerChange(e) {
  			this.timePickerValue = e.detail.value
  		},
  		closeTimePicker() {
  			this.timePickerShow = false
  		},
  		confirmTimePicker() {
  			const value = this.pickerValueToTime(this.timePickerValue)
  			if (this.timePickerTarget === 'single') this.singleTime = value
  			if (this.timePickerTarget === 'start') this.rangeStartTime = value
  			if (this.timePickerTarget === 'end') this.rangeEndTime = value
  			this.timePickerShow = false
ecbfbe06   刘淇   树巡检记录
498
  		},
9441e28e   刘淇   考勤打卡
499
500
501
502
503
504
505
  		timeToSecond(timeText = '') {
  			const [hour, minute, second] = this.parseTimeValue(timeText)
  			return hour * 3600 + minute * 60 + second
  		},
  		validateSameDayRangeTime() {
  			if (!this.enableTime || this.mode !== 'range' || this.rangeResultMode !== 'boundary') {
  				return true
ecbfbe06   刘淇   树巡检记录
506
  			}
9441e28e   刘淇   考勤打卡
507
508
509
510
511
512
513
514
515
516
517
518
  			if (this.selected.length < 2) return true
  			const startDate = this.selected[0]
  			const endDate = this.selected[this.selected.length - 1]
  			if (startDate !== endDate) return true
  			const startSeconds = this.timeToSecond(this.rangeStartTime)
  			const endSeconds = this.timeToSecond(this.rangeEndTime)
  			if (endSeconds < startSeconds) {
  				uni.showToast({
  					title: '结束时间不能早于开始时间',
  					icon: 'none'
  				})
  				return false
ecbfbe06   刘淇   树巡检记录
519
  			}
9441e28e   刘淇   考勤打卡
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
  			return true
  		},
  		appendTime(dateText, timeText) {
  			return `${dateText} ${timeText}`
  		},
  		getConfirmValue(selected = this.selected) {
  			let result = selected
  			if (
  				this.mode === 'range' &&
  				this.rangeResultMode === 'boundary' &&
  				selected.length >= 2
  			) {
  				const len = selected.length - 1
  				result = [selected[0], selected[len]]
  			}
  			if (!this.showTimePanel || !this.enableTime) {
  				return result
  			}
  			if (this.mode === 'single' && result.length >= 1) {
  				return [this.appendTime(result[0], this.singleTime)]
  			}
  			if (this.mode === 'range' && this.rangeResultMode === 'boundary' && result.length >= 2) {
  				return [
  					this.appendTime(result[0], this.rangeStartTime),
  					this.appendTime(result[1], this.rangeEndTime)
  				]
  			}
  			return result
  		},
  		// 在微信小程序中,不支持将函数当做props参数,故只能通过ref形式调用
  		setFormatter(e) {
  			this.innerFormatter = e
  		},
  		// month组件内部选择日期后,通过事件通知给父组件
  		monthSelected(e,scene ='init') {
  			this.selected = e
  			if (!this.showConfirm) {
  				// 在不需要确认按钮的情况下,如果为单选,或者范围多选且已选长度大于2,则直接进行返还
  				if (
  					this.mode === 'multiple' ||
  					this.mode === 'single' ||
  					(this.mode === 'range' && this.selected.length >= 2)
  				) {
  				   if( scene === 'init'){
  					 return
  				   }
  				   if( scene === 'tap') {
  					 if (!this.validateSameDayRangeTime()) return
  					 this.$emit('confirm', this.getConfirmValue())
  				   }
252962bb   刘淇   uni_modu
570
  				}
ecbfbe06   刘淇   树巡检记录
571
  			}
ecbfbe06   刘淇   树巡检记录
572
  		},
9441e28e   刘淇   考勤打卡
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  		init() {
  			// 校验maxDate,不能小于minDate。
  			if (
  				this.innerMaxDate &&
                  this.innerMinDate &&
  				new Date(this.innerMaxDate).getTime() < new Date(this.innerMinDate).getTime()
  			) {
  				return error('maxDate不能小于minDate时间')
  			}
  			// 滚动区域的高度
  			let bottomPadding = 0;
  			if (this.pageInline) {
  				bottomPadding = 0
  			} else {
  				bottomPadding = 30
  			}
  			this.listHeight = this.rowHeight * (this.monthSwitch ? 6 : 5) + bottomPadding
  			this.initTimeOptions()
  			this.initTimeValues()
  			this.setMonth()
  		},
ecbfbe06   刘淇   树巡检记录
594
  		close() {
9441e28e   刘淇   考勤打卡
595
  			this.$emit('close')
ecbfbe06   刘淇   树巡检记录
596
  		},
9441e28e   刘淇   考勤打卡
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
  		// 点击确定按钮
  		confirm() {
  			if (!this.buttonDisabled) {
  				if (!this.validateSameDayRangeTime()) return
  				this.$emit('confirm', this.getConfirmValue())
  			}
  		},
  		// 获得两个日期之间的月份数
  		getMonths(minDate, maxDate) {
  			const minYear = dayjs(minDate).year()
  			const minMonth = dayjs(minDate).month() + 1
  			const maxYear = dayjs(maxDate).year()
  			const maxMonth = dayjs(maxDate).month() + 1
  			return (maxYear - minYear) * 12 + (maxMonth - minMonth) + 1
  		},
  		// 设置月份数据
  		setMonth() {
  			// 最小日期的毫秒数
  			const minDate = this.innerMinDate || dayjs().valueOf()
  			// 如果没有指定最大日期,则往后推3个月
  			const maxDate =
  				this.innerMaxDate ||
  				dayjs(minDate)
  					.add(this.monthNum - 1, 'month')
  					.valueOf()
  			// 最大最小月份之间的共有多少个月份,
  			const months = range(
  				1,
  				this.monthNum,
  				this.getMonths(minDate, maxDate)
  			)
  			// 记录上一次测量到的各月份top值,月份未发生变化时高度也不会变,
  			// 复用后可避免重新生成数据后onScroll没有判断依据
  			const topCache = {}
  			this.months.forEach(item => {
  				if (typeof item.top === 'number') {
  					topCache[`${item.year}-${item.month}`] = item.top
252962bb   刘淇   uni_modu
634
  				}
9441e28e   刘淇   考勤打卡
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
  			})
  			// 先清空数组
  			this.months = []
  			// 最大最小日期只需格式化一次,YYYY-MM-DD的字典序即时间序,可直接比较字符串
  			const minDateStr = dayjs(minDate).format('YYYY-MM-DD')
  			const maxDateStr = dayjs(maxDate).format('YYYY-MM-DD')
  			const formatter = this.formatter || this.innerFormatter
  			for (let i = 0; i < months; i++) {
  				// 每个月只构造一个dayjs对象,当月的日期数据都由它派生,
  				// 避免按天重复解析(monthNum较大时这里是主要开销)
  				const monthStart = dayjs(minDate).add(i, 'month')
  				const monthValue = monthStart.month() + 1
  				this.months.push({
  					date: new Array(monthStart.daysInMonth())
  						.fill(1)
  						.map((item, index) => {
  							// 日期,取值1-31
  							let day = index + 1
  							const current = monthStart.date(day)
  							// 星期,0-6,0为周日
  							const week = current.day()
  							const date = current.format('YYYY-MM-DD')
  							let bottomInfo = ''
  							if (this.showLunar) {
  								// 将日期转为农历格式
  								const lunar = Calendar.solar2lunar(
  									current.year(),
  									monthValue,
  									day
  								)
  								bottomInfo = lunar.IDayCn
  							}
  							let config = {
  								day,
  								week,
  								// 小于最小允许的日期,或者大于最大的日期,则设置为disabled状态
  								disabled:
  									date < minDateStr || date > maxDateStr,
  								// 返回一个日期对象,供外部的formatter获取当前日期的年月日等信息,进行加工处理
  								date: new Date(date),
  								// 已格式化好的日期字符串,供month组件比较使用,
  								// 省掉渲染期对每个日期格子的重复解析
  								dateStr: date,
  								bottomInfo,
  								dot: false,
  								month: monthValue
  							}
  							return formatter(config)
  						}),
  					// 当前所属的月份
  					month: monthValue,
  					// 当前年份
  					year: monthStart.year()
  				})
  			}
  			this.months.forEach(item => {
  				const cachedTop = topCache[`${item.year}-${item.month}`]
  				if (typeof cachedTop === 'number') {
  					item.top = cachedTop
  				}
  			})
  			if (this.monthSwitch) {
  				this.monthIndex = this.getDefaultMonthIndex()
  			}
  		},
  		getDefaultMonthIndex() {
  			let selected = dayjs().format('YYYY-MM')
  			if (this.defaultDate) {
  				if (!test.array(this.defaultDate)) {
  					selected = dayjs(this.defaultDate).format('YYYY-MM')
  				} else if (this.defaultDate.length) {
  					selected = dayjs(this.defaultDate[0]).format('YYYY-MM')
  				}
  			}
  			const index = this.months.findIndex(({ year, month }) => {
  				return `${year}-${padZero(month)}` === selected
  			})
  			return index === -1 ? 0 : index
  		},
  		prevMonth() {
  			if (!this.switchPrevDisabled) {
  				this.monthIndex -= 1
  			}
  		},
  		nextMonth() {
  			if (!this.switchNextDisabled) {
  				this.monthIndex += 1
  			}
  		},
  		prevYear() {
  			if (!this.switchPrevYearDisabled) {
  				this.monthIndex -= 12
  			}
  		},
  		nextYear() {
  			if (!this.switchNextYearDisabled) {
  				this.monthIndex += 12
  			}
  		},
  		jumpToToday() {
  			if (this.todayDisabled) {
  				return
  			}
  			const targetMonth = dayjs(this.todayDate).format('YYYY-MM')
  			const selectToday = () => {
  				if (this.mode === 'range') {
  					return
  				}
  				this.$refs.month && this.$refs.month.selectDate(this.todayDate)
  			}
  			if (this.monthSwitch) {
  				const todayMonthIndex = this.months.findIndex(({ year, month }) => {
  					return `${year}-${padZero(month)}` === targetMonth
  				})
  				if (todayMonthIndex !== -1) {
  					this.monthIndex = todayMonthIndex
  					this.$nextTick(selectToday)
252962bb   刘淇   uni_modu
752
  				}
9441e28e   刘淇   考勤打卡
753
  				return
ecbfbe06   刘淇   树巡检记录
754
  			}
9441e28e   刘淇   考勤打卡
755
756
  			this.scrollIntoDefaultMonth(targetMonth)
  			this.$nextTick(selectToday)
ecbfbe06   刘淇   树巡检记录
757
  		},
9441e28e   刘淇   考勤打卡
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
  		// 滚动到默认设置的月份
  		scrollIntoDefaultMonth(selected) {
  			// 查询默认日期在可选列表的下标
  			const _index = this.months.findIndex(({
  				  year,
  				  month
  			  }) => {
  				month = padZero(month)
  				return `${year}-${month}` === selected
  			})
  			if (_index !== -1) {
  				// 滚动位置是程序主动设置的,同步更新副标题指向的月份索引。
  				// 只依赖scroll事件的话,滚动位置没有真正变化时收不到事件,副标题就会停留在上一次的月份
  				this.monthIndex = _index
  				// #ifndef MP-WEIXIN
  				this.$nextTick(() => {
  					this.scrollIntoView = ''
  					this.scrollIntoView = `month-${_index}`
  					this.scrollIntoViewScroll = this.scrollIntoView
  				})
  				// #endif
  				// #ifdef MP-WEIXIN
  				// scrollTop与scrollIntoView同理,需要有一个值变动过程才会生效,
  				// 否则二次打开日历时沿用上次的数值,scroll-view不会滚动到默认月份
  				const _top = this.months[_index].top || 0;
  				this.scrollTop = 0;
  				if (_top !== 0) {
  					this.$nextTick(() => {
  						this.scrollTop = _top;
  					})
  				}
  				// #endif
252962bb   刘淇   uni_modu
790
  			}
ecbfbe06   刘淇   树巡检记录
791
  		},
9441e28e   刘淇   考勤打卡
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
  		// scroll-view滚动监听
  		onScroll(event) {
  			// 不允许小于0的滚动值,如果scroll-view到顶了,继续下拉,会出现负数值
  			const scrollTop = Math.max(0, event.detail.scrollTop)
  			// 月份的top值尚未测量出来时不做判断,否则所有月份的判断阈值相同,
  			// 会把副标题固定到最后一个月份上
  			if (!this.months.some(item => typeof item.top === 'number')) return
  			// 将当前滚动条数值,与各月份的top值比较,可以得出当前滚动到了哪一个月份的索引
  			let monthIndex = 0
  			for (let i = 0; i < this.months.length; i++) {
  				const top = this.months[i].top
  				if (typeof top !== 'number') continue
  				if (scrollTop >= top) {
  					monthIndex = i
  				} else {
  					break
  				}
  			}
  			this.monthIndex = monthIndex
  			this.scrollIntoViewScroll = `month-${monthIndex}`
  		},
  		// 更新月份的top值
  		onUpdateMonthTop(topArr = []) {
  			if (this.monthSwitch) {
  				return
  			}
  			this.updateMonthTop(topArr)
ecbfbe06   刘淇   树巡检记录
819
  		},
9441e28e   刘淇   考勤打卡
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  		updateMonthTop(topArr = []) {
  			// 设置对应月份的top值,用于onScroll方法更新月份
  			topArr.map((item, index) => {
  				this.months[index].top = item
  			})
  
  			// 获取默认日期的下标
  			if (!this.defaultDate) {
  				// 如果没有设置默认日期,则将当天日期设置为默认选中的日期
  				const selected = dayjs().format("YYYY-MM")
  				this.scrollIntoDefaultMonth(selected)
  				return
  			}
  			let selected = dayjs().format("YYYY-MM");
  			// 单选模式,可以是字符串或数组,Date对象等
  			if (!test.array(this.defaultDate)) {
  				selected = dayjs(this.defaultDate).format("YYYY-MM")
  			} else {
  				selected = dayjs(this.defaultDate[0]).format("YYYY-MM");
ecbfbe06   刘淇   树巡检记录
839
  			}
9441e28e   刘淇   考勤打卡
840
  			this.scrollIntoDefaultMonth(selected)
252962bb   刘淇   uni_modu
841
842
  		}
  	}
ecbfbe06   刘淇   树巡检记录
843
  }
252962bb   刘淇   uni_modu
844
  </script>
ecbfbe06   刘淇   树巡检记录
845
  
9441e28e   刘淇   考勤打卡
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
  <style lang="scss" scoped>
  .u-calendar {
  	color: var(--up-main-color, $u-main-color);
  	background-color: var(--up-card-bg-color, #ffffff);
  
  	&__time-panel {
  		padding: 8px 16px 0;
  	}
  
  	&__time-row {
  		height: 34px;
  		display: flex;
  		align-items: center;
  		justify-content: space-between;
  		margin-bottom: 6px;
  	}
  
  	&__time-date {
  		font-size: 13px;
  		color: #303133;
  	}
  
  	&__time-trigger {
  		min-width: 92px;
  		height: 30px;
  		padding: 0 10px;
  		border-radius: 15px;
  		border: 1px solid #dcdfe6;
  		display: flex;
  		align-items: center;
  		justify-content: center;
  	}
  
  	&__time-text {
  		font-size: 14px;
  		color: #303133;
  	}
  
  	&__time-picker {
  		width: 320px;
  		background-color: #ffffff;
  		border-radius: 8px;
252962bb   刘淇   uni_modu
888
  		overflow: hidden;
9441e28e   刘淇   考勤打卡
889
  	}
252962bb   刘淇   uni_modu
890
  
9441e28e   刘淇   考勤打卡
891
892
893
894
895
896
897
898
  	&__time-picker__header {
  		height: 44px;
  		padding: 0 14px;
  		display: flex;
  		align-items: center;
  		justify-content: space-between;
  		border-bottom: 1px solid #f0f0f0;
  	}
252962bb   刘淇   uni_modu
899
  
9441e28e   刘淇   考勤打卡
900
901
902
903
  	&__time-picker__cancel {
  		font-size: 14px;
  		color: #909399;
  	}
252962bb   刘淇   uni_modu
904
  
9441e28e   刘淇   考勤打卡
905
906
907
908
  	&__time-picker__title {
  		font-size: 15px;
  		color: #303133;
  		font-weight: 600;
252962bb   刘淇   uni_modu
909
  	}
ecbfbe06   刘淇   树巡检记录
910
  
9441e28e   刘淇   考勤打卡
911
912
913
  	&__time-picker__confirm {
  		font-size: 14px;
  		color: #3c9cff;
252962bb   刘淇   uni_modu
914
  	}
9441e28e   刘淇   考勤打卡
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  
  	&__time-picker__body {
  		width: 320px;
  		height: 200px;
  	}
  
  	&__time-picker__item {
  		height: 40px;
  		line-height: 40px;
  		text-align: center;
  		font-size: 16px;
  		color: #303133;
  	}
  
  	&__confirm {
  		padding: 7px 18px;
  	}
  }
  </style>