9.9 KiB
出国申请详情职务字段未显示问题诊断报告
问题发现时间: 2025-10-09
问题类型: 前端显示问题
影响范围: 出国申请详情查看功能
诊断状态: ✅ 已完成分析
📋 问题描述
问题现象
在出国申请管理页面中,点击"查看详情"按钮,弹窗界面中的职务字段显示为"-",但用户反馈数据库中该字段有数据。
🔍 完整诊断分析
✅ 1. 数据库层面检查(用户确认:有数据)
数据库表: rs_overseas_application
- ✅ 表结构中存在
position字段 - ✅ 用户确认数据库中
position字段有数据
-- 检查表结构
SHOW COLUMNS FROM rs_overseas_application LIKE 'position';
-- 结果: position varchar(100) DEFAULT NULL COMMENT '职务职称'
-- 查看数据
SELECT application_id, applicant_name, position FROM rs_overseas_application;
-- 用户确认: position字段有数据
✅ 2. 后端实体类检查(正确)
Java实体类: RsOverseasApplication.java(第99-103行)
/**
* 职务职称
*/
@ExcelProperty(value = "职务职称")
private String position;
✅ 结论: 实体类包含 position 字段。
✅ 3. 后端VO类检查(正确)
VO类: RsOverseasApplicationVo.java(第92-95行)
/**
* 职务职称
*/
private String position;
✅ 结论: VO类包含 position 字段。
✅ 4. 后端Mapper XML检查(正确)
Mapper XML: RsOverseasApplicationMapper.xml
① ResultMap映射(第19行)
<result property="position" column="position"/>
② SQL查询语句(第82行)
<sql id="selectOverseasApplicationVo">
select oa.application_id, oa.serial_number, oa.applicant_id, oa.applicant_name,
oa.gender, oa.birth_date, oa.photo, oa.id_number, oa.political_status, oa.registered_address,
oa.department, oa.position, oa.professional_title, ...
from rs_overseas_application oa
</sql>
③ 查询详情方法(第274-277行)
<select id="selectOverseasApplicationById" parameterType="Long" resultMap="RsOverseasApplicationVoResult">
<include refid="selectOverseasApplicationVo"/>
where oa.application_id = #{applicationId} and oa.deleted = '0'
</select>
✅ 结论: Mapper XML配置正确,查询语句包含 position 字段。
✅ 5. 后端Service层检查(正确)
Service实现: RsOverseasApplicationServiceImpl.java(第136-138行)
@Override
public RsOverseasApplicationVo queryById(Long applicationId) {
return baseMapper.selectOverseasApplicationById(applicationId);
}
✅ 结论: Service层调用正确。
✅ 6. 后端Controller层检查(正确)
Controller: RsOverseasApplicationController.java(第175-177行)
@SaCheckPermission("rs:overseas:query")
@GetMapping("/{applicationId}")
public R<RsOverseasApplicationVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable Long applicationId) {
return R.ok(applicationService.queryById(applicationId));
}
✅ 结论: Controller接口正确。
✅ 7. 前端TypeScript接口检查(正确)
前端API接口: web/src/api/rs/overseas.ts(第37行)
export interface OverseasApplicationVO {
applicationId: number | string;
applicantName: string;
department: string;
position?: string; // ✅ 职务字段已定义
professionalTitle?: string;
// ... 其他字段
}
✅ 结论: TypeScript接口定义正确。
✅ 8. 前端模板检查(正确)
前端详情弹窗: web/src/views/rs/overseas/index.vue(第837行)
<el-descriptions-item label="职务" :span="2">
{{ state.viewData.position || '-' }}
</el-descriptions-item>
✅ 结论: 前端模板正确引用了 position 字段。
✅ 9. 前端数据获取方法检查(正确)
查看详情方法: web/src/views/rs/overseas/index.vue(第1595-1604行)
const handleViewApplication = async (row: OverseasApplicationVO) => {
try {
const response = await getOverseasApplication(row.applicationId);
state.viewData = response.data; // 直接赋值响应数据
state.viewDialog.title = '出国申请详情';
state.viewDialog.visible = true;
} catch (error) {
console.error('获取申请详情失败:', error);
}
};
✅ 结论: 前端数据获取方法正确。
🎯 问题根本原因分析
所有代码层面都是正确的!
经过完整的9个层面的检查:
- ✅ 数据库表结构
- ✅ 后端实体类
- ✅ 后端VO类
- ✅ Mapper XML映射
- ✅ Service层
- ✅ Controller层
- ✅ 前端TS接口
- ✅ 前端Vue模板
- ✅ 前端数据获取
所有代码都是正确的!
🔬 可能的原因
原因1:数据库中该记录的 position 字段确实为空
虽然用户说数据库中有数据,但可能:
- ✅ 某些记录有数据
- ❌ 查看的这条记录没有数据(NULL 或空字符串)
原因2:缓存问题
- 后端可能有缓存(但检查代码没有发现缓存配置)
- 前端浏览器缓存了旧的API响应
原因3:数据隔离问题
- 多租户数据隔离
- 逻辑删除标志(deleted字段)
- 权限过滤
🛠️ 诊断步骤(请用户执行)
步骤1:确认数据库中具体记录的数据
请执行以下SQL,找到您查看详情的那条记录:
-- 替换 {application_id} 为您实际查看的申请ID
SELECT
application_id,
applicant_name,
department,
position,
professional_title,
status,
deleted,
tenant_id,
LENGTH(position) as position_length,
HEX(position) as position_hex
FROM rs_overseas_application
WHERE application_id = {application_id};
关键检查:
position字段值是什么?position_length是否为 0 或 NULL?deleted字段值是什么?(必须是 '0')
步骤2:查看后端API响应
- 打开浏览器开发者工具(F12)
- 切换到 Network(网络) 标签页
- 点击查看详情按钮
- 找到请求URL:
/rs/overseas/application/{applicationId} - 查看响应内容(Response)
检查响应JSON:
{
"code": 200,
"msg": "操作成功",
"data": {
"applicationId": 123,
"applicantName": "张三",
"department": "智能控制学院",
"position": "???", // <-- 这里的值是什么?
"professionalTitle": "高级职称"
}
}
关键问题:
position字段在响应中存在吗?- 如果存在,值是什么?(NULL / "" / 实际值)
步骤3:清除缓存重新测试
- 清除浏览器缓存:Ctrl+Shift+Delete(Windows)或 Cmd+Shift+Delete(Mac)
- 强制刷新页面:Ctrl+F5(Windows)或 Cmd+Shift+R(Mac)
- 重启后端服务(如果怀疑有后端缓存)
- 重新测试查看详情功能
步骤4:直接调用API测试
使用Postman或curl直接测试后端API:
# 替换 {token} 和 {application_id}
curl -X GET \
'http://localhost:8080/rs/overseas/application/{application_id}' \
-H 'Authorization: Bearer {token}' \
-H 'clientid: your-client-id'
或者在浏览器控制台执行:
// 在已登录的页面中执行
fetch('/rs/overseas/application/123', {
headers: {
'Authorization': localStorage.getItem('token')
}
})
.then(res => res.json())
.then(data => console.log('position值:', data.data.position));
📊 诊断决策树
数据库中position字段有数据?
├─ 是 → API响应中有position字段?
│ ├─ 是 → position值是什么?
│ │ ├─ NULL/空字符串 → **数据库该记录position确实为空**
│ │ └─ 有值 → 前端赋值问题(需要检查state.viewData)
│ └─ 否 → **后端序列化问题**(检查VO类的Getter方法)
│
└─ 否 → **数据库该记录position确实为空**
→ 需要更新数据库数据或在新增/编辑时填写职务字段
✅ 临时解决方案(如果数据确实为空)
方案1:批量更新现有数据
如果数据库中很多记录的 position 字段为空,可以批量更新:
-- 示例:根据职称自动填充职务
UPDATE rs_overseas_application
SET position = CASE
WHEN professional_title LIKE '%教授%' THEN '教授'
WHEN professional_title LIKE '%副教授%' THEN '副教授'
WHEN professional_title LIKE '%讲师%' THEN '讲师'
WHEN professional_title LIKE '%主任%' THEN '主任'
ELSE '教师'
END
WHERE (position IS NULL OR position = '')
AND deleted = '0';
方案2:前端表单新增/编辑时强制填写
在前端表单中将 position 字段设为必填项:
<!-- web/src/views/rs/overseas/index.vue -->
<el-form-item label="职务" prop="position">
<el-input v-model="applicationForm.position" placeholder="请输入职务" />
</el-form-item>
<!-- 表单验证规则 -->
<script setup lang="ts">
const rules = {
position: [
{ required: true, message: '请输入职务', trigger: 'blur' }
]
};
</script>
📝 总结
代码层面
✅ 所有代码都是正确的,从数据库到前端的完整链路都没有问题。
问题本质
❓ 最可能的原因:数据库中查看的这条记录的 position 字段确实为空(NULL或空字符串)。
下一步
请用户按照诊断步骤执行检查,确认:
- 数据库中该记录的
position字段实际值 - 后端API响应中的
position字段值 - 是否有缓存影响
📁 附件文件
已生成以下诊断文件:
- ✅
检查职务字段数据.sql- 数据库诊断SQL脚本
诊断完成时间: 2025-10-09
诊断结论: 代码层面无问题,需要确认数据库实际数据
文档版本: v1.0