Files
hzdyjs/政治面貌职务出境事由字段修复报告.md
T
2025-10-14 16:41:19 +08:00

24 KiB
Raw Blame History

政治面貌、职务、出境事由字段修复报告

修复时间

2025-10-08

问题描述

用户反馈:

  1. ✅ 职称(professionalTitle) - 已显示(之前修复已生效)
  2. ❌ 职务(position) - 未显示到列表中
  3. ❌ 政治面貌(politicalStatus) - 未正确存入数据库
  4. ❌ 出境事由(exitReason) - 未显示到列表中

问题分析

问题1:政治面貌未存入数据库 🔴 严重

根本原因:Service层的buildEntityFromBo方法中缺少politicalStatus字段映射

// ❌ 修复前:缺少政治面貌字段映射
entity.setApplicantName(bo.getApplicantName());
entity.setDepartment(bo.getDepartment());
// entity.setPoliticalStatus(bo.getPoliticalStatus()); // 缺失!

影响:

  • 前端提交的政治面貌数据无法保存到数据库
  • 数据库rs_overseas_application.political_status字段为NULL
  • 影响党籍保留判断逻辑(需要根据政治面貌判断是否为党员)

问题2:职务和出境事由未显示到列表 🔴 严重

根本原因:前端列表页面的列定义字段绑定错误

<!-- ❌ 修复前:字段绑定错误 -->
<el-table-column label="职称" align="center" prop="position" />
<!-- label是"职称",但prop绑定的是position(职务字段),应该绑定professionalTitle -->

<el-table-column label="出境事由" align="center" prop="purposeText" />
<!-- label是"出境事由",但prop绑定的是purposeText(出国目的),应该绑定exitReason -->

影响:

  • 列表页面"职称"列显示的是职务数据(position)
  • 列表页面"出境事由"列显示的是出国目的数据(purpose)
  • 真正的职务和出境事由字段被隐藏,用户无法看到

问题3:Service层缺少基础字段映射 🔴 严重

经过全面检查,发现Service层的buildEntityFromBo和updateByBo方法中缺少大量基础字段的映射:

缺失的基础字段:

  1. gender - 性别
  2. birthDate - 出生日期
  3. photo - 照片
  4. idNumber - 公民身份号码
  5. politicalStatus - 政治面貌 ⬅️ 关键
  6. registeredAddress - 户籍所在地
  7. administrativeLevel - 行政职级
  8. personnelCategory - 人员类别代码
  9. registrationUnit - 登记备案责任单位
  10. unitLeaderSignature - 单位负责人签名
  11. unitContact - 单位联系人
  12. officePhone - 办公电话
  13. mobilePhone - 移动电话

影响:

  • 这些字段在前端填写后无法保存到数据库
  • 导致出国登记信息不完整
  • 影响后续的出国登记生成和审批流程

修复内容

1. Service层字段映射修复 ✅

文件:RsOverseasApplicationServiceImpl.java

① buildEntityFromBo方法(新增时的字段映射)

修复前:只有部分字段映射,缺少13个基础字段

修复后:完整的字段映射,按业务分类组织

