element根据输入,动态生成表格
场景:后台页面根据商品规格和规格值,动态(增删改查)在表格中生成对应的sku.
如图:
代码如下:
edit.html
<template xmlns="">
<div class="app-container">
<el-form ref="form" :model="form" label-width="80px" autocomplete="off" @submit.native.prevent>
<h3>基础信息</h3>
<div style="padding-left: 60px">
<el-row>
<el-col :span="7">
<el-form-item label="spu_id">
<el-input v-model="form.id" autocomplete="off" placeholder="" :disabled="true" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="名称" :required="true">
<el-input v-model="form.goods_name" autocomplete="off" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="商品类型" :required="true">
<el-select v-model="form.goods_type" placeholder="请选择">
<el-option
v-for="item in goodsTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<el-form-item label="品牌" :required="true">
<el-select v-model="form.brand_code" style="width: 100%">
<el-option
v-for="item in brandOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="分类" :required="true">
<el-cascader
v-model="form.cate_code"
collapse-tags
clearable
:options="cateOptions"
:props="{ multiple: false, checkStrictly: true }"
filterable
style="width: 100%"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<el-form-item label="赠品" :required="true">
<el-radio v-model="form.is_gift" label="1">否</el-radio>
<el-radio v-model="form.is_gift" label="2">是</el-radio>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="列表显示" :required="true">
<el-radio v-model="form.is_show_video" label="1">是</el-radio>
<el-radio v-model="form.is_show_video" label="2">否</el-radio>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="是否套组" :required="true">
<el-radio v-model="form.is_suite" label="1">否</el-radio>
<el-radio v-model="form.is_suite" label="2">是</el-radio>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<el-form-item label="是否预售" :required="true">
<el-radio v-model="form.is_pre_sales" label="1">否</el-radio>
<el-radio v-model="form.is_pre_sales" label="2">是</el-radio>
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="是否临期" :required="true">
<el-radio v-model="form.is_expire" label="1">否</el-radio>
<el-radio v-model="form.is_expire" label="2">是</el-radio>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="5">
<el-form-item label="包装规格">
<el-input v-model="form.pack_spec" autocomplete="off" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="包装数量">
<el-input v-model="form.pack_count" autocomplete="off" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="销售单位">
<el-input v-model="form.unit_name" autocomplete="off" placeholder="" />
</el-form-item>
</el-col>
<el-col :span="5">
<el-form-item label="保质期">
<el-date-picker
v-model="form.expire_date"
type="date"
value-format="yyyy-MM-dd"
placeholder="选择日期"
/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="商品图片" :required="true">
<ul class="el-upload-list el-upload-list--picture-card">
<vuedraggable v-model="form.images">
<li v-for="(item, index) in form.images" :key="index" class="el-upload-list__item is-success animated">
<img :src="item" alt="" class="el-upload-list__item-thumbnail ">
<i class="el-icon-close" />
<span class="el-upload-list__item-actions">
<!-- 预览 -->
<span class="el-upload-list__item-preview" @click="viewImage(item)">
<i class="el-icon-zoom-in" />
</span>
<!-- 删除 -->
<span class="el-upload-list__item-delete" @click="delImage(index)">
<i class="el-icon-delete" />
</span>
</span>
</li>
</vuedraggable>
</ul>
<!-- <el-button size="small" type="info" @click="uploadImageDialog = true">点击上传</el-button>-->
<label for="upload-btn" class="el-button el-button--info el-button--mini">上传文件</label>
<input
v-show="false"
id="upload-btn"
ref="uploadBtn"
type="file"
accept="image/png, image/jpeg, image/gif, image/jpg"
@change="loadImg($event)"
>
<div class="el-upload__tip">第1张为主图,其它为从图.尺寸800*800</div>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="7">
<el-form-item label="推荐语">
<el-input v-model="form.recommendation" autocomplete="off" placeholder="" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="描述" :required="true">
<tinymce v-model="form.description" :height="300" />
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="保管事项">
<el-select v-model="form.keep_desc_tpl_id" placeholder="请选择" style="width: 100%">
<el-option
v-for="item in keepOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="温馨提示">
<el-select v-model="form.notice_desc_tpl_id" placeholder="请选择" style="width: 100%">
<el-option
v-for="item in noticeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<h3>sku信息</h3>
<div style="padding-left: 60px">
<sku-edit ref="skuEdit" />
</div>
<el-form-item>
<el-button type="primary" @click="save">保存</el-button>
<router-link style="padding-left: 10px;" to="/goods/erp-goods-list">
<el-button>返回列表</el-button>
</router-link>
</el-form-item>
</el-form>
<el-dialog :visible.sync="imageViewDialog">
<img width="100%" :src="imageViewUrl" alt="">
</el-dialog>
<el-dialog
width="700px"
custom-class="image-upload"
:visible.sync="croperImageDialog"
:close-on-click-modal="false"
@close="emptyUpload"
>
<div style="display:flex;justify-content: center;">
<cropper ref="myCropper" @updateImageList="updateImageList" />
</div>
<div slot="footer">
<div class="dialog-footer-btn">
<div>
<el-button @click="croperImageDialog = false">返 回</el-button>
<el-button type="primary" @click="cropImg">确 定</el-button>
</div>
</div>
</div>
</el-dialog>
</div>
</template>
<script>
import { spuCreate, spuDetail } from '@/api/goods/goods'
import { getOptions, uploadUrl } from '@/api/common/common'
import { empty } from '@/utils/index'
import Tinymce from '@/components/Tinymce/index.vue'
import skuEdit from '@/views/goods/goods/sku_edit.vue'
import { getToken } from '@/utils/auth'
import vuedraggable from 'vuedraggable'
import cropper from '@/views/goods/component/cropper.vue'
export default {
name: 'GoodsEdit',
components: { Tinymce, vuedraggable, cropper, skuEdit },
props: ['id'],
data() {
return {
salesAmountLimit: 1,
uploadImageDialog: false,
croperImageDialog: false,
imageViewDialog: false,
imageViewUrl: false,
uploadUrl: uploadUrl,
cropperDialogVisible: false,
tagOptions: [],
keepOptions: [],
noticeOptions: [],
uppy: {},
cateOptions: [],
brandOptions: [],
goodsTypeOptions: [],
uploadHeaders: {
token: getToken()
},
leftTagFileList: [],
rightTagFileList: [],
form: {},
copy: false,
initForm: {
id: '',
goods_name: '',
barcode: '',
cate_code: '',
brand_code: '',
description: '',
images: [],
pack_spec: '',
pack_count: '',
unit_name: '',
expire_date: '',
video: '',
is_expire: '1',
is_gift: '1',
is_pre_sales: '1',
video_cover: '',
is_show_video: '1',
recommendation: '',
goods_type: '1',
is_suite: '1',
merchant_id: '',
keep_desc_tpl_id: '',
notice_desc_tpl_id: '',
sku_map_list: [],
spu_attrs: []
}
}
},
computed: {},
watch: {
'form.left_tag_type': {
deep: true,
handler(newVal, oldVal) {
if ((newVal === 7 && oldVal !== 7) || (newVal !== 7 && oldVal === 7)) {
this.form.left_tag = ''
this.leftTagFileList = []
}
}
},
'form.right_tag_type': {
deep: true,
handler(newVal, oldVal) {
if ((newVal === 7 && oldVal !== 7) || (newVal !== 7 && oldVal === 7)) {
this.form.right_tag = ''
this.rightTagFileList = []
}
}
}
},
mounted() {
if (this.$route.query.copy) {
this.copy = JSON.parse(this.$route.query.copy)
}
},
activated() {
this.form = JSON.parse(JSON.stringify(this.initForm))
this.detail()
getOptions({ option_names: [
'cateOptions', 'brandOptions', 'goodsTypeOptions', 'goodsDescTplOption', 'goodsKeepTplOption'] }).then(response => {
this.goodsTypeOptions = response.data.goodsTypeOptions
this.cateOptions = response.data.cateOptions
this.brandOptions = response.data.brandOptions
this.keepOptions = response.data.goodsKeepTplOption
this.noticeOptions = response.data.goodsDescTplOption
})
},
methods: {
async save() {
// 获取 skuEdit 子组件 的信息
this.form.sku_map_list = this.$refs.skuEdit.spuInfo.sku_map_list
// is_draft =1 为草稿数据 2-为审核通过的数据
this.form.is_draft = 2
await spuCreate(this.form)
this.$message({
message: '保存成功,待审核!',
type: 'success'
})
this.form = JSON.parse(JSON.stringify(this.initForm))
this.$router.push({ path: '/goods/goods/draft-list' })
},
detail() {
const id = this.$route.query.id
const params = {}
params.id = id
if (empty(id)) {
return
}
spuDetail(params).then(response => {
this.form = response.data
this.$refs.skuEdit.spuInfo.sku_map_list = this.form.sku_map_list
this.$refs.skuEdit.spuAttrs = this.form.spu_attrs
this.form.is_expire = this.form.is_expire.toString()
this.form.is_gift = this.form.is_gift.toString()
this.form.is_show_video = this.form.is_show_video.toString()
this.form.is_suite = this.form.is_suite.toString()
this.form.is_pre_sales = this.form.is_pre_sales.toString()
this.form.is_expire = this.form.is_expire.toString()
if (this.copy) {
this.form.id = ''
}
})
},
viewImage(item) {
this.imageViewUrl = item.url
this.imageViewDialog = true
},
delImage(index) {
this.form.images.splice(index, 1)
},
loadImg(e) {
const file = e.target.files[0]
if (file.size / 1024 / 1024 > 5) {
this.$message.error('上传文件不能超过5M')
return false
}
if (!/\.(jpg|png|gif|JPG|PNG|GIF|)$/.test(file.name)) {
this.$message.info('图片类型必须是jpg,png的一种')
return false
}
const reader = new FileReader()
reader.onload = (e) => {
let data
if (typeof e.target.result === 'object') {
data = window.URL.createObjectURL(new Blob([e.target.result]))
} else {
data = e.target.result
}
this.croperImageDialog = true
this.$nextTick(() => {
this.$refs.myCropper.imgLoad(file, data)
})
}
reader.readAsArrayBuffer(file)
},
emptyUpload() {
this.$refs.uploadBtn.value = ''
},
cropImg() {
this.$refs.myCropper.crop()
},
updateImageList(item) {
this.form.images.push(item.url)
this.croperImageDialog = false
}
}
}
</script>
<style lang="scss" scoped>
.app-container {
overflow-y: auto;
height: 100%;
}
.app-container >>> .cropper-modal {
opacity: 0.5;
}
el-input {
width: 300px;
}
</style>
子组件sku_edit.html
<template>
<div class="">
<el-form ref="SkuEdit" label-width="110px">
<el-form-item label="spu规格" required>
<vuedraggable v-model="spuAttrs" @start="onStart" @end="onEnd">
<transition-group>
<template v-for="(item, index) in spuAttrs">
<div :key="index" :class="(index < (spuAttrs.length - 1)) ? 'attr_select_index' : '' ">
<div>
<el-select
v-model="item.attr"
filterable
allow-create
placeholder="选择或创建"
size="mini"
@blur="addAttr($event,item,index)"
@change="changeAttr($event, index)"
>
<el-option
v-for="(cateItem, cateIndex) in cateAttrs"
:key="cateIndex"
:label="cateItem.label"
:value="cateIndex"
/>
</el-select>
<i :key="index" class="item el-icon-sort" @mouseover="showTooltipSpec" @mouseleave="hideTooltipSpec" />
<span v-if="tooltipVisibleSpec&&index===0">拖动上下排序</span>
<i :key="index" class="el-icon-circle-plus attr_options_add" @click="spuAttrItem(1, index + 1)" />
<i v-if="spuAttrs.length>1" :key="index" class="el-icon-remove attr_options_del" @click="spuAttrItem(2,index)" />
</div>
<div style="margin-left: 20px">
<vuedraggable v-model="item.values" @start="onStart" @end="onEnd">
<transition-group style="display: flex; flex-wrap: wrap;">
<template v-for="(attrVal,vi) in item.values">
<div :key="vi">
<div style="margin-left: 15px">
<el-input
v-model="item.values[vi]"
placeholder="添加规格值"
size="mini"
style="width: 100px;"
@blur="addAttrValue($event,index, vi)"
/>
<template>
<i
:key="vi"
class="item el-icon-s-operation"
@mouseover="showTooltipSpecValue"
@mouseleave="hideTooltipSpecValue"
/>
<span v-if="tooltipVisibleSpecValue&&vi===0&&index===0">拖动左右排序</span>
<i
:key="vi"
class="el-icon-circle-plus attr_val_options_add"
@click="spuAttrValueItem(1,index)"
/>
<i
v-if="item.values.length>1"
:key="vi"
class="el-icon-remove attr_val_options_del"
@click="spuAttrValueItem(2,index,vi)"
/>
</template>
</div>
</div>
</template>
</transition-group>
</vuedraggable>
</div>
</div>
</template>
</transition-group>
</vuedraggable>
</el-form-item>
<el-form-item label="映射sku" required>
<el-table
:data="spuInfo.sku_map_list"
border
:header-row-style="tableHeaderRowStyle"
:header-cell-style="tableHeaderCellStyle"
:max-height="tableHeight"
size="mini"
style="width: 100%"
empty-text="暂无数据"
>
<el-table-column
v-for="(item,index) in spuAttrs"
:key="index"
:label="item.attr"
>
<template slot-scope="scop">
<div>{{ getAttrValue(scop.row, index) }}</div>
</template>
</el-table-column>
<el-table-column
prop="barcode"
label="商品条码"
>
<template slot-scope="scope">
<el-input
v-model="scope.row.barcode"
size="mini"
placeholder="请输入商品条码"
@blur="addBarcode($event,scope.row,scope.$index)"
/>
</template>
</el-table-column>
<el-table-column
prop="price"
label="售价"
>
<template slot-scope="scope">
<el-input
v-model="scope.row.price"
size="mini"
placeholder="请输入商品售价"
@blur="addPrice($event,scope.row,scope.$index)"
/>
</template>
</el-table-column>
<el-table-column
prop="market_price"
label="市场价"
>
<template slot-scope="scope">
<el-input
v-model="scope.row.price"
size="mini"
placeholder="请输入商品市场价"
@blur="addMarketPrice($event,scope.row,scope.$index)"
/>
</template>
</el-table-column>
<el-table-column
prop="image"
label="图片"
width="100"
>
<template slot-scope="scope">
<el-upload
class="avatar-uploader"
:action="uploadUrl+'?type=image'"
:limit="1"
:show-file-list="false"
:on-success="(res,file,fileList) => {handleAvatarSuccess(res,file,fileList,scope.$index)}"
:headers="uploadHeaders"
>
<img v-if="scope.row.image!=''" :src="scope.row.image" class="avatar">
<i v-else class="el-icon-plus avatar-uploader-icon" />
</el-upload>
</template>
</el-table-column>
</el-table>
</el-form-item>
</el-form>
</div>
</template>
<script>
import vuedraggable from 'vuedraggable'
import { getOptions, uploadUrl } from '@/api/common/common'
import { spuDetail, saveSpu } from '@/api/goods/spu'
import { empty } from '@/utils'
import Common from '@/layout/mixin/Common'
import { getToken } from '@/utils/auth'
export default {
name: 'SkuEdit',
components: {
'vuedraggable': vuedraggable
},
mixins: [Common],
props: ['spu_id'],
data() {
return {
// 1-为规格 2-为规格值
changeType: 1,
// 变化内容
changeContent: '',
drag: false,
tooltipVisibleSpec: false,
tooltipVisibleSpecValue: false,
uploadUrl: uploadUrl,
spuInfo: {
sku_map_list: []
},
uploadHeaders: {
token: getToken()
},
cateAttrs: [],
cateAttrCount: 0,
spuAttrs: [],
selectMapSkuVisible: false,
skuListLoading: false,
skuList: [],
barcode: '',
goodsName: '',
selectSkuPage: 1,
selectSkuPageSize: 30,
selectSkuTotal: 0,
selectSkuMapIndex: -1
}
},
mounted() {
getOptions({ option_names: ['spuSpecOptions'] }).then(response => {
this.cateAttrs = response.data.spuSpecOptions
})
if (!empty(this.spu_id)) {
this.spuInfo.id = this.spu_id
spuDetail({ id: this.spu_id }).then(res => {
this.cateAttrCount = Object.keys(this.cateAttrs).length
this.spuInfo.sku_map_list = res.data.sku_map_list
this.spuAttrs = res.data.spu_attrs
this.$refs.imageCropperUpload.setImage([{ path: this.spuInfo.image, url: this.spuInfo.image_url }])
})
}
if (empty(this.spuAttrs)) {
this.spuAttrs = [
{
attr: '',
values: ['']
}
]
}
},
methods: {
empty,
showTooltipSpec() {
console.log('showTooltipSpec','----------')
setTimeout(() => {
this.tooltipVisibleSpec = true
}, 1000)
},
hideTooltipSpec() {
console.log('hideTooltipSpec','----------')
this.tooltipVisibleSpec = false
},
showTooltipSpecValue() {
console.log('showTooltipSpecValue','----------')
setTimeout(() => {
this.tooltipVisibleSpecValue = true
}, 1000)
},
hideTooltipSpecValue() {
console.log('hideTooltipSpecValue','----------')
this.tooltipVisibleSpecValue = false
},
onStart() {
this.drag = true
},
handleAvatarSuccess(res, file, fileList, index) {
this.spuInfo.sku_map_list[index].image = res.data[0].url
},
// 添加规格
addAttr(e, item, index) {
if (empty(e.target.value)) {
return
}
this.spuAttrs.push({
attr: e.target.value,
values: ['']
})
// 判断this.spuAttrs.attr 是否有空值,如果有空值则删除
for (let i = 0; i < this.spuAttrs.length; i++) {
if (empty(this.spuAttrs[i].attr)) {
this.spuAttrs.splice(i, 1)
}
}
},
addBarcode(e, row, index) {
this.spuInfo.sku_map_list[index].barcode = e.target.value
},
addPrice(e, row, index) {
this.spuInfo.sku_map_list[index].price = e.target.value
},
addMarketPrice(e, row, index) {
this.spuInfo.sku_map_list[index].market_price = e.target.value
},
addAttrValue(e, index, vi) {
if (empty(e.target.value)) {
return
}
this.attrSkuMap(1, index, this.spuAttrs[index].values.length - 1)
},
onEnd() {
this.drag = false
this.attrSkuMap(3, 0, 0)
},
// 选择规格名
changeAttr(e, index) {
this.spuAttrs[index].values = ['']
this.spuAttrs[index].attr = this.cateAttrs[index].label
this.attrSkuMap(3, index, -1)
},
spuAttrItem(type, index) {
if (type === 1) {
this.spuAttrs.push({
attr: '',
values: ['']
})
} else {
this.changeType = 1
this.changeContent = this.spuAttrs[index].attr
this.spuAttrs.splice(index, 1)
}
this.attrSkuMap(type, index, type === 1 ? 0 : 1)
},
// 添加|删除规格值
spuAttrValueItem(type, pIndex, subIndex) {
if (type === 1) {
this.spuAttrs[pIndex].values.push('')
} else {
this.changeType = 2
this.changeContent = this.spuAttrs[pIndex].values[subIndex]
this.spuAttrs[pIndex].values.splice(subIndex, 1)
}
this.attrSkuMap(type, pIndex, subIndex)
},
// 生成sku组合表格,处理每行数据x
generateCombinations(type, pIndex, subIndex, changeIndex = 0, spliceIndex = -1, currentCombination = [], index = 0) {
if (index >= this.spuAttrs.length) {
// 1-新增,2-删除,3-修改
if (type === 1) {
// 页面新开 新增的sku情况
if (empty(this.spuInfo.sku_map_list[changeIndex])) {
this.spuInfo.sku_map_list.push({
barcode: '',
price: '',
market_price: '',
attrs: [],
image: ''
})
// attrs 字段与页面显示无关,只为传给后端使用
for (let j = 0; j < currentCombination.length; j++) {
this.spuInfo.sku_map_list[changeIndex].attrs.push({
attr: currentCombination[j].attr,
value: currentCombination[j].value
})
}
// 页面新开 编辑的sku情况
} else if (currentCombination.length === this.spuInfo.sku_map_list[changeIndex].attrs.length) {
for (let j = 0; j < currentCombination.length; j++) {
this.spuInfo.sku_map_list[changeIndex].attrs[j].attr = currentCombination[j].attr
this.spuInfo.sku_map_list[changeIndex].attrs[j].value = currentCombination[j].value
}
} else if (currentCombination.length > this.spuInfo.sku_map_list[changeIndex].attrs.length) {
const item = currentCombination.slice(-1)
this.spuInfo.sku_map_list[changeIndex].attrs.push({
attr: item.attr,
value: item.value
})
}
} else if (type === 2) {
// 遍历currentCombination,把value 拼接组合,后面在循环中删除多余重复的行
if (this.changeType === 1) {
let currentCombinationValue = ''
for (let j = 0; j < currentCombination.length; j++) {
currentCombinationValue += currentCombination[j].value + '_'
}
for (let k = 0; k < this.spuInfo.sku_map_list.length; k++) {
if (empty(this.spuInfo.sku_map_list[k])) {
continue
}
for (let j = 0; j < this.spuInfo.sku_map_list[k].attrs.length; j++) {
if (empty(this.spuInfo.sku_map_list[k].attrs[j])) {
continue
}
if (this.changeContent === this.spuInfo.sku_map_list[k].attrs[j].attr
) {
// 删除规格
this.spuInfo.sku_map_list[k].attrs.splice(j, 1)
// 组合规格值
let itemValueCombination = ''
for (let m = 0; m < this.spuInfo.sku_map_list[k].attrs.length; m++) {
itemValueCombination += this.spuInfo.sku_map_list[k].attrs[m].value + '_'
}
this.spuInfo.sku_map_list[k].combination = itemValueCombination
}
}
}
for (let v = 0; v < this.spuInfo.sku_map_list.length; v++) {
let count = 0
if (empty(this.spuInfo.sku_map_list[v])) {
continue
}
if (currentCombinationValue === this.spuInfo.sku_map_list[v].combination) {
count++
}
// 相同规格的行只保留一条
if (count > 1) {
this.spuInfo.sku_map_list.splice(v, 1)
}
}
} else {
for (let k = 0; k < this.spuInfo.sku_map_list.length; k++) {
if (empty(this.spuInfo.sku_map_list[k]) || empty(this.spuInfo.sku_map_list[k].attrs)) {
continue
}
const attrs = this.spuInfo.sku_map_list[k]?.attrs || []
for (let j = 0; j < attrs.length; j++) {
if (this.empty(attrs[j])) {
continue
}
if (this.changeContent === attrs[j].value) {
// 删除整行
this.spuInfo.sku_map_list.splice(k, 1)
break // 如果删除了当前行,需要跳出循环
}
}
}
}
} else {
for (let j = 0; j < currentCombination.length; j++) {
this.spuInfo.sku_map_list[changeIndex].attrs[j].attr = currentCombination[j].attr
this.spuInfo.sku_map_list[changeIndex].attrs[j].value = currentCombination[j].value
}
}
changeIndex++
spliceIndex = -1
// return 之后执行 this.generateCombinations 的逻辑
return [changeIndex, spliceIndex]
}
// 规格和规格值都遍历
for (var i = 0; i < this.spuAttrs[index].values.length; i++) {
currentCombination.push({
attr: this.spuAttrs[index].attr,
value: this.spuAttrs[index].values[i]
})
// 假如有 尺寸 S M ,颜色 黄色 白色
// 第一次遍历生成 {"attr":"尺寸","value":"S"}
// 第二次遍历生成 {"attr":"尺寸","value":"S"},{"attr":"颜色","value":"黄色"}组合,然后在渲染到表格的第一行中
// changeIndex 为行数或者组合数量
// generateCombinations 自循环,遇到return [changeIndex, spliceIndex]后才往下执行
const res = this.generateCombinations(type, pIndex, subIndex, changeIndex, spliceIndex, currentCombination, index + 1)
changeIndex = res[0]
spliceIndex = res[1]
currentCombination.pop()
}
return [changeIndex, spliceIndex]
},
attrSkuMap(type, pIndex, subIndex) {
this.generateCombinations(type, pIndex, subIndex)
return
},
getAttrValue(item, i) {
return item.attrs[i].value
},
async saveSpu() {
return await saveSpu(this.spuInfo)
}
}
}
</script>
<style scoped lang="scss">
.cate_level1 {
color: #E6A23C;
}
.attr_select_index {
margin-bottom: 14px;
}
.attr_options_add, .attr_val_options_add {
margin-left: -2px;
font-size: 20px;
color: #409EFF;
cursor: pointer;
}
.item {
padding: 3px;
//background-color: #fdfdfd;
//border: solid 1px #eee;
margin-bottom: 10px;
cursor: move;
}
.item:hover {
background-color: #f1f1f1;
cursor: move;
}
.chosen {
border: solid 2px #3089dc !important;
}
.attr_options_del, .attr_val_options_del {
margin-left: -2px;
font-size: 20px;
color: #F56C6C;
cursor: pointer;
}
.tooltip-container {
position: relative;
display: inline-block;
}
.tooltip-text {
visibility: visible;
width: 120px;
background-color: black;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px 0;
position: absolute;
z-index: 1;
bottom: 125%; /* Position the tooltip above the icon */
left: 50%;
margin-left: -60px;
opacity: 0;
transition: opacity 0.3s;
}
.tooltip-container:hover .tooltip-text {
visibility: visible;
opacity: 1;
}
.avatar-uploader .el-upload {
border: 1px dashed #d9d9d9;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
}
.avatar-uploader .el-upload:hover {
border-color: #409EFF;
}
.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 30px;
height: 30px;
line-height: 30px;
text-align: center;
}
.avatar {
width: 30px;
height: 30px;
display: block;
}
</style>
数据结构
{
"msg": "ok",
"code": 10000,
"data": {
"id": "710432902999261184",
"goods_name": "spu测试ywz",
"cate_code": "Lthg98",
"brand_code": "UpsPhd",
"supplier_code": "",
"audit_status": 1,
"pack_spec": "101",
"pack_count": "102",
"unit_name": "103",
"expire_date": "2024-10-24",
"images": [
"https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png",
"https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/4508beb29e17b950796cc5961a88b520299817.png"
],
"video": "",
"video_cover": "",
"is_show_video": 1,
"description": "<p>spu测试spu测试spu测试<\/p>",
"sort": 0,
"is_gift": 1,
"goods_type": 1,
"sales_count": 0,
"is_sales_amount_limit": 1,
"recommendation": "spu测试spu测试spu测试",
"is_search": 1,
"is_pre_sales": 1,
"is_expire": 1,
"is_suite": 1,
"merchant_id": 1,
"business_type": 1,
"keep_desc_tpl_id": 2,
"notice_desc_tpl_id": 0,
"del_status": 1,
"create_time": "2024-10-31 10:06:43",
"update_time": "2024-10-31 10:06:43",
"sku_map_list": [
{
"id": 710432903292862464,
"spu_id": "710432902999261184",
"goods_code": "",
"barcode": "spu_1234561345678ywz1",
"image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png",
"search_weight": 0,
"sort": 0,
"sales_count": 0,
"price": "99.00",
"market_price": "199.00",
"cost_price": "0.00",
"create_time": "2024-10-31 10:06:43",
"update_time": "2024-10-31 10:06:43",
"attrs": [
{
"attr": "尺寸",
"value": "尺寸1"
},
{
"attr": "颜色",
"value": "颜色1"
}
]
},
{
"id": 710432903292862465,
"spu_id": "710432902999261184",
"goods_code": "",
"barcode": "spu_12345631345678ywz1",
"image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png",
"search_weight": 0,
"sort": 0,
"sales_count": 0,
"price": "99.00",
"market_price": "199.00",
"cost_price": "0.00",
"create_time": "2024-10-31 10:06:43",
"update_time": "2024-10-31 10:06:43",
"attrs": [
{
"attr": "尺寸",
"value": "尺寸1"
},
{
"attr": "颜色",
"value": "颜色2"
}
]
},
{
"id": 710432903292862466,
"spu_id": "710432902999261184",
"goods_code": "",
"barcode": "spu_123456451345678ywz1",
"image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png",
"search_weight": 0,
"sort": 0,
"sales_count": 0,
"price": "99.00",
"market_price": "199.00",
"cost_price": "0.00",
"create_time": "2024-10-31 10:06:43",
"update_time": "2024-10-31 10:06:43",
"attrs": [
{
"attr": "尺寸",
"value": "尺寸2"
},
{
"attr": "颜色",
"value": "颜色1"
}
]
},
{
"id": 710432903292862467,
"spu_id": "710432902999261184",
"goods_code": "",
"barcode": "spu_123456561345678ywz1",
"image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png",
"search_weight": 0,
"sort": 0,
"sales_count": 0,
"price": "99.00",
"market_price": "199.00",
"cost_price": "0.00",
"create_time": "2024-10-31 10:06:43",
"update_time": "2024-10-31 10:06:43",
"attrs": [
{
"attr": "尺寸",
"value": "尺寸2"
},
{
"attr": "颜色",
"value": "颜色2"
}
]
}
],
"spu_attrs": [
{
"attr": "尺寸",
"values": [
"尺寸1",
"尺寸2"
]
},
{
"attr": "颜色",
"values": [
"颜色1",
"颜色2"
]
}
]
},
"log_id": "710498316961951744"
}