分类管理
顶部
全局组件三级联动以及它的自定义事件
底部
展示列表
1、静态
2、接口
//获取SPU列表数据的接口
///admin/product/{page}/{limit} get page limit category3Id
export const reqSpuList = (page, limit, category3Id) => request({ url: `/admin/product/${page}/${limit}`, method: 'get', params: { category3Id } });
3、发请求获取数据并保存
4、完成分页器
添加分类和修改分类
1、三个模块的切换展示
添加属性scene给它赋予三个值,当它的值变化,页面展示也发生变化
2、静态
3、接口
//获取SPU信息
///admin/product/getSpuById/{spuId} get
export const reqSpu = (spuId) => request({ url: `/admin/product/getSpuById/${spuId}`, method: 'get' });
//获取品牌的信息
///admin/product/baseTrademark/getTrademarkList get
export const reqTradeMarkList = () => request({ url: `/admin/product/baseTrademark/getTrademarkList`, method: 'get' });
//获取SPU图标的接口
///admin/product/spuImageList/{spuId} get
export const reqSpuImageList = (spuId) => request({ url: `/admin/product/spuImageList/${spuId}`, method: 'get' });
//获取平台全部销售属性----整个平台销售属性一共三个
//GET /admin/product/baseSaleAttrList
export const reqBaseSaleAttrList = () => request({ url: '/admin/product/baseSaleAttrList', method: 'get' });
4、修改分类发送请求获取数据
不能在挂载完毕之后发请求,因为该子组件是在父组件中被使用,当父组件挂载完毕之后就会立即发送请求。v-show只是控制子组件的显示与隐藏,这个子组件并没有卸载,mounted只能执行一次。
选择在点击按钮时发送请求,使用ref获取子组件,即可以使用子组件的方法。然后通过传参将父组件收集到的被点击的某个对象传递给子组件,子组件利用对象的id发送请求。
5、点击保存按钮时
修改分类时,点击保存按钮时,它所需要收集的数据已经存放在了data中的spu中,因为当发送请求时,已经给spu赋值为服务器返回的数据。所以可以利用这个返回的对象收集修改后的数据再次发送给服务器。
在添加分类时,spu并没有数据,是一个空对象,因为它没有向服务器发送请求。所以此时需要修改spu的初始值,为点击保存所发请求需要携带的字段。
6、展示数据、收集数据
由于照片墙展示图片的数据需要是数组,数组里面的元素里面需要有name与url字段,将图片数组赋值给一个新的数组,使用forEach方法对新的数组遍历,然后对每个数据增加一个name和url属性,然后再将新的数组赋值给图片数组。
销售属性静态需要计算未选择几个销售属性:使用计算属性,数组的filter方法:从已有的数组中过滤出需要的元素,并且返回新的数组。
数组的evey方法:会返回一个布尔值。
逻辑:
filter遍历平台所有属性得到item,再利用evey遍历出新数组得到item1,当item.name与item1.name相等时,evey返回的布尔值为false,当item.name与item1.name不相等时,返回的布尔值为true,此时filter返回的也是true,这时filter过滤出的元素才符合条件然后组成新的数组。此时再将新的数组返回给计算属性,再进行数据展示。
//计算出还未选择的销售属性
unSelectSaleAttr() {
//整个平台的销售属性一共三个:尺寸、颜色、版本 ----saleAttrList
//当前SPU拥有的属于自己的销售属性SPU.spuSaleAttrList ----颜色
//数组的过滤方法,可以从已有的数组当中过滤出用户需要的元素,并未返回一个新的数据
let result = this.saleAttrList.filter((item) => {
//every数组的方法,会返回一个布尔值【真,假的】
return this.spu.spuSaleAttrList.every((item1) => {
return item.name != item1.saleAttrName;
});
});
return result;
},
照片墙图片的收集:
当删除图片的回调中,会有剩余其他图片的数组,先将该数组存储在data其他中地方,该数组数据中含有name和url属性,但是发送请求时并不需要,所以需要再次处理。
当添加图片之后的回调中,将所有图片信息收集,这些图片仍然有name和url属性,但是发送请求时并不需要,所以也需要再次处理。
点击取消按钮:需要清理数据。
Object.assign(this._data, this.$options.data());
Object.assign:es6中新增的方法可以合并对象
组件实例this._data,可以操作data当中的响应式数据
$options.data()可以获取配置对象,配置对象的data函数执行,返回的响应式数据为空。
删除分类
1、接口
2、动态
3、发请求
需要考虑删除之后停留的页数
添加详情实例
1、当跳转至性情实例页面时,就立即获取详情数据
利用ref让父组件调用子组件的方法,让子组件发请求
2、数据展示和收集数据
同时收集一级id和二级id,可以使用模板字符串将两个id拼成一个字符串,使用时再将其使用split切割一下
设置默认:收集图片数据时,给数据添加一个isDefault,注意此时不要将数据收集在向服务器发送的对象中,当isDefault为0时显示‘设置默认’。再进行排他操作,forEach遍历得到每个item的isDefault赋值为0,被点击的item的isDefault赋值为1
3、点击保存或取消按钮
(1)接口
(2)取消添加时,利用自定义事件,父组件通知子组件切换场景,并且清除数据
(3)整理收集的数据
方式一:创建一个空数组,遍历所有详情获得item,判断被用户点击的某个item,即判断attrIdAndValue是否有值,有的话将该字符串切割,将切割后的两个值存放在一个对象中,再将该对象push到空数组内,再将该数组赋值给data中的skuInfo.skuAttrValueList。
const {attrInfoList,skuInfo} = this
let arr = []
attrInfoList.forEach(item => {
if(item.attrIdAndValue){
const [attrId,valueId] = item.attrIdAndValueId.split(":")
let obj = {attrId,valueId}
arr.push(obj)
}
skuInfo.skuAttrValueList = arr
})
方式二:可将forEach换成reduce将切割玩的数据push到prev中,再将prev返回,用this.skuInfo.skuAttrValueList接收
const {attrInfoList,skuInfo} = this
attrInfoList.reduce((prev,item)=>{
if(item.attrIdAndValueId){
const [attrId,valueId] = item.attrIdAndValueId.split(":")
prev.push({attrId,valueId})
}
return prev;
},[])
图片列表收集:
map:将数组遍历对每个item进行操作再将操作后的数据返回
skuInfo.skuImageList = imageList.map(item=>{
return {
imgName:item.imgName,
imgUrl:item.imgUrl,
isDefault:item.isDefault,
spuImgId:item.id,
}
})
(4)发请求,成功之后切换场景
详情列表展示
1、接口
2、给按钮绑定事件,控制对话框的显示与隐藏,并且将被点击分类的数据保存下来,让对话框里的数据可以动态显示
3、发请求
4、数据展示
loading
默认效果为true,当请求成功,效果为false。
问题:
loading效果只会展示一次,快速切换查看详情列表发现上一次的数据会显示。
解决:
给对话框加上属性:before-close=‘close’,close为关闭对话框的回调,将loading属性变为真。并且将skuList赋值为空数组。
详情管理
数据展示与分页器
1、静态
2、接口
3、发请求
上架与下架
1、用isSale的值控制图标
2、上架和下架的接口
3、给上架和下架按钮都添加点击事件,分别发请求
单个详情内容的查看
1、获取单个详情内容的接口
2、当点击按钮之后,窗体弹出
深度选择器
1、scoped属性的作用
对于某一个组件,如果style添加上scoped属性,给当前子组件的结构中都添加上一个data-v-xxx自定属性,vue是通过属性选择器给需要添加的元素加上样式
2、子组件的根标签
如果子组件的跟标签拥有父组件当中一样的自定义属性,也会添加上相应的样式
注意:
如果父组件的样式使用了scoped属性,而且还想影响到子组件的样式,这种情况应该选择使用深度选择器。
3、深度选择器(实现样式穿透)
- 原生CSS ——— >>>
- less ——— /deep/
- scss ——— ::v-deep
代码
分类管理
1、分类列表
<template>
<div>
<el-form ref="form" label-width="80px" :model="spu">
<el-form-item label="SPU名称">
<el-input placeholder="SPU名称" v-model="spu.spuName"></el-input>
</el-form-item>
<el-form-item label="品牌">
<el-select placeholder="请选择品牌" v-model="spu.tmId">
<el-option
:label="tm.tmName"
:value="tm.id"
v-for="(tm, index) in tradeMarkList"
:key="tm.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="SPU描述">
<el-input
type="textarea"
rows="4"
placeholder="描述"
v-model="spu.description"
></el-input>
</el-form-item>
<el-form-item label="SPU图片">
<!-- 上传图片:action图片上传的地址 list-type: 文件列表的类型 on-preview:图片预览的时候会出发 on-remove:当删除图片的时候会出发
file-list:照片墙需要展示的数据【数组:数组里面的元素务必要有name、url属性】
on-preview:图片预览功能
on-remove:删除图片的时候会触发
-->
<el-upload
action="/dev-api/admin/product/fileUpload"
list-type="picture-card"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-success="handlerSuccess"
:file-list="spuImageList"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="" />
</el-dialog>
</el-form-item>
<el-form-item label="销售属性">
<el-select
:placeholder="`还有${unSelectSaleAttr.length}未选择`"
v-model="attrIdAndAttrName"
>
<el-option
:label="unselect.name"
:value="`${unselect.id}:${unselect.name}`"
v-for="(unselect, index) in unSelectSaleAttr"
:key="unselect.id"
></el-option>
</el-select>
<el-button
type="primary"
icon="el-icon-plus"
:disabled="!attrIdAndAttrName"
@click="addSaleAttr"
>添加销售属性</el-button
>
<!-- 展示的是当前SPU属于自己的销售属性 -->
<el-table style="width: 100%" border :data="spu.spuSaleAttrList">
<el-table-column
type="index"
label="序号"
width="80px"
align="center"
>
</el-table-column>
<el-table-column prop="saleAttrName" label="属性名" width="width">
</el-table-column>
<el-table-column prop="prop" label="属性值名称列表" width="width">
<template slot-scope="{ row, $index }">
<!-- " -->
<!-- el-tag:用户展示已有属性值列表的数据的 -->
<el-tag
:key="tag.id"
v-for="(tag, index) in row.spuSaleAttrValueList"
closable
:disable-transitions="false"
@close="row.spuSaleAttrValueList.splice(index, 1)"
>{{ tag.saleAttrValueName }}</el-tag
>
<!-- 底下的解构可以当中咱们当年的span与input切换 -->
<!-- @keyup.enter.native="handleInputConfirm" -->
<el-input
class="input-new-tag"
v-if="row.inputVisible"
v-model="row.inputValue"
ref="saveTagInput"
size="small"
@blur="handleInputConfirm(row)"
>
</el-input>
<!-- @click="showInput" -->
<el-button
v-else
class="button-new-tag"
size="small"
@click="addSaleAttrValue(row)"
>添加</el-button
>
</template>
</el-table-column>
<el-table-column prop="prop" label="操作" width="width">
<template slot-scope="{ row, $index }">
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="spu.spuSaleAttrList.splice($index, 1)"
></el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="addOrUpdateSpu">保存</el-button>
<el-button @click="cancel">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
dialogImageUrl: "",
dialogVisible: false,
//spu属性初始化的时候是一个空的对象,在修改SPU的时候,会想服务器发请求,返回SPU信息(对象),在修改的时候可以利用服务器返回的这个对象收集最新的数据提交给服务器
//添加SPU,如果是添加SPU的时候并没有向服务器发请求,数据收集到哪里呀[SPU],收集数据的时候有哪些字段呀,看文档
spu: {
//三级分类的id
category3Id: 0,
//描述
description: "",
//spu名称
spuName: "",
//平台的id
tmId: "",
//收集SPU图片的信息
spuImageList: [
// {
// id: 0,
// imgName: "string",
// imgUrl: "string",
// spuId: 0,
// },
],
//平台属性与属性值收集
spuSaleAttrList: [
// {
// baseSaleAttrId: 0,
// id: 0,
// saleAttrName: "string",
// spuId: 0,
// spuSaleAttrValueList: [
// {
// baseSaleAttrId: 0,
// id: 0,
// isChecked: "string",
// saleAttrName: "string",
// saleAttrValueName: "string",
// spuId: 0,
// },
// ],
// },
],
},
tradeMarkList: [], //存储品牌信息
spuImageList: [], //存储SPU图片的数据
saleAttrList: [], //销售属性的数据(项目全部的销售属性)
attrIdAndAttrName: "", //收集未选择的销售属性的id-----
};
},
methods: {
//照片墙删除某一个图片的时候会触发
handleRemove(file, fileList) {
//file参数:代表的是删除的那个张图片
//fileList:照片墙删除某一张图片以后,剩余的其他的图片
// console.log(file, fileList,22222);
//收集照片墙图片的数据
//对于已有的图片【照片钱中显示的图片:有name、url字段的】,因为照片墙显示数据务必要有这两个属性
//对于服务器而言,不需要name、url字段,将来对于有的图片的数据在提交给服务器的时候,需要处理的
this.spuImageList = fileList;
},
//照片墙图片预览的回调
handlePictureCardPreview(file) {
//将图片地址赋值给这个属性
this.dialogImageUrl = file.url;
//对话框显示
this.dialogVisible = true;
},
//初始化SpuForm数据
async initSpuData(spu) {
//获取SPU信息的数据
let spuResult = await this.$API.spu.reqSpu(spu.id);
if (spuResult.code == 200) {
//在修改spu的时候,需要向服务器发请求的,把服务器返回的数据(对象),赋值给spu属性
this.spu = spuResult.data;
}
//获取品牌的信息
let tradeMarkResult = await this.$API.spu.reqTradeMarkList();
if (tradeMarkResult.code == 200) {
this.tradeMarkList = tradeMarkResult.data;
}
//获取spu图片的数据
let spuImageResult = await this.$API.spu.reqSpuImageList(spu.id);
if (spuImageResult.code == 200) {
let listArr = spuImageResult.data;
//由于照片墙显示图片的数据需要数组,数组里面的元素需要有name与url字段
//需要把服务器返回的数据进行修改
listArr.forEach((item) => {
item.name = item.imgName;
item.url = item.imgUrl;
});
//把整理好的数据赋值给
this.spuImageList = listArr;
}
//获取平台全部的销售属性
let saleResult = await this.$API.spu.reqBaseSaleAttrList();
if (saleResult.code == 200) {
this.saleAttrList = saleResult.data;
}
},
//照片墙图片上传成功的回调
handlerSuccess(response, file, fileList) {
//收集图片的信息
this.spuImageList = fileList;
},
//添加新的销售属性
addSaleAttr() {
//已经收集需要添加的销售属性的信息
//把收集到的销售属性数据进行分割
const [baseSaleAttrId, saleAttrName] = this.attrIdAndAttrName.split(":");
//向SPU对象的spuSaleAttrList属性里面添加新的销售属性
let newSaleAttr = {
baseSaleAttrId,
saleAttrName,
spuSaleAttrValueList: [],
};
//添加新的销售属性
this.spu.spuSaleAttrList.push(newSaleAttr);
//清空数据
this.attrIdAndAttrName = "";
},
//添加按钮的回调
addSaleAttrValue(row) {
//点击销售属性值当中添加按钮的时候,需要有button变为input,通过当前销售属性的inputVisible控制
//挂载在销售属性身上的响应式数据inputVisible,控制button与input切换
this.$set(row, "inputVisible", true);
//通过响应式数据inputValue字段收集新增的销售属性值
this.$set(row, "inputValue", "");
},
//el-input失却焦点的事件
handleInputConfirm(row) {
//解构出销售属性当中收集数据
const { baseSaleAttrId, inputValue } = row;
//新增的销售属性值的名称不能为空
if (inputValue.trim() == "") {
this.$message("属性值不能为空");
return;
}
//属性值不能重复,这里也可以用some
let result = row.spuSaleAttrValueList.every(
(item) => item.saleAttrValueName != inputValue
);
if (!result) return;
//新增的销售属性值
let newSaleAttrValue = { baseSaleAttrId, saleAttrValueName: inputValue };
//新增
row.spuSaleAttrValueList.push(newSaleAttrValue);
//修改inputVisible为false,不就显示button
row.inputVisible = false;
},
//保存按钮的回调
async addOrUpdateSpu() {
//整理参数:需要整理照片墙的数据
//携带参数:对于图片,需要携带imageName与imageUrl字段
this.spu.spuImageList = this.spuImageList.map((item) => {
return {
imageName: item.name,
imageUrl: (item.response && item.response.data) || item.url,
};
});
//发请求
let result = await this.$API.spu.reqAddOrUpdateSpu(this.spu);
if (result.code == 200) {
//提示
this.$message({ type: "success", message: "保存成功" });
//通知父组件回到场景0
this.$emit("changeScene", {
scene: 0,
flag: this.spu.id ? "修改" : "添加",
});
}
//清除数据
Object.assign(this._data, this.$options.data());
},
//点击添加SPU按钮的时候,发请求的函数
async addSpuData(category3Id) {
//添加SPU的时候收集三级分类的id
this.spu.category3Id = category3Id;
//获取品牌的信息
let tradeMarkResult = await this.$API.spu.reqTradeMarkList();
if (tradeMarkResult.code == 200) {
this.tradeMarkList = tradeMarkResult.data;
}
//获取平台全部的销售属性
let saleResult = await this.$API.spu.reqBaseSaleAttrList();
if (saleResult.code == 200) {
this.saleAttrList = saleResult.data;
}
},
//取消按钮
cancel() {
//取消按钮的回调,通知父亲切换场景为0
this.$emit("changeScene", { scene: 0, flag: "" });
//清理数据
//Object.assign:es6中新增的方法可以合并对象
//组件实例this._data,可以操作data当中响应式数据
//this.$options可以获取配置对象,配置对象的data函数执行,返回的响应式数据为空的
Object.assign(this._data, this.$options.data());
},
},
computed: {
//计算出还未选择的销售属性
unSelectSaleAttr() {
//整个平台的销售属性一共三个:尺寸、颜色、版本 ----saleAttrList
//当前SPU拥有的属于自己的销售属性SPU.spuSaleAttrList ----颜色
//数组的过滤方法,可以从已有的数组当中过滤出用户需要的元素,并未返回一个新的数据
let result = this.saleAttrList.filter((item) => {
//every数组的方法,会返回一个布尔值【真,假的】
return this.spu.spuSaleAttrList.every((item1) => {
return item.name != item1.saleAttrName;
});
});
return result;
},
},
};
</script>
<style>
.el-tag + .el-tag {
margin-left: 10px;
}
.button-new-tag {
margin-left: 10px;
height: 32px;
line-height: 30px;
padding-top: 0;
padding-bottom: 0;
}
.input-new-tag {
width: 90px;
margin-left: 10px;
vertical-align: bottom;
}
</style>
2、详情列表
<template>
<div>
<el-form ref="form" label-width="80px">
<el-form-item label="SPU名称">{{spu.spuName}}</el-form-item>
<el-form-item label="SKU名称">
<el-input placeholder="sku名称" v-model="skuInfo.skuName"></el-input>
</el-form-item>
<el-form-item label="价格(元)">
<el-input placeholder="价格(元素)" type="number" v-model="skuInfo.price"></el-input>
</el-form-item>
<el-form-item label="重量(千克)">
<el-input placeholder="重量(千克)" v-model="skuInfo.weight"></el-input>
</el-form-item>
<el-form-item label="规格描述">
<el-input type="textarea" rows="4" v-model="skuInfo.skuDesc"></el-input>
</el-form-item>
<el-form-item label="平台属性">
<el-form :inline="true" ref="form" label-width="80px">
<el-form-item :label="attr.attrName" v-for="(attr,index) in attrInfoList" :key="attr.id">
<el-select placeholder="请选择" v-model="attr.attrIdAndValueId">
<el-option :label="attrValue.valueName" :value="`${attr.id}:${attrValue.id}`" v-for="(attrValue,index) in attr.attrValueList" :key="attrValue.id"></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="销售属性">
<el-form :inline="true" ref="form" label-width="80px">
<el-form-item :label="saleAttr.saleAttrName" v-for="(saleAttr,index) in spuSaleAttrList" :key="saleAttr.id">
<el-select placeholder="请选择" v-model="saleAttr.attrIdAndValueId">
<el-option :label="saleAttrValue.saleAttrValueName" :value="`${saleAttr.id}:${saleAttrValue.id}`" v-for="(saleAttrValue,index) in saleAttr.spuSaleAttrValueList" :key="saleAttrValue.id"></el-option>
</el-select>
</el-form-item>
</el-form>
</el-form-item>
<el-form-item label="图片列表">
<el-table style="width: 100%" border :data="spuImageList" @selection-change="handleSelectionChange">
<el-table-column type="selection" prop="prop" width="80">
</el-table-column>
<el-table-column prop="prop" label="图片" width="width">
<template slot-scope="{row,$index}">
<img :src="row.imgUrl" style="width:100px;height:100px">
</template>
</el-table-column>
<el-table-column prop="imgName" label="名称" width="width">
</el-table-column>
<el-table-column prop="prop" label="操作" width="width">
<template slot-scope="{row,$index}">
<el-button type="primary" v-if="row.isDefault==0" @click="changeDefault(row)">设置默认</el-button>
<el-button v-else>默认</el-button>
</template>
</el-table-column>
</el-table>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="save">保存</el-button>
<el-button @click="cancel">取消</el-button>
</el-form-item>
</el-form>
</div>
</template>
<script>
export default {
name: "",
data() {
return {
//存储图片的信息
spuImageList: [],
//存储销售是属性
spuSaleAttrList: [],
//存储平台属性的数据
attrInfoList: [],
//收集sku数据的字段
skuInfo: {
//第一类收集的数据:父组件给的数据
category3Id: 0,
spuId: 0,
tmId: 0,
//第二类:需要通过数据双向绑定v-model收集
skuName: "",
price: 0,
weight: "",
skuDesc: "",
//第三类:需要自己书写代码
//默认图片
skuDefaultImg: "",
//收集图片的字段
skuImageList: [
// {
// id: 0,
// imgName: "string",
// imgUrl: "string",
// isDefault: "string",
// skuId: 0,
// spuImgId: 0,
// },
],
//平台属性
skuAttrValueList: [
// {
// attrId: 0,
// valueId: 0,
// },
],
//销售属性
skuSaleAttrValueList: [
// {
// id: 0,
// saleAttrId: 0,
// saleAttrName: "string",
// saleAttrValueId: 0,
// saleAttrValueName: "string",
// skuId: 0,
// spuId: 0,
// },
],
},
spu:{},
//收集图片的数据字段:但是需要注意,收集的数据目前缺少isDefault字段,将来提交给服务器数据的时候,需要整理参数
imageList:[]
};
},
methods: {
//获取SkuForm数据
async getData(category1Id, category2Id, spu) {
//收集父组件给予的数据
this.skuInfo.category3Id = spu.category3Id;
this.skuInfo.spuId = spu.id;
this.skuInfo.tmId = spu.tmId;
this.spu = spu;
//获取图片的数据
let result = await this.$API.spu.reqSpuImageLIst(spu.id);
if (result.code == 200) {
let list = result.data;
list.forEach(item=>{
item.isDefault = 0;
});
this.spuImageList = list;
}
//获取销售属性的数据
let result1 = await this.$API.spu.reqSpuSaleAttrList(spu.id);
if (result1.code == 200) {
this.spuSaleAttrList = result1.data;
}
//获取平台属性的数据
let result2 = await this.$API.spu.reqAttrInfoList(
category1Id,
category2Id,
spu.category3Id
);
if (result2.code == 200) {
this.attrInfoList = result2.data;
}
},
//table表格复选框按钮的事件
handleSelectionChange(params){
//获取到用户选中图片的信息数据,但是需要注意,当前收集的数据当中,缺少isDefault字段
this.imageList = params;
},
//排他操作
changeDefault(row){
//图片列表的数据的isDefault字段变为 0
this.spuImageList.forEach(item=>{
item.isDefault = 0;
});
//点击的那个图片的数据变为1
row.isDefault = 1;
//收集默认图片的地址
this.skuInfo.skuDefaultImg = row.imgUrl;
},
cancel(){
//自定义事件,让父组件切换场景0
this.$emit('changeScenes',0);
//清除数据
Object.assign(this._data,this.$options.data());
},
//保存按钮的事件
async save(){
//整理参数
//整理平台属性
const {attrInfoList,skuInfo,spuSaleAttrList,imageList} = this;
//整理平台属的数据
skuInfo.skuAttrValueList = attrInfoList.reduce((prev,item)=>{
if(item.attrIdAndValueId){
const [attrId,valueId] = item.attrIdAndValueId.split(":");
prev.push({attrId,valueId});
}
return prev;
},[]);
//整理销售属性
skuInfo.skuSaleAttrValueList = spuSaleAttrList.reduce((prev,item)=>{
if(item.attrIdAndValueId){
const [saleAttrId,saleAttrValueId] = item.attrIdAndValueId.split(':');
prev.push({saleAttrId,saleAttrValueId});
}
return prev;
},[]);
//整理图片的数据
skuInfo.skuImageList = imageList.map(item=>{
return {
imgName:item.imgName,
imgUrl:item.imgUrl,
isDefault:item.isDefault,
spuImgId:item.id,
}
});
//发请求
let result = await this.$API.spu.reqAddSku(skuInfo);
if(result.code==200){
this.$message({type:'success',message:'添加SKU成功'})
this.$emit('changeScenes',0);
}
}
},
};
</script>
详情管理
<template>
<div>
<!-- 表格 -->
<el-table style="width: 100%" border :data="records">
<el-table-column
type="index"
label="序号"
width="80"
align="center"
></el-table-column>
<el-table-column
prop="skuName"
label="名称"
width="width"
></el-table-column>
<el-table-column
prop="skuDesc"
label="描述"
width="width"
></el-table-column>
<el-table-column label="默认图片" width="110">
<template slot-scope="{ row, $index }">
<img
:src="row.skuDefaultImg"
alt=""
style="width: 80px; height: 80px"
/>
</template>
</el-table-column>
<el-table-column prop="weight" label="重量" width="80"></el-table-column>
<el-table-column prop="price" label="价格" width="80"></el-table-column>
<el-table-column prop="prop" label="操作" width="width">
<template slot-scope="{ row, $index }">
<el-button
type="success"
icon="el-icon-sort-down"
size="mini"
v-if="row.isSale == 0"
@click="sale(row)"
></el-button>
<el-button
type="success"
icon="el-icon-sort-up"
size="mini"
v-else
@click="cancel(row)"
></el-button>
<el-button
type="primary"
icon="el-icon-edit"
size="mini"
@click="edit"
></el-button>
<el-button
type="info"
icon="el-icon-info"
size="mini"
@click="getSkuInfo(row)"
></el-button>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
></el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="getSkuList"
style="text-align: center"
:current-page="page"
:page-sizes="[3, 5, 10]"
:page-size="limit"
layout="prev, pager, next, jumper,->,sizes,total"
:total="total"
>
</el-pagination>
<!-- 抽屉效果 -->
<el-drawer :visible.sync="show" :show-close="false" size="50%">
<el-row>
<el-col :span="5">名称</el-col>
<el-col :span="16">{{skuInfo.skuName}}</el-col>
</el-row>
<el-row>
<el-col :span="5">描述</el-col>
<el-col :span="16">{{skuInfo.skuDesc}}</el-col>
</el-row>
<el-row>
<el-col :span="5">价格</el-col>
<el-col :span="16">{{skuInfo.price}}元</el-col>
</el-row>
<el-row>
<el-col :span="5">平台属性</el-col>
<el-col :span="16">
<template>
<el-tag type="success" v-for="(attr,index) in skuInfo.skuAttrValueList" :key="attr.id" style="margin-right:10px">{{attr.attrId}}-{{attr.valueId}}</el-tag>
</template>
</el-col>
</el-row>
<el-row>
<el-col :span="5">商品图片</el-col>
<el-col :span="16">
<el-carousel height="150px">
<el-carousel-item v-for="item in skuInfo.skuImageList" :key="item.id">
<img :src="item.imgUrl">
</el-carousel-item>
</el-carousel>
</el-col>
</el-row>
</el-drawer>
</div>
</template>
<script>
export default {
name: "Sku",
data() {
return {
page: 1, //代表当前第几页
limit: 10, //代表当前页面有几条数据
records: [], //存储SKU列表的数据
total: 0, //存储分页器一共展示的数据
skuInfo:{},//存储SKU信息
show:false,
};
},
//组件挂载完毕
mounted() {
//获取sku列表的方法
this.getSkuList();
},
methods: {
//获取sku列表数据的方法
async getSkuList(pages = 1) {
this.page = pages;
//解构出默认的参数
const { page, limit } = this;
let result = await this.$API.sku.reqSkuList(page, limit);
if (result.code == 200) {
this.total = result.data.total;
this.records = result.data.records;
}
},
handleSizeChange(limit) {
//修改参数
this.limit = limit;
this.getSkuList();
},
//上架
async sale(row) {
let result = await this.$API.sku.reqSale(row.id);
if (result.code == 200) {
row.isSale = 1;
this.$message({ type: "success", message: "上架成功" });
}
},
//下架
async cancel(row) {
let result = await this.$API.sku.reqCancel(row.id);
if (result.code == 200) {
row.isSale = 0;
this.$message({ type: "success", message: "下架成功" });
}
},
edit() {
this.$message("正在开发中");
},
//获取SKU详情的方法
async getSkuInfo(sku){
//展示抽屉
this.show = true;
//获取SKU数据
let result = await this.$API.sku.reqSkuById(sku.id);
if(result.code==200){
this.skuInfo = result.data;
}
}
},
};
</script>
<style>
.el-carousel__item h3 {
color: #475669;
font-size: 14px;
opacity: 0.75;
line-height: 150px;
margin: 0;
}
.el-carousel__item:nth-child(2n) {
background-color: #99a9bf;
}
.el-carousel__item:nth-child(2n+1) {
background-color: #d3dce6;
}
</style>
<style scoped>
.el-row .el-col-5{
font-size:18px;
text-align:right;
}
.el-col{
margin:10px 10px;
}
>>>.el-carousel__button{
width:10px;
height:10px;
background:red;
border-radius:50%;
}
</style>