private RsOverseasApplication buildEntityFromBo(RsOverseasApplicationBo bo) {
    RsOverseasApplication entity = new RsOverseasApplication();
    entity.setApplicationId(bo.getApplicationId());
    
    // ==================== 基本信息 ====================
    entity.setApplicantId(bo.getApplicantId());
    entity.setApplicantName(bo.getApplicantName());
    entity.setGender(bo.getGender());  // ✅ 新增:性别
    entity.setBirthDate(bo.getBirthDate());  // ✅ 新增:出生日期
    entity.setPhoto(bo.getPhoto());  // ✅ 新增:照片
    entity.setIdNumber(bo.getIdNumber());  // ✅ 新增:公民身份号码
    entity.setPoliticalStatus(bo.getPoliticalStatus());  // ✅ 新增:政治面貌(关键)
    entity.setRegisteredAddress(bo.getRegisteredAddress());  // ✅ 新增:户籍所在地
    
    // ==================== 工作信息 ====================
    entity.setDepartment(bo.getDepartment());
    entity.setPosition(bo.getPosition());  // 职务
    entity.setProfessionalTitle(bo.getProfessionalTitle());  // 职称
    entity.setAdministrativeLevel(bo.getAdministrativeLevel());  // ✅ 新增:行政职级
    entity.setPersonnelCategory(bo.getPersonnelCategory());  // ✅ 新增:人员类别代码
    
    // ==================== 单位和联系信息 ====================
    entity.setRegistrationUnit(bo.getRegistrationUnit());  // ✅ 新增:登记备案责任单位
    entity.setUnitLeaderSignature(bo.getUnitLeaderSignature());  // ✅ 新增:单位负责人签名
    entity.setUnitContact(bo.getUnitContact());  // ✅ 新增:单位联系人
    entity.setOfficePhone(bo.getOfficePhone());  // ✅ 新增:办公电话
    entity.setMobilePhone(bo.getMobilePhone());  // ✅ 新增:移动电话
    entity.setContactPhone(bo.getContactPhone());  // 联系电话(兼容字段)
    
    // ==================== 出国目的和行程 ====================
    entity.setPurpose(bo.getPurpose());
    entity.setPurposeDetail(bo.getPurposeDetail());
    entity.setDestination(bo.getDestination());
    entity.setDestinationCountry(bo.getDestinationCountry());
    entity.setDestinationCity(bo.getDestinationCity());
    entity.setStartDate(bo.getStartDate());
    entity.setEndDate(bo.getEndDate());
    entity.setDuration(bo.getDuration());
    entity.setBudget(bo.getBudget());
    
    // ==================== 证件和文档 ====================
    entity.setInvitation(bo.getInvitation());
    entity.setDocumentName(bo.getDocumentName());
    entity.setDocumentNumber(bo.getDocumentNumber());
    entity.setItinerary(bo.getItinerary());
    entity.setAccommodationPlan(bo.getAccommodationPlan());
    entity.setTransportationPlan(bo.getTransportationPlan());
    
    // ==================== 出境事由和备注 ====================
    entity.setExitReason(bo.getExitReason());  // 出境事由(关键)
    entity.setVisitRelationship(bo.getVisitRelationship());
    entity.setRemarks(bo.getRemarks());
    entity.setApplicantRemark(bo.getApplicantRemark());
    
    // ==================== 盖章文件相关字段 ====================
    entity.setStampedRegistrationFilePath(bo.getStampedRegistrationFilePath());
    entity.setStampedRegistrationFileName(bo.getStampedRegistrationFileName());
    entity.setStampedFileUploadTime(bo.getStampedFileUploadTime());
    entity.setStampedFileUploadStatus(bo.getStampedFileUploadStatus());
    
    return entity;
}

修复要点:

  • ✅ 补全13个基础字段映射
  • ✅ 按业务逻辑分组组织代码
  • ✅ 添加清晰的注释标识新增字段
  • ✅ 保持原有字段映射不变

② updateByBo方法(修改时的字段更新)

修复前:只有部分字段更新,缺少13个基础字段

修复后:完整的字段更新逻辑

// ==================== 基本信息 ====================
if (update.getApplicantId() != null) updateWrapper.set(...);
if (update.getApplicantName() != null) updateWrapper.set(...);
if (update.getGender() != null) updateWrapper.set(RsOverseasApplication::getGender, update.getGender());  // ✅ 新增
if (update.getBirthDate() != null) updateWrapper.set(RsOverseasApplication::getBirthDate, update.getBirthDate());  // ✅ 新增
if (update.getPhoto() != null) updateWrapper.set(RsOverseasApplication::getPhoto, update.getPhoto());  // ✅ 新增
if (update.getIdNumber() != null) updateWrapper.set(RsOverseasApplication::getIdNumber, update.getIdNumber());  // ✅ 新增
if (update.getPoliticalStatus() != null) updateWrapper.set(RsOverseasApplication::getPoliticalStatus, update.getPoliticalStatus());  // ✅ 政治面貌(关键)
if (update.getRegisteredAddress() != null) updateWrapper.set(RsOverseasApplication::getRegisteredAddress, update.getRegisteredAddress());  // ✅ 新增

