Files
starRiverProperty/docs/superpowers/walkthroughs/2026-05-09-guangfa-28f-hardcoded-design.md
T
hpd840321 42c4a9fd6b docs: mark elevator-side tenant policy SQL as deprecated, add guangfa visitor floor design
- Deprecate elevator-side tenant_visitor_floor_policy SQL files
  (V2 queries only component-organization library)
- Add guangfa 28F visitor floor design spec (table-driven approach A)
- Add complete database ER diagram (14 DBs, 537 tables)
- Add implementation plan for guangfa visitor floor policy
- Code walkthrough docs for visitor floor policy analysis
2026-05-09 23:56:12 +08:00

13 KiB
Raw Blame History

广发基金 28F 硬编码方案 — 组件/模块/位置细化设计

日期: 2026-05-09 分支: feature/guangfa-28f-hardcoded 状态: 方案细化完成,待实施


1. 涉及组件与模块总览

source/backend/
├── ninca-common-component-organization/          ★ 唯一变更组件
│   ├── cwos-component-organization-service/      ★ 代码变更
│   │   └── src/main/java/cn/cloudwalk/service/organization/service/
│   │       └── ImgPersonServiceImpl.java          ★ 唯一变更 Java 文件
│   │
│   ├── cwos-component-organization-starter/      ★ 配置变更
│   │   └── deploy/run-verify/
│   │       └── application.properties             ★ 唯一变更配置文件
│   │
│   └── (其余模块不变: data, interface, web)
│
├── cw-elevator-application/                       ☆ 仅增强日志
│   └── cw-elevator-application-service/
│       └── .../impl/PersonRuleServiceImpl.java    ☆ +2 行日志
│
└── intelligent-cwoscomponent/                     不变 (仅 Feign 接口定义)

2. 变更点详细定位

2.1 模块: cwos-component-organization-service

文件: backend/ninca-common-component-organization/cwos-component-organization-service/src/main/java/cn/cloudwalk/service/organization/service/ImgPersonServiceImpl.java

: cn.cloudwalk.service.organization.service : ImgPersonServiceImpl (1414 行)

位置 A — 依赖注入区 (第 157-158 行后,新增 2 行)

原代码:

157:   @Value("${xhwSixFloorId}")
158:   private String xhwSixFloorId;
159:
160:   private static final String imageBase64 =

改为:

157:   @Value("${xhwSixFloorId}")
158:   private String xhwSixFloorId;
159:
160:   @Value("${gfOrgId}")
161:   private String gfOrgId;
162:
163:   @Value("${gfDefaultFloorId}")
164:   private String gfDefaultFloorId;
165:
166:   private static final String imageBase64 =

位置 B — listByPage() 访客列表分支 (第 354-370 行,插入 else-if)

当前代码 (精确):

354:                 if (imgStorePersonResult.getOrganizationIds().contains(this.xhwId)) {
355:                   imgStorePersonResult.setDefaultChooseFloor(this.xhwDefaultFloorId);
356:                   List<AcsPassRuleImageResultDto> floorInfoList = new ArrayList<>();
357:                   AcsPassRuleImageResultDto resultDto = new AcsPassRuleImageResultDto();
358:                   resultDto.setZoneId(this.xhwDefaultFloorId);
359:                   resultDto.setZoneName("40F");
360:                   floorInfoList.add(resultDto);
361:                   imgStorePersonResult.setFloorInfoList(floorInfoList);
362:                 } else {
363:                   imgStorePersonResult.setDefaultChooseFloor(this.xhwSixFloorId);
364:                   List<AcsPassRuleImageResultDto> floorInfoList = new ArrayList<>();
365:                   AcsPassRuleImageResultDto resultDto = new AcsPassRuleImageResultDto();
366:                   resultDto.setZoneId(this.xhwSixFloorId);
367:                   resultDto.setZoneName("6F");
368:                   floorInfoList.add(resultDto);
369:                   imgStorePersonResult.setFloorInfoList(floorInfoList);
370:                 }

改为:

