Java全栈项目 - 学生档案管理系统

news/2024/12/21 23:13:52/

项目介绍

学生档案管理系统是一个基于 Spring Boot + Vue.js 的全栈项目,主要用于管理学生的基本信息、学习记录、考勤情况等数据。系统采用前后端分离架构,具有良好的可扩展性和维护性。

技术栈

后端技术

  • Spring Boot 2.7.x
  • Spring Security
  • MyBatis Plus
  • MySQL 8.0
  • Redis
  • JWT

前端技术

  • Vue 3
  • Element Plus
  • Axios
  • Vue Router
  • Pinia

核心功能

1. 用户管理

  • 用户登录/注销
  • 角色权限控制
  • 密码修改
  • 用户信息管理

2. 学生信息管理

  • 基本信息录入与修改
  • 学生照片上传
  • 信息批量导入/导出
  • 学生信息查询与筛选

3. 学习记录管理

  • 成绩录入
  • 成绩统计分析
  • 学习评价
  • 成绩报表导出

4. 考勤管理

  • 考勤记录
  • 请假管理
  • 考勤统计
  • 异常考勤提醒

数据库设计

主要数据表

-- 学生信息表
CREATE TABLE student (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_no VARCHAR(20) NOT NULL COMMENT '学号',name VARCHAR(50) NOT NULL COMMENT '姓名',gender TINYINT COMMENT '性别:0-女,1-男',birth_date DATE COMMENT '出生日期',phone VARCHAR(20) COMMENT '联系电话',email VARCHAR(100) COMMENT '邮箱',address TEXT COMMENT '家庭住址',create_time DATETIME DEFAULT CURRENT_TIMESTAMP,update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);-- 成绩记录表
CREATE TABLE score (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_id BIGINT COMMENT '学生ID',subject VARCHAR(50) COMMENT '科目',score DECIMAL(5,2) COMMENT '分数',exam_time DATE COMMENT '考试时间',create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

系统架构

├── backend                        // 后端项目
│   ├── src/main/java
│   │   ├── config                // 配置类
│   │   ├── controller            // 控制器
│   │   ├── service              // 服务层
│   │   ├── mapper               // 数据访问层
│   │   ├── entity               // 实体类
│   │   └── util                 // 工具类
│   └── resources
│       └── application.yml       // 配置文件
│
├── frontend                       // 前端项目
│   ├── src
│   │   ├── api                  // 接口请求
│   │   ├── components           // 组件
│   │   ├── router              // 路由配置
│   │   ├── store               // 状态管理
│   │   ├── utils               // 工具函数
│   │   └── views               // 页面
│   └── package.json

核心代码示例

后端接口示例

java">@RestController
@RequestMapping("/api/student")
public class StudentController {@Autowiredprivate StudentService studentService;@GetMapping("/list")public Result<IPage<Student>> list(PageParam pageParam, StudentQuery query) {IPage<Student> page = studentService.getStudentList(pageParam, query);return Result.success(page);}@PostMapping("/add")public Result<Boolean> add(@RequestBody Student student) {boolean success = studentService.save(student);return Result.success(success);}
}

前端代码示例

<template><div class="student-list"><el-table :data="studentList" border><el-table-column prop="studentNo" label="学号" /><el-table-column prop="name" label="姓名" /><el-table-column prop="gender" label="性别"><template #default="scope">{{ scope.row.gender === 1 ? '男' : '女' }}</template></el-table-column><el-table-column label="操作"><template #default="scope"><el-button @click="handleEdit(scope.row)">编辑</el-button><el-button type="danger" @click="handleDelete(scope.row)">删除</el-button></template></el-table-column></el-table></div>
</template>

项目亮点

  1. 前后端分离架构

    • 采用RESTful API设计规范
    • 使用JWT实现无状态认证
  2. 权限控制

    • 基于RBAC模型的权限设计
    • 细粒度的接口权限控制
  3. 性能优化

    • Redis缓存优化
    • MyBatis Plus分页查询优化
    • 前端组件按需加载
  4. 数据安全

    • 密码加密存储
    • SQL注入防护
    • XSS防护

部署方案

  1. 环境要求

    • JDK 1.8+
    • MySQL 8.0+
    • Redis 6.0+
    • Node.js 14+
  2. 部署步骤

    # 后端部署
    mvn clean package
    java -jar student-system.jar# 前端部署
    npm install
    npm run build
    

总结与展望

本项目实现了学生档案管理的核心功能,采用主流的技术栈和最佳实践,具有良好的可扩展性。未来计划添加以下功能:

  1. 接入第三方登录
  2. 添加移动端适配
  3. 引入数据分析功能
  4. 优化系统性能
  5. 增加系统监控功能

通过本项目的开发,不仅实现了学生档案的信息化管理,也为后续的功能扩展打下了良好的基础。

Java全栈项目 - 学生档案管理系统(一):用户与学生信息管理模块详解

一、用户管理模块

1. 数据库设计

-- 用户表
CREATE TABLE sys_user (id BIGINT PRIMARY KEY AUTO_INCREMENT,username VARCHAR(50) NOT NULL COMMENT '用户名',password VARCHAR(100) NOT NULL COMMENT '密码',real_name VARCHAR(50) COMMENT '真实姓名',phone VARCHAR(20) COMMENT '手机号',email VARCHAR(100) COMMENT '邮箱',avatar VARCHAR(255) COMMENT '头像URL',status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用',create_time DATETIME DEFAULT CURRENT_TIMESTAMP,update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);-- 角色表
CREATE TABLE sys_role (id BIGINT PRIMARY KEY AUTO_INCREMENT,role_name VARCHAR(50) NOT NULL COMMENT '角色名称',role_code VARCHAR(50) NOT NULL COMMENT '角色编码',description VARCHAR(200) COMMENT '角色描述',status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用'
);-- 用户角色关联表
CREATE TABLE sys_user_role (user_id BIGINT NOT NULL,role_id BIGINT NOT NULL,PRIMARY KEY (user_id, role_id)
);-- 权限表
CREATE TABLE sys_permission (id BIGINT PRIMARY KEY AUTO_INCREMENT,parent_id BIGINT COMMENT '父权限ID',name VARCHAR(50) NOT NULL COMMENT '权限名称',code VARCHAR(50) NOT NULL COMMENT '权限编码',type TINYINT COMMENT '类型:1-菜单,2-按钮',url VARCHAR(200) COMMENT '访问路径',status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用'
);

2. 核心功能实现

2.1 用户登录/注销
java">@RestController
@RequestMapping("/api/auth")
public class AuthController {@Autowiredprivate AuthService authService;@PostMapping("/login")public Result<LoginVO> login(@RequestBody LoginDTO loginDTO) {// 验证码校验if (!captchaService.verify(loginDTO.getCaptchaKey(), loginDTO.getCaptchaCode())) {throw new BusinessException("验证码错误");}// 用户认证String token = authService.login(loginDTO.getUsername(), loginDTO.getPassword());// 获取用户信息UserVO userInfo = authService.getUserInfo();return Result.success(new LoginVO(token, userInfo));}@PostMapping("/logout")public Result<Void> logout() {authService.logout();return Result.success();}
}
2.2 角色权限控制
java">@Service
public class RoleServiceImpl implements RoleService {@Autowiredprivate RoleMapper roleMapper;@Overridepublic List<RoleVO> getUserRoles(Long userId) {return roleMapper.selectRolesByUserId(userId);}@Override@PreAuthorize("hasRole('ADMIN')")public void assignRole(Long userId, List<Long> roleIds) {// 删除原有角色roleMapper.deleteUserRoles(userId);// 分配新角色if (!CollectionUtils.isEmpty(roleIds)) {roleMapper.insertUserRoles(userId, roleIds);}}
}
2.3 密码修改
java">@Service
public class UserServiceImpl implements UserService {@Autowiredprivate PasswordEncoder passwordEncoder;@Overridepublic void updatePassword(Long userId, String oldPassword, String newPassword) {SysUser user = userMapper.selectById(userId);if (user == null) {throw new BusinessException("用户不存在");}// 校验原密码if (!passwordEncoder.matches(oldPassword, user.getPassword())) {throw new BusinessException("原密码错误");}// 更新密码user.setPassword(passwordEncoder.encode(newPassword));userMapper.updateById(user);}
}

二、学生信息管理模块

1. 数据库设计

-- 学生基本信息表
CREATE TABLE student_info (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_no VARCHAR(20) NOT NULL COMMENT '学号',name VARCHAR(50) NOT NULL COMMENT '姓名',gender TINYINT COMMENT '性别:0-女,1-男',birth_date DATE COMMENT '出生日期',id_card VARCHAR(18) COMMENT '身份证号',phone VARCHAR(20) COMMENT '联系电话',email VARCHAR(100) COMMENT '邮箱',address TEXT COMMENT '家庭住址',photo_url VARCHAR(255) COMMENT '照片URL',class_id BIGINT COMMENT '班级ID',status TINYINT DEFAULT 1 COMMENT '状态:1-在读,2-毕业,3-退学',create_time DATETIME DEFAULT CURRENT_TIMESTAMP,update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

2. 核心功能实现

2.1 学生信息管理接口
java">@RestController
@RequestMapping("/api/student")
public class StudentController {@Autowiredprivate StudentService studentService;@PostMapping("/add")@PreAuthorize("hasPermission('student:add')")public Result<Boolean> add(@Valid @RequestBody StudentDTO studentDTO) {return Result.success(studentService.addStudent(studentDTO));}@PutMapping("/update")@PreAuthorize("hasPermission('student:update')")public Result<Boolean> update(@Valid @RequestBody StudentDTO studentDTO) {return Result.success(studentService.updateStudent(studentDTO));}@GetMapping("/page")@PreAuthorize("hasPermission('student:view')")public Result<IPage<StudentVO>> page(StudentQueryDTO queryDTO) {return Result.success(studentService.getStudentPage(queryDTO));}@PostMapping("/import")@PreAuthorize("hasPermission('student:import')")public Result<ImportResultVO> importStudents(MultipartFile file) {return Result.success(studentService.importStudents(file));}@GetMapping("/export")@PreAuthorize("hasPermission('student:export')")public void export(StudentQueryDTO queryDTO, HttpServletResponse response) {studentService.exportStudents(queryDTO, response);}
}
2.2 文件上传服务
java">@Service
public class FileServiceImpl implements FileService {@Value("${file.upload.path}")private String uploadPath;@Value("${file.access.url}")private String accessUrl;@Overridepublic String uploadPhoto(MultipartFile file) {// 校验文件类型String originalFilename = file.getOriginalFilename();if (!isImageFile(originalFilename)) {throw new BusinessException("只能上传图片文件");}// 生成文件名String fileName = generateFileName(originalFilename);// 保存文件try {File targetFile = new File(uploadPath + fileName);FileUtils.copyInputStreamToFile(file.getInputStream(), targetFile);} catch (IOException e) {throw new BusinessException("文件上传失败");}return accessUrl + fileName;}
}
2.3 Excel导入导出
java">@Service
public class StudentExcelService {@Autowiredprivate StudentService studentService;public ImportResultVO importStudents(MultipartFile file) {ImportResultVO result = new ImportResultVO();try {EasyExcel.read(file.getInputStream(), StudentImportDTO.class, new StudentImportListener(studentService)).sheet().doRead();} catch (Exception e) {throw new BusinessException("导入失败:" + e.getMessage());}return result;}public void exportStudents(List<StudentVO> students, HttpServletResponse response) {try {response.setContentType("application/vnd.ms-excel");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("学生信息", "UTF-8");response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), StudentExportVO.class).sheet("学生信息").doWrite(students);} catch (Exception e) {throw new BusinessException("导出失败:" + e.getMessage());}}
}

3. 前端实现

3.1 学生信息列表
<template><div class="student-list"><!-- 搜索表单 --><el-form :inline="true" :model="queryForm" class="search-form"><el-form-item label="学号"><el-input v-model="queryForm.studentNo" placeholder="请输入学号" /></el-form-item><el-form-item label="姓名"><el-input v-model="queryForm.name" placeholder="请输入姓名" /></el-form-item><el-form-item label="班级"><el-select v-model="queryForm.classId" placeholder="请选择班级"><el-optionv-for="item in classList":key="item.id":label="item.name":value="item.id"/></el-select></el-form-item><el-form-item><el-button type="primary" @click="handleSearch">查询</el-button><el-button @click="resetForm">重置</el-button></el-form-item></el-form><!-- 操作按钮 --><div class="operation-bar"><el-button type="primary" @click="handleAdd">新增学生</el-button><el-button type="success" @click="handleImport">批量导入</el-button><el-button type="warning" @click="handleExport">导出Excel</el-button></div><!-- 数据表格 --><el-table:data="studentList"borderv-loading="loading"><el-table-column prop="studentNo" label="学号" width="120" /><el-table-column prop="name" label="姓名" width="100" /><el-table-column prop="gender" label="性别" width="60"><template #default="scope">{{ scope.row.gender === 1 ? '男' : '女' }}</template></el-table-column><el-table-column prop="phone" label="联系电话" width="120" /><el-table-column prop="className" label="班级" width="120" /><el-table-column prop="status" label="状态" width="80"><template #default="scope"><el-tag :type="getStatusType(scope.row.status)">{{ getStatusText(scope.row.status) }}</el-tag></template></el-table-column><el-table-column label="操作" width="200" fixed="right"><template #default="scope"><el-button type="text" @click="handleEdit(scope.row)">编辑</el-button><el-button type="text" @click="handleViewDetail(scope.row)">查看</el-button><el-popconfirmtitle="确定删除该学生信息吗?"@confirm="handleDelete(scope.row)"><template #reference><el-button type="text" class="delete-btn">删除</el-button></template></el-popconfirm></template></el-table-column></el-table><!-- 分页 --><el-pagination:current-page="page.current":page-size="page.size":total="page.total"layout="total, sizes, prev, pager, next, jumper"@size-change="handleSizeChange"@current-change="handleCurrentChange"/><!-- 新增/编辑对话框 --><student-dialogv-if="dialogVisible":visible.sync="dialogVisible":student="currentStudent"@success="handleDialogSuccess"/></div>
</template><script>
import { ref, reactive } from 'vue'
import { getStudentList, deleteStudent } from '@/api/student'
import StudentDialog from './components/StudentDialog.vue'export default {name: 'StudentList',components: { StudentDialog },setup() {const loading = ref(false)const dialogVisible = ref(false)const currentStudent = ref(null)const queryForm = reactive({studentNo: '',name: '',classId: null})const page = reactive({current: 1,size: 10,total: 0})// 获取学生列表const loadData = async () => {loading.value = truetry {const res = await getStudentList({...queryForm,current: page.current,size: page.size})studentList.value = res.data.recordspage.total = res.data.total} finally {loading.value = false}}// 其他方法实现...return {loading,queryForm,page,dialogVisible,currentStudent,loadData,// ...其他方法}}
}
</script>

4. 安全性考虑

  1. 数据验证

    • 使用JSR-303注解进行参数校验
    • 前端表单验证
    • 文件上传类型限制
  2. 权限控制

    • 基于RBAC的权限控制
    • 使用Spring Security注解控制接口访问
    • 前端按钮级别权限控制
  3. 敏感信息保护

    • 身份证号等敏感信息加密存储
    • 密码加密传输和存储
    • 文件上传路径安全处理
  4. 操作日志

    • 记录重要操作日志
    • 使用AOP统一处理日志记录

这两个模块是学生档案管理系统的基础,为其他功能模块提供了必要的支持。通过合理的数据库设计、规范的接口实现和友好的用户界面,实现了用户管理和学生信息管理的核心功能。

Java全栈项目 - 学生档案管理系统(二):学习记录与考勤管理模块详解

一、学习记录管理模块

1. 数据库设计

-- 课程表
CREATE TABLE course (id BIGINT PRIMARY KEY AUTO_INCREMENT,course_name VARCHAR(100) NOT NULL COMMENT '课程名称',course_code VARCHAR(50) NOT NULL COMMENT '课程代码',credit DECIMAL(3,1) COMMENT '学分',teacher_id BIGINT COMMENT '任课教师ID',semester VARCHAR(20) COMMENT '学期',status TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-启用'
);-- 成绩记录表
CREATE TABLE score_record (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_id BIGINT NOT NULL COMMENT '学生ID',course_id BIGINT NOT NULL COMMENT '课程ID',score DECIMAL(5,2) COMMENT '成绩',exam_type TINYINT COMMENT '考试类型:1-平时成绩,2-期中考试,3-期末考试',score_type TINYINT COMMENT '成绩类型:1-百分制,2-等级制',grade_level VARCHAR(2) COMMENT '等级:A+、A、B+、B、C+、C、D、F',remark TEXT COMMENT '备注',create_time DATETIME DEFAULT CURRENT_TIMESTAMP,create_by BIGINT COMMENT '创建人ID'
);-- 学习评价表
CREATE TABLE study_evaluation (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_id BIGINT NOT NULL COMMENT '学生ID',course_id BIGINT NOT NULL COMMENT '课程ID',semester VARCHAR(20) COMMENT '学期',attendance_rate DECIMAL(5,2) COMMENT '出勤率',homework_completion DECIMAL(5,2) COMMENT '作业完成率',class_performance DECIMAL(5,2) COMMENT '课堂表现',evaluation_content TEXT COMMENT '评价内容',create_time DATETIME DEFAULT CURRENT_TIMESTAMP,create_by BIGINT COMMENT '评价人ID'
);

2. 核心功能实现

2.1 成绩录入与管理
java">@RestController
@RequestMapping("/api/score")
public class ScoreController {@Autowiredprivate ScoreService scoreService;@PostMapping("/batch-save")@PreAuthorize("hasPermission('score:add')")public Result<Boolean> batchSaveScore(@RequestBody List<ScoreDTO> scoreDTOList) {return Result.success(scoreService.batchSaveScore(scoreDTOList));}@GetMapping("/student/{studentId}")public Result<List<ScoreVO>> getStudentScores(@PathVariable Long studentId,@RequestParam(required = false) String semester) {return Result.success(scoreService.getStudentScores(studentId, semester));}
}@Service
public class ScoreServiceImpl implements ScoreService {@Autowiredprivate ScoreRecordMapper scoreRecordMapper;@Override@Transactional(rollbackFor = Exception.class)public boolean batchSaveScore(List<ScoreDTO> scoreDTOList) {List<ScoreRecord> records = scoreDTOList.stream().map(this::convertToEntity).collect(Collectors.toList());return scoreRecordMapper.batchInsert(records) > 0;}@Overridepublic ScoreAnalysisVO analyzeClassScore(Long courseId, String semester) {List<ScoreRecord> records = scoreRecordMapper.selectByCourseAndSemester(courseId, semester);return ScoreAnalysisVO.builder().averageScore(calculateAverage(records)).maxScore(calculateMax(records)).minScore(calculateMin(records)).passRate(calculatePassRate(records)).distributionMap(calculateDistribution(records)).build();}
}
2.2 成绩统计分析
java">@Service
public class ScoreAnalysisService {public ScoreStatisticsVO calculateStatistics(List<ScoreRecord> records) {DoubleSummaryStatistics stats = records.stream().mapToDouble(ScoreRecord::getScore).summaryStatistics();return ScoreStatisticsVO.builder().averageScore(stats.getAverage()).maxScore(stats.getMax()).minScore(stats.getMin()).totalCount(stats.getCount()).passCount(calculatePassCount(records)).excellentCount(calculateExcellentCount(records)).build();}public Map<String, Long> calculateDistribution(List<ScoreRecord> records) {return records.stream().collect(Collectors.groupingBy(record -> getScoreLevel(record.getScore()),Collectors.counting()));}private String getScoreLevel(double score) {if (score >= 90) return "优秀";if (score >= 80) return "良好";if (score >= 70) return "中等";if (score >= 60) return "及格";return "不及格";}
}
2.3 成绩报表导出
java">@Service
public class ScoreExportService {@Autowiredprivate ScoreService scoreService;public void exportScoreReport(ScoreQueryDTO queryDTO, HttpServletResponse response) {List<ScoreExportVO> exportData = scoreService.getScoreExportData(queryDTO);try {response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");response.setCharacterEncoding("utf-8");String fileName = URLEncoder.encode("成绩报表", "UTF-8").replaceAll("\\+", "%20");response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");EasyExcel.write(response.getOutputStream(), ScoreExportVO.class).sheet("成绩数据").registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).doWrite(exportData);} catch (IOException e) {throw new BusinessException("导出失败:" + e.getMessage());}}
}

二、考勤管理模块

1. 数据库设计

-- 考勤记录表
CREATE TABLE attendance_record (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_id BIGINT NOT NULL COMMENT '学生ID',course_id BIGINT NOT NULL COMMENT '课程ID',attendance_date DATE NOT NULL COMMENT '考勤日期',attendance_type TINYINT COMMENT '考勤类型:1-正常,2-迟到,3-早退,4-旷课,5-请假',check_in_time DATETIME COMMENT '签到时间',check_out_time DATETIME COMMENT '签退时间',remark VARCHAR(255) COMMENT '备注',create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);-- 请假申请表
CREATE TABLE leave_application (id BIGINT PRIMARY KEY AUTO_INCREMENT,student_id BIGINT NOT NULL COMMENT '学生ID',leave_type TINYINT COMMENT '请假类型:1-事假,2-病假,3-其他',start_time DATETIME NOT NULL COMMENT '开始时间',end_time DATETIME NOT NULL COMMENT '结束时间',reason TEXT COMMENT '请假原因',attachment_url VARCHAR(255) COMMENT '附件URL',status TINYINT COMMENT '状态:1-待审核,2-已通过,3-已驳回',approver_id BIGINT COMMENT '审批人ID',approve_time DATETIME COMMENT '审批时间',approve_remark VARCHAR(255) COMMENT '审批意见',create_time DATETIME DEFAULT CURRENT_TIMESTAMP
);

2. 核心功能实现

2.1 考勤记录管理
java">@RestController
@RequestMapping("/api/attendance")
public class AttendanceController {@Autowiredprivate AttendanceService attendanceService;@PostMapping("/check-in")public Result<Boolean> checkIn(@RequestBody AttendanceCheckDTO checkDTO) {return Result.success(attendanceService.checkIn(checkDTO));}@GetMapping("/statistics")public Result<AttendanceStatisticsVO> getStatistics(@RequestParam Long studentId,@RequestParam String semester) {return Result.success(attendanceService.calculateStatistics(studentId, semester));}
}@Service
public class AttendanceServiceImpl implements AttendanceService {@Autowiredprivate AttendanceRecordMapper attendanceRecordMapper;@Overridepublic boolean checkIn(AttendanceCheckDTO checkDTO) {// 判断是否迟到AttendanceType type = determineAttendanceType(checkDTO.getCourseId(), LocalDateTime.now());AttendanceRecord record = AttendanceRecord.builder().studentId(checkDTO.getStudentId()).courseId(checkDTO.getCourseId()).attendanceDate(LocalDate.now()).attendanceType(type.getCode()).checkInTime(LocalDateTime.now()).build();return attendanceRecordMapper.insert(record) > 0;}private AttendanceType determineAttendanceType(Long courseId, LocalDateTime checkTime) {// 获取课程时间安排CourseSchedule schedule = courseScheduleMapper.selectByCourseId(courseId);// 判断考勤类型if (checkTime.isAfter(schedule.getStartTime().plusMinutes(15))) {return AttendanceType.LATE;}return AttendanceType.NORMAL;}
}
2.2 请假管理
java">@RestController
@RequestMapping("/api/leave")
public class LeaveApplicationController {@Autowiredprivate LeaveApplicationService leaveService;@PostMapping("/apply")public Result<Boolean> applyLeave(@RequestBody LeaveApplicationDTO leaveDTO) {return Result.success(leaveService.submitApplication(leaveDTO));}@PostMapping("/approve/{id}")@PreAuthorize("hasRole('TEACHER')")public Result<Boolean> approveLeave(@PathVariable Long id,@RequestBody LeaveApprovalDTO approvalDTO) {return Result.success(leaveService.approveApplication(id, approvalDTO));}
}@Service
public class LeaveApplicationServiceImpl implements LeaveApplicationService {@Autowiredprivate LeaveApplicationMapper leaveApplicationMapper;@Override@Transactional(rollbackFor = Exception.class)public boolean submitApplication(LeaveApplicationDTO leaveDTO) {// 验证请假时间validateLeaveTime(leaveDTO);LeaveApplication application = convertToEntity(leaveDTO);application.setStatus(LeaveStatus.PENDING.getCode());// 保存请假申请boolean success = leaveApplicationMapper.insert(application) > 0;if (success) {// 发送通知给相关教师notifyTeachers(application);}return success;}@Overridepublic boolean approveApplication(Long id, LeaveApprovalDTO approvalDTO) {LeaveApplication application = leaveApplicationMapper.selectById(id);if (application == null) {throw new BusinessException("请假申请不存在");}application.setStatus(approvalDTO.getApproved() ? LeaveStatus.APPROVED.getCode() : LeaveStatus.REJECTED.getCode());application.setApproveRemark(approvalDTO.getRemark());application.setApproveTime(LocalDateTime.now());application.setApproverId(SecurityUtils.getCurrentUserId());boolean success = leaveApplicationMapper.updateById(application) > 0;if (success) {// 发送通知给学生notifyStudent(application);}return success;}
}
2.3 考勤统计与提醒
java">@Service
public class AttendanceAnalysisService {@Autowiredprivate AttendanceRecordMapper attendanceRecordMapper;@Autowiredprivate MessageService messageService;public AttendanceStatisticsVO calculateStatistics(Long studentId, String semester) {List<AttendanceRecord> records = attendanceRecordMapper.selectByStudentAndSemester(studentId, semester);return AttendanceStatisticsVO.builder().totalDays(records.size()).normalDays(countByType(records, AttendanceType.NORMAL)).lateDays(countByType(records, AttendanceType.LATE)).absentDays(countByType(records, AttendanceType.ABSENT)).leaveDays(countByType(records, AttendanceType.LEAVE)).attendanceRate(calculateAttendanceRate(records)).build();}@Scheduled(cron = "0 0 20 * * ?")  // 每天晚上8点执行public void checkAbsenceAndNotify() {// 获取当天的考勤异常记录List<AttendanceAbnormalVO> abnormalRecords = attendanceRecordMapper.selectAbnormalRecords(LocalDate.now());for (AttendanceAbnormalVO record : abnormalRecords) {// 发送通知给学生messageService.sendMessage(MessageDTO.builder().userId(record.getStudentId()).title("考勤异常提醒").content(buildAbnormalMessage(record)).type(MessageType.ATTENDANCE_ABNORMAL).build());// 发送通知给班主任messageService.sendMessage(MessageDTO.builder().userId(record.getTeacherId()).title("学生考勤异常通知").content(buildTeacherMessage(record)).type(MessageType.ATTENDANCE_ABNORMAL).build());}}
}

3. 前端实现

3.1 考勤记录页面
<template><div class="attendance-page"><!-- 日历视图 --><el-calendar v-model="currentDate"><template #dateCell="{ data }"><div class="calendar-cell" @click="showDayDetail(data)"><span>{{ data.day.split('-').slice(2).join('') }}</span><div class="attendance-status" v-if="getAttendanceStatus(data)"><el-tag :type="getStatusType(getAttendanceStatus(data))">{{ getStatusText(getAttendanceStatus(data)) }}</el-tag></div></div></template></el-calendar><!-- 考勤详情弹窗 --><el-dialogtitle="考勤详情":visible.sync="dialogVisible"width="600px"><div class="attendance-detail"><div class="detail-item" v-for="item in dayAttendanceList" :key="item.id"><span class="course-name">{{ item.courseName }}</span><span class="attendance-time">{{ formatDateTime(item.checkInTime) }}</span><span class="attendance-status"><el-tag :type="getStatusType(item.attendanceType)">{{ getStatusText(item.attendanceType) }}</el-tag></span></div></div></el-dialog><!-- 请假申请按钮 --><el-buttontype="primary"class="leave-button"@click="showLeaveDialog">申请请假</el-button><!-- 请假申请表单 --><leave-application-dialogv-if="leaveDialogVisible":visible.sync="leaveDialogVisible"@success="handleLeaveSuccess"/></div>
</template><script>
import { ref, reactive, onMounted } from 'vue'
import { getAttendanceList, getAttendanceDetail } from '@/api/attendance'
import LeaveApplicationDialog from './components/LeaveApplicationDialog.vue'export default {name: 'AttendancePage',components: { LeaveApplicationDialog },setup() {const currentDate = ref(new Date())const dialogVisible = ref(false)const leaveDialogVisible = ref(false)const dayAttendanceList = ref([])const attendanceMap = reactive({})// 获取考勤数据const loadAttendanceData = async () => {try {const res = await getAttendanceList({year: currentDate.value.getFullYear(),month: currentDate.value.getMonth() + 1})// 将考勤数据转换为日期映射res.data.forEach(item => {const date = item.attendanceDate.split('T')[0]if (!attendanceMap[date]) {attendanceMap[date] = []}attendanceMap[date].push(item)})} catch (error) {console.error('获取考勤数据失败:', error)}}// 获取某天的考勤状态const getAttendanceStatus = (data) => {const date = data.dayreturn attendanceMap[date]?.[0]?.attendanceType}// 显示某天的详细考勤记录const showDayDetail = async (data) => {const date = data.daytry {const res = await getAttendanceDetail(date)dayAttendanceList.value = res.datadialogVisible.value = true} catch (error) {console.error('获取考勤详情失败:', error)}}onMounted(() => {loadAttendanceData()})return {currentDate,dialogVisible,leaveDialogVisible,dayAttendanceList,getAttendanceStatus,showDayDetail}}
}
</script><style scoped>
.attendance-page {padding: 20px;
}.calendar-cell {height: 100%;position: relative;cursor: pointer;
}.attendance-status {position: absolute;bottom: 5px;right: 5px;
}.attendance-detail {max-height: 400px;overflow-y: auto;
}.detail-item {display: flex;justify-content: space-between;align-items: center;padding: 10px;border-bottom: 1px solid #eee;
}.leave-button {position: fixed;bottom: 30px;right: 30px;
}
</style>

4. 系统优化

  1. 性能优化

    • 使用Redis缓存考勤统计数据
    • 批量处理考勤记录
    • 定时任务性能优化
  2. 用户体验

    • 移动端适配
    • 实时推送考勤异常提醒
    • 请假审批进度实时通知
  3. 数据分析

    • 考勤趋势分析
    • 学生成绩与考勤关联分析
    • 可视化报表展示
  4. 系统集成

    • 对接门禁系统
    • 集成短信通知
    • 支持微信小程序签到

这两个模块通过合理的数据结构设计和功能实现,为学生档案管理系统提供了完整的学习记录和考勤管理功能。系统不仅支持基本的数据录入和管理,还提供了丰富的统计分析功能,帮助教师更好地了解学生的学习情况和出勤状况。


http://www.ppmy.cn/news/1557041.html

相关文章

解决docker环境下aspose-words转换word成pdf后乱码问题

描述 环境&#xff1a;docker 部署工具&#xff1a;Jenkins 需求&#xff1a;本地上传的word文档需要转换成pdf 问题&#xff1a;转换之后的pdf文档出现小框框&#xff08;乱码&#xff09; 转换成PDF的操作 pom&#xff1a; <dependency><groupId>org.apach…

【5G】5G 无线协议 Radio Protocols(一)

长期演进&#xff08;LTE&#xff09;无线电协议主要设计用于通过扁平架构提供PS服务&#xff0c;相比之前的代际&#xff0c;这代表了一个重大改进&#xff0c;它消除了支持电路交换&#xff08;CS&#xff09;服务和复杂架构中固有的复杂性。许多原始的LTE原则自第8版以来一直…

使用Vue创建前后端分离项目的过程(前端部分)

前端使用Vue.js作为前端开发框架&#xff0c;使用Vue CLI3脚手架搭建项目&#xff0c;使用axios作为HTTP库与后端API交互&#xff0c;使用Vue-router实现前端路由的定义、跳转以及参数的传递等&#xff0c;使用vuex进行数据状态管理&#xff0c;后端使用Node.jsexpress&#xf…

13.罗意文面试

1、工程化与架构设计&#xff08;考察项目管理和架构能力&#xff09; 1.1 你负责的可视化编排项目中&#xff0c;如何设计组件的数据结构来支持"拖拉拽"功能&#xff1f;如何处理组件间的联动关系&#xff1f; // 组件数据结构示例 {components: [{id: comp1,type…

【数据库系列】MongoTemplate 基本入门:MongoDB 的增删改查

MongoDB 是一种流行的 NoSQL 数据库&#xff0c;适合存储大量的非结构化数据。在 Spring 框架中&#xff0c;MongoTemplate 提供了一种方便的方式来与 MongoDB 进行交互&#xff0c;支持基本的增删改查操作。本文将详细介绍 MongoTemplate 的基本用法&#xff0c;包含语法介绍和…

轻松上手:使用 Vercel 部署 HTML 页面教程

&#x1f600; 在学习前端的过程中&#xff0c;部署项目往往是一个令人头疼的问题。然而&#xff0c;Vercel 为我们提供了一个便捷且免费的解决方案。 Vercel 是一个强大的云平台&#xff0c;专门用于前端项目的部署和托管。它不仅支持多种前端框架和静态网站生成器&#xff0…

3D视觉[一]3D计算机视觉

3D视觉[一]3D计算机视觉 3D计算机视觉概述 像机标定 文章目录 3D视觉[一]3D计算机视觉前言一、人类视觉二、计算机视觉2.1 计算机视觉的研究目的2.2 计算机视觉的研究任务2.3 计算机视觉的研究方法2.4 视觉计算理论2.5 马尔框架中计算机视觉表达的四个层次2.5.1 图像&#xff…

JS CSS HTML 的代码如何快速封装

我们为什么要封装代码&#xff0c;是因为封装后的代码&#xff0c;会显得非常美观&#xff0c;减少代码的复用&#xff0c;方便我们更好的去维护代码&#xff0c;不用一个一个页面的去找去改&#xff0c;直接封装好的代码里面去改就可以了 目录 1.html代码封装 2.CSS代码封装…