song-ui-u
Version:
vue3 + js的PC前端组件库
601 lines (598 loc) • 22.6 kB
JavaScript
import { defineComponent, ref, computed, onMounted, onUnmounted, createVNode, createTextVNode, resolveComponent } from 'vue';
import '../../button/index.mjs';
import '../../buttonGroup/index.mjs';
import { XIcon } from '../../icon/index.mjs';
import { XInput } from '../../input/index.mjs';
import '../../textarea/index.mjs';
import '../../row/index.mjs';
import '../../col/index.mjs';
import '../../container/index.mjs';
import '../../checkbox/index.mjs';
import '../../switch/index.mjs';
import '../../form/index.mjs';
import '../../message/index.mjs';
import '../../mask/src/mask.mjs';
import '../../modal/index.mjs';
import '../../messageBox/index.mjs';
import '../../drawer/index.mjs';
import '../../badge/index.mjs';
import '../../space/index.mjs';
import '../../image/index.mjs';
import '../../radio/index.mjs';
import '../../divider/index.mjs';
import '../../chat/index.mjs';
import '../../progress/index.mjs';
import '../../upload/index.mjs';
import '../../vTree/index.mjs';
import '../../table/index.mjs';
import '../../tabs/index.mjs';
import '../../menu/index.mjs';
import '../../steps/index.mjs';
import '../../header/index.mjs';
import '../../breadcrumble/index.mjs';
import '../index.mjs';
import '../../tooltip/index.mjs';
import '../../popover/index.mjs';
import '../../timePicker/index.mjs';
import '../../select/index.mjs';
import '../../collapse/index.mjs';
import '../../card/index.mjs';
import '../../timeline/index.mjs';
import '../../tag/index.mjs';
import '../../result/index.mjs';
import '../../sender/index.mjs';
import { Calendar, ChevronsLeft, ChevronLeft, ChevronRight, ChevronsRight } from 'song-ui-pro-icon';
import { useNamespace } from '../../../hook/use-namespace/index.mjs';
import '../../../hook/use-zindex/index.mjs';
import { addMonths, parse, format, setMonth, setYear, isSameDay, setDate, endOfMonth, getDay, subDays, isToday, addDays, isAfter, isBefore, subYears, addYears, subMonths } from 'date-fns';
var datePicker = /* @__PURE__ */ 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 = useNamespace("date-picker");
const visible = ref(false);
const currentDate = ref(new Date(props.modelValue || /* @__PURE__ */ new Date()));
const nextMonthDate = ref(addMonths(currentDate.value, 1));
const displayValue = ref("");
const weekDays = ["\u65E5", "\u4E00", "\u4E8C", "\u4E09", "\u56DB", "\u4E94", "\u516D"];
const rangeState = ref({
selecting: false,
// 是否正在选择范围
startDate: null,
// 开始日期
endDate: null
// 结束日期
});
if (props.range && Array.isArray(props.modelValue) && props.modelValue.length === 2) {
rangeState.value.startDate = parse(props.modelValue[0], props.format, /* @__PURE__ */ new Date());
rangeState.value.endDate = parse(props.modelValue[1], props.format, /* @__PURE__ */ new Date());
displayValue.value = `${formatDate(rangeState.value.startDate)} \u81F3 ${formatDate(rangeState.value.endDate)}`;
}
const currentYear = computed(() => currentDate.value.getFullYear());
const currentMonth = computed(() => currentDate.value.getMonth());
const placeholder = 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 = 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 = 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 = format(setMonth(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 && isSameDay(date, rangeState.value.startDate)) return true;
if (rangeState.value.endDate && isSameDay(date, rangeState.value.endDate)) return true;
return false;
}
if (props.multiple) {
return multipleData.value.includes(formatDate(value));
}
return 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 = format(setMonth(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 isAfter(date, start) && isBefore(date, end);
};
const formatDate = (date) => {
return 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 = 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 = setMonth(setYear(/* @__PURE__ */ new Date(), currentYear.value), value.month);
const formattedMonth = format(selectedDate, "yyyy-MM");
emit("update:modelValue", formattedMonth);
emit("change", formattedMonth);
console.log(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 (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 = subYears(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = subYears(nextMonthDate.value, 1);
}
};
const nextYear = () => {
currentDate.value = addYears(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = addYears(nextMonthDate.value, 1);
}
};
const prevMonth = () => {
currentDate.value = subMonths(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = subMonths(nextMonthDate.value, 1);
}
};
const nextMonth = () => {
currentDate.value = addMonths(currentDate.value, 1);
if (props.range) {
nextMonthDate.value = addMonths(nextMonthDate.value, 1);
}
};
const generateUniqueId = () => {
return `date-picker-${Math.random().toString(36).substr(2, 9)}`;
};
const uniqueId = 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;
}
};
onMounted(() => {
const root = document.querySelector(`[data-id="${uniqueId.value}"]`);
if (root) {
root.addEventListener("click", handleClickOutside);
}
});
onUnmounted(() => {
const root = document.querySelector(`[data-id="${uniqueId.value}"]`);
if (root) {
root.removeEventListener("click", handleClickOutside);
}
});
const nextMonthDays = computed(() => {
const year = nextMonthDate.value.getFullYear();
const month = nextMonthDate.value.getMonth();
const firstDay = setDate(setMonth(setYear(/* @__PURE__ */ new Date(), year), month), 1);
const lastDay = endOfMonth(setMonth(setYear(/* @__PURE__ */ new Date(), year), month));
const days2 = [];
for (let i = getDay(firstDay); i > 0; i--) {
const date = subDays(firstDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
for (let i = 1; i <= lastDay.getDate(); i++) {
const date = setDate(setMonth(setYear(/* @__PURE__ */ new Date(), year), month), i);
days2.push({
day: i,
date,
isCurrentMonth: true,
isToday: isToday(date),
isSelected: isSelected(date),
isInRange: isInRange(date)
});
}
const remaining = 42 - days2.length;
for (let i = 1; i <= remaining; i++) {
const date = addDays(lastDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
return days2;
});
const days = computed(() => {
const year = currentYear.value;
const month = currentMonth.value;
const firstDay = setDate(setMonth(setYear(/* @__PURE__ */ new Date(), year), month), 1);
const lastDay = endOfMonth(setMonth(setYear(/* @__PURE__ */ new Date(), year), month));
const days2 = [];
for (let i = getDay(firstDay); i > 0; i--) {
const date = subDays(firstDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
for (let i = 1; i <= lastDay.getDate(); i++) {
const date = setDate(setMonth(setYear(/* @__PURE__ */ new Date(), year), month), i);
days2.push({
day: i,
date,
isCurrentMonth: true,
isToday: isToday(date),
isSelected: isSelected(date),
isInRange: isInRange(date)
});
}
const remaining = 42 - days2.length;
for (let i = 1; i <= remaining; i++) {
const date = addDays(lastDay, i);
days2.push({
day: date.getDate(),
date,
isCurrentMonth: false
});
}
return days2;
});
const renderDays = (data, getKey, getContent, getClasses, onClick) => {
return createVNode("div", {
"class": ns.e("days")
}, [data.map((item, index) => createVNode("span", {
"key": getKey(item, index),
"class": getClasses(item),
"onClick": () => onClick(item)
}, [getContent(item)]))]);
};
return () => createVNode("div", {
"data-id": uniqueId.value,
"class": ns.b()
}, [createVNode("div", {
"class": [ns.e("input"), ns.is("range", props.range)],
"onClick": showPanel
}, [createVNode(XInput, {
"modelValue": displayValue.value,
"placeholder": placeholder.value,
"disabled": props.disabled,
"readonly": props.readonly,
"clearance": props.clearance,
"onClear": handleClear
}, {
prepend: () => createVNode(XIcon, null, {
default: () => [createVNode(Calendar, null, null)]
})
})]), visible.value && createVNode("div", {
"class": [ns.e("panel"), props.range ? ns.m("panel", "range") : ""]
}, [createVNode("div", {
"class": props.range ? ns.e("panel-left") : ""
}, [props.model == "date" && createVNode("div", {
"class": ns.e("header")
}, [createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("prev-month"),
"onClick": prevMonth
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, createTextVNode("\u5E74 "), currentMonth.value + 1, createTextVNode("\u6708")]), createVNode("span", {
"class": ns.e("next-month"),
"onClick": nextMonth
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronRight, null, null)]
})]), createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsRight, null, null)]
})])]), props.model == "year" && createVNode("div", {
"class": ns.e("header")
}, [createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, createTextVNode("\u5E74")]), createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsRight, null, null)]
})])]), props.model == "month" && createVNode("div", {
"class": ns.e("header")
}, [createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("header-label")
}, [currentYear.value, createTextVNode("\u5E74")]), createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsRight, null, null)]
})])]), createVNode("div", {
"class": ns.e("content")
}, [props.model == "date" && createVNode("div", {
"class": ns.e("week-header")
}, [weekDays.map((day) => 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 && isSameDay(cell.date, rangeState.value.startDate)), ns.is("range-end", props.range && rangeState.value.endDate && 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 && createVNode("div", {
"class": ns.e("footer")
}, [createVNode(resolveComponent("x-button"), {
"type": "primary",
"size": "small",
"onClick": () => confirm()
}, {
default: () => [createTextVNode("\u786E\u5B9A")]
}), createVNode(resolveComponent("x-button"), {
"size": "small",
"onClick": () => handleClear()
}, {
default: () => [createTextVNode("\u53D6\u6D88")]
})])]), props.range && props.model === "date" && createVNode("div", {
"class": ns.e("panel-right")
}, [createVNode("div", {
"class": ns.e("header")
}, [createVNode("span", {
"class": ns.e("prev-year"),
"onClick": prevYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("prev-month"),
"onClick": prevMonth
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronLeft, null, null)]
})]), createVNode("span", {
"class": ns.e("header-label")
}, [nextMonthDate.value.getFullYear(), createTextVNode("\u5E74"), " ", nextMonthDate.value.getMonth() + 1, createTextVNode("\u6708")]), createVNode("span", {
"class": ns.e("next-month"),
"onClick": nextMonth
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronRight, null, null)]
})]), createVNode("span", {
"class": ns.e("next-year"),
"onClick": nextYear
}, [createVNode(XIcon, null, {
default: () => [createVNode(ChevronsRight, null, null)]
})])]), createVNode("div", {
"class": ns.e("content")
}, [createVNode("div", {
"class": ns.e("week-header")
}, [weekDays.map((day) => 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 && isSameDay(cell.date, rangeState.value.startDate)), ns.is("range-end", props.range && rangeState.value.endDate && isSameDay(cell.date, rangeState.value.endDate))], (cell) => selectDate(cell))])])])]);
}
});
export { datePicker as default };
//# sourceMappingURL=index.mjs.map