项目初始化提交,移除仓库默认README
build / build-push (push) Failing after 48s

This commit is contained in:
chenxing
2026-08-21 09:37:21 +08:00
parent 729e1d0c35
commit 000993df80
30 changed files with 1497 additions and 0 deletions
@@ -0,0 +1,12 @@
package com.yunhai.userhome;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserHomeApplication {
public static void main(String[] args) {
SpringApplication.run(UserHomeApplication.class, args);
}
}
@@ -0,0 +1,35 @@
package com.yunhai.userhome.common;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
* JPA 实体基类(与 UserBase/BasePlatform 约定一致):自增主键 + 创建/更新时间。
*/
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
@MappedSuperclass
public abstract class BaseEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
@Column(name = "id")
private Integer id;
@Column(name = "create_time")
private LocalDateTime createTime;
@Column(name = "update_time")
private LocalDateTime updateTime;
}
@@ -0,0 +1,13 @@
package com.yunhai.userhome.config;
/**
* 路径前缀约定(与 UserBase 保持一致):
* {@code /{platform}} 普通接口(CAS 登录态),{@code /oapi/} 开放接口(yh-app-auth 签名)。
*/
public enum Config {
Inst;
// 末尾不要带斜杠:Boot 2.6+ 默认 PathPatternParser 不合并连续斜杠,会导致 404。
public static final String API_PATH = "/{platform}";
public static final String OPEN_API_PATH = "/oapi/";
}
@@ -0,0 +1,154 @@
package com.yunhai.userhome.controller.api;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.config.Config;
import com.yunhai.userhome.entity.UsedApp;
import com.yunhai.userhome.model.SetType;
import com.yunhai.userhome.service.AppRemoteService;
import com.yunhai.userhome.service.UsedAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 常用应用接口(CAS 登录态,路径 {@code /{platform}/usedapp/}),对齐旧 UserHome契约
*/
@RestController
@RequestMapping(value = Config.API_PATH + "/usedapp/")
public class UsedAppController {
@Autowired
private UsedAppService usedAppService;
@Autowired
private AppRemoteService appRemoteService;
/**
* 取当前角色生效的常用应用(BoaApp 详情,按 appIds 顺序)。
*
* @param roleType 角色类型
* @param schId 学校ID(0 时按用户主学校/主归属组推断)
* @param isSch 是否学校级(超管设置学校常用时 true,isSch 时 uid=schId)
*/
@GetMapping("getUsedApp")
public List<BoaApp> getUsedApp(BoaUser authUserWithDept, Integer roleType, Integer schId,
@RequestParam(name = "isSch", defaultValue = "false") Boolean isSch) {
if (schId == null || schId == 0) {
schId = resolveSchId(authUserWithDept);
}
Integer uid = authUserWithDept.getId();
if (authUserWithDept.getType() != null && authUserWithDept.getType() == 1) {
isSch = false; // 超管设置学校常用时走用户维度
}
if (isSch) {
uid = schId;
}
return usedAppService.getUsedAppList(schId, uid, roleType, authUserWithDept);
}
/**
* 覆盖式保存常用应用(≤8 由前端控制)。
* 参数:appIds(逗号分隔)、type(0系统/1学校/2用户)、roleType、schId;超管强制 type=0。
*/
@PostMapping("saveUsedApp")
public void saveUsedApp(BoaUser authUserWithDept, @RequestBody Map<String, Object> params) {
String appIds = params.get("appIds") == null ? "" : String.valueOf(params.get("appIds"));
Integer type = params.get("type") == null ? SetType.USER.id()
: Integer.valueOf(String.valueOf(params.get("type")));
Integer roleType = params.get("roleType") == null ? -1
: Integer.valueOf(String.valueOf(params.get("roleType")));
Integer schId = params.get("schId") == null ? 0
: Integer.valueOf(String.valueOf(params.get("schId")));
if (schId == 0) {
schId = resolveSchId(authUserWithDept);
}
UsedApp usedApp = new UsedApp();
usedApp.setAppIds(appIds);
usedApp.setType(SetType.byId(type));
usedApp.setRoleType(roleType);
usedApp.setCDate(new Date());
usedApp.setCId(authUserWithDept.getId());
usedApp.setSchId(schId);
usedApp.setSetId(usedApp.getType() == SetType.SCHOOL ? schId : authUserWithDept.getId());
if (authUserWithDept.getType() != null && authUserWithDept.getType() == 1) {
// 超管保存 → 系统级
usedApp.setType(SetType.BASE);
usedApp.setSetId(authUserWithDept.getId());
}
usedAppService.save(usedApp);
}
/** 用户级常用(type=USER, roleType=-1)精简映射(id/name/icon/url)。 */
@GetMapping("getUsedAppById")
public List<Map<String, Object>> getUsedAppById(BoaUser authUserWithDept) {
return usedAppService.getUsedAppMapList(authUserWithDept, authUserWithDept.getId());
}
/** 用户级保存常用(type=USER, roleType=-1)。 */
@PostMapping("saveUsedAppById")
public void saveUsedAppById(BoaUser authUserWithDept, @RequestBody Map<String, Object> params) {
String appIds = params.get("appIds") == null ? "" : String.valueOf(params.get("appIds"));
UsedApp usedApp = new UsedApp();
usedApp.setAppIds(appIds);
usedApp.setType(SetType.USER);
usedApp.setRoleType(-1);
usedApp.setCDate(new Date());
usedApp.setCId(authUserWithDept.getId());
usedApp.setSetId(authUserWithDept.getId());
usedAppService.saveUserId(usedApp);
}
/** 按 appIds(逗号分隔)取应用精简映射(id/name/icon/url),在全集中查找。 */
@GetMapping("getAppByIds")
public List<Map<String, Object>> getAppByIds(BoaUser authUserWithDept, String appIds) {
List<Map<String, Object>> list = new ArrayList<>();
if (appIds == null || appIds.trim().isEmpty()) {
return list;
}
List<BoaApp> appList = appRemoteService.getUserApps(authUserWithDept).stream()
.filter(t -> t.getApps() != null)
.flatMap(t -> t.getApps().stream())
.collect(Collectors.toList());
for (String appId : appIds.split(",")) {
try {
Integer id = Integer.parseInt(appId.trim());
appList.stream().filter(a -> id.equals(a.getId())).findFirst().ifPresent(app -> {
Map<String, Object> m = new HashMap<>();
m.put("id", app.getId());
m.put("name", app.getName());
m.put("icon", app.getIcon());
m.put("url", app.getWebAddr());
list.add(m);
});
} catch (NumberFormatException ignore) {
// 脏数据容错
}
}
return list;
}
/** schId=0 时推断:主学校 → 主归属组(bureau)→ 0。 */
private Integer resolveSchId(BoaUser user) {
if (user.getSchool() != null) {
return user.getSchool().getId();
}
if (user.getBureau() != null) {
return user.getBureau().getId();
}
return 0;
}
}
@@ -0,0 +1,88 @@
package com.yunhai.userhome.controller.api;
import com.yunhai.platform.apistd.BizException;
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
import com.yunhai.platform.utils.exception.ErrorCode;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaRoleInfo;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.config.Config;
import com.yunhai.userhome.entity.UserCurrentRole;
import com.yunhai.userhome.service.AppRemoteService;
import com.yunhai.userhome.service.IUserCurrentRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* 用户首页接口(CAS 登录态,路径 {@code /{platform}/user/})。
* 控制器直接 return 对象,由 yh-api-std 包成 {@code {code:0,data}}。
*/
@RestController
@RequestMapping(value = Config.API_PATH + "/user/")
public class UserController {
@Autowired
private AppRemoteService appRemoteService;
@Autowired
private IUserCurrentRoleService userCurrentRoleService;
/** 当前登录用户信息(CAS 注入)。 */
@GetMapping("GetUserInfo")
public BoaUser getUserInfo(BoaUser authUserWithDept) {
return authUserWithDept;
}
/**
* 当前用户可访问的应用全集(跨仓 UserBase 实时拉取,按应用类型分组)。
* 前端据此:渲染分类 tab(含「全部」)+ 图标网格;常用区由 getUsedApp 独立提供。
*
* @param schId 兼容旧前端入参(yh-platform getUserApp 当前按 userId 全局权限过滤,schId 暂不参与)
* @param userId 指定用户(缺省用登录用户)
*/
@GetMapping("GetUserApp")
public List<BoaAppType> getUserApp(BoaUser authUserWithDept, Integer schId,
@RequestParam(name = "userId", required = false) Integer userId) {
return appRemoteService.getUserApps(authUserWithDept);
}
/** 按应用ID取单个应用(在已拉取全集中查找,免额外跨仓请求)。 */
@GetMapping("GetAppInfoById")
public BoaApp getAppInfoById(BoaUser authUserWithDept, @RequestParam(name = "id", required = false) Integer id) {
return appRemoteService.getAppById(authUserWithDept, id).orElse(null);
}
/** 当前用户角色身份列表(跨仓 UserBase,含 学校/角色/子节点)。 */
@GetMapping("getUserRole")
public List<BoaRoleInfo> getUserRole(BoaUser authUserWithDept) {
return YschBaseOpenApi.getUserRoleList(authUserWithDept.getId());
}
/** 当前用户激活的角色(本地 user_current_role,可能为空)。 */
@GetMapping("findUserRole")
public UserCurrentRole findUserRole(BoaUser authUserWithDept) {
return userCurrentRoleService.findById(authUserWithDept.getId()).orElse(null);
}
/** 保存当前激活角色(校验所选 学校+角色 属于用户角色列表,防越权)。 */
@PostMapping("savUserRole")
public void savUserRole(BoaUser authUserWithDept, @RequestBody UserCurrentRole roleInfo) {
List<BoaRoleInfo> roleList = YschBaseOpenApi.getUserRoleList(authUserWithDept.getId());
boolean exists = roleList.stream().anyMatch(r ->
r.getRoleId() != null && r.getRoleId().equals(roleInfo.getRoleId())
&& r.getSchId() != null && r.getSchId().equals(roleInfo.getSchId()));
if (!exists) {
throw new BizException(ErrorCode.FORBIDDEN, "非法操作,没有权限");
}
roleInfo.setUserId(authUserWithDept.getId());
userCurrentRoleService.save(roleInfo);
}
}
@@ -0,0 +1,64 @@
package com.yunhai.userhome.entity;
import com.yunhai.userhome.common.BaseEntity;
import com.yunhai.userhome.model.SetType;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Index;
import javax.persistence.Table;
import java.util.Date;
/**
* 用户「常用应用」设置(本地表)。
*
* <p>对齐旧 UserHome used_app 结构:<b>一行存一组常用</b>(appIds 逗号分隔),
* 按 {@code setType(0系统/1学校/2用户) + setId + roleType + schId} 四维唯一覆盖保存。
* 应用元数据不落本地,跨仓来自 UserBase。</p>
*/
@NoArgsConstructor
@Data
@Entity
@Table(
name = "used_app",
indexes = {
@Index(name = "idx_used_app_set", columnList = "set_id,set_type,role_type,sch_id")
}
)
@EqualsAndHashCode(onlyExplicitlyIncluded = true, callSuper = false)
public class UsedApp extends BaseEntity {
/** 常用应用ID,逗号分隔字符串(按展示顺序)。 */
@Column(name = "app_ids", length = 500)
private String appIds;
/** 设置级别:0=系统 1=学校 2=用户。 */
@Enumerated(EnumType.ORDINAL)
@Column(name = "set_type")
private SetType type;
/** 归属维度ID:系统=超管用户ID、学校=schId、用户=用户ID。 */
@Column(name = "set_id")
private Integer setId;
/** 学校ID(逻辑外键 → UserBase sys_group.id,schId=0 表示非学校群组)。 */
@Column(name = "sch_id")
private Integer schId;
/** 角色类型(-1 表示用户级不区分角色)。 */
@Column(name = "role_type")
private Integer roleType;
/** 操作人ID(逻辑外键 → UserBase 用户)。 */
@Column(name = "c_id")
private Integer cId;
/** 操作时间。 */
@Column(name = "c_date")
private Date cDate;
}
@@ -0,0 +1,41 @@
package com.yunhai.userhome.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Index;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
/**
* 用户当前激活角色(会话态,本地表 user_current_role)。
* 对应旧 UserHome 同名单表:一用户一行,记录当前角色 + 学校。
*/
@Data
@Entity
@Table(
name = "user_current_role",
uniqueConstraints = @UniqueConstraint(columnNames = {"userId"}),
indexes = {@Index(columnList = "userId")}
)
public class UserCurrentRole {
@Id
@JsonIgnore
private Integer userId;
private Integer roleId;
private String roleName;
private Integer schId;
private String schName;
private Integer childId;
private String childName;
}
@@ -0,0 +1,38 @@
package com.yunhai.userhome.model;
/**
* 常用应用设置级别(对齐旧 UserHome 约定):
* 0=系统(超管默认)、1=学校(按学校+角色)、2=用户(按用户+角色)。
*/
public enum SetType {
BASE(0, "系统"),
SCHOOL(1, "学校"),
USER(2, "用户");
private final int mId;
private final String mName;
SetType(int id, String name) {
this.mId = id;
this.mName = name;
}
public int id() {
return mId;
}
public static SetType byId(int id) {
for (SetType t : values()) {
if (t.mId == id) {
return t;
}
}
return null;
}
@Override
public String toString() {
return mName;
}
}
@@ -0,0 +1,21 @@
package com.yunhai.userhome.repository;
import com.yunhai.userhome.entity.UsedApp;
import com.yunhai.userhome.model.SetType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
import java.util.Optional;
public interface UsedAppRepository extends JpaRepository<UsedApp, Integer>, JpaSpecificationExecutor<UsedApp> {
/** 按「归属+级别+角色+学校」四维查唯一记录(覆盖保存前判重)。 */
Optional<UsedApp> findFirstBySetIdAndTypeAndRoleTypeAndSchId(Integer setId, SetType type, Integer roleType, Integer schId);
/** 按「归属+级别+角色」查(用户级保存,schId 不参与)。 */
Optional<UsedApp> findFirstBySetIdAndTypeAndRoleType(Integer setId, SetType type, Integer roleType);
/** 兼容旧查询(供 Specification 之外的简单场景)。 */
List<UsedApp> findBySetIdAndTypeAndRoleTypeAndSchId(Integer setId, SetType type, Integer roleType, Integer schId);
}
@@ -0,0 +1,11 @@
package com.yunhai.userhome.repository;
import com.yunhai.userhome.entity.UserCurrentRole;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserCurrentRoleRepository extends JpaRepository<UserCurrentRole, Integer> {
Optional<UserCurrentRole> findByUserId(Integer userId);
}
@@ -0,0 +1,24 @@
package com.yunhai.userhome.service;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaUser;
import java.util.List;
import java.util.Optional;
/**
* 远程「用户可访问应用」数据服务(跨仓 UserBase)。
*
* <p>实现 {@link com.yunhai.userhome.service.impl.OpenApiAppRemoteServiceImpl}
* 经 {@code YschBaseOpenApi.getUserApp} 实时拉取(自动带 yh-app-auth 签名),
* 数据权威在 UserBase;本模块不冗余应用元数据。</p>
*/
public interface AppRemoteService {
/** 取当前用户可访问的应用全集(按应用类型分组,BoaAppType.id/name/apps)。 */
List<BoaAppType> getUserApps(BoaUser user);
/** 按应用ID取单个应用(在已拉取的全集中查找,避免额外跨仓请求)。 */
Optional<BoaApp> getAppById(BoaUser user, Integer appId);
}
@@ -0,0 +1,17 @@
package com.yunhai.userhome.service;
import com.yunhai.userhome.entity.UserCurrentRole;
import java.util.Optional;
/**
* 用户当前激活角色(user_current_role 表读写)。
*/
public interface IUserCurrentRoleService {
/** 取用户当前角色(可能不存在)。 */
Optional<UserCurrentRole> findById(Integer userId);
/** 保存/覆盖用户当前角色。 */
void save(UserCurrentRole role);
}
@@ -0,0 +1,39 @@
package com.yunhai.userhome.service;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.entity.UsedApp;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 本地「常用应用」服务(used_app 表读写,对齐旧 UserHome 四维结构)。
*/
public interface UsedAppService {
/** 覆盖式保存(同 setId+type+roleType+schId 唯一,存在则更新)。 */
void save(UsedApp usedApp);
/**
* 按「学校+用户+角色」取生效的常用设置(多级:用户 > 学校 > 系统;schId==uid 直接取学校级)。
*
* @param schId 学校ID(0 时按用户主学校推断后由调用方处理)
* @param uid 用户ID(isSch 时为 schId)
* @param roleType 角色类型(用户级 -1)
*/
Optional<UsedApp> findById(Integer schId, Integer uid, Integer roleType);
/** 取常用应用详情列表(BoaApp,按 appIds 顺序从可访问全集过滤)。 */
List<BoaApp> getUsedAppList(Integer schId, Integer uid, Integer roleType, BoaUser user);
/** 用户级保存(type=USER, roleType=-1)。 */
void saveUserId(UsedApp usedApp);
/** 用户级常用(type=USER, roleType=-1)。 */
Optional<UsedApp> findByUserId(Integer uid);
/** 常用应用精简映射(id/name/icon/url),用于 getUsedAppById / getAppByIds。 */
List<Map<String, Object>> getUsedAppMapList(BoaUser user, Integer uid);
}
@@ -0,0 +1,42 @@
package com.yunhai.userhome.service.impl;
import com.yunhai.platform.openapi.client.YschBaseOpenApi;
import com.yunhai.platform.utils.enums.ClientEnum;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.service.AppRemoteService;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* {@link AppRemoteService} 真实实现:经 yh-platform {@code YschBaseOpenApi} 调 UserBase
* {@code GET /oapi/app/list?userId=&clientType=}(自动带 app-auth 签名)。
*/
@Service
public class OpenApiAppRemoteServiceImpl implements AppRemoteService {
@Override
public List<BoaAppType> getUserApps(BoaUser user) {
if (user == null || user.getId() == null) {
return Collections.emptyList();
}
// PC 浏览器端;UserBase 侧已按 userId 权限过滤(组开通 ∪ 角色模块所属应用,超管全量)
return YschBaseOpenApi.getUserApp(user.getId(), ClientEnum.PC_BROWSER);
}
@Override
public Optional<BoaApp> getAppById(BoaUser user, Integer appId) {
if (appId == null) {
return Optional.empty();
}
return getUserApps(user).stream()
.filter(t -> t.getApps() != null)
.flatMap(t -> t.getApps().stream())
.filter(a -> appId.equals(a.getId()))
.findFirst();
}
}
@@ -0,0 +1,182 @@
package com.yunhai.userhome.service.impl;
import com.yunhai.platform.utils.model.BoaApp;
import com.yunhai.platform.utils.model.BoaAppType;
import com.yunhai.platform.utils.model.BoaUser;
import com.yunhai.userhome.entity.UsedApp;
import com.yunhai.userhome.model.SetType;
import com.yunhai.userhome.repository.UsedAppRepository;
import com.yunhai.userhome.service.AppRemoteService;
import com.yunhai.userhome.service.UsedAppService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class UsedAppServiceImpl implements UsedAppService {
@Autowired
private UsedAppRepository usedAppRepository;
@Autowired
private AppRemoteService appRemoteService;
@Override
public void save(UsedApp usedApp) {
Optional<UsedApp> model = usedAppRepository
.findFirstBySetIdAndTypeAndRoleTypeAndSchId(usedApp.getSetId(), usedApp.getType(),
usedApp.getRoleType(), usedApp.getSchId());
if (model.isPresent()) {
usedApp.setId(model.get().getId());
}
usedAppRepository.save(usedApp);
}
@Override
public Optional<UsedApp> findById(Integer schId, Integer uid, Integer roleType) {
List<UsedApp> list = usedAppRepository.findAll(select(schId, uid, roleType));
Optional<UsedApp> baseMod = list.stream()
.filter(x -> x.getType() == SetType.BASE)
.sorted(Comparator.comparing(UsedApp::getCDate).reversed())
.findFirst();
Optional<UsedApp> schMod = list.stream()
.filter(x -> x.getType() == SetType.SCHOOL)
.sorted(Comparator.comparing(UsedApp::getCDate).reversed())
.findFirst();
Optional<UsedApp> userMod = list.stream()
.filter(x -> x.getType() == SetType.USER)
.sorted(Comparator.comparing(UsedApp::getCDate).reversed())
.findFirst();
if (schId != null && schId.equals(uid)) {
return schMod;
}
// 优先级:用户 > 学校 > 系统
if (userMod.isPresent()) {
return userMod;
}
if (schMod.isPresent()) {
return schMod;
}
return baseMod;
}
@Override
public List<BoaApp> getUsedAppList(Integer schId, Integer uid, Integer roleType, BoaUser user) {
List<String> appIdList = new ArrayList<>();
Optional<UsedApp> data = findById(schId, uid, roleType);
if (data.isPresent() && data.get().getAppIds() != null) {
String usedStr = data.get().getAppIds();
if (!usedStr.trim().isEmpty()) {
appIdList = Arrays.asList(usedStr.split(","));
}
}
if (appIdList.isEmpty()) {
return new ArrayList<>();
}
List<BoaApp> appList = flattenApps(appRemoteService.getUserApps(user));
Map<Integer, BoaApp> appMap = appList.stream()
.collect(Collectors.toMap(BoaApp::getId, a -> a, (a, b) -> a));
List<BoaApp> result = new ArrayList<>();
for (String appId : appIdList) {
try {
BoaApp app = appMap.get(Integer.parseInt(appId.trim()));
if (app != null) {
result.add(app);
}
} catch (NumberFormatException ignore) {
// 脏数据容错
}
}
return result;
}
@Override
public void saveUserId(UsedApp usedApp) {
Optional<UsedApp> model = usedAppRepository
.findFirstBySetIdAndTypeAndRoleType(usedApp.getSetId(), SetType.USER, -1);
if (model.isPresent()) {
usedApp.setId(model.get().getId());
}
usedAppRepository.save(usedApp);
}
@Override
public Optional<UsedApp> findByUserId(Integer uid) {
return usedAppRepository.findFirstBySetIdAndTypeAndRoleType(uid, SetType.USER, -1);
}
@Override
public List<Map<String, Object>> getUsedAppMapList(BoaUser user, Integer uid) {
List<Map<String, Object>> list = new ArrayList<>();
Optional<UsedApp> data = findByUserId(uid);
if (!data.isPresent() || data.get().getAppIds() == null) {
return list;
}
List<String> appIds = Arrays.asList(data.get().getAppIds().split(","));
List<BoaApp> appList = flattenApps(appRemoteService.getUserApps(user));
Map<Integer, BoaApp> appMap = appList.stream()
.collect(Collectors.toMap(BoaApp::getId, a -> a, (a, b) -> a));
for (String appId : appIds) {
try {
BoaApp app = appMap.get(Integer.parseInt(appId.trim()));
if (app != null) {
Map<String, Object> m = new HashMap<>();
m.put("id", app.getId());
m.put("name", app.getName());
m.put("icon", app.getIcon());
m.put("url", app.getWebAddr());
list.add(m);
}
} catch (NumberFormatException ignore) {
// 脏数据容错
}
}
return list;
}
/** BoaAppType 分组平铺为 BoaApp 列表。 */
private List<BoaApp> flattenApps(List<BoaAppType> types) {
List<BoaApp> apps = new ArrayList<>();
if (types == null) {
return apps;
}
for (BoaAppType type : types) {
if (type.getApps() != null) {
apps.addAll(type.getApps());
}
}
return apps;
}
/** 一级常用生效范围:BASE(按角色) OR SCHOOL(setId=schId+角色) OR USER(setId=uid+角色+schId)。 */
private Specification<UsedApp> select(Integer schId, Integer uid, Integer roleType) {
return (Root<UsedApp> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
Predicate basePre = cb.and(
cb.equal(root.get("type"), SetType.BASE),
cb.equal(root.get("roleType"), roleType));
Predicate schPer = cb.and(
cb.equal(root.get("setId"), schId),
cb.equal(root.get("type"), SetType.SCHOOL),
cb.equal(root.get("roleType"), roleType));
Predicate userPer = cb.and(
cb.equal(root.get("setId"), uid),
cb.equal(root.get("type"), SetType.USER),
cb.equal(root.get("roleType"), roleType),
cb.equal(root.get("schId"), schId));
return cb.or(basePre, schPer, userPer);
};
}
}
@@ -0,0 +1,26 @@
package com.yunhai.userhome.service.impl;
import com.yunhai.userhome.entity.UserCurrentRole;
import com.yunhai.userhome.repository.UserCurrentRoleRepository;
import com.yunhai.userhome.service.IUserCurrentRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
public class UserCurrentRoleServiceImpl implements IUserCurrentRoleService {
@Autowired
private UserCurrentRoleRepository repository;
@Override
public Optional<UserCurrentRole> findById(Integer userId) {
return repository.findByUserId(userId);
}
@Override
public void save(UserCurrentRole role) {
repository.save(role);
}
}