🐛 修复非超管「全部组织」账户跨组织操作仍报无权操作其他组织

配载提交按子运单组织逐个校验当前会话组织,且列表默认不按组织过滤,
超管能勾到他组织运单、提交却被拦;用户档案的「数据权限范围」此前只被
组织树消费,设成全部组织对业务无效。

统一为 hasAllDeptScope():超管或 data_scope_range=2 免组织校验,
写校验、allDept 门禁、列表组织过滤共用该口径;其余用户仍严格要求等于当前组织。
This commit is contained in:
2026-10-20 11:54:23 +08:00
parent 776861fc5b
commit 02d75e7e95
@@ -28,7 +28,9 @@ import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.system.cache.SysCache;
import org.springblade.system.cache.UserCache;
import org.springblade.system.pojo.entity.Dept;
import org.springblade.system.pojo.entity.User;
import java.math.BigDecimal;
import java.time.LocalDate;
@@ -50,6 +52,8 @@ public final class TransportBusinessSupport {
public static final String DATA_SOURCE_EXTERNAL = "外部系统";
private static final Pattern PHONE_PATTERN = Pattern.compile("^(1\\d{10}|0\\d{2,3}-?\\d{7,8})$");
/** 用户档案「数据权限范围」的取值:全部组织,与组织树过滤口径一致 */
private static final int DATA_SCOPE_ALL = 2;
private static final BigDecimal MIN_LONGITUDE = new BigDecimal("-180");
private static final BigDecimal MAX_LONGITUDE = new BigDecimal("180");
private static final BigDecimal MIN_LATITUDE = new BigDecimal("-90");
@@ -76,6 +80,26 @@ public final class TransportBusinessSupport {
return false;
}
/**
* 是否被授予跨组织数据权限:超级管理员,或用户档案「数据权限范围」为全部组织。
* <p>
* 「数据权限范围」在用户管理里配置,组织树已按它过滤(DeptServiceImpl 的组织树数据权限);
* 运输业务的列表过滤与写入校验必须与组织树同一口径。
*
* @return true-不限组织
*/
public static boolean hasAllDeptScope() {
if (isAdministrator()) {
return true;
}
Long userId = AuthUtil.getUserId();
if (Func.isEmpty(userId) || userId <= 0) {
return false;
}
User user = UserCache.getUser(userId);
return Objects.equals(user == null ? null : user.getDataScopeRange(), DATA_SCOPE_ALL);
}
public static Long currentDeptId(String moduleName) {
Long deptId = Func.firstLong(AuthUtil.getDeptId());
if (Func.isEmpty(deptId) || deptId <= 0) {
@@ -92,14 +116,22 @@ public final class TransportBusinessSupport {
return dept;
}
/**
* 校验目标业务数据属于当前用户可操作的组织。
* <p>
* 超管与「数据权限范围=全部组织」的用户不限组织;其余用户仍严格要求与当前会话组织相等。
*/
public static void assertCurrentDept(Long deptId, String moduleName) {
if (hasAllDeptScope()) {
return;
}
if (!Objects.equals(deptId, currentDeptId(moduleName))) {
throw new ServiceException("无权操作其他组织" + moduleName);
}
}
public static void validateAllDept(Integer allDept, String moduleName) {
if (Objects.equals(allDept, 1) && !isAdministrator()) {
if (Objects.equals(allDept, 1) && !hasAllDeptScope()) {
throw new ServiceException("无权查看全部组织" + moduleName);
}
}
@@ -107,7 +139,8 @@ public final class TransportBusinessSupport {
/**
* 解析列表组织筛选 ID。
* <p>
* 普通用户 allDept!=1 时强制当前组织;超管默认不按组织过滤,仅在 allDept=1 且传入 deptId 时精确匹配该组织。
* 普通用户 allDept!=1 时强制当前组织;超管与「全部组织」用户默认不按组织过滤,
* 仅在 allDept=1 且传入 deptId 时精确匹配该组织。
*
* @param allDept 是否查看全部组织
* @param deptId 筛选组织 ID
@@ -116,7 +149,7 @@ public final class TransportBusinessSupport {
*/
public static List<Long> resolveDeptFilterIds(Integer allDept, Long deptId, String moduleName) {
validateAllDept(allDept, moduleName);
if (isAdministrator()) {
if (hasAllDeptScope()) {
if (Objects.equals(allDept, 1) && Func.isNotEmpty(deptId) && deptId > 0) {
return Collections.singletonList(deptId);
}