2026-05-11 15:32:18 +08:00

266 lines
7.8 KiB
JavaScript

const { API } = require('../../../utils/constants');
const { request } = require('../../../utils/http');
function toNumber(v, fallback = 0) {
const n = Number(v);
return Number.isFinite(n) ? n : fallback;
}
function formatMoney(v) {
const n = toNumber(v, 0);
return (Math.round(n * 100) / 100).toFixed(2).replace(/\.00$/, '');
}
function genderText(v) {
if (v == null) return '';
const s = String(v).toLowerCase();
if (s === 'male' || s === 'm' || s === '1') return '男';
if (s === 'female' || s === 'f' || s === '2') return '女';
return '';
}
Page({
data: {
registrationId: null,
loading: true,
calculating: false,
refundRulesText: '退款规则以赛事说明为准',
items: [],
selectAll: false,
selectedCount: 0,
refundAmount: '0',
refundableAmount: '0',
actualPaidAmount: '',
refundedAmount: '0'
},
onLoad(options) {
const registrationId = Number(options.registrationId);
this.setData({ registrationId });
if (!registrationId) {
this.setData({ loading: false });
wx.showToast({ title: '参数错误', icon: 'none' });
return;
}
this.fetchRegistrationDetail(registrationId);
},
fetchRegistrationDetail(registrationId) {
this.setData({ loading: true });
request({
path: API.myRegistrationDetail(registrationId),
method: 'GET',
needAuth: true
})
.then((detail) => {
const d = detail && typeof detail === 'object' ? detail : {};
const paymentStatus = d.paymentStatus != null ? Number(d.paymentStatus) : null;
if (paymentStatus === 3) {
wx.showModal({
title: '提示',
content: '该报名已取消,无法继续操作',
showCancel: false,
confirmText: '确定',
success: () => {
wx.navigateBack();
}
});
this.setData({ loading: false });
return;
}
const rawItems = Array.isArray(d.items) ? d.items : [];
const items = rawItems.map((it, idx) => {
const projectName = it.projectName || it.ProjectName || `项目${idx + 1}`;
const groupName = it.groupName || it.GroupName || '';
const price = it.price != null ? toNumber(it.price, 0) : 0;
const persons = Array.isArray(it.persons) ? it.persons : [];
const pills =
persons.length > 0
? persons.map((p, pi) => {
const gender = genderText(p.gender);
const label = [groupName, gender].filter(Boolean).join(' | ') || groupName || '参赛人';
return {
pillKey: `i-${idx}-p-${pi}`,
personId: p.id,
label,
price,
selected: false
};
})
: [
{
pillKey: `i-${idx}-g`,
groupId: it.id,
label: groupName || '组别',
price,
selected: false
}
];
return {
itemKey: `it-${idx}`,
projectName,
pills
};
});
const refundRulesText = d.refundRulesText || d.RefundRulesText || '退款规则以赛事说明为准';
this.setData({
items,
selectAll: false,
refundRulesText,
loading: false
});
this.recalcFromBackend();
})
.catch((err) => {
this.setData({ loading: false, items: [] });
wx.showToast({ title: (err && err.message) || '加载失败', icon: 'none' });
});
},
onTogglePill(e) {
const pillKey = e.currentTarget.dataset.pillkey;
if (!pillKey) return;
const items = this.data.items.map((it) => ({
...it,
pills: it.pills.map((p) => (p.pillKey === pillKey ? { ...p, selected: !p.selected } : p))
}));
this.setData({ items });
this.recalcFromBackend();
},
onToggleAll() {
const next = !this.data.selectAll;
const items = this.data.items.map((it) => ({
...it,
pills: it.pills.map((p) => ({ ...p, selected: next }))
}));
this.setData({ items, selectAll: next });
this.recalcFromBackend();
},
recalcFromBackend() {
const all = [];
this.data.items.forEach((it) => it.pills.forEach((p) => all.push(p)));
const selected = all.filter((p) => p.selected);
const selectAll = all.length > 0 && selected.length === all.length;
this.setData({
selectedCount: selected.length,
selectAll
});
const personIds = [];
const cancelTeams = [];
selected.forEach((p) => {
if (p.personId) {
personIds.push(p.personId);
} else if (p.groupId) {
cancelTeams.push(`${p.groupId}_team`);
}
});
this.setData({ calculating: true });
request({
path: API.calculateRefundAmount,
method: 'POST',
needAuth: true,
data: {
registrationId: this.data.registrationId,
cancelType: selectAll ? 0 : 1,
personIds: personIds.length > 0 ? personIds : null,
cancelTeams: cancelTeams.length > 0 ? cancelTeams : null
}
})
.then((result) => {
const r = result && typeof result === 'object' ? result : {};
this.setData({
calculating: false,
// 如果没有选择项目,退款金额显示为 0
refundAmount: selected.length > 0 ? formatMoney(r.refundAmount) : '0',
refundableAmount: formatMoney(r.refundableAmount),
actualPaidAmount: formatMoney(r.actualPaidAmount),
refundedAmount: formatMoney(r.refundedAmount)
});
})
.catch((err) => {
this.setData({ calculating: false });
wx.showToast({ title: (err && err.message) || '计算退款金额失败', icon: 'none' });
});
},
onConfirmCancel() {
if (this.data.selectedCount === 0) return;
wx.showModal({
title: '确认取消报名?',
content: `本次预计退款金额 ¥${this.data.refundAmount}`,
cancelText: '取消',
confirmText: '确定',
success: (res) => {
if (!res || !res.confirm) return;
this.submitCancelRegistration();
}
});
},
submitCancelRegistration() {
const all = [];
this.data.items.forEach((it) => it.pills.forEach((p) => all.push(p)));
const selected = all.filter((p) => p.selected);
const selectAll = all.length > 0 && selected.length === all.length;
const personIds = [];
const cancelTeams = [];
selected.forEach((p) => {
if (p.personId) {
personIds.push(p.personId);
} else if (p.groupId) {
cancelTeams.push(`${p.groupId}_team`);
}
});
wx.showLoading({ title: '提交中...' });
request({
path: API.cancelRegistrationRefund,
method: 'POST',
needAuth: true,
data: {
registrationId: this.data.registrationId,
cancelType: selectAll ? 0 : 1,
personIds: personIds.length > 0 ? personIds : null,
cancelTeams: cancelTeams.length > 0 ? cancelTeams : null,
refundReason: '用户取消报名'
}
})
.then(() => {
wx.hideLoading();
wx.showToast({ title: '退款申请已提交', icon: 'success' });
setTimeout(() => {
const pages = getCurrentPages();
if (pages.length > 1) {
const prevPage = pages[pages.length - 2];
if (prevPage && prevPage.route && prevPage.route.includes('records')) {
if (prevPage.initData) {
prevPage.initData(true);
}
}
}
wx.navigateBack();
}, 1500);
})
.catch((err) => {
wx.hideLoading();
wx.showToast({ title: (err && err.message) || '提交失败,请稍后重试', icon: 'none' });
});
}
});