Files
starRiverProperty/backend/cw-elevator-application/cw-elevator-application-service/docs/08-visitor-registration-and-elevator-auth.md
T
hpd840321 7b2bd307f1 Initial commit: reorganized source tree
- backend/: 13 Maven modules (cw-elevator-application, cloudwalk-cloud, intelligent-cwoscomponent, ninca-crk, etc.)
- frontend/: 4 Vue projects (elevator-front, cwos-portal, alarm-front, front_acs) + decompiled + scripts
- scripts/: build, test-env, tools (Docker Compose, service templates, API parity)
- docs/: AGENTS.md, superpowers specs, architecture docs
- .gitignore: standard Java/Maven exclusions

Moved from legacy maven-*/ root layout to backend/ organized structure.
2026-05-09 09:56:45 +08:00

18 KiB
Raw Blame History

访客与电梯业务:注册/登记与派梯授权完整说明

本文档覆盖 组织组件maven-ninca-common-component-organization)、智能组件 Feign 路由maven-intelligent-cwoscomponent)与 电梯应用maven-cw-elevator-application)中与「访客派梯」相关的可追踪路径;区分 访客主数据登记POST /elevator/person/add/visitor 派梯授权。文中源码路径均相对于各 Maven 模块仓库根目录。


1. 概念与边界

