feat: (feature/REQ-3167) 修改前端资源的bug,把business的异常抛出去

This commit is contained in:
李龙 2024-11-26 16:00:40 +08:00
parent 164ea1361a
commit ceb8fb1fb5
20 changed files with 605 additions and 19 deletions

View File

@ -1,4 +1,66 @@
package cn.axzo.tyr.client.feign; 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 { public interface TerminalApi {
/**
* 端的类型业务类型查询
*/
@PostMapping("/api/terminal/config/get")
ApiResult<TerminalConfigRes> getConfig();
/**
* 端list接口
* @param req
* @return
*/
@PostMapping("/api/terminal/list")
ApiResult<List<TerminalRes>> list(@RequestBody ListTerminalReq req);
/**
* 新增端
* @param req
* @return
*/
@PostMapping("/api/terminal/create")
ApiResult<Long> create(@RequestBody @Validated CreateTerminalReq req);
/**
* 更新端
* @param req
* @return
*/
@PostMapping("/api/terminal/update")
ApiResult<Void> update(@RequestBody @Validated UpdateTerminalReq req);
/**
* 删除端
* @param req
* @return
*/
@PostMapping("/api/terminal/delete")
ApiResult<Void> delete(@RequestBody @Validated DeleteTerminalReq req);
/**
* 克隆端
* @param req
* @return
*/
@PostMapping("/api/terminal/clone")
ApiResult<Void> clone(@RequestBody @Validated CloneTerminalReq req);
} }

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.client.model.base; package cn.axzo.tyr.client.model.base;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -27,4 +28,18 @@ public class FeatureResourceExtraDO implements Serializable {
* 更多图标 * 更多图标
*/ */
private String moreIcon; private String moreIcon;
/**
* 端类型PCAPP
*/
private String terminalType;
/**
* 端业务类型的code用于业务处理GOV:政务AXZO_MANAGER:安心筑管理业务AXZO_WORKER:安心筑工人业务OMS:OMS管理
*/
private String terminalBizType;
public JSONObject toJSONObject() {
return JSONObject.parseObject(JSONObject.toJSONString(this));
}
} }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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<Long> ids;
}

View File

@ -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;
}

View File

@ -12,6 +12,7 @@ import lombok.NoArgsConstructor;
import java.util.Arrays; import java.util.Arrays;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -159,4 +160,10 @@ public class SaasFeatureResourceResp {
.map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet())) .map(e -> Arrays.stream(e.split(",")).map(Long::valueOf).collect(Collectors.toSet()))
.orElseGet(Sets::newHashSet); .orElseGet(Sets::newHashSet);
} }
public static final Long ROOT_PARENT_ID = 0L;
public boolean isRoot() {
return Objects.equals(this.getParentId(), ROOT_PARENT_ID);
}
} }

View File

@ -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<TerminalType> terminalTypes;
/**
* 端业务类型
*/
private List<TerminalBizType> terminalBizTypes;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class TerminalType {
/**
* 端类型的中文描述用于显示
*/
private String desc;
/**
* 端类型的code用于业务处理PCAPP
*/
private String code;
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class TerminalBizType {
/**
* 端业务类型的中文描述用于显示
*/
private String desc;
/**
* 端业务类型的code用于业务处理GOVAXZO_MANAGERAXZO_WORKEROMS
*/
private String code;
}
}

View File

@ -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;
}

View File

@ -156,6 +156,12 @@
<artifactId>braum-api</artifactId> <artifactId>braum-api</artifactId>
<version>1.0.0-SNAPSHOT</version> <version>1.0.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>cn.axzo.nanopart</groupId>
<artifactId>config-api</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<build> <build>
<plugins> <plugins>

View File

