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' }); }); } });