10 changed files with 13967 additions and 2970 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,452 @@ |
|||
<template> |
|||
<view class="points-detail-page"> |
|||
<!-- 积分总览 --> |
|||
<view class="points-overview"> |
|||
<view class="total-points"> |
|||
<text class="points-number">{{ totalPoints }}</text> |
|||
<text class="points-label">当前积分</text> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 筛选选项 --> |
|||
<view class="filter-tabs"> |
|||
<view class="tab-item" :class="[{ active: currentTab === 'all' }]" @click="switchTab('all')"> |
|||
全部 |
|||
</view> |
|||
<view class="tab-item" :class="[{ active: currentTab === 'in' }]" @click="switchTab('in')"> |
|||
收入 |
|||
</view> |
|||
<view class="tab-item" :class="[{ active: currentTab === 'out' }]" @click="switchTab('out')"> |
|||
支出 |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 积分记录列表 --> |
|||
<scroll-view class="points-list" scroll-y="true" @scrolltolower="loadMore"> |
|||
<template v-if="pointsList.length"> |
|||
<view class="record-item" v-for="(item, index) in pointsList" :key="index"> |
|||
<view class="record-left"> |
|||
<view class="record-icon" :class="item.fromType === 'in' ? 'income' : 'expense'"> |
|||
<uni-icons type="vip" size="30" style="color: white;"></uni-icons> |
|||
</view> |
|||
<view class="record-info"> |
|||
<view class="record-title">{{ item.dictName }}</view> |
|||
<view class="record-desc">{{ item.remark }}</view> |
|||
<view class="record-time">{{ item.createTime }}</view> |
|||
</view> |
|||
</view> |
|||
<view class="record-right"> |
|||
<view class="record-points" :class="item.fromType === 'in' ? 'income' : 'expense'"> |
|||
{{ item.points }} |
|||
</view> |
|||
</view> |
|||
</view> |
|||
|
|||
<!-- 加载更多提示 --> |
|||
<view class="load-more" v-if="hasMore"> |
|||
<text class="load-text">{{ |
|||
loading ? "加载中..." : "上拉加载更多" |
|||
}}</text> |
|||
</view> |
|||
|
|||
<!-- 没有更多数据 --> |
|||
<view class="no-more" v-if="!hasMore && pointsList.length > 0"> |
|||
<text class="no-more-text">没有更多数据了</text> |
|||
</view> |
|||
</template> |
|||
|
|||
<!-- 空状态 --> |
|||
<view class="empty-state" v-if="pointsList.length === 0 && !loading"> |
|||
<image class="empty-icon" |
|||
src="https://epic.js-dyyj.com/uploads/20250808/c16267f9cc2b7a68bf23713b5847987e.png" |
|||
mode="aspectFit"></image> |
|||
<text class="empty-text">暂无积分记录</text> |
|||
</view> |
|||
</scroll-view> |
|||
</view> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
return { |
|||
totalPoints: 0, |
|||
currentTab: "all", |
|||
pointsList: [], |
|||
page: 1, |
|||
pageSize: 20, |
|||
hasMore: true, |
|||
loading: false, |
|||
refreshing: false, |
|||
}; |
|||
}, |
|||
|
|||
onLoad() { |
|||
this.loadPointsData(); |
|||
this.getTotalPoints(); |
|||
}, |
|||
|
|||
methods: { |
|||
// 返回上一页 |
|||
goBack() { |
|||
uni.navigateBack(); |
|||
}, |
|||
|
|||
// 切换筛选标签 |
|||
switchTab(tab) { |
|||
if (this.currentTab === tab) return; |
|||
this.currentTab = tab; |
|||
this.resetData(); |
|||
this.loadPointsData(); |
|||
}, |
|||
|
|||
// 重置数据 |
|||
resetData() { |
|||
this.pointsList = []; |
|||
this.page = 1; |
|||
this.hasMore = true; |
|||
}, |
|||
|
|||
// 获取总积分 |
|||
async getTotalPoints() { |
|||
try { |
|||
this.Post({}, '/framework/points/getLastBalance', 'DES').then(res =>{ |
|||
if (res.code === 200) { |
|||
this.totalPoints = res.data || 0; |
|||
} |
|||
}) |
|||
|
|||
} catch (error) { |
|||
console.error("获取总积分失败:", error); |
|||
} |
|||
}, |
|||
|
|||
// 加载积分数据 |
|||
async loadPointsData() { |
|||
if (this.loading) return; |
|||
|
|||
this.loading = true; |
|||
|
|||
try { |
|||
const params = { |
|||
page: this.page, |
|||
pageSize: this.pageSize, |
|||
}; |
|||
|
|||
if (this.currentTab !== "all") { |
|||
params.fromType = this.currentTab; |
|||
} |
|||
|
|||
this.Post(params, '/framework/points/list', 'DES') |
|||
.then(res => { |
|||
console.log(res) |
|||
if (res.code === 200) { |
|||
const newData = res.rows || []; |
|||
|
|||
if (this.page === 1) { |
|||
this.pointsList = newData; |
|||
} else { |
|||
this.pointsList = [...this.pointsList, ...newData]; |
|||
} |
|||
|
|||
this.hasMore = newData.length === this.pageSize; |
|||
|
|||
if (this.hasMore) { |
|||
this.page++; |
|||
} |
|||
} else { |
|||
uni.showToast({ |
|||
title: res.msg || "加载失败", |
|||
icon: "none", |
|||
}); |
|||
} |
|||
}) |
|||
|
|||
|
|||
} catch (error) { |
|||
console.error("加载积分记录失败:", error); |
|||
uni.showToast({ |
|||
title: "网络错误,请重试", |
|||
icon: "none", |
|||
}); |
|||
} finally { |
|||
this.loading = false; |
|||
this.refreshing = false; |
|||
} |
|||
}, |
|||
|
|||
// 加载更多 |
|||
loadMore() { |
|||
if (this.hasMore && !this.loading) { |
|||
this.loadPointsData(); |
|||
} |
|||
}, |
|||
|
|||
// 下拉刷新 |
|||
onRefresh() { |
|||
this.refreshing = true; |
|||
this.resetData(); |
|||
this.loadPointsData(); |
|||
this.getTotalPoints(); |
|||
}, |
|||
|
|||
|
|||
|
|||
// 格式化时间 |
|||
formatTime(timestamp) { |
|||
const date = new Date(timestamp); |
|||
const now = new Date(); |
|||
const diff = now.getTime() - date.getTime(); |
|||
|
|||
// 今天 |
|||
if (diff < 24 * 60 * 60 * 1000 && now.getDate() === date.getDate()) { |
|||
return `今天 ${date.getHours().toString().padStart(2, "0")}:${date |
|||
.getMinutes() |
|||
.toString() |
|||
.padStart(2, "0")}`; |
|||
} |
|||
|
|||
// 昨天 |
|||
const yesterday = new Date(now.getTime() - 24 * 60 * 60 * 1000); |
|||
if (yesterday.getDate() === date.getDate()) { |
|||
return `昨天 ${date.getHours().toString().padStart(2, "0")}:${date |
|||
.getMinutes() |
|||
.toString() |
|||
.padStart(2, "0")}`; |
|||
} |
|||
|
|||
// 其他日期 |
|||
return `${date.getMonth() + 1}-${date.getDate()} ${date |
|||
.getHours() |
|||
.toString() |
|||
.padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`; |
|||
}, |
|||
}, |
|||
}; |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.points-detail-page { |
|||
min-height: 100vh; |
|||
background-color: #f5f5f5; |
|||
} |
|||
|
|||
/* 导航栏 */ |
|||
.nav-bar { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
height: 88rpx; |
|||
padding: 0 32rpx; |
|||
background-color: #fff; |
|||
border-bottom: 1rpx solid #eee; |
|||
} |
|||
|
|||
.nav-back { |
|||
width: 60rpx; |
|||
height: 60rpx; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
} |
|||
|
|||
.nav-back .iconfont { |
|||
font-size: 36rpx; |
|||
color: #333; |
|||
} |
|||
|
|||
.nav-title { |
|||
font-size: 36rpx; |
|||
font-weight: 600; |
|||
color: #333; |
|||
} |
|||
|
|||
.nav-placeholder { |
|||
width: 60rpx; |
|||
} |
|||
|
|||
/* 积分总览 */ |
|||
.points-overview { |
|||
background: linear-gradient(135deg, #77f3f9 0%, #764ba2 100%); |
|||
padding: 60rpx 32rpx; |
|||
text-align: center; |
|||
} |
|||
|
|||
.total-points { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
} |
|||
|
|||
.points-number { |
|||
font-size: 72rpx; |
|||
font-weight: bold; |
|||
color: #fff; |
|||
margin-bottom: 12rpx; |
|||
} |
|||
|
|||
.points-label { |
|||
font-size: 28rpx; |
|||
color: rgba(255, 255, 255, 0.8); |
|||
} |
|||
|
|||
/* 筛选标签 */ |
|||
.filter-tabs { |
|||
display: flex; |
|||
background-color: #fff; |
|||
padding: 0 32rpx; |
|||
} |
|||
|
|||
.tab-item { |
|||
flex: 1; |
|||
text-align: center; |
|||
padding: 32rpx 0; |
|||
font-size: 30rpx; |
|||
color: #666; |
|||
position: relative; |
|||
} |
|||
|
|||
.tab-item.active { |
|||
color: #77f3f9; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.tab-item.active::after { |
|||
content: ""; |
|||
position: absolute; |
|||
bottom: 0; |
|||
left: 50%; |
|||
transform: translateX(-50%); |
|||
width: 60rpx; |
|||
height: 4rpx; |
|||
background-color: #77f3f9; |
|||
border-radius: 2rpx; |
|||
} |
|||
|
|||
/* 积分记录列表 */ |
|||
.points-list { |
|||
height: calc(100vh - 368rpx); |
|||
padding: 0 30rpx; |
|||
width: 690rpx; |
|||
} |
|||
|
|||
.record-item { |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: space-between; |
|||
background-color: #fff; |
|||
padding: 32rpx 24rpx; |
|||
margin-top: 20rpx; |
|||
border-radius: 16rpx; |
|||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.05); |
|||
} |
|||
|
|||
.record-left { |
|||
display: flex; |
|||
align-items: center; |
|||
flex: 1; |
|||
} |
|||
|
|||
.record-icon { |
|||
width: 80rpx; |
|||
height: 80rpx; |
|||
border-radius: 50%; |
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
margin-right: 24rpx; |
|||
} |
|||
|
|||
.record-icon.income { |
|||
background-color: #e8f5e8; |
|||
} |
|||
|
|||
.record-icon.expense { |
|||
background-color: #ffeaea; |
|||
} |
|||
|
|||
.record-icon .iconfont { |
|||
font-size: 36rpx; |
|||
} |
|||
|
|||
.record-icon.income .iconfont { |
|||
color: #52c41a; |
|||
} |
|||
|
|||
.record-icon.expense .iconfont { |
|||
color: #ff4d4f; |
|||
} |
|||
|
|||
.record-info { |
|||
flex: 1; |
|||
} |
|||
|
|||
.record-title { |
|||
font-size: 32rpx; |
|||
color: #333; |
|||
font-weight: 500; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.record-desc { |
|||
font-size: 26rpx; |
|||
color: #999; |
|||
margin-bottom: 8rpx; |
|||
} |
|||
|
|||
.record-time { |
|||
font-size: 24rpx; |
|||
color: #ccc; |
|||
} |
|||
|
|||
.record-right { |
|||
text-align: right; |
|||
} |
|||
|
|||
.record-points { |
|||
font-size: 32rpx; |
|||
font-weight: 600; |
|||
} |
|||
|
|||
.record-points.income { |
|||
color: #52c41a; |
|||
} |
|||
|
|||
.record-points.expense { |
|||
color: #ff4d4f; |
|||
} |
|||
|
|||
/* 加载状态 */ |
|||
.load-more, |
|||
.no-more { |
|||
text-align: center; |
|||
padding: 40rpx 0; |
|||
} |
|||
|
|||
.load-text, |
|||
.no-more-text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
|
|||
/* 空状态 */ |
|||
.empty-state { |
|||
display: flex; |
|||
flex-direction: column; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 120rpx 0; |
|||
} |
|||
|
|||
.empty-icon { |
|||
width: 200rpx; |
|||
height: 200rpx; |
|||
margin-bottom: 32rpx; |
|||
opacity: 0.6; |
|||
} |
|||
|
|||
.empty-text { |
|||
font-size: 28rpx; |
|||
color: #999; |
|||
} |
|||
</style> |
Loading…
Reference in new issue