Merge branch 'feature/REQ-3167' into 'release-20241211'

Feature/req 3167

See merge request universal/infrastructure/backend/tyr!375
This commit is contained in:
李龙 2024-12-10 08:14:00 +00:00
commit bba4ac2a5f
76 changed files with 3759 additions and 441 deletions

5
.reviewboardrc Normal file
View File

@ -0,0 +1,5 @@
REVIEWBOARD_URL = "https://reviewboard.axzo.cn/"
REPOSITORY = "tyr"
REPOSITORY_TYPE = "git"
BRANCH = "feature/REQ-3167"
LAND_DEST_BRANCH = "feature/REQ-3167"

View File

@ -0,0 +1,11 @@
package cn.axzo.tyr.client;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.tyr.client.model.req.GetTerminalInfoReq;
import java.util.Optional;
public interface TerminalClient {
Optional<TerminalInfo> getTerminalInfo(GetTerminalInfoReq param);
}

View File

@ -1,8 +1,10 @@
package cn.axzo.tyr.client.common.enums;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
@ -52,7 +54,7 @@ public enum FeatureResourceType {
}
public static List<Integer> navTypes() {
return Arrays.asList(FeatureResourceType.MENU.getCode(),
return Lists.newArrayList(FeatureResourceType.MENU.getCode(),
FeatureResourceType.PAGE.getCode(),
FeatureResourceType.APP_ENTRY.getCode(),
FeatureResourceType.ROOT.getCode(),
@ -60,7 +62,7 @@ public enum FeatureResourceType {
}
public static List<Integer> pageTypes() {
return Arrays.asList(
return Lists.newArrayList(
FeatureResourceType.PAGE.getCode(),
FeatureResourceType.APP_ENTRY.getCode());
}

View File

@ -0,0 +1,46 @@
package cn.axzo.tyr.client.common.util;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.function.Consumer;
import java.util.function.Supplier;
@Slf4j
public class RpcUtil {
/**
* 常用的RPC请求返回值解析如果 被请求方 返回非200会抛出异常
*/
public static <T> ApiResult<T> rpcProcessor(Supplier<ApiResult<T>> supplier, String operationType, Object... param) {
return rpcProcessorMayThrow(supplier, operationType, (commonResponse) -> {
throw new ServiceException(commonResponse.getMsg());
}, param);
}
public static <T> ApiResult<T> rpcProcessorMayThrow(Supplier<ApiResult<T>> supplier, String operationType, Consumer<ApiResult<T>> throwConsumer, Object... param) {
AssertUtil.notNull(throwConsumer, "自定义的异常处理不可为空");
log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
ApiResult<T> result = null;
try {
result = supplier.get();
} catch (Throwable e) {
throwConsumer.accept(ApiResult.err(e.getMessage()));
}
log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
Assert.notNull(result, "服务调用异常");
// 200自定义处理
if (HttpStatus.HTTP_OK != result.getCode()) {
throwConsumer.accept(result);
}
return result;
}
}

View File

@ -2,8 +2,26 @@ package cn.axzo.tyr.client.feign;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.*;
import cn.axzo.tyr.client.model.res.*;
import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.DeletePageElementReq;
import cn.axzo.tyr.client.model.req.GetPageElementReq;
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
import cn.axzo.tyr.client.model.req.IdReq;
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementImportDataReq;
import cn.axzo.tyr.client.model.req.PageElementReportReq;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
import cn.axzo.tyr.client.model.req.PageQueryElementV2Req;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq;
import cn.axzo.tyr.client.model.req.SyncPageElementReq;
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementCategoryAndElementResp;
import cn.axzo.tyr.client.model.res.PageElementRelationFeatureResourceResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -42,11 +60,11 @@ public interface PageElementApi {
ApiResult<GetUserHasPermissionPageElementResp> getUserHasPermissionPageElement(@RequestBody @Valid GetUserHasPermissionPageElementReq req);
@PostMapping("/api/pageElement/list")
ApiResult<List<PageElementResp>> list(PageElementReq param);
ApiResult<List<PageElementResp>> list(@RequestBody PageElementReq param);
/** 查询页面元素类型(按端分组) **/
@PostMapping("/api/pageElementCategory/list")
ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory();
ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory(@RequestBody PageElementCategoryReq req);
/** 新增、编辑页面元素类型 **/
@PostMapping("/api/pageElementCategory/saveOrUpdate")
@ -75,4 +93,12 @@ public interface PageElementApi {
/** 查询页面元素关联关系 **/
@PostMapping("/api/pageElement/importData")
ApiResult<Void> importData(@RequestBody @Valid List<PageElementImportDataReq> req);
/**
* 从基准环境把前端资源元素同步到当前环境
* @param req
* @return
*/
@PostMapping("/api/pageElement/sync")
ApiResult<Void> syncPageElement(@RequestBody @Valid SyncPageElementReq req);
}

View File

@ -0,0 +1,22 @@
package cn.axzo.tyr.client.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import org.springframework.cloud.openfeign.FeignClient;
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 PageElementCategoryApi {
/**
* 从基准环境查询分类信息
* @param req
* @return
*/
@PostMapping("/api/pageElementCategory/base/list")
ApiResult<List<ListPageElementCategoryResp>> listFromBase(@RequestBody PageElementCategoryReq req);
}

View File

@ -0,0 +1,76 @@
package cn.axzo.tyr.client.feign;
import cn.axzo.framework.auth.domain.TerminalInfo;
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.GetTerminalInfoReq;
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<TerminalConfigRes> getConfig();
/**
* 端list接口
* @param req
* @return
*/
@PostMapping("/api/terminal/list")
ApiResult<List<TerminalRes>> list(@RequestBody ListTerminalReq req);
/**
* 组装以前的端的信息为了兼容以前TerminalInfo的地方方便动态使用
* @param req
* @return
*/
@PostMapping("/api/terminalInfo/get")
ApiResult<TerminalInfo> getTerminalInfo(@RequestBody @Validated GetTerminalInfoReq 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

@ -0,0 +1,44 @@
package cn.axzo.tyr.client.impl;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.tyr.client.TerminalClient;
import cn.axzo.tyr.client.common.util.RpcUtil;
import cn.axzo.tyr.client.feign.TerminalApi;
import cn.axzo.tyr.client.model.req.GetTerminalInfoReq;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class TerminalClientImpl implements TerminalClient {
@Autowired
private TerminalApi terminalApi;
private LoadingCache<String, Optional<TerminalInfo>> terminalInfoCache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(100)
.build(new CacheLoader<String, Optional<TerminalInfo>>() {
@Override
public Optional<TerminalInfo> load(String terminalCode) {
GetTerminalInfoReq getTerminalInfoReq = GetTerminalInfoReq.builder()
.terminalCode(terminalCode)
.build();
return Optional.ofNullable(RpcUtil.rpcProcessor(() -> terminalApi.getTerminalInfo(getTerminalInfoReq),
"查询端的信息", getTerminalInfoReq).getData());
}
});
@Override
public Optional<TerminalInfo> getTerminalInfo(GetTerminalInfoReq param) {
return terminalInfoCache.getUnchecked(param.getTerminalCode());
}
}

View File

@ -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;
/**
* 端类型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,44 @@
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.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BatchUpsertPageElementCategoryReq {
@NotEmpty(message = "upsertPageElementCategories不能为空")
private List<UpsertPageElementCategory> upsertPageElementCategories;
@NotNull(message = "操作人不能为空")
private Long operatorId;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UpsertPageElementCategory {
private Long id;
/** 项目编码 **/
private String itemCode;
/** 项目名称 **/
@NotBlank(message = "项目名称不能为空")
private String itemName;
/** 登录端 **/
@NotBlank(message = "所属端不能为空")
private String terminal;
}
}

View File

@ -0,0 +1,105 @@
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.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BatchUpsertPageElementReq {
@NotEmpty(message = "upsertPageElementReqs不能为空")
private List<UpsertPageElementReq> upsertPageElementReqs;
@NotNull(message = "操作人不能为空")
private Long operatorId;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class UpsertPageElementReq {
private Long id;
/** 项目编码 **/
private String itemCode;
/** 分组ID **/
private String groupCode;
/** 页面元素类型PAGE/COMPONENT **/
@NotBlank(message = "页面元素类型不能为空")
private String type;
/** 项目编码 **/
@NotBlank(message = "项目编码不能为空")
private String code;
/** 元素名称 **/
@NotBlank(message = "元素名称不能为空")
private String name;
/** app类型APP:原生H5:h5页面, PC:web页面 **/
private String appType;
/** H5的appId **/
private String appId;
/** pc/h5路由地址 **/
private String linkUrl;
/** ios跳转地址 **/
private String iosRouterUrl;
/** android跳转地址 **/
private String androidRouterUrl;
/**
* 已经作废不能再使用现在分iosandroid的版本号
*/
@Deprecated
private Integer version;
/** 操作人personId **/
private Long operatorId;
/**
* ios 最低版本要求
*/
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* ios 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean iosMaxVersionEnabled;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* android 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean androidMaxVersionEnabled;
}
}

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

@ -39,4 +39,6 @@ public class GetFeatureResourceTreeReq {
*/
@Builder.Default
private Boolean needFilterBlankMenu = Boolean.FALSE;
private String uniCode;
}

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.NotBlank;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GetTerminalInfoReq {
/**
* 端的code
*/
@NotBlank(message = "terminalCode不能为空")
private String terminalCode;
}

View File

@ -75,11 +75,6 @@ public class IdentityAuthReq {
*/
private String itemCode;
/**
* 客户端版本号
*/
private Integer versionMax;
public void distinctOUWorkspacePair() {
if (CollectionUtil.isEmpty(this.workspaceOusPairs)) {
return;

View File

@ -54,6 +54,11 @@ public class ListPermissionFeatureReq {
*/
private Integer versionMax;
/**
* 客户端系统版本ANDROIDIOS
*/
private String system;
/**
* 查询菜单树节点类型
*/

View File

@ -0,0 +1,30 @@
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 {
/**
* 端的id
*/
private Set<Long> ids;
/**
* 端的code
*/
private String terminalCode;
/**
* 端业务类型的code用于业务处理GOVAXZO_MANAGERAXZO_WORKEROMS
*/
private String terminalBizType;
}

View File

@ -0,0 +1,18 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PageElementCategoryReq {
/**
* 是否需要查询分组下的页面元素
*/
private Boolean needPage;
}

View File

@ -0,0 +1,34 @@
package cn.axzo.tyr.client.model.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.IPageReq;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageElementCategoryV2Req implements IPageReq {
@CriteriaField(ignore = true)
Integer page;
@CriteriaField(ignore = true)
Integer pageSize;
/**
* 排序使用示例createTime__DESC
*/
@CriteriaField(ignore = true)
List<String> sort;
@CriteriaField(field = "itemCode", operator = Operator.IN)
private Set<String> itemCodes;
}

View File

@ -41,4 +41,16 @@ public class PageElementFeatureResourceRelationReq implements IPageReq {
@CriteriaField(ignore = true)
private Set<PageElementFeatureResourceRelationTypeEnum> types;
@CriteriaField(ignore = true)
private Boolean needPageElement;
@CriteriaField(ignore = true)
private Boolean needFeatureResource;
/**
* 需要跟needPageElement一起使用
*/
@CriteriaField(ignore = true)
private Boolean needPageElementCategory;
}

View File

@ -3,6 +3,7 @@ package cn.axzo.tyr.client.model.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.IPageReq;
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -34,4 +35,25 @@ public class PageElementReq implements IPageReq {
@CriteriaField(ignore = true)
private Boolean needFeatureSource;
@CriteriaField(field = "itemCode", operator = Operator.IN)
private Set<String> itemCodes;
@CriteriaField(field = "type", operator = Operator.IN)
private Set<PageElementTypeEnum> types;
@CriteriaField(field = "id", operator = Operator.IN)
private Set<Long> ids;
@CriteriaField(ignore = true)
private Boolean needChildren;
@CriteriaField(ignore = true)
private Boolean needPageElementCategory;
/**
* 现在只有组件的父节点是页面
*/
@CriteriaField(ignore = true)
private Boolean needAncestor;
}

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.client.model.req;
import cn.axzo.foundation.dao.support.mysql.MybatisPlusOperatorProcessor;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.page.IPageReq;
@ -42,6 +43,9 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(field = "authType", operator = Operator.EQ)
private Integer authType;
@CriteriaField(field = "featureName", operator = Operator.EQ)
private String featureName;
/**
* 资源所属端
*/
@ -54,6 +58,9 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(field = "featureType", operator = Operator.IN)
private List<Integer> featureResourceTypes;
@CriteriaField(field = "featureType", operator = Operator.EQ)
private Integer featureResourceType;
@CriteriaField(field = "path", operator = Operator.SW)
private String path;
@ -73,6 +80,9 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(field = "terminal", operator = Operator.IN)
private Set<String> terminals;
@CriteriaField(operator = Operator.JSON_QUERY, field = "extra")
private List<MybatisPlusOperatorProcessor.JSONQuery> terminalBizType;
@CriteriaField(ignore = true)
private Boolean needPageElement;
@ -85,6 +95,18 @@ public class PageSaasFeatureResourceReq implements IPageReq {
@CriteriaField(ignore = true)
private Set<PageElementFeatureResourceRelationTypeEnum> pageElementTypes;
/**
* 是否需要所有子节点
*/
@CriteriaField(ignore = true)
private Boolean needChildren;
/**
* 是否需要所有父节点
*/
@CriteriaField(ignore = true)
private Boolean needAncestor;
public PageResp toEmpty() {
return PageResp.builder()
.current(this.getPage())

View File

@ -55,9 +55,43 @@ public class SaveOrUpdatePageElementReq {
/** android跳转地址 **/
private String androidRouterUrl;
/** 版本号 **/
/**
* 已经作废不能再使用现在分iosandroid的版本号
*/
@Deprecated
private Integer version;
/** 操作人personId **/
private Long operatorId;
/**
* ios 最低版本要求
*/
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* ios 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean iosMaxVersionEnabled;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* android 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean androidMaxVersionEnabled;
}

View File

@ -0,0 +1,26 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Set;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SyncPageElementReq {
/**
* 分组下类型是PAGE的pageElement记录id同步时会把PAGE下的COMPONENT信息也一起同步
*/
@NotEmpty(message = "资源页面元素id不能为空")
private Set<Long> pageElementIds;
@NotNull(message = "操作人不能为空")
private Long operatorId;
}

View File

@ -59,6 +59,11 @@ public class TreePermissionReq {
*/
private Integer versionMax;
/**
* 客户端系统版本ANDROIDIOS
*/
private String system;
/**
* 查询父组件code下的有权限的uniCode
*/

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

@ -151,7 +151,9 @@ public class FeatureResourceDTO implements Serializable {
/**
* 最低版本序列,主要支持版本灰度策略
* 已经废弃不准确分iosandroid有各自的版本支持
*/
@Deprecated
private Integer version;
/**
@ -162,5 +164,36 @@ public class FeatureResourceDTO implements Serializable {
/**
* 页面元素对象
*/
@Deprecated
private List<PageElementBasicDTO> pageElements;
/**
* ios 最低版本要求
*/
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* ios 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean iosMaxVersionEnabled;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* android 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean androidMaxVersionEnabled;
}

View File

@ -35,6 +35,8 @@ public class FeatureResourceTreeNode extends FeatureResourceDTO implements IBase
*/
private List<Role> roles;
private List<PageElementFeatureResourceRelationResp> pageElementFeatureResourceRelationResps;
@Data
@Builder
@NoArgsConstructor

View File

@ -37,5 +37,11 @@ public class ListPageElementCategoryResp {
private String itemName;
/** 端 **/
private String terminal;
/**
* 分组下的页面元素
* 1needPage = true这里只有saas_page_element.type = PAGE的记录
*/
private List<PageElementResp> pageElement;
}
}

View File

@ -41,4 +41,34 @@ public class PageElementBasicDTO {
* @see cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum
*/
private Integer relationType;
/**
* ios 最低版本要求
*/
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* ios 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean iosMaxVersionEnabled;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* android 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean androidMaxVersionEnabled;
}

View File

@ -0,0 +1,48 @@
package cn.axzo.tyr.client.model.res;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageElementCategoryResp {
private Long id;
private Date createAt;
private Date updateAt;
private Long isDelete;
/**
* 创建人
*/
private Long createBy;
/**
* 更新人
*/
private Long updateBy;
/**
* 项目codeH5会拉取项目下所有的元素
*/
private String itemCode;
/**
* 项目名称
*/
private String itemName;
/**
* 所属端
*/
private String terminal;
}

View File

@ -0,0 +1,54 @@
package cn.axzo.tyr.client.model.res;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class PageElementFeatureResourceRelationResp {
private Long id;
private Date createAt;
private Date updateAt;
private Long isDelete;
private Integer type;
/**
* 创建人
*/
private Long createBy;
/**
* 更新人
*/
private Long updateBy;
/**
* 页面元素code
*/
private String pageElementCode;
/**
* 菜单组件code
*/
private String featureResourceUniCode;
/**
* 所属端
*/
private String terminal;
private PageElementResp pageElement;
private SaasFeatureResourceResp saasFeatureResource;
}

View File

@ -64,7 +64,9 @@ public class PageElementResp {
/**
* 客户端版本号
* 已经废弃
*/
@Deprecated
private Integer version;
/**
@ -95,6 +97,43 @@ public class PageElementResp {
/** android挑战地址 **/
private String androidRouterUrl;
/**
* ios 最低版本要求
*/
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* ios 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean iosMaxVersionEnabled;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* android 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean androidMaxVersionEnabled;
/**
* 所属的itemCode的分类
*/
private PageElementCategoryResp pageElementCategory;
private PageElementResp ancestor;
@Data
@Builder
@NoArgsConstructor

View File

@ -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;
@ -154,9 +155,25 @@ public class SaasFeatureResourceResp {
*/
private List<PageElementResp> saasPageElements;
/**
* 所有父节点
*/
private List<SaasFeatureResourceResp> ancestors;
/**
* 所有子节点
*/
private List<SaasFeatureResourceResp> children;
public Set<Long> resolvePath() {
return Optional.ofNullable(this.getPath())
.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);
}
}

View File

@ -0,0 +1,74 @@
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;
/**
* 是否允许克隆
*/
private Boolean allowClone;
/**
* DISABLED,ENABLED
*/
private String status;
/**
* 是否允许删除
*/
private Boolean allowDelete;
}
}

View File

@ -0,0 +1,39 @@
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 terminalTypeDesc;
private String terminalBizType;
private String terminalBizTypeDesc;
private Integer featureType;
/**
* 是否允许克隆
*/
private Boolean allowClone;
/**
* 是否允许删除
*/
private Boolean allowDelete;
}

View File

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

View File

@ -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<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://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")) {

View File

@ -14,7 +14,25 @@ public enum BizResultCode implements IResultCode {
REDIS_PRODUCT_NOT_NULL("100004", "产品不能为空"),
FEATURE_RESOURCE_NOT_FOUND("100005", "菜单资源不存在"),
WORKSPACE_ID_NOT_NULL("100006", "项目id不能为空"),
REMOVE_USER_ROLE_ERROR("100007", "删除用户角色数据异常");
REMOVE_USER_ROLE_ERROR("100007", "删除用户角色数据异常"),
DATA_ERROR("100008", "数据异常"),
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", "分组编码不能为空"),
PAGE_ELEMENT_GROUP_CODE_NOT_FOUND("100013", "页面元素不存在:{}"),
ITEM_NAME_DUPLICATE("100014", "资源分组名字重复,重复的名字:{}"),
ITEM_CODE_DUPLICATE("100015", "资源分组code重复,重复的code:{}"),
PAGE_ELEMENT_CATEGORY_NOT_FOUND("100016", "资源分组数据不存在"),
PAGE_ELEMENT_ERROR("100017", "资源分组错误:{}"),
PAGE_CODE_DUPLICATE("100018", "资源元素code重复,重复的code:{}"),
PARAM_ERROR("100019", "参数错误"),
FEATURE_NAME_EXIST("100020", "菜单组件名字已经存在:{}"),
TERMINAL_CODE_EXIST("100021", "端code已经存在请修改"),
TERMINAL_NOT_FOUND("100022", "原端不存在:{}"),
FEATURE_CODE_OVER_LENGTH("100023", "组件code不能超过100个字符:{}"),
TERMINAL_NAME_EXIST("100024", "端名字已经存在,请修改");
private String errorCode;
private String errorMessage;

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,73 @@
package cn.axzo.tyr.server.controller;
import cn.axzo.tyr.server.repository.dao.SaasPageElementDao;
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/private/pageElement")
public class PrivatePageElementController {
@Autowired
private SaasPageElementDao pageElementDao;
/**
* 刷新pageElement上的version到iosandroid的version
* @return
*/
@PostMapping("/version/refresh")
public Object refreshVersion() {
List<SaasPageElement> saasPageElements = pageElementDao.lambdaQuery().list();
if (CollectionUtils.isEmpty(saasPageElements)) {
return "ok";
}
List<SaasPageElement> updates = saasPageElements.stream()
.filter(e -> Objects.nonNull(e.getVersion()))
.map(e -> {
List<SaasPageElement.Application> applications = Lists.newArrayList();
applications.add(SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.IOS)
.minVersion(e.getVersion())
.build());
applications.add(SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.ANDROID)
.minVersion(e.getVersion())
.build());
SaasPageElement saasPageElement = SaasPageElement.builder()
.ext(SaasPageElement.Ext.builder()
.applications(applications)
.build()
.toJSONObject())
.build();
saasPageElement.setId(e.getId());
return saasPageElement;
})
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(updates)) {
return "ok";
}
pageElementDao.updateBatchById(updates);
return "ok";
}
}

View File

@ -0,0 +1,28 @@
package cn.axzo.tyr.server.controller.permission;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.feign.PageElementCategoryApi;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import cn.axzo.tyr.server.inner.feign.BasePageElementCategoryApi;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Slf4j
@RestController
public class PageElementCategoryController implements PageElementCategoryApi {
@Autowired
private BasePageElementCategoryApi basePageElementCategoryApi;
@Override
public ApiResult<List<ListPageElementCategoryResp>> listFromBase(PageElementCategoryReq req) {
return RpcInternalUtil.rpcProcessor(() -> basePageElementCategoryApi.listPageElementCategory(req),
"list pageElementCategory from base env", req);
}
}

View File

@ -3,8 +3,26 @@ package cn.axzo.tyr.server.controller.permission;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.feign.PageElementApi;
import cn.axzo.tyr.client.model.req.*;
import cn.axzo.tyr.client.model.res.*;
import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.DeletePageElementReq;
import cn.axzo.tyr.client.model.req.GetPageElementReq;
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
import cn.axzo.tyr.client.model.req.IdReq;
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementImportDataReq;
import cn.axzo.tyr.client.model.req.PageElementReportReq;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PageQueryElementReq;
import cn.axzo.tyr.client.model.req.PageQueryElementV2Req;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq;
import cn.axzo.tyr.client.model.req.SyncPageElementReq;
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementCategoryAndElementResp;
import cn.axzo.tyr.client.model.res.PageElementRelationFeatureResourceResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import lombok.RequiredArgsConstructor;
@ -59,8 +77,8 @@ public class PageElementController implements PageElementApi {
}
@Override
public ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory() {
return ApiResult.ok(saasPageElementCategoryService.listGroupByTerminal());
public ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory(PageElementCategoryReq req) {
return ApiResult.ok(saasPageElementCategoryService.listGroupByTerminal(req));
}
@Override
@ -101,4 +119,10 @@ public class PageElementController implements PageElementApi {
saasPageElementService.importData(req);
return ApiResult.ok();
}
@Override
public ApiResult<Void> syncPageElement(SyncPageElementReq req) {
saasPageElementService.syncPageElement(req);
return ApiResult.ok();
}
}

View File

@ -0,0 +1,216 @@
package cn.axzo.tyr.server.controller.terminal;
import cn.axzo.foundation.dao.support.mysql.MybatisPlusOperatorProcessor;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import cn.axzo.foundation.exception.Axssert;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.framework.domain.web.result.ApiResult;
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.GetTerminalInfoReq;
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.service.TerminalService;
import cn.hutool.json.JSONObject;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
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.TERMINAL_NAME_EXIST;
@Slf4j
@RestController
public class TerminalController implements TerminalApi {
@Autowired
private SaasFeatureResourceService featureResourceService;
@Autowired
private TerminalService terminalService;
private static final String GOV_BIZ_TYPE = "GOV";
private static final String PC_TYPE = "PC";
private static final String APP_TYPE = "APP";
@Override
public ApiResult<TerminalConfigRes> getConfig() {
return ApiResult.ok(terminalService.getConfig());
}
@Override
public ApiResult<List<TerminalRes>> list(ListTerminalReq req) {
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.ids(Optional.ofNullable(req.getIds())
.map(Lists::newArrayList)
.orElse(null))
.terminal(req.getTerminalCode())
.featureResourceType(FeatureResourceType.ROOT.getCode())
.terminalBizType(Optional.ofNullable(req.getTerminalBizType())
.map(e -> Lists.newArrayList(MybatisPlusOperatorProcessor.JSONQuery.builder()
.data(req.getTerminalBizType())
.operator(Operator.EQ)
.jsonPath("$.terminalBizType")
.build()))
.orElse(null))
.build();
List<SaasFeatureResourceResp> saasFeatureResources = featureResourceService.list(pageSaasFeatureResourceReq);
if (CollectionUtils.isEmpty(saasFeatureResources)) {
return ApiResult.ok();
}
Map<String, String> terminalTypes = terminalService.getConfig().getTerminalTypes().stream()
.collect(Collectors.toMap(TerminalConfigRes.TerminalType::getCode, TerminalConfigRes.TerminalType::getDesc));
Map<String, TerminalConfigRes.TerminalBizType> terminalBizTypes = terminalService.getConfig().getTerminalBizTypes().stream()
.collect(Collectors.toMap(TerminalConfigRes.TerminalBizType::getCode, Function.identity()));
return ApiResult.ok(saasFeatureResources.stream()
.map(e -> {
FeatureResourceExtraDO extra = e.getExtra();
String terminalTypeCode = Optional.ofNullable(extra)
.map(FeatureResourceExtraDO::getTerminalType)
.orElse(null);
String terminalBizTypeCode = Optional.ofNullable(extra)
.map(FeatureResourceExtraDO::getTerminalBizType)
.orElse(null);
TerminalConfigRes.TerminalBizType terminalBizType = terminalBizTypes.get(terminalBizTypeCode);
return TerminalRes.builder()
.id(e.getId())
.code(e.getTerminal())
.name(e.getFeatureName())
.terminalType(terminalTypeCode)
.terminalTypeDesc(Optional.ofNullable(terminalTypeCode)
.map(terminalTypes::get)
.orElse(null))
.terminalBizType(terminalBizTypeCode)
.terminalBizTypeDesc(Optional.ofNullable(terminalBizType)
.map(TerminalConfigRes.TerminalBizType::getDesc)
.orElse(null))
.allowClone(Optional.ofNullable(terminalBizType)
.map(TerminalConfigRes.TerminalBizType::getAllowClone)
.orElse(false))
.allowDelete(Optional.ofNullable(terminalBizType)
.map(TerminalConfigRes.TerminalBizType::getAllowDelete)
.orElse(false))
.featureType(e.getFeatureType())
.build();
})
.collect(Collectors.toList()));
}
private void checkTerminalName(CreateTerminalReq req) {
List<SaasFeatureResourceResp> newFeatureResources = featureResourceService.list(PageSaasFeatureResourceReq.builder()
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.ROOT.getCode()))
.featureName(req.getName())
.build());
Axssert.check(CollectionUtils.isEmpty(newFeatureResources), TERMINAL_NAME_EXIST);
}
@Override
public ApiResult<Long> create(CreateTerminalReq req) {
checkTerminalName(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();
}
@Override
public ApiResult<TerminalInfo> getTerminalInfo(GetTerminalInfoReq req) {
List<TerminalRes> terminalRes = this.list(ListTerminalReq.builder()
.terminalCode(req.getTerminalCode())
.build())
.getData();
// 找不到端有可能是以前的旧端设置的为了兼容直接使用原来的new TerminalInfo方式返回
if (CollectionUtils.isEmpty(terminalRes)) {
return ApiResult.ok(new TerminalInfo(req.getTerminalCode()));
}
if (terminalRes.size() > 1) {
log.warn("重复的端信息,{}", req.getTerminalCode());
}
return ApiResult.ok(terminalRes.stream()
.map(e -> {
Boolean isGov = Objects.equals(e.getTerminalBizType(), GOV_BIZ_TYPE);
TerminalInfo terminalInfo = new TerminalInfo(req.getTerminalCode());
terminalInfo.setNewTerminalString(req.getTerminalCode());
terminalInfo.setBizData(new JSONObject()
.putOpt("isGov", isGov)
.putOpt("isGovPC", isGov && Objects.equals(e.getTerminalType(), PC_TYPE)));
return terminalInfo;
})
.findFirst()
.orElse(null));
}
}

View File

@ -3,10 +3,13 @@ package cn.axzo.tyr.server.event.inner;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventHandler;
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@ -39,8 +42,22 @@ public class CacheSaasFeatureResourceHandler implements EventHandler, Initializi
log.info("end cached saasFeatureResource handler rocketmq event: {}", event);
}
public void onPageElementFeatureResourceUpsert(Event event, EventConsumer.Context context) {
PageElementFeatureResourceUpsertPayload payload = event.normalizedData(PageElementFeatureResourceUpsertPayload.class);
if (StringUtils.isBlank(payload.getTerminal())) {
return;
}
SaasFeatureResourceService.RefreshFeatureResourceCacheParam param = SaasFeatureResourceService.RefreshFeatureResourceCacheParam.builder()
.terminals(Sets.newHashSet(payload.getTerminal()))
.build();
saasFeatureResourceService.refreshCache(param);
}
@Override
public void afterPropertiesSet() throws Exception {
eventConsumer.registerHandler(EventTypeEnum.SAAS_FEATURE_RESOURCE_UPSERT.getEventCode(), this);
eventConsumer.registerHandler(EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode(), this::onPageElementFeatureResourceUpsert);
}
}

View File

@ -0,0 +1,17 @@
package cn.axzo.tyr.server.inner.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.res.PageElementResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = "tyr", url = "${axzo.service.base.tyr:https://pre-api.axzo.cn/tyr}")
public interface BasePageElementApi {
@PostMapping("/api/pageElement/list")
ApiResult<List<PageElementResp>> list(@RequestBody PageElementReq param);
}

View File

@ -0,0 +1,18 @@
package cn.axzo.tyr.server.inner.feign;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import java.util.List;
@FeignClient(name = "tyr", url = "${axzo.service.base.tyr:https://pre-api.axzo.cn/tyr}")
public interface BasePageElementCategoryApi {
/** 查询页面元素类型(按端分组) **/
@PostMapping("/api/pageElementCategory/list")
ApiResult<List<ListPageElementCategoryResp>> listPageElementCategory(@RequestBody PageElementCategoryReq req);
}

View File

@ -6,6 +6,7 @@ import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.Set;
/**
* @author likunpeng
@ -27,4 +28,9 @@ public class RelationOperateLogResourceBindRoleDO {
* 角色code列表
*/
private List<String> roleCodes;
/**
* 前端资源code列表
*/
private Set<String> pageElementCodes;
}