354:                 if (imgStorePersonResult.getOrganizationIds().contains(this.xhwId)) {
355:                   imgStorePersonResult.setDefaultChooseFloor(this.xhwDefaultFloorId);
356:                   List<AcsPassRuleImageResultDto> floorInfoList = new ArrayList<>();
357:                   AcsPassRuleImageResultDto resultDto = new AcsPassRuleImageResultDto();
358:                   resultDto.setZoneId(this.xhwDefaultFloorId);
359:                   resultDto.setZoneName("40F");
360:                   floorInfoList.add(resultDto);
361:                   imgStorePersonResult.setFloorInfoList(floorInfoList);
362:                 } else if (imgStorePersonResult.getOrganizationIds().contains(this.gfOrgId)) {
363:                   imgStorePersonResult.setDefaultChooseFloor(this.gfDefaultFloorId);
364:                   List<AcsPassRuleImageResultDto> floorInfoList = new ArrayList<>();
365:                   AcsPassRuleImageResultDto resultDto = new AcsPassRuleImageResultDto();
366:                   resultDto.setZoneId(this.gfDefaultFloorId);
367:                   resultDto.setZoneName("28F");
368:                   floorInfoList.add(resultDto);
369:                   imgStorePersonResult.setFloorInfoList(floorInfoList);
370:                   imgStorePersonResult.setIsAcrossDay(Integer.valueOf(0));
371:                   this.logger.info("[GF-28F] listByPage MATCH orgId={} in orgIds={} → default 28F",
372:                       this.gfOrgId, imgStorePersonResult.getOrganizationIds());
373:                 } else {
374:                   imgStorePersonResult.setDefaultChooseFloor(this.xhwSixFloorId);
375:                   List<AcsPassRuleImageResultDto> floorInfoList = new ArrayList<>();
376:                   AcsPassRuleImageResultDto resultDto = new AcsPassRuleImageResultDto();
377:                   resultDto.setZoneId(this.xhwSixFloorId);
378:                   resultDto.setZoneName("6F");
379:                   floorInfoList.add(resultDto);
380:                   imgStorePersonResult.setFloorInfoList(floorInfoList);
381:                 }

注意: 行号偏移 (+5 行,因上方注入区新增)。实际编辑以内容匹配为准。

位置 C — detail() 邀约+派梯核心路径 (第 643-651 行,在策略替代块后插入)

当前代码 (精确):

643:           Optional<List<String>> replacementFloors =
644:               this.tenantVisitorFloorPolicyService.replacementZoneIdsIfPolicyActive(
645:                   result.getOrganizationIds());
646:           if (replacementFloors.isPresent()) {
647:             floorList = new ArrayList<>(replacementFloors.get());
648:             zoneNames = buildCommaSeparatedFloorNames(businessId, floorList);
649:           }
650:           result.setFloorNames(zoneNames);
651:           result.setFloorList(floorList);

改为:

643:           Optional<List<String>> replacementFloors =
644:               this.tenantVisitorFloorPolicyService.replacementZoneIdsIfPolicyActive(
645:                   result.getOrganizationIds());
646:           if (replacementFloors.isPresent()) {
647:             floorList = new ArrayList<>(replacementFloors.get());
648:             zoneNames = buildCommaSeparatedFloorNames(businessId, floorList);
649:           }
650:           // 广发基金: 邀约 + UC-01 派梯 floorList 限制为 28F
651:           if (!CollectionUtils.isEmpty(result.getOrganizationIds())
652:                   && result.getOrganizationIds().contains(this.gfOrgId)) {
653:               List<String> originalFloors = new ArrayList<>(floorList);
654:               floorList = Collections.singletonList(this.gfDefaultFloorId);
655:               zoneNames = "28F";
656:               this.logger.info("[GF-28F] detail MATCH orgId={} in orgIds={} → floor restricted: {}→[28F]",
657:                       this.gfOrgId, result.getOrganizationIds(), originalFloors);
658:           } else {
659:               this.logger.debug("[GF-28F] detail NO-MATCH orgId={} not in orgIds={}",
660:                       this.gfOrgId, result.getOrganizationIds());
661:           }
662:           result.setFloorNames(zoneNames);
663:           result.setFloorList(floorList);

注意: Collections.singletonList 需要 import java.util.Collections; — 检查是否已存在(当前代码 listByPage 中使用了 Collections.singletonListimport 应已存在)。

位置 D — detail() 入口日志 (在第 600 行附近,detail() 方法体内)

detail() 方法体的早期(如第 570-600 行区间,根据实际方法体定位),新增:

this.logger.info("[GF-DETAIL] entry personId={} businessId={} orgIds={}",
    param.getId(), businessId, result.getOrganizationIds());

位置 E — detail() listByImageId 返回日志 (在第 630 行附近)

listByImageId 调用成功后、循环组装 floorList 前:

this.logger.info("[GF-DETAIL] listByImageId returned {} zones: {}",
    acsPassRuleImageResultDtoList.size(),
    acsPassRuleImageResultDtoList.stream()
        .map(AcsPassRuleImageResultDto::getZoneId).collect(Collectors.toList()));

2.2 模块: cw-elevator-application-service

