feat(sku): addd sku select

This commit is contained in:
21世纪小八路
2024-11-14 23:31:33 +08:00
parent 66e483f53f
commit 290e99d73f
3 changed files with 204 additions and 53 deletions

View File

@@ -141,6 +141,7 @@ export interface GoodsSpecListType {
name ?: string; name ?: string;
select ?: boolean; select ?: boolean;
show ?: boolean; show ?: boolean;
noStock ?: boolean;
} }
export interface GoodsFootprintType { export interface GoodsFootprintType {

View File

@@ -74,6 +74,11 @@
color: #d33123; color: #d33123;
background-color: rgba(211, 49, 35, 0.04); background-color: rgba(211, 49, 35, 0.04);
} }
.noStock{
border: 1px solid #eee;
background-color: #eee;
color: #6e737d;
}
.gray { .gray {
border: 1px solid #eee; border: 1px solid #eee;
background-color: #eee; background-color: #eee;

View File

@@ -14,9 +14,10 @@
<view class="item-box" v-for="item, index in state?.spec_list" :key="index"> <view class="item-box" v-for="item, index in state?.spec_list" :key="index">
<view class="title">{{ item.name }}</view> <view class="title">{{ item.name }}</view>
<view class="tag-box"> <view class="tag-box">
<!-- :class="['tag', { 'active': itemChild.select }, { 'gray': !itemChild.show && state.skuLength == 1 }]" -->
<view v-for="itemChild, indexChild in item?.list" :key="indexChild" <view v-for="itemChild, indexChild in item?.list" :key="indexChild"
:class="['tag', { 'active': itemChild.select }, { 'gray': !itemChild.show && state.skuLength == 1 }]" :class="['tag', { 'active': itemChild.select },{'noStock':itemChild.noStock}]"
@click="handleChooseSku(index, itemChild)"> @click="handleChooseSku(index, itemChild,item.name)">
{{ itemChild.name }} {{ itemChild.name }}
<image v-if="itemChild.select" class="icon-select" <image v-if="itemChild.select" class="icon-select"
:src="handleStaticResources('/static/images/tag-select.png')"> </image> :src="handleStaticResources('/static/images/tag-select.png')"> </image>
@@ -32,13 +33,14 @@
<view class="btn-box"> <view class="btn-box">
<!-- <view v-if="props.isShowAddCartBtn" class="btn add-cart" @click="handleAddCart">加入购物车</view> --> <!-- <view v-if="props.isShowAddCartBtn" class="btn add-cart" @click="handleAddCart">加入购物车</view> -->
<view v-if="props.isShowAddCartBtn" class="core-button-confirm add-cart"> <view v-if="props.isShowAddCartBtn" class="core-button-confirm add-cart">
<coreshop-button :loading="props.addCartloading" class="core-button-confirm_" :radius="0" title="加入购物车" <coreshop-button :loading="props.addCartloading" class="core-button-confirm_" :radius="0"
:customStyle="addCartCustomStyle" @onClick="handleAddCart()"></coreshop-button> title="加入购物车" :customStyle="addCartCustomStyle" @onClick="handleAddCart()"></coreshop-button>
</view> </view>
<!-- <view class="btn buy-now" @click="handleBuyNow">{{ props.btnBuyTitlt }}</view> --> <!-- <view class="btn buy-now" @click="handleBuyNow">{{ props.btnBuyTitlt }}</view> -->
<view class="core-button-confirm"> <view class="core-button-confirm">
<coreshop-button :loading="props.buyNowNowloading" class="core-button-confirm_" :radius="0" <coreshop-button :loading="props.buyNowNowloading" class="core-button-confirm_" :radius="0"
:title="props.btnBuyTitlt" :customStyle="buyNowCustomStyle" @onClick="handleBuyNow()"></coreshop-button> :title="props.btnBuyTitlt" :customStyle="buyNowCustomStyle"
@onClick="handleBuyNow()"></coreshop-button>
</view> </view>
</view> </view>
</view> </view>
@@ -106,39 +108,86 @@
spec_list : Array<GoodsSpecListType>; spec_list : Array<GoodsSpecListType>;
chooseSku : GoodsSkuListType; chooseSku : GoodsSkuListType;
skuLength : number; skuLength : number;
sku_list : Array<{ [key : string] : any }>
}>({ }>({
numberVal: 1, numberVal: 1,
spec_list: [], spec_list: [],
chooseSku: {}, chooseSku: {},
skuLength: 1, skuLength: 1,
sku_list: []
}); });
watch(() => props.goodsDetailData, (newVal : any) => { watch(() => props.goodsDetailData, (goodsDetail : any) => {
if (newVal) { if (goodsDetail && (!goodsDetail.skuList || Object.keys(goodsDetail.skuList).length === 0)) {
/** 获取sku有几层 */ return;
state.skuLength = newVal?.skuList?.spec_list.length;
/** 默认选择第一个sku */
state.chooseSku = newVal?.skuList?.sku_list.find((item : any) => item.stock != 0);
state.spec_list = deepClone(newVal?.skuList?.spec_list.map((item : GoodsSpecListType) => {
item.list.forEach((itemChild : GoodsSpecListType, indexChild : number) => {
let findSku = newVal?.skuList?.sku_list.find((item : any) => item.sku_name_arr.includes(itemChild.name))
if (findSku && state.skuLength == 1) {
itemChild['show'] = true;
} else {
itemChild['show'] = false;
}
let findChooseSku = state.chooseSku.sku_name_arr.includes(itemChild.name);
if (findChooseSku) {
itemChild['select'] = true;
} else {
itemChild['select'] = false;
}
})
return item;
}))
} }
const goodsDetailData = deepClone(goodsDetail);
// sku 集合
const spec_list = goodsDetailData.skuList.spec_list;
// sku 组合商品列表
const sku_list = goodsDetailData.skuList.sku_list;
if (!Array.isArray(spec_list) || spec_list.length === 0) {
return;
}
if (!Array.isArray(sku_list) || sku_list.length === 0) {
return;
}
state.sku_list = sku_list;
// state.spec_list = deepClone(goodsDetailData.skuList.spec_list);
// 设置默认选中的sku
const spesDesc : string = goodsDetailData?.product?.spesDesc;
let defaultSelectedSku = [];
if (spesDesc) {
const skuDescArr = spesDesc.split(',');
if (Array.isArray(skuDescArr) && skuDescArr.length) {
defaultSelectedSku = skuDescArr.map(sku => sku.split(':')[1]);
console.log('defaultSelectedSku', defaultSelectedSku);
}
}
state.spec_list = spec_list.map(sku => {
sku.list = sku.list?.map(item => {
item.select = defaultSelectedSku.includes(item.name);
return item;
});
return sku;
});
const defaultSelectedSkuStr = defaultSelectedSku.join(',');
state.chooseSku = sku_list.find(item => item.sku_name_arr?.join(',') === defaultSelectedSkuStr);
state.spec_list.forEach(item => checkSkuHasStock(item.list.find(x => x.select)))
// /** 获取sku有几层 */
// state.skuLength = newVal?.skuList?.spec_list.length;
// /** 默认选择第一个sku */
// state.chooseSku = newVal?.skuList?.sku_list.find((item : any) => item.stock != 0);
// state.spec_list = deepClone(newVal?.skuList?.spec_list.map((item : GoodsSpecListType) => {
// item.list.forEach((itemChild : GoodsSpecListType, indexChild : number) => {
// let findSku = newVal?.skuList?.sku_list.find((item : any) => item.sku_name_arr.includes(itemChild.name))
// if (findSku && state.skuLength == 1) {
// itemChild['show'] = true;
// } else {
// itemChild['show'] = false;
// }
// let findChooseSku = state.chooseSku.sku_name_arr.includes(itemChild.name);
// if (findChooseSku) {
// itemChild['select'] = true;
// } else {
// itemChild['select'] = false;
// }
// })
// return item;
// }))
}, { }, {
deep: true deep: true
}) })
@@ -163,32 +212,76 @@
} }
/** sku选择 */ /** sku选择 */
const handleChooseSku = (index : number, sku : GoodsSpecListType) => { const handleChooseSku = (index : number, sku : GoodsSpecListType, skuType : string) => {
let chooseSku : GoodsSkuListType = {}; // 选中的sku console.log('sku', sku);
if (!Array.isArray(state.sku_list) || state.sku_list.length === 0) {
if (state.skuLength === 1) { /** 当sku只有一层的时候 */ return;
chooseSku = props.goodsDetailData?.skuList?.sku_list.find((item : GoodsSkuListType) => item.sku_name_arr.includes(sku.name));
} else { /** 当sku多层的时候 */
let nameArr : Array<string> = [sku.name];
let noClickSpecList = state.spec_list.filter((item : any, idx : number) => idx !== index);
noClickSpecList.forEach((item : GoodsSpecListType) => {
item.list.forEach((itemChild : GoodsSpecListType) => {
if (itemChild.select) {
nameArr.push(itemChild.name)
}
})
})
chooseSku = props.goodsDetailData.skuList?.sku_list.find((item : GoodsSkuListType) => item.sku_name_arr.every((itemChild : string) => nameArr.includes(itemChild)));
} }
if (!chooseSku || chooseSku.stock <= 0) { // 根据选择的sku项 判断组合的商品,是否有库存
handleShowToast('没有库存了,请选择其它规格'); const productContainSkuNoStockList = state.sku_list.filter(x => (x.sku_name_arr as Array<string>).includes(sku.name)).filter((x => x.stock <= 0));
return false; console.log('productContainSkuList', productContainSkuNoStockList);
}
state.spec_list[index].list.forEach((item : any) => item.select = false);
sku.select = !sku.select; sku.select = !sku.select;
state.chooseSku = chooseSku; state.spec_list = state.spec_list.map(spec => {
spec.list.map(_sku => {
_sku.noStock = productContainSkuNoStockList.some(product => (product.sku_name_arr as Array<string>).includes(_sku.name));
return _sku;
});
return spec;
});
// let spec : GoodsSpecListType = state.spec_list.find(x => x.name === skuType);
// spec.list = spec.list.map(item => ({ ...item, select: item.name === sku.name }));
// sku.select = !sku.select;
// if (state.spec_list.length === 1) {
// return;
// }
// // 如果存在多个sku必须必须sku的数量-1 然后计算对应的sku 是否有库存再选择最后一个sku 才能组合最终的商品
// if (state.spec_list.length - 1 !== state.sku_list.filter(x => x.select).length) {
// return;
// }
// 根据选择的sku 筛选对应sku组成的商品
// const productContainSkuList = state.sku_list.filter(x => x.sku_name_arr.includes(sku.name));
// console.log('productContainSkuList', productContainSkuList);
// const noStockSkuList = productContainSkuList.filter(sku => sku.stock <= 0);
// let chooseSku : GoodsSkuListType = {}; // 选中的sku
// if (state.skuLength === 1) { /** 当sku只有一层的时候 */
// chooseSku = props.goodsDetailData?.skuList?.sku_list.find((item : GoodsSkuListType) => item.sku_name_arr.includes(sku.name));
// } else { /** 当sku多层的时候 */
// let nameArr : Array<string> = [sku.name];
// let noClickSpecList = state.spec_list.filter((item : any, idx : number) => idx !== index);
// noClickSpecList.forEach((item : GoodsSpecListType) => {
// item.list.forEach((itemChild : GoodsSpecListType) => {
// if (itemChild.select) {
// nameArr.push(itemChild.name)
// }
// })
// })
// chooseSku = props.goodsDetailData.skuList?.sku_list.find((item : GoodsSkuListType) => item.sku_name_arr.every((itemChild : string) => nameArr.includes(itemChild)));
// }
// if (!chooseSku || chooseSku.stock <= 0) {
// handleShowToast('没有库存了,请选择其它规格');
// return false;
// }
// state.spec_list[index].list.forEach((item : any) => item.select = false);
// sku.select = !sku.select;
// state.chooseSku = chooseSku;
emits('handleChangeGoodSku', state.chooseSku); emits('handleChangeGoodSku', state.chooseSku);
}; };
@@ -223,6 +316,58 @@
} }
return true; return true;
} }
/** 判断sku是否存在库存 */
const checkSkuHasStock = (selectedSku : GoodsSpecListType) => {
console.log('selectedSku', selectedSku)
if (!Array.isArray(state.sku_list) || state.sku_list.length === 0) {
return;
}
// sku.select = !sku.select;
let selectedSkuArr = [];
state.spec_list.forEach(spec => {
spec.list.forEach(_sku => {
if (_sku.select) {
selectedSkuArr.push(_sku.name)
}
})
})
const skuCombination : Array<string> = getSkuCombination(selectedSkuArr);
if (!Array.isArray(skuCombination) || skuCombination.length === 0) {
return;
}
// 根据选择的sku项 判断组合的商品,是否有库存
let productContainSkuNoStockList = [];
skuCombination.forEach(comb => {
productContainSkuNoStockList = productContainSkuNoStockList.concat(state.sku_list.filter(x => (x.sku_name_arr as Array<string>).join(',').indexOf(comb) >= 0))
.filter((x => x.stock <= 0));
});
console.log('productContainSkuList', productContainSkuNoStockList);
state.spec_list = state.spec_list.map(spec => {
spec.list = spec.list.map(_sku => {
_sku.noStock = productContainSkuNoStockList.some(product => (product.sku_name_arr as Array<string>).join(',').includes(_sku.name));
return _sku;
});
return spec;
});
}
const getSkuCombination = (skuArr : Array<string>) => {
const combinations = skuArr.reduce((acc, current, index, arr) => {
return acc.concat(arr.slice(index + 1).map(item => [current, item]));
}, []);
return combinations.map(item => item.join(','));
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>