diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/controller/XgClassInfoController.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/controller/XgClassInfoController.java new file mode 100644 index 00000000..1045bc22 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/controller/XgClassInfoController.java @@ -0,0 +1,265 @@ +package org.dromara.xg.controller; + +import java.util.List; +import java.util.Map; + +import lombok.RequiredArgsConstructor; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.web.core.BaseController; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.xg.domain.vo.XgClassInfoVo; +import org.dromara.xg.domain.bo.XgClassInfoBo; +import org.dromara.xg.service.IXgClassInfoService; +import org.dromara.common.mybatis.core.page.TableDataInfo; + +/** + * 班级信息管理 + * + * @author Cursor AI + * @date 2025-01-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/xg/classInfo") +public class XgClassInfoController extends BaseController { + + private final IXgClassInfoService xgClassInfoService; + + /** + * 查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:list") + @GetMapping("/list") + public TableDataInfo list(XgClassInfoBo bo, PageQuery pageQuery) { + return xgClassInfoService.queryPageList(bo, pageQuery); + } + + /** + * 导出班级信息列表 + */ + @SaCheckPermission("xg:classInfo:export") + @Log(title = "班级信息", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(XgClassInfoBo bo, HttpServletResponse response) { + List list = xgClassInfoService.queryList(bo); + ExcelUtil.exportExcel(list, "班级信息", XgClassInfoVo.class, response); + } + + /** + * 获取班级信息详细信息 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(xgClassInfoService.queryById(id)); + } + + /** + * 新增班级信息 + */ + @SaCheckPermission("xg:classInfo:add") + @Log(title = "班级信息", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody XgClassInfoBo bo) { + return toAjax(xgClassInfoService.insertByBo(bo)); + } + + /** + * 修改班级信息 + */ + @SaCheckPermission("xg:classInfo:edit") + @Log(title = "班级信息", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody XgClassInfoBo bo) { + return toAjax(xgClassInfoService.updateByBo(bo)); + } + + /** + * 删除班级信息 + */ + @SaCheckPermission("xg:classInfo:remove") + @Log(title = "班级信息", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(xgClassInfoService.deleteWithValidByIds(List.of(ids), true)); + } + + /** + * 根据班级代码查询班级信息 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByClassCode/{classCode}") + public R getByClassCode(@NotBlank(message = "班级代码不能为空") + @PathVariable String classCode) { + return R.ok(xgClassInfoService.queryByClassCode(classCode)); + } + + /** + * 根据年级查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByGrade/{grade}") + public R> getByGrade(@NotBlank(message = "年级不能为空") + @PathVariable String grade) { + return R.ok(xgClassInfoService.queryByGrade(grade)); + } + + /** + * 根据学院代码查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByCollegeCode/{collegeCode}") + public R> getByCollegeCode(@NotBlank(message = "学院代码不能为空") + @PathVariable String collegeCode) { + return R.ok(xgClassInfoService.queryByCollegeCode(collegeCode)); + } + + /** + * 根据专业代码查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByMajorCode/{majorCode}") + public R> getByMajorCode(@NotBlank(message = "专业代码不能为空") + @PathVariable String majorCode) { + return R.ok(xgClassInfoService.queryByMajorCode(majorCode)); + } + + /** + * 根据辅导员ID查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByCounselorId/{counselorId}") + public R> getByCounselorId(@NotNull(message = "辅导员ID不能为空") + @PathVariable Long counselorId) { + return R.ok(xgClassInfoService.queryByCounselorId(counselorId)); + } + + /** + * 根据班主任ID查询班级信息列表 + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getByClassTeacherId/{classTeacherId}") + public R> getByClassTeacherId(@NotNull(message = "班主任ID不能为空") + @PathVariable Long classTeacherId) { + return R.ok(xgClassInfoService.queryByClassTeacherId(classTeacherId)); + } + + /** + * 获取班级可用选项列表(用于下拉框) + */ + @SaCheckPermission("xg:classInfo:query") + @GetMapping("/getClassOptions") + public R> getClassOptions() { + return R.ok(xgClassInfoService.getClassOptions()); + } + + /** + * 更新班级学生统计数据 + */ + @SaCheckPermission("xg:classInfo:edit") + @Log(title = "班级信息", businessType = BusinessType.UPDATE) + @PostMapping("/updateStudentCount/{id}") + public R updateStudentCount(@NotNull(message = "班级ID不能为空") + @PathVariable Long id) { + return toAjax(xgClassInfoService.updateStudentCount(id)); + } + + /** + * 批量更新班级学生统计数据 + */ + @SaCheckPermission("xg:classInfo:edit") + @Log(title = "班级信息", businessType = BusinessType.UPDATE) + @PostMapping("/batchUpdateStudentCount") + public R batchUpdateStudentCount(@NotEmpty(message = "班级ID列表不能为空") + @RequestBody List ids) { + return toAjax(xgClassInfoService.batchUpdateStudentCount(ids)); + } + + /** + * 启用班级 + */ + @SaCheckPermission("xg:classInfo:edit") + @Log(title = "班级信息", businessType = BusinessType.UPDATE) + @PostMapping("/enable/{id}") + public R enable(@NotNull(message = "班级ID不能为空") + @PathVariable Long id) { + return toAjax(xgClassInfoService.enableClass(id)); + } + + /** + * 禁用班级 + */ + @SaCheckPermission("xg:classInfo:edit") + @Log(title = "班级信息", businessType = BusinessType.UPDATE) + @PostMapping("/disable/{id}") + public R disable(@NotNull(message = "班级ID不能为空") + @PathVariable Long id) { + return toAjax(xgClassInfoService.disableClass(id)); + } + + // ================================ + // 统计数据接口 - 新增 + // ================================ + + /** + * 获取班级信息统计概览 + */ + @SaCheckPermission("xg:classInfo:statistics") + @GetMapping("/statistics") + public R> getStatistics() { + return R.ok(xgClassInfoService.getStatistics()); + } + + /** + * 统计各学院班级数量 + */ + @SaCheckPermission("xg:classInfo:statistics") + @GetMapping("/statistics/college") + public R>> countByCollege() { + return R.ok(xgClassInfoService.countByCollege()); + } + + /** + * 统计各年级班级数量 + */ + @SaCheckPermission("xg:classInfo:statistics") + @GetMapping("/statistics/grade") + public R>> countByGrade() { + return R.ok(xgClassInfoService.countByGrade()); + } + + /** + * 统计各专业班级数量 + */ + @SaCheckPermission("xg:classInfo:statistics") + @GetMapping("/statistics/major") + public R>> countByMajor() { + return R.ok(xgClassInfoService.countByMajor()); + } + + /** + * 统计班级状态分布 + */ + @SaCheckPermission("xg:classInfo:statistics") + @GetMapping("/statistics/status") + public R>> countByStatus() { + return R.ok(xgClassInfoService.countByStatus()); + } + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/XgClassInfo.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/XgClassInfo.java new file mode 100644 index 00000000..9e4d2d6a --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/XgClassInfo.java @@ -0,0 +1,346 @@ +package org.dromara.xg.domain; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 班级信息对象 xg_class_info + * + * @author Cursor AI + * @date 2025-01-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("xg_class_info") +public class XgClassInfo extends BaseEntity implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 班级ID + */ + @TableId(value = "id", type = IdType.ASSIGN_ID) + private Long id; + + /** + * 租户编号 + */ + @TableField("tenant_id") + private String tenantId; + + /** + * 班级代码 + */ + @TableField("class_code") + private String classCode; + + /** + * 班级名称 + */ + @TableField("class_name") + private String className; + + /** + * 班级类型:regular-普通班级,honor-荣誉班级,experimental-实验班级,special-特殊班级 + */ + @TableField("class_type") + private String classType; + + /** + * 年级 + */ + @TableField("grade") + private String grade; + + /** + * 入学年份 + */ + @TableField("enrollment_year") + private Integer enrollmentYear; + + /** + * 毕业年份 + */ + @TableField("graduation_year") + private Integer graduationYear; + + /** + * 专业代码 + */ + @TableField("major_code") + private String majorCode; + + /** + * 专业名称 + */ + @TableField("major_name") + private String majorName; + + /** + * 培养方式:全日制、在职、函授、夜大等 + */ + @TableField("training_type") + private String trainingType; + + /** + * 学位类型:本科、专科、研究生等 + */ + @TableField("degree_type") + private String degreeType; + + /** + * 学院代码 + */ + @TableField("college_code") + private String collegeCode; + + /** + * 学院名称 + */ + @TableField("college_name") + private String collegeName; + + /** + * 辅导员ID + */ + @TableField("counselor_id") + private Long counselorId; + + /** + * 辅导员姓名 + */ + @TableField("counselor_name") + private String counselorName; + + /** + * 班主任ID + */ + @TableField("class_teacher_id") + private Long classTeacherId; + + /** + * 班主任姓名 + */ + @TableField("class_teacher_name") + private String classTeacherName; + + /** + * 班级导师ID + */ + @TableField("class_advisor_id") + private Long classAdvisorId; + + /** + * 班级导师姓名 + */ + @TableField("class_advisor_name") + private String classAdvisorName; + + /** + * 班长ID + */ + @TableField("class_monitor_id") + private Long classMonitorId; + + /** + * 班长姓名 + */ + @TableField("class_monitor_name") + private String classMonitorName; + + /** + * 副班长ID + */ + @TableField("deputy_monitor_id") + private Long deputyMonitorId; + + /** + * 副班长姓名 + */ + @TableField("deputy_monitor_name") + private String deputyMonitorName; + + /** + * 班级状态:1-正常,2-暂停,3-毕业,4-解散 + */ + @TableField("class_status") + private String classStatus; + + /** + * 是否毕业:0-未毕业,1-已毕业 + */ + @TableField("is_graduation") + private Integer isGraduation; + + /** + * 毕业日期 + */ + @TableField("graduation_date") + private LocalDate graduationDate; + + /** + * 计划容量 + */ + @TableField("planned_capacity") + private Integer plannedCapacity; + + /** + * 当前学生数量 + */ + @TableField("current_student_count") + private Integer currentStudentCount; + + /** + * 最大学生数量 + */ + @TableField("max_student_count") + private Integer maxStudentCount; + + /** + * 男生数量 + */ + @TableField("male_count") + private Integer maleCount; + + /** + * 女生数量 + */ + @TableField("female_count") + private Integer femaleCount; + + /** + * 在籍学生数量 + */ + @TableField("active_count") + private Integer activeCount; + + /** + * 转入学生数量 + */ + @TableField("transfer_in_count") + private Integer transferInCount; + + /** + * 转出学生数量 + */ + @TableField("transfer_out_count") + private Integer transferOutCount; + + /** + * 退学学生数量 + */ + @TableField("dropout_count") + private Integer dropoutCount; + + /** + * 毕业学生数量 + */ + @TableField("graduate_count") + private Integer graduateCount; + + /** + * 办公室位置 + */ + @TableField("office_location") + private String officeLocation; + + /** + * 教室位置 + */ + @TableField("class_location") + private String classLocation; + + /** + * 联系电话 + */ + @TableField("contact_phone") + private String contactPhone; + + /** + * QQ群号 + */ + @TableField("qq_group") + private String qqGroup; + + /** + * 微信群 + */ + @TableField("wechat_group") + private String wechatGroup; + + /** + * 邮箱 + */ + @TableField("email") + private String email; + + /** + * 课程安排 + */ + @TableField("class_schedule") + private String classSchedule; + + /** + * 班级文化 + */ + @TableField("class_culture") + private String classCulture; + + /** + * 班级规章制度 + */ + @TableField("class_rules") + private String classRules; + + /** + * 班级描述 + */ + @TableField("class_description") + private String classDescription; + + /** + * 最后统计更新时间 + */ + @TableField("last_count_update") + private LocalDateTime lastCountUpdate; + + /** + * 扩展字段1 + */ + @TableField("ext_field1") + private String extField1; + + /** + * 扩展字段2 + */ + @TableField("ext_field2") + private String extField2; + + /** + * 扩展字段3 + */ + @TableField("ext_field3") + private String extField3; + + /** + * 备注 + */ + @TableField("remark") + private String remark; + + /** + * 删除标志(0代表存在 1代表删除) + */ + @TableField("deleted") + @TableLogic + private Integer deleted; + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/bo/XgClassInfoBo.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/bo/XgClassInfoBo.java new file mode 100644 index 00000000..6ffdba2c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/bo/XgClassInfoBo.java @@ -0,0 +1,378 @@ +package org.dromara.xg.domain.bo; + +import org.dromara.xg.domain.XgClassInfo; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import lombok.EqualsAndHashCode; +import jakarta.validation.constraints.*; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 班级信息业务对象 xg_class_info + * + * @author Cursor AI + * @date 2025-01-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = XgClassInfo.class, reverseConvertGenerate = false) +public class XgClassInfoBo extends BaseEntity { + + /** + * 班级ID + */ + @NotNull(message = "班级ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 班级代码 + */ + @NotBlank(message = "班级代码不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(max = 32, message = "班级代码长度不能超过32个字符") + private String classCode; + + /** + * 班级名称 + */ + @NotBlank(message = "班级名称不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(max = 100, message = "班级名称长度不能超过100个字符") + private String className; + + /** + * 班级类型:regular-普通班级,honor-荣誉班级,experimental-实验班级,special-特殊班级 + */ + private String classType; + + /** + * 年级 + */ + @NotBlank(message = "年级不能为空", groups = { AddGroup.class, EditGroup.class }) + @Size(max = 10, message = "年级长度不能超过10个字符") + private String grade; + + /** + * 入学年份 + */ + @NotNull(message = "入学年份不能为空", groups = { AddGroup.class, EditGroup.class }) + @Min(value = 1900, message = "入学年份不能小于1900") + @Max(value = 2100, message = "入学年份不能大于2100") + private Integer enrollmentYear; + + /** + * 毕业年份 + */ + @Min(value = 1900, message = "毕业年份不能小于1900") + @Max(value = 2100, message = "毕业年份不能大于2100") + private Integer graduationYear; + + /** + * 专业代码 + */ + @Size(max = 20, message = "专业代码长度不能超过20个字符") + private String majorCode; + + /** + * 专业名称 + */ + @Size(max = 100, message = "专业名称长度不能超过100个字符") + private String majorName; + + /** + * 培养方式:全日制、在职、函授、夜大等 + */ + @Size(max = 20, message = "培养方式长度不能超过20个字符") + private String trainingType; + + /** + * 学位类型:本科、专科、研究生等 + */ + @Size(max = 20, message = "学位类型长度不能超过20个字符") + private String degreeType; + + /** + * 学院代码 + */ + @Size(max = 20, message = "学院代码长度不能超过20个字符") + private String collegeCode; + + /** + * 学院名称 + */ + @Size(max = 100, message = "学院名称长度不能超过100个字符") + private String collegeName; + + /** + * 辅导员ID + */ + private Long counselorId; + + /** + * 辅导员姓名 + */ + @Size(max = 50, message = "辅导员姓名长度不能超过50个字符") + private String counselorName; + + /** + * 班主任ID + */ + private Long classTeacherId; + + /** + * 班主任姓名 + */ + @Size(max = 50, message = "班主任姓名长度不能超过50个字符") + private String classTeacherName; + + /** + * 班级导师ID + */ + private Long classAdvisorId; + + /** + * 班级导师姓名 + */ + @Size(max = 50, message = "班级导师姓名长度不能超过50个字符") + private String classAdvisorName; + + /** + * 班长ID + */ + private Long classMonitorId; + + /** + * 班长姓名 + */ + @Size(max = 50, message = "班长姓名长度不能超过50个字符") + private String classMonitorName; + + /** + * 副班长ID + */ + private Long deputyMonitorId; + + /** + * 副班长姓名 + */ + @Size(max = 50, message = "副班长姓名长度不能超过50个字符") + private String deputyMonitorName; + + /** + * 班级状态:1-正常,2-暂停,3-毕业,4-解散 + */ + private String classStatus; + + /** + * 是否毕业:0-未毕业,1-已毕业 + */ + private Integer isGraduation; + + /** + * 毕业日期 + */ + private LocalDate graduationDate; + + /** + * 计划容量 + */ + @Min(value = 1, message = "计划容量不能小于1") + @Max(value = 200, message = "计划容量不能大于200") + private Integer plannedCapacity; + + /** + * 当前学生数量 + */ + private Integer currentStudentCount; + + /** + * 最大学生数量 + */ + @Min(value = 1, message = "最大学生数量不能小于1") + @Max(value = 200, message = "最大学生数量不能大于200") + private Integer maxStudentCount; + + /** + * 男生数量 + */ + private Integer maleCount; + + /** + * 女生数量 + */ + private Integer femaleCount; + + /** + * 在籍学生数量 + */ + private Integer activeCount; + + /** + * 转入学生数量 + */ + private Integer transferInCount; + + /** + * 转出学生数量 + */ + private Integer transferOutCount; + + /** + * 退学学生数量 + */ + private Integer dropoutCount; + + /** + * 毕业学生数量 + */ + private Integer graduateCount; + + /** + * 办公室位置 + */ + @Size(max = 200, message = "办公室位置长度不能超过200个字符") + private String officeLocation; + + /** + * 教室位置 + */ + @Size(max = 100, message = "教室位置长度不能超过100个字符") + private String classLocation; + + /** + * 联系电话 + */ + @Size(max = 20, message = "联系电话长度不能超过20个字符") + private String contactPhone; + + /** + * QQ群号 + */ + @Size(max = 20, message = "QQ群号长度不能超过20个字符") + private String qqGroup; + + /** + * 微信群 + */ + @Size(max = 100, message = "微信群长度不能超过100个字符") + private String wechatGroup; + + /** + * 邮箱 + */ + @Email(message = "邮箱格式不正确") + @Size(max = 100, message = "邮箱长度不能超过100个字符") + private String email; + + /** + * 课程安排 + */ + private String classSchedule; + + /** + * 班级文化 + */ + private String classCulture; + + /** + * 班级规章制度 + */ + private String classRules; + + /** + * 班级描述 + */ + @Size(max = 500, message = "班级描述长度不能超过500个字符") + private String classDescription; + + /** + * 最后统计更新时间 + */ + private LocalDateTime lastCountUpdate; + + /** + * 扩展字段1 + */ + @Size(max = 200, message = "扩展字段1长度不能超过200个字符") + private String extField1; + + /** + * 扩展字段2 + */ + @Size(max = 200, message = "扩展字段2长度不能超过200个字符") + private String extField2; + + /** + * 扩展字段3 + */ + @Size(max = 200, message = "扩展字段3长度不能超过200个字符") + private String extField3; + + /** + * 备注 + */ + @Size(max = 500, message = "备注长度不能超过500个字符") + private String remark; + + // ========== 查询条件字段 ========== + + /** + * 入学年份开始 + */ + private Integer enrollmentYearStart; + + /** + * 入学年份结束 + */ + private Integer enrollmentYearEnd; + + /** + * 班级代码列表(用于批量查询) + */ + private List classCodeList; + + /** + * 班级状态列表(用于批量查询) + */ + private List classStatusList; + + /** + * 学院代码列表(用于批量查询) + */ + private List collegeCodeList; + + /** + * 专业代码列表(用于批量查询) + */ + private List majorCodeList; + + /** + * 年级列表(用于批量查询) + */ + private List gradeList; + + /** + * 辅导员ID列表(用于批量查询) + */ + private List counselorIdList; + + /** + * 班主任ID列表(用于批量查询) + */ + private List classTeacherIdList; + + /** + * 创建时间开始 + */ + private String createTimeStart; + + /** + * 创建时间结束 + */ + private String createTimeEnd; + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/vo/XgClassInfoVo.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/vo/XgClassInfoVo.java new file mode 100644 index 00000000..aa09eb8d --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/domain/vo/XgClassInfoVo.java @@ -0,0 +1,355 @@ +package org.dromara.xg.domain.vo; + +import org.dromara.xg.domain.XgClassInfo; +import cn.idev.excel.annotation.ExcelIgnoreUnannotated; +import cn.idev.excel.annotation.ExcelProperty; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 班级信息视图对象 xg_class_info + * + * @author Cursor AI + * @date 2025-01-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = XgClassInfo.class) +public class XgClassInfoVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 班级ID + */ + @ExcelProperty(value = "班级ID") + private Long id; + + /** + * 班级代码 + */ + @ExcelProperty(value = "班级代码") + private String classCode; + + /** + * 班级名称 + */ + @ExcelProperty(value = "班级名称") + private String className; + + /** + * 班级类型:regular-普通班级,honor-荣誉班级,experimental-实验班级,special-特殊班级 + */ + @ExcelProperty(value = "班级类型", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "xg_class_type") + private String classType; + + /** + * 年级 + */ + @ExcelProperty(value = "年级") + private String grade; + + /** + * 入学年份 + */ + @ExcelProperty(value = "入学年份") + private Integer enrollmentYear; + + /** + * 毕业年份 + */ + @ExcelProperty(value = "毕业年份") + private Integer graduationYear; + + /** + * 专业代码 + */ + @ExcelProperty(value = "专业代码") + private String majorCode; + + /** + * 专业名称 + */ + @ExcelProperty(value = "专业名称") + private String majorName; + + /** + * 培养方式:全日制、在职、函授、夜大等 + */ + @ExcelProperty(value = "培养方式") + private String trainingType; + + /** + * 学位类型:本科、专科、研究生等 + */ + @ExcelProperty(value = "学位类型") + private String degreeType; + + /** + * 学院代码 + */ + @ExcelProperty(value = "学院代码") + private String collegeCode; + + /** + * 学院名称 + */ + @ExcelProperty(value = "学院名称") + private String collegeName; + + /** + * 辅导员ID + */ + private Long counselorId; + + /** + * 辅导员姓名 + */ + @ExcelProperty(value = "辅导员姓名") + private String counselorName; + + /** + * 班主任ID + */ + private Long classTeacherId; + + /** + * 班主任姓名 + */ + @ExcelProperty(value = "班主任姓名") + private String classTeacherName; + + /** + * 班级导师ID + */ + private Long classAdvisorId; + + /** + * 班级导师姓名 + */ + @ExcelProperty(value = "班级导师姓名") + private String classAdvisorName; + + /** + * 班长ID + */ + private Long classMonitorId; + + /** + * 班长姓名 + */ + @ExcelProperty(value = "班长姓名") + private String classMonitorName; + + /** + * 副班长ID + */ + private Long deputyMonitorId; + + /** + * 副班长姓名 + */ + @ExcelProperty(value = "副班长姓名") + private String deputyMonitorName; + + /** + * 班级状态:1-正常,2-暂停,3-毕业,4-解散 + */ + @ExcelProperty(value = "班级状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "xg_class_status") + private String classStatus; + + /** + * 是否毕业:0-未毕业,1-已毕业 + */ + @ExcelProperty(value = "是否毕业", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未毕业,1=已毕业") + private Integer isGraduation; + + /** + * 毕业日期 + */ + @ExcelProperty(value = "毕业日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate graduationDate; + + /** + * 计划容量 + */ + @ExcelProperty(value = "计划容量") + private Integer plannedCapacity; + + /** + * 当前学生数量 + */ + @ExcelProperty(value = "当前学生数量") + private Integer currentStudentCount; + + /** + * 最大学生数量 + */ + @ExcelProperty(value = "最大学生数量") + private Integer maxStudentCount; + + /** + * 男生数量 + */ + @ExcelProperty(value = "男生数量") + private Integer maleCount; + + /** + * 女生数量 + */ + @ExcelProperty(value = "女生数量") + private Integer femaleCount; + + /** + * 在籍学生数量 + */ + @ExcelProperty(value = "在籍学生数量") + private Integer activeCount; + + /** + * 转入学生数量 + */ + @ExcelProperty(value = "转入学生数量") + private Integer transferInCount; + + /** + * 转出学生数量 + */ + @ExcelProperty(value = "转出学生数量") + private Integer transferOutCount; + + /** + * 退学学生数量 + */ + @ExcelProperty(value = "退学学生数量") + private Integer dropoutCount; + + /** + * 毕业学生数量 + */ + @ExcelProperty(value = "毕业学生数量") + private Integer graduateCount; + + /** + * 办公室位置 + */ + @ExcelProperty(value = "办公室位置") + private String officeLocation; + + /** + * 教室位置 + */ + @ExcelProperty(value = "教室位置") + private String classLocation; + + /** + * 联系电话 + */ + @ExcelProperty(value = "联系电话") + private String contactPhone; + + /** + * QQ群号 + */ + @ExcelProperty(value = "QQ群号") + private String qqGroup; + + /** + * 微信群 + */ + @ExcelProperty(value = "微信群") + private String wechatGroup; + + /** + * 邮箱 + */ + @ExcelProperty(value = "邮箱") + private String email; + + /** + * 课程安排 + */ + private String classSchedule; + + /** + * 班级文化 + */ + private String classCulture; + + /** + * 班级规章制度 + */ + private String classRules; + + /** + * 班级描述 + */ + @ExcelProperty(value = "班级描述") + private String classDescription; + + /** + * 最后统计更新时间 + */ + @ExcelProperty(value = "最后统计更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime lastCountUpdate; + + /** + * 扩展字段1 + */ + private String extField1; + + /** + * 扩展字段2 + */ + private String extField2; + + /** + * 扩展字段3 + */ + private String extField3; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + /** + * 创建者 + */ + private Long createBy; + + /** + * 创建时间 + */ + @ExcelProperty(value = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + /** + * 更新者 + */ + private Long updateBy; + + /** + * 更新时间 + */ + @ExcelProperty(value = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/mapper/XgClassInfoMapper.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/mapper/XgClassInfoMapper.java new file mode 100644 index 00000000..aed57614 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/mapper/XgClassInfoMapper.java @@ -0,0 +1,106 @@ +package org.dromara.xg.mapper; + +import org.dromara.xg.domain.XgClassInfo; +import org.dromara.xg.domain.vo.XgClassInfoVo; +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import com.baomidou.mybatisplus.core.conditions.Wrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; + +/** + * 班级信息Mapper接口 + * + * @author Cursor AI + * @date 2025-01-21 + */ +public interface XgClassInfoMapper extends BaseMapperPlus { + + /** + * 重写分页查询方法,使用自定义ResultMap + * + * @param page 分页参数 + * @param wrapper 查询条件 + * @return 分页结果 + */ +

> P selectVoPage(IPage page, @Param("ew") Wrapper wrapper); + + /** + * 根据班级代码查询班级信息 + * + * @param classCode 班级代码 + * @return 班级信息 + */ + XgClassInfoVo selectByClassCode(String classCode); + + /** + * 查询指定年级的班级列表 + * + * @param grade 年级 + * @return 班级列表 + */ + List selectByGrade(String grade); + + /** + * 查询指定学院的班级列表 + * + * @param collegeCode 学院代码 + * @return 班级列表 + */ + List selectByCollegeCode(String collegeCode); + + /** + * 查询指定专业的班级列表 + * + * @param majorCode 专业代码 + * @return 班级列表 + */ + List selectByMajorCode(String majorCode); + + /** + * 查询指定辅导员的班级列表 + * + * @param counselorId 辅导员ID + * @return 班级列表 + */ + List selectByCounselorId(Long counselorId); + + /** + * 查询指定班主任的班级列表 + * + * @param classTeacherId 班主任ID + * @return 班级列表 + */ + List selectByClassTeacherId(Long classTeacherId); + + /** + * 统计各学院班级数量 + * + * @return 学院班级数量统计 + */ + List> countByCollege(); + + /** + * 统计各年级班级数量 + * + * @return 年级班级数量统计 + */ + List> countByGrade(); + + /** + * 统计各专业班级数量 + * + * @return 专业班级数量统计 + */ + List> countByMajor(); + + /** + * 统计班级状态分布 + * + * @return 班级状态统计 + */ + List> countByClassStatus(); + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/IXgClassInfoService.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/IXgClassInfoService.java new file mode 100644 index 00000000..334bb88c --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/IXgClassInfoService.java @@ -0,0 +1,195 @@ +package org.dromara.xg.service; + +import org.dromara.xg.domain.vo.XgClassInfoVo; +import org.dromara.xg.domain.bo.XgClassInfoBo; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +/** + * 班级信息Service接口 + * + * @author Cursor AI + * @date 2025-01-21 + */ +public interface IXgClassInfoService { + + /** + * 查询班级信息 + * + * @param id 班级信息主键 + * @return 班级信息 + */ + XgClassInfoVo queryById(Long id); + + /** + * 查询班级信息列表 + * + * @param bo 班级信息 + * @return 班级信息集合 + */ + TableDataInfo queryPageList(XgClassInfoBo bo, PageQuery pageQuery); + + /** + * 查询班级信息列表 + * + * @param bo 班级信息 + * @return 班级信息集合 + */ + List queryList(XgClassInfoBo bo); + + /** + * 新增班级信息 + * + * @param bo 班级信息 + * @return 结果 + */ + Boolean insertByBo(XgClassInfoBo bo); + + /** + * 修改班级信息 + * + * @param bo 班级信息 + * @return 结果 + */ + Boolean updateByBo(XgClassInfoBo bo); + + /** + * 校验并批量删除班级信息信息 + * + * @param ids 需要删除的班级信息主键集合 + * @param isValid 是否校验,true-删除前校验,false-不校验 + * @return 结果 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); + + /** + * 根据班级代码查询班级信息 + * + * @param classCode 班级代码 + * @return 班级信息 + */ + XgClassInfoVo queryByClassCode(String classCode); + + /** + * 根据年级查询班级信息列表 + * + * @param grade 年级 + * @return 班级信息集合 + */ + List queryByGrade(String grade); + + /** + * 根据学院代码查询班级信息列表 + * + * @param collegeCode 学院代码 + * @return 班级信息集合 + */ + List queryByCollegeCode(String collegeCode); + + /** + * 根据专业代码查询班级信息列表 + * + * @param majorCode 专业代码 + * @return 班级信息集合 + */ + List queryByMajorCode(String majorCode); + + /** + * 根据辅导员ID查询班级信息列表 + * + * @param counselorId 辅导员ID + * @return 班级信息集合 + */ + List queryByCounselorId(Long counselorId); + + /** + * 根据班主任ID查询班级信息列表 + * + * @param classTeacherId 班主任ID + * @return 班级信息集合 + */ + List queryByClassTeacherId(Long classTeacherId); + + /** + * 获取班级可用选项列表(用于下拉框) + * + * @return 班级选项集合 + */ + List getClassOptions(); + + /** + * 更新班级学生统计数据 + * + * @param classId 班级ID + * @return 结果 + */ + Boolean updateStudentCount(Long classId); + + /** + * 批量更新班级学生统计数据 + * + * @param classIds 班级ID集合 + * @return 结果 + */ + Boolean batchUpdateStudentCount(Collection classIds); + + /** + * 启用班级 + * + * @param id 班级ID + * @return 结果 + */ + Boolean enableClass(Long id); + + /** + * 禁用班级 + * + * @param id 班级ID + * @return 结果 + */ + Boolean disableClass(Long id); + + // ================================ + // 统计数据接口 - 新增 + // ================================ + + /** + * 获取班级信息统计概览 + * + * @return 统计概览数据 + */ + Map getStatistics(); + + /** + * 统计各学院班级数量 + * + * @return 学院班级数量统计 + */ + List> countByCollege(); + + /** + * 统计各年级班级数量 + * + * @return 年级班级数量统计 + */ + List> countByGrade(); + + /** + * 统计各专业班级数量 + * + * @return 专业班级数量统计 + */ + List> countByMajor(); + + /** + * 统计班级状态分布 + * + * @return 班级状态统计 + */ + List> countByStatus(); + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/impl/XgClassInfoServiceImpl.java b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/impl/XgClassInfoServiceImpl.java new file mode 100644 index 00000000..3470e278 --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/java/org/dromara/xg/service/impl/XgClassInfoServiceImpl.java @@ -0,0 +1,513 @@ +package org.dromara.xg.service.impl; + +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.mybatis.core.page.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import lombok.RequiredArgsConstructor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; +import org.dromara.xg.domain.bo.XgClassInfoBo; +import org.dromara.xg.domain.vo.XgClassInfoVo; +import org.dromara.xg.domain.XgClassInfo; +import org.dromara.xg.mapper.XgClassInfoMapper; +import org.dromara.xg.service.IXgClassInfoService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; +import java.util.ArrayList; +import java.util.HashMap; +import java.time.LocalDateTime; + +/** + * 班级信息Service业务层处理 + * + * @author Cursor AI + * @date 2025-01-21 + */ +@RequiredArgsConstructor +@Service +public class XgClassInfoServiceImpl implements IXgClassInfoService { + + private static final Logger log = LoggerFactory.getLogger(XgClassInfoServiceImpl.class); + + private final XgClassInfoMapper baseMapper; + + /** + * 查询班级信息 + */ + @Override + public XgClassInfoVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 查询班级信息列表 + */ + @Override + public TableDataInfo queryPageList(XgClassInfoBo bo, PageQuery pageQuery) { + log.info("=== 班级信息分页查询开始 ==="); + log.info("查询条件: {}", bo); + log.info("分页参数: {}", pageQuery); + + // 构建查询条件 + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + log.info("Service构建的Lambda查询条件: {}", lqw.getTargetSql()); + + // 执行分页查询 + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + log.info("Mapper查询结果 - 总数: {}, 当前页记录数: {}", result.getTotal(), result.getRecords().size()); + + if (!result.getRecords().isEmpty()) { + log.info("第一条记录详情: {}", result.getRecords().get(0)); + } else { + log.warn("Mapper查询结果为空!"); + } + + TableDataInfo tableDataInfo = TableDataInfo.build(result); + log.info("最终返回结果 - 总数: {}, 行数: {}", tableDataInfo.getTotal(), tableDataInfo.getRows().size()); + log.info("=== 班级信息分页查询结束 ==="); + + return tableDataInfo; + } + + /** + * 查询班级信息列表 + */ + @Override + public List queryList(XgClassInfoBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(XgClassInfoBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getClassCode()), XgClassInfo::getClassCode, bo.getClassCode()); + lqw.like(StringUtils.isNotBlank(bo.getClassName()), XgClassInfo::getClassName, bo.getClassName()); + lqw.eq(StringUtils.isNotBlank(bo.getClassType()), XgClassInfo::getClassType, bo.getClassType()); + lqw.eq(StringUtils.isNotBlank(bo.getGrade()), XgClassInfo::getGrade, bo.getGrade()); + lqw.eq(bo.getEnrollmentYear() != null, XgClassInfo::getEnrollmentYear, bo.getEnrollmentYear()); + lqw.ge(bo.getEnrollmentYearStart() != null, XgClassInfo::getEnrollmentYear, bo.getEnrollmentYearStart()); + lqw.le(bo.getEnrollmentYearEnd() != null, XgClassInfo::getEnrollmentYear, bo.getEnrollmentYearEnd()); + lqw.eq(bo.getGraduationYear() != null, XgClassInfo::getGraduationYear, bo.getGraduationYear()); + lqw.eq(StringUtils.isNotBlank(bo.getMajorCode()), XgClassInfo::getMajorCode, bo.getMajorCode()); + lqw.like(StringUtils.isNotBlank(bo.getMajorName()), XgClassInfo::getMajorName, bo.getMajorName()); + lqw.eq(StringUtils.isNotBlank(bo.getTrainingType()), XgClassInfo::getTrainingType, bo.getTrainingType()); + lqw.eq(StringUtils.isNotBlank(bo.getDegreeType()), XgClassInfo::getDegreeType, bo.getDegreeType()); + lqw.eq(StringUtils.isNotBlank(bo.getCollegeCode()), XgClassInfo::getCollegeCode, bo.getCollegeCode()); + lqw.like(StringUtils.isNotBlank(bo.getCollegeName()), XgClassInfo::getCollegeName, bo.getCollegeName()); + lqw.eq(bo.getCounselorId() != null, XgClassInfo::getCounselorId, bo.getCounselorId()); + lqw.like(StringUtils.isNotBlank(bo.getCounselorName()), XgClassInfo::getCounselorName, bo.getCounselorName()); + lqw.eq(bo.getClassTeacherId() != null, XgClassInfo::getClassTeacherId, bo.getClassTeacherId()); + lqw.like(StringUtils.isNotBlank(bo.getClassTeacherName()), XgClassInfo::getClassTeacherName, bo.getClassTeacherName()); + lqw.eq(StringUtils.isNotBlank(bo.getClassStatus()), XgClassInfo::getClassStatus, bo.getClassStatus()); + lqw.eq(bo.getIsGraduation() != null, XgClassInfo::getIsGraduation, bo.getIsGraduation()); + + // 批量查询条件 + lqw.in(bo.getClassCodeList() != null && !bo.getClassCodeList().isEmpty(), XgClassInfo::getClassCode, bo.getClassCodeList()); + lqw.in(bo.getClassStatusList() != null && !bo.getClassStatusList().isEmpty(), XgClassInfo::getClassStatus, bo.getClassStatusList()); + lqw.in(bo.getCollegeCodeList() != null && !bo.getCollegeCodeList().isEmpty(), XgClassInfo::getCollegeCode, bo.getCollegeCodeList()); + lqw.in(bo.getMajorCodeList() != null && !bo.getMajorCodeList().isEmpty(), XgClassInfo::getMajorCode, bo.getMajorCodeList()); + lqw.in(bo.getGradeList() != null && !bo.getGradeList().isEmpty(), XgClassInfo::getGrade, bo.getGradeList()); + lqw.in(bo.getCounselorIdList() != null && !bo.getCounselorIdList().isEmpty(), XgClassInfo::getCounselorId, bo.getCounselorIdList()); + lqw.in(bo.getClassTeacherIdList() != null && !bo.getClassTeacherIdList().isEmpty(), XgClassInfo::getClassTeacherId, bo.getClassTeacherIdList()); + + // 时间范围查询 + lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null, + XgClassInfo::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime")); + + return lqw; + } + + /** + * 新增班级信息 + */ + @Override + public Boolean insertByBo(XgClassInfoBo bo) { + XgClassInfo add = MapstructUtils.convert(bo, XgClassInfo.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改班级信息 + */ + @Override + public Boolean updateByBo(XgClassInfoBo bo) { + XgClassInfo update = MapstructUtils.convert(bo, XgClassInfo.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(XgClassInfo entity) { + // 校验班级代码唯一性 + if (StringUtils.isNotBlank(entity.getClassCode())) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getClassCode, entity.getClassCode()); + lqw.ne(entity.getId() != null, XgClassInfo::getId, entity.getId()); + XgClassInfo existEntity = baseMapper.selectOne(lqw); + if (existEntity != null) { + throw new RuntimeException("班级代码已存在,请重新输入"); + } + } + + // 设置默认值 + if (entity.getClassType() == null) { + entity.setClassType("regular"); + } + if (entity.getClassStatus() == null) { + entity.setClassStatus("1"); + } + if (entity.getIsGraduation() == null) { + entity.setIsGraduation(0); + } + if (entity.getPlannedCapacity() == null) { + entity.setPlannedCapacity(50); + } + if (entity.getMaxStudentCount() == null) { + entity.setMaxStudentCount(entity.getPlannedCapacity()); + } + if (entity.getCurrentStudentCount() == null) { + entity.setCurrentStudentCount(0); + } + if (entity.getMaleCount() == null) { + entity.setMaleCount(0); + } + if (entity.getFemaleCount() == null) { + entity.setFemaleCount(0); + } + if (entity.getActiveCount() == null) { + entity.setActiveCount(0); + } + if (entity.getTransferInCount() == null) { + entity.setTransferInCount(0); + } + if (entity.getTransferOutCount() == null) { + entity.setTransferOutCount(0); + } + if (entity.getDropoutCount() == null) { + entity.setDropoutCount(0); + } + if (entity.getGraduateCount() == null) { + entity.setGraduateCount(0); + } + } + + /** + * 批量删除班级信息 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if (isValid) { + // 校验是否存在学生关联 + // TODO: 添加学生关联校验逻辑 + } + return baseMapper.deleteBatchIds(ids) > 0; + } + + /** + * 根据班级代码查询班级信息 + */ + @Override + public XgClassInfoVo queryByClassCode(String classCode) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getClassCode, classCode); + return baseMapper.selectVoOne(lqw); + } + + /** + * 根据年级查询班级信息列表 + */ + @Override + public List queryByGrade(String grade) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getGrade, grade); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.orderByAsc(XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据学院代码查询班级信息列表 + */ + @Override + public List queryByCollegeCode(String collegeCode) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getCollegeCode, collegeCode); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.orderByAsc(XgClassInfo::getGrade, XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据专业代码查询班级信息列表 + */ + @Override + public List queryByMajorCode(String majorCode) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getMajorCode, majorCode); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.orderByAsc(XgClassInfo::getGrade, XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据辅导员ID查询班级信息列表 + */ + @Override + public List queryByCounselorId(Long counselorId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getCounselorId, counselorId); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.orderByAsc(XgClassInfo::getGrade, XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 根据班主任ID查询班级信息列表 + */ + @Override + public List queryByClassTeacherId(Long classTeacherId) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getClassTeacherId, classTeacherId); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.orderByAsc(XgClassInfo::getGrade, XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 获取班级可用选项列表(用于下拉框) + */ + @Override + public List getClassOptions() { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getClassStatus, "1"); + lqw.select(XgClassInfo::getId, XgClassInfo::getClassCode, XgClassInfo::getClassName, + XgClassInfo::getGrade, XgClassInfo::getMajorName, XgClassInfo::getCollegeName); + lqw.orderByAsc(XgClassInfo::getGrade, XgClassInfo::getClassCode); + return baseMapper.selectVoList(lqw); + } + + /** + * 更新班级学生统计数据 + */ + @Override + public Boolean updateStudentCount(Long classId) { + // TODO: 实现学生统计数据更新逻辑 + // 1. 查询班级下的学生数量 + // 2. 统计男女学生数量 + // 3. 统计在籍学生数量 + // 4. 更新班级统计字段 + + XgClassInfo classInfo = baseMapper.selectById(classId); + if (classInfo != null) { + classInfo.setLastCountUpdate(LocalDateTime.now()); + return baseMapper.updateById(classInfo) > 0; + } + return false; + } + + /** + * 批量更新班级学生统计数据 + */ + @Override + public Boolean batchUpdateStudentCount(Collection classIds) { + boolean result = true; + for (Long classId : classIds) { + result = result && updateStudentCount(classId); + } + return result; + } + + /** + * 启用班级 + */ + @Override + public Boolean enableClass(Long id) { + XgClassInfo classInfo = baseMapper.selectById(id); + if (classInfo != null) { + classInfo.setClassStatus("1"); + return baseMapper.updateById(classInfo) > 0; + } + return false; + } + + /** + * 禁用班级 + */ + @Override + public Boolean disableClass(Long id) { + XgClassInfo classInfo = baseMapper.selectById(id); + if (classInfo != null) { + classInfo.setClassStatus("0"); + return baseMapper.updateById(classInfo) > 0; + } + return false; + } + + // ================================ + // 统计数据接口实现 - 新增 + // ================================ + + /** + * 获取班级信息统计概览 + */ + @Override + public Map getStatistics() { + Map result = new HashMap<>(); + + // 总班级数 + LambdaQueryWrapper totalLqw = Wrappers.lambdaQuery(); + long totalCount = baseMapper.selectCount(totalLqw); + result.put("totalCount", totalCount); + + // 正常班级数 + LambdaQueryWrapper activeLqw = Wrappers.lambdaQuery(); + activeLqw.eq(XgClassInfo::getClassStatus, "1"); + long activeCount = baseMapper.selectCount(activeLqw); + result.put("activeCount", activeCount); + + // 暂停班级数 + LambdaQueryWrapper pausedLqw = Wrappers.lambdaQuery(); + pausedLqw.eq(XgClassInfo::getClassStatus, "2"); + long pausedCount = baseMapper.selectCount(pausedLqw); + result.put("pausedCount", pausedCount); + + // 已毕业班级数 + LambdaQueryWrapper graduatedLqw = Wrappers.lambdaQuery(); + graduatedLqw.eq(XgClassInfo::getClassStatus, "3"); + long graduatedCount = baseMapper.selectCount(graduatedLqw); + result.put("graduatedCount", graduatedCount); + + // 总学生数(统计当前学生数量字段的总和) + LambdaQueryWrapper studentLqw = Wrappers.lambdaQuery(); + studentLqw.select(XgClassInfo::getCurrentStudentCount); + List classList = baseMapper.selectList(studentLqw); + long totalStudents = classList.stream() + .mapToLong(c -> c.getCurrentStudentCount() != null ? c.getCurrentStudentCount() : 0) + .sum(); + result.put("totalStudents", totalStudents); + + return result; + } + + /** + * 统计各学院班级数量 + */ + @Override + public List> countByCollege() { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.select(XgClassInfo::getCollegeCode, XgClassInfo::getCollegeName) + .groupBy(XgClassInfo::getCollegeCode, XgClassInfo::getCollegeName); + + List list = baseMapper.selectList(lqw); + List> result = new ArrayList<>(); + + for (XgClassInfo item : list) { + LambdaQueryWrapper countLqw = Wrappers.lambdaQuery(); + countLqw.eq(XgClassInfo::getCollegeCode, item.getCollegeCode()); + long count = baseMapper.selectCount(countLqw); + + Map map = new HashMap<>(); + map.put("collegeCode", item.getCollegeCode()); + map.put("collegeName", item.getCollegeName()); + map.put("count", count); + result.add(map); + } + + return result; + } + + /** + * 统计各年级班级数量 + */ + @Override + public List> countByGrade() { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.select(XgClassInfo::getGrade) + .groupBy(XgClassInfo::getGrade); + + List list = baseMapper.selectList(lqw); + List> result = new ArrayList<>(); + + for (XgClassInfo item : list) { + LambdaQueryWrapper countLqw = Wrappers.lambdaQuery(); + countLqw.eq(XgClassInfo::getGrade, item.getGrade()); + long count = baseMapper.selectCount(countLqw); + + Map map = new HashMap<>(); + map.put("grade", item.getGrade()); + map.put("count", count); + result.add(map); + } + + return result; + } + + /** + * 统计各专业班级数量 + */ + @Override + public List> countByMajor() { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.select(XgClassInfo::getMajorCode, XgClassInfo::getMajorName) + .groupBy(XgClassInfo::getMajorCode, XgClassInfo::getMajorName); + + List list = baseMapper.selectList(lqw); + List> result = new ArrayList<>(); + + for (XgClassInfo item : list) { + LambdaQueryWrapper countLqw = Wrappers.lambdaQuery(); + countLqw.eq(XgClassInfo::getMajorCode, item.getMajorCode()); + long count = baseMapper.selectCount(countLqw); + + Map map = new HashMap<>(); + map.put("majorCode", item.getMajorCode()); + map.put("majorName", item.getMajorName()); + map.put("count", count); + result.add(map); + } + + return result; + } + + /** + * 统计班级状态分布 + */ + @Override + public List> countByStatus() { + List> result = new ArrayList<>(); + + // 状态码对应的名称 + String[] statusCodes = {"1", "2", "3", "4"}; + String[] statusNames = {"正常", "暂停", "毕业", "解散"}; + + for (int i = 0; i < statusCodes.length; i++) { + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(XgClassInfo::getClassStatus, statusCodes[i]); + long count = baseMapper.selectCount(lqw); + + Map map = new HashMap<>(); + map.put("statusCode", statusCodes[i]); + map.put("statusName", statusNames[i]); + map.put("count", count); + result.add(map); + } + + return result; + } + +} diff --git a/backend/ruoyi-modules/ruoyi-xg-xx/src/main/resources/mapper/xg/XgClassInfoMapper.xml b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/resources/mapper/xg/XgClassInfoMapper.xml new file mode 100644 index 00000000..abc0a5ab --- /dev/null +++ b/backend/ruoyi-modules/ruoyi-xg-xx/src/main/resources/mapper/xg/XgClassInfoMapper.xml @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + select id, class_code, class_name, class_type, grade, enrollment_year, graduation_year, + major_code, major_name, training_type, degree_type, college_code, college_name, + counselor_id, counselor_name, class_teacher_id, class_teacher_name, + class_advisor_id, class_advisor_name, class_monitor_id, class_monitor_name, + deputy_monitor_id, deputy_monitor_name, class_status, is_graduation, graduation_date, + planned_capacity, current_student_count, max_student_count, male_count, female_count, + active_count, transfer_in_count, transfer_out_count, dropout_count, graduate_count, + office_location, class_location, contact_phone, qq_group, wechat_group, email, + class_schedule, class_culture, class_rules, class_description, last_count_update, + ext_field1, ext_field2, ext_field3, remark, create_by, create_time, update_by, update_time + from xg_class_info + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/web/src/api/xg-xx/classInfo.ts b/web/src/api/xg-xx/classInfo.ts new file mode 100644 index 00000000..e28c22df --- /dev/null +++ b/web/src/api/xg-xx/classInfo.ts @@ -0,0 +1,287 @@ +import request from '@/utils/request' +import { AxiosPromise } from 'axios' +import { ClassInfoVO, ClassInfoQuery, ClassInfoForm, OptionData } from './classInfo/types' + +// 通用类型定义 +interface TableDataInfo { + code: number; + msg: string; + rows: T[]; + total: number; +} + +interface R { + code: number; + msg: string; + data: T; +} + +/** + * 查询班级信息列表 + */ +export const listClassInfo = (query: ClassInfoQuery): AxiosPromise> => { + return request({ + url: '/xg/classInfo/list', + method: 'get', + params: query + }) +} + +/** + * 查询班级信息详细 + */ +export const getClassInfo = (id: string | number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/' + id, + method: 'get' + }) +} + +/** + * 新增班级信息 + */ +export const addClassInfo = (data: ClassInfoForm): AxiosPromise> => { + return request({ + url: '/xg/classInfo', + method: 'post', + data: data + }) +} + +/** + * 修改班级信息 + */ +export const updateClassInfo = (data: ClassInfoForm): AxiosPromise> => { + return request({ + url: '/xg/classInfo', + method: 'put', + data: data + }) +} + +/** + * 删除班级信息 + */ +export const delClassInfo = (id: string | number | Array): AxiosPromise> => { + return request({ + url: '/xg/classInfo/' + id, + method: 'delete' + }) +} + +/** + * 导出班级信息 + */ +export const exportClassInfo = (query: ClassInfoQuery): AxiosPromise => { + return request({ + url: '/xg/classInfo/export', + method: 'post', + data: query + }) +} + +/** + * 根据班级代码查询班级信息 + */ +export const getClassInfoByCode = (classCode: string): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByClassCode/' + classCode, + method: 'get' + }) +} + +/** + * 根据年级查询班级信息列表 + */ +export const getClassInfoByGrade = (grade: string): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByGrade/' + grade, + method: 'get' + }) +} + +/** + * 根据学院代码查询班级信息列表 + */ +export const getClassInfoByCollege = (collegeCode: string): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByCollegeCode/' + collegeCode, + method: 'get' + }) +} + +/** + * 根据专业代码查询班级信息列表 + */ +export const getClassInfoByMajor = (majorCode: string): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByMajorCode/' + majorCode, + method: 'get' + }) +} + +/** + * 根据辅导员ID查询班级信息列表 + */ +export const getClassInfoByCounselor = (counselorId: number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByCounselorId/' + counselorId, + method: 'get' + }) +} + +/** + * 根据班主任ID查询班级信息列表 + */ +export const getClassInfoByClassTeacher = (classTeacherId: number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getByClassTeacherId/' + classTeacherId, + method: 'get' + }) +} + +/** + * 获取班级选项列表(用于下拉框) + */ +export const getClassOptions = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/getClassOptions', // 修正路径:从 /options 改为 /getClassOptions + method: 'get' + }) +} + +/** + * 更新班级学生统计 + */ +export const updateStudentCount = (classId: number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/updateStudentCount/' + classId, + method: 'post' // 修正HTTP方法:从 put 改为 post + }) +} + +/** + * 批量更新班级学生统计 + */ +export const batchUpdateStudentCount = (classIds: number[]): AxiosPromise> => { + return request({ + url: '/xg/classInfo/batchUpdateStudentCount', + method: 'post', // 修正HTTP方法:从 put 改为 post + data: classIds + }) +} + +/** + * 启用班级 + */ +export const enableClass = (id: number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/enable/' + id, + method: 'post' // 修正HTTP方法:从 put 改为 post + }) +} + +/** + * 禁用班级 + */ +export const disableClass = (id: number): AxiosPromise> => { + return request({ + url: '/xg/classInfo/disable/' + id, + method: 'post' // 修正HTTP方法:从 put 改为 post + }) +} + +// ================================ +// 统计数据接口 - 新增 +// ================================ + +/** + * 获取班级信息统计概览 + */ +export const getClassStatistics = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/statistics', + method: 'get' + }) +} + +/** + * 统计各学院班级数量 + */ +export const countClassByCollege = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/statistics/college', + method: 'get' + }) +} + +/** + * 统计各年级班级数量 + */ +export const countClassByGrade = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/statistics/grade', + method: 'get' + }) +} + +/** + * 统计各专业班级数量 + */ +export const countClassByMajor = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/statistics/major', + method: 'get' + }) +} + +/** + * 统计班级状态分布 + */ +export const countClassByStatus = (): AxiosPromise> => { + return request({ + url: '/xg/classInfo/statistics/status', + method: 'get' + }) +} + +/** + * 获取学院选项 + */ +export const getCollegeOptions = (): AxiosPromise> => { + return request({ + url: '/xg/studentInfo/options/colleges', + method: 'get' + }) +} + +/** + * 获取专业选项 + */ +export const getMajorOptions = (collegeCode?: string): AxiosPromise> => { + return request({ + url: '/xg/studentInfo/options/majors', + method: 'get', + params: { collegeCode } + }) +} + +/** + * 获取辅导员选项 + */ +export const getCounselorOptions = (): AxiosPromise> => { + return request({ + url: '/xg/studentInfo/options/counselors', + method: 'get' + }) +} + +/** + * 获取班主任选项 + */ +export const getClassTeacherOptions = (): AxiosPromise> => { + return request({ + url: '/xg/studentInfo/options/classTeachers', + method: 'get' + }) +} diff --git a/web/src/api/xg-xx/classInfo/types.ts b/web/src/api/xg-xx/classInfo/types.ts new file mode 100644 index 00000000..0a9c2977 --- /dev/null +++ b/web/src/api/xg-xx/classInfo/types.ts @@ -0,0 +1,786 @@ +/** + * 班级信息管理模块 - 类型定义 + */ + +/** + * 班级信息 VO + */ +export interface ClassInfoVO { + /** + * 主键ID + */ + id: string | number; + + /** + * 租户编号 + */ + tenantId?: string; + + /** + * 班级代码 + */ + classCode: string; + + /** + * 班级名称 + */ + className: string; + + /** + * 班级类型:regular-普通班级,honor-荣誉班级,experimental-实验班级,special-特殊班级 + */ + classType?: string; + + /** + * 年级 + */ + grade: string; + + /** + * 入学年份 + */ + enrollmentYear: number; + + /** + * 毕业年份 + */ + graduationYear?: number; + + /** + * 专业代码 + */ + majorCode?: string; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 培养方式:全日制、在职、函授、夜大等 + */ + trainingType?: string; + + /** + * 学位类型:本科、专科、研究生等 + */ + degreeType?: string; + + /** + * 学院代码 + */ + collegeCode?: string; + + /** + * 学院名称 + */ + collegeName?: string; + + /** + * 辅导员ID + */ + counselorId?: string | number; + + /** + * 辅导员姓名 + */ + counselorName?: string; + + /** + * 班主任ID + */ + classTeacherId?: string | number; + + /** + * 班主任姓名 + */ + classTeacherName?: string; + + /** + * 班级导师ID + */ + classAdvisorId?: string | number; + + /** + * 班级导师姓名 + */ + classAdvisorName?: string; + + /** + * 班长ID + */ + classMonitorId?: string | number; + + /** + * 班长姓名 + */ + classMonitorName?: string; + + /** + * 副班长ID + */ + deputyMonitorId?: string | number; + + /** + * 副班长姓名 + */ + deputyMonitorName?: string; + + /** + * 班级状态:1-正常,2-暂停,3-毕业,4-解散 + */ + classStatus?: string; + + /** + * 是否毕业:0-未毕业,1-已毕业 + */ + isGraduation?: number; + + /** + * 毕业日期 + */ + graduationDate?: string; + + /** + * 计划容量 + */ + plannedCapacity?: number; + + /** + * 当前学生数量 + */ + currentStudentCount?: number; + + /** + * 最大学生数量 + */ + maxStudentCount?: number; + + /** + * 男生数量 + */ + maleCount?: number; + + /** + * 女生数量 + */ + femaleCount?: number; + + /** + * 在籍学生数量 + */ + activeCount?: number; + + /** + * 转入学生数量 + */ + transferInCount?: number; + + /** + * 转出学生数量 + */ + transferOutCount?: number; + + /** + * 退学学生数量 + */ + dropoutCount?: number; + + /** + * 毕业学生数量 + */ + graduateCount?: number; + + /** + * 办公室位置 + */ + officeLocation?: string; + + /** + * 教室位置 + */ + classLocation?: string; + + /** + * 联系电话 + */ + contactPhone?: string; + + /** + * QQ群号 + */ + qqGroup?: string; + + /** + * 微信群 + */ + wechatGroup?: string; + + /** + * 邮箱 + */ + email?: string; + + /** + * 课程安排 + */ + classSchedule?: string; + + /** + * 班级文化 + */ + classCulture?: string; + + /** + * 班级规章制度 + */ + classRules?: string; + + /** + * 班级描述 + */ + classDescription?: string; + + /** + * 最后统计更新时间 + */ + lastCountUpdate?: string; + + /** + * 扩展字段1 + */ + extField1?: string; + + /** + * 扩展字段2 + */ + extField2?: string; + + /** + * 扩展字段3 + */ + extField3?: string; + + /** + * 备注 + */ + remark?: string; + + /** + * 创建者 + */ + createBy?: string | number; + + /** + * 创建时间 + */ + createTime?: string; + + /** + * 更新者 + */ + updateBy?: string | number; + + /** + * 更新时间 + */ + updateTime?: string; +} + +/** + * 班级信息查询对象 + */ +export interface ClassInfoQuery { + /** + * 当前页数 + */ + pageNum?: number; + + /** + * 每页显示记录数 + */ + pageSize?: number; + + /** + * 班级代码 + */ + classCode?: string; + + /** + * 班级名称 + */ + className?: string; + + /** + * 班级类型 + */ + classType?: string; + + /** + * 年级 + */ + grade?: string; + + /** + * 入学年份 + */ + enrollmentYear?: number; + + /** + * 毕业年份 + */ + graduationYear?: number; + + /** + * 学院代码 + */ + collegeCode?: string; + + /** + * 学院名称 + */ + collegeName?: string; + + /** + * 专业代码 + */ + majorCode?: string; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 班主任ID + */ + classTeacherId?: string | number; + + /** + * 班主任姓名 + */ + classTeacherName?: string; + + /** + * 辅导员ID + */ + counselorId?: string | number; + + /** + * 辅导员姓名 + */ + counselorName?: string; + + /** + * 班级状态 + */ + classStatus?: string; + + /** + * 班级代码列表(批量查询) + */ + classCodeList?: string[]; + + /** + * 班级状态列表(批量查询) + */ + classStatusList?: string[]; + + /** + * 入学年份开始 + */ + enrollmentYearStart?: number; + + /** + * 入学年份结束 + */ + enrollmentYearEnd?: number; + + /** + * 创建时间开始 + */ + createTimeStart?: string; + + /** + * 创建时间结束 + */ + createTimeEnd?: string; +} + +/** + * 班级信息表单对象 + */ +export interface ClassInfoForm { + /** + * 主键ID + */ + id?: string | number; + + /** + * 班级代码 + */ + classCode?: string; + + /** + * 班级名称 + */ + className?: string; + + /** + * 班级类型 + */ + classType?: string; + + /** + * 年级 + */ + grade?: string; + + /** + * 入学年份 + */ + enrollmentYear?: number; + + /** + * 毕业年份 + */ + graduationYear?: number; + + /** + * 专业代码 + */ + majorCode?: string; + + /** + * 专业名称 + */ + majorName?: string; + + /** + * 培养方式 + */ + trainingType?: string; + + /** + * 学位类型 + */ + degreeType?: string; + + /** + * 学院代码 + */ + collegeCode?: string; + + /** + * 学院名称 + */ + collegeName?: string; + + /** + * 辅导员ID + */ + counselorId?: string | number; + + /** + * 辅导员姓名 + */ + counselorName?: string; + + /** + * 班主任ID + */ + classTeacherId?: string | number; + + /** + * 班主任姓名 + */ + classTeacherName?: string; + + /** + * 班级导师ID + */ + classAdvisorId?: string | number; + + /** + * 班级导师姓名 + */ + classAdvisorName?: string; + + /** + * 班长ID + */ + classMonitorId?: string | number; + + /** + * 班长姓名 + */ + classMonitorName?: string; + + /** + * 副班长ID + */ + deputyMonitorId?: string | number; + + /** + * 副班长姓名 + */ + deputyMonitorName?: string; + + /** + * 班级状态 + */ + classStatus?: string; + + /** + * 是否毕业 + */ + isGraduation?: number; + + /** + * 毕业日期 + */ + graduationDate?: string; + + /** + * 计划容量 + */ + plannedCapacity?: number; + + /** + * 当前学生数量 + */ + currentStudentCount?: number; + + /** + * 最大学生数量 + */ + maxStudentCount?: number; + + /** + * 男生数量 + */ + maleCount?: number; + + /** + * 女生数量 + */ + femaleCount?: number; + + /** + * 在籍学生数量 + */ + activeCount?: number; + + /** + * 转入学生数量 + */ + transferInCount?: number; + + /** + * 转出学生数量 + */ + transferOutCount?: number; + + /** + * 退学学生数量 + */ + dropoutCount?: number; + + /** + * 毕业学生数量 + */ + graduateCount?: number; + + /** + * 办公室位置 + */ + officeLocation?: string; + + /** + * 教室位置 + */ + classLocation?: string; + + /** + * 联系电话 + */ + contactPhone?: string; + + /** + * QQ群号 + */ + qqGroup?: string; + + /** + * 微信群 + */ + wechatGroup?: string; + + /** + * 邮箱 + */ + email?: string; + + /** + * 课程安排 + */ + classSchedule?: string; + + /** + * 班级文化 + */ + classCulture?: string; + + /** + * 班级规章制度 + */ + classRules?: string; + + /** + * 班级描述 + */ + classDescription?: string; + + /** + * 最后统计更新时间 + */ + lastCountUpdate?: string; + + /** + * 扩展字段1 + */ + extField1?: string; + + /** + * 扩展字段2 + */ + extField2?: string; + + /** + * 扩展字段3 + */ + extField3?: string; + + /** + * 备注 + */ + remark?: string; +} + +/** + * 班级统计数据 + */ +export interface ClassStatisticsData { + /** + * 总班级数 + */ + totalCount: number; + + /** + * 正常班级数 + */ + activeCount: number; + + /** + * 已毕业班级数 + */ + graduatedCount: number; + + /** + * 暂停班级数 + */ + suspendedCount: number; + + /** + * 解散班级数 + */ + dissolvedCount: number; + + /** + * 总学生数 + */ + totalStudentCount: number; + + /** + * 平均班级人数 + */ + averageClassSize: number; +} + +/** + * 班级选项数据 + */ +export interface OptionData { + /** + * 值 + */ + value: string | number; + + /** + * 标签 + */ + label: string; + + /** + * 是否禁用 + */ + disabled?: boolean; + + /** + * 扩展数据 + */ + data?: any; +} + +/** + * 班级图表数据 + */ +export interface ClassChartData { + /** + * 类别 + */ + category: string; + + /** + * 数值 + */ + value: number; + + /** + * 颜色 + */ + color?: string; + + /** + * 百分比 + */ + percentage?: number; +} + +/** + * 批量操作结果 + */ +export interface BatchOperationResult { + /** + * 总数 + */ + total: number; + + /** + * 成功数 + */ + success: number; + + /** + * 失败数 + */ + failed: number; + + /** + * 失败的记录 + */ + failedRecords?: Array<{ + id: string | number; + reason: string; + }>; +} diff --git a/web/src/views/xg-xx/classInfo/README.md b/web/src/views/xg-xx/classInfo/README.md new file mode 100644 index 00000000..6af9e3d5 --- /dev/null +++ b/web/src/views/xg-xx/classInfo/README.md @@ -0,0 +1,217 @@ +# 班级信息管理模块 + +## 📋 模块说明 + +- **模块名称**: 班级信息管理 (Class Information Management) +- **模块简称**: classInfo +- **对应后端**: backend/ruoyi-modules/ruoyi-xg-xx/ +- **对应API**: web/src/api/xg-xx/classInfo.ts + +## 🎯 功能概述 + +班级信息管理模块提供完整的班级信息管理功能,包括: + +### 📊 统计概览 +- 总班级数统计 +- 正常班级数统计 +- 总学生数统计 +- 平均学生数统计 + +### 🔍 查询功能 +- 班级代码、班级名称模糊查询 +- 年级、学院、专业级联查询 +- 班级类型、班级状态筛选 +- 班主任姓名查询 + +### 📝 基础管理 +- 班级信息新增、修改、删除 +- 班级信息详情查看 +- 班级信息批量导出 + +### 👥 人员配置 +- 班主任、辅导员配置 +- 班干部信息管理(班长、学习委员、生活委员等) +- 联系方式管理 + +### 📈 统计功能 +- 学生数量统计更新 +- 批量统计刷新 +- 实时数据同步 + +## 🎨 页面设计 + +### 页面布局 +- **搜索区域**: 8个搜索条件,支持组合查询 +- **统计卡片**: 4个统计指标,渐变色彩设计 +- **表格区域**: 完整的班级信息展示 +- **操作按钮**: 查看、编辑、删除、统计更新 + +### 对话框设计 +- **新增/编辑**: 分页签设计(基本信息、人员配置、联系方式) +- **详情查看**: 描述列表展示完整信息 +- **响应式布局**: 适配不同屏幕尺寸 + +## 🔧 技术特性 + +### 前端技术 +- **Vue 3.5.13** + **TypeScript 5.8.3** +- **Element Plus** UI组件库 +- **Composition API** 组合式API +- **响应式设计** 适配多端 + +### 样式设计 +- **参考后勤管理模块** 保持风格一致 +- **渐变色卡片** 美观的统计展示 +- **悬停效果** 良好的交互体验 +- **操作按钮** 图标化设计 + +### 数据处理 +- **级联选择** 学院-专业联动 +- **表单验证** 完整的输入校验 +- **状态管理** 响应式数据更新 +- **错误处理** 友好的错误提示 + +## 📋 API接口 + +### 16个标准API接口 + +#### 基础CRUD接口 +1. `GET /list` - 查询班级信息列表 +2. `POST /export` - 导出班级信息列表 +3. `GET /{id}` - 获取班级信息详情 +4. `POST /` - 新增班级信息 +5. `PUT /` - 修改班级信息 +6. `DELETE /{ids}` - 删除班级信息 + +#### 业务查询接口 +7. `GET /getByClassCode/{classCode}` - 根据班级代码查询 +8. `GET /getByGrade/{grade}` - 根据年级查询 +9. `GET /getByCollegeCode/{collegeCode}` - 根据学院代码查询 +10. `GET /getByMajorCode/{majorCode}` - 根据专业代码查询 +11. `GET /getByCounselorId/{counselorId}` - 根据辅导员ID查询 +12. `GET /getByClassTeacherId/{classTeacherId}` - 根据班主任ID查询 + +#### 辅助功能接口 +13. `GET /getClassOptions` - 获取班级选项列表 +14. `POST /updateStudentCount/{id}` - 更新班级学生统计 +15. `POST /batchUpdateStudentCount` - 批量更新学生统计 +16. `POST /enable/{id}` 和 `POST /disable/{id}` - 启用/禁用班级 + +## 🎯 权限控制 + +### 权限编码 +- `xg:classInfo:list` - 班级信息查询 +- `xg:classInfo:query` - 班级信息详情 +- `xg:classInfo:add` - 班级信息新增 +- `xg:classInfo:edit` - 班级信息修改 +- `xg:classInfo:remove` - 班级信息删除 +- `xg:classInfo:export` - 班级信息导出 + +### 按钮权限 +- 所有操作按钮都配置了对应的权限控制 +- 使用 `v-hasPermi` 指令进行权限验证 +- 无权限时自动隐藏相关按钮 + +## 📊 数据字典 + +### 班级类型 (xg_class_type) +- `regular` - 普通班级 +- `honor` - 荣誉班级 +- `experimental` - 实验班级 +- `special` - 特殊班级 + +### 班级状态 (xg_class_status) +- `1` - 正常 +- `2` - 暂停 +- `3` - 毕业 +- `4` - 解散 + +### 年级选项 (xg_grade_options) +- 支持动态配置年级选项 +- 适配不同学制需求 + +## 🔄 数据流程 + +### 查询流程 +1. 用户输入查询条件 +2. 前端组装查询参数 +3. 调用列表查询API +4. 后端返回分页数据 +5. 前端渲染表格和统计 + +### 新增/修改流程 +1. 用户填写表单信息 +2. 前端表单验证 +3. 调用新增/修改API +4. 后端业务处理 +5. 返回操作结果 +6. 刷新列表和统计 + +### 统计更新流程 +1. 用户点击统计更新 +2. 调用统计更新API +3. 后端重新计算学生数 +4. 更新班级统计信息 +5. 返回最新统计数据 + +## 🎨 样式规范 + +### 色彩设计 +- **主色调**: 蓝色系 (#409eff) +- **统计卡片**: 渐变色设计 +- **状态标签**: 语义化颜色 +- **交互效果**: 悬停和点击反馈 + +### 布局规范 +- **页面间距**: 8px 外边距 +- **组件间距**: 10px 组件间距 +- **表格样式**: 斑马纹和悬停效果 +- **按钮样式**: 图标化小按钮 + +### 响应式设计 +- **搜索区域**: 4列布局,支持响应式 +- **统计卡片**: 4列布局,移动端自适应 +- **表格列**: 固定宽度和自适应结合 +- **对话框**: 固定宽度,内容自适应 + +## 📝 使用说明 + +### 基本操作 +1. **查询班级**: 使用搜索条件筛选班级信息 +2. **新增班级**: 点击"新增班级"按钮,填写班级信息 +3. **修改班级**: 点击表格行的"编辑"按钮 +4. **查看详情**: 双击表格行或点击"查看"按钮 +5. **删除班级**: 选择班级后点击"删除"按钮 + +### 高级功能 +1. **批量操作**: 选择多个班级进行批量删除 +2. **导出数据**: 根据查询条件导出Excel文件 +3. **统计更新**: 手动更新班级学生统计数据 +4. **级联查询**: 学院-专业联动查询 + +### 注意事项 +- 班级代码必须唯一,系统会自动校验 +- 删除班级前请确认该班级下无学生信息 +- 统计数据会定期自动更新,也可手动刷新 +- 导出功能会根据当前查询条件生成文件 + +## 🚀 扩展功能 + +### 计划功能 +- 班级学生管理集成 +- 班级活动管理 +- 班级成绩统计 +- 班级考勤管理 + +### 技术优化 +- 虚拟滚动优化大数据量 +- 缓存机制提升查询性能 +- 实时数据推送 +- 移动端适配优化 + +--- + +**📅 创建时间**: 2025-01-01 +**👨‍💻 开发者**: Cursor AI +**📝 版本**: v1.0.0 +**🔄 更新**: 持续迭代中 \ No newline at end of file diff --git a/web/src/views/xg-xx/classInfo/index.vue b/web/src/views/xg-xx/classInfo/index.vue new file mode 100644 index 00000000..c8521938 --- /dev/null +++ b/web/src/views/xg-xx/classInfo/index.vue @@ -0,0 +1,1044 @@ + + + + +