Files
hzdyjs/行程变更申请-recordId修复说明.md
T
2025-10-14 16:41:19 +08:00

9.5 KiB
Raw Blame History

出国行程变更申请 - 必填字段修复说明

📋 问题描述

问题现象:点击"新增变更申请"按钮,填写表单后点击提交,系统依次提示:

  1. ❌ "关联备案记录ID不能为空"
  2. ❌ "申请人ID不能为空"

根本原因:

  1. 数据库表 rs_overseas_itinerary_change 中 record_id 和 applicant_id 字段为必填(NOT NULL)
  2. 前端表单提交时未包含 recordId 和 applicantId 字段
  3. 后端验证失败,返回错误提示

🔧 修复方案

1. 核心思路

通过出国申请ID(applicationId)获取对应的出国记录(record),从而获得 recordId。

数据关系链:

出国申请表 (rs_overseas_application)
    ↓ applicationId
出国记录表 (rs_overseas_record) 
    ↓ recordId
行程变更表 (rs_overseas_itinerary_change)

2. 修复步骤

Step 1: 添加必填字段到 TypeScript 类型定义

文件: web/src/api/rs/overseas.ts

// 行程变更表单类型
export interface ItineraryChangeForm {
  changeId?: number | string;
  recordId: number;      // ✅ 新增:关联出国记录ID(必填)
  applicationId: number;
  applicantId: number;   // ✅ 新增:申请人ID(必填)
  applicantName?: string;
  // ... 其他字段
}

Step 2: 导入获取出国记录的 API

文件: web/src/views/rs/overseas/itinerary-change.vue

import { 
  // ... 其他导入
  getOverseasRecordByApplication,  // ✅ 新增:根据申请ID获取出国记录
  type ItineraryChangeQuery,
  type ItineraryChangeVO,
  type ItineraryChangeForm,
  type OverseasApplicationVO
} from '@/api/rs/overseas';

Step 3: 在选择出国申请时获取必填字段

文件: web/src/views/rs/overseas/itinerary-change.vue

// 选择原出国申请后,自动填充原申请信息
const handleApplicationChange = async (applicationId: number) => {
  try {
    // 1. 获取出国申请详情
    const response = await getOverseasApplication(applicationId);
    const selectedApplication = response.data;
    
    // 2. ✅ 根据申请ID获取出国记录(包含recordId)
    const recordResponse = await getOverseasRecordByApplication(applicationId);
    const recordData = recordResponse.data;
    
    if (selectedApplication && recordData) {
      // ✅ 设置recordId(关键字段,必填)
      state.form.recordId = recordData.recordId;
      
      // ✅ 设置申请人ID(关键字段,必填)
      state.form.applicantId = selectedApplication.applicantId;
      
      // 填充其他字段...
    }
  } catch (error) {
    console.error('获取申请详情失败:', error);
    ElMessage.error('获取出国申请详情失败,请确保该申请已有对应的出国记录');
  }
};

Step 4: 在表单重置时包含必填字段

文件: web/src/views/rs/overseas/itinerary-change.vue

// 重置表单
const resetForm = () => {
  state.form = {
    changeId: undefined,
    recordId: undefined as any,     // ✅ 新增
    applicationId: undefined as any,
    applicantId: undefined as any,  // ✅ 新增
    // ... 其他字段
  };
  state.changeTypes = [];
  formRef.value?.resetFields();
};

✅ 修复效果

修复前

用户操作流程:
1. 点击"新增变更申请"
2. 选择原出国申请
3. 填写变更信息
4. 点击提交
❌ 错误提示:关联备案记录ID不能为空

修复后

用户操作流程:
1. 点击"新增变更申请"
2. 选择原出国申请
   ✅ 自动获取 applicationId
   ✅ 通过 applicationId 获取 recordId
   ✅ 设置 form.recordId
3. 填写变更信息
4. 点击提交
✅ 提交成功!变更申请已进入审批流程
✅ 数据流转到"出国行程变更审批"选项卡

🔍 数据流转

1. 前端提交数据结构

{
  "changeId": null,
  "recordId": 1849311999315025922,     // ✅ 必填字段
  "applicationId": 1849311999315025920,
  "applicantId": 1001,                 // ✅ 必填字段
  "applicantName": "张三",
  "gender": "0",
  "newDestination": "美国",
  "newExitReason": "学术交流",
  "changeReason": "会议时间调整",
  "changeType": "时间变更",
  // ... 其他字段
}

2. 后端数据库存储

