1 Star 0 Fork 0

Wayne831/vue_shop

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
Categories.vue 16.33 KB
一键复制 编辑 原始数据 按行查看 历史
Wayne831 提交于 2021-10-08 18:09 +08:00 . 完成了后期优化
<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-row>
<el-col>
<!-- 点击添加用户则显示提示框 -->
<!-- 注意有两种绑定方法 一种是直接设置对话框展示 适用于对话框内不需要展示数据 如Users中的添加 -->
<!-- 而第二种就是写一个showXXX方法再去methods里配置 适用于对话框内要获取数据并展示 比如Users中的编辑
这种情况下点击按钮不能只是展示对话框 还有发送请求并挂载等异步操作 -->
<el-button type="primary" @click="showAddCategoryDialog">添加分类</el-button>
</el-col>
</el-row>
<!-- 商品分类表格区 -->
<!-- tree-table是安装的组件 具体使用可以参考官方文档 -->
<!-- data数据源 columns配置列 expand/selection展开/多选 show-index索引列 index-text索引列标题 -->
<!-- border纵向分割线 showrowhover鼠标悬停高亮 -->
<tree-table
:data="categoryList"
:columns="columns"
:expand-type="false"
:selection-type="false"
:show-index="true"
index-text="#"
border
:show-row-hover="false"
class="tree-table"
>
<!-- 是否有效的那列 -->
<template slot="isok" slot-scope="scope">
<i v-if="scope.row.cat_deleted === false" class="el-icon-success"></i>
<i v-else class="el-icon-error"></i>
</template>
<!-- 排序的那列 -->
<template slot="order" slot-scope="scope">
<el-tag v-if="scope.row.cat_level === 0">一级</el-tag>
<el-tag v-else-if="scope.row.cat_level === 1" type="success">二级</el-tag>
<el-tag v-else type="warning">三级</el-tag>
</template>
<!-- 操作的那列 -->
<template slot="operate" slot-scope="scope">
<el-button type="primary" icon="el-icon-edit" size="small" @click="showEditCategoryDialog(scope.row)">编辑</el-button>
<!-- 同样的 删除操作只需要传id 不需要弹出对话框 只需要二次确认 -->
<el-button type="danger" icon="el-icon-delete" size="small" @click="deleteCategory(scope.row.cat_id)">删除</el-button>
</template>
</tree-table>
<!-- 分页区 -->
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pagenum"
:page-sizes="[3, 5, 8, 10]"
:page-size="queryInfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
>
</el-pagination>
<!-- 添加分类的对话框 -->
<el-dialog title="添加分类" :visible.sync="addCategoryDialogVisible" width="50%" @close="addCategoryDialogClosed">
<!-- 添加分类的表单 -->
<el-form :model="addCategoryForm" :rules="addCategoryRules" ref="addCategoryRef" label-width="80px">
<!-- prop是验证规则属性 形式是数组 -->
<!-- 设置label-width使得label不用换行 否则太窄 但不影响整个form宽度 只是input宽度缩小 -->
<el-form-item label="分类名称" prop="cat_name">
<el-input v-model="addCategoryForm.cat_name"></el-input>
</el-form-item>
<!-- 父级分类区域使用级联选择器 -->
<el-form-item label="父级分类">
<!-- options属性指定选项数组即可渲染出一个级联选择器 props对级联选择器进行各项配置 v-model将最终选中的值双向绑定,注意绑定的必须是数组 -->
<!-- @change绑定事件在级联选择器的选中项发生变化时触发 -->
<el-cascader
v-model="selectedParentCategory"
:options="parentCategoryList"
:props="cascaderProps"
@change="parentCategoryChange"
clearable
></el-cascader>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="addCategoryDialogVisible=false">取 消</el-button>
<el-button type="primary" @click="addCategory">确 定</el-button>
</span>
</el-dialog>
<!-- 编辑分类的对话框 -->
<el-dialog title="编辑分类" :visible.sync="editCategoryDialogVisible" width="50%" @close="editCategoryDialogClosed">
<!-- 验证规则直接用添加分类里的 因为规则一致 -->
<el-form :model="editCategoryForm" :rules="addCategoryRules" ref="editCategoryRef" label-width="100px">
<el-form-item label="分类名称:" prop="cat_name">
<el-input v-model="editCategoryForm.cat_name"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button @click="editCategoryDialogVisible=false">取 消</el-button>
<el-button type="primary" @click="editCategory">确 定</el-button>
</span>
</el-dialog>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
// 商品分类的数据列表
categoryList: [],
// 总商品分类数量
total: 0,
// 查询条件 http请求用的
queryInfo: {
// type指定获取到几级分类 3代表一直获取到三级分类 即全部
type: 3,
// 当前页码
pagenum: 1,
// 每页展示几条
pagesize: 5
},
// 为tree-table指定各列的配置 数组元素是对象 指定对应那一列
// label标题 prop对应列内容的属性名,用服务端返回数据的cat_name
// type表示当当前列定义为模板列 template指定模板列名称
columns: [
{
label: '分类名称',
prop: 'cat_name'
},
{
label: '是否有效',
type: 'template',
template: 'isok'
},
{
label: '排序',
type: 'template',
template: 'order'
},
{
label: '操作',
type: 'template',
template: 'operate'
}
],
// 控制添加分类对话框的显示与隐藏
addCategoryDialogVisible: false,
// 控制编辑分类对话框的显示与隐藏
editCategoryDialogVisible: false,
// 添加分类对话框的表单数据对象 参考API接口文档1.6.2进行定义和初始化
addCategoryForm: {
// 将要添加的分类的名称
cat_name: '',
// 将要添加的分类的父级分类id 设置为0代表添加一级分类
cat_pid: 0,
// 将要添加的分类的层级 为0代表默认为一级分类
cat_level: 0
},
// 添加编辑对话框的表单数据对象
editCategoryForm: {
// 因为改名字后要根据id发送http请求 所以这里也需要id
id: 0,
cat_name: ''
},
// 添加分类表单的验证规则
addCategoryRules: {
cat_name: [
{ required: true, message: '请输入分类名称', trigger: 'blur' }
]
},
// 添加分类对话框里需要用到的父级分类数据列表 包括一级分类和二级分类
parentCategoryList: [],
// 级联选择器的配置项props 在global.css中设置高度来使得数据滑动窗口显示 不然全屏展示所有 很难看
cascaderProps: {
// 次级菜单的展开方式
expandTrigger: 'hover',
// 指定选中的值的实际值 即分类的id
value: 'cat_id',
// 指定选中的值的展示属性 即分类的名字
label: 'cat_name',
// 指定父子嵌套用的哪个属性
children: 'children',
// 代替change-on-select 设置级联选择器可以选中任意一级作为结果(默认必须选中最后一级)
checkStrictly: true
},
// 级联选择器的双向数据绑定
selectedParentCategory: []
}
},
methods: {
// 获取商品分类数据 参考API接口文档1.6.1
async getCategoryList() {
const { data: res } = await this.$http.get('categories', { params: this.queryInfo })
if (res.meta.status !== 200) {
return this.$message.error(res.meta.msg)
}
this.categoryList = res.data.result
this.total = res.data.total
},
// 设置pagesize改变事件的函数 就是每页最多展示多少 然后重新发送请求获取数据 因为发起请求时用了pagesize
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getCategoryList()
},
// 设置页码值改变事件的函数 改变后也要重新获取数据 因为发送请求时用到了pagenum
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getCategoryList()
},
// 点击添加分类按钮的事件回调 因为有异步操作所以要写个method 不能简单的设置visible
showAddCategoryDialog() {
// 先获取父级分类的数据 再展示对话框
this.getParentCategoryList()
this.addCategoryDialogVisible = true
},
// 获取父级分类的数据列表 用于在添加分类对话框内让用户选择
async getParentCategoryList() {
// 还是用API接口文档1.6.1 但传参不同 只需要type值就行
// 因为只有前两级有资格作为父级分类 所以type设置为2会获取到二级(获取一级和二级)
const { data: res } = await this.$http.get('categories', { params: { type: 2 } })
if (res.meta.status !== 200) {
return this.$message.error(res.meta.msg)
}
this.parentCategoryList = res.data
},
// 添加对话框种级联选择器的选中项发生变化时
parentCategoryChange() {
// 因为data里的addCategoryForm是表单数据的双向绑定 因此选中项发生变化后 应该立即更新其中的内容
// 包括要添加的分类名称 他的父级id 他自己的层级
// 而级联选择器的选中项 双向绑定在data里的selectedParentCategory 所以可以根据这个判断
// 当selectedParentCategory数组中的length(数组存放的是父级分类id)>0 证明选中了父级分类
// 而选中的具体父级分类应该数组里最后一项(只有一项代表一级 有两项第二项代表二级)
if (this.selectedParentCategory.length > 0) {
// 取出父级分类id
this.addCategoryForm.cat_pid = this.selectedParentCategory[this.selectedParentCategory.length - 1]
// 并根据父级分类的层级确认要添加的分类的层级 初始设置自己的分类层级为0
// 注意层级和cat_level的关系 一级对应0 二级对应1 三级对应2 v-if就是这么渲染的 也可参考API接口文档1.6.1
// 如果数组有一项代表父级层级是一级(父级cat_level为0) 所以要添加的分类是二级(cat_level=1)
// 如果数组有二项代表父级层级是二级(父级cat_level为1) 所以要添加的分类是三级(cat_level=2)
// 可以发现要添加的分类的cat_level总是等于数组长度
this.addCategoryForm.cat_level = this.selectedParentCategory.length
} else {
// else证明现在数组长度为空 即用户清空了选中项 需要把addCategoryForm里的数据重置
this.addCategoryForm.cat_pid = 0
this.addCategoryForm.cat_level = 0
}
},
// 添加对话框确认按钮的点击事件
addCategory() {
// 预验证 通过后参考API接口文档1.6.2添加分类
this.$refs.addCategoryRef.validate(async valid => {
if (!valid) {
return this.$message.error('请输入分类名称!')
}
// 疑问: 为什么请求传参可以直接写 而不像getCategoryList()中用{params: this.queryInfo}
const { data: res } = await this.$http.post('categories', this.addCategoryForm)
if (res.meta.status !== 201) {
return this.$message.error(res.meta.msg)
}
// 添加成功后提示成功 刷新数据列表 并关闭对话框
this.$message.success(res.meta.msg)
this.getCategoryList()
this.addCategoryDialogVisible = false
})
},
// 关闭添加分类对话框时进行重置
addCategoryDialogClosed() {
this.$refs.addCategoryRef.resetFields()
// 存储父级分类的数组也要重置
this.selectedParentCategory = []
// 还要将表单双向绑定的数据重置
this.addCategoryForm.cat_level = 0
this.addCategoryForm.cat_pid = 0
},
// 点击编辑按钮时的事件回调
showEditCategoryDialog(category) {
// 存储当前row里的id和name 以供点击确定按钮后发送请求
this.editCategoryForm.cat_name = category.cat_name
// 天坑 这里应该拿cat_id 当时写错了拿了pid导致改的都是父节点
this.editCategoryForm.id = category.cat_id
this.editCategoryDialogVisible = true
},
// 编辑分类对话框的确定按钮
editCategory() {
// 预验证 通过验证后根据API接口文档1.6.4编辑分类
this.$refs.editCategoryRef.validate(async valid => {
if (!valid) {
return this.$message.error('请输入分类名称!')
}
// 天坑: cat_name应该放到请求体中 即用对象的属性名和属性值方式传递
const { data: res } = await this.$http.put('categories/' + this.editCategoryForm.id, { cat_name: this.editCategoryForm.cat_name })
if (res.meta.status !== 200) {
return this.$message.error(res.meta.msg)
}
// 请求成功则提示成功 更新页面 关闭对话框
this.$message.success(res.meta.msg)
this.getCategoryList()
this.editCategoryDialogVisible = false
})
},
// 关闭添加分类对话框时进行重置
editCategoryDialogClosed() {
this.$refs.editCategoryRef.resetFields()
},
// 点击删除按钮的事件回调
async deleteCategory(id) {
// 先弹框 让用户进行二次确认 $confirm返回值也是一个Promise
// 经过async await修饰后 如果用户确认删除 则返回值为字符串'confirm'
// 经过async await修饰后 如果用户取消删除 则返回值为字符串'cancel'
const confirmResult = await this.$confirm('此操作将永久删除该分类, 是否继续?', '警告', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).catch(err => err)// 用catch来捕获前面的所有错误 简略了() {} return
if (confirmResult !== 'confirm') {
return this.$message.info('已取消删除')
}
// 如果确认删除 参考API接口文档1.6.5
const { data: res } = await this.$http.delete('categories/' + id)
if (res.meta.status !== 200) {
return this.$message.error(res.meta.msg)
}
// 别忘了删除成功之后刷新用户列表
this.getCategoryList()
this.$message.success(res.meta.msg)
}
},
created() {
this.getCategoryList()
}
}
</script>
<style lang="less" scoped>
.el-icon-success {
color: lightgreen;
font-size: 15px;
}
.el-icon-error {
color: red;
font-size: 15px;
}
.tree-table {
margin-top: 15px;
}
// 设置级联选择器占满父元素宽度 和输入框同宽
.el-cascader {
width: 100%;
}
</style>
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/wayne831/vue_shop.git
git@gitee.com:wayne831/vue_shop.git
wayne831
vue_shop
vue_shop
master

搜索帮助