谷粒商城项目实战——04商品服务之属性分组

三. 属性分组

1. 前期工作
1. 数据导入
  1. 将课件中菜单数据库中的数据导入数据库, 这样就不用自己后期一个一个的添加

    image-20210502112148174

2. 三级分类抽取成公共组件
1. 抽取公共类
  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. 页面导入
  1. 展示页面获取组件的操作

    从代码生成器中拷贝页面到前端项目

    image-20210502112906613

    image-20210502112628896

3. 传递参数
  1. 子组件传递(公共组件)

    image-20210502113124301

  2. 父组件接收

    <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>
    

    image-20210502113222892

    image-20210502113458894

  3. 效果

    image-20210502113605704

2. 获取分类属性(查询)

生成的查询方法只能查询所有分类, 所以需要手动编写相关方法

1. 后端代码
1. Controller层
  1. 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层
  1. 接口

    PageUtils queryPage(Map<String, Object> params, Long catelogId);
    
  2. 实现

    @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);
        }
    }
    

    image-20210502141535487

2. 前端代码
  1. 代码

    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
          })
        },
    

    image-20210502141803730

  2. 效果

    image-20210502141946007

3. 分组新增
1. 前端
  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>
    
  2. 此时可以显示数据库中的分类信息, 但是最后一级会显示一个空的子分类列表

    因为最后一级的时候虽然children为空, 但是仍然会返回

    image-20210502145037061

  3. 修改, 在CategoryEntity实体类的children属性上添加注解

    // 如果json中这个字段不为空时才会包含
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    @TableField(exist = false)
    private List<CategoryEntity> children;
    

    image-20210502145624382

  4. 提交时只需要提交最后选中的分类id, 而不需要保存父类的id

    1. bug

    image-20210502150206303

    1. 解决: 用catelogIds来存储是所有的id, 但是用catelogId来存储最后一个id

    image-20210502150120426

    ​ 提交表单时读取最后一位数据

    image-20210502150727052

2. 后端代码
  1. 代码

    @RequestMapping("/save")
    public R save(@RequestBody AttrGroupEntity attrGroup){
        attrGroupService.save(attrGroup);
        return R.ok();
    }
    
4. 分组修改
1. 前端代码
1. 问题
  1. 点击修改按钮时, 所选分类没有回显, 因为添加的时候只传递了最后一个分类的id

    image-20210502151149996
2. 实现
  1. 将页面中的属性catelogIds全部改为catelogPath

  2. AttrGroupEntry实体类中添加一个分类路径的属性

    // 不是数据库中存在的属性
    @TableField(exist = false)
    private Long[] catelogPath;
    
  3. 读取完整路径

    // 查出catelogId的完整路径
    this.dataForm.catelogPath = data.attrGroup.catelogPath
    

    image-20210502161803433

  4. 关闭窗口后, 并没有将catelogPath中的值清空, 如果点击新增, 则会回显之前的值, 所以关闭窗口时需要清空

    image-20210502162223959

    image-20210502162247270

  5. 优化: 给联级添加上可搜索

    image-20210502162637403

    image-20210502162704732

2. 后端代码
1. controller层
  1. 代码

    @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层
  1. 接口

    Long[] findCatelogPath(Long catelogId);
    
  2. 实现

    /**
     * 找到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;
    }
    

    image-20210502163341875

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值