chore: 工作区反编译与 Maven/文档/脚本同步到发布分支

- artifacts/decompiled 树与相关源码变更
- maven-cw-elevator-application 业务 docs 与 package-info
- scripts 下 formatter 校验与辅助脚本
- 其他子工程/接口与发布线一并纳入版本控制

Made-with: Cursor

Former-commit-id: e102e8cab64e575bcd23c9a66a598aa1892bb492
This commit is contained in:
反编译工作区
2026-04-25 09:35:35 +08:00
parent 1c28fcedfc
commit dee355b4a7
2000 changed files with 133077 additions and 169300 deletions
@@ -1,44 +1,44 @@
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片追加参数(与存储层 append 调用约定一致)。 */
public class FilePartAppendParam<T> implements Serializable {
private static final long serialVersionUID = 1L;
private String filePath;
private Integer partNumber;
private String uploadId;
private T content;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Integer getPartNumber() {
return partNumber;
}
public void setPartNumber(Integer partNumber) {
this.partNumber = partNumber;
}
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片追加参数(与存储层 append 调用约定一致)。 */
public class FilePartAppendParam<T> implements Serializable {
private static final long serialVersionUID = 1L;
private String filePath;
private Integer partNumber;
private String uploadId;
private T content;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Integer getPartNumber() {
return partNumber;
}
public void setPartNumber(Integer partNumber) {
this.partNumber = partNumber;
}
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
@@ -1,44 +1,44 @@
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片结束参数(与 PartFinishDTO 字段对齐)。 */
public class FilePartFinishParam implements Serializable {
private static final long serialVersionUID = 1L;
private String uploadId;
private Long fileSize;
private String filePath;
private Integer returnType;
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Integer getReturnType() {
return returnType;
}
public void setReturnType(Integer returnType) {
this.returnType = returnType;
}
}
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片结束参数(与 PartFinishDTO 字段对齐)。 */
public class FilePartFinishParam implements Serializable {
private static final long serialVersionUID = 1L;
private String uploadId;
private Long fileSize;
private String filePath;
private Integer returnType;
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
public Long getFileSize() {
return fileSize;
}
public void setFileSize(Long fileSize) {
this.fileSize = fileSize;
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public Integer getReturnType() {
return returnType;
}
public void setReturnType(Integer returnType) {
this.returnType = returnType;
}
}
@@ -1,17 +1,17 @@
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片上传初始化参数(与 PartInitDTO 字段对齐,供 BeanCopy 与业务层使用)。 */
public class FilePartInitParam implements Serializable {
private static final long serialVersionUID = 1L;
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
package cn.cloudwalk.client.davinci.portal.file.param.part;
import java.io.Serializable;
/** 分片上传初始化参数(与 PartInitDTO 字段对齐,供 BeanCopy 与业务层使用)。 */
public class FilePartInitParam implements Serializable {
private static final long serialVersionUID = 1L;
private String fileName;
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
@@ -1,26 +1,26 @@
package cn.cloudwalk.client.davinci.portal.file.result;
import java.io.Serializable;
/** 分片初始化/追加返回(与 PartInitResultDTO 字段对齐)。 */
public class FilePartResult implements Serializable {
private static final long serialVersionUID = 1L;
private String filePath;
private String uploadId;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
}
package cn.cloudwalk.client.davinci.portal.file.result;
import java.io.Serializable;
/** 分片初始化/追加返回(与 PartInitResultDTO 字段对齐)。 */
public class FilePartResult implements Serializable {
private static final long serialVersionUID = 1L;
private String filePath;
private String uploadId;
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
public String getUploadId() {
return uploadId;
}
public void setUploadId(String uploadId) {
this.uploadId = uploadId;
}
}
@@ -16,8 +16,7 @@ public interface AcsElevatorCodeService {
AcsElevatorCodeResultDTO getFirstByParentId(String paramString) throws ServiceException;
/**
* 按区域 ID 批量查询电梯编码,供树形接口一次拉取,避免循环内逐条查询。
* 不改变 {@link #get} 语义;入参去重由调用方控制。
* 按区域 ID 批量查询电梯编码,供树形接口一次拉取,避免循环内逐条查询。 不改变 {@link #get} 语义;入参去重由调用方控制。
*/
Map<String, AcsElevatorCodeResultDTO> mapByZoneIds(List<String> zoneIds) throws ServiceException;
}
@@ -10,6 +10,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 设备相关服务的抽象基类:提供区域树扁平化、以及为远程调用组装的 {@link CloudwalkCallContext}(含 Feign 线程本地传参)。
*/
public class AbstractAcsDeviceService extends AbstractCloudwalkService {
protected void getAreaMap(List<AreaTreeResult> areaTreeResultList, Map<String, String> areaMap) {
for (AreaTreeResult areaTree : areaTreeResultList) {
@@ -1,27 +1,27 @@
package cn.cloudwalk.elevator.common;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ElevatorRemoteIoExecutorConfig {
@Autowired
private ElevatorRemoteIoPoolProperties elevatorRemoteIoPoolProperties;
@Bean(name = {"elevatorRemoteBoundedExecutor"})
public ThreadPoolTaskExecutor elevatorRemoteBoundedExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(this.elevatorRemoteIoPoolProperties.getCorePoolSize());
ex.setMaxPoolSize(this.elevatorRemoteIoPoolProperties.getMaxPoolSize());
ex.setQueueCapacity(this.elevatorRemoteIoPoolProperties.getQueueCapacity());
ex.setKeepAliveSeconds(this.elevatorRemoteIoPoolProperties.getKeepAliveSeconds());
ex.setAllowCoreThreadTimeOut(this.elevatorRemoteIoPoolProperties.isAllowCoreThreadTimeOut());
ex.setThreadNamePrefix("elevator-remote-io-");
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
ex.initialize();
return ex;
}
}
package cn.cloudwalk.elevator.common;
import java.util.concurrent.ThreadPoolExecutor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ElevatorRemoteIoExecutorConfig {
@Autowired
private ElevatorRemoteIoPoolProperties elevatorRemoteIoPoolProperties;
@Bean(name = {"elevatorRemoteBoundedExecutor"})
public ThreadPoolTaskExecutor elevatorRemoteBoundedExecutor() {
ThreadPoolTaskExecutor ex = new ThreadPoolTaskExecutor();
ex.setCorePoolSize(this.elevatorRemoteIoPoolProperties.getCorePoolSize());
ex.setMaxPoolSize(this.elevatorRemoteIoPoolProperties.getMaxPoolSize());
ex.setQueueCapacity(this.elevatorRemoteIoPoolProperties.getQueueCapacity());
ex.setKeepAliveSeconds(this.elevatorRemoteIoPoolProperties.getKeepAliveSeconds());
ex.setAllowCoreThreadTimeOut(this.elevatorRemoteIoPoolProperties.isAllowCoreThreadTimeOut());
ex.setThreadNamePrefix("elevator-remote-io-");
ex.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
ex.initialize();
return ex;
}
}
@@ -1,55 +1,55 @@
package cn.cloudwalk.elevator.common;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "ninca.elevator.remote-io.pool")
public class ElevatorRemoteIoPoolProperties {
/** 约定 §3.2 / §3.3 / §3.4:有界并行建议 4~8,默认 6 */
private int corePoolSize = 6;
private int maxPoolSize = 6;
private int queueCapacity = 512;
private int keepAliveSeconds = 60;
private boolean allowCoreThreadTimeOut = true;
public int getCorePoolSize() {
return this.corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return this.maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getQueueCapacity() {
return this.queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public int getKeepAliveSeconds() {
return this.keepAliveSeconds;
}
public void setKeepAliveSeconds(int keepAliveSeconds) {
this.keepAliveSeconds = keepAliveSeconds;
}
public boolean isAllowCoreThreadTimeOut() {
return this.allowCoreThreadTimeOut;
}
public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
}
}
package cn.cloudwalk.elevator.common;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConfigurationProperties(prefix = "ninca.elevator.remote-io.pool")
public class ElevatorRemoteIoPoolProperties {
/** 约定 §3.2 / §3.3 / §3.4:有界并行建议 4~8,默认 6 */
private int corePoolSize = 6;
private int maxPoolSize = 6;
private int queueCapacity = 512;
private int keepAliveSeconds = 60;
private boolean allowCoreThreadTimeOut = true;
public int getCorePoolSize() {
return this.corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return this.maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getQueueCapacity() {
return this.queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public int getKeepAliveSeconds() {
return this.keepAliveSeconds;
}
public void setKeepAliveSeconds(int keepAliveSeconds) {
this.keepAliveSeconds = keepAliveSeconds;
}
public boolean isAllowCoreThreadTimeOut() {
return this.allowCoreThreadTimeOut;
}
public void setAllowCoreThreadTimeOut(boolean allowCoreThreadTimeOut) {
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
}
}
@@ -1,6 +1,7 @@
package cn.cloudwalk.elevator.device.impl;
import cn.cloudwalk.cloud.context.CloudwalkCallContext;
import cn.cloudwalk.cloud.exception.DataAccessException;
import cn.cloudwalk.cloud.exception.ServiceException;
import cn.cloudwalk.cloud.result.CloudwalkResult;
import cn.cloudwalk.elevator.common.AbstractAcsDeviceService;
@@ -14,23 +15,37 @@ import cn.cloudwalk.elevator.passrule.dto.AcsPassRuleDeleteDto;
import cn.cloudwalk.elevator.passrule.dto.AcsPassRuleImageResultDto;
import cn.cloudwalk.elevator.passrule.param.AcsPassRuleDeleteParam;
import cn.cloudwalk.elevator.passrule.param.AcsPassRuleNewParam;
import cn.cloudwalk.elevator.config.FeignThreadLocalUtil;
import cn.cloudwalk.elevator.passrule.service.ImageRuleRefService;
import cn.cloudwalk.elevator.person.param.AcsPersonAddParam;
import cn.cloudwalk.elevator.person.param.AcsPersonDeleteParam;
import cn.cloudwalk.elevator.person.service.PersonRuleService;
import cn.cloudwalk.elevator.util.CollectionUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
/**
* 设备异步任务:推进绑定进度、按楼层增删人员/规则;{@code updateFloors} 在楼层维度使用有界线程池并行远程调用,并按 Future 完成顺序推进
* {@code bindDevices},与走查约定 §9 一致。
*/
@Service
public class AcsDeviceTaskServiceImpl extends AbstractAcsDeviceService implements AcsDeviceTaskService {
/** 单次并发执行的楼层数上限,与 {@code elevatorRemoteBoundedExecutor} 池容量配合,避免对下游突发压测。 */
private static final int UPDATE_FLOORS_FLOOR_PARALLEL = 6;
@Autowired
private PersonRuleService personRuleService;
@Autowired
@@ -39,107 +54,220 @@ public class AcsDeviceTaskServiceImpl extends AbstractAcsDeviceService implement
private AcsDeviceTaskDao acsDeviceTaskDao;
@Resource
private ImageRuleRefDao imageRuleRefDao;
@Autowired
@Qualifier("elevatorRemoteBoundedExecutor")
private ThreadPoolTaskExecutor elevatorRemoteBoundedExecutor;
@Async("updateFloorsExecutor")
public void updateFloors(AcsRestructureBindingParam param, List<AcsPassRuleImageResultDto> addFloors,
List<String> delFloorIds, CloudwalkCallContext context) throws ServiceException {
try {
if (!CollectionUtils.isEmpty(addFloors)) {
for (AcsPassRuleImageResultDto addFloor : addFloors) {
AcsDeviceTaskDTO task = this.acsDeviceTaskDao.getById(param.getTaskId());
if (task == null) {
this.logger.error("updateFloors 任务不存在 taskId={}", param.getTaskId());
throw new ServiceException("设备任务不存在");
}
if (task.getIsStop().intValue() == 0) {
if (!ObjectUtils.isEmpty(param.getPersonId())) {
AcsPersonAddParam addParam = new AcsPersonAddParam();
addParam.setPersonIds(Collections.singletonList(param.getPersonId()));
addParam.setParentId(param.getParentId());
addParam.setZoneId(addFloor.getZoneId());
addParam.setZoneName(addFloor.getZoneName());
CloudwalkResult<Boolean> addResult = this.personRuleService.add(addParam, context);
requireTaskStepSuccess(addResult, "personRuleService.add");
} else {
AcsPassRuleNewParam ruleParam = new AcsPassRuleNewParam();
ruleParam.setParentId(param.getParentId());
ruleParam.setZoneId(addFloor.getZoneId());
ruleParam.setZoneName(addFloor.getZoneName());
if (!ObjectUtils.isEmpty(param.getLabelId())) {
ruleParam.setIncludeLabels(Collections.singletonList(param.getLabelId()));
ruleParam.setRuleName(addFloor.getZoneName() + param.getLabelName());
}
if (!ObjectUtils.isEmpty(param.getOrgId())) {
ruleParam.setIncludeOrganizations(Collections.singletonList(param.getOrgId()));
ruleParam.setRuleName(addFloor.getZoneName() + param.getOrgName());
}
CloudwalkResult<Boolean> addRuleResult =
this.imageRuleRefService.addOnlyRule(ruleParam, context);
requireTaskStepSuccess(addRuleResult, "imageRuleRefService.addOnlyRule");
}
AcsDeviceTaskAddDto addDto = new AcsDeviceTaskAddDto();
addDto.setId(task.getId());
addDto.setBindDevices(Integer.valueOf(task.getBindDevices().intValue() + 1));
this.acsDeviceTaskDao.updateBingDevices(addDto);
}
}
runAddFloorsInBoundedParallel(param, addFloors, context);
}
if (!CollectionUtils.isEmpty(delFloorIds)) {
List<AcsPassRuleImageResultDto> ruleList = this.imageRuleRefDao.listZoneInfoByIds(delFloorIds);
Map<String, String> ruleMap = new HashMap<>();
ruleList.forEach(rule -> ruleMap.put(rule.getZoneId(), rule.getZoneName()));
for (String delFloorId : delFloorIds) {
AcsDeviceTaskDTO task = this.acsDeviceTaskDao.getById(param.getTaskId());
if (task == null) {
this.logger.error("updateFloors 任务不存在 taskId={}", param.getTaskId());
throw new ServiceException("设备任务不存在");
}
if (task.getIsStop().intValue() == 0) {
if (!ObjectUtils.isEmpty(param.getPersonId())) {
AcsPersonDeleteParam delParam = new AcsPersonDeleteParam();
delParam.setParentId(param.getParentId());
delParam.setZoneId(delFloorId);
delParam.setPersonIds(Collections.singletonList(param.getPersonId()));
CloudwalkResult<Boolean> delResult = this.personRuleService.delete(delParam, context);
requireTaskStepSuccess(delResult, "personRuleService.delete");
} else {
String ruleName = "";
if (!ObjectUtils.isEmpty(param.getLabelName())) {
ruleName = (String)ruleMap.get(delFloorId) + param.getLabelName();
}
if (!ObjectUtils.isEmpty(param.getOrgName())) {
ruleName = (String)ruleMap.get(delFloorId) + param.getOrgName();
}
String ruleId = this.imageRuleRefDao.getByRuleName(ruleName, delFloorId);
if (!ObjectUtils.isEmpty(ruleId)) {
AcsPassRuleDeleteParam deleteParam = new AcsPassRuleDeleteParam();
deleteParam.setIds(Collections.singletonList(ruleId));
deleteParam.setZoneId(delFloorId);
deleteParam.setParentId(param.getParentId());
CloudwalkResult<Boolean> delRuleResult =
this.imageRuleRefService.delete(deleteParam, context);
requireTaskStepSuccess(delRuleResult, "imageRuleRefService.delete");
} else {
AcsPassRuleDeleteDto dto = new AcsPassRuleDeleteDto();
dto.setZoneId(delFloorId);
dto.setLabelId(param.getLabelId());
dto.setOrgId(param.getOrgId());
this.imageRuleRefDao.deleteByOrgAndLabel(dto);
}
}
AcsDeviceTaskAddDto addDto = new AcsDeviceTaskAddDto();
addDto.setId(task.getId());
addDto.setBindDevices(Integer.valueOf(task.getBindDevices().intValue() + 1));
this.acsDeviceTaskDao.updateBingDevices(addDto);
}
}
runDelFloorsInBoundedParallel(param, delFloorIds, ruleMap, context);
}
} catch (Exception e) {
this.logger.error("处理设备任务失败,失败原因:{}", e);
if (e instanceof ServiceException) {
throw (ServiceException)e;
}
throw new ServiceException(e.getMessage());
}
}
/**
* 约定 §3.5:楼层级有界并行发起远程调用;本方法内按原列表顺序 {@code get()} Future
* 与串行时一致地「每成功一层 → 重读任务行并 BIND_DEVICES+1」。
*/
private void runAddFloorsInBoundedParallel(AcsRestructureBindingParam param, List<AcsPassRuleImageResultDto> addFloors,
CloudwalkCallContext context) throws ServiceException {
for (int i = 0; i < addFloors.size(); i += UPDATE_FLOORS_FLOOR_PARALLEL) {
int end = Math.min(i + UPDATE_FLOORS_FLOOR_PARALLEL, addFloors.size());
List<Callable<Integer>> batch = new ArrayList<>();
for (int j = i; j < end; j++) {
final AcsPassRuleImageResultDto addFloor = addFloors.get(j);
batch.add(
() -> FeignThreadLocalUtil.callWithContext(context, () -> addOneFloorStep(addFloor, param, context)));
}
List<Future<Integer>> futures;
try {
futures = this.elevatorRemoteBoundedExecutor.getThreadPoolExecutor().invokeAll(batch);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("76260540", "updateFloors 被中断");
}
for (Future<Integer> f : futures) {
int inc;
try {
inc = f.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("76260540", "updateFloors 被中断");
} catch (ExecutionException e) {
Throwable c = e.getCause();
if (c instanceof ServiceException) {
throw (ServiceException)c;
}
throw new ServiceException(c != null ? c.getMessage() : e.getMessage());
}
if (inc > 0) {
advanceBindProgressOne(param.getTaskId());
}
}
}
}
private void runDelFloorsInBoundedParallel(AcsRestructureBindingParam param, List<String> delFloorIds,
Map<String, String> ruleMap, CloudwalkCallContext context) throws ServiceException {
for (int i = 0; i < delFloorIds.size(); i += UPDATE_FLOORS_FLOOR_PARALLEL) {
int end = Math.min(i + UPDATE_FLOORS_FLOOR_PARALLEL, delFloorIds.size());
List<Callable<Integer>> batch = new ArrayList<>();
for (int j = i; j < end; j++) {
final String delFloorId = delFloorIds.get(j);
batch.add(
() -> FeignThreadLocalUtil.callWithContext(context, () -> delOneFloorStep(delFloorId, param, ruleMap, context)));
}
List<Future<Integer>> futures;
try {
futures = this.elevatorRemoteBoundedExecutor.getThreadPoolExecutor().invokeAll(batch);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("76260540", "updateFloors 被中断");
}
for (Future<Integer> f : futures) {
int inc;
try {
inc = f.get();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new ServiceException("76260540", "updateFloors 被中断");
} catch (ExecutionException e) {
Throwable c = e.getCause();
if (c instanceof ServiceException) {
throw (ServiceException)c;
}
throw new ServiceException(c != null ? c.getMessage() : e.getMessage());
}
if (inc > 0) {
advanceBindProgressOne(param.getTaskId());
}
}
}
}
private void advanceBindProgressOne(String taskId) throws ServiceException {
AcsDeviceTaskDTO task = this.acsDeviceTaskDao.getById(taskId);
if (task == null) {
this.logger.error("updateFloors 任务不存在 taskId={}", taskId);
throw new ServiceException("设备任务不存在");
}
AcsDeviceTaskAddDto addDto = new AcsDeviceTaskAddDto();
addDto.setId(task.getId());
addDto.setBindDevices(Integer.valueOf(task.getBindDevices().intValue() + 1));
this.acsDeviceTaskDao.updateBingDevices(addDto);
}
/**
* @return 1 本层已执行远程步骤且应推进 bind 计数;0 任务已停止跳过
*/
private int addOneFloorStep(AcsPassRuleImageResultDto addFloor, AcsRestructureBindingParam param,
CloudwalkCallContext context) throws ServiceException {
AcsDeviceTaskDTO task = this.acsDeviceTaskDao.getById(param.getTaskId());
if (task == null) {
this.logger.error("updateFloors 任务不存在 taskId={}", param.getTaskId());
throw new ServiceException("设备任务不存在");
}
if (task.getIsStop().intValue() != 0) {
return 0;
}
if (!ObjectUtils.isEmpty(param.getPersonId())) {
AcsPersonAddParam addParam = new AcsPersonAddParam();
addParam.setPersonIds(Collections.singletonList(param.getPersonId()));
addParam.setParentId(param.getParentId());
addParam.setZoneId(addFloor.getZoneId());
addParam.setZoneName(addFloor.getZoneName());
CloudwalkResult<Boolean> addResult = this.personRuleService.add(addParam, context);
requireTaskStepSuccess(addResult, "personRuleService.add");
} else {
AcsPassRuleNewParam ruleParam = new AcsPassRuleNewParam();
ruleParam.setParentId(param.getParentId());
ruleParam.setZoneId(addFloor.getZoneId());
ruleParam.setZoneName(addFloor.getZoneName());
if (!ObjectUtils.isEmpty(param.getLabelId())) {
ruleParam.setIncludeLabels(Collections.singletonList(param.getLabelId()));
ruleParam.setRuleName(addFloor.getZoneName() + param.getLabelName());
}
if (!ObjectUtils.isEmpty(param.getOrgId())) {
ruleParam.setIncludeOrganizations(Collections.singletonList(param.getOrgId()));
ruleParam.setRuleName(addFloor.getZoneName() + param.getOrgName());
}
CloudwalkResult<Boolean> addRuleResult = this.imageRuleRefService.addOnlyRule(ruleParam, context);
requireTaskStepSuccess(addRuleResult, "imageRuleRefService.addOnlyRule");
}
return 1;
}
private int delOneFloorStep(String delFloorId, AcsRestructureBindingParam param, Map<String, String> ruleMap,
CloudwalkCallContext context) throws ServiceException {
AcsDeviceTaskDTO task = this.acsDeviceTaskDao.getById(param.getTaskId());
if (task == null) {
this.logger.error("updateFloors 任务不存在 taskId={}", param.getTaskId());
throw new ServiceException("设备任务不存在");
}
if (task.getIsStop().intValue() != 0) {
return 0;
}
if (!ObjectUtils.isEmpty(param.getPersonId())) {
AcsPersonDeleteParam delParam = new AcsPersonDeleteParam();
delParam.setParentId(param.getParentId());
delParam.setZoneId(delFloorId);
delParam.setPersonIds(Collections.singletonList(param.getPersonId()));
CloudwalkResult<Boolean> delResult = this.personRuleService.delete(delParam, context);
requireTaskStepSuccess(delResult, "personRuleService.delete");
} else {
String baseName = ruleMap.getOrDefault(delFloorId, "");
String ruleName = "";
if (!ObjectUtils.isEmpty(param.getLabelName())) {
ruleName = baseName + param.getLabelName();
}
if (!ObjectUtils.isEmpty(param.getOrgName())) {
ruleName = baseName + param.getOrgName();
}
String ruleId;
try {
ruleId = this.imageRuleRefDao.getByRuleName(ruleName, delFloorId);
} catch (DataAccessException e) {
this.logger.error("updateFloors getByRuleName 失败 delFloorId={} {}", delFloorId, e.getMessage());
throw new ServiceException("76260540", e.getMessage());
}
if (!ObjectUtils.isEmpty(ruleId)) {
AcsPassRuleDeleteParam deleteParam = new AcsPassRuleDeleteParam();
deleteParam.setIds(Collections.singletonList(ruleId));
deleteParam.setZoneId(delFloorId);
deleteParam.setParentId(param.getParentId());
CloudwalkResult<Boolean> delRuleResult = this.imageRuleRefService.delete(deleteParam, context);
requireTaskStepSuccess(delRuleResult, "imageRuleRefService.delete");
} else {
AcsPassRuleDeleteDto dto = new AcsPassRuleDeleteDto();
dto.setZoneId(delFloorId);
dto.setLabelId(param.getLabelId());
dto.setOrgId(param.getOrgId());
try {
this.imageRuleRefDao.deleteByOrgAndLabel(dto);
} catch (DataAccessException e) {
this.logger.error("updateFloors deleteByOrgAndLabel 失败 delFloorId={} {}", delFloorId, e.getMessage());
throw new ServiceException("76260540", e.getMessage());
}
}
}
return 1;
}
/**
* 约定 §2.2:异步任务内对业务服务返回的 {@link CloudwalkResult} 须校验成功后再推进进度(避免失败仍递增 bindDevices)。
*/
@@ -0,0 +1,6 @@
/**
* 设备域服务层:电梯设备查询/编辑、设备任务(含楼层变更)、设备侧设置与图库应用绑定等编排。
* <p>
* 同包名在 data 模块中承担 DAO/Mapper;此处仅放接口、入参出参与 {@code impl} 实现,表结构见 data 包说明。
*/
package cn.cloudwalk.elevator.device;
@@ -8,9 +8,18 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 设备第三方 MQTT 发布入口:向指定 topic 推送 JSON 载荷(由 {@code /mqtt/publish} 落到底层 broker)。
*/
@FeignClient(name = "${feign.mqtt.name:cloudwalk-device-thirdparty}", path = "/mqtt",
fallback = MqttFeignClientFallback.class)
public interface MqttFeignClient {
/**
* 发布一条 MQTT 消息。
*
* @param paramMqttSendMessageParam topic 与 body(通常为业务侧 JSON 字符串)
* @return 是否投递成功,由下游服务定义成功语义
*/
@RequestMapping(value = {"/publish"}, method = {RequestMethod.POST})
CloudwalkResult<Boolean> publish(MqttSendMessageParam paramMqttSendMessageParam) throws ServiceException;
}
@@ -6,8 +6,16 @@ import cn.cloudwalk.elevator.mqtt.client.MqttFeignClient;
import cn.cloudwalk.elevator.mqtt.param.MqttSendMessageParam;
import org.springframework.stereotype.Component;
/**
* {@link MqttFeignClient} 熔断/降级:调用失败时抛出运行时异常,促使上层按失败处理(不伪造成功投递)。
*/
@Component
public class MqttFeignClientFallback implements MqttFeignClient {
/**
* {@inheritDoc}
* @implSpec 不返回降级业务结果,直接抛错以暴露下游不可用
*/
@Override
public CloudwalkResult<Boolean> publish(MqttSendMessageParam param) throws ServiceException {
throw new RuntimeException("mqtt发送数据失败");
}
@@ -23,10 +23,16 @@ import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
/**
* {@link MqttService} 实现:先短暂休眠以便识别明细入库,再按通行流水查人名、访客标签,向 {@code businessId + ELEVATOR_RECORD_SUFFIX} topic 推送 JSON。
*/
@Component
public class MqttServiceImpl extends AbstractAcsDeviceService implements MqttService {
/** 人员标签中表示「访客」的编码,与识别记录里 {@code personLabelIds} 包含关系判断一致。 */
private static final String VISITOR_LABEL_CODE = "1";
/** 与 {@link #VISITOR_LABEL_CODE} 对应的展示名,当前实现未参与逻辑,仅作文档对齐。 */
private static final String VISITOR_LABEL_NAME = "访客";
/** MQTT topic 后缀,与 {@code businessId} 拼接为完整 topic。 */
private static final String ELEVATOR_RECORD_SUFFIX = "_elevator_record";
@Qualifier("cn.cloudwalk.elevator.mqtt.client.MqttFeignClient")
@Resource
@@ -34,6 +40,12 @@ public class MqttServiceImpl extends AbstractAcsDeviceService implements MqttSer
@Resource
private AcsRecogRecordDao acsRecogRecordDao;
/**
* {@inheritDoc}
* <p>
* 异常在方法内记录日志后吞掉(除中断转 {@link ServiceException}),避免异步线程因下游偶发错误反复未捕获终止。
*/
@Override
@Async
public void sendInfoToOne(AcsElevatorRecordAddDTO addDTO) throws ServiceException {
this.logger.info("防止人员识别记录未入库即开始推送消息,休眠10秒");
@@ -56,11 +68,11 @@ public class MqttServiceImpl extends AbstractAcsDeviceService implements MqttSer
acsElevatorRecordMqttParam.setOpenDoorId(addDTO.getId());
acsElevatorRecordMqttParam.setPersonName(acsRecogRecordResultDTO.getPersonName());
if (StringUtils.isNotBlank(acsRecogRecordResultDTO.getPersonLabelIds())
&& acsRecogRecordResultDTO.getPersonLabelIds().contains("1")) {
&& acsRecogRecordResultDTO.getPersonLabelIds().contains(VISITOR_LABEL_CODE)) {
acsElevatorRecordMqttParam.setIsVisitor(Boolean.TRUE);
}
CloudwalkResult<Boolean> publish = this.mqttFeignClient
.publish(MqttSendMessageParam.builder().topic(addDTO.getBusinessId() + "_elevator_record")
.publish(MqttSendMessageParam.builder().topic(addDTO.getBusinessId() + ELEVATOR_RECORD_SUFFIX)
.data(JSON.toJSONString(acsElevatorRecordMqttParam)).build());
if (publish.isSuccess()) {
this.logger.info("推送数据成功!!!,数据,{}", JSON.toJSONString(acsElevatorRecordMqttParam));
@@ -0,0 +1,6 @@
/**
* 电梯识别记录 MQTT 推送:经 {@code cloudwalk-device-thirdparty} 等下游将消息发布到业务 topic,供大屏/第三方订阅。
* <p>
* 与 {@code record} 域协作:在人员识别记录落库后异步组装载荷并调用发布接口。
*/
package cn.cloudwalk.elevator.mqtt;
@@ -1,5 +1,8 @@
package cn.cloudwalk.elevator.mqtt.param;
/**
* 推送到 MQTT 的电梯记录载荷:在 {@link cn.cloudwalk.elevator.record.dto.AcsElevatorRecordAddDTO} 基础上补全人名、开门流水 id、是否访客等,序列化为 {@code data} 字段内容。
*/
public class AcsElevatorRecordMqttParam {
private String openDoorId;
private String openDoorType;
@@ -2,6 +2,9 @@ package cn.cloudwalk.elevator.mqtt.param;
import java.beans.ConstructorProperties;
/**
* Feign 发布请求体:MQTT topic 与一条 JSON 字符串形式的业务数据。
*/
public class MqttSendMessageParam {
private String topic;
private String data;
@@ -3,6 +3,17 @@ package cn.cloudwalk.elevator.mqtt.service;
import cn.cloudwalk.cloud.exception.ServiceException;
import cn.cloudwalk.elevator.record.dto.AcsElevatorRecordAddDTO;
/**
* 将单条电梯通行/识别结果异步推送到 MQTT(供订阅方如大屏展示),与落库存在时序上的缓冲(实现内会短暂休眠后查库补全人名等)。
*/
public interface MqttService {
/**
* 按一条待写入或已关联的识别记录,组装业务 topic 与 JSON 后发起 {@link cn.cloudwalk.elevator.mqtt.client.MqttFeignClient#publish}。
* <p>
* 异步方法:调用方不应依赖其完成时刻做强一致逻辑。
*
* @param paramAcsElevatorRecordAddDTO 电梯识别记录主数据(需含 businessId、recognition 关联键等,供拼 topic 与反查人员)
* @throws ServiceException 睡眠被中断等不可恢复情况
*/
void sendInfoToOne(AcsElevatorRecordAddDTO paramAcsElevatorRecordAddDTO) throws ServiceException;
}
@@ -0,0 +1,7 @@
/**
* 电梯应用业务编排层({@code cw-elevator-application-service}):领域服务接口与实现、远程调用、异步与任务推进。
* <p>
* 与 {@code cw-elevator-application-data} 的持久化、{@code cw-elevator-application-web} 的 HTTP 入口分工协作;
* 本模块内可依赖对外 Feign 契约(如 {@code intelligent-cwoscomponent-interface}),但不应向上依赖 Web 层。
*/
package cn.cloudwalk.elevator;
@@ -126,7 +126,7 @@ public class AcsPassRuleServiceImpl extends AbstractAcsPassService implements Ac
}
int floorCount = passRuleResults.size();
long[] personTotals = new long[floorCount];
for (int i = 0; i < floorCount; ) {
for (int i = 0; i < floorCount;) {
int end = Math.min(i + REMOTE_IO_PARALLEL, floorCount);
List<Callable<Void>> batch = new ArrayList<>();
for (int j = i; j < end; j++) {
@@ -237,7 +237,7 @@ public class AcsPassRuleServiceImpl extends AbstractAcsPassService implements Ac
this.acsDeviceImageStoreAppBindService.bindAppImageStoreDevice(appBindParam, context);
if (!CollectionUtils.isEmpty(deviceList)) {
final String newImageStoreId = (String)imageStoreId.getData();
for (int i = 0; i < deviceList.size(); ) {
for (int i = 0; i < deviceList.size();) {
int end = Math.min(i + REMOTE_IO_PARALLEL, deviceList.size());
List<Callable<Void>> bindBatch = new ArrayList<>();
for (int j = i; j < end; j++) {
@@ -556,8 +556,7 @@ public class AcsPassRuleServiceImpl extends AbstractAcsPassService implements Ac
ImageStoreDelParam delParam = new ImageStoreDelParam();
delParam.setId(imageStoreIdValue);
delParam.setBusinessId(context.getCompany().getCompanyId());
this.logger.info("回滚删除图库开始,delParam={},context={}", JSONObject.toJSON(delParam),
JSONObject.toJSON(context));
this.logger.info("回滚删除图库开始,delParam={},context={}", JSONObject.toJSON(delParam), JSONObject.toJSON(context));
CloudwalkResult<Boolean> deleteResult = this.imageStoreService.delete(delParam, context);
this.logger.info("删除图库:图库id={},结果:{}", imageStoreIdValue, deleteResult.getMessage());
}
@@ -678,8 +678,8 @@ public class ImageRuleRefServiceImpl extends AbstractAcsPassService implements I
}
/**
* 一次 {@link LabelService#getAll} 建 id→详情索引,避免规则详情/分页组装时对 {@link LabelService#detail} 的 N 次远程调用。
* 若某 id 不在全量列表中(数据不同步),回退单次 detail。
* 一次 {@link LabelService#getAll} 建 id→详情索引,避免规则详情/分页组装时对 {@link LabelService#detail} 的 N 次远程调用。 若某 id
* 不在全量列表中(数据不同步),回退单次 detail。
*/
private Map<String, LabelDetailResult> loadLabelDetailMap(CloudwalkCallContext context) throws ServiceException {
CloudwalkResult<List<LabelDetailResult>> all = this.labelService.getAll(new LabelQueryParam(), context);
@@ -0,0 +1,6 @@
/**
* 通行/人员规则与图库规则引用:规则增删、与区域/标签/组织维度的组合,及与设备任务的协作。
* <p>
* 与 {@code person} 包在“按人下发”和“按规则下发”两种路径上常共同出现在设备任务流中。
*/
package cn.cloudwalk.elevator.passrule;
@@ -208,8 +208,7 @@ public class AcsPersonServiceImpl extends AbstractAcsPassService implements AcsP
Throwable c = e.getCause();
if (c instanceof ServiceException) {
ServiceException se = (ServiceException)c;
return CloudwalkResult.fail(
se.getCode() != null ? se.getCode() : "76260407",
return CloudwalkResult.fail(se.getCode() != null ? se.getCode() : "76260407",
getMessage("76260407") + " " + se.getMessage());
}
return CloudwalkResult.fail("76260407",
@@ -0,0 +1,4 @@
/**
* 人员与人员-规则服务:人员增删、与区域/父级人员关系、及与设备侧同步相关的编排。
*/
package cn.cloudwalk.elevator.person;
@@ -44,8 +44,8 @@ public class AcsPersonAddVisitorParam implements Serializable {
return false;
}
return Objects.equals(visitorId, other.visitorId) && Objects.equals(personId, other.personId)
&& Objects.equals(begVisitorTime, other.begVisitorTime) && Objects.equals(endVisitorTime, other.endVisitorTime)
&& Objects.equals(floorIds, other.floorIds);
&& Objects.equals(begVisitorTime, other.begVisitorTime)
&& Objects.equals(endVisitorTime, other.endVisitorTime) && Objects.equals(floorIds, other.floorIds);
}
protected boolean canEqual(Object other) {
@@ -86,8 +86,23 @@ import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.util.UriComponentsBuilder;
/**
* 电梯开门/通行记录:查询、落库、统计与域内事件发布。
* <p>
* 新增记录时通过 {@link cn.cloudwalk.elevator.util.RestTemplateUtil} 请求 {@code ninca-crk-std} 的
* {@code intelligent/three/visitor/record/query},用识别 id 反查是否访客及被访人;该路径与
* {@link cn.cloudwalk.elevator.visitor.client.VisitorFeignClient} 所映射的
* {@code /intelligent/visitor/record/query} 为两套接口,本处固定走「three」版 HTTP。
* <p>
* {@link MqttService} 为识别结果 MQTT 推送能力,本类已注入但<strong>未直接调用</strong>;若需与入库联动,可在监听
* {@link cn.cloudwalk.elevator.record.result.VisitorRecordPushEvent} 的处理器中显式
* {@link cn.cloudwalk.elevator.mqtt.service.MqttService#sendInfoToOne}(或其它入口接线)。
*/
@Service
public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService implements AcsElevatorRecordService {
/**
* 标准访客/三方服务所在主机(IP 或 host:port),与 {@link #combineAuthClientURI} 拼成完整 URL。
*/
@Value("${ninca-crk-std.ip}")
private String nincaCrkStd;
@Autowired
@@ -104,6 +119,9 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
private DeviceDistrictService deviceDistrictService;
@Resource
private AcsAreaTreeCacheableService acsAreaTreeCacheableService;
/**
* 识别记录 MQTT 异步推送服务;本类当前不调用,保留供与 {@link #sendRecordEvent} 或外部监听协同接入。
*/
@Resource
private MqttService mqttService;
@Resource
@@ -118,6 +136,9 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
protected static final int CACHE_EXPIRE_TIME = 8;
private static final String ELEVATOR_RECORD_SUFFIX = "elevator_record";
/**
* 分页查询开门记录明细:组装区域/片区/人员等展示字段,时间跨度超过一年直接拒绝。
*/
@CloudwalkParamsValidate(argsIndexs = {0, 1})
public CloudwalkResult<CloudwalkPageAble<AcsElevatorRecordResult>> openRecord(AcsElevatorRecordDetailParam param,
CloudwalkPageInfo pageInfo, CloudwalkCallContext cloudwalkContext) throws ServiceException {
@@ -210,6 +231,7 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
}
}
/** 从记录列表中按片区或区域去重后收集 id,供批量拉取名称。 */
private List<String> acsElevatorRecordListDupRemove(List<AcsElevatorRecordDetailQueryResultDTO> list, String flag) {
List<String> tempList = new ArrayList<>();
if (flag.equals("district")) {
@@ -227,6 +249,16 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
return tempList;
}
/**
* 新增单条电梯通行/识别结果:写库并发布 {@link cn.cloudwalk.elevator.record.result.VisitorRecordPushEvent} 域事件。
* <p>
* 在持久化前通过 {@link cn.cloudwalk.elevator.util.RestTemplateUtil#post} 调访客「three」线查询,若命中则置访客并回填被访人
* {@code interviewee};再拉人员详情补工号/组织。此处未调用 {@link cn.cloudwalk.elevator.mqtt.service.MqttService}。
*
* @param param 设备侧识别结果、图片、操作者等
* @param context 租户与调用方上下文
* @return 落库与事件是否成功
*/
public CloudwalkResult<Boolean> add(AcsElevatorRecordAddParam param, CloudwalkCallContext context)
throws ServiceException {
try {
@@ -393,6 +425,9 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
}
}
/**
* 将入库后的记录复制为域事件并发布,供图库/订阅方等异步入队处理(可能间接触发其它推送,与 MQTT 无强绑定)。
*/
private void sendRecordEvent(AcsElevatorRecordAddDTO addDTO) {
VisitorRecordPushEvent event =
(VisitorRecordPushEvent)BeanCopyUtils.copyProperties(addDTO, VisitorRecordPushEvent.class);
@@ -401,6 +436,9 @@ public class AcsElevatorRecordServiceImpl extends AbstractAcsDeviceService imple
this.cloudwalkEventManager.publish((BaseEvent)event);
}
/**
* 构造访问 {@code ninca-crk-std} 的绝对 URI{@code api} 为不含前导斜杠的 path 段(如 {@code intelligent/three/...})。
*/
private URI combineAuthClientURI(String api, @Nullable MultiValueMap<String, String> params) {
return UriComponentsBuilder.fromUriString("http://" + this.nincaCrkStd).path(api).queryParams(params).build()
.toUri();
@@ -0,0 +1,4 @@
/**
* 电梯通行/识别记录业务:查询、落库、统计,并与访客中心(HTTP「three」线或 Feign「intelligent」线)、域事件、可选 MQTT 推送协同。
*/
package cn.cloudwalk.elevator.record;
@@ -2,6 +2,10 @@ package cn.cloudwalk.elevator.record.result;
import cn.cloudwalk.cwos.client.event.event.CustomEvent;
/**
* 通行记录入库后发布的域事件,{@link #getTopic()} 固定为 {@code VISITOR_RECORD_TOPIC};监听方可据此做下游同步,与
* {@link cn.cloudwalk.elevator.mqtt.service.MqttService} 无强制耦合。
*/
public class VisitorRecordPushEvent extends CustomEvent {
private String businessId;
private String deviceId;
@@ -9,9 +9,18 @@ import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 标准访客服务:按访客主键分页查询其档案与到访/识别记录列表(路径 {@code /intelligent/visitor/record/query})。
*/
@FeignClient(name = "${feign.ninca-crk-std.name:ninca-crk-std}", path = "/intelligent/visitor/record",
fallback = VisitorFeignClientFallback.class)
public interface VisitorFeignClient {
/**
* 查询某租户下指定访客的详细资料及关联识别记录。
*
* @param paramVisitorRecordQueryParam 访客 id、业务租户 id 与分页参数
* @return 聚合 {@link cn.cloudwalk.elevator.visitor.result.VisitorQueryResult}
*/
@RequestMapping(value = {"/query"}, method = {RequestMethod.POST})
CloudwalkResult<VisitorQueryResult> query(VisitorRecordQueryParam paramVisitorRecordQueryParam)
throws ServiceException;
@@ -7,8 +7,13 @@ import cn.cloudwalk.elevator.visitor.param.VisitorRecordQueryParam;
import cn.cloudwalk.elevator.visitor.result.VisitorQueryResult;
import org.springframework.stereotype.Component;
/**
* {@link VisitorFeignClient} 熔断/降级:查询失败时抛错,不返回空壳数据,避免业务误判「无记录」与「服务不可用」。
*/
@Component
public class VisitorFeignClientFallback implements VisitorFeignClient {
/** {@inheritDoc} */
@Override
public CloudwalkResult<VisitorQueryResult> query(VisitorRecordQueryParam param) throws ServiceException {
throw new RuntimeException("查询识别记录详情失败");
}
@@ -0,0 +1,6 @@
/**
* 访客主数据与识别记录查询:通过 Feign 调用 {@code ninca-crk-std} 等标准访客服务,为电梯业务侧提供访客档案与到访记录。
* <p>
* 本包内为入参/出参模型与客户端;业务组装与调用方在 record 等域中完成。
*/
package cn.cloudwalk.elevator.visitor;
@@ -3,6 +3,9 @@ package cn.cloudwalk.elevator.visitor.param;
import java.io.Serializable;
import java.util.List;
/**
* 按主键批量拉取访客(或软删过滤)的查询条件,供与标准访客服务其它接口对接时复用。
*/
public class VisitorGetsParam implements Serializable {
private static final long serialVersionUID = 3454014008721633675L;
private List<String> ids;
@@ -1,5 +1,8 @@
package cn.cloudwalk.elevator.visitor.param;
/**
* 轻量入参模型,仅含访客 id,字段可与 {@link VisitorRecordQueryParam#visitorId} 对应后再补全租户、分页等。
*/
public class VisitorRecordQueryForm {
private String visitorId;
@@ -3,6 +3,9 @@ package cn.cloudwalk.elevator.visitor.param;
import cn.cloudwalk.cloud.page.CloudwalkPageInfo;
import java.io.Serializable;
/**
* 访客记录分页查询条件:必含业务租户与访客主键,继承公共分页信息。
*/
public class VisitorRecordQueryParam extends CloudwalkPageInfo implements Serializable {
private static final long serialVersionUID = -5418825126025402170L;
private String visitorId;
@@ -3,6 +3,9 @@ package cn.cloudwalk.elevator.visitor.result;
import java.io.Serializable;
import java.util.List;
/**
* 访客查询接口的聚合出参:一份访客档案 + 多页识别记录集合。
*/
public class VisitorQueryResult implements Serializable {
private static final long serialVersionUID = 5547248296251558353L;
private VisitorResult visitorInfo;
@@ -3,6 +3,9 @@ package cn.cloudwalk.elevator.visitor.result;
import java.io.Serializable;
import java.math.BigDecimal;
/**
* 单条访客识别/签到记录:设备与区域信息、比分数、以及电梯业务扩展字段(如原因、起止楼层、派梯号等)。
*/
public class VisitorRecordResult implements Serializable {
private static final long serialVersionUID = -7671207718927334038L;
private String id;
@@ -4,6 +4,9 @@ import cn.cloudwalk.cloud.annotation.SensitiveField;
import cn.cloudwalk.cloud.enums.SensitiveType;
import java.io.Serializable;
/**
* 访客主数据:含证件号(脱敏标注)、访期、登记人脸/展示图、与平台人员关系等;字段与标准访客中心模型对齐。
*/
public class VisitorResult implements Serializable {
private static final long serialVersionUID = -6835803928819332341L;
private String id;
@@ -0,0 +1,6 @@
/**
* 区域(园区/楼栋/楼层等)树与下一级树查询,供设备、通行与前端级联选择使用。
* <p>
* 多通过 Feign 拉取平台区域数据并在本包内做组装与 {@code result} 封装。
*/
package cn.cloudwalk.elevator.zone;