Parcourir la source

页面装修修改,后端只负责存取

jason il y a 1 an
Parent
commit
ad1f656dfa
25 fichiers modifiés avec 352 ajouts et 439 suppressions
  1. 4 4
      sql/mysql/optional/mall.sql
  2. 8 1
      yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java
  3. 0 12
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/CommonStyle.java
  4. 0 52
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/NavMenuComponent.java
  5. 0 39
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/PageComponentDTO.java
  6. 0 25
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/ProductCategoryComponent.java
  7. 0 43
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/RollingBannerComponent.java
  8. 30 0
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/DecorateComponentEnum.java
  9. 16 3
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/DecoratePageTypeEnum.java
  10. 0 54
      yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/PageComponentEnum.java
  11. 45 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/DecorateComponentController.java
  12. 9 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecorateComponentReqVO.java
  13. 4 8
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecorateComponentRespVO.java
  14. 38 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/decorate/AppDecorateController.java
  15. 30 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/decorate/vo/AppDecorateComponentRespVO.java
  16. 41 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/decorate/DecorateComponentConvert.java
  17. 0 45
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/decorate/DecoratePageConvert.java
  18. 6 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/decorate/DecorateComponentDO.java
  19. 4 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/decorate/DecorateComponentMapper.java
  20. 27 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentService.java
  21. 45 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentServiceImpl.java
  22. 0 26
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageService.java
  23. 0 30
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageServiceImpl.java
  24. 45 0
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentServiceImplTest.java
  25. 0 83
      yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageServiceImplTest.java

+ 4 - 4
sql/mysql/optional/mall.sql

@@ -448,10 +448,10 @@ CREATE TABLE `trade_delivery_express` (
 ) ENGINE=InnoDB COMMENT='快递公司';
 
 -- ----------------------------
--- 页面装修表结构
+-- 页面装修表
 -- ----------------------------
-DROP TABLE IF EXISTS `promotion_page_decorate`;
-CREATE TABLE `promotion_page_decorate` (
+DROP TABLE IF EXISTS `promotion_decorate_component`;
+CREATE TABLE `promotion_decorate_component` (
    `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
    `type` int  NOT NULL COMMENT '页面类型',
    `component_code` varchar(64)  NOT NULL COMMENT '组件编码',
@@ -464,7 +464,7 @@ CREATE TABLE `promotion_page_decorate` (
    `deleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否删除',
    `tenant_id` bigint NOT NULL DEFAULT 0 COMMENT '租户编号',
    PRIMARY KEY (`id`) USING BTREE
-) ENGINE=InnoDB COMMENT='页面装修';
+) ENGINE=InnoDB COMMENT='页面装修';
 
 SET FOREIGN_KEY_CHECKS = 1;
 

+ 8 - 1
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/mapper/BaseMapperX.java

@@ -113,7 +113,6 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         Db.saveBatch(entities, size);
     }
 
-    // @芋艿 是不是叫  updateByDo 或者  updateByEntity 更合适;回复:因为是使用实体作为条件去批量更新,所以没加 ByEntity,保持和 mybatis plus 风格一致
     default void updateBatch(T update) {
         update(update, new QueryWrapper<>());
     }
@@ -131,4 +130,12 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
         Db.updateBatchById(entities, size);
     }
 
+    /**
+     * 批量修改插入, 会根据实体的主键是否为空,更新还是修改。默认为 1000
+     * @param entities 实体们
+     */
+    default  void saveOrUpdateBatch(Collection<T> entities){
+        Db.saveOrUpdateBatch(entities);
+    }
+
 }

+ 0 - 12
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/CommonStyle.java

@@ -1,12 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.decorate.dto;
-
-import lombok.Data;
-
-/**
- * 通用的样式 DTO. 由于每个组件的样式配置可能会不一样。 样式配置暂时没想好如何做。 暂时使用一个通用的DTO, 没有任何属性
- *
- * @author jason
- */
-@Data
-public class CommonStyle {
-}

