效果图
demo 代码
<script setup lang="ts">
import { ElInput, ElMessage, ElMessageBox } from 'element-plus'
// 显示添加规格组表单
const showAddGroupForm = ref(false)
// 新增规格组值
const addSpec = {
specName: '',
specValue: '',
}
// 添加规格组
const addSpecGroup = ref([])
// 规格组合列表
function toggleAddSpecForm() {
showAddGroupForm.value = !showAddGroupForm.value
}
function submitAddGroup() {
if (addSpec.specName === '' || addSpec.specValue === '') {
ElMessage.error('规格信息不能为空')
return false
}
const index = addSpecGroup.value.length
addSpecGroup.value.push({
id: index,
title: addSpec.specName,
values: [addSpec.specValue],
temp: '',
})
// 构建 sku 信息表格
buildSkuTable()
addSpec.specName = ''
addSpec.specValue = ''
toggleAddSpecForm()
}
/* 删除规格组事件 */
function deleteGroup(index) {
ElMessageBox.confirm('删除后不可恢复,确认删除该记录吗?', '提示', {
type: 'warning',
}).then(() => {
// 删除指定规则组
addSpecGroup.value.splice(index, 1)
// 构建规格组合列表
buildSkuTable()
})
}
function addSpecVal(spec) {
if (spec.temp) {
spec.values.push(spec.temp)
}
spec.temp = ''
buildSkuTable()
}
function delSpecVal(specValues, index) {
ElMessageBox.confirm('删除后不可恢复,确认删除该记录吗?', '提示', {
type: 'warning',
}).then(() => {
specValues.splice(index, 1)
buildSkuTable()
})
}
// 构建sku表格
let tableData = []
function buildSkuTable() {
const specKeys = addSpecGroup.value.map(spec => spec.title)
const specCombinations = cartesianProduct(addSpecGroup.value.map(spec => spec.values))
// 生成 SKU 列表
tableData = specCombinations.map((spec) => {
const specObj = []
spec.forEach((value, index) => {
const tmp = {
title: specKeys[index],
val: value,
}
specObj.push(tmp)
})
return specObj
})
}
// 笛卡尔积处理规格
function cartesianProduct(arr) {
return arr.reduce((total, currentValue) => {
return total.flatMap(value => currentValue.map(v => [].concat(value, v)))
}, [[]])
}
function changeVal() {
console.log(tableData)
}
</script>
<template>
<div class="add-spec-btn">
<ElText size="default">
产品规格:
</ElText>
<ElButton type="primary" size="default" @click="toggleAddSpecForm">
添加规格
</ElButton>
</div>
<!-- 规格 -->
<div class="mb2">
<!-- 添加规格 -->
<div v-show="showAddGroupForm" class="spec-form mt-4 flex">
<div class="ml-2">
<ElText size="default">
规格名:
</ElText>
<ElInput v-model="addSpec.specName" placeholder="请输入规格名称" @input="$forceUpdate()" />
</div>
<div class="ml-4">
<ElText size="default">
规格值:
</ElText>
<ElInput v-model="addSpec.specValue" placeholder="请输入规格名称" @input="$forceUpdate()" @keyup.enter="submitAddGroup" />
</div>
<div class="ml-4">
<ElButton type="primary" @click="submitAddGroup">
确定
</ElButton>
<ElButton @click="toggleAddSpecForm">
取消
</ElButton>
</div>
</div>
<!-- 规格组 -->
<div v-if="addSpecGroup.length > 0" class="spec-list ml-6 mt-4 flex">
<div v-for="(spec, i) in addSpecGroup" :key="i" class="spec-info">
<div class="spec-info-detail spec-info-key">
<span>
{{ spec.title }}
</span>
<a href="javascript:void(0)" @click="deleteGroup(i)">
<SvgIcon name="i-ep:delete" />
</a>
</div>
<div class="spec-info-detail spec-info-value flex-inline">
<ElTag
v-for="(spec_item, j) in spec.values"
:key="j"
class="mr-2"
closable
:disable-transitions="false"
@close="delSpecVal(spec.values, j)"
>
{{ spec_item }}
</ElTag>
<ElInput
v-model="spec.temp"
class="mr-1 w-20 flex"
size="small"
@keyup.enter="addSpecVal(spec)"
/>
<ElButton type="primary" class="button-new-tag" size="small" @click="addSpecVal(spec)">
+ 添加
</ElButton>
</div>
</div>
</div>
<!-- 规格表格 -->
<div v-if="tableData.length > 0" class="spec-table ml-6 mt-4">
<ElTable :data="tableData" border style="width: 100%">
<ElTableColumn v-for="(spec, index) in addSpecGroup" :key="index" :label="spec.title">
<template #default="scope">
<span>{{ scope.row[index].val }}</span>
</template>
</ElTableColumn>
<ElTableColumn label="销售价">
<template #default="scope">
<ElInput v-model="scope.row.sale_price" @input="changeVal" />
</template>
</ElTableColumn>
<ElTableColumn label="划线价">
<template #default="scope">
<ElInput v-model="scope.row.price" />
</template>
</ElTableColumn>
<ElTableColumn label="库存">
<template #default="scope">
<ElInput v-model="scope.row.stock" />
</template>
</ElTableColumn>
</ElTable>
</div>
</div>
</template>
<style>
.el-input {
--el-input-width: 200px;
}
.spec-list {
padding: 5px;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
border: 1px solid #dfecf8;
background: #f6f9fc;
}
.spec-info {
width: 90%;
border: 1px solid #dfecf8;
position: relative;
padding: 5px;
background: #ffffff;
margin: 10px 10px;
}
.spec-table {
padding: 5px;
display: flex;
justify-content: flex-start;
flex-wrap: wrap;
border: 1px solid #dfecf8;
}
.spec-info-detail {
height: 36px;
display: flex;
margin-left: 6px;
}
.spec-info-key {
padding: 4px;
font-size: 12px;
font-weight: bold;
justify-content: space-between;
border-bottom: 1px solid #dfecf8;
}
.spec-info-value {
padding: 6px;
}
</style>