From 58c59ecd124e3983ea58ea485f011b8a7a5a9881 Mon Sep 17 00:00:00 2001 From: wkc <978997012@qq.com> Date: Thu, 12 Mar 2026 15:38:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=91=98=E5=B7=A5=E8=B5=84?= =?UTF-8?q?=E4=BA=A7=E4=BF=A1=E6=81=AF=E8=AE=BE=E8=AE=A1=E4=B8=8E=E5=AE=9E?= =?UTF-8?q?=E6=96=BD=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...sset-maintenance-backend-implementation.md | 335 ++++++++++++++++++ ...03-12-employee-asset-maintenance-design.md | 259 ++++++++++++++ ...set-maintenance-frontend-implementation.md | 328 +++++++++++++++++ 3 files changed, 922 insertions(+) create mode 100644 docs/plans/2026-03-12-employee-asset-maintenance-backend-implementation.md create mode 100644 docs/plans/2026-03-12-employee-asset-maintenance-design.md create mode 100644 docs/plans/2026-03-12-employee-asset-maintenance-frontend-implementation.md diff --git a/docs/plans/2026-03-12-employee-asset-maintenance-backend-implementation.md b/docs/plans/2026-03-12-employee-asset-maintenance-backend-implementation.md new file mode 100644 index 0000000..ec22e90 --- /dev/null +++ b/docs/plans/2026-03-12-employee-asset-maintenance-backend-implementation.md @@ -0,0 +1,335 @@ +# Employee Asset Maintenance Backend Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Add backend support for employee asset maintenance, including aggregated employee detail/save, employee-asset cascade delete, and asynchronous asset import based on employee ID card linkage. + +**Architecture:** Keep employee maintenance on the existing `CcdiBaseStaff` aggregate, and introduce a new `CcdiAssetInfo` resource in `ccdi-info-collection`. Employee add/edit/detail/delete will orchestrate asset persistence inside transactions, while asset import will mirror the existing employee import flow with a dedicated controller, service, Redis task keys, and failure records. + +**Tech Stack:** Java 21, Spring Boot 3, MyBatis Plus, XML mapper SQL, EasyExcel, Redis, Maven + +--- + +### Task 1: Add the asset table SQL and document the data contract + +**Files:** +- Create: `sql/2026-03-12_ccdi_asset_info.sql` +- Review: `assets/资产信息表.csv` +- Review: `docs/plans/2026-03-12-employee-asset-maintenance-design.md` + +**Step 1: Write the SQL script** + +Create `ccdi_asset_info` with: + +- `asset_id BIGINT` auto increment primary key +- `person_id VARCHAR(18)` storing employee `id_card` +- business columns from the approved design +- audit columns `create_by`, `create_time`, `update_by`, `update_time` +- indexes `idx_person_id` and `idx_asset_main_type` + +**Step 2: Verify the script matches the approved constraints** + +Confirm the script: + +- does not include `asset_id` in any import-facing note +- keeps the field name `person_id` +- links by employee `id_card`, not `staff_id` + +**Step 3: Commit** + +```bash +git add sql/2026-03-12_ccdi_asset_info.sql docs/plans/2026-03-12-employee-asset-maintenance-design.md +git commit -m "新增员工资产信息设计与建表脚本" +``` + +### Task 2: Add the asset domain, DTO, VO, Excel, and mapper skeletons + +**Files:** +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiAssetInfo.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiAssetInfoDTO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiAssetInfoVO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/excel/CcdiAssetInfoExcel.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/AssetImportFailureVO.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiAssetInfoMapper.java` +- Create: `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiAssetInfoMapper.xml` + +**Step 1: Create the entity** + +Model `CcdiAssetInfo` with MyBatis Plus annotations and audit fields consistent with existing `CcdiBaseStaff`. + +**Step 2: Create request and response objects** + +Add one DTO for nested employee-form submission and one VO for employee detail response. + +**Step 3: Create the Excel and failure record objects** + +`CcdiAssetInfoExcel` must exclude `asset_id` and include `person_id`. + +**Step 4: Create mapper methods** + +Define methods for: + +- query by `person_id` +- delete by `person_id` +- delete by `person_id` list +- batch insert +- import lookup by employee `id_card` + +### Task 3: Extend employee DTO and VO aggregation + +**Files:** +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiBaseStaffAddDTO.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiBaseStaffEditDTO.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiBaseStaffVO.java` +- Test: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiBaseStaffServiceAssetAggregationTest.java` + +**Step 1: Write the failing test** + +Add a focused service test that asserts employee detail, add DTO, and edit DTO support `assetInfoList`. + +**Step 2: Run test to verify it fails** + +Run: + +```bash +mvn test -Dtest=CcdiBaseStaffServiceAssetAggregationTest +``` + +Expected: FAIL because `assetInfoList` does not exist yet. + +**Step 3: Add the aggregate fields** + +Add `List` to add/edit DTOs and `List` to the employee VO. + +**Step 4: Run test to verify it passes** + +Run: + +```bash +mvn test -Dtest=CcdiBaseStaffServiceAssetAggregationTest +``` + +Expected: PASS + +### Task 4: Add asset service interfaces and focused persistence methods + +**Files:** +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoService.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoServiceImpl.java` +- Test: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiAssetInfoServiceImplTest.java` + +**Step 1: Write the failing test** + +Cover these behaviors: + +- query all assets by `person_id` +- replace all assets for one employee +- delete assets by one or more employee ID cards +- ignore empty rows when replacing assets + +**Step 2: Run test to verify it fails** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoServiceImplTest +``` + +Expected: FAIL because the asset service does not exist yet. + +**Step 3: Implement minimal service logic** + +Implement methods: + +- `selectByPersonId` +- `replaceByPersonId` +- `deleteByPersonId` +- `deleteByPersonIds` + +Use batch delete + batch insert. + +**Step 4: Run test to verify it passes** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoServiceImplTest +``` + +Expected: PASS + +### Task 5: Update employee service to aggregate asset query and transactional save + +**Files:** +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiBaseStaffService.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java` +- Test: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiBaseStaffServiceImplTest.java` + +**Step 1: Write the failing test** + +Add or extend service tests for: + +- add employee with multiple assets +- edit employee and replace assets +- edit employee with changed `id_card` +- detail query returns `assetInfoList` +- delete employee cascades asset deletion + +**Step 2: Run test to verify it fails** + +Run: + +```bash +mvn test -Dtest=CcdiBaseStaffServiceImplTest +``` + +Expected: FAIL because employee service does not yet coordinate asset persistence. + +**Step 3: Implement the aggregate behavior** + +Update `CcdiBaseStaffServiceImpl` to: + +- inject `ICcdiAssetInfoService` +- load assets during detail query +- save employee first, then replace assets by current employee `id_card` +- capture old `id_card` during edit and clean old asset records when it changes +- delete asset rows before deleting employee rows + +**Step 4: Run the focused test again** + +Run: + +```bash +mvn test -Dtest=CcdiBaseStaffServiceImplTest +``` + +Expected: PASS + +### Task 6: Add asset import controller and async import service + +**Files:** +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiAssetInfoController.java` +- Create: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiAssetInfoImportServiceImpl.java` +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiAssetInfoImportService.java` +- Test: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/service/CcdiAssetInfoImportServiceImplTest.java` + +**Step 1: Write the failing test** + +Cover: + +- import template entity excludes `asset_id` +- import fails when `person_id` does not match an employee `id_card` +- import stores failure records only for bad rows +- import status and failure list use dedicated asset task keys + +**Step 2: Run test to verify it fails** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoImportServiceImplTest +``` + +Expected: FAIL because no asset import pipeline exists yet. + +**Step 3: Implement the import flow** + +Mirror the employee import design with asset-specific names: + +- Redis key prefix `import:assetInfo:` +- asynchronous import execution +- failure record caching for 7 days +- controller endpoints for template, upload, status, and failures + +**Step 4: Run the focused test again** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoImportServiceImplTest +``` + +Expected: PASS + +### Task 7: Add mapper XML SQL for batch asset operations + +**Files:** +- Modify: `ccdi-info-collection/src/main/resources/mapper/info/collection/CcdiAssetInfoMapper.xml` +- Test: `ccdi-info-collection/src/test/java/com/ruoyi/info/collection/mapper/CcdiAssetInfoMapperTest.java` + +**Step 1: Write the failing test** + +Verify: + +- select by `person_id` +- batch insert multiple assets +- delete by one `person_id` +- delete by multiple `person_id` values +- employee existence lookup by `id_card` + +**Step 2: Run test to verify it fails** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoMapperTest +``` + +Expected: FAIL because the mapper XML SQL is incomplete. + +**Step 3: Implement minimal XML SQL** + +Add: + +- result map +- select by `person_id` +- delete by `person_id` +- delete by `person_id` list +- batch insert +- employee existence lookup + +**Step 4: Run the mapper test** + +Run: + +```bash +mvn test -Dtest=CcdiAssetInfoMapperTest +``` + +Expected: PASS + +### Task 8: Verify the backend changes end to end + +**Files:** +- Modify: `ccdi-info-collection/src/main/java/com/ruoyi/info/collection/` +- Modify: `ccdi-info-collection/src/main/resources/mapper/info/collection/` +- Modify: `sql/2026-03-12_ccdi_asset_info.sql` + +**Step 1: Run focused backend tests** + +Run: + +```bash +mvn test -Dtest=CcdiBaseStaffServiceAssetAggregationTest,CcdiAssetInfoServiceImplTest,CcdiBaseStaffServiceImplTest,CcdiAssetInfoImportServiceImplTest,CcdiAssetInfoMapperTest +``` + +Expected: all focused tests pass. + +**Step 2: Run module compile verification** + +Run: + +```bash +mvn clean compile +``` + +Expected: compile succeeds without Java or mapper XML errors. + +**Step 3: Commit** + +```bash +git add sql/2026-03-12_ccdi_asset_info.sql ccdi-info-collection/src/main/java/com/ruoyi/info/collection ccdi-info-collection/src/main/resources/mapper/info/collection docs/plans/2026-03-12-employee-asset-maintenance-backend-implementation.md +git commit -m "新增员工资产信息后端实施计划" +``` diff --git a/docs/plans/2026-03-12-employee-asset-maintenance-design.md b/docs/plans/2026-03-12-employee-asset-maintenance-design.md new file mode 100644 index 0000000..f9a4ce1 --- /dev/null +++ b/docs/plans/2026-03-12-employee-asset-maintenance-design.md @@ -0,0 +1,259 @@ +# 员工资产信息维护设计 + +## 背景 +员工信息维护页面当前仅支持维护员工基础信息,不支持维护员工名下资产信息。现需在现有员工维护页面中补齐资产信息的新增、编辑、删除、详情展示和导入能力,并与现有员工导入交互保持一致。 + +本次设计基于 `2026-03-12` 确认了以下业务约束: + +- 资产表保留字段名 `person_id` +- `person_id` 存员工身份证号,关联 `ccdi_base_staff.id_card` +- `asset_id` 改为数据库自增主键,不出现在导入模板中 +- 资产导入失败记录入口需与员工导入失败记录入口明确区分,按钮文案为“查看员工资产导入失败记录” + +## 目标 +- 在员工信息维护页新增员工资产信息维护能力 +- 在员工新增和编辑弹窗中支持员工资产信息的添加、编辑、删除 +- 在员工详情弹窗中展示该员工全部资产信息 +- 在员工列表页新增“导入资产信息”入口,并复用现有异步导入交互 +- 删除员工时同步删除该员工全部资产信息 + +## 非目标 +- 不新增独立的“员工资产信息管理”菜单页面 +- 不在资产维护中暴露 `asset_id` +- 不允许用户在前端手工填写 `person_id` +- 不改造现有员工列表查询条件和分页结构 + +## 现状 +当前员工维护能力主要集中在以下位置: + +- 前端页面:`ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- 前端接口:`ruoyi-ui/src/api/ccdiBaseStaff.js` +- 后端控制器:`ccdi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiBaseStaffController.java` +- 后端服务:`ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffServiceImpl.java` +- 导入服务:`ccdi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiBaseStaffImportServiceImpl.java` + +现有员工导入采用异步任务 + Redis 状态轮询 + 失败记录分页查询的模式,前端使用本地存储保存最近一次导入任务信息。 + +## 方案对比 + +### 方案一:员工页内嵌资产子表聚合维护 +- 员工新增、编辑、详情接口返回员工主信息和资产列表聚合结果 +- 员工弹窗内部直接维护资产子表 +- 资产导入使用独立接口,但交互完全复用员工导入模式 + +优点: +- 最符合当前需求和现有页面使用习惯 +- 用户一次打开员工弹窗即可维护完整信息 +- 删除员工时做事务级联最直接 + +缺点: +- 员工 DTO、VO、Service、前端表单都需要联动调整 + +### 方案二:资产作为独立模块实现,员工页只嵌入调用 +- 后端和前端都按独立资源建设资产模块 +- 员工页通过额外接口拉取并嵌入展示 + +优点: +- 模块边界更清晰 +- 未来扩展独立资产菜单更容易 + +缺点: +- 本次需求明显超出必要范围 +- 页面状态和接口交互更复杂 + +### 方案三:员工页只加资产查看和导入,编辑改为二级弹窗 +- 员工弹窗中通过二级弹窗维护资产 + +优点: +- 对现有员工表单侵入较小 + +缺点: +- 交互割裂 +- 不符合“新增和编辑弹窗中支持添加、编辑、删除”的要求 + +## 最终方案 +采用方案一:在员工信息维护页内嵌资产信息子表,员工接口作为聚合接口返回和保存资产列表;资产导入保持独立入口和独立后端接口,但沿用现有员工导入的上传、异步处理、结果通知、失败记录查询交互。 + +## 数据模型设计 + +### 数据表 +新增 `ccdi_asset_info` 表,字段来源于 `assets/资产信息表.csv`,并做以下调整: + +- `asset_id`:`BIGINT` 自增主键 +- `person_id`:`VARCHAR(18)`,保存员工身份证号,关联 `ccdi_base_staff.id_card` +- 审计字段沿用当前项目规范,由后端自动填充 + +建议字段如下: + +- `asset_id` +- `person_id` +- `asset_main_type` +- `asset_sub_type` +- `asset_name` +- `ownership_ratio` +- `purchase_eval_date` +- `original_value` +- `current_value` +- `valuation_date` +- `asset_status` +- `remarks` +- `create_by` +- `create_time` +- `update_by` +- `update_time` + +建议索引: + +- `idx_person_id(person_id)` +- `idx_asset_main_type(asset_main_type)` + +## 后端设计 + +### 新增资产信息模块对象 +在 `ccdi-info-collection` 中新增: + +- `domain/CcdiAssetInfo.java` +- `domain/dto/CcdiAssetInfoDTO.java` +- `domain/vo/CcdiAssetInfoVO.java` +- `domain/excel/CcdiAssetInfoExcel.java` +- `domain/vo/AssetImportFailureVO.java` +- `mapper/CcdiAssetInfoMapper.java` +- `service/ICcdiAssetInfoService.java` +- `service/ICcdiAssetInfoImportService.java` +- `service/impl/CcdiAssetInfoServiceImpl.java` +- `service/impl/CcdiAssetInfoImportServiceImpl.java` +- `controller/CcdiAssetInfoController.java` +- `resources/mapper/info/collection/CcdiAssetInfoMapper.xml` + +### 扩展员工聚合接口 +扩展现有员工 DTO 和 VO: + +- `CcdiBaseStaffAddDTO.assetInfoList` +- `CcdiBaseStaffEditDTO.assetInfoList` +- `CcdiBaseStaffVO.assetInfoList` + +后端聚合规则: + +- 查询员工详情时,按员工 `id_card` 查询全部资产并组装到 `assetInfoList` +- 新增员工时,先保存员工,再以员工 `id_card` 回填并保存资产列表 +- 编辑员工时,更新员工主信息,再按员工身份证号重建资产列表 +- 删除员工时,先删资产再删员工,整个过程置于同一事务内 + +### 编辑时的资产处理策略 +编辑员工时不要求前端传递资产行状态,直接按“当前完整列表”覆盖: + +- 获取编辑前员工旧身份证号 +- 更新员工主信息 +- 如果身份证号变更,按旧身份证号删除旧资产 +- 按当前最新身份证号删除对应资产 +- 将前端提交的资产列表统一设置 `person_id = 当前员工身份证号` +- 批量插入最新资产列表 + +该策略实现简单,能直接覆盖资产新增、编辑、删除三种变化。 + +### 资产导入接口 +新增独立资产导入接口: + +- `POST /ccdi/assetInfo/importTemplate` +- `POST /ccdi/assetInfo/importData` +- `GET /ccdi/assetInfo/importStatus/{taskId}` +- `GET /ccdi/assetInfo/importFailures/{taskId}` + +导入交互沿用现有员工导入设计: + +- 异步任务执行 +- Redis 保存任务状态 +- 失败记录单独缓存 +- 前端轮询状态并显示通知 + +### 校验规则 + +#### 员工保存时 +- 员工基础信息仍沿用现有校验规则 +- `assetInfoList` 中空行自动过滤 +- 资产必填项:`assetMainType`、`assetSubType`、`assetName`、`currentValue`、`assetStatus` +- 数值和日期格式必须合法 +- 后端强制回填 `person_id = 员工 id_card` + +#### 资产导入时 +- `person_id` 必填,且必须能匹配到员工 `id_card` +- 模板中不包含 `asset_id` +- 允许同一员工导入多条资产 +- 失败记录仅返回失败数据,不返回成功数据 + +## 前端设计 + +### 列表页 +在 `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` 的按钮区新增: + +- “导入资产信息”按钮 +- “查看员工资产导入失败记录”按钮 + +资产导入相关状态全部独立维护: + +- 独立弹窗状态 +- 独立轮询定时器 +- 独立任务 ID +- 独立 localStorage key +- 独立失败记录弹窗和分页状态 + +### 新增和编辑弹窗 +在现有员工弹窗的“基本信息”下方新增“资产信息”分区,采用可编辑子表形式。 + +子表字段: + +- 资产大类 +- 资产小类 +- 资产名称 +- 产权占比 +- 购买/评估日期 +- 资产原值 +- 当前估值 +- 估值截止日期 +- 资产状态 +- 备注 +- 操作 + +交互规则: + +- 分区右侧提供“新增资产”按钮 +- 每行支持删除 +- 编辑时回显 `assetInfoList` +- 前端不展示 `asset_id`、`person_id` + +### 详情弹窗 +在“员工详情”弹窗中新增“资产信息”区域,使用只读表格展示全部资产。 + +若无资产数据,显示“暂无资产信息”空状态。 + +## 数据流 + +### 员工新增 +前端提交员工基础信息和 `assetInfoList`,后端保存员工后按 `id_card` 批量保存资产。 + +### 员工编辑 +前端拉取员工详情回显基础信息和资产列表,用户修改后提交完整列表,后端按最新员工身份证号重建资产明细。 + +### 员工详情 +后端查询员工主信息,再按 `id_card` 查询资产列表并一并返回。 + +### 员工删除 +后端先按员工身份证号删除资产,再删除员工主记录。 + +### 资产导入 +前端上传资产 Excel,后端异步校验并批量插入资产数据,失败记录通过独立入口查看。 + +## 异常处理 +- 资产导入时,若 `person_id` 无法匹配员工,记录失败原因 +- 员工编辑时若身份证号变更,必须同步处理旧资产清理和新资产重建 +- 员工删除和员工编辑资产重建均使用事务,防止主从数据不一致 +- 前端提示文案中明确区分“员工导入”和“员工资产导入” + +## 验收标准 +- 员工列表页新增“导入资产信息”按钮 +- 资产导入失败时显示“查看员工资产导入失败记录”按钮 +- 员工新增和编辑弹窗中可添加、编辑、删除资产信息 +- 员工详情弹窗中可查看该员工全部资产信息 +- 删除员工后,该员工资产信息同步删除 +- 资产导入模板不包含 `asset_id` +- 资产导入使用 `person_id` 关联员工身份证号 diff --git a/docs/plans/2026-03-12-employee-asset-maintenance-frontend-implementation.md b/docs/plans/2026-03-12-employee-asset-maintenance-frontend-implementation.md new file mode 100644 index 0000000..a69bf4d --- /dev/null +++ b/docs/plans/2026-03-12-employee-asset-maintenance-frontend-implementation.md @@ -0,0 +1,328 @@ +# Employee Asset Maintenance Frontend Implementation Plan + +> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task. + +**Goal:** Extend the employee maintenance page so users can maintain employee assets inside the add/edit dialog, view all assets in the detail dialog, and import asset data with a dedicated failure-record entry. + +**Architecture:** Keep the existing employee page and API module in place, and add a nested asset-table editing experience within `ccdiBaseStaff/index.vue`. Reuse the existing async import interaction model, but isolate all asset-import state, storage keys, dialogs, and button copy from the original employee-import flow. + +**Tech Stack:** Vue 2, Element UI 2, RuoYi request wrapper, scoped SFC styles, Node-based source assertions or existing frontend unit checks + +--- + +### Task 1: Extend the frontend API layer for asset import + +**Files:** +- Modify: `ruoyi-ui/src/api/ccdiBaseStaff.js` +- Create: `ruoyi-ui/src/api/ccdiAssetInfo.js` +- Test: `ruoyi-ui/tests/unit/employee-asset-api-contract.test.js` + +**Step 1: Write the failing test** + +Add a focused source-based test that asserts: + +- employee detail save payload can include `assetInfoList` +- a dedicated asset import API module exists +- asset import API exposes template, upload, status, and failure methods + +**Step 2: Run test to verify it fails** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-api-contract.test.js +``` + +Expected: FAIL because the asset API module does not exist yet. + +**Step 3: Implement the minimal API surface** + +Create `ccdiAssetInfo.js` with: + +- `importAssetTemplate` +- `importAssetData` +- `getAssetImportStatus` +- `getAssetImportFailures` + +Keep `ccdiBaseStaff.js` for employee CRUD. + +**Step 4: Run the test again** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-api-contract.test.js +``` + +Expected: PASS + +### Task 2: Add a regression test for the new employee asset UI structure + +**Files:** +- Create: `ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js` +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` + +**Step 1: Write the failing test** + +Assert the employee page contains: + +- an “导入资产信息” trigger +- a “查看员工资产导入失败记录” trigger hook +- an “资产信息” section inside the add/edit dialog +- an add-asset action +- a detail-table section for assets + +**Step 2: Run test to verify it fails** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js +``` + +Expected: FAIL because the current page lacks all asset-maintenance UI. + +### Task 3: Add the editable asset section to the employee dialog + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js` + +**Step 1: Add asset form state** + +Extend `form` defaults with `assetInfoList: []`. + +**Step 2: Add UI helpers** + +Add methods for: + +- create an empty asset row +- add one asset row +- remove one asset row +- normalize empty asset rows before submit + +**Step 3: Add the asset editing table** + +Render a section below basic employee info with columns for: + +- `assetMainType` +- `assetSubType` +- `assetName` +- `ownershipRatio` +- `purchaseEvalDate` +- `originalValue` +- `currentValue` +- `valuationDate` +- `assetStatus` +- `remarks` +- row delete action + +**Step 4: Run the layout test** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js +``` + +Expected: PASS + +### Task 4: Add detail dialog asset display + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js` + +**Step 1: Add an asset table section to the detail dialog** + +Render employee assets below the existing basic info card. + +**Step 2: Add an empty state** + +If `employeeDetail.assetInfoList` is empty, show “暂无资产信息”. + +**Step 3: Keep existing employee detail fields intact** + +Do not regress name, staff ID, department, ID card, phone, hire date, or status display. + +### Task 5: Wire add/edit/detail requests to aggregate employee data + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-submit-flow.test.js` + +**Step 1: Write the failing test** + +Assert that: + +- `handleAdd` initializes an empty `assetInfoList` +- `handleUpdate` stores returned `assetInfoList` +- `submitForm` posts the employee object with `assetInfoList` +- empty asset rows are filtered before submit + +**Step 2: Run test to verify it fails** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-submit-flow.test.js +``` + +Expected: FAIL because submit logic does not process asset rows yet. + +**Step 3: Implement minimal submit behavior** + +Update: + +- `reset` +- `handleAdd` +- `handleUpdate` +- `handleDetail` +- `submitForm` + +so they all preserve `assetInfoList`. + +**Step 4: Run the submit-flow test** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-submit-flow.test.js +``` + +Expected: PASS + +### Task 6: Add dedicated asset import UI state and upload dialog + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-import-ui.test.js` + +**Step 1: Write the failing test** + +Verify the page defines dedicated asset-import state: + +- independent upload dialog object +- independent polling timer +- independent current task ID +- independent failure dialog state +- asset-specific localStorage key + +**Step 2: Run test to verify it fails** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-import-ui.test.js +``` + +Expected: FAIL because only employee import state exists today. + +**Step 3: Implement the asset import dialog** + +Add: + +- “导入资产信息” button +- asset upload dialog with template download +- asset-specific upload methods +- independent polling and completion handlers + +**Step 4: Distinguish failure record copy** + +Ensure the failure entry text is exactly `查看员工资产导入失败记录`. + +**Step 5: Run the import UI test** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-import-ui.test.js +``` + +Expected: PASS + +### Task 7: Add the asset failure record dialog and isolate storage + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-import-ui.test.js` + +**Step 1: Add an asset failure dialog** + +The dialog title must be `员工资产导入失败记录`. + +**Step 2: Add asset failure columns** + +Show: + +- `personId` +- `assetMainType` +- `assetSubType` +- `assetName` +- `errorMessage` + +**Step 3: Use a dedicated localStorage key** + +Keep employee import history under `employee_import_last_task` and store asset import history under a new asset-specific key. + +**Step 4: Keep the original employee import flow unchanged** + +Do not rename or regress the existing employee import controls and methods unless needed for clear separation. + +### Task 8: Refine styles for the embedded asset table + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Test: `ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js` + +**Step 1: Add focused scoped styles** + +Style: + +- asset section header row +- editable asset table +- empty asset state +- detail asset block + +**Step 2: Preserve the existing employee dialog layout** + +Ensure basic info layout remains readable on desktop and mobile widths. + +### Task 9: Verify the frontend changes end to end + +**Files:** +- Modify: `ruoyi-ui/src/views/ccdiBaseStaff/index.vue` +- Modify: `ruoyi-ui/src/api/ccdiAssetInfo.js` +- Modify: `ruoyi-ui/src/api/ccdiBaseStaff.js` + +**Step 1: Run focused frontend tests** + +Run: + +```bash +node ruoyi-ui/tests/unit/employee-asset-api-contract.test.js +node ruoyi-ui/tests/unit/employee-asset-maintenance-layout.test.js +node ruoyi-ui/tests/unit/employee-asset-submit-flow.test.js +node ruoyi-ui/tests/unit/employee-asset-import-ui.test.js +``` + +Expected: all focused tests pass. + +**Step 2: Run production build verification** + +Run: + +```bash +npm run build:prod +``` + +Workdir: `ruoyi-ui` + +Expected: build succeeds without Vue template or script errors. + +**Step 3: Commit** + +```bash +git add ruoyi-ui/src/api/ccdiAssetInfo.js ruoyi-ui/src/api/ccdiBaseStaff.js ruoyi-ui/src/views/ccdiBaseStaff/index.vue ruoyi-ui/tests/unit docs/plans/2026-03-12-employee-asset-maintenance-frontend-implementation.md +git commit -m "新增员工资产信息前端实施计划" +```