文件: backend/cw-elevator-application/cw-elevator-application-service/src/main/java/cn/cloudwalk/elevator/person/impl/PersonRuleServiceImpl.java

: cn.cloudwalk.elevator.person.impl : PersonRuleServiceImpl

位置 F — addVisitor() 日志增强 (第 187-194 行附近)

当前代码 (精确):

187:             boolean callerProvidedFloors = !CollectionUtils.isEmpty(param.getFloorIds());
188:             if (callerProvidedFloors) {
189:                 effective = param.getFloorIds();
190:                 this.logger.info("UC-02:调用方显式楼层 effective={}", effective);
191:             } else {
192:                 effective = personResult.getFloorList();
193:                 if (CollectionUtils.isEmpty(effective)) {
194:                     this.logger.warn("UC-01:被访人 detail.floorList 为空 personId={}", param.getPersonId());

改为:

187:             boolean callerProvidedFloors = !CollectionUtils.isEmpty(param.getFloorIds());
188:             if (callerProvidedFloors) {
189:                 effective = param.getFloorIds();
190:                 this.logger.info("[GF-ADDV] UC-02 effective={}", effective);
191:             } else {
192:                 effective = personResult.getFloorList();
193:                 if (CollectionUtils.isEmpty(effective)) {
194:                     this.logger.warn("[GF-ADDV] UC-01 floorList empty personId={}", param.getPersonId());

2.3 模块: cwos-component-organization-starter (配置)

文件: backend/ninca-common-component-organization/cwos-component-organization-starter/deploy/run-verify/application.properties

位置: 第 172 行后(xhwSixFloorId 之后),新增 2 行:

# 第 170-172 行 (现有):
xhwId=21474e012cd14e26bc62771873b22562
xhwDefaultFloorId=605560547135455232
xhwSixFloorId=605560541473144832

# 第 173-174 行 (新增):
gfOrgId=488b8ad049bb43408a6fbcc50bcb89ac
gfDefaultFloorId=605560545117995008

2.4 数据层: 禁用原表驱动策略

数据库: component-organization (组织库) : tenant_visitor_floor_policy

UPDATE tenant_visitor_floor_policy
SET enabled = 0,
    remark = CONCAT(remark, ' [DISABLED 2026-05-09: migrated to hardcoded 28F in ImgPersonServiceImpl]'),
    updated_at = UNIX_TIMESTAMP(NOW()) * 1000
WHERE id = 'gf_vstr_policy_guangfa_fund_001x'
  AND enabled = 1;

数据库: cw-elevator-application (电梯库,如果存在同步表)

-- 仅当电梯库也有 tenant_visitor_floor_policy 表时执行
UPDATE tenant_visitor_floor_policy
SET enabled = 0
WHERE id = 'gf_vstr_policy_guangfa_fund_001x'
  AND enabled = 1;

3. 不变更清单

组件 模块 文件 原因
intelligent-cwoscomponent interface PersonService.java Feign 接口定义,不变
intelligent-cwoscomponent rest PersonFeignClient.java HTTP 路径映射,不变
ninca-common-component-organization data TenantVisitorFloorPolicyMapper.java 仍服务物业策略,不删
ninca-common-component-organization service TenantVisitorFloorPolicyService.java 仍服务物业策略,不删
ninca-common-component-organization web PersonController.java REST 入口,不变
ninca-common-component-organization starter bootstrap.properties 启动配置,不变
cw-elevator-application web AcsPersonController.java REST 入口,不变
cw-elevator-application data ImageRuleRefDao.java DAO 层,不变
scripts/test-env config component-org.properties 测试模板(最小配置),不变
ninca-common-component-organization releases/ 所有 releases/ 下文件 历史发布快照,不变

4. 汇总

# 组件 Maven 模块 文件 变更类型 行数
A component-org cwos-component-organization-service ImgPersonServiceImpl.java 注入 @Value ×2 +4
B component-org cwos-component-organization-service ImgPersonServiceImpl.java listByPage else-if 分支 +11
C component-org cwos-component-organization-service ImgPersonServiceImpl.java detail() floorList 截断 +13
D component-org cwos-component-organization-service ImgPersonServiceImpl.java detail() 入口日志 +2
E component-org cwos-component-organization-service ImgPersonServiceImpl.java listByImageId 返回日志 +3
F elevator-app cw-elevator-application-service PersonRuleServiceImpl.java addVisitor 日志前缀 ~0 (替换)
component-org cwos-component-organization-starter application.properties 配置 ×2 +2
(数据库) tenant_visitor_floor_policy UPDATE enabled=0 1 行

总计: 2 个组件, 3 个模块, 3 个文件, ~35 行新增