@ -44,6 +44,9 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware {
@Value("${workspace:http://dev-app.axzo.cn/workspace}") @Value("${workspace:http://dev-app.axzo.cn/workspace}")
private String workspaceUrl; private String workspaceUrl;
@Value("${nanopartUrl:http://dev-app.axzo.cn/nanopart}")
private String nanopartUrl;
private static String POD_NAMESPACE; private static String POD_NAMESPACE;
static { static {
Map<String, String> env = System.getenv(); Map<String, String> env = System.getenv();
@ -67,6 +70,7 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware {
url = url.replace("http://pudge:10099", pudgeEnvUrl); url = url.replace("http://pudge:10099", pudgeEnvUrl);
url = url.replace("http://apisix-plat:8080", apisixUrl); url = url.replace("http://apisix-plat:8080", apisixUrl);
url = url.replace("http://workspace:8080", workspaceUrl); url = url.replace("http://workspace:8080", workspaceUrl);
url = url.replace("http://nanopart:8080", nanopartUrl);
String profile = environment.getProperty("spring.profiles.active"); String profile = environment.getProperty("spring.profiles.active");
if(Objects.equals(profile, "test") && url.contains("dev-app.axzo.cn")) { if(Objects.equals(profile, "test") && url.contains("dev-app.axzo.cn")) {

View File

@ -16,7 +16,7 @@ public enum BizResultCode implements IResultCode {
WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空"), WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空"),
REMOVE_USER_ROLE_ERROR("100007", "删除用户角色数据异常"), REMOVE_USER_ROLE_ERROR("100007", "删除用户角色数据异常"),
DATA_ERROR("100008", "数据异常"), 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_FOUND("100010", "资源分组不存在:{}"),
PAGE_ELEMENT_ITEM_CODE_NOT_NULL("100011", "资源分组数据不存在"), PAGE_ELEMENT_ITEM_CODE_NOT_NULL("100011", "资源分组数据不存在"),
PAGE_ELEMENT_GROUP_CODE_NOT_NULL("100012", "分组编码不能为空"), PAGE_ELEMENT_GROUP_CODE_NOT_NULL("100012", "分组编码不能为空"),
@ -26,7 +26,9 @@ public enum BizResultCode implements IResultCode {
PAGE_ELEMENT_CATEGORY_NOT_FOUND("100016", "资源分组数据不存在"), PAGE_ELEMENT_CATEGORY_NOT_FOUND("100016", "资源分组数据不存在"),
PAGE_ELEMENT_ERROR("100017", "资源分组错误:{}"), PAGE_ELEMENT_ERROR("100017", "资源分组错误:{}"),
PAGE_CODE_DUPLICATE("100018", "资源元素code重复,重复的code:{}"), PAGE_CODE_DUPLICATE("100018", "资源元素code重复,重复的code:{}"),
PARAM_ERROR("100019", "参数错误"); PARAM_ERROR("100019", "参数错误"),
FEATURE_NAME_EXIST("100020", "菜单组件名字已经存在:{}"),
TERMINAL_EXIST("100021", "新端已经存在:{}");
private String errorCode; private String errorCode;

View File

@ -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<BusinessException> {
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;
}
}

View File

@ -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<TerminalConfigRes> 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<TerminalRes>> list(ListTerminalReq req) {
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.ids(Lists.newArrayList(req.getIds()))
.build();
List<SaasFeatureResourceResp> 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<Long> 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<Void> 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<Void> delete(DeleteTerminalReq req) {
DeleteFeatureResourceReq deleteFeatureResourceReq = DeleteFeatureResourceReq.builder()
.featureId(req.getId())
.operatorId(req.getOperatorId())
.build();
featureResourceService.deleteFeatureResource(deleteFeatureResourceReq);
return ApiResult.ok();
}
@Override
public ApiResult<Void> clone(CloneTerminalReq req) {
featureResourceService.clone(req);
return ApiResult.ok();
}
}

View File

@ -3,6 +3,7 @@ package cn.axzo.tyr.server.repository.entity;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO; import cn.axzo.tyr.client.model.base.FeatureResourceExtraDO;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
@ -15,6 +16,7 @@ import org.apache.commons.lang3.StringUtils;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -208,4 +210,19 @@ public class SaasFeatureResource extends BaseEntity<SaasFeatureResource> {
private String desc; 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);
}
} }

View File

@ -171,7 +171,7 @@ public class SaasPageElement extends BaseEntity<SaasPageElement> {
} }
public JSONObject normalizedExt() { public JSONObject normalizedExt() {
return Optional.ofNullable(ext).orElse(new JSONObject()); return Optional.ofNullable(ext).orElseGet(JSONObject::new);
} }
public Ext covertToExt() { public Ext covertToExt() {

View File

@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp; import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.permission.SaasFeatureBO; 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.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq; import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq; import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
@ -74,6 +75,8 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
List<SaasFeatureBO> listAllFeatureByTerminal(String terminal); List<SaasFeatureBO> listAllFeatureByTerminal(String terminal);
void clone(CloneTerminalReq req);
@Data @Data
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor

View File

@ -8,7 +8,6 @@ import cn.axzo.foundation.dao.support.converter.PageConverter;
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper; import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.foundation.exception.Axssert; import cn.axzo.foundation.exception.Axssert;
import cn.axzo.foundation.page.PageResp; import cn.axzo.foundation.page.PageResp;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.framework.rocketmq.Event; import cn.axzo.framework.rocketmq.Event;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity; import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType; 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.common.enums.RoleTypeEnum;
import cn.axzo.tyr.client.model.enums.DelegatedType; import cn.axzo.tyr.client.model.enums.DelegatedType;
import cn.axzo.tyr.client.model.permission.SaasFeatureBO; 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.DeleteFeatureResourceReq;
import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq; import cn.axzo.tyr.client.model.req.DetailFeatureResourceReq;
import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq; 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.PageElementResp;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp; import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.client.model.res.SaasRoleRes; 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.config.MqProducer;
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload; import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.model.ResourcePermission; 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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@ -93,7 +93,11 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; 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.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.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.SaasFeatureResource.DEFAULT_WORKSPACE_TYPE;
import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE; import static cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation.NEW_FEATURE;
@ -381,7 +385,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
mqProducer.send(event); mqProducer.send(event);
} else { } else {
//补充path //补充path
SaasFeatureResource newValue = featureResourceDao.getById(baseResource.getId()); SaasFeatureResource oldValue = featureResourceDao.getById(baseResource.getId());
Axssert.notNull(oldValue, FEATURE_RESOURCE_NOT_FOUND);
if (Objects.nonNull(req.getParentId())) { if (Objects.nonNull(req.getParentId())) {
SaasFeatureResource parent = featureResourceDao.lambdaQuery().eq(SaasFeatureResource::getId,req.getParentId()).one(); SaasFeatureResource parent = featureResourceDao.lambdaQuery().eq(SaasFeatureResource::getId,req.getParentId()).one();
baseResource.setPath(StringUtils.isBlank(parent.getPath()) ? baseResource.getId().toString() + "," : parent.getPath() + baseResource.getId() + ","); baseResource.setPath(StringUtils.isBlank(parent.getPath()) ? baseResource.getId().toString() + "," : parent.getPath() + baseResource.getId() + ",");
@ -390,14 +395,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
baseResource.setPath(dbResource.getPath()); baseResource.setPath(dbResource.getPath());
} }
baseResource.setFeatureCode(req.getUniCode()); baseResource.setFeatureCode(req.getUniCode());
baseResource.setExtra(oldValue.buildMergedExt(req.getExtra()));
featureResourceDao.updateById(baseResource); featureResourceDao.updateById(baseResource);
Event event = Event.builder() Event event = Event.builder()
.targetType(TARGET_TYPE) .targetType(TARGET_TYPE)
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode()) .eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
.data(SaasFeatureResourceUpsertPayload.builder() .data(SaasFeatureResourceUpsertPayload.builder()
.oldValue(featureResourceDao.getById(baseResource.getId())) .oldValue(oldValue)
.newValue(newValue) .newValue(featureResourceDao.getById(baseResource.getId()))
.action(SaasFeatureResource.Action.UPDATE) .action(SaasFeatureResource.Action.UPDATE)
.build()) .build())
.build(); .build();
@ -647,26 +653,24 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
*/ */
void validFeatureCode(SaasFeatureResource featureResource) { void validFeatureCode(SaasFeatureResource featureResource) {
Assert.notNull(featureResource.getUniCode(), "权限码code不能为空"); Assert.notNull(featureResource.getUniCode(), "权限码code不能为空");
SaasFeatureResource exist = featureResourceDao.lambdaQuery() List<SaasFeatureResource> exist = featureResourceDao.lambdaQuery()
.eq(SaasFeatureResource::getUniCode, featureResource.getUniCode()) .eq(SaasFeatureResource::getUniCode, featureResource.getUniCode())
.eq(BaseEntity::getIsDelete, 0) .eq(BaseEntity::getIsDelete, 0)
.one(); .ne(Objects.nonNull(featureResource.getId()), BaseEntity::getId, featureResource.getId())
if (exist != null && !exist.getId().equals(featureResource.getId())) { .list();
Throws.bizException(BaseCode.BAD_REQUEST, featureResource.getFeatureName() + "-存在重复的权限码code"); Axssert.check(CollectionUtils.isEmpty(exist), FEATURE_CODE_EXIST, FEATURE_CODE_EXIST.getErrorMessage(), featureResource.getUniCode());
}
} }
void validFeatureName(SaasFeatureResource featureResource) { void validFeatureName(SaasFeatureResource featureResource) {
Assert.notNull(featureResource.getFeatureName(), "名称不能为空"); Assert.notNull(featureResource.getFeatureName(), "名称不能为空");
SaasFeatureResource exist = featureResourceDao.lambdaQuery() List<SaasFeatureResource> exist = featureResourceDao.lambdaQuery()
.eq(SaasFeatureResource::getParentId, featureResource.getParentId() == null ? 0 : featureResource.getParentId()) .eq(SaasFeatureResource::getParentId, featureResource.getParentId() == null ? 0 : featureResource.getParentId())
.eq(SaasFeatureResource::getTerminal, featureResource.getTerminal()) .eq(SaasFeatureResource::getTerminal, featureResource.getTerminal())
.eq(SaasFeatureResource::getFeatureName, featureResource.getFeatureName()) .eq(SaasFeatureResource::getFeatureName, featureResource.getFeatureName())
.eq(BaseEntity::getIsDelete, 0) .eq(BaseEntity::getIsDelete, 0)
.one(); .ne(Objects.nonNull(featureResource.getId()), BaseEntity::getId, featureResource.getId())
if (exist != null && !exist.getId().equals(featureResource.getId())) { .list();
Throws.bizException(BaseCode.BAD_REQUEST, featureResource.getFeatureName() + "-存在重复的名称"); Axssert.check(CollectionUtils.isEmpty(exist), FEATURE_NAME_EXIST, FEATURE_NAME_EXIST.getErrorMessage(), featureResource.getFeatureName());
}
} }
@Override @Override
@ -1017,4 +1021,88 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
return BeanMapper.mapList(saasFeatures, SaasFeatureBO.class); return BeanMapper.mapList(saasFeatures, SaasFeatureBO.class);
} }
@Override
@Transactional
public void clone(CloneTerminalReq req) {
List<SaasFeatureResourceResp> 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<SaasFeatureResourceResp> sourceFeatureResources = this.list(pageSaasFeatureResourceReq);
if (CollectionUtils.isEmpty(sourceFeatureResources)) {
return;
}
// 因为要修改数据的path和parentId所以必须先insert再update
cloneInsert(sourceFeatureResources, req);
// refresh pathparentId
cloneUpdate(sourceFeatureResources, req);
}
private void cloneUpdate(List<SaasFeatureResourceResp> sourceFeatureResources,
CloneTerminalReq req) {
List<SaasFeatureResourceResp> allNewFeatureResources = this.list(PageSaasFeatureResourceReq.builder()
.terminal(req.getNewTerminalCode())
.build());
Map<String, SaasFeatureResourceResp> newUnicodeMap = allNewFeatureResources.stream()
.collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, Function.identity()));
Map<Long, String> oldIdUnicodeMap = sourceFeatureResources.stream()
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, SaasFeatureResourceResp::getUniCode));
Map<String, String> 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<SaasFeatureResource> saasFeatureResources = Lists.newArrayList(root);
this.updateBatchById(saasFeatureResources);
}
private void cloneInsert(List<SaasFeatureResourceResp> sourceFeatureResources,
CloneTerminalReq req) {
List<SaasFeatureResource> 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);
}
} }

View File

@ -1244,7 +1244,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
}) })
.collect(Collectors.toList()); .collect(Collectors.toList());
this.updateBatchById(upsert); this.saveOrUpdateBatch(upsert);
// 1更新页面的code时需要把对应组件的groupCode都更新需要把菜单资源关联表的pageCode进行更新 // 1更新页面的code时需要把对应组件的groupCode都更新需要把菜单资源关联表的pageCode进行更新
// 2更新组件的code时需要把菜单资源关联表的pageCode进行更新 // 2更新组件的code时需要把菜单资源关联表的pageCode进行更新