Files
ngele c4ca8a87fa feat: 同步签约宝手机端功能到签约宝页面
- sign页面与签约宝精简版对齐:查看合同入口、AI积分区块(合同审查/我的报告/积分充值)
- 新增pages/ai/{points,review,reports}三个页面(与签约宝精简版一致)
- pages.json注册AI页面路由
2026-10-23 19:57:27 +08:00

243 lines
5.6 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="page-wrap">
<uititle title="积分管理"></uititle>
<!-- 积分概览 -->
<view class="points-header">
<view class="ph-card main">
<view class="ph-label">可用积分</view>
<view class="ph-value">{{ pointsBalance }}</view>
</view>
<view class="ph-card sub">
<view class="ph-label">累计获得</view>
<view class="ph-value">{{ pointsTotalEarned }}</view>
</view>
</view>
<!-- 充值套餐 -->
<view class="section-title">💎 积分充值</view>
<view class="recharge-grid">
<view v-for="(pkg, i) in rechargePackages" :key="i"
:class="['recharge-card', selectedRecharge === i && 'selected']"
@click="selectedRecharge = i">
<view class="rc-points">{{ pkg.points }}</view>
<view class="rc-price">{{ pkg.price }}</view>
<view v-if="pkg.bonus" class="rc-bonus">{{ pkg.bonus }}</view>
</view>
</view>
<view class="p-20">
<u-button type="primary" shape="circle" @click="doRecharge">
立即充值 {{ rechargePackages[selectedRecharge].price }}({{ rechargePackages[selectedRecharge].points }} 积分)
</u-button>
</view>
<!-- 积分明细 -->
<view class="section-title">📊 积分明细</view>
<view v-if="pointsLogList.length === 0" class="empty-tip">暂无积分记录</view>
<view v-for="(item, i) in pointsLogList" :key="i" class="log-item">
<view class="log-left">
<view class="log-reason">{{ item.reason }}</view>
<view class="log-time">{{ item._add_time_str }}</view>
</view>
<view :class="['log-amount', item.type === 'earn' ? 'green' : 'red']">
{{ item.type === 'earn' ? '+' : '-' }}{{ Math.abs(item.amount) }}
</view>
</view>
</view>
</template>
<script>
import uititle from '@/components/common/title'
import dayjs from 'dayjs'
export default {
components: { uititle },
data() {
return {
pointsBalance: 0,
pointsTotalEarned: 0,
pointsLogList: [],
selectedRecharge: 1,
rechargePackages: [
{ points: 10000, price: '20元', bonus: '' },
{ points: 50000, price: '100元', bonus: '' },
{ points: 100000, price: '200元', bonus: '' },
{ points: 450000, price: '900元', bonus: '' },
{ points: 1000000, price: '2000元', bonus: '' },
{ points: 2000000, price: '4000元', bonus: '' },
]
}
},
onShow() {
this.getPointsBalance()
this.getPointsLog()
},
methods: {
async getPointsBalance() {
const res = await vk.callFunction({ url: 'client/points/kh/getBalance' })
if (res.code === 0 && res.data) {
this.pointsBalance = res.data.balance || 0
this.pointsTotalEarned = res.data.total_earned || 0
}
},
async getPointsLog() {
const res = await vk.callFunction({
url: 'client/points/kh/getLog',
data: { pageIndex: 1, pageSize: 50 }
})
if (res.code === 0 && res.data) {
this.pointsLogList = (res.data.rows || []).map(r => ({
...r,
_add_time_str: dayjs(r._add_time && r._add_time['$date'] ? r._add_time['$date'] : r._add_time).format('YYYY-MM-DD HH:mm')
}))
}
},
async doRecharge() {
const pkg = this.rechargePackages[this.selectedRecharge]
const priceMap = {
'20元': 2000, '100元': 10000, '200元': 20000,
'900元': 90000, '2000元': 200000, '4000元': 400000
}
const price = priceMap[pkg.price] || 2000
const res = await vk.callFunction({
url: 'client/points/kh/createOrder',
data: { points: pkg.points, price }
})
if (res.code === 0 && res.data) {
uni.navigateTo({ url: '/pages/shop/pay?id=' + res.data })
} else {
uni.showToast({ title: res.msg || '创建订单失败', icon: 'none' })
}
}
}
}
</script>
<style lang="scss" scoped>
.page-wrap {
min-height: 100vh;
background: #f5f5f5;
}
.points-header {
display: flex;
gap: 20rpx;
padding: 30rpx;
}
.ph-card {
flex: 1;
padding: 30rpx;
border-radius: 16rpx;
color: #fff;
text-align: center;
}
.ph-card.main {
background: linear-gradient(135deg, #a92924, #d4574e);
}
.ph-card.sub {
background: linear-gradient(135deg, #333, #666);
}
.ph-label {
font-size: 24rpx;
opacity: 0.85;
}
.ph-value {
font-size: 48rpx;
font-weight: 700;
margin-top: 8rpx;
}
.section-title {
font-size: 30rpx;
font-weight: 600;
padding: 20rpx 30rpx 10rpx;
}
.recharge-grid {
display: flex;
flex-wrap: wrap;
gap: 12rpx;
padding: 0 30rpx;
}
.recharge-card {
flex: 0 0 calc(33.33% - 12rpx);
padding: 24rpx 0;
text-align: center;
border: 2rpx solid #e0e0e0;
border-radius: 12rpx;
background: #fff;
position: relative;
}
.recharge-card.selected {
border-color: #a92924;
background: #fdf0f0;
}
.rc-points {
font-size: 32rpx;
font-weight: 700;
color: #333;
}
.rc-price {
font-size: 24rpx;
color: #999;
margin-top: 4rpx;
}
.rc-bonus {
position: absolute;
top: -2rpx;
right: -2rpx;
background: #a92924;
color: #fff;
font-size: 18rpx;
padding: 2rpx 10rpx;
border-radius: 0 10rpx 0 10rpx;
}
.log-item {
display: flex;
align-items: center;
padding: 24rpx 30rpx;
background: #fff;
border-bottom: 1rpx solid #f0f0f0;
}
.log-left {
flex: 1;
}
.log-reason {
font-size: 28rpx;
color: #333;
}
.log-time {
font-size: 22rpx;
color: #999;
margin-top: 4rpx;
}
.log-amount {
font-size: 32rpx;
font-weight: 600;
}
.log-amount.green { color: #67c23a; }
.log-amount.red { color: #f56c6c; }
.empty-tip {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 26rpx;
}
</style>