| @ -1,414 +1,414 @@ | |||
| <!-- 会员中心页面 --> | |||
| <template> | |||
| <view class="page"> | |||
| <view class="bg"></view> | |||
| <view class="content"> | |||
| <!-- 导航栏 --> | |||
| <navbar title="会员中心" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" color="#fff" /> | |||
| <view class="flex user"> | |||
| <image class="user-avatar" :src="userInfo.headImage" mode="aspectFill"></image> | |||
| <view class="user-info"> | |||
| <view class="flex user-name"> | |||
| <text>{{ userInfo.nickName }}</text> | |||
| <template v-if="role === 'member-personal'"> | |||
| <image class="icon icon-role" src="@/static/image/center/icon-member-personal.png" mode="widthFix"></image> | |||
| </template> | |||
| <template v-else-if="role === 'member-business'"> | |||
| <image class="icon icon-role" src="@/static/image/center/icon-member-business.png" mode="widthFix"></image> | |||
| </template> | |||
| </view> | |||
| <view class="user-desc"> | |||
| <template v-if="role"> | |||
| <!-- todo: 换回接口字段 --> | |||
| <text>{{ `将于${'2026-12-12'} 到期` }}</text> | |||
| </template> | |||
| <template v-else> | |||
| <text>暂未开通会员</text> | |||
| </template> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="consumption" v-if="!role"> | |||
| <!-- todo: 对接接口 --> | |||
| <progress :current="1000" :total="3800"></progress> | |||
| <text class="consumption-desc">{{ `累积消费达到${3800}元或直接充值即可成为会员` }}</text> | |||
| </view> | |||
| <view class="charge"> | |||
| <view class="charge-header"> | |||
| <view class="flex charge-header-title">充值会员</view> | |||
| <view class="charge-header-mask"></view> | |||
| </view> | |||
| <view class="charge-content"> | |||
| <view class="flex charge-selection"> | |||
| <view class="flex charge-option" | |||
| v-for="item in chargeOptions" | |||
| :key="item.id" | |||
| :class="[selectedChargeId === item.id ? 'is-active' : '']" | |||
| @click="onSelectCharge(item.id)" | |||
| > | |||
| <view class="charge-option-value"> | |||
| <text class="charge-option-unit">¥</text> | |||
| <text>{{ item.price }}</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="charge-rights"> | |||
| <view class="flex charge-rights-header"> | |||
| <image class="title" src="../static/memberCenter/title-rights.png" mode="widthFix"></image> | |||
| </view> | |||
| <view class="charge-rights-content"> | |||
| <uv-parse :content="configList.config_rights"></uv-parse> | |||
| <image class="icon" src="../static/memberCenter/icon-rights.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="flex bar"> | |||
| <view class="flex count"> | |||
| <text>合计:</text> | |||
| <view class="price"> | |||
| <text class="price-unit">¥</text> | |||
| <!-- todo: check --> | |||
| <text>{{ totalPrice }}</text> | |||
| </view> | |||
| </view> | |||
| <view class="btn btn-pay" @click="submit"> | |||
| 开通会员 | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import progress from '../components/progress.vue' | |||
| import { mapGetters, mapState } from 'vuex' | |||
| export default { | |||
| name: "MemberCenter", | |||
| components: { | |||
| progress, | |||
| }, | |||
| data() { | |||
| return { | |||
| chargeOptions: [], | |||
| selectedChargeId: '001', | |||
| } | |||
| }, | |||
| onShow() { | |||
| this.fetchCargeOptions() | |||
| }, | |||
| computed: { | |||
| ...mapGetters(['role']), | |||
| ...mapState(['userInfo']), | |||
| selectedChargeObj() { | |||
| return this.chargeOptions.find(item => item.id === this.selectedChargeId) | |||
| }, | |||
| totalPrice() { | |||
| return this.selectedChargeObj?.price || 0 | |||
| } | |||
| }, | |||
| methods: { | |||
| async fetchCargeOptions() { | |||
| try { | |||
| this.chargeOptions = (await this.$fetch('queryComboList'))?.records || [] | |||
| this.selectedChargeId = this.chargeOptions?.[0]?.id | |||
| } catch (err) { | |||
| } | |||
| }, | |||
| onSelectCharge(id) { | |||
| this.selectedChargeId = id | |||
| }, | |||
| async submit() { | |||
| // todo: check jump to create order ? | |||
| try { | |||
| let params = { | |||
| comoId: this.selectedChargeId | |||
| } | |||
| await this.$fetch('addVip', params) | |||
| // await uni.requestPaymentWxPay(res) | |||
| uni.showToast({ | |||
| title: '充值成功', | |||
| icon : 'none' | |||
| }) | |||
| setTimeout(uni.navigateBack, 800, -1) | |||
| } catch (err) { | |||
| } | |||
| return | |||
| this.$api('addVip', res => { | |||
| if(res.code == 200){ | |||
| uni.requestPaymentWxPay(res) | |||
| .then(e => { | |||
| uni.showToast({ | |||
| title: '下单成功', | |||
| icon: 'none' | |||
| }) | |||
| this.paySuccess(res) | |||
| }).catch(n => { | |||
| setTimeout(uni.redirectTo, 700, { | |||
| url: '/pages/index/center' | |||
| }) | |||
| }) | |||
| // uni.showToast({ | |||
| // title: '充值成功', | |||
| // icon : 'none' | |||
| // }) | |||
| setTimeout(uni.navigateBack, 800, -1) | |||
| } | |||
| }) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| $bar-height: 132rpx; | |||
| .bg { | |||
| width: 100vw; | |||
| height: 550rpx; | |||
| background-image: linear-gradient(#84A73F, #D8FF8F); | |||
| } | |||
| .page { | |||
| padding-bottom: calc(#{$bar-height} + env(safe-area-inset-bottom)); | |||
| background-color: $uni-fg-color; | |||
| min-height: 100vh; | |||
| position: relative; | |||
| } | |||
| .content { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100vw; | |||
| } | |||
| .user { | |||
| align-items: flex-start; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 22rpx; | |||
| margin: 34rpx 18rpx 0 18rpx; | |||
| &-avatar { | |||
| width: 147rpx; | |||
| height: 147rpx; | |||
| margin-right: 8rpx; | |||
| } | |||
| &-info { | |||
| flex: 1; | |||
| } | |||
| &-name { | |||
| font-size: 32rpx; | |||
| margin-top: 16rpx; | |||
| justify-content: flex-start; | |||
| .icon { | |||
| height: auto; | |||
| &-role { | |||
| width: 138rpx; | |||
| } | |||
| } | |||
| } | |||
| &-desc { | |||
| margin-top: 26rpx; | |||
| } | |||
| } | |||
| .consumption { | |||
| margin: 0 28rpx; | |||
| &-desc { | |||
| color: $uni-text-color-inverse; | |||
| font-size: 22rpx; | |||
| margin-top: 1rpx; | |||
| } | |||
| } | |||
| .charge { | |||
| background-color: $uni-fg-color; | |||
| border-top-left-radius: 18rpx; | |||
| border-top-right-radius: 18rpx; | |||
| margin-top: 45rpx; | |||
| &-header { | |||
| $header-height: 90rpx; | |||
| height: $header-height; | |||
| position: relative; | |||
| &-title { | |||
| width: calc(50% + 25rpx); | |||
| height: 100%; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 28rpx; | |||
| background-image: linear-gradient(#84A73F, #D8FF8F); | |||
| box-sizing: border-box; | |||
| border-top-left-radius: 18rpx; | |||
| border-bottom-right-radius: 90rpx; | |||
| } | |||
| &-mask { | |||
| $marsk-width: 50rpx; | |||
| position: absolute; | |||
| top: 0; | |||
| right: 50%; | |||
| transform: translateX(25rpx); | |||
| // height: 100%; | |||
| // width: 70rpx; | |||
| width: 0; | |||
| height: 0; | |||
| border-top: calc(#{$header-height}/2) solid transparent; | |||
| border-left: calc(#{$marsk-width}/2) solid transparent; | |||
| border-bottom: calc(#{$header-height}/2) solid $uni-fg-color; | |||
| border-right: calc(#{$marsk-width}/2) solid $uni-fg-color; | |||
| } | |||
| } | |||
| &-content { | |||
| padding: 57rpx 14rpx; | |||
| } | |||
| &-selection { | |||
| justify-content: space-between; | |||
| font-size: 0; | |||
| } | |||
| &-option { | |||
| width: 230rpx; | |||
| height: 248rpx; | |||
| box-sizing: border-box; | |||
| background-color: #F5F5F5; | |||
| border: 3rpx solid #C7C7C7; | |||
| border-radius: 16rpx; | |||
| box-shadow: 0rpx 3rpx 6rpx 0rpx #eef3e3; | |||
| color: #999999; | |||
| &-value { | |||
| font-size: 61rpx; | |||
| } | |||
| &-unit { | |||
| font-size: 34rpx; | |||
| margin-right: 6rpx; | |||
| } | |||
| &.is-active { | |||
| background-color: rgba($color: #E9FFC3, $alpha: 0.74); | |||
| border-color: $uni-color-light; | |||
| color: #F64041; | |||
| } | |||
| } | |||
| &-rights { | |||
| margin-top: 67rpx; | |||
| &-header { | |||
| .title { | |||
| width: 202rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| &-content { | |||
| margin-top: 31rpx; | |||
| color: $uni-color-light; | |||
| font-size: 28rpx; | |||
| line-height: 66rpx; | |||
| background-color: rgba($color: #E2FFAE, $alpha: 0.71); | |||
| border-radius: 16rpx; | |||
| padding: 29rpx 30rpx; | |||
| width: 100%; | |||
| min-height: 500rpx; | |||
| box-sizing: border-box; | |||
| position: relative; | |||
| .icon { | |||
| position: absolute; | |||
| top: 23rpx; | |||
| right: 11rpx; | |||
| width: 131rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // 下单 | |||
| .bar { | |||
| position: fixed; | |||
| z-index: 1000; | |||
| bottom: 0; | |||
| left: 0; | |||
| width: 100vw; | |||
| height: $bar-height; | |||
| padding-bottom: env(safe-area-inset-bottom); | |||
| background-color: $uni-fg-color; | |||
| .count { | |||
| flex: 1; | |||
| color: #000000; | |||
| font-size: 28rpx; | |||
| margin-left: 48rpx; | |||
| justify-content: flex-start; | |||
| .price { | |||
| color: #FF2A2A; | |||
| font-size: 30rpx; | |||
| &-unit { | |||
| font-size: 18rpx; | |||
| } | |||
| } | |||
| } | |||
| .btn { | |||
| border: none; | |||
| line-height: 1; | |||
| background-color: transparent; | |||
| padding: 0; | |||
| width: auto; | |||
| height: auto; | |||
| margin: 0; | |||
| &-pay { | |||
| margin-right: 41rpx; | |||
| padding: 24rpx 137rpx; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 28rpx; | |||
| border-radius: 44rpx; | |||
| background-image: linear-gradient(to right, #84A73F, #D8FF8F); | |||
| } | |||
| } | |||
| } | |||
| <!-- 会员中心页面 --> | |||
| <template> | |||
| <view class="page"> | |||
| <view class="bg"></view> | |||
| <view class="content"> | |||
| <!-- 导航栏 --> | |||
| <navbar title="会员中心" leftClick @leftClick="$utils.navigateBack" bgColor="transparent" color="#fff" /> | |||
| <view class="flex user"> | |||
| <image class="user-avatar" :src="userInfo.headImage" mode="aspectFill"></image> | |||
| <view class="user-info"> | |||
| <view class="flex user-name"> | |||
| <text>{{ userInfo.nickName }}</text> | |||
| <template v-if="role === 'member-personal'"> | |||
| <image class="icon icon-role" src="@/static/image/center/icon-member-personal.png" | |||
| mode="widthFix"></image> | |||
| </template> | |||
| <template v-else-if="role === 'member-business'"> | |||
| <image class="icon icon-role" src="@/static/image/center/icon-member-business.png" | |||
| mode="widthFix"></image> | |||
| </template> | |||
| </view> | |||
| <view class="user-desc"> | |||
| <template v-if="role"> | |||
| <!-- todo: 换回接口字段 --> | |||
| <text>{{ `将于${'2026-12-12'} 到期` }}</text> | |||
| </template> | |||
| <template v-else> | |||
| <text>暂未开通会员</text> | |||
| </template> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="consumption" v-if="!role"> | |||
| <!-- todo: 对接接口 --> | |||
| <progress :current="1000" :total="3800"></progress> | |||
| <text class="consumption-desc">{{ `累积消费达到${3800}元或直接充值即可成为会员` }}</text> | |||
| </view> | |||
| <view class="charge"> | |||
| <view class="charge-header"> | |||
| <view class="flex charge-header-title">充值会员</view> | |||
| <view class="charge-header-mask"></view> | |||
| </view> | |||
| <view class="charge-content"> | |||
| <view class="flex charge-selection"> | |||
| <view class="flex charge-option" v-for="item in chargeOptions" :key="item.id" | |||
| :class="[selectedChargeId === item.id ? 'is-active' : '']" @click="onSelectCharge(item.id)"> | |||
| <view class="charge-option-value"> | |||
| <text class="charge-option-unit">¥</text> | |||
| <text>{{ item.price }}</text> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="charge-rights"> | |||
| <view class="flex charge-rights-header"> | |||
| <image class="title" src="../static/memberCenter/title-rights.png" mode="widthFix"></image> | |||
| </view> | |||
| <view class="charge-rights-content"> | |||
| <uv-parse :content="configList.config_rights"></uv-parse> | |||
| <image class="icon" src="../static/memberCenter/icon-rights.png" mode="widthFix"></image> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| <view class="flex bar"> | |||
| <view class="flex count"> | |||
| <text>合计:</text> | |||
| <view class="price"> | |||
| <text class="price-unit">¥</text> | |||
| <!-- todo: check --> | |||
| <text>{{ totalPrice }}</text> | |||
| </view> | |||
| </view> | |||
| <view class="btn btn-pay" @click="submit"> | |||
| 开通会员 | |||
| </view> | |||
| </view> | |||
| </view> | |||
| </template> | |||
| <script> | |||
| import progress from '../components/progress.vue' | |||
| import { | |||
| mapGetters, | |||
| mapState | |||
| } from 'vuex' | |||
| export default { | |||
| name: "MemberCenter", | |||
| components: { | |||
| progress, | |||
| }, | |||
| data() { | |||
| return { | |||
| chargeOptions: [], | |||
| selectedChargeId: '001', | |||
| } | |||
| }, | |||
| onShow() { | |||
| this.fetchCargeOptions() | |||
| }, | |||
| computed: { | |||
| ...mapGetters(['role']), | |||
| ...mapState(['userInfo']), | |||
| selectedChargeObj() { | |||
| return this.chargeOptions.find(item => item.id === this.selectedChargeId) | |||
| }, | |||
| totalPrice() { | |||
| return this.selectedChargeObj?.price || 0 | |||
| } | |||
| }, | |||
| methods: { | |||
| async fetchCargeOptions() { | |||
| try { | |||
| this.chargeOptions = (await this.$fetch('queryComboList'))?.records || [] | |||
| this.selectedChargeId = this.chargeOptions?.[0]?.id | |||
| } catch (err) { | |||
| } | |||
| }, | |||
| onSelectCharge(id) { | |||
| this.selectedChargeId = id | |||
| }, | |||
| async submit() { | |||
| // todo: check jump to create order ? | |||
| try { | |||
| let params = { | |||
| comoId: this.selectedChargeId | |||
| } | |||
| let result = await this.$fetch('addVip', params) | |||
| await uni.requestPaymentWxPay({result}) | |||
| uni.showToast({ | |||
| title: '充值成功', | |||
| icon : 'none' | |||
| }) | |||
| setTimeout(uni.navigateBack, 800, -1) | |||
| } catch (err) { | |||
| } | |||
| return | |||
| // this.$api('addVip', { | |||
| // comoId: this.selectedChargeId | |||
| // }, res => { | |||
| // if (res.code == 200) { | |||
| // uni.requestPayment({ | |||
| // provider: 'wxpay', // 服务提提供商 | |||
| // timeStamp: res.result.timeStamp, // 时间戳 | |||
| // nonceStr: res.result.nonceStr, // 随机字符串 | |||
| // package: res.result.packageValue, | |||
| // signType: res.result.signType, // 签名算法 | |||
| // paySign: res.result.paySign, // 签名 | |||
| // success: function(res) { | |||
| // console.log('支付成功', res); | |||
| // }, | |||
| // fail: function(err) { | |||
| // console.log('支付失败', err); | |||
| // uni.showToast({ | |||
| // icon: 'none', | |||
| // title: "支付失败" | |||
| // }) | |||
| // } | |||
| // }); | |||
| // } | |||
| // }) | |||
| } | |||
| } | |||
| } | |||
| </script> | |||
| <style scoped lang="scss"> | |||
| $bar-height: 132rpx; | |||
| .bg { | |||
| width: 100vw; | |||
| height: 550rpx; | |||
| background-image: linear-gradient(#84A73F, #D8FF8F); | |||
| } | |||
| .page { | |||
| padding-bottom: calc(#{$bar-height} + env(safe-area-inset-bottom)); | |||
| background-color: $uni-fg-color; | |||
| min-height: 100vh; | |||
| position: relative; | |||
| } | |||
| .content { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 0; | |||
| width: 100vw; | |||
| } | |||
| .user { | |||
| align-items: flex-start; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 22rpx; | |||
| margin: 34rpx 18rpx 0 18rpx; | |||
| &-avatar { | |||
| width: 147rpx; | |||
| height: 147rpx; | |||
| margin-right: 8rpx; | |||
| } | |||
| &-info { | |||
| flex: 1; | |||
| } | |||
| &-name { | |||
| font-size: 32rpx; | |||
| margin-top: 16rpx; | |||
| justify-content: flex-start; | |||
| .icon { | |||
| height: auto; | |||
| &-role { | |||
| width: 138rpx; | |||
| } | |||
| } | |||
| } | |||
| &-desc { | |||
| margin-top: 26rpx; | |||
| } | |||
| } | |||
| .consumption { | |||
| margin: 0 28rpx; | |||
| &-desc { | |||
| color: $uni-text-color-inverse; | |||
| font-size: 22rpx; | |||
| margin-top: 1rpx; | |||
| } | |||
| } | |||
| .charge { | |||
| background-color: $uni-fg-color; | |||
| border-top-left-radius: 18rpx; | |||
| border-top-right-radius: 18rpx; | |||
| margin-top: 45rpx; | |||
| &-header { | |||
| $header-height: 90rpx; | |||
| height: $header-height; | |||
| position: relative; | |||
| &-title { | |||
| width: calc(50% + 25rpx); | |||
| height: 100%; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 28rpx; | |||
| background-image: linear-gradient(#84A73F, #D8FF8F); | |||
| box-sizing: border-box; | |||
| border-top-left-radius: 18rpx; | |||
| border-bottom-right-radius: 90rpx; | |||
| } | |||
| &-mask { | |||
| $marsk-width: 50rpx; | |||
| position: absolute; | |||
| top: 0; | |||
| right: 50%; | |||
| transform: translateX(25rpx); | |||
| // height: 100%; | |||
| // width: 70rpx; | |||
| width: 0; | |||
| height: 0; | |||
| border-top: calc(#{$header-height}/2) solid transparent; | |||
| border-left: calc(#{$marsk-width}/2) solid transparent; | |||
| border-bottom: calc(#{$header-height}/2) solid $uni-fg-color; | |||
| border-right: calc(#{$marsk-width}/2) solid $uni-fg-color; | |||
| } | |||
| } | |||
| &-content { | |||
| padding: 57rpx 14rpx; | |||
| } | |||
| &-selection { | |||
| justify-content: space-between; | |||
| font-size: 0; | |||
| } | |||
| &-option { | |||
| width: 230rpx; | |||
| height: 248rpx; | |||
| box-sizing: border-box; | |||
| background-color: #F5F5F5; | |||
| border: 3rpx solid #C7C7C7; | |||
| border-radius: 16rpx; | |||
| box-shadow: 0rpx 3rpx 6rpx 0rpx #eef3e3; | |||
| color: #999999; | |||
| &-value { | |||
| font-size: 61rpx; | |||
| } | |||
| &-unit { | |||
| font-size: 34rpx; | |||
| margin-right: 6rpx; | |||
| } | |||
| &.is-active { | |||
| background-color: rgba($color: #E9FFC3, $alpha: 0.74); | |||
| border-color: $uni-color-light; | |||
| color: #F64041; | |||
| } | |||
| } | |||
| &-rights { | |||
| margin-top: 67rpx; | |||
| &-header { | |||
| .title { | |||
| width: 202rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| &-content { | |||
| margin-top: 31rpx; | |||
| color: $uni-color-light; | |||
| font-size: 28rpx; | |||
| line-height: 66rpx; | |||
| background-color: rgba($color: #E2FFAE, $alpha: 0.71); | |||
| border-radius: 16rpx; | |||
| padding: 29rpx 30rpx; | |||
| width: 100%; | |||
| min-height: 500rpx; | |||
| box-sizing: border-box; | |||
| position: relative; | |||
| .icon { | |||
| position: absolute; | |||
| top: 23rpx; | |||
| right: 11rpx; | |||
| width: 131rpx; | |||
| height: auto; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| // 下单 | |||
| .bar { | |||
| position: fixed; | |||
| z-index: 1000; | |||
| bottom: 0; | |||
| left: 0; | |||
| width: 100vw; | |||
| height: $bar-height; | |||
| padding-bottom: env(safe-area-inset-bottom); | |||
| background-color: $uni-fg-color; | |||
| .count { | |||
| flex: 1; | |||
| color: #000000; | |||
| font-size: 28rpx; | |||
| margin-left: 48rpx; | |||
| justify-content: flex-start; | |||
| .price { | |||
| color: #FF2A2A; | |||
| font-size: 30rpx; | |||
| &-unit { | |||
| font-size: 18rpx; | |||
| } | |||
| } | |||
| } | |||
| .btn { | |||
| border: none; | |||
| line-height: 1; | |||
| background-color: transparent; | |||
| padding: 0; | |||
| width: auto; | |||
| height: auto; | |||
| margin: 0; | |||
| &-pay { | |||
| margin-right: 41rpx; | |||
| padding: 24rpx 137rpx; | |||
| color: $uni-text-color-inverse; | |||
| font-size: 28rpx; | |||
| border-radius: 44rpx; | |||
| background-image: linear-gradient(to right, #84A73F, #D8FF8F); | |||
| } | |||
| } | |||
| } | |||
| </style> | |||