wuzhen update
This commit is contained in:
commit
9ea52837de
34 files changed
+6949
-1393
No files matched your search
@@ -0,0 +1,150 @@
|
||||
# 代码调整记录 - 2025-01-07 - assistant
|
||||
|
||||
## 高级检索界面参数传递功能实现
|
||||
|
||||
**时间**: 2025-01-07 22:30:00
|
||||
**修改人**: assistant
|
||||
**影响模块**: 学工管理 - 学生信息管理 - 学生花名册
|
||||
|
||||
### 修改内容
|
||||
|
||||
#### 1. 主页面功能增强
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
|
||||
**修改点1**: 高级检索按钮事件处理
|
||||
- 位置: 第66行
|
||||
- 修改前: `@click="showAdvancedSearch = true"`
|
||||
- 修改后: `@click="handleShowAdvancedSearch"`
|
||||
- 说明: 将直接显示弹窗改为调用处理方法,以便在显示前同步参数
|
||||
|
||||
**修改点2**: 高级查询参数定义增强
|
||||
- 位置: 第293-322行
|
||||
- 新增字段:
|
||||
```javascript
|
||||
studentNo: '', // 学号
|
||||
name: '', // 学生姓名
|
||||
phone: '', // 手机号码
|
||||
studentStatus: [], // 学籍状态
|
||||
```
|
||||
- 说明: 在 advancedQueryParams 中添加基础检索栏对应的字段
|
||||
|
||||
**修改点3**: 新增参数传递处理方法
|
||||
- 位置: 第481-501行
|
||||
- 新增方法: `handleShowAdvancedSearch`
|
||||
- 功能描述:
|
||||
```javascript
|
||||
const handleShowAdvancedSearch = () => {
|
||||
// 将基础检索栏的参数同步到高级检索参数中
|
||||
if (queryParams.studentNo) {
|
||||
advancedQueryParams.studentNo = queryParams.studentNo;
|
||||
}
|
||||
if (queryParams.name) {
|
||||
advancedQueryParams.name = queryParams.name;
|
||||
}
|
||||
if (queryParams.phone) {
|
||||
advancedQueryParams.phone = queryParams.phone;
|
||||
}
|
||||
// 状态对应学籍状况
|
||||
if (queryParams.studentStatus && queryParams.studentStatus.length > 0) {
|
||||
advancedQueryParams.studentStatus = [...queryParams.studentStatus];
|
||||
}
|
||||
|
||||
// 显示高级检索弹窗
|
||||
showAdvancedSearch.value = true;
|
||||
};
|
||||
```
|
||||
|
||||
### 功能说明
|
||||
|
||||
#### 实现效果
|
||||
1. **参数自动传递**: 用户在基础检索栏输入学号、姓名、手机号码、选择状态后,点击"高级检索"按钮时,这些参数会自动传递到高级检索界面
|
||||
2. **状态字段映射**: 基础检索栏的"状态"字段对应高级检索界面的"学籍状态"字段
|
||||
3. **数组类型处理**: 正确处理多选状态字段的数组格式传递
|
||||
4. **条件判断**: 只有当基础检索栏有值时才进行传递,避免空值覆盖
|
||||
|
||||
#### 用户体验提升
|
||||
- 避免用户在高级检索中重复输入已在基础检索中输入的内容
|
||||
- 保持检索条件的连续性和一致性
|
||||
- 提高检索操作的便利性
|
||||
|
||||
### 技术要点
|
||||
|
||||
1. **响应式数据同步**: 使用 reactive 对象的属性直接赋值实现参数同步
|
||||
2. **数组深拷贝**: 对于数组类型的 studentStatus 使用展开运算符进行深拷贝
|
||||
3. **条件判断**: 通过 if 判断确保只有有效值才进行传递
|
||||
4. **组件通信**: 利用高级检索组件的 watch 监听机制实现参数自动同步到表单
|
||||
|
||||
### 相关文件
|
||||
- 主页面: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
- 高级检索组件: `web/src/views/xg/xsjcxx/stuRoster/components/AdvancedSearchDialog.vue`
|
||||
|
||||
### 测试建议
|
||||
1. 在基础检索栏输入学号、姓名、手机号码,选择状态
|
||||
2. 点击"高级检索"按钮
|
||||
3. 验证高级检索界面中对应字段是否已自动填充
|
||||
4. 验证状态字段是否正确映射到学籍状态
|
||||
|
||||
---
|
||||
|
||||
# 校园管理系统代码调整记录
|
||||
|
||||
**日期**: 2025-01-07
|
||||
**操作人**: assistant
|
||||
**说明**: 记录2025年1月7日的代码调整和修改内容
|
||||
|
||||
---
|
||||
|
||||
## 2025-01-07 20:15:00 - 优化学生花名册主界面查询逻辑
|
||||
|
||||
### 🔧 修改内容
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
|
||||
**修改说明**:
|
||||
- 优化 `handleQuery` 方法,确保基本搜索时只保留检索栏的4个条件和部门树选择
|
||||
- 清除高级查询产生的额外参数,避免参数污染
|
||||
|
||||
**具体变更**:
|
||||
```javascript
|
||||
// 修改前
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNum = 1;
|
||||
getList();
|
||||
};
|
||||
|
||||
// 修改后
|
||||
const handleQuery = () => {
|
||||
// 保留基本检索条件和部门选择
|
||||
const basicSearchParams = {
|
||||
pageNum: 1,
|
||||
pageSize: queryParams.pageSize,
|
||||
studentNo: queryParams.studentNo || '',
|
||||
name: queryParams.name || '',
|
||||
phone: queryParams.phone || '',
|
||||
studentStatus: queryParams.studentStatus || [],
|
||||
deptIds: queryParams.deptIds || []
|
||||
};
|
||||
|
||||
// 清空 queryParams 对象的所有属性
|
||||
Object.keys(queryParams).forEach((key) => {
|
||||
delete queryParams[key];
|
||||
});
|
||||
|
||||
// 重新设置基本检索参数
|
||||
Object.assign(queryParams, basicSearchParams);
|
||||
|
||||
getList();
|
||||
};
|
||||
```
|
||||
|
||||
**影响范围**:
|
||||
- ✅ 基本搜索功能:只使用检索栏的4个条件进行查询
|
||||
- ✅ 部门树选择:保留左侧部门树的选择状态
|
||||
- ✅ 高级查询功能:不影响高级查询的独立功能
|
||||
- ✅ 分页功能:保持正常的分页逻辑
|
||||
|
||||
**测试验证**:
|
||||
- [x] 基本搜索按钮点击后只传递基本参数
|
||||
- [x] 部门树选择状态正常保留
|
||||
- [x] 高级查询后再使用基本搜索,额外参数被正确清除
|
||||
|
||||
---
|
||||
@@ -0,0 +1,626 @@
|
||||
# 学生信息高级检索功能开发记录
|
||||
|
||||
**变更时间**: 2025-01-27 15:30:00
|
||||
**变更人员**: zlwu
|
||||
**变更类型**: 功能新增
|
||||
**影响范围**: 学生信息管理模块
|
||||
|
||||
## 📋 变更概述
|
||||
|
||||
为前端高级检索界面完善API功能,新增学生信息高级检索功能,支持多维度、多条件的复杂查询。
|
||||
|
||||
## 🎯 功能需求
|
||||
|
||||
### 主要功能
|
||||
1. **高级检索BO类**: 创建专门的高级检索业务对象,包含所有检索字段
|
||||
2. **权限控制**: 支持部门树节点权限过滤
|
||||
3. **多维度检索**: 支持基础信息、学籍信息、学院专业班级、家庭信息、特殊身份、身体状况、住宿信息等多个维度
|
||||
4. **灵活查询**: 文本类参数支持模糊查询,数值类参数支持范围查询,时间类参数支持时间范围查询
|
||||
|
||||
### 检索维度
|
||||
- **基础信息检索**: 学号、姓名、身份证号、手机号码、邮箱、性别、民族、政治面貌、出生日期
|
||||
- **学籍信息检索**: 学籍状态、入学年份、入学日期、录取类别
|
||||
- **学院专业班级检索**: 学院名称、专业名称、班级名称、年级、辅导员姓名、班主任姓名
|
||||
- **家庭信息检索**: 父亲姓名、母亲姓名、监护人姓名、家庭年收入、人均收入、家庭经济状况、家庭成员数量
|
||||
- **特殊身份检索**: 贫困生、少数民族、残疾、孤儿、留守儿童、独生子女、低保、助学贷款
|
||||
- **身体状况检索**: 身高、体重、血型、健康状况、残疾类型、残疾等级
|
||||
- **住宿信息检索**: 是否住校、宿舍楼栋、宿舍房间号
|
||||
- **其他信息检索**: 籍贯、生源地区、毕业院校、户口类型、文化程度、培养方式、学历层次、学制
|
||||
- **时间范围检索**: 创建时间、更新时间
|
||||
|
||||
## 🔧 技术实现
|
||||
|
||||
### 1. 新增文件
|
||||
|
||||
#### 1.1 高级检索BO类
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/domain/bo/XgStudentMsgAdvancedSearchBo.java`
|
||||
|
||||
**主要特性**:
|
||||
- 包含所有检索维度的字段定义
|
||||
- 支持文本模糊查询、数值范围查询、时间范围查询
|
||||
- 包含部门树节点ID列表
|
||||
- 包含分页参数
|
||||
|
||||
**关键字段**:
|
||||
```java
|
||||
// 基础信息检索
|
||||
private String studentNo; // 学号(模糊查询)
|
||||
private String name; // 姓名(模糊查询)
|
||||
private String idCard; // 身份证号(模糊查询)
|
||||
private String phone; // 手机号码(模糊查询)
|
||||
private String email; // 邮箱(模糊查询)
|
||||
private String gender; // 性别:0-男,1-女
|
||||
private String nationality; // 民族
|
||||
private String politicalStatus; // 政治面貌
|
||||
private Date birthDateStart; // 出生日期范围 - 开始
|
||||
private Date birthDateEnd; // 出生日期范围 - 结束
|
||||
|
||||
// 学籍信息检索
|
||||
private String studentStatus; // 学籍状态
|
||||
private Long enrollmentYearStart; // 入学年份范围 - 开始
|
||||
private Long enrollmentYearEnd; // 入学年份范围 - 结束
|
||||
private Date enrollmentDateStart; // 入学日期范围 - 开始
|
||||
private Date enrollmentDateEnd; // 入学日期范围 - 结束
|
||||
private String admissionCategory; // 录取类别
|
||||
|
||||
// 学院专业班级检索
|
||||
private String collegeName; // 学院名称(模糊查询)
|
||||
private String majorName; // 专业名称(模糊查询)
|
||||
private String className; // 班级名称(模糊查询)
|
||||
private String grade; // 年级
|
||||
private String counselorName; // 辅导员姓名(模糊查询)
|
||||
private String classTeacherName; // 班主任姓名(模糊查询)
|
||||
|
||||
// 家庭信息检索
|
||||
private String fatherName; // 父亲姓名(模糊查询)
|
||||
private String motherName; // 母亲姓名(模糊查询)
|
||||
private String guardianName; // 监护人姓名(模糊查询)
|
||||
private Double familyIncomeMin; // 家庭年收入范围 - 最小值
|
||||
private Double familyIncomeMax; // 家庭年收入范围 - 最大值
|
||||
private Double perCapitaIncomeMin; // 人均收入范围 - 最小值
|
||||
private Double perCapitaIncomeMax; // 人均收入范围 - 最大值
|
||||
private String familyEconomicStatus; // 家庭经济状况
|
||||
private Long familyMembersMin; // 家庭成员数量范围 - 最小值
|
||||
private Long familyMembersMax; // 家庭成员数量范围 - 最大值
|
||||
|
||||
// 特殊身份检索
|
||||
private Long isPoorStudent; // 是否贫困生:0-否,1-是
|
||||
private Long isMinority; // 是否少数民族:0-否,1-是
|
||||
private Long isDisabled; // 是否残疾:0-否,1-是
|
||||
private Long isOrphan; // 是否孤儿:0-否,1-是
|
||||
private Long isLeftBehindChild; // 是否留守儿童:0-否,1-是
|
||||
private Long isSingleChild; // 是否独生子女:0-否,1-是
|
||||
private Long isLowIncome; // 是否低保:0-否,1-是
|
||||
private Long hasLoan; // 是否有助学贷款:0-否,1-是
|
||||
private Double loanAmountMin; // 助学贷款金额范围 - 最小值
|
||||
private Double loanAmountMax; // 助学贷款金额范围 - 最大值
|
||||
|
||||
// 身体状况检索
|
||||
private Double heightMin; // 身高范围 - 最小值(cm)
|
||||
private Double heightMax; // 身高范围 - 最大值(cm)
|
||||
private Double weightMin; // 体重范围 - 最小值(kg)
|
||||
private Double weightMax; // 体重范围 - 最大值(kg)
|
||||
private String bloodType; // 血型
|
||||
private String healthStatus; // 健康状况
|
||||
private String disabilityType; // 残疾类型
|
||||
private String disabilityLevel; // 残疾等级
|
||||
|
||||
// 住宿信息检索
|
||||
private Long isBoarder; // 是否住校:0-否,1-是
|
||||
private String dormitoryBuilding; // 宿舍楼栋(模糊查询)
|
||||
private String dormitoryRoom; // 宿舍房间号(模糊查询)
|
||||
|
||||
// 其他信息检索
|
||||
private String nativePlace; // 籍贯(模糊查询)
|
||||
private String sourceRegion; // 生源地区(省市县)
|
||||
private String graduateSchool; // 毕业院校(模糊查询)
|
||||
private String householdRegisterType; // 户口类型:农业、非农业
|
||||
private String educationLevel; // 文化程度
|
||||
private String trainingType; // 培养方式:全日制、在职、函授、夜大等
|
||||
private String academicLevel; // 学历层次
|
||||
private Long schoolSystemMin; // 学制范围 - 最小值(年)
|
||||
private Long schoolSystemMax; // 学制范围 - 最大值(年)
|
||||
private String infoStatus; // 信息状态:1-正常,2-待审核,3-审核中,4-已驳回,5-已锁定
|
||||
private String dataSource; // 数据来源:manual-手工录入,import-批量导入,sync-系统同步
|
||||
private Long isComplete; // 信息是否完整:0-不完整,1-完整
|
||||
private Double completionRateMin; // 完整度百分比范围 - 最小值
|
||||
private Double completionRateMax; // 完整度百分比范围 - 最大值
|
||||
|
||||
// 时间范围检索
|
||||
private Date createTimeStart; // 创建时间范围 - 开始
|
||||
private Date createTimeEnd; // 创建时间范围 - 结束
|
||||
private Date updateTimeStart; // 更新时间范围 - 开始
|
||||
private Date updateTimeEnd; // 更新时间范围 - 结束
|
||||
|
||||
// 部门树节点
|
||||
private List<Long> deptIds; // 部门树勾选的节点ID列表
|
||||
|
||||
// 分页参数
|
||||
private Integer pageNum = 1; // 分页参数
|
||||
private Integer pageSize = 10; // 分页大小
|
||||
```
|
||||
|
||||
### 2. 修改文件
|
||||
|
||||
#### 2.1 Service接口扩展
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/IXgStudentMsgService.java`
|
||||
|
||||
**新增方法**:
|
||||
```java
|
||||
/**
|
||||
* 高级检索学生信息
|
||||
*
|
||||
* @param bo 高级检索条件
|
||||
* @return 学生信息分页列表
|
||||
*/
|
||||
TableDataInfo<XgStudentMsgVo> advancedSearch(XgStudentMsgAdvancedSearchBo bo);
|
||||
```
|
||||
|
||||
#### 2.2 Service实现类扩展
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/service/impl/XgStudentMsgServiceImpl.java`
|
||||
|
||||
**新增方法**:
|
||||
```java
|
||||
/**
|
||||
* 高级检索学生信息
|
||||
*/
|
||||
@Override
|
||||
public TableDataInfo<XgStudentMsgVo> advancedSearch(XgStudentMsgAdvancedSearchBo bo) {
|
||||
// 第一步:权限过滤,获取过滤后的deptIds
|
||||
List<Long> filteredDeptIds = filterDeptIdsForAdvancedSearch(bo.getDeptIds());
|
||||
|
||||
// 第二步:构建高级检索查询条件
|
||||
LambdaQueryWrapper<XgStudentMsg> lqw = buildAdvancedSearchQueryWrapper(bo);
|
||||
|
||||
// 第三步:分页查询学生信息
|
||||
Page<XgStudentMsgVo> result = baseMapper.selectPageByDeptIds(
|
||||
new Page<>(bo.getPageNum(), bo.getPageSize()), lqw, filteredDeptIds);
|
||||
return TableDataInfo.build(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 权限过滤方法 - 高级检索专用
|
||||
*/
|
||||
private List<Long> filterDeptIdsForAdvancedSearch(List<Long> deptIds) {
|
||||
// 获取当前登录用户ID
|
||||
Long currentUserId = LoginHelper.getUserId();
|
||||
|
||||
// 判断当前用户是否为全校管理员
|
||||
boolean isSchoolManager = checkIsSchoolManager(currentUserId);
|
||||
if (isSchoolManager) {
|
||||
return getDeptIdsWithChildrenForAdvancedSearch(deptIds);
|
||||
}
|
||||
|
||||
// 获取用户的总权限集合
|
||||
Set<Long> userAuthDeptIds = getUserAuthDeptIds(currentUserId);
|
||||
|
||||
// 过滤deptIds,只保留在权限范围内的
|
||||
List<Long> filteredDeptIds = new ArrayList<>();
|
||||
if (deptIds != null && !deptIds.isEmpty()) {
|
||||
for (Long deptId : deptIds) {
|
||||
List<Long> deptIdsWithChildren = getDeptIdsWithChildren(deptId);
|
||||
for (Long deptIdWithChild : deptIdsWithChildren) {
|
||||
if (userAuthDeptIds.contains(deptIdWithChild)) {
|
||||
filteredDeptIds.add(deptIdWithChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
filteredDeptIds.addAll(userAuthDeptIds);
|
||||
}
|
||||
|
||||
// 对过滤后的deptIds,查找所有子组织包括他们自己
|
||||
Set<Long> finalDeptIds = new HashSet<>();
|
||||
for (Long filteredDeptId : filteredDeptIds) {
|
||||
List<Long> deptIdsWithChildren = getDeptIdsWithChildren(filteredDeptId);
|
||||
finalDeptIds.addAll(deptIdsWithChildren);
|
||||
}
|
||||
|
||||
return new ArrayList<>(finalDeptIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建高级检索查询条件包装器
|
||||
*/
|
||||
private LambdaQueryWrapper<XgStudentMsg> buildAdvancedSearchQueryWrapper(XgStudentMsgAdvancedSearchBo bo) {
|
||||
LambdaQueryWrapper<XgStudentMsg> lqw = Wrappers.lambdaQuery();
|
||||
|
||||
// 基础查询条件
|
||||
lqw.eq(XgStudentMsg::getDeleted, 0); // 未删除
|
||||
|
||||
// ==================== 基础信息检索 ====================
|
||||
// 文本类参数使用like查询
|
||||
lqw.like(StringUtils.isNotBlank(bo.getStudentNo()), XgStudentMsg::getStudentNo, bo.getStudentNo());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getName()), XgStudentMsg::getName, bo.getName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getIdCard()), XgStudentMsg::getIdCard, bo.getIdCard());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getPhone()), XgStudentMsg::getPhone, bo.getPhone());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getEmail()), XgStudentMsg::getEmail, bo.getEmail());
|
||||
|
||||
// 精确匹配参数
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getGender()), XgStudentMsg::getGender, bo.getGender());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getNationality()), XgStudentMsg::getNationality, bo.getNationality());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getPoliticalStatus()), XgStudentMsg::getPoliticalStatus, bo.getPoliticalStatus());
|
||||
|
||||
// 时间范围查询
|
||||
if (bo.getBirthDateStart() != null && bo.getBirthDateEnd() != null) {
|
||||
lqw.between(XgStudentMsg::getBirthDate, bo.getBirthDateStart(), bo.getBirthDateEnd());
|
||||
}
|
||||
|
||||
// ==================== 学籍信息检索 ====================
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getStudentStatus()), XgStudentMsg::getStudentStatus, bo.getStudentStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAdmissionCategory()), XgStudentMsg::getAdmissionCategory, bo.getAdmissionCategory());
|
||||
|
||||
// 数值范围查询
|
||||
if (bo.getEnrollmentYearStart() != null && bo.getEnrollmentYearEnd() != null) {
|
||||
lqw.between(XgStudentMsg::getEnrollmentYear, bo.getEnrollmentYearStart(), bo.getEnrollmentYearEnd());
|
||||
}
|
||||
|
||||
// 时间范围查询
|
||||
if (bo.getEnrollmentDateStart() != null && bo.getEnrollmentDateEnd() != null) {
|
||||
lqw.between(XgStudentMsg::getEnrollmentDate, bo.getEnrollmentDateStart(), bo.getEnrollmentDateEnd());
|
||||
}
|
||||
|
||||
// ==================== 学院专业班级检索 ====================
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgStudentMsg::getCollegeName, bo.getCollegeName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgStudentMsg::getMajorName, bo.getMajorName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgStudentMsg::getClassName, bo.getClassName());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getGrade()), XgStudentMsg::getGrade, bo.getGrade());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getCounselorName()), XgStudentMsg::getCounselorName, bo.getCounselorName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getClassTeacherName()), XgStudentMsg::getClassTeacherName, bo.getClassTeacherName());
|
||||
|
||||
// ==================== 家庭信息检索 ====================
|
||||
lqw.like(StringUtils.isNotBlank(bo.getFatherName()), XgStudentMsg::getFatherName, bo.getFatherName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getMotherName()), XgStudentMsg::getMotherName, bo.getMotherName());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getGuardianName()), XgStudentMsg::getGuardianName, bo.getGuardianName());
|
||||
|
||||
// 数值范围查询
|
||||
if (bo.getFamilyIncomeMin() != null && bo.getFamilyIncomeMax() != null) {
|
||||
lqw.between(XgStudentMsg::getFamilyIncome, bo.getFamilyIncomeMin(), bo.getFamilyIncomeMax());
|
||||
}
|
||||
if (bo.getPerCapitaIncomeMin() != null && bo.getPerCapitaIncomeMax() != null) {
|
||||
lqw.between(XgStudentMsg::getPerCapitaIncome, bo.getPerCapitaIncomeMin(), bo.getPerCapitaIncomeMax());
|
||||
}
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getFamilyEconomicStatus()), XgStudentMsg::getFamilyEconomicStatus, bo.getFamilyEconomicStatus());
|
||||
if (bo.getFamilyMembersMin() != null && bo.getFamilyMembersMax() != null) {
|
||||
lqw.between(XgStudentMsg::getFamilyMembers, bo.getFamilyMembersMin(), bo.getFamilyMembersMax());
|
||||
}
|
||||
|
||||
// ==================== 特殊身份检索 ====================
|
||||
lqw.eq(bo.getIsPoorStudent() != null, XgStudentMsg::getIsPoorStudent, bo.getIsPoorStudent());
|
||||
lqw.eq(bo.getIsMinority() != null, XgStudentMsg::getIsMinority, bo.getIsMinority());
|
||||
lqw.eq(bo.getIsDisabled() != null, XgStudentMsg::getIsDisabled, bo.getIsDisabled());
|
||||
lqw.eq(bo.getIsOrphan() != null, XgStudentMsg::getIsOrphan, bo.getIsOrphan());
|
||||
lqw.eq(bo.getIsLeftBehindChild() != null, XgStudentMsg::getIsLeftBehindChild, bo.getIsLeftBehindChild());
|
||||
lqw.eq(bo.getIsSingleChild() != null, XgStudentMsg::getIsSingleChild, bo.getIsSingleChild());
|
||||
lqw.eq(bo.getIsLowIncome() != null, XgStudentMsg::getIsLowIncome, bo.getIsLowIncome());
|
||||
lqw.eq(bo.getHasLoan() != null, XgStudentMsg::getHasLoan, bo.getHasLoan());
|
||||
if (bo.getLoanAmountMin() != null && bo.getLoanAmountMax() != null) {
|
||||
lqw.between(XgStudentMsg::getLoanAmount, bo.getLoanAmountMin(), bo.getLoanAmountMax());
|
||||
}
|
||||
|
||||
// ==================== 身体状况检索 ====================
|
||||
if (bo.getHeightMin() != null && bo.getHeightMax() != null) {
|
||||
lqw.between(XgStudentMsg::getHeight, bo.getHeightMin(), bo.getHeightMax());
|
||||
}
|
||||
if (bo.getWeightMin() != null && bo.getWeightMax() != null) {
|
||||
lqw.between(XgStudentMsg::getWeight, bo.getWeightMin(), bo.getWeightMax());
|
||||
}
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getBloodType()), XgStudentMsg::getBloodType, bo.getBloodType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getHealthStatus()), XgStudentMsg::getHealthStatus, bo.getHealthStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDisabilityType()), XgStudentMsg::getDisabilityType, bo.getDisabilityType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDisabilityLevel()), XgStudentMsg::getDisabilityLevel, bo.getDisabilityLevel());
|
||||
|
||||
// ==================== 住宿信息检索 ====================
|
||||
lqw.eq(bo.getIsBoarder() != null, XgStudentMsg::getIsBoarder, bo.getIsBoarder());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDormitoryBuilding()), XgStudentMsg::getDormitoryBuilding, bo.getDormitoryBuilding());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getDormitoryRoom()), XgStudentMsg::getDormitoryRoom, bo.getDormitoryRoom());
|
||||
|
||||
// ==================== 其他信息检索 ====================
|
||||
lqw.like(StringUtils.isNotBlank(bo.getNativePlace()), XgStudentMsg::getNativePlace, bo.getNativePlace());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getSourceRegion()), XgStudentMsg::getSourceRegion, bo.getSourceRegion());
|
||||
lqw.like(StringUtils.isNotBlank(bo.getGraduateSchool()), XgStudentMsg::getGraduateSchool, bo.getGraduateSchool());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getHouseholdRegisterType()), XgStudentMsg::getHouseholdRegisterType, bo.getHouseholdRegisterType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getEducationLevel()), XgStudentMsg::getEducationLevel, bo.getEducationLevel());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getTrainingType()), XgStudentMsg::getTrainingType, bo.getTrainingType());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getAcademicLevel()), XgStudentMsg::getAcademicLevel, bo.getAcademicLevel());
|
||||
if (bo.getSchoolSystemMin() != null && bo.getSchoolSystemMax() != null) {
|
||||
lqw.between(XgStudentMsg::getSchoolSystem, bo.getSchoolSystemMin(), bo.getSchoolSystemMax());
|
||||
}
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getInfoStatus()), XgStudentMsg::getInfoStatus, bo.getInfoStatus());
|
||||
lqw.eq(StringUtils.isNotBlank(bo.getDataSource()), XgStudentMsg::getDataSource, bo.getDataSource());
|
||||
lqw.eq(bo.getIsComplete() != null, XgStudentMsg::getIsComplete, bo.getIsComplete());
|
||||
if (bo.getCompletionRateMin() != null && bo.getCompletionRateMax() != null) {
|
||||
lqw.between(XgStudentMsg::getCompletionRate, bo.getCompletionRateMin(), bo.getCompletionRateMax());
|
||||
}
|
||||
|
||||
// ==================== 时间范围检索 ====================
|
||||
if (bo.getCreateTimeStart() != null && bo.getCreateTimeEnd() != null) {
|
||||
lqw.between(XgStudentMsg::getCreateTime, bo.getCreateTimeStart(), bo.getCreateTimeEnd());
|
||||
}
|
||||
if (bo.getUpdateTimeStart() != null && bo.getUpdateTimeEnd() != null) {
|
||||
lqw.between(XgStudentMsg::getUpdateTime, bo.getUpdateTimeStart(), bo.getUpdateTimeEnd());
|
||||
}
|
||||
|
||||
// 排序:按创建时间倒序
|
||||
lqw.orderByDesc(XgStudentMsg::getCreateTime);
|
||||
|
||||
return lqw;
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.3 Controller新增API
|
||||
**文件路径**: `backend/ruoyi-modules/ruoyi-xg/src/main/java/org/dromara/xg/controller/XgStudentMsgController.java`
|
||||
|
||||
**新增API方法**:
|
||||
```java
|
||||
/**
|
||||
* 高级检索学生信息
|
||||
*
|
||||
* @param bo 高级检索条件
|
||||
* @return 学生信息分页列表
|
||||
*/
|
||||
@SaCheckPermission("studentMsg:studentMsg:list")
|
||||
@PostMapping("/advancedSearch")
|
||||
public TableDataInfo<XgStudentMsgVo> advancedSearch(@RequestBody XgStudentMsgAdvancedSearchBo bo) {
|
||||
log.info("接收到高级检索请求,检索条件: {}", bo);
|
||||
return xgStudentMsgService.advancedSearch(bo);
|
||||
}
|
||||
```
|
||||
|
||||
## 🔍 查询逻辑说明
|
||||
|
||||
### 1. 查询类型分类
|
||||
|
||||
#### 1.1 文本类参数 - 模糊查询
|
||||
使用 `LIKE` 操作符进行模糊匹配:
|
||||
- 学号、姓名、身份证号、手机号码、邮箱
|
||||
- 学院名称、专业名称、班级名称、辅导员姓名、班主任姓名
|
||||
- 父亲姓名、母亲姓名、监护人姓名
|
||||
- 宿舍楼栋、宿舍房间号
|
||||
- 籍贯、毕业院校
|
||||
|
||||
#### 1.2 数值类参数 - 范围查询
|
||||
使用 `BETWEEN` 操作符进行范围查询:
|
||||
- 入学年份:`enrollmentYearStart` 到 `enrollmentYearEnd`
|
||||
- 家庭年收入:`familyIncomeMin` 到 `familyIncomeMax`
|
||||
- 人均收入:`perCapitaIncomeMin` 到 `perCapitaIncomeMax`
|
||||
- 家庭成员数量:`familyMembersMin` 到 `familyMembersMax`
|
||||
- 助学贷款金额:`loanAmountMin` 到 `loanAmountMax`
|
||||
- 身高:`heightMin` 到 `heightMax`
|
||||
- 体重:`weightMin` 到 `weightMax`
|
||||
- 学制:`schoolSystemMin` 到 `schoolSystemMax`
|
||||
- 完整度百分比:`completionRateMin` 到 `completionRateMax`
|
||||
|
||||
#### 1.3 时间类参数 - 时间范围查询
|
||||
使用 `BETWEEN` 操作符进行时间范围查询:
|
||||
- 出生日期:`birthDateStart` 到 `birthDateEnd`
|
||||
- 入学日期:`enrollmentDateStart` 到 `enrollmentDateEnd`
|
||||
- 创建时间:`createTimeStart` 到 `createTimeEnd`
|
||||
- 更新时间:`updateTimeStart` 到 `updateTimeEnd`
|
||||
|
||||
#### 1.4 枚举类参数 - 精确匹配
|
||||
使用 `=` 操作符进行精确匹配:
|
||||
- 性别、民族、政治面貌、学籍状态、录取类别
|
||||
- 年级、家庭经济状况、血型、健康状况
|
||||
- 残疾类型、残疾等级、户口类型、文化程度
|
||||
- 培养方式、学历层次、信息状态、数据来源
|
||||
- 各种是否标识(贫困生、少数民族、残疾等)
|
||||
|
||||
### 2. 权限控制逻辑
|
||||
|
||||
#### 2.1 全校管理员权限
|
||||
- 不进行权限过滤
|
||||
- 可以查看所有部门的学生信息
|
||||
- 返回包含入参deptIds及其子组织的列表
|
||||
|
||||
#### 2.2 普通用户权限
|
||||
- 获取用户的总权限集合
|
||||
- 过滤deptIds,只保留在权限范围内的
|
||||
- 如果入参deptIds为空,直接使用用户权限范围内的所有部门
|
||||
- 对过滤后的deptIds,查找所有子组织包括他们自己
|
||||
|
||||
### 3. 查询优化
|
||||
|
||||
#### 3.1 条件构建优化
|
||||
- 使用 `StringUtils.isNotBlank()` 进行空值检查
|
||||
- 只有非空参数才会添加到查询条件中
|
||||
- 避免无效的查询条件影响性能
|
||||
|
||||
#### 3.2 排序优化
|
||||
- 默认按创建时间倒序排列
|
||||
- 确保查询结果的一致性和可预测性
|
||||
|
||||
## 📊 API接口规范
|
||||
|
||||
### 请求信息
|
||||
- **接口路径**: `POST /studentMsg/studentMsg/advancedSearch`
|
||||
- **权限要求**: `studentMsg:studentMsg:list`
|
||||
- **请求方式**: POST
|
||||
- **Content-Type**: application/json
|
||||
|
||||
### 请求参数
|
||||
```json
|
||||
{
|
||||
"studentNo": "2021001",
|
||||
"name": "张三",
|
||||
"gender": "0",
|
||||
"studentStatus": "1",
|
||||
"collegeName": "计算机学院",
|
||||
"isPoorStudent": 1,
|
||||
"heightMin": 160,
|
||||
"heightMax": 180,
|
||||
"deptIds": [1001, 1002, 1003],
|
||||
"pageNum": 1,
|
||||
"pageSize": 10
|
||||
}
|
||||
```
|
||||
|
||||
### 响应格式
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"msg": "操作成功",
|
||||
"rows": [
|
||||
{
|
||||
"id": 1234567890,
|
||||
"studentNo": "2021001",
|
||||
"name": "张三",
|
||||
"gender": "0",
|
||||
"phone": "13800138000",
|
||||
"email": "zhangsan@example.com",
|
||||
"studentStatus": "1",
|
||||
"collegeName": "计算机学院",
|
||||
"majorName": "软件工程",
|
||||
"className": "软件2101班",
|
||||
"isPoorStudent": 1,
|
||||
"height": 175.0,
|
||||
"weight": 65.0,
|
||||
"createTime": "2025-01-27 15:30:00",
|
||||
"updateTime": "2025-01-27 15:30:00"
|
||||
}
|
||||
],
|
||||
"total": 1
|
||||
}
|
||||
```
|
||||
|
||||
## ✅ 测试验证
|
||||
|
||||
### 1. 功能测试
|
||||
- [x] 基础信息检索测试
|
||||
- [x] 学籍信息检索测试
|
||||
- [x] 学院专业班级检索测试
|
||||
- [x] 家庭信息检索测试
|
||||
- [x] 特殊身份检索测试
|
||||
- [x] 身体状况检索测试
|
||||
- [x] 住宿信息检索测试
|
||||
- [x] 其他信息检索测试
|
||||
- [x] 时间范围检索测试
|
||||
|
||||
### 2. 权限测试
|
||||
- [x] 全校管理员权限测试
|
||||
- [x] 普通用户权限测试
|
||||
- [x] 部门树节点权限过滤测试
|
||||
|
||||
### 3. 性能测试
|
||||
- [x] 大数据量查询性能测试
|
||||
- [x] 复杂条件组合查询测试
|
||||
- [x] 分页查询性能测试
|
||||
|
||||
## 🚀 部署说明
|
||||
|
||||
### 1. 编译部署
|
||||
```bash
|
||||
# 编译项目
|
||||
mvn clean compile
|
||||
|
||||
# 打包项目
|
||||
mvn clean package
|
||||
|
||||
# 启动服务
|
||||
java -jar ruoyi-admin.jar
|
||||
```
|
||||
|
||||
### 2. 数据库验证
|
||||
- 确保 `xg_student_msg` 表结构完整
|
||||
- 确保相关索引已创建
|
||||
- 确保权限相关表数据正确
|
||||
|
||||
### 3. 接口验证
|
||||
```bash
|
||||
# 测试高级检索接口
|
||||
curl -X POST http://localhost:8080/studentMsg/studentMsg/advancedSearch \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "Authorization: Bearer YOUR_TOKEN" \
|
||||
-d '{
|
||||
"name": "张三",
|
||||
"pageNum": 1,
|
||||
"pageSize": 10
|
||||
}'
|
||||
```
|
||||
|
||||
## 📝 注意事项
|
||||
|
||||
### 1. 性能考虑
|
||||
- 大量数据查询时建议使用分页
|
||||
- 复杂条件组合可能影响查询性能
|
||||
- 建议在常用查询字段上创建索引
|
||||
|
||||
### 2. 权限安全
|
||||
- 严格遵循权限控制逻辑
|
||||
- 确保用户只能查看有权限的数据
|
||||
- 定期检查权限配置的正确性
|
||||
|
||||
### 3. 数据一致性
|
||||
- 确保查询条件的数据类型匹配
|
||||
- 注意时间格式的统一性
|
||||
- 验证枚举值的有效性
|
||||
|
||||
## 🔄 后续优化
|
||||
|
||||
### 1. 功能扩展
|
||||
- 支持更多检索维度
|
||||
- 增加检索条件保存功能
|
||||
- 支持检索结果导出
|
||||
|
||||
### 2. 性能优化
|
||||
- 添加查询缓存机制
|
||||
- 优化数据库索引
|
||||
- 实现异步查询处理
|
||||
|
||||
### 3. 用户体验
|
||||
- 提供检索条件模板
|
||||
- 增加检索历史记录
|
||||
- 优化前端交互体验
|
||||
|
||||
---
|
||||
|
||||
**变更完成时间**: 2025-01-27 17:00:00
|
||||
**变更状态**: ✅ 已完成
|
||||
**测试状态**: ✅ 已通过
|
||||
**部署状态**: ⏳ 待部署
|
||||
|
||||
## 📝 后续完善记录
|
||||
|
||||
### 2025-01-27 16:30:00 - 完善检索条件配置
|
||||
|
||||
#### 完善内容
|
||||
1. **补充BO类缺失字段**:
|
||||
- 英文姓名、曾用名
|
||||
- 户籍所在地、家庭地址、现住址
|
||||
- QQ号码、微信号、婚姻状况
|
||||
- 宗教信仰
|
||||
- 父亲电话、父亲工作单位
|
||||
- 母亲电话、母亲工作单位
|
||||
- 监护人电话、监护人关系
|
||||
- 收入来源
|
||||
- 紧急联系人姓名、电话、关系
|
||||
- 特长爱好、获奖情况、违纪记录、社会活动
|
||||
- 特殊体质或疾病、病史、过敏史
|
||||
|
||||
2. **完善查询条件构建方法**:
|
||||
- 按照前端界面顺序重新组织查询条件
|
||||
- 基础信息 → 学籍信息 → 家庭信息 → 扩展信息 → 健康信息 → 时间范围
|
||||
- 修正查询类型:文本类使用like,数值类使用between,枚举类使用eq
|
||||
- 添加详细的注释说明每个检索条件的作用
|
||||
|
||||
#### 技术改进
|
||||
- 修复了BO类中重复字段定义的问题
|
||||
- 优化了查询条件的组织结构,提高代码可读性
|
||||
- 确保所有前端界面的检索条件都有对应的后端处理逻辑
|
||||
|
||||
### 2025-01-27 17:00:00 - 支持下拉框多选功能
|
||||
|
||||
#### 完善内容
|
||||
1. **修改BO类字段类型**:
|
||||
- 将多选下拉框字段从String改为List<String>或List<Long>
|
||||
- 涉及字段:民族、政治面貌、户口类型、文化程度、婚姻状况、录取类别、学历层次、培养方式、学籍状态、是否住校、各种特殊身份标识、血型、残疾类型
|
||||
|
||||
2. **修改查询条件构建方法**:
|
||||
- 将多选字段的查询方式从eq改为in
|
||||
- 使用`bo.getField() != null && !bo.getField().isEmpty()`进行空值检查
|
||||
- 支持多选值的OR查询逻辑
|
||||
|
||||
#### 技术改进
|
||||
- 支持前端多选下拉框的数据传递
|
||||
- 优化了多选字段的查询性能
|
||||
- 确保查询条件的准确性和完整性
|
||||
@@ -1728,6 +1728,7 @@ data() {
|
||||
|
||||
---
|
||||
|
||||
<<<<<<< HEAD
|
||||
## 🔧 审批操作优化和意见填写强化 (2025-01-27 17:30:00)
|
||||
|
||||
### 问题描述
|
||||
@@ -1958,10 +1959,220 @@ loadAvailableApprovers(applicationId) {
|
||||
}).catch(error => {
|
||||
console.error('获取审批人列表失败:', error);
|
||||
this.approverList = [];
|
||||
=======
|
||||
本次修改遵循了项目的前端开发规范,使用了Element Plus的ElMessage组件实现loading效果,保持了代码风格的一致性。
|
||||
|
||||
# 学生花名册页面左侧树加载API实现 - 变更记录
|
||||
|
||||
**变更时间**: 2025-01-27 15:30:00
|
||||
**变更人员**: Cursor AI
|
||||
**变更类型**: 功能实现
|
||||
|
||||
## 📋 变更概述
|
||||
|
||||
为学生花名册页面(`web/src/views/xg/xsjcxx/stuRoster/index.vue`)的左侧部门树实现API加载功能,与学生信息管理页面的getDeptTree API保持一致。
|
||||
|
||||
## 🔧 具体变更内容
|
||||
|
||||
### 1. 创建API文件
|
||||
- **新增文件**: `web/src/api/xg/xsjcxx/stuRoster/index.ts`
|
||||
- 实现 `XgDeptTreeSelect` 方法,调用 `/xgStudentManagerSource/studentManagerSource/currentUserAuthTree` 接口
|
||||
- 实现 `deptTreeSelect` 方法,调用 `/system/dept/treeselect` 接口作为备选
|
||||
- 实现 `listStudentRoster` 方法,调用 `/studentMsg/studentMsg/list` 接口
|
||||
- 实现 `exportStudentRoster` 方法,调用 `/studentMsg/studentMsg/export` 接口
|
||||
|
||||
### 2. 创建类型定义文件
|
||||
- **新增文件**: `web/src/api/xg/xsjcxx/stuRoster/types.ts`
|
||||
- 定义 `XgDeptTreeVO` 部门树节点类型
|
||||
- 定义 `R` 通用响应类型
|
||||
- 定义 `TableDataInfo` 分页数据信息类型
|
||||
- 定义 `StudentRosterQuery` 查询参数类型
|
||||
- 定义 `StudentRosterVO` 学生花名册数据类型
|
||||
|
||||
### 3. 修改学生花名册页面
|
||||
- **文件**: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
- 添加API导入: `import api from '@/api/xg/xsjcxx/stuRoster/index'`
|
||||
- 实现 `getDeptTree` 方法,与学生信息管理页面保持一致
|
||||
- 修改 `getList` 方法,使用真实API替代模拟数据
|
||||
- 修改 `handleExport` 方法,使用真实导出API
|
||||
- 删除静态部门树数据,改为动态加载
|
||||
- 删除模拟数据生成代码
|
||||
- 在 `onMounted` 中先调用 `getDeptTree()` 再调用 `getList()`
|
||||
|
||||
## 🔄 API实现细节
|
||||
|
||||
### getDeptTree方法实现
|
||||
```typescript
|
||||
const getDeptTree = async () => {
|
||||
try {
|
||||
const res = await api.XgDeptTreeSelect(101);
|
||||
if (res.data && Array.isArray(res.data)) {
|
||||
deptOptions.value = res.data;
|
||||
} else {
|
||||
console.warn('部门树数据格式不符合预期');
|
||||
const backup = await api.deptTreeSelect();
|
||||
deptOptions.value = backup.data.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取部门树失败:', error);
|
||||
try {
|
||||
const backup = await api.deptTreeSelect();
|
||||
deptOptions.value = backup.data.data;
|
||||
} catch (backupError) {
|
||||
console.error('备选API也失败:', backupError);
|
||||
ElMessage.error('获取部门树失败,请重试');
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### API接口映射
|
||||
- **主要接口**: `/xgStudentManagerSource/studentManagerSource/currentUserAuthTree`
|
||||
- **备选接口**: `/system/dept/treeselect`
|
||||
- **学生列表接口**: `/studentMsg/studentMsg/list`
|
||||
- **导出接口**: `/studentMsg/studentMsg/export`
|
||||
|
||||
## ✅ 变更验证
|
||||
|
||||
### 功能验证
|
||||
- [x] 部门树能够从API动态加载
|
||||
- [x] 学生列表能够从API获取数据
|
||||
- [x] 导出功能能够正常工作
|
||||
- [x] 错误处理机制完善
|
||||
|
||||
### 代码质量
|
||||
- [x] API接口与学生信息管理页面保持一致
|
||||
- [x] 类型定义完整
|
||||
- [x] 错误处理完善
|
||||
- [x] 代码结构清晰
|
||||
|
||||
## 📝 注意事项
|
||||
|
||||
1. **API一致性**: 学生花名册页面的getDeptTree方法与学生信息管理页面完全一致
|
||||
2. **错误处理**: 实现了主API失败时的备选API机制
|
||||
3. **数据格式**: 支持两种不同的API返回格式
|
||||
4. **性能优化**: 删除了大量静态数据,改为动态加载
|
||||
|
||||
## 🔗 相关文件
|
||||
|
||||
- `web/src/views/xg/xsjcxx/stuRoster/index.vue` - 学生花名册页面
|
||||
- `web/src/api/xg/xsjcxx/stuRoster/index.ts` - API接口文件
|
||||
- `web/src/api/xg/xsjcxx/stuRoster/types.ts` - 类型定义文件
|
||||
- `web/src/views/xg/xsjcxx/studentMsg/studentMsg/index.vue` - 参考的学生信息管理页面
|
||||
|
||||
---
|
||||
|
||||
**变更完成时间**: 2025-01-27 15:30:00
|
||||
**状态**: ✅ 已完成
|
||||
|
||||
# 代码调整记录 - 2025-01-27
|
||||
|
||||
## 修改概述
|
||||
在高级检索界面中为籍贯和生源地区字段添加API数据获取功能,替换原有的字典数据源。
|
||||
|
||||
## 修改文件
|
||||
- `web/src/views/xg/xsjcxx/stuRoster/components/AdvancedSearchDialog.vue`
|
||||
|
||||
## 具体修改内容
|
||||
|
||||
### 1. 导入依赖
|
||||
- 添加 `onMounted` 生命周期钩子导入
|
||||
- 添加 `ElMessage` 消息提示组件导入
|
||||
- 添加 `request` HTTP请求工具导入
|
||||
|
||||
### 2. 响应式数据
|
||||
- 新增 `regionOptions` 响应式数组,用于存储行政区划数据
|
||||
- 移除 `xg_source_region` 字典数据依赖
|
||||
|
||||
### 3. 模板修改
|
||||
- 将籍贯字段的数据源从 `xg_native_place` 字典改为 `regionOptions` API数据
|
||||
- 将生源地区字段的数据源从 `xg_source_region` 字典改为 `regionOptions` API数据
|
||||
- 修改选项的key、label、value属性映射:
|
||||
- `key`: `item.id`
|
||||
- `label`: `item.name`
|
||||
- `value`: `item.id`
|
||||
|
||||
### 4. 方法实现
|
||||
- 新增 `getRegionTree` 异步方法:
|
||||
- 调用 `/system/SysRegion/tree` API接口
|
||||
- 获取行政区划树形数据
|
||||
- 错误处理和用户提示
|
||||
|
||||
### 5. 生命周期
|
||||
- 在 `onMounted` 钩子中调用 `getRegionTree` 方法
|
||||
- 确保组件挂载时自动获取行政区划数据
|
||||
|
||||
## 技术实现要点
|
||||
|
||||
### API接口
|
||||
- **接口地址**: `/system/SysRegion/tree`
|
||||
- **请求方式**: GET
|
||||
- **返回格式**: 树形结构的行政区划数据
|
||||
|
||||
### 数据结构
|
||||
```typescript
|
||||
interface RegionItem {
|
||||
id: string | number; // 区域ID
|
||||
name: string; // 区域名称
|
||||
// 其他树形结构字段...
|
||||
}
|
||||
```
|
||||
|
||||
### 错误处理
|
||||
- 使用 try-catch 捕获API请求异常
|
||||
- 控制台输出详细错误信息
|
||||
- 用户友好的错误提示消息
|
||||
|
||||
## 影响范围
|
||||
- 高级检索对话框中的籍贯选择功能
|
||||
- 高级检索对话框中的生源地区选择功能
|
||||
- 用户可以选择真实的行政区划数据而不是字典数据
|
||||
- 提升了数据的准确性和实用性
|
||||
|
||||
## 测试建议
|
||||
1. 打开高级检索对话框
|
||||
2. 验证籍贯下拉选项是否正确加载
|
||||
3. 测试多选功能是否正常
|
||||
4. 检查网络异常时的错误提示
|
||||
|
||||
## 相关文档
|
||||
- 参考实现:`web/src/views/xg/xsjcxx/stuPersonalMsg/index.vue` 中的 `getRegionTree` 方法
|
||||
- API文档:行政区划管理相关接口
|
||||
|
||||
---
|
||||
**修改时间**: 2025-01-27
|
||||
**修改人**: Cursor AI
|
||||
**状态**: 已完成
|
||||
|
||||
# 代码调整记录 - 2025-01-27
|
||||
|
||||
## 修改概述
|
||||
将学生花名册API从基础的list接口改为使用高级搜索接口,以支持更丰富的查询功能。
|
||||
|
||||
## 修改详情
|
||||
|
||||
### 1. 前端API接口修改
|
||||
**文件**: `web/src/api/xg/xsjcxx/stuRoster/index.ts`
|
||||
|
||||
**修改内容**:
|
||||
- 将 `listStudentRoster` 方法的请求方式从 `GET` 改为 `POST`
|
||||
- 将请求URL从 `/studentMsg/studentMsg/list` 改为 `/studentMsg/studentMsg/advancedSearch`
|
||||
- 将请求参数从 `params` 改为 `data`(POST请求体)
|
||||
- 添加了新的类型导入 `XgStudentMsgAdvancedSearchQuery`
|
||||
|
||||
**修改前**:
|
||||
```typescript
|
||||
export function listStudentRoster(query?: any): AxiosPromise<R<TableDataInfo<any[]>>> {
|
||||
return request({
|
||||
url: '/studentMsg/studentMsg/list',
|
||||
method: 'get',
|
||||
params: query
|
||||
>>>>>>> 2b5db607f6268a7631c2075e81359ee1ca827e07
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
<<<<<<< HEAD
|
||||
#### 模板绑定
|
||||
```html
|
||||
<!-- 下一审批人选择框 -->
|
||||
@@ -2575,4 +2786,82 @@ API提交到后端 (包含所有分年度预算字段)
|
||||
|
||||
---
|
||||
|
||||
// ... existing code ...
|
||||
// ... existing code ...
|
||||
=======
|
||||
**修改后**:
|
||||
```typescript
|
||||
export function listStudentRoster(query?: XgStudentMsgAdvancedSearchQuery): AxiosPromise<R<TableDataInfo<any[]>>> {
|
||||
return request({
|
||||
url: '/studentMsg/studentMsg/advancedSearch',
|
||||
method: 'post',
|
||||
data: query
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 2. 类型定义扩展
|
||||
**文件**: `web/src/api/xg/xsjcxx/stuRoster/types.ts`
|
||||
|
||||
**新增内容**:
|
||||
- 添加了 `XgStudentMsgAdvancedSearchQuery` 接口类型定义
|
||||
- 包含了完整的 advancedSearch 接口支持的所有查询参数
|
||||
- 涵盖了基础信息、学籍信息、学院专业班级、家庭信息、特殊身份、身体状况、住宿信息等多个维度的检索条件
|
||||
|
||||
**新增类型结构**:
|
||||
```typescript
|
||||
export interface XgStudentMsgAdvancedSearchQuery {
|
||||
// 基础信息检索
|
||||
studentNo?: string;
|
||||
name?: string;
|
||||
idCard?: string;
|
||||
phone?: string;
|
||||
email?: string;
|
||||
gender?: string[];
|
||||
// ... 更多字段
|
||||
|
||||
// 分页参数
|
||||
pageNum?: number;
|
||||
pageSize?: number;
|
||||
}
|
||||
```
|
||||
|
||||
## 技术要点
|
||||
|
||||
### 1. 接口兼容性
|
||||
- 保持了原有的函数签名,只是改变了内部实现
|
||||
- 新的查询参数类型是扩展的,向后兼容原有的简单查询参数
|
||||
|
||||
### 2. 请求方式变更
|
||||
- 从 GET 请求改为 POST 请求,支持更复杂的查询条件
|
||||
- 参数传递方式从 URL 参数改为请求体,避免 URL 过长的问题
|
||||
|
||||
### 3. 类型安全
|
||||
- 添加了完整的 TypeScript 类型定义
|
||||
- 提供了更好的开发体验和代码提示
|
||||
|
||||
## 影响范围
|
||||
|
||||
### 1. 前端调用方
|
||||
- 使用 `listStudentRoster` 方法的组件需要确保传递的参数符合新的类型定义
|
||||
- 原有的简单查询参数仍然可以正常工作
|
||||
|
||||
### 2. 后端接口
|
||||
- 后端 `XgStudentMsgController.advancedSearch` 方法已经实现
|
||||
- 支持完整的查询条件处理
|
||||
|
||||
## 验证建议
|
||||
|
||||
1. **功能测试**: 验证学生花名册列表页面是否正常加载
|
||||
2. **查询测试**: 测试各种查询条件组合是否正常工作
|
||||
3. **类型检查**: 确保 TypeScript 编译无错误
|
||||
4. **向后兼容**: 验证原有的简单查询是否仍然有效
|
||||
|
||||
## 相关文档
|
||||
- 后端接口文档: `docs/开发文档/API/学生信息管理API.md`
|
||||
- 高级搜索功能说明: 参考 `XgStudentMsgAdvancedSearchBo` 类的完整字段说明
|
||||
|
||||
---
|
||||
**修改时间**: 2025-01-27 14:30:00
|
||||
**修改人**: Cursor AI
|
||||
**修改原因**: 提升学生信息查询功能,支持更丰富的高级搜索条件
|
||||
>>>>>>> 2b5db607f6268a7631c2075e81359ee1ca827e07
|
||||
@@ -0,0 +1,184 @@
|
||||
# 学生详情弹窗集成修改记录
|
||||
|
||||
**修改时间**: 2025-01-27 16:00:00
|
||||
**修改人员**: AI Assistant
|
||||
**修改类型**: 功能增强
|
||||
|
||||
## 修改概述
|
||||
|
||||
将学生详情弹窗(`StudentDetailDialog.vue`)从独立页面改造为可复用的弹窗组件,支持从学生花名册页面的列表视图和卡片视图中传递学生ID并显示详细信息。
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 1. 学生详情弹窗组件改造
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/components/StudentDetailDialog.vue`
|
||||
|
||||
#### 1.1 模板结构修改
|
||||
- 将原有的独立页面结构包装在`el-dialog`组件中
|
||||
- 添加弹窗标题、宽度、关闭行为等配置
|
||||
- 保持原有的Tab页结构和表单布局
|
||||
|
||||
#### 1.2 Props和Emits定义
|
||||
```typescript
|
||||
// 定义props
|
||||
interface Props {
|
||||
visible: boolean;
|
||||
studentId?: number | null;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
visible: false,
|
||||
studentId: null
|
||||
});
|
||||
|
||||
// 定义emits
|
||||
const emit = defineEmits<{
|
||||
'update:visible': [value: boolean];
|
||||
}>();
|
||||
|
||||
// 计算属性:控制弹窗显示
|
||||
const dialogVisible = computed({
|
||||
get: () => props.visible,
|
||||
set: (value) => emit('update:visible', value)
|
||||
});
|
||||
```
|
||||
|
||||
#### 1.3 API调用修改
|
||||
- 修改`getPersonalInfoData`方法,支持传入学生ID参数
|
||||
- 使用正确的API路径:`/studentMsg/studentMsg/personalInfo`
|
||||
- 通过查询参数`userId`传递学生ID
|
||||
|
||||
```typescript
|
||||
/** 获取学生个人信息 */
|
||||
const getPersonalInfoData = async (studentId?: number) => {
|
||||
if (!studentId) {
|
||||
ElMessage.warning('学生ID不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
const response = await request({
|
||||
url: '/studentMsg/studentMsg/personalInfo',
|
||||
method: 'get',
|
||||
params: { userId: studentId }
|
||||
});
|
||||
// ... 处理响应数据
|
||||
} catch (error) {
|
||||
console.error('获取个人信息失败:', error);
|
||||
ElMessage.error('获取个人信息失败,请稍后重试');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
#### 1.4 数据监听机制
|
||||
- 添加`watch`监听器,监听`props.visible`和`props.studentId`的变化
|
||||
- 当弹窗打开且有学生ID时,自动获取学生信息
|
||||
- 在获取新数据前重置表单数据
|
||||
|
||||
```typescript
|
||||
// 监听学生ID变化,当弹窗打开且有学生ID时获取数据
|
||||
watch(
|
||||
() => [props.visible, props.studentId],
|
||||
async ([visible, studentId]) => {
|
||||
if (visible && studentId && typeof studentId === 'number') {
|
||||
// 重置表单数据
|
||||
Object.keys(form).forEach((key) => {
|
||||
const value = form[key];
|
||||
if (typeof value === 'string') {
|
||||
(form as any)[key] = '';
|
||||
} else if (typeof value === 'number') {
|
||||
(form as any)[key] = undefined;
|
||||
} else if (typeof value === 'boolean') {
|
||||
(form as any)[key] = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
// 获取学生个人信息
|
||||
await getPersonalInfoData(studentId);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 主页面集成
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
|
||||
#### 2.1 详情弹窗状态管理
|
||||
```typescript
|
||||
// 详情弹窗
|
||||
const detailDialog = reactive({
|
||||
visible: false,
|
||||
studentId: null as number | null
|
||||
});
|
||||
```
|
||||
|
||||
#### 2.2 查看详情方法
|
||||
```typescript
|
||||
const handleDetail = (row: any) => {
|
||||
detailDialog.studentId = row.id;
|
||||
detailDialog.visible = true;
|
||||
};
|
||||
```
|
||||
|
||||
#### 2.3 组件使用
|
||||
```vue
|
||||
<!-- 学生详情弹窗 -->
|
||||
<student-detail-dialog
|
||||
:visible="detailDialog.visible"
|
||||
:student-id="detailDialog.studentId"
|
||||
@update:visible="(val) => (detailDialog.visible = val)"
|
||||
/>
|
||||
```
|
||||
|
||||
### 3. 触发方式
|
||||
|
||||
#### 3.1 列表视图
|
||||
- 在操作列中添加"查看详情"按钮
|
||||
- 点击按钮调用`handleDetail(row)`方法
|
||||
|
||||
#### 3.2 卡片视图
|
||||
- 卡片支持双击事件
|
||||
- 双击卡片调用`handleDetail(item)`方法
|
||||
- 添加视觉提示:"双击查看详情"
|
||||
|
||||
## 功能特点
|
||||
|
||||
1. **响应式设计**: 弹窗支持不同屏幕尺寸的响应式布局
|
||||
2. **数据隔离**: 每次打开弹窗都会重置表单数据,避免数据混淆
|
||||
3. **错误处理**: 完善的错误提示和异常处理机制
|
||||
4. **用户体验**: 加载状态提示,操作反馈及时
|
||||
5. **代码复用**: 组件化设计,可在其他页面复用
|
||||
|
||||
## 技术要点
|
||||
|
||||
1. **Vue 3 Composition API**: 使用`defineProps`、`defineEmits`、`computed`等现代Vue 3特性
|
||||
2. **TypeScript支持**: 完整的类型定义和类型安全
|
||||
3. **响应式数据**: 使用`reactive`和`ref`管理组件状态
|
||||
4. **生命周期管理**: 合理使用`onMounted`和`watch`监听器
|
||||
5. **API集成**: 正确调用后端API并处理响应数据
|
||||
|
||||
## 测试验证
|
||||
|
||||
1. **列表视图测试**: 点击"查看详情"按钮,弹窗正常打开并显示学生信息
|
||||
2. **卡片视图测试**: 双击学生卡片,弹窗正常打开并显示学生信息
|
||||
3. **数据验证**: 确认显示的学生信息与列表/卡片中的基本信息一致
|
||||
4. **错误处理**: 测试无效学生ID的情况,确认错误提示正常
|
||||
5. **响应式测试**: 在不同屏幕尺寸下测试弹窗显示效果
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **API路径**: 确保后端API路径`/studentMsg/studentMsg/personalInfo`正确配置
|
||||
2. **权限控制**: 确认用户有访问学生个人信息的权限
|
||||
3. **数据格式**: 注意API返回的数据格式与表单字段的映射关系
|
||||
4. **性能优化**: 避免频繁的API调用,合理使用缓存机制
|
||||
5. **用户体验**: 提供清晰的加载状态和错误提示
|
||||
|
||||
---
|
||||
|
||||
**修改完成**: 学生详情弹窗已成功集成到学生花名册页面,支持从列表视图和卡片视图查看学生详细信息。
|
||||
@@ -1,74 +1,172 @@
|
||||
# 代码调整记录 - 2025-01-27
|
||||
|
||||
## 修改时间
|
||||
2025-01-27 14:30:00
|
||||
## 修复内容
|
||||
|
||||
## 修改人员
|
||||
wuzilong
|
||||
|
||||
## 修改内容
|
||||
|
||||
### 高级检索弹出框学籍信息优化
|
||||
### 高级检索界面多选下拉框参数传递格式修复
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/components/AdvancedSearchDialog.vue`
|
||||
|
||||
**问题描述**:
|
||||
- 高级检索界面中,检索按钮调用后台API时,对于下拉框的多选传的参数是 `dormitoryBuilding[0]`、`dormitoryBuilding[1]` 等索引格式
|
||||
- 需要调整为传递 `dormitoryBuilding: list<String>` 的数组格式
|
||||
- 其他所有下拉框都需要做同样的调整
|
||||
|
||||
**修复方案**:
|
||||
1. 在 `handleSearch` 方法中新增多选字段处理逻辑
|
||||
2. 定义所有多选下拉框字段列表:
|
||||
```javascript
|
||||
const multiSelectFields = [
|
||||
'gender', 'nationality', 'nativePlace', 'politicalStatus', 'educationLevel',
|
||||
'admissionCategory', 'academicLevel', 'trainingType', 'householdRegisterType',
|
||||
'studentStatus', 'isBoarder', 'dormitoryBuilding', 'familyEconomicStatus',
|
||||
'isPoorStudent', 'isMinority', 'isDisabled', 'isOrphan', 'isLeftBehindChild',
|
||||
'isSingleChild', 'isLowIncome', 'hasLoan', 'sourceRegion', 'bloodType',
|
||||
'disabilityType'
|
||||
];
|
||||
```
|
||||
|
||||
1. **学制字段改为输入框**
|
||||
- 将学制从下拉选择框改为文本输入框
|
||||
- 移除 `school_system` 字典数据依赖
|
||||
- 用户可以直接输入学制信息
|
||||
3. 统一处理多选字段:
|
||||
- 过滤掉空值,确保只传递有效的数组
|
||||
- 如果数组为空则删除该字段
|
||||
- 保持数组格式传递给后端
|
||||
|
||||
2. **新增学籍状态检索条件**
|
||||
- 在学籍信息部分新增"学籍状态"字段
|
||||
- 添加 `student_status` 字典数据,包含:在读、休学、退学、毕业、结业、肄业
|
||||
- 位置:学籍信息部分的最后一行
|
||||
**修复效果**:
|
||||
- ✅ 所有多选下拉框现在都传递正确的数组格式
|
||||
- ✅ 避免了 `dormitoryBuilding[0]`、`dormitoryBuilding[1]` 等索引格式问题
|
||||
- ✅ 后端可以正确接收 `dormitoryBuilding: list<String>` 格式的参数
|
||||
- ✅ 提高了代码的可维护性和一致性
|
||||
|
||||
3. **新增是否住校检索条件**
|
||||
- 在学籍信息部分新增"是否住校"字段
|
||||
- 使用现有的 `yes_no` 字典数据
|
||||
- 位置:学籍信息部分的最后一行
|
||||
**涉及的多选字段**:
|
||||
- 基础信息:性别、民族、籍贯、政治面貌、文化程度
|
||||
- 学籍信息:录取类别、学历层次、培养方式、户口类型、学籍状态、是否住校、宿舍楼栋
|
||||
- 家庭信息:家庭经济状况
|
||||
- 扩展信息:是否贫困生、是否少数民族、是否残疾、是否孤儿、是否留守儿童、是否独生子女、是否低保、是否有助学贷款、生源地区
|
||||
- 健康信息:血型、残疾类型
|
||||
|
||||
4. **新增宿舍楼栋检索条件**
|
||||
- 在学籍信息部分新增"宿舍楼栋"字段
|
||||
- 使用文本输入框,支持模糊检索
|
||||
- 位置:学籍信息部分的最后一行
|
||||
**测试建议**:
|
||||
1. 测试各个多选下拉框的选择功能
|
||||
2. 验证传递给后端的参数格式是否正确
|
||||
3. 确认后端能正确接收和处理数组格式的参数
|
||||
|
||||
5. **户口类型字段位置调整**
|
||||
- 将户口类型从学籍信息部分移动到基础信息部分
|
||||
- 位置:基础信息中户籍地址的前一行
|
||||
- 保持字段功能和字典数据不变
|
||||
---
|
||||
**记录时间**: 2025-01-27 14:30:00
|
||||
**记录人**: wuzilong
|
||||
**变更类型**: 功能修复
|
||||
|
||||
6. **修复重复字段问题**
|
||||
- 移除特殊标识部分重复的"是否住校"字段
|
||||
- 修复 `familyMembers` 字段类型错误(从string改为number)
|
||||
# 角色管理页面新增按钮isSystemRole问题修复
|
||||
|
||||
7. **家庭收入字段优化**
|
||||
- 家庭年收入标签添加单位"(元)"
|
||||
- 人均收入标签添加单位"(元)"
|
||||
- 将两个字段的输入框从数字输入框改为普通文本输入框
|
||||
- 保持范围查询功能(最小值-最大值)
|
||||
- 数据类型从number数组改为string数组
|
||||
- 输入框宽度优化:从45%调整为40%,分隔符间距从5px调整为3px
|
||||
**日期**: 2025-01-27 15:30:00
|
||||
**修改人**: wuzilong
|
||||
**文件**: `web/src/views/system/role/index.vue`
|
||||
|
||||
#### 技术细节
|
||||
## 问题描述
|
||||
|
||||
- 新增字段在 `formData` 中正确定义
|
||||
- 字典数据 `student_status` 已添加到组件中
|
||||
- 表单布局保持一致性,每行4个字段
|
||||
- 所有新增字段都支持清空操作
|
||||
点击角色管理页面的新增按钮时,`isSystemRole` 计算属性应该为 `false`,允许用户填写表单。但实际显示为 `true`,导致表单字段被禁用。
|
||||
|
||||
#### 影响范围
|
||||
## 问题分析
|
||||
|
||||
- 学生花名册高级检索功能
|
||||
- 检索条件更加完善,支持按学籍状态、住宿情况进行筛选
|
||||
- 用户体验提升,检索条件更加直观
|
||||
1. **根本原因**: `isSystemRole` 计算属性检查 `form.value.roleKey` 是否以 `'XT-BJZW-'` 开头
|
||||
2. **初始化问题**: 虽然 `initForm` 中 `roleKey` 初始化为空字符串,但可能存在重置不完整的情况
|
||||
3. **逻辑问题**: 原计算属性没有正确处理空字符串的情况
|
||||
|
||||
## 验证状态
|
||||
- [x] 代码语法检查通过
|
||||
- [x] 字段类型正确
|
||||
- [x] 字典数据完整
|
||||
- [x] 布局合理
|
||||
## 修复方案
|
||||
|
||||
### 1. 优化 `isSystemRole` 计算属性
|
||||
```typescript
|
||||
// 修复前
|
||||
const isSystemRole = computed(() => {
|
||||
return form.value.roleKey && form.value.roleKey.startsWith('XT-BJZW-');
|
||||
});
|
||||
|
||||
// 修复后
|
||||
const isSystemRole = computed(() => {
|
||||
return form.value.roleKey && form.value.roleKey.trim() !== '' && form.value.roleKey.startsWith('XT-BJZW-');
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 优化 `isSystemRoleInTable` 函数
|
||||
```typescript
|
||||
// 修复前
|
||||
const isSystemRoleInTable = (row: RoleVO) => {
|
||||
return row.roleKey && row.roleKey.startsWith('XT-BJZW-');
|
||||
};
|
||||
|
||||
// 修复后
|
||||
const isSystemRoleInTable = (row: RoleVO) => {
|
||||
return row.roleKey && row.roleKey.trim() !== '' && row.roleKey.startsWith('XT-BJZW-');
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 增强 `reset` 函数
|
||||
```typescript
|
||||
const reset = () => {
|
||||
menuRef.value?.setCheckedKeys([]);
|
||||
menuExpand.value = false;
|
||||
menuNodeAll.value = false;
|
||||
deptExpand.value = true;
|
||||
deptNodeAll.value = false;
|
||||
form.value = { ...initForm };
|
||||
// 确保roleKey被明确重置为空字符串
|
||||
form.value.roleKey = '';
|
||||
roleFormRef.value?.resetFields();
|
||||
};
|
||||
```
|
||||
|
||||
### 4. 增强 `handleAdd` 函数
|
||||
```typescript
|
||||
const handleAdd = () => {
|
||||
reset();
|
||||
// 确保roleKey被正确重置为空字符串
|
||||
form.value.roleKey = '';
|
||||
console.log('新增角色 - roleKey:', `"${form.value.roleKey}"`, 'isSystemRole:', isSystemRole.value);
|
||||
getMenuTreeselect();
|
||||
dialog.visible = true;
|
||||
dialog.title = '添加角色';
|
||||
};
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
1. ✅ **新增角色**: 点击新增按钮时,`isSystemRole` 正确显示为 `false`
|
||||
2. ✅ **表单可用**: 角色名称、权限字符等字段可以正常填写
|
||||
3. ✅ **系统角色保护**: 对于真正的系统角色(`XT-BJZW-` 开头),仍然正确识别并禁用编辑
|
||||
4. ✅ **调试信息**: 添加了控制台日志,便于调试和验证
|
||||
|
||||
## 验证结果
|
||||
|
||||
### ✅ 修复成功验证
|
||||
|
||||
**测试日志输出**:
|
||||
```
|
||||
新增角色 - roleKey: "" isSystemRole: false
|
||||
```
|
||||
|
||||
**验证结果**:
|
||||
- ✅ `roleKey` 正确显示为空字符串 `""`
|
||||
- ✅ `isSystemRole` 正确显示为 `false`
|
||||
- ✅ 表单字段未被禁用,可以正常填写
|
||||
- ✅ 系统角色保护机制仍然正常工作
|
||||
|
||||
## 测试验证
|
||||
|
||||
1. **新增角色测试**:
|
||||
- 点击"新增"按钮
|
||||
- 验证表单字段未被禁用
|
||||
- 验证控制台显示 `roleKey: ""` 和 `isSystemRole: false`
|
||||
|
||||
2. **系统角色测试**:
|
||||
- 编辑系统内置角色(`XT-BJZW-` 开头)
|
||||
- 验证表单字段被正确禁用
|
||||
- 验证系统角色提示信息显示
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `web/src/views/system/role/index.vue` - 角色管理页面
|
||||
- `docs/变更管理/code-adjust-record-2025-01-27-wuzilong.md` - 本变更记录
|
||||
|
||||
## 备注
|
||||
本次修改提升了学生信息检索的灵活性和准确性,特别是针对学籍状态和住宿情况的检索需求。
|
||||
|
||||
此修复确保了角色管理页面的新增功能正常工作,同时保持了对系统内置角色的保护机制。修复后的代码更加健壮,能够正确处理各种边界情况。
|
||||
|
||||
**修复状态**: ✅ 完全成功
|
||||
**验证时间**: 2025-01-27 15:35:00
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
# 学生花名册详情弹窗API调用修复记录
|
||||
|
||||
**修改时间**: 2025-07-17 16:30:00
|
||||
**修改人员**: AI Assistant
|
||||
**修改类型**: 功能修复
|
||||
|
||||
## 问题描述
|
||||
|
||||
学生花名册主界面(`web/src/views/xg/xsjcxx/stuRoster/index.vue`)中的学生详情弹窗(`StudentDetailDialog.vue`)没有调用API获取学生数据,导致详情弹窗显示空白。
|
||||
|
||||
## 问题分析
|
||||
|
||||
1. **组件导入错误**: StudentDetailDialog和AdvancedSearchDialog组件使用`<script setup>`语法,但没有默认导出,导致主页面导入失败
|
||||
2. **API缺失**: stuRoster的API文件中缺少获取学生个人信息的API方法
|
||||
3. **API调用错误**: StudentDetailDialog组件中直接使用request调用API,而不是使用统一的API模块
|
||||
|
||||
## 修复内容
|
||||
|
||||
### 1. 修复组件导出问题
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/components/AdvancedSearchDialog.vue`
|
||||
```typescript
|
||||
// 添加默认导出
|
||||
defineOptions({
|
||||
name: 'AdvancedSearchDialog'
|
||||
});
|
||||
```
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/components/StudentDetailDialog.vue`
|
||||
```typescript
|
||||
// 添加默认导出
|
||||
defineOptions({
|
||||
name: 'StudentDetailDialog'
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 添加学生个人信息API
|
||||
|
||||
**文件**: `web/src/api/xg/xsjcxx/stuRoster/index.ts`
|
||||
```typescript
|
||||
/**
|
||||
* 获取学生个人信息
|
||||
* @param userId 用户ID,可为空,为空时使用当前登录用户ID
|
||||
*/
|
||||
export function getStudentPersonalInfo(userId?: number): AxiosPromise<any> {
|
||||
return request({
|
||||
url: '/studentMsg/studentMsg/personalInfo',
|
||||
method: 'get',
|
||||
params: { userId }
|
||||
});
|
||||
}
|
||||
|
||||
export default {
|
||||
XgDeptTreeSelect,
|
||||
deptTreeSelect,
|
||||
listStudentRoster,
|
||||
exportStudentRoster,
|
||||
getStudentPersonalInfo // 新增
|
||||
};
|
||||
```
|
||||
|
||||
### 3. 修复StudentDetailDialog组件API调用
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/components/StudentDetailDialog.vue`
|
||||
|
||||
#### 3.1 导入API模块
|
||||
```typescript
|
||||
import api from '@/api/xg/xsjcxx/stuRoster/index';
|
||||
```
|
||||
|
||||
#### 3.2 修改API调用方法
|
||||
```typescript
|
||||
/** 获取学生个人信息 */
|
||||
const getPersonalInfoData = async (studentId?: number) => {
|
||||
if (!studentId) {
|
||||
ElMessage.warning('学生ID不能为空');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
// 使用统一的API模块
|
||||
const response = await api.getStudentPersonalInfo(studentId);
|
||||
if (response.code === 200) {
|
||||
const data = response.data;
|
||||
// 将是否字段的数值转换为字符串
|
||||
const booleanFields = [
|
||||
'isPoorStudent',
|
||||
'isMinority',
|
||||
'isOrphan',
|
||||
'isLeftBehindChild',
|
||||
'isSingleChild',
|
||||
'isLowIncome',
|
||||
'hasLoan',
|
||||
'isDisabled',
|
||||
'isBoarder'
|
||||
];
|
||||
|
||||
booleanFields.forEach((field) => {
|
||||
if (data[field] !== undefined && data[field] !== null) {
|
||||
data[field] = String(data[field]);
|
||||
}
|
||||
});
|
||||
// 将API返回的数据映射到表单
|
||||
Object.assign(form, data);
|
||||
} else {
|
||||
ElMessage.error(response.msg || '获取个人信息失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取个人信息失败:', error);
|
||||
ElMessage.error('获取个人信息失败,请稍后重试');
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### 4. 修复主页面API响应处理
|
||||
|
||||
**文件**: `web/src/views/xg/xsjcxx/stuRoster/index.vue`
|
||||
```typescript
|
||||
// 修复API响应数据结构处理
|
||||
api
|
||||
.listStudentRoster(queryParams)
|
||||
.then((response: any) => {
|
||||
if (response.code === 200) {
|
||||
studentList.value = response.data.rows || [];
|
||||
total.value = response.data.total || 0;
|
||||
} else {
|
||||
ElMessage.error(response.msg || '查询失败');
|
||||
studentList.value = [];
|
||||
total.value = 0;
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
1. **组件导入正常**: StudentDetailDialog和AdvancedSearchDialog组件可以正常导入和使用
|
||||
2. **API调用成功**: 学生详情弹窗可以正确调用后端API获取学生个人信息
|
||||
3. **数据展示完整**: 详情弹窗可以显示学生的完整个人信息,包括基础信息、扩展信息、家庭信息、健康信息、学籍信息、银行卡信息等
|
||||
4. **错误处理完善**: 添加了完善的错误处理和用户提示
|
||||
|
||||
## 技术要点
|
||||
|
||||
1. **Vue 3 Composition API**: 使用`<script setup>`语法和`defineOptions`进行组件定义
|
||||
2. **API模块化**: 统一使用API模块进行接口调用,便于维护和管理
|
||||
3. **类型安全**: 使用TypeScript进行类型定义,提高代码质量
|
||||
4. **错误处理**: 完善的错误处理和用户友好的提示信息
|
||||
|
||||
## 测试验证
|
||||
|
||||
1. 打开学生花名册页面
|
||||
2. 点击学生列表中的"查看详情"按钮
|
||||
3. 验证详情弹窗是否正确显示学生个人信息
|
||||
4. 验证各个Tab页(基础信息、扩展信息、家庭信息、健康信息、学籍信息、银行卡信息)是否正常显示
|
||||
5. 验证API调用是否成功,网络请求是否正常
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `web/src/views/xg/xsjcxx/stuRoster/index.vue` - 主页面
|
||||
- `web/src/views/xg/xsjcxx/stuRoster/components/StudentDetailDialog.vue` - 学生详情弹窗
|
||||
- `web/src/views/xg/xsjcxx/stuRoster/components/AdvancedSearchDialog.vue` - 高级搜索弹窗
|
||||
- `web/src/api/xg/xsjcxx/stuRoster/index.ts` - API接口定义
|
||||
- `web/src/api/xg/xsjcxx/stuRoster/types.ts` - 类型定义
|
||||
@@ -296,6 +296,82 @@
|
||||
#### 响应数据
|
||||
返回Excel文件流
|
||||
|
||||
### 2.8.1 高级检索导出学生信息
|
||||
- **接口路径**: POST `/studentMsg/studentMsg/advancedSearchExport`
|
||||
- **权限标识**: `studentMsg:studentMsg:export`
|
||||
- **功能描述**: 根据高级检索条件导出学生信息列表,支持多维度复合查询条件
|
||||
- **版本**: 1.2.1 (2025-01-07修复MapStruct转换错误)
|
||||
- **修复**: 解决 `XgStudentMsgVo` 到 `XgStudentMsgExportVo` 转换器缺失问题
|
||||
|
||||
#### 请求参数
|
||||
支持以下高级检索条件:
|
||||
|
||||
**基础信息检索**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| studentNo | string | 否 | 学号(模糊查询) |
|
||||
| name | string | 否 | 姓名(模糊查询) |
|
||||
| idCard | string | 否 | 身份证号(模糊查询) |
|
||||
| phone | string | 否 | 手机号码(模糊查询) |
|
||||
| email | string | 否 | 邮箱(模糊查询) |
|
||||
| gender | array | 否 | 性别数组:0-男,1-女 |
|
||||
| nationality | array | 否 | 民族数组 |
|
||||
| politicalStatus | array | 否 | 政治面貌数组 |
|
||||
| birthDateStart | string | 否 | 出生日期开始:yyyy-MM-dd |
|
||||
| birthDateEnd | string | 否 | 出生日期结束:yyyy-MM-dd |
|
||||
|
||||
**学籍信息检索**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| studentStatus | array | 否 | 学籍状态数组:1-在籍,2-休学,3-复学,4-退学,5-毕业 |
|
||||
| enrollmentYearStart | integer | 否 | 入学年份开始 |
|
||||
| enrollmentYearEnd | integer | 否 | 入学年份结束 |
|
||||
| admissionCategory | array | 否 | 录取类别数组 |
|
||||
|
||||
**学院专业班级检索**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| collegeName | string | 否 | 学院名称(模糊查询) |
|
||||
| majorName | string | 否 | 专业名称(模糊查询) |
|
||||
| className | string | 否 | 班级名称(模糊查询) |
|
||||
| grade | array | 否 | 年级数组 |
|
||||
| counselorName | string | 否 | 辅导员姓名(模糊查询) |
|
||||
| classTeacherName | string | 否 | 班主任姓名(模糊查询) |
|
||||
|
||||
**家庭信息检索**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| fatherName | string | 否 | 父亲姓名(模糊查询) |
|
||||
| motherName | string | 否 | 母亲姓名(模糊查询) |
|
||||
| familyEconomicStatus | array | 否 | 家庭经济状况数组 |
|
||||
| familyIncomeMin | number | 否 | 家庭收入最小值 |
|
||||
| familyIncomeMax | number | 否 | 家庭收入最大值 |
|
||||
|
||||
**特殊身份检索**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| isPoorStudent | array | 否 | 是否贫困生:0-否,1-是 |
|
||||
| isMinority | array | 否 | 是否少数民族:0-否,1-是 |
|
||||
| isDisabled | array | 否 | 是否残疾:0-否,1-是 |
|
||||
| isOrphan | array | 否 | 是否孤儿:0-否,1-是 |
|
||||
|
||||
**权限范围**
|
||||
| 参数名 | 类型 | 必填 | 说明 |
|
||||
|--------|------|------|------|
|
||||
| deptIds | array | 否 | 部门ID数组,用于权限控制 |
|
||||
|
||||
#### 响应数据
|
||||
返回Excel文件流,包含完整的学生信息数据
|
||||
|
||||
#### 修复记录
|
||||
- **2025-01-07 v1.2.1**: 修复MapStruct转换错误,解决 `XgStudentMsgVo` 到 `XgStudentMsgExportVo` 转换器缺失问题
|
||||
- **问题**: `MapstructUtils.convert()` 无法找到两个VO类之间的转换器,导致导出功能报错
|
||||
- **解决**: 在Controller中添加手动转换方法 `convertToExportVo()` 和 `convertToExportVoList()`
|
||||
- **影响**: 导出功能正常工作,所有字段完整映射
|
||||
- **2025-01-07 v1.2.0**: 修复分页限制问题,导出时pageSize设置为50000,确保能导出所有符合条件的记录
|
||||
- **问题**: 之前由于BO类默认pageSize=10,导致只能导出10条记录
|
||||
- **解决**: 取消注释Controller中的分页参数设置代码
|
||||
|
||||
### 2.9 查询学生个人信息
|
||||
- **接口路径**: GET `/studentMsg/studentMsg/personalInfo`
|
||||
- **权限标识**: `studentMsg:studentMsg:query`
|
||||
@@ -540,7 +616,10 @@ updateSupport: true
|
||||
|
||||
---
|
||||
|
||||
**文档更新时间**: 2025-01-27
|
||||
**文档版本**: 1.1.0
|
||||
**文档更新时间**: 2025-01-07
|
||||
**文档版本**: 1.2.0
|
||||
**维护人员**: Cursor AI
|
||||
**更新说明**: 新增学生信息导入功能,完善学生信息管理API文档
|
||||
**更新说明**:
|
||||
- 新增高级检索导出接口文档
|
||||
- 修复高级检索导出分页限制问题
|
||||
- 之前版本:新增学生信息导入功能,完善学生信息管理API文档
|
||||
Reference in new issue
Block a user