|
|
@@ -1,52 +1,299 @@
|
|
|
<template>
|
|
|
- <picker
|
|
|
- mode="date"
|
|
|
- @change="onChange"
|
|
|
- :value="value"
|
|
|
- :start="start"
|
|
|
- :end="end"
|
|
|
- :fields="fields"
|
|
|
- >
|
|
|
- <slot></slot>
|
|
|
- </picker>
|
|
|
+ <nut-picker
|
|
|
+ :visible="show"
|
|
|
+ @close="closeHandler"
|
|
|
+ :list-data="columns"
|
|
|
+ @change="changeHandler"
|
|
|
+ :title="title"
|
|
|
+ @confirm="confirm"
|
|
|
+ ></nut-picker>
|
|
|
</template>
|
|
|
<script lang="ts">
|
|
|
-import { toRefs } from 'vue';
|
|
|
+import { toRefs, watch, computed, reactive, onMounted } from 'vue';
|
|
|
+
|
|
|
+import nutPicker from '../picker/index.taro.vue';
|
|
|
import { createComponent } from '../../utils/create';
|
|
|
-const { create } = createComponent('datepicker');
|
|
|
-import picker from '../picker/index.vue';
|
|
|
+const { componentName, create } = createComponent('datepicker');
|
|
|
+const currentYear = new Date().getFullYear();
|
|
|
+function isDate(val: Date): val is Date {
|
|
|
+ return Object.prototype.toString.call(val) === '[object Date]' && !isNaN(val.getTime());
|
|
|
+}
|
|
|
+
|
|
|
+const zhCNType = {
|
|
|
+ day: '日',
|
|
|
+ year: '年',
|
|
|
+ month: '月',
|
|
|
+ hour: '时',
|
|
|
+ minute: '分',
|
|
|
+ seconds: '秒'
|
|
|
+};
|
|
|
export default create({
|
|
|
components: {
|
|
|
- [picker.name]: [picker]
|
|
|
+ nutPicker
|
|
|
},
|
|
|
props: {
|
|
|
- value: {
|
|
|
- type: String,
|
|
|
- default: new Date()
|
|
|
+ modelValue: null,
|
|
|
+ visible: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false
|
|
|
},
|
|
|
- start: {
|
|
|
+ title: {
|
|
|
type: String,
|
|
|
- default: '1970-01-01'
|
|
|
+ default: ''
|
|
|
},
|
|
|
- end: {
|
|
|
+ type: {
|
|
|
type: String,
|
|
|
- default: '2999-01-01'
|
|
|
+ default: 'date'
|
|
|
},
|
|
|
- fields: {
|
|
|
- type: String,
|
|
|
- default: 'day'
|
|
|
+ isShowChinese: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true
|
|
|
+ },
|
|
|
+ minuteStep: {
|
|
|
+ type: Number,
|
|
|
+ default: 1
|
|
|
+ },
|
|
|
+ minDate: {
|
|
|
+ type: Date,
|
|
|
+ default: () => new Date(currentYear - 10, 0, 1),
|
|
|
+ validator: isDate
|
|
|
+ },
|
|
|
+ maxDate: {
|
|
|
+ type: Date,
|
|
|
+ default: () => new Date(currentYear + 10, 11, 31),
|
|
|
+ validator: isDate
|
|
|
}
|
|
|
},
|
|
|
- emits: ['onChange'],
|
|
|
+ emits: ['click', 'update:visible', 'confirm'],
|
|
|
|
|
|
setup(props, { emit }) {
|
|
|
- const onChange = (e: any) => {
|
|
|
- emit('onChange', e.detail.value);
|
|
|
+ const state = reactive({
|
|
|
+ show: false,
|
|
|
+ currentDate: new Date(),
|
|
|
+ title: props.title
|
|
|
+ });
|
|
|
+ const formatValue = (value: Date) => {
|
|
|
+ if (!isDate(value)) {
|
|
|
+ value = props.minDate;
|
|
|
+ }
|
|
|
+ let timestmp = Math.max(value.getTime(), props.minDate.getTime());
|
|
|
+ timestmp = Math.min(timestmp, props.maxDate.getTime());
|
|
|
+
|
|
|
+ return new Date(timestmp);
|
|
|
+ };
|
|
|
+
|
|
|
+ function getMonthEndDay(year: number, month: number): number {
|
|
|
+ return 32 - new Date(year, month - 1, 32).getDate();
|
|
|
+ }
|
|
|
+ const getBoundary = (type: string, value: Date) => {
|
|
|
+ const boundary = props[`${type}Date`];
|
|
|
+ const year = boundary.getFullYear();
|
|
|
+ let month = 1;
|
|
|
+ let date = 1;
|
|
|
+ let hour = 0;
|
|
|
+ let minute = 0;
|
|
|
+
|
|
|
+ if (type === 'max') {
|
|
|
+ month = 12;
|
|
|
+ date = getMonthEndDay(value.getFullYear(), value.getMonth() + 1);
|
|
|
+ hour = 23;
|
|
|
+ minute = 59;
|
|
|
+ }
|
|
|
+ const seconds = minute;
|
|
|
+ if (value.getFullYear() === year) {
|
|
|
+ month = boundary.getMonth() + 1;
|
|
|
+ if (value.getMonth() + 1 === month) {
|
|
|
+ date = boundary.getDate();
|
|
|
+ if (value.getDate() === date) {
|
|
|
+ hour = boundary.getHours();
|
|
|
+ if (value.getHours() === hour) {
|
|
|
+ minute = boundary.getMinutes();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ [`${type}Year`]: year,
|
|
|
+ [`${type}Month`]: month,
|
|
|
+ [`${type}Date`]: date,
|
|
|
+ [`${type}Hour`]: hour,
|
|
|
+ [`${type}Minute`]: minute,
|
|
|
+ [`${type}Seconds`]: seconds
|
|
|
+ };
|
|
|
+ };
|
|
|
+
|
|
|
+ const ranges = computed(() => {
|
|
|
+ const { maxYear, maxDate, maxMonth, maxHour, maxMinute, maxSeconds } = getBoundary('max', state.currentDate);
|
|
|
+
|
|
|
+ const { minYear, minDate, minMonth, minHour, minMinute, minSeconds } = getBoundary('min', state.currentDate);
|
|
|
+
|
|
|
+ let result = [
|
|
|
+ {
|
|
|
+ type: 'year',
|
|
|
+ range: [minYear, maxYear]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'month',
|
|
|
+ range: [minMonth, maxMonth]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'day',
|
|
|
+ range: [minDate, maxDate]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'hour',
|
|
|
+ range: [minHour, maxHour]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'minute',
|
|
|
+ range: [minMinute, maxMinute]
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'seconds',
|
|
|
+ range: [minSeconds, maxSeconds]
|
|
|
+ }
|
|
|
+ ];
|
|
|
+
|
|
|
+ switch (props.type) {
|
|
|
+ case 'date':
|
|
|
+ result = result.slice(0, 3);
|
|
|
+ break;
|
|
|
+ case 'datetime':
|
|
|
+ result = result.slice(0, 5);
|
|
|
+ break;
|
|
|
+ case 'time':
|
|
|
+ result = result.slice(3, 6);
|
|
|
+ break;
|
|
|
+ case 'month-day':
|
|
|
+ result = result.slice(1, 3);
|
|
|
+ break;
|
|
|
+ case 'datehour':
|
|
|
+ result = result.slice(0, 4);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return result;
|
|
|
+ });
|
|
|
+
|
|
|
+ const changeHandler = (val: string[]) => {
|
|
|
+ if (['date', 'datetime'].includes(props.type)) {
|
|
|
+ let formatDate = [];
|
|
|
+ if (props.isShowChinese) {
|
|
|
+ formatDate = val.map((res: string) => {
|
|
|
+ return Number(res.slice(0, res.length - 1));
|
|
|
+ }) as any;
|
|
|
+ } else {
|
|
|
+ formatDate = val;
|
|
|
+ }
|
|
|
+ let date: Date;
|
|
|
+ if (props.type === 'date') {
|
|
|
+ state.currentDate = formatValue(
|
|
|
+ new Date(
|
|
|
+ formatDate[0],
|
|
|
+ formatDate[1] - 1,
|
|
|
+ Math.min(formatDate[2], getMonthEndDay(formatDate[0], formatDate[1]))
|
|
|
+ )
|
|
|
+ );
|
|
|
+ } else if (props.type === 'datetime') {
|
|
|
+ state.currentDate = formatValue(
|
|
|
+ new Date(
|
|
|
+ formatDate[0],
|
|
|
+ formatDate[1] - 1,
|
|
|
+ Math.min(formatDate[2], getMonthEndDay(formatDate[0], formatDate[1])),
|
|
|
+ formatDate[3],
|
|
|
+ formatDate[4]
|
|
|
+ )
|
|
|
+ );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ const generateValue = (min: number, max: number, val: number, type: string) => {
|
|
|
+ // if (!(max > min)) return;
|
|
|
+ const arr: Array<number | string> = [];
|
|
|
+ let index = 0;
|
|
|
+ while (min <= max) {
|
|
|
+ if (props.isShowChinese) {
|
|
|
+ arr.push(min + zhCNType[type]);
|
|
|
+ } else {
|
|
|
+ arr.push(min);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (type === 'minute') {
|
|
|
+ min += props.minuteStep;
|
|
|
+ } else {
|
|
|
+ min++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (min <= val) {
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return { values: arr, defaultIndex: index };
|
|
|
+ };
|
|
|
+
|
|
|
+ const getDateIndex = (type: string) => {
|
|
|
+ if (type === 'year') {
|
|
|
+ return state.currentDate.getFullYear();
|
|
|
+ } else if (type === 'month') {
|
|
|
+ return state.currentDate.getMonth() + 1;
|
|
|
+ } else if (type === 'day') {
|
|
|
+ return state.currentDate.getDate();
|
|
|
+ } else if (type === 'hour') {
|
|
|
+ return state.currentDate.getHours();
|
|
|
+ } else if (type === 'minute') {
|
|
|
+ return state.currentDate.getMinutes();
|
|
|
+ } else if (type === 'seconds') {
|
|
|
+ return state.currentDate.getSeconds();
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
+
|
|
|
+ const columns = computed(() => {
|
|
|
+ // console.log(ranges.value);
|
|
|
+ const val = ranges.value.map((res) => {
|
|
|
+ return generateValue(res.range[0], res.range[1], getDateIndex(res.type), res.type);
|
|
|
+ });
|
|
|
+ return val;
|
|
|
+ });
|
|
|
+ const handleClick = (event: Event) => {
|
|
|
+ emit('click', event);
|
|
|
+ };
|
|
|
+
|
|
|
+ const closeHandler = () => {
|
|
|
+ emit('update:visible', false);
|
|
|
+ };
|
|
|
+
|
|
|
+ const confirm = (val: Event) => {
|
|
|
+ emit('update:visible', false);
|
|
|
+ emit('confirm', val);
|
|
|
};
|
|
|
+
|
|
|
+ onMounted(() => {
|
|
|
+ state.currentDate = formatValue(props.modelValue);
|
|
|
+ });
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.title,
|
|
|
+ (val) => {
|
|
|
+ state.title = val;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
+ watch(
|
|
|
+ () => props.visible,
|
|
|
+ (val) => {
|
|
|
+ state.show = val;
|
|
|
+ }
|
|
|
+ );
|
|
|
+
|
|
|
return {
|
|
|
+ ...toRefs(state),
|
|
|
+ changeHandler,
|
|
|
+ closeHandler,
|
|
|
confirm,
|
|
|
- onChange,
|
|
|
- ...toRefs(props)
|
|
|
+ columns
|
|
|
};
|
|
|
}
|
|
|
});
|