新增监管端和机构端首页数据

dev
huwei 2026-08-03 15:48:10 +08:00
parent 311fbf6946
commit cc604203c5
4 changed files with 153 additions and 7 deletions

View File

@ -26,6 +26,7 @@ import org.qinan.safetyeval.domain.service.OrgPositionDomainService;
import org.qinan.safetyeval.infrastructure.adapter.ThreadLocalUserInfoAdapter;
import org.qinan.safetyeval.infrastructure.adapter.auth.AuthUserContextAdapter;
import org.qinan.safetyeval.infrastructure.adapter.gbs.GbsUserFacadeClient;
import org.qinan.safetyeval.infrastructure.support.UserOrgIdResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@ -77,6 +78,10 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
@Autowired
private OrgPersonnelExcelImporter orgPersonnelExcelImporter;
@Lazy
@Autowired(required = false)
private UserOrgIdResolver userOrgIdResolver;
@Value("${def.password:a123456}")
private String defPassword;
@Value("${def.publicKey:0402df2195296d4062ac85ad766994d73e871b887e18efb9a9a06b4cebc72372869b7da6c347c129dee2b46a0f279ff066b01c76208c2a052af75977c722a2ccee}")
@ -94,6 +99,10 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
public SingleResponse<OrgPersonnelCO> add(OrgPersonnelAddCmd cmd) {
OrgPersonnelEntity entity = orgPersonnelConvertor.toEntity(cmd);
OrgPersonnelEntity result = orgPersonnelDomainService.add(entity);
// 组织信息变更,清理该用户机构缓存
if (userOrgIdResolver != null && result != null) {
userOrgIdResolver.evict(result.getId());
}
OrgPersonnelCO co = orgPersonnelConvertor.toCO(result);
enrich(co);
UserAddCmd userAddCmd = new UserAddCmd();
@ -134,6 +143,10 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
OrgPersonnelEntity entity = orgPersonnelConvertor.toEntity(cmd);
entity.setId(cmd.getId());
OrgPersonnelEntity result = orgPersonnelDomainService.modify(entity);
// 组织信息变更,清理该用户机构缓存
if (userOrgIdResolver != null) {
userOrgIdResolver.evict(cmd.getId());
}
orgPersonnelChangeRecorder.recordChanges(existing, result);
// 岗位变更且新岗位已关联 GBS 角色时,同步该人员 GBS 角色
if (result != null && !Objects.equals(
@ -148,6 +161,10 @@ public class OrgPersonnelExecutor implements OrgPersonnelApi {
@Override
public SingleResponse<Void> delete(Long id) {
orgPersonnelDomainService.delete(id);
// 组织信息变更,清理该用户机构缓存
if (userOrgIdResolver != null) {
userOrgIdResolver.evict(id);
}
return SingleResponse.success();
}

View File

@ -20,7 +20,9 @@ import org.qinan.safetyeval.domain.gateway.SafetyMessageGateway;
import org.qinan.safetyeval.domain.query.EvalProjectQuery;
import org.qinan.safetyeval.domain.query.PageResult;
import org.qinan.safetyeval.domain.query.SafetyMessageQuery;
import org.qinan.safetyeval.infrastructure.adapter.ThreadLocalUserInfoAdapter;
import org.qinan.safetyeval.infrastructure.support.InstitutionOrgSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
@ -35,7 +37,8 @@ import java.util.stream.Collectors;
*
*
* <p><b></b> Gateway / </p>
* <p>orgId {@link ThreadLocalUserInfoAdapter}</p>
* <p>orgId {@link InstitutionOrgSupport#resolveCurrentOrgIdByUserId()} userId
* org_personnel 使 token orgId </p>
*/
@Component
public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@ -52,6 +55,10 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Resource
private EvalCustomerGateway evalCustomerGateway;
@Lazy
@Autowired(required = false)
private InstitutionOrgSupport institutionOrgSupport;
/** 节点编码 → 大屏展示名称待X */
private static final LinkedHashMap<String, String> NODE_DISPLAY = new LinkedHashMap<>();
static {
@ -73,7 +80,7 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardProjectNodeStatsCO> projectNodeStats() {
Long orgId = ThreadLocalUserInfoAdapter.get();
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardProjectNodeStatsCO());
}
@ -129,7 +136,7 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardNoticeCO> notices() {
Long orgId = ThreadLocalUserInfoAdapter.get();
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardNoticeCO());
}
@ -144,7 +151,7 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardIndustryStatCO> industryStat() {
Long orgId = ThreadLocalUserInfoAdapter.get();
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardIndustryStatCO());
}
@ -177,7 +184,7 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardEvalTypeRatioCO> evalTypeRatio() {
Long orgId = ThreadLocalUserInfoAdapter.get();
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardEvalTypeRatioCO());
}
@ -209,7 +216,7 @@ public class InstitutionDashboardExecutor implements InstitutionDashboardApi {
@Override
public SingleResponse<InstitutionDashboardProjectExecutionCO> projectExecution(Integer limit) {
Long orgId = ThreadLocalUserInfoAdapter.get();
Long orgId = institutionOrgSupport.resolveCurrentOrgIdByUserId();
if (orgId == null) {
return SingleResponse.success(new InstitutionDashboardProjectExecutionCO());
}

View File

@ -4,7 +4,9 @@ import org.qinan.safetyeval.domain.exception.BizException;
import org.qinan.safetyeval.domain.exception.ErrorCode;
import org.qinan.safetyeval.domain.gateway.OrgInfoGateway;
import org.qinan.safetyeval.infrastructure.adapter.ThreadLocalUserInfoAdapter;
import org.qinan.safetyeval.infrastructure.adapter.auth.AuthUserContextAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
/**
@ -16,6 +18,15 @@ public class InstitutionOrgSupport {
@Autowired(required = false)
private OrgInfoGateway orgInfoGateway;
@Lazy
@Autowired(required = false)
private UserOrgIdResolver userOrgIdResolver;
/**
* orgId沿 orgInfoId ThreadLocal
* <p> ID org_id
* {@link #resolveCurrentOrgIdByUserId()}</p>
*/
public Long resolveCurrentOrgId() {
Long orgId = ThreadLocalUserInfoAdapter.getOrgId();
if (orgId == null) {
@ -24,6 +35,30 @@ public class InstitutionOrgSupport {
return orgId;
}
/**
* userId orgId使 token orgId
* <p>使
* {@link #evictCurrentUserOrgId()} </p>
*
* @return orgId null
*/
public Long resolveCurrentOrgIdByUserId() {
if (userOrgIdResolver == null) {
return null;
}
Long userId = AuthUserContextAdapter.getCurrentUserId();
return userOrgIdResolver.resolveOrgIdByUserId(userId);
}
/**
*
*/
public void evictCurrentUserOrgId() {
if (userOrgIdResolver != null) {
userOrgIdResolver.evict(AuthUserContextAdapter.getCurrentUserId());
}
}
public void assertOrgAccess(Long resourceOrgId, ErrorCode notFoundCode) {
if (resourceOrgId == null || !resolveCurrentOrgId().equals(resourceOrgId)) {
throw new BizException(notFoundCode);

View File

@ -0,0 +1,87 @@
package org.qinan.safetyeval.infrastructure.support;
import org.qinan.safetyeval.infrastructure.dataobject.OrgPersonnelDO;
import org.qinan.safetyeval.infrastructure.mapper.OrgPersonnelMapper;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* userId
*
* <p><b></b> {@code org_id} {@code org_info.id}
* SSO token {@code orgId} ID使 token orgId
* {@code eval_project.org_id}
* {@code userId} {@code org_personnel.org_id}
* </p>
*
* <p> {@code userId} 5 30
* // {@link #evict(Long)}
* {@link #evictAll()} </p>
*/
@Component
public class UserOrgIdResolver {
/** 组织信息有效缓存时长(毫秒) */
private static final long ORG_TTL_MILLIS = 5 * 60 * 1000L;
/** 未命中机构(非机构人员)的缓存时长(毫秒) */
private static final long MISS_TTL_MILLIS = 30 * 1000L;
@Resource
private OrgPersonnelMapper orgPersonnelMapper;
private final Map<Long, CacheEntry> cache = new ConcurrentHashMap<>();
/**
* userId orgId
*
* @param userId idorg_personnel.id
* @return orgId null
*/
public Long resolveOrgIdByUserId(Long userId) {
if (userId == null) {
return null;
}
long now = System.currentTimeMillis();
CacheEntry entry = cache.get(userId);
if (entry != null && entry.expireAt > now) {
return entry.orgId;
}
Long orgId = queryOrgIdByUserId(userId);
cache.put(userId, new CacheEntry(orgId, now + (orgId == null ? MISS_TTL_MILLIS : ORG_TTL_MILLIS)));
return orgId;
}
/**
*
*/
public void evict(Long userId) {
if (userId != null) {
cache.remove(userId);
}
}
/**
*
*/
public void evictAll() {
cache.clear();
}
private Long queryOrgIdByUserId(Long userId) {
OrgPersonnelDO personnel = orgPersonnelMapper.selectById(userId);
return personnel == null ? null : personnel.getOrgId();
}
private static class CacheEntry {
private final Long orgId;
private final long expireAt;
CacheEntry(Long orgId, long expireAt) {
this.orgId = orgId;
this.expireAt = expireAt;
}
}
}