INSERT INTO rs_overseas_itinerary_change (
  change_id,
  record_id,          -- ✅ 从前端获取
  application_id,
  applicant_id,       -- ✅ 从前端获取
  applicant_name,
  -- ... 其他字段
) VALUES (
  1234567890123456789,
  1849311999315025922,  -- ✅ 成功插入
  1849311999315025920,
  1001,                 -- ✅ 成功插入
  '张三',
  -- ... 其他值
);

3. 审批流程

提交成功
  ↓
自动刷新列表(根据当前Tab)
  ↓
状态变更为"待审核"(status='0')
  ↓
流转到"出国行程变更审批"选项卡
  ↓
审批人可以查看并审批

📊 API 调用链

前端操作
  ↓
handleApplicationChange(applicationId)
  ↓
┌─────────────────────────────────────────┐
│ getOverseasApplication(applicationId)   │ → 获取申请详情
└─────────────────────────────────────────┘
  ↓
┌─────────────────────────────────────────┐
│ getOverseasRecordByApplication(         │ → 获取出国记录
│   applicationId                         │   (包含recordId)
│ )                                       │
└─────────────────────────────────────────┘
  ↓
设置 state.form.recordId = recordData.recordId
  ↓
用户填写变更信息
  ↓
submitForm()
  ↓
┌─────────────────────────────────────────┐
│ addItineraryChange(state.form)          │ → 提交变更申请
│ {                                       │   (包含必填字段)
│   recordId: 1849311999315025922,        │
│   applicationId: 1849311999315025920,   │
│   applicantId: 1001,                    │
│   ...                                   │
│ }                                       │
└─────────────────────────────────────────┘
  ↓
✅ 提交成功

🎯 关键要点

✅ 必须要做的

  1. 类型定义:ItineraryChangeForm 必须包含 recordId: number 和 applicantId: number
  2. API导入:导入 getOverseasRecordByApplication 函数
  3. 获取必填字段:在选择出国申请时,同时获取对应的出国记录和申请人ID
  4. 表单重置:resetForm 中包含 recordId 和 applicantId 字段初始化

⚠️ 注意事项

  1. 错误处理:如果出国申请没有对应的出国记录,需要友好提示
  2. 数据验证:确保 recordId 和 applicantId 在提交前不为空
  3. 用户体验:选择出国申请后,必填字段自动获取,用户无感知

📝 错误消息优化

catch (error) {
  console.error('获取申请详情失败:', error);
  ElMessage.error('获取出国申请详情失败,请确保该申请已有对应的出国记录');
}

🧪 测试验证

测试场景

场景1:正常流程

✅ 选择已审批通过的出国申请
✅ 系统自动获取 recordId
✅ 填写变更信息
✅ 提交成功
✅ 状态显示"待审核"

场景2:异常处理

❌ 选择的申请没有对应的出国记录
✅ 显示友好错误提示
✅ 用户可以重新选择其他申请

场景3:数据完整性

✅ 提交的数据包含 recordId 和 applicantId
✅ 后端验证通过
✅ 数据库记录正确插入

📁 修改文件清单

文件路径 修改内容 修改行数
web/src/api/rs/overseas.ts ItineraryChangeForm 添加 recordId 和 applicantId 字段 +2 行
web/src/views/rs/overseas/itinerary-change.vue 导入 getOverseasRecordByApplication +1 行
web/src/views/rs/overseas/itinerary-change.vue handleApplicationChange 获取 recordId 和 applicantId +7 行
web/src/views/rs/overseas/itinerary-change.vue resetForm 添加 recordId 和 applicantId 初始化 +2 行

总计修改:3 个文件,+12 行代码


🎉 总结

问题根源:前端表单缺少必填字段 recordId 和 applicantId

解决方案:

  1. ✅ 类型定义中添加 recordId 和 applicantId 字段
  2. ✅ 选择出国申请时,通过 API 自动获取 recordId 和 applicantId
  3. ✅ 表单提交时包含所有必填字段
  4. ✅ 后端验证通过,数据成功存储

修复效果:

  • ✅ 用户可以正常提交行程变更申请
  • ✅ 变更申请成功流转到审批流程
  • ✅ 显示在"出国行程变更审批"选项卡中
  • ✅ 审批人可以正常审批

修复时间:2025-10-13

修复人员:Cursor AI Assistant


📚 相关文档

  • 数据库表设计:docs/设计文档/database/rs_overseas_itinerary_change_full.sql
  • API文档:待补充到 docs/开发文档/API/ 目录
  • 表单优化:行程变更申请表单优化-更新说明.md
  • 效果对比:行程变更表单优化-效果对比.md

文档生成时间:2025-10-13
文档版本:v1.0