song-ui-u
Version:
vue3 + js的PC前端组件库
603 lines (599 loc) • 23.4 kB
JavaScript
;
var vue = require('vue');
require('../../button/index.cjs');
require('../../buttonGroup/index.cjs');
var index$1 = require('../../icon/index.cjs');
var index = require('../../input/index.cjs');
require('../../textarea/index.cjs');
require('../../row/index.cjs');
require('../../col/index.cjs');
require('../../container/index.cjs');
require('../../checkbox/index.cjs');
require('../../switch/index.cjs');
require('../../form/index.cjs');
require('../../message/index.cjs');
require('../../mask/src/mask.cjs');
require('../../modal/index.cjs');
require('../../messageBox/index.cjs');
require('../../drawer/index.cjs');
require('../../badge/index.cjs');
require('../../space/index.cjs');
require('../../image/index.cjs');
require('../../radio/index.cjs');
require('../../divider/index.cjs');
require('../../chat/index.cjs');
require('../../progress/index.cjs');
require('../../upload/index.cjs');
require('../../vTree/index.cjs');
require('../../table/index.cjs');
require('../../tabs/index.cjs');
require('../../menu/index.cjs');
require('../../steps/index.cjs');
require('../../header/index.cjs');
require('../../breadcrumble/index.cjs');
require('../index.cjs');
require('../../tooltip/index.cjs');
require('../../popover/index.cjs');
require('../../timePicker/index.cjs');
require('../../select/index.cjs');
require('../../collapse/index.cjs');
require('../../card/index.cjs');
require('../../timeline/index.cjs');
require('../../tag/index.cjs');
require('../../result/index.cjs');
require('../../sender/index.cjs');
var icons = require('song-ui-pro-icon');
var index$2 = require('../../../hook/use-namespace/index.cjs');
require('../../../hook/use-zindex/index.cjs');
var dateFns = require('date-fns');
var datePicker = /* @__PURE__ */ vue.defineComponent({
name: "x-date-picker",
props: {
modelValue: {
type: [String, Date, Array],
default: ""
},
placeholder: {
type: String,
default: "\u8BF7\u9009\u62E9\u65E5\u671F"
},
format: {
type: String,
default: "yyyy-MM-dd"
},
disabled: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
clearance: {
type: Boolean,
default: true
},
model: {
type: String,
default: "date"
},
multiple: {
type: Boolean,
default: false
},
range: {
type: Boolean,
default: false
},
startPlaceholder: {
type: String,
default: "\u5F00\u59CB\u65E5\u671F"
},
endPlaceholder: {
type: String,
default: "\u7ED3\u675F\u65E5\u671F"
}
},
setup(props, {
emit
}) {
const ns = index$2.useNamespace("date-picker");
const visible = vue.ref(false);
const currentDate = vue.ref(new Date(props.modelValue || /* @__PURE__ */ new Date()));
const nextMonthDate = vue.ref(dateFns.addMonths(currentDate.value, 1));
const displayValue = vue.ref("");
const weekDays = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
const rangeState = vue.ref({
selecting: false,
// 是否正在选择范围
startDate: null,
// 开始日期
endDate: null
// 结束日期
});
if (props.range && Array.isArray(props.modelValue) && props.modelValue.length === 2) {
rangeState.value.startDate = dateFns.parse(props.modelValue[0], props.format, /* @__PURE__ */ new Date());
rangeState.value.endDate = dateFns.parse(props.modelValue[1], props.format, /* @__PURE__ */ new Date());
displayValue.value = `${formatDate(rangeState.value.startDate)} \u81F3 ${formatDate(rangeState.value.endDate)}`;
}
const currentYear = vue.computed(() => currentDate.value.getFullYear());
const currentMonth = vue.computed(() => currentDate.value.getMonth());
const placeholder = vue.computed(() => {
if (props.range) return `${props.startPlaceholder} \u81F3 ${props.endPlaceholder}`;
if (props.model == "date") return "\u8BF7\u9009\u62E9\u65E5\u671F";
if (props.model == "year") return "\u8BF7\u9009\u62E9\u5E74\u4EFD";
if (props.model == "month") return "\u8BF7\u9009\u62E9\u6708\u4EFD";
});
const years = vue.computed(() => {
const startYear = currentYear.value - 10;
const endYear = currentYear.value + 10;
const years2 = [];
for (let year = startYear; year <= endYear; year++) {
years2.push({
year,
isSelected: isSelected(year),
isYear: isYear(year)
});
}
return years2;
});
const months = vue.computed(() => {
const months2 = [];
for (let month = 0; month < 12; month++) {
months2.push({
month,
name: `${month + 1}\u6708`,
isSelected: isSelectedMonth(month),
isCurrentMonth: isCurrentMonth(month)
});
}
return months2;
});
const isSelectedMonth = (month) => {
if (!props.modelValue) return false;
if (props.model === "month") {
if (props.multiple) {
const formattedMonth = dateFns.format(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), currentYear.value), month), "yyyy-MM");
return multipleData.value.includes(formattedMonth);
}
return month === new Date(props.modelValue).getMonth();
}
return false;
};
const isCurrentMonth = (month) => {
return month === (/* @__PURE__ */ new Date()).getMonth();
};
const isYear = (data) => {
return data == currentYear.value;
};
const isSelected = (value) => {
if (!props.modelValue) return false;
if (props.model === "date") {
if (props.range) {
const date = new Date(value);
if (!rangeState.value.startDate && !rangeState.value.endDate) return false;
if (rangeState.value.startDate && dateFns.isSameDay(date, rangeState.value.startDate)) return true;
if (rangeState.value.endDate && dateFns.isSameDay(date, rangeState.value.endDate)) return true;
return false;
}
if (props.multiple) {
return multipleData.value.includes(formatDate(value));
}
return dateFns.isSameDay(new Date(value), new Date(props.modelValue));
}
if (props.model === "year") {
if (props.multiple) {
return multipleData.value.includes(value.toString());
}
return value == new Date(props.modelValue).getFullYear();
}
if (props.model === "month") {
if (props.multiple) {
const formattedMonth = dateFns.format(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), currentYear.value), value), "yyyy-MM");
return multipleData.value.includes(formattedMonth);
}
return value == new Date(props.modelValue).getMonth();
}
return false;
};
const isInRange = (value) => {
if (!props.range || !rangeState.value.startDate || !rangeState.value.endDate) return false;
const date = new Date(value);
const start = rangeState.value.startDate;
const end = rangeState.value.endDate;
return dateFns.isAfter(date, start) && dateFns.isBefore(date, end);
};
const formatDate = (date) => {
return dateFns.format(date, props.format);
};
const showPanel = () => {
if (props.disabled || props.readonly) return;
visible.value = true;
console.log("showPanel", visible.value);
};
const handleClear = () => {
emit("update:modelValue", props.range ? [] : "");
emit("change", props.range ? [] : "");
displayValue.value = "";
if (props.multiple) {
multipleData.value = [];
visible.value = false;
}
if (props.range) {
rangeState.value.startDate = null;
rangeState.value.endDate = null;
rangeState.value.selecting = false;
}
};
const multipleData = vue.ref([]);
const selectDate = (value) => {
if (props.model === "year") {
const formattedYear = value.toString();
emit("update:modelValue", formattedYear);
emit("change", formattedYear);
if (!props.multiple) {
displayValue.value = formattedYear;
}
if (props.multiple) {
if (multipleData.value.includes(formattedYear)) {
multipleData.value = multipleData.value.filter((item) => item !== formattedYear);
} else {
multipleData.value.push(formattedYear);
}
}
return;
}
if (props.model === "month") {
const selectedDate = dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), currentYear.value), value.month);
const formattedMonth = dateFns.format(selectedDate, "yyyy-MM");
emit("update:modelValue", formattedMonth);
emit("change", formattedMonth);
console.log(dateFns.format(selectedDate, "yyyy-MM"));
if (!props.multiple) {
displayValue.value = formattedMonth;
}
if (props.multiple) {
if (multipleData.value.includes(formattedMonth)) {
multipleData.value = multipleData.value.filter((item) => item !== formattedMonth);
} else {
multipleData.value.push(formattedMonth);
}
}
return;
}
if (!value.isCurrentMonth) {
currentDate.value = value.date;
return;
}
if (props.model === "date") {
if (props.range) {
const selectedDate = value.date;
if (!rangeState.value.selecting) {
rangeState.value.startDate = selectedDate;
rangeState.value.endDate = null;
rangeState.value.selecting = true;
} else {
if (dateFns.isBefore(selectedDate, rangeState.value.startDate)) {
rangeState.value.endDate = rangeState.value.startDate;
rangeState.value.startDate = selectedDate;
} else {
rangeState.value.endDate = selectedDate;
}
const startFormatted = formatDate(rangeState.value.startDate);
const endFormatted = formatDate(rangeState.value.endDate);
emit("update:modelValue", [startFormatted, endFormatted]);
emit("change", [startFormatted, endFormatted]);
displayValue.value = `${startFormatted} \u81F3 ${endFormatted}`;
rangeState.value.selecting = false;
visible.value = false;
}
return;
}
if (!props.multiple) {
const formattedDate = formatDate(value.date);
emit("update:modelValue", formattedDate);
emit("change", formattedDate);
displayValue.value = formattedDate;
visible.value = false;
return;
}
if (props.multiple) {
if (multipleData.value.includes(formatDate(value.date))) {
multipleData.value = multipleData.value.filter((item) => item !== formatDate(value.date));
} else {
multipleData.value.push(formatDate(value.date));
}
}
}
if (!props.multiple) {
visible.value = false;
}
};
const confirm = () => {
visible.value = false;
emit("update:modelValue", multipleData.value.join(","));
emit("change", multipleData.value.join(","));
displayValue.value = multipleData.value.join(",");
};
const prevYear = () => {
currentDate.value = dateFns.subYears(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = dateFns.subYears(nextMonthDate.value, 1);
}
};
const nextYear = () => {
currentDate.value = dateFns.addYears(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = dateFns.addYears(nextMonthDate.value, 1);
}
};
const prevMonth = () => {
currentDate.value = dateFns.subMonths(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = dateFns.subMonths(nextMonthDate.value, 1);
}
};
const nextMonth = () => {
currentDate.value = dateFns.addMonths(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = dateFns.addMonths(nextMonthDate.value, 1);
}
};
const generateUniqueId = () => {
return `date-picker-${Math.random().toString(36).substr(2, 9)}`;
};
const uniqueId = vue.ref(generateUniqueId());
const handleClickOutside = (e) => {
const root = e.currentTarget;
const panel = root.querySelector(".x-date-picker__panel");
const input = root.querySelector(".x-date-picker__input");
if (panel && !panel.contains(e.target) && !input.contains(e.target)) {
visible.value = false;
}
};
vue.onMounted(() => {
const root = document.querySelector(`[data-id="${uniqueId.value}"]`);
if (root) {
root.addEventListener("click", handleClickOutside);
}
});
vue.onUnmounted(() => {
const root = document.querySelector(`[data-id="${uniqueId.value}"]`);
if (root) {
root.removeEventListener("click", handleClickOutside);
}
});
const nextMonthDays = vue.computed(() => {
const year = nextMonthDate.value.getFullYear();
const month = nextMonthDate.value.getMonth();
const firstDay = dateFns.setDate(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month), 1);
const lastDay = dateFns.endOfMonth(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month));
const days2 = [];
for (let i = dateFns.getDay(firstDay); i > 0; i--) {
const date = dateFns.subDays(firstDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
for (let i = 1; i <= lastDay.getDate(); i++) {
const date = dateFns.setDate(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month), i);
days2.push({
day: i,
date,
isCurrentMonth: true,
isToday: dateFns.isToday(date),
isSelected: isSelected(date),
isInRange: isInRange(date)
});
}
const remaining = 42 - days2.length;
for (let i = 1; i <= remaining; i++) {
const date = dateFns.addDays(lastDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
return days2;
});
const days = vue.computed(() => {
const year = currentYear.value;
const month = currentMonth.value;
const firstDay = dateFns.setDate(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month), 1);
const lastDay = dateFns.endOfMonth(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month));
const days2 = [];
for (let i = dateFns.getDay(firstDay); i > 0; i--) {
const date = dateFns.subDays(firstDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
for (let i = 1; i <= lastDay.getDate(); i++) {
const date = dateFns.setDate(dateFns.setMonth(dateFns.setYear(/* @__PURE__ */ new Date(), year), month), i);
days2.push({
day: i,
date,
isCurrentMonth: true,
isToday: dateFns.isToday(date),
isSelected: isSelected(date),
isInRange: isInRange(date)
});
}
const remaining = 42 - days2.length;
for (let i = 1; i <= remaining; i++) {
const date = dateFns.addDays(lastDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
return days2;
});
const renderDays = (data, getKey, getContent, getClasses, onClick) => {
return vue.createVNode("div", {
"class": ns.e("days")
}, [data.map((item, index) => vue.createVNode("span", {
"key": getKey(item, index),
"class": getClasses(item),
"onClick": () => onClick(item)
}, [getContent(item)]))]);
};
return () => vue.createVNode("div", {
"data-id": uniqueId.value,
"class": ns.b()
}, [vue.createVNode("div", {
"class": [ns.e("input"), ns.is("range", props.range)],
"onClick": showPanel
}, [vue.createVNode(index.XInput, {
"modelValue": displayValue.value,
"placeholder": placeholder.value,
"disabled": props.disabled,
"readonly": props.readonly,
"clearance": props.clearance,
"onClear": handleClear
}, {
prepend: () => vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.Calendar, null, null)]
})
})]), visible.value && vue.createVNode("div", {
"class": [ns.e("panel"), props.range ? ns.m("panel", "range") : ""]
}, [vue.createVNode("div", {
"class": props.range ? ns.e("panel-left") : ""
}, [props.model == "date" && vue.createVNode("div", {
"class": ns.e("header")
}, [vue.createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("prev-month"),
"onClick": prevMonth
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, vue.createTextVNode("\u5E74 "), currentMonth.value + 1, vue.createTextVNode("\u6708")]), vue.createVNode("span", {
"class": ns.e("next-month"),
"onClick": nextMonth
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronRight, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsRight, null, null)]
})])]), props.model == "year" && vue.createVNode("div", {
"class": ns.e("header")
}, [vue.createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, vue.createTextVNode("\u5E74")]), vue.createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsRight, null, null)]
})])]), props.model == "month" && vue.createVNode("div", {
"class": ns.e("header")
}, [vue.createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, vue.createTextVNode("\u5E74")]), vue.createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsRight, null, null)]
})])]), vue.createVNode("div", {
"class": ns.e("content")
}, [props.model == "date" && vue.createVNode("div", {
"class": ns.e("week-header")
}, [weekDays.map((day) => vue.createVNode("span", {
"key": day
}, [day]))]), props.model == "date" && renderDays(
days.value,
(_, index) => index,
// 使用索引作为 key
(cell) => cell.day,
// 显示日期
(cell) => [ns.e("cell"), ns.is("selected", cell.isSelected), ns.is("today", cell.isToday), ns.is("not-current-month", !cell.isCurrentMonth), ns.is("in-range", cell.isInRange), ns.is("range-start", props.range && rangeState.value.startDate && dateFns.isSameDay(cell.date, rangeState.value.startDate)), ns.is("range-end", props.range && rangeState.value.endDate && dateFns.isSameDay(cell.date, rangeState.value.endDate))],
(cell) => selectDate(cell)
), props.model == "year" && renderDays(
years.value,
(cell) => cell.year,
// 使用年份作为 key
(cell) => cell.year,
// 显示年份
(cell) => [ns.e("cell"), ns.is("today", cell.isYear), ns.is("selected", cell.isSelected)],
(cell) => selectDate(cell.year)
), props.model == "month" && renderDays(
months.value,
(cell) => cell.month,
// 使用月份作为 key
(cell) => cell.name,
// 显示月份名称
(cell) => [ns.e("cell"), ns.is("selected", cell.isSelected), ns.is("today", cell.isCurrentMonth)],
(cell) => selectDate(cell)
)]), props.multiple && vue.createVNode("div", {
"class": ns.e("footer")
}, [vue.createVNode(vue.resolveComponent("x-button"), {
"type": "primary",
"size": "small",
"onClick": () => confirm()
}, {
default: () => [vue.createTextVNode("\u786E\u5B9A")]
}), vue.createVNode(vue.resolveComponent("x-button"), {
"size": "small",
"onClick": () => handleClear()
}, {
default: () => [vue.createTextVNode("\u53D6\u6D88")]
})])]), props.range && props.model === "date" && vue.createVNode("div", {
"class": ns.e("panel-right")
}, [vue.createVNode("div", {
"class": ns.e("header")
}, [vue.createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("prev-month"),
"onClick": prevMonth
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronLeft, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("header-label")
}, [nextMonthDate.value.getFullYear(), vue.createTextVNode("\u5E74"), " ", nextMonthDate.value.getMonth() + 1, vue.createTextVNode("\u6708")]), vue.createVNode("span", {
"class": ns.e("next-month"),
"onClick": nextMonth
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronRight, null, null)]
})]), vue.createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [vue.createVNode(index$1.XIcon, null, {
default: () => [vue.createVNode(icons.ChevronsRight, null, null)]
})])]), vue.createVNode("div", {
"class": ns.e("content")
}, [vue.createVNode("div", {
"class": ns.e("week-header")
}, [weekDays.map((day) => vue.createVNode("span", {
"key": day
}, [day]))]), renderDays(nextMonthDays.value, (_, index) => index, (cell) => cell.day, (cell) => [ns.e("cell"), ns.is("selected", cell.isSelected), ns.is("today", cell.isToday), ns.is("not-current-month", !cell.isCurrentMonth), ns.is("in-range", cell.isInRange), ns.is("range-start", props.range && rangeState.value.startDate && dateFns.isSameDay(cell.date, rangeState.value.startDate)), ns.is("range-end", props.range && rangeState.value.endDate && dateFns.isSameDay(cell.date, rangeState.value.endDate))], (cell) => selectDate(cell))])])])]);
}
});
module.exports = datePicker;
//# sourceMappingURL=index.cjs.map