// ==================== 工作信息 ====================
if (update.getDepartment() != null) updateWrapper.set(...);
if (update.getPosition() != null) updateWrapper.set(RsOverseasApplication::getPosition, update.getPosition());  // 职务
if (update.getProfessionalTitle() != null) updateWrapper.set(RsOverseasApplication::getProfessionalTitle, update.getProfessionalTitle());  // 职称
if (update.getAdministrativeLevel() != null) updateWrapper.set(RsOverseasApplication::getAdministrativeLevel, update.getAdministrativeLevel());  // ✅ 新增
if (update.getPersonnelCategory() != null) updateWrapper.set(RsOverseasApplication::getPersonnelCategory, update.getPersonnelCategory());  // ✅ 新增

// ==================== 单位和联系信息 ====================
if (update.getRegistrationUnit() != null) updateWrapper.set(...);  // ✅ 新增
if (update.getUnitLeaderSignature() != null) updateWrapper.set(...);  // ✅ 新增
if (update.getUnitContact() != null) updateWrapper.set(...);  // ✅ 新增
if (update.getOfficePhone() != null) updateWrapper.set(...);  // ✅ 新增
if (update.getMobilePhone() != null) updateWrapper.set(...);  // ✅ 新增
if (update.getContactPhone() != null) updateWrapper.set(...);

// ... 其他分类 ...

// ==================== 出境事由和备注 ====================
if (update.getExitReason() != null) updateWrapper.set(RsOverseasApplication::getExitReason, update.getExitReason());  // 出境事由(关键)

修复要点:

  • ✅ 补全13个基础字段更新逻辑
  • ✅ 保持只更新非null字段的原则
  • ✅ 按业务逻辑分组组织代码
  • ✅ 添加清晰的注释标识

2. 前端列表字段绑定修复 ✅

文件:web/src/views/rs/overseas/index.vue

修复前:

<el-table-column label="职称" align="center" prop="position" width="120" />
<!-- ❌ label是"职称",但绑定的是position字段(职务) -->

<el-table-column label="职位" align="center" prop="administrativeLevelText" width="120" />
<!-- ❌ 缺少"职务"列 -->

<el-table-column label="出境事由" align="center" prop="purposeText" width="110" />
<!-- ❌ label是"出境事由",但绑定的是purposeText字段(出国目的) -->

修复后:

<el-table-column label="职务" align="center" prop="position" width="120" />
<!-- ✅ 正确:职务列绑定position字段 -->

<el-table-column label="职称" align="center" prop="professionalTitle" width="120" />
<!-- ✅ 正确:职称列绑定professionalTitle字段 -->

<el-table-column label="政治面貌" align="center" prop="politicalStatusText" width="100" />
<!-- ✅ 正确:政治面貌已有正确绑定 -->

<el-table-column label="出境事由" align="center" prop="exitReason" width="110" />
<!-- ✅ 正确:出境事由列绑定exitReason字段 -->

修复要点:

  • ✅ 职务列:prop="position"
  • ✅ 职称列:prop="professionalTitle"
  • ✅ 出境事由列:prop="exitReason"
  • ✅ 政治面貌列:保持prop="politicalStatusText"不变

数据流程对比

❌ 修复前的数据流程(问题状态)

前端提交:
{
  politicalStatus: "1",  // 中共党员
  position: "处长",
  exitReason: "旅游"
}
    ↓
Controller接收: Bo对象
{
  politicalStatus: "1" ✅
  position: "处长" ✅
  exitReason: "旅游" ✅
}
    ↓
Service层: buildEntityFromBo(bo)
{
  // entity.setPoliticalStatus(bo.getPoliticalStatus());  ❌ 缺失!
  entity.setPosition(bo.getPosition());  ✅ 有映射
  entity.setExitReason(bo.getExitReason());  ✅ 有映射
}
    ↓
Entity对象:
{
  politicalStatus: null  ❌ 未映射
  position: "处长"  ✅
  exitReason: "旅游"  ✅
}
    ↓
数据库:
political_status = NULL  ❌
position = "处长"  ✅
exit_reason = "旅游"  ✅
    ↓
