|
|
<!--
|
|
|
* @Author: ch
|
|
|
* @Date: 2022-03-24 11:30:55
|
|
|
* @LastEditors: ch
|
|
|
* @LastEditTime: 2022-05-17 22:21:10
|
|
|
* @Description: file content
|
|
|
-->
|
|
|
<template>
|
|
|
<u-popup :show="visible" round="24rpx" closeable @close="close">
|
|
|
<view class="sku-popup">
|
|
|
<view class="product-info">
|
|
|
<!-- <image class="product-info--img" src="https://msb-edu-dev.oss-cn-beijing.aliyuncs.com/test/1.png"/> -->
|
|
|
<image class="product-info--img" :src="goodsInfo.pictureList[0]"/>
|
|
|
<view>
|
|
|
<view v-if="curSku.sellPrice" class="product-info--price">¥{{curSku.sellPrice}}</view>
|
|
|
<view v-else class="product-info--price">
|
|
|
¥{{activityStatus === 'startActivity' ? goodsInfo.productActivityVO.activityPrice : goodsInfo.startingPrice}}
|
|
|
</view>
|
|
|
<view class="product-info--sku">{{curSku.name}}</view>
|
|
|
<view>库存:{{curSku.stock}}</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="attr-group" v-for="(item, index) in attributeGroupList" :key="item.id">
|
|
|
<text class="attr-name">{{item.name}}</text>
|
|
|
<view class="attr-items">
|
|
|
<text class="attr-item" :class="{'attr-item__active' : i.active, 'attr-item__disabled' : i.disabled}"
|
|
|
v-for="i in item.attributes" :key="i.symbol"
|
|
|
@click="handleAttrItem(i, index)"
|
|
|
>{{i.name}}</text>
|
|
|
</view>
|
|
|
</view>
|
|
|
<view class="sku-num">
|
|
|
<view class="sku-num--single-box">
|
|
|
<template>
|
|
|
<text>数量</text>
|
|
|
<text class="sku-num--single" v-if="goodsInfo.singleBuyLimit > 0">限购:{{goodsInfo.singleBuyLimit}}</text>
|
|
|
</template>
|
|
|
</view>
|
|
|
<u-number-box :min="1" :max="maxBuyNum" button-size="40rpx" bgColor="#F5F6FA"
|
|
|
v-model="curBuyNum" >
|
|
|
<text slot="minus" class="cart-item--stepper-icon">-</text>
|
|
|
<text slot="plus" class="cart-item--stepper-icon">+</text>
|
|
|
</u-number-box>
|
|
|
</view>
|
|
|
<view class="footer">
|
|
|
<view class="btn-bg" v-if="mode == 1">
|
|
|
<UiButton class="btn" @click="addCart" size="max" :disable="curSku.stock == 0">加入购物车</UiButton>
|
|
|
<UiButton class="btn btn__buy" @click="buyNow" size="max" :disable="curSku.stock == 0">立即购买</UiButton>
|
|
|
</view>
|
|
|
<UiButton v-else class="btn__confirm" type="gradual" size="max" @click="confirm">确认</UiButton>
|
|
|
</view>
|
|
|
</view>
|
|
|
</u-popup>
|
|
|
</template>
|
|
|
|
|
|
<script>
|
|
|
import UiButton from '@/components/UiButton.vue';
|
|
|
import {ApiPutAddCart} from '@/common/api/cart';
|
|
|
|
|
|
export default {
|
|
|
components: { UiButton },
|
|
|
props: {
|
|
|
// true 组件显示 false 组件隐藏
|
|
|
visible : {
|
|
|
type : Boolean,
|
|
|
default : false
|
|
|
},
|
|
|
// 模式 1:都显示 2:只显示购物车 3:只显示立即购买
|
|
|
mode: {
|
|
|
type: Number,
|
|
|
default: 1,
|
|
|
},
|
|
|
// 商品详情信息
|
|
|
goodsInfo: {
|
|
|
type: Object,
|
|
|
default: {},
|
|
|
},
|
|
|
// 商品sku信息
|
|
|
skuInfo : {
|
|
|
type : Array,
|
|
|
default : []
|
|
|
},
|
|
|
// 活动状态
|
|
|
activityStatus : {
|
|
|
type : String,
|
|
|
default : 'noActivity'
|
|
|
}
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
// 属性组数据,因为会修改数据,不能直接操作props中传入的数据
|
|
|
attributeGroupList : [],
|
|
|
// 数量
|
|
|
curBuyNum : 1,
|
|
|
};
|
|
|
},
|
|
|
watch : {
|
|
|
goodsInfo(newData){
|
|
|
if(newData.attributeGroupList){
|
|
|
this.attributeGroupList = newData.attributeGroupList;
|
|
|
// 请求数据返回后设置默认选中规格
|
|
|
if(this.skuInfo.length){
|
|
|
this.setDefaultAttr();
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
skuInfo(newData){
|
|
|
// 请求数据返回后设置默认选中规格
|
|
|
if(newData.length){
|
|
|
this.setDefaultAttr();
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
computed : {
|
|
|
/**
|
|
|
* 当前选中SKU,根据选中规格计算
|
|
|
*/
|
|
|
curSku(){
|
|
|
return this.skuInfo.find(i => i.attributeSymbolList === this.selectedSymbol.join(',')) || {};
|
|
|
},
|
|
|
// [1,.,3]
|
|
|
selectedSymbol(){
|
|
|
return this.attributeGroupList.map(item => {
|
|
|
const activeAttr = item.attributes.find(i => i.active);
|
|
|
return activeAttr ? activeAttr.symbol : '.'
|
|
|
}).filter(i => i)//.sort();
|
|
|
},
|
|
|
/**
|
|
|
* 最大可购买数量
|
|
|
* 1、有限购则对比限购跟库存,取最小值
|
|
|
* 2、没限购取库存
|
|
|
*/
|
|
|
maxBuyNum(){
|
|
|
const singleBuyLimit = this.goodsInfo.singleBuyLimit;
|
|
|
const stock = this.curSku.stock;
|
|
|
return singleBuyLimit ? Math.min(singleBuyLimit, stock || 1) : stock;
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
/**
|
|
|
* 设置默认选中规格
|
|
|
*/
|
|
|
setDefaultAttr(){
|
|
|
const curSku = this.skuInfo.find(i => i.stock > 0);
|
|
|
if(!curSku){
|
|
|
return false
|
|
|
}
|
|
|
this.attributeGroupList.forEach((item, index) => {
|
|
|
for(let i of item.attributes){
|
|
|
if(curSku.attributeSymbolList.includes(i.symbol)){
|
|
|
this.$set(i,'active', true);
|
|
|
this.setDisabledItem(i, index, true);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
this.$emit('input',this.curSku);
|
|
|
},
|
|
|
/**
|
|
|
* 点击属性项,设置选中和禁用项
|
|
|
*/
|
|
|
handleAttrItem(item, groupIndex){
|
|
|
// 禁用选项
|
|
|
if(item.disabled){
|
|
|
return false;
|
|
|
}
|
|
|
// 每次重选规格,购买数量都置为1
|
|
|
this.curBuyNum = 1;
|
|
|
const active = item.active;
|
|
|
// 把当前选项组的装先置为未选状态
|
|
|
this.attributeGroupList[groupIndex].attributes.forEach(item =>{
|
|
|
this.$set(item,'active', false);
|
|
|
});
|
|
|
// 设置当前点击选项选中
|
|
|
this.$set(item,'active', !active);
|
|
|
this.setDisabledItem(item, groupIndex);
|
|
|
|
|
|
this.$emit('input',this.curSku);
|
|
|
|
|
|
},
|
|
|
|
|
|
/**
|
|
|
* 每次点击选项属性时,计算不可选属性
|
|
|
*/
|
|
|
setDisabledItem(item, groupIndex){
|
|
|
|
|
|
this.attributeGroupList.forEach((group, idx) => {
|
|
|
// 拿到已选项数组,这个是按照项组顺序排序好的缓存数组
|
|
|
let symbolCache = Object.assign([],this.selectedSymbol);
|
|
|
// 跳过当前属性组
|
|
|
if(groupIndex === idx) return false;
|
|
|
// 遍历其他选项组中的选项
|
|
|
group.attributes.forEach( item => {
|
|
|
// 根据选项组下标,补位选项属性
|
|
|
symbolCache[idx] = item.symbol;
|
|
|
const reg = new RegExp(symbolCache.join(','));
|
|
|
// 根据补位选项寻找是否有有效SKU,有则可选,没有则禁用
|
|
|
const res = this.skuInfo.filter(i => {
|
|
|
let v = reg.test(i.attributeSymbolList)
|
|
|
console.log(reg, i.attributeSymbolList , v);
|
|
|
return v
|
|
|
}).find(i => i.stock > 0);
|
|
|
|
|
|
if(res){
|
|
|
item.disabled = false;
|
|
|
}else{
|
|
|
item.disabled = true;
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
},
|
|
|
/**
|
|
|
* 加入购物车
|
|
|
*/
|
|
|
async addCart(){
|
|
|
if(!this.curSku.skuId){
|
|
|
uni.$u.toast('请选择规格~');
|
|
|
return false;
|
|
|
}
|
|
|
const {error, result} = await ApiPutAddCart({
|
|
|
productSkuId : this.curSku.skuId,
|
|
|
productId : this.goodsInfo.id,
|
|
|
number : this.curBuyNum
|
|
|
});
|
|
|
if(error){
|
|
|
uni.$u.toast(error.message);
|
|
|
return false;
|
|
|
}
|
|
|
uni.$u.toast('加入购物车成功~');
|
|
|
this.close();
|
|
|
// this.$Router.push('/cart');
|
|
|
},
|
|
|
/**
|
|
|
* 立即购买
|
|
|
*/
|
|
|
buyNow(){
|
|
|
if(!this.curSku.skuId){
|
|
|
uni.$u.toast('请选择规格~');
|
|
|
return false;
|
|
|
}
|
|
|
let query = {
|
|
|
mode : 'buyNow',
|
|
|
skuId : this.curSku.skuId,
|
|
|
num : this.curBuyNum,
|
|
|
activityType : 1
|
|
|
}
|
|
|
const {productActivityVO} = this.goodsInfo;
|
|
|
if(this.activityStatus === 'startActivity'){
|
|
|
query.activityType = 3;
|
|
|
query.activityId = productActivityVO.activityId;
|
|
|
query.activityTimeId = productActivityVO.activityTimeId;
|
|
|
}
|
|
|
this.$Router.push({
|
|
|
path : '/orderSubmit',
|
|
|
query
|
|
|
})
|
|
|
},
|
|
|
confirm(){
|
|
|
if(this.mode == 2){
|
|
|
this.addCart();
|
|
|
}
|
|
|
if(this.mode == 3){
|
|
|
this.buyNow();
|
|
|
}
|
|
|
},
|
|
|
close(){
|
|
|
this.$emit('update:visible', false);
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
</script>
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
.sku-popup{
|
|
|
padding: 30rpx;
|
|
|
}
|
|
|
.product-info{
|
|
|
display: flex;
|
|
|
font-size: $font-size-base;
|
|
|
color: $color-grey4;
|
|
|
line-height: 42rpx;
|
|
|
&--img{
|
|
|
width: 200rpx;
|
|
|
height: 200rpx;
|
|
|
margin-right: 40rpx;
|
|
|
}
|
|
|
&--price{
|
|
|
font-size: 40rpx;
|
|
|
color: $color-yellow4;
|
|
|
line-height: 48rpx;
|
|
|
margin-bottom: 20rpx;
|
|
|
}
|
|
|
}
|
|
|
.attr-group{
|
|
|
margin-top: 40rpx;
|
|
|
font-size: 30rpx;
|
|
|
}
|
|
|
.attr-items{
|
|
|
display: flex;
|
|
|
flex-wrap: wrap;
|
|
|
padding: 10rpx 0;
|
|
|
}
|
|
|
.attr-item{
|
|
|
background: $color-grey1;
|
|
|
line-height: 70rpx;
|
|
|
border-radius: 100rpx;
|
|
|
border: 1px solid $color-grey1;
|
|
|
color: $color-grey5;
|
|
|
display: block;
|
|
|
min-width: 158rpx;
|
|
|
max-width: 630rpx;
|
|
|
text-align: center;
|
|
|
margin: 20rpx 28rpx 0 0;
|
|
|
padding: 0 20rpx;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
white-space: nowrap;
|
|
|
&__active{
|
|
|
background: #FFF3EE;
|
|
|
border-color: $color-yellow4;
|
|
|
color: $color-yellow3;
|
|
|
}
|
|
|
&__disabled{
|
|
|
color: $color-grey3;
|
|
|
}
|
|
|
}
|
|
|
.sku-num{
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
margin: 40rpx 0;
|
|
|
line-height: 40rpx;
|
|
|
&--single-box{
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
}
|
|
|
&--single{
|
|
|
color: $color-grey4;
|
|
|
margin-left: 10rpx;
|
|
|
font-size: $font-size-base;
|
|
|
display: block;
|
|
|
height: 30rpx;
|
|
|
}
|
|
|
}
|
|
|
.footer{
|
|
|
display: flex;
|
|
|
justify-content: space-between;
|
|
|
.btn-bg{
|
|
|
background: #FFE6D9;
|
|
|
border-radius: 50rpx;
|
|
|
height: 80rpx;
|
|
|
}
|
|
|
.btn{
|
|
|
border: 0;
|
|
|
padding: 0;
|
|
|
border-radius: 0;
|
|
|
width: 340rpx;
|
|
|
font-size: $font-size-base;
|
|
|
color: $color-yellow3;
|
|
|
&::after{
|
|
|
border: 0;
|
|
|
}
|
|
|
&__buy{
|
|
|
width: 350rpx;
|
|
|
background: url('@/static/goods/buy_max.png');
|
|
|
background-size: 350rpx;
|
|
|
color: $color-grey0;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.btn__confirm{
|
|
|
margin: 0;
|
|
|
width: 670rpx;
|
|
|
}
|
|
|
}
|
|
|
</style>
|