View File

@ -6,6 +6,7 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import java.util.List;
@ -33,7 +34,10 @@ public class SaasFeatureResourceDao extends ServiceImpl<SaasFeatureResourceMappe
SaasFeatureResource::getTerminal, SaasFeatureResource::getParentId,
SaasFeatureResource::getDisplayOrder,
SaasFeatureResource::getWorkspaceType,
SaasFeatureResource::getWorkspaceTypes)
SaasFeatureResource::getWorkspaceTypes,
SaasFeatureResource::getExtra,
SaasFeatureResource::getUniCode,
SaasFeatureResource::getPath)
.eq(SaasFeatureResource::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.in(CollectionUtils.isNotEmpty(req.getTerminals()), SaasFeatureResource::getTerminal, req.getTerminals())
.eq(Objects.nonNull(req.getStatus()), SaasFeatureResource::getStatus, req.getStatus())

View File

@ -71,14 +71,4 @@ public class SaasPageElementDao extends ServiceImpl<SaasPageElementMapper, SaasP
.set(SaasPageElement::getIsDelete, DeleteEnum.DELETE.getValue())
.update();
}
public void updateComponentsGroupCode(String oldGroupCode, String newGroupCode, String terminal) {
lambdaUpdate()
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue())
.eq(SaasPageElement::getTerminal, terminal)
.eq(SaasPageElement::getType, PageElementTypeEnum.COMPONENT.getCode())
.eq(SaasPageElement::getGroupCode, oldGroupCode)
.set(SaasPageElement::getGroupCode, newGroupCode)
.update();
}
}

View File

