初始上传

This commit is contained in:
2026-04-04 17:27:12 +08:00
parent 4d80d28eb4
commit b7e11774ee
11191 changed files with 1588469 additions and 0 deletions

View File

@@ -0,0 +1,195 @@
import {
getMemberCardList
} from '@/api/member'
import {mapGetters} from 'vuex';
export default {
data() {
return {
memberCardData: {
page: 0,
total: 1,
list: [],
index: 0,
currData: {},
selected: {}
},
itemNum: 1
}
},
computed: {
...mapGetters(['billingGoodsData'])
},
methods: {
open() {
this.$refs.memberCardPopup.open();
this.memberCardData.page = 0;
this.memberCardData.index = 0;
this.memberCardData.list = [];
this.memberCardData.currData = {};
this.memberCardData.selected = {};
this.getMemberCard()
},
// 获取会员项目
getMemberCard() {
if (this.memberCardData.page + 1 > this.memberCardData.total) return;
this.memberCardData.page += 1;
getMemberCardList({
status: 1,
page: this.memberCardData.page,
member_id: this.globalMemberInfo.member_id
}).then(res => {
if (res.code == 0) {
this.memberCardData.total = res.data.page_count || 1;
Object.values(this.billingGoodsData).forEach(data => {
if (data.card_id) {
res.data.list.forEach((card)=>{
if(card.card_id == data.card_id){
// 通用卡:选择商品,总数量发生变化
if (data.card_type == 'commoncard') {
card.total_use_num += data.num;
} else if (data.card_type == 'oncecard') {
// 限次卡:选择商品后,商品和总数量都要发生变化
card.total_use_num += data.num;
card.item_list.forEach((card_item)=>{
if(card_item.item_id == data.item_id){
card_item.use_num += data.num;
}
})
}
}
})
}
});
if (res.data.list.length) this.memberCardData.list = this.memberCardData.list.concat(res.data.list);
if (this.memberCardData.page == 1) {
// 默认展示第一个卡项信息
if (res.data.count) this.selectMemberCard(this.memberCardData.list[0], 0);
}
}
})
},
/**
* 选择会员套餐
* @param {Object} data
* @param {Object} index
*/
selectMemberCard(data, index) {
this.memberCardData.index = index;
this.memberCardData.currData = this.$util.deepClone(data);
this.memberCardData.selected = {};
},
/**
* 选择会员套餐商品项
* @param {Object} data
* @param {Object} index
*/
selectMemberCardItem(data, index) {
if (this.memberCardData.selected['item_' + data.item_id]) {
if (data.card_type == 'commoncard') {
this.memberCardData.currData.total_use_num -= this.memberCardData.selected['item_' + data.item_id].input_num;
}
delete this.memberCardData.selected['item_' + data.item_id];
} else {
if (!this.checkStatus(data)) return;
this.memberCardData.selected['item_' + data.item_id] = this.$util.deepClone(data);
this.memberCardData.selected['item_' + data.item_id].input_num = 1;
this.memberCardData.selected['item_' + data.item_id].index = index;
this.memberCardData.selected['item_' + data.item_id].card_name = this.memberCardData.currData.goods_name;
if (data.card_type == 'commoncard') {
this.memberCardData.currData.total_use_num += 1;
}
}
this.$forceUpdate();
},
/**
* 加入购物车
*/
selectGoods() {
if (!Object.keys(this.memberCardData.selected).length) {
this.$util.showToast({
title: '请选择服务/商品',
});
return;
}
let billingGoodsData = this.$util.deepClone(this.billingGoodsData);
let billingGoodsKeys = Object.keys(billingGoodsData);
Object.keys(this.memberCardData.selected).forEach((key) => {
let data = this.memberCardData.selected[key];
data.card_index = this.memberCardData.index;
this.memberCardData.list[this.memberCardData.index].total_use_num += data.input_num;
this.memberCardData.list[this.memberCardData.index].item_list[data.index].use_num += data.input_num;
this.memberCardData.currData.item_list[data.index].use_num += data.input_num;
//服务商品每个都是一个订单项,需要循环处理
if(data.goods_class == this.$util.goodsClassDict.service){
let addNum = 0;
Object.values(billingGoodsData).forEach((item)=>{
if(item.sku_id == data.sku_id){
addNum ++;
}
})
data.num = 1;
for(let num = 1;num <= data.input_num;num ++){
let skuKey = 'sku_' + data.sku_id + '_item_' + data.item_id + '_' + addNum;
billingGoodsData[skuKey] = this.$util.deepClone(data);
addNum ++;
}
}else{
data.num = data.input_num;
let skuKey = 'sku_' + data.sku_id + '_item_' + data.item_id;
if(billingGoodsData.hasOwnProperty(skuKey)){
data.num += billingGoodsData[skuKey].num;
}
billingGoodsData[skuKey] = this.$util.deepClone(data);
}
});
this.$store.commit('billing/setGoodsData', billingGoodsData);
this.memberCardData.selected = {};
},
/**
* 数量减
* @param {Object} data
*/
itemDec(data) {
let currData = this.memberCardData.currData;
if (this.memberCardData.selected['item_' + data.item_id].input_num > 1) {
this.memberCardData.selected['item_' + data.item_id].input_num -= 1;
if (data.card_type == 'commoncard') {
currData.total_use_num -= 1;
}
this.$forceUpdate();
}
},
/**
* 数量加
* @param {Object} data
*/
itemInc(data) {
let currData = this.memberCardData.currData;
if (data.card_type == 'commoncard') {
if ((currData.total_num - currData.total_use_num - 1) < 0) return;
} else if (data.card_type == 'oncecard') {
if ((data.num - data.use_num - this.memberCardData.selected['item_' + data.item_id].input_num - 1) < 0) return;
}
if (data.card_type == 'commoncard') {
currData.total_use_num += 1;
}
this.memberCardData.selected['item_' + data.item_id].input_num += 1;
this.$forceUpdate();
},
checkStatus(data) {
let currData = this.memberCardData.currData;
if (data.card_type == 'commoncard') {
return currData.total_num > currData.total_use_num;
} else if (data.card_type == 'oncecard') {
return data.num > data.use_num;
}
return true;
}
}
}

