diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TerminalApi.java b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TerminalApi.java index ac90b865..f615f265 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TerminalApi.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/feign/TerminalApi.java @@ -1,4 +1,66 @@ package cn.axzo.tyr.client.feign; +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.tyr.client.model.req.CloneTerminalReq; +import cn.axzo.tyr.client.model.req.CreateTerminalReq; +import cn.axzo.tyr.client.model.req.DeleteTerminalReq; +import cn.axzo.tyr.client.model.req.ListTerminalReq; +import cn.axzo.tyr.client.model.req.UpdateTerminalReq; +import cn.axzo.tyr.client.model.res.TerminalConfigRes; +import cn.axzo.tyr.client.model.res.TerminalRes; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; + +import java.util.List; + +@FeignClient(name = "tyr", url = "${axzo.service.tyr:http://tyr:8080}") public interface TerminalApi { + + /** + * 端的类型、业务类型查询 + */ + @PostMapping("/api/terminal/config/get") + ApiResult getConfig(); + + /** + * 端list接口 + * @param req + * @return + */ + @PostMapping("/api/terminal/list") + ApiResult> list(@RequestBody ListTerminalReq req); + + /** + * 新增端 + * @param req + * @return + */ + @PostMapping("/api/terminal/create") + ApiResult create(@RequestBody @Validated CreateTerminalReq req); + + /** + * 更新端 + * @param req + * @return + */ + @PostMapping("/api/terminal/update") + ApiResult update(@RequestBody @Validated UpdateTerminalReq req); + + /** + * 删除端 + * @param req + * @return + */ + @PostMapping("/api/terminal/delete") + ApiResult delete(@RequestBody @Validated DeleteTerminalReq req); + + /** + * 克隆端 + * @param req + * @return + */ + @PostMapping("/api/terminal/clone") + ApiResult clone(@RequestBody @Validated CloneTerminalReq req); } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java index 5b17780b..1d0274fb 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/base/FeatureResourceExtraDO.java @@ -1,5 +1,6 @@ package cn.axzo.tyr.client.model.base; +import com.alibaba.fastjson.JSONObject; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -27,4 +28,18 @@ public class FeatureResourceExtraDO implements Serializable { * 更多图标 */ private String moreIcon; + + /** + * 端类型:PC、APP + */ + private String terminalType; + + /** + * 端业务类型的code,用于业务处理:GOV:政务、AXZO_MANAGER:安心筑管理业务、AXZO_WORKER:安心筑工人业务、OMS:OMS管理 + */ + private String terminalBizType; + + public JSONObject toJSONObject() { + return JSONObject.parseObject(JSONObject.toJSONString(this)); + } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CloneTerminalReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CloneTerminalReq.java new file mode 100644 index 00000000..b7e65ec3 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CloneTerminalReq.java @@ -0,0 +1,31 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class CloneTerminalReq { + + @NotNull(message = "原端id不能为空") + private Long fromTerminalId; + + @NotBlank(message = "新端的名字不能为空") + private String newTerminalName; + + @NotBlank(message = "新端的code不能为空") + private String newTerminalCode; + + @NotBlank(message = "新端的页面编码前缀不能为空") + private String newTerminalFeatureCodePrefix; + + @NotNull(message = "操作人不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CreateTerminalReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CreateTerminalReq.java new file mode 100644 index 00000000..3da1d841 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/CreateTerminalReq.java @@ -0,0 +1,31 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class CreateTerminalReq { + + @NotBlank(message = "名字不能为空") + private String name; + + @NotBlank(message = "编码不能为空") + private String code; + + @NotBlank(message = "类型不能为空") + private String terminalType; + + @NotBlank(message = "业务类型不能为空") + private String terminalBizType; + + @NotNull(message = "操作人不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteTerminalReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteTerminalReq.java new file mode 100644 index 00000000..2ea51c16 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/DeleteTerminalReq.java @@ -0,0 +1,21 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class DeleteTerminalReq { + + @NotNull(message = "id不能为空") + private Long id; + + @NotNull(message = "操作人不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListTerminalReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListTerminalReq.java new file mode 100644 index 00000000..22c6dfcf --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListTerminalReq.java @@ -0,0 +1,17 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Set; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ListTerminalReq { + + private Set ids; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateTerminalReq.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateTerminalReq.java new file mode 100644 index 00000000..6f9c8dde --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/req/UpdateTerminalReq.java @@ -0,0 +1,29 @@ +package cn.axzo.tyr.client.model.req; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.NotNull; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class UpdateTerminalReq { + + @NotNull(message = "id不能为空") + private Long id; + + private String name; + + private String code; + + private String terminalType; + + private String terminalBizType; + + @NotNull(message = "操作人不能为空") + private Long operatorId; +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java index 3a812a46..2e50a545 100644 --- a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/SaasFeatureResourceResp.java @@ -12,6 +12,7 @@ import lombok.NoArgsConstructor; import java.util.Arrays; import java.util.Date; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -159,4 +160,10 @@ public class SaasFeatureResourceResp { .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet())) .orElseGet(Sets::newHashSet); } + + public static final Long ROOT_PARENT_ID = 0L; + + public boolean isRoot() { + return Objects.equals(this.getParentId(), ROOT_PARENT_ID); + } } diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalConfigRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalConfigRes.java new file mode 100644 index 00000000..dc659bdc --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalConfigRes.java @@ -0,0 +1,59 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TerminalConfigRes { + + /** + * 端类型:PC端、APP端 + */ + private List terminalTypes; + + /** + * 端业务类型 + */ + private List terminalBizTypes; + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class TerminalType { + + /** + * 端类型的中文描述,用于显示 + */ + private String desc; + + /** + * 端类型的code,用于业务处理:PC、APP + */ + private String code; + } + + @Data + @Builder + @AllArgsConstructor + @NoArgsConstructor + public static class TerminalBizType { + + /** + * 端业务类型的中文描述,用于显示 + */ + private String desc; + + /** + * 端业务类型的code,用于业务处理:GOV、AXZO_MANAGER、AXZO_WORKER、OMS + */ + private String code; + } +} diff --git a/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalRes.java b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalRes.java new file mode 100644 index 00000000..25ab7b09 --- /dev/null +++ b/tyr-api/src/main/java/cn/axzo/tyr/client/model/res/TerminalRes.java @@ -0,0 +1,23 @@ +package cn.axzo.tyr.client.model.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class TerminalRes { + + private Long id; + + private String name; + + private String code; + + private String terminalType; + + private String terminalBizType; +} diff --git a/tyr-server/pom.xml b/tyr-server/pom.xml index 4b79e636..db5e665d 100644 --- a/tyr-server/pom.xml +++ b/tyr-server/pom.xml @@ -156,6 +156,12 @@ braum-api 1.0.0-SNAPSHOT + + + cn.axzo.nanopart + config-api + 2.0.0-SNAPSHOT + diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/FeignConfig.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/FeignConfig.java index f3e49a69..0d4542d0 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/FeignConfig.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/FeignConfig.java @@ -44,6 +44,9 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware { @Value("${workspace:http://dev-app.axzo.cn/workspace}") private String workspaceUrl; + @Value("${nanopartUrl:http://dev-app.axzo.cn/nanopart}") + private String nanopartUrl; + private static String POD_NAMESPACE; static { Map env = System.getenv(); @@ -67,6 +70,7 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware { url = url.replace("http://pudge:10099", pudgeEnvUrl); url = url.replace("http://apisix-plat:8080", apisixUrl); url = url.replace("http://workspace:8080", workspaceUrl); + url = url.replace("http://nanopart:8080", nanopartUrl); String profile = environment.getProperty("spring.profiles.active"); if(Objects.equals(profile, "test") && url.contains("dev-app.axzo.cn")) { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java index ffa2ab5d..b716f792 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BizResultCode.java @@ -16,7 +16,7 @@ public enum BizResultCode implements IResultCode { WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空"), REMOVE_USER_ROLE_ERROR("100007", "删除用户角色数据异常"), DATA_ERROR("100008", "数据异常"), - FEATURE_CODE_EXIST("100009", "featureCode已经存在"), + FEATURE_CODE_EXIST("100009", "featureCode已经存在:{}"), PAGE_ELEMENT_ITEM_CODE_NOT_FOUND("100010", "资源分组不存在:{}"), PAGE_ELEMENT_ITEM_CODE_NOT_NULL("100011", "资源分组数据不存在"), PAGE_ELEMENT_GROUP_CODE_NOT_NULL("100012", "分组编码不能为空"), @@ -26,7 +26,9 @@ public enum BizResultCode implements IResultCode { PAGE_ELEMENT_CATEGORY_NOT_FOUND("100016", "资源分组数据不存在"), PAGE_ELEMENT_ERROR("100017", "资源分组错误:{}"), PAGE_CODE_DUPLICATE("100018", "资源元素code重复,重复的code:{}"), - PARAM_ERROR("100019", "参数错误"); + PARAM_ERROR("100019", "参数错误"), + FEATURE_NAME_EXIST("100020", "菜单组件名字已经存在:{}"), + TERMINAL_EXIST("100021", "新端已经存在:{}"); private String errorCode; diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BusinessExceptionResultHandler.java b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BusinessExceptionResultHandler.java new file mode 100644 index 00000000..303fe45b --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/config/exception/BusinessExceptionResultHandler.java @@ -0,0 +1,26 @@ +package cn.axzo.tyr.server.config.exception; + +import cn.axzo.foundation.exception.BusinessException; +import cn.axzo.framework.autoconfigure.web.exception.RespErrorCodeMappingProperties; +import cn.axzo.framework.autoconfigure.web.exception.handler.AbstractExceptionApiResultHandler; +import cn.axzo.framework.domain.web.code.IRespCode; +import cn.axzo.framework.domain.web.code.RespCode; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +@Component +public class BusinessExceptionResultHandler extends AbstractExceptionApiResultHandler { + public BusinessExceptionResultHandler(RespErrorCodeMappingProperties properties) { + super(properties); + } + + @Override + protected IRespCode decode(BusinessException ex, IRespCode fallbackCode) { + return new RespCode(ex.getErrorCode(), ex.getMessage()); + } + + @Override + protected HttpStatus mappingHttpStatus(String code, BusinessException ex) { + return HttpStatus.OK; + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/controller/terminal/TerminalController.java b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/terminal/TerminalController.java new file mode 100644 index 00000000..61ecd370 --- /dev/null +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/controller/terminal/TerminalController.java @@ -0,0 +1,145 @@ +package cn.axzo.tyr.server.controller.terminal; + +import cn.axzo.framework.domain.web.result.ApiResult; +import cn.axzo.framework.jackson.utility.JSON; +import cn.axzo.nanopart.api.ConfigApi; +import cn.axzo.nanopart.api.constant.enums.BizTypeEnum; +import cn.axzo.nanopart.api.response.ConfigResp; +import cn.axzo.tyr.client.common.enums.FeatureResourceType; +import cn.axzo.tyr.client.feign.TerminalApi; +import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; +import cn.axzo.tyr.client.model.req.CloneTerminalReq; +import cn.axzo.tyr.client.model.req.CreateTerminalReq; +import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; +import cn.axzo.tyr.client.model.req.DeleteTerminalReq; +import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; +import cn.axzo.tyr.client.model.req.ListTerminalReq; +import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq; +import cn.axzo.tyr.client.model.req.UpdateTerminalReq; +import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; +import cn.axzo.tyr.client.model.res.TerminalConfigRes; +import cn.axzo.tyr.client.model.res.TerminalRes; +import cn.axzo.tyr.server.service.SaasFeatureResourceService; +import cn.axzo.tyr.server.util.RpcInternalUtil; +import com.google.common.collect.Lists; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; + +import static cn.axzo.tyr.client.model.res.SaasFeatureResourceResp.ROOT_PARENT_ID; + +@Slf4j +@RestController +public class TerminalController implements TerminalApi { + @Autowired + private ConfigApi configApi; + @Autowired + private SaasFeatureResourceService featureResourceService; + + private static final String TERMINAL_CONFIG = "terminal.config"; + + @Override + public ApiResult getConfig() { + + + ConfigResp configByBizCode = RpcInternalUtil.rpcProcessor( + () -> configApi.getConfigByBizCode(TERMINAL_CONFIG, BizTypeEnum.BACKEND), + "查找端的业务配置配置", + TERMINAL_CONFIG, + BizTypeEnum.BACKEND) + .getData(); + if (Objects.isNull(configByBizCode) || Objects.isNull(configByBizCode.getContent())) { + return ApiResult.ok(); + } + + TerminalConfigRes terminalConfigRes = JSON.parseObject(configByBizCode.getContent(), TerminalConfigRes.class); + + return ApiResult.ok(terminalConfigRes); + } + + @Override + public ApiResult> list(ListTerminalReq req) { + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .ids(Lists.newArrayList(req.getIds())) + .build(); + List saasFeatureResources = featureResourceService.list(pageSaasFeatureResourceReq); + + return ApiResult.ok(saasFeatureResources.stream() + .map(e -> { + FeatureResourceExtraDO extra = e.getExtra(); + + return TerminalRes.builder() + .id(e.getId()) + .code(e.getTerminal()) + .name(e.getFeatureName()) + .terminalType(Optional.ofNullable(extra) + .map(FeatureResourceExtraDO::getTerminalType) + .orElse(null)) + .terminalBizType(Optional.ofNullable(extra) + .map(FeatureResourceExtraDO::getTerminalBizType) + .orElse(null)) + .build(); + }) + .collect(Collectors.toList())); + } + + @Override + public ApiResult create(CreateTerminalReq req) { + + FeatureResourceTreeSaveReq featureResourceTreeSaveReq = FeatureResourceTreeSaveReq.builder() + .parentId(ROOT_PARENT_ID) + .featureName(req.getName()) + .featureType(FeatureResourceType.ROOT.getCode()) + .uniCode(req.getCode()) + .operatorId(req.getOperatorId()) + .terminal(req.getCode()) + .extra(FeatureResourceExtraDO.builder() + .terminalType(req.getTerminalType()) + .terminalBizType(req.getTerminalBizType()) + .build()) + .build(); + Long id = featureResourceService.saveOrUpdateMenu(featureResourceTreeSaveReq); + return ApiResult.ok(id); + } + + @Override + public ApiResult update(UpdateTerminalReq req) { + FeatureResourceTreeSaveReq featureResourceTreeSaveReq = FeatureResourceTreeSaveReq.builder() + .id(req.getId()) + .featureName(req.getName()) + .uniCode(req.getCode()) + .operatorId(req.getOperatorId()) + .terminal(req.getCode()) + .extra(FeatureResourceExtraDO.builder() + .terminalType(req.getTerminalType()) + .terminalBizType(req.getTerminalBizType()) + .build()) + .build(); + featureResourceService.saveOrUpdateMenu(featureResourceTreeSaveReq); + return ApiResult.ok(); + } + + @Override + public ApiResult delete(DeleteTerminalReq req) { + + DeleteFeatureResourceReq deleteFeatureResourceReq = DeleteFeatureResourceReq.builder() + .featureId(req.getId()) + .operatorId(req.getOperatorId()) + .build(); + featureResourceService.deleteFeatureResource(deleteFeatureResourceReq); + return ApiResult.ok(); + } + + @Override + public ApiResult clone(CloneTerminalReq req) { + + featureResourceService.clone(req); + return ApiResult.ok(); + } +} diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java index a3420f41..10e11943 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasFeatureResource.java @@ -3,6 +3,7 @@ package cn.axzo.tyr.server.repository.entity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.hutool.core.util.StrUtil; +import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; @@ -15,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** @@ -208,4 +210,19 @@ public class SaasFeatureResource extends BaseEntity { private String desc; } + + public JSONObject normalizedExt() { + return Optional.ofNullable(this.getExtra()) + .map(FeatureResourceExtraDO::toJSONObject) + .orElseGet(JSONObject::new); + } + + public FeatureResourceExtraDO buildMergedExt(FeatureResourceExtraDO ext) { + if (Objects.isNull(ext)) { + return this.getExtra(); + } + + return JSONObject.toJavaObject(normalizedExt() + .fluentPutAll(ext.toJSONObject()), FeatureResourceExtraDO.class); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java index 46a2f880..a8ef4fe3 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/repository/entity/SaasPageElement.java @@ -171,7 +171,7 @@ public class SaasPageElement extends BaseEntity { } public JSONObject normalizedExt() { - return Optional.ofNullable(ext).orElse(new JSONObject()); + return Optional.ofNullable(ext).orElseGet(JSONObject::new); } public Ext covertToExt() { diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java index 1455ca4d..b5751f75 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/SaasFeatureResourceService.java @@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service; import cn.axzo.foundation.page.PageResp; import cn.axzo.tyr.client.model.permission.SaasFeatureBO; +import cn.axzo.tyr.client.model.req.CloneTerminalReq; import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; @@ -74,6 +75,8 @@ public interface SaasFeatureResourceService extends IService listAllFeatureByTerminal(String terminal); + void clone(CloneTerminalReq req); + @Data @Builder @NoArgsConstructor diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java index 7331e639..3210e40e 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasFeatureResourceServiceImpl.java @@ -8,7 +8,6 @@ import cn.axzo.foundation.dao.support.converter.PageConverter; import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.foundation.exception.Axssert; import cn.axzo.foundation.page.PageResp; -import cn.axzo.framework.domain.web.code.BaseCode; import cn.axzo.framework.rocketmq.Event; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; @@ -18,6 +17,7 @@ import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnu import cn.axzo.tyr.client.common.enums.RoleTypeEnum; import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.permission.SaasFeatureBO; +import cn.axzo.tyr.client.model.req.CloneTerminalReq; import cn.axzo.tyr.client.model.req.DeleteFeatureResourceReq; import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq; import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; @@ -35,7 +35,6 @@ import cn.axzo.tyr.client.model.res.PageElementBasicDTO; import cn.axzo.tyr.client.model.res.PageElementResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasRoleRes; -import cn.axzo.tyr.server.common.util.Throws; import cn.axzo.tyr.server.config.MqProducer; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.model.ResourcePermission; @@ -80,6 +79,7 @@ import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; @@ -93,7 +93,11 @@ import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.stream.Collectors; +import static cn.axzo.tyr.client.model.res.SaasFeatureResourceResp.ROOT_PARENT_ID; +import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_CODE_EXIST; +import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_NAME_EXIST; import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_RESOURCE_NOT_FOUND; +import static cn.axzo.tyr.server.config.exception.BizResultCode.TERMINAL_EXIST; import static cn.axzo.tyr.server.event.inner.EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT; import static cn.axzo.tyr.server.repository.entity.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; @@ -381,7 +385,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl exist = featureResourceDao.lambdaQuery() .eq(SaasFeatureResource::getUniCode, featureResource.getUniCode()) .eq(BaseEntity::getIsDelete, 0) - .one(); - if (exist != null && !exist.getId().equals(featureResource.getId())) { - Throws.bizException(BaseCode.BAD_REQUEST, featureResource.getFeatureName() + "-存在重复的权限码code"); - } + .ne(Objects.nonNull(featureResource.getId()), BaseEntity::getId, featureResource.getId()) + .list(); + Axssert.check(CollectionUtils.isEmpty(exist), FEATURE_CODE_EXIST, FEATURE_CODE_EXIST.getErrorMessage(), featureResource.getUniCode()); } void validFeatureName(SaasFeatureResource featureResource) { Assert.notNull(featureResource.getFeatureName(), "名称不能为空"); - SaasFeatureResource exist = featureResourceDao.lambdaQuery() + List exist = featureResourceDao.lambdaQuery() .eq(SaasFeatureResource::getParentId, featureResource.getParentId() == null ? 0 : featureResource.getParentId()) .eq(SaasFeatureResource::getTerminal, featureResource.getTerminal()) .eq(SaasFeatureResource::getFeatureName, featureResource.getFeatureName()) .eq(BaseEntity::getIsDelete, 0) - .one(); - if (exist != null && !exist.getId().equals(featureResource.getId())) { - Throws.bizException(BaseCode.BAD_REQUEST, featureResource.getFeatureName() + "-存在重复的名称"); - } + .ne(Objects.nonNull(featureResource.getId()), BaseEntity::getId, featureResource.getId()) + .list(); + Axssert.check(CollectionUtils.isEmpty(exist), FEATURE_NAME_EXIST, FEATURE_NAME_EXIST.getErrorMessage(), featureResource.getFeatureName()); } @Override @@ -1017,4 +1021,88 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl newFeatureResources = this.list(PageSaasFeatureResourceReq.builder() + .parentId(ROOT_PARENT_ID) + .terminal(req.getNewTerminalCode()) + .build()); + Axssert.check(CollectionUtils.isEmpty(newFeatureResources), TERMINAL_EXIST, TERMINAL_EXIST.getErrorMessage(), req.getNewTerminalCode()); + + PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder() + .parentId(req.getFromTerminalId()) + .build(); + List sourceFeatureResources = this.list(pageSaasFeatureResourceReq); + if (CollectionUtils.isEmpty(sourceFeatureResources)) { + return; + } + + // 因为要修改数据的path和parentId,所以必须先insert,再update + cloneInsert(sourceFeatureResources, req); + + // refresh path,parentId + cloneUpdate(sourceFeatureResources, req); + } + + private void cloneUpdate(List sourceFeatureResources, + CloneTerminalReq req) { + + List allNewFeatureResources = this.list(PageSaasFeatureResourceReq.builder() + .terminal(req.getNewTerminalCode()) + .build()); + Map newUnicodeMap = allNewFeatureResources.stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, Function.identity())); + + Map oldIdUnicodeMap = sourceFeatureResources.stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getId, SaasFeatureResourceResp::getUniCode)); + + Map unicodeParentUnicodeMap = sourceFeatureResources.stream() + .collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, e -> oldIdUnicodeMap.get(e.getParentId()))); + + SaasFeatureResource root = allNewFeatureResources.stream() + .filter(SaasFeatureResourceResp::isRoot) + .map(e -> { + SaasFeatureResource saasFeatureResource = new SaasFeatureResource(); + saasFeatureResource.setId(e.getId()); + saasFeatureResource.setPath(e.getId().toString() + ","); + return saasFeatureResource; + }) + .findFirst() + .get(); + List saasFeatureResources = Lists.newArrayList(root); + + this.updateBatchById(saasFeatureResources); + } + + private void cloneInsert(List sourceFeatureResources, + CloneTerminalReq req) { + List inserts = sourceFeatureResources.stream() + .map(e -> { + SaasFeatureResource saasFeatureResource = new SaasFeatureResource(); + + BeanUtils.copyProperties(e, saasFeatureResource); + saasFeatureResource.setId(null); + saasFeatureResource.setCreateAt(null); + saasFeatureResource.setUpdateAt(null); + saasFeatureResource.setTerminal(req.getNewTerminalCode()); + saasFeatureResource.setCreateBy(req.getOperatorId()); + saasFeatureResource.setUpdateBy(req.getOperatorId()); + // 端应该使用最新的code和名字,其他节点使用原始的名字,code增加前缀 + if (e.isRoot()) { + saasFeatureResource.setUniCode(req.getNewTerminalCode()); + saasFeatureResource.setFeatureCode(req.getNewTerminalCode()); + saasFeatureResource.setFeatureName(req.getNewTerminalName()); + } else { + saasFeatureResource.setUniCode(req.getNewTerminalFeatureCodePrefix() + ":" + e.getUniCode()); + saasFeatureResource.setFeatureCode(saasFeatureResource.getUniCode()); + saasFeatureResource.setFeatureName(e.getFeatureName()); + } + return saasFeatureResource; + }) + .collect(Collectors.toList()); + this.saveBatch(inserts); + } } diff --git a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java index f40b2acf..2ee41487 100644 --- a/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java +++ b/tyr-server/src/main/java/cn/axzo/tyr/server/service/impl/SaasPageElementServiceImpl.java @@ -1244,7 +1244,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl