// pages/checkin/checkin.ts interface CalendarDay { day: number | string; // 日期数字或空字符串 fullDate?: string; // 完整日期字符串,如 'YYYY-MM-DD' isPrevMonth?: boolean; // 是否上月日期 isNextMonth?: boolean; // 是否下月日期 isToday?: boolean; // 是否今天 isCheckedIn?: boolean; // 是否已签到 } Page({ data: { weekdays: ['日', '一', '二', '三', '四', '五', '六'], currentYear: 0, currentMonth: 0, // 1-12月 calendarDays: [] as CalendarDay[], // 日历日期数据 consecutiveCheckInDays: 0, // 连续签到天数 monthCheckInDays: 0, // 本月签到天数 todayCheckedIn: false, // 今日是否已签到 // 假设这些是用户已签到的日期(仅日期数字),在真实项目中从后端获取 checkedInDates: [] as number[], // [1, 5, 18, 29] 表示当月哪些天已签到 // 用于保存当前显示的月份的Date对象,方便计算 displayMonthDate: new Date(), }, onLoad() { this.initCalendar(); this.fetchCheckInStats(); // 模拟从后端获取签到数据 }, /** * 初始化日历,生成当前月份的日期 */ initCalendar() { const today = new Date(); this.data.displayMonthDate = new Date(today.getFullYear(), today.getMonth(), 1); // 设置为当前月的第一天 this.renderCalendar(this.data.displayMonthDate); }, /** * 渲染指定月份的日历 * @param date 当前月份的任意一天,例如 new Date(2025, 8, 1) 表示 2025年9月 */ renderCalendar(date: Date) { const year = date.getFullYear(); const month = date.getMonth(); // 0-11 this.setData({ currentYear: year, currentMonth: month + 1, // 显示给用户是1-12月 }); const calendarDays: CalendarDay[] = []; const firstDayOfMonth = new Date(year, month, 1); const lastDayOfMonth = new Date(year, month + 1, 0); // 当月最后一天 // 补充上个月的日期(如果需要) const startDayOfWeek = firstDayOfMonth.getDay(); // 0-6,0是周日 for (let i = 0; i < startDayOfWeek; i++) { calendarDays.push({ day: '', isPrevMonth: true }); // 用空字符串占位或显示上月日期 } // 填充当前月份的日期 for (let i = 1; i <= lastDayOfMonth.getDate(); i++) { const currentDay = new Date(year, month, i); const isToday = this.isSameDay(currentDay, new Date()); const isCheckedIn = this.data.checkedInDates.includes(i); // 判断是否已签到 calendarDays.push({ day: i, fullDate: this.formatDate(currentDay), isToday: isToday, isCheckedIn: isCheckedIn, }); } // 补充下个月的日期(如果需要,凑够6行或7的倍数) const totalDays = calendarDays.length; const remainingDays = 42 - totalDays; // 假设日历固定6行7列,共42个格子 for (let i = 0; i < remainingDays; i++) { calendarDays.push({ day: '', isNextMonth: true }); // 用空字符串占位 } this.setData({ calendarDays: calendarDays, }); }, /** * 模拟从后端获取签到统计数据和已签到日期 */ fetchCheckInStats() { // 真实项目中这里会发起 wx.request 到您的后端接口 // 假设后端返回的数据格式如下: const mockApiResponse = { consecutiveCheckInDays: 29, // 连续签到天数 monthCheckInDays: 15, // 本月签到天数 todayCheckedIn: false, // 假设今天未签到 checkedInDaysInMonth: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 29], // 当月已签到的日期数字 }; this.setData({ consecutiveCheckInDays: mockApiResponse.consecutiveCheckInDays, monthCheckInDays: mockApiResponse.monthCheckInDays, todayCheckedIn: mockApiResponse.todayCheckedIn, checkedInDates: mockApiResponse.checkedInDaysInMonth, }); // 重新渲染日历以应用新的签到状态 this.renderCalendar(this.data.displayMonthDate); }, /** * 处理签到按钮点击 */ handleCheckIn() { if (this.data.todayCheckedIn) { wx.showToast({ title: '今日已签到', icon: 'none' }); return; } // 模拟后端签到逻辑 wx.showLoading({ title: '签到中...' }); setTimeout(() => { // 假设后端返回签到成功 const today = new Date().getDate(); const newCheckedInDates = [...this.data.checkedInDates, today]; this.setData({ todayCheckedIn: true, consecutiveCheckInDays: this.data.consecutiveCheckInDays + 1, // 假设连续+1 monthCheckInDays: this.data.monthCheckInDays + 1, // 假设当月+1 checkedInDates: newCheckedInDates, }); // 重新渲染日历,标记今天为已签到 this.renderCalendar(this.data.displayMonthDate); wx.hideLoading(); wx.showToast({ title: '签到成功!', icon: 'success' }); }, 1000); // 模拟网络请求 }, /** * 处理日历中的日期点击(可选,如果需要点击日期查看历史签到等) */ handleDayClick(event: WechatMiniprogram.TouchEvent) { const fullDate = event.currentTarget.dataset.date; if (fullDate) { console.log('点击了日期:', fullDate); // 可在此处实现点击日期查看历史签到详情等逻辑 } }, /** * 辅助函数:判断两个日期是否是同一天 (忽略时间) */ isSameDay(date1: Date, date2: Date): boolean { return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate(); }, /** * 辅助函数:格式化日期为 YYYY-MM-DD */ formatDate(date: Date): string { const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return `${year}-${month}-${day}`; }, });