فهرست منبع

优化日期选择体验

icssoa 7 ماه پیش
والد
کامیت
57809c7a37

+ 21 - 6
pages/demo/form/select-date.uvue

@@ -2,14 +2,18 @@
 	<cl-page>
 		<view class="p-3">
 			<demo-item :label="t('基础用法')">
-				<cl-select-date v-model="form.date1" type="date"></cl-select-date>
+				<cl-select-date
+					v-model="form.date1"
+					type="date"
+					@change="onDateChange"
+				></cl-select-date>
 			</demo-item>
 
 			<demo-item :label="t('固定开始、结束日期')">
 				<cl-select-date
 					v-model="form.date3"
 					start="2025-06-01"
-					end="2026-06-01"
+					end="2027-08-01"
 					type="date"
 				></cl-select-date>
 			</demo-item>
@@ -34,7 +38,7 @@
 
 			<demo-item :label="t('自定义快捷选项')">
 				<cl-select-date
-					v-model:values="form.date5"
+					v-model:values="form.date6"
 					type="date"
 					rangeable
 					:shortcuts="shortcuts"
@@ -43,7 +47,7 @@
 
 			<demo-item :label="t('自定义')">
 				<cl-select-date
-					v-model="form.date6"
+					v-model="form.date7"
 					:type="type"
 					:label-format="labelFormat"
 					:disabled="isDisabled"
@@ -129,13 +133,23 @@ import { dayUts } from "@/cool";
 
 const ui = useUi();
 
