hku-class/miniprogram/pages/module/index.js

243 lines
8.0 KiB
JavaScript

const { del, get } = require("../../utils/api");
const { getModule } = require("../../utils/modules");
const { hasManagePermission } = require("../../utils/permissions");
const { ensureModuleOpen, getActiveClassId, showError } = require("../../utils/page-helpers");
const ENDPOINTS = {
announcements: "/api/announcements/",
directory: "/api/directory/",
timeline: "/api/timeline/",
votes: "/api/votes/",
schedule: "/api/schedule/",
fund: "/api/fund/"
};
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 || "排期";
}
Page({
data: {
moduleKey: "",
title: "功能",
moduleIcon: "项",
items: [],
canManage: false,
canPostTimeline: false,
isTimeline: false,
isDirectory: false,
isSchedule: false,
isFund: false,
isVotes: false,
fundStats: null,
directoryStats: null,
needsRefresh: false,
loading: false
},
onLoad(options) {
const moduleKey = options.module || "";
const module = getModule(moduleKey);
const app = getApp();
const classId = getActiveClassId();
const title = module ? module.title : "功能";
const icon = module ? module.icon : "项";
this.setData({
moduleKey,
title,
moduleIcon: icon,
isTimeline: moduleKey === "timeline",
isDirectory: moduleKey === "directory",
isSchedule: moduleKey === "schedule",
isFund: moduleKey === "fund",
isVotes: moduleKey === "votes",
canPostTimeline: moduleKey === "timeline",
canManage: ["announcements", "votes", "schedule", "fund"].includes(moduleKey) &&
hasManagePermission(app.globalData.user, classId, moduleKey)
});
wx.setNavigationBarTitle({ title });
if (!module || !ensureModuleOpen(moduleKey)) return;
this.load();
},
onShow() {
if (this.data.moduleKey && getModule(this.data.moduleKey)) {
this.setData({ needsRefresh: false });
this.load();
}
},
async onPullDownRefresh() {
await this.load();
wx.stopPullDownRefresh();
},
async load() {
const classId = getActiveClassId();
const endpoint = ENDPOINTS[this.data.moduleKey];
if (!endpoint) return;
this.setData({ loading: true });
try {
let stats = null;
if (this.data.moduleKey === "fund") {
stats = await get("/api/fund/statistics", { class_id: classId });
}
let directoryStats = null;
if (this.data.moduleKey === "directory") {
directoryStats = await get("/api/directory/stats", { class_id: classId });
}
const res = await get(endpoint, { page_size: 20, class_id: classId });
const rawItems = Array.isArray(res) ? res : res.items || [];
const currentUser = getApp().globalData.user || {};
const currentUserId = currentUser.id;
const formatAmount = (value) => Number(value || 0).toFixed(2);
const items = rawItems.map((item) => ({
...item,
can_delete: this.data.moduleKey === "timeline" && item.author_id === currentUserId,
initial: String(item.name || item.author_name || this.data.title || "项").slice(0, 1),
member_role_text: item.membership_role === "teacher" ? "老师" : "同学",
member_role_class: item.membership_role === "teacher" ? "teacher" : "student",
show_student_id: item.membership_role !== "teacher" && item.student_id,
schedule_day: item.start_time ? String(item.start_time).slice(8, 10) : "",
schedule_month: item.start_time ? `${String(item.start_time).slice(5, 7)}` : "",
schedule_time_text: this.data.moduleKey === "schedule" ? formatScheduleTime(item) : "",
schedule_type_text: this.data.moduleKey === "schedule" ? scheduleTypeText(item.type) : "",
vote_status_text: item.status === "open" ? "进行中" : "已关闭",
vote_type_text: item.vote_type === "multiple" ? `多选,最多 ${item.max_choices || 1}` : "单选",
vote_action_text: item.has_voted ? "已参与" : "待参与",
vote_pill_class: item.has_voted ? "done" : "",
vote_options_text: Array.isArray(item.options) ? `${item.options.length} 个选项` : "",
committee_text: item.committee_role ? ` · ${item.committee_role}` : "",
fund_type_text: item.type === "income" ? "收入" : "支出",
fund_type_class: item.type === "income" ? "income" : "expense",
amount_text: formatAmount(item.amount),
image_urls: Array.isArray(item.image_urls) ? item.image_urls : []
}));
const fundStats = stats ? {
...stats,
total_income_text: formatAmount(stats.total_income),
total_expense_text: formatAmount(stats.total_expense),
balance_text: formatAmount(stats.balance)
} : null;
this.setData({ items, fundStats, directoryStats });
} catch (error) {
if (error.message === "该功能当前未开放") {
wx.redirectTo({
url: `/pages/module-unavailable/index?title=${encodeURIComponent(this.data.title)}`
});
return;
}
showError(error);
} finally {
this.setData({ loading: false });
}
},
openItem(event) {
const id = event.currentTarget.dataset.id;
const key = this.data.moduleKey;
if (!id) return;
if (key === "directory") {
wx.navigateTo({ url: `/pages/member-detail/index?id=${id}` });
return;
}
if (key === "schedule") {
wx.navigateTo({ url: `/pages/schedule-detail/index?id=${id}` });
return;
}
if (key === "timeline") {
wx.navigateTo({ url: `/pages/timeline-detail/index?id=${id}` });
return;
}
if (key === "votes") {
wx.navigateTo({ url: `/pages/vote-detail/index?id=${id}` });
return;
}
if (key === "fund") {
wx.navigateTo({ url: `/pages/fund-detail/index?id=${id}` });
}
},
previewImage(event) {
const current = event.currentTarget.dataset.src;
const postId = Number(event.currentTarget.dataset.postId);
const post = this.data.items.find((item) => item.id === postId);
const urls = post && post.image_urls ? post.image_urls : [];
if (!current || !urls.length) return;
wx.previewImage({ current, urls });
},
previewFundImage(event) {
const current = event.currentTarget.dataset.src;
const recordId = Number(event.currentTarget.dataset.recordId);
const record = this.data.items.find((item) => item.id === recordId);
const urls = record && record.image_urls ? record.image_urls : [];
if (!current || !urls.length) return;
wx.previewImage({ current, urls });
},
openTimelineActions(event) {
const id = event.currentTarget.dataset.id;
wx.showActionSheet({
itemList: ["删除动态"],
itemColor: "#b42318",
success: () => {
wx.showModal({
title: "删除动态",
content: "删除后无法恢复,确认删除这条动态?",
confirmText: "删除",
confirmColor: "#b42318",
success: async (res) => {
if (!res.confirm) return;
try {
await del(`/api/timeline/${id}`);
wx.showToast({ title: "已删除", icon: "success" });
this.load();
} catch (error) {
showError(error, "删除失败");
}
}
});
}
});
},
openManage() {
wx.navigateTo({ url: `/pages/manage/index?module=${this.data.moduleKey}` });
},
openTimelineCreate() {
wx.navigateTo({ url: "/pages/timeline-create/index" });
},
openCreate() {
if (this.data.canPostTimeline) {
this.openTimelineCreate();
return;
}
if (this.data.canManage) {
this.openManage();
}
}
});