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.
This commit is contained in:
hpd840321
2026-05-09 09:00:12 +08:00
commit 7b2bd307f1
7260 changed files with 612980 additions and 0 deletions
@@ -0,0 +1,123 @@
# 访客注册与派梯:被访人、访客与楼层 — 源码级业务流程
> 本文与 `**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**` 字段。