编辑商品按钮显示商品对应数据
- 同用户管理,权限管理等之前各个模块的编辑功能不同,因为商品具有很多可编辑的选项,所以选择像添加商品一样,单独放在一个组件中Edit.vue 。
- 不过相比于添加商品,还需要传递一下这个商品的id值。
- 布局与添加商品一致(下文省略解释布局),只是需要发送请求,将后台返回的数据渲染到组件中
初步设置
设置路由规则
传递商品id到Edit.vue
router/index.js中:
{ path: '/goods/edit/:id', component: Edit }
1
Edit.vue中:
data () {
return {
// 传递过来的 商品id
id: this.$route.params.id
}
}
List.vue中:
// 点击编辑按钮,跳转到编辑页面
editById (id) {
this.$router.push('/goods/edit/' + id)
}
2. 获取数据
1. 查询商品信息
async getGoodsInfo () {
const { data: res } = await this.$http.get('goods/' + this.id)
if (res.meta.status !== 200) {
return this.$message.error('获取商品信息失败!')
}
this.editForm = res.data
this.$message.success('获取商品信息成功!')
}
2. 获取商品分类数据
// 获取所有商品分类数据
async getCateList () {
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类数据失败!')
}
this.cateList = res.data
}
3. 获取商品参数列表和静态属性
// 当切换tab页签时触发的函数
async tabClicked () {
// console.log(this.activeIndex)
if (this.activeIndex === '1') {
// 访问的是 动态参数面板
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`,
{
params: {
sel: 'many'
}
})
if (res.meta.status !== 200) {
return this.$message.error('获取动态参数列表失败!')
}
console.log(res.data)
res.data.forEach(item => {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
})
this.manyTableData = res.data
} else if (this.activeIndex === '2') {
// 访问的是静态属性面板
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`,
{
params: {
sel: 'only'
}
})
if (res.meta.status !== 200) {
return this.$message.error('获取静态属性列表失败!')
}
console.log(res.data)
this.onlyTableData = res.data
}
}
3. 关于数据和图片的回显
1. 级联选择器数据回显
在getGoodsInfo ()这个函数中加入以下代码:
// 设置级联选择器绑定值
const tempList = res.data.goods_cat.split(',') // 这一步只是转化成了['1','3','6']
//每个数组成员都是字符,而不是数字
// 这里必须重新赋值为空数组,再赋值,否则v-model不能实现默认值回显
this.editForm.goods_cat = []
tempList.forEach(item => {
// item - 0是把数据类型转换为数字,以与cateList 数据类型一致,否则不能正确回显默认值
this.editForm.goods_cat.push(item - 0)
})
功能实现:
2. 点击编辑后图片回显
查询文档得知有一个属性file-list:
则进行绑定:
<el-tab-pane label="商品图片" name="3">
<!-- action表示图片要上传到的后台api地址 -->
<el-upload
:action="uploadURL"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:headers="headerObj"
:file-list="uploadedList"
:on-success="handleSuccess">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-tab-pane>
最后,在getGoodsInfo ()这个函数中,循环editForm.pics中的每一项,把带有name和url属性的对象push到data节点下的picList:
// 将已上传的图片放入列表
this.editForm.pics.forEach(item => {
const obj =
{
name: item.pics_id + '.jpg',
url: item.pics_sma_url
}
this.uploadedList.push(obj)
})
查阅了官方文档发现,有name属性,才能够点击到图片名字,从而有预览效果
4. 编辑完成后点击提交按钮
文档里面是不需要传递分类id的,但是通过请求得到的信息“该商品未设置分类”,推测需要传递商品的分类id,并且类型是一个包括每一级分类,且用逗号“,”分割的字符串
// 点击修改商品按钮
edit () {
this.$refs.editFormRef.validate(async valid => {
if (!valid) {
return this.$message.error('请填写必要的表单项!')
}
const form = _.cloneDeep(this.editForm)
form.goods_cat = form.goods_cat.join(',')
// console.log(form)
const { data: res } = await this.$http.put('goods/' + form.goods_id, form)
if (res.meta.status !== 200) {
return this.$message.error('修改商品失败!')
}
this.$message.success('修改商品成功!')
this.$router.push('/goods')
})
}
编辑功能其实还差商品参数和静态属性还没完全弄好,经过了很久的尝试之后,我猜测后台有一些不周全的地方
如果一个商品是新添加的,那么我根据id查询得到的商品信息的参数/属性是以 空格 为分隔符的字符串
而如果是数据库中本来就存在的商品,我点击编辑按钮,通过id查询得到的信息的参数/属性 是以 逗号","为分隔符的字符串
加上我对elementui使用不熟练,目前,还无法完全实现这个功能,等日后有时间再进行完善。目前的进度,是能够做到成功修改商品基本信息,商品图片,商品描述三个部分。
Edit.vue完整代码如下:
<template>
<div>
<!-- 面包屑导航区域 -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item>
<el-breadcrumb-item>商品管理</el-breadcrumb-item>
<el-breadcrumb-item>编辑商品</el-breadcrumb-item>
</el-breadcrumb>
<!-- 卡片视图区域 -->
<el-card>
<!-- 提示区域 -->
<el-alert
title="修改商品信息" type="info" center show-icon :closable="false">
</el-alert>
<!-- 步骤条区域 -->
<el-steps :space="200" :active="activeIndex-0" finish-status="success" align-center>
<el-step title="基本信息"></el-step>
<el-step title="商品参数"></el-step>
<el-step title="商品属性"></el-step>
<el-step title="商品图片"></el-step>
<el-step title="商品内容"></el-step>
<el-step title="完成"></el-step>
</el-steps>
<el-form :model="editForm" :rules="editFormRules"
ref="editFormRef" label-width="100px"
label-position="top">
<!-- Tab栏区域 -->
<el-tabs :tab-position="'left'"
:before-leave="beforeTabLeave"
@tab-click="tabClicked"
v-model="activeIndex">
<el-tab-pane label="基本信息" name="0">
<el-form-item label="商品名称"
prop="goods_name">
<el-input v-model="editForm.goods_name"></el-input>
</el-form-item>
<el-form-item label="商品价格"
prop="goods_price">
<el-input v-model="editForm.goods_price"
type="number"></el-input>
</el-form-item>
<el-form-item label="商品重量"
prop="goods_weight">
<el-input v-model="editForm.goods_weight"
type="number"></el-input>
</el-form-item>
<el-form-item label="商品数量"
prop="goods_number">
<el-input v-model="editForm.goods_number"
type="number"></el-input>
</el-form-item>
<el-form-item label="商品分类" prop="goods_cat">
<el-cascader
:show-all-levels="true"
v-model="editForm.goods_cat"
:options="cateList"
expand-trigger="hover"
:props="cateProps"
@change="handleChange"></el-cascader>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品参数" name="1" >
<!-- 渲染表单的item项 -->
<el-form-item v-for="item in manyTableData"
:key="item.attr_id" :label="item.attr_name">
<!-- 复选框组 -->
<el-checkbox-group v-model="item.attr_vals">
<el-checkbox :label="cb" border
v-for="(cb,i) in item.attr_vals"
:key="i"></el-checkbox>
</el-checkbox-group>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品属性" name="2">
<el-form-item :label="item.attr_name"
v-for="item in onlyTableData"
:key="item.attr_id">
<el-input v-model="item.attr_vals"></el-input>
</el-form-item>
</el-tab-pane>
<el-tab-pane label="商品图片" name="3">
<!-- action表示图片要上传到的后台api地址 -->
<el-upload
:action="uploadURL"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:headers="headerObj"
:file-list="uploadedList"
:on-success="handleSuccess">
<el-button size="small" type="primary">点击上传</el-button>
</el-upload>
</el-tab-pane>
<el-tab-pane label="商品内容" name="4">
<!-- 富文本编辑器组件 -->
<quill-editor v-model="editForm.goods_introduce">
</quill-editor>
<el-button type="primary" class="btnAdd"
@click="edit">修改商品</el-button>
</el-tab-pane>
</el-tabs>
</el-form>
</el-card>
<!-- 图片预览 -->
<el-dialog title="图片预览"
:visible.sync="previewVisible" width="50%">
<img :src="previewPath" alt="" class="previewImg">
</el-dialog>
</div>
</template>
<script>
import _ from 'lodash'
export default {
data () {
return {
// 传递过来的 商品id
id: this.$route.params.id,
// 激活的步骤
activeIndex: '0',
// 修改商品的表单数据对象
editForm: {
goods_name: '',
goods_price: 0,
goods_weight: 0,
goods_number: 0,
// 商品所属的分类数组
goods_cat: [],
// 图片的数组
pics: [],
// 商品的详情描述
goods_introduce: '',
attrs: []
},
editFormRules: {
goods_name: [
{ required: true, message: '请输入商品名称', trigger: 'blur' }
],
goods_price: [
{ required: true, message: '请输入商品价格', trigger: 'blur' }
],
goods_weight: [
{ required: true, message: '请输入商品重量', trigger: 'blur' }
],
goods_number: [
{ required: true, message: '请输入商品数量', trigger: 'blur' }
],
goods_cat: [
{ required: true, message: '请选择商品分类', trigger: 'blur' }
]
},
// 分类列表
cateList: [],
cateProps: {
label: 'cat_name',
value: 'cat_id',
children: 'children'
},
// 已经上传了的图片列表
uploadedList: [],
// 动态参数列表
manyTableData: [],
// 静态属性列表
onlyTableData: [],
// 上传图片的url地址
uploadURL: 'http://127.0.0.1:8889/api/private/v1/upload',
// 图片上传组件的 headers请求头对象
headerObj: {
Authorization: window.sessionStorage.getItem('token')
},
previewPath: '',
previewVisible: false
}
},
created () {
this.getGoodsInfo()
this.getCateList()
},
methods: {
// 发送请求,查询商品信息
async getGoodsInfo () {
const { data: res } = await this.$http.get('goods/' + this.id)
if (res.meta.status !== 200) {
return this.$message.error('获取商品信息失败!')
}
this.editForm = res.data
// 设置级联选择器绑定值
const tempList = res.data.goods_cat.split(',')
// 这里必须重新赋值为空数组,再赋值,否则v-model不能实现默认值回显
this.editForm.goods_cat = []
tempList.forEach(item => {
// item - 0是把数据类型转换为数字,以与cateList 数据类型一致,否则不能正确回显默认值
this.editForm.goods_cat.push(item - 0)
})
this.editForm.pics.forEach(item => {
const obj =
{
name: item.pics_id + '.jpg',
url: item.pics_sma_url
}
this.uploadedList.push(obj)
})
this.$message.success('获取商品信息成功!')
},
// 获取所有商品分类数据
async getCateList () {
const { data: res } = await this.$http.get('categories')
if (res.meta.status !== 200) {
return this.$message.error('获取商品分类数据失败!')
}
this.cateList = res.data
},
// 级联选择器选中项发生变化时,触发的函数
handleChange () {
// console.log(this.editFrom.goods_cat)
if (this.editForm.goods_cat.length !== 3) {
// 没有选中三级商品分类
this.editForm.goods_cat = []
}
},
beforeTabLeave (activeName, oldActiveName) {
if (oldActiveName === '0' &&
this.editForm.goods_cat.length !== 3) {
this.$message.error('请先选择商品分类!')
return false
}
},
// 当切换tab页签时触发的函数
async tabClicked () {
if (this.activeIndex === '1') {
// 访问的是 动态参数面板
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`,
{
params: {
sel: 'many'
}
})
if (res.meta.status !== 200) {
return this.$message.error('获取动态参数列表失败!')
}
res.data.forEach(item => {
item.attr_vals =
item.attr_vals.length === 0 ? []
: item.attr_vals.split(',')
})
this.manyTableData = res.data
} else if (this.activeIndex === '2') {
// 访问的是静态属性面板
const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`,
{
params: {
sel: 'only'
}
})
if (res.meta.status !== 200) {
return this.$message.error('获取静态属性列表失败!')
}
this.onlyTableData = res.data
}
},
// 处理图片预览效果
handlePreview (file) {
// console.log(file)
if (file.response) {
this.previewPath = file.response.data.url
} else {
this.previewPath = file.url
}
this.previewVisible = true
},
// 处理移除图片的操作
handleRemove (file) {
if (file.response) {
// 如果存在file.response,则是之后上传的
const filePath = file.response.data.tmp_path
const i = this.editForm.pics.findIndex(x =>
x.pic === filePath)
this.editForm.pics.splice(i, 1)
} else {
// 则是一开始就有图片
const Url = file.url
const i = this.editForm.pics.findIndex(x =>
x.pics_sma_url === Url)
this.editForm.pics.splice(i, 1)
}
},
// 监听图片上传成功的事件
handleSuccess (response) {
// 1. 拼接得到一个图片信息对象
const picInfo = { pic: response.data.tmp_path }
// 2.将图片信息对象,push到pics数组中
this.editForm.pics.push(picInfo)
},
// 点击修改商品按钮
edit () {
this.$refs.editFormRef.validate(async valid => {
if (!valid) {
return this.$message.error('请填写必要的表单项!')
}
const form = _.cloneDeep(this.editForm)
form.goods_cat = form.goods_cat.join(',')
// console.log(form)
const { data: res } = await this.$http.put('goods/' + form.goods_id, form)
console.log(res)
if (res.meta.status !== 200) {
return this.$message.error('修改商品失败!')
}
this.$message.success('修改商品成功!')
this.$router.push('/goods')
})
}
},
computed: {
cateId () {
if (this.editForm.goods_cat.length === 3) {
return this.editForm.goods_cat[2]
}
return null
}
}
}
</script>
<style lang="less" scoped>
.el-checkbox {
margin:0 10px 0 0 !important
}
.previewImg {
width: 100%;
}
.btnAdd {
margin-top:15px;
}
</style>