feat:兑换中心
This commit is contained in:
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user