24 KiB
政治面貌、职务、出境事由字段修复报告
修复时间
2025-10-08
问题描述
用户反馈:
- ✅ 职称(professionalTitle) - 已显示(之前修复已生效)
- ❌ 职务(position) - 未显示到列表中
- ❌ 政治面貌(politicalStatus) - 未正确存入数据库
- ❌ 出境事由(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方法中缺少大量基础字段的映射:
缺失的基础字段:
gender- 性别birthDate- 出生日期photo- 照片idNumber- 公民身份号码politicalStatus- 政治面貌 ⬅️ 关键registeredAddress- 户籍所在地administrativeLevel- 行政职级personnelCategory- 人员类别代码registrationUnit- 登记备案责任单位unitLeaderSignature- 单位负责人签名unitContact- 单位联系人officePhone- 办公电话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. 修改申请测试
- 编辑已有申请
- 修改政治面貌从"中共党员"改为"群众"
- 修改职务从"处长"改为"科长"
- 修改出境事由从"旅游"改为"探亲"
- 保存修改
- 查询数据库验证字段是否正确更新
- 查看列表验证显示是否正确
修复影响范围
直接影响
-
政治面貌字段 ✅
- 新增申请:政治面貌可以正确保存
- 修改申请:政治面貌可以正确更新
- 列表显示:政治面貌可以正确显示
- 党籍保留判断:可以根据政治面貌判断是否为党员
-
职务字段 ✅
- 列表显示:职务列显示正确的职务数据
- 职称列显示:职称列显示正确的职称数据
- 数据保存:职务数据已经可以正确保存(之前就有映射)
-
出境事由字段 ✅
- 列表显示:出境事由列显示正确的出境事由数据
- 数据保存:出境事由数据已经可以正确保存(之前就有映射)
间接影响
-
基础信息完整性 ✅
- 13个基础字段现在都可以正确保存和更新
- 出国登记信息更加完整
- 支持完整的出国登记表生成
-
党籍保留功能 ✅
- 可以正确判断是否为中共党员
- 党籍保留附件上传逻辑可以正常工作
- 党籍保留记录可以正确创建
-
审批流程 ✅
- 审批人员可以看到完整的申请信息
- 包括政治面貌、职务、出境事由等关键信息
-
报表统计 ✅
- 可以按政治面貌统计出国人员
- 可以按职务级别统计
- 可以按出境事由统计
技术要点总结
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_statusvarchar(20) - ✅
positionvarchar(100) - ✅
professional_titlevarchar(100) - ✅
exit_reasonvarchar(50)
相关文档
- 出国申请字段映射问题修复报告.md - 之前的修复报告
- RsOverseasApplicationServiceImpl.java - Service层修复代码
- index.vue - 前端列表页修复代码
下一步行动
1. ⚠️ 必须重启后端服务
cd /Users/weizzzz/Documents/Cursor/0828CURSOR/all-project/backend
mvn clean install
# 重启后端服务
2. 执行完整测试
- 新增申请测试(重点测试政治面貌、职务、出境事由)
- 数据库验证(查询这些字段是否正确保存)
- 列表显示验证(查看列表各列显示是否正确)
- 修改申请测试(验证字段更新功能)
3. 反馈结果
如果测试发现问题,请提供:
- 具体的错误信息
- 后端日志
- 前端控制台输出
- 数据库查询结果截图
- 列表页面截图
修复完成时间: 2025-10-08
修复执行者: Cursor AI Assistant
代码审查状态: ✅ 已通过语法检查
测试状态: ⏳ 待用户验证
预期效果:
- ✅ 政治面貌可以正确保存和显示
- ✅ 职务列和职称列显示正确的数据
- ✅ 出境事由列显示正确的数据
- ✅ 13个基础字段都可以正确保存和更新