HM后台(四点二)
一,商品管理中的商品参数页面搭建
1.1,商品参数组件的路由配置
{ path: '/home', component: Home, // 重定向 redirect: '/welcome', children: [ { path: '/welcome', component: Welcome }, { path: '/users', component: User }, { path: '/rights', component: Rights }, { path: '/roles', component: Roles }, { path: '/categories', component: Cate }, { path: '/params', component: Params } ] }
1.2,页面一加载,发送请求,获取所有的商品分类列表数据
mounted() { this.getCateList() }, methods: { // 获取所有的商品分类列表 async getCateList() { const { data: res } = await this.$http.get('categories') if (res.meta.status !== 200) { return this.$message.error('获取商品分类失败!') } this.catelist = res.data // console.log(this.catelist) },
<!-- 面包屑导航区域 --> <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 style="margin-top:20px"> <!-- 警告区域 --> <el-alert show-icon title="注意:只允许为第三级分类设置相关参数!" type="warning" :closable="false" ></el-alert> <!-- 选择商品分类区域 --> <el-row class="cat_opt"> <el-col> <span>选择商品分类:</span> <!-- 选择商品分类的级联选择框 --> <el-cascader :options="catelist" :props="cateProps" v-model="selectedCateKeys" @change="handleChange" > </el-cascader> </el-col> </el-row> </el-card>
在data中定义属性
data() { return { // 商品分类列表 catelist: [], // 级联选择框的配置对象 cateProps: { value: 'cat_id', label: 'cat_name', children: 'children', expandTrigger: 'click', checkStrictly: true }, // 级联选择框双向绑定到的数组 selectedCateKeys: []
1.3, 选项卡页面搭建
<!-- tab页标签区域 --> <el-tabs v-model="activeName" @tab-click="handleTabClick"> <!-- 添加动态参数的面板 --> <el-tab-pane label="动态参数" name="many"> <!-- 添加参数的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" >添加参数</el-button> </el-tab-pane> <!-- 添加静态属性的面板 --> <el-tab-pane label="静态属性" name="only"> <!-- 添加参数的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" >添加属性</el-button> </el-tab-pane> </el-tabs>
在data中定义
// 被激活的页签的名称 activeName: 'many',
// tab 页签点击事件的处理函数 handleTabClick() { console.log(this.activeName) },
如果用户选中了三级分类,则按钮是高亮的,如果没选中,则按钮禁用,computed计算
computed:{ // 如果按钮需要被禁用,则返回true,否则返回false isBtnDisabled() { if (this.selectedCateKeys.length !== 3) { return true } return false } },
级联选择框的选中事件触发,发送参数列表请求(需要收集三级的id)
请求参数
计算三级分类id
// 当前选中的三级分类的Id cateId() { if (this.selectedCateKeys.length === 3) { return this.selectedCateKeys[2] } return null }
// 级联选择框选中项变化,会触发这个函数 async handleChange() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // console.log(res) } else { this.$message.error('获取数据失败') } //console.log(this.selectedCateKeys) },
1.4, 此时,三类分类的id已收集,如果用户在触发选中tabs的时候,也要发送参数分类请求,分别获取动态参数的数据和静态属性的数据
我们需要把发送请求,获取的数据单独封装一个函数,在级联选中三级id时,或者触发选中tabs时调用该函数
// 获取参数的列表数据 async getParamsData() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // console.log(res) // 判断tabs的名称,分别获取不同的数据 if (this.activeName === 'many') { this.manyTableData = res.data } else if (this.activeName === 'only') { this.onlyTableData = res.data } } else { this.$message.error('获取数据失败') } // console.log(this.selectedCateKeys) }
在两个时间点调用该函数
// 级联选择框选中项变化,会触发这个函数 handleChange() { this.getParamsData() },
// tab 页签点击事件的处理函数 handleTabClick() { this.getParamsData() // console.log(this.activeName) },
在data中定义获取的数据
// 动态参数的数据 manyTableData: [], // 静态属性的数据 onlyTableData: [], }
1.5, 动态参数表格和静态属性表格搭建
<!-- tab页标签区域 --> <el-tabs v-model="activeName" @tab-click="handleTabClick"> <!-- 添加动态参数的面板 --> <el-tab-pane label="动态参数" name="many"> <!-- 添加参数的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" >添加参数</el-button > <!-- 动态参数表格 --> <el-table :data="manyTableData" border stripe> <!-- 展开行 --> <el-table-column type="expand"></el-table-column> <!-- 索引列 --> <el-table-column type="index"></el-table-column> <el-table-column label="参数名称" prop="attr_name"></el-table-column> <el-table-column label="操作"> <template slot-scope="{row,$index}"> <el-button size="mini" type="primary" icon="el-icon-edit" >编辑</el-button> <el-button size="mini" type="danger" icon="el-icon-delete" >删除</el-button> </template> </el-table-column> </el-table> </el-tab-pane> <!-- 添加静态属性的面板 --> <el-tab-pane label="静态属性" name="only"> <!-- 添加参数的按钮 --> <el-button type="primary" size="mini" :disabled="isBtnDisabled" >添加属性</el-button > <!-- 静态属性表格 --> <el-table :data="onlyTableData" border stripe> <!-- 展开行 --> <el-table-column type="expand"></el-table-column> <!-- 索引列 --> <el-table-column type="index"></el-table-column> <el-table-column label="属性名称" prop="attr_name"></el-table-column> <el-table-column label="操作"> <template slot-scope="{row,$index}"> <el-button size="mini" type="primary" icon="el-icon-edit" >编辑</el-button> <el-button size="mini" type="danger" icon="el-icon-delete" >删除</el-button> </template> </el-table-column> </el-table> </el-tab-pane> </el-tabs>
1.6,点击添加参数或者添加属性按钮,弹出添加参数的对话框
titleText() { // 判断tabs的名称 if (this.activeName === 'many') { return '动态参数' } else { return '静态属性' } }
<!-- 添加参数的对话框 --> <el-dialog :title="`添加${titleText}`" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed" > <!-- 添加参数的对话框 --> <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" > <el-form-item :label="titleText" prop="attr_name"> <el-input v-model="addForm.attr_name"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addDialogVisible = false" >确 定</el-button > </span> </el-dialog>
动态添加属性或者参数的请求参数
data中定义
addDialogVisible: false, // 收集动态/静态的属性 addForm: { attr_name: '' }, // 添加表单的验证规则对象 addFormRules: { attr_name: [ { required: true, message: '请输入参数名称', trigger: 'blur' } ] },
关闭dialog,清空参数
// 监听添加对话框的关闭事件 addDialogClosed() { this.$refs.addFormRef.resetFields() }
<span slot="footer" class="dialog-footer"> <el-button @click="addDialogVisible = false">取 消</el-button> <el-button type="primary" @click="addParams" >确 定</el-button > </span> </el-dialog>
// 点击确定按钮,添加参数 addParams() { this.$refs.addFormRef.validate(async valid => { if (!valid) return const { data: res } = await this.$http.post( `categories/${this.cateId}/attributes`, { attr_name: this.addForm.attr_name, attr_sel: this.activeName } ) if (res.meta.status !== 201) { return this.$message.error('添加参数失败!') } this.$message.success('添加参数成功!') this.addDialogVisible = false // 重新发送获取参数列表的请求 this.getParamsData() }) },
1.8,点击编辑按钮,弹出修改的dialog
点击编辑按钮,弹出修改框
<el-table-column label="操作"> <template slot-scope="{ row, $index }"> <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog()" >编辑</el-button >
// 点击编辑按钮,弹出修改dialog showEditDialog() { this.editDialogVisible = true }
<!-- 修改参数的对话框 --> <el-dialog :title="'修改' + titleText" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed" > <!-- 添加参数的对话框 --> <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="100px" > <el-form-item :label="titleText" prop="attr_name"> <el-input v-model="editForm.attr_name"></el-input> </el-form-item> </el-form> <span slot="footer" class="dialog-footer"> <el-button @click="editDialogVisible = false">取 消</el-button> <el-button type="primary" @click="editDialogVisible = false">确定</el-button> >确 定</el-button > </span> </el-dialog>
在data中定义
// 控制修改对话框的显示与隐藏 editDialogVisible: false, // 修改的表单数据对象 editForm: { }, // 修改表单的验证规则对象 editFormRules: { attr_name: [ { required: true, message: '请输入参数名称', trigger: 'blur' } ] }
1.9,点击编辑按钮,根据属性id和分类id来发送请求,获取修改表单的数据
请求参数
// 点击编辑按钮,弹出修改dialog async showEditDialog(attrId) { // 根据参数id和父级分类id来发送请求 const {data :res} = await this.$http.get(`categories/${this.cateId}/attributes/${attrId}`,{params:{attr_sel:this.activeName}}) if(res.meta.status ===200){ this.editForm = res.data this.editDialogVisible = true }else{ this.$message.error('请求失败') } }
关闭修改的dialog,清空数据
<!-- 修改参数的对话框 --> <el-dialog :title="'修改' + titleText" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed" >
// 重置修改的表单 editDialogClosed() { this.$refs.editFormRef.resetFields() },
1.10,编辑弹框,点击确定按钮,发送请求,是否编辑成功
请求参数
// 编辑提交按钮,发送请求 async editParams(){ // 表单校验 this.$refs.editFormRef.validate((valid)=>{ if(!valid) return // 校验成功 const {data :res} = await this.$http.put(`categories/${this.cateId}/attributes/${this.editForm.attr_id}`,{ attr_name:this.editForm.attr_name, attr_sel:this.activeName }) if(res.meta.status ===200){ this.$message.success('编辑成功') this.editDialogVisible = true // 重新发送请求,获取新的参数列表 this.getParamsData() }else{ this.$message.error('编辑失败') } }) }
1.11, 点击删除按钮,发送请求,删除属性
<el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(row.attr_id)" >删除</el-button > </template>
// 点击删除按钮,发送请求,删除属性 async removeParams(attrId){ // messageBox弹出删除框 const result = await this.$confirm('此操作将永久删除该属性, 是否继续?', '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' }).catch((error)=>error) // 点击确定 if(result = 'confirm'){ // 发送删除请求 const {data:res} = await this.$http.delete(`categories/${this.cateId}/attributes/${attrId}`) if(res.meta.status ===200){ this.$message.success('删除成功') // 重新发送请求,获取最新的参数列表 this.getParamsData() } } }
// 获取参数的列表数据 async getParamsData() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // 将attr_vals参数值整理成数组,字符串分割成数组 res.data.forEach(item =>{ item.attr_vals = item.attr_vals.split(',') }) // console.log(res) // 判断tabs的名称,分别获取不同的数据 if (this.activeName === 'many') { this.manyTableData = res.data } else if (this.activeName === 'only') { this.onlyTableData = res.data } } else { this.$message.error('获取数据失败') } // console.log(this.selectedCateKeys) },
<!-- 动态参数表格 --> <el-table :data="manyTableData" border stripe> <!-- 展开行 --> <el-table-column type="expand"> <template slot-scope="{row, $index}"> <el-tag type="danger" size="normal" closable v-for="(item, index) in row.attr_vals" :key="index" >{{item}}</el-tag> </template> </el-table-column>
此时有个小bug,新增一个参数,那个会在attr_vals中新增一个空字符串,页面呈现的效果
那么怎么办呢,我们需要在将attr_vals属性整理成数组时,需要判断下是不是空窜
// 获取参数的列表数据 async getParamsData() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // 将attr_vals参数值整理成数组,字符串分割成数组 res.data.forEach(item => { item.attr_vals = item.attr_vals ? item.attr_vals.split(',') : [] })
此时的效果
1.13,动态编辑标签,添加添加button按钮,变成input,input失去焦点或者enter键,变成button按钮
<!-- 输入框 --> <el-input class="input-new-tag" v-if="inputVisible" v-model="inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm" @blur="handleInputConfirm" > </el-input> <!-- 添加按钮 --> <el-button v-else class="button-new-tag" size="small" @click="showInput" >+ New Tag</el-button >
在data中定义
inputVisible: false, inputValue: ''
定义函数
// input框失去焦点或者按下enter,触发 handleInputConfirm() { console.log('ok') }, // 点击添加按钮,变成input框 showInput(){ this.inputVisible = true }
此时有个小bug,表格中遍历了数据,当你点击button按钮,变成input框,下一行的情况也是这样,因为inputVisible,inputValue这两个属性是组件公共的,我们需要在请求列表参数
的时候,对每一个列表添加这两个属性,此时他们是每个参数的,不是公共的
// 获取参数的列表数据 async getParamsData() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // 将attr_vals参数值整理成数组,字符串分割成数组 res.data.forEach(item => { item.attr_vals = item.attr_vals ? item.attr_vals.split(',') : [] // 往每一个参数列表添加inputVisible,inputValue item.inputVisible = false item.inputValue = '' }) // console.log(res) // 判断tabs的名称,分别获取不同的数据 if (this.activeName === 'many') { this.manyTableData = res.data } else if (this.activeName === 'only') { this.onlyTableData = res.data } } else { this.$message.error('获取数据失败') } // console.log(this.selectedCateKeys) },
页面改造
<!-- 输入框 --> <el-input class="input-new-tag" v-if="inputVisible" v-model="row.inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm(row)" @blur="handleInputConfirm(row)" > </el-input>
那么data中的定义属性就可删除了
inputVisible: false, inputValue: ''
button变成input自动获取焦点
// 点击添加按钮,变成input框 showInput() { this.inputVisible = true // 让文本框自动获得焦点 // $nextTick 方法的作用,就是当页面上元素被重新渲染之后,才会指定回调函数中的代码 this.$nextTick(_ => { this.$refs.saveTagInput.$refs.input.focus() }) }
当input失去焦点或者enter键,我们需要将参数保存到参数值数组attr_vals中,并发送请求,保存到数据库中
请求参数
注,此时attr_vals,是一个数组,我们需要将他改造成字符串,用jion方法
// input框失去焦点或者按下enter,触发 async handleInputConfirm(row) { // console.log('ok') // 判断空格 if (row.inputValue.trim()) { // 将新增的属性添加到attr_vals数组中 row.attr_vals.push(row.inputValue) // 变成button按钮 this.inputVisible = false // 发送请求,将他添加到数据库中 const { data: res } = await this.$http.put( `categories/${this.cateId}/attributes/${row.attr_id}`, { attr_name: row.attr_name, attr_sel: row.attr_sel, attr_vals: row.attr_vals.join(',') } ) if (res.meta.code === 200) { this.$message.error('添加参数成功') } } },
<!-- 展开行 --> <el-table-column type="expand"> <template slot-scope="{ row, $index }"> <el-tag type="danger" size="normal" closable @close="handleClose(index, row)" v-for="(item, index) in row.attr_vals" :key="index" >{{ item }}</el-tag >
// 将对 attr_vals 的操作,保存到数据库 async saveAttrVals(row) { // 发送请求,将他添加到数据库中 const { data: res } = await this.$http.put( `categories/${this.cateId}/attributes/${row.attr_id}`, { attr_name: row.attr_name, attr_sel: row.attr_sel, attr_vals: row.attr_vals.join(',') } ) if (res.meta.code === 200) { this.$message.error('添加参数成功') } else { this.$message.error('添加失败') } }
// tag按钮删除操作哦 handleClose(index, row) { row.attr_vals.splice(index, 1) // 发送请求,提交参数 this.saveAttrVals(row) },
// input框失去焦点或者按下enter,触发 async handleInputConfirm(row) { // console.log('ok') // 判断空格 if (row.inputValue.trim()) { // 将新增的属性添加到attr_vals数组中 row.attr_vals.push(row.inputValue) // 变成button按钮 this.inputVisible = false // 发送请求,提交参数 this.saveAttrVals(row) } },
// 获取参数的列表数据 async getParamsData() { // 判断是否是三级分类,然后发送请求,获取参数列表 if (this.selectedCateKeys.length !== 3) { this.selectedCateKeys = [] this.manyTableData = [] this.onlyTableData = [] return } // 是三级分类 // 根据所选分类的Id,和当前所处的面板,获取对应的参数 const { data: res } = await this.$http.get(`categories/${this.cateId}`, { params: { sel: this.activeName } }) if (res.meta.status === 200) { // 将attr_vals参数值整理成数组,字符串分割成数组 res.data.forEach(item => { item.attr_vals = item.attr_vals ? item.attr_vals.split(',') : [] // 往每一个参数列表添加inputVisible,inputValue item.inputVisible = false item.inputValue = '' }) // console.log(res) // 判断tabs的名称,分别获取不同的数据 if (this.activeName === 'many') { this.manyTableData = res.data } else if (this.activeName === 'only') { this.onlyTableData = res.data } } else { this.$message.error('获取数据失败') } // console.log(this.selectedCateKeys) },