diff --git a/docs/superpowers/specs/2026-04-23-staff-family-enterprise-relation-design.md b/docs/superpowers/specs/2026-04-23-staff-family-enterprise-relation-design.md new file mode 100644 index 00000000..d0cc389f --- /dev/null +++ b/docs/superpowers/specs/2026-04-23-staff-family-enterprise-relation-design.md @@ -0,0 +1,544 @@ +# 员工亲属实体关联维护设计 + +## 1. 背景 + +当前信息维护中的员工实体关联维护模块,底层使用 `ccdi_staff_enterprise_relation` 表,页面、接口、导入能力均已完整存在,但现有语义以“员工本人”为主对象。 + +本次需求要求将该模块整体切换为“员工亲属与实体的关联关系维护”: + +- 主对象从员工本人切换为员工亲属 +- 员工亲属必须来源于员工亲属关系维护中已维护的亲属 +- 新增和导入时仅允许使用员工亲属关系中状态为有效的亲属 +- 列表需要展示亲属身份证、亲属名称、亲属关联的员工 +- 现有导入能力同步切换为员工亲属实体关联导入 +- 若亲属关系后续被改为无效,则该亲属名下已有实体关联自动更新为无效 + +本次设计按最短路径实施,不新增平行模块,不做兼容性方案,不额外扩展用户未提出的兜底逻辑。 + +## 2. 目标与范围 + +### 2.1 目标 + +在保留现有员工实体关联模块入口、表结构和基本交互骨架的前提下,将其业务语义改造为员工亲属实体关联维护,并保证新增、编辑、查询、详情、导入、失效联动链路闭环。 + +### 2.2 本次范围 + +- 改造员工实体关联模块的查询、详情、新增、编辑、导入语义 +- 接入员工亲属关系表作为唯一合法亲属来源 +- 页面支持按亲属身份证模糊搜索有效亲属并自动带出信息 +- 列表和详情展示亲属名称及关联员工 +- 员工亲属关系失效时,自动将对应实体关联更新为无效 + +### 2.3 非本次范围 + +- 不新增独立“员工亲属实体关联”新表 +- 不迁移旧的员工本人实体关联历史数据 +- 不设计旧数据兼容展示逻辑 +- 不增加亲属关系失效后自动恢复实体关联为有效的反向联动 +- 不扩展用户未提出的新查询条件、新统计能力或新菜单入口 + +## 3. 现状分析 + +### 3.1 现有实体关联模块 + +当前模块主要位置如下: + +- 后端控制器:`ccdi-info-collection/.../controller/CcdiStaffEnterpriseRelationController.java` +- 后端服务:`ccdi-info-collection/.../service/impl/CcdiStaffEnterpriseRelationServiceImpl.java` +- 查询 Mapper:`ccdi-info-collection/.../mapper/info/collection/CcdiStaffEnterpriseRelationMapper.xml` +- 前端页面:`ruoyi-ui/src/views/ccdiStaffEnterpriseRelation/index.vue` +- 前端 API:`ruoyi-ui/src/api/ccdiStaffEnterpriseRelation.js` + +当前主表为 `ccdi_staff_enterprise_relation`,核心字段包括: + +- `person_id`:当前语义为员工身份证号 +- `social_credit_code` +- `enterprise_name` +- `relation_person_post` +- `status` +- `remark` +- `data_source` + +当前列表通过 `ccdi_base_staff.id_card = person_id` 查询员工姓名。 + +### 3.2 现有员工亲属关系模块 + +员工亲属关系维护模块已完整存在,主要使用: + +- 表:`ccdi_staff_fmy_relation` +- 员工身份证:`person_id` +- 亲属名称:`relation_name` +- 亲属身份证:`relation_cert_no` +- 员工亲属标记:`is_emp_family` +- 状态:`status` + +该表已经能够稳定表达“某亲属属于哪个员工”,可以直接作为本次改造的唯一合法来源。 + +## 4. 方案对比 + +### 4.1 方案 A:沿用现有表并切换业务语义 + +做法: + +- 继续使用 `ccdi_staff_enterprise_relation` +- 将 `person_id` 改为表示“亲属身份证号” +- 查询时通过亲属关系表回补亲属名称和关联员工 + +优点: + +- 改动最小 +- 现有增删改查和导入框架可复用 +- 不需要新增表、菜单、权限和页面 + +缺点: + +- `person_id` 字段命名不再直观表达“亲属” + +### 4.2 方案 B:沿用现有表并增加冗余字段 + +做法: + +- 在原表上补充亲属名称、关联员工身份证、关联员工姓名等冗余字段 + +优点: + +- 查询 SQL 简单 + +缺点: + +- 引入冗余数据 +- 与员工亲属关系、员工基础信息容易产生不一致 +- 超出最短路径原则 + +### 4.3 方案 C:新建员工亲属实体关联表 + +做法: + +- 新建全新表结构与全新模块 + +优点: + +- 语义最干净 + +缺点: + +- 改造范围明显扩大 +- 需要增加整套表、接口、页面和权限 +- 不符合本次“最短路径实现”要求 + +### 4.4 选型结论 + +采用方案 A。 + +原因: + +- 可以在现有模块上直接改造,成本最低 +- 满足业务闭环,不需要额外兜底 +- 与当前仓库已有的员工亲属关系维护能力天然衔接 + +## 5. 数据模型设计 + +## 5.1 主表沿用 + +继续使用 `ccdi_staff_enterprise_relation`,但字段语义调整如下: + +| 字段 | 新语义 | +|------|--------| +| `person_id` | 亲属身份证号 | +| `social_credit_code` | 统一社会信用代码 | +| `enterprise_name` | 企业名称 | +| `relation_person_post` | 亲属在企业中的职务 | +| `status` | 关联关系状态 | +| `remark` | 补充说明 | +| `data_source` | 数据来源 | + +本次不修改表结构,不新增字段。 + +## 5.2 查询回填链路 + +列表和详情展示使用以下关联链路: + +1. 以 `ccdi_staff_enterprise_relation` 为主表 +2. 通过 `ccdi_staff_fmy_relation.relation_cert_no = ccdi_staff_enterprise_relation.person_id` +3. 并限定 `ccdi_staff_fmy_relation.is_emp_family = 1` +4. 从 `ccdi_staff_fmy_relation` 获取: + - `relation_name` 作为亲属名称 + - `person_id` 作为关联员工身份证 +5. 再通过 `ccdi_base_staff.id_card = ccdi_staff_fmy_relation.person_id` 获取员工姓名 + +最终返回给前端的核心展示字段为: + +- `personId`:亲属身份证 +- `relationName`:亲属名称 +- `staffPersonId`:关联员工身份证 +- `staffPersonName`:关联员工姓名 + +现有 `personName` 字段不再承载员工姓名语义,避免前后端继续误用,改造后统一使用新的返回字段。 + +## 6. 业务规则 + +### 6.1 合法亲属来源 + +新增和导入时,亲属身份证号必须匹配到一条满足以下条件的员工亲属关系: + +- `is_emp_family = 1` +- `status = 1` +- `relation_cert_no = person_id` + +只要任一条件不满足,即判定该亲属不允许用于实体关联维护。 + +### 6.2 唯一性规则 + +业务唯一性继续沿用现有模式,但语义变更为: + +- `亲属身份证号 + 统一社会信用代码` 唯一 + +新增与导入都必须校验该组合唯一,禁止重复录入。 + +### 6.3 编辑规则 + +编辑时延续现有“业务主键不可修改”的方式: + +- 亲属身份证号不可修改 +- 统一社会信用代码不可修改 + +只允许修改: + +- 企业名称 +- 关联人在企业的职务 +- 状态 +- 补充说明 + +### 6.4 亲属失效联动规则 + +当员工亲属关系模块中某条亲属关系状态从有效改为无效时: + +- 自动将该亲属名下所有实体关联记录的 `status` 更新为 `0` + +联动范围限定为: + +- `ccdi_staff_enterprise_relation.person_id = ccdi_staff_fmy_relation.relation_cert_no` + +本次仅实现“改为无效时自动同步为无效”的单向联动,不设计反向自动恢复为有效。 + +## 7. 后端设计 + +### 7.1 接口延用 + +继续沿用现有接口路径: + +- `GET /ccdi/staffEnterpriseRelation/list` +- `GET /ccdi/staffEnterpriseRelation/{id}` +- `POST /ccdi/staffEnterpriseRelation` +- `PUT /ccdi/staffEnterpriseRelation` +- `DELETE /ccdi/staffEnterpriseRelation/{ids}` +- `POST /ccdi/staffEnterpriseRelation/importTemplate` +- `POST /ccdi/staffEnterpriseRelation/importData` +- `GET /ccdi/staffEnterpriseRelation/importStatus/{taskId}` +- `GET /ccdi/staffEnterpriseRelation/importFailures/{taskId}` + +不新增平行接口组。 + +### 7.2 查询 DTO 与 VO + +查询条件建议调整为围绕亲属语义: + +- 亲属身份证号 +- 亲属名称 +- 关联员工 +- 统一社会信用代码 +- 企业名称 +- 状态 + +VO 增加或切换为以下字段: + +- `personId` +- `relationName` +- `staffPersonId` +- `staffPersonName` +- `relationPersonPost` +- `socialCreditCode` +- `enterpriseName` +- `status` +- `remark` +- `dataSource` +- `createTime` +- `updateTime` +- `createdBy` +- `updatedBy` + +### 7.3 查询 SQL + +列表和详情 SQL 改为从亲属关系表回补字段,示意逻辑如下: + +```sql +SELECT + ser.id, + ser.person_id, + sfr.relation_name, + sfr.person_id AS staff_person_id, + bs.name AS staff_person_name, + ser.relation_person_post, + ser.social_credit_code, + ser.enterprise_name, + ser.status, + ser.remark, + ser.data_source, + ser.created_by, + ser.create_time, + ser.updated_by, + ser.update_time +FROM ccdi_staff_enterprise_relation ser +LEFT JOIN ccdi_staff_fmy_relation sfr + ON sfr.relation_cert_no = ser.person_id + AND sfr.is_emp_family = 1 +LEFT JOIN ccdi_base_staff bs + ON bs.id_card = sfr.person_id +``` + +其中: + +- 列表查询不额外过滤 `sfr.status = 1` +- 原因是历史记录需要正常展示,即使亲属后续失效,记录仍可查到,但实体关联状态会被联动改为无效 + +### 7.4 新增与导入校验 + +新增和导入都统一改为校验有效亲属关系: + +1. 根据亲属身份证号查询 `ccdi_staff_fmy_relation` +2. 要求命中 `is_emp_family = 1 and status = 1` +3. 未命中则报错 +4. 命中后继续校验 `亲属身份证号 + 统一社会信用代码` 唯一 + +### 7.5 亲属下拉搜索接口 + +前端新增/编辑弹窗需要按身份证号模糊搜索有效亲属。 + +实现方式: + +- 在员工实体关联模块后端新增一个用于下拉搜索的查询接口 +- 返回有效亲属列表 + +返回项建议包含: + +- `relationCertNo` +- `relationName` +- `personId` +- `personName` + +查询条件: + +- `relation_cert_no` 模糊匹配输入值 +- `is_emp_family = 1` +- `status = 1` + +### 7.6 亲属失效联动落点 + +联动逻辑放在员工亲属关系保存链路中处理,即: + +- `CcdiStaffFmyRelationServiceImpl.updateRelation` + +处理规则: + +1. 查询更新前旧记录 +2. 判断旧状态是否为有效、更新后状态是否为无效 +3. 若是,则按当前亲属身份证号批量更新实体关联表状态为无效 + +该联动需和亲属关系更新处于同一事务内,保证状态一致。 + +## 8. 前端设计 + +### 8.1 页面延用 + +继续使用: + +- `ruoyi-ui/src/views/ccdiStaffEnterpriseRelation/index.vue` + +不新建新页面。 + +### 8.2 查询区 + +查询区改为亲属语义,保留或新增: + +- 亲属身份证号 +- 亲属名称 +- 关联员工 +- 统一社会信用代码 +- 企业名称 +- 状态 + +### 8.3 列表区 + +列表核心列调整为: + +- 亲属身份证 +- 亲属名称 +- 关联员工 +- 企业名称 +- 关联人在企业的职务 +- 状态 +- 数据来源 +- 创建时间 +- 操作 + +其中“关联员工”展示建议为: + +- `员工姓名(员工身份证号)` + +这样可以避免用户只看到姓名无法定位员工。 + +### 8.4 新增弹窗 + +新增弹窗保留现有骨架,调整主录入方式: + +- 身份证号输入改为“按亲属身份证模糊搜索” +- 下拉数据来源改为有效员工亲属 + +下拉项显示建议: + +- 左侧:亲属身份证号 +- 右侧:亲属名称 / 关联员工姓名 + +用户选中后,自动回填并只读展示: + +- 亲属名称 +- 关联员工 + +其余字段继续录入: + +- 统一社会信用代码 +- 企业名称 +- 关联人在企业的职务 +- 补充说明 + +新增时状态仍默认有效。 + +### 8.5 编辑弹窗 + +编辑弹窗延续现有模式: + +- 亲属身份证号不可编辑 +- 统一社会信用代码不可编辑 +- 亲属名称和关联员工仅展示,不可改 + +### 8.6 详情弹窗 + +详情弹窗基础信息展示: + +- 亲属身份证 +- 亲属名称 +- 关联员工 +- 统一社会信用代码 +- 企业名称 +- 关联人在企业的职务 +- 状态 +- 数据来源 +- 补充说明 +- 审计信息 + +## 9. 导入设计 + +### 9.1 导入模板 + +继续沿用现有异步导入机制,但模板标题、文案和字段语义改为亲属口径。 + +模板标题改为: + +- 员工亲属实体关联信息 + +模板中的“身份证号”字段实际表示: + +- 亲属身份证号 + +### 9.2 导入校验规则 + +每行导入数据按以下顺序校验: + +1. 基础字段非空与格式合法 +2. 亲属身份证号必须存在于员工亲属关系中 +3. 且该亲属必须为员工亲属、状态有效 +4. `亲属身份证号 + 统一社会信用代码` 在库中不能重复 +5. 导入文件内同组合不能重复 + +### 9.3 失败记录展示 + +失败记录弹窗字段调整为: + +- 亲属身份证号 +- 亲属名称 +- 企业名称 +- 统一社会信用代码 +- 失败原因 + +失败原因示例: + +- 亲属身份证号不存在于员工亲属关系中 +- 亲属已失效,无法导入实体关联 +- 亲属身份证号和统一社会信用代码组合已存在 + +### 9.4 导入结果提示 + +所有导入提示文案统一改为: + +- 员工亲属实体关联导入 + +避免继续出现“员工实体关系”旧语义。 + +## 10. 错误处理 + +后端错误提示统一切换为亲属语义,示例: + +- 所选身份证号不是有效的员工亲属,无法新增实体关联 +- 亲属身份证号和统一社会信用代码组合已存在 +- 亲属身份证号不存在于员工亲属关系中,或该亲属已无效 +- 亲属身份证号不可修改 + +前端不新增特殊兜底逻辑,直接按现有错误提示机制回显后端返回信息。 + +## 11. 测试要点 + +### 11.1 列表与详情 + +- 列表正确展示亲属身份证、亲属名称、关联员工 +- 详情页展示字段与列表语义一致 + +### 11.2 新增 + +- 输入亲属身份证可模糊搜索有效亲属 +- 选中亲属后自动带出亲属名称和关联员工 +- 无效亲属、非员工亲属、不存在的亲属身份证不能新增 +- 重复的亲属身份证号 + 统一社会信用代码不能新增 + +### 11.3 编辑 + +- 亲属身份证号不可修改 +- 统一社会信用代码不可修改 +- 企业名称、职务、状态、备注可正常编辑 + +### 11.4 导入 + +- 有效亲属导入成功 +- 亲属不存在导入失败 +- 亲属无效导入失败 +- 导入文件内重复失败 +- 数据库内重复失败 +- 失败记录文案与字段正确 + +### 11.5 失效联动 + +- 将员工亲属关系从有效改为无效后 +- 该亲属名下已有实体关联自动更新为无效 +- 列表仍能查到该记录,但状态为无效 + +## 12. 实施边界总结 + +本次改造严格限定为“在原员工实体关联模块上切换主对象为员工亲属”,核心边界如下: + +- 不新建表 +- 不新建页面 +- 不迁移旧数据 +- 不做兼容性兜底 +- 不做反向恢复联动 +- 所有合法性判断均以员工亲属关系表为准 + +在此边界内,前后端和导入链路均可形成完整闭环,并满足本次需求。