前端列表查询:
{
  politicalStatusText: null  ❌
  position: "处长"
  exitReason: "旅游"
}
    ↓
前端列表显示:
<el-table-column label="政治面貌" prop="politicalStatusText" />  ❌ 显示空
<el-table-column label="职称" prop="position" />  ❌ 显示"处长"(应该显示职称)
<el-table-column label="出境事由" prop="purposeText" />  ❌ 显示出国目的(不是出境事由)

✅ 修复后的数据流程(正确状态)

前端提交:
{
  politicalStatus: "1",  // 中共党员
  position: "处长",
  professionalTitle: "副教授",
  exitReason: "旅游"
}
    ↓
Controller接收: Bo对象
{
  politicalStatus: "1" ✅
  position: "处长" ✅
  professionalTitle: "副教授" ✅
  exitReason: "旅游" ✅
}
    ↓
Service层: buildEntityFromBo(bo)
{
  entity.setPoliticalStatus(bo.getPoliticalStatus());  ✅ 已添加映射
  entity.setPosition(bo.getPosition());  ✅ 有映射
  entity.setProfessionalTitle(bo.getProfessionalTitle());  ✅ 有映射
  entity.setExitReason(bo.getExitReason());  ✅ 有映射
}
    ↓
Entity对象:
{
  politicalStatus: "1"  ✅ 映射成功
  position: "处长"  ✅
  professionalTitle: "副教授"  ✅
  exitReason: "旅游"  ✅
}
    ↓
数据库:
political_status = "1"  ✅
position = "处长"  ✅
professional_title = "副教授"  ✅
exit_reason = "旅游"  ✅
    ↓
前端列表查询:
{
  politicalStatusText: "中共党员"  ✅
  position: "处长"  ✅
  professionalTitle: "副教授"  ✅
  exitReason: "旅游"  ✅
}
    ↓
前端列表显示:
<el-table-column label="政治面貌" prop="politicalStatusText" />  ✅ 显示"中共党员"
<el-table-column label="职务" prop="position" />  ✅ 显示"处长"
<el-table-column label="职称" prop="professionalTitle" />  ✅ 显示"副教授"
<el-table-column label="出境事由" prop="exitReason" />  ✅ 显示"旅游"

修复文件总览

文件 修复内容 行数 状态
RsOverseasApplicationServiceImpl.java buildEntityFromBo方法补全13个基础字段映射 548-609 ✅ 完成
RsOverseasApplicationServiceImpl.java updateByBo方法补全13个基础字段更新逻辑 220-274 ✅ 完成
web/src/views/rs/overseas/index.vue 列表页面列定义字段绑定修正 68-74 ✅ 完成

修复字段清单

本次修复的关键字段

序号 字段名 Java属性 数据库字段 修复内容 优先级
1 政治面貌 politicalStatus political_status Service层映射 🔴 高
2 职务 position position 前端列绑定 🔴 高
3 出境事由 exitReason exit_reason 前端列绑定 🔴 高

一并补全的基础字段

序号 字段名 Java属性 数据库字段 修复内容 优先级
4 性别 gender gender Service层映射 🟡 中
5 出生日期 birthDate birth_date Service层映射 🟡 中
6 照片 photo photo Service层映射 🟡 中
7 公民身份号码 idNumber id_number Service层映射 🟡 中
8 户籍所在地 registeredAddress registered_address Service层映射 🟡 中
9 行政职级 administrativeLevel administrative_level Service层映射 🟡 中
10 人员类别代码 personnelCategory personnel_category Service层映射 🟡 中
11 登记备案责任单位 registrationUnit registration_unit Service层映射 🟢 低
12 单位负责人签名 unitLeaderSignature unit_leader_signature Service层映射 🟢 低
13 单位联系人 unitContact unit_contact Service层映射 🟢 低
14 办公电话 officePhone office_phone Service层映射 🟢 低
15 移动电话 mobilePhone mobile_phone Service层映射 🟢 低

测试验证

⚠️ 必须重启后端服务

cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn clean install
# 然后重启后端服务

测试步骤

1. 新增申请测试

