笛卡尔积 SKU
笛卡尔积 SKU
git 地址
代码
-
template
<center><h1>笛卡尔积 sku</h1></center> <el-button type="primary" @click="showAddSkuAttrDialog">添加属性</el-button> <el-form> <el-form-item v-for="(item, i) in manyTableData" :key="item.attr_id"> <el-row> <el-col :span="24"> <span><span class="span-box"><span>{{ item.attr_name }}</span> <el-tooltip class="item" effect="dark" content="删除" placement="top-start" :enterable="false"><el-button @click="delAttrMany(i)" size="mini"><i class="el-icon-delete"/></el-button></el-tooltip> </span></span> </el-col> <el-col :span="24"> <!-- 复选框组 --> <el-checkbox-group v-model="item.cb" @change="setSkuTable"> <el-checkbox v-for="cb in item.attr_vals" :label="cb.id" :key="cb.id" border >{{ cb.value }} </el-checkbox> </el-checkbox-group> <el-input class="input-new-tag" v-if="item.inputVisible" v-model="item.inputValue" ref="saveSkuAttrInput" size="small" @keyup.enter.native="handleInputConfirm(item)" @blur="handleInputConfirm(item)" > </el-input> <el-button v-else class="button-new-tag" size="small" @click="showInput(item)">+ New Tag </el-button> </el-col> </el-row> </el-form-item> </el-form> <el-table :data="tableData7" :span-method="objectSpanMethod" border > <el-table-column v-for="(item, i) in tableHeader" :key="i" :prop="item.prop" :label="item.label"></el-table-column> <el-table-column prop="kucun" label="库存"> <template slot-scope="scope"> <el-input-number v-model="scope.row.kucun" :min="0" :step="1" label="描述文字" @blur="handlerBlur(scope.row)" ></el-input-number> </template> </el-table-column> <el-table-column prop="moany" label="金钱"> <template slot-scope="scope"> <el-input-number v-model="scope.row.moany" :precision="2" :step="0.01" :min="0.00"></el-input-number> </template> </el-table-column> </el-table> <!-- 添加属性对话框 --> <el-dialog title="提示" :visible.sync="addSkuAttrDialogVisible" width="50%" @close="addSkuAttrDialogClosed" v-if="addSkuAttrDialogVisible" > <el-form :model="addSkuAttrForm" :rules="addSkuAttrFormRule" ref="addSkuAttrFormRef" label-width="100px"> <el-form-item label="属性名称" prop="name"> <el-input v-model="addSkuAttrForm.name" ref="addSkuAttrInput" @keyup.enter.native="submitAddSkuAttr"></el-input> </el-form-item> <el-form-item label="英文名称" prop="en_name"> <el-input v-model="addSkuAttrForm.en_name" @keyup.enter.native="submitAddSkuAttr"></el-input> <el-button @click="createEnNameBind()">随机生成</el-button> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addSkuAttrDialogVisible = false">取 消</el-button> <el-button type="primary" @click="submitAddSkuAttr" >确 定</el-button> </span> </el-dialog>
-
vuex
state: { // 参数源 manyTableData: [ { attr_id: 1, attr_name: '颜色', attr_vals: [ { id: 1, value: '白色' }, { id: 2, value: '黑色' }, { id: 3, value: '红色' } ], cb: [], en_name: 'a', inputValue: '', inputVisible: false }, { attr_id: 2, attr_name: '型号', attr_vals: [ { id: 4, value: 'X' }, { id: 5, value: 'L' }, { id: 6, value: 'XL' } ], cb: [], en_name: 'b', inputValue: '', inputVisible: false }, { attr_id: 3, attr_name: '大小', attr_vals: [ { id: 7, value: '大' }, { id: 8, value: '中' }, { id: 9, value: '小' } ], cb: [], en_name: 'c', inputValue: '', inputVisible: false } ], // 选中的参数 shopType: [], // 动态参数表头 tableHeader: [], tableData7: [], // 参数属性 skuAttr: [], spanArr: [], // 添加属性对话框的显示与隐藏 addSkuAttrDialogVisible: false, // 添加属性 表单对象 addSkuAttrForm: { name: '', en_name: '' }, // 添加属性 验证对象 addSkuAttrFormRule: { name: [ { required: true, message: '属性名必须', trigger: 'blur' } ], en_name: [ { required: true, message: '英文名称必须', trigger: 'change' }, { required: true, message: '英文名称必须', trigger: 'blur' } ] }, // 获取英文名的初始设置 i: 0, flag: true }
-
methods
methods: { addSkuAttrInputFocus () { this.$nextTick(_ => { this.$refs.addSkuAttrInput.$refs.input.focus() }) }, descartes, // 删除参数 - 动态参数 delAttrMany (key) { this.$confirm('是否删除?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).then(() => { this.manyTableData.splice(key, 1) this.$message({ type: 'success', message: '删除成功!' }) this.setSkuTable() }).catch(() => { this.$message({ type: 'info', message: '已取消删除' }) }) }, // 设置 sku 表格 setSkuTable () { this.shopType = [] this.manyTableData.forEach(item => { // item // { // id: 1, // prop: "color", // name: "颜色", // typeNames: [ // {type: "红色", id: 301}, // {type: "白色", id: 302}, // {type: "蓝色", id: 303}, // {type: "粉色", id: 304} // ] // } if (item.cb.length > 0) { // 有选中才进来 const obj = { id: item.attr_id, prop: item.en_name, name: item.attr_name, typeNames: [] } item.attr_vals.forEach(item2 => { if (item.cb.includes(item2.id)) { obj.typeNames.push({ type: item2.value, id: item2.id }) } }) this.shopType.push(obj) } }) this.setTableHeader() this.processing() }, handleInputConfirm (row) { const inputValue = row.inputValue.trim().toUpperCase() if (inputValue) { // 判断是否存在 const res = row.attr_vals.find(item => item.value.toUpperCase() === inputValue) console.log(res) if (res) { this.$message.error('已存在') row.inputVisible = false row.inputValue = '' return false } // id 集合 const ids = [] this.manyTableData.forEach(item => { item.attr_vals.forEach(item2 => { ids.push(item2.id) }) }) // 向后端请求添加属性值 let newParams = {} newParams = { id: Math.max(...ids) + 1, value: inputValue } this.$message.success('ok') row.attr_vals.push(newParams) } row.inputVisible = false row.inputValue = '' }, showInput (row) { row.inputVisible = true this.$nextTick(_ => { this.$refs.saveSkuAttrInput[0].$refs.input.focus() }) }, // 处理数据 processing () { this.newData = [] for ( let i = 0; i < this.shopType.length; i++ ) { var newlist = [] for ( let index = 0; index < this.shopType[i].typeNames.length; index++ ) { const currArr = { id: this.shopType[i].typeNames[index].id, name: this.shopType[i].typeNames[index].type } newlist.push(currArr) } this.newData.push(newlist) } this.getList() }, // 转换数据 getList () { this.tableData7 = [] this.newList = this.descartes(this.newData) for (let index = 0; index < this.newList.length; index++) { const obj = {} for (var key in this.skuAttr) { obj[this.skuAttr[key]] = this.newList[index].name[key] obj.skuids = this.newList[index].id } Object.assign(obj, { kucun: 0, moany: 0.00 }) this.tableData7.push(obj) } this.getSpanArr(this.shopType) }, // 计算位置的方法 getSpanArr (data) { const it = data[Symbol.iterator]() let currIt = it.next() var i = 0 const res = [] while (!currIt.done) { res[i] = currIt.value.typeNames.length currIt = it.next() i++ } for (const i in res) { let cj = 1 delete res[i] for (const j of res) { cj = cj * (j === undefined ? 1 : j) } this.spanArr[i] = cj } }, // 合并行数 objectSpanMethod ({ row, column, rowIndex, columnIndex }) { for (const i in this.spanArr) { if (columnIndex === parseInt(i)) { if (rowIndex % this.spanArr[i] === 0) { return [ this.spanArr[i], 1 ] } return [0, 0] } } }, // 设置库存校验 handlerBlur (row) { const kucun = row.kucun if (kucun === undefined) { row.kucun = 0 } else if (!/^\d+$/.test(kucun)) row.kucun = 0 }, // 设置表头 setTableHeader () { this.tableHeader = [] this.skuAttr = [] this.shopType.forEach(item => { this.tableHeader.push({ label: item.name, prop: item.prop }) this.skuAttr.push(item.prop) }) }, showAddSkuAttrDialog () { this.addSkuAttrDialogVisible = true this.addSkuAttrInputFocus() }, submitAddSkuAttr () { this.$refs.addSkuAttrFormRef.validate((valid, e) => { if (!valid) { if (JSON.stringify(e) !== {}) { const errMsg = Object.values(e)[0][0].message return this.$message.error(errMsg) } } else { const obj = this.addSkuAttrForm obj.name = obj.name.trim().toUpperCase() const res = this.manyTableData.find(item => item.attr_name === obj.name) if (res) return this.$message.error('已存在') // 获取当前最大的 ID 值 const ids = [] this.manyTableData.forEach(item => ids.push(item.attr_id)) const newId = Math.max(...ids) + 1 // 获取英文名 const enName = this.getCharacterOnly() const newSkuAttrObj = { attr_id: newId, attr_name: obj.name, attr_vals: [], cb: [], en_name: enName, inputValue: '', inputVisible: false } this.manyTableData.push(newSkuAttrObj) } }) }, // 生成随机英文并绑定 createEnNameBind (prefix = '') { this.addSkuAttrForm.en_name = prefix + this.getCharacter().toLowerCase() }, // 生成唯一的英文名 getCharacterOnly () { while (this.flag) { if (this.i < 3) { this.createEnNameBind() } else { this.createEnNameBind(this.addSkuAttrForm.en_name) } const res = this.checkEnNameExists() if (!res) { this.flag = false } this.i++ } this.initEnNameJishu() return this.addSkuAttrForm.en_name }, // 重置获取英文名的配置 initEnNameJishu () { this.i = 0 this.flag = true }, // 判断英文名是否已经存在 checkEnNameExists () { return this.manyTableData.find(item => item.en_name.toLowerCase() === this.addSkuAttrForm.en_name.toLowerCase()) }, /** * 随机生成一个字母(可设置大小写) * @param flag * @returns {string} */ getCharacter (flag = 'upper') { let res switch (flag) { case 'upper': res = String.fromCharCode(Math.floor(Math.random() * 26) + 'A'.charCodeAt(0)) break case 'lower': res = String.fromCharCode(Math.floor(Math.random() * 26) + 'a'.charCodeAt(0)) break default: res = '' break } return res }, addSkuAttrDialogClosed () { if (this.$refs.addSkuAttrFormRef) this.$refs.addSkuAttrFormRef.resetFields() } }
-
computed
computed: { ...mapState([ 'manyTableData', 'spanArr' ]), tableHeader: { get () { return this.$store.state.tableHeader }, set (val) { this.$store.state.tableHeader = val } }, skuAttr: { get () { return this.$store.state.skuAttr }, set (val) { this.$store.state.skuAttr = val } }, tableData7: { get () { return this.$store.state.tableData7 }, set (val) { this.$store.state.tableData7 = val } }, shopType: { get () { return this.$store.state.shopType }, set (val) { this.$store.state.shopType = val } }, addSkuAttrDialogVisible: { get () { return this.$store.state.addSkuAttrDialogVisible }, set (val) { this.$store.state.addSkuAttrDialogVisible = val } }, addSkuAttrForm: { get () { return this.$store.state.addSkuAttrForm }, set (val) { this.$store.state.addSkuAttrForm = val } }, addSkuAttrFormRule: { get () { return this.$store.state.addSkuAttrFormRule }, set (val) { this.$store.state.addSkuAttrFormRule = val } }, i: { get () { return this.$store.state.i }, set (val) { this.$store.state.i = val } }, flag: { get () { return this.$store.state.flag }, set (val) { this.$store.state.flag = val } } }