@ -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<SaasFeatureResource> {
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

@ -1,9 +1,26 @@
package cn.axzo.tyr.server.repository.entity;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.model.res.PageElementResp;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/**
* 页面元素表
@ -12,21 +29,24 @@ import lombok.*;
* @version 1.0
* @date 2024/6/18
*/
@Getter
@Setter
@ToString
@Data
@Builder
@EqualsAndHashCode(callSuper = true)
@TableName("saas_page_element")
@NoArgsConstructor
@AllArgsConstructor
@TableName(value = "saas_page_element", autoResultMap = true)
public class SaasPageElement extends BaseEntity<SaasPageElement> {
/**
* 客户端版本号
* @see cn.axzo.tyr.server.repository.entity.SaasPageElement.Application
*/
@Deprecated
private Integer version;
/**
* 元素的组编码
* type = PAGE时code跟groupCode一样
* type = COMPONENT时groupCode是对应 type = PAGE的code
*/
@TableField("group_code")
private String groupCode;
@ -87,6 +107,7 @@ public class SaasPageElement extends BaseEntity<SaasPageElement> {
/**
* 项目名称
*/
@Deprecated
@TableField("item_name")
private String itemName;
@ -94,4 +115,115 @@ public class SaasPageElement extends BaseEntity<SaasPageElement> {
* H5的应用ID
*/
private String appId;
/**
* 扩展字段
*/
@TableField(value = "ext", typeHandler = FastjsonTypeHandler.class)
private JSONObject ext;
/**
* 创建人
*/
private Long createBy;
/**
* 更新人
*/
private Long updateBy;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Ext {
/**
* 应用上的相关信息
*/
private List<Application> applications;
public JSONObject toJSONObject() {
return JSONObject.parseObject(JSONObject.toJSONString(this));
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public static class Application {
/**
* 端的系统iosandroid
*/
private ApplicationTypeEnum type;
/**
* 最低版本要求
*/
private Integer minVersion;
/**
* 最高版本要求
*/
private Integer maxVersion;
/**
* 是否开启最高版本要求:true-开启false-关闭
*/
private Boolean maxVersionEnabled;
}
public JSONObject normalizedExt() {
return Optional.ofNullable(ext).orElseGet(JSONObject::new);
}
public Ext covertToExt() {
return JSONObject.toJavaObject(normalizedExt(), Ext.class);
}
public JSONObject buildMergedExt(Ext ext) {
return normalizedExt()
.fluentPutAll(ext.toJSONObject());
}
@Getter
public enum ApplicationTypeEnum {
IOS,
ANDROID;
}
public PageElementResp to() {
PageElementResp pageElementResp = PageElementResp.builder().build();
BeanUtils.copyProperties(this, pageElementResp);
pageElementResp.setIosRouterUrl(pageElementResp.resolveIosRouterUrl());
pageElementResp.setAndroidRouterUrl(pageElementResp.resolveAndroidRouterUrl());
List<SaasPageElement.Application> applications = this.covertToExt().getApplications();
// 把这个平铺出去方便使用
if (CollectionUtils.isNotEmpty(applications)) {
SaasPageElement.Application iosApplication = applications.stream()
.filter(application -> Objects.equals(application.getType(), SaasPageElement.ApplicationTypeEnum.IOS))
.findFirst()
.orElse(null);
if (Objects.nonNull(iosApplication)) {
pageElementResp.setIosMinVersion(iosApplication.getMinVersion());
pageElementResp.setIosMaxVersion(iosApplication.getMaxVersion());
pageElementResp.setIosMaxVersionEnabled(iosApplication.getMaxVersionEnabled());
}
SaasPageElement.Application androidApplication = applications.stream()
.filter(application -> Objects.equals(application.getType(), SaasPageElement.ApplicationTypeEnum.ANDROID))
.findFirst()
.orElse(null);
if (Objects.nonNull(androidApplication)) {
pageElementResp.setAndroidMinVersion(androidApplication.getMinVersion());
pageElementResp.setAndroidMaxVersion(androidApplication.getMaxVersion());
pageElementResp.setAndroidMaxVersionEnabled(androidApplication.getMaxVersionEnabled());
}
}
return pageElementResp;
}
}

View File

@ -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;
@ -36,30 +37,40 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
void updateFeatureAuthType(Long featureId, Integer authType);
/**递归的**/
@Deprecated
List<SaasFeatureResource> batchListDescendant(List<Long> featureIds);
@Deprecated
SaasFeatureResource featureResourceById(Long featureId);
@Deprecated
FeatureResourceTreeNode getTreeFeatureDescendant(DetailFeatureResourceReq param);
/**菜单重排序**/
void reorderMenuFeature(Long featureId, Integer offset);
@Deprecated
/** 根据ID查询导航菜单页面信息 仅可显示 - 限制查询字段 **/
List<SaasFeatureResource> listNavByIds(List<Long> featureIds, List<Integer> featureTypes);
/** 资源权限通用查询 **/
@Deprecated
List<ResourcePermission> permissionQuery(ResourcePermissionQueryDTO param);
/** 查询资源树 **/
@Deprecated
List<FeatureResourceTreeNode> getTree(GetFeatureResourceTreeReq req);
@Deprecated
SaasFeatureResource getByCode(String featureCode);
@Deprecated
Set<Long> listAuthFree();
@Deprecated
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
@Deprecated
List<SaasFeatureResource> listByParentIdAndBlurTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
List<SaasFeatureResourceResp> list(PageSaasFeatureResourceReq param);
@ -72,8 +83,11 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
void refreshCache(RefreshFeatureResourceCacheParam param);
@Deprecated
List<SaasFeatureBO> listAllFeatureByTerminal(String terminal);
void clone(CloneTerminalReq req);
@Data
@Builder
@NoArgsConstructor
@ -125,10 +139,24 @@ public interface SaasFeatureResourceService extends IService<SaasFeatureResource
private String uniCode;
/**
* 客户端版本号
* 在根据版本号查询菜单树限的时候需要
* ios 最低版本要求
*/
private Integer version;
private Integer iosMinVersion;
/**
* ios 最高版本要求
*/
private Integer iosMaxVersion;
/**
* android 最低版本要求
*/
private Integer androidMinVersion;
/**
* android 最高版本要求
*/
private Integer androidMaxVersion;
/**
* 1展示

View File

@ -1,8 +1,18 @@
package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.BatchUpsertPageElementCategoryReq;
import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementCategoryV2Req;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementCategoryResp;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@ -11,11 +21,18 @@ import java.util.List;
* @version 1.0
* @date 2024/8/20
*/
public interface SaasPageElementCategoryService {
public interface SaasPageElementCategoryService extends IService<SaasPageElementCategory> {
List<ListPageElementCategoryResp> listGroupByTerminal();
@Deprecated
List<ListPageElementCategoryResp> listGroupByTerminal(PageElementCategoryReq req);
Long saveOrUpdate(SaveOrUpdatePageElementCategoryReq req);
void delete(DeletePageElementCategoryReq req);
void batchUpsert(BatchUpsertPageElementCategoryReq req);
List<PageElementCategoryResp> list(PageElementCategoryV2Req param);
PageResp<PageElementCategoryResp> page(PageElementCategoryV2Req param);
}

View File

@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import com.baomidou.mybatisplus.extension.service.IService;
@ -9,7 +10,7 @@ import java.util.List;
public interface SaasPageElementFeatureResourceRelationService extends IService<SaasPageElementFeatureResourceRelation> {
List<SaasPageElementFeatureResourceRelation> list(PageElementFeatureResourceRelationReq param);
List<PageElementFeatureResourceRelationResp> list(PageElementFeatureResourceRelationReq param);
PageResp<SaasPageElementFeatureResourceRelation> page(PageElementFeatureResourceRelationReq param);
PageResp<PageElementFeatureResourceRelationResp> page(PageElementFeatureResourceRelationReq param);
}

View File

@ -20,6 +20,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
*
* @param request 上报元素列表
*/
@Deprecated
void report(PageElementReportReq request);
/**
@ -28,6 +29,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
* @param request
* @return
*/
@Deprecated
List<PageElementResp> getPageElement(GetPageElementReq request);
/**
@ -37,6 +39,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
* @param featureResourceUniCodes 组件code
* @return
*/
@Deprecated
List<PageElementBasicDTO> getByTerminalAndUniCodes(String terminal, List<String> featureResourceUniCodes);
/**
@ -44,6 +47,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
*
* @param modifyPageElementRelation 关系对象
*/
@Deprecated
void modifyPageElementRelation(ModifyPageElementRelationDTO modifyPageElementRelation);
/**
@ -53,6 +57,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
* @param featureResourceUniCodes 组件code
* @param operatorId 操作人
*/
@Deprecated
void deleteRelationByTerminalAndUniCodes(String terminal, List<String> featureResourceUniCodes, Long operatorId);
/**
@ -61,6 +66,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
* @param request 查询条件
* @return
*/
@Deprecated
PageResp<PageElementCategoryAndElementResp> page(PageQueryElementReq request);
/**
@ -76,6 +82,7 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
cn.axzo.foundation.page.PageResp<PageElementResp> page(PageElementReq param);
@Deprecated
PageResp<PageElementResp> pageV2(PageQueryElementV2Req req);
Long saveOrUpdate(SaveOrUpdatePageElementReq req);
@ -85,4 +92,8 @@ public interface SaasPageElementService extends IService<SaasPageElement> {
List<PageElementRelationFeatureResourceResp> getFeatureResourceRelations(Long pageElementId);
void importData(List<PageElementImportDataReq> req);
void syncPageElement(SyncPageElementReq req);
List<Long> batchUpsert(BatchUpsertPageElementReq req);
}

View File

@ -0,0 +1,12 @@
package cn.axzo.tyr.server.service;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.tyr.client.model.req.GetTerminalInfoReq;
import cn.axzo.tyr.client.model.res.TerminalConfigRes;
public interface TerminalService {
TerminalConfigRes getConfig();
TerminalInfo getTerminalInfo(GetTerminalInfoReq param);
}

View File

@ -2,6 +2,7 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.constant.enums.DeleteEnum;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.basics.profiles.api.UserProfileServiceApi;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
@ -11,8 +12,12 @@ import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum;
import cn.axzo.tyr.client.model.enums.RolePermissionTagEnum;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.ResourceSyncReq;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import cn.axzo.tyr.server.config.MqProducer;
import cn.axzo.tyr.server.event.payload.RolePermissionCreatedPayload;
import cn.axzo.tyr.server.event.payload.SaasFeatureResourceUpsertPayload;
@ -30,6 +35,8 @@ import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelationOperateL
import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.service.FeatureResourceSyncService;
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import cn.azxo.framework.common.constatns.Constants;
@ -46,6 +53,7 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.MDC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@ -95,6 +103,8 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService;
private final UserProfileServiceApi userProfileServiceApi;
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
private final SaasPageElementService saasPageElementService;
@Qualifier("asyncExecutor")
@Autowired
@ -135,31 +145,71 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
}
Map<Long, List<FeatureResourceTreeNode.Role>> featureResourceRoleCodeMap = getFeatureResourceRoleCodeMap(allFeatureResourceIds);
Map<String, List<PageElementFeatureResourceRelationResp>> pageElementMap = listPageElement(resourceList);
List<FeatureResourceTreeNode> dtoList = BeanMapper.copyList(resourceList, FeatureResourceTreeNode.class);
dtoList.forEach(e -> {
List<FeatureResourceTreeNode.Role> roles = featureResourceRoleCodeMap.get(e.getId());
if (Objects.isNull(roles)) {
return;
if (Objects.nonNull(roles)) {
e.setRoleCodes(roles.stream()
.map(FeatureResourceTreeNode.Role::getRoleCode)
.distinct()
.collect(Collectors.toList()));
e.setRoles(roles);
}
e.setRoleCodes(roles.stream()
.map(FeatureResourceTreeNode.Role::getRoleCode)
.distinct()
.collect(Collectors.toList()));
e.setRoles(roles);
e.setPageElementFeatureResourceRelationResps(pageElementMap.get(e.getUniCode()));
});
return TreeUtil.buildTree(dtoList);
}
private Map<String, List<PageElementFeatureResourceRelationResp>> listPageElement(List<SaasFeatureResource> resourceList) {
if (CollectionUtils.isEmpty(resourceList)) {
return Collections.emptyMap();
}
Set<String> uniCodes = resourceList.stream()
.map(SaasFeatureResource::getUniCode)
.collect(Collectors.toSet());
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
.featureResourceUniCodes(uniCodes)
.needPageElement(true)
.build();
List<PageElementFeatureResourceRelationResp> pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq);
return pageElementFeatureResourceRelations.stream()
.filter(e -> e.getPageElement() != null)
.collect(Collectors.groupingBy(PageElementFeatureResourceRelationResp::getFeatureResourceUniCode));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void syncFromBase(ResourceSyncReq req) {
// TODO 删除代码同步处理但是改的比较多
req.setTraceId(MDC.get(Constants.CTX_LOG_ID_MDC));
if (req.getIds().size() > 1) {
//超过一个异步处理
CompletableFuture.runAsync(() -> doSyncFromBase(req), asyncExecutor).whenComplete((t, ex) -> saasFeatureResourceCacheService.clearCache());
// 同步这里不要求效率没有角色id全部刷新也不容易找这个
Event event = Event.builder()
.targetType(ROLE_PERMISSION_TARGET_TYPE)
.eventCode(ROLE_PERMISSION_CREATED.getEventCode())
.data(RolePermissionCreatedPayload.builder()
.build())
.build();
mqProducer.send(event);
return;
}
doSyncFromBase(req);
// 同步这里不要求效率没有角色id全部刷新也不容易找这个
Event event = Event.builder()
.targetType(ROLE_PERMISSION_TARGET_TYPE)
.eventCode(ROLE_PERMISSION_CREATED.getEventCode())
.data(RolePermissionCreatedPayload.builder()
.build())
.build();
mqProducer.send(event);
saasFeatureResourceCacheService.clearCache();
}
@ -169,13 +219,14 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
//处理数据缓存避免同级节点上级重复处理 - 上级code查询
final Map<Long, String> codeCache = new ConcurrentHashMap<>();
Set<Long> syncedRoleFeatureResourceIds = Sets.newConcurrentHashSet();
Set<Long> syncedPageElementFeatureResourceIds = Sets.newConcurrentHashSet();
Set<String> terminals = Sets.newHashSet();
try {
for (Long id : req.getIds()) {
//获取基准环境配置数据:同步某个ID的数据 需要同步处理它所有上级及下级组件
List<FeatureResourceTreeNode> syncList = RpcInternalUtil.rpcProcessor(() -> baseFeatureResourceApi.getSyncTreeById(id),
"get base sync tree by id", id).getData();
syncResourceProcess(syncList, codeCache, req.getOperatorId(), operateDos, syncedRoleFeatureResourceIds);
syncResourceProcess(syncList, codeCache, req.getOperatorId(), operateDos, syncedRoleFeatureResourceIds, syncedPageElementFeatureResourceIds);
terminals.addAll(syncList.stream()
.map(FeatureResourceTreeNode::getTerminal)
.collect(Collectors.toSet()));
@ -232,7 +283,8 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
}
private void syncResourceProcess(List<FeatureResourceTreeNode> syncList, Map<Long, String> codeCache, Long operatorId,
List<RelationOperateLogResourceBindRoleDO> operateDos, Set<Long> syncedRoleFeatureResourceIds) {
List<RelationOperateLogResourceBindRoleDO> operateDos, Set<Long> syncedRoleFeatureResourceIds,
Set<Long> syncedPageElementFeatureResourceIds) {
for (FeatureResourceTreeNode treeNode : syncList) {
if (codeCache.containsKey(treeNode.getId())) {
@ -240,7 +292,7 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
log.info("already sync resource:{}", treeNode.getId());
//递归子节点
if (CollectionUtils.isNotEmpty(treeNode.getChildren())) {
syncResourceProcess(treeNode.getChildren(), codeCache, operatorId, operateDos, syncedRoleFeatureResourceIds);
syncResourceProcess(treeNode.getChildren(), codeCache, operatorId, operateDos, syncedRoleFeatureResourceIds, syncedRoleFeatureResourceIds);
}
continue;
}
@ -301,9 +353,13 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
operateDos.add(logResourceBindRoleDO);
}
RelationOperateLogResourceBindRoleDO relationOperateLogResourceBindRoleDO = syncPageElement(baseResource, treeNode, operatorId, syncedPageElementFeatureResourceIds);
if (Objects.nonNull(relationOperateLogResourceBindRoleDO)) {
operateDos.add(relationOperateLogResourceBindRoleDO);
}
//递归子节点
if (CollectionUtils.isNotEmpty(treeNode.getChildren())) {
syncResourceProcess(treeNode.getChildren(), codeCache, operatorId, operateDos, syncedRoleFeatureResourceIds);
syncResourceProcess(treeNode.getChildren(), codeCache, operatorId, operateDos, syncedRoleFeatureResourceIds, syncedPageElementFeatureResourceIds);
}
}
}
@ -404,15 +460,73 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
logResourceBindRoleDO.setRoleCodes(saasRoles.stream().filter(e -> existRoleIds.contains(e.getId())).map(SaasRole::getRoleCode).collect(Collectors.toList()));
}
return logResourceBindRoleDO;
}
// 同步这里不要求效率没有角色id全部刷新也不容易找这个
Event event = Event.builder()
.targetType(ROLE_PERMISSION_TARGET_TYPE)
.eventCode(ROLE_PERMISSION_CREATED.getEventCode())
.data(RolePermissionCreatedPayload.builder()
.build())
private RelationOperateLogResourceBindRoleDO syncPageElement(SaasFeatureResource featureResource,
FeatureResourceTreeNode treeNode,
Long operatorId,
Set<Long> syncedPageElementFeatureResourceIds) {
if (Objects.isNull(featureResource)) {
return null;
}
// 同一FeatureResource如果已经处理过前端资源同步不再进行再次处理
if (syncedPageElementFeatureResourceIds.contains(featureResource.getId())) {
log.warn("sync role bind has handled,feature resource id:{}", featureResource.getId());
return null;
}
syncedPageElementFeatureResourceIds.add(featureResource.getId());
// 先清除资源绑定的角色 @20240723 产品武艳华要求资源绑定的前端资源以PRE角色为准
List<PageElementFeatureResourceRelationResp> oldData = saasPageElementFeatureResourceRelationService.list(PageElementFeatureResourceRelationReq.builder()
.featureResourceUniCodes(Sets.newHashSet(featureResource.getUniCode()))
.build());
if (CollectionUtils.isNotEmpty(oldData)) {
log.warn("sync menu delete PageElementFeatureResourceRelation operateId:{} featureResourceId:{}, PageElementFeatureResourceRelationIds:{}", operatorId, featureResource.getId(), oldData.stream().map(PageElementFeatureResourceRelationResp::getId).collect(Collectors.toList()));
saasPageElementFeatureResourceRelationDao.lambdaUpdate()
.in(SaasPageElementFeatureResourceRelation::getId, Lists.transform(oldData, PageElementFeatureResourceRelationResp::getId))
.set(SaasPageElementFeatureResourceRelation::getUpdateBy, operatorId)
.set(SaasPageElementFeatureResourceRelation::getIsDelete, TableIsDeleteEnum.DELETE.value)
.update();
}
// 操作日志
RelationOperateLogResourceBindRoleDO logResourceBindRoleDO = RelationOperateLogResourceBindRoleDO.builder()
.uniCode(featureResource.getUniCode())
.build();
mqProducer.send(event);
Set<String> pageElementCodes = CollectionUtils.emptyIfNull(treeNode.getPageElementFeatureResourceRelationResps()).stream()
.map(PageElementFeatureResourceRelationResp::getPageElementCode)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(pageElementCodes)) {
return logResourceBindRoleDO;
}
Set<String> localPageElementCodes = saasPageElementService.list(PageElementReq.builder()
.codes(pageElementCodes)
.build())
.stream()
.map(PageElementResp::getCode)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(localPageElementCodes)) {
return logResourceBindRoleDO;
}
// 只关联本地已经有的前端资源code
List<SaasPageElementFeatureResourceRelation> inserts = treeNode.getPageElementFeatureResourceRelationResps().stream()
.filter(e -> localPageElementCodes.contains(e.getPageElementCode()))
.map(e -> {
SaasPageElementFeatureResourceRelation result = SaasPageElementFeatureResourceRelation.builder().build();
BeanUtils.copyProperties(e, result);
result.setId(null);
return result;
})
.collect(Collectors.toList());
saasPageElementFeatureResourceRelationDao.saveBatch(inserts);
return logResourceBindRoleDO;
}
@ -456,37 +570,27 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
return Collections.emptyMap();
}
Map<Long, SaasRole> roleMap = roles.stream()
.filter(e -> StringUtils.isNotBlank(e.getRoleCode()))
.collect(Collectors.toMap(SaasRole::getId, Function.identity()));
Map<Long, List<Long>> groupIdToRoleIdsMap = roleRelations.stream()
Map<Long, List<SaasRole>> groupRoleMap = roleRelations.stream()
.collect(Collectors.groupingBy(SaasPgroupRoleRelation::getGroupId,
Collectors.mapping(SaasPgroupRoleRelation::getRoleId, Collectors.toList())));
Map<Long, String> roleIdToRoleCodeMap = Maps.newHashMap();
for (SaasRole role : roles) {
if (StringUtils.isNotBlank(role.getRoleCode())) {
roleIdToRoleCodeMap.put(role.getId(), role.getRoleCode());
}
}
Collectors.mapping(e -> roleMap.get(e.getRoleId()), Collectors.toList())));
return permissionRelations.stream()
.map(e -> {
List<Long> roleIds = groupIdToRoleIdsMap.get(e.getGroupId());
if (CollectionUtils.isEmpty(roleIds)) {
List<SaasRole> saasRoles = groupRoleMap.get(e.getGroupId());
if (CollectionUtils.isEmpty(saasRoles)) {
return null;
}
return roleIds.stream()
.map(roleId -> {
String roleCode = roleIdToRoleCodeMap.get(roleId);
if (StringUtils.isBlank(roleCode)) {
return null;
}
return PermissionGroupRoleWrapper.builder()
return saasRoles.stream()
.filter(Objects::nonNull)
.map(role -> PermissionGroupRoleWrapper.builder()
.featureId(e.getFeatureId())
.roleCode(roleCode)
.roleCode(role.getRoleCode())
.tags(e.getTags())
.build();
})
.build())
.filter(Objects::nonNull)
.collect(Collectors.toList());
})

View File

@ -11,6 +11,7 @@ import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.thrones.client.saas.ServicePkgClient;
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
import cn.axzo.tyr.client.TerminalClient;
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
@ -19,6 +20,7 @@ import cn.axzo.tyr.client.model.base.WorkspaceOUPair;
import cn.axzo.tyr.client.model.enums.IdentityType;
import cn.axzo.tyr.client.model.enums.RolePermissionTagEnum;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
import cn.axzo.tyr.client.model.req.GetTerminalInfoReq;
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
import cn.axzo.tyr.client.model.req.ListPermissionFeatureReq;
import cn.axzo.tyr.client.model.req.NavTreeReq;
@ -55,6 +57,7 @@ import cn.axzo.tyr.server.service.RoleSaasFeatureResourceCacheService;
import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
import cn.axzo.tyr.server.service.TerminalService;
import cn.axzo.tyr.server.service.TyrSaasAuthService;
import cn.axzo.tyr.server.service.WorkspaceProductService;
import cn.axzo.tyr.server.utils.RpcInternalUtil;
@ -111,6 +114,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
private final WorkspaceProductService workspaceProductService;
private final RoleSaasFeatureResourceCacheService roleSaasFeatureResourceCacheService;
private final PermissionTagService permissionTagService;
private final TerminalService terminalService;
@Value("${not.auth.uniCodes:}")
private Set<String> notAuthUniCodes;
@ -174,7 +178,10 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
return false;
}
TerminalInfo tm = new TerminalInfo(terminal);
GetTerminalInfoReq getTerminalInfoReq = GetTerminalInfoReq.builder()
.terminalCode(terminal)
.build();
TerminalInfo tm = terminalService.getTerminalInfo(getTerminalInfoReq);
return tm.isGA();
}
@ -397,6 +404,7 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.versionMax(req.getVersionMax())
.parentUniCode(req.getParentUniCode())
.status(req.getStatus())
.system(req.getSystem())
.build();
Set<Long> featureIds = listUserPermissionFeatureIds(treePermissionReq);
@ -686,8 +694,23 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.build())
.get(treePermissionReq.getTerminal())
.stream()
.filter(f -> Objects.isNull(treePermissionReq.getVersionMax())
|| treePermissionReq.getVersionMax().compareTo(f.getVersion()) > -1)
.filter(f -> {
if (StringUtils.isBlank(treePermissionReq.getSystem()) || Objects.isNull(treePermissionReq.getVersionMax())) {
return true;
}
if (Objects.equals(treePermissionReq.getSystem(), "ANDROID")) {
return treePermissionReq.getVersionMax().compareTo(f.getAndroidMinVersion()) > -1
&& treePermissionReq.getVersionMax().compareTo(f.getAndroidMaxVersion()) < 1;
}
if (Objects.equals(treePermissionReq.getSystem(), "IOS")) {
return treePermissionReq.getVersionMax().compareTo(f.getIosMinVersion()) > -1
&& treePermissionReq.getVersionMax().compareTo(f.getIosMaxVersion()) < 1;
}
// 其他不支持的系统暂时不根据版本过滤先让用户能使用起来
return true;
})
.collect(Collectors.toList());
// 查询显示的菜单需要过滤掉隐藏的节点如果父节点隐藏则下面所有子节点也需要过滤掉

View File

@ -231,7 +231,6 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
.terminal(featureResource.getTerminal())
.cooperateType(relation.getDictCode())
.itemCode(pageElement.getItemCode())
.version(pageElement.getVersion())
.appType(pageElement.getAppType())
.build())
.collect(Collectors.toList());
@ -252,7 +251,6 @@ public class ProductPermissionCacheServiceImpl implements ProductPermissionCache
.terminal(f.getTerminal())
.cooperateType(relation.getDictCode())
.itemCode(pageElement.getItemCode())
.version(pageElement.getVersion())
.appType(pageElement.getAppType())
.build())
.collect(Collectors.toList());

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.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;
@ -26,16 +26,15 @@ import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.ListRoleReq;
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PagePgroupPermissionRelationReq;
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.client.model.res.PageElementBasicDTO;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
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;
@ -46,7 +45,6 @@ import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.dao.SaasPgroupRoleRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasFeature;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelation;
import cn.axzo.tyr.server.repository.entity.SaasPgroupRoleRelation;
import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper;
@ -81,6 +79,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
@ -93,7 +92,13 @@ import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_CODE_EXIST;
import static cn.axzo.tyr.server.config.exception.BizResultCode.FEATURE_CODE_OVER_LENGTH;
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_CODE_EXIST;
import static cn.axzo.tyr.server.config.exception.BizResultCode.TERMINAL_NAME_EXIST;
import static cn.axzo.tyr.server.config.exception.BizResultCode.TERMINAL_NOT_FOUND;
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;
@ -127,9 +132,13 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
private static final String TARGET_TYPE = "saasFeatureResourceId";
/**
* 分组这些菜单节点没有版本号默认为0方便权限过滤
* 分组这些菜单节点没有版本号最小默认为0方便权限过滤
*/
private static final int DEFAULT_VERSION = 0;
private static final Integer DEFAULT_MIN_VERSION = 0;
/**
* 分组这些菜单节点没有版本号最大默认为Integer.MAX_VALUE方便权限过滤
*/
private static final Integer DEFAULT_MAX_VERSION = Integer.MAX_VALUE;
private LoadingCache<String, Optional<List<SaasFeatureResourceCache>>> featureResourceCache = CacheBuilder.newBuilder()
.expireAfterWrite(1, TimeUnit.DAYS)
@ -202,6 +211,11 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
watch.start("dbQuery");
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceCacheService.getByResourceTreeParam(req);
watch.stop();
// 因为前面使用了缓存没有切换到统一的查询接口这里如果入参有unicode则需要只查询unicode的子节点以及父节点构建tree
// 后面切换至统一的查询就改造
saasFeatureResources = filter(saasFeatureResources, req);
if (CollectionUtils.isEmpty(saasFeatureResources)) {
return Collections.emptyList();
}
@ -211,7 +225,12 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
// 非分组和页面的菜单资源应该都能看到所以只有有配置应用范围的菜单资源才进行过滤
.filter(e -> filterWorkspaceType(req, e))
.map(this::featureResource2Node)
.sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder))
.sorted(Comparator.comparing(e -> {
if (Objects.equals(e.getFeatureType(), FeatureResourceType.ROOT.getCode())) {
return e.getId();
}
return e.getDisplayOrder().longValue();
}))
.collect(Collectors.toList()))
.stream()
// 因为存在tree中某个节点被隐藏导致它的子节点构建在tree的root上应该排除掉root节点一定是parentId == 0的
@ -231,6 +250,35 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
return resultNode;
}
private List<SaasFeatureResource> filter(List<SaasFeatureResource> saasFeatureResources,
GetFeatureResourceTreeReq req) {
if (StringUtils.isBlank(req.getUniCode())) {
return saasFeatureResources;
}
SaasFeatureResource saasFeatureResource = saasFeatureResources.stream()
.filter(e -> Objects.equals(e.getUniCode(), req.getUniCode()))
.findFirst()
.orElse(null);
if (Objects.isNull(saasFeatureResource)) {
return Collections.emptyList();
}
Set<Long> parentIds = Sets.newHashSet(saasFeatureResource.splitPath());
parentIds.remove(saasFeatureResource.getId());
List<SaasFeatureResource> parentFeatureResources = saasFeatureResources.stream()
.filter(e -> parentIds.contains(e.getId()))
.collect(Collectors.toList());
List<SaasFeatureResource> children = saasFeatureResources.stream()
.filter(e -> e.getPath().startsWith(saasFeatureResource.getPath()))
.collect(Collectors.toList());
List<SaasFeatureResource> result = Lists.newArrayList();
result.addAll(parentFeatureResources);
result.addAll(children);
return result;
}
private boolean filterWorkspaceType(GetFeatureResourceTreeReq req, SaasFeatureResource e) {
if (Objects.isNull(req.getWorkspaceType())) {
return true;
@ -341,9 +389,41 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
List<String> allUniCodes = descendants.stream().map(SaasFeatureResource::getUniCode).filter(StringUtils::isNotBlank).collect(Collectors.toList());
fillPageElement2PageFeatureResource(treeList, allUniCodes, param);
// 查询页面关联资源的版本号
assemblePageRouteVersion(featureResourceTreeNode);
return featureResourceTreeNode;
}
private void assemblePageRouteVersion(FeatureResourceTreeNode featureResourceTreeNode) {
if (Objects.isNull(featureResourceTreeNode)) {
return;
}
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
.featureResourceUniCodes(Sets.newHashSet(featureResourceTreeNode.getUniCode()))
.types(Sets.newHashSet(PageElementFeatureResourceRelationTypeEnum.PAGE_ROUTE))
.needPageElement(true)
.build();
Optional<PageElementResp> pageElementOptional = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq)
.stream()
.map(PageElementFeatureResourceRelationResp::getPageElement)
.findFirst();
if (!pageElementOptional.isPresent()) {
return;
}
PageElementResp pageElementResp = pageElementOptional.get();
featureResourceTreeNode.setAndroidMinVersion(pageElementResp.getAndroidMinVersion());
featureResourceTreeNode.setAndroidMaxVersion(pageElementResp.getAndroidMaxVersion());
featureResourceTreeNode.setAndroidMaxVersionEnabled(pageElementResp.getAndroidMaxVersionEnabled());
featureResourceTreeNode.setIosMinVersion(pageElementResp.getIosMinVersion());
featureResourceTreeNode.setIosMaxVersion(pageElementResp.getIosMaxVersion());
featureResourceTreeNode.setIosMaxVersionEnabled(pageElementResp.getIosMaxVersionEnabled());
}
@Override
@Transactional(rollbackFor = Exception.class)
@CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true)
@ -381,7 +461,8 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
mqProducer.send(event);
} else {
//补充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())) {
SaasFeatureResource parent = featureResourceDao.lambdaQuery().eq(SaasFeatureResource::getId,req.getParentId()).one();
baseResource.setPath(StringUtils.isBlank(parent.getPath()) ? baseResource.getId().toString() + "," : parent.getPath() + baseResource.getId() + ",");
@ -390,14 +471,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
baseResource.setPath(dbResource.getPath());
}
baseResource.setFeatureCode(req.getUniCode());
baseResource.setExtra(oldValue.buildMergedExt(req.getExtra()));
featureResourceDao.updateById(baseResource);
Event event = Event.builder()
.targetType(TARGET_TYPE)
.eventCode(SAAS_FEATURE_RESOURCE_UPSERT.getEventCode())
.data(SaasFeatureResourceUpsertPayload.builder()
.oldValue(featureResourceDao.getById(baseResource.getId()))
.newValue(newValue)
.oldValue(oldValue)
.newValue(featureResourceDao.getById(baseResource.getId()))
.action(SaasFeatureResource.Action.UPDATE)
.build())
.build();
@ -614,6 +696,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
.terminal(featureResource.getTerminal())
.parentId(featureResource.getParentId())
.displayOrder(featureResource.getDisplayOrder())
.extra(featureResource.getExtra())
.build();
}
@ -647,26 +730,24 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
*/
void validFeatureCode(SaasFeatureResource featureResource) {
Assert.notNull(featureResource.getUniCode(), "权限码code不能为空");
SaasFeatureResource exist = featureResourceDao.lambdaQuery()
List<SaasFeatureResource> 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<SaasFeatureResource> 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
@ -732,20 +813,84 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
Map<String, List<PageElementResp>> pageElements = listPageElements(param, page.getRecords());
Map<Long, List<SaasFeatureResourceResp>> children = listChildren(param, page.getRecords());
Map<Long, List<SaasFeatureResourceResp>> ancestors = listAncestor(param, page.getRecords());
return PageConverter.toResp(page, e -> from(e,
uniCodeFeatureCodeMap,
pageElements));
pageElements,
ancestors,
children));
}
private Map<Long, List<SaasFeatureResourceResp>> listAncestor(PageSaasFeatureResourceReq param,
List<SaasFeatureResource> saasFeatureResources) {
if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedAncestor())) {
return Collections.emptyMap();
}
List<Long> parentIds = saasFeatureResources.stream()
.map(SaasFeatureResource::splitPath)
.flatMap(Collection::stream)
.distinct()
.collect(Collectors.toList());
Map<Long, SaasFeatureResourceResp> parents = this.list(PageSaasFeatureResourceReq.builder()
.ids(parentIds)
.build())
.stream()
.collect(Collectors.toMap(SaasFeatureResourceResp::getId, Function.identity()));
return saasFeatureResources.stream()
.collect(Collectors.toMap(SaasFeatureResource::getId,
e -> e.splitPath().stream()
.filter(parentId -> !Objects.equals(parentId, e.getId()))
.map(parents::get)
.collect(Collectors.toList())));
}
private Map<Long, List<SaasFeatureResourceResp>> listChildren(PageSaasFeatureResourceReq param,
List<SaasFeatureResource> saasFeatureResources) {
if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedChildren())) {
return Collections.emptyMap();
}
Set<String> paths = saasFeatureResources.stream()
.map(SaasFeatureResource::getPath)
.collect(Collectors.toSet());
List<SaasFeatureResourceResp> children = this.list(PageSaasFeatureResourceReq.builder()
.paths(paths)
.build());
if (CollectionUtils.isEmpty(children)) {
return Collections.emptyMap();
}
return saasFeatureResources.stream()
.collect(Collectors.toMap(SaasFeatureResource::getId,
e -> children.stream()
.filter(c -> c.getPath().startsWith(e.getPath()) && !Objects.equals(e.getPath(), c.getPath()))
.collect(Collectors.toList())));
}
private SaasFeatureResourceResp from(SaasFeatureResource featureResource,
Map<String, Set<String>> uniCodeFeatureCodeMap,
Map<String, List<PageElementResp>> pageElements) {
Map<String, List<PageElementResp>> pageElements,
Map<Long, List<SaasFeatureResourceResp>> children,
Map<Long, List<SaasFeatureResourceResp>> ancestors) {
SaasFeatureResourceResp saasFeatureResourceResp = SaasFeatureResourceResp.builder().build();
BeanUtils.copyProperties(featureResource, saasFeatureResourceResp);
saasFeatureResourceResp.setFeatureCodes(uniCodeFeatureCodeMap.get(featureResource.getUniCode()));
saasFeatureResourceResp.setSaasPageElements(pageElements.get(saasFeatureResourceResp.getUniCode()));
saasFeatureResourceResp.setChildren(children.get(saasFeatureResourceResp.getId()));
saasFeatureResourceResp.setAncestors(ancestors.get(saasFeatureResourceResp.getId()));
return saasFeatureResourceResp;
}
@ -764,12 +909,12 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
.build();
return saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq)
.stream()
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode,
Collectors.mapping(SaasPageElementFeatureResourceRelation::getPageElementCode, Collectors.toSet())));
.collect(Collectors.groupingBy(PageElementFeatureResourceRelationResp::getFeatureResourceUniCode,
Collectors.mapping(PageElementFeatureResourceRelationResp::getPageElementCode, Collectors.toSet())));
}
private Map<String, List<PageElementResp>> listPageElements(PageSaasFeatureResourceReq param,
List<SaasFeatureResource> saasFeatureResources) {
List<SaasFeatureResource> saasFeatureResources) {
if (CollectionUtils.isEmpty(saasFeatureResources) || BooleanUtils.isNotTrue(param.getNeedPageElement())) {
return Collections.emptyMap();
@ -781,28 +926,15 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
.featureResourceUniCodes(uniCodes)
.types(param.getPageElementTypes())
.needPageElement(true)
.build();
List<SaasPageElementFeatureResourceRelation> pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq);
if (CollectionUtils.isEmpty(pageElementFeatureResourceRelations)) {
return Collections.emptyMap();
}
Set<String> elementCodes = pageElementFeatureResourceRelations.stream()
.map(SaasPageElementFeatureResourceRelation::getPageElementCode)
.collect(Collectors.toSet());
PageElementReq pageElementReq = PageElementReq.builder()
.codes(elementCodes)
.build();
Map<String, PageElementResp> elementMap = saasPageElementService.list(pageElementReq).stream()
.collect(Collectors.toMap(PageElementResp::getCode, Function.identity()));
List<PageElementFeatureResourceRelationResp> pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq);
return pageElementFeatureResourceRelations.stream()
.filter(e -> elementMap.get(e.getPageElementCode()) != null)
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode,
Collectors.mapping(e -> elementMap.get(e.getPageElementCode()), Collectors.toList())));
.filter(e -> e.getPageElement() != null)
.collect(Collectors.groupingBy(PageElementFeatureResourceRelationResp::getFeatureResourceUniCode,
Collectors.mapping(PageElementFeatureResourceRelationResp::getPageElement, Collectors.toList())));
}
@ -957,6 +1089,7 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
}
private List<SaasFeatureResourceDTO> resolveSaasFeature(Set<String> terminals) {
// 老版本的菜单信息
Map<String, List<SaasFeatureResourceService.SaasFeatureResourceCache>> saasFeatures = saasFeatureDao.lambdaQuery()
.in(SaasFeature::getTerminal, terminals)
.list()
@ -977,27 +1110,16 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
.build())
.collect(Collectors.toList());
// 新版本的菜单信息
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.terminals(terminals)
.needPageElement(true)
.build();
List<SaasFeatureResourceDTO> saasFeatureResources = list(pageSaasFeatureResourceReq)
.stream()
.collect(Collectors.groupingBy(SaasFeatureResourceResp::getTerminal,
Collectors.mapping(e -> SaasFeatureResourceService.SaasFeatureResourceCache
.builder()
.featureId(e.getId())
.notAuth(SaasFeatureResource.AuthType.isAllRole(e.getAuthType()))
.parentIds(e.resolvePath())
.uniCode(e.getUniCode())
.status(e.getStatus())
.version(Optional.ofNullable(e.getSaasPageElements())
.map(pageElement -> pageElement.stream()
.findFirst()
.map(PageElementResp::getVersion)
.orElse(DEFAULT_VERSION))
.orElse(DEFAULT_VERSION))
.build(), Collectors.toList())))
Collectors.mapping(this::from, Collectors.toList())))
.entrySet().stream()
.map(e -> SaasFeatureResourceDTO.builder()
.terminal(e.getKey())
@ -1010,6 +1132,48 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
return allFeatureResources;
}
private SaasFeatureResourceService.SaasFeatureResourceCache from(SaasFeatureResourceResp saasFeatureResourceResp) {
// 菜单页面应用只能绑定一个关联资源所以取第一个资源的版本
PageElementResp pageElementResp = Optional.ofNullable(saasFeatureResourceResp.getSaasPageElements())
.flatMap(pageElement -> pageElement.stream()
.findFirst())
.orElse(null);
Integer androidMinVersion = Optional.ofNullable(pageElementResp)
.map(PageElementResp::getAndroidMinVersion)
.orElse(DEFAULT_MIN_VERSION);
Integer iosMinVersion = Optional.ofNullable(pageElementResp)
.map(PageElementResp::getIosMinVersion)
.orElse(DEFAULT_MIN_VERSION);
SaasFeatureResourceService.SaasFeatureResourceCache result = SaasFeatureResourceService.SaasFeatureResourceCache
.builder()
.featureId(saasFeatureResourceResp.getId())
.notAuth(SaasFeatureResource.AuthType.isAllRole(saasFeatureResourceResp.getAuthType()))
.parentIds(saasFeatureResourceResp.resolvePath())
.uniCode(saasFeatureResourceResp.getUniCode())
.status(saasFeatureResourceResp.getStatus())
.androidMinVersion(androidMinVersion)
.iosMinVersion(iosMinVersion)
.build();
Boolean androidMaxVersionEnabled = Optional.ofNullable(pageElementResp)
.map(PageElementResp::getAndroidMaxVersionEnabled)
.orElse(false);
result.setAndroidMaxVersion(BooleanUtils.isTrue(androidMaxVersionEnabled) ? Optional.ofNullable(pageElementResp)
.map(PageElementResp::getAndroidMaxVersion)
.orElse(DEFAULT_MAX_VERSION) : DEFAULT_MAX_VERSION);
Boolean iosMaxVersionEnabled = Optional.ofNullable(pageElementResp)
.map(PageElementResp::getIosMaxVersionEnabled)
.orElse(false);
result.setIosMaxVersion(BooleanUtils.isTrue(iosMaxVersionEnabled) ? Optional.ofNullable(pageElementResp)
.map(PageElementResp::getIosMaxVersion)
.orElse(DEFAULT_MAX_VERSION) : DEFAULT_MAX_VERSION);
return result;
}
@Override
public List<SaasFeatureBO> listAllFeatureByTerminal(String terminal) {
@ -1017,4 +1181,181 @@ public class SaasFeatureResourceServiceImpl extends ServiceImpl<SaasFeatureResou
return BeanMapper.mapList(saasFeatures, SaasFeatureBO.class);
}
@Override
@Transactional
// 因为历史的菜单tree接口使用的注解来实现缓存这里同步后就需要更新缓存否则查询不出来
@CacheEvict(value = SaasFeatureResourceCacheService.CACHE_FEATURE_RESOURCE_TREE,allEntries = true)
public void clone(CloneTerminalReq req) {
check(req);
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()));
// 去除根节点因为新的端的根节点数据不需要知道以前的层级关系
List<FeatureResourceTreeNode> oldChildren = TreeUtil.buildTree(sourceFeatureResources.stream()
.map(e -> FeatureResourceTreeNode.builder()
.id(e.getId())
.uniCode(e.getUniCode())
.parentId(e.getParentId())
.build())
.collect(Collectors.toList()))
.stream()
.collect(Collectors.toList())
.stream()
.map(FeatureResourceTreeNode::getChildren)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toList());
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);
appendChildren(saasFeatureResources, root, oldChildren, newUnicodeMap, req);
this.updateBatchById(saasFeatureResources);
}
private void appendChildren(List<SaasFeatureResource> saasFeatureResources,
SaasFeatureResource parent,
List<FeatureResourceTreeNode> oldChildren,
Map<String, SaasFeatureResourceResp> newUnicodeMap,
CloneTerminalReq req) {
if (CollectionUtils.isEmpty(oldChildren)) {
return;
}
// 通过旧端的层级关系找到对应新端的记录然后更新path和parentId
List<SaasFeatureResource> children = oldChildren.stream()
.map(e -> {
SaasFeatureResourceResp saasFeatureResourceResp = newUnicodeMap.get(replaceUnicode(req.getNewTerminalFeatureCodePrefix(), e.getUniCode()));
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(saasFeatureResourceResp.getId());
saasFeatureResource.setUniCode(saasFeatureResourceResp.getUniCode());
saasFeatureResource.setPath(parent.getPath() + saasFeatureResourceResp.getId() + ",");
saasFeatureResource.setParentId(parent.getId());
return saasFeatureResource;
})
.collect(Collectors.toList());
saasFeatureResources.addAll(children);
children.forEach(e -> {
List<FeatureResourceTreeNode> oldNextChildren = oldChildren.stream()
.filter(old -> Objects.equals(replaceUnicode(req.getNewTerminalFeatureCodePrefix(), old.getUniCode()), e.getUniCode()))
.map(FeatureResourceTreeNode::getChildren)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toList());
appendChildren(saasFeatureResources, e, oldNextChildren, newUnicodeMap, req);
});
}
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(replaceUnicode(req.getNewTerminalFeatureCodePrefix(), e.getUniCode()));
saasFeatureResource.setFeatureCode(saasFeatureResource.getUniCode());
saasFeatureResource.setFeatureName(e.getFeatureName());
}
return saasFeatureResource;
})
.collect(Collectors.toList());
this.saveBatch(inserts);
}
/**
* 新code的解析
* 原code第一个":"前的字符串替换成newTerminalFeatureCodePrefix
* 如果原code没有":"则直接把newTerminalFeatureCodePrefix + ":" + oldUniCode
* @param newTerminalFeatureCodePrefix
* @param oldUniCode
* @return
*/
private String replaceUnicode(String newTerminalFeatureCodePrefix, String oldUniCode) {
int i = oldUniCode.indexOf(":");
String newCode = i < 0 ? newTerminalFeatureCodePrefix + ":" + oldUniCode : newTerminalFeatureCodePrefix + oldUniCode.substring(i);
Axssert.check(100 > newCode.length(), FEATURE_CODE_OVER_LENGTH, FEATURE_CODE_OVER_LENGTH.getErrorMessage(), newCode);
return newCode;
}
private void check(CloneTerminalReq req) {
checkTerminalCode(req);
checkTerminalName(req);
checkFromTerminal(req);
}
private void checkFromTerminal(CloneTerminalReq req) {
List<SaasFeatureResourceResp> fromTerminalFeatureResources = this.list(PageSaasFeatureResourceReq.builder()
.ids(Lists.newArrayList(req.getFromTerminalId()))
.build());
Axssert.checkNotEmpty(fromTerminalFeatureResources, TERMINAL_NOT_FOUND, TERMINAL_NOT_FOUND.getErrorMessage(), req.getFromTerminalId());
}
private void checkTerminalName(CloneTerminalReq req) {
List<SaasFeatureResourceResp> newFeatureResources = this.list(PageSaasFeatureResourceReq.builder()
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.ROOT.getCode()))
.featureName(req.getNewTerminalName())
.build());
Axssert.check(CollectionUtils.isEmpty(newFeatureResources), TERMINAL_NAME_EXIST);
}
private void checkTerminalCode(CloneTerminalReq req) {
List<SaasFeatureResourceResp> newFeatureResources = this.list(PageSaasFeatureResourceReq.builder()
.featureResourceTypes(Lists.newArrayList(FeatureResourceType.ROOT.getCode()))
.terminal(req.getNewTerminalCode())
.build());
Axssert.check(CollectionUtils.isEmpty(newFeatureResources), TERMINAL_CODE_EXIST);
}
}

