修改学生预览界面的bug

This commit is contained in:
zlwu committed 2025-07-28 10:05:53 +08:00
1 parent 244477a771
commit 760fd8d07a
8 files changed
+1483 -59

No files matched your search

@@ -208,4 +208,20 @@ public class XgStudentMsgController extends BaseController {
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable Long[] ids) {
return toAjax(xgStudentMsgService.deleteWithValidByIds(List.of(ids), true));
}
/**
* 查询学生个人信息
*
* @param userId 用户ID,可为空,为空时使用当前登录用户ID
* @return 学生信息
*/
@SaCheckPermission("studentMsg:studentMsg:query")
@GetMapping("/personalInfo")
public R<XgStudentMsgVo> getPersonalInfo(@RequestParam(required = false) Long userId) {
XgStudentMsgVo personalInfo = xgStudentMsgService.queryPersonalInfo(userId);
if (personalInfo == null) {
return R.fail("未找到学生信息");
}
return R.ok(personalInfo);
}
}
@@ -77,4 +77,12 @@ public interface IXgStudentMsgService {
* @return 是否删除成功
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 查询学生个人信息
*
* @param userId 用户ID,可为空,为空时使用当前登录用户ID
* @return 学生信息
*/
XgStudentMsgVo queryPersonalInfo(Long userId);
}
@@ -28,6 +28,7 @@ import java.util.Map;
import java.util.Collection;
import java.util.ArrayList;
import java.util.stream.Collectors;
import org.dromara.common.satoken.utils.LoginHelper;
/**
* 学生信息Service业务层处理
@@ -444,4 +445,23 @@ public class XgStudentMsgServiceImpl implements IXgStudentMsgService {
return studentDeleteResult;
}
/**
* 查询学生个人信息
*
* @param userId 用户ID,可为空,为空时使用当前登录用户ID
* @return 学生信息
*/
@Override
public XgStudentMsgVo queryPersonalInfo(Long userId) {
// 如果userId为空,使用当前登录用户ID
if (userId == null) {
userId = LoginHelper.getUserId();
}
// deleted 为0 且 用户ID为userId
return baseMapper.selectVoOne(new LambdaQueryWrapper<XgStudentMsg>()
.eq(XgStudentMsg::getDeleted, 0)
.eq(XgStudentMsg::getId, userId));
}
}
@@ -0,0 +1,156 @@
# 学生个人信息页面API集成修改记录
**修改时间**: 2025-01-27 15:30:00
**修改人员**: AI Assistant
**修改类型**: 功能增强
## 修改概述
将学生个人信息页面(`web/src/views/stuPersonalMsg/index.vue`)从静态数据展示改为动态API数据获取,实现界面初始化时自动调用后端API获取当前登录学生的个人信息并渲染表单。
## 修改内容
### 1. 后端API接口
**文件**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java`
- **接口路径**: `GET /studentMsg/studentMsg/personalInfo`
- **功能**: 查询学生个人信息
- **参数**: `userId` (可选,为空时使用当前登录用户ID)
- **返回**: `R<XgStudentMsgBo>` 学生信息对象
### 2. 前端API接口
**文件**: `web/src/api/studentMsg/studentMsg/index.ts`
- **新增方法**: `getPersonalInfo(userId?: number)`
- **功能**: 调用后端获取个人信息API
- **返回**: `AxiosPromise<StudentMsgForm>`
### 3. 前端页面修改
**文件**: `web/src/views/stuPersonalMsg/index.vue`
#### 3.1 导入修改
```typescript
// 新增导入
import request from '@/utils/request';
import ElMessage from 'element-plus/es/components/message/index';
```
#### 3.2 数据初始化
- 移除所有硬编码的模拟数据
- 将表单字段初始化为空值或undefined
- 添加loading状态管理
#### 3.3 API调用方法
```typescript
/** 获取学生个人信息 */
const getPersonalInfoData = async () => {
try {
loading.value = true;
const response = await request({
url: '/studentMsg/studentMsg/personalInfo',
method: 'get'
});
if (response.data.code === 200) {
const data = response.data.data;
// 将API返回的数据映射到表单
Object.assign(form, data);
} else {
ElMessage.error(response.data.msg || '获取个人信息失败');
}
} catch (error) {
console.error('获取个人信息失败:', error);
ElMessage.error('获取个人信息失败,请稍后重试');
} finally {
loading.value = false;
}
};
```
#### 3.4 模板修改
- 添加`v-loading="loading"`到主卡片组件
- 修改头部信息显示为动态数据:`{{ form.studentNo }}` 和 `{{ form.name }}`
- 添加条件渲染:`v-if="form.studentNo && form.name"`
#### 3.5 生命周期修改
```typescript
onMounted(async () => {
await Promise.all([getRegionTree(), getDormBuildingTree()]);
// 获取个人信息
await getPersonalInfoData();
});
```
## 技术实现要点
### 1. 数据映射
- 使用`Object.assign(form, data)`将API返回的数据直接映射到表单对象
- 保持表单字段与API返回字段的一致性
### 2. 错误处理
- 添加try-catch错误捕获
- 使用ElMessage显示友好的错误提示
- 区分API错误和网络错误
### 3. 加载状态
- 添加loading状态管理
- 在API调用期间显示加载动画
- 防止用户重复操作
### 4. 用户体验
- 保持原有的Tab页布局和表单样式
- 所有表单字段保持disabled状态(只读展示)
- 动态显示学生学号和姓名信息
## 测试验证
### 1. 功能测试
- [ ] 页面加载时自动调用API获取个人信息
- [ ] API返回数据正确渲染到表单
- [ ] 加载状态正常显示和隐藏
- [ ] 错误情况下的提示信息正确
### 2. 兼容性测试
- [ ] 不同浏览器下的正常显示
- [ ] 响应式布局在不同屏幕尺寸下的表现
- [ ] 字典数据的正确显示
### 3. 异常测试
- [ ] 网络异常时的错误处理
- [ ] API返回错误时的提示
- [ ] 数据为空时的页面显示
## 相关文档
- **API文档**: `docs/开发文档/API/学生信息管理API.md`
- **前端规范**: `.cursor/cursorrules-frontend.md`
- **后端规范**: `.cursor/cursorrules-backend.md`
## 后续优化建议
1. **数据缓存**: 考虑添加本地缓存,避免重复请求
2. **实时更新**: 添加定时刷新或手动刷新功能
3. **权限控制**: 根据用户权限显示不同的信息字段
4. **数据验证**: 添加前端数据格式验证
5. **性能优化**: 考虑分页加载大量数据
## 变更影响
### 正面影响
- 实现真实数据展示,提升用户体验
- 统一数据源,避免数据不一致
- 支持多用户个性化信息展示
### 潜在风险
- 依赖后端API可用性
- 需要确保API权限配置正确
- 网络异常可能影响页面显示
## 部署注意事项
1. 确保后端API服务正常运行
2. 验证用户权限配置
3. 测试网络连接和API响应时间
4. 监控API调用频率和性能
@@ -1,68 +1,161 @@
# 学生信息审核对话框字段原值显示修复记录
# 学生信息管理页面码表显示优化记录
**变更时间**: 2025-01-27 15:30:00
**变更时间**: 2025-01-27 14:30:00
**变更人员**: wuzilong
**变更文件**: `web/src/views/stuMsgAudit/stuMsgDialog.vue`
**变更文件**: `web/src/views/studentMsg/studentMsg/index.vue`
## 🔧 问题描述
## 变更概述
在学生信息审核对话框中,助学贷款等字段的变动标识中显示原值时,对于值为 `0` 的字段没有正确转换为字典标签,而是直接显示数字 `0`。
对学生信息管理页面的查看详情功能进行了码表显示优化,统一了码表映射的处理方式,提升了用户体验和代码一致性。
**具体问题**:
- 助学贷款字段 `hasLoan` 原值为 `0` 时,显示为 "原值:0" 而不是 "原值:否"
- 其他类似的是否字段也存在同样问题
## 具体变更内容
**根本原因**:
- 各个字典转换函数使用 `if (!value)` 判断,将 `0` 误判为 falsy 值
- 导致值为 `0` 的字段直接返回原值,没有进行字典转换
### 1. 婚姻状况码表优化
## 🛠️ 修复方案
**问题描述**: 查看详情时婚姻状况显示逻辑不一致,使用了数组索引方式
### 修复的函数列表
**解决方案**:
- 新增 `getMaritalStatusLabel` 方法进行码表映射
- 修改查看详情显示逻辑,使用码表映射方法
1. **getDictLabel** - 字典值转换函数
2. **getMaritalStatusLabel** - 婚姻状况转换函数
3. **getYesNoLabel** - 是否字段转换函数
4. **getBloodTypeLabel** - 血型转换函数
5. **getDisabilityTypeLabel** - 残疾类型转换函数
6. **getAcademicLevelLabel** - 学历层次转换函数
7. **getStudentStatusLabel** - 学籍状态转换函数
### 修复内容
**修复前**:
```javascript
if (!value) return value || '';
**代码变更**:
```typescript
/** 婚姻状况码表映射 */
const getMaritalStatusLabel = (value: string | number) => {
const maritalStatusMap: Record<string, string> = {
'1': '未婚',
'2': '已婚',
'3': '离异',
'4': '丧偶'
};
return maritalStatusMap[String(value)] || value || '未知';
};
```
**修复后**:
```javascript
// 修复:0 也是有效值,需要正确处理
if (value === null || value === undefined || value === '') return '';
**模板变更**:
```vue
<!-- 修改前 -->
<span class="form-value">{{ ['', '未婚', '已婚', '离异', '丧偶'][detailForm.maritalStatus] || detailForm.maritalStatus }}</span>
<!-- 修改后 -->
<span class="form-value">{{ getMaritalStatusLabel(detailForm.maritalStatus) }}</span>
```
### 修复原理
### 2. 家庭经济状况码表优化
- **问题**: `if (!value)` 会将 `0` 判断为 falsy 值,导致直接返回原值
- **解决**: 明确判断 `null`、`undefined`、空字符串,保留 `0` 作为有效值进行字典转换
- **效果**: 值为 `0` 的是否字段现在会正确显示为 "否"
**问题描述**: 查看详情时家庭经济状况直接显示原始值,缺乏统一的码表处理
## ✅ 验证结果
**解决方案**:
- 新增 `getFamilyEconomicStatusLabel` 方法进行码表映射
- 修改查看详情显示逻辑,使用码表映射方法
修复后,助学贷款等字段的原值显示将正确转换为字典标签:
- `hasLoan: 0` → 显示 "否"
- `isPoorStudent: 0` → 显示 "否"
- `isMinority: 0` → 显示 "否"
- 其他类似字段同理
**代码变更**:
```typescript
/** 家庭经济状况码表映射 */
const getFamilyEconomicStatusLabel = (value: string | number) => {
const economicStatusMap: Record<string, string> = {
'富裕': '富裕',
'一般': '一般',
'困难': '困难',
'特困': '特困'
};
return economicStatusMap[String(value)] || value || '未知';
};
```
## 📝 相关文件
**模板变更**:
```vue
<!-- 修改前 -->
<span class="form-value">{{ detailForm.familyEconomicStatus }}</span>
- **主要文件**: `web/src/views/stuMsgAudit/stuMsgDialog.vue`
- **影响范围**: 学生信息审核对话框中的字段原值显示功能
- **测试建议**: 验证所有是否字段的原值显示是否正确转换
<!-- 修改后 -->
<span class="form-value">{{ getFamilyEconomicStatusLabel(detailForm.familyEconomicStatus) }}</span>
```
## 🔄 后续建议
### 3. 血型码表优化
1. **代码审查**: 检查其他类似页面是否存在同样问题
2. **单元测试**: 为字典转换函数添加单元测试,确保边界值处理正确
3. **文档更新**: 更新前端开发规范,明确字典转换函数的正确使用方式
**问题描述**: 查看详情时血型直接显示原始值,缺乏统一的码表处理
**解决方案**:
- 新增 `getBloodTypeLabel` 方法进行码表映射
- 修改查看详情显示逻辑,使用码表映射方法
**代码变更**:
```typescript
/** 血型码表映射 */
const getBloodTypeLabel = (value: string | number) => {
const bloodTypeMap: Record<string, string> = {
'A': 'A型',
'B': 'B型',
'AB': 'AB型',
'O': 'O型',
'未知': '未知'
};
return bloodTypeMap[String(value)] || value || '未知';
};
```
**模板变更**:
```vue
<!-- 修改前 -->
<span class="form-value">{{ detailForm.bloodType }}</span>
<!-- 修改后 -->
<span class="form-value">{{ getBloodTypeLabel(detailForm.bloodType) }}</span>
```
## 变更效果
### 优化前
- 婚姻状况显示逻辑复杂,使用数组索引
- 家庭经济状况和血型直接显示原始值
- 码表处理方式不统一
### 优化后
- 所有码表字段使用统一的映射方法
- 显示效果更加规范和一致
- 代码可维护性提升
- 支持未知值的友好显示
## 码表映射规则
### 婚姻状况码表
- `1` → `未婚`
- `2` → `已婚`
- `3` → `离异`
- `4` → `丧偶`
- 其他值 → 显示原值或"未知"
### 家庭经济状况码表
- `富裕` → `富裕`
- `一般` → `一般`
- `困难` → `困难`
- `特困` → `特困`
- 其他值 → 显示原值或"未知"
### 血型码表
- `A` → `A型`
- `B` → `B型`
- `AB` → `AB型`
- `O` → `O型`
- `未知` → `未知`
- 其他值 → 显示原值或"未知"
## 技术要点
1. **类型安全**: 使用 TypeScript 的 Record 类型确保码表映射的类型安全
2. **容错处理**: 对未知值进行友好处理,避免显示空白或错误信息
3. **统一接口**: 所有码表映射方法使用相同的参数和返回值类型
4. **可扩展性**: 新增码表字段时只需添加对应的映射方法即可
## 后续建议
1. 可以考虑将码表映射方法抽取到公共工具文件中,供其他页面复用
2. 建议为其他码表字段(如残疾类型、学历层次等)也应用相同的优化
3. 可以考虑添加码表配置管理功能,支持动态配置码表映射关系
---
**变更状态**: ✅ 已完成
**测试状态**: 🔄 待测试
**影响范围**: 学生信息管理页面查看详情功能
@@ -61,3 +61,15 @@ export const delStudentMsg = (id: string | number | Array<string | number>) => {
method: 'delete'
});
};
/**
* 获取学生个人信息
* @param userId 用户ID,可为空,为空时使用当前登录用户ID
*/
export const getPersonalInfo = (userId?: number): AxiosPromise<StudentMsgForm> => {
return request({
url: '/studentMsg/studentMsg/personalInfo',
method: 'get',
params: { userId }
});
};
File diff suppressed because it is too large. Load diff
+64 -11
View File
@@ -948,7 +948,7 @@
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="出生日期">
<span class="form-value">{{ detailForm.birthDate }}</span>
<span class="form-value">{{ proxy.parseTime(detailForm.birthDate, '{y}-{m}-{d}') }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -1053,7 +1053,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="婚姻状况">
<span class="form-value">{{ ['', '未婚', '已婚', '离异', '丧偶'][detailForm.maritalStatus] || detailForm.maritalStatus }}</span>
<span class="form-value">{{ getMaritalStatusLabel(detailForm.maritalStatus) }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1225,7 +1225,7 @@
<el-row :gutter="20">
<el-col :span="8">
<el-form-item label="家庭经济状况">
<span class="form-value">{{ detailForm.familyEconomicStatus }}</span>
<span class="form-value">{{ getFamilyEconomicStatusLabel(detailForm.familyEconomicStatus) }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -1253,7 +1253,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="血型">
<span class="form-value">{{ detailForm.bloodType }}</span>
<span class="form-value">{{ getBloodTypeLabel(detailForm.bloodType) }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1270,9 +1270,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="残疾类型">
<span class="form-value">{{
['', '视力残疾', '听力残疾', '智力残疾', '', '', '', '', '', '其他残疾'][detailForm.disabilityType] || detailForm.disabilityType
}}</span>
<span class="form-value">{{ getDisabilityTypeLabel(detailForm.disabilityType) }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1335,9 +1333,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="学历层次">
<span class="form-value">{{
['', '中级工', '高级工', '预备技师', '技师', '中高职一体'][detailForm.academicLevel] || detailForm.academicLevel
}}</span>
<span class="form-value">{{ getAcademicLevelLabel(detailForm.academicLevel) }}</span>
</el-form-item>
</el-col>
</el-row>
@@ -1349,7 +1345,7 @@
</el-col>
<el-col :span="8">
<el-form-item label="入学日期">
<span class="form-value">{{ detailForm.enrollmentDate }}</span>
<span class="form-value">{{ proxy.parseTime(detailForm.enrollmentDate, '{y}-{m}-{d}') }}</span>
</el-form-item>
</el-col>
<el-col :span="8">
@@ -1517,6 +1513,63 @@ const sys_normal_disable = ref([
{ value: '5', label: '毕业' }
]);
/** 婚姻状况码表映射 */
const getMaritalStatusLabel = (value: string | number) => {
const maritalStatusMap: Record<string, string> = {
'1': '未婚',
'2': '已婚',
'3': '离异',
'4': '丧偶'
};
return maritalStatusMap[String(value)] || value || '未知';
};
/** 家庭经济状况码表映射 */
const getFamilyEconomicStatusLabel = (value: string | number) => {
const economicStatusMap: Record<string, string> = {
'富裕': '富裕',
'一般': '一般',
'困难': '困难',
'特困': '特困'
};
return economicStatusMap[String(value)] || value || '未知';
};
/** 血型码表映射 */
const getBloodTypeLabel = (value: string | number) => {
const bloodTypeMap: Record<string, string> = {
'A': 'A型',
'B': 'B型',
'AB': 'AB型',
'O': 'O型',
'未知': '未知'
};
return bloodTypeMap[String(value)] || value || '未知';
};
/** 残疾类型码表映射 */
const getDisabilityTypeLabel = (value: string | number) => {
const disabilityTypeMap: Record<string, string> = {
'1': '视力残疾',
'2': '听力残疾',
'3': '智力残疾',
'9': '其他残疾'
};
return disabilityTypeMap[String(value)] || value || '未知';
};
/** 学历层级码表映射 */
const getAcademicLevelLabel = (value: string | number) => {
const academicLevelMap: Record<string, string> = {
'1': '中级工',
'2': '高级工',
'3': '预备技师',
'4': '技师',
'5': '中高职一体'
};
return academicLevelMap[String(value)] || value || '未知';
};
const activeTab = ref('basic'); // 当前激活的tab页
const activeDetailTab = ref('basic'); // 当前激活的详细信息tab页