概念 通常含义 在本项目中的落点
访客主数据登记/注册 在标准访客/一卡通中录入档案 不在电梯应用内完成完整登记 UI;人员以 visitorId(平台 personId 等形式存在于外部服务。
电梯侧「访客派梯授权」 在已有访客人员 ID 前提下写入通行规则、绑定图库、访期 PersonRuleServiceImpl#addVisitorPOST /elevator/person/add/visitorAcsPersonController)。
通行记录「是否访客」打标 识别流水写库时标记访客/被访人 AcsElevatorRecordServiceImpl#add → CRK /intelligent/three/visitor/record/query(见第 8 节)。

2. 组件关系总览

访客邀约页、电梯 addVisitorfloorList 语义上应对齐:二者都应依赖 PersonService.detailPersonResult.floorList(经 Intelligent 转发到组织 POST /component/person/detail)。组织组装 floorList 时会 Feign 回调电梯(见 §3.3):电梯 image_rule_ref 里已有的人员—楼层规则,经 /elevator/passRule/image 转成 zoneId 列表,再写回组织的 floorList

flowchart LR
  subgraph fe["前端 / BFF / 第三方"]
    UI[访客邀约 / 派梯调用方]
  end
  subgraph intelligent["maven-intelligent-cwoscomponent"]
    PS[PersonService / RestPersonServiceImpl]
    PFC[PersonFeignClient → /component/person]
  end
  subgraph org["maven-ninca-common-component-organization"]
    PC[PersonController /component/person]
    IMG[ImgPersonServiceImpl]
    EF[ElevatorFeignClient → /elevator/passRule/image]
  end
  subgraph elevator["maven-cw-elevator-application"]
    AC[AcsPersonController /elevator/person/add/visitor]
    PR[PersonRuleServiceImpl addVisitor]
    IRR[ImageRuleRefDao / ZoneService / DeviceImageStoreDao]
    IS[ImageStorePersonService Feign 绑定图库]
  end
  UI --> PS
  PS --> PFC --> PC --> IMG
  IMG --> EF
  UI --> AC --> PR
  PR --> PS
  PR --> IRR
  PR --> IS

3. 组织侧:被访人 detailfloorList(邀约页 / UC-01 的数据源)

3.1 HTTP 入口与实现类

说明
路径 POST /component/person/detail
Controller cwos-component-organization-web · PersonController#detail
服务 ImgStorePersonService#detailImgPersonServiceImpl#detail

对外契约返回 CloudwalkResult<ImgStorePersonGetResult>;经 Intelligent PersonFeignClient 解码为 PersonResult(字段名一致部分落入 floorList,电梯 addVisitor 仅消费 PersonResult.getFloorList())。

3.2 ImgPersonServiceImpl#detail 处理顺序(与源码一致)

步骤 做什么 floorList 的关系
1 selectByPrimaryKey 查组织库人员 无此人则 data 可为 null(见下)
2 可选 defaultFloorzoneFeignClient.findZonelist floorName 展示不等于下面得到的 floorList
3 可选 vehicleFeignClient.getVehicleIds 与楼层列表无关
4 getImgStorePersonResults 得到 organizationIdslabelIds,供 §3.3 调用电梯
5 elevatorFeignClient.listByImageId(...)Feign,语义见 §3.3 唯一写入 floorList / floorNames(在返回码成功且进入分支时)
6 (规范)租户 allow_zone_ids 替代 当前未实现,运行态 floorList = 步骤 5 结果
7 portalUserService.query 填创建/更新人姓名 与楼层无关
  • 查无此人result 仍为 null,接口 CloudwalkResult.success(null);电梯 addVisitorpersonResult == null76260531
  • 步骤 5 失败或未进入分支floorList 不会被赋值(可能为 null / 未覆盖);UC-01 addVisitor76260531

3.3 组织 Feign listByImageId ↔ 电梯 HTTP ↔ 真实落库(避免混淆)

这一块名字容易混:组织侧 Java 方法叫 listByImageId,并不等于电梯里另一个 DAO 方法 listByImageId

3.3.1 组织侧调用(入口)

说明
组织代码 ElevatorFeignClient#listByImageIdcwos-component-organization-service/.../feign/ElevatorFeignClient.java
HTTP POST {elevator-base}/elevator/passRule/imageFeign name 一般为 feign.elevator.name,如 elevator-app
请求体 AcsPassRuleImageFormpersonIdbusinessIdincludeOrganizationsincludeLabels(对应组织 detailgetImgStorePersonResults 填好的档案字段)

3.3.2 电梯侧实际执行(与「另一个 listByImageId」区分)

易混点 说明
本链路 AcsPassRuleController(类上 @RequestMapping("/elevator/passRule"))方法 @RequestMapping("/image")ImageRuleRefServiceImpl#listByPersonInfoImageRuleRefDao#listByPersonInfoImageRuleRefMapper.xml#listByPersonInfo
勿混 AcsPassRuleServiceImpl#listByImageIdacsPassRuleDao.listByImageId 查的是 it_acs_pass_rule,按 imageStoreIds 过滤——不是组织 Feign 这条 HTTP 路径当前走的实现。

3.3.3 listByPersonInfo 在查什么(业务语义)

  • :电梯库 image_rule_ref(人员与楼层通行规则引用:访客 addVisitor 写入的也是这张表的语义同类数据)。
  • 返回字段DISTINCT zone_id, zone_name(映射 AcsPassRuleImageResultDto)。
  • 查询逻辑(摘要)
    • 至少包含:person_id = 被访人person_delete = 0 的规则所对应的楼层;
    • includeOrganizations / includeLabels 非空,SQL 中另有 OR 分支,按机构/标签关联规则补充楼层,并排除 person_delete = 1 等条件下已标记删除的 zone_id(详见 ImageRuleRefMapper.xml 全文)。
    • 排序order by CAST(zone_name as signed)(按楼层名称可解析的数字排序)。

因此:组织 detail 里的 floorList,本质上是「电梯侧已为该被访人(及档案上的机构/标签)开通过的楼层 zoneId 列表」的只读投影,不是组织库自己存的楼层字段。

3.3.4 组织如何把返回值写进 detail

仅当 images.getCode() 等于 00000000(成功)时,ImgPersonServiceImpl#detail 才遍历 images.getData(),把每条 zoneId 依次 floorList.add,并把 zoneName 拼成逗号分隔的 floorNames
若 Feign 失败超时、或业务码非 00000000不会进入该分支floorList 保持未赋值 → 下游 UC-01 常 76260531

3.3.5 与「访客派梯 addVisitor」的数据关系(闭环)

环节 数据
被访人已在电梯侧挂规则 image_rule_ref 中有 person_id=被访人 等记录
组织 detail listByImageId(Feign) → /passRule/imagelistByPersonInfo 读出 zone 列表PersonResult.floorList
电梯 addVisitor UC-01 再次 PersonService.detail,用同一 floorList 作为 effective,再 写入访客image_rule_ref

所以:floorList 不是「组织凭空算的」,而是「电梯规则表里已有被访人楼层」经 /passRule/image 汇总后的结果;租户策略若要做「替代」,应在步骤 §3.2 第 6 步floorList,而不是再发明一套与 image_rule_ref 无关的算法(除非产品另行约定)。


3.4 时序图 — 组织侧「单人 detail」(含回调电梯)

sequenceDiagram
  autonumber
  participant Caller as 调用方 / Intelligent
  participant PC as PersonController
  participant IMG as ImgPersonServiceImpl
  participant Zone as ZoneFeignClient
  participant Veh as VehicleFeignClient
  participant Elev as ElevatorFeignClient<br/>方法名 listByImageId
  participant EA as 电梯 AcsPassRuleController<br/>/elevator/passRule/image<br/>→ ImageRuleRefService listByPersonInfo

  Caller->>PC: POST /component/person/detail
  PC->>IMG: detail(param, context)
  IMG->>IMG: selectByPrimaryKey(personId)
  opt defaultFloor 非空
    IMG->>Zone: findZonelist
    Zone-->>IMG: ZoneResult
  end
  IMG->>Veh: getVehicleIds
  Veh-->>IMG: vehicle ids
  IMG->>IMG: getImgStorePersonResults → organizationIds, labelIds
  IMG->>Elev: listByImageId(AcsPassRuleImageForm)
  Elev->>EA: POST /elevator/passRule/image
  EA->>EA: listByPersonInfo → SQL image_rule_ref
  EA-->>Elev: List zoneId/zoneName
  Elev-->>IMG: CloudwalkResult code=00000000 + list
  IMG->>IMG: setFloorList / setFloorNames(策略替代:待实现)
  IMG-->>PC: ImgStorePersonGetResult
  PC-->>Caller: CloudwalkResult

4. 电梯侧:addVisitor 业务步骤

4.1 对外入口

HTTP POST /elevator/person/add/visitor
Controller cw-elevator-application-web · AcsPersonController#addVisitor
实现 PersonRuleServiceImpl#addVisitor

4.2 与源码一致的执行顺序

阶段 1 — 被访人详情(必经)

  • 组装 PersonDetailParamid = param.getPersonId()(被访人),businessId = context.getCompany().getCompanyId()
  • personService.detail(detailParam, context) → Intelligent PersonFeignClient → 组织 POST /component/person/detail
  • 失败或 personResult == null → 返回失败码(常见 76260531)。

阶段 2 — 生效楼层 effectiveUC 分流)

  • callerProvidedFloors = !CollectionUtils.isEmpty(param.getFloorIds())
    • trueUC-02effective = param.getFloorIds()使用 personResult.getFloorList() 作为列表来源;仍已执行阶段 1,用于保证被访人可查)。
    • falseUC-01effective = personResult.getFloorList()76260531

