feat(elevator): 租户访客默认楼层策略表与 UC-01 求交

- 新增 tenant_visitor_floor_policy DDL(docs/sql)
- MyBatis:TenantVisitorFloorPolicyMapper/Dao 按 businessId 读启用策略
- PersonRuleServiceImpl.addVisitor:未传 floorIds 时组织 floorList 与 allow_zone_ids 求交;无交集 76260532;无楼层 76260531;显式 floorIds 不读表;ServiceException 原样抛出

Made-with: Cursor
This commit is contained in:
反编译工作区
2026-04-24 11:11:06 +08:00
parent 717b9a9240
commit 25cff4d132
8 changed files with 526 additions and 2 deletions
@@ -29,6 +29,8 @@ import cn.cloudwalk.elevator.passrule.dto.ImageRuleRefAddDto;
import cn.cloudwalk.elevator.passrule.dto.ImageRuleRefResultDto;
import cn.cloudwalk.elevator.passrule.impl.AbstractAcsPassService;
import cn.cloudwalk.elevator.passrule.result.AcsPassRuleResult;
import cn.cloudwalk.elevator.person.dao.TenantVisitorFloorPolicyDao;
import cn.cloudwalk.elevator.person.dto.TenantVisitorFloorPolicyDto;
import cn.cloudwalk.elevator.person.param.AcsPersonAddParam;
import cn.cloudwalk.elevator.person.param.AcsPersonAddVisitorParam;
import cn.cloudwalk.elevator.person.param.AcsPersonDeleteParam;
@@ -45,12 +47,16 @@ import cn.cloudwalk.elevator.util.StringUtils;
import cn.cloudwalk.elevator.zone.param.ZoneQueryParam;
import cn.cloudwalk.elevator.zone.result.ZoneResult;
import cn.cloudwalk.elevator.zone.service.ZoneService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
@@ -73,6 +79,8 @@ public class PersonRuleServiceImpl extends AbstractAcsPassService implements Per
private AcsElevatorDeviceDao acsElevatorDeviceDao;
@Resource
private ZoneService zoneService;
@Resource
private TenantVisitorFloorPolicyDao tenantVisitorFloorPolicyDao;
@CloudwalkParamsValidate
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
@@ -167,12 +175,47 @@ public class PersonRuleServiceImpl extends AbstractAcsPassService implements Per
this.logger.info("根据被访人添加访客派梯权限开始,AcsPersonAddVisitorParam=[{}], CloudwalkCallContext=[{}]",
JSONObject.toJSONString(param), JSONObject.toJSONString(context));
try {
if (CollectionUtils.isEmpty(param.getFloorIds())) {
boolean callerProvidedFloors = !CollectionUtils.isEmpty(param.getFloorIds());
if (!callerProvidedFloors) {
PersonDetailParam detailParam = new PersonDetailParam();
detailParam.setId(param.getPersonId());
detailParam.setBusinessId(context.getCompany().getCompanyId());
CloudwalkResult<PersonResult> detail = this.personService.detail(detailParam, context);
param.setFloorIds(((PersonResult)detail.getData()).getFloorList());
if (detail == null || !detail.isSuccess()) {
String code = detail != null ? detail.getCode() : "76260531";
String msg = detail != null ? detail.getMessage() : getMessage("76260531");
return CloudwalkResult.fail(code, msg);
}
PersonResult personResult = (PersonResult)detail.getData();
if (personResult == null) {
return CloudwalkResult.fail("76260531", getMessage("76260531"));
}
List<String> hostFloors = personResult.getFloorList();
if (CollectionUtils.isEmpty(hostFloors)) {
return CloudwalkResult.fail("76260531", getMessage("76260531"));
}
List<String> effectiveFloors = hostFloors;
TenantVisitorFloorPolicyDto policy =
this.tenantVisitorFloorPolicyDao.selectEnabledTenantDefault(context.getCompany().getCompanyId());
if (policy != null && policy.getEnabled() != null && policy.getEnabled().intValue() == 1) {
List<String> allow = parseAllowZoneIds(policy.getAllowZoneIds());
if (!CollectionUtils.isEmpty(allow)) {
Set<String> allowSet = new HashSet<>(allow);
List<String> intersected = intersectPreserveHostOrder(hostFloors, allowSet);
if (intersected.isEmpty()) {
return CloudwalkResult.fail("76260532", getMessage("76260532"));
}
effectiveFloors = intersected;
this.logger.info(
"租户访客楼层策略求交 businessId={} personId={} visitorId={} policyId={} policyVersion={} effectiveSize={}",
context.getCompany().getCompanyId(), param.getPersonId(), param.getVisitorId(),
policy.getId(), policy.getPolicyVersion(), Integer.valueOf(intersected.size()));
}
}
param.setFloorIds(effectiveFloors);
}
if (CollectionUtils.isEmpty(param.getFloorIds())) {
return CloudwalkResult.fail("76260531", getMessage("76260531"));
}
ZoneQueryParam zoneQueryParam = new ZoneQueryParam();
zoneQueryParam.setId(param.getFloorIds().get(0));
@@ -221,6 +264,8 @@ public class PersonRuleServiceImpl extends AbstractAcsPassService implements Per
refParam.setPersonIds(Collections.singletonList(param.getVisitorId()));
refParam.setImageStoreId(imageStoreId);
this.imageStorePersonService.updateGroupPersonRef(refParam, context);
} catch (ServiceException e) {
throw e;
} catch (Exception e) {
this.logger.error("根据被访人添加访客派梯权限失败,原因:[{}]", e);
throw new ServiceException("76260530", getMessage("76260530"));
@@ -228,6 +273,29 @@ public class PersonRuleServiceImpl extends AbstractAcsPassService implements Per
return CloudwalkResult.success(Boolean.valueOf(true));
}
/**
* 解析 allow_zone_ids JSON;无效或空则返回空列表(等同未配置有效策略)。
*/
private List<String> parseAllowZoneIds(String json) {
if (StringUtils.isBlank(json)) {
return Collections.emptyList();
}
try {
List<String> list = JSON.parseArray(json, String.class);
if (list == null) {
return Collections.emptyList();
}
return list.stream().filter(Objects::nonNull).filter(s -> !s.isEmpty()).collect(Collectors.toList());
} catch (Exception e) {
this.logger.warn("allow_zone_ids JSON 无效,按无策略处理: {}", e.getMessage());
return Collections.emptyList();
}
}
private static List<String> intersectPreserveHostOrder(List<String> hostFloors, Set<String> allowSet) {
return hostFloors.stream().filter(allowSet::contains).collect(Collectors.toList());
}
public CloudwalkResult<Boolean> edit(AcsPersonEditParam param, CloudwalkCallContext context)
throws ServiceException {
return null;