Files
cashier_wx/user/vip/buy-vip.vue
2025-09-28 18:27:27 +08:00

611 lines
15 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view>
<up-navbar bg-color="transparent" title="会员中心" @leftClick="back"></up-navbar>
<view class="top" style=" background-image: url(/static/czzx_header_bg.png);">
<view>
<view class="u-flex">
<up-image radius="20rpx" width="136rpx" height="136rpx" :src="shopInfo.logo" mode="aspectFill"></up-image>
<view class="u-p-l-20">
<view class="shop-name u-line-1">{{shopInfo.shopName||'店铺名称' }}</view>
<view class="u-flex">
<view class="no-buy">暂未开通</view>
</view>
</view>
</view>
</view>
</view>
<view class="box">
<view class="vip-quanyi">
<template v-if="state.openType=='CONDITION'">
<view class="font-700 color-000 color-000 u-m-t-8">
如何成为会员
</view>
<view class="u-flex u-m-t-20 u-flex-between" v-for="(item,index) in conditionList" :key="index">
<text class="color-000">{{item.title}}</text>
<view class="finish-btn" :class="item.isFinsh?'active':''">
{{item.isFinsh?'已完成':'未完成'}}
</view>
</view>
<view class="u-flex u-flex-between u-m-t-48">
<text class="color-000 font-14 font-700">会员专属权益</text>
<view class="u-flex">
<text class="color-666 u-m-r-4 font-12">会员说明</text>
<up-icon name="question-circle" size="12" @click="modelShow"></up-icon>
</view>
</view>
<view class="u-m-t-32">
<view class="menus menus-tiaojian">
<view class="item " v-for="(item,index) in tiaojian_menus" :key="index">
<view class="u-flex u-flex-x-center u-m-t-4">
<image :src="item.icon" mode="" style="width: 100rpx;height: 100rpx;"></image>
</view>
<view class="font-14 color-333 text-center u-m-t-4 u-flex u-flex-center">
<text class="no-wrap u-m-r-4">{{item.name}}</text>
<up-icon @click="modelShow(item.name)" size="12" name="question-circle" color="#333"
v-if="showQuestion(index,tiaojian_menus)"></up-icon>
</view>
<view class="font-12 color-666 text-center">{{item.desc}}</view>
</view>
</view>
</view>
</template>
<template v-else>
<view class="vip-list">
<view v-for="(item,index) in configList" :key="index" class="vip-list-item"
@click="vipSel=index" :class="{active:vipSel==index}">
<view class="font-16 color-333">{{item.name}}</view>
<view class="u-m-t-16 color-333">
<text class="font-14"></text>
<text style="font-size: 48rpx;">{{item.price}}</text>
</view>
<view class="color-999 font-14 line-through text-center" v-if="item.origin_price">
<text></text>
<text>{{item.origin_price}}</text>
</view>
</view>
</view>
<view class="u-flex u-flex-between u-m-t-48">
<text class="color-000 font-14 font-700">会员专属权益</text>
<view class="u-flex">
<text class="color-666 u-m-r-4 font-12">会员说明</text>
<up-icon name="question-circle" size="12" @click="modelShow('会员说明')"></up-icon>
</view>
</view>
<view class="u-m-t-32">
<view class="menus menus-pays">
<view class="item " v-for="(item,index) in pay_menus" :key="index">
<view class="u-flex u-flex-x-center u-m-t-4">
<image :src="item.icon" mode="" style="width: 100rpx;height: 100rpx;"></image>
</view>
<view class="font-14 color-333 text-center u-m-t-4 u-flex u-flex-center">
<text class="no-wrap u-m-r-4">{{item.name}}</text>
<up-icon @click="modelShow(item.name)" size="12" name="question-circle" color="#333"
v-if="showQuestion(index,pay_menus)&& memberLevel"></up-icon>
</view>
<view class="font-12 color-666 text-center" v-if="item.name=='赠送成长值'">
{{'赠送'+returnReward+'成长值'}}
</view>
<view class="font-12 color-666 text-center"
v-else-if="item.name=='优惠券'&&returCouponList.length">
{{'赠送'+returCouponList.length+'张优惠券'}}
</view>
<view class="font-12 color-666 text-center" v-else-if="item.name=='会员折扣'&&memberLevel">
全店折扣{{memberLevel.discount}}
</view>
<view class="font-12 color-666 text-center" v-else>{{item.desc}}</view>
</view>
</view>
</view>
<button class="buy-btn" @click="buy">立即开通</button>
</template>
</view>
</view>
<up-popup :show="model.show" mode="center" round="16rpx" close-on-click-overlay @close="model.show=false">
<view class="model-box">
<view class="u-flex u-flex-between">
<text class="color-000 font-700 font-16">{{model.title}}</text>
<up-icon name="close-circle" color="#666" size="28rpx" @click="modelHide"></up-icon>
</view>
<view class="u-m-t-18 up-content">
<up-parse :content="modelContent"></up-parse>
</view>
</view>
</up-popup>
<up-popup :show="model.show1" mode="bottom" round="16rpx" close-on-click-overlay @close="model.show1=false">
<view class="model-box">
<view class="u-flex u-flex-between">
<text class="color-000 font-700 font-16">{{model.title}}</text>
<up-icon name="close-circle" color="#666" size="28rpx" @click="modelHide"></up-icon>
</view>
<view class="u-m-t-18 up-content">
<up-parse :content="modelContent"></up-parse>
</view>
</view>
</up-popup>
<registermember :memberOpen="memberOpen" :shopUserInfo="shopInfo" @emitsmemberOpen="emitsmemberOpen">
</registermember>
</view>
</template>
<script setup>
import {
ref,
reactive,
computed
} from "vue"
import {
joinMember,
ltPayMember
} from '@/common/api/order/index.js'
import * as vipApi from '@/common/api/market/vip.js'
import {pay} from '@/utils/pay.js'
import {
APIusershopInfodetail,APIshopUserInfo
} from '@/common/api/member.js'
import {
onLoad
} from '@dcloudio/uni-app'
import registermember from '@/user/components/registermember.vue'
const model = reactive({
show: false,
show1: false,
title: ''
})
const memberOpen = ref(false)
function modelHide() {
model.show = false;
}
function modelShow(name) {
if (name == '消费送积分') {
model.title = '消费送积分'
modelContent.value = `每消耗${memberLevel.value.costRewardPoints}元赠送1积分`
}
if (name == '周期福利') {
model.title = '周期福利'
modelContent.value =
`${memberLevel.value.cycleUnit}赠送${memberLevel.value.cycleRewardPoints}积分,${memberLevel.value.cycleRewardCouponList.length}张优惠券`
}
if (name == '会员说明') {
model.title = '会员说明'
modelContent.value = state.remark
}
model.show = true;
}
const modelContent = ref(`
1、可适用门店全部门店<br>
2、可适用商品部分商品<br>
3、可使用类型堂食<br>
4、可用时间段全时段可用<br>
5、限量规则每人限领3张每日可最多使用3张<br>
6、同享规则与限时折扣同享、与会员价同享<br>
7、其它说明这里是后台配置内容
`)
const state = reactive({
openType: 'CONDITION'
})
const pay_menus = ref([{
name: '赠送成长值',
desc: '赠送成长值',
icon: '/user/static/buy-vip/Frame_220.png',
},
{
name: '优惠券',
desc: '每月赠送2张优惠券',
icon: '/user/static/buy-vip/Frame_221.png'
},
{
name: '享会员价',
desc: '全店会员价',
icon: '/user/static/buy-vip/Frame_222.png'
},
{
name: '会员折扣',
desc: '全店折扣98折',
icon: '/user/static/buy-vip/Frame_223.png'
},
{
name: '消费送积分',
desc: '',
icon: '/user/static/buy-vip/Frame_224.png'
},
{
name: '周期福利',
desc: '',
icon: '/user/static/buy-vip/Frame_225.png'
}
])
let tiaojian_menus =ref( [{
name: '享会员价',
desc: '全店会员价',
icon: '/user/static/buy-vip/Frame_222.png'
},
{
name: '会员折扣',
desc: '全店折扣98折',
icon: '/user/static/buy-vip/Frame_223.png'
},
{
name: '消费送积分',
desc: '',
icon: '/user/static/buy-vip/Frame_224.png'
},
{
name: '周期福利',
desc: '',
icon: '/user/static/buy-vip/Frame_225.png'
}
])
function showQuestion(index, arr) {
const len = arr.length
if (index >= len - 2) {
return true
}
return false
}
function back() {
uni.navigateBack()
}
const configList = ref([])
const vipSel = ref(0)
const conditionList = ref([])
const conditionListMap = {
'BIND_PHONE': '绑定手机号',
'ORDER': '完成消费',
'COST_AMOUNT': '消费达到指定金额',
'RECHARGE_AMOUNT': '充值达到指定金额',
}
const memberLevel = ref(null)
const shopInfo = reactive({})
const shopUserInfo = ref({})
async function init(shopId) {
const userRes= await APIshopUserInfo({
shopId
})
if (userRes) {
shopUserInfo.value=userRes
}
const shopRes = await APIusershopInfodetail({
shopId
})
if (shopRes) {
Object.assign(shopInfo, shopRes.shopInfo)
}
const res = await vipApi.config({
shopId: shopId
})
if (res) {
if(!res.memberConfig.isMemberPrice){
tiaojian_menus.value=tiaojian_menus.value.filter(v=>v.name!='享会员价')
pay_menus.value=pay_menus.value.filter(v=>v.name!='享会员价')
}
if (res.memberConfig.isSubmitInfo && (shopUserInfo.value.sex === null || shopUserInfo.value.sex ===
undefined || !shopUserInfo.value.nickName || !shopUserInfo.value.birthDay || !shopUserInfo.value
.phone)) {
memberOpen.value = true;
}
conditionList.value = res.memberConfig.conditionList.map(v => {
const json = {
...v,
isFinsh: res.conditionMap[v.code],
title: conditionListMap[v.code],
}
if (v.code == 'ORDER') {
json.title = json.title + v.value + '次'
}
if (v.code == 'COST_AMOUNT' || v.code == 'RECHARGE_AMOUNT') {
json.title = json.title + v.value + '元'
}
return json
})
configList.value = res.memberConfig.configList
Object.assign(state, res.memberConfig)
memberLevel.value = res.memberLevel
}
}
const returnReward = computed(() => {
const item = configList.value[vipSel.value]
if (item) {
return item.reward
}
return ''
})
const returCouponList = computed(() => {
const item = configList.value[vipSel.value]
if (item.couponList) {
return item.couponList
}
return []
})
const option = reactive({
shopId: ''
})
onLoad((opt) => {
Object.assign(option, opt)
console.log(option);
let shopId = option.shopId
init(shopId)
})
function emitsmemberOpen(e) {
memberOpen.value = false
Object.assign(shopUserInfo.value,e)
}
async function buy() {
const json = {
shopId: option.shopId,
name: configList.value[vipSel.value].name,
num: 1,
shopId: option.shopId,
shopUserId: shopUserInfo.value.id
}
if (state.isSubmitInfo) {
json.sex = shopUserInfo.value.sex;
json.birthDay = shopUserInfo.value.birthDay;
json.nickName = shopUserInfo.value.nickName
}
const res = await ltPayMember(json)
if (!res) {
return uni.showToast({
title: '购买失败',
icon:'error'
})
}
const payRes=await pay(res)
console.log(payRes);
if(payRes){
uni.showToast({
title: '开通会员成功',
icon:'none'
})
setTimeout(()=>{
uni.redirectTo({
url:'/user/vip/vip?shopId='+option.shopId
})
},1000)
}
}
</script>
<style>
page {
background: #F9F9F9;
}
</style>
<style lang="scss" scoped>
.finish-btn {
padding: 2rpx 28rpx;
border-radius: 40rpx;
font-size: 14px;
border: 2rpx solid #D9D9D9;
padding: 4rpx 28rpx;
&.active {
border: 2rpx solid #FF6300;
color: #FF6300;
}
}
.box {
background-color: rgba(255, 255, 255, .3);
}
.font-700 {
font-weight: 700;
}
.color-one {
color: #558ABF;
}
.color-2 {
color: #273d7a;
}
.top {
background: linear-gradient(283deg, #A9CBF8 11.62%, #E5E7EB 74.58%);
}
.top {
padding: 208rpx 30rpx 78rpx 30rpx;
background-size: cover;
box-sizing: border-box;
height: 530rpx;
.shop-name {
color: #5E3110;
font-size: 16px;
font-weight: 700;
}
.no-buy {
margin-top: 12rpx;
padding: 8rpx 22rpx;
border-radius: 50rpx;
background-color: #F8F8F8;
font-size: 14px;
color: #999;
text-align: center;
}
}
.vip-box {
position: relative;
border-radius: 12px;
overflow: hidden;
padding-left: 6px;
padding-right: 64rpx;
padding-bottom: 24rpx;
.icon {
position: absolute;
right: 42rpx;
top: 0;
.huangguan {
width: 214rpx;
height: 206rpx;
}
}
.tag {
position: absolute;
top: 0;
font-size: 12px;
color: #46739F;
padding: 2px 12px;
background: #c7d0da;
border-radius: 0 0 12px 0;
}
.lv {
color: #273d7a;
font-weight: 700;
font-size: 64rpx;
letter-spacing: 4rpx;
transform: skewX(-10deg);
}
.time {
color: #6988ab;
font-size: 24rpx;
font-weight: 400;
}
.rule {
.exp {}
.desc {
color: #273d7a;
font-size: 24rpx;
font-weight: 400;
}
}
.next-tips {
color: #6988ab;
font-size: 24rpx;
font-weight: 400;
}
}
.progress {
margin-top: 8rpx;
background-color: #BDD5E9;
height: 10rpx;
border-radius: 10rpx;
.block {
height: 100%;
border-radius: 10rpx;
background: linear-gradient(90deg, #F9FBFA 0.03%, #334783 115.59%);
}
}
.vip-quanyi {
padding: 44rpx 28rpx 42rpx 28rpx;
border-radius: 40rpx 40rpx 0 0;
transform: translateY(-140rpx);
background-color: rgba(255, 255, 255, .3);
}
.menus-pays {
display: grid;
/* 每行显示3列每列宽度相等 */
grid-template-columns: repeat(3, 1fr);
/* 列间距 */
column-gap: 10px;
/* 行间距 */
row-gap: 32rpx;
/* 可以添加容器的内边距 */
}
.menus-tiaojian {
display: grid;
/* 每行显示3列每列宽度相等 */
grid-template-columns: repeat(4, 1fr);
/* 列间距 */
column-gap: 10px;
/* 行间距 */
row-gap: 10px;
/* 可以添加容器的内边距 */
}
.model-box {
padding: 32rpx 56rpx;
width: 702rpx;
}
.up-content {
color: #999;
font-size: 12px;
}
.vip-list {
display: grid;
grid-template-columns: repeat(3, 1fr);
column-gap: 36rpx;
row-gap: 36rpx;
.vip-list-item {
border: 4rpx solid #D9D9D9;
border-radius: 40rpx;
overflow: hidden;
transition: all .3s ease-in-out;
background-color: #fff;
padding: 42rpx 34rpx;
&.active {
border: 4rpx solid #FF6300;
background-image: linear-gradient(180deg, #FFC29A -26.17%, #FFF 64.06%);
}
}
}
.buy-btn {
margin-top: 98rpx;
padding: 32rpx 32rpx;
color: #fff;
font-size: 16px;
font-weight: 700;
border-radius: 80rpx;
line-height: 1;
background: linear-gradient(98deg, #fe6d1100 40.64%, #FFD1B4 105.2%), linear-gradient(259deg, #FE6D11 50.14%, #FFD1B4 114.93%);
box-shadow: 0 14rpx 30.4rpx 0 #fe8b435e;
}
</style>