9afce6f6创建于 2025年5月7日历史提交
/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import Constants from '../constant/Constants';
import { CalendarController, CalendarViewType, DayInfo } from '../components/CustomCalendar';
import { CalendarStyle, Day } from '../model/CalendarModel';
import { StyleUtils } from '../utils/StyleUtils';
import { TimeUtils } from '../utils/TimeUtils'; // 时间计算工具类

/**
 * 月视图子组件
 */
@Component
export struct MonthViewItem {
  // 月视图日期数据
  @State monthDays: Day[][] = [];
  // 年月信息
  @Link @Watch('updateMonthData') yearMonth: string;
  // 当前选中的日期
  @State currentSelectDay: DayInfo =
    new DayInfo(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate(), 0); // 当前选中的日期
  // 当前选中的日期,格式'year-month-date-week'
  @Link @Watch('OnChangeSelectDate') currentSelectDate: string;
  private year: number = Constants.TODAY_YEAR;
  private month: number = Constants.TODAY_MONTH;
  // 自定义日历样式
  CalendarStyle: CalendarStyle = {};
  // 日期点击回调
  onDateClick: (year: number, month: number, date: number) => void = () => {
  };
  // 日历控制器。这里用于控制添加日程后月视图数据刷新
  controller?: CalendarController;

  /**
   * 日期选择监听
   */
  OnChangeSelectDate() {
    const PARTS: string[] = this.currentSelectDate.split('-');
    this.currentSelectDay.year = Number(PARTS[0]);
    this.currentSelectDay.month = Number(PARTS[1]);
    this.currentSelectDay.date = Number(PARTS[2]);
  }

  /**
   * 获取指定月份数据
   */
  getMonthViewData(year: number, month: number) {
    this.monthDays = [...TimeUtils.byMonthDayForYear(year, month)];
  }

  /**
   * 更新月数据
   */
  updateMonthData() {
    const PARTS: string[] = this.yearMonth.split('-');
    this.year = Number(PARTS[0]);
    this.month = Number(PARTS[1]);
    this.getMonthViewData(this.year, this.month);
  }

  /**
   * 刷新日程点数据
   */
  private schedulePointRefresh = () => {
    this.updateMonthData();
  }

  aboutToAppear() {
    if (this.controller) {
      this.controller.schedulePointRefresh = this.schedulePointRefresh;
    }
    const PARTS: string[] = this.yearMonth.split('-');
    this.year = Number(PARTS[0]);
    this.month = Number(PARTS[1]);
    this.getMonthViewData(this.year, this.month);
  }

  /**
   * 月视图点击上个月或下个月日期切换月份
   * @param is true为下月,false为上一月
   */
  nextMouth(is: boolean) {
    if (is) {
      this.year =
        (this.month + 1 > 12) ? this.year + 1 : this.year;
      this.month = (this.month + 1 > 12) ? 1 : this.month + 1;
    } else {
      this.year =
        (this.month - 1 < 1) ? this.year - 1 : this.year;
      this.month = (this.month - 1 < 1) ? 12 : this.month - 1;
    }
    this.yearMonth = this.year + '-' + this.month;
  }

  /**
   * 月视图一天的子组件
   * @param day 日期
   * @param week 月视图周信息。0上个月,1当前月,2下个月
   */
  @Builder
  monthDayBuilder(day: Day, week: number) {
    Column() {
      Text(day.dayNum + '')
        .fontColor(StyleUtils.getColor(day, this.month, this.currentSelectDay, CalendarViewType.MONTH,
          this.CalendarStyle))
        .fontSize(Constants.DAY_FONT_SIZE *
          (this.CalendarStyle.textScaling ? this.CalendarStyle.textScaling : Constants.FONT_MULTIPLIER))
        .fontWeight(FontWeight.Medium)
      Text(day.lunarDay)
        .fontColor(StyleUtils.getLunarDayColor(day, this.month, this.currentSelectDay, CalendarViewType.MONTH,
          this.CalendarStyle))
        .fontSize(Constants.LUNAR_DAY_FONT_SIZE *
          (this.CalendarStyle.textScaling ? this.CalendarStyle.textScaling : Constants.FONT_MULTIPLIER))
    }
    .width($r('app.integer.calendar_switch_size_forty'))
    .height($r('app.integer.calendar_switch_size_forty'))
    .borderRadius($r('app.integer.calendar_switch_size_forty'))
    .borderColor($r('app.color.calendar_switch_border_color'))
    .borderWidth(StyleUtils.getBorderWidth(day, this.month, this.currentSelectDay, CalendarViewType.MONTH))
    .backgroundColor(StyleUtils.getBackgroundColor(day, this.currentSelectDay, this.CalendarStyle))
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Center)
    .onClick(() => {
      this.onDateClick(day.dayInfo.year, day.dayInfo.month, day.dayInfo.date);
      // 月视图需要拼接day.dayInfo.week
      this.currentSelectDate =
        day.dayInfo.year + '-' + day.dayInfo.month + '-' + day.dayInfo.date + '-' + day.dayInfo.week;
      this.currentSelectDay.year = day.dayInfo.year;
      this.currentSelectDay.month = day.dayInfo.month;
      this.currentSelectDay.date = day.dayInfo.date;
      // 必须记录点击日期的week值。CalendarSwitch的onSelectDayChange监听中需要根据week值点击的是上个月还是下个月的日期,从而进行相应的月份切换
      this.currentSelectDay.week = day.dayInfo.week;
      // 选中了上个月的日期,切换到上个月。1表示月视图第一周
      if (week == 1 && day.dayNum > Constants.DAYS_IN_WEEK) {
        this.nextMouth(false);
      }
      // 选中了下个月的日期,切换到下个月。2表示月视图第二周
      if (week > 2 && day.dayNum < Constants.DAYS_IN_WEEK) {
        this.nextMouth(true);
      }
    })
  }

  build() {
    Column() {
      ForEach(this.monthDays, (items: Day[], index: number) => {
        Row() {
          ForEach(items, (item: Day) => {
            Column() {
              this.monthDayBuilder(item, index + 1)
              if (item.isShowSchedulePoint) {
                // 日程点
                Circle({ width: Constants.SCHEDULE_POINT_DIAMETER, height: Constants.SCHEDULE_POINT_DIAMETER })
                  .fill($r('app.color.calendar_switch_schedule_point_color'))
                  .margin({ top: $r('app.integer.calendar_switch_size_one') })
              }
            }
            .height($r('app.integer.calendar_switch_size_forty_six'))
          }, (item: Day, index: number) => {
            return item.dayNum + '' + index + item.isShowSchedulePoint;
          })
        }
        .width($r('app.string.calendar_switch_full_size'))
        .justifyContent(FlexAlign.SpaceBetween)
      }, (item: Day[], index: number) => {
        return item.reduce((item1, item2) => {
          return item1 + item2.dayInfo.year + item2.dayInfo.month + item2.dayInfo.date + item2.isShowSchedulePoint
        }, '') + index
      })
    }.width($r('app.string.calendar_switch_full_size'))
  }
}