代码:
//utils/index.js
export const cartesianProduct = (arrays) => {
function recursiveProduct(arrays, index, current) {
if (index === arrays.length) {
result.push({
specification: current.slice(),
});
return;
}
for (let i = 0; i < arrays[index].length; i++) {
current.push(arrays[index][i]);
recursiveProduct(arrays, index + 1, current);
current.pop();
}
}
let result = [];
recursiveProduct(arrays, 0, []);
return result;
};
//page页面
<template>
<view class="base-page-container container">
<u-navbar
autoBack
placeholder
title="多规格"
:titleStyle="{ color: '#000', fontSize: '36rpx', fontWeight: 600 }"
>
<template slot="right">
<u-button
:customStyle="{
width: '128rpx',
height: '56rpx',
background: '#4ABE45',
borderRadius: '30rpx',
color: '#fff',
}"
>完成</u-button
>
</template>
</u-navbar>
<!-- 规格信息 -->
<view
class="specification-box"
v-for="(item, index) in specificationList"
:key="index"
>
<view class="specification-box-header">
<text>{{ item.name }}</text>
<u-icon
name="trash"
size="32rpx"
@click="deleteSpecification(index)"
></u-icon>
</view>
<view class="specification-class" v-for="(obj, i) in item.class" :key="i">
<view class="specification-class-name">{{ obj.name }}</view>
<u-icon
name="close-circle-fill"
size="38rpx"
style="margin-right: 12rpx"
@click="onDeleteClass(index, i)"
></u-icon>
</view>
<view class="add-class" @click="addClass(index)"
><u-icon name="plus" size="28rpx" style="margin-right: 12rpx"></u-icon
>添加</view
>
</view>
<view class="add-specification" @click="addSpecification"
><u-icon name="plus" color="#FFA918" style="margin-right: 15rpx"></u-icon
>添加多个规格</view
>
<!-- 设置价格 -->
<view class="set-price">
<view class="set-price-title">设置价格</view>
<view class="table-box">
<view class="table-header">
<view v-for="(item, index) in specificationList" :key="index">{{
item.name
}}</view>
<view>图片</view>
<view>原价</view>
<view>现价</view>
<view>批发价</view>
</view>
<view
class="table-body"
v-for="(item, index) in tableData"
:key="index"
>
<view v-for="(obj, i) in item.specification" :key="i">{{
obj.name
}}</view>
<view>上传</view>
<view>100</view>
<view>100</view>
<view>100</view>
</view>
</view>
</view>
<!-- 添加规格弹窗 -->
<u-popup :show="popupShow" @close="popupShow = false" @open="addText = ''">
<view class="add-box">
<u--input
placeholder="多规格商品以空格隔开"
border="none"
v-model="addText"
:customStyle="{
background: '#F9F9F9',
borderRadius: '16rpx',
height: '85rpx',
}"
></u--input>
<view class="add-btn"
><u-button
:customStyle="{
width: '126rpx',
height: '62rpx',
borderRadius: '36rpx',
borderColor: '#e9e9e9',
color: '#999',
}"
@click="onAdd"
>添加</u-button
></view
>
</view>
</u-popup>
</view>
</template>
<script>
import { cartesianProduct } from "@/utils";
export default {
data() {
return {
popupShow: false,
tableData: [],
addText: "",
addType: "", //添加规格或者规格下的分类 ,specification->规格 class-> 规格的子项
addSpecificationIndex: "", //准备添加的规格index
specificationList: [
{
name: "颜色",
class: [],
},
{
name: "尺寸",
class: [],
},
],
};
},
methods: {
addClass(index) {
this.addSpecificationIndex = index;
this.addType = "class";
this.popupShow = true;
},
//添加规格
addSpecification() {
this.addType = "specification";
this.popupShow = true;
},
//点击添加按钮
onAdd() {
if (!this.addText) return;
const arr = this.addText.trim().split(/\s+/);
//判断是否是添加的规格
if (this.addType === "specification") {
arr.forEach((item) => {
this.$set(this.specificationList, this.specificationList.length, {
name: item,
class: [],
});
});
this.popupShow = false;
this.$nextTick(() => {
this.getTableData();
});
return;
}
//添加规格下的分类
const index = this.addSpecificationIndex; //要给哪个规格添加子项
const classList = arr.map((item) => {
return {
name: item,
};
});
this.$set(this.specificationList, index, {
...this.specificationList[index],
class: [...this.specificationList[index].class, ...classList],
});
this.popupShow = false;
this.$nextTick(() => {
this.getTableData();
});
},
//删除规格
deleteSpecification(index) {
this.specificationList = this.specificationList.filter(
(item, i) => i != index
);
this.$nextTick(() => {
this.getTableData();
});
},
//删除某个规格中的某个子项
onDeleteClass(index, i) {
let classList = this.specificationList[index].class;
classList = classList.filter((item, i2) => i2 != i);
this.$set(this.specificationList, index, {
...this.specificationList[index],
class: classList,
});
this.$nextTick(() => {
this.getTableData();
});
},
//计算循环出下面的列表
getTableData() {
const list = this.specificationList.map((item, index) => {
const newArr = [];
item.class.forEach((item2, index2) => {
newArr.push({
name: item2.name,
id: index + "-" + index2,
});
});
return newArr;
});
const newList = cartesianProduct(list);
this.tableData = newList;
},
},
};
</script>
<style scoped lang="scss">
.container {
background-color: #f6f7fb;
padding: 16rpx 14rpx;
.specification-box {
background-color: #fff;
padding: 30rpx;
margin-bottom: 14rpx;
border-radius: 14rpx;
&-header {
font-size: 28rpx;
color: #333;
display: flex;
justify-content: space-between;
align-items: center;
}
.specification-class {
display: flex;
margin-top: 16rpx;
align-items: center;
justify-content: space-between;
&-name {
flex: 1;
height: 70rpx;
line-height: 70rpx;
background: #f6f7f9;
border-radius: 8rpx;
padding-left: 24rpx;
color: #333;
font-size: 26rpx;
margin-right: 34rpx;
}
}
.add-class {
height: 70rpx;
border-radius: 8rpx;
font-size: 26rpx;
background: #f6f7f9;
display: flex;
align-items: center;
padding-left: 23rpx;
margin-top: 16rpx;
}
}
.add-specification {
background-color: #fff;
height: 110rpx;
border-radius: 14rpx;
margin-top: 14rpx;
display: flex;
align-items: center;
color: #ffa918;
font-size: 28rpx;
justify-content: center;
&:active {
background-color: rgba(0, 0, 0, 0.05);
}
}
.set-price {
background-color: #fff;
padding: 31rpx;
border-radius: 14rpx;
margin-top: 14rpx;
&-title {
font-size: 28rpx;
color: #333333;
margin-bottom: 28rpx;
}
.table-box {
font-size: 26rpx;
}
.table-header {
height: 72rpx;
background-color: #f8f8f8;
border-radius: 6rpx;
color: #676767;
display: flex;
align-items: center;
& > view {
// width: 90rpx;
flex: 1;
// max-width: 90rpx;
text-align: center;
}
}
.table-body {
display: flex;
align-items: center;
margin-top: 20rpx;
& > view {
flex: 1;
text-align: center;
}
}
}
.add-box {
padding: 19rpx 25rpx;
padding-bottom: 60rpx;
.add-btn {
height: 104rpx;
display: flex;
align-items: center;
justify-content: flex-end;
}
}
}
</style>