const { API } = require('../../utils/constants'); const { request } = require('../../utils/http'); const { formatDateTime, eventStatusText, eventStatusForPill, eventFormatText } = require('../../utils/format'); const auth = require('../../utils/auth'); /** 统一后台轮播字段(camelCase / PascalCase、枚举数字)供 wxml 绑定 */ function normalizeBannerItem(raw) { if (!raw || typeof raw !== 'object') { return { imageUrl: '', linkType: '', eventId: null, linkUrl: '' }; } const imageUrl = raw.imageUrl || raw.ImageUrl || ''; const linkUrl = String(raw.linkUrl || raw.LinkUrl || '').trim(); let linkType = raw.linkType != null ? raw.linkType : raw.LinkType; const rawEventId = raw.eventId != null ? raw.eventId : raw.EventId; const eventId = rawEventId != null && rawEventId !== '' ? Number(rawEventId) : null; const idOk = Number.isFinite(eventId) && eventId > 0; if (typeof linkType === 'number') { if (linkType === 1) linkType = 'Event'; else if (linkType === 2) linkType = 'Url'; else if (linkType === 0) linkType = ''; else linkType = String(linkType); } else if (typeof linkType === 'string') { const lower = linkType.toLowerCase(); if (lower === 'event') linkType = 'Event'; else if (lower === 'url' || lower === 'link' || lower === 'external') linkType = 'Url'; } if (linkType == null || linkType === '' || linkType === '0') { if (idOk) linkType = 'Event'; else if (linkUrl) linkType = 'Url'; else linkType = ''; } return { imageUrl, linkType, eventId: idOk ? eventId : null, linkUrl }; } function canCancelByEventStatus(rawEventStatus) { // 仅报名中(Enrolling / 1)允许取消 if (rawEventStatus === 'Enrolling') return true; const n = Number(rawEventStatus); if (!Number.isNaN(n)) return n === 1; const s = rawEventStatus == null ? '' : String(rawEventStatus).toLowerCase(); return s === 'enrolling' || s === '1'; } Page({ data: { sectionTab: 'list', loggedIn: false, banners: [], rows: [], loading: false, isFirstLoad: false, loadingText: '加载中...', pageNo: 1, pageSize: 10, hasMore: true, /** 列表筛选:-1=全部(不传 status),0~4 与后端 EventStatus 一致;默认报名中 */ status: 1, keyword: '', refresherTriggered: false }, onLoad() { this.fetchBanners(); this.loadEvents(true); }, onShow() { const loggedIn = !!(wx.getStorageSync('accessToken') || ''); this.setData({ loggedIn }); if (this.data.sectionTab === 'registered' && loggedIn) { this.loadMyEvents(true); } }, /** 页面 disableScroll 后,下拉刷新由 scroll-view 的 refresher 承担 */ onRefresherRefresh() { this.setData({ refresherTriggered: true }); this.fetchBanners(); const p = this.data.sectionTab === 'list' ? this.loadEvents(true) : this.loadMyEvents(true); p.finally(() => { this.setData({ refresherTriggered: false }); }); }, onPullDownRefresh() { this.fetchBanners(); const p = this.data.sectionTab === 'list' ? this.loadEvents(true) : this.loadMyEvents(true); p.finally(() => { wx.stopPullDownRefresh(); }); }, fetchBanners() { request({ path: API.banners, method: 'GET', needAuth: false }) .then((data) => { const arr = Array.isArray(data) ? data : []; const banners = arr.map((item, index) => ({ ...normalizeBannerItem(item), _bannerKey: index })); this.setData({ banners }); }) .catch(() => { this.setData({ banners: [] }); }); }, onSectionTab(e) { const tab = e.currentTarget.dataset.tab; if (!tab || tab === this.data.sectionTab) return; this.setData({ sectionTab: tab, pageNo: 1, rows: [], hasMore: true }); if (tab === 'list') { this.loadEvents(true); } else { this.loadMyEvents(true); } }, onStatusTap(e) { const status = Number(e.currentTarget.dataset.status); if (Number.isNaN(status)) return; this.setData({ status, pageNo: 1, rows: [], hasMore: true }); this.loadEvents(true); }, onKeywordInput(e) { this.setData({ keyword: e.detail.value || '' }); }, onSearch() { if (this.data.sectionTab !== 'list') { this.setData({ sectionTab: 'list', pageNo: 1, rows: [], hasMore: true }); } this.setData({ pageNo: 1, rows: [], hasMore: true }); this.loadEvents(true); }, onScrollToLower() { if (this.data.loading || !this.data.hasMore) return; if (this.data.sectionTab === 'list') { const next = this.data.pageNo + 1; this.setData({ pageNo: next }); this.loadEvents(false); } else { if (!this.data.loggedIn) return; const next = this.data.pageNo + 1; this.setData({ pageNo: next }); this.loadMyEvents(false); } }, goLogin() { wx.navigateTo({ url: '/subpackages/mine/login/login' }); }, onBannerTap(e) { const linkType = e.currentTarget.dataset.linktype; const eventId = Number(e.currentTarget.dataset.eventid); const linkUrl = e.currentTarget.dataset.linkurl || ''; if (linkType === 'Event' && eventId > 0) { wx.navigateTo({ url: `/pages/detail/detail?id=${eventId}` }); return; } if (linkUrl) { wx.showToast({ title: '该轮播链接为外部链接/其他跳转,请在后台配置', icon: 'none' }); } }, onEventTap(e) { const id = Number(e.currentTarget.dataset.id); if (!id) return; wx.navigateTo({ url: `/pages/detail/detail?id=${id}` }); }, onCancelRegistrationTap(e) { const canCancel = e.currentTarget.dataset.cancancel; if (!canCancel) return; const registrationId = Number(e.currentTarget.dataset.registrationid); if (!registrationId) return; wx.navigateTo({ url: `/subpackages/mine/cancel-registration/cancel-registration?registrationId=${registrationId}` }); }, onUploadMaterialTap(e) { const registrationId = Number(e.currentTarget.dataset.registrationid); if (!registrationId) return; const now = Date.now(); console.log('时间', e.currentTarget.dataset.matstarttime, e.currentTarget.dataset.matendtime , now); const matStartTime = e.currentTarget.dataset.matstarttime; const matEndTime = e.currentTarget.dataset.matendtime; const rangeText = e.currentTarget.dataset.materialrangetext || ''; if (matStartTime && now < Number(matStartTime)) { wx.showToast({ title: `素材上传未开始,开始时间:${rangeText.split(' ~ ')[0] || rangeText}`, icon: 'none', duration: 2500 }); return; } if (matEndTime && now > Number(matEndTime)) { wx.showToast({ title: `素材上传已截止,截止时间:${rangeText.split(' ~ ')[1] || rangeText}`, icon: 'none', duration: 2500 }); return; } this.openUploadPicker({ kind: 'material', registrationId }); }, onUploadVoucherTap(e) { const registrationId = Number(e.currentTarget.dataset.registrationid); if (!registrationId) return; this.openUploadPicker({ kind: 'voucher', registrationId }); }, openUploadPicker({ kind, registrationId }) { const title = kind === 'voucher' ? '上传付款凭证' : '上传素材'; if (kind === 'material') { wx.showActionSheet({ itemList: ['从相册选择图片/视频', '拍照/录视频', '选择音乐文件'], success: (r) => { if (!r || typeof r.tapIndex !== 'number') return; if (r.tapIndex === 2) { wx.chooseMessageFile({ count: 1, type: 'file', extension: ['mp3', 'wav', 'aac', 'flac', 'm4a', 'ogg'], success: (res) => { const file = res && res.tempFiles && res.tempFiles[0]; const tempFilePath = file ? file.path : ''; if (!tempFilePath) return; this._confirmAndUploadMaterial(title, tempFilePath, registrationId); } }); } else { const sourceType = r.tapIndex === 1 ? ['camera'] : ['album']; wx.chooseMedia({ count: 1, mediaType: ['image', 'video'], sourceType, success: (res) => { const tempFilePath = res && res.tempFiles && res.tempFiles[0] ? res.tempFiles[0].tempFilePath : ''; if (!tempFilePath) return; this._confirmAndUploadMaterial(title, tempFilePath, registrationId); } }); } } }); } else { wx.showActionSheet({ itemList: ['从相册选择', '拍照'], success: (r) => { if (!r || typeof r.tapIndex !== 'number') return; const sourceType = r.tapIndex === 1 ? ['camera'] : ['album']; wx.chooseMedia({ count: 1, mediaType: ['image'], sourceType, success: (res) => { const tempFilePath = res && res.tempFiles && res.tempFiles[0] ? res.tempFiles[0].tempFilePath : ''; if (!tempFilePath) return; wx.showModal({ title, content: '确认上传该图片?', cancelText: '取消', confirmText: '确定', success: (mr) => { if (!mr || !mr.confirm) return; // TODO: 接入付款凭证上传接口 wx.showToast({ title: '已选择', icon: 'success' }); } }); } }); } }); } }, _confirmAndUploadMaterial(title, tempFilePath, registrationId) { wx.showModal({ title, content: '确认上传该文件?', cancelText: '取消', confirmText: '确定', success: (mr) => { console.log('用户选择:', mr); if (!mr || !mr.confirm) return; wx.showLoading({ title: '上传中...', mask: true }); auth.uploadFile(tempFilePath) .then((url) => { return request({ path: API.uploadMaterial, method: 'POST', needAuth: true, data: { registrationId, materialUrl: url } }); }) .then(() => { wx.showToast({ title: '上传成功', icon: 'success' }); }) .catch((err) => { wx.showToast({ title: (err && err.message) || '上传失败', icon: 'none' }); }); } }); }, loadEvents(reset) { if (this.data.loading) return Promise.resolve(); if (reset) { this.setData({ rows: [], pageNo: 1, hasMore: true }); } this.setData({ loading: true, isFirstLoad: !!reset }); const pageNo = reset ? 1 : this.data.pageNo; const pageSize = this.data.pageSize; const status = this.data.status; const keyword = this.data.keyword; const query = { page: pageNo, pagesize: pageSize, PageNo: pageNo, PageSize: pageSize, keyword, Keyword: keyword }; if (status >= 0) { query.status = status; query.Status = status; } return request({ path: API.eventList, method: 'GET', needAuth: false, data: query }) .then((res) => { const rows = (res && Array.isArray(res.rows) ? res.rows : []).map((item) => { const id = item.id; const rawEventStatus = item.eventStatus != null ? item.eventStatus : item.EventStatus != null ? item.EventStatus : item.status != null ? item.status : item.Status; return { ...item, rowKey: `e-${id}`, registrationStartText: formatDateTime(item.registrationStartTime), registrationEndText: formatDateTime(item.registrationEndTime), matchStartText: formatDateTime(item.matchStartTime), matchEndText: formatDateTime(item.matchEndTime), eventStatusText: eventStatusText(rawEventStatus), eventStatusPill: eventStatusForPill(rawEventStatus), eventFormatText: eventFormatText(item.eventType || item.eventFormat) }; }); const nextRows = reset ? rows : this.data.rows.concat(rows); const pages = res && typeof res.pages === 'number' ? res.pages : 1; const hasMore = pageNo < pages && rows.length > 0; this.setData({ rows: nextRows, hasMore, loading: false, isFirstLoad: false, loadingText: hasMore ? '加载中...' : '没有更多了' }); }) .catch((err) => { this.setData({ loading: false, isFirstLoad: false, hasMore: false, rows: reset ? [] : this.data.rows, loadingText: err && err.message ? err.message : '加载失败' }); }); }, loadMyEvents(reset) { if (!this.data.loggedIn) { this.setData({ rows: [], loading: false }); return Promise.resolve(); } if (this.data.loading) return Promise.resolve(); if (reset) { this.setData({ rows: [], pageNo: 1, hasMore: true }); } this.setData({ loading: true, isFirstLoad: !!reset }); const pageNo = reset ? 1 : this.data.pageNo; const pageSize = this.data.pageSize; return request({ path: API.eventMyList, method: 'GET', needAuth: true, data: { page: pageNo, pagesize: pageSize, PageNo: pageNo, PageSize: pageSize } }) .then((res) => { const rows = (res && Array.isArray(res.rows) ? res.rows : []).map((item) => { const eid = item.eventId; const rid = item.registrationId; const rawEventStatus = item.eventStatus != null ? item.eventStatus : item.EventStatus != null ? item.EventStatus : item.status != null ? item.status : item.Status; const eventStatusPill = eventStatusForPill(rawEventStatus); const matStart = item.materialUploadStartTime || item.MaterialUploadStartTime || item.uploadMaterialStartTime || item.UploadMaterialStartTime; const matEnd = item.materialUploadEndTime || item.MaterialUploadEndTime || item.uploadMaterialEndTime || item.UploadMaterialEndTime; const matDeadlineText = item.materialUploadDeadlineText || item.MaterialUploadDeadlineText || ''; const matStartFmt = formatDateTime(matStart); const matEndFmt = formatDateTime(matEnd); let materialRangeText = matDeadlineText; if (!materialRangeText) { if (matStartFmt && matStartFmt !== '-' && matEndFmt && matEndFmt !== '-') { materialRangeText = `${matStartFmt} ~ ${matEndFmt}`; } else if (matStartFmt && matStartFmt !== '-') { materialRangeText = matStartFmt; } else if (matEndFmt && matEndFmt !== '-') { materialRangeText = matEndFmt; } } return { id: eid, rowKey: `m-${rid}`, registrationId: rid, eventName: item.eventName, coverImage: item.coverImage, address: '', isNeedMaterial: !!item.isNeedMaterial, materialRangeText, matStartTime: matStart ? new Date(matStart).getTime() : null, matEndTime: matEnd ? new Date(matEnd).getTime() : null, eventStatusPill, eventStatusText: eventStatusText(rawEventStatus) || '已报名', registrationTimeText: formatDateTime(item.registrationTime), projectCount: item.projectCount, eventFormatText: '', paymentStatus: item.paymentStatus != null ? Number(item.paymentStatus) : null, canCancel: canCancelByEventStatus(rawEventStatus) }; }); const nextRows = reset ? rows : this.data.rows.concat(rows); const pages = res && typeof res.pages === 'number' ? res.pages : 1; const hasMore = pageNo < pages && rows.length > 0; this.setData({ rows: nextRows, hasMore, loading: false, isFirstLoad: false, loadingText: hasMore ? '加载中...' : '没有更多了' }); }) .catch(() => { this.setData({ loading: false, isFirstLoad: false, hasMore: false, rows: reset ? [] : this.data.rows, loadingText: '加载失败' }); }); } });