243 lines
8.0 KiB
JavaScript
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();
|
|
}
|
|
}
|
|
});
|