Merge branch 'feature/REQ-2186'

# Conflicts:
#	tyr-api/pom.xml
#	tyr-api/src/main/java/cn/axzo/tyr/client/model/enums/DictWorkSpaceTypeEnum.java
#	tyr-api/src/main/java/cn/axzo/tyr/client/model/req/ListRoleReq.java
#	tyr-api/src/main/java/cn/axzo/tyr/client/model/req/PageRoleReq.java
#	tyr-server/pom.xml
This commit is contained in:
lilong 2024-06-05 19:42:04 +08:00
commit 51278dcc27
59 changed files with 2080 additions and 188 deletions

View File

@ -6,9 +6,9 @@
dev环境启动参数
-Dspring.datasource.url=jdbc:mysql://172.16.2.197:3311/pudge-dev?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&serverTimezone=Asia/Shanghai&useSSL=true&verifyServerCertificate=false&rewriteBatchedStatements=true
-Drocketmq.name-server=114.116.202.128:9876
-Drocketmq.name-server=172.16.2.82:9876
-DCUSTOM_ENV=dev
-Dspring.profiles.active=dev
-Dspring.redis.host=123.249.44.111
-Dspring.redis.host=172.16.2.23
-Dspring.redis.port=31270
-Dserver.port=8080

View File

@ -32,5 +32,6 @@
<artifactId>dao-support-lib</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@ -23,6 +23,7 @@ public enum FeatureResourceType {
PAGE(2, "页面"),
APP_ENTRY(3, "应用入口"),
COMPONENT(4, "组件"),
ROOT(5, "ROOT"),
;
private static final Map<Integer, FeatureResourceType> MAPPING = new HashMap<>();
@ -50,7 +51,8 @@ public enum FeatureResourceType {
public static List<Integer> navTypes() {
return Arrays.asList(FeatureResourceType.MENU.getCode(),
FeatureResourceType.PAGE.getCode(),
FeatureResourceType.APP_ENTRY.getCode());
FeatureResourceType.APP_ENTRY.getCode(),
FeatureResourceType.ROOT.getCode());
}
public static List<Integer> pageTypes() {

View File

@ -0,0 +1,27 @@
package cn.axzo.tyr.client.common.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.Getter;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/13
*/
public enum ProductModuleFeatureRelationTypeEnum {
FEATURE(0, "FEATURE"),
FEATURE_RESOURCE(1, "FEATURE_RESOURCE")
;
@Getter
@EnumValue
@JsonValue
public final Integer code;
public final String desc;
ProductModuleFeatureRelationTypeEnum(Integer code, String desc){
this.code = code;
this.desc = desc;
}
}

View File

@ -20,12 +20,12 @@ import java.util.stream.Collectors;
@AllArgsConstructor
public enum RoleTypeEnum {
//角色类型common 普通角色 super_admin超级管理员(禁止删除) admin子管理员(禁止删除) init初始化内置角色 auto_own自定义角色(禁止删除)<承载向用户单独分配的自定义权限>
COMMON("common", "普通角色",false),
//角色类型common 自定义角色 super_admin超级管理员(禁止删除) admin子管理员(禁止删除) init初始化内置角色 auto_own自定义角色(禁止删除)<承载向用户单独分配的自定义权限>
COMMON("common", "自定义角色",false),
SUPER_ADMIN("super_admin", "超级管理员",true),
ADMIN("admin", "子管理员",true),
INIT("init", "初始化内置角色",false),
AUTO_OWN("auto_own", "自定义角色",false);
INIT("init", "初始化内置角色-标准角色",false),
AUTO_OWN("auto_own", "虚拟角色(自定义权限使用)",false);
@EnumValue
private final String value;

View File

@ -5,8 +5,12 @@ import cn.axzo.tyr.client.model.req.NavTreeReq;
import cn.axzo.tyr.client.model.req.PagePermissionReq;
import cn.axzo.tyr.client.model.req.PagePermissionResp;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.NavTreeResp;
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
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;
@ -34,4 +38,20 @@ public interface PermissionQueryApi {
/** 鉴权接口 **/
@PostMapping(value = "/api/v3/permission/query/hasPermission")
ApiResult<Boolean> hasPermission(@RequestBody @Valid PermissionCheckReq req);
/**
* 查询租户的权限树
* @param request
* @return
*/
@PostMapping(value = "/api/v3/productPermission/tree")
ApiResult<List<ProductFeatureResourceResp>> treeProduct(@RequestBody @Validated TreeProductFeatureResourceReq request);
/**
* 查询租户的权限点list
* @param request
* @return
*/
@PostMapping(value = "/api/v3/productPermission/list")
ApiResult<List<FeatureResourceDTO>> listFeatureResource(@RequestBody @Validated TreeProductFeatureResourceReq request);
}

View File

@ -10,6 +10,10 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
import cn.axzo.tyr.client.model.res.WorkspaceProductResp;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
@ -113,4 +117,42 @@ public interface ProductApi {
*/
@PostMapping("api/auth/product/feature/query")
ApiResult<Map<Long, List<ProductFeatureRelationVO>>> queryProductFeatureRelationByWorkspace(@RequestBody Set<Long> workspaceIds);
/**
* 产品上下架
*
* @param req 产品id及状态
* @return 是否更新成功
*/
@PostMapping("api/auth/product/updateStatus")
ApiResult<Void> updateStatus(@Validated @RequestBody UpdateProductStatusReq req);
/**
* 保存更新产品v2版本
*
* @param req 产品信息
* @return 返回产品ID
*/
@PostMapping("api/auth/product/saveOrUpdate")
ApiResult<Long> saveOrUpdate(@Validated @RequestBody ProductSaveReq req);
/**
* 获取政务端列表
*
* @param terminal 政务端
* @return {@link GovernmentTerminalResp}
*/
@GetMapping("api/auth/product/getGovernmentTerminal")
ApiResult<List<GovernmentTerminalResp>> getGovernmentTerminal(@RequestParam @NotNull(message = "terminal不能为空") String terminal);
/**
* 根据租户类型查询产品信息新增租户开通管理
*
* @param workspaceType 租户类型
* @return 租户产品信息
*/
@GetMapping("api/auth/product/getWorkspaceProduct")
ApiResult<WorkspaceProductResp> getWorkspaceProduct(@RequestParam @NotNull(message = "workspaceType不能为空") String workspaceType);
}

View File

@ -21,7 +21,7 @@ public class BaseFeatureResourceDO {
/** 资源名称 **/
private String featureName;
/** 资源类型 1-菜单 2-页面 3-应用入口 4-组件 **/
/** 资源类型 1-菜单 2-页面 3-应用入口 4-组件 5-ROOT根节点 **/
private Integer featureType;
/** 资源编码 **/

View File

@ -27,7 +27,7 @@ public enum DictWorkSpaceTypeEnum {
*/
PROJ("proj", "项目部工作台",1,2, "项目租户"),
GOVERNMENT("government", "政务监管平台",3,3, "政务监管平台"),
GOVERNMENT("gov", "政务监管平台",3,3, "政务监管平台"),
/**
* OMS工作台

View File

@ -0,0 +1,64 @@
package cn.axzo.tyr.client.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@Getter
@AllArgsConstructor
public enum ProductModuleCategoryEnum {
/**
* 产品版本
*/
PRODUCT_VERSION("PRODUCT_VERSION", "产品版本"),
/**
* 增值服务包
*/
ADD_VALUE_SERVICE("ADD_VALUE_SERVICE", "增值服务包"),
/**
* 通用产品
*/
GENERAL_SERVICE("GENERAL_SERVICE", "通用产品"),
/**
* 硬件产品
*/
HARD_WARE("HARD_WARE", "硬件产品"),
;
@EnumValue
@JsonValue
private String code;
private String desc;
/**
* 通过value值获取枚举类型
*
* @param code code值
* @return
*/
public static ProductModuleCategoryEnum getByCode(String code) {
return Arrays.stream(values()).filter(l -> l.getCode().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return Optional.ofNullable(getByCode(code)).map(ProductModuleCategoryEnum::getDesc).orElse(null);
}
public static List<String> ALL_CATEGORY_CODE = Lists.newArrayList(PRODUCT_VERSION.getCode(), ADD_VALUE_SERVICE.getCode(), GENERAL_SERVICE.getCode(), HARD_WARE.getCode());
}

View File

@ -0,0 +1,72 @@
package cn.axzo.tyr.client.model.enums;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@Getter
@AllArgsConstructor
public enum WorkspaceTypeCodeEnum {
/**
* 企业
*/
GENERAL_ENT("1", "企业"),
/**
* 项目
*/
GENERAL_PROJECT("2", "项目"),
/**
* 政务
*/
GOVERNMENT("3", "政务"),
/**
* 班组
*/
TEAM("5", "班组"),
/**
* OMS
*/
OMS("6", "OMS"),
;
@EnumValue
@JsonValue
private String code;
private String desc;
/**
* 通过value值获取枚举类型
*
* @param code code值
* @return
*/
public static WorkspaceTypeCodeEnum getByCode(String code) {
return Arrays.stream(values()).filter(l -> l.getCode().equals(code)).findFirst().orElse(null);
}
public static String getDescByCode(String code) {
return Optional.ofNullable(getByCode(code)).map(WorkspaceTypeCodeEnum::getDesc).orElse(null);
}
/**
* 后台允许新增的租户类型
*/
public static final List<WorkspaceTypeCodeEnum> ALLOW_ADD_WORKSPACE_TYPE_CODE_ENUM = Lists.newArrayList(GENERAL_ENT, GENERAL_PROJECT, GOVERNMENT);
}

View File

@ -41,4 +41,6 @@ public class ProductFeatureRelationUpdateReq {
* 权限点 ID
*/
private List<Long> featureIds = new ArrayList<>();
private Integer featureRelationType;
}

View File

@ -27,9 +27,18 @@ public class ProductSearchPageReq extends PageRequest {
*/
private Long dictWorkspaceTypeId;
/**
* 租户编码工作台编码
*/
private Long dictWorkspaceTypeCode;
/**
* 状态
*/
private Integer status;
/**
* 产品类型
*/
private String productCategory;
}

View File

@ -97,4 +97,116 @@ public class ProductVO {
*/
private List<Integer> ouTypes;
/**
* 产品类型
* PRODUCT_VERSON:产品版本类型ADD_VALUE_SERVICE:增值服务类型
* GENERAL_SERVICE:通用产品类型HARD_WARE:硬件产品类型
*/
private String category;
/**
* 产品类型名称
*/
private String productCategoryDesc;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
private Integer maxWorkspaceCount;
/**
* 价格(单位)
*/
private Long price;
/**
* 产品详情
*/
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>
*/
private Material material;
/**
* 功能范围(政务产品只取根节点的featureId后台取拉群所选根节点的所有子节点featureId)
*/
private List<FeatureScope> featureScopes;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
private Integer count;
/**
* 单位
*/
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片
*/
private List<String> images;
/**
* 视频
*/
private List<String> videos;
/**
* 详情大图
*/
private List<String> detailImages;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureScope {
/**
* 政务端featureResourceId
*/
private Long governmentFeatureResourceId;
/**
* 功能资源名称
*/
private String featureResourceName;
}
}

View File

@ -13,23 +13,63 @@ import java.util.List;
@AllArgsConstructor
public class ListRoleReq {
/**
* 角色id
*/
private List<Long> roleIds;
/**
* 租户类型:DictWorkSpaceTypeEnum
*/
private Integer workspaceType;
/**
* 是否显示
*/
private Boolean isDisplay;
/**
* 角色权限码
*/
private String roleCode;
/**
* 租户id
*/
private List<Long> workspaceIds;
/**
* 单位id
*/
private List<Long> ouIds;
/**
* 是否启用
*/
private Boolean enabled;
/**
* 角色类型:RoleTypeEnum
* super_admin:超级管理员
* admin:管理员
* init:初始化内置角色-标准角色
* auto_own:虚拟角色(自定义权限使用)
* common:自定义角色
*/
private List<String> roleTypes;
/**
* 是否需要角色下的权限信息
*/
private Boolean needPermission;
/**
* 是否需要角色对应的角色分组信息
*/
private Boolean needRoleGroup;
/**
* 是否需要角色对应的用户信息
*/
private Boolean needRoleUser;
}

View File

@ -1,7 +1,6 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
@ -14,8 +13,6 @@ import java.util.List;
@AllArgsConstructor
public class PageRoleReq extends ListRoleReq {
private Integer page;
private Integer pageSize;

View File

@ -0,0 +1,167 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.Valid;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.List;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/26
*/
@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ProductSaveReq {
/**
* 产品ID
*/
private Long id;
/**
* 产品名称
*/
@NotBlank(message = "产品名称不能为空")
@Length(max = 35, message = "产品名称长度不能超过 35 个字符")
private String productName;
/**
* 产品icon
*/
private String icon;
/**
* 产品所属租户类型
*/
@NotNull(message = "租户类型不能为空")
private Long dictWorkspaceTypeId;
/**
* 产品类型
*/
@NotBlank(message = "产品类型不能为空")
private String productCategory;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
@Min(value = 0, message = "版本升级序列有误")
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
@Min(value = 0, message = "人数上限有误")
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
@Min(value = 0, message = "最大项目数有误")
private Integer maxWorkspaceCount;
/**
* 价格单位 <企业项目产品>
*/
@Min(value = 0, message = "价格有误")
private Long price;
/**
* SKU列表
*/
@Valid
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>
*/
private Material material;
/**
* 功能范围(政务产品只取根节点的featureId后台取拉群所选根节点的所有子节点featureId)
*/
private FeatureScope featureScope;
/**
* 描述
*/
private String remark;
/**
* 操作人
*/
private Long operator;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
@Min(value = 1, message = "数量有误")
private Integer count;
/**
* 单位
*/
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片素材
*/
private List<String> images;
/**
* 视频素材
*/
private List<String> videos;
/**
* 详情介绍大图
*/
private List<String> detailImages;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class FeatureScope {
/**
* 政务端featureResourceId
*/
private List<Long> governmentFeatureResourceIds;
}
}

View File

@ -0,0 +1,23 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import javax.validation.constraints.NotNull;
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class TreeProductFeatureResourceReq {
/**
* 租户id
*/
@NotNull(message = "workspaceId不能为空")
private Long workspaceId;
private String terminal;
}

View File

@ -0,0 +1,35 @@
package cn.axzo.tyr.client.model.req;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/26
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class UpdateProductStatusReq {
/**
* 产品ID
*/
@NotNull(message = "产品ID不能为空")
@Min(value = 1, message = "产品ID有误")
private Long id;
/**
* 状态
*/
@NotNull(message = "状态不能为空")
@Min(value = 0, message = "状态有误")
@Max(value = 1, message = "状态有误")
private Integer status;
}

View File

@ -0,0 +1,28 @@
package cn.axzo.tyr.client.model.res;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/30
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class GovernmentTerminalResp {
/**
* 功能资源ID
*/
private Long featureResourceId;
/**
* 功能资源名称
*/
private String featureResourceName;
}

View File

@ -0,0 +1,80 @@
package cn.axzo.tyr.client.model.res;
import cn.axzo.basics.common.model.IBaseTree;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class ProductFeatureResourceResp implements IBaseTree<ProductFeatureResourceResp, Long> {
/**
* 权限id
*/
private Long id;
/**
* 权限编码
*/
private String featureCode;
/**
* 权限名字
*/
private String featureName;
/**
* 资源类型1-菜单 2-页面 3-应用入口 4-组件
*/
private Integer featureType;
/**
* 资源所属端
*/
private String terminal;
/**
* 展示顺序
*/
private Integer displayOrder;
/**
* 父节点id
*/
private Long parentId;
/**
* 子节点信息
*/
private List<ProductFeatureResourceResp> children;
@JsonIgnore
@Override
public Long getNodeCode() {
return this.getId();
}
@JsonIgnore
@Override
public Long getParentNodeCode() {
return this.getParentId();
}
@JsonIgnore
@Override
public List<ProductFeatureResourceResp> getNodeChildren() {
return this.children;
}
@Override
public void setNodeChildren(List<ProductFeatureResourceResp> nodeChildren) {
this.children = nodeChildren;
}
}

View File

@ -1,5 +1,6 @@
package cn.axzo.tyr.client.model.res;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO;
import lombok.AllArgsConstructor;
import lombok.Builder;
@ -107,4 +108,26 @@ public class SaasRoleRes {
* 角色权限
*/
private List<SaasPermissionRes> saasPermissions;
/**
* 角色对应的人员信息
*/
private List<SaasRoleUserV2DTO.SaasRoleUser> saasRoleUsers;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SaasRoleUser {
/**
* 用户id
*/
private Long personId;
/**
* 用户名字
*/
private String realName;
}
}

View File

@ -0,0 +1,118 @@
package cn.axzo.tyr.client.model.res;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author likunpeng
* @version 1.0
* @date 2024/4/28
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class WorkspaceProductResp {
/**
* 产品版本产品
*/
private List<Product> productVersions;
/**
* 增值服务产品
*/
private List<Product> addValueServices;
/**
* 通用服务产品
*/
private List<Product> generalServices;
/**
* 硬件服务产品
*/
private List<Product> hardware;
/**
* 政务产品
*/
private List<Product> governmentProduct;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Product {
/**
* 产品ID
*/
private Long productId;
/**
* 产品名称
*/
private String productName;
/**
* 人数上限 <企业项目产品>
*/
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
private Integer maxWorkspaceCount;
/**
* SKU列表
*/
private List<Sku> skus;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
private Integer count;
/**
* 单位
*/
private String unit;
}
public static WorkspaceProductResp init() {
return WorkspaceProductResp.builder()
.productVersions(Lists.newArrayList())
.addValueServices(Lists.newArrayList())
.generalServices(Lists.newArrayList())
.hardware(Lists.newArrayList())
.governmentProduct(Lists.newArrayList())
.build();
}
}

View File

@ -0,0 +1,37 @@
package cn.axzo.tyr.client.model.roleuser.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class SaasRoleUserV2DTO {
/**
* 角色Id
*/
private Long roleId;
private SaasRoleUser saasRoleUser;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SaasRoleUser {
/**
* 用户id
*/
private Long personId;
/**
* 用户名字
*/
private String realName;
}
}

View File

@ -0,0 +1,23 @@
package cn.axzo.tyr.client.model.roleuser.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.dao.support.wrapper.Operator;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@SuperBuilder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ListRoleUserRelationParam {
@CriteriaField(field = "roleId", operator = Operator.IN)
private List<Long> roleIds;
@CriteriaField(ignore = true)
private Boolean needUsers;
}

View File

@ -0,0 +1,29 @@
package cn.axzo.tyr.client.model.roleuser.req;
import cn.axzo.foundation.dao.support.wrapper.CriteriaField;
import cn.axzo.foundation.page.IPageReq;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
import java.util.List;
@SuperBuilder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PageRoleUserRelationParam extends ListRoleUserRelationParam implements IPageReq {
@CriteriaField(ignore = true)
Integer page;
@CriteriaField(ignore = true)
Integer pageSize;
/**
* 排序使用示例createTime__DESC
*/
@CriteriaField(ignore = true)
List<String> sort;
}

View File

@ -103,8 +103,9 @@
</dependency>
<dependency>
<groupId>cn.axzo.pokonyan</groupId>
<artifactId>pokonyan</artifactId>
<groupId>cn.axzo.foundation</groupId>
<artifactId>dao-support-lib</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
<dependency>
@ -123,11 +124,9 @@
</dependency>
<dependency>
<groupId>cn.axzo.foundation</groupId>
<artifactId>dao-support-lib</artifactId>
<version>2.0.0-SNAPSHOT</version>
<groupId>cn.axzo.basics</groupId>
<artifactId>basics-profiles-api</artifactId>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -35,7 +35,8 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware {
@Value("${maokaiEnvUrl:http://dev-app.axzo.cn/maokai}")
private String maokaiEnvUrl;
@Value("${pudgeEnvUrl:http://dev-app.axzo.cn/pudge}")
private String pudgeEnvUrl;
private static String POD_NAMESPACE;
static {
@ -57,6 +58,7 @@ public class FeignConfig implements RequestInterceptor, EnvironmentAware {
url = url.replace("http://workflow-engine:8080", workflowEnvUrl);
url = url.replace("http://thrones", thronesEnvUrl);
url = url.replace("http://maokai:8080", maokaiEnvUrl);
url = url.replace("http://pudge:10099", pudgeEnvUrl);
String profile = environment.getProperty("spring.profiles.active");
if(Objects.equals(profile, "test") && url.contains("dev-app.axzo.cn")) {
url = url.replace("dev-app", "test-api");

View File

@ -18,7 +18,8 @@ import static cn.axzo.tyr.server.config.GlobalConfig.FeignClientConstant.*;
@Configuration
@EnableFeignClients(basePackages = {
WORKFLOW_ENGINE,
INNER_FEIGN
INNER_FEIGN,
"cn.axzo"
})
public class GlobalConfig {
/**

View File

@ -1,25 +1,45 @@
package cn.axzo.tyr.server.controller;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.req.QuerySaasRoleGroupReq;
import cn.axzo.tyr.client.model.res.CommonDictResp;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.client.model.res.SaasRoleRes;
import cn.axzo.tyr.client.model.vo.SaasRoleGroupVO;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroup;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasCommonDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasRoleGroupService;
import cn.axzo.tyr.server.service.impl.SaasFeatureResourceCacheService;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
@ -28,6 +48,7 @@ import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
@Slf4j
@RestController
@RequiredArgsConstructor
public class PrivateController {
@ -40,6 +61,13 @@ public class PrivateController {
private SaasRoleGroupRelationDao saasRoleGroupRelationDao;
@Autowired
private RoleService roleService;
@Autowired
private SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private SaasFeatureResourceDao saasFeatureResourceDao;
@Autowired
private SaasFeatureResourceCacheService saasFeatureResourceCacheService;
/**
* 统一层级的roleGroup按照id升序sort从1递增
@ -148,4 +176,90 @@ public class PrivateController {
roleService.updateBatchById(updateSaasRoles);
return "ok";
}
@PostMapping("/api/private/saasFeatureResource/path/refresh")
public Object createFeatureResourceRoot(@Validated @RequestBody RefreshFeatureResourcePathParam request) {
GetFeatureResourceTreeReq getFeatureResourceTreeReq = GetFeatureResourceTreeReq.builder()
.terminals(Lists.newArrayList(request.getTerminal()))
.build();
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceCacheService.getByResourceTreeParam(getFeatureResourceTreeReq);
if (CollectionUtils.isEmpty(saasFeatureResources)) {
return Collections.emptyList();
}
List<FeatureResourceTreeNode> tree = TreeUtil.buildTree(saasFeatureResources.stream()
.map(featureResource -> FeatureResourceTreeNode.builder()
.id(featureResource.getId())
.featureCode(featureResource.getFeatureCode())
.featureName(featureResource.getFeatureName())
.featureType(featureResource.getFeatureType())
.terminal(featureResource.getTerminal())
.parentId(featureResource.getParentId())
.displayOrder(featureResource.getDisplayOrder())
.build())
.sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder))
.collect(Collectors.toList()));
if (CollectionUtils.isEmpty(tree)) {
log.info("not found featureResource,{}", request.getTerminal());
return "error";
}
FeatureResourceTreeNode root = tree.stream()
.filter(e -> Objects.equals(e.getId(), request.getRootId()))
.findFirst()
.orElse(null);
if (root == null) {
log.info("not found root,{}", request.getTerminal());
return "error";
}
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(root.getId());
saasFeatureResource.setParentId(0L);
saasFeatureResource.setPath(root.getId() + ",");
saasFeatureResourceDao.updateById(saasFeatureResource);
updateChildrenPath(root, tree);
saasFeatureResourceCacheService.clearCache();
return "ok";
}
private void updateChildrenPath(FeatureResourceTreeNode parent,
List<FeatureResourceTreeNode> featureResources) {
if (CollectionUtils.isEmpty(featureResources)) {
return;
}
List<FeatureResourceTreeNode> children = featureResources.stream()
.filter(e -> !Objects.equals(e.getId(), parent.getId()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(children)) {
return;
}
SaasFeatureResource parentFeatureResource = saasFeatureResourceDao.getById(parent.getId());
children.forEach(e -> {
SaasFeatureResource saasFeatureResource = new SaasFeatureResource();
saasFeatureResource.setId(e.getId());
saasFeatureResource.setParentId(parentFeatureResource.getId());
saasFeatureResource.setPath(parentFeatureResource.getPath() + e.getId() + ",");
saasFeatureResourceDao.updateById(saasFeatureResource);
updateChildrenPath(e, e.getChildren());
});
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class RefreshFeatureResourcePathParam {
@NotBlank(message = "terminal不能为空")
private String terminal;
@NotNull(message = "rootId不能为空")
private Long rootId;
}
}

View File

@ -6,7 +6,10 @@ import cn.axzo.tyr.client.model.req.NavTreeReq;
import cn.axzo.tyr.client.model.req.PagePermissionReq;
import cn.axzo.tyr.client.model.req.PagePermissionResp;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.NavTreeResp;
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
import cn.axzo.tyr.server.service.PermissionQueryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -42,4 +45,14 @@ public class PermissionQueryController implements PermissionQueryApi {
public ApiResult<Boolean> hasPermission(PermissionCheckReq req) {
return ApiResult.ok(permissionService.hasPermission(req));
}
@Override
public ApiResult<List<ProductFeatureResourceResp>> treeProduct(TreeProductFeatureResourceReq request) {
return ApiResult.ok(permissionService.treeProduct(request));
}
@Override
public ApiResult<List<FeatureResourceDTO>> listFeatureResource(TreeProductFeatureResourceReq request) {
return ApiResult.ok(permissionService.listFeatureResource(request));
}
}

View File

@ -11,6 +11,10 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
import cn.axzo.tyr.client.model.res.WorkspaceProductResp;
import cn.axzo.tyr.server.model.PermissionCacheKey;
import cn.axzo.tyr.server.service.PermissionCacheService;
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
@ -135,4 +139,48 @@ public class ProductController implements ProductApi {
public ApiResult<Map<Long, List<ProductFeatureRelationVO>>> queryProductFeatureRelationByWorkspace(Set<Long> workspaceIds) {
return ApiResult.ok(productFeatureRelationService.getByWorkspace(workspaceIds));
}
/**
* 产品上下架
*
* @param req 产品及状态信息
* @return 返回是否更新成功
*/
@Override
public ApiResult<Void> updateStatus(UpdateProductStatusReq req) {
return productService.updateStatus(req);
}
/**
* 保存更新产品v2版本
*
* @param req 产品信息
* @return 返回产品ID
*/
@Override
public ApiResult<Long> saveOrUpdate(ProductSaveReq req) {
return productService.saveOrUpdate(req);
}
/**
* 获取政务端列表
*
* @param terminal 政务端
* @return 返回端列表
*/
@Override
public ApiResult<List<GovernmentTerminalResp>> getGovernmentTerminal(String terminal) {
return productService.getGovernmentTerminal(terminal);
}
/**
* 根据租户类型查询产品信息新增租户开通管理
*
* @param workspaceType 租户类型
* @return 租户产品信息
*/
@Override
public ApiResult<WorkspaceProductResp> getWorkspaceProduct(String workspaceType) {
return productService.getWorkspaceProduct(workspaceType);
}
}

View File

@ -43,7 +43,6 @@ import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasCommonDictService;
import cn.axzo.tyr.server.service.SaasRoleGroupRelationService;
import cn.axzo.tyr.server.service.SaasRoleGroupService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.RequiredArgsConstructor;
@ -295,8 +294,15 @@ public class SaasRoleController implements TyrSaasRoleApi {
public ApiPageResult<SaasRoleRes> page(PageRoleReq request) {
RoleService.PageSaasRoleParam param = RoleService.PageSaasRoleParam.builder().build();
BeanUtils.copyProperties(request, param);
Page<SaasRoleRes> page = roleService.page(param);
return ApiPageResult.ok(page.getRecords(), page.getTotal(), (int) page.getCurrent(), (int) page.getSize());
cn.axzo.foundation.page.PageResp<SaasRoleRes> page = roleService.page(param);
return ApiPageResult.ok(page.getData(), page.getTotal(), (int) page.getCurrent(), (int) page.getSize());
}
@Override
public ApiListResult<SaasRoleRes> list(ListRoleReq request) {
RoleService.ListSaasRoleParam param = RoleService.ListSaasRoleParam.builder().build();
BeanUtils.copyProperties(request, param);
return ApiListResult.ok(roleService.list(param));
}
@Override

View File

@ -4,7 +4,6 @@ import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.mapper.SaasFeatureResourceMapper;
import cn.azxo.framework.common.utils.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Repository;
@ -27,9 +26,6 @@ public class SaasFeatureResourceDao extends ServiceImpl<SaasFeatureResourceMappe
return this.lambdaQuery().eq(SaasFeatureResource::getFeatureCode, featureCode).one();
}
public void replacePath(String oldPath, String newPath) {
this.baseMapper.replacePath(oldPath, newPath);
}
public List<SaasFeatureResource> getByResourceTreeParam(GetFeatureResourceTreeReq req) {
return this.lambdaQuery().select(SaasFeatureResource::getId, SaasFeatureResource::getFeatureCode,

View File

@ -1,11 +1,11 @@
package cn.axzo.tyr.server.repository.entity;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.server.repository.handler.ProductModuleSkuHandler;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.*;
import org.apache.commons.lang3.StringUtils;
import java.io.Serializable;
@ -13,7 +13,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* saas-产品表(SaasProduct)表实体类
@ -25,7 +24,7 @@ import java.util.stream.Stream;
@Setter
@ToString
@EqualsAndHashCode(callSuper = true)
@TableName("product_module")
@TableName(value = "product_module", autoResultMap = true)
public class ProductModule extends BaseEntity<ProductModule> {
/**
@ -82,6 +81,56 @@ public class ProductModule extends BaseEntity<ProductModule> {
*/
private String ouType;
/**
* 创建人
*/
private Long createBy;
/**
* 修改人
*/
private Long updateBy;
/**
* 产品类型
* PRODUCT_VERSION:产品版本类型ADD_VALUE_SERVICE:增值服务类型
* GENERAL_SERVICE:通用产品类型HARD_WARE:硬件产品类型
*/
private String category;
/**
* 版本升级序列(数字越小版本越低不能降级只能升级) <企业项目产品>
*/
private Integer version;
/**
* 人数上限 <企业项目产品>
*/
private Integer maxPersonCount;
/**
* 最大项目数 <企业产品>
*/
private Integer maxWorkspaceCount;
/**
* 价格(单位)
*/
private Long price;
/**
* 产品详情 jsonList(skuNameSKU名称model规格型号count数量unit单位)
*/
@TableField(value = "skus", typeHandler = ProductModuleSkuHandler.class)
private List<Sku> skus;
/**
* 素材<仅硬件产品支持>json类型
* ({"miages":List<String>,"videos":List<String>,"detailImages":List<String>})
*/
@TableField(value = "material", typeHandler = FastjsonTypeHandler.class)
private Material material;
/**
* 获取主键值
*
@ -100,5 +149,54 @@ public class ProductModule extends BaseEntity<ProductModule> {
return new ArrayList<>();
}
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Sku {
/**
* SKU名称
*/
private String skuName;
/**
* 规格型号
*/
private String model;
/**
* 数量
*/
private Integer count;
/**
* 单位
*/
private String unit;
}
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class Material {
/**
* 图片
*/
private List<String> images;
/**
* 视频
*/
private List<String> videos;
/**
* 详情大图
*/
private List<String> detailImages;
}
}

View File

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.List;
@ -39,7 +40,7 @@ public class SaasFeatureResource extends BaseEntity<SaasFeature> {
private String featureName;
/**
* 资源类型1-菜单 2-页面 3-应用入口 4-组件
* 资源类型1-菜单 2-页面 3-应用入口 4-组件;5-root节点
*/
private Integer featureType;
@ -137,7 +138,7 @@ public class SaasFeatureResource extends BaseEntity<SaasFeature> {
if (StrUtil.isBlank(this.path)) {
return Collections.emptyList();
}
return StrUtil.split(this.path, ",").stream().map(Long::valueOf).collect(Collectors.toList());
return StrUtil.split(this.path, ",").stream().filter(StringUtils::isNotBlank).map(Long::valueOf).collect(Collectors.toList());
}

View File

@ -42,6 +42,11 @@ public class SaasProductModuleFeatureRelation extends BaseEntity<SaasProductModu
*/
private Long featureId;
/**
* 关联类型0saas_feature,1:saas_feature_resource
*/
private Integer type;
/**
* 获取主键值

View File

@ -0,0 +1,42 @@
package cn.axzo.tyr.server.repository.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
/**
* @author likunpeng
* @date 2024/5/16
* @version 1.0
*/
public abstract class ListTypeHandler<T> extends BaseTypeHandler<List<T>> {
@Override
public void setNonNullParameter(PreparedStatement ps, int i, List<T> parameter, JdbcType jdbcType) throws SQLException {
ps.setString(i, JSON.toJSONString(parameter));
}
@Override
public List<T> getNullableResult(ResultSet rs, String columnName) throws SQLException {
return rs.wasNull() ? null : JSON.parseObject(rs.getString(columnName), specificType());
}
@Override
public List<T> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
return rs.wasNull() ? null : JSON.parseObject(rs.getString(columnIndex), specificType());
}
@Override
public List<T> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
return cs.wasNull() ? null : JSON.parseObject(cs.getString(columnIndex), specificType());
}
protected abstract TypeReference<List<T>> specificType();
}

View File

@ -0,0 +1,20 @@
package cn.axzo.tyr.server.repository.handler;
import cn.axzo.tyr.server.repository.entity.ProductModule;
import com.alibaba.fastjson.TypeReference;
import org.apache.ibatis.type.MappedTypes;
import java.util.List;
/**
* @author likunpeng
* @version 1.0
* @date 2024/5/6
*/
@MappedTypes({List.class})
public class ProductModuleSkuHandler extends ListTypeHandler<ProductModule.Sku> {
@Override
protected TypeReference<List<ProductModule.Sku>> specificType() {
return new TypeReference<List<ProductModule.Sku>>(){};
}
}

View File

@ -2,8 +2,6 @@ package cn.axzo.tyr.server.repository.mapper;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
/**
* <p>
@ -15,8 +13,4 @@ import org.apache.ibatis.annotations.Update;
*/
public interface SaasFeatureResourceMapper extends BaseMapper<SaasFeatureResource> {
@Update("UPDATE saas_feature_resource" +
" SET path = REPLACE(path, #{oldPath}, #{newPath})" +
" WHERE is_delete = 0 AND path LIKE CONCAT(#{oldPath}, '%')")
void replacePath(@Param("oldPath") String oldPath, @Param("newPath") String newPath);
}

View File

@ -4,7 +4,11 @@ import cn.axzo.tyr.client.model.req.NavTreeReq;
import cn.axzo.tyr.client.model.req.PagePermissionReq;
import cn.axzo.tyr.client.model.req.PagePermissionResp;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.NavTreeResp;
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import java.util.List;
@ -23,4 +27,18 @@ public interface PermissionQueryService {
boolean hasPermission(PermissionCheckReq req);
List<PagePermissionResp> getPagePermission(PagePermissionReq req);
/**
* 查询租户的权限树
* @param request
* @return
*/
List<ProductFeatureResourceResp> treeProduct(TreeProductFeatureResourceReq request);
/**
* 查询租户的权限点list
* @param request
* @return
*/
List<FeatureResourceDTO> listFeatureResource(TreeProductFeatureResourceReq request);
}

View File

@ -7,6 +7,10 @@ import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
import cn.axzo.tyr.client.model.res.WorkspaceProductResp;
import java.util.List;
@ -29,4 +33,12 @@ public interface ProductService {
ApiResult<ProductVO> update(ProductUpdateReq req);
ApiResult<ProductVO> delete(Long id);
ApiResult<Void> updateStatus(UpdateProductStatusReq req);
ApiResult<Long> saveOrUpdate(ProductSaveReq req);
ApiResult<List<GovernmentTerminalResp>> getGovernmentTerminal(String terminal);
ApiResult<WorkspaceProductResp> getWorkspaceProduct(String workspaceType);
}

View File

@ -1,9 +1,9 @@
package cn.axzo.tyr.server.service;
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.framework.domain.page.PageResp;
import cn.axzo.pokonyan.dao.page.IPageParam;
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
import cn.axzo.pokonyan.dao.wrapper.Operator;
import cn.axzo.tyr.client.model.enums.IdentityType;
import cn.axzo.tyr.client.model.req.ChangeGroupLeaderRoleReq;
import cn.axzo.tyr.client.model.req.FeatureRoleRelationReq;
@ -121,7 +121,7 @@ public interface RoleService extends IService<SaasRole> {
List<SaasRoleRes> list(ListSaasRoleParam param);
Page<SaasRoleRes> page(PageSaasRoleParam param);
cn.axzo.foundation.page.PageResp<SaasRoleRes> page(PageSaasRoleParam param);
void saveOrUpdateFeatureRoleRelation(List<FeatureRoleRelationReq.RelationRoleSettings> req, Long operatorId);
@ -165,13 +165,16 @@ public interface RoleService extends IService<SaasRole> {
@CriteriaField(ignore = true)
private Boolean needRoleGroup;
@CriteriaField(ignore = true)
private Boolean needRoleUser;
}
@SuperBuilder
@Data
@NoArgsConstructor
@AllArgsConstructor
class PageSaasRoleParam extends ListSaasRoleParam implements IPageParam {
class PageSaasRoleParam extends ListSaasRoleParam implements IPageReq {
@CriteriaField(ignore = true)
Integer page;

View File

@ -27,6 +27,9 @@ public interface SaasFeatureResourceService {
/**递归的**/
List<SaasFeatureResource> listDescendant(Long featureId);
/**递归的**/
List<SaasFeatureResource> batchListDescendant(List<Long> featureIds);
SaasFeatureResource featureResourceById(Long featureId);
FeatureResourceTreeNode getTreeFeatureDescendant(Long featureId, Integer featureType);
@ -51,4 +54,6 @@ public interface SaasFeatureResourceService {
Set<Long> listAuthFree();
List<SaasFeatureResource> listNavMenu(String terminal);
List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds);
}

View File

@ -1,10 +1,10 @@
package cn.axzo.tyr.server.service;
import cn.axzo.pokonyan.dao.page.IPageParam;
import cn.axzo.pokonyan.dao.wrapper.CriteriaField;
import cn.axzo.pokonyan.dao.wrapper.Operator;
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.foundation.page.PageResp;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.AllArgsConstructor;
import lombok.Data;
@ -18,7 +18,7 @@ public interface SaasRoleGroupRelationService extends IService<SaasRoleGroupRela
List<SaasRoleGroupRelation> list(ListSaasRoleGroupRelationParam param);
Page<SaasRoleGroupRelation> page(PageSaasRoleGroupRelationParam param);
PageResp<SaasRoleGroupRelation> page(PageSaasRoleGroupRelationParam param);
@SuperBuilder
@Data
@ -38,7 +38,7 @@ public interface SaasRoleGroupRelationService extends IService<SaasRoleGroupRela
@Data
@NoArgsConstructor
@AllArgsConstructor
class PageSaasRoleGroupRelationParam extends ListSaasRoleGroupRelationParam implements IPageParam {
class PageSaasRoleGroupRelationParam extends ListSaasRoleGroupRelationParam implements IPageReq {
@CriteriaField(ignore = true)
Integer page;

View File

@ -2,7 +2,14 @@ package cn.axzo.tyr.server.service;
import cn.axzo.framework.domain.page.PageResp;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserDTO;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam;
import cn.axzo.tyr.client.model.roleuser.req.PageRoleUserRelationParam;
import cn.axzo.tyr.client.model.roleuser.req.RoleUserParam;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.List;
@ -10,8 +17,12 @@ import java.util.List;
* @author haiyangjin
* @date 2023/9/14
*/
public interface SaasRoleUserRelationService {
public interface SaasRoleUserRelationService extends IService<SaasRoleUserRelation> {
List<SaasRoleUserDTO> list(RoleUserParam param);
PageResp<SaasRoleUserDTO> pageQuery(RoleUserParam param);
List<SaasRoleUserV2DTO> listV2(ListRoleUserRelationParam param);
cn.axzo.foundation.page.PageResp<SaasRoleUserV2DTO> page(PageRoleUserRelationParam param);
}

View File

@ -12,9 +12,9 @@ import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.FeatureResourceSyncService;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
@ -122,31 +122,24 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
SaasFeatureResource baseResource = BeanMapper.copyBean(treeNode, SaasFeatureResource.class);
//修正数据
String parentCode = codeCache.get(baseResource.getParentId());
fixData(baseResource, parentCode);
SaasFeatureResource parent = StringUtils.isBlank(parentCode) ? null : featureResourceDao.getByCode(parentCode);
SaasFeatureResource resource = featureResourceDao.getByCode(treeNode.getFeatureCode());
if (resource == null) {
//新增
baseResource.setCreateBy(operatorId);
baseResource.setUpdateBy(operatorId);
newResource(baseResource);
newResource(baseResource, parent);
} else {
//更新 - 恢复不能变更的数据
baseResource.setId(resource.getId());
if (baseResource.getParentId() < 0) {
baseResource.setPath(resource.getId().toString());
} else {
baseResource.setPath(baseResource.getPath() + "," + resource.getId());
}
// 当前节点是父节点
resolveParentAndPath(baseResource, parent);
baseResource.setUpdateBy(operatorId);
baseResource.setAppItemId(resource.getAppItemId());
featureResourceDao.updateById(baseResource);
if (!StrUtil.equals(baseResource.getPath(), resource.getPath())) {
//层级变化
log.info("replace path from old:{} to new:{}", resource.getPath(), baseResource.getPath());
featureResourceDao.replacePath(resource.getPath(), baseResource.getPath());
}
}
//递归子节点
if (CollectionUtil.isNotEmpty(treeNode.getChildren())) {
@ -155,40 +148,22 @@ public class FeatureResourceSyncServiceImpl implements FeatureResourceSyncServic
}
}
/** 修正当前环境的数据 parentId path **/
private void fixData(SaasFeatureResource resource, String parentCode) {
// 原数据的parentId为负数表示是端下面的第一层数据此数据的path为当前数据的idparentId为原数据的parentId
if (resource.getParentId() < 0) {
resource.setParentId(resource.getParentId());
return;
}
if (StrUtil.isBlank(parentCode)) {
resource.setParentId(0L);
resource.setPath("0");
} else {
//找当前环境的parent
SaasFeatureResource parent = featureResourceDao.getByCode(parentCode);
if (parent == null) {
resource.setParentId(0L);
resource.setPath("0");
} else {
resource.setParentId(parent.getId());
resource.setPath(parent.getPath());
}
}
}
private void newResource(SaasFeatureResource resource) {
private void newResource(SaasFeatureResource resource, SaasFeatureResource parent) {
featureResourceDao.save(resource);
//path追加自身ID
if (resource.getParentId() < 0) {
resource.setPath(resource.getId().toString());
} else {
resource.setPath(resource.getPath() + "," + resource.getId());
}
resolveParentAndPath(resource, parent);
featureResourceDao.updateById(resource);
}
private void resolveParentAndPath(SaasFeatureResource resource, SaasFeatureResource parent) {
// 当前节点是父节点
if (parent == null) {
resource.setParentId(0L);
resource.setPath(resource.getId().toString() + ",");
} else {
resource.setParentId(parent.getId());
resource.setPath(parent.getPath() + resource.getId() + ",");
}
}
}

View File

@ -5,19 +5,27 @@ import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.basics.common.util.NumberUtil;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.maokai.common.enums.SaasCooperateShipCooperateTypeEnum;
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType;
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.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
import cn.axzo.tyr.client.model.base.WorkspaceOUPair;
import cn.axzo.tyr.client.model.enums.IdentityType;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationVO;
import cn.axzo.tyr.client.model.req.IdentityAuthReq;
import cn.axzo.tyr.client.model.req.NavTreeReq;
import cn.axzo.tyr.client.model.req.PagePermissionReq;
import cn.axzo.tyr.client.model.req.PagePermissionResp;
import cn.axzo.tyr.client.model.req.PermissionCheckReq;
import cn.axzo.tyr.client.model.req.TreeProductFeatureResourceReq;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.IdentityAuthRes;
import cn.axzo.tyr.client.model.res.NavTreeResp;
import cn.axzo.tyr.client.model.res.ProductFeatureResourceResp;
import cn.axzo.tyr.server.model.PermissionDO;
import cn.axzo.tyr.server.model.PermissionQueryContext;
import cn.axzo.tyr.server.model.ResourcePermission;
@ -25,18 +33,23 @@ import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
import cn.axzo.tyr.server.model.RoleWithFeature;
import cn.axzo.tyr.server.model.UserIdentity;
import cn.axzo.tyr.server.model.WorkspaceFeatureRelation;
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
import cn.axzo.tyr.server.service.PermissionQueryService;
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.TyrSaasAuthService;
import cn.axzo.tyr.server.util.KeyUtil;
import cn.axzo.tyr.server.utils.RpcInternalUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@ -67,6 +80,9 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
private final RoleUserService roleUserService;
private final RoleService roleService;
private final TyrSaasAuthService saasAuthService;
private final ServicePkgClient servicePkgClient;
private final ProductModuleDao productModuleDao;
private final ProductFeatureRelationService productFeatureRelationService;
@Override
public List<NavTreeResp> getNavTree(NavTreeReq req) {
@ -105,15 +121,15 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.sorted(Comparator.comparingInt(SaasFeatureResource::getDisplayOrder))
.collect(Collectors.toList());
//组装导航树
List<NavTreeResp> navTreeList = TreeUtil.buildTree(BeanMapper.copyList(finalResources, NavTreeResp.class));
//过滤顶级孤儿节点
return navTreeList.stream().filter(t -> !NumberUtil.isPositiveNumber(t.getParentId())).collect(Collectors.toList());
return TreeUtil.buildTree(BeanMapper.copyList(finalResources, NavTreeResp.class));
}
@Override
public boolean hasPermission(PermissionCheckReq req) {
//这里暂时硬编码-非OMS端鉴权请求 直接转老接口处理
if (!StrUtil.equals("NT_OMS_WEB" ,req.getTerminal())) {
if (!StrUtil.equals("NT_OMS_WEB" ,req.getTerminal())
&& !Objects.equals(TerminalInfo.NT_PC_GA_GENERAL, req.getTerminal())) {
return hasPermissionV2(req);
}
//权限编码转ID
@ -178,19 +194,94 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
.collect(Collectors.toList());
}
private List<PermissionDO> queryAllPermission(PermissionQueryContext context) {
//mock 调试用 返回全部权限
List<WorkspaceFeatureRelation> workspaceFeatureRelations = listWorkspaceFeatureRelations(context);
if (CollectionUtil.isEmpty(workspaceFeatureRelations)) {
@Override
public List<ProductFeatureResourceResp> treeProduct(TreeProductFeatureResourceReq request) {
List<FeatureResourceDTO> saasFeatureResources = listFeatureResource(request);
if (CollectionUtil.isEmpty(saasFeatureResources)) {
return Collections.emptyList();
}
Set<Long> featureIds = workspaceFeatureRelations.stream()
.map(WorkspaceFeatureRelation::getFeatureId)
.collect(Collectors.toSet());
PermissionDO permission = PermissionDO.builder().featureIds(featureIds).build();
return Collections.singletonList(permission);
List<ProductFeatureResourceResp> collect = saasFeatureResources.stream()
.map(this::resolveProductFeatureResourceResp)
.sorted(Comparator.comparing(ProductFeatureResourceResp::getDisplayOrder))
.collect(Collectors.toList());
return TreeUtil.buildTree(collect);
}
@Override
public List<FeatureResourceDTO> listFeatureResource(TreeProductFeatureResourceReq request) {
List<ProductFeatureRelationVO> productFeatureRelations = getProductFeatureRelationByWorkspace(Sets.newHashSet(request.getWorkspaceId()));
if (CollectionUtil.isEmpty(productFeatureRelations)) {
return Collections.emptyList();
}
List<Long> featureIds = productFeatureRelations.stream()
.map(ProductFeatureRelationVO::getFeatureId)
.distinct()
.collect(Collectors.toList());
return featureResourceService.listByParentIdAndTerminalAndIds(null, request.getTerminal(), featureIds).stream()
.map(e -> {
FeatureResourceDTO featureResourceDTO = FeatureResourceDTO.builder().build();
BeanUtils.copyProperties(e, featureResourceDTO);
return featureResourceDTO;
})
.collect(Collectors.toList());
}
private List<ProductFeatureRelationVO> getProductFeatureRelationByWorkspace(Set<Long> workspaceIds) {
List<ServicePkgDetailRes> servicePkgDetailRes = RpcInternalUtil.rpcListProcessor(() -> servicePkgClient.getServicePkgDetailBySpaceId(workspaceIds),
"查询租户的产品", workspaceIds).getData();
if (CollectionUtil.isEmpty(servicePkgDetailRes)) {
return Collections.emptyList();
}
List<Long> productIds = servicePkgDetailRes.stream()
.map(ServicePkgDetailRes::getProducts)
.filter(CollectionUtil::isNotEmpty)
.flatMap(List::stream)
.map(ServicePkgProduct::getProductId)
.distinct()
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(productIds)) {
log.warn("no product found for workspace :{}", workspaceIds);
return Collections.emptyList();
}
// 已被删除产品过滤一层
productIds = productModuleDao.listByIds(productIds)
.stream()
.filter(productModule -> Objects.equals(productModule.getIsDelete(),0L))
.map(BaseEntity::getId)
.distinct()
.collect(Collectors.toList());
if (CollectionUtil.isEmpty(productIds)) {
log.warn("all product is deleted for workspace :{}", workspaceIds);
return Collections.emptyList();
}
ApiResult<List<ProductFeatureRelationVO>> listProductFeatureRelation = productFeatureRelationService.featureListByProduct(productIds);
if (listProductFeatureRelation.isError() || CollectionUtil.isEmpty(listProductFeatureRelation.getData())) {
log.warn("no product features found for productIds :{} result:{}", productIds, listProductFeatureRelation);
return Collections.emptyList();
}
return listProductFeatureRelation.getData();
}
private ProductFeatureResourceResp resolveProductFeatureResourceResp(FeatureResourceDTO featureResource) {
return ProductFeatureResourceResp.builder()
.id(featureResource.getId())
.featureCode(featureResource.getFeatureCode())
.featureName(featureResource.getFeatureName())
.featureType(featureResource.getFeatureType())
.terminal(featureResource.getTerminal())
.parentId(featureResource.getParentId())
.displayOrder(featureResource.getDisplayOrder())
.build();
}
private List<PermissionDO> queryUserPermission(PermissionQueryContext context) {
//查询用户具有的角色
@ -278,19 +369,49 @@ public class PermissionQueryServiceImpl implements PermissionQueryService {
private List<WorkspaceFeatureRelation> listWorkspaceFeatureRelations(PermissionQueryContext context) {
//TODO:@Zhan 本期没做产品权限配置这里暂时先查询所有OMS资源作为已配置产品权限
List<ResourcePermission> permissions = featureResourceService.permissionQuery(ResourcePermissionQueryDTO.builder()
.terminals(Collections.singletonList(TerminalInfo.NT_OMS_WEB))
.build());
// 接口调用方用户传入端则以它为准没传入则兼容历史情况查询NT_OMS_WEB
String terminal = StringUtils.isBlank(context.getTerminal()) ? TerminalInfo.NT_OMS_WEB : context.getTerminal();
List<WorkspaceFeatureRelation> result = new ArrayList<>();
for (WorkspaceOUPair ow : context.getWorkspaceOUPairs()) {
List<WorkspaceFeatureRelation> owPermission = permissions.stream()
.map(p -> WorkspaceFeatureRelation.builder()
.workspaceId(ow.getWorkspaceId())
.productUnitType(SaasCooperateShipCooperateTypeEnum.OMS.code)
.featureId(p.getId())
.build())
.collect(Collectors.toList());
result.addAll(owPermission);
if (TerminalInfo.NT_OMS_WEB.equals(terminal)) {
List<ResourcePermission> permissions = featureResourceService.permissionQuery(ResourcePermissionQueryDTO.builder()
.terminals(Collections.singletonList(terminal))
.build());
for (WorkspaceOUPair ow : context.getWorkspaceOUPairs()) {
List<WorkspaceFeatureRelation> owPermission = permissions.stream()
.map(p -> WorkspaceFeatureRelation.builder()
.workspaceId(ow.getWorkspaceId())
.productUnitType(SaasCooperateShipCooperateTypeEnum.OMS.code)
.featureId(p.getId())
.build())
.collect(Collectors.toList());
result.addAll(owPermission);
}
} else {
// 其它端则查询租户的产品权限
Set<Long> workspaceIds = context.getWorkspaceOUPairs().stream().map(WorkspaceOUPair::getWorkspaceId).collect(Collectors.toSet());
List<ProductFeatureRelationVO> productFeatureRelations = getProductFeatureRelationByWorkspace(workspaceIds);
if (CollectionUtil.isEmpty(productFeatureRelations)) {
return result;
}
for (WorkspaceOUPair ow : context.getWorkspaceOUPairs()) {
List<WorkspaceFeatureRelation> owPermission = productFeatureRelations.stream()
.map(p -> {
WorkspaceFeatureRelation relation = WorkspaceFeatureRelation.builder()
.workspaceId(ow.getWorkspaceId())
.featureId(p.getFeatureId())
.productUnitType(0)
.build();
if (StringUtils.isNotBlank(p.getDictCode())) {
try {
relation.setProductUnitType(Integer.parseInt(p.getDictCode()));
} catch(Exception e){
log.warn("productDictCode to ProductUnitType error.");
}
}
return relation;
}).collect(Collectors.toList());
result.addAll(owPermission);
}
}
return result;
}

View File

@ -7,6 +7,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.common.enums.ProductModuleFeatureRelationTypeEnum;
import cn.axzo.tyr.client.model.permission.PermissionPointTreeNode;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationSearchReq;
import cn.axzo.tyr.client.model.product.ProductFeatureRelationUpdateReq;
@ -90,6 +91,7 @@ public class ProductFeatureRelationServiceImpl implements ProductFeatureRelation
relation.setDictCodeId(i.getDictCodeId());
relation.setDictCode(i.getDictCode());
relation.setFeatureId(featureId);
relation.setType(Objects.isNull(i.getFeatureRelationType()) ? 0 : i.getFeatureRelationType());
saveList.add(relation);
}));
saasProductModuleFeatureRelationDao.saveBatch(saveList);

View File

@ -2,26 +2,37 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.auth.domain.TerminalInfo;
import cn.axzo.framework.domain.page.PageResp;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.tyr.client.model.product.ProductAddReq;
import cn.axzo.tyr.client.model.product.ProductSearchListReq;
import cn.axzo.tyr.client.model.product.ProductSearchPageReq;
import cn.axzo.tyr.client.model.product.ProductUpdateReq;
import cn.axzo.tyr.client.model.product.ProductVO;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.common.enums.ProductModuleFeatureRelationTypeEnum;
import cn.axzo.tyr.client.model.dict.response.BasicDictNodeResp;
import cn.axzo.tyr.client.model.enums.ProductModuleCategoryEnum;
import cn.axzo.tyr.client.model.enums.WorkspaceTypeCodeEnum;
import cn.axzo.tyr.client.model.product.*;
import cn.axzo.tyr.client.model.req.ProductSaveReq;
import cn.axzo.tyr.client.model.req.UpdateProductStatusReq;
import cn.axzo.tyr.client.model.res.GovernmentTerminalResp;
import cn.axzo.tyr.client.model.res.WorkspaceProductResp;
import cn.axzo.tyr.server.repository.entity.ProductModule;
import cn.axzo.tyr.server.repository.dao.ProductModuleDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.ProductFeatureRelationService;
import cn.axzo.tyr.server.service.ProductService;
import cn.hutool.core.util.StrUtil;
import cn.axzo.tyr.server.service.SaasBasicDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import io.swagger.models.auth.In;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Integers;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
@ -40,6 +51,8 @@ import java.util.stream.Collectors;
public class ProductServiceImpl implements ProductService {
private final ProductModuleDao productModuleDao;
private final ProductFeatureRelationService productFeatureRelationService;
private final SaasFeatureResourceService saasFeatureResourceService;
private final SaasBasicDictService saasBasicDictService;
@Override
public ApiResult<List<ProductVO>> list(ProductSearchListReq req) {
@ -76,9 +89,16 @@ public class ProductServiceImpl implements ProductService {
IPage<ProductModule> page = productModuleDao.lambdaQuery()
.like(StringUtils.hasLength(req.getName()), ProductModule::getProductName, req.getName())
.eq(Objects.nonNull(req.getDictWorkspaceTypeId()), ProductModule::getDictWorkspaceTypeId, req.getDictWorkspaceTypeId())
.eq(Objects.nonNull(req.getDictWorkspaceTypeCode()), ProductModule::getDictWorkspaceTypeCode, req.getDictWorkspaceTypeCode())
.eq(Objects.nonNull(req.getStatus()), ProductModule::getStatus, req.getStatus())
.eq(org.apache.commons.lang3.StringUtils.isNotBlank(req.getProductCategory()), ProductModule::getCategory, req.getProductCategory())
.orderByDesc(BaseEntity::getId)
.page(req.toPage());
List<ProductVO> list = BeanMapper.copyList(page.getRecords(), ProductVO.class);
list.forEach(e -> {
e.setProductCategoryDesc(ProductModuleCategoryEnum.getDescByCode(e.getCategory()));
e.setDictWorkspaceTypeDesc(WorkspaceTypeCodeEnum.getDescByCode(e.getDictWorkspaceTypeCode()));
});
PageResp<ProductVO> data = PageResp.list(page.getCurrent(), page.getSize(), page.getTotal(), list);
return ApiPageResult.ok(data);
}
@ -88,6 +108,23 @@ public class ProductServiceImpl implements ProductService {
ProductModule byId = productModuleDao.getById(id);
ProductVO productVO = BeanMapper.copyBean(byId, ProductVO.class);
productVO.setOuTypes(byId.parseOuType());
productVO.setProductCategoryDesc(ProductModuleCategoryEnum.getDescByCode(productVO.getCategory()));
productVO.setDictWorkspaceTypeDesc(WorkspaceTypeCodeEnum.getDescByCode(productVO.getDictWorkspaceTypeCode()));
productVO.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(byId.getSkus()) ? Collections.emptyList()
: byId.getSkus().stream().map(e -> ProductVO.Sku.builder()
.skuName(e.getSkuName())
.model(e.getModel())
.count(e.getCount())
.unit(e.getUnit())
.build()).collect(Collectors.toList()));
productVO.setMaterial(Objects.isNull(byId.getMaterial()) ? null : ProductVO.Material.builder()
.images(byId.getMaterial().getImages())
.videos(byId.getMaterial().getVideos())
.detailImages(byId.getMaterial().getDetailImages())
.build());
if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(productVO.getDictWorkspaceTypeCode())) {
fillFeatureScope(productVO);
}
return ApiResult.ok(productVO);
}
@ -137,4 +174,211 @@ public class ProductServiceImpl implements ProductService {
productFeatureRelationService.removeByProductId(id);
return ApiResult.ok(BeanMapper.copyBean(productModule, ProductVO.class));
}
@Override
public ApiResult<Void> updateStatus(UpdateProductStatusReq req) {
ProductModule productModule = productModuleDao.getOne(new LambdaQueryWrapper<ProductModule>()
.eq(BaseEntity::getId, req.getId())
.eq(BaseEntity::getIsDelete, Boolean.FALSE)
.last("LIMIT 1"));
AssertUtil.notNull(productModule, "产品不存在");
productModuleDao.lambdaUpdate()
.eq(ProductModule::getId, req.getId())
.set(ProductModule::getStatus, req.getStatus())
.update();
return ApiResult.ok();
}
@Override
@Transactional(rollbackFor = Exception.class)
public ApiResult<Long> saveOrUpdate(ProductSaveReq req) {
ProductModule productModule = new ProductModule();
if (Objects.nonNull(req.getId())) {
productModule = productModuleDao.getOne(new LambdaQueryWrapper<ProductModule>()
.eq(BaseEntity::getId, req.getId())
.eq(BaseEntity::getIsDelete, Boolean.FALSE)
.last("LIMIT 1"));
AssertUtil.notNull(productModule, "产品不存在");
if (Objects.nonNull(req.getVersion()) && Objects.nonNull(productModule.getVersion())) {
AssertUtil.isTrue(req.getVersion() >= productModule.getVersion(), "版本升级序列不允许降级");
}
}
validAndFillEntity(req, productModule);
if (Objects.nonNull(req.getId())) {
productModule.setUpdateBy(req.getOperator());
productModuleDao.updateById(productModule);
} else {
productModule.setCreateBy(req.getOperator());
productModuleDao.save(productModule);
}
// 保存商品权限信息
if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(productModule.getDictWorkspaceTypeCode())) {
saveGovernmentFeatureResource(productModule.getId(), productModule.getDictWorkspaceTypeId(), productModule.getDictWorkspaceTypeCode(), req.getFeatureScope().getGovernmentFeatureResourceIds());
}
return ApiResult.ok(productModule.getId());
}
@Override
public ApiResult<List<GovernmentTerminalResp>> getGovernmentTerminal(String terminal) {
List<SaasFeatureResource> featureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(0L, terminal, null);
List<GovernmentTerminalResp> resps = CollectionUtil.isEmpty(featureResources) ? Collections.emptyList() : featureResources.stream().map(e -> GovernmentTerminalResp.builder()
.featureResourceId(e.getId())
.featureResourceName(e.getFeatureName())
.build()).collect(Collectors.toList());
return ApiResult.ok(resps);
}
@Override
public ApiResult<WorkspaceProductResp> getWorkspaceProduct(String workspaceType) {
List<ProductModule> productModules = productModuleDao.lambdaQuery()
.eq(ProductModule::getStatus, 1)
.eq(Objects.nonNull(workspaceType), ProductModule::getDictWorkspaceTypeCode, workspaceType)
.in(ProductModule::getCategory, ProductModuleCategoryEnum.ALL_CATEGORY_CODE)
.list();
if (CollectionUtil.isEmpty(productModules)) {
return ApiResult.ok(WorkspaceProductResp.builder().build());
}
WorkspaceProductResp resp = WorkspaceProductResp.init();
Map<String, List<ProductModule>> categoryMap = productModules.stream().collect(Collectors.groupingBy(ProductModule::getCategory));
categoryMap.forEach((k,v) -> {
// 政务产品
if (WorkspaceTypeCodeEnum.GOVERNMENT.getCode().equals(workspaceType)) {
resp.getGovernmentProduct().addAll(v.stream().map(e -> WorkspaceProductResp.Product.builder()
.productId(e.getId())
.productName(e.getProductName())
.build()).collect(Collectors.toList()));
} else {
if (ProductModuleCategoryEnum.PRODUCT_VERSION.getCode().equals(k)) {
resp.getProductVersions().addAll(v.stream().map(this::buildRespProduct).filter(Objects::nonNull).collect(Collectors.toList()));
}
if (ProductModuleCategoryEnum.ADD_VALUE_SERVICE.getCode().equals(k)) {
resp.getAddValueServices().addAll(v.stream().map(this::buildRespProduct).filter(Objects::nonNull).collect(Collectors.toList()));
}
if (ProductModuleCategoryEnum.GENERAL_SERVICE.getCode().equals(k)) {
resp.getGeneralServices().addAll(v.stream().map(this::buildRespProduct).filter(Objects::nonNull).collect(Collectors.toList()));
}
if (ProductModuleCategoryEnum.HARD_WARE.getCode().equals(k)) {
resp.getHardware().addAll(v.stream().map(this::buildRespProduct).filter(Objects::nonNull).collect(Collectors.toList()));
}
}
});
return ApiResult.ok(resp);
}
private void validAndFillEntity(ProductSaveReq req, ProductModule productModule) {
ProductModule nameProduct = productModuleDao.getOne(new LambdaQueryWrapper<ProductModule>()
.eq(BaseEntity::getIsDelete, Boolean.FALSE)
.eq(ProductModule::getProductName, req.getProductName())
.eq(ProductModule::getDictWorkspaceTypeId, req.getDictWorkspaceTypeId())
.ne(Objects.nonNull(req.getId()), BaseEntity::getId, req.getId())
.last("LIMIT 1"));
AssertUtil.isNull(nameProduct, "产品【" + req.getProductName() + "】已存在");
BasicDictNodeResp basicDictNodeResp = saasBasicDictService.getById(req.getDictWorkspaceTypeId());
AssertUtil.notNull(basicDictNodeResp, "租户类型有误");
WorkspaceTypeCodeEnum workspaceTypeCodeEnum = WorkspaceTypeCodeEnum.getByCode(basicDictNodeResp.getCode());
AssertUtil.notNull(workspaceTypeCodeEnum, "租户类型有误");
AssertUtil.isTrue(WorkspaceTypeCodeEnum.ALLOW_ADD_WORKSPACE_TYPE_CODE_ENUM.contains(workspaceTypeCodeEnum), "租户类型选择有误");
ProductModuleCategoryEnum productModuleCategoryEnum = ProductModuleCategoryEnum.getByCode(req.getProductCategory());
AssertUtil.notNull(productModuleCategoryEnum, "产品类型有误");
// if (WorkspaceTypeCodeEnum.GENERAL_ENT.equals(workspaceTypeCodeEnum) || WorkspaceTypeCodeEnum.GENERAL_PROJECT.equals(workspaceTypeCodeEnum)) {
// AssertUtil.notNull(req.getMaxPersonCount(), "人数上限不能为空");
// AssertUtil.notNull(req.getPrice(), "价格不能为空");
// if (ProductModuleCategoryEnum.PRODUCT_VERSION.getCode().equals(req.getProductCategory())) {
// AssertUtil.notNull(req.getVersion(), "版本升级序列不能为空");
// }
// }
if (WorkspaceTypeCodeEnum.GOVERNMENT.equals(workspaceTypeCodeEnum)) {
AssertUtil.isTrue(Objects.nonNull(req.getFeatureScope())
&& org.apache.commons.collections4.CollectionUtils.isNotEmpty(req.getFeatureScope().getGovernmentFeatureResourceIds()), "功能范围选择有误");
}
productModule.setProductName(req.getProductName());
productModule.setIcon(req.getIcon());
productModule.setDictWorkspaceTypeId(req.getDictWorkspaceTypeId());
productModule.setDictWorkspaceTypeCode(workspaceTypeCodeEnum.getCode());
productModule.setProductType(0);
productModule.setStatus(Objects.nonNull(productModule.getId()) ? productModule.getStatus() : 1);
productModule.setCategory(req.getProductCategory());
productModule.setVersion(req.getVersion());
productModule.setMaxPersonCount(req.getMaxPersonCount());
productModule.setMaxWorkspaceCount(req.getMaxWorkspaceCount());
productModule.setPrice(req.getPrice());
productModule.setSkus(org.apache.commons.collections.CollectionUtils.isEmpty(req.getSkus()) ? Lists.newArrayList()
: req.getSkus().stream().map(e -> ProductModule.Sku.builder()
.skuName(e.getSkuName())
.model(e.getModel())
.count(e.getCount())
.unit(e.getUnit())
.build()).collect(Collectors.toList()));
productModule.setMaterial(Optional.ofNullable(req.getMaterial()).map(e -> ProductModule.Material.builder()
.images(e.getImages())
.videos(e.getVideos())
.detailImages(e.getDetailImages())
.build()).orElse(ProductModule.Material.builder().build()));
productModule.setRemark(req.getRemark());
}
/**
* 保存政务端产品功能权限
*/
private void saveGovernmentFeatureResource(Long productId, Long dictWorkspaceTypeId, String dictWorkspaceTypeCode, List<Long> rootFeatureIds) {
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(null, null, rootFeatureIds);
AssertUtil.notEmpty(saasFeatureResources, "功能范围选择端不能为空");
saasFeatureResources.forEach(e -> {
AssertUtil.isTrue(e.getParentId() == 0 && TerminalInfo.NT_PC_GA_GENERAL.equals(e.getTerminal()), "功能范围选择端有误");
});
List<SaasFeatureResource> frs = saasFeatureResourceService.batchListDescendant(rootFeatureIds);
ProductFeatureRelationUpdateReq req = new ProductFeatureRelationUpdateReq();
req.setDictCodeId(dictWorkspaceTypeId);
req.setDictCode(dictWorkspaceTypeCode);
req.setProductModuleId(productId);
Set<Long> featureIds = org.apache.commons.collections.CollectionUtils.isEmpty(frs) ? Sets.newHashSet()
: frs.stream().map(BaseEntity::getId).collect(Collectors.toSet());
featureIds.addAll(rootFeatureIds);
req.getFeatureIds().addAll(featureIds);
req.setFeatureRelationType(ProductModuleFeatureRelationTypeEnum.FEATURE_RESOURCE.getCode());
productFeatureRelationService.updateFeatureRelation(Collections.singletonList(req));
}
private void fillFeatureScope(ProductVO product) {
ProductFeatureRelationSearchReq req = new ProductFeatureRelationSearchReq();
req.setProductModuleId(product.getId());
req.setDictCodeId(product.getDictWorkspaceTypeId());
req.setDictCode(product.getDictWorkspaceTypeCode());
ApiResult<List<ProductFeatureRelationVO>> result = productFeatureRelationService.featureList(req);
if (org.apache.commons.collections.CollectionUtils.isEmpty(result.getData())) {
return;
}
List<Long> featureIds = result.getData().stream().map(ProductFeatureRelationVO::getFeatureId).collect(Collectors.toList());
List<SaasFeatureResource> featureResources = saasFeatureResourceService.listByParentIdAndTerminalAndIds(0L, TerminalInfo.NT_PC_GA_GENERAL, featureIds);
if (CollectionUtil.isNotEmpty(featureResources)) {
product.setFeatureScopes(featureResources.stream().map(e -> ProductVO.FeatureScope.builder()
.governmentFeatureResourceId(e.getId())
.featureResourceName(e.getFeatureName())
.build()).collect(Collectors.toList()));
}
}
private WorkspaceProductResp.Product buildRespProduct(ProductModule pm) {
return Optional.ofNullable(pm).map(e -> WorkspaceProductResp.Product.builder()
.productId(e.getId())
.productName(e.getProductName())
.maxPersonCount(e.getMaxPersonCount())
.maxWorkspaceCount(e.getMaxWorkspaceCount())
.skus(CollectionUtil.isNotEmpty(e.getSkus()) ? e.getSkus().stream().map(s -> WorkspaceProductResp.Sku
.builder()
.skuName(s.getSkuName())
.model(s.getModel())
.count(s.getCount())
.unit(s.getUnit())
.build()).collect(Collectors.toList()) : Collections.emptyList())
.build()).orElse(null);
}
}

View File

@ -2,10 +2,10 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.foundation.dao.support.converter.PageConverter;
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.framework.domain.page.PageResp;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
import cn.axzo.tyr.client.common.enums.RoleResourceTypeEnum;
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
import cn.axzo.tyr.client.model.enums.IdentityType;
@ -27,6 +27,8 @@ import cn.axzo.tyr.client.model.res.RoleWithUserRes;
import cn.axzo.tyr.client.model.res.SaasPermissionRes;
import cn.axzo.tyr.client.model.res.SaasRoleGroupRes;
import cn.axzo.tyr.client.model.res.SaasRoleRes;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam;
import cn.axzo.tyr.client.model.vo.DeleteRoleVO;
import cn.axzo.tyr.client.model.vo.SaasPermissionGroupVO;
import cn.axzo.tyr.client.model.vo.SaasRoleAndGroupVO;
@ -64,14 +66,17 @@ import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
import cn.axzo.tyr.server.service.SaasRoleGroupRelationService;
import cn.axzo.tyr.server.service.SaasRoleGroupService;
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
@ -154,6 +159,9 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
SaasRoleGroupRelationDao saasRoleGroupRelationDao;
@Autowired
SaasFeatureResourceService saasFeatureResourceService;
@Autowired
private SaasRoleUserRelationService saasRoleUserRelationService;
@Value("${groupLeader.code:projectTeamGPLeader}")
private String groupLeaderCode;
@ -1164,28 +1172,33 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
}
@Override
public Page<SaasRoleRes> page(PageSaasRoleParam param) {
public cn.axzo.foundation.page.PageResp<SaasRoleRes> page(PageSaasRoleParam param) {
QueryWrapper<SaasRole> wrapper = QueryWrapperHelper.fromBean(param, SaasRole.class);
wrapper.eq("is_delete", 0);
Page<SaasRole> page = this.page(PageConverter.convertToMybatis(param, SaasRole.class), wrapper);
IPage<SaasRole> page = this.page(PageConverter.toMybatis(param, SaasRole.class), wrapper);
Map<Long, List<SaasRoleGroupRes>> saasRoleGroups = listRoleGroups(param, page.getRecords());
Map<Long, List<SaasPermissionRes>> saasPermissions = listRolePermissions(param, page.getRecords());
return PageConverter.convert(page, (record) -> from(record,
Map<Long, List<SaasRoleUserV2DTO.SaasRoleUser>> saasRoleUsers = listSaasRoleUser(param, page.getRecords());
return PageConverter.toResp(page, (record) -> from(record,
saasRoleGroups,
saasPermissions));
saasPermissions,
saasRoleUsers));
}
private SaasRoleRes from(SaasRole saasRole,
Map<Long, List<SaasRoleGroupRes>> saasRoleGroups,
Map<Long, List<SaasPermissionRes>> saasPermissions) {
Map<Long, List<SaasPermissionRes>> saasPermissions,
Map<Long, List<SaasRoleUserV2DTO.SaasRoleUser>> saasRoleUsers) {
SaasRoleRes saasRoleRes = SaasRoleRes.builder().build();
BeanUtils.copyProperties(saasRole, saasRoleRes);
saasRoleRes.setSaasRoleGroups(saasRoleGroups.get(saasRoleRes.getId()));
saasRoleRes.setSaasPermissions(saasPermissions.get(saasRoleRes.getId()));
saasRoleRes.setSaasRoleUsers(saasRoleUsers.get(saasRoleRes.getId()));
return saasRoleRes;
}
@ -1378,4 +1391,23 @@ public class RoleServiceImpl extends ServiceImpl<SaasRoleMapper, SaasRole>
throw new ServiceException(String.format("权限点 %s 信息错误", permissionIds));
}
}
private Map<Long, List<SaasRoleUserV2DTO.SaasRoleUser>> listSaasRoleUser(PageSaasRoleParam param,
List<SaasRole> saasRoles) {
if (CollectionUtils.isEmpty(saasRoles) || BooleanUtils.isNotTrue(param.getNeedRoleUser())) {
return Collections.emptyMap();
}
List<Long> roleIds = Lists.transform(saasRoles, SaasRole::getId);
ListRoleUserRelationParam listRoleUserRelationParam = ListRoleUserRelationParam.builder()
.roleIds(roleIds)
.needUsers(param.getNeedRoleUser())
.build();
List<SaasRoleUserV2DTO> saasRoleUserV2DTOS = saasRoleUserRelationService.listV2(listRoleUserRelationParam);
return saasRoleUserV2DTOS.stream()
.map(e -> Pair.of(e.getRoleId(), e.getSaasRoleUser()))
.collect(Collectors.groupingBy(Pair::getKey, Collectors.mapping(Pair::getValue, Collectors.toList())));
}
}

View File

@ -253,18 +253,18 @@ public class RoleUserService implements SaasRoleUserService {
private SaasRole findSuperAdmin(Long workspaceId, Long ouId, Integer workspaceType) {
//优先取租户超管 没有再取标准角色超管
//租户超管
SaasRole superAdmin = saasRoleDao
return saasRoleDao
.findRoleByTypeAndWorkspaceIdAndOuId(RoleTypeEnum.SUPER_ADMIN.getValue(),
workspaceId, ouId);
if (superAdmin != null) {
return superAdmin;
}
// if (superAdmin != null) {
// return superAdmin;
// }
//标准角超管
String superAdminCode = superAdminCodes.get(workspaceType);
if (StrUtil.isBlank(superAdminCode)) {
throw new ServiceException("租户类型[" + workspaceType + "]未配置超管编码");
}
return saasRoleDao.lambdaQuery().eq(SaasRole::getRoleCode, superAdminCode).one();
// String superAdminCode = superAdminCodes.get(workspaceType);
// if (StrUtil.isBlank(superAdminCode)) {
// throw new ServiceException("租户类型[" + workspaceType + "]未配置超管编码");
// }
// return saasRoleDao.lambdaQuery().eq(SaasRole::getRoleCode, superAdminCode).one();
}
private void checkRoleName(String name, Long workspaceId, Long ouId) {

View File

@ -30,7 +30,8 @@ public class SaasCommonDictServiceImpl implements SaasCommonDictService {
private final SaasCommonDictDao commonDictDao;
@Override
public List<CommonDictResp> query(CommonDictQueryReq req) {
public List<CommonDictResp>
query(CommonDictQueryReq req) {
List<SaasCommonDict> list = commonDictDao.lambdaQuery()
.eq(Objects.nonNull(req.getScope()), SaasCommonDict::getScope, req.getScope())

View File

@ -3,18 +3,14 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.util.StopWatchUtil;
import cn.axzo.basics.common.util.TreeUtil;
import cn.axzo.framework.domain.web.BizException;
import cn.axzo.framework.domain.web.code.BaseCode;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.pokonyan.config.redis.RedisClient;
import cn.axzo.tyr.client.common.enums.FeatureResourceAuthType;
import cn.axzo.tyr.client.common.enums.FeatureResourceStatus;
import cn.axzo.tyr.client.common.enums.FeatureResourceType;
import cn.axzo.tyr.client.model.req.CommonDictQueryReq;
import cn.axzo.tyr.client.model.req.FeatureComponentSaveReq;
import cn.axzo.tyr.client.model.req.FeatureResourceTreeSaveReq;
import cn.axzo.tyr.client.model.req.GetFeatureResourceTreeReq;
import cn.axzo.tyr.client.model.res.CommonDictResp;
import cn.axzo.tyr.client.model.res.FeatureResourceDTO;
import cn.axzo.tyr.client.model.res.FeatureResourceTreeNode;
import cn.axzo.tyr.server.common.util.Throws;
@ -23,16 +19,13 @@ import cn.axzo.tyr.server.model.ResourcePermissionQueryDTO;
import cn.axzo.tyr.server.model.convert.SaasFeatureResourceConvert;
import cn.axzo.tyr.server.repository.dao.SaasFeatureResourceDao;
import cn.axzo.tyr.server.repository.entity.SaasFeatureResource;
import cn.axzo.tyr.server.service.RoleService;
import cn.axzo.tyr.server.service.SaasCommonDictService;
import cn.axzo.tyr.server.service.SaasFeatureResourceService;
import cn.axzo.tyr.server.service.SaasPgroupPermissionRelationService;
import cn.azxo.framework.common.utils.StringUtils;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
@ -46,15 +39,9 @@ import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import java.util.stream.Collectors;
import static cn.axzo.framework.domain.web.code.BaseCode.BAD_REQUEST;
import static cn.axzo.framework.domain.web.code.BaseCode.SERVER_ERROR;
import static cn.axzo.tyr.server.common.constants.CacheConstant.KEY_AUTH_FREE;
/**
* 功能资源服务实现
* 功能资源树查询增加了redis缓存在新增修改该表时记得清空缓存
@ -121,17 +108,6 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
@Override
public List<FeatureResourceTreeNode> getTree(GetFeatureResourceTreeReq req) {
List<CommonDictResp> commonDictResponses = saasCommonDictService.query(CommonDictQueryReq.builder().scope(RESOURCE_TERMINAL_SCOPE).build());
if (CollectionUtils.isEmpty(commonDictResponses)) {
log.error("not config resource terminal in saas_common_dict table");
return Collections.emptyList();
}
final AtomicLong rootIdIndex = new AtomicLong(0L);
List<FeatureResourceTreeNode> rootNodes = commonDictResponses.stream().map(e -> FeatureResourceTreeNode.builder()
.id(rootIdIndex.decrementAndGet()).terminal(e.getDictCode()).featureName(e.getDictValue())
.featureCode(e.getDictCode()).featureType(-1).children(Lists.newArrayList()).build()).collect(Collectors.toList());
StopWatchUtil watch = StopWatchUtil.createStarted("feature-resource-tree");
watch.start("dbQuery");
List<SaasFeatureResource> saasFeatureResources = saasFeatureResourceCacheService.getByResourceTreeParam(req);
@ -143,17 +119,15 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
List<FeatureResourceTreeNode> treeList = TreeUtil.buildTree(saasFeatureResources.stream()
.map(this::featureResource2Node)
.sorted(Comparator.comparing(FeatureResourceDTO::getDisplayOrder))
.collect(Collectors.toList()));
saasFeatureResources = null; // help GC
.collect(Collectors.toList()))
.stream()
// 因为存在tree中某个节点被隐藏导致它的子节点构建在tree的root上应该排除掉root节点一定是parentId == 0的
.filter(e -> e.getParentId() == 0)
.collect(Collectors.toList());
//搜索或需要按授权策略过滤 - 有额外的过滤条件
watch.start("filter-node");
List<FeatureResourceTreeNode> filterResultNode = filterTreeNode(req.getKeyword(), treeList);
watch.stop();
//把处理后的树结构添加上根节点
watch.start("fill-children-to-root");
List<FeatureResourceTreeNode> resultNode = fillChildren2Root(rootNodes, filterResultNode);
List<FeatureResourceTreeNode> resultNode = filterTreeNode(req.getKeyword(), treeList);
watch.stop();
log.info("feature-resource-tree cost:{} , ms:{}", watch.prettyPrint(), watch.getTotalTimeMillis());
@ -234,7 +208,8 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
private void newResource(SaasFeatureResource resource, String parentPath) {
featureResourceDao.save(resource);
//path追加自身ID
resource.setPath(StringUtils.isBlank(parentPath) ? resource.getId().toString() : parentPath + "," + resource.getId());
// path增加","后缀方便后续查询所有子节点
resource.setPath(StringUtils.isBlank(parentPath) ? resource.getId().toString() + "," : parentPath + resource.getId() + ",");
featureResourceDao.updateById(resource);
}
@ -312,6 +287,18 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
.list();
}
// 查询resource节点及子节点
@Override
public List<SaasFeatureResource> batchListDescendant(List<Long> featureIds) {
if (CollectionUtils.isEmpty(featureIds)) {
return Collections.emptyList();
}
return featureResourceDao.lambdaQuery()
.eq(BaseEntity::getIsDelete,0)
.and(i -> featureIds.forEach(f -> i.or().likeRight(SaasFeatureResource::getPath, f + ",")))
.list();
}
@Override
public SaasFeatureResource featureResourceById(Long featureId) {
if (featureId == null) {
@ -479,4 +466,14 @@ public class SaasFeatureResourceServiceImpl implements SaasFeatureResourceServic
.orderByAsc(SaasFeatureResource::getDisplayOrder)
.list();
}
@Override
public List<SaasFeatureResource> listByParentIdAndTerminalAndIds(Long parentId, String terminal, List<Long> featureIds) {
return featureResourceDao.lambdaQuery()
.eq(BaseEntity::getIsDelete, 0)
.eq(Objects.nonNull(parentId), SaasFeatureResource::getParentId, parentId)
.eq(StringUtils.isNotBlank(terminal), SaasFeatureResource::getTerminal, terminal)
.in(CollectionUtil.isNotEmpty(featureIds), SaasFeatureResource::getId, featureIds)
.list();
}
}

View File

@ -1,14 +1,15 @@
package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
import cn.axzo.pokonyan.dao.converter.PageConverter;
import cn.axzo.pokonyan.dao.mysql.QueryWrapperHelper;
import cn.axzo.foundation.dao.support.converter.PageConverter;
import cn.axzo.foundation.dao.support.mysql.QueryWrapperHelper;
import cn.axzo.foundation.page.PageResp;
import cn.axzo.tyr.server.repository.dao.SaasRoleGroupRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasRoleGroupRelation;
import cn.axzo.tyr.server.repository.mapper.SaasRoleGroupRelationMapper;
import cn.axzo.tyr.server.service.SaasRoleGroupRelationService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -19,6 +20,7 @@ import org.springframework.transaction.annotation.Transactional;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Slf4j
@ -63,10 +65,11 @@ public class SaasRoleGroupRelationServiceImpl extends ServiceImpl<SaasRoleGroupR
}
@Override
public Page<SaasRoleGroupRelation> page(PageSaasRoleGroupRelationParam param) {
public PageResp<SaasRoleGroupRelation> page(PageSaasRoleGroupRelationParam param) {
QueryWrapper<SaasRoleGroupRelation> wrapper = QueryWrapperHelper.fromBean(param, SaasRoleGroupRelation.class);
wrapper.eq("is_delete", 0);
IPage<SaasRoleGroupRelation> page = this.page(PageConverter.toMybatis(param, SaasRoleGroupRelation.class), wrapper);
return this.page(PageConverter.convertToMybatis(param, SaasRoleGroupRelation.class), wrapper);
return PageConverter.toResp(page, Function.identity());
}
}

View File

@ -226,6 +226,8 @@ public class SaasRoleGroupServiceImpl extends ServiceImpl<SaasRoleGroupMapper, S
Integer count = saasRoleGroupDao.lambdaQuery()
.eq(SaasRoleGroup::getCode, req.getCode())
.eq(SaasRoleGroup::getIsDelete, TableIsDeleteEnum.NORMAL.value)
.eq(Objects.nonNull(req.getWorkspaceId()), SaasRoleGroup::getWorkspaceId,req.getWorkspaceId())
.eq(Objects.nonNull(req.getOuId()), SaasRoleGroup::getOuId,req.getOuId())
.count();
if (count > 0) {
throw new ServiceException("角色分组编码已经存在");

View File

@ -2,24 +2,41 @@ package cn.axzo.tyr.server.service.impl;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.basics.common.constant.enums.TableIsDeleteEnum;
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.framework.domain.page.PageResp;
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
import cn.axzo.tyr.client.common.enums.RoleTypeEnum;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserDTO;
import cn.axzo.tyr.client.model.roleuser.dto.SaasRoleUserV2DTO;
import cn.axzo.tyr.client.model.roleuser.req.ListRoleUserRelationParam;
import cn.axzo.tyr.client.model.roleuser.req.PageRoleUserRelationParam;
import cn.axzo.tyr.client.model.roleuser.req.RoleUserParam;
import cn.axzo.tyr.server.repository.dao.SaasRoleDao;
import cn.axzo.tyr.server.repository.dao.SaasRoleUserRelationDao;
import cn.axzo.tyr.server.repository.entity.SaasRole;
import cn.axzo.tyr.server.repository.entity.SaasRoleUserRelation;
import cn.axzo.tyr.server.repository.mapper.SaasRoleUserRelationMapper;
import cn.axzo.tyr.server.service.SaasRoleUserRelationService;
import cn.axzo.tyr.server.util.RpcInternalUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@ -33,7 +50,8 @@ import java.util.stream.Collectors;
*/
@Slf4j
@Service
public class SaasRoleUserRelationServiceImpl implements SaasRoleUserRelationService {
public class SaasRoleUserRelationServiceImpl extends ServiceImpl<SaasRoleUserRelationMapper, SaasRoleUserRelation>
implements SaasRoleUserRelationService {
@Resource
private SaasRoleUserRelationDao saasRoleUserRelationDao;
@ -41,6 +59,9 @@ public class SaasRoleUserRelationServiceImpl implements SaasRoleUserRelationServ
@Resource
private SaasRoleDao saasRoleDao;
@Autowired
private UserProfileServiceApi userProfileServiceApi;
@Override
public List<SaasRoleUserDTO> list(RoleUserParam param) {
// TODO jhy 角色查询 需要验证标准角色和自定义角色的查询逻辑
@ -99,4 +120,73 @@ public class SaasRoleUserRelationServiceImpl implements SaasRoleUserRelationServ
.collect(Collectors.toList());
return PageResp.list(param.getPage(), param.getPageSize(), page.getTotal(), list);
}
@Override
public List<SaasRoleUserV2DTO> listV2(ListRoleUserRelationParam param) {
return PageConverter.drainAll(pageNumber -> {
PageRoleUserRelationParam pageParam = PageRoleUserRelationParam.builder().build();
BeanUtils.copyProperties(param, pageParam);
pageParam.setPage(pageNumber);
pageParam.setPageSize(500);
return page(pageParam);
});
}
@Override
public cn.axzo.foundation.page.PageResp<SaasRoleUserV2DTO> page(PageRoleUserRelationParam param) {
QueryWrapper<SaasRoleUserRelation> wrapper = QueryWrapperHelper.fromBean(param, SaasRoleUserRelation.class);
wrapper.eq("is_delete", 0);
IPage<SaasRoleUserRelation> page = this.page(PageConverter.toMybatis(param, SaasRoleUserRelation.class), wrapper);
Map<Long, SaasRoleUserV2DTO.SaasRoleUser> saasRoleUsers = listSaasRoleUser(param, page.getRecords());
return PageConverter.toResp(page, (record) -> from(record, saasRoleUsers));
}
private Map<Long, SaasRoleUserV2DTO.SaasRoleUser> listSaasRoleUser(PageRoleUserRelationParam param,
List<SaasRoleUserRelation> saasRoleUserRelations) {
if (CollectionUtils.isEmpty(saasRoleUserRelations) || BooleanUtils.isNotTrue(param.getNeedUsers())) {
return Collections.emptyMap();
}
List<Long> personIds = saasRoleUserRelations.stream()
.map(SaasRoleUserRelation::getNaturalPersonId)
.distinct()
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(personIds)) {
return Collections.emptyMap();
}
List<List<Long>> partition = Lists.partition(personIds, 1000);
// 返回字段太多所以截取部分字段返回后续需要新增的手动增加
return partition.stream()
.map(e -> RpcInternalUtil.rpcListProcessor(() -> userProfileServiceApi.postPersonProfiles(e), "查询用户信息", e).getData())
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.collect(Collectors.toMap(PersonProfileDto::getId, this::from, (f, s) -> f));
}
private SaasRoleUserV2DTO.SaasRoleUser from(PersonProfileDto personProfileDto) {
if (personProfileDto == null) {
return null;
}
return SaasRoleUserV2DTO.SaasRoleUser.builder()
.personId(personProfileDto.getId())
.realName(personProfileDto.getRealName())
.build();
}
private SaasRoleUserV2DTO from(SaasRoleUserRelation saasRoleUserRelation,
Map<Long, SaasRoleUserV2DTO.SaasRoleUser> saasRoleUsers) {
return SaasRoleUserV2DTO.builder()
.roleId(saasRoleUserRelation.getRoleId())
.saasRoleUser(saasRoleUsers.get(saasRoleUserRelation.getNaturalPersonId()))
.build();
}
}

View File

@ -3,14 +3,18 @@ package cn.axzo.tyr.server.util;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.BizException;
import cn.axzo.framework.domain.web.result.ApiListResult;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -100,5 +104,43 @@ public class RpcInternalUtil {
return data;
}
/**
* 常用的RPC请求返回值解析如果 被请求方 返回非200会抛出异常
*/
public static <T> CommonResponse<List<T>> rpcListProcessor(Supplier<CommonResponse<List<T>>> supplier, String operationType, Object... param) {
return rpcListProcessorMayThrow(supplier, operationType, (msg) -> {
throw new ServiceException(msg);
}, param);
}
public static <T> CommonResponse<List<T>> rpcListProcessorMayThrow(Supplier<CommonResponse<List<T>>> supplier, String operationType, Consumer<String> throwConsumer, Object... param) {
AssertUtil.notNull(throwConsumer, "自定义的异常处理不可为空");
log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
CommonResponse<List<T>> result = null;
try {
result = printLatency(supplier, operationType);
} catch (Throwable e) {
log.warn("rpc process error:{}", e.getMessage());
throwConsumer.accept("服务调用异常");
}
log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
Assert.notNull(result, "服务调用异常");
// 200自定义处理
if (HttpStatus.HTTP_OK != result.getCode()) {
throwConsumer.accept(result.getMsg());
}
return result;
}
public static <R> R printLatency(Supplier<R> function, String optType) {
StopWatch stopWatch = new StopWatch(optType);
stopWatch.start(optType);
R r = function.get();
stopWatch.stop();
log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS));
return r;
}
}

View File

@ -3,13 +3,19 @@ package cn.axzo.tyr.server.utils;
import cn.axzo.basics.common.util.AssertUtil;
import cn.axzo.framework.domain.ServiceException;
import cn.axzo.framework.domain.web.BizException;
import cn.axzo.framework.domain.web.result.ApiListResult;
import cn.axzo.framework.domain.web.result.ApiPageResult;
import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.thrones.client.saas.entity.servicepkg.ServicePkgDetailRes;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.lang.Assert;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -87,5 +93,43 @@ public class RpcInternalUtil {
return data;
}
/**
* 常用的RPC请求返回值解析如果 被请求方 返回非200会抛出异常
*/
public static <T> CommonResponse<List<T>> rpcListProcessor(Supplier<CommonResponse<List<T>>> supplier, String operationType, Object... param) {
return rpcListProcessorMayThrow(supplier, operationType, (msg) -> {
throw new ServiceException(msg);
}, param);
}
public static <T> CommonResponse<List<T>> rpcListProcessorMayThrow(Supplier<CommonResponse<List<T>>> supplier, String operationType, Consumer<String> throwConsumer, Object... param) {
AssertUtil.notNull(throwConsumer, "自定义的异常处理不可为空");
log.info(operationType + "-Param: " + JSONUtil.toJsonStr(param));
CommonResponse<List<T>> result = null;
try {
result = printLatency(supplier, operationType);
} catch (Throwable e) {
log.warn("rpc process error:{}", e.getMessage());
throwConsumer.accept("服务调用异常");
}
log.info(operationType + "-Result: " + JSONUtil.toJsonStr(result));
Assert.notNull(result, "服务调用异常");
// 200自定义处理
if (HttpStatus.HTTP_OK != result.getCode()) {
throwConsumer.accept(result.getMsg());
}
return result;
}
public static <R> R printLatency(Supplier<R> function, String optType) {
StopWatch stopWatch = new StopWatch(optType);
stopWatch.start(optType);
R r = function.get();
stopWatch.stop();
log.info(stopWatch.shortSummary(TimeUnit.MILLISECONDS));
return r;
}
}