+ 0 - 52
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/NavMenuComponent.java

@@ -1,52 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.decorate.dto;
-
-import lombok.Data;
-
-/**
- * 导航菜单组件的内容配置,数据结构 定义
- * 不知道放哪里比较好 // TODO @芋艿 貌似放 api 这里不太合适。有什么建议没有?
- *
- * @author jason
- */
-@Data
-public class NavMenuComponent {
-
-    /**
-     * 导航菜单组件对内容的配置项
-     */
-    @Data
-    public static class Config {
-
-        /**
-         * 是否启用
-         */
-        private Boolean enabled;
-    }
-
-    /**
-     * 导航菜单组件的数据结构
-     */
-    @Data
-    public static class DataStructure {
-        /**
-         * 显示名称
-         */
-        private String name;
-
-        /**
-         * 显示图片
-         */
-        private String img;
-
-        /**
-         * 连接路径
-         */
-        private String path;
-
-        /**
-         * 状态, 是否显示
-         */
-        private Integer status;
-
-    }
-}

+ 0 - 39
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/PageComponentDTO.java

@@ -1,39 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.decorate.dto;
-
-import lombok.Data;
-
-/**
- * 页面组件通用模板结构 DTO
- * 每个组件都有自己对应的内容配置, 样式配置, 具体数据,和其他组件不同的。但这个三个配置是必须的, 所以定义通用的模板结构
- * 内容配置, 样式配置, 具体数据的结构 需要每个组件单独定义。
- * 1. 内容配置 (不包括具体的内容) 例如是否启用,是否显示, 商品分类页的排版方式等
- * 2. 样式设置,对应 crmeb php 版组件的样式配置。 暂时可能用不。 所以使用通用 CommonStyleDTO,后续可能用上
- * 3. 具体数据, 有些组件(导航菜单组件)数据是通过装修配置, 需要定制数据。有些组件(如商品分类),数据从接口获取,不需要该项
- *
- * @author jason
- */
-@Data
-public class PageComponentDTO<Config, Style, Content> {
-
-    /**
-     * 组件标题, 每个组件都有的
-     */
-    private String title;
-
-    /**
-     * 组件的内容配置项
-     */
-    private Config config;
-
-    /**
-     * 组件的样式配置
-     */
-    private Style style;
-
-    /**
-     * 组件的具体数据
-     *
-     */
-    private Content data;
-
-}

+ 0 - 25
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/ProductCategoryComponent.java

@@ -1,25 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.decorate.dto;
-
-import lombok.Data;
-
-/**
- * 商品分类组件的内容配置, 无数据结构定义。数据从接口获取
- *
- * @author jason
- */
-public class ProductCategoryComponent {
-
-    /**
-     * 商品分类组件组件的内容配置项
-     */
-    @Data
-    public static class Config {
-
-        /**
-         * 页面风格类型
-         */
-        private Integer layoutStyle;
-
-        // TODO 其它
-    }
-}

+ 0 - 43
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/api/decorate/dto/RollingBannerComponent.java

@@ -1,43 +0,0 @@
-package cn.iocoder.yudao.module.promotion.api.decorate.dto;
-
-import lombok.Data;
-
-/**
- * 滚动横幅广告组件的内容配置,数据结构定义
- *
- * @author jason
- */
-public class RollingBannerComponent {
-    /**
-     * 滚动横幅广告组件的内容配置项
-     */
-    @Data
-    public static class Config {
-
-        /**
-         * 是否启用
-         */
-        private Boolean enabled;
-    }
-
-    /**
-     * 导航菜单组件的数据结构
-     */
-    @Data
-    public static class DataStructure {
-        /**
-         * 显示图片
-         */
-        private String img;
-
-        /**
-         * 连接路径
-         */
-        private String path;
-
-        /**
-         * 状态, 是否显示
-         */
-        private Integer status;
-    }
-}

