108 lines
3.5 KiB
JavaScript
108 lines
3.5 KiB
JavaScript
const { get, post } = require("../../utils/api");
|
|
const { showError } = require("../../utils/page-helpers");
|
|
|
|
function formatDateTime(value) {
|
|
if (!value) return "";
|
|
return String(value).replace("T", " ").slice(0, 16);
|
|
}
|
|
|
|
function normalizeVote(item, selectedIds) {
|
|
const optionIds = selectedIds || item.my_option_ids || [];
|
|
const totalVotes = (item.options || []).reduce((sum, option) => sum + Number(option.vote_count || 0), 0);
|
|
return {
|
|
...item,
|
|
status_text: item.status === "open" ? "进行中" : "已关闭",
|
|
vote_type_text: item.vote_type === "multiple" ? `多选,最多 ${item.max_choices || 1} 项` : "单选",
|
|
deadline_text: item.deadline ? formatDateTime(item.deadline) : "",
|
|
can_submit: item.status === "open" && !item.has_voted,
|
|
voted_action_text: item.has_voted ? "已参与" : "请选择",
|
|
submit_text: item.has_voted ? "你已参与" : "投票已关闭",
|
|
selectedIds: optionIds,
|
|
options: (item.options || []).map((option) => {
|
|
const voteCount = Number(option.vote_count || 0);
|
|
const percent = totalVotes > 0 ? Math.round((voteCount / totalVotes) * 100) : 0;
|
|
return {
|
|
...option,
|
|
checked: optionIds.includes(option.id),
|
|
selected_class: optionIds.includes(option.id) ? "selected" : "",
|
|
check_text: optionIds.includes(option.id) ? "✓" : "",
|
|
percent,
|
|
percent_style: `width: ${percent}%`,
|
|
voter_names_text: Array.isArray(option.voter_names) ? option.voter_names.join("、") : ""
|
|
};
|
|
})
|
|
};
|
|
}
|
|
|
|
Page({
|
|
data: {
|
|
id: null,
|
|
item: null,
|
|
loading: false,
|
|
submitting: false
|
|
},
|
|
|
|
onLoad(options) {
|
|
wx.setNavigationBarTitle({ title: "投票详情" });
|
|
this.setData({ id: options.id || null });
|
|
this.load(options.id);
|
|
},
|
|
|
|
async onPullDownRefresh() {
|
|
await this.load(this.data.id);
|
|
wx.stopPullDownRefresh();
|
|
},
|
|
|
|
async load(id) {
|
|
if (!id) return;
|
|
this.setData({ loading: true });
|
|
try {
|
|
const item = await get(`/api/votes/${id}`);
|
|
this.setData({ item: normalizeVote(item) });
|
|
} catch (error) {
|
|
showError(error, "加载投票失败");
|
|
} finally {
|
|
this.setData({ loading: false });
|
|
}
|
|
},
|
|
|
|
toggleOption(event) {
|
|
const optionId = Number(event.currentTarget.dataset.id);
|
|
const item = this.data.item;
|
|
if (!item || item.status !== "open" || item.has_voted) return;
|
|
let selectedIds = item.selectedIds || [];
|
|
if (item.vote_type === "single") {
|
|
selectedIds = [optionId];
|
|
} else if (selectedIds.includes(optionId)) {
|
|
selectedIds = selectedIds.filter((id) => id !== optionId);
|
|
} else {
|
|
if (selectedIds.length >= Number(item.max_choices || 1)) {
|
|
wx.showToast({ title: `最多选择 ${item.max_choices} 项`, icon: "none" });
|
|
return;
|
|
}
|
|
selectedIds = [...selectedIds, optionId];
|
|
}
|
|
this.setData({ item: normalizeVote(item, selectedIds) });
|
|
},
|
|
|
|
async submit() {
|
|
const item = this.data.item;
|
|
if (!item || item.has_voted || item.status !== "open") return;
|
|
const selectedIds = item.selectedIds || [];
|
|
if (!selectedIds.length) {
|
|
wx.showToast({ title: "请选择投票选项", icon: "none" });
|
|
return;
|
|
}
|
|
this.setData({ submitting: true });
|
|
try {
|
|
await post(`/api/votes/${item.id}/submit`, { option_ids: selectedIds });
|
|
wx.showToast({ title: "已投票", icon: "success" });
|
|
await this.load(item.id);
|
|
} catch (error) {
|
|
showError(error, "投票失败");
|
|
} finally {
|
|
this.setData({ submitting: false });
|
|
}
|
|
}
|
|
});
|