<!-- ### 组件说明
* 日期时间选择器
* 组件的默认日期有效期范围为："1970-01-01 00:00" - "2300-01-01 00:00"。
* 注意：如果您传递的日期有效范围的结束日期小于开始日期，则日期有效范围的结束日期会自动修正为开始日期+300年，比如，您传递的日期有效范围的开始日期为 "2020-11-11 18:30"，
* 结束日期为 "2018-11-11 18:30"，则此时将会自动修正结束日期为 "2320-11-11 18:30"。
* 注意：如果您传递的默认值不在日期有效范围内，则会自动修正默认值为当前日期时间，如果当前日期时间也不在日期有效范围内，则会再次修正为日期有效范围的开始日期。
* 注意：该组件用到了我自己封装的 utils.js，位置在 '@/common/js/utils.js'。


### 插件 props 属性
* disabled: 是否禁用该组件？Boolean类型；
* placeholder: 组件没有选中值时显示的内容，String类型；
* start: 表示有效日期时间范围的开始，String类型，格式为 "YYYY-MM-DD hh:mm"；
* end: 表示有效日期时间范围的结束，String类型，格式必为 "YYYY-MM-DD hh:mm"；
* fields: 选择器的粒度，String类型，有效值为 year、month、day、hour、minute；
* defaultValue: 默认值，String类型，格式为 "YYYY-MM-DD hh:mm"；

### 插件事件
- change(date)：选择日期时间后的回调事件。
 * date.YYYY: 年；
 * date.M: 月；
 * date.MM: 月（补0）；
 * date.D: 日；
 * date.DD: 日（补0）；
 * date.h: 时；
 * date.hh: 时（补0）；
 * date.m: 分；
 * date.mm: 分（补0）；
 * date.dt: Date对象；
 * ... 还有一些其他的字段，具体看返回值吧！ -->
<template>
	<view class="datatime">
		<picker 
			mode="multiSelector" 
			:range="range" 
			range-key="text" 
			@change="change" 
			@columnchange="columnchange" 
			:value="value" 
			:disabled="disabled"
		>
			<view class="content" :class="{ placeholder: !dateStr }">
				<text>{{ dateStr ? dateStr : placeholder }}</text>
			</view>
		</picker>
	</view>
</template>

