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

271 lines
9.4 KiB
JavaScript

const { post, uploadFile } = require("../../utils/api");
const { getModule } = require("../../utils/modules");
const { hasManagePermission } = require("../../utils/permissions");
const { ensureModuleOpen, getActiveClassId, showError } = require("../../utils/page-helpers");
const FORM_DEFAULTS = {
announcements: { title: "", content: "", is_pinned: false },
votes: { title: "", description: "", options_text: "", vote_type: "single", is_anonymous: false },
schedule: { title: "", type: "course", start_time: "", end_time: "", location: "", description: "" },
fund: { type: "expense", amount: "", category: "", description: "", record_date: "" }
};
Page({
data: {
moduleKey: "",
title: "新增",
form: {},
isAnnouncements: false,
isVotes: false,
isSchedule: false,
isFund: false,
isScheduleDeadline: false,
scheduleTimeLabel: "开始时间",
isFundIncome: false,
isFundExpense: true,
fundIncomeClass: "",
fundExpenseClass: "active expense",
scheduleTypes: ["课程", "截止日", "活动"],
scheduleTypeValues: ["course", "deadline", "activity"],
scheduleTypeLabel: "课程",
fundTypes: ["income", "expense"],
fundTypeLabels: ["入账", "出账"],
fundIncomeCategories: ["班费收取", "活动赞助", "其他收入"],
fundExpenseCategories: ["聚餐", "活动物资", "场地费", "交通费", "礼品", "其他支出"],
fundCategories: ["聚餐", "活动物资", "场地费", "交通费", "礼品", "其他支出"],
fundImageUrls: [],
uploadingImages: false,
loading: false
},
onLoad(options) {
const moduleKey = options.module || "";
const module = getModule(moduleKey);
const classId = getActiveClassId();
const user = getApp().globalData.user;
if (!module || !ensureModuleOpen(moduleKey) || !hasManagePermission(user, classId, moduleKey)) {
const unavailableTitle = module ? module.title : "功能";
wx.redirectTo({
url: `/pages/module-unavailable/index?title=${encodeURIComponent(unavailableTitle)}`
});
return;
}
const form = Object.assign({}, FORM_DEFAULTS[moduleKey] || {});
if (moduleKey === "fund" && !form.record_date) {
form.record_date = new Date().toISOString().slice(0, 10);
}
if (moduleKey === "fund" && !form.category) {
form.category = form.type === "income" ? "班费收取" : "聚餐";
}
this.setData({
moduleKey,
title: `新增${module.title}`,
form,
isAnnouncements: moduleKey === "announcements",
isVotes: moduleKey === "votes",
isSchedule: moduleKey === "schedule",
isScheduleDeadline: moduleKey === "schedule" && form.type === "deadline",
scheduleTimeLabel: form.type === "deadline" ? "截止时间" : "开始时间",
scheduleTypeLabel: moduleKey === "schedule" ? this.scheduleTypeText(form.type) : "课程",
isFund: moduleKey === "fund",
isFundIncome: form.type === "income",
isFundExpense: form.type === "expense",
fundIncomeClass: form.type === "income" ? "active income" : "",
fundExpenseClass: form.type === "expense" ? "active expense" : "",
fundCategories: form.type === "income"
? this.data.fundIncomeCategories
: this.data.fundExpenseCategories,
fundImageUrls: []
});
wx.setNavigationBarTitle({ title: `新增${module.title}` });
},
onInput(event) {
const field = event.currentTarget.dataset.field;
this.setData({ [`form.${field}`]: event.detail.value });
},
onSwitch(event) {
const field = event.currentTarget.dataset.field;
this.setData({ [`form.${field}`]: event.detail.value });
},
onPicker(event) {
const field = event.currentTarget.dataset.field;
const value = event.currentTarget.dataset.values.split(",")[Number(event.detail.value)];
const nextData = { [`form.${field}`]: value };
if (this.data.moduleKey === "schedule" && field === "type") {
nextData.isScheduleDeadline = value === "deadline";
if (value === "deadline") {
nextData["form.end_time"] = "";
}
}
this.setData(nextData);
},
scheduleTypeText(type) {
return {
course: "课程",
deadline: "截止日",
activity: "活动"
}[type] || type || "课程";
},
onScheduleTypeChange(event) {
const index = Number(event.detail.value);
const value = this.data.scheduleTypeValues[index];
const nextData = {
"form.type": value,
scheduleTypeLabel: this.scheduleTypeText(value),
isScheduleDeadline: value === "deadline",
scheduleTimeLabel: value === "deadline" ? "截止时间" : "开始时间"
};
if (value === "deadline") {
nextData["form.end_time"] = "";
}
this.setData(nextData);
},
setFundType(event) {
const type = event.currentTarget.dataset.type;
const categories = type === "income"
? this.data.fundIncomeCategories
: this.data.fundExpenseCategories;
this.setData({
"form.type": type,
"form.category": categories[0],
isFundIncome: type === "income",
isFundExpense: type === "expense",
fundIncomeClass: type === "income" ? "active income" : "",
fundExpenseClass: type === "expense" ? "active expense" : "",
fundCategories: categories
});
},
onDateChange(event) {
this.setData({ "form.record_date": event.detail.value });
},
onFundCategoryChange(event) {
const index = Number(event.detail.value);
this.setData({ "form.category": this.data.fundCategories[index] });
},
chooseFundImages() {
if (this.data.uploadingImages) return;
if (this.data.fundImageUrls.length >= 6) {
wx.showToast({ title: "最多 6 张图片", icon: "none" });
return;
}
wx.chooseMedia({
count: 6 - this.data.fundImageUrls.length,
mediaType: ["image"],
sourceType: ["album", "camera"],
success: async (res) => {
const paths = (res.tempFiles || []).map((item) => item.tempFilePath);
if (!paths.length) return;
this.setData({ uploadingImages: true });
try {
const uploaded = [...this.data.fundImageUrls];
for (const path of paths) {
const result = await uploadFile("/api/upload/image", path, {}, "file");
if (result && result.url) uploaded.push(result.url);
}
this.setData({ fundImageUrls: uploaded.slice(0, 6) });
} catch (error) {
showError(error, "上传图片失败");
} finally {
this.setData({ uploadingImages: false });
}
}
});
},
removeFundImage(event) {
const index = Number(event.currentTarget.dataset.index);
this.setData({
fundImageUrls: this.data.fundImageUrls.filter((_, itemIndex) => itemIndex !== index)
});
},
async submit() {
const classId = getActiveClassId();
const moduleKey = this.data.moduleKey;
const form = this.data.form;
this.setData({ loading: true });
try {
if (moduleKey === "announcements") {
await post(`/api/announcements/?class_id=${classId}`, {
title: form.title,
content: form.content || null,
is_pinned: Boolean(form.is_pinned)
});
}
if (moduleKey === "votes") {
const options = String(form.options_text || "")
.split("\n")
.map((item) => item.trim())
.filter(Boolean);
await post(`/api/votes/?class_id=${classId}`, {
title: form.title,
description: form.description || null,
vote_type: form.vote_type || "single",
is_anonymous: Boolean(form.is_anonymous),
max_choices: form.vote_type === "multiple" ? Math.max(2, options.length) : 1,
options
});
}
if (moduleKey === "schedule") {
if (!form.title || !form.start_time) {
wx.showToast({ title: "请填写标题和开始时间", icon: "none" });
return;
}
if (form.type !== "deadline" && !form.end_time) {
wx.showToast({ title: "请填写结束时间", icon: "none" });
return;
}
if (form.end_time && new Date(form.end_time).getTime() <= new Date(form.start_time).getTime()) {
wx.showToast({ title: "结束时间应晚于开始时间", icon: "none" });
return;
}
await post(`/api/schedule/?class_id=${classId}`, {
title: form.title,
type: form.type,
start_time: form.start_time,
end_time: form.end_time || null,
location: form.location || null,
description: form.description || null
});
}
if (moduleKey === "fund") {
if (!form.amount || Number(form.amount) <= 0) {
wx.showToast({ title: "请输入有效金额", icon: "none" });
return;
}
if (!form.category) {
wx.showToast({ title: "请输入分类", icon: "none" });
return;
}
if (!form.record_date) {
wx.showToast({ title: "请选择日期", icon: "none" });
return;
}
await post(`/api/fund/?class_id=${classId}`, {
type: form.type,
amount: Number(form.amount),
category: form.category,
description: form.description || null,
image_urls: this.data.fundImageUrls,
record_date: form.record_date
});
}
wx.showToast({ title: "已保存", icon: "success" });
setTimeout(() => wx.navigateBack(), 500);
} catch (error) {
showError(error, "保存失败");
} finally {
this.setData({ loading: false });
}
}
});