View File

@ -2,13 +2,24 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.constant.enums.DeleteEnum;
import cn.axzo.basics.common.util.AssertUtil;
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.rocketmq.Event;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum;
import cn.axzo.tyr.client.model.req.BatchUpsertPageElementCategoryReq;
import cn.axzo.tyr.client.model.req.DeletePageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementCategoryReq;
import cn.axzo.tyr.client.model.req.PageElementCategoryV2Req;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PermissionOperateLogReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
import cn.axzo.tyr.client.model.res.ListPageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import cn.axzo.tyr.server.config.MqProducer;
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao;
@ -16,20 +27,34 @@ import cn.axzo.tyr.server.repository.dao.SaasPageElementDao;
import cn.axzo.tyr.server.repository.dao.SaasPageElementFeatureResourceRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasPageElement;
import cn.axzo.tyr.server.repository.entity.SaasPageElementCategory;
import cn.axzo.tyr.server.repository.mapper.SaasPageElementCategoryMapper;
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService;
import com.google.common.collect.Lists;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Sets;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.config.exception.BizResultCode.ITEM_CODE_DUPLICATE;
import static cn.axzo.tyr.server.config.exception.BizResultCode.ITEM_NAME_DUPLICATE;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_CATEGORY_NOT_FOUND;
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT;
/**
@ -40,7 +65,8 @@ import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_
@Slf4j
@Service
@AllArgsConstructor
public class SaasPageElementCategoryServiceImpl implements SaasPageElementCategoryService {
public class SaasPageElementCategoryServiceImpl extends ServiceImpl<SaasPageElementCategoryMapper, SaasPageElementCategory>
implements SaasPageElementCategoryService {
public static final String PAGE_ELEMENT_CATEGORY_TABLE_NAME = "saas_page_element_category";
private static final String TARGET_TYPE = "pageElementFeatureResourceId";
@ -50,28 +76,65 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego
private final SaasPageElementFeatureResourceRelationDao saasPageElementFeatureResourceRelationDao;
private final SaasPgroupPermissionRelationOperateLogService saasPgroupPermissionRelationOperateLogService;
private final MqProducer mqProducer;
private final SaasPageElementService saasPageElementService;
@Override
public List<ListPageElementCategoryResp> listGroupByTerminal() {
List<ListPageElementCategoryResp> categoryResps = Lists.newArrayList();
public List<ListPageElementCategoryResp> listGroupByTerminal(PageElementCategoryReq req) {
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
.list();
if (CollectionUtils.isEmpty(categories)) {
return categoryResps;
return Collections.emptyList();
}
Map<String, List<SaasPageElementCategory>> categoryMap = categories.stream().collect(Collectors.groupingBy(SaasPageElementCategory::getTerminal));
categoryMap.forEach((key, value) -> {
categoryResps.add(ListPageElementCategoryResp.builder().terminal(key)
.pageElementCategories(value.stream().map(c -> ListPageElementCategoryResp.PageElementCategoryDTO
.builder()
.id(c.getId())
.itemCode(c.getItemCode())
.itemName(c.getItemName())
.terminal(c.getTerminal())
.build()).collect(Collectors.toList())).build());
});
return categoryResps;
Map<String, List<PageElementResp>> pageElementMap = listPageElement(categories, req);
return categories.stream()
.collect(Collectors.groupingBy(SaasPageElementCategory::getTerminal))
.entrySet()
.stream()
.map(e -> from(e, pageElementMap))
.collect(Collectors.toList());
}
private ListPageElementCategoryResp from(Map.Entry<String, List<SaasPageElementCategory>> entry,
Map<String, List<PageElementResp>> pageElementMap) {
return ListPageElementCategoryResp.builder()
.terminal(entry.getKey())
.pageElementCategories(entry.getValue().stream()
.map(c -> ListPageElementCategoryResp.PageElementCategoryDTO
.builder()
.id(c.getId())
.itemCode(c.getItemCode())
.itemName(c.getItemName())
.terminal(c.getTerminal())
.pageElement(pageElementMap.get(c.getItemCode()))
.build())
.collect(Collectors.toList()))
.build();
}
private Map<String, List<PageElementResp>> listPageElement(List<SaasPageElementCategory> categories,
PageElementCategoryReq req) {
if (CollectionUtils.isEmpty(categories) || BooleanUtils.isNotTrue(req.getNeedPage())) {
return Collections.emptyMap();
}
Set<String> itemCodes = categories.stream()
.map(SaasPageElementCategory::getItemCode)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(itemCodes)) {
return Collections.emptyMap();
}
return saasPageElementService.list(PageElementReq.builder()
.itemCodes(itemCodes)
.types(Sets.newHashSet(PageElementTypeEnum.PAGE))
.build())
.stream()
.collect(Collectors.groupingBy(PageElementResp::getItemCode));
}
@Override
@ -111,6 +174,147 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego
return baseCategory.getId();
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchUpsert(BatchUpsertPageElementCategoryReq req) {
check(req);
List<SaasPageElementCategory> saasPageElementCategories = req.getUpsertPageElementCategories().stream()
.map(e -> {
SaasPageElementCategory saasPageElementCategory = SaasPageElementCategory.builder()
.itemCode(e.getItemCode())
.itemName(e.getItemName())
.terminal(e.getTerminal())
.createBy(Objects.nonNull(e.getId()) ? null : req.getOperatorId())
.updateBy(req.getOperatorId())
.build();
saasPageElementCategory.setId(e.getId());
return saasPageElementCategory;
})
.collect(Collectors.toList());
saasPageElementCategoryDao.saveOrUpdateBatch(saasPageElementCategories);
try {
saveOrUpdateOperateLog(req, saasPageElementCategories);
} catch (Exception e) {
log.warn("save operate log error", e);
}
}
private void checkItemName(BatchUpsertPageElementCategoryReq req) {
// check入参中重复的名字
Set<String> duplicateItemNames = req.getUpsertPageElementCategories().stream()
.collect(Collectors.groupingBy(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemName))
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
Axssert.check(CollectionUtils.isEmpty(duplicateItemNames), ITEM_NAME_DUPLICATE,
ITEM_NAME_DUPLICATE.getErrorMessage(), duplicateItemNames);
// check新增或者更新的itemName是否已经存在
List<String> itemNames = req.getUpsertPageElementCategories().stream()
.map(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemName)
.collect(Collectors.toList());
List<SaasPageElementCategory> saasPageElementCategories = this.lambdaQuery()
.in(SaasPageElementCategory::getItemName, itemNames)
.eq(SaasPageElementCategory::getIsDelete, DeleteEnum.NORMAL.value)
.list();
if (CollectionUtils.isEmpty(saasPageElementCategories)) {
return;
}
Map<String, SaasPageElementCategory> itemNameMap = saasPageElementCategories.stream()
.collect(Collectors.toMap(SaasPageElementCategory::getItemName, Function.identity()));
List<String> dbDuplicateItemNames = req.getUpsertPageElementCategories().stream()
.filter(e -> {
SaasPageElementCategory oldSaasPageElementCategory = itemNameMap.get(e.getItemName());
if (Objects.isNull(oldSaasPageElementCategory)) {
return false;
}
// 新增里重复的itemName
if (Objects.isNull(e.getId())) {
return true;
}
// 更新里重复的itemName
return !Objects.equals(e.getId(), oldSaasPageElementCategory.getId());
})
.map(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemName)
.collect(Collectors.toList());
Axssert.check(CollectionUtils.isEmpty(dbDuplicateItemNames), ITEM_NAME_DUPLICATE,
ITEM_NAME_DUPLICATE.getErrorMessage(), dbDuplicateItemNames);
}
private void checkItemCode(BatchUpsertPageElementCategoryReq req) {
// check入参中重复的ItemCode
Set<String> duplicateItemCodes = req.getUpsertPageElementCategories().stream()
.collect(Collectors.groupingBy(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemCode))
.entrySet()
.stream()
.filter(e -> e.getValue().size() > 1)
.map(Map.Entry::getKey)
.collect(Collectors.toSet());
Axssert.check(CollectionUtils.isEmpty(duplicateItemCodes), ITEM_CODE_DUPLICATE,
ITEM_CODE_DUPLICATE.getErrorMessage(), duplicateItemCodes);
// check新增或者更新的itemCode是否已经存在
List<String> itemCodes = req.getUpsertPageElementCategories().stream()
.map(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemCode)
.collect(Collectors.toList());
List<SaasPageElementCategory> saasPageElementCategories = this.lambdaQuery()
.in(SaasPageElementCategory::getItemCode, itemCodes)
.eq(SaasPageElementCategory::getIsDelete, DeleteEnum.NORMAL.value)
.list();
if (CollectionUtils.isEmpty(saasPageElementCategories)) {
return;
}
Map<String, SaasPageElementCategory> itemCodeMap = saasPageElementCategories.stream()
.collect(Collectors.toMap(SaasPageElementCategory::getItemCode, Function.identity()));
List<String> dbDuplicateItemCodes = req.getUpsertPageElementCategories().stream()
.filter(e -> {
SaasPageElementCategory oldSaasPageElementCategory = itemCodeMap.get(e.getItemName());
if (Objects.isNull(oldSaasPageElementCategory)) {
return false;
}
// 新增里重复的itemName
if (Objects.isNull(e.getId())) {
return true;
}
// 更新里重复的itemName
return !Objects.equals(e.getId(), oldSaasPageElementCategory.getId());
})
.map(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getItemCode)
.collect(Collectors.toList());
Axssert.check(CollectionUtils.isEmpty(dbDuplicateItemCodes), ITEM_CODE_DUPLICATE,
ITEM_CODE_DUPLICATE.getErrorMessage(), dbDuplicateItemCodes);
}
private void check(BatchUpsertPageElementCategoryReq req) {
checkItemName(req);
checkItemCode(req);
List<Long> ids = req.getUpsertPageElementCategories().stream()
.map(BatchUpsertPageElementCategoryReq.UpsertPageElementCategory::getId)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(ids)) {
List<SaasPageElementCategory> saasPageElementCategories = saasPageElementCategoryDao.listByIds(ids);
Axssert.check(ids.size() == saasPageElementCategories.size(), PAGE_ELEMENT_CATEGORY_NOT_FOUND);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(DeletePageElementCategoryReq req) {
@ -178,6 +382,20 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego
.build());
}
private void saveOrUpdateOperateLog(BatchUpsertPageElementCategoryReq req,
List<SaasPageElementCategory> saasPageElementCategories) {
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
.tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME)
.operatorId(req.getOperatorId())
.scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT_CATEGORY.getValue())
// 批量更新记录id会超长后续提供统一的更基础的日志记录表先暂时用
.sceneId(UuidUtils.generateUuid())
.requestData(req)
.operateData(saasPageElementCategories)
.build());
}
private void saveDeleteOperateLog(DeletePageElementCategoryReq req, SaasPageElementCategory baseCategory) {
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
.tableName(PAGE_ELEMENT_CATEGORY_TABLE_NAME)
@ -188,4 +406,28 @@ public class SaasPageElementCategoryServiceImpl implements SaasPageElementCatego
.operateData(baseCategory)
.build());
}
@Override
public List<PageElementCategoryResp> list(PageElementCategoryV2Req param) {
return PageConverter.drainAll(pageNumber -> {
param.setPage(pageNumber);
param.setPageSize(1000);
return page(param);
});
}
@Override
public PageResp<PageElementCategoryResp> page(PageElementCategoryV2Req param) {
QueryWrapper<SaasPageElementCategory> wrapper = QueryWrapperHelper.fromBean(param, SaasPageElementCategory.class);
wrapper.eq("is_delete", 0);
IPage<SaasPageElementCategory> page = this.page(PageConverter.toMybatis(param, SaasPageElementCategory.class), wrapper);
return PageConverter.toResp(page, this::from);
}
private PageElementCategoryResp from(SaasPageElementCategory saasPageElementCategory) {
PageElementCategoryResp result = PageElementCategoryResp.builder().build();
BeanUtils.copyProperties(saasPageElementCategory, result);
return result;
}
}

View File

@ -5,17 +5,30 @@ import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.client.model.req.PageElementReq;
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import cn.axzo.tyr.server.repository.mapper.SaasPageElementFeatureResourceRelationMapper;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@ -24,8 +37,13 @@ import java.util.stream.Collectors;
public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceImpl<SaasPageElementFeatureResourceRelationMapper, SaasPageElementFeatureResourceRelation>
implements SaasPageElementFeatureResourceRelationService {
@Autowired
private SaasPageElementService saasPageElementService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Override
public List<SaasPageElementFeatureResourceRelation> list(PageElementFeatureResourceRelationReq param) {
public List<PageElementFeatureResourceRelationResp> list(PageElementFeatureResourceRelationReq param) {
return PageConverter.drainAll(pageNumber -> {
param.setPage(pageNumber);
param.setPageSize(1000);
@ -34,7 +52,7 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm
}
@Override
public PageResp<SaasPageElementFeatureResourceRelation> page(PageElementFeatureResourceRelationReq param) {
public PageResp<PageElementFeatureResourceRelationResp> page(PageElementFeatureResourceRelationReq param) {
QueryWrapper<SaasPageElementFeatureResourceRelation> wrapper = QueryWrapperHelper.fromBean(param, SaasPageElementFeatureResourceRelation.class);
wrapper.eq("is_delete", 0);
@ -45,6 +63,57 @@ public class SaasPageElementFeatureResourceRelationServiceImpl extends ServiceIm
IPage<SaasPageElementFeatureResourceRelation> page = this.page(PageConverter.toMybatis(param, SaasPageElementFeatureResourceRelation.class), wrapper);
return PageConverter.toResp(page, Function.identity());
Map<String, PageElementResp> pageElements = listPageElement(page.getRecords(), param);
Map<String, SaasFeatureResourceResp> saasFeatureResources = listSaasFeatureResource(page.getRecords(), param);
return PageConverter.toResp(page, e -> from(e, pageElements, saasFeatureResources));
}
private PageElementFeatureResourceRelationResp from(SaasPageElementFeatureResourceRelation saasPageElementFeatureResourceRelation,
Map<String, PageElementResp> pageElements,
Map<String, SaasFeatureResourceResp> saasFeatureResources) {
PageElementFeatureResourceRelationResp result = PageElementFeatureResourceRelationResp.builder().build();
BeanUtils.copyProperties(saasPageElementFeatureResourceRelation, result);
result.setPageElement(pageElements.get(result.getPageElementCode()));
result.setSaasFeatureResource(saasFeatureResources.get(result.getFeatureResourceUniCode()));
return result;
}
private Map<String, PageElementResp> listPageElement(List<SaasPageElementFeatureResourceRelation> saasPageElementFeatureResourceRelations,
PageElementFeatureResourceRelationReq param) {
if (CollectionUtils.isEmpty(saasPageElementFeatureResourceRelations) || BooleanUtils.isNotTrue(param.getNeedPageElement())) {
return Collections.emptyMap();
}
return saasPageElementService.list(PageElementReq.builder()
.codes(saasPageElementFeatureResourceRelations.stream()
.map(SaasPageElementFeatureResourceRelation::getPageElementCode)
.collect(Collectors.toSet()))
.needPageElementCategory(param.getNeedPageElementCategory())
.build())
.stream()
.collect(Collectors.toMap(PageElementResp::getCode, Function.identity()));
}
private Map<String, SaasFeatureResourceResp> listSaasFeatureResource(List<SaasPageElementFeatureResourceRelation> saasPageElementFeatureResourceRelations,
PageElementFeatureResourceRelationReq param) {
if (CollectionUtils.isEmpty(saasPageElementFeatureResourceRelations) || BooleanUtils.isNotTrue(param.getNeedFeatureResource())) {
return Collections.emptyMap();
}
Set<String> uniCodes = saasPageElementFeatureResourceRelations.stream()
.map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode)
.collect(Collectors.toSet());
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.uniCodes(uniCodes)
.build();
List<SaasFeatureResourceResp> featureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq);
return featureResources.stream()
.collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, Function.identity()));
}
}

View File

@ -9,6 +9,7 @@ import cn.axzo.basics.profiles.api.UserProfileServiceApi;
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
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.exception.BusinessException;
import cn.axzo.framework.domain.page.PageResp;
import cn.axzo.framework.rocketmq.Event;
@ -18,11 +19,14 @@ import cn.axzo.tyr.client.common.enums.PageElementAppTypeEnum;
import cn.axzo.tyr.client.common.enums.PageElementFeatureResourceRelationTypeEnum;
import cn.axzo.tyr.client.common.enums.PageElementTypeEnum;
import cn.axzo.tyr.client.common.enums.PermissionRelationOperateLogSceneEnum;
import cn.axzo.tyr.client.model.req.BatchUpsertPageElementCategoryReq;
import cn.axzo.tyr.client.model.req.BatchUpsertPageElementReq;
import cn.axzo.tyr.client.model.req.DeletePageElementReq;
import cn.axzo.tyr.client.model.req.GetPageElementReq;
import cn.axzo.tyr.client.model.req.GetUserHasPermissionPageElementReq;
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
import cn.axzo.tyr.client.model.req.ModifyPageElementRelationDTO;
import cn.axzo.tyr.client.model.req.PageElementCategoryV2Req;
import cn.axzo.tyr.client.model.req.PageElementFeatureResourceRelationReq;
import cn.axzo.tyr.client.model.req.PageElementImportDataReq;
import cn.axzo.tyr.client.model.req.PageElementReportReq;
@ -32,15 +36,19 @@ import cn.axzo.tyr.client.model.req.PageQueryElementV2Req;
import cn.axzo.tyr.client.model.req.PageSaasFeatureResourceReq;
import cn.axzo.tyr.client.model.req.PermissionOperateLogReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq;
import cn.axzo.tyr.client.model.req.SyncPageElementReq;
import cn.axzo.tyr.client.model.res.GetUserHasPermissionPageElementResp;
import cn.axzo.tyr.client.model.res.IdentityAuthRes;
import cn.axzo.tyr.client.model.res.PageElementBasicDTO;
import cn.axzo.tyr.client.model.res.PageElementCategoryAndElementResp;
import cn.axzo.tyr.client.model.res.PageElementCategoryResp;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
import cn.axzo.tyr.client.model.res.PageElementRelationFeatureResourceResp;
import cn.axzo.tyr.client.model.res.PageElementResp;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.server.config.MqProducer;
import cn.axzo.tyr.server.event.payload.PageElementFeatureResourceUpsertPayload;
import cn.axzo.tyr.server.inner.feign.BasePageElementApi;
import cn.axzo.tyr.server.model.RelationOperateLogResourceBindElementDO;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.dao.SaasPageElementCategoryDao;
@ -53,6 +61,7 @@ import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelati
import cn.axzo.tyr.server.repository.entity.SaasPgroupPermissionRelationOperateLog;
import cn.axzo.tyr.server.repository.mapper.SaasPageElementMapper;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
import cn.axzo.tyr.server.service.SaasPageElementFeatureResourceRelationService;
import cn.axzo.tyr.server.service.SaasPageElementService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationOperateLogService;
@ -61,6 +70,7 @@ import cn.axzo.tyr.server.util.RpcInternalUtil;
import cn.azxo.framework.common.constatns.Constants;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
@ -81,10 +91,13 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -96,6 +109,13 @@ import java.util.concurrent.ExecutorService;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_CODE_DUPLICATE;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_ERROR;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_GROUP_CODE_NOT_FOUND;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_GROUP_CODE_NOT_NULL;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_ITEM_CODE_NOT_FOUND;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_ITEM_CODE_NOT_NULL;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PARAM_ERROR;
import static cn.axzo.tyr.server.event.inner.EventTypeEnum.PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT;
/**
@ -120,6 +140,8 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
private final SaasFeatureResourceService saasFeatureResourceService;
private final SaasPageElementFeatureResourceRelationService saasPageElementFeatureResourceRelationService;
private final SaasPageElementCategoryDao saasPageElementCategoryDao;
private final BasePageElementApi basePageElementApi;
private final SaasPageElementCategoryService saasPageElementCategoryService;
@Qualifier("asyncExecutor")
@Autowired
@ -539,7 +561,11 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
Map<String, List<SaasFeatureResourceResp>> featureResources = listFeatureResource(page.getRecords(), param);
return PageConverter.toResp(page, e -> from(e, featureResources));
Map<String, List<PageElementResp>> childrenPageElements = listChildrenPageElement(page.getRecords(), param);
Map<String, PageElementCategoryResp> pageElementCategories = listPageElementCategory(page.getRecords(), param);
return PageConverter.toResp(page, e -> from(e, featureResources, childrenPageElements, pageElementCategories));
}
@Override
@ -572,7 +598,9 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
IPage<SaasPageElement> page = wrapper.orderByDesc(BaseEntity::getId)
.page(new Page<>(request.getPage(), request.getPageSize()));
List<PageElementResp> list = BeanMapper.copyList(page.getRecords(), PageElementResp.class);
List<PageElementResp> list = page.getRecords().stream()
.map(this::from)
.collect(Collectors.toList());
// 补充元素组名
fillGroupName(list);
// 补充元素iosandroid路由地址
@ -580,81 +608,113 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
return PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list);
}
private PageElementResp from(SaasPageElement saasPageElement) {
PageElementResp result = PageElementResp.builder().build();
BeanUtils.copyProperties(saasPageElement, result);
List<SaasPageElement.Application> applications = saasPageElement.covertToExt().getApplications();
// 把这个平铺出去方便使用
if (CollectionUtils.isNotEmpty(applications)) {
SaasPageElement.Application iosApplication = applications.stream()
.filter(application -> Objects.equals(application.getType(), SaasPageElement.ApplicationTypeEnum.IOS))
.findFirst()
.orElse(null);
if (Objects.nonNull(iosApplication)) {
result.setIosMinVersion(iosApplication.getMinVersion());
result.setIosMaxVersion(iosApplication.getMaxVersion());
result.setIosMaxVersionEnabled(iosApplication.getMaxVersionEnabled());
}
SaasPageElement.Application androidApplication = applications.stream()
.filter(application -> Objects.equals(application.getType(), SaasPageElement.ApplicationTypeEnum.ANDROID))
.findFirst()
.orElse(null);
if (Objects.nonNull(androidApplication)) {
result.setAndroidMinVersion(androidApplication.getMinVersion());
result.setAndroidMaxVersion(androidApplication.getMaxVersion());
result.setAndroidMaxVersionEnabled(androidApplication.getMaxVersionEnabled());
}
}
return result;
}
private SaasPageElement.Ext resolveExt(BatchUpsertPageElementReq.UpsertPageElementReq req) {
List<SaasPageElement.Application> applications = Lists.newArrayList();
if (Objects.nonNull(req.getIosMinVersion())
|| Objects.nonNull(req.getIosMaxVersion())
|| Objects.nonNull(req.getIosMaxVersionEnabled())) {
SaasPageElement.Application application = SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.IOS)
.minVersion(req.getIosMinVersion())
.maxVersion(req.getIosMaxVersion())
.maxVersionEnabled(req.getIosMaxVersionEnabled())
.build();
applications.add(application);
}
if (Objects.nonNull(req.getAndroidMaxVersion())
|| Objects.nonNull(req.getAndroidMinVersion())
|| Objects.nonNull(req.getAndroidMaxVersionEnabled())) {
SaasPageElement.Application application = SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.ANDROID)
.minVersion(req.getAndroidMinVersion())
.maxVersion(req.getAndroidMaxVersion())
.maxVersionEnabled(req.getAndroidMaxVersionEnabled())
.build();
applications.add(application);
}
return SaasPageElement.Ext.builder()
.applications(applications)
.build();
}
private SaasPageElement.Ext resolveExt(SaveOrUpdatePageElementReq req) {
List<SaasPageElement.Application> applications = Lists.newArrayList();
if (Objects.nonNull(req.getIosMinVersion())
|| Objects.nonNull(req.getIosMaxVersion())
|| Objects.nonNull(req.getIosMaxVersionEnabled())) {
SaasPageElement.Application application = SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.IOS)
.minVersion(req.getIosMinVersion())
.maxVersion(req.getIosMaxVersion())
.maxVersionEnabled(req.getIosMaxVersionEnabled())
.build();
applications.add(application);
}
if (Objects.nonNull(req.getAndroidMaxVersion())
|| Objects.nonNull(req.getAndroidMinVersion())
|| Objects.nonNull(req.getAndroidMaxVersionEnabled())) {
SaasPageElement.Application application = SaasPageElement.Application.builder()
.type(SaasPageElement.ApplicationTypeEnum.ANDROID)
.minVersion(req.getAndroidMinVersion())
.maxVersion(req.getAndroidMaxVersion())
.maxVersionEnabled(req.getAndroidMaxVersionEnabled())
.build();
applications.add(application);
}
return SaasPageElement.Ext.builder()
.applications(applications)
.build();
}
@Override
@Transactional(rollbackFor = Exception.class)
public Long saveOrUpdate(SaveOrUpdatePageElementReq req) {
SaasPageElement basePageElement = SaasPageElement.builder()
.version(req.getVersion())
.groupCode(req.getCode())
.code(req.getCode())
.name(req.getName())
.type(req.getType())
.linkUrl(req.getLinkUrl())
.linkExt(getLinkExtStr(req.getIosRouterUrl(), req.getAndroidRouterUrl()))
.appType(req.getAppType())
.appId(req.getAppId())
.itemCode(req.getItemCode())
BatchUpsertPageElementReq.UpsertPageElementReq upsertPageElementReq = BatchUpsertPageElementReq.UpsertPageElementReq.builder().build();
BeanUtils.copyProperties(req, upsertPageElementReq);
BatchUpsertPageElementReq batchUpsertPageElementReq = BatchUpsertPageElementReq.builder()
.operatorId(req.getOperatorId())
.upsertPageElementReqs(Lists.newArrayList(upsertPageElementReq))
.build();
List<Long> ids = batchUpsert(batchUpsertPageElementReq);
if (Objects.nonNull(req.getId())) {
SaasPageElement dbPageElement = saasPageElementDao.getById(req.getId());
AssertUtil.notNull(dbPageElement, "页面元素资源不存在");
basePageElement.setId(dbPageElement.getId());
if (!dbPageElement.getCode().equals(basePageElement.getCode())) {
// 校验code唯一
validCode(basePageElement.getCode());
if (PageElementTypeEnum.PAGE.getCode().equals(req.getType())) {
// 更新子元素的group_code
saasPageElementDao.updateComponentsGroupCode(dbPageElement.getCode(), basePageElement.getCode(), dbPageElement.getTerminal());
}
// 更新关联关系的page_element_code
saasPageElementFeatureResourceRelationDao.updateGroupCode(dbPageElement.getCode(), basePageElement.getCode(), dbPageElement.getTerminal());
}
// page的groupCode是自己的code但是component的groupCode是父级页面的code
// 原来component在更新时会把自己的groupCode更新成自己的code
if (PageElementTypeEnum.COMPONENT.getCode().equals(req.getType())) {
basePageElement.setGroupCode(req.getGroupCode());
}
saasPageElementDao.updateById(basePageElement);
} else {
if (PageElementTypeEnum.PAGE.getCode().equals(req.getType())) {
AssertUtil.isTrue(StringUtils.isNotBlank(req.getItemCode()), "页面元素不存在");
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
.eq(SaasPageElementCategory::getItemCode, req.getItemCode()).list();
AssertUtil.notEmpty(categories, "元素分类不存在。");
SaasPageElementCategory category = categories.get(0);
basePageElement.setTerminal(category.getTerminal());
basePageElement.setItemName(category.getItemName());
} else if (PageElementTypeEnum.COMPONENT.getCode().equals(req.getType())) {
AssertUtil.isTrue(StringUtils.isNotBlank(req.getGroupCode()), "页面元素不存在");
List<SaasPageElement> pageElements = saasPageElementDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
.eq(SaasPageElement::getCode, req.getGroupCode()).list();
AssertUtil.notEmpty(pageElements, "父级元素不存在。");
SaasPageElement pageElement = pageElements.get(0);
basePageElement.setVersion(pageElement.getVersion());
basePageElement.setGroupCode(pageElement.getCode());
basePageElement.setTerminal(pageElement.getTerminal());
basePageElement.setAppType(pageElement.getAppType());
basePageElement.setAppId(pageElement.getAppId());
basePageElement.setItemCode(pageElement.getItemCode());
basePageElement.setItemName(pageElement.getItemName());
}
// 校验code唯一
validCode(basePageElement.getCode());
saasPageElementDao.save(basePageElement);
}
// 记录操作日志
try {
saveOrUpdateOperateLog(req, basePageElement);
} catch (Exception e) {
log.warn("save operate log error", e);
}
return basePageElement.getId();
return ids.stream().findFirst().get();
}
@Override
@ -794,11 +854,16 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
}
private PageElementResp from(SaasPageElement saasPageElement,
Map<String, List<SaasFeatureResourceResp>> featureResources) {
PageElementResp pageElementResp = PageElementResp.builder().build();
Map<String, List<SaasFeatureResourceResp>> featureResources,
Map<String, List<PageElementResp>> childrenPageElements,
Map<String, PageElementCategoryResp> pageElementCategories) {
BeanUtils.copyProperties(saasPageElement, pageElementResp);
PageElementResp pageElementResp = saasPageElement.to();
pageElementResp.setFeatureResources(featureResources.get(saasPageElement.getCode()));
pageElementResp.setChildren(childrenPageElements.get(saasPageElement.getCode()));
pageElementResp.setPageElementCategory(pageElementCategories.get(saasPageElement.getItemCode()));
return pageElementResp;
}
@ -818,10 +883,10 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
.builder()
.pageElementCodes(pageElementCodes)
.build();
List<SaasPageElementFeatureResourceRelation> elementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(elementFeatureResourceRelationReq);
List<PageElementFeatureResourceRelationResp> elementFeatureResourceRelations = saasPageElementFeatureResourceRelationService.list(elementFeatureResourceRelationReq);
Set<String> uniCodes = elementFeatureResourceRelations.stream()
.map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode)
.map(PageElementFeatureResourceRelationResp::getFeatureResourceUniCode)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(uniCodes)) {
@ -836,7 +901,7 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
.collect(Collectors.toMap(SaasFeatureResourceResp::getUniCode, Function.identity()));
return elementFeatureResourceRelations.stream()
.collect(Collectors.groupingBy(SaasPageElementFeatureResourceRelation::getPageElementCode,
.collect(Collectors.groupingBy(PageElementFeatureResourceRelationResp::getPageElementCode,
Collectors.mapping(e -> featureResources.get(e.getFeatureResourceUniCode()), Collectors.toList())));
}
@ -882,6 +947,18 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
}
}
private void saveOrUpdateOperateLog(BatchUpsertPageElementReq req, List<SaasPageElement> basePageElement) {
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
.tableName(PAGE_ELEMENT_TABLE_NAME)
.operatorId(req.getOperatorId())
.scene(PermissionRelationOperateLogSceneEnum.OMS_UPSERT_PAGE_ELEMENT.getValue())
// 批量更新记录id会超长后续提供统一的更基础的日志记录表先暂时用
.sceneId(UuidUtils.generateUuid())
.requestData(req)
.operateData(basePageElement)
.build());
}
private void saveOrUpdateOperateLog(SaveOrUpdatePageElementReq req, SaasPageElement basePageElement) {
saasPgroupPermissionRelationOperateLogService.save(PermissionOperateLogReq.builder()
.tableName(PAGE_ELEMENT_TABLE_NAME)
@ -941,4 +1018,550 @@ public class SaasPageElementServiceImpl extends ServiceImpl<SaasPageElementMappe
.list();
}
private Map<String, List<PageElementResp>> listChildrenPageElement(List<SaasPageElement> pageElements,
PageElementReq param) {
if (CollectionUtils.isEmpty(pageElements) || BooleanUtils.isNotTrue(param.getNeedChildren())) {
return Collections.emptyMap();
}
Set<String> codes = pageElements.stream()
.map(SaasPageElement::getCode)
.collect(Collectors.toSet());
// 因为现在的数据结构type为PAGE的和type为COMPONENT的groupCode一样所以要排除type=PAGE的记录
return this.lambdaQuery()
.in(SaasPageElement::getGroupCode, codes)
.ne(SaasPageElement::getType, PageElementTypeEnum.PAGE)
.list()
.stream()
.map(SaasPageElement::to)
.collect(Collectors.groupingBy(PageElementResp::getGroupCode));
}
/**
* 目前saas_page_element上提现不出来层级关系只有通过type来确定只有type = COMPONENT时才有父节点的记录
* @param pageElements
* @param param
* @return
*/
private Map<String, PageElementResp> listAncestorPageElement(List<SaasPageElement> pageElements,
PageElementReq param) {
if (CollectionUtils.isEmpty(pageElements) || BooleanUtils.isNotTrue(param.getNeedAncestor())) {
return Collections.emptyMap();
}
Set<String> codes = pageElements.stream()
.map(SaasPageElement::getCode)
.collect(Collectors.toSet());
// 因为现在的数据结构type为PAGE的和type为COMPONENT的groupCode一样所以要排除type=PAGE的记录
// return this.lambdaQuery()
// .in(SaasPageElement::getGroupCode, codes)
// .ne(SaasPageElement::getType, PageElementTypeEnum.PAGE)
// .list()
// .stream()
// .map(SaasPageElement::to)
// .collect(Collectors.groupingBy(PageElementResp::getGroupCode));
return Collections.emptyMap();
}
private Map<String, PageElementCategoryResp> listPageElementCategory(List<SaasPageElement> pageElements,
PageElementReq param) {
if (CollectionUtils.isEmpty(pageElements) || BooleanUtils.isNotTrue(param.getNeedPageElementCategory())) {
return Collections.emptyMap();
}
Set<String> itemCodes = pageElements.stream()
.map(SaasPageElement::getItemCode)
.collect(Collectors.toSet());
return saasPageElementCategoryDao.lambdaQuery()
.in(SaasPageElementCategory::getItemCode, itemCodes)
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.value)
.list()
.stream()
.map(e -> {
PageElementCategoryResp pageElementCategoryResp = PageElementCategoryResp.builder().build();
BeanUtils.copyProperties(e, pageElementCategoryResp);
return pageElementCategoryResp;
})
.collect(Collectors.toMap(PageElementCategoryResp::getItemCode, Function.identity()));
}
/**
* 资源对应的category如果不存在则需要补上对应的category
* @param req
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void syncPageElement(SyncPageElementReq req) {
PageElementReq pageElementReq = PageElementReq.builder()
.ids(req.getPageElementIds())
.needPageElementCategory(true)
.needChildren(true)
.build();
List<PageElementResp> prePageElements = RpcInternalUtil.rpcProcessor(() -> basePageElementApi.list(pageElementReq),
"list pageElement from base env", pageElementReq).getData();
if (CollectionUtils.isEmpty(prePageElements)) {
return;
}
// upsert pageElementCategory
upsertPageElementCategory(prePageElements, req);
Map<String, PageElementResp> localDBPageElements = listLocalDBPageElement(prePageElements);
List<BatchUpsertPageElementReq.UpsertPageElementReq> preUpsertPageElements = prePageElements.stream()
.flatMap(e -> {
BatchUpsertPageElementReq.UpsertPageElementReq upsertPageElementReq = from(localDBPageElements, e);
ArrayList<BatchUpsertPageElementReq.UpsertPageElementReq> result = Lists.newArrayList(upsertPageElementReq);
if (CollectionUtils.isEmpty(e.getChildren())) {
return result.stream();
}
result.addAll(e.getChildren().stream()
.map(children -> from(localDBPageElements, children))
.collect(Collectors.toList()));
return result.stream();
})
.collect(Collectors.toList());
BatchUpsertPageElementReq batchUpsertPageElementReq = BatchUpsertPageElementReq.builder()
.upsertPageElementReqs(preUpsertPageElements)
.operatorId(req.getOperatorId())
.build();
batchUpsert(batchUpsertPageElementReq);
}
private BatchUpsertPageElementReq.UpsertPageElementReq from(Map<String, PageElementResp> localDBPageElements,
PageElementResp pageElementResp) {
PageElementResp localDBPageElement = localDBPageElements.get(pageElementResp.getCode());
BatchUpsertPageElementReq.UpsertPageElementReq upsertPageElementReq = BatchUpsertPageElementReq.UpsertPageElementReq.builder().build();
BeanUtils.copyProperties(pageElementResp, upsertPageElementReq);
upsertPageElementReq.setId(Objects.isNull(localDBPageElement) ? null : localDBPageElement.getId());
return upsertPageElementReq;
}
private void upsertPageElementCategory(List<PageElementResp> prePageElements,
SyncPageElementReq req) {
List<PageElementCategoryResp> prePageElementCategories = prePageElements.stream()
.map(PageElementResp::getPageElementCategory)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(prePageElementCategories)) {
log.info("no pageElementCategory need sync");
return;
}
Map<String, PageElementCategoryResp> localDBPageElementCategories = saasPageElementCategoryService.list(PageElementCategoryV2Req.builder()
.itemCodes(prePageElementCategories.stream()
.map(PageElementCategoryResp::getItemCode)
.collect(Collectors.toSet()))
.build())
.stream()
.collect(Collectors.toMap(PageElementCategoryResp::getItemCode, Function.identity()));
List<BatchUpsertPageElementCategoryReq.UpsertPageElementCategory> upsert = prePageElementCategories.stream()
.map(e -> {
PageElementCategoryResp localDBPageElementCategory = localDBPageElementCategories.get(e.getItemCode());
return BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder()
.id(Optional.ofNullable(localDBPageElementCategory)
.map(PageElementCategoryResp::getId)
.orElse(null))
.terminal(e.getTerminal())
.itemCode(e.getItemCode())
.itemName(e.getItemName())
.build();
})
.distinct()
.collect(Collectors.toList());
BatchUpsertPageElementCategoryReq batchUpsertPageElementCategoryReq = BatchUpsertPageElementCategoryReq.builder()
.operatorId(req.getOperatorId())
.upsertPageElementCategories(upsert)
.build();
saasPageElementCategoryService.batchUpsert(batchUpsertPageElementCategoryReq);
}
private Map<String, PageElementResp> listLocalDBPageElement(List<PageElementResp> prePageElements) {
Set<String> codes = prePageElements.stream()
.map(PageElementResp::getCode)
.collect(Collectors.toSet());
Set<String> childrenCodes = prePageElements.stream()
.map(PageElementResp::getChildren)
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.map(PageElementResp::getCode)
.collect(Collectors.toSet());
codes.addAll(childrenCodes);
return this.list(PageElementReq.builder()
.codes(codes)
.needPageElementCategory(true)
.build())
.stream()
.collect(Collectors.toMap(PageElementResp::getCode, Function.identity()));
}
/**
* 对type = page的数据进行upsert
* @param req
* @return
*/
private List<SaasPageElement> upsertPage(BatchUpsertPageElementReq req,
Map<Long, SaasPageElement> oldSaasPageElements) {
List<BatchUpsertPageElementReq.UpsertPageElementReq> pages = req.getUpsertPageElementReqs().stream()
.filter(e -> Objects.equals(PageElementTypeEnum.PAGE.getCode(), e.getType()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(pages)) {
return Collections.emptyList();
}
Map<String, SaasPageElementCategory> cagetories = checkItemCode(pages);
List<SaasPageElement> upsert = pages.stream()
.map(e -> {
SaasPageElement saasPageElement = SaasPageElement.builder()
.version(e.getVersion())
.groupCode(e.getCode())
.code(e.getCode())
.name(e.getName())
.type(e.getType())
.linkUrl(e.getLinkUrl())
.linkExt(getLinkExtStr(e.getIosRouterUrl(), e.getAndroidRouterUrl()))
.appType(e.getAppType())
.appId(e.getAppId())
.itemCode(e.getItemCode())
.createBy(Objects.nonNull(e.getId()) ? null : req.getOperatorId())
.updateBy(req.getOperatorId())
.build();
SaasPageElementCategory category = cagetories.get(e.getItemCode());
Axssert.notNull(category, PAGE_ELEMENT_ITEM_CODE_NOT_FOUND);
saasPageElement.setTerminal(category.getTerminal());
saasPageElement.setItemCode(category.getItemCode());
saasPageElement.setItemName(category.getItemName());
SaasPageElement.Ext ext = resolveExt(e);
if (Objects.nonNull(e.getId())) {
SaasPageElement dbPageElement = oldSaasPageElements.get(e.getId());
Axssert.notNull(dbPageElement, PAGE_ELEMENT_ERROR);
saasPageElement.setExt(dbPageElement.buildMergedExt(ext));
} else {
saasPageElement.setExt(saasPageElement.buildMergedExt(ext));
}
saasPageElement.setId(e.getId());
return saasPageElement;
})
.collect(Collectors.toList());
this.saveOrUpdateBatch(upsert);
return upsert;
}
/**
* 对type = COMPONENT的数据进行upsert
* @param req
* @param oldSaasPageElements
* @return
*/
private List<SaasPageElement> upsertComponent(BatchUpsertPageElementReq req,
Map<Long, SaasPageElement> oldSaasPageElements) {
List<BatchUpsertPageElementReq.UpsertPageElementReq> components = req.getUpsertPageElementReqs().stream()
.filter(e -> Objects.equals(PageElementTypeEnum.COMPONENT.getCode(), e.getType()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(components)) {
return Collections.emptyList();
}
Map<String, SaasPageElement> parentPageElements = checkGroupCode(components);
List<SaasPageElement> upsert = components.stream()
.map(e -> {
SaasPageElement parentPageElement = parentPageElements.get(e.getGroupCode());
Axssert.notNull(parentPageElement, PAGE_ELEMENT_GROUP_CODE_NOT_FOUND);
SaasPageElement saasPageElement = SaasPageElement.builder()
.version(parentPageElement.getVersion())
.groupCode(parentPageElement.getCode())
.terminal(parentPageElement.getTerminal())
.appType(parentPageElement.getAppType())
.appId(parentPageElement.getAppId())
.itemCode(parentPageElement.getItemCode())
.itemName(parentPageElement.getItemName())
.code(e.getCode())
.name(e.getName())
.type(e.getType())
.linkUrl(e.getLinkUrl())
.linkExt(getLinkExtStr(e.getIosRouterUrl(), e.getAndroidRouterUrl()))
.createBy(Objects.nonNull(e.getId()) ? null : req.getOperatorId())
.updateBy(req.getOperatorId())
.build();
SaasPageElement.Ext ext = resolveExt(e);
if (Objects.nonNull(e.getId())) {
SaasPageElement dbPageElement = oldSaasPageElements.get(e.getId());
Axssert.notNull(dbPageElement, PAGE_ELEMENT_ERROR);
saasPageElement.setExt(dbPageElement.buildMergedExt(ext));
} else {
saasPageElement.setExt(saasPageElement.buildMergedExt(ext));
}
saasPageElement.setId(e.getId());
return saasPageElement;
})
.collect(Collectors.toList());
this.saveOrUpdateBatch(upsert);
return upsert;
}
@Override
@Transactional(rollbackFor = Exception.class)
public List<Long> batchUpsert(BatchUpsertPageElementReq req) {
Axssert.checkNotEmpty(req.getUpsertPageElementReqs(), PARAM_ERROR);
checkCode(req);
Map<Long, SaasPageElement> oldSaasPageElements = checkId(req);
// 原来设计问题点
// 1组件的groupCode是父级页面的code页面的groupCode是页面的code
// 2组件的itemCode使用父级页面的itemCode并且冗余了itemName
// 3新增页面需要根据itemCode找到category设置terminalitemCodeitemName
// 4新增组件需要根据页面的信息设置terminalitemCodeitemNameappTypeappId等
// 分开按照页面组件进行操作页面组件都可能需要新增checkGroupCode就不会成功1同步2一个入口同时添加页面组件
List<SaasPageElement> saasPageElements = Lists.newArrayList();
List<SaasPageElement> pageElements = upsertPage(req, oldSaasPageElements);
saasPageElements.addAll(pageElements);
List<SaasPageElement> componentElements = upsertComponent(req, oldSaasPageElements);
saasPageElements.addAll(componentElements);
// 1更新页面的code时需要把对应组件的groupCode都更新需要把菜单资源关联表的pageCode进行更新
// 2更新组件的code时需要把菜单资源关联表的pageCode进行更新
refreshRelationData(req, oldSaasPageElements);
// 记录操作日志
try {
saveOrUpdateOperateLog(req, saasPageElements);
} catch (Exception e) {
log.warn("save operate log error", e);
}
Event event = Event.builder()
.targetType(TARGET_TYPE)
.eventCode(PAGE_ELEMENT_FEATURE_RESOURCE_UPSERT.getEventCode())
.data(PageElementFeatureResourceUpsertPayload.builder()
.terminal(saasPageElements.stream()
.map(SaasPageElement::getTerminal)
.findFirst()
.orElse(null))
.build())
.build();
mqProducer.send(event);
return saasPageElements.stream()
.map(BaseEntity::getId)
.collect(Collectors.toList());
}
private void refreshRelationData(BatchUpsertPageElementReq req,
Map<Long, SaasPageElement> oldSaasPageElements) {
// first:oldCode second:newCode
Map<String, BatchUpsertPageElementReq.UpsertPageElementReq> updatedCodePageElements = req.getUpsertPageElementReqs().stream()
.map(e -> {
if (Objects.isNull(e.getId())) {
return null;
}
SaasPageElement oldPageElement = oldSaasPageElements.get(e.getId());
if (Objects.equals(oldPageElement.getCode(), e.getCode())) {
return null;
}
return Pair.of(oldPageElement.getCode(), e);
})
.filter(Objects::nonNull)
.collect(Collectors.toMap(Pair::getFirst, Pair::getSecond));
if (updatedCodePageElements.isEmpty()) {
return;
}
// TODO 待统一的更新接口收口后切换
updateComponentGroupCode(updatedCodePageElements);
// 更新关联关系的page_element_code
updatePageElementFeatureResource(updatedCodePageElements);
}
private void updateComponentGroupCode(Map<String, BatchUpsertPageElementReq.UpsertPageElementReq> updatedCodePageElementMap) {
if (Objects.isNull(updatedCodePageElementMap) || updatedCodePageElementMap.isEmpty()) {
return;
}
List<BatchUpsertPageElementReq.UpsertPageElementReq> updatedCodePageElements = updatedCodePageElementMap.values().stream()
.filter(e -> Objects.equals(PageElementTypeEnum.PAGE.getCode(), e.getType()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(updatedCodePageElements)) {
return;
}
List<SaasPageElement> components = this.lambdaQuery()
.in(SaasPageElement::getGroupCode, updatedCodePageElementMap.keySet())
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.getValue())
.eq(SaasPageElement::getType, PageElementTypeEnum.COMPONENT.getCode())
.list();
if (CollectionUtils.isEmpty(components)) {
return;
}
this.updateBatchById(components.stream()
.map(e -> {
SaasPageElement saasPageElement = SaasPageElement.builder()
.groupCode(updatedCodePageElementMap.get(e.getGroupCode()).getCode())
.build();
saasPageElement.setId(e.getId());
return saasPageElement;
})
.collect(Collectors.toList()));
}
private void updatePageElementFeatureResource(Map<String, BatchUpsertPageElementReq.UpsertPageElementReq> updatedCodePageElements) {
if (Objects.isNull(updatedCodePageElements) || updatedCodePageElements.isEmpty()) {
return;
}
List<SaasPageElementFeatureResourceRelation> pageElementFeatureResourceRelations = saasPageElementFeatureResourceRelationDao.lambdaQuery()
.in(SaasPageElementFeatureResourceRelation::getPageElementCode, updatedCodePageElements.keySet())
.eq(SaasPageElementFeatureResourceRelation::getIsDelete, DeleteEnum.NORMAL.getValue())
.list();
if (CollectionUtils.isEmpty(pageElementFeatureResourceRelations)) {
return;
}
List<SaasPageElementFeatureResourceRelation> updates = pageElementFeatureResourceRelations.stream()
.map(e -> {
SaasPageElementFeatureResourceRelation result = SaasPageElementFeatureResourceRelation.builder()
.pageElementCode(updatedCodePageElements.get(e.getPageElementCode()).getCode())
.build();
result.setId(e.getId());
return result;
})
.collect(Collectors.toList());
saasPageElementFeatureResourceRelationDao.updateBatchById(updates);
}
private Map<Long, SaasPageElement> checkId(BatchUpsertPageElementReq req) {
Set<Long> ids = req.getUpsertPageElementReqs().stream()
.map(BatchUpsertPageElementReq.UpsertPageElementReq::getId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyMap();
}
List<SaasPageElement> pageElements = saasPageElementDao.listByIds(ids);
if (!Objects.equals(ids.size(), pageElements.size())) {
ids.removeAll(pageElements.stream().map(SaasPageElement::getId).collect(Collectors.toSet()));
throw PAGE_ELEMENT_ERROR.toException(PAGE_ELEMENT_ERROR.getErrorMessage(), ids);
}
return pageElements.stream()
.collect(Collectors.toMap(SaasPageElement::getId, Function.identity()));
}
private Map<String, SaasPageElement> checkGroupCode(List<BatchUpsertPageElementReq.UpsertPageElementReq> components) {
// 后续如果有其他类型也需要传groupCode这里就不按照组件来过滤
Set<String> groupCodes = components.stream()
.map(BatchUpsertPageElementReq.UpsertPageElementReq::getGroupCode)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
Axssert.checkNotEmpty(groupCodes, PAGE_ELEMENT_GROUP_CODE_NOT_NULL);
List<SaasPageElement> pageElements = saasPageElementDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
.in(SaasPageElement::getCode, groupCodes)
.list();
if (!Objects.equals(groupCodes.size(), pageElements.size())) {
groupCodes.removeAll(pageElements.stream().map(SaasPageElement::getCode).collect(Collectors.toSet()));
throw PAGE_ELEMENT_GROUP_CODE_NOT_FOUND.toException(PAGE_ELEMENT_GROUP_CODE_NOT_FOUND.getErrorMessage(), groupCodes);
}
return pageElements.stream()
.collect(Collectors.toMap(SaasPageElement::getCode, Function.identity()));
}
private Map<String, SaasPageElementCategory> checkItemCode(List<BatchUpsertPageElementReq.UpsertPageElementReq> pages) {
Set<String> itemCodes = pages.stream()
.map(BatchUpsertPageElementReq.UpsertPageElementReq::getItemCode)
.filter(StringUtils::isNotBlank)
.collect(Collectors.toSet());
Axssert.checkNotEmpty(itemCodes, PAGE_ELEMENT_ITEM_CODE_NOT_NULL);
List<SaasPageElementCategory> categories = saasPageElementCategoryDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, DeleteEnum.NORMAL.getValue())
.in(SaasPageElementCategory::getItemCode, itemCodes)
.list();
if (!Objects.equals(itemCodes.size(), categories.size())) {
itemCodes.removeAll(categories.stream().map(SaasPageElementCategory::getItemCode).collect(Collectors.toSet()));
throw PAGE_ELEMENT_ITEM_CODE_NOT_FOUND.toException(PAGE_ELEMENT_ITEM_CODE_NOT_FOUND.getErrorMessage(), itemCodes);
}
return categories.stream()
.collect(Collectors.toMap(SaasPageElementCategory::getItemCode, Function.identity()));
}
private void checkCode(BatchUpsertPageElementReq req) {
// check新增或者更新的Code是否已经存在
List<String> codes = req.getUpsertPageElementReqs().stream()
.map(BatchUpsertPageElementReq.UpsertPageElementReq::getCode)
.collect(Collectors.toList());
List<SaasPageElement> saasPageElements = this.lambdaQuery()
.in(SaasPageElement::getCode, codes)
.eq(SaasPageElement::getIsDelete, DeleteEnum.NORMAL.value)
.list();
if (CollectionUtils.isEmpty(saasPageElements)) {
return;
}
Map<String, SaasPageElement> codeMap = saasPageElements.stream()
.collect(Collectors.toMap(SaasPageElement::getCode, Function.identity()));
List<String> dbDuplicateCodes = req.getUpsertPageElementReqs().stream()
.filter(e -> {
SaasPageElement oldSaasPageElement = codeMap.get(e.getCode());
if (Objects.isNull(oldSaasPageElement)) {
return false;
}
// 新增里重复的code
if (Objects.isNull(e.getId())) {
return true;
}
// 更新里重复的code
return !Objects.equals(e.getId(), oldSaasPageElement.getId());
})
.map(BatchUpsertPageElementReq.UpsertPageElementReq::getCode)
.collect(Collectors.toList());
Axssert.check(CollectionUtils.isEmpty(dbDuplicateCodes), PAGE_CODE_DUPLICATE,
PAGE_CODE_DUPLICATE.getErrorMessage(), dbDuplicateCodes);
}
}