+// 测试日期选择变化事件
+function onDateChange(value: string) {
+	console.log("日期选择变化:", value);
+	ui.showToast({
+		message: `选择了日期: ${value}`,
+		type: "success"
+	});
+}
+
 type Form = {
 	date1: string;
 	date2: string;
 	date3: string;
 	date4: string;
 	date5: string[];
-	date6: string;
+	date6: string[];
+	date7: string;
 };
 
 const form = reactive<Form>({
@@ -144,7 +158,8 @@ const form = reactive<Form>({
 	date3: "",
 	date4: "",
 	date5: [],
-	date6: ""
+	date6: [],
+	date7: ""
 });
 
 const isDisabled = ref(false);

+ 11 - 30
uni_modules/cool-ui/components/cl-picker-view/cl-picker-view.uvue

@@ -89,15 +89,10 @@ const props = defineProps({
 	height: {
 		type: Number,
 		default: 600
-	},
-	// 选择后子集是否回到0
-	resetOnChange: {
-		type: Boolean,
-		default: true
 	}
 });
 
-const emit = defineEmits(["change"]);
+const emit = defineEmits(["change-value", "change-index"]);
 
 // 获取窗口宽度,用于计算选择器列宽
 const { windowWidth } = uni.getWindowInfo();
@@ -151,33 +146,19 @@ const indicatorStyle = computed(() => {
 	return str;
 });
 
-// 选择器值改变事件
+// 监听选择器值改变事件
 function onChange(e: UniPickerViewChangeEvent) {
 	// 获取选择器当前选中值数组
-	const arr = e.detail.value;
-
-	// 如果选择后子集是否回到0
-	if (props.resetOnChange) {
-		// 记录第一个发生变化的列的索引,初始为-1表示未发生变化
-		let start = -1;
-
-		// 遍历原选中值数组
-		props.value.forEach((e, i) => {
-			if (start >= 0) {
-				// 如果之前的列发生过变化,后续列都重置为0
-				arr[i] = 0;
-			} else {
-				// 比较当前列的值是否发生变化
-				if (e != arr[i]) {
-					// 记录第一个变化的列的索引
-					start = i;
-				}
-			}
-		});
-	}
+	const indexs = e.detail.value;
+
+	// 获取所有列的值
+	const values = props.columns.map((c, i) => {
+		return c[indexs[i]].value;
+	});
 
-	// 触发change事件,传递新的选中值数组
-	emit("change", arr);
+	// 返回所有列的值或下标
+	emit("change-value", values);
+	emit("change-index", indexs);
 }
 </script>
 

+ 85 - 18
uni_modules/cool-ui/components/cl-select-date/cl-select-date.uvue

@@ -101,7 +101,8 @@
 					:headers="headers"
 					:value="indexes"
 					:columns="columns"
-					@change="onChange"
+					:reset-on-change="false"
+					@change-value="onChange"
 				></cl-picker-view>
 			</view>
 
@@ -514,12 +515,19 @@ const indexes = computed(() => {
 	if (isEmpty(value.value)) {
 		return [];
 	}
+
 	// 遍历每一列,查找当前值在选项中的下标
 	return value.value.map((e, i) => {
-		const index = list.value[i].findIndex((a) => a.value == e);
-		// 如果未找到,返回0
+		let index = list.value[i].findIndex((a) => a.value == e) as number;
+
+		// 如果未找到,返回最后一个
 		if (index == -1) {
-			return 0;
+			index = list.value[i].length - 1;
+		}
+
+		// 如果小于0,返回0
+		if (index < 0) {
+			index = 0;
 		}
 
 		return index;
@@ -548,6 +556,58 @@ function toDate() {
 	return parts.join("");
 }
 
+// 检查边界值
+function checkDate(values: number[]): number[] {
+	if (values.length == 0) {
+		return values;
+	}
+
+	// 确保至少有6个元素,缺失的用默认值填充
+	const checkedValues = [...values];
+	const defaultValues = [2000, 1, 1, 0, 0, 0];
+	for (let i = checkedValues.length; i < 6; i++) {
+		checkedValues.push(defaultValues[i]);
+	}
+
+	let [year, month, date, hour, minute, second] = checkedValues;
+
+	// 检查日期边界(根据年份和月份确定最大天数)
+	// 判断是否为闰年
+	const isLeapYear = (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;
+	// 每月天数数组,2月根据闰年判断
+	const daysInMonth = [31, isLeapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+	const maxDay = daysInMonth[month - 1];
+
+	if (date < 1) {
+		date = 1;
+	} else if (date > maxDay) {
+		date = maxDay;
+	}
+
+	// 检查小时边界 (0-23)
+	if (hour < 0) {
+		hour = 0;
+	} else if (hour > 23) {
+		hour = 23;
+	}
+
+	// 检查分钟边界 (0-59)
+	if (minute < 0) {
+		minute = 0;
+	} else if (minute > 59) {
+		minute = 59;
+	}
+
+	// 检查秒钟边界 (0-59)
+	if (second < 0) {
+		second = 0;
+	} else if (second > 59) {
+		second = 59;
+	}
+
+	return [year, month, date, hour, minute, second];
+}
+
 // 显示文本,展示当前选中的日期字符串
 const text = ref("");
 
@@ -563,19 +623,19 @@ function getText() {
 }
 
 // 选择器值改变事件,更新value
-async function onChange(arr: number[]) {
-	const data = [] as number[];
-
-	for (let i = 0; i < arr.length; i++) {
-		const item = list.value[i][arr[i]];
+async function onChange(data: number[]) {
+	// 更新value
+	value.value = checkDate(data);
 
-		if (!isNull(item)) {
-			data.push(item.value as number);
-		}
+	// 不能大于结束日期
+	if (dayUts(toDate()).isAfter(dayUts(props.end))) {
+		value.value = dayUts(props.end).toArray();
 	}
 
-	// 更新value
-	value.value = data;
+	// 不能小于开始日期
+	if (dayUts(toDate()).isBefore(dayUts(props.start))) {
+		value.value = dayUts(props.start).toArray();
+	}
 
 	// 设置范围值
 	if (props.rangeable) {
@@ -597,10 +657,10 @@ function setValue(val: string) {
 
 	// 如果值为空,使用当前时间
 	if (isNull(val) || isEmpty(val)) {
-		value.value = dayUts().toArray();
+		value.value = checkDate(dayUts().toArray());
 	} else {
 		// 否则解析为数组
-		value.value = dayUts(val).toArray();
+		value.value = checkDate(dayUts(val).toArray());
 		getText();
 	}
 }
@@ -669,8 +729,7 @@ function close() {
 
 // 选择器关闭后
 function onClosed() {
-	value.value = [];
-	values.value = [];
+	values.value = ["", ""];
 }
 
 // 清空选择器,重置显示文本并触发事件
@@ -761,6 +820,14 @@ watch(
 	}
 );
 
+// 更新显示文本
+watch(
+	computed(() => props.labelFormat),
+	() => {
+		getText();
+	}
+);
+
 defineExpose({
 	open,
 	close,

+ 1 - 1
uni_modules/cool-ui/components/cl-select-time/cl-select-time.uvue

@@ -33,7 +33,7 @@
 					:headers="headers"
 					:columns="columns"
 					:reset-on-change="false"
-					@change="onChange"
+					@change-index="onChange"
 				></cl-picker-view>
 			</view>