Browse Source

cl-calendar 支持添加上下文案

icssoa 6 months ago
parent
commit
21dd6a5eed

+ 165 - 14
pages/demo/form/calendar.uvue

@@ -5,37 +5,188 @@
 				<cl-calendar-select v-model="date"></cl-calendar-select>
 			</demo-item>
 
-			<demo-item :label="t('范围选择器')">
-				<cl-calendar-select v-model:date="dateArr" mode="range"></cl-calendar-select>
+			<demo-item :label="t('多选')">
+				<cl-calendar-select v-model:date="dateArr" mode="multiple"></cl-calendar-select>
+			</demo-item>
+
+			<demo-item :label="t('范围选')">
+				<cl-calendar-select v-model:date="dateRange" mode="range"></cl-calendar-select>
 			</demo-item>
 
 			<demo-item :label="t('禁用部分日期')">
-				<cl-calendar-select
-					v-model="date"
-					:disabled-date="disabledDate"
-				></cl-calendar-select>
+				<cl-calendar-select v-model="date" :date-config="dateConfig"></cl-calendar-select>
 			</demo-item>
 
+			<!-- <demo-item :label="t('日历长列表')">
+				<cl-button>{{ t("打开日历长列表") }}</cl-button>
+			</demo-item> -->
+
 			<demo-item :label="t('日历面板')">
-				<cl-calendar v-model="date"></cl-calendar>
+				<cl-calendar
+					v-model:date="dateRange2"
+					mode="range"
+					:month="10"
+					:show-header="isShowHeader"
+					:show-weeks="isShowWeeks"
+					:show-other-month="isShowOtherMonth"
+					:date-config="dateConfig2"
+					@change="onChange"
+				></cl-calendar>
+
+				<cl-list
+					border
+					:pt="{
+						className: 'mt-5'
+					}"
+				>
+					<cl-list-item :label="t('自定义文案和颜色')">
+						<cl-switch v-model="isCustomDateConfig"></cl-switch>
+					</cl-list-item>
+					<cl-list-item :label="t('显示头')">
+						<cl-switch v-model="isShowHeader"></cl-switch>
+					</cl-list-item>
+					<cl-list-item :label="t('显示星期')">
+						<cl-switch v-model="isShowWeeks"></cl-switch>
+					</cl-list-item>
+					<cl-list-item :label="t('显示其他月份')">
+						<cl-switch v-model="isShowOtherMonth"></cl-switch>
+					</cl-list-item>
+				</cl-list>
 			</demo-item>
 		</view>
 	</cl-page>
 </template>
 
 <script lang="ts" setup>
-import { ref } from "vue";
+import { computed, ref } from "vue";
 import { t } from "@/locale";
 import DemoItem from "../components/item.uvue";
-import { dayUts } from "@/cool";
+import { dayUts, first, last } from "@/cool";
+import type { ClCalendarDateConfig } from "@/uni_modules/cool-ui";
 
 const date = ref<string | null>(dayUts().format("YYYY-MM-DD"));
 
-const dateArr = ref<string[]>(["2025-09-02", "2025-09-09"]);
+const dateArr = ref<string[]>([
+	dayUts().format("YYYY-MM-DD"),
+	dayUts().add(1, "day").format("YYYY-MM-DD")
+]);
 