View File

@ -0,0 +1,69 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.framework.auth.domain.TerminalInfo;
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.model.req.GetTerminalInfoReq;
import cn.axzo.tyr.client.model.res.TerminalConfigRes;
import cn.axzo.tyr.server.controller.terminal.TerminalController;
import cn.axzo.tyr.server.service.TerminalService;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class TerminalServiceImpl implements TerminalService {
@Autowired
private ConfigApi configApi;
@Autowired
private TerminalController terminalController;
private static final String TERMINAL_CONFIG = "terminal.config";
@Override
public 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 null;
}
return JSON.parseObject(configByBizCode.getContent(), TerminalConfigRes.class);
}
private LoadingCache<String, Optional<TerminalInfo>> terminalInfoCache = CacheBuilder.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(100)
.build(new CacheLoader<String, Optional<TerminalInfo>>() {
@Override
public Optional<TerminalInfo> load(String terminalCode) {
GetTerminalInfoReq getTerminalInfoReq = GetTerminalInfoReq.builder()
.terminalCode(terminalCode)
.build();
return Optional.ofNullable(terminalController.getTerminalInfo(getTerminalInfoReq).getData());
}
});
@Override
public TerminalInfo getTerminalInfo(GetTerminalInfoReq param) {
return terminalInfoCache.getUnchecked(param.getTerminalCode())
.orElseGet(() -> new TerminalInfo(param.getTerminalCode()));
}
}