View File

@@ -0,0 +1,376 @@
.container {
height: 100%;
}
.header {
height: 0.66rem;
line-height: 0.66rem;
text-align: left;
border-bottom: 0.01rem solid #e6e6e6;
color: #303133;
font-size: 0.14rem;
}
.info-wrap {
display: flex;
flex-direction: column;
height: 6.5rem;
padding: 0 0.2rem;
box-sizing: border-box;
.headimg-content {
display: flex;
align-items: center;
margin-top: 0.2rem;
.headimg {
width: 0.7rem;
height: 0.7rem;
border-radius: 50%;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.header-info {
margin-left: 0.15rem;
width: calc(100% - 0.85rem);
.name {
font-size: 0.16rem;
color: #303133;
text {
background: #ffffff;
border: 0.01rem solid $primary-color;
border-radius: 0.02rem;
font-size: 0.12rem;
color: $primary-color;
margin-left: 0.15rem;
padding: 0.01rem 0.04rem;
}
}
.header-info-item {
display: flex;
align-items: center;
margin-top: 0.1rem;
justify-content: space-between;
view {
text-align: left;
font-size: 0.14rem;
color: #303133;
opacity: 0.9;
}
}
}
}
}
.empty {
text-align: center;
padding-top: 1.2rem;
margin: 0 auto;
image {
width: 2rem;
}
.tips {
color: #999;
margin-top: 0.15rem;
}
}
.member-card-wrap {
flex: 1;
height: 0;
display: flex;
flex-direction: column;
.card-wrap {
flex: 1;
height: 0;
display: flex;
padding-top: 0.2rem;
margin-bottom: 0.2rem;
}
.card-list {
width: 2rem;
border: 0.01rem solid #e6e6e6;
margin-right: 0.1rem;
padding: 0.1rem 0;
.card-item {
width: calc(100% - 0.2rem);
height: 1rem;
border: 0.01rem solid $primary-color;
margin: 0 0.1rem 0.1rem 0.1rem;
box-sizing: border-box;
border-radius: 0.05rem;
cursor: pointer;
padding: 0.15rem 0.1rem;
display: flex;
flex-direction: column;
justify-content: space-between;
background-color: var(--primary-color-light-8);
&.active {
background-color: $primary-color;
color: #fff;
.card-name {
color: #fff;
}
.info {
color: #fff;
}
}
.card-name {
font-weight: bold;
}
.info {
display: flex;
justify-content: space-between;
color: #999;
& > view {
font-size: 0.12rem;
}
}
}
}
.item-list {
flex: 1;
border: 0.01rem solid #e6e6e6;
display: flex;
flex-direction: column;
width: 0;
.content {
padding: 0 0.1rem;
}
.empty {
padding-top: 0.8rem;
}
.title {
line-height: 0.3rem;
padding: 0.1rem;
display: flex;
justify-content: space-between;
.num {
color: $primary-color;
margin: 0 0.02rem;
}
}
.button-wrap {
display: flex;
background-color: #fff;
height: 0.5rem;
line-height: 0.5rem;
align-items: center;
justify-content: flex-end;
box-shadow: 0 0.04rem 0.12rem 0 rgba(0, 0, 0, 0.1);
padding: 0.1rem 0;
button {
height: 0.4rem;
line-height: 0.4rem;
margin: 0 0.1rem 0 0;
}
}
.item-wrap {
flex: 1;
height: 0;
display: flex;
.uni-flex {
flex-wrap: wrap;
}
}
.card-item {
display: flex;
width: calc(50% - 0.05rem);
padding: 0.1rem;
border: 0.01rem solid #eee;
border-radius: 0.03rem;
cursor: pointer;
transition: all 0.3s;
box-sizing: border-box;
margin-bottom: 0.1rem;
.image {
width: 0.7rem;
height: 0.7rem;
margin-right: 0.1rem;
overflow: hidden;
image {
width: 100%;
}
}
.info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
width: 0;
.num {
margin-top: 0.05rem;
color: #999;
font-size: 0.12rem;
}
.price {
font-size: 0.14rem;
color: #fe2278;
line-height: 1;
.util {
font-size: 0.12rem;
}
}
.name {
word-break: break-all;
text-overflow: ellipsis;
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.5;
.tag {
border-radius: 0.02rem;
padding: 0.01rem 0.05rem;
background-color: var(--primary-color-light-8);
color: $primary-color;
font-size: 0.12rem;
margin-right: 0.05rem;
}
}
}
}
.action-wrap {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.12rem;
margin-top: 0.05rem;
height: 0.25rem;
}
.number-wrap {
display: none;
height: 0.25rem;
border: 0.01rem solid #e6e6e6;
border-radius: 0.02rem;
overflow: hidden;
input {
height: 0.25rem;
line-height: 0.25rem;
width: 0.25rem;
border: 1px solid #e6e6e6;
text-align: center;
background: #fff;
font-size: 0.12rem;
}
.iconfont {
height: 0.25rem;
width: 0.25rem;
text-align: center;
line-height: 0.25rem;
background: #f5f5f5;
}
}
.card-item.active {
background-color: var(--primary-color-light-2);
.num {
color: #fff;
}
.price {
color: #fff;
}
.name {
color: #fff;
.tag {
background-color: #fff;
}
}
.number-wrap {
display: flex;
}
}
.not-select {
background: #eee;
cursor: not-allowed;
}
}
}
// pop弹框
.pop-box {
background: #ffffff;
width: 8rem;
height: 7rem;
.pop-header {
padding: 0 0.15rem 0 0.2rem;
height: 0.5rem;
line-height: 0.5rem;
border-bottom: 0.01rem solid #f0f0f0;
font-size: 0.14rem;
color: #333;
overflow: hidden;
border-radius: 0.02rem 0.2rem 0 0;
box-sizing: border-box;
display: flex;
justify-content: space-between;
.pop-header-text {
}
.pop-header-close {
cursor: pointer;
text {
font-size: 0.18rem;
}
}
}
.pop-content {
height: calc(100% - 1rem);
overflow-y: scroll;
padding: 0.1rem 0.2rem;
box-sizing: border-box;
}
}

