feat:兑换中心

This commit is contained in:
Blizzard
2026-02-25 13:28:17 +08:00
parent 5789e8bf17
commit bcba77f912
11 changed files with 1169 additions and 10 deletions
+196 -1
View File
@@ -1 +1,196 @@
Page({});
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;
}
});