hku-class/miniprogram/pages/home/index.js
2026-05-16 23:59:13 +08:00

201 lines
6.4 KiB
JavaScript

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}` });
}
});