Files
starRiverProperty/docs/business/访客邀约与派梯楼层一致性梳理.md
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

21 KiB
Raw Permalink Blame History

访客邀约与派梯楼层一致性梳理

文档用途:把「邀约页展示的楼层」与「电梯开通权限实际生效的楼层」如何在现有代码中对齐,用大白话 + 源码位置一并说明,便于产品、集成与排障。
关联文档访客与电梯业务完整说明租户访客默认楼层技术产品方案租户访客策略迁入组织规格租户访客楼层策略 — 代码重构实施指南(落地步骤与阶段划分)。


1. 一句话原则

所有环节只信同一串楼层 ID:能去哪几层,应在拉被访人详情时由组织侧算清(含租户默认楼层策略时写入 floorList);邀约登记把用户选定写进自己的业务单;派梯时把这份楼层列表放进请求里的 floorIds,电梯就按这一串执行。不要用「人员列表分页」等接口顶替详情里的楼层主数据。


2. 大白话说明

诉求 做法
邀约和派梯不要两套楼层 选人后楼层候选以 PersonService.detail(组织 /component/person/detail)→ floorList 为准;租户「默认只开放某几层」应在组织 **detail 链路内完成策略替代后再返回(规范见 §5,落地状态见 §6)。
邀约单已经定了访问楼层 后续 POST /elevator/person/add/visitor 必须把邀约单里保存的那串楼层放进 floorIds;电梯不会根据邀约单号去数据库查记录——只认本次 HTTP 参数
派梯请求不传楼层 电梯会用 被访人详情里的 floorList 作为生效楼层,不会自动对齐你们库里存的邀约楼层——若要与邀约一致,集成侧应始终传 floorIds

3. 时序图(实现归属:组织侧 / 电梯侧 / 集成侧)

图例

标注 含义
组织侧 maven-ninca-common-component-organizationPersonControllerImgPersonServiceImpl#detail、组织库、(规范中的)租户访客策略服务
电梯侧 maven-cw-elevator-applicationAcsPersonControllerPersonRuleServiceImpl#addVisitor、电梯库 image_rule_ref / zone / 楼栋图库映射等
Intelligent maven-intelligent-cwoscomponentPersonService.detail → Feign 调组织 /component/person/detail
集成侧 第三方 / BFF / 访客业务库:邀约单持久化、派梯前组装 floorIds(电梯代码中无邀约表)

3.0 端到端:访客建档在前、派梯在后(推荐集成顺序)

典型闭环:完成 访客人员建档 并得到 visitorId(平台人员主键),调用 POST /elevator/person/add/visitor。邀约页拉 detail、保存 floorIds 可与建档分步编排;但 addVisitor 必须在建档成功之后调用(电梯侧不写访客主数据,见 §4.4)。

