Explorar o código

feat: 添加装修管理后台接口,暂不考虑使用

luofeiyun hai 7 meses
pai
achega
66732492ba
Modificáronse 32 ficheiros con 1474 adicións e 0 borrados
  1. 8 0
      ship-module-marketing/ship-module-marketing-api/src/main/java/com/yc/ship/module/marketing/enums/ErrorCodeConstants.java
  2. 39 0
      ship-module-marketing/ship-module-marketing-api/src/main/java/com/yc/ship/module/marketing/enums/diy/DiyPageEnum.java
  3. 100 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/DiyPageController.java
  4. 105 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/DiyTemplateController.java
  5. 29 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageBaseVO.java
  6. 14 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageCreateReqVO.java
  7. 28 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePageReqVO.java
  8. 20 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java
  9. 23 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java
  10. 22 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageRespVO.java
  11. 20 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageUpdateReqVO.java
  12. 26 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateBaseVO.java
  13. 14 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateCreateReqVO.java
  14. 35 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePageReqVO.java
  15. 26 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java
  16. 23 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java
  17. 28 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateRespVO.java
  18. 20 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateUpdateReqVO.java
  19. 39 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/AppDiyPageController.java
  20. 66 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/AppDiyTemplateController.java
  21. 23 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/vo/AppDiyPagePropertyRespVO.java
  22. 31 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java
  23. 37 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/convert/diy/DiyPageConvert.java
  24. 39 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/convert/diy/DiyTemplateConvert.java
  25. 57 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/dataobject/diy/DiyPageDO.java
  26. 64 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/dataobject/diy/DiyTemplateDO.java
  27. 39 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/mysql/diy/DiyPageMapper.java
  28. 36 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/mysql/diy/DiyTemplateMapper.java
  29. 83 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyPageService.java
  30. 129 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyPageServiceImpl.java
  31. 79 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyTemplateService.java
  32. 172 0
      ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyTemplateServiceImpl.java

+ 8 - 0
ship-module-marketing/ship-module-marketing-api/src/main/java/com/yc/ship/module/marketing/enums/ErrorCodeConstants.java

@@ -49,6 +49,14 @@ public interface ErrorCodeConstants {
     ErrorCode COUPON_PACKAGE_OVER_TIMES = new ErrorCode(1_005_001_019, "优惠券包剩余次数不足");
 
 
+    // ========== 装修模板 1-013-017-000 ==========
+    ErrorCode DIY_TEMPLATE_NOT_EXISTS = new ErrorCode(1_013_017_000, "装修模板不存在");
+    ErrorCode DIY_TEMPLATE_NAME_USED = new ErrorCode(1_013_017_001, "装修模板名称({})已经被使用");
+    ErrorCode DIY_TEMPLATE_USED_CANNOT_DELETE = new ErrorCode(1_013_017_002, "不能删除正在使用的装修模板");
+    // ========== 装修页面 1-013-018-000 ==========
+    ErrorCode DIY_PAGE_NOT_EXISTS = new ErrorCode(1_013_018_000, "装修页面不存在");
+    ErrorCode DIY_PAGE_NAME_USED = new ErrorCode(1_013_018_001, "装修页面名称({})已经被使用");
+
 
 
 }

+ 39 - 0
ship-module-marketing/ship-module-marketing-api/src/main/java/com/yc/ship/module/marketing/enums/diy/DiyPageEnum.java

@@ -0,0 +1,39 @@
+package com.yc.ship.module.marketing.enums.diy;
+
+import com.yc.ship.framework.common.core.IntArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 装修页面枚举
+ *
+ * @author jason
+ */
+@AllArgsConstructor
+@Getter
+public enum DiyPageEnum implements IntArrayValuable {
+
+    INDEX(1, "首页"),
+    MY(2, "我的"),
+    ;
+
+    private static final int[] ARRAYS = Arrays.stream(values()).mapToInt(DiyPageEnum::getPage).toArray();
+
+    /**
+     * 页面编号
+     */
+    private final Integer page;
+
+    /**
+     * 页面名称
+     */
+    private final String name;
+
+    @Override
+    public int[] array() {
+        return ARRAYS;
+    }
+
+}

+ 100 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/DiyPageController.java