阶段 3 — 再次空集校验 — 防御 effective 仍为空

阶段 4 — 楼栋与图库

  • zoneService.page:查询 effective.get(0) 对应 ZoneResult,取 parentId 作为楼栋。
  • deviceImageStoreDao.getByBuildingId(parentId)imageStoreId(后续 batchBind / updateGroupPersonRef 均绑定该图库)。

阶段 5 — 每层通行规则引用

  • 对每个 floorIdimageRuleRefDao.getDefaultByZoneId(floorId) 取默认父规则,拼装 ImageRuleRefAddDtopersonId = visitorId),imageRuleRefDao.insertList

阶段 6 — 图库与分组

  • ImageStorePersonBindParamimageStoreIdpersonIds=[visitorId]、访期 begVisitorTime/endVisitorTime
  • imageStorePersonService.batchBindFeign 至 Intelligent/组织图库能力)。
  • updateGroupPersonRef 同步组人员引用。

异常 — 未捕获的运行异常包装 76260530batchBind 失败透传下游码。

4.3 租户策略语义(与仓库规范一致)

电梯 注入 TenantVisitorFloorPolicyDaoaddVisitor 内做 floorList ∩ allow。租户 allow_zone_ids 替代须落在 组织 detail(见第 3.2 节「待实现」说明)。


5. 时序图 — 电梯 addVisitorUC-01:不传 floorIds

sequenceDiagram
  autonumber
  participant C as 调用方
  participant API as AcsPersonController
  participant PR as PersonRuleServiceImpl
  participant PS as PersonService Intelligent
  participant Org as 组织 /component/person/detail
  participant Z as ZoneService
  participant DIS as DeviceImageStoreDao
  participant IRR as ImageRuleRefDao
  participant IS as ImageStorePersonService

  C->>API: POST /elevator/person/add/visitorfloorIds 空)
  API->>PR: addVisitor(param, context)
  PR->>PS: detail(personId, businessId)
  PS->>Org: Feign POST detail
  Org-->>PS: PersonResult.floorList
  PS-->>PR: PersonResult
  Note over PR: effective = floorList;空则 76260531
  PR->>Z: page(首 floorId)
  Z-->>PR: ZoneResult.parentId
  PR->>DIS: getByBuildingId(parentId)
  DIS-->>PR: imageStoreId
  loop 每个 floorId
    PR->>IRR: getDefaultByZoneId + insertList
  end
  PR->>IS: batchBind(visitorId, 访期, imageStoreId)
  IS-->>PR: 成功
  PR->>IS: updateGroupPersonRef
  PR-->>API: CloudwalkResult Boolean
  API-->>C: 结果

6. 时序图 — 电梯 addVisitorUC-02:显式 floorIds

