418 lines
11 KiB
Plaintext
418 lines
11 KiB
Plaintext
<template>
|
|
<div
|
|
:class="['layui-date-picker', { 'layui-date-range-picker': range }]"
|
|
:size="size"
|
|
>
|
|
<lay-dropdown
|
|
ref="dropdownRef"
|
|
:disabled="disabled"
|
|
:autoFitMinWidth="false"
|
|
:contentClass="contentClass"
|
|
:contentStyle="contentStyle"
|
|
updateAtScroll
|
|
>
|
|
<lay-input
|
|
:name="name"
|
|
:readonly="readonly"
|
|
:placeholder="startPlaceholder"
|
|
:prefix-icon="prefixIcon"
|
|
:suffix-icon="suffixIcon"
|
|
:disabled="disabled"
|
|
v-model="dateValue"
|
|
v-if="!range"
|
|
@change="onChange"
|
|
@blur="$emit('blur')"
|
|
@focus="$emit('focus')"
|
|
:allow-clear="!disabled && allowClear"
|
|
:size="size"
|
|
@clear="
|
|
dateValue = '';
|
|
onChange();
|
|
"
|
|
>
|
|
</lay-input>
|
|
<div class="laydate-range-inputs" v-else>
|
|
<lay-input
|
|
:readonly="readonly"
|
|
:name="name"
|
|
v-model="dateValue[0]"
|
|
:placeholder="startPlaceholder"
|
|
:disabled="disabled"
|
|
@change="onChange"
|
|
@blur="$emit('blur')"
|
|
@focus="$emit('focus')"
|
|
class="start-input"
|
|
:size="size"
|
|
>
|
|
</lay-input>
|
|
<span class="range-separator">{{ rangeSeparator }}</span>
|
|
<lay-input
|
|
:readonly="readonly"
|
|
:name="name"
|
|
:allow-clear="disabled && allowClear"
|
|
:placeholder="endPlaceholder"
|
|
v-model="dateValue[1]"
|
|
:disabled="disabled"
|
|
@change="onChange"
|
|
@blur="$emit('blur')"
|
|
@focus="$emit('focus')"
|
|
class="end-input"
|
|
:size="size"
|
|
@clear="
|
|
dateValue = [];
|
|
onChange();
|
|
"
|
|
>
|
|
</lay-input>
|
|
</div>
|
|
|
|
<template #content>
|
|
<!-- 日期选择 -->
|
|
<DatePanel
|
|
v-if="!range && (showPanel === 'date' || showPanel === 'datetime')"
|
|
v-model="currentDay"
|
|
></DatePanel>
|
|
<!-- 时间选择 -->
|
|
<TimePanel
|
|
v-if="!range && showPanel === 'time'"
|
|
v-model="hms"
|
|
></TimePanel>
|
|
<!-- 年份选择器 -->
|
|
<YearPanel
|
|
v-if="!range && (showPanel === 'year' || showPanel === 'yearmonth')"
|
|
v-model="currentYear"
|
|
>
|
|
</YearPanel>
|
|
<!-- 月份选择器 -->
|
|
<MonthPanel
|
|
v-if="!range && showPanel === 'month'"
|
|
v-model="currentMonth"
|
|
></MonthPanel>
|
|
<!-- 范围选择 -->
|
|
<DateRange
|
|
v-if="range && (showPanel === 'date' || showPanel === 'datetime')"
|
|
v-model:startTime="rangeValue.first"
|
|
v-model:endTime="rangeValue.last"
|
|
></DateRange>
|
|
|
|
<MonthRange
|
|
v-if="range && showPanel === 'yearmonth'"
|
|
v-model:startTime="rangeValue.first"
|
|
v-model:endTime="rangeValue.last"
|
|
>
|
|
</MonthRange>
|
|
</template>
|
|
</lay-dropdown>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
export default {
|
|
name: "LayDatePicker",
|
|
};
|
|
</script>
|
|
|
|
<script lang="ts" setup>
|
|
import "./index.less";
|
|
import dayjs from "dayjs";
|
|
import { LayIcon } from "@layui/icons-vue";
|
|
import LayInput from "../input/index.vue";
|
|
import LayDropdown from "../dropdown/index.vue";
|
|
import { getMonth, getYear, getDay } from "./day";
|
|
import {
|
|
ref,
|
|
watch,
|
|
defineProps,
|
|
defineEmits,
|
|
reactive,
|
|
provide,
|
|
StyleValue,
|
|
} from "vue";
|
|
import DatePanel from "./components/DatePanel.vue";
|
|
import TimePanel from "./components/TimePanel.vue";
|
|
import YearPanel from "./components/YearPanel.vue";
|
|
import MonthPanel from "./components/MonthPanel.vue";
|
|
import DateRange from "./components/DateRange.vue";
|
|
import MonthRange from "./components/MonthRange.vue";
|
|
import { computed } from "@vue/reactivity";
|
|
|
|
export interface DatePickerProps {
|
|
type?: "date" | "datetime" | "year" | "time" | "month" | "yearmonth";
|
|
placeholder?: string | string[];
|
|
modelValue?: string | number | string[];
|
|
disabled?: boolean;
|
|
simple?: boolean;
|
|
name?: string;
|
|
max?: string;
|
|
min?: string;
|
|
range?: boolean;
|
|
rangeSeparator?: string;
|
|
readonly?: boolean;
|
|
allowClear?: boolean;
|
|
size?: "lg" | "md" | "sm" | "xs";
|
|
prefixIcon?: string;
|
|
suffixIcon?: string;
|
|
timestamp?: boolean;
|
|
contentClass?: string | Array<string | object> | object;
|
|
contentStyle?: StyleValue;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<DatePickerProps>(), {
|
|
modelValue: "",
|
|
type: "date",
|
|
disabled: false,
|
|
simple: false,
|
|
range: false,
|
|
rangeSeparator: "至",
|
|
readonly: false,
|
|
allowClear: false,
|
|
size: "md",
|
|
prefixIcon: "layui-icon-date",
|
|
suffixIcon: "",
|
|
timestamp: false,
|
|
});
|
|
|
|
const startPlaceholder = computed(() => {
|
|
if (Array.isArray(props.placeholder)) {
|
|
return props.placeholder[0];
|
|
}
|
|
return props.placeholder;
|
|
});
|
|
|
|
const endPlaceholder = computed(() => {
|
|
if (Array.isArray(props.placeholder)) {
|
|
return props.placeholder[1];
|
|
}
|
|
return props.placeholder;
|
|
});
|
|
|
|
const dropdownRef = ref(null);
|
|
const $emits = defineEmits(["update:modelValue", "change", "blur", "focus"]);
|
|
const hms = ref({
|
|
hh: 0,
|
|
mm: 0,
|
|
ss: 0,
|
|
});
|
|
const currentYear = ref<number>(0);
|
|
const currentMonth = ref<number>(0);
|
|
const currentDay = ref<number>(0);
|
|
const showPanel = ref<string>("date");
|
|
const rangeValue = reactive({ first: "", last: "" });
|
|
|
|
let unWatch = false;
|
|
// 计算结果日期
|
|
const dateValue = props.range ? ref(["", ""]) : ref("");
|
|
const getDateValue = () => {
|
|
unWatch = true;
|
|
let dayjsVal;
|
|
switch (props.type) {
|
|
case "date":
|
|
dayjsVal =
|
|
currentDay.value !== -1
|
|
? dayjs(currentDay.value).format("YYYY-MM-DD")
|
|
: "";
|
|
break;
|
|
case "datetime":
|
|
dayjsVal =
|
|
currentDay.value !== -1
|
|
? dayjs(currentDay.value)
|
|
.hour(hms.value.hh)
|
|
.minute(hms.value.mm)
|
|
.second(hms.value.ss)
|
|
.format("YYYY-MM-DD HH:mm:ss")
|
|
: "";
|
|
break;
|
|
case "year":
|
|
dayjsVal =
|
|
currentYear.value !== -1
|
|
? dayjs().year(currentYear.value).format("YYYY")
|
|
: "";
|
|
break;
|
|
case "month":
|
|
dayjsVal =
|
|
currentMonth.value !== -1 ? (currentMonth.value + 1).toString() : "";
|
|
break;
|
|
case "time":
|
|
dayjsVal = dayjs()
|
|
.hour(hms.value.hh)
|
|
.minute(hms.value.mm)
|
|
.second(hms.value.ss)
|
|
.format("HH:mm:ss");
|
|
break;
|
|
case "yearmonth":
|
|
dayjsVal =
|
|
currentYear.value !== -1 && currentMonth.value !== -1
|
|
? dayjs()
|
|
.year(currentYear.value)
|
|
.month(currentMonth.value)
|
|
.format("YYYY-MM")
|
|
: "";
|
|
break;
|
|
default:
|
|
dayjsVal =
|
|
currentDay.value !== -1
|
|
? dayjs(currentDay.value)
|
|
.hour(hms.value.hh)
|
|
.minute(hms.value.mm)
|
|
.second(hms.value.ss)
|
|
.format()
|
|
: "";
|
|
break;
|
|
}
|
|
dateValue.value = dayjsVal !== "Invalid Date" ? dayjsVal : "";
|
|
if (dayjsVal === "Invalid Date") {
|
|
unWatch = false;
|
|
$emits("update:modelValue", "");
|
|
return;
|
|
}
|
|
if (props.timestamp) {
|
|
$emits("update:modelValue", dayjs(dayjsVal).unix() * 1000);
|
|
$emits("change", dayjs(dayjsVal).unix() * 1000);
|
|
} else {
|
|
$emits("update:modelValue", dayjsVal);
|
|
$emits("change", dayjsVal);
|
|
}
|
|
setTimeout(() => {
|
|
unWatch = false;
|
|
}, 0);
|
|
};
|
|
const getDateValueByRange = () => {
|
|
unWatch = true;
|
|
if (rangeValue.first === "" || rangeValue.last === "") {
|
|
dateValue.value = ["", ""];
|
|
$emits("update:modelValue", dateValue.value);
|
|
$emits("change", dateValue.value);
|
|
return;
|
|
}
|
|
let format = "YYYY-MM-DD";
|
|
switch (props.type) {
|
|
case "date":
|
|
format = "YYYY-MM-DD";
|
|
break;
|
|
case "datetime":
|
|
format = "YYYY-MM-DD HH:mm:ss";
|
|
break;
|
|
case "yearmonth":
|
|
format = "YYYY-MM";
|
|
break;
|
|
}
|
|
dateValue.value = [
|
|
dayjs(rangeValue.first).format(format),
|
|
dayjs(rangeValue.last).format(format),
|
|
];
|
|
$emits("update:modelValue", dateValue.value);
|
|
$emits("change", dateValue.value);
|
|
setTimeout(() => {
|
|
unWatch = false;
|
|
}, 0);
|
|
};
|
|
|
|
// 确认事件
|
|
const ok = () => {
|
|
if (!props.range) {
|
|
getDateValue();
|
|
} else {
|
|
getDateValueByRange();
|
|
}
|
|
if (dropdownRef.value)
|
|
// @ts-ignore
|
|
dropdownRef.value.hide();
|
|
showPanel.value = props.type;
|
|
};
|
|
|
|
//面板类型判断
|
|
watch(
|
|
() => props.type,
|
|
() => {
|
|
showPanel.value = props.type;
|
|
if (props.type === "yearmonth" && !props.range) {
|
|
showPanel.value = "year";
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
//监听modelValue改变
|
|
watch(
|
|
() => props.modelValue,
|
|
() => {
|
|
if (unWatch) {
|
|
return;
|
|
}
|
|
let initModelValue: string =
|
|
props.range && props.modelValue
|
|
? (props.modelValue as string[])[0] || ""
|
|
: (props.modelValue as string);
|
|
if (props.type === "month" || props.type === "year") {
|
|
initModelValue += "";
|
|
}
|
|
|
|
hms.value.hh = isNaN(dayjs(initModelValue).hour())
|
|
? 0
|
|
: dayjs(initModelValue).hour();
|
|
hms.value.mm = isNaN(dayjs(initModelValue).minute())
|
|
? 0
|
|
: dayjs(initModelValue).minute();
|
|
hms.value.ss = isNaN(dayjs(initModelValue).second())
|
|
? 0
|
|
: dayjs(initModelValue).second();
|
|
|
|
if (initModelValue.length === 8 && props.type === "time") {
|
|
let modelValue = initModelValue;
|
|
modelValue = "1970-01-01 " + modelValue;
|
|
hms.value.hh = dayjs(modelValue).hour();
|
|
hms.value.mm = dayjs(modelValue).minute();
|
|
hms.value.ss = dayjs(modelValue).second();
|
|
}
|
|
|
|
currentYear.value = initModelValue ? getYear(initModelValue) : -1;
|
|
currentMonth.value = initModelValue ? getMonth(initModelValue) : -1;
|
|
currentDay.value = initModelValue ? getDay(initModelValue) : -1;
|
|
if (props.type === "date" || props.type === "datetime") {
|
|
if (currentYear.value === -1) currentYear.value = dayjs().year();
|
|
if (currentMonth.value === -1) currentMonth.value = dayjs().month();
|
|
if (props.timestamp) {
|
|
currentDay.value = initModelValue
|
|
? dayjs(parseInt(initModelValue)).startOf("date").unix() * 1000
|
|
: -1;
|
|
}
|
|
}
|
|
rangeValue.first = initModelValue;
|
|
rangeValue.last =
|
|
props.range && props.modelValue
|
|
? (props.modelValue as string[])[1] || ""
|
|
: "";
|
|
if (!props.range) {
|
|
getDateValue();
|
|
} else {
|
|
getDateValueByRange();
|
|
}
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
const onChange = () => {
|
|
if (dropdownRef.value)
|
|
// @ts-ignore
|
|
dropdownRef.value.hide();
|
|
$emits("update:modelValue", dateValue.value);
|
|
};
|
|
|
|
provide("datePicker", {
|
|
currentYear: currentYear,
|
|
currentMonth: currentMonth,
|
|
currentDay: currentDay,
|
|
dateValue: dateValue,
|
|
type: props.type,
|
|
showPanel: showPanel,
|
|
hms: hms,
|
|
ok: () => ok(),
|
|
getDateValue: () => getDateValue,
|
|
range: props.range,
|
|
rangeValue: rangeValue,
|
|
rangeSeparator: props.rangeSeparator,
|
|
simple: props.simple,
|
|
timestamp: props.timestamp,
|
|
});
|
|
</script>
|