const { get } = require("../../utils/api"); const { refreshMe, requireLogin } = require("../../utils/auth"); const { isModuleEnabled, visibleModules } = require("../../utils/modules"); const { getActiveClassId, getActiveClassName, getEnabledModules, showError } = require("../../utils/page-helpers"); function formatDateTime(value) { if (!value) return ""; return String(value).replace("T", " ").slice(0, 16); } function formatScheduleTime(item) { const start = formatDateTime(item.start_time); const end = formatDateTime(item.end_time); if (item.type === "deadline") return `截止 ${start}`; if (!end) return start; if (start.slice(0, 10) === end.slice(0, 10)) { return `${start} - ${end.slice(11)}`; } return `${start} - ${end}`; } function scheduleTypeText(type) { return { course: "课程", deadline: "截止日", activity: "活动" }[type] || type || "排期"; } function countdownText(value) { if (!value) return ""; const target = new Date(value).getTime(); if (Number.isNaN(target)) return ""; const now = Date.now(); const diffDays = Math.ceil((target - now) / (24 * 60 * 60 * 1000)); if (diffDays < 0) return `已逾期 ${Math.abs(diffDays)} 天`; if (diffDays === 0) return "今天截止"; if (diffDays === 1) return "明天截止"; return `还有 ${diffDays} 天`; } Page({ data: { className: "HKU ICB", homeStatus: "班级信息已同步", announcements: [], schedules: [], votes: [], timelines: [], quickModules: [], focusItems: [], unreadCount: 0, loading: false }, async onShow() { if (!requireLogin()) return; await this.load(); }, async load() { this.setData({ loading: true }); try { await refreshMe(); const app = getApp(); const user = app.globalData.user; const classId = getActiveClassId(); const enabledModules = getEnabledModules(); const className = getActiveClassName(); this.setData({ className, quickModules: [ ...visibleModules("class", enabledModules), ...visibleModules("interact", enabledModules) ].slice(0, 4) }); const tasks = [get("/api/notifications/unread-count").catch(() => ({ unread_count: 0 }))]; const names = ["unread"]; if (isModuleEnabled("announcements", enabledModules)) { names.push("announcements"); tasks.push(get("/api/announcements/", { page_size: 3, class_id: classId })); } if (isModuleEnabled("schedule", enabledModules)) { names.push("schedules"); tasks.push(get("/api/schedule/upcoming", { limit: 3, class_id: classId })); } if (isModuleEnabled("votes", enabledModules)) { names.push("votes"); tasks.push(get("/api/votes/", { page_size: 3, class_id: classId })); } const results = await Promise.all(tasks); const next = { announcements: [], schedules: [], votes: [], timelines: [] }; names.forEach((name, index) => { const value = results[index]; if (name === "unread") next.unreadCount = value.unread_count || 0; if (name === "announcements") next.announcements = value.items || []; if (name === "schedules") { next.schedules = (value || []).map((item) => ({ ...item, schedule_time_text: formatScheduleTime(item), schedule_type_text: scheduleTypeText(item.type), countdown_text: item.type === "deadline" ? countdownText(item.start_time) : "" })); } if (name === "votes") { next.votes = (value.items || []).map((item) => ({ ...item, vote_type_text: item.vote_type === "multiple" ? "多选" : "单选", vote_action_text: item.has_voted ? "已参与" : "待参与" })); } if (name === "timelines") next.timelines = value.items || []; }); const pendingVotes = next.votes.filter((item) => !item.has_voted); const focusItems = []; if (next.schedules.length) { const schedule = next.schedules[0]; focusItems.push({ id: schedule.id, type: "schedule", mark: "日", label: "下一项排期", title: schedule.title, detail: schedule.schedule_time_text, badge: schedule.countdown_text || schedule.schedule_type_text }); } if (pendingVotes.length) { const vote = pendingVotes[0]; focusItems.push({ id: vote.id, type: "vote", mark: "选", label: "待参与投票", title: vote.title, detail: `${vote.vote_type_text} · ${vote.total_voters} 人参与`, badge: "去参与" }); } if (next.announcements.length) { const announcement = next.announcements[0]; focusItems.push({ id: announcement.id, type: "announcements", mark: "告", label: "最新公告", title: announcement.title, detail: announcement.author_name || "班级公告", badge: "查看" }); } next.focusItems = focusItems.slice(0, 3); next.homeStatus = next.unreadCount > 0 ? `${next.unreadCount} 条未读通知` : "暂无未读通知"; this.setData(next); } catch (error) { showError(error); } finally { this.setData({ loading: false }); } }, openModule(event) { const key = event.currentTarget.dataset.key; wx.navigateTo({ url: `/pages/module/index?module=${key}` }); }, openFocus(event) { const type = event.currentTarget.dataset.type; const id = event.currentTarget.dataset.id; if (type === "schedule") { wx.navigateTo({ url: `/pages/schedule-detail/index?id=${id}` }); return; } if (type === "vote") { wx.navigateTo({ url: `/pages/vote-detail/index?id=${id}` }); return; } if (type === "announcements") { wx.navigateTo({ url: `/pages/announcement-detail/index?id=${id}` }); return; } wx.navigateTo({ url: `/pages/module/index?module=${type}` }); }, openSchedule(event) { wx.navigateTo({ url: `/pages/schedule-detail/index?id=${event.currentTarget.dataset.id}` }); }, openVote(event) { wx.navigateTo({ url: `/pages/vote-detail/index?id=${event.currentTarget.dataset.id}` }); }, openTimeline(event) { wx.navigateTo({ url: `/pages/timeline-detail/index?id=${event.currentTarget.dataset.id}` }); } });