From b2aa119a3e476cbb43f23a82745159d8071925f7 Mon Sep 17 00:00:00 2001 From: Administrator <15274802129@163.com> Date: Fri, 12 Sep 2025 16:30:58 +0800 Subject: [PATCH] feat(ai): 添加产品类别层级功能 --- src/main/java/cc/mrbird/febs/ai/service/impl/AiProductCategoryServiceImpl.java | 66 ++++++++++++++++++++++ src/main/java/cc/mrbird/febs/ai/entity/AiProductCategory.java | 7 ++ src/main/java/cc/mrbird/febs/ai/service/AiProductCategoryService.java | 2 src/main/resources/templates/febs/views/modules/ai/productCategory/list.html | 2 src/main/resources/templates/febs/views/modules/ai/productCategory/info.html | 23 +++++++ src/main/java/cc/mrbird/febs/ai/enums/ProductCategoryLevelEnum.java | 24 ++++++++ src/main/resources/templates/febs/views/modules/ai/productCategory/add.html | 23 +++++++ src/main/java/cc/mrbird/febs/ai/controller/productCategory/AiProductCategoryController.java | 9 +++ 8 files changed, 155 insertions(+), 1 deletions(-) diff --git a/src/main/java/cc/mrbird/febs/ai/controller/productCategory/AiProductCategoryController.java b/src/main/java/cc/mrbird/febs/ai/controller/productCategory/AiProductCategoryController.java index c50d176..8063a2a 100644 --- a/src/main/java/cc/mrbird/febs/ai/controller/productCategory/AiProductCategoryController.java +++ b/src/main/java/cc/mrbird/febs/ai/controller/productCategory/AiProductCategoryController.java @@ -6,6 +6,7 @@ import cc.mrbird.febs.common.controller.BaseController; import cc.mrbird.febs.common.entity.FebsResponse; import cc.mrbird.febs.common.entity.QueryRequest; +import cc.mrbird.febs.mall.vo.AdminMallGoodsCategoryTreeVo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.annotation.Validated; @@ -13,6 +14,7 @@ import javax.validation.Valid; import javax.validation.constraints.NotNull; +import java.util.List; import java.util.Map; /** @@ -73,4 +75,11 @@ return new FebsResponse().success().data(service.categoryTree()); } + + @GetMapping("categoryTree/parent") + @ControllerEndpoint(exceptionMessage = "获取分类失败") + public List<AiProductCategory> parent(){ + + return service.parent(); + } } diff --git a/src/main/java/cc/mrbird/febs/ai/entity/AiProductCategory.java b/src/main/java/cc/mrbird/febs/ai/entity/AiProductCategory.java index de558aa..778994c 100644 --- a/src/main/java/cc/mrbird/febs/ai/entity/AiProductCategory.java +++ b/src/main/java/cc/mrbird/febs/ai/entity/AiProductCategory.java @@ -1,8 +1,11 @@ package cc.mrbird.febs.ai.entity; import cc.mrbird.febs.common.entity.AiBaseEntity; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; + +import java.util.List; /** * AI产品类别 @@ -54,4 +57,8 @@ private Integer hotState; private Integer level; private String parentId; + @TableField(exist = false) + private String parentName; + @TableField(exist = false) + private List<AiProductCategory> child; } diff --git a/src/main/java/cc/mrbird/febs/ai/enums/ProductCategoryLevelEnum.java b/src/main/java/cc/mrbird/febs/ai/enums/ProductCategoryLevelEnum.java new file mode 100644 index 0000000..73782ba --- /dev/null +++ b/src/main/java/cc/mrbird/febs/ai/enums/ProductCategoryLevelEnum.java @@ -0,0 +1,24 @@ +package cc.mrbird.febs.ai.enums; + +import lombok.Getter; + +/** + * @author wzy + * @date 2021-09-26 + **/ +@Getter +public enum ProductCategoryLevelEnum { + + LEVEL_TWO("二级菜单",2), + LEVEL_ONE("一级菜单",1); + + + private String name; + private Integer level; + + ProductCategoryLevelEnum(String name,Integer level) { + + this.level = level; + this.name = name; + } +} diff --git a/src/main/java/cc/mrbird/febs/ai/service/AiProductCategoryService.java b/src/main/java/cc/mrbird/febs/ai/service/AiProductCategoryService.java index 1e2ce17..3f640aa 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/AiProductCategoryService.java +++ b/src/main/java/cc/mrbird/febs/ai/service/AiProductCategoryService.java @@ -40,4 +40,6 @@ FebsResponse delete(String id); List<AiProductCategory> categoryTree(); + + List<AiProductCategory> parent(); } diff --git a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductCategoryServiceImpl.java b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductCategoryServiceImpl.java index a64f47e..8550d52 100644 --- a/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductCategoryServiceImpl.java +++ b/src/main/java/cc/mrbird/febs/ai/service/impl/AiProductCategoryServiceImpl.java @@ -2,6 +2,7 @@ import cc.mrbird.febs.ai.entity.AiMemberRole; import cc.mrbird.febs.ai.entity.AiProductCategory; +import cc.mrbird.febs.ai.enums.ProductCategoryLevelEnum; import cc.mrbird.febs.ai.mapper.AiProductCategoryMapper; import cc.mrbird.febs.ai.service.AiProductCategoryService; import cc.mrbird.febs.ai.util.UUID; @@ -9,6 +10,7 @@ import cc.mrbird.febs.common.entity.QueryRequest; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -20,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional; import java.util.*; +import java.util.stream.Collectors; /** * AI产品类别 Service实现类 @@ -43,9 +46,42 @@ public List<AiProductCategory> getList() { LambdaQueryWrapper<AiProductCategory> query = Wrappers.lambdaQuery(AiProductCategory.class); query.ne(AiProductCategory::getState, 2); + query.eq(AiProductCategory::getLevel, ProductCategoryLevelEnum.LEVEL_ONE.getLevel()); query.orderByDesc(AiProductCategory::getHotState); query.orderByAsc(AiProductCategory::getSort); List<AiProductCategory> aiProductCategories = aiProductCategoryMapper.selectList(query); + if (CollUtil.isNotEmpty(aiProductCategories)){ + Set<String> parentIds = aiProductCategories.stream().map(AiProductCategory::getId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(parentIds)){ + List<AiProductCategory> aiProductCategoriesChild = aiProductCategoryMapper.selectList( + Wrappers.lambdaQuery(AiProductCategory.class) + .in(AiProductCategory::getParentId, parentIds) + .ne(AiProductCategory::getState, 2) + .eq(AiProductCategory::getLevel, ProductCategoryLevelEnum.LEVEL_TWO.getLevel()) + .orderByAsc(AiProductCategory::getSort) + ); + + //Stream流操作aiProductCategoriesChild,返回一个Map<ParentId,List<AiProductCategory>>,List<AiProductCategory>按照sort排序 + Map<String, List<AiProductCategory>> resultMap = aiProductCategoriesChild.stream() + .collect(Collectors.groupingBy( + AiProductCategory::getParentId, + Collectors.collectingAndThen( + Collectors.toList(), + list -> list.stream() + .sorted(Comparator.comparing(AiProductCategory::getSort)) + .collect(Collectors.toList()) + ) + )); + if (CollUtil.isNotEmpty(resultMap)){ + aiProductCategories.forEach(aiProductCategory -> { + List<AiProductCategory> collect = resultMap.get(aiProductCategory.getId()); + if (CollUtil.isNotEmpty(collect)){ + aiProductCategory.setChild(collect); + } + }); + } + } + } return aiProductCategories; } @@ -74,6 +110,25 @@ query.orderByDesc(AiProductCategory::getHotState); query.orderByAsc(AiProductCategory::getSort); Page<AiProductCategory> pages = aiProductCategoryMapper.selectPage(page, query); + List<AiProductCategory> records = pages.getRecords(); + if (CollUtil.isNotEmpty( records)){ + //stream流获取全部的parentId + Set<String> parentIds = records.stream().map(AiProductCategory::getParentId).collect(Collectors.toSet()); + if (CollUtil.isNotEmpty(parentIds)){ + List<AiProductCategory> aiProductCategories = aiProductCategoryMapper.selectList( + Wrappers.lambdaUpdate(AiProductCategory.class) + .in(AiProductCategory::getId, parentIds) + ); + Map<String, AiProductCategory> map = aiProductCategories.stream().collect( + Collectors.toMap(AiProductCategory::getId, aiProductCategory -> aiProductCategory)); + records.forEach(aiProductCategory -> { + AiProductCategory orDefault = map.getOrDefault(aiProductCategory.getParentId(), null); + if(ObjectUtil.isNotNull(orDefault)){ + aiProductCategory.setParentName(orDefault.getName()); + } + }); + } + } return pages; } @@ -110,6 +165,8 @@ entity.setIconImg(dto.getIconImg()); entity.setSort(dto.getSort()); entity.setCreatedTime(new Date()); + entity.setParentId(dto.getParentId()); + entity.setLevel(StrUtil.isNotEmpty(dto.getParentId()) ? 2 : 1); this.save(entity); return new FebsResponse().success().message("操作成功"); } @@ -152,4 +209,13 @@ public List<AiProductCategory> categoryTree() { return this.getList() ; } + + @Override + public List<AiProductCategory> parent() { + LambdaQueryWrapper<AiProductCategory> query = Wrappers.lambdaQuery(AiProductCategory.class); + query.select(AiProductCategory::getId,AiProductCategory::getName); + query.eq(AiProductCategory::getLevel, 1); + query.ne(AiProductCategory::getState, 2); + return this.getBaseMapper().selectList(query); + } } diff --git a/src/main/resources/templates/febs/views/modules/ai/productCategory/add.html b/src/main/resources/templates/febs/views/modules/ai/productCategory/add.html index b25cda5..2bb8184 100644 --- a/src/main/resources/templates/febs/views/modules/ai/productCategory/add.html +++ b/src/main/resources/templates/febs/views/modules/ai/productCategory/add.html @@ -9,6 +9,17 @@ </ul> <div class="layui-tab-content"> <div class="layui-tab-item layui-show"> + + <div class="layui-row layui-col-space10 layui-form-item"> + <div class="layui-col-lg6"> + <label class="layui-form-label">父类:</label> + <div class="layui-input-block"> + <select name="parentId" class="category-add-productCategory"> + <option value="">请选择</option> + </select> + </div> + </div> + </div> <div class="layui-row layui-col-space10 layui-form-item"> <div class="layui-col-lg6"> <label class="layui-form-label febs-form-item-require">名称:</label> @@ -151,6 +162,18 @@ } }); + //(下拉框) + $.get(ctx + 'admin/productCategory/categoryTree/parent', function (data) { + for (var k in data) + { + $(".category-add-productCategory").append("<option value='" + data[k].id + "'>" + data[k].name + "</option>"); + } + layui.use('form', function () { + var form = layui.form; + form.render(); + }); + }); + form.on('submit(productCategory-add-form-submit)', function (data) { $.ajax({ 'url':ctx + 'admin/productCategory/add', diff --git a/src/main/resources/templates/febs/views/modules/ai/productCategory/info.html b/src/main/resources/templates/febs/views/modules/ai/productCategory/info.html index 96bb4a2..2e07b6b 100644 --- a/src/main/resources/templates/febs/views/modules/ai/productCategory/info.html +++ b/src/main/resources/templates/febs/views/modules/ai/productCategory/info.html @@ -13,6 +13,16 @@ <div class="layui-tab-item layui-show"> <div class="layui-row layui-col-space10 layui-form-item"> <div class="layui-col-lg6"> + <label class="layui-form-label">父类:</label> + <div class="layui-input-block"> + <select name="parentId" class="category-add-productCategory" id="category-add-productCategory-select"> + <option value="">请选择</option> + </select> + </div> + </div> + </div> + <div class="layui-row layui-col-space10 layui-form-item"> + <div class="layui-col-lg6"> <label class="layui-form-label febs-form-item-require">名称:</label> <div class="layui-input-block"> <input type="text" name="name" lay-verify="required" @@ -161,7 +171,18 @@ } }); - + //(下拉框) + $.get(ctx + 'admin/productCategory/categoryTree/parent', function (data) { + for (var k in data) + { + $(".category-add-productCategory").append("<option value='" + data[k].id + "'>" + data[k].name + "</option>"); + } + layui.use('form', function () { + var form = layui.form; + $("#category-add-productCategory-select").val(aiProductCategory.parentId) + form.render(); + }); + }); setTimeout(() => { initproductCategoryInfo(); diff --git a/src/main/resources/templates/febs/views/modules/ai/productCategory/list.html b/src/main/resources/templates/febs/views/modules/ai/productCategory/list.html index e125bcb..3c1c7a7 100644 --- a/src/main/resources/templates/febs/views/modules/ai/productCategory/list.html +++ b/src/main/resources/templates/febs/views/modules/ai/productCategory/list.html @@ -242,7 +242,9 @@ {field: 'state', title: '状态', templet: '#productCategoryStateSwitch', minWidth: 130,align:'center'}, {field: 'sort', title: '排序', minWidth: 100,align:'center'}, {field: 'code', title: '编码', minWidth: 100,align:'center'}, + {field: 'level', title: '级别', minWidth: 100,align:'center'}, {field: 'name', title: '名称', minWidth: 100,align:'center'}, + {field: 'parentName', title: '父级名称', minWidth: 100,align:'center'}, {field: 'iconImg',title: '小图标', templet: function (d) { return '<a lay-event="seeImage">' + -- Gitblit v1.9.1