feat(M08-A): 接入顾客端充值入口
This commit is contained in:
@@ -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 })
|
||||
}
|
||||
},
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"navigationBarTitleText": "余额充值"
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user