cl-calendar 支持添加上下文案
This commit is contained in:
@@ -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 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 dateArr = ref<string[]>([
|
||||
dayUts().format("YYYY-MM-DD"),
|
||||
dayUts().add(1, "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>
|
||||
|
||||
@@ -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: () => []
|
||||
},
|
||||
// 选择器标题
|
||||
@@ -132,6 +133,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
|
||||
|
||||
@@ -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: () => []
|
||||
},
|
||||
// 日期选择模式:单选/多选/范围选择
|
||||
mode: {
|
||||
type: String as PropType<ClCalendarMode>,
|
||||
default: "single"
|
||||
},
|
||||
// 日期配置
|
||||
dateConfig: {
|
||||
type: Array as PropType<ClCalendarDateConfig[]>,
|
||||
default: () => []
|
||||
},
|
||||
// 设置年份
|
||||
year: {
|
||||
type: Number
|
||||
},
|
||||
// 设置月份
|
||||
month: {
|
||||
type: Number
|
||||
},
|
||||
// 是否显示其他月份的日期
|
||||
showOtherMonth: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 禁用的日期列表
|
||||
disabledDate: {
|
||||
type: Array as PropType<string[]>,
|
||||
default: () => []
|
||||
// 是否显示头部导航栏
|
||||
showHeader: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
// 单元格高度
|
||||
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
|
||||
},
|
||||
// 其他月日期颜色
|
||||
otherMonthColor: {
|
||||
type: String,
|
||||
default: () => ctx.color["surface-300"] as string
|
||||
},
|
||||
// 今天日期颜色
|
||||
todayColor: {
|
||||
type: String,
|
||||
default: "#ff6b6b"
|
||||
},
|
||||
// 选中日期文字颜色
|
||||
selectedTextColor: {
|
||||
type: String,
|
||||
default: "#ffffff"
|
||||
},
|
||||
// 选中日期背景色
|
||||
selectedBgColor: {
|
||||
type: String,
|
||||
default: () => ctx.color["primary-500"] as string
|
||||
},
|
||||
// 范围选择背景色
|
||||
rangeBgColor: {
|
||||
type: String,
|
||||
default: () => ctx.color["primary-100"] as string
|
||||
},
|
||||
// 禁用的日期颜色
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -284,6 +311,63 @@ function isDateInRange(dateStr: string): boolean {
|
||||
return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单元格字体颜色
|
||||
* @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,9 +522,12 @@ async function renderCalendarCanvas() {
|
||||
const weekRow = dateMatrix.value[rowIndex];
|
||||
for (let colIndex = 0; colIndex < weekRow.length; colIndex++) {
|
||||
const dateCell = weekRow[colIndex];
|
||||
|
||||
if (!dateCell.isHide) {
|
||||
drawSingleCell(dateCell, colIndex, rowIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
canvasContext!.update(); // 更新画布显示
|
||||
// #endif
|
||||
@@ -489,42 +589,11 @@ function selectDateCell(dateCell: DateCell) {
|
||||
renderCalendarCanvas();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取单元格字体颜色
|
||||
* @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;
|
||||
|
||||
@@ -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}`;
|
||||
});
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user