first commit
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* 订阅支付页
|
||||
* 接收参数:channelId, channelName, monthlyPrice, quarterlyPrice, annualPrice
|
||||
*/
|
||||
const app = getApp()
|
||||
const api = require('../../utils/api')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
channelId: '',
|
||||
channelName: '',
|
||||
monthlyPrice: 0,
|
||||
quarterlyPrice: 0,
|
||||
annualPrice: 0,
|
||||
selectedPlan: '', // 'monthly' | 'quarterly' | 'annual'
|
||||
currentPrice: 0
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 后端价格单位为「分」,除以 100 转为「元」
|
||||
const monthly = (parseFloat(options.monthlyPrice) || 0) / 100
|
||||
const quarterly = (parseFloat(options.quarterlyPrice) || 0) / 100
|
||||
const annual = (parseFloat(options.annualPrice) || 0) / 100
|
||||
|
||||
// 默认选中"包年"(如果有),否则最便宜的
|
||||
let defaultPlan = ''
|
||||
let defaultPrice = 0
|
||||
if (annual > 0) {
|
||||
defaultPlan = 'annual'
|
||||
defaultPrice = annual
|
||||
} else if (quarterly > 0) {
|
||||
defaultPlan = 'quarterly'
|
||||
defaultPrice = quarterly
|
||||
} else if (monthly > 0) {
|
||||
defaultPlan = 'monthly'
|
||||
defaultPrice = monthly
|
||||
}
|
||||
|
||||
this.setData({
|
||||
channelId: options.channelId || '',
|
||||
channelName: decodeURIComponent(options.channelName || ''),
|
||||
monthlyPrice: monthly,
|
||||
quarterlyPrice: quarterly,
|
||||
annualPrice: annual,
|
||||
selectedPlan: defaultPlan,
|
||||
currentPrice: defaultPrice,
|
||||
// 预计算节省金额和月均价(WXML 不支持 .toFixed())
|
||||
_quarterlySaving: monthly > 0 && quarterly > 0 ? Math.round(monthly * 3 - quarterly) : 0,
|
||||
_quarterlyMonthly: quarterly > 0 ? (quarterly / 3).toFixed(1) : '0',
|
||||
_annualSaving: monthly > 0 && annual > 0 ? Math.round(monthly * 12 - annual) : 0,
|
||||
_annualMonthly: annual > 0 ? (annual / 12).toFixed(1) : '0'
|
||||
})
|
||||
},
|
||||
|
||||
/** 选择套餐 */
|
||||
selectPlan(e) {
|
||||
const plan = e.currentTarget.dataset.plan
|
||||
const priceMap = {
|
||||
monthly: this.data.monthlyPrice,
|
||||
quarterly: this.data.quarterlyPrice,
|
||||
annual: this.data.annualPrice
|
||||
}
|
||||
this.setData({
|
||||
selectedPlan: plan,
|
||||
currentPrice: priceMap[plan] || 0
|
||||
})
|
||||
},
|
||||
|
||||
/** 发起支付 */
|
||||
onPay() {
|
||||
const { channelId, selectedPlan, currentPrice, channelName } = this.data
|
||||
|
||||
if (!selectedPlan) {
|
||||
wx.showToast({ title: '请选择订阅方案', icon: 'none' })
|
||||
return
|
||||
}
|
||||
|
||||
// 调用订阅/支付接口
|
||||
wx.showLoading({ title: '处理中...' })
|
||||
api.subscribeChannel({
|
||||
channelId,
|
||||
plan: selectedPlan,
|
||||
price: currentPrice
|
||||
}).then(function (res) {
|
||||
wx.hideLoading()
|
||||
if (res.code === 200) {
|
||||
wx.showToast({ title: '订阅成功!', icon: 'success' })
|
||||
setTimeout(function () {
|
||||
wx.navigateBack()
|
||||
}, 1500)
|
||||
} else {
|
||||
wx.showToast({ title: res.msg || '订阅失败', icon: 'none' })
|
||||
}
|
||||
}).catch(function (err) {
|
||||
wx.hideLoading()
|
||||
console.error('[订阅] 失败:', err)
|
||||
wx.showToast({ title: '网络异常,请重试', icon: 'none' })
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"usingComponents": {
|
||||
"t-icon": "tdesign-miniprogram/icon/icon",
|
||||
"t-tag": "tdesign-miniprogram/tag/tag"
|
||||
},
|
||||
"navigationBarTitleText": "订阅频道"
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<!-- 订阅支付页 -->
|
||||
<page-meta page-style="overflow: hidden;" />
|
||||
<view class="subscribe-page">
|
||||
|
||||
<!-- 顶部频道信息 -->
|
||||
<view class="channel-card">
|
||||
<view class="channel-avatar">
|
||||
<text class="channel-avatar-emoji">📻</text>
|
||||
</view>
|
||||
<text class="channel-title">{{channelName}}</text>
|
||||
<text class="channel-desc">选择适合你的订阅方案</text>
|
||||
</view>
|
||||
|
||||
<!-- 价格套餐选择 -->
|
||||
<view class="plans-wrap">
|
||||
<!-- 包月 -->
|
||||
<view
|
||||
wx:if="{{monthlyPrice > 0}}"
|
||||
class="plan-card {{selectedPlan === 'monthly' ? 'selected' : ''}}"
|
||||
bindtap="selectPlan"
|
||||
data-plan="monthly"
|
||||
>
|
||||
<view class="plan-top">
|
||||
<text class="plan-name">包月</text>
|
||||
<view class="plan-badge" wx:if="{{selectedPlan === 'monthly'}}">
|
||||
<t-icon name="check-circle-filled" size="36rpx" color="#FF9D42" />
|
||||
</view>
|
||||
</view>
|
||||
<text class="plan-price">¥{{monthlyPrice}}</text>
|
||||
<text class="plan-unit">/ 月</text>
|
||||
</view>
|
||||
|
||||
<!-- 包季 -->
|
||||
<view
|
||||
wx:if="{{quarterlyPrice > 0}}"
|
||||
class="plan-card {{selectedPlan === 'quarterly' ? 'selected' : ''}}"
|
||||
bindtap="selectPlan"
|
||||
data-plan="quarterly"
|
||||
>
|
||||
<view class="plan-top">
|
||||
<text class="plan-name">包季</text>
|
||||
<t-tag wx:if="{{quarterlyPrice > 0 && monthlyPrice > 0}}" size="small" variant="filled" theme="success">省{{_quarterlySaving}}元</t-tag>
|
||||
<view class="plan-badge" wx:if="{{selectedPlan === 'quarterly'}}">
|
||||
<t-icon name="check-circle-filled" size="36rpx" color="#FF9D42" />
|
||||
</view>
|
||||
</view>
|
||||
<text class="plan-price">¥{{quarterlyPrice}}</text>
|
||||
<text class="plan-unit">/ 季 · 约¥{{_quarterlyMonthly}}/月</text>
|
||||
</view>
|
||||
|
||||
<!-- 包年 -->
|
||||
<view
|
||||
wx:if="{{annualPrice > 0}}"
|
||||
class="plan-card popular {{selectedPlan === 'annual' ? 'selected' : ''}}"
|
||||
bindtap="selectPlan"
|
||||
data-plan="annual"
|
||||
>
|
||||
<view class="plan-hot-tag">最受欢迎</view>
|
||||
<view class="plan-top">
|
||||
<text class="plan-name">包年</text>
|
||||
<t-tag wx:if="{{annualPrice > 0 && monthlyPrice > 0}}" size="small" variant="filled" theme="success">省{{_annualSaving}}元</t-tag>
|
||||
<view class="plan-badge" wx:if="{{selectedPlan === 'annual'}}">
|
||||
<t-icon name="check-circle-filled" size="36rpx" color="#FF9D42" />
|
||||
</view>
|
||||
</view>
|
||||
<text class="plan-price">¥{{annualPrice}}</text>
|
||||
<text class="plan-unit">/ 年 · 约¥{{_annualMonthly}}/月</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 权益说明 -->
|
||||
<view class="benefits">
|
||||
<view class="benefit-item">
|
||||
<t-icon name="check" size="28rpx" color="#FF9D42" />
|
||||
<text>订阅后可无限收听该频道所有节目</text>
|
||||
</view>
|
||||
<view class="benefit-item">
|
||||
<t-icon name="check" size="28rpx" color="#FF9D42" />
|
||||
<text>后台播放,边听边做其他事</text>
|
||||
</view>
|
||||
<view class="benefit-item">
|
||||
<t-icon name="check" size="28rpx" color="#FF9D42" />
|
||||
<text>新节目第一时间推送通知</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部支付按钮 -->
|
||||
<view class="pay-bar">
|
||||
<view class="pay-amount" wx:if="{{selectedPlan}}">
|
||||
<text class="pay-label">合计</text>
|
||||
<text class="pay-price">¥{{currentPrice}}</text>
|
||||
</view>
|
||||
<view class="pay-btn tap-active" bindtap="onPay">
|
||||
<text>立即订阅</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
@@ -0,0 +1,147 @@
|
||||
/* 订阅支付页 */
|
||||
.subscribe-page {
|
||||
min-height: 100vh;
|
||||
background: #F6F6F6;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-bottom: 160rpx;
|
||||
}
|
||||
|
||||
/* 顶部频道卡片 */
|
||||
.channel-card {
|
||||
background: linear-gradient(135deg, #FF9D42, #FF7832);
|
||||
padding: 60rpx 40rpx 48rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
.channel-avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
background: rgba(255, 255, 255, 0.25);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
.channel-avatar-emoji { font-size: 56rpx; }
|
||||
.channel-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: 800;
|
||||
color: #FFF;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
.channel-desc {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
|
||||
/* 套餐区域 */
|
||||
.plans-wrap {
|
||||
padding: 32rpx 32rpx 20rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20rpx;
|
||||
}
|
||||
.plan-card {
|
||||
background: #FFF;
|
||||
border-radius: 28rpx;
|
||||
padding: 32rpx 36rpx;
|
||||
border: 3rpx solid transparent;
|
||||
position: relative;
|
||||
transition: all 0.2s;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0,0,0,0.04);
|
||||
}
|
||||
.plan-card.selected {
|
||||
border-color: #FF9D42;
|
||||
background: #FFFAF5;
|
||||
}
|
||||
.plan-card.popular {
|
||||
border-color: #FFD580;
|
||||
}
|
||||
.plan-card.popular.selected {
|
||||
border-color: #FF9D42;
|
||||
}
|
||||
/* 最受欢迎标签 */
|
||||
.plan-hot-tag {
|
||||
position: absolute;
|
||||
top: -20rpx;
|
||||
left: 36rpx;
|
||||
background: linear-gradient(135deg, #FF9D42, #FF7832);
|
||||
color: #FFF;
|
||||
font-size: 20rpx;
|
||||
font-weight: 700;
|
||||
padding: 6rpx 20rpx;
|
||||
border-radius: 999rpx;
|
||||
}
|
||||
.plan-top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
.plan-name {
|
||||
font-size: 28rpx;
|
||||
font-weight: 700;
|
||||
color: #222;
|
||||
flex: 1;
|
||||
}
|
||||
.plan-badge { margin-left: auto; }
|
||||
.plan-price {
|
||||
font-size: 52rpx;
|
||||
font-weight: 800;
|
||||
color: #FF7832;
|
||||
line-height: 1;
|
||||
}
|
||||
.plan-unit {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
margin-top: 6rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* 权益说明 */
|
||||
.benefits {
|
||||
margin: 0 32rpx;
|
||||
background: #FFF;
|
||||
border-radius: 24rpx;
|
||||
padding: 28rpx 32rpx;
|
||||
}
|
||||
.benefit-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
margin-bottom: 18rpx;
|
||||
font-size: 26rpx;
|
||||
color: #444;
|
||||
}
|
||||
.benefit-item:last-child { margin-bottom: 0; }
|
||||
|
||||
/* 底部支付栏 */
|
||||
.pay-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #FFF;
|
||||
padding: 20rpx 32rpx 48rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
border-top: 1rpx solid #F0F0F0;
|
||||
box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
.pay-amount { flex: 1; }
|
||||
.pay-label { font-size: 22rpx; color: #999; display: block; }
|
||||
.pay-price { font-size: 44rpx; font-weight: 800; color: #FF7832; line-height: 1; }
|
||||
.pay-btn {
|
||||
background: linear-gradient(135deg, #FF9D42, #FF7832);
|
||||
color: #FFF;
|
||||
font-size: 30rpx;
|
||||
font-weight: 700;
|
||||
padding: 24rpx 64rpx;
|
||||
border-radius: 999rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(255, 120, 50, 0.35);
|
||||
}
|
||||
.pay-btn:active { transform: scale(0.96); opacity: 0.9; }
|
||||
Reference in New Issue
Block a user