@@ -0,0 +1,100 @@
+package com.yc.ship.module.marketing.controller.admin.diy;
+
+import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.*;
+import com.yc.ship.module.marketing.convert.diy.DiyPageConvert;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.service.diy.DiyPageService;
+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.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
+
+import static com.yc.ship.framework.common.pojo.CommonResult.success;
+
+
+@Tag(name = "管理后台 - 装修页面")
+@RestController
+@RequestMapping("/marketing/diy-page")
+@Validated
+public class DiyPageController {
+
+    @Resource
+    private DiyPageService diyPageService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建装修页面")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:create')")
+    public CommonResult<Long> createDiyPage(@Valid @RequestBody DiyPageCreateReqVO createReqVO) {
+        return success(diyPageService.createDiyPage(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新装修页面")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:update')")
+    public CommonResult<Boolean> updateDiyPage(@Valid @RequestBody DiyPageUpdateReqVO updateReqVO) {
+        diyPageService.updateDiyPage(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除装修页面")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:delete')")
+    public CommonResult<Boolean> deleteDiyPage(@RequestParam("id") Long id) {
+        diyPageService.deleteDiyPage(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得装修页面")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:query')")
+    public CommonResult<DiyPageRespVO> getDiyPage(@RequestParam("id") Long id) {
+        DiyPageDO diyPage = diyPageService.getDiyPage(id);
+        return success(DiyPageConvert.INSTANCE.convert(diyPage));
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获得装修页面列表")
+    @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:query')")
+    public CommonResult<List<DiyPageRespVO>> getDiyPageList(@RequestParam("ids") Collection<Long> ids) {
+        List<DiyPageDO> list = diyPageService.getDiyPageList(ids);
+        return success(DiyPageConvert.INSTANCE.convertList(list));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得装修页面分页")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:query')")
+    public CommonResult<PageResult<DiyPageRespVO>> getDiyPagePage(@Valid DiyPagePageReqVO pageVO) {
+        PageResult<DiyPageDO> pageResult = diyPageService.getDiyPagePage(pageVO);
+        return success(DiyPageConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    @GetMapping("/get-property")
+    @Operation(summary = "获得装修页面属性")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:query')")
+    public CommonResult<DiyPagePropertyRespVO> getDiyPageProperty(@RequestParam("id") Long id) {
+        DiyPageDO diyPage = diyPageService.getDiyPage(id);
+        return success(DiyPageConvert.INSTANCE.convertPropertyVo(diyPage));
+    }
+
+    @PutMapping("/update-property")
+    @Operation(summary = "更新装修页面属性")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-page:update')")
+    public CommonResult<Boolean> updateDiyPageProperty(@Valid @RequestBody DiyPagePropertyUpdateRequestVO updateReqVO) {
+        diyPageService.updateDiyPageProperty(updateReqVO);
+        return success(true);
+    }
+
+}

+ 105 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/DiyTemplateController.java

@@ -0,0 +1,105 @@
+package com.yc.ship.module.marketing.controller.admin.diy;
+
+import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.*;
+import com.yc.ship.module.marketing.convert.diy.DiyTemplateConvert;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+import com.yc.ship.module.marketing.service.diy.DiyPageService;
+import com.yc.ship.module.marketing.service.diy.DiyTemplateService;
+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.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static com.yc.ship.framework.common.pojo.CommonResult.success;
+
+
+@Tag(name = "管理后台 - 装修模板")
+@RestController
+@RequestMapping("/marketing/diy-template")
+@Validated
+public class DiyTemplateController {
+
+    @Resource
+    private DiyTemplateService diyTemplateService;
+    @Resource
+    private DiyPageService diyPageService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建装修模板")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:create')")
+    public CommonResult<Long> createDiyTemplate(@Valid @RequestBody DiyTemplateCreateReqVO createReqVO) {
+        return success(diyTemplateService.createDiyTemplate(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新装修模板")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:update')")
+    public CommonResult<Boolean> updateDiyTemplate(@Valid @RequestBody DiyTemplateUpdateReqVO updateReqVO) {
+        diyTemplateService.updateDiyTemplate(updateReqVO);
+        return success(true);
+    }
+
+    @PutMapping("/use")
+    @Operation(summary = "使用装修模板")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:use')")
+    public CommonResult<Boolean> useDiyTemplate(@RequestParam("id") Long id) {
+        diyTemplateService.useDiyTemplate(id);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除装修模板")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:delete')")
+    public CommonResult<Boolean> deleteDiyTemplate(@RequestParam("id") Long id) {
+        diyTemplateService.deleteDiyTemplate(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得装修模板")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:query')")
+    public CommonResult<DiyTemplateRespVO> getDiyTemplate(@RequestParam("id") Long id) {
+        DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
+        return success(DiyTemplateConvert.INSTANCE.convert(diyTemplate));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得装修模板分页")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:query')")
+    public CommonResult<PageResult<DiyTemplateRespVO>> getDiyTemplatePage(@Valid DiyTemplatePageReqVO pageVO) {
+        PageResult<DiyTemplateDO> pageResult = diyTemplateService.getDiyTemplatePage(pageVO);
+        return success(DiyTemplateConvert.INSTANCE.convertPage(pageResult));
+    }
+
+    // TODO @疯狂:这个要不和 getDiyTemplate 合并,然后 DiyTemplateRespVO 里面直接把 DiyPagePropertyRespVO 也加上。减少 VO 好了,管理后台 get 多返回点数据,也问题不大的。目的,还是想尽可能降低大家的理解成本哈;
+    @GetMapping("/get-property")
+    @Operation(summary = "获得装修模板属性")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:query')")
+    public CommonResult<DiyTemplatePropertyRespVO> getDiyTemplateProperty(@RequestParam("id") Long id) {
+        DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
+        List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(id);
+        return success(DiyTemplateConvert.INSTANCE.convertPropertyVo(diyTemplate, pages));
+    }
+
+    // TODO @疯狂:这个接口,要不和 useDiyTemplate 合并成一个,然后 VO 改成我们新的 VO 规范。不改的字段,就不传递。
+    @PutMapping("/update-property")
+    @Operation(summary = "更新装修模板属性")
+    @PreAuthorize("@ss.hasPermission('marketing:diy-template:update')")
+    public CommonResult<Boolean> updateDiyTemplateProperty(@Valid @RequestBody DiyTemplatePropertyUpdateRequestVO updateReqVO) {
+        diyTemplateService.updateDiyTemplateProperty(updateReqVO);
+        return success(true);
+    }
+
+}

+ 29 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageBaseVO.java

@@ -0,0 +1,29 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 装修页面 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class DiyPageBaseVO {
+
+    @Schema(description = "装修模板编号", example = "26179")
+    private Long templateId;
+
+    @Schema(description = "页面名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+    @NotNull(message = "页面名称不能为空")
+    private String name;
+
+    @Schema(description = "备注", example = "随便")
+    private String remark;
+
+    @Schema(description = "预览图")
+    private List<String> previewPicUrls;
+
+}

+ 14 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageCreateReqVO.java

@@ -0,0 +1,14 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 装修页面创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyPageCreateReqVO extends DiyPageBaseVO {
+
+}

+ 28 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePageReqVO.java

@@ -0,0 +1,28 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import com.yc.ship.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.yc.ship.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+
+@Schema(description = "管理后台 - 装修页面分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyPagePageReqVO extends PageParam {
+
+    @Schema(description = "页面名称", example = "王五")
+    private String name;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 20 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePropertyRespVO.java

@@ -0,0 +1,20 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 装修页面属性 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyPagePropertyRespVO extends DiyPageBaseVO {
+
+    @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    private Long id;
+
+    @Schema(description = "页面属性", example = "[]")
+    private String property;
+
+}

+ 23 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPagePropertyUpdateRequestVO.java

@@ -0,0 +1,23 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 装修页面属性更新 Request VO")
+@Data
+@ToString(callSuper = true)
+public class DiyPagePropertyUpdateRequestVO {
+
+    @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    @NotNull(message = "装修页面编号不能为空")
+    private Long id;
+
+    @Schema(description = "页面属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    @NotBlank(message = "页面属性不能为空")
+    private String property;
+
+}

+ 22 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageRespVO.java

@@ -0,0 +1,22 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 装修页面 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyPageRespVO extends DiyPageBaseVO {
+
+    @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12082")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+}

+ 20 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/page/DiyPageUpdateReqVO.java

@@ -0,0 +1,20 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.page;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 装修页面更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyPageUpdateReqVO extends DiyPageBaseVO {
+
+    @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "12082")
+    @NotNull(message = "装修页面编号不能为空")
+    private Long id;
+
+}

+ 26 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateBaseVO.java

@@ -0,0 +1,26 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * 装修模板 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class DiyTemplateBaseVO {
+
+    @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题")
+    @NotEmpty(message = "模板名称不能为空")
+    private String name;
+
+    @Schema(description = "备注", example = "默认主题")
+    private String remark;
+
+    @Schema(description = "预览图", example = "[https://www.iocoder.cn/1.jpg]")
+    private List<String> previewPicUrls;
+
+}

+ 14 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateCreateReqVO.java

@@ -0,0 +1,14 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 装修模板创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyTemplateCreateReqVO extends DiyTemplateBaseVO {
+
+}

+ 35 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePageReqVO.java

@@ -0,0 +1,35 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import com.yc.ship.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static com.yc.ship.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+
+@Schema(description = "管理后台 - 装修模板分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyTemplatePageReqVO extends PageParam {
+
+    @Schema(description = "模板名称", example = "默认主题")
+    private String name;
+
+    @Schema(description = "是否使用", example = "true")
+    private Boolean used;
+
+    @Schema(description = "使用时间", example = "使用时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] usedTime;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 26 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePropertyRespVO.java

@@ -0,0 +1,26 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePropertyRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 装修模板属性 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyTemplatePropertyRespVO extends DiyTemplateBaseVO {
+
+    @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    private Long id;
+
+    @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    private String property;
+
+    @Schema(description = "模板页面", requiredMode = Schema.RequiredMode.REQUIRED, example = "[]")
+    private List<DiyPagePropertyRespVO> pages;
+
+}

+ 23 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplatePropertyUpdateRequestVO.java

@@ -0,0 +1,23 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 装修模板属性更新 Request VO")
+@Data
+@ToString(callSuper = true)
+public class DiyTemplatePropertyUpdateRequestVO {
+
+    @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    @NotNull(message = "装修模板编号不能为空")
+    private Long id;
+
+    @Schema(description = "模板属性,JSON 格式", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    @NotBlank(message = "模板属性不能为空")
+    private String property;
+
+}

+ 28 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateRespVO.java

@@ -0,0 +1,28 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 装修模板 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyTemplateRespVO extends DiyTemplateBaseVO {
+
+    @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    private Long id;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    private LocalDateTime createTime;
+
+    @Schema(description = "是否使用", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+    private Boolean used;
+
+    @Schema(description = "使用时间", example = "使用时间")
+    private LocalDateTime usedTime;
+
+}

+ 20 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/admin/diy/vo/template/DiyTemplateUpdateReqVO.java

@@ -0,0 +1,20 @@
+package com.yc.ship.module.marketing.controller.admin.diy.vo.template;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 装修模板更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DiyTemplateUpdateReqVO extends DiyTemplateBaseVO {
+
+    @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    @NotNull(message = "装修模板编号不能为空")
+    private Long id;
+
+}

+ 39 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/AppDiyPageController.java

@@ -0,0 +1,39 @@
+package com.yc.ship.module.marketing.controller.app.diy;
+
+import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.framework.common.util.object.BeanUtils;
+import com.yc.ship.module.marketing.controller.app.diy.vo.AppDiyPagePropertyRespVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.service.diy.DiyPageService;
+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 com.yc.ship.framework.common.pojo.CommonResult.success;
+
+
+@Tag(name = "用户 APP - 装修页面")
+@RestController
+@RequestMapping("/marketing/diy-page")
+@Validated
+public class AppDiyPageController {
+
+    @Resource
+    private DiyPageService diyPageService;
+
+    @GetMapping("/get")
+    @Operation(summary = "获得装修页面")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    public CommonResult<AppDiyPagePropertyRespVO> getDiyPage(@RequestParam("id") Long id) {
+        DiyPageDO diyPage = diyPageService.getDiyPage(id);
+        return success(BeanUtils.toBean(diyPage, AppDiyPagePropertyRespVO.class));
+    }
+
+}

+ 66 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/AppDiyTemplateController.java

@@ -0,0 +1,66 @@
+package com.yc.ship.module.marketing.controller.app.diy;
+
+import com.yc.ship.framework.common.pojo.CommonResult;
+import com.yc.ship.module.marketing.controller.app.diy.vo.AppDiyTemplatePropertyRespVO;
+import com.yc.ship.module.marketing.convert.diy.DiyTemplateConvert;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+import com.yc.ship.module.marketing.enums.diy.DiyPageEnum;
+import com.yc.ship.module.marketing.service.diy.DiyPageService;
+import com.yc.ship.module.marketing.service.diy.DiyTemplateService;
+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 java.util.List;
+
+import static com.yc.ship.framework.common.pojo.CommonResult.success;
+import static com.yc.ship.framework.common.util.collection.CollectionUtils.findFirst;
+
+
+@Tag(name = "用户 APP - 装修模板")
+@RestController
+@RequestMapping("/marketing/diy-template")
+@Validated
+public class AppDiyTemplateController {
+
+    @Resource
+    private DiyTemplateService diyTemplateService;
+    @Resource
+    private DiyPageService diyPageService;
+
+    // TODO @疯狂:要不要把 used 和 get 接口合并哈;不传递 id,直接拿默认;
+    @GetMapping("/used")
+    @Operation(summary = "使用中的装修模板")
+    public CommonResult<AppDiyTemplatePropertyRespVO> getUsedDiyTemplate() {
+        DiyTemplateDO diyTemplate = diyTemplateService.getUsedDiyTemplate();
+        return success(buildVo(diyTemplate));
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得装修模板")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    public CommonResult<AppDiyTemplatePropertyRespVO> getDiyTemplate(@RequestParam("id") Long id) {
+        DiyTemplateDO diyTemplate = diyTemplateService.getDiyTemplate(id);
+        return success(buildVo(diyTemplate));
+    }
+
+    private AppDiyTemplatePropertyRespVO buildVo(DiyTemplateDO diyTemplate) {
+        if (diyTemplate == null) {
+            return null;
+        }
+        // 查询模板下的页面
+        List<DiyPageDO> pages = diyPageService.getDiyPageByTemplateId(diyTemplate.getId());
+        String home = findFirst(pages, page -> DiyPageEnum.INDEX.getName().equals(page.getName()), DiyPageDO::getProperty);
+        String user = findFirst(pages, page -> DiyPageEnum.MY.getName().equals(page.getName()), DiyPageDO::getProperty);
+        // 拼接返回
+        return DiyTemplateConvert.INSTANCE.convertPropertyVo2(diyTemplate, home, user);
+    }
+
+}

+ 23 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/vo/AppDiyPagePropertyRespVO.java

@@ -0,0 +1,23 @@
+package com.yc.ship.module.marketing.controller.app.diy.vo;
+
+import com.fasterxml.jackson.annotation.JsonRawValue;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+@Schema(description = "用户 App - 装修页面属性 Response VO")
+@Data
+@ToString(callSuper = true)
+public class AppDiyPagePropertyRespVO {
+
+    @Schema(description = "装修页面编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    private Long id;
+
+    @Schema(description = "页面名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+    private String name;
+
+    @Schema(description = "页面属性", example = "[]")
+    @JsonRawValue
+    private String property;
+
+}

+ 31 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/controller/app/diy/vo/AppDiyTemplatePropertyRespVO.java

@@ -0,0 +1,31 @@
+package com.yc.ship.module.marketing.controller.app.diy.vo;
+
+import com.fasterxml.jackson.annotation.JsonRawValue;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+@Schema(description = "用户 App - 装修模板属性 Response VO")
+@Data
+@ToString(callSuper = true)
+public class AppDiyTemplatePropertyRespVO {
+
+    @Schema(description = "装修模板编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "31209")
+    private Long id;
+
+    @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "默认主题")
+    private String name;
+
+    @Schema(description = "模板属性", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    @JsonRawValue
+    private String property;
+
+    @Schema(description = "首页", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    @JsonRawValue
+    private String home;
+
+    @Schema(description = "我的", requiredMode = Schema.RequiredMode.REQUIRED, example = "{}")
+    @JsonRawValue
+    private String user;
+
+}

+ 37 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/convert/diy/DiyPageConvert.java

@@ -0,0 +1,37 @@
+package com.yc.ship.module.marketing.convert.diy;
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.*;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 装修页面 Convert
+ *
+ * @author owen
+ */
+@Mapper
+public interface DiyPageConvert {
+
+    DiyPageConvert INSTANCE = Mappers.getMapper(DiyPageConvert.class);
+
+    DiyPageDO convert(DiyPageCreateReqVO bean);
+
+    DiyPageDO convert(DiyPageUpdateReqVO bean);
+
+    DiyPageRespVO convert(DiyPageDO bean);
+
+    List<DiyPageRespVO> convertList(List<DiyPageDO> list);
+
+    PageResult<DiyPageRespVO> convertPage(PageResult<DiyPageDO> page);
+
+    DiyPageCreateReqVO convertCreateVo(Long templateId, String name, String remark);
+
+    DiyPagePropertyRespVO convertPropertyVo(DiyPageDO diyPage);
+
+    DiyPageDO convert(DiyPagePropertyUpdateRequestVO updateReqVO);
+
+}

+ 39 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/convert/diy/DiyTemplateConvert.java

@@ -0,0 +1,39 @@
+package com.yc.ship.module.marketing.convert.diy;
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.*;
+import com.yc.ship.module.marketing.controller.app.diy.vo.AppDiyTemplatePropertyRespVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+import org.mapstruct.Mapper;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+/**
+ * 装修模板 Convert
+ *
+ * @author owen
+ */
+@Mapper
+public interface DiyTemplateConvert {
+
+    DiyTemplateConvert INSTANCE = Mappers.getMapper(DiyTemplateConvert.class);
+
+    DiyTemplateDO convert(DiyTemplateCreateReqVO bean);
+
+    DiyTemplateDO convert(DiyTemplateUpdateReqVO bean);
+
+    DiyTemplateRespVO convert(DiyTemplateDO bean);
+
+    List<DiyTemplateRespVO> convertList(List<DiyTemplateDO> list);
+
+    PageResult<DiyTemplateRespVO> convertPage(PageResult<DiyTemplateDO> page);
+
+    DiyTemplatePropertyRespVO convertPropertyVo(DiyTemplateDO diyTemplate, List<DiyPageDO> pages);
+
+    AppDiyTemplatePropertyRespVO convertPropertyVo2(DiyTemplateDO diyTemplate, String home, String user);
+
+    DiyTemplateDO convert(DiyTemplatePropertyUpdateRequestVO updateReqVO);
+
+}

+ 57 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/dataobject/diy/DiyPageDO.java

@@ -0,0 +1,57 @@
+package com.yc.ship.module.marketing.dal.dataobject.diy;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.yc.ship.framework.mybatis.core.dataobject.BaseDO;
+import com.yc.ship.framework.mybatis.core.type.StringListTypeHandler;
+import lombok.*;
+
+import java.util.List;
+
+/**
+ * 装修页面 DO
+ *
+ * @author owen
+ */
+@TableName(value = "marketing_diy_page", autoResultMap = true)
+@KeySequence("marketing_diy_page_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DiyPageDO extends BaseDO {
+
+    /**
+     * 装修页面编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 装修模板编号
+     *
+     * 关联 {@link DiyTemplateDO#getId()}
+     */
+    private Long templateId;
+    /**
+     * 页面名称
+     */
+    private String name;
+    /**
+     * 备注
+     */
+    private String remark;
+    /**
+     * 预览图,多个逗号分隔
+     */
+    @TableField(typeHandler = StringListTypeHandler.class)
+    private List<String> previewPicUrls;
+    /**
+     * 页面属性,JSON 格式
+     */
+    private String property;
+
+}

+ 64 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/dataobject/diy/DiyTemplateDO.java

@@ -0,0 +1,64 @@
+package com.yc.ship.module.marketing.dal.dataobject.diy;
+
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.yc.ship.framework.mybatis.core.dataobject.BaseDO;
+import com.yc.ship.framework.mybatis.core.type.StringListTypeHandler;
+import lombok.*;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+/**
+ * 装修模板 DO
+ *
+ * 1. 新建一个模版,下面可以包含多个 {@link DiyPageDO} 页面,例如说首页、我的
+ * 2. 如果需要使用某个模版,则将 {@link #used} 设置为 true,表示已使用,有且仅有一个
+ *
+ * @author owen
+ */
+@TableName(value = "marketing_diy_template", autoResultMap = true)
+@KeySequence("marketing_diy_template_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class DiyTemplateDO extends BaseDO {
+
+    /**
+     * 装修模板编号
+     */
+    @TableId
+    private Long id;
+    /**
+     * 模板名称
+     */
+    private String name;
+    /**
+     * 是否使用
+     */
+    private Boolean used;
+    /**
+     * 使用时间
+     */
+    private LocalDateTime usedTime;
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 预览图
+     */
+    @TableField(typeHandler = StringListTypeHandler.class)
+    private List<String> previewPicUrls;
+    /**
+     * uni-app 底部导航属性,JSON 格式
+     */
+    private String property;
+
+}

+ 39 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/mysql/diy/DiyPageMapper.java

@@ -0,0 +1,39 @@
+package com.yc.ship.module.marketing.dal.mysql.diy;
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.framework.mybatis.core.mapper.BaseMapperX;
+import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePageReqVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * 装修页面 Mapper
+ *
+ * @author owen
+ */
+@Mapper
+public interface DiyPageMapper extends BaseMapperX<DiyPageDO> {
+
+    default PageResult<DiyPageDO> selectPage(DiyPagePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<DiyPageDO>()
+                .likeIfPresent(DiyPageDO::getName, reqVO.getName())
+                .betweenIfPresent(DiyPageDO::getCreateTime, reqVO.getCreateTime())
+                // 模板下面的页面,在模板中管理
+                .isNull(DiyPageDO::getTemplateId)
+                .orderByDesc(DiyPageDO::getId));
+    }
+
+    default List<DiyPageDO> selectListByTemplateId(Long templateId) {
+        return selectList(DiyPageDO::getTemplateId, templateId);
+    }
+
+    default DiyPageDO selectByNameAndTemplateIdIsNull(String name) {
+        return selectOne(new LambdaQueryWrapperX<DiyPageDO>()
+                .eq(DiyPageDO::getName, name)
+                .isNull(DiyPageDO::getTemplateId));
+    }
+
+}

+ 36 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/dal/mysql/diy/DiyTemplateMapper.java

@@ -0,0 +1,36 @@
+package com.yc.ship.module.marketing.dal.mysql.diy;
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.framework.mybatis.core.mapper.BaseMapperX;
+import com.yc.ship.framework.mybatis.core.query.LambdaQueryWrapperX;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplatePageReqVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 装修模板 Mapper
+ *
+ * @author owen
+ */
+@Mapper
+public interface DiyTemplateMapper extends BaseMapperX<DiyTemplateDO> {
+
+    default PageResult<DiyTemplateDO> selectPage(DiyTemplatePageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<DiyTemplateDO>()
+                .likeIfPresent(DiyTemplateDO::getName, reqVO.getName())
+                .eqIfPresent(DiyTemplateDO::getUsed, reqVO.getUsed())
+                .betweenIfPresent(DiyTemplateDO::getUsedTime, reqVO.getUsedTime())
+                .betweenIfPresent(DiyTemplateDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(DiyTemplateDO::getUsed) // 排序规则1:已使用的排到最前面
+                .orderByDesc(DiyTemplateDO::getId)); // 排序规则2:新创建的排到前面
+    }
+
+    default DiyTemplateDO selectByUsed(boolean used) {
+        return selectOne(DiyTemplateDO::getUsed, used);
+    }
+
+    default DiyTemplateDO selectByName(String name) {
+        return selectOne(DiyTemplateDO::getName, name);
+    }
+
+}

+ 83 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyPageService.java

@@ -0,0 +1,83 @@
+package com.yc.ship.module.marketing.service.diy;
+
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPageCreateReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePageReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPageUpdateReqVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 装修页面 Service 接口
+ *
+ * @author owen
+ */
+public interface DiyPageService {
+
+    /**
+     * 创建装修页面
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createDiyPage(@Valid DiyPageCreateReqVO createReqVO);
+
+    /**
+     * 更新装修页面
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDiyPage(@Valid DiyPageUpdateReqVO updateReqVO);
+
+    /**
+     * 删除装修页面
+     *
+     * @param id 编号
+     */
+    void deleteDiyPage(Long id);
+
+    /**
+     * 获得装修页面
+     *
+     * @param id 编号
+     * @return 装修页面
+     */
+    DiyPageDO getDiyPage(Long id);
+
+    /**
+     * 获得装修页面列表
+     *
+     * @param ids 编号
+     * @return 装修页面列表
+     */
+    List<DiyPageDO> getDiyPageList(Collection<Long> ids);
+
+    /**
+     * 获得装修页面分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 装修页面分页
+     */
+    PageResult<DiyPageDO> getDiyPagePage(DiyPagePageReqVO pageReqVO);
+
+    /**
+     * 更新装修页面属性
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO);
+
+    /**
+     * 获得模板所属的页面列表
+     *
+     * @param templateId 模板编号
+     * @return 装修页面列表
+     */
+    List<DiyPageDO> getDiyPageByTemplateId(Long templateId);
+
+}

+ 129 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyPageServiceImpl.java

@@ -0,0 +1,129 @@
+package com.yc.ship.module.marketing.service.diy;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.ListUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPageCreateReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePageReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPagePropertyUpdateRequestVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.page.DiyPageUpdateReqVO;
+import com.yc.ship.module.marketing.convert.diy.DiyPageConvert;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyPageDO;
+import com.yc.ship.module.marketing.dal.mysql.diy.DiyPageMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.yc.ship.module.marketing.enums.ErrorCodeConstants.DIY_PAGE_NAME_USED;
+import static com.yc.ship.module.marketing.enums.ErrorCodeConstants.DIY_PAGE_NOT_EXISTS;
+
+/**
+ * 装修页面 Service 实现类
+ *
+ * @author owen
+ */
+@Service
+@Validated
+public class DiyPageServiceImpl implements DiyPageService {
+
+    @Resource
+    private DiyPageMapper diyPageMapper;
+
+    @Override
+    public Long createDiyPage(DiyPageCreateReqVO createReqVO) {
+        // 校验名称唯一
+        validateNameUnique(null, createReqVO.getTemplateId(), createReqVO.getName());
+        // 插入
+        DiyPageDO diyPage = DiyPageConvert.INSTANCE.convert(createReqVO);
+        diyPage.setProperty("{}");
+        diyPageMapper.insert(diyPage);
+        return diyPage.getId();
+    }
+
+    @Override
+    public void updateDiyPage(DiyPageUpdateReqVO updateReqVO) {
+        // 校验存在
+        validateDiyPageExists(updateReqVO.getId());
+        // 校验名称唯一
+        validateNameUnique(updateReqVO.getId(), updateReqVO.getTemplateId(), updateReqVO.getName());
+        // 更新
+        DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO);
+        diyPageMapper.updateById(updateObj);
+    }
+
+    /**
+     * 校验 Page 页面,在一个 template 模版下的名字是唯一的
+     *
+     * @param id Page 编号
+     * @param templateId 模版编号
+     * @param name Page 名字
+     */
+    void validateNameUnique(Long id, Long templateId, String name) {
+        if (templateId != null || StrUtil.isBlank(name)) {
+            return;
+        }
+        DiyPageDO page = diyPageMapper.selectByNameAndTemplateIdIsNull(name);
+        if (page == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的页面
+        if (id == null) {
+            throw exception(DIY_PAGE_NAME_USED, name);
+        }
+        if (!page.getId().equals(id)) {
+            throw exception(DIY_PAGE_NAME_USED, name);
+        }
+    }
+
+    @Override
+    public void deleteDiyPage(Long id) {
+        // 校验存在
+        validateDiyPageExists(id);
+        // 删除
+        diyPageMapper.deleteById(id);
+    }
+
+    private void validateDiyPageExists(Long id) {
+        if (diyPageMapper.selectById(id) == null) {
+            throw exception(DIY_PAGE_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public DiyPageDO getDiyPage(Long id) {
+        return diyPageMapper.selectById(id);
+    }
+
+    @Override
+    public List<DiyPageDO> getDiyPageList(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return ListUtil.empty();
+        }
+        return diyPageMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public PageResult<DiyPageDO> getDiyPagePage(DiyPagePageReqVO pageReqVO) {
+        return diyPageMapper.selectPage(pageReqVO);
+    }
+
+    @Override
+    public List<DiyPageDO> getDiyPageByTemplateId(Long templateId) {
+        return diyPageMapper.selectListByTemplateId(templateId);
+    }
+
+    @Override
+    public void updateDiyPageProperty(DiyPagePropertyUpdateRequestVO updateReqVO) {
+        // 校验存在
+        validateDiyPageExists(updateReqVO.getId());
+        // 更新
+        DiyPageDO updateObj = DiyPageConvert.INSTANCE.convert(updateReqVO);
+        diyPageMapper.updateById(updateObj);
+    }
+
+}

+ 79 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyTemplateService.java

@@ -0,0 +1,79 @@
+package com.yc.ship.module.marketing.service.diy;
+
+
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplatePageReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+
+import javax.validation.Valid;
+
+/**
+ * 装修模板 Service 接口
+ *
+ * @author owen
+ */
+public interface DiyTemplateService {
+
+    /**
+     * 创建装修模板
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createDiyTemplate(@Valid DiyTemplateCreateReqVO createReqVO);
+
+    /**
+     * 更新装修模板
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDiyTemplate(@Valid DiyTemplateUpdateReqVO updateReqVO);
+
+    /**
+     * 删除装修模板
+     *
+     * @param id 编号
+     */
+    void deleteDiyTemplate(Long id);
+
+    /**
+     * 获得装修模板
+     *
+     * @param id 编号
+     * @return 装修模板
+     */
+    DiyTemplateDO getDiyTemplate(Long id);
+
+    /**
+     * 获得装修模板分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 装修模板分页
+     */
+    PageResult<DiyTemplateDO> getDiyTemplatePage(DiyTemplatePageReqVO pageReqVO);
+
+    /**
+     * 使用装修模板
+     *
+     * @param id 编号
+     */
+    void useDiyTemplate(Long id);
+
+    /**
+     * 更新装修模板属性
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO);
+
+    /**
+     * 获取使用中的装修模板
+     *
+     * @return 装修模板
+     */
+    DiyTemplateDO getUsedDiyTemplate();
+
+}

+ 172 - 0
ship-module-marketing/ship-module-marketing-biz/src/main/java/com/yc/ship/module/marketing/service/diy/DiyTemplateServiceImpl.java

@@ -0,0 +1,172 @@
+package com.yc.ship.module.marketing.service.diy;
+
+import cn.hutool.core.util.BooleanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.yc.ship.framework.common.pojo.PageResult;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplateCreateReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplatePageReqVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplatePropertyUpdateRequestVO;
+import com.yc.ship.module.marketing.controller.admin.diy.vo.template.DiyTemplateUpdateReqVO;
+import com.yc.ship.module.marketing.convert.diy.DiyPageConvert;
+import com.yc.ship.module.marketing.convert.diy.DiyTemplateConvert;
+import com.yc.ship.module.marketing.dal.dataobject.diy.DiyTemplateDO;
+import com.yc.ship.module.marketing.dal.mysql.diy.DiyTemplateMapper;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static com.yc.ship.module.marketing.enums.ErrorCodeConstants.*;
+
+
+/**
+ * 装修模板 Service 实现类
+ *
+ * @author owen
+ */
+@Service
+@Validated
+public class DiyTemplateServiceImpl implements DiyTemplateService {
+
+    @Resource
+    private DiyTemplateMapper diyTemplateMapper;
+
+    @Resource
+    private DiyPageService diyPageService;
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public Long createDiyTemplate(DiyTemplateCreateReqVO createReqVO) {
+        // 校验名称唯一
+        validateNameUnique(null, createReqVO.getName());
+        // 插入
+        DiyTemplateDO diyTemplate = DiyTemplateConvert.INSTANCE.convert(createReqVO);
+        diyTemplate.setProperty("{}");
+        diyTemplateMapper.insert(diyTemplate);
+        // 创建默认页面
+        createDefaultPage(diyTemplate);
+        // 返回
+        return diyTemplate.getId();
+    }
+
+    /**
+     * 创建模板下面的默认页面
+     * 默认创建两个页面:首页、我的
+     *
+     * @param diyTemplate 模板对象
+     */
+    private void createDefaultPage(DiyTemplateDO diyTemplate) {
+        String remark = String.format("模板【%s】自动创建", diyTemplate.getName());
+        diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "首页", remark));
+        diyPageService.createDiyPage(DiyPageConvert.INSTANCE.convertCreateVo(diyTemplate.getId(), "我的", remark));
+    }
+
+    @Override
+    public void updateDiyTemplate(DiyTemplateUpdateReqVO updateReqVO) {
+        // 校验存在
+        validateDiyTemplateExists(updateReqVO.getId());
+        // 校验名称唯一
+        validateNameUnique(updateReqVO.getId(), updateReqVO.getName());
+        // 更新
+        DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO);
+        diyTemplateMapper.updateById(updateObj);
+    }
+
+    void validateNameUnique(Long id, String name) {
+        if (StrUtil.isBlank(name)) {
+            return;
+        }
+        DiyTemplateDO template = diyTemplateMapper.selectByName(name);
+        if (template == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的模板
+        if (id == null) {
+            throw exception(DIY_TEMPLATE_NAME_USED, name);
+        }
+        if (!template.getId().equals(id)) {
+            throw exception(DIY_TEMPLATE_NAME_USED, name);
+        }
+    }
+
+    @Override
+    public void deleteDiyTemplate(Long id) {
+        // 校验存在
+        DiyTemplateDO diyTemplateDO = validateDiyTemplateExists(id);
+        // 校验使用中
+        if (BooleanUtil.isTrue(diyTemplateDO.getUsed())) {
+            throw exception(DIY_TEMPLATE_USED_CANNOT_DELETE);
+        }
+        // 删除
+        diyTemplateMapper.deleteById(id);
+    }
+
+    private DiyTemplateDO validateDiyTemplateExists(Long id) {
+        DiyTemplateDO diyTemplateDO = diyTemplateMapper.selectById(id);
+        if (diyTemplateDO == null) {
+            throw exception(DIY_TEMPLATE_NOT_EXISTS);
+        }
+        return diyTemplateDO;
+    }
+
+    @Override
+    public DiyTemplateDO getDiyTemplate(Long id) {
+        return diyTemplateMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<DiyTemplateDO> getDiyTemplatePage(DiyTemplatePageReqVO pageReqVO) {
+        return diyTemplateMapper.selectPage(pageReqVO);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void useDiyTemplate(Long id) {
+        // 校验存在
+        validateDiyTemplateExists(id);
+        // TODO @疯狂:要不已使用的情况,抛个业务异常?
+        // 已使用的更新为未使用
+        DiyTemplateDO used = diyTemplateMapper.selectByUsed(true);
+        if (used != null) {
+            // 如果 id 相同,说明未发生变化
+            if (used.getId().equals(id)) {
+                return;
+            }
+            this.updateTemplateUsed(used.getId(), false, null);
+        }
+        // 更新为已使用
+        this.updateTemplateUsed(id, true, LocalDateTime.now());
+    }
+
+    /**
+     * 更新模板是否使用
+     *
+     * @param id       模板编号
+     * @param used     是否使用
+     * @param usedTime 使用时间
+     */
+    private void updateTemplateUsed(Long id, Boolean used, LocalDateTime usedTime) {
+        DiyTemplateDO updateObj = new DiyTemplateDO().setId(id)
+                .setUsed(used).setUsedTime(usedTime);
+        diyTemplateMapper.updateById(updateObj);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void updateDiyTemplateProperty(DiyTemplatePropertyUpdateRequestVO updateReqVO) {
+        // 校验存在
+        validateDiyTemplateExists(updateReqVO.getId());
+        // 更新模板属性
+        DiyTemplateDO updateObj = DiyTemplateConvert.INSTANCE.convert(updateReqVO);
+        diyTemplateMapper.updateById(updateObj);
+    }
+
+    @Override
+    public DiyTemplateDO getUsedDiyTemplate() {
+        return diyTemplateMapper.selectByUsed(true);
+    }
+
+}