View File

@ -25,6 +25,7 @@ import cn.axzo.tyr.client.model.req.WorkspacePermissionIdentityReq;
import cn.axzo.tyr.client.model.res.IdentityAuthRes;
import cn.axzo.tyr.client.model.res.ListIdentityFromPermissionResp;
import cn.axzo.tyr.client.model.res.ListPermissionFromRoleGroupResp;
import cn.axzo.tyr.client.model.res.PageElementFeatureResourceRelationResp;
import cn.axzo.tyr.client.model.res.QueryIdentityByPermissionResp;
import cn.axzo.tyr.client.model.res.SaasFeatureResourceResp;
import cn.axzo.tyr.client.model.res.SaasRoleRes;
@ -36,7 +37,6 @@ import cn.axzo.tyr.server.repository.entity.ProductFeatureQuery;
import cn.axzo.tyr.server.repository.entity.RolePermission;
import cn.axzo.tyr.server.repository.entity.SaasFeature;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasPageElementFeatureResourceRelation;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
import cn.axzo.tyr.server.repository.entity.SaasRoleWithUser;
import cn.axzo.tyr.server.repository.mapper.SaasRoleUserRelationMapper;
@ -380,8 +380,9 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
PageElementFeatureResourceRelationReq pageElementFeatureResourceRelationReq = PageElementFeatureResourceRelationReq.builder()
.pageElementCodes(req.getFeatureCodes())
.terminal(req.getTerminal())
.needFeatureResource(true)
.build();
List<SaasPageElementFeatureResourceRelation> relations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq);
List<PageElementFeatureResourceRelationResp> relations = saasPageElementFeatureResourceRelationService.list(pageElementFeatureResourceRelationReq);
if (CollectionUtils.isEmpty(relations)) {
log.info("not found in SaasPageElementFeatureResourceRelation, featureCodes:{},terminal:{}",
@ -389,14 +390,13 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
return Collections.emptyList();
}
Set<String> uniCodes = relations.stream().map(SaasPageElementFeatureResourceRelation::getFeatureResourceUniCode).collect(Collectors.toSet());
PageSaasFeatureResourceReq pageSaasFeatureResourceReq = PageSaasFeatureResourceReq.builder()
.uniCodes(uniCodes)
.build();
List<SaasFeatureResourceResp> featureResources = saasFeatureResourceService.list(pageSaasFeatureResourceReq);
List<SaasFeatureResourceResp> featureResources = relations.stream()
.map(PageElementFeatureResourceRelationResp::getSaasFeatureResource)
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(featureResources)) {
log.info("not found in SaasFeatureResource, unicode:{}", uniCodes);
log.info("not found in SaasFeatureResource, pageElementCodes:{}", req.getFeatureCodes());
return Collections.emptyList();
}
return saasFeatureResourceService.list(PageSaasFeatureResourceReq.builder()
@ -1229,8 +1229,6 @@ public class TyrSaasAuthServiceImpl implements TyrSaasAuthService {
|| Objects.equals(identityAuthReq.getItemCode(), f.getItemCode()))
.filter(f -> StringUtils.isBlank(identityAuthReq.getAppType())
|| Objects.equals(identityAuthReq.getAppType(), f.getAppType()))
.filter(f -> Objects.isNull(identityAuthReq.getVersionMax())
|| identityAuthReq.getVersionMax().compareTo(f.getVersion()) > -1)
.collect(Collectors.toList()))
.orElse(null);

