页面装修数据结构定义

plp
jason 3 years ago
parent b0fcd96dfe
commit 6b1d996b66

@ -447,6 +447,25 @@ CREATE TABLE `trade_delivery_express` (
PRIMARY KEY (`id`) USING BTREE PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB COMMENT='快递公司'; ) ENGINE=InnoDB COMMENT='快递公司';
-- ----------------------------
-- 页面装修表结构
-- ----------------------------
DROP TABLE IF EXISTS `promotion_page_decorate`;
CREATE TABLE `promotion_page_decorate` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`type` int NOT NULL COMMENT '页面类型',
`component_code` varchar(64) NOT NULL COMMENT '组件编码',
`component_value` json NOT NULL COMMENT '组件值json 格式。包含配置和数据',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '状态',
`creator` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '创建者',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT '' COMMENT '更新者',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`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='页面装修';
SET FOREIGN_KEY_CHECKS = 1; SET FOREIGN_KEY_CHECKS = 1;
BEGIN; BEGIN;

@ -14,6 +14,7 @@ import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -72,6 +73,18 @@ public class JsonUtils {
} }
} }
public static <T> T parseObject(String text, Type type) {
if (StrUtil.isEmpty(text)) {
return null;
}
try {
return objectMapper.readValue(text, objectMapper.getTypeFactory().constructType(type));
} catch (IOException e) {
log.error("json parse err,json:{}", text, e);
throw new RuntimeException(e);
}
}
/** /**
* *
* 使 {@link #parseObject(String, Class)} @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) * 使 {@link #parseObject(String, Class)} @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)

@ -28,6 +28,13 @@
<artifactId>spring-boot-starter-validation</artifactId> <artifactId>spring-boot-starter-validation</artifactId>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<!-- 工具类中使用了 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<optional>true</optional>
</dependency>
</dependencies> </dependencies>
</project> </project>

@ -0,0 +1,12 @@
package cn.iocoder.yudao.module.promotion.api.decorate.dto;
import lombok.Data;
/**
* DTO. 使DTO
*
* @author jason
*/
@Data
public class CommonStyle {
}

@ -0,0 +1,52 @@
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,0 +1,39 @@
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,0 +1,25 @@
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,0 +1,43 @@
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;
}
}

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.promotion.enums.decorate;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
*
*
* @author jason
*/
@AllArgsConstructor
@Getter
public enum DecoratePageTypeEnum {
INDEX(1, "首页");
private final Integer type;
/**
*
*/
private final String name;
}

@ -0,0 +1,54 @@
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);
}
}

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

@ -0,0 +1,34 @@
package cn.iocoder.yudao.module.promotion.controller.admin.decorate.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
/**
* @author jason
*/
@Schema(description = "管理后台 - 页面装修 Resp VO")
@Data
public class DecoratePageRespVO {
@Schema(description = "页面类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer type;
@Schema(description = "页面组件", requiredMode = Schema.RequiredMode.REQUIRED, example = "TODO")
private List<ComponentRespVO> components;
@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 = "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;
}
}

@ -0,0 +1,45 @@
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);
}
}

@ -0,0 +1,48 @@
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 com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
/**
* DO
*
* @author jason
*/
@TableName(value ="promotion_page_decorate")
@KeySequence("promotion_page_decorate_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
@Data
public class PageDecorateDO extends BaseDO {
/**
*
*/
@TableId
private Long id;
/**
*
* {@link DecoratePageTypeEnum#getType()}
*/
private Integer type;
/**
*
* {@link PageComponentEnum#getCode()}
*/
private String componentCode;
/**
* json
*/
private String componentValue;
/**
*
* {@link CommonStatusEnum}
*/
private Integer status;
}

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.promotion.dal.mysql.decorate;
import cn.iocoder.yudao.module.promotion.dal.dataobject.decorate.PageDecorateDO;
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);
}
}

@ -0,0 +1,26 @@
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,0 +1,30 @@
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));
}
}

@ -0,0 +1,83 @@
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));
}
}
Loading…
Cancel
Save