sequenceDiagram
  autonumber
  participant C as 调用方
  participant API as AcsPersonController
  participant PR as PersonRuleServiceImpl
  participant PS as PersonService Intelligent
  participant Z as ZoneService
  participant DIS as DeviceImageStoreDao
  participant IRR as ImageRuleRefDao
  participant IS as ImageStorePersonService

  C->>API: POST /elevator/person/add/visitorfloorIds 非空)
  API->>PR: addVisitor
  PR->>PS: detail(被访人)(校验被访人存在)
  PS-->>PR: PersonResult
  Note over PR: effective = param.floorIds(不用 detail.floorList
  PR->>Z: page(首 floorId)
  Z-->>PR: parentId
  PR->>DIS: getByBuildingId
  DIS-->>PR: imageStoreId
  loop 每层
    PR->>IRR: 默认规则 + insertList visitorId
  end
  PR->>IS: batchBind + updateGroupPersonRef
  PR-->>API: success

7. 活动图(addVisitor 分支汇总)

flowchart TD
  Start([POST /elevator/person/add/visitor]) --> D[PersonService.detail 被访人]
  D --> E{success 且 PersonResult 非空?}
  E -- 否 --> E1[76260531 等]
  E -- 是 --> F{param.floorIds 非空?}
  F -- 是 UC-02 --> G[effective = floorIds]
  F -- 否 UC-01 --> H{personResult.floorList 非空?}
  H -- 否 --> E1
  H -- 是 --> G2[effective = floorList]
  G --> K[zone.page 首层 → imageStoreId]
  G2 --> K
  K --> L[逐层 ImageRuleRef 挂 visitorId]
  L --> M[batchBind + updateGroupPersonRef]
  M --> Ok([true])

8. 主线 B:通行记录落库时「访客身份」认定(非派梯)

场景:设备上报识别结果写入电梯通行记录。

实现AcsElevatorRecordServiceImpl#add 在写库前 RestTemplateUtil.posthttp://{ninca-crk-std}/intelligent/three/visitor/record/query;返回非空则 isVisitor=1 并回填被访人。该路径 不创建 访客主档,与第 3~7 节派梯链路独立。

sequenceDiagram
  participant R as AcsElevatorRecordServiceImpl
  participant HTTP as CRK three/query
  participant DAO as 电梯记录 DAO
  R->>HTTP: visitorId + tenant
  HTTP-->>R: 访客档案或空
  R->>DAO: add(含 isVisitor, interviewee)

9. 其它:MQTT 访客标签

MqttServiceImpl 若识别流水 personLabelIds 含 "1"MQTT JSON 置 isVisitor=true标签维度,与档案访客不同)。


10. 错误与日志索引(addVisitor

场景
detail 失败 / 被访人无数据 / UC-01 floorList 为空 / effective 仍为空 76260531
其它未预期异常 76260530
batchBind 失败 透传下游 code/message

日志关键字根据被访人添加访客派梯权限UC-01 / UC-02最终生效楼层访客添加派梯权限远程调用绑定人员图库


11. 关键源码索引

层级 路径
电梯 Controller cw-elevator-application-web/.../person/controller/AcsPersonController.java
电梯派梯 cw-elevator-application-service/.../person/impl/PersonRuleServiceImpl.java addVisitor
Intelligent Feign intelligent-cwoscomponent-rest/.../person/feign/PersonFeignClient.java/component/person/detail
组织 Controller cwos-component-organization-web/.../controller/PersonController.java /detail
组织 detail 实现 cwos-component-organization-service/.../ImgPersonServiceImpl.java detail
组织→电梯 Feign cwos-component-organization-service/.../feign/ElevatorFeignClient.java(方法 listByImageIdPOST /elevator/passRule/image
电梯「按人员信息列楼层」 cw-elevator-application-web/.../passrule/controller/AcsPassRuleController.java /image
电梯实现 cw-elevator-application-service/.../passrule/impl/ImageRuleRefServiceImpl.java listByPersonInfo
电梯 SQL cw-elevator-application-data/.../mapper/ImageRuleRefMapper.xml listByPersonInfo(表 image_rule_ref
(勿与本链路混淆) AcsPassRuleServiceImpl#listByImageId / it_acs_pass_rule不同入口
通行访客打标 cw-elevator-application-service/.../record/impl/AcsElevatorRecordServiceImpl.java add

12. 规范交叉引用

  • 租户楼层策略 替代 语义与迁移边界:docs/superpowers/specs/2026-05-06-tenant-visitor-policy-organization-implementation.md

说明:组织 detail 内租户策略替代若未落地,UC-01 的 floorList 完全等于 /elevator/passRule/imagelistByPersonInfo 返回的 zone 列表(经 Feign listByImageId 写入 ImgStorePersonGetResult)。与产品「仅开放接待层」不一致时,应排查 image_rule_ref 数据、该接口 成功与否,以及 组织侧策略替代是否已实现。