View File

@ -1,127 +0,0 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.thrones.client.saas.ServicePkgClient;
import cn.axzo.thrones.client.saas.entity.serivicepgkproduct.ServicePkgProduct;
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
import cn.axzo.tyr.base.BaseTest;
import cn.axzo.tyr.base.MysqlDataLoader;
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.client.model.res.IdentityAuthRes;
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
import cn.axzo.tyr.server.repository.entity.ProductModule;
import cn.axzo.tyr.server.service.PermissionQueryService;
import cn.axzo.tyr.server.service.TyrSaasAuthService;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.collection.CollectionUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@Slf4j
class PermissionQueryServiceImplTest extends BaseTest {
@Autowired
private PermissionQueryService permissionQueryService;
@Autowired
private MysqlDataLoader mysqlDataLoader;
@Autowired
private TyrSaasAuthService tyrSaasAuthService;
@Autowired
private SaasFeatureDao saasFeatureDao;
@Autowired
private ServicePkgClient servicePkgClient;
@Autowired
private ProductModuleDao productModuleDao;
@BeforeEach
@Override
public void setup() {
super.setup();
mysqlDataLoader.loadFromClassName(getClass().getSimpleName());
MockitoAnnotations.initMocks(this);
}
@Test
void hasPermissionNew() {
ServicePkgDetailRes servicePkgDetailRes = new ServicePkgDetailRes();
ServicePkgProduct servicePkgProduct = new ServicePkgProduct();
servicePkgProduct.setProductId(1L);
ServicePkgProduct servicePkgProduct2 = new ServicePkgProduct();
servicePkgProduct2.setProductId(6L);
servicePkgDetailRes.setProducts(Lists.newArrayList(
servicePkgProduct,
servicePkgProduct2
));
Mockito.when(servicePkgClient.getServicePkgDetailBySpaceId(Mockito.any()))
.thenReturn(CommonResponse.success(Lists.newArrayList(servicePkgDetailRes)));
// 普通角色和产品有旧权限码权限begin
PermissionCheckReq permissionCheckReq = PermissionCheckReq.builder()
.personId(80792L)
.featureCodes(Lists.newArrayList("cms:ent_contact", "cms:ent_contact_new"))
.ouId(5154L)
.workspaceId(205L)
.build();
List<ProductModule> list = productModuleDao.list();
log.info("size:{}", list.size());
System.out.println("size+" + list.size());
new Thread(() -> {
synchronized (this) {
List<ProductModule> productModules = productModuleDao.list();
log.info("inner size:{}", productModules.size());
System.out.println("inner size+" + list.size());
}
}).start();
boolean result = authPermission(permissionCheckReq);
boolean resultOld = authPermissionOld(permissionCheckReq);
Assertions.assertTrue(result);
Assertions.assertTrue(resultOld);
// 普通角色和产品有旧权限码权限end
// 管理员角色和产品有旧权限码权限begin
permissionCheckReq = PermissionCheckReq.builder()
.personId(80792L)
.featureCodes(Lists.newArrayList("cms:ent_contact", "cms:ent_contact_new"))
.ouId(5154L)
.workspaceId(290L)
.build();
result = authPermission(permissionCheckReq);
resultOld = authPermissionOld(permissionCheckReq);
Assertions.assertTrue(result);
Assertions.assertTrue(resultOld);
// 管理员角色和产品有旧权限码权限end
}
private boolean authPermission(PermissionCheckReq permissionCheckReq) {
return tyrSaasAuthService.authPermission(permissionCheckReq) || tyrSaasAuthService.authNewPermission(permissionCheckReq);
}
private boolean authPermissionOld(PermissionCheckReq req) {
IdentityAuthReq authReq = IdentityAuthReq.builder()
.personId(req.getPersonId())
.workspaceOusPairs(Collections.singletonList(IdentityAuthReq.WorkspaceOuPair.builder()
.workspaceId(req.getWorkspaceId())
.ouId(req.getOuId()).build()))
.featureCode(new HashSet<>(req.getFeatureCodes()))
.terminal(StringUtils.isBlank(req.getTerminal()) ? null : Collections.singletonList(req.getTerminal()))
.build();
IdentityAuthRes.WorkspacePermission permissions = tyrSaasAuthService.findIdentityAuthMix(authReq).getPermissions().get(0);
return CollectionUtil.isNotEmpty(permissions.getPermissionPoint());
}
}

View File

@ -0,0 +1,49 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.foundation.exception.BusinessException;
import cn.axzo.tyr.base.BaseTest;
import cn.axzo.tyr.base.MysqlDataLoader;
import cn.axzo.tyr.client.model.req.CloneTerminalReq;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import static cn.axzo.tyr.server.config.exception.BizResultCode.TERMINAL_CODE_EXIST;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class SaasFeatureResourceServiceImplTest extends BaseTest {
@Autowired
private MysqlDataLoader mysqlDataLoader;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@BeforeEach
@Override
public void setup() {
super.setup();
mysqlDataLoader.loadFromClassName(getClass().getSimpleName());
MockitoAnnotations.initMocks(this);
}
@Test
void testClone() {
BusinessException businessException = assertThrows(BusinessException.class, ()->{
CloneTerminalReq req = CloneTerminalReq.builder()
.fromTerminalId(3434L)
.newTerminalCode("NT_PC_GA_TFXQZW_GENERAL")
.newTerminalName("测试克隆端")
.newTerminalFeatureCodePrefix("TEST")
.operatorId(111L)
.build();
saasFeatureResourceService.clone(req);
});
assertEquals(businessException.getErrorCode(), TERMINAL_CODE_EXIST.getErrorCode());
assertEquals(businessException.getErrorMsg(), "新端已经存在:[3434]");
}
}

View File

@ -0,0 +1,53 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.foundation.exception.BusinessException;
import cn.axzo.tyr.base.BaseTest;
import cn.axzo.tyr.client.model.req.BatchUpsertPageElementCategoryReq;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementCategoryReq;
import cn.axzo.tyr.server.service.SaasPageElementCategoryService;
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
import com.google.common.collect.Sets;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
import static cn.axzo.tyr.server.config.exception.BizResultCode.ITEM_NAME_DUPLICATE;
import static cn.axzo.tyr.server.config.exception.BizResultCode.REMOVE_USER_ROLE_ERROR;
import static org.junit.jupiter.api.Assertions.*;
class SaasPageElementCategoryServiceImplTest extends BaseTest {
@Autowired
private SaasPageElementCategoryService saasPageElementCategoryService;
@BeforeEach
@Override
public void setup() {
super.setup();
}
@Test
void batchUpsert() {
BusinessException businessException = assertThrows(BusinessException.class, ()->{
List<BatchUpsertPageElementCategoryReq.UpsertPageElementCategory> req = Lists.newArrayList(
BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder().itemName("A1").build(),
BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder().itemName("A1").build(),
BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder().itemName("B1").build(),
BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder().itemName("B1").build(),
BatchUpsertPageElementCategoryReq.UpsertPageElementCategory.builder().itemName("C1").build()
);
BatchUpsertPageElementCategoryReq batchUpsertPageElementCategoryReq = BatchUpsertPageElementCategoryReq.builder()
.upsertPageElementCategories(req)
.operatorId(11L)
.build();
saasPageElementCategoryService.batchUpsert(batchUpsertPageElementCategoryReq);
});
assertEquals(businessException.getErrorCode(), ITEM_NAME_DUPLICATE.getErrorCode());
assertEquals(businessException.getErrorMsg(), "资源分组名字重复,重复的名字:[A1, B1]");
}
}

View File

@ -0,0 +1,45 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.foundation.exception.BusinessException;
import cn.axzo.tyr.base.BaseTest;
import cn.axzo.tyr.base.MysqlDataLoader;
import cn.axzo.tyr.client.model.req.SaveOrUpdatePageElementReq;
import cn.axzo.tyr.server.service.SaasPageElementService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.annotation.Autowired;
import static cn.axzo.tyr.server.config.exception.BizResultCode.PAGE_ELEMENT_ERROR;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
class SaasPageElementServiceImplTest extends BaseTest {
@Autowired
private MysqlDataLoader mysqlDataLoader;
@Autowired
private SaasPageElementService saasPageElementService;
@BeforeEach
@Override
public void setup() {
super.setup();
mysqlDataLoader.loadFromClassName(getClass().getSimpleName());
MockitoAnnotations.initMocks(this);
}
@Test
void saveOrUpdate() {
// 更新时id是错的
BusinessException businessException = assertThrows(BusinessException.class, ()->{
SaveOrUpdatePageElementReq saveOrUpdatePageElementReq = SaveOrUpdatePageElementReq.builder()
.id(1L)
.build();
saasPageElementService.saveOrUpdate(saveOrUpdatePageElementReq);
});
assertEquals(businessException.getErrorCode(), PAGE_ELEMENT_ERROR.getErrorCode());
assertEquals(businessException.getErrorMsg(), "资源分组错误:[1]");
}
}

View File

@ -1,62 +0,0 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.tyr.base.BaseTest;
import cn.axzo.tyr.base.MysqlDataLoader;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.server.repository.dao.SaasFeatureDao;
import cn.axzo.tyr.server.repository.dao.SaasRoleDao;
import cn.axzo.tyr.server.repository.entity.SaasFeature;
import cn.axzo.tyr.server.service.TyrSaasAuthService;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import static org.junit.jupiter.api.Assertions.*;
class TyrSaasAuthServiceImplTest extends BaseTest {
@Autowired
private MysqlDataLoader mysqlDataLoader;
@Autowired
private TyrSaasAuthService tyrSaasAuthService;
@Autowired
private SaasFeatureDao saasFeatureDao;
@BeforeEach
@Override
public void setup() {
super.setup();
mysqlDataLoader.loadFromClassName(getClass().getSimpleName());
}
@Test
void authPermission() {
saasFeatureDao.save(SaasFeature.builder()
.featureCode("CMS_001")
.terminal("CMS")
.build());
PermissionCheckReq permissionCheckReq = PermissionCheckReq.builder()
.ouId(5708L)
.workspaceId(300L)
.personId(42642L)
.featureCodes(Lists.newArrayList("dfff"))
.build();
boolean result = tyrSaasAuthService.authPermission(permissionCheckReq);
Assertions.assertFalse(result);
result = tyrSaasAuthService.authPermission(PermissionCheckReq.builder()
.ouId(5708L)
.workspaceId(300L)
.personId(42642L)
.featureCodes(Lists.newArrayList("CMS_001"))
.terminal("sdf")
.build());
Assertions.assertFalse(result);
}
}

View File