+ 30 - 0
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/DecorateComponentEnum.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.promotion.enums.decorate;
+
+import lombok.Getter;
+
+/**
+ * 页面组件枚举
+ *
+ * @author jason
+ */
+@Getter
+public enum DecorateComponentEnum {
+    NAV_MENU("nav-menu", "导航菜单"),
+    ROLLING_BANNER("rolling-banner", "滚动横幅广告"),
+    PRODUCT_CATEGORY("product-category", "商品分类");
+
+    /**
+     * 页面组件代码
+     */
+    private final String code;
+
+    /**
+     * 页面组件说明
+     */
+    private final String desc;
+
+    DecorateComponentEnum(String code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+}

+ 16 - 3
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/DecoratePageTypeEnum.java

@@ -1,21 +1,34 @@
 package cn.iocoder.yudao.module.promotion.enums.decorate;
 
+import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
+import java.util.Arrays;
+
 /**
- * 装修页面枚举
+ * 装修页面类型枚举
  *
  * @author jason
  */
 @AllArgsConstructor
 @Getter
-public enum DecoratePageTypeEnum {
+public enum DecoratePageTypeEnum implements IntArrayValuable {
     INDEX(1, "首页");
 
+    private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DecoratePageTypeEnum::getType).toArray();
+
+    /**
+     * 页面类型
+     */
     private final Integer type;
     /**
-     * 名字
+     * 页面名称
      */
     private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
 }

+ 0 - 54
yudao-module-mall/yudao-module-promotion-api/src/main/java/cn/iocoder/yudao/module/promotion/enums/decorate/PageComponentEnum.java

@@ -1,54 +0,0 @@
-package cn.iocoder.yudao.module.promotion.enums.decorate;
-
-import cn.hutool.core.lang.TypeReference;
-import cn.hutool.core.util.ArrayUtil;
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.module.promotion.api.decorate.dto.*;
-import lombok.Getter;
-
-import java.lang.reflect.Type;
-import java.util.List;
-
-/**
- * 页面组件枚举
- *
- * @author jason
- */
-@Getter
-public enum PageComponentEnum {
-    NAV_MENU("nav-menu", "导航菜单",
-            new TypeReference<PageComponentDTO<NavMenuComponent.Config, CommonStyle, List<NavMenuComponent.DataStructure>>>() {}.getType()),
-    ROLLING_BANNER("rolling-banner", "滚动横幅广告",
-            new TypeReference<PageComponentDTO<RollingBannerComponent.Config, CommonStyle, List<RollingBannerComponent.DataStructure>>>() {}.getType()),
-    PRODUCT_CATEGORY("product-category", "商品分类",
-            new TypeReference<PageComponentDTO<ProductCategoryComponent.Config, CommonStyle, Object>>() {}.getType()); // data 会为null 用 object 代替
-
-    /**
-     * 页面组件代码
-     */
-    private final String code;
-
-    /**
-     * 页面组件说明
-     */
-    private final String desc;
-
-    /**
-     * 具体组件的类型
-     */
-    private final Type  componentType;
-
-    PageComponentEnum(String code, String desc, Type componentType) {
-        this.code = code;
-        this.desc = desc;
-        this.componentType = componentType;
-    }
-
-    public static PageComponentEnum getOfCode(String code) {
-        return ArrayUtil.firstMatch(component -> component.getCode().equals(code), PageComponentEnum.values());
-    }
-
-    public <C, S, D> PageComponentDTO<C, S, D> parsePageComponent(String text) {
-        return JsonUtils.parseObject(text, componentType);
-    }
-}

+ 45 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/DecorateComponentController.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.promotion.controller.admin.decorate;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO;
+import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum;
+import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert.INSTANCE;
+
+@Tag(name = "管理后台 - 店铺页面装修")
+@RestController
+@RequestMapping("/promotion/decorate")
+@Validated
+public class DecorateComponentController {
+    @Resource
+    private DecorateComponentService decorateComponentService;
+
+    @PostMapping("/page-save")
+    @Operation(summary = "页面装修保存")
+    // TODO 加权限
+    public CommonResult<Boolean> pageSave(@Valid @RequestBody DecorateComponentReqVO reqVO) {
+        decorateComponentService.pageSave(reqVO);
+        return success(true);
+    }
+
+    @GetMapping("/get-page-components")
+    @Operation(summary = "获取装修页面组件")
+    @Parameter(name = "type", description = "页面类型", required = true)
+    // TODO 加权限
+    public CommonResult<DecorateComponentRespVO> getPageComponents(@RequestParam("type")
+                                                                   @InEnum(DecoratePageTypeEnum.class) Integer type) {
+        return success(INSTANCE.convert2(type, decorateComponentService.getPageComponents(type)));
+    }
+}

+ 9 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecoratePageReqVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecorateComponentReqVO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
@@ -11,20 +13,23 @@ import java.util.List;
 /**
  * @author jason
  */
-@Schema(description = "管理后台 - 页面装,整个页面 Request VO ")
+@Schema(description = "管理后台 - 页面装 Request VO ")
 @Data
-public class DecoratePageReqVO {
+public class DecorateComponentReqVO {
     @Schema(description = "页面类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "页面类型不能为空")
+    @InEnum(DecoratePageTypeEnum.class)
     private Integer type;
     @Schema(description = "页面组件列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
     @NotEmpty(message = "页面组件列表不能为空")
     @Valid
     private List<ComponentReqVO> components;
 
-    @Schema(description = "管理后台 - 页面组件 Request VO, 后面是不是可以做分组件保存?? ")
+    @Schema(description = "管理后台 - 页面装修组件 Request VO")
     @Data
     public static class ComponentReqVO {
+        @Schema(description = "组件编码",  example = "1")
+        private Long id;
 
         @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
         @NotEmpty(message = "组件编码不能为空")
@@ -32,7 +37,7 @@ public class DecoratePageReqVO {
 
         @Schema(description = "组件对应值, json 字符串, 含内容配置,具体数据", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
         @NotEmpty(message = "组件值为空")
-        private String value;
+        private String componentValue;
     }
 
 }

+ 4 - 8
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecoratePageRespVO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/admin/decorate/vo/DecorateComponentRespVO.java

@@ -10,7 +10,7 @@ import java.util.List;
  */
 @Schema(description = "管理后台 - 页面装修 Resp VO")
 @Data
-public class DecoratePageRespVO {
+public class DecorateComponentRespVO {
     @Schema(description = "页面类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer type;
     @Schema(description = "页面组件", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
@@ -19,16 +19,12 @@ public class DecoratePageRespVO {
     @Schema(description = "管理后台 - 页面组件 Resp VO")
     @Data
     public static class ComponentRespVO {
-        @Schema(description = "组件标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "首页广告")
-        private String title;
+        @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        private Long id;
         @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
         private String componentCode;
         @Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
-        private Object config;
-        @Schema(description = "组件的样式配置", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
-        private Object style;
-        @Schema(description = "组件的具体数据", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
-        private Object data;
+        private String componentValue;
     }
 
 }

+ 38 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/decorate/AppDecorateController.java

@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.promotion.controller.app.decorate;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO;
+import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum;
+import cn.iocoder.yudao.module.promotion.service.decorate.DecorateComponentService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert.INSTANCE;
+
+@Tag(name = "用户 APP - 店铺装修")
+@RestController
+@RequestMapping("/promotion/decorate")
+@Validated
+public class AppDecorateController {
+
+    @Resource
+    private DecorateComponentService decorateComponentService;
+
+    @GetMapping("/get-page-components")
+    @Operation(summary = "获取装修页面组件")
+    @Parameter(name = "type", description = "页面类型", required = true)
+    public CommonResult<AppDecorateComponentRespVO> getPageComponents(@RequestParam("type")
+                                                                      @InEnum(DecoratePageTypeEnum.class) Integer type) {
+        return success(INSTANCE.appConvert(type, decorateComponentService.getPageComponents(type)));
+    }
+}

+ 30 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/decorate/vo/AppDecorateComponentRespVO.java

@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.promotion.controller.app.decorate.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author jason
+ */
+@Schema(description = "用户 App - 页面装修 Resp VO")
+@Data
+public class AppDecorateComponentRespVO {
+    @Schema(description = "页面类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer type;
+    @Schema(description = "页面组件", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
+    private List<AppComponentRespVO> components;
+
+    @Schema(description = "用户 App - 页面组件 Resp VO")
+    @Data
+    public static class AppComponentRespVO {
+        @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+        private Long id;
+        @Schema(description = "组件编码", requiredMode = Schema.RequiredMode.REQUIRED, example = "nav-menu")
+        private String componentCode;
+        @Schema(description = "组件的内容配置项", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "TODO")
+        private String componentValue;
+    }
+
+}

+ 41 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/decorate/DecorateComponentConvert.java

@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.promotion.convert.decorate;
+
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO;
+import cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentRespVO.*;
+import static cn.iocoder.yudao.module.promotion.controller.app.decorate.vo.AppDecorateComponentRespVO.*;
+
+@Mapper
+public interface DecorateComponentConvert {
+
+    DecorateComponentConvert INSTANCE = Mappers.getMapper(DecorateComponentConvert.class);
+
+    default List<DecorateComponentDO> convertList(Integer type, List<DecorateComponentReqVO.ComponentReqVO> components) {
+        return CollectionUtils.convertList(components, c -> convert(type, c));
+    }
+
+    default DecorateComponentRespVO convert2(Integer type, List<DecorateComponentDO> doList) {
+        List<ComponentRespVO> components = CollectionUtils.convertList(doList, this::convert3);
+        return new DecorateComponentRespVO().setType(type).setComponents(components);
+    }
+
+    DecorateComponentDO convert(Integer type, DecorateComponentReqVO.ComponentReqVO reqVO);
+
+    ComponentRespVO convert3(DecorateComponentDO componentDO);
+
+    // ========== App convert ==========
+    default AppDecorateComponentRespVO appConvert(Integer type, List<DecorateComponentDO> doList) {
+        List<AppComponentRespVO> components = CollectionUtils.convertList(doList, this::appConvert2);
+        return new AppDecorateComponentRespVO().setType(type).setComponents(components);
+    }
+
+    AppComponentRespVO appConvert2(DecorateComponentDO componentDO);
+}

+ 0 - 45
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/convert/decorate/DecoratePageConvert.java

@@ -1,45 +0,0 @@
-package cn.iocoder.yudao.module.promotion.convert.decorate;
-
-import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
-import cn.iocoder.yudao.module.promotion.api.decorate.dto.PageComponentDTO;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageRespVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
-import cn.iocoder.yudao.module.promotion.enums.decorate.PageComponentEnum;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-import java.util.List;
-
-@Mapper
-public interface DecoratePageConvert {
-
-    DecoratePageConvert INSTANCE = Mappers.getMapper(DecoratePageConvert.class);
-
-    default List<PageDecorateDO> convert(Integer type, List<DecoratePageReqVO.ComponentReqVO> components) {
-        return CollectionUtils.convertList(components, c -> {
-            PageComponentEnum component = PageComponentEnum.getOfCode(c.getComponentCode());
-            if (component == null) {
-                return null;
-            }
-            return new PageDecorateDO().setComponentCode(c.getComponentCode())
-                    .setType(type).setComponentValue(c.getValue());
-        });
-    }
-
-    default DecoratePageRespVO convert2(Integer type, List<PageDecorateDO> doList) {
-        List<DecoratePageRespVO.ComponentRespVO> components = CollectionUtils.convertList(doList,
-                item -> {
-                    PageComponentEnum component = PageComponentEnum.getOfCode(item.getComponentCode());
-                    if (component == null) {
-                        return null;
-                    }
-                    @SuppressWarnings("rawtypes")
-                    PageComponentDTO dto = component.parsePageComponent(item.getComponentValue());
-                    return new DecoratePageRespVO.ComponentRespVO()
-                            .setTitle(dto.getTitle()).setStyle(dto.getStyle()).setComponentCode(item.getComponentCode())
-                            .setConfig(dto.getConfig()).setData(dto.getData());
-                });
-        return new DecoratePageRespVO().setType(type).setComponents(components);
-    }
-}

+ 6 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/decorate/PageDecorateDO.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/dataobject/decorate/DecorateComponentDO.java

@@ -3,20 +3,20 @@ package cn.iocoder.yudao.module.promotion.dal.dataobject.decorate;
 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
 import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum;
-import cn.iocoder.yudao.module.promotion.enums.decorate.PageComponentEnum;
+import cn.iocoder.yudao.module.promotion.enums.decorate.DecorateComponentEnum;
 import com.baomidou.mybatisplus.annotation.*;
 
 import lombok.Data;
 
 /**
- * 页面装修 DO
+ * 页面装修组件 DO, 一个页面由多个组件构成
  *
  * @author jason
  */
-@TableName(value ="promotion_page_decorate")
-@KeySequence("promotion_page_decorate_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@TableName(value ="promotion_decorate_component")
+@KeySequence("promotion_decorate_component_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
 @Data
-public class PageDecorateDO extends BaseDO {
+public class DecorateComponentDO extends BaseDO {
     /**
      * 编号
      */
@@ -31,7 +31,7 @@ public class PageDecorateDO extends BaseDO {
 
     /**
      *  组件编码
-     *  枚举 {@link PageComponentEnum#getCode()}
+     *  枚举 {@link DecorateComponentEnum#getCode()}
      */
     private String componentCode;
 

+ 4 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/decorate/PageDecorateMapper.java → yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/dal/mysql/decorate/DecorateComponentMapper.java

@@ -1,15 +1,15 @@
 package cn.iocoder.yudao.module.promotion.dal.mysql.decorate;
 
-import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
 
 @Mapper
-public interface PageDecorateMapper extends BaseMapperX<PageDecorateDO> {
-    default List<PageDecorateDO> selectByPageType(Integer type){
-        return selectList(PageDecorateDO::getType, type);
+public interface DecorateComponentMapper extends BaseMapperX<DecorateComponentDO> {
+    default List<DecorateComponentDO> selectByPageType(Integer type){
+        return selectList(DecorateComponentDO::getType, type);
     }
 }
 

+ 27 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentService.java

@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.promotion.service.decorate;
+
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
+import cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum;
+
+import java.util.List;
+
+/**
+ * 装修组件 Service 接口
+ *
+ * @author jason
+ */
+public interface DecorateComponentService {
+
+    /**
+     * 店铺装修页面保存
+     * @param reqVO 请求 VO
+     */
+    void pageSave(DecorateComponentReqVO reqVO);
+
+    /**
+     * 根据页面类型。获取页面的组件信息
+     * @param type 页面类型 {@link DecoratePageTypeEnum#getType()}
+     */
+    List<DecorateComponentDO> getPageComponents(Integer type);
+}

+ 45 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentServiceImpl.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.promotion.service.decorate;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentReqVO;
+import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecorateComponentReqVO.ComponentReqVO;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.decorate.DecorateComponentMapper;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.module.promotion.convert.decorate.DecorateComponentConvert.INSTANCE;
+
+/**
+ * 装修组件 Service 接口实现
+ * @author jason
+ */
+@Service
+public class DecorateComponentServiceImpl implements DecorateComponentService {
+    @Resource
+    private DecorateComponentMapper decorateComponentMapper;
+
+    @Override
+    public void pageSave(DecorateComponentReqVO reqVO) {
+        // 1.新增或修改页面组件
+        List<DecorateComponentDO> oldList = decorateComponentMapper.selectByPageType(reqVO.getType());
+
+        decorateComponentMapper.saveOrUpdateBatch(INSTANCE.convertList(reqVO.getType(), reqVO.getComponents()));
+        // 2.删除相关组件
+        Set<Long> deleteIds = convertSet(oldList, DecorateComponentDO::getId);
+        deleteIds.removeAll(convertSet(reqVO.getComponents(), ComponentReqVO::getId, vo->Objects.nonNull(vo.getId())));
+        if (CollUtil.isNotEmpty(deleteIds)) {
+            decorateComponentMapper.deleteBatchIds(deleteIds);
+        }
+    }
+
+    @Override
+    public List<DecorateComponentDO> getPageComponents(Integer type) {
+        return decorateComponentMapper.selectByPageType(type);
+    }
+}

+ 0 - 26
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageService.java

@@ -1,26 +0,0 @@
-package cn.iocoder.yudao.module.promotion.service.decorate;
-
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageRespVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
-
-import java.util.List;
-
-/**
- * 页面装修 Service 接口
- *
- * @author jason
- */
-public interface DecoratePageService {
-
-    /**
-     * 测试请求
-     */
-    List<PageDecorateDO> testReq(DecoratePageReqVO reqVO);
-
-    /**
-     * 测试响应
-     * @param type 页面类型
-     */
-    DecoratePageRespVO testResp(Integer type);
-}

+ 0 - 30
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageServiceImpl.java

@@ -1,30 +0,0 @@
-package cn.iocoder.yudao.module.promotion.service.decorate;
-
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageRespVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.decorate.PageDecorateMapper;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.List;
-
-import static cn.iocoder.yudao.module.promotion.convert.decorate.DecoratePageConvert.INSTANCE;
-
-/**
- * @author jason
- */
-@Service
-public class DecoratePageServiceImpl implements DecoratePageService {
-    @Resource
-    private PageDecorateMapper pageDecorateMapper;
-    @Override
-    public List<PageDecorateDO> testReq(DecoratePageReqVO reqVO) {
-        return INSTANCE.convert(reqVO.getType(), reqVO.getComponents());
-    }
-
-    @Override
-    public DecoratePageRespVO testResp(Integer type) {
-        return INSTANCE.convert2(type,pageDecorateMapper.selectByPageType(type));
-    }
-}

+ 45 - 0
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/decorate/DecorateComponentServiceImplTest.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.promotion.service.decorate;
+
+import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
+import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.DecorateComponentDO;
+import cn.iocoder.yudao.module.promotion.dal.mysql.decorate.DecorateComponentMapper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static cn.iocoder.yudao.module.promotion.enums.decorate.DecorateComponentEnum.ROLLING_BANNER;
+import static cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum.INDEX;
+import static org.mockito.ArgumentMatchers.eq;
+
+/**
+ * @author jason
+ */
+public class DecorateComponentServiceImplTest extends BaseMockitoUnitTest {
+
+    @InjectMocks
+    private DecorateComponentServiceImpl decoratePageService;
+
+    @Mock
+    private DecorateComponentMapper decorateComponentMapper;
+
+    @BeforeEach
+    public void init(){
+
+    }
+
+    @Test
+    void testResp(){
+        List<DecorateComponentDO> list = new ArrayList<>(1);
+        DecorateComponentDO decorateDO = new DecorateComponentDO()
+                .setType(INDEX.getType()).setComponentValue("")
+                .setComponentCode(ROLLING_BANNER.getCode()).setId(1L);
+        list.add(decorateDO);
+        //mock 方法
+        Mockito.when(decorateComponentMapper.selectByPageType(eq(1))).thenReturn(list);
+    }
+}

+ 0 - 83
yudao-module-mall/yudao-module-promotion-biz/src/test/java/cn/iocoder/yudao/module/promotion/service/decorate/DecoratePageServiceImplTest.java

@@ -1,83 +0,0 @@
-package cn.iocoder.yudao.module.promotion.service.decorate;
-
-import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
-import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
-import cn.iocoder.yudao.module.promotion.api.decorate.dto.CommonStyle;
-import cn.iocoder.yudao.module.promotion.api.decorate.dto.PageComponentDTO;
-import cn.iocoder.yudao.module.promotion.api.decorate.dto.RollingBannerComponent;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageReqVO;
-import cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo.DecoratePageRespVO;
-import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
-import cn.iocoder.yudao.module.promotion.dal.mysql.decorate.PageDecorateMapper;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.Mockito;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import static cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE;
-import static cn.iocoder.yudao.module.promotion.enums.decorate.DecoratePageTypeEnum.INDEX;
-import static cn.iocoder.yudao.module.promotion.enums.decorate.PageComponentEnum.ROLLING_BANNER;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.ArgumentMatchers.eq;
-
-/**
- * @author jason
- */
-public class DecoratePageServiceImplTest extends BaseMockitoUnitTest {
-
-    @InjectMocks
-    private DecoratePageServiceImpl decoratePageService;
-
-    @Mock
-    private PageDecorateMapper pageDecorateMapper;
-
-    private PageComponentDTO<RollingBannerComponent.Config,
-            CommonStyle,
-            List<RollingBannerComponent.DataStructure>> bannerComponent;
-    @BeforeEach
-    public void init(){
-        CommonStyle commonStyle = new CommonStyle();
-        RollingBannerComponent.DataStructure banner1 = new RollingBannerComponent.DataStructure().setImg("http://127.0.0.1:8084/a.jpg")
-                .setPath("/pages/coupon_center/coupon_center")
-                .setStatus(ENABLE.getStatus());
-        List<RollingBannerComponent.DataStructure> banners = new ArrayList<>(1);
-        banners.add(banner1);
-        bannerComponent
-                = new PageComponentDTO<RollingBannerComponent.Config, CommonStyle, List<RollingBannerComponent.DataStructure>>().setTitle("首页横幅广告")
-                .setConfig(new RollingBannerComponent.Config().setEnabled(Boolean.TRUE))
-                .setStyle(commonStyle)
-                .setData(banners);
-    }
-    @Test
-    void testReq() {
-        // 准备请求参数
-        DecoratePageReqVO.ComponentReqVO cReq = new DecoratePageReqVO.ComponentReqVO()
-                .setComponentCode(ROLLING_BANNER.getCode())
-                .setValue(JsonUtils.toJsonString(bannerComponent));
-        List<DecoratePageReqVO.ComponentReqVO> cReqList = new ArrayList<>();
-        cReqList.add(cReq);
-        DecoratePageReqVO reqVO = new DecoratePageReqVO();
-        reqVO.setType(1);
-        reqVO.setComponents(cReqList);
-        System.out.printf("请求数据:%s%n",JsonUtils.toJsonPrettyString(reqVO));
-        List<PageDecorateDO> list = decoratePageService.testReq(reqVO);
-        assertThat(list).hasSize(1);
-    }
-    @Test
-    void testResp(){
-        List<PageDecorateDO> list = new ArrayList<>(1);
-        PageDecorateDO decorateDO = new PageDecorateDO()
-                .setType(INDEX.getType()).setComponentValue(JsonUtils.toJsonString(bannerComponent))
-                .setComponentCode(ROLLING_BANNER.getCode()).setId(1L);
-        list.add(decorateDO);
-        //mock 方法
-        Mockito.when(pageDecorateMapper.selectByPageType(eq(1))).thenReturn(list);
-
-        DecoratePageRespVO respVO = decoratePageService.testResp(1);
-        System.out.printf("响应数据:%s%n",JsonUtils.toJsonPrettyString(respVO));
-    }
-}