vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > element动态生成表格

element根据输入动态生成表格的示例代码

作者:vvvbird

在现代电商系统开发中,后台管理界面经常需要根据商品规格和规格值动态生成SKU表格,本文通过element-ui框架,展示了如何在Vue.js的环境下,利用子组件和动态绑定的方式,实现SKU表格的增删改查功能

场景:后台页面根据商品规格和规格值,动态(增删改查)在表格中生成对应的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"
}

到此这篇关于element根据输入,动态生成表格的文章就介绍到这了,更多相关element动态生成表格内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文