@ -0,0 +1,111 @@
#-->DEFAULT
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102223, 'ROOT:NT_PC_GA_YX_GZZW_GENERAL', '越秀地产(广州区域)PC端', 5, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 0, '102223,', 0, '', 0, 'ROOT:NT_PC_GA_YX_GZZW_GENERAL', 26, 1, '', 0, ' ', 1, ' ', null, 0, null, 1, 0, '2024-10-15 16:14:00', '2024-11-26 17:09:48', 25923, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102226, 'NT_PC_GA_YX_GZZW_GENERAL:home_page', '首页', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102226,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:home_page', 0, 1, '', 1, '/home-page/home', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:21:09', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102227, 'NT_PC_GA_YX_GZZW_GENERAL:salary_supervision_menu', '薪资监管', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102227,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_supervision_menu', 1, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:22:42', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102228, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_menu', '风险预警', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102228,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_menu', 2, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 09:49:29', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102229, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_page', '整改单', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102229,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_page', 3, 1, '', 1, '/warn-manage/rectification-form', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 09:59:21', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102230, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_detail_btn', '查看', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102229, '102223,102229,102230,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 09:59:21', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102231, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_handle_btn', '去处理', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102229, '102223,102229,102231,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rectification_handle_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 09:59:21', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102232, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_page', '信访调处', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102232,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_page', 4, 1, '', 1, '/complaint-manage/offline-complaint', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:04:36', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102233, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_add_btn', '新建', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102232, '102223,102232,102233,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:04:36', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102234, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_export_btn', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102232, '102223,102232,102234,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_export_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:04:36', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102235, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_handle_btn', '去处理', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102232, '102223,102232,102235,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:complaint_handle_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:04:36', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102236, 'NT_PC_GA_YX_GZZW_GENERAL:check_list_page', '隐患排查', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102236,', 0, '0', 0, 'NT_PC_GA_YX_GZZW_GENERAL:check_list_page', 5, 1, '', 1, '/hidden-risk/check-list', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:05:28', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102237, 'NT_PC_GA_YX_GZZW_GENERAL:check_list_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102236, '102223,102236,102237,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:check_list_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:05:28', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102238, 'NT_PC_GA_YX_GZZW_GENERAL:credit_menu', '行业征信', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102238,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:credit_menu', 6, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 10:06:52', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102239, 'NT_PC_GA_YX_GZZW_GENERAL:data_drive_center_menu', '数据中心', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102239,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:data_drive_center_menu', 7, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 10:18:34', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102240, 'NT_PC_GA_YX_GZZW_GENERAL:sys_menu', '系统管理', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102223, '102223,102240,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:sys_menu', 8, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 10:53:25', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102241, 'NT_PC_GA_YX_GZZW_GENERAL:special_account_page', '专户管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102227, '102223,102227,102241,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:special_account_page', 0, 1, '', 1, '/fund-supervision/special-account-list', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:25:31', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102242, 'NT_PC_GA_YX_GZZW_GENERAL:special_account_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102241, '102223,102227,102241,102242,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:special_account_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:25:31', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102243, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_menu', '拨付管理', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102227, '102223,102227,102243,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_menu', 1, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:26:20', '2024-10-16 11:12:47', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102244, 'NT_PC_GA_YX_GZZW_GENERAL:salary_statistics_menu', '发薪统计', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102227, '102223,102227,102244,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_statistics_menu', 2, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:34:12', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102245, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_menu', '预付管理', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102227, '102223,102227,102245,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_menu', 3, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:43:54', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102246, 'NT_PC_GA_YX_GZZW_GENERAL:history_page', '历史人工费', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102227, '102223,102227,102246,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:history_page', 4, 1, '', 1, '/fund-supervision/history-labor-cost/summary-list', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 09:47:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102247, 'NT_PC_GA_YX_GZZW_GENERAL:history_detail_page', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102246, '102223,102227,102246,102247,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:history_detail_page', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:47:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102248, 'NT_PC_GA_YX_GZZW_GENERAL:history_export_btn', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102246, '102223,102227,102246,102248,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:history_export_btn', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:47:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102249, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_event_page', '预警事件', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102228, '102223,102228,102249,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_event_page', 0, 1, '', 1, '/warn-manage/event-list', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 09:51:02', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102250, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_event_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102249, '102223,102228,102249,102250,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:alarm_event_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:51:02', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102251, 'NT_PC_GA_YX_GZZW_GENERAL:event_view_rectification_btn', '查看整改单', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102250, '102223,102228,102249,102250,102251,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:event_view_rectification_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:51:02', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102252, 'NT_PC_GA_YX_GZZW_GENERAL:event_view_report_btn', '查看报告', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102250, '102223,102228,102249,102250,102252,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:event_view_report_btn', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:51:02', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102253, 'NT_PC_GA_YX_GZZW_GENERAL:rule_page', '规则设置', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102228, '102223,102228,102253,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rule_page', 1, 1, '', 1, '/warn-manage/rule', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 09:56:35', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102254, 'NT_PC_GA_YX_GZZW_GENERAL:rule_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102253, '102223,102228,102253,102254,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rule_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:56:35', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102255, 'NT_PC_GA_YX_GZZW_GENERAL:rule_edit_btn', '编辑规则', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102253, '102223,102228,102253,102255,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:rule_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:56:35', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102256, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_page', '风险人员', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102238, '102223,102238,102256,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_page', 0, 1, '', 1, '/industry-credit/person', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:08:46', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102257, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_add_btn', '添加人员', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102256, '102223,102238,102256,102257,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:08:46', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102258, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_detail_btn', '查看人员详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102256, '102223,102238,102256,102258,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_detail_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:08:46', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102259, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_del_btn', '移除人员', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102256, '102223,102238,102256,102259,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:person_blacklist_del_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:08:46', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102260, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_page', '风险企业', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102238, '102223,102238,102260,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_page', 1, 1, '', 1, '/industry-credit/company', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:11:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102261, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_add_btn', '添加企业', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102260, '102223,102238,102260,102261,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:11:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102262, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_detail_btn', '查看企业详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102260, '102223,102238,102260,102262,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_detail_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:11:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102263, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_del_btn', '移除企业', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102260, '102223,102238,102260,102263,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:company_blacklist_del_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:11:11', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102264, 'NT_PC_GA_YX_GZZW_GENERAL:search_home_page', '大数据中心', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102264,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:search_home_page', 0, 1, '', 1, '/data-driven/search/home', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:38:48', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102265, 'NT_PC_GA_YX_GZZW_GENERAL:enterprise_page', '企业管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102265,', 0, '0', 0, 'NT_PC_GA_YX_GZZW_GENERAL:enterprise_page', 1, 1, '', 1, '/data-driven/enterprise', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:39:31', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102266, 'NT_PC_GA_YX_GZZW_GENERAL:enterprise_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102265, '102223,102239,102265,102266,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:enterprise_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:39:31', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102267, 'NT_PC_GA_YX_GZZW_GENERAL:project_page', '工程管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102267,', 0, '0', 0, 'NT_PC_GA_YX_GZZW_GENERAL:project_page', 2, 1, '', 1, '/data-driven/project', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:40:42', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102268, 'NT_PC_GA_YX_GZZW_GENERAL:project_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102267, '102223,102239,102267,102268,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:project_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:40:42', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102269, 'NT_PC_GA_YX_GZZW_GENERAL:team_page', '班组管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102269,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:team_page', 3, 1, '', 1, '/data-driven/team-manage', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:44:26', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102270, 'NT_PC_GA_YX_GZZW_GENERAL:team_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102269, '102223,102239,102269,102270,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:team_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:44:26', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102271, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_menu', '人员管理', 1, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102271,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_menu', 4, 1, '', null, '', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 10:44:59', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102272, 'NT_PC_GA_YX_GZZW_GENERAL:construction_page', '施工管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102239, '102223,102239,102272,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:construction_page', 5, 1, '', 1, '/data-driven/construction', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:52:52', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102273, 'NT_PC_GA_YX_GZZW_GENERAL:construction_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102272, '102223,102239,102272,102273,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:construction_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:52:52', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102274, 'NT_PC_GA_YX_GZZW_GENERAL:account_page', '账号管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102240, '102223,102240,102274,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:account_page', 0, 1, '', 1, '/sys/account-manage/account', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:56:22', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102275, 'NT_PC_GA_YX_GZZW_GENERAL:account_add_btn', '新增', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102274, '102223,102240,102274,102275,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:account_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:56:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102276, 'NT_PC_GA_YX_GZZW_GENERAL:account_edit_btn', '编辑', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102274, '102223,102240,102274,102276,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:account_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:56:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102277, 'NT_PC_GA_YX_GZZW_GENERAL:account_del_btn', '删除', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102274, '102223,102240,102274,102277,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:account_del_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:56:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102278, 'NT_PC_GA_YX_GZZW_GENERAL:account_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102274, '102223,102240,102274,102278,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:account_view_btn', 3, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:56:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102279, 'NT_PC_GA_YX_GZZW_GENERAL:role_page', '角色管理', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102240, '102223,102240,102279,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:role_page', 1, 1, '', 1, '/sys/account-manage/role', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 11:00:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102280, 'NT_PC_GA_YX_GZZW_GENERAL:role_add_btn', '新增', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102279, '102223,102240,102279,102280,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:role_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:00:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102281, 'NT_PC_GA_YX_GZZW_GENERAL:role_edit_btn', '编辑', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102279, '102223,102240,102279,102281,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:role_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:00:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102282, 'NT_PC_GA_YX_GZZW_GENERAL:role_del_btn', '删除', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102279, '102223,102240,102279,102282,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:role_del_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:00:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102283, 'NT_PC_GA_YX_GZZW_GENERAL:role_view_btn', '查看', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102279, '102223,102240,102279,102283,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:role_view_btn', 3, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:00:23', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102284, 'NT_PC_GA_YX_GZZW_GENERAL:org_page', '组织架构', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102240, '102223,102240,102284,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:org_page', 2, 1, '', 1, '/sys/account-manage/organizational-structure', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 11:02:41', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102285, 'NT_PC_GA_YX_GZZW_GENERAL:org_add_btn', '新增', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102284, '102223,102240,102284,102285,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:org_add_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:02:41', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102286, 'NT_PC_GA_YX_GZZW_GENERAL:org_edit_btn', '编辑', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102284, '102223,102240,102284,102286,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:org_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:02:41', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102287, 'NT_PC_GA_YX_GZZW_GENERAL:org_del_btn', '删除', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102284, '102223,102240,102284,102287,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:org_del_btn', 2, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:02:41', '2024-10-16 11:12:48', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102288, 'NT_PC_GA_YX_GZZW_GENERAL:org_view_btn', '查看', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102284, '102223,102240,102284,102288,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:org_view_btn', 3, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:02:41', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102289, 'NT_PC_GA_YX_GZZW_GENERAL:project_settle_page', '工程入驻', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102240, '102223,102240,102289,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:project_settle_page', 3, 1, '', 1, '/sys/project-settle', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 11:03:39', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102290, 'NT_PC_GA_YX_GZZW_GENERAL:project_settle_import_btn', '导入工程', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102289, '102223,102240,102289,102290,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:project_settle_import_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:03:39', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102291, 'NT_PC_GA_YX_GZZW_GENERAL:site_page', '站点配置', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102240, '102223,102240,102291,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:site_page', 4, 1, '', 1, '/sys/site', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 11:04:46', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102292, 'NT_PC_GA_YX_GZZW_GENERAL:site_view_btn', '查看', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102291, '102223,102240,102291,102292,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:site_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:04:46', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102293, 'NT_PC_GA_YX_GZZW_GENERAL:site_edit_btn', '编辑', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102291, '102223,102240,102291,102293,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:site_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 11:04:46', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102294, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_project_page', '工程拨付统计', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102243, '102223,102227,102243,102294,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_project_page', 0, 1, '', 1, '/fund-supervision/appropriate-info/project', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:28:59', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102295, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_project_detail_btn', '查看工程拨付详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102294, '102223,102227,102243,102294,102295,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_project_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:28:59', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102296, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_detail_project_btn', '查看工程详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102295, '102223,102227,102243,102294,102295,102296,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_detail_project_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:28:59', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102297, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_detail_money_btn', '查看专户详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102295, '102223,102227,102243,102294,102295,102297,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_detail_money_btn', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:28:59', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102298, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_month_page', '月度拨付统计', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102243, '102223,102227,102243,102298,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_month_page', 1, 1, '', 1, '/fund-supervision/appropriate-info/month', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:31:23', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102299, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_month_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 1, 102298, '102223,102227,102243,102298,102299,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_month_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:31:23', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102300, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_page', '拨付规则设置', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102243, '102223,102227,102243,102300,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_page', 2, 1, '', 1, '/fund-supervision/appropriate-info/rule', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:32:52', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102301, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102300, '102223,102227,102243,102300,102301,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:32:52', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102302, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_edit_btn', '编辑规则', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102300, '102223,102227,102243,102300,102302,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:appropriate_rule_edit_btn', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:32:52', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102303, 'NT_PC_GA_YX_GZZW_GENERAL:salary_month_page', '月度统计', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102244, '102223,102227,102244,102303,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_month_page', 0, 1, '', 1, '/fund-supervision/salary/month-salary-statistic', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:37:51', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102304, 'NT_PC_GA_YX_GZZW_GENERAL:salary_month_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102303, '102223,102227,102244,102303,102304,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_month_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:37:51', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102305, 'NT_PC_GA_YX_GZZW_GENERAL:salary_project_page', '工程发薪统计', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102244, '102223,102227,102244,102305,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_project_page', 1, 1, '', 1, '/fund-supervision/salary/project-salary-statistic', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:38:58', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102306, 'NT_PC_GA_YX_GZZW_GENERAL:salary_project_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102305, '102223,102227,102244,102305,102306,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_project_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:38:58', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102307, 'NT_PC_GA_YX_GZZW_GENERAL:salary_team_page', '班组发薪', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102244, '102223,102227,102244,102307,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_team_page', 2, 1, '', 1, '/fund-supervision/salary/team-salary-statistic', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:39:56', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102308, 'NT_PC_GA_YX_GZZW_GENERAL:salary_team_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102307, '102223,102227,102244,102307,102308,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_team_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:39:56', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102309, 'NT_PC_GA_YX_GZZW_GENERAL:salary_worker_page', '工人发薪', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102244, '102223,102227,102244,102309,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_worker_page', 3, 1, '', 1, '/fund-supervision/salary/worker-salary-statistic', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:41:11', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102310, 'NT_PC_GA_YX_GZZW_GENERAL:salary_worker_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102309, '102223,102227,102244,102309,102310,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_worker_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:41:11', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102311, 'NT_PC_GA_YX_GZZW_GENERAL:salary_detail_page', '发薪明细', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102244, '102223,102227,102244,102311,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_detail_page', 4, 1, '', 1, '/fund-supervision/salary/worker-salary-detail', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:42:42', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102312, 'NT_PC_GA_YX_GZZW_GENERAL:salary_detail_view_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102311, '102223,102227,102244,102311,102312,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:salary_detail_view_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:42:42', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102313, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_project_page', '预付工程统计', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102245, '102223,102227,102245,102313,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_project_page', 0, 1, '', 1, '/fund-supervision/prepaid/project-prepaid', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:44:43', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102314, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_project_export', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102313, '102223,102227,102245,102313,102314,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_project_export', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:44:44', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102315, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_person_page', '个人/企业预付', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102245, '102223,102227,102245,102315,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_person_page', 1, 1, '', 1, '/fund-supervision/prepaid/person-prepaid', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:45:38', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102316, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_person_export', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102315, '102223,102227,102245,102315,102316,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_person_export', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:45:38', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102317, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_salary_page', '预付发薪明细', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102245, '102223,102227,102245,102317,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_salary_page', 2, 1, '', 1, '/fund-supervision/prepaid/salary-detail', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-15 18:46:56', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102318, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_worker_btn', '预付工人明细详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102317, '102223,102227,102245,102317,102318,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_worker_btn', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:46:56', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102319, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_salary_export', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102317, '102223,102227,102245,102317,102319,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_salary_export', 1, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-15 18:46:56', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102320, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_payment_page', '预付回款明细', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102245, '102223,102227,102245,102320,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_payment_page', 3, 1, '', 1, '/fund-supervision/prepaid/payment-detail', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 0, 0, '2024-10-16 09:44:16', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102321, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_payment_export', '导出', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102320, '102223,102227,102245,102320,102321,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:prepaid_payment_export', 0, 1, '', null, '', null, null, null, 0, null, 0, 1, '2024-10-16 09:44:16', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102322, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_worker_page', '产业工人', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102271, '102223,102239,102271,102322,', 0, '0', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_worker_page', 0, 1, '', 1, '/data-driven/personnel-management/personnel-worker', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:47:45', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102323, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_worker_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102322, '102223,102239,102271,102322,102323,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_worker_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:47:46', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102324, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_teamleader_page', '班组管理人员', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102271, '102223,102239,102271,102324,', 0, '0', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_teamleader_page', 1, 1, '', 1, '/data-driven/personnel-management/personnel-teamleader', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:48:44', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102325, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_teamleader_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102324, '102223,102239,102271,102324,102325,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_teamleader_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:48:44', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102326, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_employee_page', '项目管理人员', 2, 'NT_PC_GA_YX_GZZW_GENERAL', 0, 102271, '102223,102239,102271,102326,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_employee_page', 2, 1, '', 1, '/data-driven/personnel-management/personnel-employee', null, null, null, 0, '{"moreIcon": "", "activeIcon": ""}', 1, 0, '2024-10-16 10:49:31', '2024-10-16 11:12:49', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102327, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_employee_detail_btn', '查看详情', 4, 'NT_PC_GA_YX_GZZW_GENERAL', 5, 102326, '102223,102239,102271,102326,102327,', 0, '', 0, 'NT_PC_GA_YX_GZZW_GENERAL:personnel_employee_detail_btn', 0, 1, '', null, '', null, null, null, 0, null, 1, 1, '2024-10-16 10:49:32', '2024-10-16 11:12:50', 190265, 9000404204, 0);
INSERT INTO saas_feature_resource (id, feature_code, feature_name, feature_type, terminal, component_type, parent_id, path, workspace_type, workspace_types, version, uni_code, display_order, status, icon, redirect_type, link_url, link_type, link_ext, app_item_id, sync_version, extra, auth_type, sub_auth_type, create_at, update_at, create_by, update_by, is_delete) VALUES (102444, 'ROOT:NT_PC_GA_TFXQZW_GENERAL', '成都天府新区政务PC端', 5, 'NT_PC_GA_TFXQZW_GENERAL', 0, 0, '102444,', 0, '', 0, 'ROOT:NT_PC_GA_TFXQZW_GENERAL', 28, 1, ' ', 0, ' ', 1, ' ', null, 0, null, 1, 0, '2024-11-13 11:04:07', '2024-11-26 17:09:48', 9000400021, 9000400021, 0);
#-->SaasRoleUserRelationServiceImplTest.sql

View File

@ -0,0 +1,7 @@
#-->DEFAULT
INSERT INTO saas_page_element (id, group_code, code, name, type, link_url, terminal, create_at, update_at, is_delete, create_name, app_type, version, item_code, link_ext, app_id, item_name, ext, create_by, update_by) VALUES (364184, 'h5:cmp_invite_team_page', 'h5:cmp_invite_team_page', '项目通讯录-邀请班组', 'PAGE', '__UNI__33771704#/inviteTeam', 'NT_CMP_APP_GENERAL', '2024-09-02 11:19:33', '2024-11-22 15:55:22', 0, '', 'H5', 0, 'h5:member_33771704', '', '__UNI__33771704', '通讯录H5', '{"applications": [{"type": "IOS", "minVersion": 0}, {"type": "ANDROID", "minVersion": 0}]}', null, null);
INSERT INTO saas_page_element (id, group_code, code, name, type, link_url, terminal, create_at, update_at, is_delete, create_name, app_type, version, item_code, link_ext, app_id, item_name, ext, create_by, update_by) VALUES (364185, 'h5:cmp_invite_team_page', 'h5:cmp_invite_qr_code_btn', '项目通讯录-邀请班组-二维码邀请', 'COMPONENT', '', 'NT_CMP_APP_GENERAL', '2024-09-02 11:19:33', '2024-11-22 15:55:22', 0, '', 'H5', 0, 'h5:member_33771704', '', '__UNI__33771704', '通讯录H5', '{"applications": [{"type": "IOS", "minVersion": 0}, {"type": "ANDROID", "minVersion": 0}]}', null, null);
#-->SaasRoleUserRelationServiceImplTest.sql

View File

@ -169,6 +169,7 @@ CREATE TABLE `saas_feature_resource` (
`create_by` bigint NOT NULL DEFAULT '0' COMMENT '创建人',
`update_by` bigint NOT NULL DEFAULT '0' COMMENT '更新人',
`is_delete` bigint NOT NULL DEFAULT '0' COMMENT '删除标识',
`workspace_types` varchar(64) NOT NULL DEFAULT '' COMMENT '应用范围(租户类型)1:企业工作台 2;项目工作台 以英文逗号分隔 cmp的应用可以配置支持多工作台类型',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=459 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='功能资源表';
@ -188,6 +189,13 @@ CREATE TABLE `saas_page_element` (
`create_at` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`is_delete` bigint NOT NULL DEFAULT '0' COMMENT '删除标识',
`create_name` varchar(64) NOT NULL DEFAULT '' COMMENT '创建人名',
`app_type` varchar(32) NOT NULL DEFAULT '' COMMENT 'app类型APP:原生H5:h5页面',
`version` bigint NOT NULL DEFAULT '0' COMMENT '客户端版本号',
`item_code` varchar(64) NOT NULL DEFAULT '' COMMENT '项目code',
`link_ext` varchar(4096) NOT NULL DEFAULT '' COMMENT 'APP适配参数',
`app_id` varchar(128) NOT NULL DEFAULT '' COMMENT 'AppID',
`item_name` varchar(64) NOT NULL DEFAULT '' COMMENT '项目名称',
PRIMARY KEY (`id`),
KEY `idx_page_element_gcode` (`group_code`),
KEY `idx_page_element_code` (`code`)
@ -313,3 +321,29 @@ CREATE TABLE `permission_rule` (
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='权限系统规则定义表';
alter table saas_role_group add column `path` varchar(255) DEFAULT '0' COMMENT 'ID层级路径 逗号分隔';
CREATE TABLE `saas_page_element_category` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
`item_code` varchar(64) NOT NULL DEFAULT '' COMMENT '项目编码',
`item_name` varchar(128) NOT NULL DEFAULT '' COMMENT '项目名称',
`terminal` varchar(64) NOT NULL DEFAULT '' COMMENT '',
`is_delete` bigint NOT NULL DEFAULT '0' COMMENT '删除标志',
`create_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`create_by` bigint NOT NULL DEFAULT '0' COMMENT '创建人',
`update_by` bigint NOT NULL DEFAULT '0' COMMENT '更新人',
PRIMARY KEY (`id`),
UNIQUE KEY `saas_page_element_category_item_code` (`item_code`),
KEY `saas_page_element_category_item_name` (`item_name`)
) ENGINE=InnoDB AUTO_INCREMENT=41 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='前端元素类型';
-- alter table saas_page_element add column `ext` JSON NULL COMMENT '额外信息, 使用json便于查询';
alter table saas_page_element add column `ext` VARCHAR(2048) NOT NULL DEFAULT '{}' COMMENT '额外信息';
alter table saas_page_element add column `create_by` bigint DEFAULT NULL COMMENT '创建人';
alter table saas_page_element add column `update_by` bigint DEFAULT NULL COMMENT '更新人';
alter table saas_feature_resource modify column feature_code varchar(100) not null comment '资源编码-权限码';
alter table saas_feature_resource modify column uni_code varchar(100) default '' not null comment '唯一编码用于pre环境菜单同步';