动态sku多规格表格
在项目中很常见的就是我们的动态输入添加模式
我这边给各位演示另外一个select跟输入版本一致
还有很多优化点各位可以提建议
<template>
<div>
<div class="border-box">
<el-tabs type="border-card">
<el-tab-pane label="商品规格">
<div v-if="itemList == null || itemList.length <= 0" class="el-table__empty-block">
<span class="el-table__empty-text">暂无数据</span>
</div>
<div class="border-guige">
<div v-for="(item, index) in itemList" :key="index">
<div class="flex-guige">
<div class="ym_thead" style="display: flex; justify-content: space-between; border-bottom: 1px solid #f7f7f7">
<div>{{ item.specName }}</div>
<div class="remove">
<el-link type="primary" :underline="false">移除</el-link>
</div>
</div>
</div>
<div class="flex-guige" style="padding-bottom: 10px; margin: 20px 0; border-bottom: 1px solid #e5e5e5">
<div class="width-tag" style="margin-bottom: 10px">
<el-tag v-for="(tag, ins) in item.specValueName" :key="ins" closable :disable-transitions="false" type="info" @close="handleClose(index, ins)">
{{ tag.specValueName }}
</el-tag>
</div>
<el-popover placement="top" width="160">
<el-select v-model="inputValue" placeholder="添加规格值" @blur="focusConfirm(index)" @change="handleInputConfirm(index)">
<el-option v-for="spec in optionsvalue" :key="spec.id" :disabled="spec.disabled" :label="spec.name" :value="spec.id" />
</el-select>
<el-link type="primary" slot="reference" :underline="false" @click="specValueName(item.specName)">添加规格值</el-link>
</el-popover>
</div>
</div>
</div>
<el-popover placement="top" style="position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%)" width="160">
<el-select v-model="selinfo" placeholder="添加规格" @change="getrow">
<el-option v-for="item in options" :key="item.id" :disabled="item.disabled" :label="item.name" :value="item.name" />
</el-select>
<el-link type="primary" slot="reference" :underline="false">添加规格</el-link>
</el-popover>
</el-tab-pane>
</el-tabs>
<el-tabs style="margin-top: 20px" type="border-card">
<el-tab-pane label="商品SKU">
<div v-show="mapList.length > 0" class="ad" style="display: flex; gap: 15px; justify-content: space-around; margin-bottom: 20px">
<div class="head_title">
<div class="grid-content bg-purple" style="font-size: 14px; font-weight: bold">批量设置</div>
</div>
<div class="menu_btn" style="width: calc(100% - 120px)">
<div style="display: grid; grid-template-columns: repeat(7, 1fr)">
<div class="grid-content bg-purple">
<el-input-number v-model="batch.skuCode" controls-position="right" placeholder="sku编码" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.salesPrice" controls-position="right" placeholder="销售价(元)" :precision="2" :step="0.1" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.marketPrice" controls-position="right" placeholder="市场价(元)" :precision="2" :step="0.1" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.costPrice" controls-position="right" placeholder="成本价(元)" :precision="2" :step="0.1" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.stock" controls-position="right" placeholder="库存" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.weight" controls-position="right" placeholder="重量" />
</div>
<div class="grid-content bg-purple">
<el-input-number v-model="batch.volume" controls-position="right" placeholder="体积" />
</div>
<div style="margin-top: 10px">
<div class="grid-content bg-purple">
<el-input-number v-model="batch.firstRebate" controls-position="right" placeholder="一级返佣" />
</div>
</div>
<div style="margin-top: 10px">
<div class="grid-content bg-purple">
<el-input-number v-model="batch.secondRebate" controls-position="right" placeholder="二级返佣" />
</div>
</div>
<div style="margin-top: 10px">
<div class="grid-content bg-purple">
<el-button type="primary" @click="confirm">确认</el-button>
</div>
</div>
</div>
</div>
</div>
<el-table border :data="mapList" style="width: 100%">
<el-table-column v-for="(item, index) in itemList" :key="index" align="center" :label="item.specName" width="88">
<template slot-scope="scope">
<div v-if="scope.row.specs[index]">{{ scope.row.specs[index].specValueName }}</div>
</template>
</el-table-column>
<el-table-column label="头图" prop="picUrl" width="50">
<!-- <el-upload action="" list-type="picture-card" @on-preview="handlePictureCardPreview" @on-remove="handleRemove">
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img alt="" :src="dialogImageUrl" width="100%" />
</el-dialog> -->
</el-table-column>
<el-table-column align="center" label="sku编码" prop="skuCode" width="150px">
<template #default="scope">
<el-input v-model="scope.row.skuCode" placeholder="sku编码" />
</template>
</el-table-column>
<el-table-column align="center" label="销售价(元)" prop="salesPrice" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.salesPrice" controls-position="right" placeholder="销售价(元)" />
</template>
</el-table-column>
<el-table-column align="center" label="市场价(元)" prop="marketPrice" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.marketPrice" controls-position="right" placeholder="市场价(元)" />
</template>
</el-table-column>
<el-table-column align="center" label="成本价(元)" prop="costPrice" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.costPrice" controls-position="right" placeholder="成本价(元)" />
</template>
</el-table-column>
<el-table-column align="center" label="库存" prop="stock" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.stock" controls-position="right" placeholder="库存" />
</template>
</el-table-column>
<el-table-column align="center" label="重量(kg)" prop="weight" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.weight" controls-position="right" placeholder="重量(kg)" />
</template>
</el-table-column>
<el-table-column align="center" label="体积(m³)" prop="volume" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.volume" controls-position="right" placeholder="体积(m³)" />
</template>
</el-table-column>
<el-table-column align="center" label="一级返佣" prop="firstRebate" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.firstRebate" controls-position="right" placeholder="一级返佣" />
</template>
</el-table-column>
<el-table-column align="center" label="二级返佣" prop="secondRebate" width="150px">
<template #default="scope">
<el-input-number v-model="scope.row.secondRebate" controls-position="right" placeholder="二级返佣" />
</template>
</el-table-column>
<el-table-column align="center" fixed="right" label="是否启用" prop="enable" width="150px">
<template #default="scope">
<el-switch v-model="scope.row.enable" active-color="#13ce66" active-value="1" inactive-color="#ff4949" inactive-value="0" />
</template>
</el-table-column>
</el-table>
</el-tab-pane>
<span style="display: flex; justify-content: center; margin-top: 20px">
<el-button type="primary" @click="savebasic">下一步</el-button>
</span>
</el-tabs>
</div>
</div>
</template>
<script>
import { specification, getList } from '@/api/mall/goods/goodsAdd'
export default {
data() {
return {
sku: [],
inputValue: '',
itemList: [],
inpurIndex: 0,
mapList: [],
dialogImageUrl: '',
dialogVisible: false,
//补充代码
options: [],
selinfo: null,
specaname: [],
optionsvalue: [],
Variable: true,
checktags: null,
batch: {
skuCode: '',
salesPrice: '',
marketPrice: '',
costPrice: '',
stock: '',
weight: '',
volume: '',
firstRebate: 50,
secondRebate: 13,
},
}
},
created() {
this.specifications()
},
methods: {
specifications() {
// 规格名请求
specification({}).then((res) => {
res.data.forEach((element, index) => {
res.data[index].disabled = false
})
this.options = res.data
})
},
getrow(row) {
//规格名初始化
let find = this.options.findIndex((item) => item.name === row)
if (find > -1) {
const matchedItem = this.options[find]
this.$set(matchedItem, 'disabled', (matchedItem.disabled = true))
}
let specId = this.options.find((item) => item.name === row)
this.specaname.push(row)
let itList = {
specName: row,
specId: specId.id,
specValueName: [],
}
this.itemList.push(itList)
console.log(this.specaname)
},
// 聚焦判断是哪个数据
focusConfirm(index) {
this.inpurIndex = index
},
// 删除
handleClose(index, ins) {
let skuList = []
this.itemList[index].specValueName.splice(ins, 1)
for (var { specValueName } of this.itemList) {
skuList.push(specValueName)
}
var att = this.composeTableData(skuList)
this.mapList = att
},
//显示
showInput(e) {
this.inpurIndex = e
},
//输入组合
handleInputConfirm(e) {
let skuList = []
let inputValue = this.inputValue
let specValueId = this.optionsvalue.filter((item) => item.id === inputValue)
if (inputValue) {
this.itemList[this.inpurIndex].specValueName.push({
specId: this.options[e].id,
specName: this.options[e].name,
specValueId: specValueId[0].id,
specValueName: specValueId[0].name,
})
for (var { specValueName } of this.itemList) {
skuList.push(specValueName)
}
var attList = this.composeTableData(skuList)
console.log(attList)
this.mapList = attList
}
this.inputValue = ''
},
// 排列组合
cartesianProductOf() {
return Array.prototype.reduce.call(
arguments,
function (a, b) {
const result = [] // 存储拼接的结果
a.forEach((item_a) => {
b.forEach((item_b) => {
result.push(item_a.concat(item_b))
})
})
return result
},
[[]]
)
},
composeTableData(sku_list) {
console.log(sku_list)
// 获取组合好的sku规格数据
const arr = this.cartesianProductOf(...sku_list)
return arr.map((item) => {
return {
specIds: '',
specs: item, // 组合好的规格[{...},{...}]
picUrl: '',
picUrls: [],
skuCode: '',
salesPrice: '',
marketPrice: '',
costPrice: '',
stock: '',
weight: '',
volume: '',
firstRebate: 50,
secondRebate: 13,
enable: '1',
}
})
},
specValueName(e) {
//规格值请求
console.log(e)
let find = this.options.findIndex((item) => item.name === e)
if (find > -1) {
const matchedItem = this.options[find]
getList({ specId: matchedItem.id }).then((res) => {
res.data.forEach((item) => {
Object.assign(item, { disabled: false })
})
this.optionsvalue = res.data
})
}
},
handleRemove(file, fileList) {
console.log(file, fileList)
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
savebasic() {
this.$emit('Multiple', this.mapList)
},
//批量修改
confirm() {
const bat = Object.keys(this.batch)
this.mapList.forEach((item) => {
const mapList = Object.keys(item)
bat.forEach((el) => {
mapList.forEach((row) => {
if (el == row) {
item[el] = this.batch[el]
}
})
})
})
},
},
}
</script>
<style scoped>
.ym_thead {
padding-bottom: 10px;
border-bottom: 1px solid #f7f7f7;
}
.border-box {
width: 180%;
padding: 30px;
margin: auto;
/* height: 500px; */
}
</style>
在这个里面着重的就是排序并切到table中其实和我们的输入状况一致只是将输入转变成为了select的形式