cl-calendar.uvue 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. <template>
  2. <!-- 日历组件主容器 -->
  3. <view class="cl-calendar" :class="[pt.className]">
  4. <!-- 年月选择器弹窗 -->
  5. <calendar-picker
  6. :year="currentYear"
  7. :month="currentMonth"
  8. :ref="refs.set('picker')"
  9. @change="onYearMonthChange"
  10. ></calendar-picker>
  11. <!-- 头部导航栏 -->
  12. <view class="cl-calendar__header" v-if="showHeader">
  13. <!-- 上一月按钮 -->
  14. <view
  15. class="cl-calendar__header-prev"
  16. :class="{ 'is-dark': isDark }"
  17. @tap.stop="gotoPrevMonth"
  18. >
  19. <cl-icon name="arrow-left-s-line"></cl-icon>
  20. </view>
  21. <!-- 当前年月显示区域 -->
  22. <view class="cl-calendar__header-date" @tap="refs.open('picker')">
  23. <slot name="current-date">
  24. <cl-text :pt="{ className: 'text-lg' }">{{
  25. $t(`{year}年{month}月`, { year: currentYear, month: currentMonth })
  26. }}</cl-text>
  27. </slot>
  28. </view>
  29. <!-- 下一月按钮 -->
  30. <view
  31. class="cl-calendar__header-next"
  32. :class="{ 'is-dark': isDark }"
  33. @tap.stop="gotoNextMonth"
  34. >
  35. <cl-icon name="arrow-right-s-line"></cl-icon>
  36. </view>
  37. </view>
  38. <!-- 星期标题行 -->
  39. <view class="cl-calendar__weeks" :style="{ gap: `${cellGap}px` }">
  40. <view class="cl-calendar__weeks-item" v-for="weekName in weekLabels" :key="weekName">
  41. <cl-text>{{ weekName }}</cl-text>
  42. </view>
  43. </view>
  44. <!-- 日期网格容器 -->
  45. <view
  46. class="cl-calendar__view"
  47. ref="calendarViewRef"
  48. :style="{ height: `${viewHeight}px`, gap: `${cellGap}px` }"
  49. @tap="onTap"
  50. >
  51. <!-- Web端使用DOM渲染 -->
  52. <!-- #ifndef APP -->
  53. <view
  54. class="cl-calendar__view-row"
  55. :style="{ gap: `${cellGap}px` }"
  56. v-for="(weekRow, rowIndex) in dateMatrix"
  57. :key="rowIndex"
  58. >
  59. <view
  60. class="cl-calendar__view-cell"
  61. v-for="(dateCell, cellIndex) in weekRow"
  62. :key="cellIndex"
  63. :class="{
  64. 'is-selected': dateCell.isSelected,
  65. 'is-range': dateCell.isRange,
  66. 'is-hide': dateCell.isHide,
  67. 'is-disabled': dateCell.isDisabled,
  68. 'is-today': dateCell.isToday,
  69. 'is-other-month': !dateCell.isCurrentMonth
  70. }"
  71. :style="{ height: cellHeight + 'px' }"
  72. @click.stop="selectDateCell(dateCell)"
  73. >
  74. <cl-text :color="getCellColor(dateCell)" :size="`${fontSize}px`">{{
  75. dateCell.date
  76. }}</cl-text>
  77. </view>
  78. </view>
  79. <!-- #endif -->
  80. </view>
  81. </view>
  82. </template>
  83. <script lang="ts" setup>
  84. import { computed, nextTick, onMounted, ref, watch, type PropType } from "vue";
  85. import { ctx, dayUts, first, isDark, parsePt, useRefs } from "@/cool";
  86. import CalendarPicker from "./picker.uvue";
  87. import { $t, t } from "@/locale";
  88. import type { ClCalendarMode } from "../../types";
  89. defineOptions({
  90. name: "cl-calendar"
  91. });
  92. // 日期单元格数据结构
  93. type DateCell = {
  94. date: string; // 显示的日期数字
  95. isCurrentMonth: boolean; // 是否属于当前显示月份
  96. isToday: boolean; // 是否为今天
  97. isSelected: boolean; // 是否被选中
  98. isRange: boolean; // 是否在选择范围内
  99. fullDate: string; // 完整日期格式 YYYY-MM-DD
  100. isDisabled: boolean; // 是否被禁用
  101. isHide: boolean; // 是否隐藏显示
  102. };
  103. // 组件属性定义
  104. const props = defineProps({
  105. // 透传样式配置
  106. pt: {
  107. type: Object,
  108. default: () => ({})
  109. },
  110. // 是否显示头部导航栏
  111. showHeader: {
  112. type: Boolean,
  113. default: true
  114. },
  115. // 日期选择模式:单选/多选/范围选择
  116. mode: {
  117. type: String as PropType<ClCalendarMode>,
  118. default: "single"
  119. },
  120. // 当前选中的日期值(单选模式)
  121. modelValue: {
  122. type: String as PropType<string | null>,
  123. default: null
  124. },
  125. // 选中的日期数组(多选/范围模式)
  126. date: {
  127. type: Array as PropType<string[]>,
  128. default: () => []
  129. },
  130. // 是否显示其他月份的日期
  131. showOtherMonth: {
  132. type: Boolean,
  133. default: true
  134. },
  135. // 禁用的日期列表
  136. disabledDate: {
  137. type: Array as PropType<string[]>,
  138. default: () => []
  139. },
  140. // 单元格高度
  141. cellHeight: {
  142. type: Number,
  143. default: 60
  144. },
  145. // 单元格间距
  146. cellGap: {
  147. type: Number,
  148. default: 0
  149. },
  150. // 字体大小
  151. fontSize: {
  152. type: Number,
  153. default: 14
  154. },
  155. // 当前月日期颜色
  156. currentMonthColor: {
  157. type: String,
  158. default: () => ctx.color["surface-700"] as string
  159. },
  160. // 其他月日期颜色
  161. otherMonthColor: {
  162. type: String,
  163. default: () => ctx.color["surface-300"] as string
  164. },
  165. // 今天日期颜色
  166. todayColor: {
  167. type: String,
  168. default: "#ff6b6b"
  169. },
  170. // 选中日期文字颜色
  171. selectedTextColor: {
  172. type: String,
  173. default: "#ffffff"
  174. },
  175. // 选中日期背景色
  176. selectedBgColor: {
  177. type: String,
  178. default: () => ctx.color["primary-500"] as string
  179. },
  180. // 范围选择背景色
  181. rangeBgColor: {
  182. type: String,
  183. default: () => ctx.color["primary-100"] as string
  184. },
  185. // 禁用的日期颜色
  186. disabledColor: {
  187. type: String,
  188. default: () => ctx.color["surface-300"] as string
  189. }
  190. });
  191. // 事件发射器定义
  192. const emit = defineEmits(["update:modelValue", "update:date", "change"]);
  193. // 透传样式属性类型
  194. type PassThrough = {
  195. className?: string;
  196. };
  197. // 解析透传样式配置
  198. const pt = computed(() => parsePt<PassThrough>(props.pt));
  199. // 组件引用管理器
  200. const refs = useRefs();
  201. // 日历视图DOM元素引用
  202. const calendarViewRef = ref<UniElement | null>(null);
  203. // 当前显示的年份
  204. const currentYear = ref(0);
  205. // 当前显示的月份
  206. const currentMonth = ref(0);
  207. // 视图高度
  208. const viewHeight = computed(() => {
  209. return props.cellHeight * 6 + "px";
  210. });
  211. // 单元格宽度
  212. const cellWidth = ref(0);
  213. // 星期标签数组
  214. const weekLabels = computed(() => {
  215. return [t("日"), t("一"), t("二"), t("三"), t("四"), t("五"), t("六")];
  216. });
  217. // 日历日期矩阵数据(6行7列)
  218. const dateMatrix = ref<DateCell[][]>([]);
  219. // 当前选中的日期列表
  220. const selectedDates = ref<string[]>([]);
  221. /**
  222. * 获取日历视图元素的位置信息
  223. */
  224. async function getViewRect(): Promise<DOMRect | null> {
  225. return calendarViewRef.value!.getBoundingClientRectAsync();
  226. }
  227. /**
  228. * 判断指定日期是否被选中
  229. * @param dateStr 日期字符串 YYYY-MM-DD
  230. */
  231. function isDateSelected(dateStr: string): boolean {
  232. if (props.mode == "single") {
  233. // 单选模式:检查是否为唯一选中日期
  234. return selectedDates.value[0] == dateStr;
  235. } else {
  236. // 多选/范围模式:检查是否在选中列表中
  237. return selectedDates.value.includes(dateStr);
  238. }
  239. }
  240. /**
  241. * 判断指定日期是否被禁用
  242. * @param dateStr 日期字符串 YYYY-MM-DD
  243. */
  244. function isDateDisabled(dateStr: string): boolean {
  245. return props.disabledDate.includes(dateStr);
  246. }
  247. /**
  248. * 判断指定日期是否在选择范围内(不包括端点)
  249. * @param dateStr 日期字符串 YYYY-MM-DD
  250. */
  251. function isDateInRange(dateStr: string): boolean {
  252. // 仅范围选择模式且已选择两个端点时才有范围
  253. if (props.mode != "range" || selectedDates.value.length != 2) {
  254. return false;
  255. }
  256. const [startDate, endDate] = selectedDates.value;
  257. const currentDate = dayUts(dateStr);
  258. return currentDate.isAfter(startDate) && currentDate.isBefore(endDate);
  259. }
  260. /**
  261. * 计算并生成日历矩阵数据
  262. * 生成6行7列共42个日期,包含上月末尾和下月开头的日期
  263. */
  264. function calculateDateMatrix() {
  265. const weekRows: DateCell[][] = [];
  266. const todayStr = dayUts().format("YYYY-MM-DD"); // 今天的日期字符串
  267. // 获取当前月第一天
  268. const monthFirstDay = dayUts(`${currentYear.value}-${currentMonth.value}-01`);
  269. const firstDayWeekIndex = monthFirstDay.getDay(); // 第一天是星期几 (0=周日, 6=周六)
  270. // 计算日历显示的起始日期(可能是上个月的日期)
  271. const calendarStartDate = monthFirstDay.subtract(firstDayWeekIndex, "day");
  272. // 生成6周的日期数据(6行 × 7列 = 42天)
  273. let iterateDate = calendarStartDate;
  274. for (let weekIndex = 0; weekIndex < 6; weekIndex++) {
  275. const weekDates: DateCell[] = [];
  276. for (let dayIndex = 0; dayIndex < 7; dayIndex++) {
  277. const fullDateStr = iterateDate.format("YYYY-MM-DD");
  278. const nativeDate = iterateDate.toDate();
  279. const dayNumber = nativeDate.getDate();
  280. // 判断是否属于当前显示月份
  281. const belongsToCurrentMonth =
  282. nativeDate.getMonth() + 1 == currentMonth.value &&
  283. nativeDate.getFullYear() == currentYear.value;
  284. // 构建日期单元格数据
  285. const dateCell = {
  286. date: `${dayNumber}`,
  287. isCurrentMonth: belongsToCurrentMonth,
  288. isToday: fullDateStr == todayStr,
  289. isSelected: isDateSelected(fullDateStr),
  290. isRange: isDateInRange(fullDateStr),
  291. fullDate: fullDateStr,
  292. isDisabled: isDateDisabled(fullDateStr),
  293. isHide: false
  294. } as DateCell;
  295. // 根据配置决定是否隐藏相邻月份的日期
  296. if (!props.showOtherMonth && !belongsToCurrentMonth) {
  297. dateCell.isHide = true;
  298. }
  299. weekDates.push(dateCell);
  300. iterateDate = iterateDate.add(1, "day"); // 移动到下一天
  301. }
  302. weekRows.push(weekDates);
  303. }
  304. dateMatrix.value = weekRows;
  305. }
  306. /**
  307. * 使用Canvas绘制日历(仅APP端)
  308. * Web端使用DOM渲染,APP端使用Canvas提升性能
  309. */
  310. async function renderCalendarCanvas() {
  311. // #ifdef APP
  312. await nextTick(); // 等待DOM更新完成
  313. const canvasContext = calendarViewRef.value!.getDrawableContext();
  314. if (canvasContext == null) return;
  315. canvasContext!.reset(); // 清空画布
  316. /**
  317. * 绘制单个日期单元格
  318. * @param dateCell 日期单元格数据
  319. * @param colIndex 列索引 (0-6)
  320. * @param rowIndex 行索引 (0-5)
  321. */
  322. function drawSingleCell(dateCell: DateCell, colIndex: number, rowIndex: number) {
  323. // 计算单元格位置
  324. const cellX = colIndex * cellWidth.value;
  325. const cellY = rowIndex * props.cellHeight;
  326. const centerX = cellX + cellWidth.value / 2;
  327. const centerY = cellY + props.cellHeight / 2;
  328. // 绘制背景(选中状态或范围状态)
  329. if (dateCell.isSelected || dateCell.isRange) {
  330. const padding = props.cellGap; // 使用间距作为内边距
  331. const bgX = cellX + padding;
  332. const bgY = cellY + padding;
  333. const bgWidth = cellWidth.value - padding * 2;
  334. const bgHeight = props.cellHeight - padding * 2;
  335. // 设置背景颜色
  336. if (dateCell.isSelected) {
  337. canvasContext!.fillStyle = props.selectedBgColor;
  338. }
  339. if (dateCell.isRange) {
  340. canvasContext!.fillStyle = props.rangeBgColor;
  341. }
  342. canvasContext!.fillRect(bgX, bgY, bgWidth, bgHeight); // 绘制背景矩形
  343. }
  344. // 设置文字样式
  345. canvasContext!.font = `${props.fontSize}px sans-serif`;
  346. canvasContext!.textAlign = "center";
  347. // 根据状态设置文字颜色
  348. if (dateCell.isSelected) {
  349. canvasContext!.fillStyle = props.selectedTextColor;
  350. } else if (dateCell.isToday) {
  351. canvasContext!.fillStyle = props.todayColor;
  352. } else if (dateCell.isCurrentMonth) {
  353. canvasContext!.fillStyle = props.currentMonthColor;
  354. } else {
  355. canvasContext!.fillStyle = props.otherMonthColor;
  356. }
  357. // 绘制日期数字(垂直居中对齐)
  358. const textOffsetY = (props.fontSize / 2) * 0.7;
  359. canvasContext!.fillText(dateCell.date.toString(), centerX, centerY + textOffsetY);
  360. }
  361. // 获取容器尺寸信息
  362. const viewRect = await getViewRect();
  363. if (viewRect == null) {
  364. return;
  365. }
  366. // 计算单元格宽度(总宽度除以7列)
  367. const cellSize = viewRect.width / 7;
  368. // 更新渲染配置
  369. cellWidth.value = cellSize;
  370. // 遍历日期矩阵进行绘制
  371. for (let rowIndex = 0; rowIndex < dateMatrix.value.length; rowIndex++) {
  372. const weekRow = dateMatrix.value[rowIndex];
  373. for (let colIndex = 0; colIndex < weekRow.length; colIndex++) {
  374. const dateCell = weekRow[colIndex];
  375. drawSingleCell(dateCell, colIndex, rowIndex);
  376. }
  377. }
  378. canvasContext!.update(); // 更新画布显示
  379. // #endif
  380. }
  381. /**
  382. * 处理日期单元格选择逻辑
  383. * @param dateCell 被点击的日期单元格
  384. */
  385. function selectDateCell(dateCell: DateCell) {
  386. // 隐藏或禁用的日期不可选择
  387. if (dateCell.isHide || dateCell.isDisabled) {
  388. return;
  389. }
  390. if (props.mode == "single") {
  391. // 单选模式:直接替换选中日期
  392. selectedDates.value = [dateCell.fullDate];
  393. emit("update:modelValue", dateCell.fullDate);
  394. } else if (props.mode == "multiple") {
  395. // 多选模式:切换选中状态
  396. const existingIndex = selectedDates.value.indexOf(dateCell.fullDate);
  397. if (existingIndex >= 0) {
  398. // 已选中则移除
  399. selectedDates.value.splice(existingIndex, 1);
  400. } else {
  401. // 未选中则添加
  402. selectedDates.value.push(dateCell.fullDate);
  403. }
  404. } else {
  405. // 范围选择模式
  406. if (selectedDates.value.length == 0) {
  407. // 第一次点击:设置起始日期
  408. selectedDates.value = [dateCell.fullDate];
  409. } else if (selectedDates.value.length == 1) {
  410. // 第二次点击:设置结束日期
  411. const startDate = dayUts(selectedDates.value[0]);
  412. const endDate = dayUts(dateCell.fullDate);
  413. if (endDate.isBefore(startDate)) {
  414. // 结束日期早于开始日期时自动交换
  415. selectedDates.value = [dateCell.fullDate, selectedDates.value[0]];
  416. } else {
  417. selectedDates.value = [selectedDates.value[0], dateCell.fullDate];
  418. }
  419. } else {
  420. // 已有范围时重新开始选择
  421. selectedDates.value = [dateCell.fullDate];
  422. }
  423. }
  424. // 发射更新事件
  425. emit("update:date", [...selectedDates.value]);
  426. emit("change", selectedDates.value);
  427. // 重新计算日历数据并重绘
  428. calculateDateMatrix();
  429. renderCalendarCanvas();
  430. }
  431. /**
  432. * 获取单元格字体颜色
  433. * @param dateCell 日期单元格数据
  434. * @returns 字体颜色
  435. */
  436. function getCellColor(dateCell: DateCell): string {
  437. // 禁用的日期颜色
  438. if (dateCell.isDisabled) {
  439. return props.disabledColor;
  440. }
  441. // 选中的日期文字颜色
  442. if (dateCell.isSelected) {
  443. return props.selectedTextColor;
  444. }
  445. // 今天日期颜色
  446. if (dateCell.isToday) {
  447. return props.todayColor;
  448. }
  449. // 当前月份日期颜色
  450. if (dateCell.isCurrentMonth) {
  451. return props.currentMonthColor;
  452. }
  453. // 其他月份日期颜色
  454. return props.otherMonthColor;
  455. }
  456. /**
  457. * 处理年月选择器的变化事件
  458. * @param yearMonthArray [年份, 月份] 数组
  459. */
  460. function onYearMonthChange(yearMonthArray: number[]) {
  461. console.log("年月选择器变化:", yearMonthArray);
  462. currentYear.value = yearMonthArray[0];
  463. currentMonth.value = yearMonthArray[1];
  464. // 重新计算日历数据并重绘
  465. calculateDateMatrix();
  466. renderCalendarCanvas();
  467. }
  468. /**
  469. * 处理点击事件(APP端Canvas点击检测)
  470. */
  471. async function onTap(e: UniPointerEvent) {
  472. // 获取容器位置信息
  473. const viewRect = await getViewRect();
  474. if (viewRect == null) {
  475. return;
  476. }
  477. // 计算触摸点相对于容器的坐标
  478. const relativeX = e.clientX - viewRect.left;
  479. const relativeY = e.clientY - viewRect.top;
  480. // 根据坐标计算对应的行列索引
  481. const columnIndex = Math.floor(relativeX / cellWidth.value);
  482. const rowIndex = Math.floor(relativeY / props.cellHeight);
  483. // 边界检查:确保索引在有效范围内
  484. if (
  485. rowIndex < 0 ||
  486. rowIndex >= dateMatrix.value.length ||
  487. columnIndex < 0 ||
  488. columnIndex >= 7
  489. ) {
  490. return;
  491. }
  492. const targetDateCell = dateMatrix.value[rowIndex][columnIndex];
  493. selectDateCell(targetDateCell);
  494. }
  495. /**
  496. * 切换到上一个月
  497. */
  498. function gotoPrevMonth() {
  499. const [newYear, newMonth] = dayUts(`${currentYear.value}-${currentMonth.value}-01`)
  500. .subtract(1, "month")
  501. .toArray();
  502. currentYear.value = newYear;
  503. currentMonth.value = newMonth;
  504. // 重新计算并渲染日历
  505. calculateDateMatrix();
  506. renderCalendarCanvas();
  507. }
  508. /**
  509. * 切换到下一个月
  510. */
  511. function gotoNextMonth() {
  512. const [newYear, newMonth] = dayUts(`${currentYear.value}-${currentMonth.value}-01`)
  513. .add(1, "month")
  514. .toArray();
  515. currentYear.value = newYear;
  516. currentMonth.value = newMonth;
  517. // 重新计算并渲染日历
  518. calculateDateMatrix();
  519. renderCalendarCanvas();
  520. }
  521. /**
  522. * 解析选中日期
  523. */
  524. function parseDate() {
  525. // 根据选择模式初始化选中日期
  526. if (props.mode == "single") {
  527. selectedDates.value = props.modelValue != null ? [props.modelValue] : [];
  528. } else {
  529. selectedDates.value = [...props.date];
  530. }
  531. // 获取初始显示日期(优先使用选中日期,否则使用当前日期)
  532. const initialDate = first(selectedDates.value);
  533. const [initialYear, initialMonth] = dayUts(initialDate).toArray();
  534. currentYear.value = initialYear;
  535. currentMonth.value = initialMonth;
  536. // 计算初始日历数据
  537. calculateDateMatrix();
  538. // 渲染日历视图
  539. renderCalendarCanvas();
  540. }
  541. // 组件挂载时的初始化逻辑
  542. onMounted(() => {
  543. // 监听单选模式的值变化
  544. watch(
  545. computed(() => props.modelValue ?? ""),
  546. (newValue: string) => {
  547. selectedDates.value = [newValue];
  548. parseDate();
  549. },
  550. {
  551. immediate: true
  552. }
  553. );
  554. // 监听多选/范围模式的值变化
  555. watch(
  556. computed(() => props.date),
  557. (newDateArray: string[]) => {
  558. selectedDates.value = [...newDateArray];
  559. parseDate();
  560. },
  561. {
  562. immediate: true
  563. }
  564. );
  565. });
  566. </script>
  567. <style lang="scss" scoped>
  568. /* 日历组件主容器 */
  569. .cl-calendar {
  570. @apply relative;
  571. /* 头部导航栏样式 */
  572. &__header {
  573. @apply flex flex-row items-center justify-between p-3 w-full;
  574. /* 上一月/下一月按钮样式 */
  575. &-prev,
  576. &-next {
  577. @apply flex flex-row items-center justify-center rounded-full bg-surface-100;
  578. width: 60rpx;
  579. height: 60rpx;
  580. /* 暗色模式适配 */
  581. &.is-dark {
  582. @apply bg-surface-700;
  583. }
  584. }
  585. /* 当前年月显示区域 */
  586. &-date {
  587. @apply flex flex-row items-center justify-center;
  588. }
  589. }
  590. /* 星期标题行样式 */
  591. &__weeks {
  592. @apply flex flex-row;
  593. /* 单个星期标题样式 */
  594. &-item {
  595. @apply flex flex-row items-center justify-center flex-1;
  596. height: 80rpx;
  597. }
  598. }
  599. /* 日期网格容器样式 */
  600. &__view {
  601. @apply w-full;
  602. /* Web端DOM渲染样式 */
  603. // #ifndef APP
  604. /* 日期行样式 */
  605. &-row {
  606. @apply flex flex-row;
  607. }
  608. /* 日期单元格样式 */
  609. &-cell {
  610. @apply flex-1 flex flex-col items-center justify-center relative;
  611. height: 80rpx;
  612. /* 选中状态样式 */
  613. &.is-selected {
  614. background-color: v-bind("props.selectedBgColor");
  615. }
  616. /* 范围选择背景样式 */
  617. &.is-range {
  618. background-color: v-bind("props.rangeBgColor");
  619. }
  620. /* 隐藏状态(相邻月份日期) */
  621. &.is-hide {
  622. opacity: 0;
  623. }
  624. /* 禁用状态 */
  625. &.is-disabled {
  626. @apply opacity-50;
  627. }
  628. }
  629. // #endif
  630. }
  631. }
  632. </style>