填写完整表单:

  • ✅ 姓名:张三
  • ✅ 性别:男
  • ✅ 出生年月:1990-01-01
  • ✅ 政治面貌:中共党员 ⬅️ 关键测试字段
  • ✅ 现工作部门:计算机学院
  • ✅ 职务:处长 ⬅️ 关键测试字段
  • ✅ 职称:副教授 ⬅️ 测试字段
  • ✅ 前往国家:美国
  • ✅ 出境事由:旅游 ⬅️ 关键测试字段
  • ✅ 出发日期:2025-11-01
  • ✅ 返回日期:2025-11-10

2. 数据库验证SQL

SELECT 
    application_id,
    applicant_name,
    gender,
    birth_date,
    political_status,      -- ⬅️ 应该显示"1"或"中共党员"
    department,
    position,              -- ⬅️ 应该显示"处长"
    professional_title,    -- ⬅️ 应该显示"副教授"
    exit_reason,           -- ⬅️ 应该显示"旅游"
    destination_country,
    start_date,
    end_date,
    duration,
    status,
    create_time
FROM rs_overseas_application
ORDER BY create_time DESC
LIMIT 1;

预期结果:

political_status      = "1"         ✅ 不应为NULL
position              = "处长"      ✅ 不应为NULL
professional_title    = "副教授"    ✅ 不应为NULL
exit_reason           = "旅游"      ✅ 不应为NULL

3. 前端列表显示验证

刷新列表页面,查看最新记录:

姓名 现工作部门 职务 职称 政治面貌 前往国家 出境事由
张三 计算机学院 处长 副教授 中共党员 美国 旅游

验证要点:

  • ✅ "职务"列显示"处长"(不是职称)
  • ✅ "职称"列显示"副教授"(不是职务)
  • ✅ "政治面貌"列显示"中共党员"(不是空)
  • ✅ "出境事由"列显示"旅游"(不是出国目的)

4. 修改申请测试

  1. 编辑已有申请
  2. 修改政治面貌从"中共党员"改为"群众"
  3. 修改职务从"处长"改为"科长"
  4. 修改出境事由从"旅游"改为"探亲"
  5. 保存修改
  6. 查询数据库验证字段是否正确更新
  7. 查看列表验证显示是否正确

修复影响范围

直接影响

  1. 政治面貌字段 ✅

    • 新增申请:政治面貌可以正确保存
    • 修改申请:政治面貌可以正确更新
    • 列表显示:政治面貌可以正确显示
    • 党籍保留判断:可以根据政治面貌判断是否为党员
  2. 职务字段 ✅

    • 列表显示:职务列显示正确的职务数据
    • 职称列显示:职称列显示正确的职称数据
    • 数据保存:职务数据已经可以正确保存(之前就有映射)
  3. 出境事由字段 ✅

    • 列表显示:出境事由列显示正确的出境事由数据
    • 数据保存:出境事由数据已经可以正确保存(之前就有映射)

间接影响

  1. 基础信息完整性 ✅

    • 13个基础字段现在都可以正确保存和更新
    • 出国登记信息更加完整
    • 支持完整的出国登记表生成
  2. 党籍保留功能 ✅

    • 可以正确判断是否为中共党员
    • 党籍保留附件上传逻辑可以正常工作
    • 党籍保留记录可以正确创建
  3. 审批流程 ✅

    • 审批人员可以看到完整的申请信息
    • 包括政治面貌、职务、出境事由等关键信息
  4. 报表统计 ✅

    • 可以按政治面貌统计出国人员
    • 可以按职务级别统计
    • 可以按出境事由统计

技术要点总结

1. Service层字段映射机制

问题:即使Entity、Bo、Vo类都有字段定义,如果Service层的转换方法中缺少字段映射,数据仍然无法保存。

原因:项目使用了MapStruct的@AutoMapper注解,但在手动编写的buildEntityFromBo方法中,MapStruct的自动映射不生效,必须手动调用setter方法。

解决方案:在buildEntityFromBo方法中显式调用所有字段的setter方法。

2. 前端列定义字段绑定

