UNPKG

song-ui-u

Version:

vue3 + js的PC前端组件库

603 lines (599 loc) 23.4 kB
'use strict'; 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