三. 属性分组
1. 前期工作
1. 数据导入
-
将课件中菜单数据库中的数据导入数据库, 这样就不用自己后期一个一个的添加
2. 三级分类抽取成公共组件
1. 抽取公共类
-
抽取公共类
<template> <!-- :data: 获取的数据源 :props: 配置选项 @node-click: 节点被点击时的回调 node-key: 每个树节点用来作为唯一标识的属性,整棵树应该是唯一的(一定要设置) --> <el-tree :data="menus" :props="defaultProps" node-key="catId" ref="menuTree" @node-click="nodeClick"> </el-tree> </template> <script> export default { components: {}, props: {}, data() { //这里存放数据 return { menus: [], // 展开删除分类的父id expandedKey: [], defaultProps: { // 子节点的属性 children: 'children', // 要显示的内容 label: 'name' }, }; }, //计算属性 类似于 data 概念 computed: {}, //监控 data 中的数据变化 watch: {}, //方法集合 methods: { // 获取属性分类列表 getMenus(){ this.$http({ url: this.$http.adornUrl('/product/category/list/tree'), method: 'get' }).then(({data}) => { // {data}, 使用解构的方式获取对象中的data数据 console.log("成功获取到菜单数据: ", data.data) this.menus = data.data }) }, nodeClick(data, node, component){ console.log("category被点击: ", data, node, component) // 向父组件发送事件 // 子组件被点击后, 会给父组件传递tree-node-click事件, // 并携带上data, node, component信息 this.$emit("tree-node-click", data, node, component) } }, created() { this.getMenus() }, </script>
2. 页面导入
-
展示页面获取组件的操作
从代码生成器中拷贝页面到前端项目
3. 传递参数
-
子组件传递(公共组件)
-
父组件接收
<el-col :span="6"> <!-- 希望category被点击后, attrgroup能感知到 父子组件传递数据 1. 子组件给父组件传递数据, 事件机制 子组件给父组件发送一个事件, 事件携带上数据 2. 父组件获取到该事件后, 执行指定的方法 --> <category @tree-node-click="treeNodeClick"></category> </el-col> <script> import Category from '../common/category' import AddOrUpdate from './attrgroup-add-or-update' ... // 感知树节点被点击 treeNodeClick( data, node, component){ console.log("attrgroup感知到category节点被点击: ", data, node, component) console.log("刚才被点击的节点的菜单id", data.catId) }, </script>
-
效果
2. 获取分类属性(查询)
生成的查询方法只能查询所有分类, 所以需要手动编写相关方法
1. 后端代码
1. Controller层
-
AttrGroupController
@RequestMapping("/list/{catelogId}") public R list(@RequestParam Map<String, Object> params, @PathVariable("catelogId") Long catelogId){ // PageUtils page = attrGroupService.queryPage(params); PageUtils page = attrGroupService.queryPage(params, catelogId); return R.ok().put("page", page); }
2. Service层
-
接口
PageUtils queryPage(Map<String, Object> params, Long catelogId);
-
实现
@Override public PageUtils queryPage(Map<String, Object> params, Long catelogId) { if (catelogId == 0) { return this.queryPage(params); } else { String key = (String) params.get("key"); // select * from pms_attr_group where catelog_id = ? and // (attr_group_id = key || attr_group_name like %key%) QueryWrapper<AttrGroupEntity> wrapper = new QueryWrapper<>(); wrapper.eq("catelog_id",catelogId); if (!StringUtils.isEmpty(key)) { wrapper.and((obj) -> { obj.eq("attr_group_id", key).or(). like("attr_group_name", key); }); } IPage<AttrGroupEntity> page = this.page( new Query<AttrGroupEntity>().getPage(params),wrapper); return new PageUtils(page); } }
2. 前端代码
-
代码
data() { return { ... catId: 0 }; }, ... methods: { // 感知树节点被点击 treeNodeClick( data, node, component){ // 判断当前点击的节点是否是三级分类 if(node.level == 3) { this.catId = data.catId this.getDataList() // 重新查询 } }, // 获取数据列表 getDataList () { this.dataListLoading = true this.$http({ url: this.$http.adornUrl(`/product/attrgroup/list/${this.catId}`), method: 'get', params: this.$http.adornParams({ page: this.pageIndex, limit: this.pageSize, key: this.dataForm.key }) }).then(({data}) => { if (data && data.code === 0) { this.dataList = data.page.list this.totalPage = data.page.totalCount } else { this.dataList = [] this.totalPage = 0 } this.dataListLoading = false }) },
-
效果
3. 分组新增
1. 前端
-
添加级联标签
<el-form-item label="所属分类id" prop="catelogId"> <!-- <el-input v-model="dataForm.catelogId" placeholder="所属分类id"></el-input> --> <!-- 级联选择器 --> <el-cascader v-model="dataForm.catelogId" :options="categorys" :props="props"></el-cascader> </el-form-item> ... <script> export default { data () { return { // 分类列表 categorys: [], // 指定获取到的值中各字段充当什么 props: { value: "catId", label: "name", children: "children" }, ... } }, created(){ this.getCategorys() }, methods: { // 获取所有三级分类 getCategorys(){ this.$http({ url: this.$http.adornUrl('/product/category/list/tree'), method: 'get' }).then(({data}) => { this.categorys = data.data }) }, ... } } </script>
-
此时可以显示数据库中的分类信息, 但是最后一级会显示一个空的子分类列表
因为最后一级的时候虽然children为空, 但是仍然会返回
-
修改, 在
CategoryEntity
实体类的children属性上添加注解// 如果json中这个字段不为空时才会包含 @JsonInclude(JsonInclude.Include.NON_EMPTY) @TableField(exist = false) private List<CategoryEntity> children;
-
提交时只需要提交最后选中的分类id, 而不需要保存父类的id
- bug
- 解决: 用catelogIds来存储是所有的id, 但是用catelogId来存储最后一个id
提交表单时读取最后一位数据
2. 后端代码
-
代码
@RequestMapping("/save") public R save(@RequestBody AttrGroupEntity attrGroup){ attrGroupService.save(attrGroup); return R.ok(); }
4. 分组修改
1. 前端代码
1. 问题
-
点击修改按钮时, 所选分类没有回显, 因为添加的时候只传递了最后一个分类的id
2. 实现
-
将页面中的属性catelogIds全部改为catelogPath
-
在
AttrGroupEntry
实体类中添加一个分类路径的属性// 不是数据库中存在的属性 @TableField(exist = false) private Long[] catelogPath;
-
读取完整路径
// 查出catelogId的完整路径 this.dataForm.catelogPath = data.attrGroup.catelogPath
-
关闭窗口后, 并没有将catelogPath中的值清空, 如果点击新增, 则会回显之前的值, 所以关闭窗口时需要清空
-
优化: 给联级添加上可搜索
2. 后端代码
1. controller层
-
代码
@RequestMapping("/info/{attrGroupId}") public R info(@PathVariable("attrGroupId") Long attrGroupId){ // 1. 根据分组id, 查询属性分组 AttrGroupEntity attrGroup = attrGroupService.getById(attrGroupId); // 2. 根据属性分组, 获取所属分类id Long catelogId = attrGroup.getCatelogId(); // 3. 根据所属分类id, 查询分类路径 Long[] path = categoryService.findCatelogPath(catelogId); // 4. 将分类路径保存到AttrGroupEntity中, 然后封装起来返回 attrGroup.setCatelogPath(path); return R.ok().put("attrGroup", attrGroup); }
2. Service层
-
接口
Long[] findCatelogPath(Long catelogId);
-
实现
/** * 找到catelogId的完整路径 * @param catelogId * @return */ @Override public Long[] findCatelogPath(Long catelogId) { List<Long> paths = new ArrayList<>(); List<Long> parentPath = findParentPath(catelogId, paths); Collections.reverse(parentPath); return parentPath.toArray(new Long[parentPath.size()]); } private List<Long> findParentPath(Long catelogId, List<Long> paths){ // 1. 收集当前节点id paths.add(catelogId); CategoryEntity entity = this.getById(catelogId); if (entity.getParentCid() != 0) { findParentPath(entity.getParentCid(), paths); } return paths; }