View File

@@ -0,0 +1,129 @@
<template>
<view class="container">
<uni-popup ref="memberCardPopup">
<view class="pop-box member-info-wrap">
<view class="pop-header">
<view class="pop-header-text">会员卡项</view>
<view class="pop-header-close" @click="$refs.memberCardPopup.close()">
<text class="iconguanbi1 iconfont"></text>
</view>
</view>
<view class="info-wrap" v-if="globalMemberInfo">
<view class="headimg-content">
<view class="headimg">
<image :src="globalMemberInfo.headimg ? $util.img(globalMemberInfo.headimg) : $util.img(defaultImg.head)" @error="globalMemberInfo.headimg = defaultImg.head"/>
</view>
<view class="header-info">
<view class="name">
{{ globalMemberInfo.nickname }}
<text v-if="globalMemberInfo.member_level">{{ globalMemberInfo.member_level_name }}</text>
</view>
<view class="header-info-item">
<view>电话{{ globalMemberInfo.mobile }}</view>
<view>性别{{ globalMemberInfo.sex == 0 ? '未知' : globalMemberInfo.sex == 1 ? '男' : '女' }}</view>
<view>生日{{ globalMemberInfo.birthday }}</view>
<view>注册时间{{ globalMemberInfo.reg_time | timeFormat }}</view>
</view>
</view>
</view>
<view class="member-card-wrap">
<view class="card-wrap">
<scroll-view scroll-y="true" class="card-list" @scrolltolower="getMemberCard()">
<block v-if="memberCardData.list.length">
<view class="card-item" :class="{ active: memberCardData.index == index }" v-for="(item, index) in memberCardData.list" :key="index" @click="selectMemberCard(item, index)">
<view class="card-name">{{ item.goods_name }}</view>
<view class="info">
<view v-if="item.total_num > 0">可用{{ item.total_num - item.total_use_num }}</view>
<view v-else>不限次</view>
<view v-if="item.end_time > 0">{{ $util.timeFormat(item.end_time, 'Y/m/d') }}</view>
<view v-else>长期有效</view>
</view>
</view>
</block>
<view v-else class="empty">
<image src="@/static/card/card_empty.png" mode="widthFix"/>
<view class="tips">暂无可用卡项</view>
</view>
</scroll-view>
<view class="item-list">
<view class="title">
<view>可用服务/商品</view>
<view v-if="memberCardData.currData.card_type == 'commoncard'">
<text>以下服务/商品剩余可用</text>
<text class="num">{{ memberCardData.currData.total_num - memberCardData.currData.total_use_num }}</text>
<text></text>
</view>
</view>
<scroll-view scroll-y="true" class="item-wrap">
<view class="uni-flex justify-between content" v-if="memberCardData.currData.item_list">
<view class="card-item" :class="{
active: memberCardData.selected['item_' + item.item_id],
'not-select': !checkStatus(item) && !memberCardData.selected['item_' + item.item_id]
}" @click="selectMemberCardItem(item, index)" v-for="(item, index) in memberCardData.currData.item_list">
<view class="image">
<image v-if="item.sku_image == '@/static/goods/goods.png'" src="@/static/goods/goods.png" mode="widthFix"/>
<image v-else :src="$util.img(item.sku_image.split(',')[0], { size: 'small' })" @error="item.sku_image = '@/static/goods/goods.png'" mode="widthFix"/>
</view>
<view class="info">
<view>
<view class="name">
<text class="tag">{{ item.is_virtual ? '服务' : '商品' }}</text>
<text>{{ item.sku_name }}</text>
</view>
<block v-if="memberCardData.currData.card_type != 'commoncard'">
<view class="num" v-if="item.num > 0">剩余可用{{ item.num - item.use_num }}</view>
<view class="num" v-else>不限次</view>
</block>
</view>
<view class="action-wrap">
<view class="price">
<text class="util"></text>
{{ item.price }}
</view>
<view class="number-wrap" v-if="memberCardData.selected['item_' + item.item_id]">
<text class="iconfont iconjian" @click.stop="itemDec(memberCardData.selected['item_' + item.item_id])"></text>
<input type="number" v-model="memberCardData.selected['item_' + item.item_id].input_num" />
<text class="iconfont iconjia" @click.stop="itemInc(memberCardData.selected['item_' + item.item_id])"></text>
</view>
</view>
</view>
</view>
</view>
<view class="empty" v-else>
<image src="@/static/goods/goods_empty.png" mode="widthFix"/>
<view class="tips">暂无相关数据</view>
</view>
</scroll-view>
<view class="button-wrap">
<button type="default" class="primary-btn" :disabled="memberCardData.itemIndex == -1" @click="selectGoods()">加入购物车</button>
</view>
</view>
</view>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import uniDataCheckbox from '@/components/uni-data-checkbox/uni-data-checkbox.vue';
import UniPopup from "../uni-popup/uni-popup";
import index from './index.js';
export default {
name: 'nsMember',
components: {
UniPopup,
uniDataCheckbox
},
mixins: [index]
};
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>