|
|
|
|
@ -0,0 +1,422 @@
|
|
|
|
|
import java.time.LocalDate;
|
|
|
|
|
import java.time.LocalDateTime;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 培训管理系统类 - 负责培训相关业务逻辑协调
|
|
|
|
|
* 遵循单一职责原则:只负责培训业务流程的协调和管理
|
|
|
|
|
*/
|
|
|
|
|
public class TrainingManagementSystem {
|
|
|
|
|
// 数据存储
|
|
|
|
|
private final Map<String, TrainingCourse> courses;
|
|
|
|
|
private final Map<String, TrainingRecord> trainingRecords;
|
|
|
|
|
private final Map<String, Certificate> certificates;
|
|
|
|
|
private final EmailService emailService;
|
|
|
|
|
private final Map<String, List<TrainingRecord>> employeeRecords; // 员工培训记录映射
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 构造函数
|
|
|
|
|
*/
|
|
|
|
|
public TrainingManagementSystem() {
|
|
|
|
|
this.courses = new HashMap<>();
|
|
|
|
|
this.trainingRecords = new HashMap<>();
|
|
|
|
|
this.certificates = new HashMap<>();
|
|
|
|
|
this.emailService = new EmailService();
|
|
|
|
|
this.employeeRecords = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ====================== 课程管理功能 ======================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 添加课程
|
|
|
|
|
* @param course 课程对象
|
|
|
|
|
* @return true如果添加成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean addCourse(TrainingCourse course) {
|
|
|
|
|
if (courses.containsKey(course.getCourseId())) {
|
|
|
|
|
System.out.println("课程ID已存在: " + course.getCourseId());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
courses.put(course.getCourseId(), course);
|
|
|
|
|
System.out.println("课程添加成功: " + course.getCourseName());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取课程
|
|
|
|
|
* @param courseId 课程ID
|
|
|
|
|
* @return 课程对象,如果不存在则返回null
|
|
|
|
|
*/
|
|
|
|
|
public TrainingCourse getCourse(String courseId) {
|
|
|
|
|
return courses.get(courseId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 更新课程信息
|
|
|
|
|
* @param course 课程对象
|
|
|
|
|
* @return true如果更新成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean updateCourse(TrainingCourse course) {
|
|
|
|
|
if (!courses.containsKey(course.getCourseId())) {
|
|
|
|
|
System.out.println("课程不存在: " + course.getCourseId());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
courses.put(course.getCourseId(), course);
|
|
|
|
|
System.out.println("课程更新成功: " + course.getCourseName());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除课程
|
|
|
|
|
* @param courseId 课程ID
|
|
|
|
|
* @return true如果删除成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean deleteCourse(String courseId) {
|
|
|
|
|
if (!courses.containsKey(courseId)) {
|
|
|
|
|
System.out.println("课程不存在: " + courseId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
// 检查是否有相关的培训记录
|
|
|
|
|
boolean hasRecords = trainingRecords.values().stream()
|
|
|
|
|
.anyMatch(record -> record.getCourseId().equals(courseId));
|
|
|
|
|
if (hasRecords) {
|
|
|
|
|
System.out.println("无法删除课程:存在相关的培训记录");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
courses.remove(courseId);
|
|
|
|
|
System.out.println("课程删除成功: " + courseId);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取所有启用的课程
|
|
|
|
|
* @return 启用的课程列表
|
|
|
|
|
*/
|
|
|
|
|
public List<TrainingCourse> getActiveCourses() {
|
|
|
|
|
return courses.values().stream()
|
|
|
|
|
.filter(TrainingCourse::isActive)
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 按部门获取课程
|
|
|
|
|
* @param department 部门
|
|
|
|
|
* @return 部门的课程列表
|
|
|
|
|
*/
|
|
|
|
|
public List<TrainingCourse> getCoursesByDepartment(String department) {
|
|
|
|
|
return courses.values().stream()
|
|
|
|
|
.filter(course -> course.getDepartment().equals(department))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ====================== 培训记录管理功能 ======================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 员工报名课程
|
|
|
|
|
* @param employeeId 员工ID
|
|
|
|
|
* @param courseId 课程ID
|
|
|
|
|
* @param employeeName 员工姓名
|
|
|
|
|
* @param employeeEmail 员工邮箱
|
|
|
|
|
* @return 培训记录ID
|
|
|
|
|
*/
|
|
|
|
|
public String enrollEmployee(String employeeId, String courseId,
|
|
|
|
|
String employeeName, String employeeEmail) {
|
|
|
|
|
// 检查课程是否存在且可报名
|
|
|
|
|
TrainingCourse course = courses.get(courseId);
|
|
|
|
|
if (course == null || !course.isEnrollable()) {
|
|
|
|
|
System.out.println("课程不存在或不可报名: " + courseId);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 生成记录ID
|
|
|
|
|
String recordId = generateRecordId(employeeId, courseId);
|
|
|
|
|
|
|
|
|
|
// 创建培训记录
|
|
|
|
|
TrainingRecord record = new TrainingRecord(recordId, employeeId, courseId);
|
|
|
|
|
trainingRecords.put(recordId, record);
|
|
|
|
|
|
|
|
|
|
// 添加到员工培训记录映射
|
|
|
|
|
employeeRecords.computeIfAbsent(employeeId, k -> new ArrayList<>()).add(record);
|
|
|
|
|
|
|
|
|
|
// 发送报名通知邮件
|
|
|
|
|
emailService.sendTrainingNotificationEmail(employeeId, employeeName, employeeEmail,
|
|
|
|
|
course.getCourseName(), LocalDate.now().toString(), course.getTrainer());
|
|
|
|
|
|
|
|
|
|
System.out.println("员工报名成功: " + employeeId + " -> " + course.getCourseName());
|
|
|
|
|
return recordId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 开始培训
|
|
|
|
|
* @param recordId 培训记录ID
|
|
|
|
|
* @param startDate 开始日期
|
|
|
|
|
* @return true如果开始成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean startTraining(String recordId, LocalDate startDate) {
|
|
|
|
|
TrainingRecord record = trainingRecords.get(recordId);
|
|
|
|
|
if (record == null) {
|
|
|
|
|
System.out.println("培训记录不存在: " + recordId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
TrainingCourse course = courses.get(record.getCourseId());
|
|
|
|
|
record.startTraining(startDate, course.getTrainer());
|
|
|
|
|
System.out.println("培训开始成功: " + recordId);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("培训开始失败: " + e.getMessage());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 完成培训
|
|
|
|
|
* @param recordId 培训记录ID
|
|
|
|
|
* @param completionDate 完成日期
|
|
|
|
|
* @param score 成绩
|
|
|
|
|
* @param employeeName 员工姓名
|
|
|
|
|
* @param employeeEmail 员工邮箱
|
|
|
|
|
* @return true如果完成成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean completeTraining(String recordId, LocalDate completionDate, double score,
|
|
|
|
|
String employeeName, String employeeEmail) {
|
|
|
|
|
TrainingRecord record = trainingRecords.get(recordId);
|
|
|
|
|
if (record == null) {
|
|
|
|
|
System.out.println("培训记录不存在: " + recordId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
record.completeTraining(completionDate, score);
|
|
|
|
|
|
|
|
|
|
// 如果成绩合格,自动颁发证书
|
|
|
|
|
if (record.isPassed()) {
|
|
|
|
|
issueCertificate(recordId, employeeName, employeeEmail);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
System.out.println("培训完成成功: " + recordId);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("培训完成失败: " + e.getMessage());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 取消培训
|
|
|
|
|
* @param recordId 培训记录ID
|
|
|
|
|
* @param reason 取消原因
|
|
|
|
|
* @return true如果取消成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean cancelTraining(String recordId, String reason) {
|
|
|
|
|
TrainingRecord record = trainingRecords.get(recordId);
|
|
|
|
|
if (record == null) {
|
|
|
|
|
System.out.println("培训记录不存在: " + recordId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
record.cancelTraining(reason);
|
|
|
|
|
System.out.println("培训取消成功: " + recordId);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("培训取消失败: " + e.getMessage());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ====================== 证书管理功能 ======================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 颁发证书
|
|
|
|
|
* @param recordId 培训记录ID
|
|
|
|
|
* @param employeeName 员工姓名
|
|
|
|
|
* @param employeeEmail 员工邮箱
|
|
|
|
|
* @return 证书ID
|
|
|
|
|
*/
|
|
|
|
|
public String issueCertificate(String recordId, String employeeName, String employeeEmail) {
|
|
|
|
|
TrainingRecord record = trainingRecords.get(recordId);
|
|
|
|
|
if (record == null) {
|
|
|
|
|
System.out.println("培训记录不存在: " + recordId);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TrainingCourse course = courses.get(record.getCourseId());
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 生成证书ID
|
|
|
|
|
String certificateId = generateCertificateId(record.getEmployeeId(), course.getCourseId());
|
|
|
|
|
|
|
|
|
|
// 创建证书
|
|
|
|
|
Certificate certificate = new Certificate(certificateId,
|
|
|
|
|
record.getEmployeeId(),
|
|
|
|
|
course.getCourseId(),
|
|
|
|
|
course.getCourseName(),
|
|
|
|
|
"公司培训部门",
|
|
|
|
|
course.getTrainer(),
|
|
|
|
|
record.getScore());
|
|
|
|
|
|
|
|
|
|
// 设置证书有效期(默认3年)
|
|
|
|
|
certificate.setValidYears(3);
|
|
|
|
|
|
|
|
|
|
// 颁发证书
|
|
|
|
|
record.issueCertificate(certificateId);
|
|
|
|
|
certificates.put(certificateId, certificate);
|
|
|
|
|
|
|
|
|
|
// 发送证书通知邮件
|
|
|
|
|
emailService.sendCertificateEmail(record.getEmployeeId(), employeeName, employeeEmail,
|
|
|
|
|
course.getCourseName(), LocalDate.now().toString());
|
|
|
|
|
|
|
|
|
|
System.out.println("证书颁发成功: " + certificateId);
|
|
|
|
|
return certificateId;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("证书颁发失败: " + e.getMessage());
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取证书
|
|
|
|
|
* @param certificateId 证书ID
|
|
|
|
|
* @return 证书对象
|
|
|
|
|
*/
|
|
|
|
|
public Certificate getCertificate(String certificateId) {
|
|
|
|
|
return certificates.get(certificateId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 吊销证书
|
|
|
|
|
* @param certificateId 证书ID
|
|
|
|
|
* @param reason 吊销原因
|
|
|
|
|
* @return true如果吊销成功
|
|
|
|
|
*/
|
|
|
|
|
public boolean revokeCertificate(String certificateId, String reason) {
|
|
|
|
|
Certificate certificate = certificates.get(certificateId);
|
|
|
|
|
if (certificate == null) {
|
|
|
|
|
System.out.println("证书不存在: " + certificateId);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
certificate.revokeCertificate(reason);
|
|
|
|
|
System.out.println("证书吊销成功: " + certificateId);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ====================== 查询功能 ======================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取员工的所有培训记录
|
|
|
|
|
* @param employeeId 员工ID
|
|
|
|
|
* @return 培训记录列表
|
|
|
|
|
*/
|
|
|
|
|
public List<TrainingRecord> getEmployeeTrainingRecords(String employeeId) {
|
|
|
|
|
return employeeRecords.getOrDefault(employeeId, new ArrayList<>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取员工的有效证书
|
|
|
|
|
* @param employeeId 员工ID
|
|
|
|
|
* @return 有效证书列表
|
|
|
|
|
*/
|
|
|
|
|
public List<Certificate> getEmployeeActiveCertificates(String employeeId) {
|
|
|
|
|
return certificates.values().stream()
|
|
|
|
|
.filter(cert -> cert.getEmployeeId().equals(employeeId) &&
|
|
|
|
|
cert.isActive() && !cert.isExpired())
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取课程的所有培训记录
|
|
|
|
|
* @param courseId 课程ID
|
|
|
|
|
* @return 培训记录列表
|
|
|
|
|
*/
|
|
|
|
|
public List<TrainingRecord> getCourseTrainingRecords(String courseId) {
|
|
|
|
|
return trainingRecords.values().stream()
|
|
|
|
|
.filter(record -> record.getCourseId().equals(courseId))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成培训统计报告
|
|
|
|
|
* @return 培训统计信息
|
|
|
|
|
*/
|
|
|
|
|
public Map<String, Object> generateTrainingReport() {
|
|
|
|
|
Map<String, Object> report = new HashMap<>();
|
|
|
|
|
|
|
|
|
|
// 总课程数
|
|
|
|
|
report.put("totalCourses", courses.size());
|
|
|
|
|
|
|
|
|
|
// 启用课程数
|
|
|
|
|
report.put("activeCourses", getActiveCourses().size());
|
|
|
|
|
|
|
|
|
|
// 总培训记录数
|
|
|
|
|
report.put("totalRecords", trainingRecords.size());
|
|
|
|
|
|
|
|
|
|
// 各状态记录数
|
|
|
|
|
Map<TrainingRecord.RecordStatus, Long> statusCount = trainingRecords.values().stream()
|
|
|
|
|
.collect(Collectors.groupingBy(TrainingRecord::getStatus, Collectors.counting()));
|
|
|
|
|
report.put("statusCount", statusCount);
|
|
|
|
|
|
|
|
|
|
// 总证书数
|
|
|
|
|
report.put("totalCertificates", certificates.size());
|
|
|
|
|
|
|
|
|
|
// 有效证书数
|
|
|
|
|
long activeCertificates = certificates.values().stream()
|
|
|
|
|
.filter(cert -> cert.isActive() && !cert.isExpired())
|
|
|
|
|
.count();
|
|
|
|
|
report.put("activeCertificates", activeCertificates);
|
|
|
|
|
|
|
|
|
|
// 平均成绩
|
|
|
|
|
Double averageScore = trainingRecords.values().stream()
|
|
|
|
|
.filter(record -> record.getScore() != null)
|
|
|
|
|
.mapToDouble(TrainingRecord::getScore)
|
|
|
|
|
.average()
|
|
|
|
|
.orElse(0);
|
|
|
|
|
report.put("averageScore", averageScore);
|
|
|
|
|
|
|
|
|
|
return report;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ====================== 辅助方法 ======================
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成培训记录ID
|
|
|
|
|
*/
|
|
|
|
|
private String generateRecordId(String employeeId, String courseId) {
|
|
|
|
|
return String.format("REC-%s-%s-%d",
|
|
|
|
|
employeeId, courseId, System.currentTimeMillis());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 生成证书ID
|
|
|
|
|
*/
|
|
|
|
|
private String generateCertificateId(String employeeId, String courseId) {
|
|
|
|
|
return String.format("CERT-%s-%s-%d",
|
|
|
|
|
employeeId, courseId, System.currentTimeMillis());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取系统中的员工数量
|
|
|
|
|
* @return 员工数量
|
|
|
|
|
*/
|
|
|
|
|
public int getEmployeeCount() {
|
|
|
|
|
return employeeRecords.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取即将到期的证书
|
|
|
|
|
* @param days 天数
|
|
|
|
|
* @return 即将到期的证书列表
|
|
|
|
|
*/
|
|
|
|
|
public List<Certificate> getExpiringCertificates(int days) {
|
|
|
|
|
LocalDate futureDate = LocalDate.now().plusDays(days);
|
|
|
|
|
return certificates.values().stream()
|
|
|
|
|
.filter(cert -> cert.isActive() &&
|
|
|
|
|
cert.getExpiryDate() != null &&
|
|
|
|
|
!cert.isExpired() &&
|
|
|
|
|
cert.getExpiryDate().isBefore(futureDate))
|
|
|
|
|
.collect(Collectors.toList());
|
|
|
|
|
}
|
|
|
|
|
}
|