Files
starRiverProperty/docs/testing/visitor-registration-business-flow.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

124 lines
6.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 访客注册与派梯:被访人、访客与楼层 — 源码级业务流程
> 本文与 `**cw-elevator-application-service/docs/08-visitor-registration-and-elevator-auth.md**` 互补:08 偏「接口步骤清单」,本文强调 **被访人 / 访客 / 楼层** 三者关系与 **类方法落点**。电梯应用不负责完整「访客档案登记 UI」,但 `**add/visitor` 显式依赖两条人员主键**。
---
## 1. 术语(避免混用)
| 称呼 | HTTP / 参数字段 | 含义 | 数据哪里来 |
| ----------- | ----------------------------- | ----------------------------------------------------- | -------------------------------------------- |
| **访客** | `visitorId` | 已在**平台人员体系**存在的档案 ID(登记/同步发生在访客业务或 CWOS 组件侧) | 组织库 `cw_is_person` 等;常打 **「访客」标签** |
| **被访人(员工)** | `personId` | **接待访客的员工**,用于在 **未传 `floorIds`** 时拉取其可派梯楼层 | 同库在职人员,与 `cw_is_person_organization_ref` 挂组织 |
| **生效楼层** | 内部 `param.floorIds`(可能由服务端改写) | 最终写入 `**image_rule_ref`**、绑定图库的 **楼层 zoneId 列表**(雪花串) | 见 §3 |
**易错点**`personId` **不是**访客 ID,而是**被访员工** ID。
---
## 2. 端到端角色关系(产品语义)
```mermaid
flowchart LR
subgraph 登记域["登记域(多在外部/组件)"]
V["访客档案 visitorId"]
H["员工档案 personId\n被访人"]
end
subgraph 电梯域["电梯应用"]
A["POST /elevator/person/add/visitor"]
R["image_rule_ref\npersonId=visitorId"]
end
H -->|Feign detail 取 floorList| A
V --> A
A --> R
```
- **访客要访问的是员工(被访人)** → API 上体现为:用 `**personId`** 定位被访人,用 `**visitorId**` 定位访客档案。
- **电梯侧写规则**:按 `**visitorId`** 在各区写入规则引用(`ImageRuleRefAddDto.personId = visitorId`),**不是**写在被访人名下。
---
## 3. 楼层从哪里来(核心业务逻辑)
实现类:`**PersonRuleServiceImpl#addVisitor`**`person/impl/PersonRuleServiceImpl.java`)。
### 3.1 调用方 **传入非空 `floorIds`**
- **跳过**被访人详情与租户策略整段。
- **直接使用**调用方给出的楼层列表作为 `**effectiveFloors`**(需非空,否则 `76260531`)。
- **责任**:楼层合法性、是否仍应受租户策略约束,由调用方或上游 BFF 保证(产品文档另有说明)。
### 3.2 调用方 **未传 / 空 `floorIds`(常见访客路径)**
1. `**PersonService#detail`**Feign,组件 `**/component/person/detail**`
- 入参:`PersonDetailParam.id = param.getPersonId()`**被访人**)、`businessId = context.getCompany().getCompanyId()`
- 出参:`**PersonResult.getFloorList()`** → 记为 `**hostFloors**`(字符串列表,元素为电梯域认可的 **zoneId**,雪花形态,与 `**image_rule_ref.zone_id`** 一致)。
2. **失败分支**
- detail 失败 / 无数据 / `**hostFloors` 为空** → `**76260531`**(无可用楼层依据)。
3. **租户默认策略(可选收窄)**
- `**TenantVisitorFloorPolicyDao#selectEnabledTenantDefault(companyId)`** → 表 `**tenant_visitor_floor_policy**`
- 条件:`enabled=1``policy_type=INTERSECT_ALLOWLIST`、租户级默认(`building_id` 空)。
- `**allow_zone_ids**`JSON 字符串数组,解析为 `**allowSet**`
- **生效楼层**`**effectiveFloors = hostFloors 按原顺序过滤,仅保留 ∈ allowSet`**`intersectPreserveHostOrder`)。
- 若交集 **为空**`**76260532`**(与租户允许楼层无交集)。
4. **首层 → 楼栋 → 图库**
-`**effectiveFloors.get(0)`**`**ZoneService#page**``**ZoneResult**`,再 `**deviceImageStoreDao.getByBuildingId(首层 parentId)**``**imageStoreId**`
5. **逐层写规则 + 绑访客图库**
- 对每个 floorId`**imageRuleRefDao.getDefaultByZoneId`** → 组装 `**ImageRuleRefAddDto**``**personId = param.getVisitorId()**`(访客)。
- `**imageStorePersonService.batchBind**`:把 **访客** 绑到该楼栋图库,访期 `**begVisitorTime` / `endVisitorTime`**。
- `**updateGroupPersonRef**`:同步组人员引用。
### 3.3 小结公式
- **无显式 floorIds 时**
\text{effectiveFloors} = \begin{cases}
\text{hostFloors} & \text{无启用策略或 allow 为空}
\text{hostFloors} \cap \text{allowzoneids} & \text{策略启用且 allow 非空}
\end{cases}
- **交集为空** → `**76260532`****hostFloors 为空** → `**76260531`**。
---
## 4. 与「访客注册」一词的边界
| 步骤 | 是否在电梯仓实现 |
| ------------------------------------ | ------------------ |
| 访客姓名/证件/人脸建档、预约单 | **否**(外部系统 / 组件) |
| 拿到 `**visitorId` + 被访员工 `personId`** | 前置条件 |
| **派梯授权**(写规则 + 绑图库) | **是**`addVisitor` |
因此:**完整「访客注册」业务** = 外部登记 + **本接口授权**;本文楼层逻辑仅覆盖授权链。
---
## 5. 关键源码索引
| 步骤 | 类 / 方法 |
| ------- | ---------------------------------------------------------- |
| HTTP 入口 | `AcsPersonController``/elevator/person/add/visitor` |
| 聚合逻辑 | `PersonRuleServiceImpl#addVisitor` |
| 被访人楼层 | `PersonService#detail``PersonResult#getFloorList` |
| 租户策略 | `TenantVisitorFloorPolicyDao#selectEnabledTenantDefault` |
| 策略表 | `tenant_visitor_floor_policy` |
| 规则落库 | `ImageRuleRefDao#getDefaultByZoneId` / `insertList` |
| 图库 | `ImageStorePersonService#batchBind``updateGroupPersonRef` |
---
## 6. 测试数据在建模上的要求
- **每条用例**应能指向:**组织 / 部门**、**一名被访员工(host**、**一名访客(visitor**。
- 导出脚本从 DB 解析:**员工** = 部门下在职人员;**访客** = 带「访客」标签的人员池,按套件 `**business_id`** 过滤,与用例 **轮询配对**(避免同源语义缺失)。
- 详见 `**tools/visitor_floor_verification/config/test_matrix.json`** 与导出快照 `**host_employee` / `visitor_for_api**` 字段。