421 lines
11 KiB
JavaScript
421 lines
11 KiB
JavaScript
|
|
import {
|
|||
|
|
getUserPoints,
|
|||
|
|
getPointsOverview,
|
|||
|
|
getPointsHistory,
|
|||
|
|
getPointsRules,
|
|||
|
|
getPointsExchangeList,
|
|||
|
|
exchangePoints,
|
|||
|
|
getUserExchangeRecords,
|
|||
|
|
dailyCheckin
|
|||
|
|
} from '../../services/points/index';
|
|||
|
|
|
|||
|
|
const weChatAuthService = require('../../services/auth/wechat');
|
|||
|
|
|
|||
|
|
Page({
|
|||
|
|
data: {
|
|||
|
|
userPoints: 0,
|
|||
|
|
pointsOverview: {
|
|||
|
|
total_points: 0,
|
|||
|
|
available_points: 0,
|
|||
|
|
frozen_points: 0,
|
|||
|
|
total_earned: 0,
|
|||
|
|
total_spent: 0,
|
|||
|
|
this_month_earned: 0,
|
|||
|
|
this_month_spent: 0
|
|||
|
|
},
|
|||
|
|
pointsHistory: [],
|
|||
|
|
pointsRules: [],
|
|||
|
|
exchangeItems: [],
|
|||
|
|
exchangeRecords: [],
|
|||
|
|
currentTab: 0,
|
|||
|
|
showExchangeModal: false,
|
|||
|
|
selectedItem: null,
|
|||
|
|
loading: false,
|
|||
|
|
historyPage: 1,
|
|||
|
|
exchangePage: 1,
|
|||
|
|
recordsPage: 1,
|
|||
|
|
hasMoreHistory: true,
|
|||
|
|
hasMoreExchange: true,
|
|||
|
|
hasMoreRecords: true,
|
|||
|
|
tabList: [
|
|||
|
|
{ text: '积分明细', key: 0 },
|
|||
|
|
{ text: '积分规则', key: 1 },
|
|||
|
|
{ text: '积分兑换', key: 2 }
|
|||
|
|
]
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onLoad() {
|
|||
|
|
this.init();
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async init() {
|
|||
|
|
console.log('积分页面初始化');
|
|||
|
|
this.setData({ loading: true });
|
|||
|
|
|
|||
|
|
// 检查登录状态
|
|||
|
|
if (!weChatAuthService.isLoggedIn()) {
|
|||
|
|
console.log('用户未登录,跳转到登录页面');
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '请先登录',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
setTimeout(() => {
|
|||
|
|
wx.navigateTo({
|
|||
|
|
url: '/pages/login/index'
|
|||
|
|
});
|
|||
|
|
}, 1500);
|
|||
|
|
this.setData({ loading: false });
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
// 并行加载基础数据
|
|||
|
|
await Promise.all([
|
|||
|
|
this.loadUserPoints(),
|
|||
|
|
this.loadPointsOverview(),
|
|||
|
|
this.loadPointsHistory(),
|
|||
|
|
this.loadPointsRules(),
|
|||
|
|
this.loadExchangeItems()
|
|||
|
|
]);
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('积分页面初始化失败:', error);
|
|||
|
|
|
|||
|
|
// 检查是否是认证错误
|
|||
|
|
if (error.message && error.message.includes('未授权')) {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '登录已过期,请重新登录',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
setTimeout(() => {
|
|||
|
|
wx.navigateTo({
|
|||
|
|
url: '/pages/login/index'
|
|||
|
|
});
|
|||
|
|
}, 1500);
|
|||
|
|
} else {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '加载失败,请重试',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} finally {
|
|||
|
|
this.setData({ loading: false });
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载用户积分
|
|||
|
|
async loadUserPoints() {
|
|||
|
|
try {
|
|||
|
|
console.log('开始获取用户积分...');
|
|||
|
|
const response = await getUserPoints();
|
|||
|
|
console.log('用户积分API响应:', response);
|
|||
|
|
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
const points = response.data.points || 0;
|
|||
|
|
console.log('设置用户积分:', points);
|
|||
|
|
this.setData({
|
|||
|
|
userPoints: points
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
console.error('获取用户积分失败 - 业务错误:', response.message);
|
|||
|
|
throw new Error(response.message || '获取积分失败');
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取用户积分失败:', error);
|
|||
|
|
throw error; // 重新抛出错误,让上层处理
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载积分概览
|
|||
|
|
async loadPointsOverview() {
|
|||
|
|
try {
|
|||
|
|
console.log('开始获取积分概览...');
|
|||
|
|
const response = await getPointsOverview();
|
|||
|
|
console.log('积分概览API响应:', response);
|
|||
|
|
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
console.log('设置积分概览数据:', response.data);
|
|||
|
|
this.setData({
|
|||
|
|
pointsOverview: response.data
|
|||
|
|
});
|
|||
|
|
} else {
|
|||
|
|
console.error('获取积分概览失败 - 业务错误:', response.message);
|
|||
|
|
throw new Error(response.message || '获取积分概览失败');
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取积分概览失败:', error);
|
|||
|
|
throw error; // 重新抛出错误,让上层处理
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载积分历史记录
|
|||
|
|
async loadPointsHistory(page = 1, append = false) {
|
|||
|
|
try {
|
|||
|
|
const response = await getPointsHistory({ page, pageSize: 10 });
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
const newHistory = response.data.list.map(item => ({
|
|||
|
|
...item,
|
|||
|
|
type: item.type === 1 ? 'earn' : 'spend', // 转换类型:1=获得(earn), 2=消费(spend)
|
|||
|
|
date: this.formatDate(item.created_at),
|
|||
|
|
time: this.formatTime(item.created_at)
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
this.setData({
|
|||
|
|
pointsHistory: append ? [...this.data.pointsHistory, ...newHistory] : newHistory,
|
|||
|
|
historyPage: page,
|
|||
|
|
hasMoreHistory: newHistory.length === 10
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取积分历史记录失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载积分规则
|
|||
|
|
async loadPointsRules() {
|
|||
|
|
try {
|
|||
|
|
const response = await getPointsRules();
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
this.setData({
|
|||
|
|
pointsRules: response.data.map(rule => ({
|
|||
|
|
id: rule.id,
|
|||
|
|
title: rule.title, // 后端返回的字段名是title,不是name
|
|||
|
|
description: rule.description
|
|||
|
|
}))
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取积分规则失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载兑换商品
|
|||
|
|
async loadExchangeItems(page = 1, append = false) {
|
|||
|
|
try {
|
|||
|
|
const response = await getPointsExchangeList({ page, pageSize: 10 });
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
// 后端直接返回数组,不是包含list的对象
|
|||
|
|
const dataArray = Array.isArray(response.data) ? response.data : (response.data.list || []);
|
|||
|
|
const newItems = dataArray.map(item => ({
|
|||
|
|
id: item.id,
|
|||
|
|
name: item.name,
|
|||
|
|
description: item.description,
|
|||
|
|
points: item.points, // 后端返回的字段名是points,不是points_required
|
|||
|
|
image: item.image,
|
|||
|
|
stock: item.stock
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
this.setData({
|
|||
|
|
exchangeItems: append ? [...this.data.exchangeItems, ...newItems] : newItems,
|
|||
|
|
exchangePage: page,
|
|||
|
|
hasMoreExchange: newItems.length === 10
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取兑换商品失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 加载兑换记录
|
|||
|
|
async loadExchangeRecords(page = 1, append = false) {
|
|||
|
|
try {
|
|||
|
|
const response = await getUserExchangeRecords({ page, pageSize: 10 });
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
const newRecords = response.data.list.map(record => ({
|
|||
|
|
...record,
|
|||
|
|
date: this.formatDate(record.created_at)
|
|||
|
|
}));
|
|||
|
|
|
|||
|
|
this.setData({
|
|||
|
|
exchangeRecords: append ? [...this.data.exchangeRecords, ...newRecords] : newRecords,
|
|||
|
|
recordsPage: page,
|
|||
|
|
hasMoreRecords: newRecords.length === 10
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('获取兑换记录失败:', error);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 格式化日期
|
|||
|
|
formatDate(dateString) {
|
|||
|
|
const date = new Date(dateString);
|
|||
|
|
return date.toISOString().split('T')[0];
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 格式化时间
|
|||
|
|
formatTime(dateString) {
|
|||
|
|
const date = new Date(dateString);
|
|||
|
|
return date.toTimeString().split(' ')[0].substring(0, 5); // 返回 HH:MM 格式
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onTabChange(e) {
|
|||
|
|
const { value } = e.detail;
|
|||
|
|
this.setData({
|
|||
|
|
currentTab: value
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 切换到兑换记录标签时加载数据
|
|||
|
|
if (value === 3 && this.data.exchangeRecords.length === 0) {
|
|||
|
|
this.loadExchangeRecords();
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
onExchangeItem(e) {
|
|||
|
|
const { item } = e.currentTarget.dataset;
|
|||
|
|
const { userPoints } = this.data;
|
|||
|
|
|
|||
|
|
// 检查积分是否足够
|
|||
|
|
if (userPoints < item.points) {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '积分不足',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 检查库存
|
|||
|
|
if (item.stock <= 0) {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '商品已售罄',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示兑换确认弹窗
|
|||
|
|
wx.showModal({
|
|||
|
|
title: '确认兑换',
|
|||
|
|
content: `确定要用${item.points}积分兑换${item.name}吗?\n\n兑换后积分将立即扣除,请确认操作。`,
|
|||
|
|
confirmText: '确认兑换',
|
|||
|
|
cancelText: '取消',
|
|||
|
|
success: (res) => {
|
|||
|
|
if (res.confirm) {
|
|||
|
|
this.doExchangePoints(item);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async doExchangePoints(item) {
|
|||
|
|
try {
|
|||
|
|
wx.showLoading({
|
|||
|
|
title: '兑换中...',
|
|||
|
|
mask: true
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
const response = await exchangePoints(item.id, 1);
|
|||
|
|
|
|||
|
|
if (response.code === 200) {
|
|||
|
|
wx.hideLoading();
|
|||
|
|
|
|||
|
|
// 显示成功提示
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '兑换成功!',
|
|||
|
|
icon: 'success',
|
|||
|
|
duration: 2000
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 延迟刷新数据,让用户看到成功提示
|
|||
|
|
setTimeout(async () => {
|
|||
|
|
try {
|
|||
|
|
// 刷新用户积分和相关数据
|
|||
|
|
await Promise.all([
|
|||
|
|
this.loadUserPoints(),
|
|||
|
|
this.loadPointsOverview(),
|
|||
|
|
this.loadPointsHistory(1, false),
|
|||
|
|
this.loadExchangeItems(1, false)
|
|||
|
|
]);
|
|||
|
|
} catch (refreshError) {
|
|||
|
|
console.error('刷新数据失败:', refreshError);
|
|||
|
|
}
|
|||
|
|
}, 1000);
|
|||
|
|
|
|||
|
|
} else {
|
|||
|
|
throw new Error(response.message || '兑换失败');
|
|||
|
|
}
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error('积分兑换失败:', error);
|
|||
|
|
wx.hideLoading();
|
|||
|
|
|
|||
|
|
// 根据错误类型显示不同的提示
|
|||
|
|
let errorMessage = '兑换失败,请重试';
|
|||
|
|
if (error.message.includes('积分不足')) {
|
|||
|
|
errorMessage = '积分不足,无法兑换';
|
|||
|
|
} else if (error.message.includes('库存')) {
|
|||
|
|
errorMessage = '商品库存不足';
|
|||
|
|
} else if (error.message.includes('网络')) {
|
|||
|
|
errorMessage = '网络异常,请检查网络连接';
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
wx.showToast({
|
|||
|
|
title: errorMessage,
|
|||
|
|
icon: 'none',
|
|||
|
|
duration: 3000
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 下拉刷新
|
|||
|
|
async onPullDownRefresh() {
|
|||
|
|
try {
|
|||
|
|
await this.init();
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '刷新成功',
|
|||
|
|
icon: 'success'
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
wx.showToast({
|
|||
|
|
title: '刷新失败',
|
|||
|
|
icon: 'none'
|
|||
|
|
});
|
|||
|
|
} finally {
|
|||
|
|
wx.stopPullDownRefresh();
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
// 上拉加载更多
|
|||
|
|
onReachBottom() {
|
|||
|
|
const { currentTab } = this.data;
|
|||
|
|
|
|||
|
|
if (currentTab === 0 && this.data.hasMoreHistory) {
|
|||
|
|
// 加载更多积分历史
|
|||
|
|
this.loadPointsHistory(this.data.historyPage + 1, true);
|
|||
|
|
} else if (currentTab === 2 && this.data.hasMoreExchange) {
|
|||
|
|
// 加载更多兑换商品
|
|||
|
|
this.loadExchangeItems(this.data.exchangePage + 1, true);
|
|||
|
|
} else if (currentTab === 3 && this.data.hasMoreRecords) {
|
|||
|
|
// 加载更多兑换记录
|
|||
|
|
this.loadExchangeRecords(this.data.recordsPage + 1, true);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
|
|||
|
|
async onShow() {
|
|||
|
|
// 未登录则不触发签到与刷新
|
|||
|
|
if (!weChatAuthService.isLoggedIn()) {
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
// 每日签到:页面显示时尝试发放当天首次登录积分
|
|||
|
|
try {
|
|||
|
|
const res = await dailyCheckin();
|
|||
|
|
console.log('[积分] 每日签到结果:', res);
|
|||
|
|
} catch (e) {
|
|||
|
|
console.warn('[积分] 每日签到失败或未登录:', e);
|
|||
|
|
}
|
|||
|
|
// 刷新积分相关数据
|
|||
|
|
try {
|
|||
|
|
await Promise.all([
|
|||
|
|
this.loadUserPoints(),
|
|||
|
|
this.loadPointsOverview(),
|
|||
|
|
this.loadPointsHistory(1, false)
|
|||
|
|
]);
|
|||
|
|
} catch (err) {
|
|||
|
|
console.warn('[积分] 刷新数据失败:', err);
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
onShareAppMessage() {
|
|||
|
|
return {
|
|||
|
|
title: '我的积分',
|
|||
|
|
path: '/pages/points/index'
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
});
|