sequenceDiagram
    autonumber
    participant U as 用户 / 前台
    participant BFF as BFF / 集成侧
    participant PS as Intelligent<br/>PersonService.detail
    participant OC as 组织侧<br/>ImgPersonServiceImpl#detail
    participant ORG as 组织侧<br/>访客建档(示意接口)
    participant AC as 电梯侧<br/>AcsPersonController addVisitor

    rect rgb(245,248,250)
        Note over U,OC: ① 邀约:选被访人 + 楼层候选(与 §3.1 同源)
        U->>BFF: 选被访人 hostPersonId
        BFF->>PS: detail(hostPersonId)
        PS->>OC: POST /component/person/detail
        OC-->>BFF: PersonResult.floorList 等
        U->>BFF: 勾选楼层并提交邀约单
        BFF->>BFF: 持久化邀约记录(hostPersonId、floorIds、访期等)
    end

    rect rgb(248,252,255)
        Note over BFF,ORG: ② 访客建档(须先于派梯;具体路径以现场组织/访客模块为准)
        BFF->>ORG: 创建访客人员 / 人像入库(示意)
        Note over ORG: 组织侧或其它访客服务:人员落库,得到 visitorId
        ORG-->>BFF: visitorId(平台 personId
    end

    rect rgb(255,248,245)
        Note over BFF,AC: ③ 派梯开通(visitorId 已存在)
        BFF->>AC: POST /elevator/person/add/visitor<br/>personId=hostPersonId, visitorId, floorIds=邀约单楼层…
        Note over AC: 电梯侧:§3.3 UC-02;不传 floorIds 则 §3.2 UC-01
        AC-->>BFF: CloudwalkResult
    end
区块 实现归属 说明
① 邀约与楼层候选 集成侧 + Intelligent → 组织 detail 楼层权威路径与 §3.1 一致;邀约单仅存 集成侧 业务库
② 访客建档 组织侧为主(示意) 本仓库 addVisitor 不包含建档;返回的 visitorId 即后续规则与图库绑定的主体
③ 派梯 电梯侧 addVisitor + 组织 Feign 绑图库 详见 §4.5;请求体无邀约单号floorIds 须由集成侧按单据填入(对齐 §3.3

3.1 邀约页初始化 — 拉被访人「可访问楼层」主路径(与 UC-01 同源)

组织侧组装 floorList;其中 listByImageId 通过 Feign 回调电梯 HTTP 读取通行规则。

sequenceDiagram
    autonumber
    participant FE as 前端 / BFF<br/>集成侧
    participant PS as Intelligent<br/>PersonService.detail
    participant OC as 组织侧<br/>PersonController / ImgPersonServiceImpl#detail
    participant EF as 电梯 HTTP<br/>passRule/imagelistByImageId
    participant TP as 租户策略(规范)<br/>组织侧 DB / Service

    FE->>PS: detail(personId, businessId)
    Note over PS: Intelligent:路由实现
    PS->>OC: POST /component/person/detail
    Note over OC: 组织侧:查人员、组装机构标签等
    OC->>EF: Feign listByImageId(通行楼层原始列表)
    Note over EF: 电梯侧:凭规则返回 zoneId 列表
    EF-->>OC: AcsPassRuleImageResultDto 列表
    OC->>TP: (可选)命中租户访客策略则替代 floorList
    Note over TP: 组织侧:策略语义见 §5<br/>未落地时仍为 listByImageId 结果(§6
    TP-->>OC: allow_zone_ids / 未启用
    OC-->>PS: PersonResult(含 floorList
    PS-->>FE: 展示可选楼层 / 默认勾选依据
步骤 实现位置
对外 detail 聚合入口 Intelligent → 组织 PersonController
floorList 原始数据来源(通行规则) 电梯侧 HTTP,由组织 ElevatorFeignClient.listByImageId 调用
租户默认楼层「替代」写入 floorList 组织侧(规范:ImgPersonServiceImpl#detail 内;见 §5~§6
邀约单保存用户勾选 集成侧业务库,不在本仓库电梯模块

3.2 派梯 UC-01 — 请求 未带 floorIds(电梯用组织 detail 的 floorList

电梯侧编排;被访人详情仍在 组织侧 计算;写规则、绑图库在 电梯侧 + 组织 Feign

sequenceDiagram
    autonumber
    participant BFF as BFF / 调用方<br/>集成侧
    participant AC as 电梯侧<br/>AcsPersonController
    participant PR as 电梯侧<br/>PersonRuleServiceImpl#addVisitor
    participant PS as Intelligent<br/>PersonService.detail
    participant OC as 组织侧<br/>ImgPersonServiceImpl#detail
    participant DB as 电梯侧 DB<br/>image_rule_ref 等
    participant IS as 组织侧<br/>ImageStorePersonService.batchBindFeign

    BFF->>AC: POST /elevator/person/add/visitor<br/>floorIds 为空
    AC->>PR: addVisitor(param)
    PR->>PS: detail(personId)
    PS->>OC: /component/person/detail
    Note over OC: 组织侧:返回 floorList(§3.1 同源)
    OC-->>PS: PersonResult
    PS-->>PR: floorList
    PR->>PR: effective = personResult.floorListUC-01
    PR->>DB: 按楼层写规则、取楼栋 imageStoreId
    Note over DB: 电梯侧:PersonRuleServiceImpl 本地 Dao
    PR->>IS: batchBind(visitorId, 访期…)
    Note over IS: 组织侧:图库绑定
    IS-->>PR: 成功 / 失败
    PR-->>AC: CloudwalkResult
    AC-->>BFF: 结果
步骤 实现位置
HTTP 入口 电梯侧 AcsPersonController
UC-01 取楼层 电梯侧 PersonRuleServiceImpl 使用 组织 detail 返回的 floorList
PersonService.detail 实现 组织侧 ImgPersonServiceImpl#detail
image_rule_ref、选首层换楼栋 电梯侧 PersonRuleServiceImpl
访客绑图库 组织侧 服务,电梯 Feign 调用

3.3 派梯 UC-02 — 请求 携带 floorIds(与邀约单保存的楼层一致)

与 UC-01 共用同一入口;生效楼层取请求体,不再detail.floorList 替换,但仍会调 detail 做被访人存在性与前置校验。

sequenceDiagram
    autonumber
    participant BFF as BFF / 调用方<br/>集成侧
    participant AC as 电梯侧<br/>AcsPersonController
    participant PR as 电梯侧<br/>PersonRuleServiceImpl#addVisitor
    participant PS as Intelligent<br/>PersonService.detail
    participant OC as 组织侧<br/>detail(仅校验被访人)
    participant DB as 电梯侧 DB
    participant IS as 组织侧<br/>batchBindFeign

    BFF->>AC: POST /elevator/person/add/visitor<br/>floorIds = 邀约单持久化的列表
    Note over BFF: 集成侧:从邀约记录读出楼层写入 body
    AC->>PR: addVisitor(param)
    PR->>PS: detail(personId)
    PS->>OC: /component/person/detail
    OC-->>PR: PersonResultfloorList 本轮可不用于生效集)
    PR->>PR: effective = param.getFloorIds()UC-02
    Note over PR: 电梯侧:不做 floorIds ⊆ detail.floorList 校验(信任调用方)
    PR->>DB: 按 effective 写规则…
    PR->>IS: batchBind…
    IS-->>PR: ok
    PR-->>BFF: 结果
步骤 实现位置
从邀约单带出 floorIds 集成侧
UC-02 分支(effective = param.floorIds 电梯侧 PersonRuleServiceImpl
子集校验(可选) 集成侧 BFF 或后续扩展;当前电梯侧未实现

4. 派梯接口代码走查(电梯应用)

4.1 HTTP 入口

  • 路径POST /elevator/person/add/visitor
  • maven-cw-elevator-application/cw-elevator-application-web/.../AcsPersonController.java
  • 请求体AcsPersonAddVisitorForm → 拷贝为 AcsPersonAddVisitorParamPersonRuleService.addVisitor

4.2 请求体字段(与邀约记录的关系)

字段 含义
personId 被访人在组织侧的人员 ID
visitorId 访客人员 ID(平台 personId
begVisitorTime / endVisitorTime 访期(绑图库 et al.
floorIds 本次开通涉及的楼层 zoneId 列表;由调用方填入。无邀约单号字段——电梯侧不读访客邀约业务表

定义见:cw-elevator-application-web/.../form/AcsPersonAddVisitorForm.java

4.3 生效楼层如何决定(PersonRuleServiceImpl#addVisitor

实现类:cw-elevator-application-service/.../PersonRuleServiceImpl.java

  1. 始终先调 personService.detail(被访人存在性 / 组织侧详情)。失败则直接返回(如 76260531)。
  2. 决定 effective(最终开通的楼层列表)
    • floorIds 非空(实现里称 UC-02):effective = 请求里的 floorIds`,原样使用。
    • floorIds 为空UC-01):effective = personResult.getFloorList()(来自组织 detail)。
  3. 空列表:返回失败(76260531)。
  4. 后续:按 effective 每层写 image_rule_ref、取楼栋图库 imageStoreId、对 visitorId 调组织侧 batchBind、更新组人员引用等。

重要:显式传入 floorIds 时,当前实现不会再与 personResult.getFloorList() 做「子集校验」——楼层是否合规依赖调用方 / BFF;电梯信任请求体。

4.4 业务目标与范围(访客派梯做什么、不做什么)

维度 说明
目标 在已有 访客人员 IDvisitorId)前提下,为本租户本次访问开通 电梯通行规则(电梯库 image_rule_ref),并把访客绑定到 对应楼栋的人脸图库(组织侧 batchBind),使闸机/电梯侧能按楼层放行。
不做 不在此接口创建访客档案;访客姓名、证件、人像建档应在组织/访客业务前置完成并得到 visitorId
租户上下文 businessId 来自调用上下文(与 CloudwalkCallContext.company 一致),与被访人 personId、访客 visitorId 同属该租户数据范围。

4.5 分阶段业务逻辑(与 PersonRuleServiceImpl#addVisitor 对齐)

flowchart LR
  S1[1 被访人 detail] --> S2[2 确定 effective]
  S2 --> S3[3 首层 zone → 楼栋 → imageStoreId]
  S3 --> S4[4 每层写 image_rule_ref<br/>personId=visitorId]
  S4 --> S5[5 batchBind 访期 + updateGroupPersonRef]

下列阶段均在 maven-cw-elevator-application · PersonRuleServiceImpl.addVisitor 中顺序执行。

阶段 1 — 校验被访人可查(组织侧)

  • 构造 PersonDetailParamid = personIdbusinessId = context 租户),调用 personService.detail(经 Intelligent → 组织 ImgPersonServiceImpl#detail)。
  • 成功:得到 PersonResult,后续 UC-01 需要其中的 floorList
  • 失败:透传组织返回的 code / message;若结果为 null 或不成功且无语义,使用 76260531(无可用被访人信息或详情不可用)。
  • 数据为空personResult == null76260531

阶段 2 — 确定本次生效楼层列表 effective

  • 见 §4.3UC-02 用请求 floorIdsUC-01personResult.getFloorList()
  • effective 为空(含 UC-01 时 floorList 为空、或 UC-02 传空列表):76260531

阶段 3 — 解析「楼栋」并确定组织侧图库 imageStoreId(电梯侧 + 空间服务)

  • effective 的第一个元素作为 zoneQueryParam.id,调用 zoneService.page(空间服务)解析 楼层节点
  • 用返回的 ZoneResult.get(0).getParentId() 作为 楼栋 ID,再 deviceImageStoreDao.getByBuildingId(parentId) 得到 imageStoreId
  • 业务含义:多楼层同一次开通时,以列表首层所在楼栋作为本次绑定的图库归属;各 **floorId 仍分别落在对应分区规则上,但 人脸图库绑定指向同一 imageStoreId(由首层楼栋决定)。

阶段 4 — 按楼层写入访客通行规则(电梯侧库)

  • effective 中每个 floorId
    imageRuleRefDao.getDefaultByZoneId(floorId) 取该分区默认规则模板 → 组装 ImageRuleRefAddDtopersonId 填的是 visitorId(访客),写入 image_rule_ref(批量 insertList)。
  • 语义:访客在每个选定楼层上各有一条「挂默认父规则」的通行引用,与被访人自有规则分离。

阶段 5 — 访期内人脸图库绑定与组同步(组织侧 Feign)

  • ImageStorePersonBindParamimageStoreId(阶段 3)、personIds = [visitorId]nullDateIsLongTerm = trueexpiryBeginDate / expiryEndDate 取自请求的 begVisitorTime / endVisitorTime
  • 调用 imageStorePersonService.batchBind(失败则返回 组织侧错误码,电梯透传)。
  • 成功后 updateGroupPersonRef:同一 visitorId + imageStoreId,用于组人员引用同步(具体语义见组织组件实现)。

阶段 6 — 异常兜底

  • 未捕获的 ServiceException:向上抛出。
  • 其他 Exception:包装为 76260530(通用失败)。

4.6 访期参数(begVisitorTime / endVisitorTime

说明
用途 传入组织 batchBind,作为访客在该图库上的 有效期起止(与通行规则配合使用,以现场组织/图库策略为准)。
与楼层关系 访期 不改变 effective 楼层集合;仅影响绑定是否在时间上有效。
nullDateIsLongTerm=true 代码固定传入;具体与空起止如何组合以组织 batchBind 实现为准,集成时建议在测试环境验证边界。

4.7 错误码与典型原因(电梯侧可见)

错误码 典型场景
76260531 detail 失败;被访人 PersonResult 为空;UC-01 时 floorList 为空;或 effective 最终仍为空
76260530 addVisitor 内部未预期的 Exception(如 DB、空指针、空间分页无数据等未单独映射时)。
组织 / Feign 返回码 batchBind 失败时 透传对方 code / message,成功后再执行 updateGroupPersonRef;若 bind 失败则 不会继续组引用更新。
76260521 Controller 层捕获 ServiceException 时映射(多见于其它接口;addVisitor 内多为 fail 码直接返回)。

排障时建议按日志顺序核对:detail → effective → zone 首层 → imageStoreId → 每层 getDefaultByZoneId → batchBind


4.8 业务边界与集成注意

  1. 首层决定楼栋图库:若 effective 中楼层分属不同楼栋,当前实现仅以第一项imageStoreId;产品若要求「多楼栋多图库」,需拆分多次调用或扩展实现(现状未支持单次多楼栋)。
  2. 每层必须有默认规则:某 floorIdgetDefaultByZoneId 若为空,可能在后续组装/插入时异常并落入 76260530,需在数据配置层保证各访客可达层已配置默认规则。
  3. 幂等与重复开通:同一访客重复调用可能产生多条规则引用或组织侧重复绑定行为,以组织与电梯 DAO 约束为准;重要场景建议业务层幂等(例如按邀约单号去重)。
  4. 部分失败:规则已 insertList 后若 batchBind 失败,当前流程 不会自动回滚已插入的规则行(需运维或补偿策略关注)。

5. 与「租户访客默认楼层」策略的关系

  • 规范方向(详见 docs/superpowers/specs/2026-05-06-tenant-visitor-policy-organization-implementation.md):租户允许楼层在组织 ImgPersonServiceImpl#detail 内以 allow_zone_ids 替代写入返回的 floorList;电梯 UC-01 仅透传该 floorList,不在电梯库再与策略表求交。
  • 邀约初始化:应通过 detailfloorList 展示可选楼层,与 UC-01 同源。
  • 邀约单已保存楼层后的派梯:把单据里的楼层写入 floorIds(UC-02),与单据一致;若需防止超范围,应在 BFF 侧校验 floorIds ⊆ detail.floorList(策略替代后)。

6. 实现状态提示(避免误判)

组织侧已实现:TenantVisitorFloorPolicyService 读取组织库 tenant_visitor_floor_policy,在 ImgPersonServiceImpl#detail(及 page(isVisitor))对 floorList / 楼层展示allow_zone_ids 替代。部署前须在组织库执行 docs/sql/organization_tenant_visitor_floor_policy.sql;未建表时策略查询失败会自动回退为 listByImageId 原始结果。详见 租户访客楼层策略-代码重构实施指南


7. 集成 checklist

  • 邀约页初始化楼层:PersonService.detail,不要用人员分页/导出接口当作 floorList 主来源。
  • 邀约保存:持久化用户选定或允许的 楼层 zoneId 列表(与展示同源)。
  • 派梯:从邀约单读出楼层 → 填入 floorIds 调用 /elevator/person/add/visitor;若业务允许「不传楼层」,需知悉此时等价 UC-01,与邀约单无自动对齐
  • 安全(可选):BFF 校验 floorIdsdetail.floorList 的子集(或业务规则允许的超集策略)。
  • 日志:AcsPersonController 已打 requestFloorSize,便于核对是否传了楼层。

8. 源码索引(电梯)

环节 路径
Controller maven-cw-elevator-application/cw-elevator-application-web/.../AcsPersonController.javaaddVisitor
表单 .../form/AcsPersonAddVisitorForm.java
参数 cw-elevator-application-service/.../param/AcsPersonAddVisitorParam.java
核心逻辑(§4.4~§4.8 cw-elevator-application-service/.../PersonRuleServiceImpl.javaaddVisitor
空间分页(首层 → 楼栋) 同模块内 ZoneServicePersonRuleServiceImpl 注入调用)
图库绑定 / 组引用 Feign → 组织 ImageStorePersonServicebatchBindupdateGroupPersonRef

文档版本:与仓库梳理同步;若 addVisitor 行为变更,请同步更新 §4(含 §4.4~§4.8 业务逻辑与错误码)。