1.sku多规格效果图
商品的sku涉及到很多动态表单,因为分为单规格和多规格。而每次一到写动态表单就让人头疼。所以特此记录一下,方便自己下次再用也帮助他人减少麻烦。闲话少叙,先看效果图。
上面的部分输入表单可以无视了,主要还是动态商品规格sku的添加。上代码:
2.在vue框架中使用
<template><div class="goodsdetails"><div class="title" style="display: flex;justify-content: space-between;align-items: center;"><el-page-header @back="goBack" :content="title"></el-page-header><el-button type="primary" size="small" @click="submit">保存</el-button></div><a-divider /><el-descriptions title="基础信息"></el-descriptions><el-form :model="ruleForm" :inline="false" ref="ruleForm" label-width="100px" class="demo-ruleForm"><el-form-item label="封面图:"><Uploadimg :limit="1" :key="timer" :filelist="ruleForm.image" @getfile="filelist"></Uploadimg></el-form-item><el-form-item label="轮播图:"><Uploadimg :limit="3" :key="timer" :filelist="ruleForm.sliderImage" @getfile="filelistarr"></Uploadimg></el-form-item><el-form-item label="商品分类:" ><el-cascader ref="myCascader" style="width:360px" @change="getpositionName" v-model="ruleForm.cateId" :options="options" placeholder="请选择分类" :props="{ emitPath:false,checkStrictly: true,value:'id',label:'name'}" class="ml-4"></el-cascader></el-form-item><el-form-item label="商品名称:" ><el-input v-model="ruleForm.storeName"></el-input></el-form-item><el-form-item label="商品简介:" ><el-input v-model="ruleForm.storeInfo"></el-input></el-form-item><el-form-item label="详细描述:" ><el-input v-model="ruleForm.description"></el-input></el-form-item><el-form-item label="返现积分:" ><el-input v-model="ruleForm.giveIntegral" type="number" min=0></el-input></el-form-item><el-form-item label="销量:" ><el-input v-model="ruleForm.ficti" type="number" min=0></el-input></el-form-item><el-form-item label="关键词:" ><el-tag :key="tag" v-for="tag in dynamicTags" closable :disable-transitions="false" @close="handleClosekey(tag)">{{tag}}</el-tag><el-inputclass="input-new-tag"v-if="inputVisible"v-model="inputValue"ref="saveTagInput"size="small"@keyup.enter.native="handleInputConfirmkey"@blur="handleInputConfirmkey"></el-input><el-button v-else class="button-new-tag" size="small" @click="showInputkey">+ New Tag</el-button></el-form-item><el-form-item label="排序:" ><el-input v-model="ruleForm.sort" placeholder="数值越大越靠前" type="number" min=0></el-input></el-form-item><el-form-item label="是否多规格:" ><el-switch v-model="ruleForm.specType"></el-switch></el-form-item><el-form-item label="是否积分商品:" ><el-switch v-model="ruleForm.integralType"></el-switch></el-form-item><!-- 规格 --><el-divider></el-divider><div><div class="goods-spec" v-if="ruleForm.specType"><h3>商品规格</h3><el-link type="primary" @click="addPrivateSpec" class="goods-spec-add">添加规格</el-link></div><div v-if="ruleForm.specType" class="goods-container" v-for="(attr, index) in items" :key="index"><div class="goods-content"><div class="goods-content-box"><div class="goods-content-left"><el-form label-width="80px" style="width:400px"><el-form-item label="规格名"><el-input v-model="attr.value" placeholder="请输入规格名"></el-input></el-form-item><el-form-item label="规格值"><el-tag v-for="tag in attr.detail" :key="tag" closable :disable-transitions="false" @close="handleClose(tag, attr)">{{ tag }}</el-tag><el-inputclass="input-new-tag"v-if="attr.inputVisible"v-model="attr.inputValue":ref="`saveTagInput${index}`"size="small"@keyup.enter.native="handleInputConfirm(attr.inputValue, attr)"@blur="handleInputConfirm(attr.inputValue, attr)"></el-input><el-button v-else class="button-new-tag" size="small" @click="showInput(attr, index)">+ 添加</el-button></el-form-item></el-form></div><div class="goods-content-right"><el-link type="danger" @click="delPrivateSpec(index)">删除规格</el-link></div></div></div></div><p style="margin:24px 0 10px 0">价格 / 库存</p><el-table ref="multipleTable" :data="tableColumnList.tableBodyList" stripe tooltip-effect="dark" style="width: 100%;margin-top:1%;"><el-table-column :label="item.propName" :property="item.prop" v-for="item in tableColumnList.tableHeaderList" :key="item.prop" align="center"><template slot-scope="scope"><span>{{ scope.row[scope.column.property] }}</span></template></el-table-column><el-table-column label="商品条码"><template slot-scope="scope"><el-input v-model="scope.row.barCode"></el-input></template></el-table-column><el-table-column label="价格(元)"><template slot-scope="scope"><el-input v-model.number="scope.row.price"></el-input></template></el-table-column><el-table-column label="成本价(元)"><template slot-scope="scope"><el-input v-model.number="scope.row.cost"></el-input></template></el-table-column><el-table-column label="原价(元)"><template slot-scope="scope"><el-input v-model.number="scope.row.otPrice"></el-input></template></el-table-column><el-table-column label="库存"><template slot-scope="scope"><el-input v-model.number="scope.row.stock"></el-input></template></el-table-column><el-table-column label="体积"><template slot-scope="scope"><el-input v-model="scope.row.volume"></el-input></template></el-table-column><el-table-column label="重量"><template slot-scope="scope"><el-input v-model="scope.row.weight"></el-input></template></el-table-column><el-table-column label="兑换所需积分" v-if="ruleForm.integralType"><template slot-scope="scope"><el-input v-model="scope.row.integral"></el-input></template></el-table-column></el-table></div><!-- <el-button type="primary" style="width: 20%;margin-left: 30%;margin-top: 20px;">保存</el-button> --></el-form></div>
</template><script>import Uploadimg from "@/components/Uploadimg";export default {data(){return{ruleForm: {cateId:'',cateName:'',image:[],sliderImage:[],storeName: '',storeInfo: '',description: '',giveIntegral: '',ficti: '',sort: '',specType: false,integralType:false,},dynamicTags: ['标签一', '标签二'], //关键词inputVisible: false,inputValue: '',tableColumnList: {tableHeaderList: [],tableBodyList: [{}]// inventory: ''},items: [ //sku属性{value: '', //规格名detail: [], //规格值数组inputVisible: false,inputValue: ''}],options:[], //商品类列表id:"", //无则添加有则编辑timer:'', //刷新子组件title:"",}},mounted(){this.title="添加商品"if(this.$route.query.id){this.id=this.$route.query.id;this.title="商品信息"this.getdetails();}this.getoptions();},computed: {// 计算规格calculateAttribute() {// 初始化let obj = {}this.items.forEach((item) => {// 判断有没有输入规格名if (item.value) {//规格名:规格值 //'颜色':'尺寸'obj[item.value] = item.detail}})return obj}},watch: {// 监听规格数据calculateAttribute(newVal) {if(!this.ruleForm.specType){return;}this.attribute(newVal);// let cloneNewVal = JSON.parse(JSON.stringify(newVal))// let attrName = [] //规格名数组// let attrValue = [] //规格值数组// for (let key in cloneNewVal) {// attrName.push(key)// attrValue.push(cloneNewVal[key])// }// // 表格内容数据(笛卡尔积算法)// let finalArr = this.cartesianProductOf(...attrValue)// let tableObj = {// tableBodyList: [],// tableHeaderList: []// }// // 表格内容// tableObj.tableBodyList = finalArr.map((item) => {// let obj = {// barCode: '', //商品条码// cost:0, //成本价// otPrice:0, //原价// price:0, //现价// stock: 0, //库存// volume:'', //体积// weight:'', //重量// }// for (let i = 0; i < item.length; i++) {// obj[attrName[i]] = item[i]// }// return obj// })// this.tableColumnList.tableBodyList = tableObj.tableBodyList //表格内容数据// // 表头// let skuTableArr = Object.keys(newVal)// tableObj.tableHeaderList = skuTableArr.map((item) => {// return {// prop: item,// propName: item// }// })// this.tableColumnList.tableHeaderList = tableObj.tableHeaderList // 表头},'ruleForm.specType':{deep:true,handler:function(newV,oldV){if(!newV){this.tableColumnList= this.$options.data().tableColumnList;this.items=this.$options.data().items;}}}},methods: {getpositionName(){const info = this.$refs.myCascader.getCheckedNodes()[0];this.ruleForm.cateName=info.label;},getoptions(){ //获取商品分类列表const that = this;this.$api.categorylist({}).then(function (response) {if(response.code==0){that.options=that.removeEmptyChildren(response.data);}else{that.$message({message: response.message,center: true,type: 'warning',});}})},removeEmptyChildren (node) { //杀生var that=this;node.forEach(item => {if ('children' in item && item.children.length === 0) {delete item.children} else if ('children' in item && item.children.length) {that.removeEmptyChildren(item.children)}})return node;},attribute(newVal){var that=this;this.$api.goodssku(that.items).then(res=>{if(res.code==0){// console.log("属性",res);let cloneNewVal = JSON.parse(JSON.stringify(newVal))let attrName = [] //规格名数组let attrValue = [] //规格值数组for (let key in cloneNewVal) {attrName.push(key)attrValue.push(cloneNewVal[key])}// 表格内容数据(笛卡尔积算法)let finalArr = this.cartesianProductOf(...attrValue) let tableObj = {tableBodyList: [],tableHeaderList: []}// 表格内容tableObj.tableBodyList = res.data.map((item) => {var detail=item.detail;return Object.assign(item, detail);})this.tableColumnList.tableBodyList = tableObj.tableBodyList //表格内容数据this.tableColumnList.tableBodyList = res.data;// 表头let skuTableArr = Object.keys(newVal)tableObj.tableHeaderList = skuTableArr.map((item) => {return {prop: item,propName: item}})this.tableColumnList.tableHeaderList = tableObj.tableHeaderList // 表头}else{this.$message({message: res.message,center: true,});}}).catch(err=>{console.log("网络错误",err)})},//上传的图片列表filelist(list){console.log("封面图片:",list)this.ruleForm.image=list;},filelistarr(list){console.log("轮播图片:",list)this.ruleForm.sliderImage=list;},goBack(){this.$router.go(-1);},//关键词操作handleClosekey(tag) {this.dynamicTags.splice(this.dynamicTags.indexOf(tag), 1);},showInputkey() {this.inputVisible = true;this.$nextTick(_ => {this.$refs.saveTagInput.$refs.input.focus();});},handleInputConfirmkey() {let inputValue = this.inputValue;if (inputValue) {this.dynamicTags.push(inputValue);}this.inputVisible = false;this.inputValue = '';},//获取详情getdetails(){var that=this;this.$api.goodsdetails({id:that.id}).then(res=>{if(res.code==0){console.log("商品:",res);that.ruleForm=res.data;that.ruleForm.image=res.data.image.split(",");that.ruleForm.sliderImage=res.data.sliderImage.split(",");that.dynamicTags=res.data.keyword.split(",");that.items=res.data.items.map(item=>{item.inputValue="";item.inputVisible=false;return item;})setTimeout(()=>{let tablearr=[];for(var i=0; i<res.data.attrs.length;i++){tablearr.push(Object.assign(that.tableColumnList.tableBodyList[i],res.data.attrs[i]));}that.tableColumnList.tableBodyList=tablearr;},500)that.timer = new Date().getTime();}else{this.$message({message: res.message,center: true,});}}).catch(err=>{console.log("网络错误",err)})},submit(){var that=this;var obj;if(this.id){ //编辑obj=JSON.parse(JSON.stringify(that.ruleForm));obj.id=that.id;obj.items=that.items;obj.attrs=that.tableColumnList.tableBodyList;obj.keyword=that.dynamicTags.toString();obj.image=obj.image.toString();obj.sliderImage=obj.sliderImage.toString();this.$api.goodsedit(obj).then(res=>{if(res.code==0){this.$message({type:"success",message: res.message,center: true,});that.$router.push({path:'/product/goods'})}else{this.$message({message: res.message,center: true,});}}).catch(err=>{console.log("网络错误",err)})}else{obj=JSON.parse(JSON.stringify(that.ruleForm));obj.items=that.items;obj.attrs=that.tableColumnList.tableBodyList;obj.keyword=that.dynamicTags.toString();obj.image=obj.image.toString();obj.sliderImage=obj.sliderImage.toString();this.$api.goodsadd(obj).then(res=>{if(res.code==0){this.$message({type:"success",message: res.message,center: true,});that.$router.push({path:'/product/goods'})}else{this.$message({message: res.message,center: true,});}}).catch(err=>{console.log("网络错误",err)})}},/*****规格*****/// 添加规格addPrivateSpec(index) {this.items.push({value: '',detail: [],inputVisible: false,inputValue: ''})},delPrivateSpec(index) {this.items.splice(index, 1)},handleInputConfirm(val, attr) {if (val) {attr.detail.push(val)}attr.inputVisible = falseattr.inputValue = ''},handleClose(tag, item) {item.detail.splice(item.detail.indexOf(tag), 1)},showInput(attr, index) {attr.inputVisible = truethis.$nextTick((_) => {this.$refs[`saveTagInput${index}`][0].$refs.input.focus()})},// 笛卡尔积算法cartesianProductOf(...args) {return args.reduce((total, current) => {let ret = []total.forEach((a) => {current.forEach((b) => {ret.push(a.concat([b]))})})return ret},[[]])}},components:{Uploadimg:Uploadimg,}};
</script>
<style scoped>.goodsdetails{height: 100%;width: 100%;background: #FFFFFF;padding: 30px;}.goodsdetails .demo-ruleForm{width: 100%;/* display: flex;align-items: center;justify-content: space-between;flex-wrap: wrap; */}.goodsdetails .demo-ruleForm>div{width: 80%;}.goodsdetails .el-tag + .el-tag {margin-left: 10px;}.goodsdetails .button-new-tag {margin-left: 10px;height: 32px;line-height: 30px;padding-top: 0;padding-bottom: 0;}.goodsdetails .input-new-tag {width: 90px;margin-left: 10px;vertical-align: bottom;}/* .goodsdetails .uploadimg{display: flex;width: 80vw;} */.goods-spec {display: flex;justify-content: space-between;margin-bottom: 10px;}.goods-spec .goods-spec-add {margin-right: 15px;}.goods-container .button-new-tag {height: 32px;line-height: 30px;padding-top: 0;padding-bottom: 0;}.goods-container .input-new-tag {width: 90px;margin-right: 10px;vertical-align: bottom;}.goods-container .el-tag {margin-right: 10px;}.goods-container .goods-content {margin-bottom: 10px;padding: 14px;border: 1px solid #ebeef5;border-radius: 4px;background-color: #fcfcfc;}.goods-content .goods-content-box {display: flex;align-items: center;}.goods-content-box .goods-content-left {flex: 1;}
</style>
这是单个的vue文件,在使用之前,先确保你项目是否使用了element Ui组件。使用时直接复制到页面就行。可能会报错。
报错1:这里我使用了Uploadimg图片上传组件。主要是上传图片到阿里云oss。删掉即可。
报错2:页面加载时请求了接口,调用了方法this.getoptions();主要是拉取商品分类列表数据。注释和删掉即可。
其他的就是逻辑代码了。可以happy~奔放一下看到具体效果。
码字不易,转载请注明出处,谢谢~