@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user