import request from '../../../utils/request'; Page({ data: { items: [], currentSunlight: 0, isLoading: true, hasMore: true, current: 1, pageSize: 10, activeType: 'PHYSICAL', // Redeem popup showRedeemPopup: false, selectedItem: null, redeemForm: { recipientName: '', phone: '', address: '' } }, onLoad() { this.fetchProfile(); this.fetchItems(); }, onShow() { this.fetchProfile(); }, async fetchProfile() { try { const res = await request.get('/profile/detail'); if (res) { this.setData({ currentSunlight: res.currentSunlight || 0 }); } } catch (e) { // Silent } }, async fetchItems(append = false) { if (!append) { this.setData({ isLoading: true, current: 1, items: [] }); } try { const res = await request.get('/exchange/list', { current: this.data.current, pageSize: this.data.pageSize, type: this.data.activeType }); const rawList = (res && res.list) ? res.list : []; const total = (res && res.total) ? res.total : 0; const now = Date.now(); const list = rawList.map(item => { const hasStart = !!item.startTime; const hasEnd = !!item.endTime; const startTs = hasStart ? new Date(item.startTime).getTime() : 0; const endTs = hasEnd ? new Date(item.endTime).getTime() : 0; const notStarted = hasStart && now < startTs; const hasEnded = hasEnd && now > endTs; const isActive = !notStarted && !hasEnded; let timeLabel = ''; if (hasStart && hasEnd) { timeLabel = this.formatDate(item.startTime) + ' ~ ' + this.formatDate(item.endTime); } else if (hasStart) { timeLabel = this.formatDate(item.startTime) + ' 起'; } else if (hasEnd) { timeLabel = '截止 ' + this.formatDate(item.endTime); } return { ...item, hasTimeLimit: hasStart || hasEnd, timeLabel, notStarted, hasEnded, isActive }; }); this.setData({ items: append ? [...this.data.items, ...list] : list, hasMore: this.data.items.length + list.length < total }); } catch (e) { console.error('Fetch exchange items failed', e); } finally { this.setData({ isLoading: false }); wx.stopPullDownRefresh(); } }, onReachBottom() { if (!this.data.hasMore || this.data.isLoading) return; this.setData({ current: this.data.current + 1 }); this.fetchItems(true); }, onPullDownRefresh() { this.fetchProfile(); this.fetchItems(); }, switchType(e) { const key = e.currentTarget.dataset.key; if (key === this.data.activeType) return; this.setData({ activeType: key }); this.fetchItems(); }, // Redeem Flow onItemTap(e) { const item = e.currentTarget.dataset.item; if (item.notStarted) { wx.showToast({ title: '活动尚未开始', icon: 'none' }); return; } if (item.hasEnded) { wx.showToast({ title: '活动已结束', icon: 'none' }); return; } if (item.stock === 0) { wx.showToast({ title: '已兑完', icon: 'none' }); return; } this.setData({ selectedItem: item, showRedeemPopup: true, redeemForm: { recipientName: '', phone: '', address: '' } }); }, onPopupClose() { this.setData({ showRedeemPopup: false }); }, onFormInput(e) { const field = e.currentTarget.dataset.field; this.setData({ [`redeemForm.${field}`]: e.detail.value }); }, async confirmRedeem() { const item = this.data.selectedItem; if (!item) return; // Check sunlight if (this.data.currentSunlight < item.costSunlight) { wx.showToast({ title: '阳光值不足', icon: 'none' }); return; } // Physical items require address if (item.type === 'PHYSICAL') { const { recipientName, phone, address } = this.data.redeemForm; if (!recipientName || !phone || !address) { wx.showToast({ title: '请填写完整收货信息', icon: 'none' }); return; } } wx.showLoading({ title: '兑换中...', mask: true }); try { await request.post('/exchange/redeem', { itemId: item.id, quantity: 1, ...this.data.redeemForm }); wx.hideLoading(); wx.showToast({ title: '兑换成功!', icon: 'success' }); this.setData({ showRedeemPopup: false }); // Refresh data this.fetchProfile(); this.fetchItems(); } catch (e) { wx.hideLoading(); wx.showToast({ title: e.message || '兑换失败', icon: 'none' }); } }, goToOrders() { wx.navigateTo({ url: '/pages/profile/exchange/orders/index' }); }, formatDate(dateStr) { if (!dateStr) return ''; const d = new Date(dateStr); const m = (d.getMonth() + 1).toString().padStart(2, '0'); const day = d.getDate().toString().padStart(2, '0'); return m + '.' + day; } });