diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java index 6152aa66..2fb5b396 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java @@ -208,4 +208,20 @@ public class XgStudentMsgController extends BaseController { public R 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 getPersonalInfo(@RequestParam(required = false) Long userId) { + XgStudentMsgVo personalInfo = xgStudentMsgService.queryPersonalInfo(userId); + if (personalInfo == null) { + return R.fail("未找到学生信息"); + } + return R.ok(personalInfo); + } } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentMsgService.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentMsgService.java index edfc0d9f..442c56ce 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentMsgService.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentMsgService.java @@ -77,4 +77,12 @@ public interface IXgStudentMsgService { * @return 是否删除成功 */ Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 查询学生个人信息 + * + * @param userId 用户ID,可为空,为空时使用当前登录用户ID + * @return 学生信息 + */ + XgStudentMsgVo queryPersonalInfo(Long userId); } diff --git a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java index 6f5e533d..a2d0c83f 100644 --- a/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java +++ b/backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java @@ -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() + .eq(XgStudentMsg::getDeleted, 0) + .eq(XgStudentMsg::getId, userId)); + } } diff --git a/docs/变更管理/code-adjust-record-2025-01-27-stuPersonalMsg-api-integration.md b/docs/变更管理/code-adjust-record-2025-01-27-stuPersonalMsg-api-integration.md new file mode 100644 index 00000000..9d81e9ac --- /dev/null +++ b/docs/变更管理/code-adjust-record-2025-01-27-stuPersonalMsg-api-integration.md @@ -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` 学生信息对象 + +### 2. 前端API接口 + +**文件**: `web/src/api/studentMsg/studentMsg/index.ts` + +- **新增方法**: `getPersonalInfo(userId?: number)` +- **功能**: 调用后端获取个人信息API +- **返回**: `AxiosPromise` + +### 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调用频率和性能 \ No newline at end of file diff --git a/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md b/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md index 7802df06..47d8d85f 100644 --- a/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md +++ b/docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md @@ -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 = { + '1': '未婚', + '2': '已婚', + '3': '离异', + '4': '丧偶' + }; + return maritalStatusMap[String(value)] || value || '未知'; +}; ``` -**修复后**: -```javascript -// 修复:0 也是有效值,需要正确处理 -if (value === null || value === undefined || value === '') return ''; +**模板变更**: +```vue + +{{ ['', '未婚', '已婚', '离异', '丧偶'][detailForm.maritalStatus] || detailForm.maritalStatus }} + + +{{ getMaritalStatusLabel(detailForm.maritalStatus) }} ``` -### 修复原理 +### 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 = { + '富裕': '富裕', + '一般': '一般', + '困难': '困难', + '特困': '特困' + }; + return economicStatusMap[String(value)] || value || '未知'; +}; +``` -## 📝 相关文件 +**模板变更**: +```vue + +{{ detailForm.familyEconomicStatus }} -- **主要文件**: `web/src/views/stuMsgAudit/stuMsgDialog.vue` -- **影响范围**: 学生信息审核对话框中的字段原值显示功能 -- **测试建议**: 验证所有是否字段的原值显示是否正确转换 + +{{ getFamilyEconomicStatusLabel(detailForm.familyEconomicStatus) }} +``` -## 🔄 后续建议 +### 3. 血型码表优化 -1. **代码审查**: 检查其他类似页面是否存在同样问题 -2. **单元测试**: 为字典转换函数添加单元测试,确保边界值处理正确 -3. **文档更新**: 更新前端开发规范,明确字典转换函数的正确使用方式 \ No newline at end of file +**问题描述**: 查看详情时血型直接显示原始值,缺乏统一的码表处理 + +**解决方案**: +- 新增 `getBloodTypeLabel` 方法进行码表映射 +- 修改查看详情显示逻辑,使用码表映射方法 + +**代码变更**: +```typescript +/** 血型码表映射 */ +const getBloodTypeLabel = (value: string | number) => { + const bloodTypeMap: Record = { + 'A': 'A型', + 'B': 'B型', + 'AB': 'AB型', + 'O': 'O型', + '未知': '未知' + }; + return bloodTypeMap[String(value)] || value || '未知'; +}; +``` + +**模板变更**: +```vue + +{{ detailForm.bloodType }} + + +{{ getBloodTypeLabel(detailForm.bloodType) }} +``` + +## 变更效果 + +### 优化前 +- 婚姻状况显示逻辑复杂,使用数组索引 +- 家庭经济状况和血型直接显示原始值 +- 码表处理方式不统一 + +### 优化后 +- 所有码表字段使用统一的映射方法 +- 显示效果更加规范和一致 +- 代码可维护性提升 +- 支持未知值的友好显示 + +## 码表映射规则 + +### 婚姻状况码表 +- `1` → `未婚` +- `2` → `已婚` +- `3` → `离异` +- `4` → `丧偶` +- 其他值 → 显示原值或"未知" + +### 家庭经济状况码表 +- `富裕` → `富裕` +- `一般` → `一般` +- `困难` → `困难` +- `特困` → `特困` +- 其他值 → 显示原值或"未知" + +### 血型码表 +- `A` → `A型` +- `B` → `B型` +- `AB` → `AB型` +- `O` → `O型` +- `未知` → `未知` +- 其他值 → 显示原值或"未知" + +## 技术要点 + +1. **类型安全**: 使用 TypeScript 的 Record 类型确保码表映射的类型安全 +2. **容错处理**: 对未知值进行友好处理,避免显示空白或错误信息 +3. **统一接口**: 所有码表映射方法使用相同的参数和返回值类型 +4. **可扩展性**: 新增码表字段时只需添加对应的映射方法即可 + +## 后续建议 + +1. 可以考虑将码表映射方法抽取到公共工具文件中,供其他页面复用 +2. 建议为其他码表字段(如残疾类型、学历层次等)也应用相同的优化 +3. 可以考虑添加码表配置管理功能,支持动态配置码表映射关系 + +--- + +**变更状态**: ✅ 已完成 +**测试状态**: 🔄 待测试 +**影响范围**: 学生信息管理页面查看详情功能 \ No newline at end of file diff --git a/web/src/api/studentMsg/studentMsg/index.ts b/web/src/api/studentMsg/studentMsg/index.ts index daaf01ae..950adeef 100644 --- a/web/src/api/studentMsg/studentMsg/index.ts +++ b/web/src/api/studentMsg/studentMsg/index.ts @@ -61,3 +61,15 @@ export const delStudentMsg = (id: string | number | Array) => { method: 'delete' }); }; + +/** + * 获取学生个人信息 + * @param userId 用户ID,可为空,为空时使用当前登录用户ID + */ +export const getPersonalInfo = (userId?: number): AxiosPromise => { + return request({ + url: '/studentMsg/studentMsg/personalInfo', + method: 'get', + params: { userId } + }); +}; diff --git a/web/src/views/stuPersonalMsg/index.vue b/web/src/views/stuPersonalMsg/index.vue new file mode 100644 index 00000000..b5429a46 --- /dev/null +++ b/web/src/views/stuPersonalMsg/index.vue @@ -0,0 +1,1066 @@ + + + + + diff --git a/web/src/views/studentMsg/studentMsg/index.vue b/web/src/views/studentMsg/studentMsg/index.vue index 41eb9c75..ecdb7db4 100644 --- a/web/src/views/studentMsg/studentMsg/index.vue +++ b/web/src/views/studentMsg/studentMsg/index.vue @@ -948,7 +948,7 @@ - {{ detailForm.birthDate }} + {{ proxy.parseTime(detailForm.birthDate, '{y}-{m}-{d}') }} @@ -1053,7 +1053,7 @@ - {{ ['', '未婚', '已婚', '离异', '丧偶'][detailForm.maritalStatus] || detailForm.maritalStatus }} + {{ getMaritalStatusLabel(detailForm.maritalStatus) }} @@ -1225,7 +1225,7 @@ - {{ detailForm.familyEconomicStatus }} + {{ getFamilyEconomicStatusLabel(detailForm.familyEconomicStatus) }} @@ -1253,7 +1253,7 @@ - {{ detailForm.bloodType }} + {{ getBloodTypeLabel(detailForm.bloodType) }} @@ -1270,9 +1270,7 @@ - {{ - ['', '视力残疾', '听力残疾', '智力残疾', '', '', '', '', '', '其他残疾'][detailForm.disabilityType] || detailForm.disabilityType - }} + {{ getDisabilityTypeLabel(detailForm.disabilityType) }} @@ -1335,9 +1333,7 @@ - {{ - ['', '中级工', '高级工', '预备技师', '技师', '中高职一体'][detailForm.academicLevel] || detailForm.academicLevel - }} + {{ getAcademicLevelLabel(detailForm.academicLevel) }} @@ -1349,7 +1345,7 @@ - {{ detailForm.enrollmentDate }} + {{ proxy.parseTime(detailForm.enrollmentDate, '{y}-{m}-{d}') }} @@ -1517,6 +1513,63 @@ const sys_normal_disable = ref([ { value: '5', label: '毕业' } ]); +/** 婚姻状况码表映射 */ +const getMaritalStatusLabel = (value: string | number) => { + const maritalStatusMap: Record = { + '1': '未婚', + '2': '已婚', + '3': '离异', + '4': '丧偶' + }; + return maritalStatusMap[String(value)] || value || '未知'; +}; + +/** 家庭经济状况码表映射 */ +const getFamilyEconomicStatusLabel = (value: string | number) => { + const economicStatusMap: Record = { + '富裕': '富裕', + '一般': '一般', + '困难': '困难', + '特困': '特困' + }; + return economicStatusMap[String(value)] || value || '未知'; +}; + +/** 血型码表映射 */ +const getBloodTypeLabel = (value: string | number) => { + const bloodTypeMap: Record = { + 'A': 'A型', + 'B': 'B型', + 'AB': 'AB型', + 'O': 'O型', + '未知': '未知' + }; + return bloodTypeMap[String(value)] || value || '未知'; +}; + +/** 残疾类型码表映射 */ +const getDisabilityTypeLabel = (value: string | number) => { + const disabilityTypeMap: Record = { + '1': '视力残疾', + '2': '听力残疾', + '3': '智力残疾', + '9': '其他残疾' + }; + return disabilityTypeMap[String(value)] || value || '未知'; +}; + +/** 学历层级码表映射 */ +const getAcademicLevelLabel = (value: string | number) => { + const academicLevelMap: Record = { + '1': '中级工', + '2': '高级工', + '3': '预备技师', + '4': '技师', + '5': '中高职一体' + }; + return academicLevelMap[String(value)] || value || '未知'; +}; + const activeTab = ref('basic'); // 当前激活的tab页 const activeDetailTab = ref('basic'); // 当前激活的详细信息tab页