406 lines
14 KiB
JavaScript
406 lines
14 KiB
JavaScript
const { API } = require('../../utils/constants');
|
||
const { request } = require('../../utils/http');
|
||
const { formatDateTime, eventFormatText } = require('../../utils/format');
|
||
|
||
/** 接口未返回时的 UI 兜底(与产品稿一致,有真实数据后自动以接口为准) */
|
||
var DETAIL_UI_FALLBACK = {
|
||
eventTitle: '2025-2026学年上海市中小学生跳绳锦标赛',
|
||
eventFormatTag: '线下',
|
||
registrationMethodText: '只允许个人报名',
|
||
feeModeLabel: '定价模式(赛事)',
|
||
priceDisplay: 892,
|
||
registrationStartText: '2015-10-02 09:21:00',
|
||
registrationEndText: '2015-10-10 18:00:00',
|
||
matchStartText: '2015-10-02 09:21:00',
|
||
matchEndText: '2015-10-10 18:00:00',
|
||
materialRangeText: '2015-10-02 09:21:00 ~ 2015-10-10 18:00:00',
|
||
uploadMaterialRemark:
|
||
'上传素材备注备注注上传素材备注备注注上传素材备注备注注上传素材备注备注注',
|
||
eventAddress: '上海市杨浦区307号',
|
||
refundRulesText: '开赛前7天扣除金额5%,3-7天扣除金额10%,3天内扣除金额20%',
|
||
participationPointsLabel: '5积分',
|
||
rankingPointsLines: ['1--8 15积分', '9--20 10积分'],
|
||
registrationLimitLines: [
|
||
'每人限报个人项目2个,团队项目3个',
|
||
'项目-组别允许同一个个人/单位最大报名数量:30秒单摇2个,2*30秒双摇接力1个,30秒单摇2个'
|
||
],
|
||
introductionText:
|
||
'这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比赛这是一场比.赛这是一场比赛这是一场比赛这是一场',
|
||
organizerText: '上海市杨浦区闸殷路307号',
|
||
coOrganizerText: '上海市杨浦区闸殷路307号'
|
||
};
|
||
|
||
var DEMO_PROJECT_TABLE_ROWS = [
|
||
{ rowKey: 'fb-1', typeName: '个人', projectName: '30秒单摇', groupName: '少年组', fee: '23' },
|
||
{ rowKey: 'fb-2', typeName: '团队', projectName: '少年儿童组', groupName: '成年组', fee: '411' },
|
||
{ rowKey: 'fb-3', typeName: '团队', projectName: '少年儿童组', groupName: '32', fee: '32' },
|
||
{ rowKey: 'fb-4', typeName: '团队', projectName: '成年组', groupName: '12', fee: '12' }
|
||
];
|
||
|
||
function isEmptyDisplayTime(s) {
|
||
return s == null || String(s).trim() === '' || String(s).trim() === '-';
|
||
}
|
||
|
||
function pick(obj, keys) {
|
||
if (!obj) return null;
|
||
for (let i = 0; i < keys.length; i++) {
|
||
const v = obj[keys[i]];
|
||
if (v != null && v !== '') return v;
|
||
}
|
||
return null;
|
||
}
|
||
|
||
function registrationModeText(mode) {
|
||
const m = mode === undefined || mode === null ? null : Number(mode);
|
||
if (m === 1) return '只允许个人报名';
|
||
if (m === 2) return '只允许团队报名';
|
||
if (m === 0 || m === 3) return '个人与团队均可报名';
|
||
return null;
|
||
}
|
||
|
||
function formatRange(start, end) {
|
||
const a = formatDateTime(start);
|
||
const b = formatDateTime(end);
|
||
if (a === '-' && b === '-') return '';
|
||
if (a === '-') return b;
|
||
if (b === '-') return a;
|
||
return `${a} ~ ${b}`;
|
||
}
|
||
|
||
function splitLines(text) {
|
||
if (!text || typeof text !== 'string') return [];
|
||
return text
|
||
.split(/\r?\n/)
|
||
.map((s) => s.trim())
|
||
.filter(Boolean);
|
||
}
|
||
|
||
function flattenProjectTableRows(projects) {
|
||
if (!Array.isArray(projects)) return [];
|
||
const rows = [];
|
||
projects.forEach((p) => {
|
||
const pid = p.id != null ? p.id : p.Id;
|
||
const rawGroups = Array.isArray(p.groups) ? p.groups : Array.isArray(p.Groups) ? p.Groups : [];
|
||
const groups = rawGroups.length ? rawGroups : [null];
|
||
groups.forEach((g, gi) => {
|
||
const gid = g && (g.groupId != null ? g.groupId : g.GroupId != null ? g.GroupId : null);
|
||
const gname = g && (g.groupName || g.GroupName);
|
||
rows.push({
|
||
rowKey: `p-${pid}-${gi}-${gid != null ? gid : gname || 'g'}`,
|
||
typeName: p.typeName || p.TypeName || '-',
|
||
projectName: p.name || p.Name || '-',
|
||
groupName: g ? gname || gid || '-' : '-',
|
||
fee: p.fee != null ? p.fee : p.Fee != null ? p.Fee : '-'
|
||
});
|
||
});
|
||
});
|
||
return rows;
|
||
}
|
||
|
||
function normalizeEventDetail(raw) {
|
||
const d = raw && typeof raw === 'object' ? raw : {};
|
||
const projects = Array.isArray(d.projects) ? d.projects : Array.isArray(d.Projects) ? d.Projects : [];
|
||
|
||
const registrationMethodText =
|
||
pick(d, [
|
||
'registrationMethodText',
|
||
'RegistrationMethodText',
|
||
'registrationMethodDescription',
|
||
'RegistrationMethodDescription'
|
||
]) || registrationModeText(pick(d, ['registrationMode', 'RegistrationMode']));
|
||
|
||
const feeModeLabel =
|
||
pick(d, ['feeModeText', 'FeeModeText', 'feeModeDescription', 'FeeModeDescription', 'pricingModeText', 'PricingModeText']) ||
|
||
pick(d, ['feeMode', 'FeeMode', 'pricingMode', 'PricingMode']) ||
|
||
'';
|
||
|
||
const priceRaw = pick(d, [
|
||
'displayPrice',
|
||
'DisplayPrice',
|
||
'eventPrice',
|
||
'EventPrice',
|
||
'price',
|
||
'Price',
|
||
'minFee',
|
||
'MinFee'
|
||
]);
|
||
let priceDisplay = priceRaw != null && priceRaw !== '' ? priceRaw : null;
|
||
if (priceDisplay == null && projects.length) {
|
||
const fees = projects.map((p) => p.fee).filter((f) => f != null && f !== '');
|
||
if (fees.length) {
|
||
const nums = fees.map(Number).filter((n) => !Number.isNaN(n));
|
||
if (nums.length) priceDisplay = Math.min(...nums);
|
||
}
|
||
}
|
||
|
||
const materialRangeText =
|
||
pick(d, ['materialUploadDeadlineText', 'MaterialUploadDeadlineText']) ||
|
||
formatRange(
|
||
pick(d, ['materialUploadStartTime', 'MaterialUploadStartTime']),
|
||
pick(d, ['materialUploadEndTime', 'MaterialUploadEndTime'])
|
||
) ||
|
||
formatRange(
|
||
pick(d, ['uploadMaterialStartTime', 'UploadMaterialStartTime']),
|
||
pick(d, ['uploadMaterialEndTime', 'UploadMaterialEndTime'])
|
||
);
|
||
|
||
const refundRulesText = pick(d, ['refundRules', 'RefundRules', 'refundDescription', 'RefundDescription']);
|
||
const participationPoints = pick(d, ['participationPoints', 'ParticipationPoints']);
|
||
const rankingPointsRaw = pick(d, [
|
||
'rankingPointsText',
|
||
'RankingPointsText',
|
||
'rankingPointsDescription',
|
||
'RankingPointsDescription',
|
||
'rankingPoints',
|
||
'RankingPoints'
|
||
]);
|
||
let rankingPointsLines = [];
|
||
if (typeof rankingPointsRaw === 'string') {
|
||
rankingPointsLines = splitLines(rankingPointsRaw);
|
||
} else if (Array.isArray(rankingPointsRaw)) {
|
||
rankingPointsLines = rankingPointsRaw.map((x) => String(x)).filter(Boolean);
|
||
} else if (rankingPointsRaw != null && rankingPointsRaw !== '') {
|
||
rankingPointsLines = [String(rankingPointsRaw)];
|
||
}
|
||
|
||
const registrationLimitRaw = pick(d, [
|
||
'registrationLimitText',
|
||
'RegistrationLimitText',
|
||
'registrationRules',
|
||
'RegistrationRules',
|
||
'limitDescription',
|
||
'LimitDescription'
|
||
]);
|
||
let registrationLimitLines = [];
|
||
if (registrationLimitRaw != null && registrationLimitRaw !== '') {
|
||
if (typeof registrationLimitRaw === 'string') {
|
||
registrationLimitLines = splitLines(registrationLimitRaw);
|
||
} else if (Array.isArray(registrationLimitRaw)) {
|
||
registrationLimitLines = registrationLimitRaw.filter((x) => x != null && String(x).trim() !== '');
|
||
} else {
|
||
registrationLimitLines = [String(registrationLimitRaw)];
|
||
}
|
||
}
|
||
|
||
const participationPointsLabel =
|
||
pick(d, ['participationPointsText', 'ParticipationPointsText']) ||
|
||
(participationPoints != null && participationPoints !== ''
|
||
? `${participationPoints}积分`
|
||
: '');
|
||
|
||
const introImage = pick(d, ['introductionImage', 'IntroductionImage', 'detailImage', 'DetailImage']);
|
||
|
||
return {
|
||
detail: d,
|
||
projects,
|
||
eventFormatTag: eventFormatText(d.eventType || d.eventFormat || d.EventType || d.EventFormat),
|
||
registrationMethodText,
|
||
feeModeLabel: feeModeLabel || '定价模式(赛事)',
|
||
priceDisplay,
|
||
materialRangeText,
|
||
refundRulesText,
|
||
participationPointsLabel,
|
||
rankingPointsLines,
|
||
registrationLimitLines,
|
||
introImage,
|
||
hasNoticeBlock: Boolean(refundRulesText || participationPointsLabel || rankingPointsLines.length),
|
||
hasRegistrationLimit: registrationLimitLines.length > 0,
|
||
projectTableRows: flattenProjectTableRows(projects)
|
||
};
|
||
}
|
||
|
||
Page({
|
||
data: {
|
||
id: null,
|
||
eventDetail: {},
|
||
projects: [],
|
||
|
||
registrationStartText: '',
|
||
registrationEndText: '',
|
||
matchStartText: '',
|
||
matchEndText: '',
|
||
|
||
eventFormatTag: '',
|
||
registrationMethodText: '',
|
||
feeModeLabel: '',
|
||
priceDisplay: null,
|
||
materialRangeText: '',
|
||
refundRulesText: '',
|
||
participationPointsLabel: '',
|
||
rankingPointsLines: [],
|
||
registrationLimitLines: [],
|
||
introImage: '',
|
||
introductionText: '',
|
||
uploadMaterialRemark: '',
|
||
eventTitle: '',
|
||
eventAddress: '',
|
||
heroImage: '',
|
||
hasNoticeBlock: false,
|
||
hasRegistrationLimit: false,
|
||
projectTableRows: [],
|
||
organizerText: '',
|
||
coOrganizerText: ''
|
||
},
|
||
|
||
onLoad(options) {
|
||
const id = Number(options.id);
|
||
this.setData({ id });
|
||
if (!id) return;
|
||
this.fetchDetail(id);
|
||
},
|
||
|
||
fetchDetail(id) {
|
||
request({
|
||
path: API.eventDetail(id),
|
||
method: 'GET',
|
||
needAuth: false
|
||
})
|
||
.then((res) => {
|
||
const detail = res || {};
|
||
const projects = Array.isArray(detail.projects) ? detail.projects : [];
|
||
const normalizedProjects = projects.map((p) => {
|
||
const groups = Array.isArray(p.groups)
|
||
? p.groups
|
||
: Array.isArray(p.Groups)
|
||
? p.Groups
|
||
: [];
|
||
const groupSummary = groups.length
|
||
? groups
|
||
.map((g) => g.groupName || g.groupId)
|
||
.filter(Boolean)
|
||
.join(',')
|
||
: '';
|
||
return { ...p, groupSummary };
|
||
});
|
||
|
||
const n = normalizeEventDetail({ ...detail, projects: normalizedProjects });
|
||
const fb = DETAIL_UI_FALLBACK;
|
||
|
||
var introductionText =
|
||
pick(detail, ['eventIntroduction', 'EventIntroduction', 'introduction', 'Introduction']) || '';
|
||
if (!introductionText.trim()) introductionText = fb.introductionText;
|
||
|
||
var eventTitle = pick(detail, ['eventName', 'EventName']) || '';
|
||
if (!eventTitle.trim()) eventTitle = fb.eventTitle;
|
||
|
||
var eventAddress = pick(detail, ['address', 'Address']) || '';
|
||
if (!eventAddress.trim()) eventAddress = fb.eventAddress;
|
||
|
||
var heroImage = pick(detail, ['coverImage', 'CoverImage']) || '';
|
||
|
||
var registrationStartText = formatDateTime(
|
||
pick(detail, ['registrationStartTime', 'RegistrationStartTime'])
|
||
);
|
||
var registrationEndText = formatDateTime(
|
||
pick(detail, ['registrationEndTime', 'RegistrationEndTime'])
|
||
);
|
||
if (isEmptyDisplayTime(registrationStartText)) registrationStartText = fb.registrationStartText;
|
||
if (isEmptyDisplayTime(registrationEndText)) registrationEndText = fb.registrationEndText;
|
||
|
||
var matchStartText = formatDateTime(pick(detail, ['matchStartTime', 'MatchStartTime']));
|
||
var matchEndText = formatDateTime(pick(detail, ['matchEndTime', 'MatchEndTime']));
|
||
if (isEmptyDisplayTime(matchStartText)) matchStartText = fb.matchStartText;
|
||
if (isEmptyDisplayTime(matchEndText)) matchEndText = fb.matchEndText;
|
||
|
||
var eventFormatTag = n.eventFormatTag || fb.eventFormatTag;
|
||
var registrationMethodText = n.registrationMethodText || fb.registrationMethodText;
|
||
var feeModeLabel = n.feeModeLabel || fb.feeModeLabel;
|
||
var priceDisplay = n.priceDisplay != null ? n.priceDisplay : fb.priceDisplay;
|
||
|
||
var materialRangeText = n.materialRangeText || fb.materialRangeText;
|
||
|
||
var uploadMaterialRemark =
|
||
pick(detail, [
|
||
'uploadMaterialRemark',
|
||
'UploadMaterialRemark',
|
||
'materialRemark',
|
||
'MaterialRemark'
|
||
]) || '';
|
||
if (!uploadMaterialRemark.trim()) uploadMaterialRemark = fb.uploadMaterialRemark;
|
||
|
||
var refundRulesText = n.refundRulesText || fb.refundRulesText;
|
||
var participationPointsLabel = n.participationPointsLabel || fb.participationPointsLabel;
|
||
var rankingPointsLines =
|
||
n.rankingPointsLines && n.rankingPointsLines.length ? n.rankingPointsLines : fb.rankingPointsLines;
|
||
var registrationLimitLines =
|
||
n.registrationLimitLines && n.registrationLimitLines.length
|
||
? n.registrationLimitLines
|
||
: fb.registrationLimitLines;
|
||
|
||
var projectTableRows =
|
||
n.projectTableRows && n.projectTableRows.length ? n.projectTableRows : DEMO_PROJECT_TABLE_ROWS;
|
||
|
||
var hasNoticeBlock = Boolean(
|
||
refundRulesText || participationPointsLabel || rankingPointsLines.length
|
||
);
|
||
var hasRegistrationLimit = registrationLimitLines.length > 0;
|
||
|
||
var organizerText =
|
||
pick(detail, [
|
||
'organizer',
|
||
'Organizer',
|
||
'organizerText',
|
||
'OrganizerText',
|
||
'hostUnit',
|
||
'HostUnit',
|
||
'sponsor',
|
||
'Sponsor'
|
||
]) || '';
|
||
if (!String(organizerText).trim()) organizerText = fb.organizerText;
|
||
|
||
var coOrganizerText =
|
||
pick(detail, [
|
||
'coOrganizer',
|
||
'CoOrganizer',
|
||
'coOrganizerText',
|
||
'CoOrganizerText',
|
||
'assistantUnit',
|
||
'AssistantUnit',
|
||
'coSponsor',
|
||
'CoSponsor'
|
||
]) || '';
|
||
if (!String(coOrganizerText).trim()) coOrganizerText = fb.coOrganizerText;
|
||
|
||
this.setData({
|
||
eventDetail: detail,
|
||
projects: normalizedProjects,
|
||
introductionText,
|
||
eventTitle,
|
||
eventAddress,
|
||
heroImage,
|
||
registrationStartText,
|
||
registrationEndText,
|
||
matchStartText,
|
||
matchEndText,
|
||
eventFormatTag,
|
||
registrationMethodText,
|
||
feeModeLabel,
|
||
priceDisplay,
|
||
materialRangeText,
|
||
uploadMaterialRemark,
|
||
refundRulesText,
|
||
participationPointsLabel,
|
||
rankingPointsLines,
|
||
registrationLimitLines,
|
||
introImage: n.introImage || '',
|
||
hasNoticeBlock,
|
||
hasRegistrationLimit,
|
||
projectTableRows,
|
||
organizerText,
|
||
coOrganizerText
|
||
});
|
||
})
|
||
.catch(() => {
|
||
wx.showToast({ title: '加载失败', icon: 'none' });
|
||
});
|
||
},
|
||
|
||
onApplyTap() {
|
||
const id = this.data.id;
|
||
if (!id) return;
|
||
wx.navigateTo({
|
||
url: `/pages/apply/apply?eventId=${id}`
|
||
});
|
||
}
|
||
});
|