-const disabledDate = ref<string[]>([
-	dayUts().add(2, "day").format("YYYY-MM-DD"),
-	dayUts().add(4, "day").format("YYYY-MM-DD"),
-	dayUts().add(6, "day").format("YYYY-MM-DD")
+const dateRange = ref<string[]>([
+	dayUts().format("YYYY-MM-DD"),
+	dayUts().add(10, "day").format("YYYY-MM-DD")
 ]);
+
+const dateConfig = ref<ClCalendarDateConfig[]>([
+	{
+		date: dayUts().add(1, "day").format("YYYY-MM-DD"),
+		disabled: true
+	},
+	{
+		date: dayUts().add(2, "day").format("YYYY-MM-DD"),
+		disabled: true
+	},
+	{
+		date: dayUts().add(3, "day").format("YYYY-MM-DD"),
+		disabled: true
+	}
+]);
+
+const isShowHeader = ref(true);
+const isShowWeeks = ref(true);
+const isShowOtherMonth = ref(true);
+const isCustomDateConfig = ref(true);
+
+const dateRange2 = ref<string[]>([]);
+
+const dateConfig2 = computed(() => {
+	const dates = (
+		isCustomDateConfig.value
+			? [
+					{
+						date: "2025-10-01",
+						topText: "国庆节",
+						bottomText: "¥958",
+						color: "red"
+					},
+					{
+						date: "2025-10-02",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-03",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-04",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-05",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-06",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-07",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					},
+					{
+						date: "2025-10-08",
+						topText: "休",
+						bottomText: "¥613",
+						color: "red"
+					}
+				]
+			: []
+	) as ClCalendarDateConfig[];
+
+	const startDate = first(dateRange2.value);
+	const endDate = last(dateRange2.value);
+
+	if (startDate != null) {
+		const item = dates.find((e) => e.date == startDate);
+
+		if (item == null) {
+			dates.push({
+				date: startDate,
+				bottomText: "入住"
+			} as ClCalendarDateConfig);
+		} else {
+			item.bottomText = "入住";
+		}
+	}
+
+	if (endDate != null && dateRange2.value.length > 1) {
+		const item = dates.find((e) => e.date == endDate);
+
+		if (item == null) {
+			dates.push({
+				date: endDate,
+				bottomText: "离店"
+			} as ClCalendarDateConfig);
+		} else {
+			item.bottomText = "离店";
+		}
+	}
+
+	return dates;
+});
+
+function onChange(date: string[]) {
+	console.log("日期变化:", date);
+}
 </script>

+ 27 - 7
uni_modules/cool-ui/components/cl-calendar-select/cl-calendar-select.uvue

@@ -33,7 +33,8 @@
 					v-model="value"
 					v-model:date="date"
 					:mode="mode"
-					:disabled-date="disabledDate"
+					:date-config="dateConfig"
+					@change="onCalendarChange"
 				></cl-calendar>
 			</view>
 
@@ -68,7 +69,7 @@
 
 <script setup lang="ts">
 import { ref, computed, type PropType } from "vue";
-import type { ClCalendarMode } from "../../types";
+import type { ClCalendarDateConfig, ClCalendarMode } from "../../types";
 import { isEmpty, parsePt } from "@/cool";
 import type { ClSelectTriggerPassThrough } from "../cl-select-trigger/props";
 import type { ClPopupPassThrough } from "../cl-popup/props";
@@ -105,9 +106,9 @@ const props = defineProps({
 		type: String as PropType<ClCalendarMode>,
 		default: "single"
 	},
-	// 禁用的日期
-	disabledDate: {
-		type: Array as PropType<string[]>,
+	// 日期配置
+	dateConfig: {
+		type: Array as PropType<ClCalendarDateConfig[]>,
 		default: () => []
 	},
 	// 选择器标题
@@ -133,6 +134,11 @@ const props = defineProps({
 	// 分隔符
 	splitor: {
 		type: String,
+		default: "、"
+	},
+	// 范围分隔符
+	rangeSplitor: {
+		type: String,
 		default: () => t(" 至 ")
 	},
 	// 确认按钮文本
@@ -158,7 +164,7 @@ const props = defineProps({
 });
 
 // 定义事件
-const emit = defineEmits(["update:modelValue", "update:date", "change"]);
+const emit = defineEmits(["update:modelValue", "update:date", "change", "select"]);
 
 // 弹出层引用
 const popupRef = ref<ClPopupComponentPublicInstance | null>(null);
@@ -180,7 +186,16 @@ const date = ref<string[]>([]);
 
 // 显示文本
 const text = computed(() => {
-	return props.mode == "single" ? (props.modelValue ?? "") : props.date.join(props.splitor);
+	switch (props.mode) {
+		case "single":
+			return props.modelValue ?? "";
+		case "multiple":
+			return props.date.join(props.splitor);
+		case "range":
+			return props.date.join(props.rangeSplitor);
+		default:
+			return "";
+	}
 });
 
 // 选择器显示状态
@@ -249,6 +264,11 @@ function confirm() {
 	close();
 }
 
+// 日历变化
+function onCalendarChange(date: string[]) {
+	emit("select", date);
+}
+
 defineExpose({
 	open,
 	close

+ 207 - 137
uni_modules/cool-ui/components/cl-calendar/cl-calendar.uvue

@@ -40,7 +40,7 @@
 		</view>
 
 		<!-- 星期标题行 -->
-		<view class="cl-calendar__weeks" :style="{ gap: `${cellGap}px` }">
+		<view class="cl-calendar__weeks" :style="{ gap: `${cellGap}px` }" v-if="showWeeks">
 			<view class="cl-calendar__weeks-item" v-for="weekName in weekLabels" :key="weekName">
 				<cl-text>{{ weekName }}</cl-text>
 			</view>
@@ -53,7 +53,6 @@
 			:style="{ height: `${viewHeight}px`, gap: `${cellGap}px` }"
 			@tap="onTap"
 		>
-			<!-- Web端使用DOM渲染 -->
 			<!-- #ifndef APP -->
 			<view
 				class="cl-calendar__view-row"
@@ -73,12 +72,41 @@
 						'is-today': dateCell.isToday,
 						'is-other-month': !dateCell.isCurrentMonth
 					}"
-					:style="{ height: cellHeight + 'px' }"
+					:style="{
+						height: cellHeight + 'px',
+						backgroundColor: getCellBgColor(dateCell)
+					}"
 					@click.stop="selectDateCell(dateCell)"
 				>
-					<cl-text :color="getCellColor(dateCell)" :size="`${fontSize}px`">{{
-						dateCell.date
-					}}</cl-text>
+					<!-- 顶部文本 -->
+					<cl-text
+						:size="20"
+						:color="getCellTextColor(dateCell)"
+						:pt="{
+							className: 'absolute top-[2px]'
+						}"
+						>{{ dateCell.topText }}</cl-text
+					>
+
+					<!-- 主日期数字 -->
+					<cl-text
+						:color="getCellTextColor(dateCell)"
+						:size="`${fontSize}px`"
+						:pt="{
+							className: 'font-bold'
+						}"
+						>{{ dateCell.date }}</cl-text
+					>
+
+					<!-- 底部文本 -->
+					<cl-text
+						:size="20"
+						:color="getCellTextColor(dateCell)"
+						:pt="{
+							className: 'absolute bottom-[2px]'
+						}"
+						>{{ dateCell.bottomText }}</cl-text
+					>
 				</view>
 			</view>
 			<!-- #endif -->
@@ -91,7 +119,7 @@ import { computed, nextTick, onMounted, ref, watch, type PropType } from "vue";
 import { ctx, dayUts, first, isDark, parsePt, useRefs } from "@/cool";
 import CalendarPicker from "./picker.uvue";
 import { $t, t } from "@/locale";
-import type { ClCalendarMode } from "../../types";
+import type { ClCalendarDateConfig, ClCalendarMode } from "../../types";
 
 defineOptions({
 	name: "cl-calendar"
@@ -107,6 +135,9 @@ type DateCell = {
 	fullDate: string; // 完整日期格式 YYYY-MM-DD
 	isDisabled: boolean; // 是否被禁用
 	isHide: boolean; // 是否隐藏显示
+	topText: string; // 顶部文案
+	bottomText: string; // 底部文案
+	color: string; // 颜色
 };
 
 // 组件属性定义
@@ -116,16 +147,6 @@ const props = defineProps({
 		type: Object,
 		default: () => ({})
 	},
-	// 是否显示头部导航栏
-	showHeader: {
-		type: Boolean,
-		default: true
-	},
-	// 日期选择模式:单选/多选/范围选择
-	mode: {
-		type: String as PropType<ClCalendarMode>,
-		default: "single"
-	},
 	// 当前选中的日期值(单选模式)
 	modelValue: {
 		type: String as PropType<string | null>,
@@ -136,65 +157,38 @@ const props = defineProps({
 		type: Array as PropType<string[]>,
 		default: () => []
 	},
-	// 是否显示其他月份的日期
-	showOtherMonth: {
-		type: Boolean,
-		default: true
+	// 日期选择模式:单选/多选/范围选择
+	mode: {
+		type: String as PropType<ClCalendarMode>,
+		default: "single"
 	},
-	// 禁用的日期列表
-	disabledDate: {
-		type: Array as PropType<string[]>,
+	// 日期配置
+	dateConfig: {
+		type: Array as PropType<ClCalendarDateConfig[]>,
 		default: () => []
 	},
-	// 单元格高度
-	cellHeight: {
-		type: Number,
-		default: 60
-	},
-	// 单元格间距
-	cellGap: {
-		type: Number,
-		default: 0
-	},
-	// 字体大小
-	fontSize: {
-		type: Number,
-		default: 14
-	},
-	// 当前月日期颜色
-	currentMonthColor: {
-		type: String,
-		default: () => ctx.color["surface-700"] as string
+	// 设置年份
+	year: {
+		type: Number
 	},
-	// 其他月日期颜色
-	otherMonthColor: {
-		type: String,
-		default: () => ctx.color["surface-300"] as string
+	// 设置月份
+	month: {
+		type: Number
 	},
-	// 今天日期颜色
-	todayColor: {
-		type: String,
-		default: "#ff6b6b"
-	},
-	// 选中日期文字颜色
-	selectedTextColor: {
-		type: String,
-		default: "#ffffff"
-	},
-	// 选中日期背景色
-	selectedBgColor: {
-		type: String,
-		default: () => ctx.color["primary-500"] as string
+	// 是否显示其他月份的日期
+	showOtherMonth: {
+		type: Boolean,
+		default: true
 	},
-	// 范围选择背景色
-	rangeBgColor: {
-		type: String,
-		default: () => ctx.color["primary-100"] as string
+	// 是否显示头部导航栏
+	showHeader: {
+		type: Boolean,
+		default: true
 	},
-	// 禁用的日期颜色
-	disabledColor: {
-		type: String,
-		default: () => ctx.color["surface-300"] as string
+	// 是否显示星期
+	showWeeks: {
+		type: Boolean,
+		default: true
 	}
 });
 
@@ -209,6 +203,39 @@ type PassThrough = {
 // 解析透传样式配置
 const pt = computed(() => parsePt<PassThrough>(props.pt));
 
+// 主色
+const color = ref(ctx.color["primary-500"] as string);
+// 单元格高度
+const cellHeight = ref(66);
+// 单元格间距
+const cellGap = ref(0);
+// 字体大小
+const fontSize = ref(14);
+// 当前月份日期颜色
+const textColor = computed(() => {
+	return isDark.value ? "white" : (ctx.color["surface-700"] as string);
+});
+// 其他月份日期颜色
+const textOtherMonthColor = computed(() => {
+	return isDark.value
+		? (ctx.color["surface-500"] as string)
+		: (ctx.color["surface-300"] as string);
+});
+// 禁用日期颜色
+const textDisabledColor = computed(() => {
+	return isDark.value
+		? (ctx.color["surface-500"] as string)
+		: (ctx.color["surface-300"] as string);
+});
+// 今天日期颜色
+const textTodayColor = ref("#ff6b6b");
+// 选中日期颜色
+const textSelectedColor = ref("#ffffff");
+// 选中日期背景颜色
+const bgSelectedColor = ref(color.value);
+// 范围选择背景颜色
+const bgRangeColor = ref(color.value + "11");
+
 // 组件引用管理器
 const refs = useRefs();
 
@@ -223,7 +250,7 @@ const currentMonth = ref(0);
 
 // 视图高度
 const viewHeight = computed(() => {
-	return props.cellHeight * 6 + "px";
+	return cellHeight.value * 6;
 });
 
 // 单元格宽度
@@ -266,7 +293,7 @@ function isDateSelected(dateStr: string): boolean {
  * @param dateStr 日期字符串 YYYY-MM-DD
  */
 function isDateDisabled(dateStr: string): boolean {
-	return props.disabledDate.includes(dateStr);
+	return props.dateConfig.some((config) => config.date == dateStr && config.disabled == true);
 }
 
 /**
@@ -285,6 +312,63 @@ function isDateInRange(dateStr: string): boolean {
 }
 
 /**
+ * 获取单元格字体颜色
+ * @param dateCell 日期单元格数据
+ * @returns 字体颜色
+ */
+function getCellTextColor(dateCell: DateCell): string {
+	// 选中的日期文字颜色
+	if (dateCell.isSelected) {
+		return textSelectedColor.value;
+	}
+
+	if (dateCell.color != "") {
+		return dateCell.color;
+	}
+
+	// 范围选择日期颜色
+	if (dateCell.isRange) {
+		return color.value;
+	}
+
+	// 禁用的日期颜色
+	if (dateCell.isDisabled) {
+		return textDisabledColor.value;
+	}
+
+	// 今天日期颜色
+	if (dateCell.isToday) {
+		return textTodayColor.value;
+	}
+
+	// 当前月份日期颜色
+	if (dateCell.isCurrentMonth) {
+		return textColor.value;
+	}
+
+	// 其他月份日期颜色
+	return textOtherMonthColor.value;
+}
+
+/**
+ * 获取单元格背景颜色
+ * @param dateCell 日期单元格数据
+ * @returns 背景颜色
+ */
+
+function getCellBgColor(dateCell: DateCell): string {
+	if (dateCell.isSelected) {
+		return bgSelectedColor.value;
+	}
+
+	if (dateCell.isRange) {
+		return bgRangeColor.value;
+	}
+
+	return "transparent";
+}
+
+/**
  * 计算并生成日历矩阵数据
  * 生成6行7列共42个日期,包含上月末尾和下月开头的日期
  */
@@ -314,6 +398,9 @@ function calculateDateMatrix() {
 				nativeDate.getMonth() + 1 == currentMonth.value &&
 				nativeDate.getFullYear() == currentYear.value;
 
+			// 日期配置
+			const dateConfig = props.dateConfig.find((config) => config.date == fullDateStr);
+
 			// 构建日期单元格数据
 			const dateCell = {
 				date: `${dayNumber}`,
@@ -323,7 +410,10 @@ function calculateDateMatrix() {
 				isRange: isDateInRange(fullDateStr),
 				fullDate: fullDateStr,
 				isDisabled: isDateDisabled(fullDateStr),
-				isHide: false
+				isHide: false,
+				topText: dateConfig?.topText ?? "",
+				bottomText: dateConfig?.bottomText ?? "",
+				color: dateConfig?.color ?? ""
 			} as DateCell;
 
 			// 根据配置决定是否隐藏相邻月份的日期
@@ -364,47 +454,54 @@ async function renderCalendarCanvas() {
 	function drawSingleCell(dateCell: DateCell, colIndex: number, rowIndex: number) {
 		// 计算单元格位置
 		const cellX = colIndex * cellWidth.value;
-		const cellY = rowIndex * props.cellHeight;
+		const cellY = rowIndex * cellHeight.value;
 		const centerX = cellX + cellWidth.value / 2;
-		const centerY = cellY + props.cellHeight / 2;
+		const centerY = cellY + cellHeight.value / 2;
 
 		// 绘制背景(选中状态或范围状态)
 		if (dateCell.isSelected || dateCell.isRange) {
-			const padding = props.cellGap; // 使用间距作为内边距
+			const padding = cellGap.value; // 使用间距作为内边距
 			const bgX = cellX + padding;
 			const bgY = cellY + padding;
 			const bgWidth = cellWidth.value - padding * 2;
-			const bgHeight = props.cellHeight - padding * 2;
+			const bgHeight = cellHeight.value - padding * 2;
 
 			// 设置背景颜色
 			if (dateCell.isSelected) {
-				canvasContext!.fillStyle = props.selectedBgColor;
+				canvasContext!.fillStyle = bgSelectedColor.value;
 			}
 			if (dateCell.isRange) {
-				canvasContext!.fillStyle = props.rangeBgColor;
+				canvasContext!.fillStyle = bgRangeColor.value;
 			}
 
 			canvasContext!.fillRect(bgX, bgY, bgWidth, bgHeight); // 绘制背景矩形
 		}
 
-		// 设置文字样式
-		canvasContext!.font = `${props.fontSize}px sans-serif`;
+		// 获取单元格文字颜色
+		const cellTextColor = getCellTextColor(dateCell);
 		canvasContext!.textAlign = "center";
 
-		// 根据状态设置文字颜色
-		if (dateCell.isSelected) {
-			canvasContext!.fillStyle = props.selectedTextColor;
-		} else if (dateCell.isToday) {
-			canvasContext!.fillStyle = props.todayColor;
-		} else if (dateCell.isCurrentMonth) {
-			canvasContext!.fillStyle = props.currentMonthColor;
-		} else {
-			canvasContext!.fillStyle = props.otherMonthColor;
+		// 绘制顶部文本
+		if (dateCell.topText != "") {
+			canvasContext!.font = `${Math.floor(fontSize.value * 0.75)}px sans-serif`;
+			canvasContext!.fillStyle = cellTextColor;
+			const topY = cellY + 16; // 距离顶部
+			canvasContext!.fillText(dateCell.topText, centerX, topY);
 		}
 
-		// 绘制日期数字(垂直居中对齐)
-		const textOffsetY = (props.fontSize / 2) * 0.7;
+		// 绘制主日期数字
+		canvasContext!.font = `${fontSize.value}px sans-serif`;
+		canvasContext!.fillStyle = cellTextColor;
+		const textOffsetY = (fontSize.value / 2) * 0.7;
 		canvasContext!.fillText(dateCell.date.toString(), centerX, centerY + textOffsetY);
+
+		// 绘制底部文本
+		if (dateCell.bottomText != "") {
+			canvasContext!.font = `${Math.floor(fontSize.value * 0.75)}px sans-serif`;
+			canvasContext!.fillStyle = cellTextColor;
+			const bottomY = cellY + cellHeight.value - 8; // 距离底部
+			canvasContext!.fillText(dateCell.bottomText, centerX, bottomY);
+		}
 	}
 
 	// 获取容器尺寸信息
@@ -425,7 +522,10 @@ async function renderCalendarCanvas() {
 		const weekRow = dateMatrix.value[rowIndex];
 		for (let colIndex = 0; colIndex < weekRow.length; colIndex++) {
 			const dateCell = weekRow[colIndex];
-			drawSingleCell(dateCell, colIndex, rowIndex);
+
+			if (!dateCell.isHide) {
+				drawSingleCell(dateCell, colIndex, rowIndex);
+			}
 		}
 	}
 
@@ -490,41 +590,10 @@ function selectDateCell(dateCell: DateCell) {
 }
 
 /**
- * 获取单元格字体颜色
- * @param dateCell 日期单元格数据
- * @returns 字体颜色
- */
-function getCellColor(dateCell: DateCell): string {
-	// 禁用的日期颜色
-	if (dateCell.isDisabled) {
-		return props.disabledColor;
-	}
-
-	// 选中的日期文字颜色
-	if (dateCell.isSelected) {
-		return props.selectedTextColor;
-	}
-
-	// 今天日期颜色
-	if (dateCell.isToday) {
-		return props.todayColor;
-	}
-
-	// 当前月份日期颜色
-	if (dateCell.isCurrentMonth) {
-		return props.currentMonthColor;
-	}
-
-	// 其他月份日期颜色
-	return props.otherMonthColor;
-}
-
-/**
  * 处理年月选择器的变化事件
  * @param yearMonthArray [年份, 月份] 数组
  */
 function onYearMonthChange(yearMonthArray: number[]) {
-	console.log("年月选择器变化:", yearMonthArray);
 	currentYear.value = yearMonthArray[0];
 	currentMonth.value = yearMonthArray[1];
 
@@ -550,7 +619,7 @@ async function onTap(e: UniPointerEvent) {
 
 	// 根据坐标计算对应的行列索引
 	const columnIndex = Math.floor(relativeX / cellWidth.value);
-	const rowIndex = Math.floor(relativeY / props.cellHeight);
+	const rowIndex = Math.floor(relativeY / cellHeight.value);
 
 	// 边界检查:确保索引在有效范围内
 	if (
@@ -613,8 +682,8 @@ function parseDate() {
 	const initialDate = first(selectedDates.value);
 	const [initialYear, initialMonth] = dayUts(initialDate).toArray();
 
-	currentYear.value = initialYear;
-	currentMonth.value = initialMonth;
+	currentYear.value = props.year ?? initialYear;
+	currentMonth.value = props.month ?? initialMonth;
 
 	// 计算初始日历数据
 	calculateDateMatrix();
@@ -648,6 +717,18 @@ onMounted(() => {
 			immediate: true
 		}
 	);
+
+	// 重新渲染
+	watch(
+		computed(() => [props.dateConfig, props.showOtherMonth]),
+		() => {
+			calculateDateMatrix();
+			renderCalendarCanvas();
+		},
+		{
+			deep: true
+		}
+	);
 });
 </script>
 
@@ -694,7 +775,6 @@ onMounted(() => {
 	&__view {
 		@apply w-full;
 
-		/* Web端DOM渲染样式 */
 		// #ifndef APP
 		/* 日期行样式 */
 		&-row {
@@ -706,16 +786,6 @@ onMounted(() => {
 			@apply flex-1 flex flex-col items-center justify-center relative;
 			height: 80rpx;
 
-			/* 选中状态样式 */
-			&.is-selected {
-				background-color: v-bind("props.selectedBgColor");
-			}
-
-			/* 范围选择背景样式 */
-			&.is-range {
-				background-color: v-bind("props.rangeBgColor");
-			}
-
 			/* 隐藏状态(相邻月份日期) */
 			&.is-hide {
 				opacity: 0;

+ 1 - 1
uni_modules/cool-ui/components/cl-calendar/picker.uvue

@@ -140,7 +140,7 @@ const list = computed(() => {
 // - 年份模式下显示“起始年 - 结束年”
 const title = computed(() => {
 	return mode.value == "month"
-		? `${year.value}`
+		? `${year.value}`
 		: `${first(list.value)?.label} - ${last(list.value)?.label}`;
 });
 

+ 8 - 0
uni_modules/cool-ui/types/index.ts

@@ -200,3 +200,11 @@ export type ClTreeNodeInfo = {
 };
 
 export type ClCalendarMode = "single" | "multiple" | "range";
+
+export type ClCalendarDateConfig = {
+	date: string;
+	topText?: string;
+	bottomText?: string;
+	disabled?: boolean;
+	color?: string;
+};