chore: 添加输入输出文件 + .claude记忆和计划

输入文件:
- 租赁任务考核_2026年{1,2,3}月.xlsx (考核源数据)
- {1,2}月.xlsx (客户盈亏表)
- 车辆里程考核与奖金发放规则(V.1.2).docx

输出文件:
- 里程任务考核_{1,2,3}月核算.xlsx (月度核算结果)
- 里程任务考核_Q1汇总.xlsx (含车辆台账)
- 3月客户盈亏表(待填写).xlsx (模版)

.claude_memory: 项目记忆(规则/偏好/架构/测试车辆)
.claude_plans: 历次计划文件

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
kkfluous
2026-04-07 14:09:24 +08:00
parent da487c41d4
commit 573f8397a6
32 changed files with 3491 additions and 0 deletions

View File

@@ -0,0 +1,242 @@
# 数据迁移计划lingniu_prod → 新系统
## Context
老系统 `lingniu_prod`(单库 255 张表)需要全量迁移到新系统的 3 个库。新系统已做架构重构:拆分为 `ln_asset_management`(资产管理)、`ln_energy`(能源计费)、`ry-cloud`(系统核心/RuoYi 框架)。新库中现有数据为测试数据,迁移前清空。
## 源与目标
| | 源 | 目标 |
|---|---|---|
| **Host** | rm-uf65w5v2r77n674x2ko.mysql.rds.aliyuncs.com | 47.100.22.206:3306 |
| **用户** | oneos_read (只读) | root |
| **数据库** | lingniu_prod (255 表) | ln_asset_management (114), ln_energy (19), ry-cloud (29) |
## ID 策略
- `ln_asset_management` / `ln_energy``IdType.AUTO`MySQL 自增),插入时不指定 ID获取 `LAST_INSERT_ID`
- `ry-cloud`:雪花算法 ID已有数据如 sys_user ID = 2038797628680523778
所有迁移记录保存到 `ln_migration.id_mapping` 表,维护 `(old_table, old_id) → (new_table, new_id)` 映射。
## 通用字段转换规则
| 老字段 | 新字段 | 转换 |
|---|---|---|
| `is_deleted` (tinyint 0/1) | `del_flag` (char '0'/'1') | `str(val)` |
| `creater_id` (bigint) | `create_by` (bigint) | 查 user id_mapping |
| `updater_id` (bigint) | `update_by` (bigint) | 查 user id_mapping |
| int 枚举 (如 `truck_type`) | varchar 字典码 | 查 dict_mapping |
| `datetime` | `date` | 取日期部分 |
| `double` | `decimal` | `Decimal(str(val))` |
---
## 迁移分阶段执行
### Phase 0: 准备
1. 在目标库创建 `ln_migration` 数据库和 `id_mapping`
2. **清空**目标库 3 个库中所有业务表数据(保留 ry-cloud 框架种子数据如 sys_config, sys_oss_config, sys_tenant
3. 读取老库 `tab_dic` 构建枚举映射字典 → `dict_mapping.py`
### Phase 1: 基础数据(无 FK 依赖)
| 老表 | 新表 (库) | 行数 | 说明 |
|---|---|---|---|
| `tab_dic` | `sys_dict_type` + `sys_dict_data` (ry-cloud) | 681 | 按 dic_type 分组为 type+data |
| `tab_region` | `common_district` (asset) | 3,359 | 直接映射 |
| `tab_vehicle_model` | `vehicle_model` (asset) | 39 | 字段对齐 |
| `tab_insurance_company` | `insurance_company` (asset) | 20 | 直接映射 |
| `tab_hydrogen_site` | `hydrogen_station` (asset) | 101 | int→varchar 枚举 |
| `tab_parking` | `parking_lot_info` (asset) | 65 | 直接映射 |
| `tab_maintain_site` | `repair_station` (asset) | 64 | 直接映射 |
| `tab_rescue_site` | `rescue_team` (asset) | ~14 | 直接映射 |
| `tab_annual_review_service_station` | `inspection_station` (asset) | 14 | 直接映射 |
| `tab_truck_check_item` | `vehicle_check_item` (asset) | 294 | 直接映射 |
| `tab_contract_templates` | `contract_template` (asset) | 13 | 直接映射 |
| `tab_charge_station` | `charging_station` (asset) | ~数条 | 直接映射 |
### Phase 2: 系统数据(用户/组织/角色)
| 老表 | 新表 (ry-cloud) | 行数 | 说明 |
|---|---|---|---|
| `tab_org` | `sys_dept` + `sys_organization` | 19 | 重建 ancestors 字段 |
| `tab_user` | `sys_user` | 405 | 密码需重置为 BCrypt 临时密码 |
| `tab_role` | `sys_role` | 69 | 雪花 ID |
| `tab_user_role` | `sys_user_role` | 201 | 查 user+role id_mapping |
| `tab_menu` | `sys_menu` | 464 | **评估**:新系统菜单已重新定义,可能跳过 |
| `tab_role_menu` | `sys_role_menu` | 6,236 | 依赖菜单决策 |
> **密码处理**:老系统使用自定义 salt+hash新系统使用 BCrypt。迁移时统一设置临时密码如 `Abc@123456` 的 BCrypt 值),首次登录强制修改。
### Phase 3: 核心业务实体
| 老表 | 新表 (asset) | 行数 | 复杂度 |
|---|---|---|---|
| `tab_truck` | `vehicle_info` | 1,203 | 高47→29 列,大量字段重组 |
| `tab_truck_status_info` | `vehicle_status` | 1,385 | 中int→varchar 枚举 |
| `tab_driver` | `driver_info` | 212 | 低 |
| `tab_customer` | `customer_info` | 310 | 中 |
| `tab_truck_licence` | `vehicle_license` | 1,712 | 中truck_id→vehicle_id FK |
| `tab_truck_insure` | `insurance_procurement` | 740 | 中15→32 列扩展 |
| `tab_equipment_info` | `aftermarket_device` | 1,562 | 中 |
| `tab_violation_management` | `traffic_violation` | 1,285 | 低 |
| `tab_accident` + `tab_accident_cost_bearing` | `accident_info` + `accident_expense` | 293+823 | 中 |
| `tab_failure` | `vehicle_fault_manage` | 5,140 | 低 |
| `tab_vehicle_annual_inspection` | `vehicle_annual_inspection` | 353 | 低 |
| `tab_vehicle_preparation` | `prepare_car` | 1,736 | 低 |
| `tab_customer_invoice` | `invoice_info` | 219 | 低 |
| `tab_truck_device_info` | `aftermarket_device``vehicle_realtime_location` | 1,227 | 评估 |
| `tab_training_materials` | `training_material` (asset) | 3 | 低 |
**vehicle_info 字段映射(核心):**
```
tab_truck.plate_number → vehicle_info.plate_number
tab_truck.vin → vehicle_info.vin
tab_truck.truck_num → vehicle_info.vehicle_code
tab_truck.model (int) → vehicle_info.vehicle_model_id (FK, 查 vehicle_model id_mapping)
tab_truck.color → vehicle_info.body_color
tab_truck.buy_time → vehicle_info.purchase_date (datetime→date)
tab_truck.stock_area (int) → vehicle_info.packing_lot_id (FK, 查 parking_lot_info id_mapping)
tab_truck.mandatory_retirement_period → vehicle_info.mandatory_scrap_date
tab_truck.remarks → vehicle_info.remark
tab_truck.address → vehicle_info.province (提取省份)
```
### Phase 4: 合同域
| 老表 | 新表 (asset) | 行数 | 说明 |
|---|---|---|---|
| `tab_contract` | `vehicle_lease_contract_info` | 681 | 38→67 列,大量新字段 NULL |
| `tab_contract_rent_order` | `vehicle_lease_order` | 679 | 关联合同 |
| `tab_contract_rent_truck` | `vehicle_lease_order_detail` | 3,865 | 关联 order + vehicle |
| `tab_contract_rent_truck_service_cost` | `vehicle_lease_order_service_item` | 1,645 | 关联 detail |
| `tab_contract_thirty_party` | `contract_authorized_person` | 682 | 直接映射 |
| `tab_contract_authorizer_information` | `contract_authorized_person` | 666 | 合并 |
| `tab_contract_costs` | `template_*` 系列表 | 15,059 | 按费用类型拆分 |
| `tab_contract_hydrogen_fees` | `template_hydrogen_fee` | 13 | 直接映射 |
### Phase 5: 交付/退车/换车
| 老表 | 新表 (asset) | 行数 | 说明 |
|---|---|---|---|
| `tab_truck_rent_task` | `delivery_task_subject` | 3,104 | 任务容器 |
| `tab_truck_rent_take` | `delivery_order` + `delivery_vehicle` | 1,956 | 一拆多 |
| `tab_truck_rent_return` | `return_vehicle_task` | 1,079 | 重构 |
| `tab_truck_rent_return_cost` | `return_fees` | 73 | 直接映射 |
| `tab_truck_rent_return_dep_cost` | `return_settlement_*` 子表 | 4,634 | 按类型拆分 |
| `tab_truck_rent_replace` | `vehicle_replacement` | 247 | 直接映射 |
| `tab_standby_vehicle_main/detail` | `vehicle_abnormal_move` | 377+2,171 | 评估映射 |
### Phase 6: 账单/财务
| 老表 | 新表 (asset) | 行数 | 说明 |
|---|---|---|---|
| `tab_rent_contract_bill` | `bills` | 25,625 | 合同账单 |
| `tab_rent_contract_bill_truck` | `vehicle_bills` + `vehicle_bill_service_items` | **270,283** | **大表,批量处理** |
| `tab_rent_contract_bill_other_cost` | 合并到 `vehicle_bills` | ~少量 | |
| `tab_finance_receivable` | `receivable_subject` + `receivable_vehicle` | 10,308 | 拆分 |
| `tab_finance_deposit_receive` | `customer_payment_receipt` | 2,078 | 映射 |
| `tab_finance_deposit_deduction` | `customer_payment_item` | 52 | 映射 |
### Phase 7: 能源域 → ln_energy
| 老表 | 新表 (ln_energy) | 行数 | 说明 |
|---|---|---|---|
| `tab_energy_account` | `energy_account` | 201 | 结构重组 |
| `tab_energy_project_account` | `energy_account_project` | 307 | 直接映射 |
| `tab_energy_account_recharge` | `energy_recharge_order` | 942 | 字段扩展 |
| `tab_import_hydrogen_order` | `hydrogen_station_order` | 58,642 | 加氢原始订单 |
| `tab_energy_hydrogen_bill` | `energy_hydrogen_detail` | **58,554** | **大表** |
| `tab_import_ele_charge_order` | `electricity_charge_record` | 4,405 | 充电原始订单 |
| `tab_energy_electricity_bill` | `energy_bill_detail` | 4,355 | fee_type=electricity |
### Phase 8: 附件
| 老表 | 新表 (asset) | 行数 | 说明 |
|---|---|---|---|
| `tab_data_attachment` | `tab_data_attachment` | **247,447** | **最大表之一**data_id 需 FK 重映射 |
| `tab_image_attachment` | 合并到 `tab_data_attachment` 或保留 | 51,516 | 评估 |
### Phase 9: 其他
| 老表 | 新表 | 行数 | 处理 |
|---|---|---|---|
| `tab_maintain_maintenance_project` | 评估 | 243,474 | 新系统无直接对应,可能跳过 |
| `tab_truck_rent_form_data` | 评估 | 456,061 | 表单数据,新系统结构不同 |
| `tab_preparation_form_data` | 评估 | 171,497 | 同上 |
| `tab_standby_vehicle_form_data` | 评估 | 143,034 | 同上 |
---
## 暂不迁移的表(无新系统对应)
- 审批流:`tab_approve_instance*`, `tab_approve_template_node`
- 工作流:`tab_flow_task*`, `tab_flow_template*`
- G7 车联网:`tab_g7s_org`, `tab_g7s_truck_mileage` (289K), `tab_g7s_in_out_event` (159K)
- 培训考试:`tab_train_*`, `tab_safety_training`
- 系统日志:`tab_api_access_log` (4.6M), `tab_user_log`, `tab_user_message`, `tab_short_message`
- 调度记录:`tab_schedule_execute_result` (347K), `tab_data_sync_task_record`
- 应用版本:`tab_app_version`, `tab_version_user_check`, `tab_release_version_log`
- 临时表:所有 `tab_aa_temp_*`, `*_copy*`, `temp_*`
- 视图:所有 `view_*`, `v_*`
- 汇总表:`truck_info`, `truck_equipment_info`, `truck_hydrogen_info`, `truck_mileage`, `truck_parking`
---
## 实现方案Python 脚本
### 目录结构
```
/Users/kkfluous/Projects/lingniu/oneos-corp/migration/
config.py # 数据库连接配置
id_mapping.py # ID 映射表 CRUD
transform.py # 通用字段转换函数
dict_mapping.py # 老 int 枚举 → 新 varchar 编码映射
migrator.py # 基础迁移器批量读写、mapping、日志
phase0_prepare.py # 建 mapping 表、清空目标库
phase1_reference.py # 字典、区域、车型等基础数据
phase2_system.py # 组织、用户、角色
phase3_core.py # 车辆、司机、客户、证照、保险
phase4_contract.py # 合同、租赁订单
phase5_delivery.py # 交付、退车、换车
phase6_billing.py # 账单、财务
phase7_energy.py # 能源账户、加氢、充电
phase8_attachment.py # 附件
phase9_misc.py # 其他
verify.py # 行数校验、FK 完整性、抽样比对
run_all.py # 按顺序执行所有 phase
```
### 关键技术点
1. **批量处理**大表27 万+ 行)使用 `SSCursor` 服务端游标 + `executemany` 批量写入(每批 1000 行)
2. **ID 映射**`ln_migration.id_mapping(source_table, source_id, target_db, target_table, target_id)`FK 字段通过查映射表解析
3. **枚举映射**:从 `tab_dic` 读取所有字典项,预构建 `{(dic_type, int_value): new_dict_code}` 映射
4. **密码处理**:所有用户密码统一设为 BCrypt(`Abc@123456`),首次登录强制修改
5. **事务**:每个 Phase 按表粒度 commit失败可单表重试
## 验证策略
1. **行数校验**:每张表迁移后对比源/目标行数
2. **抽样比对**:每张核心表随机取 10 条,比对关键业务字段
3. **FK 完整性**:检查所有外键列无孤儿记录
4. **业务逻辑**:能源账户余额一致、合同-车辆关联完整
5. **登录测试**:使用临时密码验证 sys_user 登录
## 回滚方案
1. 迁移前对目标 3 库做 `mysqldump` 备份
2. 回滚 = truncate 所有目标表 + 从备份恢复 + drop `ln_migration`
3. 单 Phase 回滚 = 根据 `id_mapping` 删除该 Phase 写入的记录
## 关键文件
- `ln-asset-management/.../BaseEntity.java` — IdType.AUTO, del_flag char(1)
- `ln-asset-management/.../VehicleInfo.java` — 新车辆实体 29 字段
- `ln-cloud/ruoyi-common/.../BaseEntity.java` — RuoYi 基础实体
- 老后端代码 `/Users/kkfluous/Projects/lingniu/ln_asset/lingniu_asset_server/lingniu-manager/src/main/java/org/lingniu/manager/model/` — 所有老实体类