1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import Constants from '../constant/Constants'; 17import { CalendarController, CalendarViewType, DayInfo } from '../components/CustomCalendar'; 18import { CalendarStyle, Day } from '../model/CalendarModel'; 19import { StyleUtils } from '../utils/StyleUtils'; 20import { TimeUtils } from '../utils/TimeUtils'; // 时间计算工具类 21 22/** 23 * 月视图子组件 24 */ 25@Component 26export struct MonthViewItem { 27 // 月视图日期数据 28 @State monthDays: Day[][] = []; 29 // 年月信息 30 @Link @Watch('updateMonthData') yearMonth: string; 31 // 当前选中的日期 32 @State currentSelectDay: DayInfo = 33 new DayInfo(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate(), 0); // 当前选中的日期 34 // 当前选中的日期,格式'year-month-date-week' 35 @Link @Watch('OnChangeSelectDate') currentSelectDate: string; 36 private year: number = Constants.TODAY_YEAR; 37 private month: number = Constants.TODAY_MONTH; 38 // 自定义日历样式 39 calendarStyle: CalendarStyle = {}; 40 // 日期点击回调 41 onDateClick: (year: number, month: number, date: number) => void = () => { 42 }; 43 // 日历控制器。这里用于控制添加日程后月视图数据刷新 44 controller?: CalendarController; 45 46 /** 47 * 日期选择监听 48 */ 49 OnChangeSelectDate() { 50 const PARTS: string[] = this.currentSelectDate.split('-'); 51 this.currentSelectDay.year = Number(PARTS[0]); 52 this.currentSelectDay.month = Number(PARTS[1]); 53 this.currentSelectDay.date = Number(PARTS[2]); 54 } 55 56 /** 57 * 获取指定月份数据 58 */ 59 getMonthViewData(year: number, month: number) { 60 this.monthDays = [...TimeUtils.byMonthDayForYear(year, month)]; 61 } 62 63 /** 64 * 更新月数据 65 */ 66 updateMonthData() { 67 const PARTS: string[] = this.yearMonth.split('-'); 68 this.year = Number(PARTS[0]); 69 this.month = Number(PARTS[1]); 70 this.getMonthViewData(this.year, this.month); 71 } 72 73 /** 74 * 刷新日程点数据 75 */ 76 private schedulePointRefresh = () => { 77 this.updateMonthData(); 78 } 79 80 aboutToAppear() { 81 if (this.controller) { 82 this.controller.schedulePointRefresh = this.schedulePointRefresh; 83 } 84 const PARTS: string[] = this.yearMonth.split('-'); 85 this.year = Number(PARTS[0]); 86 this.month = Number(PARTS[1]); 87 this.getMonthViewData(this.year, this.month); 88 } 89 90 /** 91 * 月视图点击上个月或下个月日期切换月份 92 * @param is true为下月,false为上一月 93 */ 94 nextMouth(is: boolean) { 95 if (is) { 96 this.year = 97 (this.month + 1 > 12) ? this.year + 1 : this.year; 98 this.month = (this.month + 1 > 12) ? 1 : this.month + 1; 99 } else { 100 this.year = 101 (this.month - 1 < 1) ? this.year - 1 : this.year; 102 this.month = (this.month - 1 < 1) ? 12 : this.month - 1; 103 } 104 this.yearMonth = this.year + '-' + this.month; 105 } 106 107 /** 108 * 月视图一天的子组件 109 * @param day 日期 110 * @param week 月视图周信息。0上个月,1当前月,2下个月 111 */ 112 @Builder 113 monthDayBuilder(day: Day, week: number) { 114 Column() { 115 Text(day.dayNum + '') 116 .fontColor(StyleUtils.getColor(day, this.month, this.currentSelectDay, CalendarViewType.MONTH, 117 this.calendarStyle)) 118 .fontSize(Constants.DAY_FONT_SIZE * 119 (this.calendarStyle.textScaling ? this.calendarStyle.textScaling : Constants.FONT_MULTIPLIER)) 120 .fontWeight(FontWeight.Medium) 121 Text(day.lunarDay) 122 .fontColor(StyleUtils.getLunarDayColor(day, this.month, this.currentSelectDay, CalendarViewType.MONTH, 123 this.calendarStyle)) 124 .fontSize(Constants.LUNAR_DAY_FONT_SIZE * 125 (this.calendarStyle.textScaling ? this.calendarStyle.textScaling : Constants.FONT_MULTIPLIER)) 126 } 127 .width($r('app.integer.calendar_switch_size_forty')) 128 .height($r('app.integer.calendar_switch_size_forty')) 129 .borderRadius($r('app.integer.calendar_switch_size_forty')) 130 .borderColor($r('app.color.calendar_switch_border_color')) 131 .borderWidth(StyleUtils.getBorderWidth(day, this.month, this.currentSelectDay, CalendarViewType.MONTH)) 132 .backgroundColor(StyleUtils.getBackgroundColor(day, this.currentSelectDay, this.calendarStyle)) 133 .justifyContent(FlexAlign.Center) 134 .alignItems(HorizontalAlign.Center) 135 .onClick(() => { 136 this.onDateClick(day.dayInfo.year, day.dayInfo.month, day.dayInfo.date); 137 // 月视图需要拼接day.dayInfo.week 138 this.currentSelectDate = 139 day.dayInfo.year + '-' + day.dayInfo.month + '-' + day.dayInfo.date + '-' + day.dayInfo.week; 140 this.currentSelectDay.year = day.dayInfo.year; 141 this.currentSelectDay.month = day.dayInfo.month; 142 this.currentSelectDay.date = day.dayInfo.date; 143 // 必须记录点击日期的week值。CalendarSwitch的onSelectDayChange监听中需要根据week值点击的是上个月还是下个月的日期,从而进行相应的月份切换 144 this.currentSelectDay.week = day.dayInfo.week; 145 // 选中了上个月的日期,切换到上个月。1表示月视图第一周 146 if (week == 1 && day.dayNum > Constants.DAYS_IN_WEEK) { 147 this.nextMouth(false); 148 } 149 // 选中了下个月的日期,切换到下个月。2表示月视图第二周 150 if (week > 2 && day.dayNum < Constants.DAYS_IN_WEEK) { 151 this.nextMouth(true); 152 } 153 }) 154 } 155 156 build() { 157 Column() { 158 ForEach(this.monthDays, (items: Day[], index: number) => { 159 Row() { 160 ForEach(items, (item: Day) => { 161 Column() { 162 this.monthDayBuilder(item, index + 1) 163 if (item.isShowSchedulePoint) { 164 // 日程点 165 Circle({ width: Constants.SCHEDULE_POINT_DIAMETER, height: Constants.SCHEDULE_POINT_DIAMETER }) 166 .fill($r('app.color.calendar_switch_schedule_point_color')) 167 .margin({ top: $r('app.integer.calendar_switch_size_one') }) 168 } 169 } 170 .height($r('app.integer.calendar_switch_size_forty_six')) 171 }, (item: Day, index: number) => { 172 return item.dayNum + '' + index + item.isShowSchedulePoint; 173 }) 174 } 175 .width($r('app.string.calendar_switch_full_size')) 176 .justifyContent(FlexAlign.SpaceBetween) 177 }, (item: Day[], index: number) => { 178 return item.reduce((item1, item2) => { 179 return item1 + item2.dayInfo.year + item2.dayInfo.month + item2.dayInfo.date + item2.isShowSchedulePoint 180 }, '') + index 181 }) 182 }.width($r('app.string.calendar_switch_full_size')) 183 } 184}