一、个人简介
💖💖作者:计算机编程果茶熊 💙💙个人简介:曾长期从事计算机专业培训教学,担任过编程老师,同时本人也热爱上课教学,擅长Java、微信小程序、Python、Golang、安卓Android等多个IT方向。会做一些项目定制化开发、代码讲解、答辩教学、文档编写、也懂一些降重方面的技巧。平常喜欢分享一些自己开发中遇到的问题的解决办法,也喜欢交流技术,大家有技术代码这一块的问题可以问我! 💛💛想说的话:感谢大家的关注与支持! 💜💜 网站实战项目 安卓/小程序实战项目 大数据实战项目 计算机毕业设计选题 💕💕文末获取源码联系计算机编程果茶熊
二、系统介绍
开发语言:Java+Python 数据库:MySQL 系统架构:B/S 后端框架:SpringBoot(Spring+SpringMVC+Mybatis)+Django 前端:Vue+HTML+CSS+JavaScript+jQuery
实验室共享预约系统是一个基于B/S架构的综合性实验室管理平台,采用Java语言开发,后端运用Spring Boot框架整合Spring、SpringMVC和Mybatis技术构建稳定的服务层,前端使用Vue框架实现动态交互界面,数据存储采用MySQL关系型数据库,开发环境基于IDEA工具完成。系统围绕高校实验室资源调度的实际需求,构建了涵盖人员管理、资源管理、预约管理、设备管理、教学管理五大模块的完整业务体系。功能模块包括学生与教师的账号信息维护、实验室类型分类与详细信息登记、教师和学生的在线预约申请与审批、用户反馈意见收集、实验设备的全流程管理(涵盖设备档案建立、借用登记、归还核验、维修记录追踪)、实验课程安排与管理、科研项目的创建立项与进度监控、学生实验报告的在线提交与教师评估打分、教学资源的分类存储与共享下载等核心业务。系统通过统一的Web界面为师生提供便捷的服务入口,管理员可通过后台实时掌握实验室使用状态和设备运行情况,实现了实验室资源从申请、使用到评价的全过程数字化管理,提升了资源配置效率和服务质量。
三、视频解说
四、部分功能展示
五、部分代码展示
// 核心功能1: 实验室预约管理 - 预约冲突检测与智能调度
@Service
public class ReservationService {
@Autowired
private ReservationMapper reservationMapper;
@Autowired
private LaboratoryMapper laboratoryMapper;
@Autowired
private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public Result handleLabReservation(ReservationDTO reservationDTO) {
Integer userId = reservationDTO.getUserId();
Integer labId = reservationDTO.getLabId();
Date startTime = reservationDTO.getStartTime();
Date endTime = reservationDTO.getEndTime();
Integer participantCount = reservationDTO.getParticipantCount();
String purpose = reservationDTO.getPurpose();
// 查询实验室信息验证容量
Laboratory laboratory = laboratoryMapper.selectById(labId);
if (laboratory == null) {
return Result.error("实验室不存在");
}
if (participantCount > laboratory.getCapacity()) {
return Result.error("预约人数超过实验室容量上限" + laboratory.getCapacity() + "人");
}
if (laboratory.getStatus().equals("maintenance")) {
return Result.error("该实验室正在维护中,暂不可预约");
}
// 检测时间段冲突
List<Reservation> conflictReservations = reservationMapper.selectConflictReservations(
labId, startTime, endTime, Arrays.asList("pending", "approved")
);
if (!conflictReservations.isEmpty()) {
StringBuilder conflictInfo = new StringBuilder("该时间段存在冲突预约: ");
for (Reservation conflict : conflictReservations) {
User conflictUser = userMapper.selectById(conflict.getUserId());
conflictInfo.append(String.format("[%s %s-%s] ",
conflictUser.getName(),
new SimpleDateFormat("MM-dd HH:mm").format(conflict.getStartTime()),
new SimpleDateFormat("HH:mm").format(conflict.getEndTime())
));
}
return Result.error(conflictInfo.toString());
}
// 验证用户预约权限和频率限制
User currentUser = userMapper.selectById(userId);
Date now = new Date();
Calendar calendar = Calendar.getInstance();
calendar.setTime(now);
calendar.add(Calendar.DAY_OF_MONTH, -7);
Date weekAgo = calendar.getTime();
Integer weeklyReservationCount = reservationMapper.countUserReservations(
userId, weekAgo, now
);
Integer maxWeeklyReservations = "teacher".equals(currentUser.getRole()) ? 10 : 3;
if (weeklyReservationCount >= maxWeeklyReservations) {
return Result.error("您本周预约次数已达上限" + maxWeeklyReservations + "次");
}
// 计算用户信用评分
List<Reservation> userHistory = reservationMapper.selectUserReservationHistory(userId);
double creditScore = calculateCreditScore(userHistory);
// 计算预约优先级
long daysUntilReservation = (startTime.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
double urgencyFactor = Math.max(0, 10 - daysUntilReservation) * 2;
double priorityScore = creditScore * 0.7 + urgencyFactor * 0.3;
// 根据优先级决定审批状态
String status = priorityScore >= 70 ? "approved" : "pending";
if ("teacher".equals(currentUser.getRole())) {
status = "approved"; // 教师预约直接通过
}
// 创建预约记录
Reservation reservation = new Reservation();
reservation.setUserId(userId);
reservation.setLabId(labId);
reservation.setStartTime(startTime);
reservation.setEndTime(endTime);
reservation.setPurpose(purpose);
reservation.setParticipantCount(participantCount);
reservation.setPriorityScore(priorityScore);
reservation.setStatus(status);
reservation.setCreateTime(now);
reservationMapper.insert(reservation);
// 更新实验室使用统计
laboratory.setTotalReservations(laboratory.getTotalReservations() + 1);
laboratoryMapper.updateById(laboratory);
Map<String, Object> resultData = new HashMap<>();
resultData.put("reservationId", reservation.getId());
resultData.put("status", status);
resultData.put("priorityScore", priorityScore);
resultData.put("message", "approved".equals(status) ? "预约成功" : "预约已提交,等待审批");
return Result.success(resultData);
}
private double calculateCreditScore(List<Reservation> history) {
if (history.isEmpty()) {
return 80.0;
}
long totalCount = history.size();
long completedCount = history.stream().filter(r -> "completed".equals(r.getStatus())).count();
long cancelledCount = history.stream().filter(r -> "cancelled".equals(r.getStatus())).count();
return (completedCount * 100.0 / totalCount) - (cancelledCount * 5.0);
}
}
// 核心功能2: 设备借用归还管理 - 设备状态追踪与逾期处理
@Service
public class EquipmentBorrowService {
@Autowired
private EquipmentMapper equipmentMapper;
@Autowired
private EquipmentBorrowMapper borrowMapper;
@Autowired
private UserMapper userMapper;
@Autowired
private MaintenanceRecordMapper maintenanceMapper;
@Transactional(rollbackFor = Exception.class)
public Result processEquipmentOperation(EquipmentOperationDTO dto) {
String action = dto.getAction();
Integer equipmentId = dto.getEquipmentId();
Integer userId = dto.getUserId();
Equipment equipment = equipmentMapper.selectById(equipmentId);
if (equipment == null) {
return Result.error("设备不存在");
}
if ("borrow".equals(action)) {
return processBorrow(equipment, userId, dto);
} else if ("return".equals(action)) {
return processReturn(equipment, userId, dto);
}
return Result.error("无效的操作类型");
}
private Result processBorrow(Equipment equipment, Integer userId, EquipmentOperationDTO dto) {
if (!"available".equals(equipment.getStatus())) {
return Result.error("设备当前状态为" + equipment.getStatus() + ",无法借用");
}
Date expectedReturnDate = dto.getExpectedReturnDate();
Date now = new Date();
long borrowDays = (expectedReturnDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);
Integer maxBorrowDays = equipment.getMaxBorrowDays() != null ? equipment.getMaxBorrowDays() : 30;
if (borrowDays > maxBorrowDays) {
return Result.error("借用时长超过该设备最大限制" + maxBorrowDays + "天");
}
// 检查用户当前借用数量
User user = userMapper.selectById(userId);
Integer currentBorrowCount = borrowMapper.countUserCurrentBorrows(userId);
Integer maxBorrowCount = "teacher".equals(user.getRole()) ? 5 : 2;
if (currentBorrowCount >= maxBorrowCount) {
return Result.error("您当前已借用" + currentBorrowCount + "件设备,达到上限");
}
// 检查用户是否有逾期未处理记录
Integer overdueCount = borrowMapper.countUserOverdueRecords(userId);
if (overdueCount > 0) {
return Result.error("您有" + overdueCount + "条逾期归还记录未处理,暂不可借用");
}
// 创建借用记录
EquipmentBorrow borrow = new EquipmentBorrow();
borrow.setEquipmentId(equipmentId);
borrow.setUserId(userId);
borrow.setBorrowTime(now);
borrow.setExpectedReturnTime(expectedReturnDate);
borrow.setStatus("borrowed");
borrowMapper.insert(borrow);
// 更新设备状态
equipment.setStatus("borrowed");
equipment.setCurrentUserId(userId);
equipment.setLastBorrowTime(now);
equipmentMapper.updateById(equipment);
Map<String, Object> result = new HashMap<>();
result.put("borrowId", borrow.getId());
result.put("expectedReturnDate", expectedReturnDate);
return Result.success("借用成功", result);
}
private Result processReturn(Equipment equipment, Integer userId, EquipmentOperationDTO dto) {
EquipmentBorrow borrow = borrowMapper.selectActiveBorrow(equipmentId, userId);
if (borrow == null) {
return Result.error("未找到对应的借用记录");
}
Date now = new Date();
boolean isOverdue = now.after(borrow.getExpectedReturnTime());
long overdueDays = 0;
if (isOverdue) {
overdueDays = (now.getTime() - borrow.getExpectedReturnTime().getTime()) / (1000 * 60 * 60 * 24);
}
String condition = dto.getCondition() != null ? dto.getCondition() : "normal";
// 更新借用记录
borrow.setActualReturnTime(now);
borrow.setIsOverdue(isOverdue ? 1 : 0);
borrow.setOverdueDays((int)overdueDays);
borrow.setReturnCondition(condition);
borrow.setStatus("returned");
borrowMapper.updateById(borrow);
// 分析用户历史逾期情况
List<EquipmentBorrow> userHistory = borrowMapper.selectUserBorrowHistory(userId);
if (!userHistory.isEmpty()) {
long overdueRecords = userHistory.stream().filter(b -> b.getIsOverdue() == 1).count();
double overdueRate = (overdueRecords * 100.0) / userHistory.size();
if (overdueRate > 30) {
// 创建用户警告记录(此处简化处理)
User user = userMapper.selectById(userId);
user.setWarningCount(user.getWarningCount() + 1);
userMapper.updateById(user);
}
}
// 根据设备状态更新
if ("damaged".equals(condition) || "malfunction".equals(condition)) {
equipment.setStatus("maintenance");
// 创建维修记录
MaintenanceRecord maintenance = new MaintenanceRecord();
maintenance.setEquipmentId(equipmentId);
maintenance.setReportedBy(userId);
maintenance.setIssueDescription(dto.getIssueDescription());
maintenance.setStatus("pending");
maintenance.setReportTime(now);
maintenanceMapper.insert(maintenance);
} else {
equipment.setStatus("available");
}
equipment.setCurrentUserId(null);
equipment.setTotalBorrowCount(equipment.getTotalBorrowCount() + 1);
equipmentMapper.updateById(equipment);
Map<String, Object> result = new HashMap<>();
result.put("isOverdue", isOverdue);
result.put("overdueDays", overdueDays);
result.put("equipmentStatus", equipment.getStatus());
String message = isOverdue ? "归还成功,逾期" + overdueDays + "天" : "归还成功";
return Result.success(message, result);
}
}
// 核心功能3: 实验报告评估与统计分析
@Service
public class ReportEvaluationService {
@Autowired
private ExperimentReportMapper reportMapper;
@Autowired
private ReportEvaluationMapper evaluationMapper;
@Autowired
private CourseMapper courseMapper;
@Autowired
private UserMapper userMapper;
@Transactional(rollbackFor = Exception.class)
public Result analyzeAndEvaluateReports(EvaluationRequestDTO request) {
Integer courseId = request.getCourseId();
Integer teacherId = request.getTeacherId();
// 获取待评估报告
List<ExperimentReport> pendingReports = reportMapper.selectByCourseAndStatus(courseId, "submitted");
if (pendingReports.isEmpty()) {
return Result.error("暂无待评估报告");
}
Course course = courseMapper.selectById(courseId);
Date deadline = course.getReportDeadline();
List<Map<String, Object>> evaluationResults = new ArrayList<>();
List<Double> allScores = new ArrayList<>();
for (ExperimentReport report : pendingReports) {
// 计算提交延迟天数
long delayDays = 0;
if (report.getSubmitTime().after(deadline)) {
delayDays = (report.getSubmitTime().getTime() - deadline.getTime()) / (1000 * 60 * 60 * 24);
}
// 字数评分(满分20分)
double wordScore = Math.min(20, report.getWordCount() / 100.0);
// 附件完整性评分(满分15分)
double attachmentScore = Math.min(15, report.getAttachmentCount() * 5);
// 提交及时性评分(满分10分)
double timelinessScore = delayDays > 0 ? Math.max(0, 10 - delayDays * 2) : 10;
// 查询学生历史报告表现
List<ReportEvaluation> studentHistory = evaluationMapper.selectStudentHistory(report.getStudentId());
double historyBonus = 0;
if (!studentHistory.isEmpty()) {
double avgHistoryScore = studentHistory.stream()
.mapToDouble(ReportEvaluation::getTotalScore)
.average()
.orElse(0);
if (avgHistoryScore >= 85) {
historyBonus = 5;
} else if (avgHistoryScore >= 75) {
historyBonus = 3;
}
}
// 内容质量基础分(满分50,默认给中等水平)
double contentBaseScore = 35;
// 计算初步总分
double preliminaryScore = wordScore + attachmentScore + timelinessScore + historyBonus + contentBaseScore;
// 创建评估记录
ReportEvaluation evaluation = new ReportEvaluation();
evaluation.setReportId(report.getId());
evaluation.setEvaluatorId(teacherId);
evaluation.setWordScore(wordScore);
evaluation.setAttachmentScore(attachmentScore);
evaluation.setTimelinessScore(timelinessScore);
evaluation.setContentScore(contentBaseScore);
evaluation.setTotalScore(preliminaryScore);
evaluation.setStatus("preliminary");
evaluation.setEvaluationTime(new Date());
evaluationMapper.insert(evaluation);
// 更新报告状态
report.setStatus("evaluated");
reportMapper.updateById(report);
allScores.add(preliminaryScore);
Map<String, Object> resultItem = new HashMap<>();
resultItem.put("reportId", report.getId());
resultItem.put("studentId", report.getStudentId());
resultItem.put("preliminaryScore", preliminaryScore);
resultItem.put("delayDays", delayDays);
evaluationResults.add(resultItem);
}
// 统计分析
double avgScore = allScores.stream().mapToDouble(Double::doubleValue).average().orElse(0);
double maxScore = allScores.stream().mapToDouble(Double::doubleValue).max().orElse(0);
double minScore = allScores.stream().mapToDouble(Double::doubleValue).min().orElse(0);
// 计算标准差
double variance = allScores.stream()
.mapToDouble(score -> Math.pow(score - avgScore, 2))
.average()
.orElse(0);
double stdDev = Math.sqrt(variance);
Map<String, Object> statistics = new HashMap<>();
statistics.put("totalReports", evaluationResults.size());
statistics.put("averageScore", Math.round(avgScore * 100) / 100.0);
statistics.put("maxScore", maxScore);
statistics.put("minScore", minScore);
statistics.put("standardDeviation", Math.round(stdDev * 100) / 100.0);
Map<String, Object> finalResult = new HashMap<>();
finalResult.put("evaluatedCount", evaluationResults.size());
finalResult.put("statistics", statistics);
finalResult.put("details", evaluationResults);
return Result.success("批量评估完成", finalResult);
}
}
六、部分文档展示
七、END
💕💕文末获取源码联系计算机编程果茶熊