实施美团式的支付流程,并增强相关功能

- 将支付流程统一至礼品支付页面,禁止从阅读页面进行支付,以优化用户体验。
- 更新了礼物支付详情页面,为发起人和朋友展示了不同的用户界面元素,包括为发起人提供的分享按钮和为朋友提供的支付按钮。
- 增强了后端逻辑,以确保在支付处理过程中正确将收益归因于发起人。
- 增加了每日章节更新,并改进了章节页面的加载状态,以提升用户交互体验。
- 更新了文档,以反映新的支付流程和相关变更。
This commit is contained in:
Alex-larget
2026-03-17 12:15:08 +08:00
parent 0d12ab1d07
commit 601044ec60
30 changed files with 822 additions and 238 deletions

View File

@@ -10,7 +10,8 @@ Page({
requestSn: '',
detail: null,
loading: true,
paying: false
paying: false,
isInitiator: false // 是否发起人发起人看到「分享给好友」UI好友看到「帮他付款」
},
onLoad(options) {
@@ -32,7 +33,9 @@ Page({
try {
const res = await app.request(`/api/miniprogram/gift-pay/detail?requestSn=${encodeURIComponent(requestSn)}`)
if (res && res.success) {
this.setData({ detail: res, loading: false })
const myId = app.globalData.userInfo?.id || ''
const isInitiator = !!myId && res.initiatorUserId === myId
this.setData({ detail: res, loading: false, isInitiator })
} else {
this.setData({ loading: false })
wx.showToast({ title: res?.error || '加载失败', icon: 'none' })

View File

@@ -1,4 +1,4 @@
<!-- Soul创业派对 - 代付详情页 -->
<!-- Soul创业派对 - 代付详情页(美团式:发起人看到分享入口,好友看到帮他付款) -->
<view class="page">
<view class="nav-bar" style="padding-top: {{statusBarHeight}}px;">
<view class="nav-content">
@@ -6,7 +6,7 @@
<text class="back-arrow">←</text>
</view>
<view class="nav-info">
<text class="nav-title">帮他付款</text>
<text class="nav-title">{{isInitiator ? '找朋友代付' : '帮他付款'}}</text>
</view>
<view class="nav-right-placeholder"></view>
</view>
@@ -20,15 +20,22 @@
</view>
</block>
<block wx:elif="{{detail}}">
<!-- 营销:章节标题+内容预览,吸引代付人 -->
<view class="article-preview" wx:if="{{detail.sectionTitle || detail.contentPreview}}">
<text class="article-title">{{detail.sectionTitle || detail.description || '代付商品'}}</text>
<text class="article-content" wx:if="{{detail.contentPreview}}">{{detail.contentPreview}}</text>
</view>
<view class="card">
<view class="card-header">
<text class="card-title">代付订单</text>
<text class="initiator">{{detail.initiatorNickname || '好友'}} 请你帮忙付款</text>
<view class="card-badge">代付订单</view>
<text class="initiator" wx:if="{{!isInitiator}}">{{detail.initiatorNickname || '好友'}} 请你帮忙付款</text>
<text class="initiator" wx:else>分享给好友,好友帮你付款</text>
</view>
<view class="card-divider"></view>
<view class="card-body">
<view class="row">
<view class="row product-row" wx:if="{{!detail.contentPreview}}">
<text class="label">商品</text>
<text class="value">{{detail.description || '-'}}</text>
<text class="value product-desc">{{detail.sectionTitle || detail.description || '-'}}</text>
</view>
<view class="row amount-row">
<text class="label">金额</text>
@@ -36,12 +43,27 @@
</view>
</view>
</view>
<view class="tips">
<text>付款后,{{detail.initiatorNickname || '好友'}}将获得对应权益</text>
</view>
<button class="pay-btn" bindtap="doPay" disabled="{{paying}}">
{{paying ? '支付中...' : '帮他付款'}}
</button>
<!-- 发起人:分享给好友 -->
<block wx:if="{{isInitiator}}">
<view class="tips">
<text class="tips-icon">💡</text>
<text>分享给好友,好友打开后点击「帮他付款」即可为你代付</text>
</view>
<button class="pay-btn share-btn" open-type="share">
<image class="btn-icon-img" src="/assets/icons/share.svg" mode="aspectFit"/>
<text>分享给好友</text>
</button>
</block>
<!-- 好友:帮他付款 -->
<block wx:else>
<view class="tips">
<text class="tips-icon">✓</text>
<text>付款后,{{detail.initiatorNickname || '好友'}}将获得对应权益</text>
</view>
<button class="pay-btn" bindtap="doPay" disabled="{{paying}}">
{{paying ? '支付中...' : '帮他付款'}}
</button>
</block>
</block>
<block wx:else>
<view class="empty">

View File

@@ -1,7 +1,7 @@
/* Soul创业派对 - 代付详情页 */
.page {
min-height: 100vh;
background: #000;
background: linear-gradient(180deg, #0a0a0a 0%, #000 40%, #000 100%);
}
.nav-bar {
@@ -10,8 +10,10 @@
left: 0;
right: 0;
z-index: 100;
background: rgba(0, 0, 0, 0.9);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.08);
background: rgba(0, 0, 0, 0.92);
backdrop-filter: blur(20rpx);
-webkit-backdrop-filter: blur(20rpx);
border-bottom: 1rpx solid rgba(255, 255, 255, 0.06);
}
.nav-content {
@@ -26,25 +28,31 @@
width: 72rpx;
height: 72rpx;
border-radius: 50%;
background: #1c1c1e;
background: rgba(255, 255, 255, 0.06);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.2s;
}
.nav-back:active {
opacity: 0.7;
}
.back-arrow {
font-size: 36rpx;
color: rgba(255, 255, 255, 0.8);
color: rgba(255, 255, 255, 0.9);
}
.nav-title {
font-size: 32rpx;
font-size: 34rpx;
font-weight: 600;
color: #fff;
letter-spacing: 0.5rpx;
}
.content {
padding: 32rpx;
padding: 20rpx;
}
.loading-box {
@@ -58,7 +66,7 @@
.loading-spinner {
width: 48rpx;
height: 48rpx;
border: 4rpx solid rgba(0, 206, 209, 0.3);
border: 4rpx solid rgba(0, 206, 209, 0.2);
border-top-color: #00CED1;
border-radius: 50%;
animation: spin 0.8s linear infinite;
@@ -71,43 +79,86 @@
.loading-text {
margin-top: 24rpx;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
color: rgba(255, 255, 255, 0.45);
}
/* 营销:章节标题+内容预览,与订单卡片统一风格 */
.article-preview {
background: linear-gradient(145deg, #1a1a1c 0%, #141416 100%);
border-radius: 24rpx;
padding: 24rpx;
margin-bottom: 16rpx;
border: 1rpx solid rgba(0, 206, 209, 0.1);
}
.article-title {
display: block;
font-size: 30rpx;
font-weight: 600;
color: #fff;
line-height: 1.5;
margin-bottom: 12rpx;
}
.article-content {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
line-height: 1.65;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
}
/* 订单卡片:与文章预览统一圆角、边距 */
.card {
background: #1c1c1e;
background: linear-gradient(145deg, #1a1a1c 0%, #141416 100%);
border-radius: 24rpx;
overflow: hidden;
margin-bottom: 32rpx;
margin-bottom: 24rpx;
border: 1rpx solid rgba(0, 206, 209, 0.1);
}
.card-header {
padding: 32rpx;
border-bottom: 1rpx solid rgba(255, 255, 255, 0.06);
padding: 24rpx;
}
.card-title {
display: block;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
margin-bottom: 8rpx;
.card-badge {
display: inline-block;
font-size: 22rpx;
color: rgba(0, 206, 209, 0.9);
background: rgba(0, 206, 209, 0.08);
padding: 6rpx 14rpx;
border-radius: 8rpx;
margin-bottom: 12rpx;
letter-spacing: 0.5rpx;
}
.initiator {
font-size: 34rpx;
display: block;
font-size: 32rpx;
font-weight: 600;
color: #fff;
line-height: 1.4;
letter-spacing: 0.3rpx;
}
.card-divider {
height: 1rpx;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.08), transparent);
margin: 0 24rpx;
}
.card-body {
padding: 32rpx;
padding: 20rpx 24rpx 24rpx;
}
.row {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24rpx;
align-items: flex-start;
margin-bottom: 16rpx;
}
.row:last-child {
@@ -115,46 +166,99 @@
}
.label {
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
font-size: 26rpx;
color: rgba(255, 255, 255, 0.45);
flex-shrink: 0;
width: 80rpx;
}
.value {
.product-row .value {
flex: 1;
text-align: right;
font-size: 28rpx;
color: #fff;
color: rgba(255, 255, 255, 0.95);
line-height: 1.5;
word-break: break-all;
}
.product-desc {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.amount-row {
align-items: center;
}
.amount-row .amount {
font-size: 40rpx;
font-size: 44rpx;
font-weight: 700;
color: #00CED1;
letter-spacing: 1rpx;
text-shadow: 0 0 24rpx rgba(0, 206, 209, 0.3);
}
/* 提示文案 */
.tips {
padding: 0 8rpx 32rpx;
font-size: 24rpx;
color: rgba(255, 255, 255, 0.4);
display: flex;
align-items: flex-start;
gap: 10rpx;
padding: 0 4rpx 24rpx;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.5);
line-height: 1.5;
}
.tips-icon {
flex-shrink: 0;
font-size: 28rpx;
opacity: 0.8;
}
/* 主按钮 */
.pay-btn {
width: 100%;
height: 96rpx;
line-height: 96rpx;
background: linear-gradient(90deg, #00CED1 0%, #20B2AA 100%);
background: linear-gradient(135deg, #00CED1 0%, #18a8a8 50%, #20B2AA 100%);
color: #fff;
font-size: 32rpx;
font-size: 34rpx;
font-weight: 600;
border-radius: 48rpx;
border-radius: 50rpx;
border: none;
box-shadow: 0 8rpx 24rpx rgba(0, 206, 209, 0.35);
transition: opacity 0.2s, transform 0.1s;
}
.pay-btn:active {
opacity: 0.92;
transform: scale(0.99);
}
.pay-btn[disabled] {
opacity: 0.6;
transform: none;
}
.share-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
}
.btn-icon-img {
width: 40rpx;
height: 40rpx;
filter: brightness(0) invert(1);
}
.empty {
text-align: center;
padding: 120rpx 0;
font-size: 28rpx;
color: rgba(255, 255, 255, 0.5);
color: rgba(255, 255, 255, 0.45);
}

View File

@@ -50,7 +50,20 @@ Page({
}
},
goToDetail(e) {
const requestSn = e.currentTarget.dataset.sn
if (requestSn) {
wx.navigateTo({ url: `/pages/gift-pay/detail?requestSn=${encodeURIComponent(requestSn)}` })
}
},
shareRequest(e) {
e.stopPropagation()
wx.showToast({ title: '请点击右上角「...」分享给好友', icon: 'none', duration: 2500 })
},
async cancelRequest(e) {
e.stopPropagation()
const requestSn = e.currentTarget.dataset.sn
if (!requestSn) return
const ok = await new Promise(r => {
@@ -74,11 +87,6 @@ Page({
}
},
shareRequest(e) {
const requestSn = e.currentTarget.dataset.sn
wx.showToast({ title: '请点击右上角「...」分享给好友', icon: 'none', duration: 2500 })
},
goBack() {
app.goBackOrToHome()
},

View File

@@ -29,7 +29,7 @@
<view class="empty">暂无发起的代付</view>
</block>
<block wx:else>
<view class="card" wx:for="{{requests}}" wx:key="requestSn">
<view class="card" wx:for="{{requests}}" wx:key="requestSn" bindtap="goToDetail" data-sn="{{item.requestSn}}">
<view class="card-row">
<text class="desc">{{item.description}}</text>
<text class="amount">¥{{item.amount}}</text>
@@ -49,7 +49,7 @@
<view class="empty">暂无帮付记录</view>
</block>
<block wx:else>
<view class="card" wx:for="{{payments}}" wx:key="requestSn">
<view class="card" wx:for="{{payments}}" wx:key="requestSn" bindtap="goToDetail" data-sn="{{item.requestSn}}">
<view class="card-row">
<text class="desc">{{item.description}}</text>
<text class="amount">¥{{item.amount}}</text>