536 lines
16 KiB
Vue
536 lines
16 KiB
Vue
<template>
|
||
<view class="b-nx-sku-popup">
|
||
<u-popup :show="show" @close="show = false" round="20" closeable zIndex="20080">
|
||
<view class="commodity-sku">
|
||
<!-- 商品图 -->
|
||
<view class="commodity-sku-cover">
|
||
<!-- 封面 -->
|
||
<image class="img" :src="skuinfor['product_img']" mode="widthFix"></image>
|
||
<!-- 名称-数量 -->
|
||
<view class="commodity-sku-cover-name">
|
||
<view class="commodity-sku-cover-name-title" :style="{color:Brand()['ThemeColor']}">
|
||
{{skuinfor['product_name']}}
|
||
</view>
|
||
<view class="commodity-sku-cover-name-cart">
|
||
<image class="img" :src="qnyurl('reduce.png','rx')" mode="" @tap="reducequantity()"></image>
|
||
<view class="num" style="color: #a7d500;">
|
||
{{skuinfor['num']}}
|
||
</view>
|
||
<image class="img" :src="qnyurl('add.png','rx')" mode="" @tap="Addquantity()"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<view class="commodity-sku-option" v-if="skuinfor['details']">
|
||
<scroll-view :scroll-top="0" scroll-y="true" class="scroll-Y" style="height: 400rpx;">
|
||
<view class="commodity-sku-option-item" v-if="skuinfor['details']['accessories']['length']">
|
||
<view class="commodity-sku-option-item-label">
|
||
加料
|
||
</view>
|
||
<view class="commodity-sku-option-item-values">
|
||
<template v-for="(item,index) in skuinfor['details']['accessories']">
|
||
<view :class="{'commodity-sku-option-item-values-Disable':item['disable'],
|
||
'commodity-sku-option-item-values-activation':item['checked']}" @tap="accessoriesClick(item)"
|
||
class="commodity-sku-option-item-values-item" :key="index">
|
||
<text>{{item['name']}}</text>
|
||
<text v-if="(+item['price']) > 0 ">¥{{_amount(item['price'])}}</text>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
<template v-for="(item,index) in skuinfor['details']['spu_specs']">
|
||
<view class="commodity-sku-option-item" :key="index" v-if="item['code']">
|
||
<view class="commodity-sku-option-item-label">
|
||
{{item['name']}}
|
||
</view>
|
||
<view class="commodity-sku-option-item-values">
|
||
<template v-for="(item2,index2) in item['values']">
|
||
<view @tap="skuClick(index,index2)"
|
||
:class="{'commodity-sku-option-item-values-activation':item2['checked']}"
|
||
class="commodity-sku-option-item-values-item" :key="index2">
|
||
<text>{{item2['name']}}</text>
|
||
<text v-if="(+item2['price']) > 0 ">¥{{__amount(item2['price'])}}</text>
|
||
</view>
|
||
</template>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
</scroll-view>
|
||
</view>
|
||
<view class="commodity-sku-Infor">
|
||
<view class="commodity-sku-Infor-left">
|
||
<view class="commodity-sku-Infor-left-Price">
|
||
<text class="text1">¥</text>
|
||
<text class="text2">{{skuinfor['adj_pay'] * skuinfor['num']}}</text>
|
||
</view>
|
||
<view class="commodity-sku-Infor-left-sku">
|
||
<view class="">
|
||
{{Infos['sku']}}
|
||
</view>
|
||
<view class="">
|
||
加料:{{Infos['accessories']}}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- Addcommodity方法中不可设置形参,因为点击事件默认第一个参数就是点击事件的各种参数并不是形参中所设置的默认值 -->
|
||
<!-- 所以在点击时手动传入skuinfor参数 -->
|
||
<view class="commodity-sku-Infor-right" @tap="Addcommodity">
|
||
加入购物车
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
mapGetters
|
||
} from 'vuex';
|
||
import mixin from '@/static/js/mixin/mixin.js'
|
||
import restaurantmixins from '@/static/js/mixin/restaurantmixins.js'
|
||
export default {
|
||
mixins: [mixin, restaurantmixins],
|
||
name: "b-nx-sku-popup",
|
||
data() {
|
||
return {
|
||
// 弹框显示/隐藏
|
||
show: false,
|
||
// 弹框商品详情
|
||
skuinfor: {},
|
||
// 规格文字
|
||
skutext: '',
|
||
// 所选择的辅料组合数据,包含展示文字以及code
|
||
Infos: {},
|
||
// 所选的辅料
|
||
skuInfos:[],
|
||
};
|
||
},
|
||
computed: {
|
||
...mapGetters({
|
||
GetcommodityInfor: 'shopping/GetcommodityInfor'
|
||
}),
|
||
},
|
||
watch: {
|
||
// 计算属性获取到的弹框详情数据不可直接修改,所以重新赋值便于修改数量
|
||
GetcommodityInfor(value) {
|
||
this['skuinfor'] = JSON.parse(JSON.stringify(value));
|
||
this.skuInit();
|
||
},
|
||
},
|
||
|
||
mounted() {
|
||
// 默认选择
|
||
// this['spuCode'] = this['skuinfor']['spu_specs'][0]['code'];
|
||
|
||
},
|
||
methods: {
|
||
/**
|
||
* @添加数量
|
||
* */
|
||
Addquantity(num = 1) {
|
||
this['skuinfor']['num'] += num;
|
||
},
|
||
/**
|
||
* @选择规格数量减
|
||
* */
|
||
reducequantity(num = 1) {
|
||
if (this['skuinfor']['num'] == 1) return;
|
||
this['skuinfor']['num'] -= num;
|
||
},
|
||
|
||
/**
|
||
* @加入购物车
|
||
* */
|
||
Addcommodity() {
|
||
let self = this;
|
||
// console.log(self['skuinfor'],'skuinfor');
|
||
// return;
|
||
uni.$u.debounce(() => {
|
||
self.ADD_CART({
|
||
commodity: self['skuinfor'],
|
||
quantity: self['skuinfor']['num']
|
||
}).then(() => {
|
||
// console.log('加入成功');
|
||
self['show'] = false;
|
||
// console.log(self['show'],'show');
|
||
});
|
||
}, 800, true)
|
||
},
|
||
|
||
/**
|
||
* @规格选择
|
||
* */
|
||
skuClick(index1, index2) {
|
||
// 将当前点击的类型规格高亮状态改变,其他的设置为不高亮
|
||
this['skuinfor']['details']['spu_specs'][index1]['values'].map((item, index) => {
|
||
if (index2 == index) {
|
||
item['checked'] = true;
|
||
} else {
|
||
item['checked'] = false;
|
||
}
|
||
});
|
||
|
||
this.__skuintegration__();
|
||
},
|
||
|
||
/**
|
||
* 规格匹配辅助方法
|
||
* 先将可组合的辅料(sku_infos)code全部转为字符串,利用字符串对比方式对比用户所选择的组合
|
||
* */
|
||
skuInit() {
|
||
for (let i = 0; i < this['skuinfor']['details']['sku_infos']['length']; i++) {
|
||
let item = this['skuinfor']['details']['sku_infos'][i];
|
||
let _KYE = "name";
|
||
// 文字排序
|
||
let _SKU = item['specs'].concat([]).sort((a, b) => a[_KYE].localeCompare(b[_KYE])).map(item => item[
|
||
'spec_code']).join('_');
|
||
item['skuCode'] = _SKU;
|
||
};
|
||
|
||
/**
|
||
* 为加料选项添加是否可选,用于对用户选择辅料之后加料选项是否可选做准备
|
||
* 默认不选中
|
||
* */
|
||
if(this['skuinfor']['details']['accessories']['length']){
|
||
this['skuinfor']['details']['accessories'].map(item => {
|
||
// 是否禁用
|
||
item['disable'] = false;
|
||
// 是否选择
|
||
item['checked'] = false;
|
||
});
|
||
}
|
||
|
||
this.__skuintegration__();
|
||
},
|
||
|
||
|
||
/**
|
||
* 重点逻辑
|
||
* */
|
||
__skuintegration__() {
|
||
let self = this;
|
||
const _item = this['skuinfor']['details'];
|
||
// 该方法中每一个Promise所返回的都为一个步骤结束所得到的结果
|
||
/**
|
||
* 将spu_specs中所有辅料合并到一个数组中,并且添加新属性skuname
|
||
* 用于筛选出已经选择的(或者默认选中的)
|
||
* */
|
||
this.choice().then(_newSupItem => {
|
||
// 取出_newSupItem中checked为选中状态的每一项
|
||
this['skuInfos'] = _newSupItem.filter(item => item['checked']);
|
||
console.log(this['skuInfos'], '选择的辅料');
|
||
return self.codeSort();
|
||
}).then(skuArray=>{
|
||
console.log(skuArray, '选择的辅料在sku_infos中的数据包');
|
||
this['Infos'] = skuArray;
|
||
this.$forceUpdate();
|
||
return self.accessoriesmutex();
|
||
}).then(res=>{
|
||
console.log(res,'加料');
|
||
return this.price();
|
||
}).then(res=>{
|
||
console.log(res,'价格');
|
||
this.ExhibitionText();
|
||
})
|
||
|
||
},
|
||
|
||
// 计算价格
|
||
price() {
|
||
return new Promise(resolve => {
|
||
let skupay = 0;
|
||
try{
|
||
skupay = this['skuinfor']['details']['accessories'].map(item => {
|
||
if (item['checked']) {
|
||
return +item['price']
|
||
};
|
||
return 0;
|
||
}).reduce(function(previousValue, currentValue) {
|
||
return previousValue + currentValue;
|
||
});
|
||
}catch(e){
|
||
//TODO handle the exception
|
||
}
|
||
console.log(this['Infos'])
|
||
let price = +this['Infos']['price'] + skupay;
|
||
|
||
// 加价价格
|
||
// this['skuinfor']['add_price'] = skupay;
|
||
// 实际价格
|
||
// this['skuinfor']['adj_pay'] = price;
|
||
// 加价价格
|
||
this.$set(this['skuinfor'], 'adj_pay', price);
|
||
// 实际价格
|
||
this.$set(this['skuinfor'], 'add_price', skupay);
|
||
// 计算价格之后匹配文字
|
||
resolve(price);
|
||
})
|
||
|
||
},
|
||
|
||
// 点击加料
|
||
accessoriesClick(t) {
|
||
if (t['disable']) return;
|
||
let index = this['skuinfor']['details']['accessories'].findIndex(item => item['code'] == t['code']);
|
||
let checked = !this['skuinfor']['details']['accessories'][index]['checked'];
|
||
this.$set(this['skuinfor']['details']['accessories'][index], 'checked', checked);
|
||
this.price().then(res=>{
|
||
this.ExhibitionText();
|
||
this.$forceUpdate();
|
||
});
|
||
|
||
// console.log(this['skuinfor']['details']['accessories']);
|
||
},
|
||
|
||
// 处理选择数据
|
||
choice() {
|
||
return new Promise(resolve => {
|
||
const _newSupItemArr = this['skuinfor']['details']['spu_specs'].map(item => {
|
||
// 过滤掉吸管
|
||
if (item['code']) {
|
||
item['values'].map(_item => {
|
||
_item['skuname'] = item['name'];
|
||
});
|
||
return item['values']
|
||
};
|
||
return [];
|
||
});
|
||
const newSupItem = _newSupItemArr.flatMap(item => item);
|
||
resolve(newSupItem)
|
||
})
|
||
},
|
||
|
||
// 选中辅料组合code与可排列组合code排序,方便后面对比
|
||
codeSort(){
|
||
return new Promise(resolve=>{
|
||
/**
|
||
* sku_infos为可组合的辅料数组,为防止用户所选择的辅料组合与可选择的辅料组合的code对比匹配出现问题,利用skuname字段对两个组合经行排序
|
||
* 保证所对比的code前后顺序一直
|
||
* 注意:如果直接取出code然后转为字符串会有所不同。因为spu_specs与sku_infos的规格排序不一样
|
||
* */
|
||
let _KYE = "skuname";
|
||
let _K = this['skuInfos'].concat([]).sort((a, b) => a[_KYE].localeCompare(b[_KYE]));
|
||
let _SKU = _K.map(item => item['code']).join('_');
|
||
// 利用用户已经选择的排列组合与数据给出的可匹配的组合对比,取出整个对象
|
||
const res = this['skuinfor']['details']['sku_infos'].find(item => item['skuCode'] == _SKU);
|
||
resolve(res);
|
||
})
|
||
},
|
||
|
||
// 辅料与加料互斥处理
|
||
accessoriesmutex(){
|
||
return new Promise(resolve=>{
|
||
// 取出当前辅料互斥匹配规则
|
||
let spuSpecsCode = [];
|
||
for (let x = 0; x < this['skuinfor']['details']['allow_rules']['length']; x++) {
|
||
let item = this['skuinfor']['details']['allow_rules'][x];
|
||
for (let l = 0; l < item['length']; l++) {
|
||
if (item[l] == this['Infos']['code']) {
|
||
spuSpecsCode = item;
|
||
}
|
||
}
|
||
};
|
||
|
||
// 处理加料禁用
|
||
let skuArray = [];
|
||
{
|
||
for (let k = 0; k < this['skuinfor']['details']['accessories']['length']; k++) {
|
||
let accItem = this['skuinfor']['details']['accessories'][k];
|
||
if (spuSpecsCode.indexOf(accItem['code']) == -1) {
|
||
accItem['disable'] = true;
|
||
accItem['checked'] = false;
|
||
continue;
|
||
};
|
||
// 因为只在初始化时将disable设了状态,当用户再次选择之后如果已经设置为false的状态需要转换回来
|
||
accItem['disable'] = false;
|
||
skuArray.push(accItem);
|
||
};
|
||
};
|
||
console.log(this['skuinfor']['details']['accessories'],'*-*-*-');
|
||
|
||
this.$forceUpdate();
|
||
resolve(skuArray)
|
||
})
|
||
},
|
||
|
||
|
||
// 展示文字处理
|
||
ExhibitionText(){
|
||
// 辅料展示文字
|
||
let _KYE = "skuname";
|
||
let KYE_ = "name";
|
||
let _K = this['skuInfos'].concat([]).sort((a, b) => a[_KYE].localeCompare(b[_KYE]));
|
||
let _ACC = this['skuinfor']['details']['accessories'].filter(item => { return item['checked'] });
|
||
// 展示文字处理
|
||
const _SKUTEXT = _K.map(item => item[KYE_]).join('/');
|
||
const _ACCTEXT = _ACC.map(item => item['name']).join('/');
|
||
// CODE处理
|
||
const _ACCCODE = _ACC.map(item => item['code']).join(',');
|
||
// 展示数据
|
||
this.$set(this['Infos'],'sku',_SKUTEXT);
|
||
this.$set(this['Infos'],'accessories',_ACCTEXT);
|
||
let skustr_ = `${this['Infos']['sku']}/${this['Infos']['accessories']}`;
|
||
// 如果只有一个规格可选则不显示最后一位的/
|
||
if(skustr_[skustr_.length-1] == '/'){
|
||
skustr_ = skustr_.substr(0,skustr_['length']-1)
|
||
};
|
||
// 设置提交数据
|
||
this.$set(this['skuinfor'],'sku',`${this['Infos']['sku']}/${this['Infos']['accessories']}`);
|
||
this.$set(this['skuinfor'],'sku_code',`${this['Infos']['code']}|${_ACCCODE}`);
|
||
|
||
console.log('111111111')
|
||
},
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss">
|
||
// 规格弹框样式
|
||
.commodity-sku {
|
||
&-cover {
|
||
// height: 560rpx;
|
||
height: auto;
|
||
position: relative;
|
||
|
||
.img {
|
||
width: 100%;
|
||
}
|
||
|
||
&-title {
|
||
color: #333333;
|
||
font-size: 34rpx;
|
||
}
|
||
|
||
&-name {
|
||
position: absolute;
|
||
left: 0;
|
||
bottom: 0;
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
color: #ffffff;
|
||
padding: 10rpx 32rpx;
|
||
background-color: rgba(255, 255, 255, 0.5);
|
||
|
||
&-cart {
|
||
flex: 1;
|
||
height: 60rpx;
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
font-size: 36rpx;
|
||
align-items: center;
|
||
|
||
.num {
|
||
max-width: 100rpx;
|
||
min-width: 100rpx;
|
||
text-align: center;
|
||
color: #000000;
|
||
}
|
||
|
||
.img {
|
||
width: 42rpx;
|
||
height: 42rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&-option {
|
||
padding: 32rpx;
|
||
|
||
&-item {
|
||
width: 100%;
|
||
// height: 70rpx;
|
||
font-size: 26rpx;
|
||
margin-bottom: 32rpx;
|
||
// display: flex;
|
||
// justify-content: flex-start;
|
||
// margin-bottom: 15rpx;
|
||
|
||
&-label {
|
||
min-width: 112rpx;
|
||
height: 100%;
|
||
color: #999999;
|
||
line-height: 70rpx;
|
||
}
|
||
|
||
&-values {
|
||
width: 100%;
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
|
||
&-activation {
|
||
background: rgba(167, 213, 0, 0.2) !important;
|
||
border: 1rpx solid rgba(167, 213, 0, 0.5) !important;
|
||
color: rgb(167, 213, 0) !important;
|
||
}
|
||
|
||
&-Disable {
|
||
background-color: #adadad33 !important;
|
||
border: 1rpx solid #adadad33 !important;
|
||
color: #939393 !important;
|
||
}
|
||
|
||
&-item {
|
||
// min-width: 112rpx;
|
||
padding: 0 20rpx;
|
||
height: 100%;
|
||
line-height: 70rpx;
|
||
background: #F7F8FA;
|
||
border-radius: 6rpx;
|
||
margin-bottom: 20rpx;
|
||
text-align: center;
|
||
margin-right: 15rpx;
|
||
border: 1rpx solid #F7F8FA;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
&-Infor {
|
||
width: 100%;
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 32rpx;
|
||
border-top: 1rpx solid rgba(102, 102, 102, 0.1);
|
||
|
||
&-left {
|
||
&-Price {
|
||
color: #FF780F;
|
||
|
||
.text1 {
|
||
font-size: 24rpx;
|
||
}
|
||
|
||
.text2 {
|
||
font-size: 36rpx;
|
||
}
|
||
}
|
||
|
||
&-sku {
|
||
color: #666666;
|
||
font-size: 22rpx;
|
||
}
|
||
}
|
||
|
||
&-right {
|
||
width: 254rpx;
|
||
height: 86rpx;
|
||
max-width:254rpx;
|
||
max-height:86rpx;
|
||
min-width:254rpx;
|
||
min-height:86rpx;
|
||
background: linear-gradient(-77deg, #a7d500, #d0dbaa);
|
||
box-shadow: 0 6rpx 8rpx 0 rgba(74, 111, 231, 0.2300);
|
||
border-radius: 43rpx;
|
||
text-align: center;
|
||
line-height: 86rpx;
|
||
color: #ffffff;
|
||
}
|
||
}
|
||
}
|
||
</style>
|