459 lines
11 KiB
Vue
459 lines
11 KiB
Vue
<template>
|
||
<view class="app-container">
|
||
<HeaderBar
|
||
title="购买会员"
|
||
enable-back
|
||
text-align="center"
|
||
/>
|
||
|
||
<!-- 会员状态卡片 -->
|
||
<view class="vip-card">
|
||
<view style="flex: 1">
|
||
<view class="vip-title-row">
|
||
<image class="vip-icon" src="https://api.ccttiot.com/Vector-1746435740006.png" mode="aspectFit" />
|
||
<text class="vip-status">{{VipLevel.getName(mch.vipLevel)}}</text>
|
||
</view>
|
||
<view class="vip-desc" v-if="mch.vipLevel === VipLevel.VIP0">解锁会员获得更多权益</view>
|
||
<view class="vip-desc" v-if="[VipLevel.VIP1, VipLevel.VIP2].includes(mch.vipLevel)">普通会员有效期至 {{mch.vip1Time | dv}}</view>
|
||
<view class="vip-desc" v-if="mch.vipLevel === VipLevel.VIP2">高级会员有效期至 {{mch.vip2Time | dv}}</view>
|
||
</view>
|
||
<view class="record-btn" @tap="onViewRecords">
|
||
<text>购买记录</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 会员选择区域 -->
|
||
<view class="vip-select">
|
||
<view class="section-title">选择会员</view>
|
||
<view class="vip-options">
|
||
<view
|
||
v-for="(item, index) in vipPriceList"
|
||
class="vip-option"
|
||
:class="{'active': selectedVip === index}"
|
||
@tap="handleSelectVip(index)"
|
||
>
|
||
<view class="vip-option-title">{{VipLevel.getName(item.vipLevel)}}</view>
|
||
<view class="vip-option-duration">{{item.days | dv}}天</view>
|
||
<view class="vip-option-price">¥{{item.price | fix2 | dv}}</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 会员权益对比 -->
|
||
<view class="vip-compare">
|
||
<view class="section-title">会员权益对比</view>
|
||
<view class="compare-table">
|
||
<view class="compare-header">
|
||
<view class="compare-cell">项目</view>
|
||
<view class="compare-cell">无会员</view>
|
||
<view class="compare-cell">普通会员</view>
|
||
<view class="compare-cell highlight">高级会员</view>
|
||
</view>
|
||
<view class="compare-row">
|
||
<view class="compare-cell">查看任务</view>
|
||
<view class="compare-cell">10分钟后</view>
|
||
<view class="compare-cell">5分钟后</view>
|
||
<view class="compare-cell highlight">立即查看</view>
|
||
</view>
|
||
<view class="compare-row">
|
||
<view class="compare-cell">客服服务</view>
|
||
<view class="compare-cell">较慢</view>
|
||
<view class="compare-cell">优先回复</view>
|
||
<view class="compare-cell highlight">专属客服</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 会员服务说明 -->
|
||
<view class="vip-notice">
|
||
<view class="notice-title">会员服务说明</view>
|
||
<view class="notice-content">
|
||
<view class="notice-item">1. 会员服务有效期自购买成功后开始计算</view>
|
||
<view class="notice-item">2. 若您获得了高级会员服务,您将同时获得同等时长的普通会员服务时长</view>
|
||
<view class="notice-item">3. 会员服务不支持退款,请谨慎购买</view>
|
||
<view class="notice-item">4. 会员服务仅限本账号使用,不可转让</view>
|
||
<view class="notice-example">
|
||
<view class="example-title">举例说明:</view>
|
||
<view class="example-content">
|
||
假设您的普通会员有效期至2022年8月1日,高级会员有效期至2022年7月1日。当您开通了1张高级会员30天卡后:
|
||
<view class="example-item">• 您的高级会员有效期将延长至2022年7月31日</view>
|
||
<view class="example-item">• 您的普通会员有效期将同时延长至2022年8月30日</view>
|
||
<view class="example-item">• 在2022年7月31日前,您将享有高级会员的会员服务内容</view>
|
||
<view class="example-item">• 高级会员到期后,在2022年8月30日前,您仍将享有普通会员的会员服务内容</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部购买按钮 -->
|
||
<view class="bottom-bar">
|
||
<view class="price-info">
|
||
<text>实付金额:</text>
|
||
<text class="price">¥{{vipPriceList[selectedVip].price | fix2 | dv}}</text>
|
||
</view>
|
||
<button class="buy-btn" @click="handleBuy">立即购买</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import HeaderBar from '@/components/HeaderBar.vue'
|
||
import { VipLevel } from '@/utils/enums'
|
||
import {mchCreateVipOrder, mchGetVipPrice} from '@/api/mch/vipOrder'
|
||
import { getMchDetail } from '@/api/app/mch'
|
||
import { mapGetters } from 'vuex'
|
||
import config from '@/config'
|
||
import { appRefreshPayResult } from '@/api/app/pay'
|
||
|
||
export default {
|
||
components: {
|
||
HeaderBar
|
||
},
|
||
data() {
|
||
return {
|
||
VipLevel,
|
||
selectedVip: 0,
|
||
mch: {
|
||
vipLevel: null,
|
||
vipTime: null
|
||
},
|
||
vipPriceList: []
|
||
}
|
||
},
|
||
computed: {
|
||
...mapGetters(['mchId'])
|
||
},
|
||
onShow() {
|
||
this.getMchInfo();
|
||
this.getAllVipPrice();
|
||
},
|
||
methods: {
|
||
getAllVipPrice() {
|
||
mchGetVipPrice().then(res => {
|
||
this.vipPriceList = res.data;
|
||
})
|
||
},
|
||
getMchInfo() {
|
||
getMchDetail(this.mchId).then(res => {
|
||
this.mch = res.data
|
||
})
|
||
},
|
||
handleSelectVip(index) {
|
||
this.selectedVip = index;
|
||
},
|
||
handleBuy() {
|
||
let vip = this.vipPriceList[this.selectedVip]
|
||
this.$modal.loading('支付中');
|
||
mchCreateVipOrder({
|
||
mchId: this.mchId,
|
||
vipLevel: vip.vipLevel,
|
||
days: vip.days,
|
||
amount: vip.price,
|
||
appId: config.appId,
|
||
channelId: config.channelId
|
||
}).then(res => {
|
||
let payParams = res.data.payParams
|
||
wx.requestPayment({
|
||
timeStamp: payParams.timeStamp,
|
||
nonceStr: payParams.nonceStr,
|
||
package: payParams.packageVal,
|
||
signType: payParams.signType,
|
||
paySign: payParams.paySign,
|
||
success: () => {
|
||
this.$modal.loading("查询支付结果")
|
||
appRefreshPayResult().finally(() => {
|
||
setTimeout(() => {
|
||
this.getMchInfo();
|
||
this.$modal.closeLoading();
|
||
}, 3000)
|
||
})
|
||
},
|
||
fail: () => {
|
||
this.$modal.closeLoading();
|
||
}
|
||
})
|
||
}).catch(() => {
|
||
this.$modal.closeLoading();
|
||
})
|
||
},
|
||
onViewRecords() {
|
||
uni.navigateTo({
|
||
url: '/pages/vip/index'
|
||
})
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.app-container {
|
||
padding-bottom: 120rpx;
|
||
}
|
||
|
||
.vip-card {
|
||
display: flex;
|
||
align-items: center;
|
||
background: linear-gradient(90deg, #F1E5CC 0%, #F3D8C0 39.42%, #F5F0EA 100%);
|
||
border-radius: 20rpx;
|
||
margin: 32rpx;
|
||
padding: 24rpx 48rpx;
|
||
position: relative;
|
||
|
||
.vip-title-row {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 24rpx;
|
||
flex: 1;
|
||
|
||
.vip-icon {
|
||
width: 32rpx;
|
||
height: 32rpx;
|
||
margin-right: 12rpx;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.vip-status {
|
||
color: #000;
|
||
font-size: 28rpx;
|
||
}
|
||
}
|
||
|
||
.vip-desc {
|
||
position: relative;
|
||
color: #888;
|
||
font-size: 24rpx;
|
||
white-space: pre-line;
|
||
}
|
||
|
||
.record-btn {
|
||
font-size: 28rpx;
|
||
color: #6a8cff;
|
||
padding: 12rpx 24rpx;
|
||
margin-left: 24rpx;
|
||
}
|
||
}
|
||
|
||
.vip-select {
|
||
margin: 32rpx;
|
||
|
||
.section-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.vip-options {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 24rpx;
|
||
|
||
.vip-option {
|
||
flex: 1;
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
padding: 32rpx;
|
||
text-align: center;
|
||
border: 2rpx solid #eee;
|
||
transition: all 0.3s;
|
||
|
||
&.active {
|
||
border-color: #6a8cff;
|
||
background: rgba(106, 140, 255, 0.05);
|
||
}
|
||
|
||
.vip-option-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.vip-option-duration {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.vip-option-price {
|
||
font-size: 36rpx;
|
||
color: #6a8cff;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.vip-compare {
|
||
margin: 32rpx;
|
||
|
||
.compare-table {
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
border: 2rpx solid #eee;
|
||
overflow: hidden;
|
||
margin-top: 24rpx;
|
||
|
||
.compare-header {
|
||
display: flex;
|
||
background: #f8f9fa;
|
||
border-bottom: 2rpx solid #eee;
|
||
|
||
.compare-cell {
|
||
flex: 1;
|
||
padding: 24rpx;
|
||
text-align: center;
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
|
||
&.highlight {
|
||
color: #6a8cff;
|
||
}
|
||
}
|
||
}
|
||
|
||
.compare-row {
|
||
display: flex;
|
||
border-bottom: 2rpx solid #eee;
|
||
|
||
&:last-child {
|
||
border-bottom: none;
|
||
}
|
||
|
||
.compare-cell {
|
||
flex: 1;
|
||
padding: 24rpx;
|
||
text-align: center;
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
|
||
&.highlight {
|
||
color: #6a8cff;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.vip-benefits {
|
||
margin: 32rpx;
|
||
|
||
.benefits-list {
|
||
background: #fff;
|
||
border-radius: 20rpx;
|
||
padding: 32rpx;
|
||
border: 2rpx solid #eee;
|
||
|
||
.benefit-item {
|
||
.benefit-title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.benefit-content {
|
||
.benefit-row {
|
||
display: flex;
|
||
align-items: center;
|
||
margin-bottom: 16rpx;
|
||
|
||
&:last-child {
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.benefit-label {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
width: 160rpx;
|
||
}
|
||
|
||
.benefit-value {
|
||
font-size: 26rpx;
|
||
color: #333;
|
||
flex: 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.vip-notice {
|
||
margin: 32rpx;
|
||
|
||
.notice-title {
|
||
font-size: 32rpx;
|
||
font-weight: bold;
|
||
margin-bottom: 24rpx;
|
||
}
|
||
|
||
.notice-content {
|
||
.notice-item {
|
||
font-size: 28rpx;
|
||
color: #666;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.notice-example {
|
||
margin-top: 32rpx;
|
||
background: #f8f9fa;
|
||
border-radius: 12rpx;
|
||
padding: 24rpx;
|
||
|
||
.example-title {
|
||
font-size: 28rpx;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.example-content {
|
||
font-size: 26rpx;
|
||
color: #666;
|
||
line-height: 1.6;
|
||
|
||
.example-item {
|
||
margin-top: 12rpx;
|
||
padding-left: 24rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.bottom-bar {
|
||
position: fixed;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background: #fff;
|
||
padding: 24rpx 32rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
|
||
|
||
.price-info {
|
||
font-size: 28rpx;
|
||
|
||
.price {
|
||
color: #6a8cff;
|
||
font-size: 36rpx;
|
||
font-weight: bold;
|
||
}
|
||
}
|
||
|
||
.buy-btn {
|
||
margin: 0;
|
||
background: #6a8cff;
|
||
color: #fff;
|
||
border-radius: 40rpx;
|
||
padding: 0 60rpx;
|
||
height: 80rpx;
|
||
line-height: 80rpx;
|
||
font-size: 32rpx;
|
||
}
|
||
}
|
||
</style> |