# 访客注册与派梯楼层:完整业务流程走查 > **范围说明**:本文基于本仓库内 Maven 工程源码(`maven-cw-elevator-application`、`maven-intelligent-cwoscomponent` 等)梳理**接口调用链、业务逻辑与用例**。 > **访客业务后台**(如「轻舟 / intelligent/three」访客注册、审批流)若不在本仓库,文中以「第三方业务系统」统称,并标明本仓库可见的**被调接口**与**出站 Feign/HTTP**。 --- ## 1. 术语与角色 | 术语 | 含义 | |------|------| | 第三方业务系统 | 访客注册、邀约、审批等上层应用;可经 intelligent 组件或直接调电梯服务 | | 组织人员服务 | `ninca-common-component-organization`(可配置),提供人员详情、图库人员绑定等 | | 空间/区域服务 | `ninca-common` 的 `/sysetting/zone`,提供楼栋-楼层树、分区 page | | 电梯应用 | `cw-elevator-application`,维护派梯规则 `image_rule_ref`、设备图库绑定等 | | 被访人 | `personId`,组织侧人员主键 | | 访客 | `visitorId`,组织侧访客人员主键 | | 楼层 | 以 **分区/空间 ID**(`zoneId` / `floorId`)表示,与 `PersonResult.floorList` 元素一致 | --- ## 2. 业务总览(从「默认楼层」到「指定楼层」) ```mermaid flowchart TB subgraph third [第三方业务系统] A[访客注册/邀约完成] B{是否已知具体楼层 zoneId 列表?} C[调组织服务拉人员详情] D[组装 floorIds 显式列表] end subgraph org [组织人员服务 ninca-common-component-organization] P["POST /component/person/detail"] I["POST /component/imagestore/person/batchBind 等"] end subgraph intel [intelligent-cwoscomponent-rest 可选] E["ElevatorPersonService.addVisitor → Feign"] end subgraph elev [电梯 cw-elevator-application] F["POST /elevator/person/add/visitor"] G["PersonRuleServiceImpl.addVisitor"] end A --> B B -->|否 需默认| C C --> P P -->|PersonResult.floorList| third B -->|是 或 已补全| D D --> E C --> E E --> F F --> G G -->|缺 floorIds 时内部再调 P 取 floorList| P G --> I ``` **要点**: - 「**默认有哪些楼层**」在本仓库电梯侧的实现是:**未传 `floorIds` 时**,调用 **`PersonService.detail`**(Feign → **`POST /component/person/detail`**),取 **`PersonResult.getFloorList()`**,**不是** `PersonResult.defaultFloor` 单字段。 - 「**第三方设定具体楼层**」:**在请求体中携带非空的 `floorIds`** 调用 **`POST /elevator/person/add/visitor`**(或经 `ElevatorPersonService` 转发),电梯侧**不再**调人员详情补楼层。 --- ## 3. 流程 A:第三方如何获知「默认」楼层(可走的接口) 第三方若**自行**在注册前展示「被访人默认可达楼层」,应在**组织侧**完成数据拉取;本仓库可见的**权威数据源**为人员详情返回的 **`floorList`**(及可能同时返回的 `defaultFloor`、`floorInfoList` 等,但电梯访客派梯**仅用** `floorList` 补全逻辑)。 ### 3.1 推荐:人员详情(与电梯补全逻辑一致) | 项目 | 内容 | |------|------| | 调用方 | 任意有权限的服务;intelligent 中为 `RestPersonServiceImpl` → `PersonFeignClient` | | 服务名配置 | `${feign.component-organization.name:ninca-common-component-organization}` | | HTTP | **`POST /component/person/detail`** | | 请求体 | `PersonDetailParam`:`id` = 被访人 `personId`,`businessId` = 机构 | | 响应 | `CloudwalkResult`,关注 **`floorList`**(`List` 楼层/分区 ID) | 代码位置(Feign 声明): ```19:32:maven-intelligent-cwoscomponent/intelligent-cwoscomponent-rest/src/main/java/cn/cloudwalk/rest/cwoscomponent/intelligent/person/feign/PersonFeignClient.java @FeignClient(name = "${feign.component-organization.name:ninca-common-component-organization}", path = "/component/person", fallback = PersonFeignClientFallback.class) public interface PersonFeignClient { ... @RequestMapping(value = {"/detail"}, method = {RequestMethod.POST}) CloudwalkResult detail(@RequestBody PersonDetailParam paramPersonDetailParam); ``` `PersonResult` 中与楼层相关的字段(电梯 `addVisitor` **补全时只用 `floorList`**): ```27:34:maven-intelligent-cwoscomponent/intelligent-cwoscomponent-interface/src/main/java/cn/cloudwalk/client/cwoscomponent/intelligent/person/result/PersonResult.java private String defaultFloor; private String chooseFloor; private List floorList; private List floorInfoList; ... private String defaultChooseFloor; ``` ### 3.2 辅助:空间树 / 楼层分页(电梯网关或管理端常用) | 项目 | 内容 | |------|------| | Feign | `ZoneFeignClient` → `${feign.ninca-common.name:ninca-common}` | | HTTP | **`POST /sysetting/zone/tree`**、**`POST /sysetting/zone/page`** | | 用途 | 按楼栋展示树、按条件查分区;**不替代**人员已授权楼层列表 | ```16:23:maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/zone/client/ZoneFeignClient.java @FeignClient(name = "${feign.ninca-common.name:ninca-common}", path = "/sysetting/zone", fallback = ZoneFeignClientFallback.class) public interface ZoneFeignClient { @RequestMapping(value = {"/tree"}, method = {RequestMethod.POST}) ... @RequestMapping(value = {"/page"}, method = {RequestMethod.POST}) CloudwalkResult> page(ZoneQueryParam paramZoneQueryParam) throws ServiceException; } ``` ### 3.3 辅助:通行规则-楼层列表(管理派梯规则维度) | 项目 | 内容 | |------|------| | Controller | `AcsPassRuleController` | | HTTP | **`POST /elevator/passRule/floor`** 等 | | 用途 | 规则/图库与楼层关系维护与查询;与「人员 floorList」不同维度 | ```45:55:maven-cw-elevator-application/cw-elevator-application-web/src/main/java/cn/cloudwalk/elevator/passrule/controller/AcsPassRuleController.java @RequestMapping({"/floor"}) public CloudwalkResult> listFloor(@RequestBody AcsPassRuleFloorForm form) { ... return this.imageRuleRefService.listFloor(param, getCloudwalkContext()); ``` ### 3.4 访客记录查询(识别访客身份,非楼层来源) 电梯乘梯记录中通过 **RestTemplate** 调 **`intelligent/three/visitor/record/query`**,用于判断是否访客及被访人,**不参与** `addVisitor` 楼层列表计算: ```262:274:maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/record/impl/AcsElevatorRecordServiceImpl.java URI uri = combineAuthClientURI("intelligent/three/visitor/record/query", (MultiValueMap)null); VisitorRecordQueryParam form = new VisitorRecordQueryParam(); form.setVisitorId(addDTO.getRecognitionFaceId()); ... ``` 另有 Feign **`VisitorFeignClient`**:`ninca-crk-std` 的 **`/intelligent/visitor/record/query`**,与上为不同网关路径,同属访客记录查询能力。 --- ## 4. 流程 B:第三方设定「具体楼层」并开通访客派梯 ### 4.1 对外 HTTP(电梯应用) | 项目 | 内容 | |------|------| | Method / Path | **`POST /elevator/person/add/visitor`** | | Controller | `AcsPersonController#addVisitor` | | Body | `AcsPersonAddVisitorForm` → `AcsPersonAddVisitorParam` | ```53:62:maven-cw-elevator-application/cw-elevator-application-web/src/main/java/cn/cloudwalk/elevator/person/controller/AcsPersonController.java @RequestMapping({"/add/visitor"}) public CloudwalkResult addVisitor(@RequestBody AcsPersonAddVisitorForm form) { AcsPersonAddVisitorParam param = (AcsPersonAddVisitorParam)BeanCopyUtils.copyProperties(form, AcsPersonAddVisitorParam.class); try { return this.personRuleService.addVisitor(param, getCloudwalkContext()); ``` ### 4.2 经 intelligent 的 Feign(业务方 SDK 式调用) | 项目 | 内容 | |------|------| | 接口 | `ElevatorPersonService.addVisitor` | | 实现 | `RestElevatorPersonServiceImpl` | | Feign | `ElevatorPersonFeignClient` | | 目标 | `${feign.elevator.name:elevator-app}` **`POST /elevator/person/add/visitor`** | ```11:15:maven-intelligent-cwoscomponent/intelligent-cwoscomponent-rest/src/main/java/cn/cloudwalk/rest/cwoscomponent/intelligent/elevator/feign/ElevatorPersonFeignClient.java @FeignClient(name = "${feign.elevator.name:elevator-app}", path = "/elevator/person", fallback = ElevatorPersonFeignClientFallback.class) public interface ElevatorPersonFeignClient { @RequestMapping(value = {"/add/visitor"}, method = {RequestMethod.POST}) CloudwalkResult addVisitor(@RequestBody AcsPersonAddVisitorParam paramAcsPersonAddVisitorParam); ``` ### 4.3 请求字段语义(用例输入) | 字段 | 必填性 | 说明 | |------|--------|------| | `visitorId` | 是 | 访客在组织侧人员 ID | | `personId` | 是 | 被访人 ID;**补全楼层时**用于 `detail` | | `begVisitorTime` / `endVisitorTime` | 视图库接口 | 传入图库绑定有效期 | | `floorIds` | 否 | **非空**:第三方显式指定可派梯楼层;**空/缺省**:由电梯侧按被访人 **`floorList`** 补全 | --- ## 5. 电梯侧核心业务逻辑:`PersonRuleServiceImpl.addVisitor` 实现类:`PersonRuleServiceImpl`(`maven-cw-elevator-application/.../PersonRuleServiceImpl.java`)。 ### 5.1 步骤分解 | 步骤 | 逻辑 | 外部依赖 | |------|------|----------| | 1 | 若 `floorIds` 为空 → `PersonDetailParam(personId, businessId)` → **`personService.detail`** | Feign → **`POST /component/person/detail`**,取 **`getFloorList()`** 赋给 `floorIds` | | 2 | 用 **`floorIds.get(0)`** 构造 `ZoneQueryParam`,**`zoneService.page`** 查分区页,取首条 `ZoneResult` 得 **`parentId`(楼栋)** | Feign → **`POST /sysetting/zone/page`** | | 3 | **`deviceImageStoreDao.getByBuildingId(parentId)`** 得图库 `imageStoreId` | 本地 DAO | | 4 | 对 **每个 `floorId`**:`imageRuleRefDao.getDefaultByZoneId(floorId)` 取默认通行规则,组装 **`ImageRuleRefAddDto`**(访客 `visitorId` 挂父规则) | 本地 DAO | | 5 | **`imageRuleRefDao.insertList`** 批量写入派梯规则引用 | 本地 DAO | | 6 | 组装 **`ImageStorePersonBindParam`**(图库、访客 ID、有效期),**`imageStorePersonService.batchBind`** | Feign → **`POST /component/imagestore/person/batchBind`** | | 7 | **`imageStorePersonService.updateGroupPersonRef`** 更新组与人员引用 | Feign → **`POST /component/imagestore/person/updateGroupPersonRef`** | 关键代码(补全楼层 + 循环写规则 + 绑图库): ```170:223:maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java if (CollectionUtils.isEmpty(param.getFloorIds())) { PersonDetailParam detailParam = new PersonDetailParam(); detailParam.setId(param.getPersonId()); detailParam.setBusinessId(context.getCompany().getCompanyId()); CloudwalkResult detail = this.personService.detail(detailParam, context); param.setFloorIds(((PersonResult)detail.getData()).getFloorList()); } ZoneQueryParam zoneQueryParam = new ZoneQueryParam(); zoneQueryParam.setId(param.getFloorIds().get(0)); ... for (String floorId : param.getFloorIds()) { ImageRuleRefResultDto defaultRule = this.imageRuleRefDao.getDefaultByZoneId(floorId); ... addDto.setPersonId(param.getVisitorId()); ... } ... CloudwalkResult bindResult = this.imageStorePersonService.batchBind(imageStorePersonBindParam, context); ... this.imageStorePersonService.updateGroupPersonRef(refParam, context); ``` 图库 Feign(与上表一致): ```19:41:maven-intelligent-cwoscomponent/intelligent-cwoscomponent-rest/src/main/java/cn/cloudwalk/rest/cwoscomponent/intelligent/imagestore/feign/ImageStorePersonFeignClient.java @FeignClient(name = "${feign.component-organization.name:ninca-common-component-organization}", path = "/component/imagestore/person", fallback = ImageStorePersonFeignClientFallback.class) public interface ImageStorePersonFeignClient { ... @RequestMapping(value = {"/batchBind"}, method = {RequestMethod.POST}) CloudwalkResult batchBind(@RequestBody ImageStorePersonBindParam paramImageStorePersonBindParam); @RequestMapping(value = {"/updateGroupPersonRef"}, method = {RequestMethod.POST}) CloudwalkResult updateGroupPersonRef(@RequestBody UpdateGroupPersonRefParam paramUpdateGroupPersonRefParam); ``` ### 5.2 与「内部员工」派梯开通的对比(非访客) **`POST /elevator/person/add`** → `PersonRuleServiceImpl.add`:按**单个** `zoneId`(楼层)与 `parentId`(楼栋)给多名 **`personIds`** 写规则并绑图库;**不**调人员 `detail` 取 `floorList`。用于从已有人员批量加通行权限的另一条业务线。 ```79:136:maven-cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java public CloudwalkResult add(AcsPersonAddParam param, CloudwalkCallContext context) throws ServiceException { ... ImageRuleRefResultDto defaultRule = this.imageRuleRefDao.getDefaultByZoneId(param.getZoneId()); ... for (String personId : param.getPersonIds()) { ... addDto.setZoneId(param.getZoneId()); ``` --- ## 6. 接口调用流转汇总表 | 序号 | 调用方向 | 协议与路径 | 典型触发 | |------|----------|------------|----------| | 1 | 第三方 / intelligent → 电梯 | `POST /elevator/person/add/visitor` | 访客开通派梯 | | 2 | 电梯 → 组织 | `POST /component/person/detail` | `floorIds` 为空时补全 | | 3 | 电梯 → 空间 | `POST /sysetting/zone/page` | 取楼层所属楼栋 | | 4 | 电梯 → 组织 | `POST /component/imagestore/person/batchBind` | 访客绑图库 | | 5 | 电梯 → 组织 | `POST /component/imagestore/person/updateGroupPersonRef` | 更新组人关系 | | 6 | 第三方自行(可选) | `POST /component/person/detail` | 注册前展示默认可达楼层 | | 7 | 管理端(可选) | `POST /elevator/passRule/floor` 等 | 规则/楼层维护 | | 8 | 电梯 → 网关 HTTP | `POST intelligent/three/visitor/record/query` | 乘梯记录识别访客 | --- ## 7. 用例(UC)说明 | 用例 ID | 名称 | 前置条件 | 主流程 | 期望结果 | |---------|------|----------|--------|----------| | UC-01 | 访客派梯-使用被访人默认楼层列表 | 被访人 `personId` 在组织侧 `detail` 返回**非空** `floorList`;访客已注册 | 调 `add/visitor` 且 **不传 `floorIds`** | 电梯取 `floorList` 为访客写入各层默认规则并绑图库 | | UC-02 | 访客派梯-第三方指定楼层 | `floorIds` 为合法 zoneId 列表 | 调 `add/visitor` 且 **传入 `floorIds`** | **不再**调 `person/detail` 补楼层;按列表写规则 | | UC-03 | 注册前展示「可访楼层」 | 需与被访人授权一致 | 第三方先调 **`/component/person/detail`**,展示 `floorList`(或产品定义的 `defaultFloor` 映射) | UI 与电梯补全逻辑对齐(若仅用 `defaultFloor` 需与产品确认是否与 `floorList` 一致) | | UC-04 | `floorList` 为空 | 被访人无派梯楼层 | `add/visitor` 不传 `floorIds` | `floorIds` 仍为空 → 后续 `get(0)` 等**可能异常**;第三方应校验或传显式楼层 | | UC-05 | 内部人员加单层派梯 | 已知 `zoneId`、楼栋 `parentId` | `POST /elevator/person/add` | 单层规则 + 图库绑定 | | UC-06 | 乘梯记录标记访客 | 识别到人脸 | 记录服务调 **`visitor/record/query`** | 回填 `isVisitor`、被访人 | **扩展(租户访客默认楼层)**:若需「在 UC-01 不传 `floorIds` 的前提下,按租户策略收敛访客楼层(如默认仅开放某接待层)」的产品与技术设计,以及**从第三方登记页初始化数据项、接口编排到 `add/visitor` 的端到端闭环**,见 [租户访客默认楼层技术产品方案](租户访客默认楼层技术产品方案.md)(文中 **§2**)。 --- ## 8. 风险与待确认项(走查结论) 1. **`PersonResult.defaultFloor` 与 `floorList`**:电梯 `addVisitor` **仅使用 `floorList`**。若产品「默认访问楼层」对应 `defaultFloor` 标量,需核对组织服务是否在 `detail` 中把二者对齐,否则存在**语义偏差**。 2. **`floorIds.get(0)`**:补全后若列表为空,会在取首元素时失败;第三方或组织数据需保证一致性。 3. **`cwos-sdk-event` 等**与本文无关的依赖问题不影响本业务链结论。 4. **访客注册主流程**(表单、审批、写组织人员表)若在三方工程,需在对应仓库继续搜 **`ElevatorPersonService`**、**`addVisitor`**、**`/elevator/person/add/visitor`** 的引用以闭合「从注册到派梯」的端到端文档。 --- ## 9. 文档版本信息 | 项目 | 内容 | |------|------| | 输出路径 | `docs/business/访客注册与派梯楼层业务流程走查.md` | | 依据代码根目录 | `maven-cw-elevator-application`、`maven-intelligent-cwoscomponent` | | 说明 | 外部服务行为以接口契约为准,组织服务内部如何组装 `floorList` 需在 **ninca-common-component-organization** 源码中二次走查 | --- *本文档由代码走查自动生成梳理,若接口路径随部署配置变化,请以运行环境 `application*.yml` 中 `feign.*` 为准。*