feat(M08-A): 接入顾客端充值入口

This commit is contained in:
Codex
2026-06-25 11:51:02 +08:00
parent cb1109f387
commit dbdfe3dfca
14 changed files with 489 additions and 2 deletions
+90
View File
@@ -0,0 +1,90 @@
const {
request,
ensureLogin,
cents,
clientRequestId,
} = require('../../utils/api.js')
Page({
data: {
loading: false,
errorMessage: '',
successMessage: '',
plans: [],
selectedPlanId: '',
rechargeOrder: null,
},
onLoad() {
this.loadPlans()
},
async loadPlans() {
this.setData({ loading: true, errorMessage: '', successMessage: '' })
try {
await ensureLogin()
const response = await request('/recharge/plans')
const plans = (response.data || []).map((item) => ({
...item,
payText: cents(item.payAmountCents),
giftText: cents(item.giftAmountCents),
totalText: cents(Number(item.payAmountCents || 0) + Number(item.giftAmountCents || 0)),
}))
this.setData({
plans,
selectedPlanId: plans[0]?.planId || '',
})
} catch (error) {
this.setData({ errorMessage: error.message || '充值计划加载失败' })
} finally {
this.setData({ loading: false })
}
},
selectPlan(event) {
this.setData({
selectedPlanId: event.currentTarget.dataset.planId || '',
rechargeOrder: null,
errorMessage: '',
successMessage: '',
})
},
async createRechargeOrder() {
if (!this.data.selectedPlanId) {
this.setData({ errorMessage: '请选择充值计划' })
return
}
const plan = this.data.plans.find((item) => item.planId === this.data.selectedPlanId)
await this.withRequest(async () => {
const response = await request('/recharge/orders', {
method: 'POST',
data: {
planId: this.data.selectedPlanId,
storeId: plan?.storeId || null,
clientRequestId: clientRequestId('miniapp-recharge'),
},
})
this.setData({
rechargeOrder: {
...response.data,
payText: cents(response.data.payAmountCents),
giftText: cents(response.data.giftAmountCents),
},
successMessage: '充值单已创建',
})
})
},
async withRequest(work) {
this.setData({ loading: true, errorMessage: '', successMessage: '' })
try {
await ensureLogin()
await work()
} catch (error) {
this.setData({ errorMessage: error.message || '充值操作失败' })
} finally {
this.setData({ loading: false })
}
},
})
+3
View File
@@ -0,0 +1,3 @@
{
"navigationBarTitleText": "余额充值"
}
+35
View File
@@ -0,0 +1,35 @@
<scroll-view class="scrollarea" scroll-y type="list">
<view class="page">
<view class="title">余额充值</view>
<view wx:if="{{errorMessage}}" class="error">{{errorMessage}}</view>
<view wx:if="{{successMessage}}" class="success">{{successMessage}}</view>
<view wx:if="{{!loading && plans.length === 0}}" class="empty">暂无可用充值计划</view>
<view wx:for="{{plans}}" wx:key="planId" class="plan {{selectedPlanId === item.planId ? 'selected' : ''}}" bindtap="selectPlan" data-plan-id="{{item.planId}}">
<view class="plan-title">{{item.name}}</view>
<view class="row">
<text>实付</text>
<text>{{item.payText}}</text>
</view>
<view class="row">
<text>赠送</text>
<text>{{item.giftText}}</text>
</view>
<view class="row total">
<text>到账</text>
<text>{{item.totalText}}</text>
</view>
</view>
<button loading="{{loading}}" bindtap="createRechargeOrder">创建充值单</button>
<view wx:if="{{rechargeOrder}}" class="card">
<view class="section-title">充值单</view>
<view class="muted">单号:{{rechargeOrder.rechargeNo}}</view>
<view class="muted">状态:{{rechargeOrder.status}}</view>
<view class="muted">实付:{{rechargeOrder.payText}}</view>
<view class="muted">赠送:{{rechargeOrder.giftText}}</view>
</view>
</view>
</scroll-view>
+71
View File
@@ -0,0 +1,71 @@
.scrollarea {
height: 100vh;
background: #f5f6f8;
}
.page {
padding: 32rpx;
}
.title {
margin-bottom: 24rpx;
font-size: 40rpx;
font-weight: 600;
}
.plan,
.card {
margin-top: 20rpx;
padding: 28rpx;
border: 2rpx solid transparent;
border-radius: 16rpx;
background: #ffffff;
}
.selected {
border-color: #1f6feb;
background: #f0f6ff;
}
.plan-title,
.section-title {
font-size: 32rpx;
font-weight: 600;
}
.row {
display: flex;
justify-content: space-between;
margin-top: 16rpx;
color: #475467;
}
.total {
color: #b42318;
font-weight: 700;
}
button {
margin-top: 24rpx;
}
.muted {
margin-top: 8rpx;
color: #667085;
}
.success {
margin: 16rpx 0;
color: #17823b;
}
.error {
margin: 16rpx 0;
color: #c73535;
}
.empty {
padding: 80rpx 0;
color: #888888;
text-align: center;
}