问题:<el-table-column>的label属性和prop属性必须一致,否则会出现标题和内容不匹配的问题。

示例错误:

<el-table-column label="职称" prop="position" />
<!-- label是"职称",但prop绑定的是position(职务字段) -->

正确写法:

<el-table-column label="职务" prop="position" />
<el-table-column label="职称" prop="professionalTitle" />

3. 字段命名规范

业务概念 Java属性 数据库字段 前端字段 说明
职务 position position position 行政职务,如"处长"
职称 professionalTitle professional_title professionalTitle 专业技术职称,如"副教授"
职位/行政职级 administrativeLevel administrative_level administrativeLevel 行政级别,如"正处级"
出国目的 purpose purpose purpose 出国目的类型,如"学术交流"
出境事由 exitReason exit_reason exitReason 出境具体事由,如"旅游"、"探亲"

4. 新增字段的完整修复清单

对于任何新增的数据库字段,需要在以下位置进行修改:

  • ✅ Entity类 - 已存在
  • ✅ Bo类 - 已存在
  • ✅ Vo类 - 已存在
  • ✅ Service层 buildEntityFromBo方法 - 本次修复的关键点
  • ✅ Service层 updateByBo方法 - 本次修复的关键点
  • ✅ 前端表单字段定义 - 已存在
  • ✅ 前端表单验证规则 - 已存在
  • ✅ 前端列表列定义 - 本次修复的关键点

修复对比表

修复项 修复前 修复后
buildEntityFromBo基础字段映射 ❌ 缺少13个字段 ✅ 补全所有基础字段
updateByBo基础字段更新 ❌ 缺少13个字段 ✅ 补全所有基础字段
前端职务列绑定 ❌ label="职称" prop="position" ✅ label="职务" prop="position"
前端职称列绑定 ❌ 缺少独立的职称列 ✅ label="职称" prop="professionalTitle"
前端出境事由列绑定 ❌ prop="purposeText" ✅ prop="exitReason"
政治面貌保存 ❌ 保存为NULL ✅ 正确保存
政治面貌显示 ❌ 列表显示空 ✅ 列表正确显示
职务显示 ❌ 在职称列显示 ✅ 在职务列显示
出境事由显示 ❌ 显示出国目的 ✅ 显示出境事由
语法检查 - ✅ 通过

注意事项

1. 已有数据处理

对于修复前已经提交的申请记录,政治面貌等13个基础字段的值为NULL。

处理方案:

  • ✅ 推荐方案:让用户重新编辑并保存(Service层的updateByBo已修复,可以正确更新)
  • ⚠️ 备选方案:通过SQL脚本批量设置默认值(需要业务确认)

2. 前端表单字段已正确

前端表单中这些字段的定义和验证规则都是正确的:

  • ✅ politicalStatus - 下拉选择
  • ✅ position - 文本输入
  • ✅ professionalTitle - 文本输入
  • ✅ exitReason - 单选按钮

3. 数据库字段已存在

数据库表rs_overseas_application中所有相关字段都已经存在:

  • ✅ political_status varchar(20)
  • ✅ position varchar(100)
  • ✅ professional_title varchar(100)
  • ✅ exit_reason varchar(50)

相关文档

下一步行动

1. ⚠️ 必须重启后端服务

cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn clean install
# 重启后端服务

2. 执行完整测试

  • 新增申请测试(重点测试政治面貌、职务、出境事由)
  • 数据库验证(查询这些字段是否正确保存)
  • 列表显示验证(查看列表各列显示是否正确)
  • 修改申请测试(验证字段更新功能)

3. 反馈结果

如果测试发现问题,请提供:

  • 具体的错误信息
  • 后端日志
  • 前端控制台输出
  • 数据库查询结果截图
  • 列表页面截图

修复完成时间: 2025-10-08
修复执行者: Cursor AI Assistant
代码审查状态: ✅ 已通过语法检查
测试状态: ⏳ 待用户验证
预期效果:

  • ✅ 政治面貌可以正确保存和显示
  • ✅ 职务列和职称列显示正确的数据
  • ✅ 出境事由列显示正确的数据
  • ✅ 13个基础字段都可以正确保存和更新