<script>
export default {
	props: {
		// 是否禁用
		disabled: {
			type: Boolean,
			default: false
		},
		// 占位符
		placeholder: {
			type: String,
			default: '请选择日期时间'
		},
		// 表示有效日期时间范围的开始，
		// 字符串格式为 "YYYY-MM-DD hh:mm"
		start: {
			type: String,
			default: '2010-1-1 00:00'
		},
		// 表示有效日期时间范围的结束
		// 字符串格式为 "YYYY-MM-DD hh:mm"
		end: {
			type: String,
			default: '2300-1-1 00:00'
		},
		// 表示选择器的粒度，有效值：year | month | day | hour | minute
		fields: {
			type: String,
			default: 'minute'
		},
		// 默认值
		// 字符串格式为 "YYYY-MM-DD hh:mm"
		defaultValue: {
			type: String,
			default: '0000-00-00 00:00'
		}
	},
	data() {
		return {
			range: [],
			value: [],
			dateStr: '', // 最终显示的字符串
			dtStart: null, // 有效范围开始
			dtEnd: null, // 有效范围结束
		};
	},
	watch: {
		// 默认值
		defaultValue() {
			// 设置默认值
			this.setDefaultValue();
		}
	},
	mounted() {
		// 有效日期开始和结束
		let start = this.start;
		let end = this.end;
		
		// 验证是否是有效的开始和结束日期
		if(!this.isString(this.start)) {
			console.log('开始日期需为String类型，格式为 "YYYY-MM-DD hh:mm"');
			start = '2000-01-01 00:00';
		}
		if(!this.isString(this.start)) {
			console.log('结束日期需为String类型，格式为 "YYYY-MM-DD hh:mm"');
			start = '2300-01-01 00:00';
		}
		
		// 将开始日期和结束日期转为 Date 
		let dtStart = this.formatDate(start).dt;
		let dtEnd = this.formatDate(end).dt;
		
		// 判断有效日期结束是否大于有效日期开始，如果不是，则将有效日期结束修改为有效日期开始往后300年
		if (dtEnd <= dtStart) {
			dtEnd = this.formatDate(start).dt;
			dtEnd.setFullYear(dtStart.getFullYear() + 300);
			dtEnd.setDate(dtEnd.getDate() - 1);
		}
		
		// 更新开始日期和结束日期
		this.dtStart = dtStart;
		this.dtEnd = dtEnd;

		// 设置默认值
		this.setDefaultValue();
	},
	methods: {
		/**
		 * 确认选择
		 */
		change(event) {
			let year = this.range[0][this.value[0]].number, // 年
				month = this.range[1][this.value[1]].number, // 月
				day = this.range[2][this.value[2]].number, // 日
				hour = this.range[3][this.value[3]].number, // 时
				minute = this.range[4][this.value[4]].number; // 分
			if(this.fields == 'year') {
				let dtStr = `${year}`;
				this.setDateStr(dtStr);
				this.$emit('change', this.formatDate(dtStr));
				return;
			}else if(this.fields == 'month') {
				let dtStr = `${year}-${month}`;
				this.setDateStr(dtStr);
				this.$emit('change', this.formatDate(dtStr));
				return;
			}else if(this.fields == 'day') {
				let dtStr = `${year}-${month}-${day}`;
				this.setDateStr(dtStr);
				this.$emit('change', this.formatDate(dtStr));
				return;
			}else if(this.fields == 'hour') {
				let dtStr = `${year}-${month}-${day} ${hour}`;
				this.setDateStr(dtStr);
				this.$emit('change', this.formatDate(dtStr));
				return;
			}else if(this.fields == 'minute') {
				let dtStr = `${year}-${month}-${day} ${hour}:${minute}`;
				this.setDateStr(dtStr);
				this.$emit('change', this.formatDate(dtStr));
				return;
			}
		},

		/**
		 * 设置显示的值
		 * @param {Date|String} date 日期字符串或日期对象
		 */
		setDateStr(date) {
			let dt = this.formatDate(date);
			if(this.fields == 'year') {
				this.dateStr = `${dt.YYYY}年`;
				return;
			}
			if(this.fields == 'month') {
				this.dateStr = `${dt.YYYY}年${dt.M}月`;
				return;
			}
			if(this.fields == 'day') {
				this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日`;
				return;
			}
			if(this.fields == 'hour') {
				this.dateStr = `${dt.YYYY}年${dt.M}月${dt.D}日 ${dt.h}时`;
				return;
			}
			this.dateStr = `${dt.YYYY}-${dt.MM}-${dt.DD} ${dt.hh}:${dt.mm}`;
		},
		
		/**
		 * 设置年数据
		 */ 
		setYearData() {
			// 有效日期
			let yearStart = this.dtStart.getFullYear();
			let yearEnd = this.dtEnd.getFullYear();
			// 年
			let years = [];
			for (let year = yearStart; year <= yearEnd; year++) {
				let item = {
					number: year,
					text: `${year}年`,
				};
				years.push(item);
			}
			this.range.splice(0, 1, years);
		},
		
		/**
		 * 设置月数据
		 * @param {Number} year 年 
		 */ 
		setMonthData(year) {
			// 有效日期
			let yearStart = this.dtStart.getFullYear();
			let monthStart = this.dtStart.getMonth() + 1;
			let yearEnd = this.dtEnd.getFullYear();
			let monthEnd = this.dtEnd.getMonth() + 1;
			
			// 月
			let months = [];
			let monthStartIndex = year == yearStart ? monthStart : 1;
			let monthEndIndex = year == yearEnd ? monthEnd : 12;
			for (let month = monthStartIndex; month <= monthEndIndex; month++) {
				let item = {
					number: month,
					text: `${month}月`,
				};
				months.push(item);
			}
			this.range.splice(1, 1, months);
		},
		
		/**
		 * 设置日数据
		 * @param {Number} year 年 
		 * @param {Number} month 月 
		 */ 
		setDayData(year, month) {
			// 有效日期
			let yearStart = this.dtStart.getFullYear();
			let monthStart = this.dtStart.getMonth() + 1;
			let dayStart = this.dtStart.getDate();
			let yearEnd = this.dtEnd.getFullYear();
			let monthEnd = this.dtEnd.getMonth() + 1;
			let dayEnd = this.dtEnd.getDate();
			
			// 日
			let days = [];
			let dayStartIndex = year == yearStart && month == monthStart ? dayStart : 1;
			let dayEndIndex; 
			if(year == yearEnd && month == monthEnd) {
				dayEndIndex = dayEnd;
			} else {
				dayEndIndex = (new Date(year, month, 0)).getDate();
			}
			for (let day = dayStartIndex; day <= dayEndIndex; day++) {
				let item = {
					number: day,
					text: `${day}日`,
				};
				days.push(item);
			}
			this.range.splice(2, 1, days);
		},
		
		/**
		 * 设置时数据
		 * @param {Number} year 年 
		 * @param {Number} month 月 
		 * @param {Number} day 日 
		 */ 
		setHourData(year, month, day) {
			// 有效日期
			let yearStart = this.dtStart.getFullYear();
			let monthStart = this.dtStart.getMonth() + 1;
			let dayStart = this.dtStart.getDate();
			let hourStart = this.dtStart.getHours();
			let yearEnd = this.dtEnd.getFullYear();
			let monthEnd = this.dtEnd.getMonth() + 1;
			let dayEnd = this.dtEnd.getDate();
			let hourEnd = this.dtEnd.getHours();
			
			// 时
			let hours = [];
			let hourStartIndex = year == yearStart && month == monthStart && day == dayStart ? hourStart : 0;
			let hourEndIndex = year == yearEnd && month == monthEnd && day == dayEnd ? hourEnd : 23;
			for (let hour = hourStartIndex; hour <= hourEndIndex; hour++) {
				let item = {
					number: hour,
					text: `${hour}时`,
				};
				hours.push(item);
			}
			this.range.splice(3, 1, hours);
		},
		
		/**
		 * 设置分数据
		 * @param {Number} year 年 
		 * @param {Number} month 月 
		 * @param {Number} day 日
		 * @param {Number} hour 时
		 */ 
		setMinuteData(year, month, day, hour) {
			// 有效日期
			let yearStart = this.dtStart.getFullYear();
			let monthStart = this.dtStart.getMonth() + 1;
			let dayStart = this.dtStart.getDate();
			let hourStart = this.dtStart.getHours();
			let minuteStart = this.dtStart.getMinutes();
			let yearEnd = this.dtEnd.getFullYear();
			let monthEnd = this.dtEnd.getMonth() + 1;
			let dayEnd = this.dtEnd.getDate();
			let hourEnd = this.dtEnd.getHours();
			let minuteEnd = this.dtEnd.getMinutes();
			
			// 分
			let minutes = [];
			let minuteStartIndex = year == yearStart && month == monthStart && day == dayStart && hour == hourStart ? minuteStart : 0;
			let minuteEndIndex = year == yearEnd && month == monthEnd && day == dayEnd && hour == hourEnd ? minuteEnd : 59;
			for(let minute = minuteStartIndex; minute <= minuteEndIndex; minute++) {
				let item = {
					number: minute,
					text: `${minute}分`,
				}
				minutes.push(item);
			}
			this.range.splice(4, 1, minutes);
		},
		
		/**
		 * 设置默认值
		 */
		setDefaultValue() {
			// 默认日期
			let dtDefault;
			
			// 开始日期和结束日期
			let dtStart = this.dtStart;
			let dtEnd = this.dtEnd;
			
			// 判断是否传了默认日期
			// 传了默认日期，格式化默认日期为日期对象
			if(this.defaultValue) {
				dtDefault = this.formatDate(this.defaultValue).dt;
			} 
			// 如果没有传默认日期，将默认日期设置为当前日期
			else {
				dtDefault = new Date();
			}
			
			// 如果默认日期不在有效日期范围内，设置默认日期为有效日期开始值
			if (dtDefault < dtStart || dtDefault > dtEnd) {
				dtDefault = dtStart;
			}
			
			// 更新 dateStr
			if(this.defaultValue) this.setDateStr(dtDefault);
			
			// 默认值相关数据
			let dfYear = dtDefault.getFullYear();
			let dfMonth = dtDefault.getMonth() + 1;
			let dfDay = dtDefault.getDate();
			let dfHour = dtDefault.getHours();
			let dfMinute = dtDefault.getMinutes();
			
			// 设置年数据
			this.setYearData();
			// 设置 Year 这一列的 value 值
			let yearIndex = this.range[0].findIndex(year => {
				return dfYear == year.number;
			});
			this.value.splice(0, 1, yearIndex >= 0 ? yearIndex : 0);
			
			// 设置月数据
			if(this.fields == 'year') return;
			this.setMonthData(dfYear);
			// 设置 Month 这一列的 value 值
			let monthIndex = this.range[1].findIndex(month => {
				return dfMonth == month.number;
			});
			this.value.splice(1, 1, monthIndex >=0 ? monthIndex : 0);
			
			// 设置日数据
			if(this.fields == 'month') return;
			this.setDayData(dfYear, dfMonth);
			// 设置 Day 这一列的 value 值
			let dayIndex = this.range[2].findIndex(day => {
				return dfDay == day.number;
			});
			this.value.splice(2, 1, dayIndex >=0 ? dayIndex : 0);
			
			// 设置时数据
			if(this.fields == 'day') return;
			this.setHourData(dfYear, dfMonth, dfDay);
			// 设置 Hour 这一列的 value 值
			let hourIndex = this.range[3].findIndex(hour => {
				return dfHour == hour.number;
			});
			this.value.splice(3, 1, hourIndex >=0 ? hourIndex : 0);
			
			// 设置分数据
			if(this.fields == 'hour') return;
			this.setMinuteData(dfYear, dfMonth, dfDay, dfHour);
			// 设置 Minute 这一列的 value 值
			let minuteIndex = this.range[4].findIndex(minute => {
				return dfMinute == minute.number;
			});
			this.value.splice(4, 1, minuteIndex >=0 ? minuteIndex : 0);
		},

		/**
		 * 某一列的值改变时触发
		 * @param {Number} event.detail.column 表示改变了第几列（下标从0开始）
		 * @param {Number} event.detail.value 表示变更值的下标
		 */
		columnchange(event) {
			let columnIndex = event.detail.column; // 改变的列的下标
			let valueIndex = event.detail.value; // 变更值的下标
			
			// 更新改变列的 value
			this.value.splice(columnIndex, 1, valueIndex);
			
			// 改变年要更新月数据
			if(this.fields == 'year') return;
			if (columnIndex == 0) {
				// 当前选择的月
				let monthBeforeUpdate = this.range[1][this.value[1]];
				// 更新月数据
				this.setMonthData(this.range[0][this.value[0]].number);
				// 更新 Month Value
				let monthIndex = this.range[1].findIndex(month => {
					return month.number == monthBeforeUpdate.number;
				});
				this.value.splice(1, 1, monthIndex >= 0 ? monthIndex : 0);
			}
			
			// 改变年、月都要更新日数据
			if(this.fields == 'month') return;
			if (columnIndex == 0 || columnIndex == 1) {
				// 当前选择的日
				let dayBeforeUpdate = this.range[2][this.value[2]];
				// 更新日数据
				this.setDayData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number);
				// 更新 Day Value
				let dayIndex = this.range[2].findIndex(day => {
					return day.number == dayBeforeUpdate.number;
				});
				this.value.splice(2, 1, dayIndex >= 0 ? dayIndex : 0);
			}
			
			// 改变年、月、日都要更新时数据
			if(this.fields == 'day') return;
			if (columnIndex == 0 || columnIndex == 1 || columnIndex == 2) {
				// 当前选择的时
				let hourBeforeUpdate = this.range[3][this.value[3]];
				// 更新时数据
				this.setHourData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number);
				// 更新 Hour Value
				let hourIndex = this.range[3].findIndex(hour => {
					return hour.number == hourBeforeUpdate.number;
				});
				this.value.splice(3, 1, hourIndex >= 0 ? hourIndex : 0);
			}
			
			// 当前选择的分
			if(this.fields == 'hour') return;
			let minuteBeforeUpdate = this.range[4][this.value[4]];
			// 更新分数据
			this.setMinuteData(this.range[0][this.value[0]].number, this.range[1][this.value[1]].number, this.range[2][this.value[2]].number, this.range[3][this.value[3]].number);
			// 更新 Minute Value
			let minuteIndex = this.range[4].findIndex(minute => {
				return minute.number == minuteBeforeUpdate.number;
			});
			this.value.splice(4, 1, minuteIndex >= 0 ? minuteIndex : 0);
		},
		/**
		 * 格式化日期
		 * @param {Date|String} date 日期或日期字符串
		 */
		formatDate(date) {
			let YYYY = null;
			let M = null;
			let MM = null;
			let D = null;
			let DD = null;
			let h = null;
			let hh = null;
			let m = null;
			let mm = null;
			let s = null;
			let ss = null;
			let ms = null;
			let ms2 = null;
			let ms3 = null;
			let ms4 = null;
			let dt = null;
		
			// 如果 date 是 String 类型
			if (date && this.isString(date)) {
				// 真机运行时，如果直接用 new Date('YYYY/MM/DD hh:mm:ss') 会报 Invalid Date 错误，所以采用下面的方式创建日期
				let dtArr = date.replace(/\//g, '.').replace(/-/g, '.').replace(/:/g, '.').replace(/T/g, ' ').replace(' ', '.').replace(
					'Z', '').split('.');
		
				let year = 2020;
				let month = 12;
				let day = 18;
				let hour = 0;
				let minute = 0;
				let second = 0;
				let millisecond = 0;
				
				// 年
				if (dtArr.length > 0 && !isNaN(dtArr[0])) {
					year = parseInt(dtArr[0]);
				}
				// 月
				if (dtArr.length > 1 && !isNaN(dtArr[1])) {
					month = parseInt(dtArr[1]);
				}
				// 日
				if (dtArr.length > 2 && !isNaN(dtArr[2])) {
					day = parseInt(dtArr[2]);
				}
				// 时
				if (dtArr.length > 3 && !isNaN(dtArr[3])) {
					hour = parseInt(dtArr[3]);
				}
				// 分
				if (dtArr.length > 4 && !isNaN(dtArr[4])) {
					minute = parseInt(dtArr[4]);
				}
				// 秒
				if (dtArr.length > 5 && !isNaN(dtArr[5])) {
					second = parseInt(dtArr[5]);
				}
				// 毫秒
				if (dtArr.length > 6 && !isNaN(dtArr[6])) {
					millisecond = parseInt(dtArr[6]);
				}
		
				date = new Date(year, month - 1, day, hour, minute, second, millisecond);
			}
		
			// 如果 date 是 Date 类型
			if (date && this.isDate(date)) {
				YYYY = date.getFullYear();
				M = date.getMonth() + 1;
				MM = M >= 10 ? M : '0' + M;
				D = date.getDate();
				DD = D >= 10 ? D : '0' + D;
				h = date.getHours();
				hh = h >= 10 ? h : '0' + h;
				m = date.getMinutes();
				mm = m >= 10 ? m : '0' + m;
				s = date.getSeconds();
				ss = s >= 10 ? s : '0' + s;
				ms = date.getMilliseconds();
				ms2 = ms;
				ms3 = ms;
				ms4 = ms;
				if (ms < 10) {
					ms2 = '0' + ms;
					ms3 = '00' + ms;
					ms4 = '000' + ms;
				} else if (ms < 100) {
					ms3 = '0' + ms;
					ms4 = '00' + ms;
				} else {
					ms4 = '0' + ms;
				}
			}
		
			// 返回的数据对象
			let result = {
				YYYY: YYYY,
				MM: MM,
				M: M,
				DD: DD,
				D: D,
				hh: hh,
				h: h,
				mm: mm,
				m: m,
				ss: ss,
				s: s,
				ms: ms,
				ms2: ms2,
				ms3: ms3,
				ms4: ms4,
				dt: date,
				f1: `${YYYY}-${MM}-${DD}`,
				f2: `${YYYY}年${M}月${D}日`,
				f3: `${YYYY}-${MM}-${DD} ${hh}:${mm}`,
				f4: `${h}:${m}:${s}`,
				f5: `${MM}-${DD}`,
				f6: `${YYYY}-${MM}`,
				f7: `${YYYY}年${M}月`,
				f8: `${h}:${m}`,
				f9: `${M}月${D}日`,
				notes: 'YYYY（年），MM（月，补0），M（月，不补0），DD（日，补0），D（日，不补0），hh（时，补0），h（时，不补0），mm（分，补0），m（分，不补0），ss（秒，补0），s（秒，不补0），ms（毫秒，不补0），ms2（毫秒，补0到2位），ms3（毫秒，补0到3位），ms4（毫秒，补0到4位），其余的f1，f2，... 看格式就知道了！'
			};
			return result;
		},
		/**
		 * 判断数据是否是 String 类型
		 * @param {Any} val 要判断的数据
		 * @returns {Boolean} true：是；false：不是；
		 */
		isString(val) {
			return Object.prototype.toString.call(val) === '[object String]';
		},
		/**
		 * 精确判断数据是否是 Date 类型
		 * @param {Any} val 要判断的数据
		 * @returns {Boolean} true：是；false：不是；
		 */
		isDate(val) {
			return Object.prototype.toString.call(val) === '[object Date]';
		},
	}
};
</script>

<style lang="scss" scoped>
	.datatime{
		width: 100%;
		height: 100%;
		.content {
			width: 100%;
			min-height: 70rpx;
			// border: 1rpx solid red;
			display: flex;
			align-items: center;
		}
		.placeholder {
			color: #515151;
			display:flex;
			align-items: center;
		}
		
	}



</style>
