commit a3e2a782ea627bf46e0a66b180d3d47fb413ecf2 Author: seahi Date: Fri Dec 6 09:53:30 2024 +0800 first commit diff --git a/AbsenceManager.iml b/AbsenceManager.iml new file mode 100644 index 0000000..abe781f --- /dev/null +++ b/AbsenceManager.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/dao/BaseDAO.java b/src/dao/BaseDAO.java new file mode 100644 index 0000000..3cd994d --- /dev/null +++ b/src/dao/BaseDAO.java @@ -0,0 +1,43 @@ +package dao; + +import java.util.List; + +/** + * 基础DAO接口,定义通用的CRUD操作 + * @param 实体类型 + */ +public interface BaseDAO { + /** + * 插入一条记录 + * @param entity 实体对象 + * @return 影响的行数 + */ + int insert(T entity); + + /** + * 根据ID删除记录 + * @param id 主键ID + * @return 影响的行数 + */ + int deleteById(int id); + + /** + * 更新记录 + * @param entity 实体对象 + * @return 影响的行数 + */ + int update(T entity); + + /** + * 根据ID查询记录 + * @param id 主键ID + * @return 实体对象 + */ + T findById(int id); + + /** + * 查询所有记录 + * @return 实体对象列表 + */ + List findAll(); +} diff --git a/src/dao/DAOFactory.java b/src/dao/DAOFactory.java new file mode 100644 index 0000000..2b31ce9 --- /dev/null +++ b/src/dao/DAOFactory.java @@ -0,0 +1,38 @@ +package dao; + +import dao.impl.StudentDAOImpl; +import dao.impl.TeacherDAOImpl; +import dao.impl.LeaveRequestDAOImpl; + +/** + * DAO工厂类,用于获取各种DAO的实例 + */ +public class DAOFactory { + private static final StudentDAO studentDAO = new StudentDAOImpl(); + private static final TeacherDAO teacherDAO = new TeacherDAOImpl(); + private static final LeaveRequestDAO leaveRequestDAO = new LeaveRequestDAOImpl(); + + /** + * 获取StudentDAO实例 + * @return StudentDAO实例 + */ + public static StudentDAO getStudentDAO() { + return studentDAO; + } + + /** + * 获取TeacherDAO实例 + * @return TeacherDAO实例 + */ + public static TeacherDAO getTeacherDAO() { + return teacherDAO; + } + + /** + * 获取LeaveRequestDAO实例 + * @return LeaveRequestDAO实例 + */ + public static LeaveRequestDAO getLeaveRequestDAO() { + return leaveRequestDAO; + } +} diff --git a/src/dao/LeaveRequestDAO.java b/src/dao/LeaveRequestDAO.java new file mode 100644 index 0000000..2749117 --- /dev/null +++ b/src/dao/LeaveRequestDAO.java @@ -0,0 +1,35 @@ +package dao; + +import model.LeaveRequest; +import model.ApprovalStatus; +import java.util.Date; +import java.util.List; + +/** + * 请假申请DAO接口 + */ +public interface LeaveRequestDAO extends BaseDAO { + /** + * 根据学生ID查询请假记录 + * @param studentId 学生ID + * @return 请假记录列表 + */ + List findByStudentId(int studentId); + + /** + * 根据审批状态查询请假记录 + * @param status 审批状态 + * @return 请假记录列表 + */ + List findByStatus(ApprovalStatus status); + + + /** + * 更新请假申请状态 + * @param id 请假申请ID + * @param status 新状态 + * @param approverComment 审批意见 + * @return 影响的行数 + */ + int updateStatus(int id, ApprovalStatus status, String approverComment); +} diff --git a/src/dao/StudentDAO.java b/src/dao/StudentDAO.java new file mode 100644 index 0000000..d671652 --- /dev/null +++ b/src/dao/StudentDAO.java @@ -0,0 +1,30 @@ +package dao; + +import model.Student; +import java.util.List; + +/** + * 学生DAO接口 + */ +public interface StudentDAO extends BaseDAO { + /** + * 根据学号查询学生 + * @param studentId 学号 + * @return 学生对象 + */ + Student findByStudentId(String studentId); + + /** + * 根据班级查询学生列表 + * @param className 班级名称 + * @return 学生列表 + */ + List findByClassName(String className); + + /** + * 根据姓名模糊查询学生 + * @param name 学生姓名 + * @return 学生列表 + */ + List findByNameLike(String name); +} diff --git a/src/dao/TeacherDAO.java b/src/dao/TeacherDAO.java new file mode 100644 index 0000000..f9fa338 --- /dev/null +++ b/src/dao/TeacherDAO.java @@ -0,0 +1,30 @@ +package dao; + +import model.Teacher; +import java.util.List; + +/** + * 教师DAO接口 + */ +public interface TeacherDAO extends BaseDAO { + /** + * 根据工号查询教师 + * @param teacherId 教师工号 + * @return 教师对象 + */ + Teacher findByTeacherId(String teacherId); + + /** + * 根据部门查询教师列表 + * @param department 部门名称 + * @return 教师列表 + */ + List findByDepartment(String department); + + /** + * 根据姓名模糊查询教师 + * @param name 教师姓名 + * @return 教师列表 + */ + List findByNameLike(String name); +} diff --git a/src/dao/impl/LeaveRequestDAOImpl.java b/src/dao/impl/LeaveRequestDAOImpl.java new file mode 100644 index 0000000..6058102 --- /dev/null +++ b/src/dao/impl/LeaveRequestDAOImpl.java @@ -0,0 +1,227 @@ +package dao.impl; + +import dao.LeaveRequestDAO; +import model.ApprovalStatus; +import model.LeaveRequest; +import model.Student; +import model.Teacher; +import util.DatabaseUtil; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +public class LeaveRequestDAOImpl implements LeaveRequestDAO { + private final StudentDAOImpl studentDAO = new StudentDAOImpl(); + private final TeacherDAOImpl teacherDAO = new TeacherDAOImpl(); + + @Override + public int insert(LeaveRequest request) { + String sql = "INSERT INTO leave_requests (student_id, start_time, end_time, status, " + + "duration, location, reason_type, reason_detail, is_leaving_city, " + + "special_situation, request_time) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + stmt.setInt(1, request.getStudent().getId()); + stmt.setTimestamp(2, new Timestamp(request.getStartTime().getTime())); + stmt.setTimestamp(3, new Timestamp(request.getEndTime().getTime())); + stmt.setString(4, request.getStatus().name()); + stmt.setDouble(5, request.getDuration()); + stmt.setString(6, request.getLocation()); + stmt.setString(7, request.getReasonType()); + stmt.setString(8, request.getReasonDetail()); + stmt.setBoolean(9, request.isLeavingCity()); + stmt.setString(10, request.getSpecialSituation()); + stmt.setTimestamp(11, new Timestamp(request.getRequestTime().getTime())); + + int affectedRows = stmt.executeUpdate(); + if (affectedRows == 0) { + return 0; + } + + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) { + request.setId(generatedKeys.getInt(1)); + } + } + return affectedRows; + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int deleteById(int id) { + String sql = "DELETE FROM leave_requests WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int update(LeaveRequest request) { + String sql = "UPDATE leave_requests SET student_id = ?, start_time = ?, " + + "end_time = ?, status = ?, duration = ?, location = ?, " + + "reason_type = ?, reason_detail = ?, is_leaving_city = ?, " + + "special_situation = ?, request_time = ? WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, request.getStudent().getId()); + stmt.setTimestamp(2, new Timestamp(request.getStartTime().getTime())); + stmt.setTimestamp(3, new Timestamp(request.getEndTime().getTime())); + stmt.setString(4, request.getStatus().name()); + stmt.setDouble(5, request.getDuration()); + stmt.setString(6, request.getLocation()); + stmt.setString(7, request.getReasonType()); + stmt.setString(8, request.getReasonDetail()); + stmt.setBoolean(9, request.isLeavingCity()); + stmt.setString(10, request.getSpecialSituation()); + stmt.setTimestamp(11, new Timestamp(request.getRequestTime().getTime())); + stmt.setInt(12, request.getId()); + + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public LeaveRequest findById(int id) { + String sql = "SELECT lr.*, s.* FROM leave_requests lr " + + "JOIN students s ON lr.student_id = s.id " + + "WHERE lr.id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return mapResultSetToLeaveRequest(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public List findAll() { + List requests = new ArrayList<>(); + String sql = "SELECT lr.*, s.* FROM leave_requests lr " + + "JOIN students s ON lr.student_id = s.id"; + try (Connection conn = DatabaseUtil.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + requests.add(mapResultSetToLeaveRequest(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return requests; + } + + @Override + public List findByStudentId(int studentId) { + List requests = new ArrayList<>(); + String sql = "SELECT lr.*, s.* FROM leave_requests lr " + + "JOIN students s ON lr.student_id = s.id " + + "WHERE lr.student_id = ? ORDER BY lr.request_time DESC"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, studentId); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + requests.add(mapResultSetToLeaveRequest(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return requests; + } + + @Override + public List findByStatus(ApprovalStatus status) { + List requests = new ArrayList<>(); + String sql = "SELECT lr.*, s.* FROM leave_requests lr " + + "JOIN students s ON lr.student_id = s.id " + + "WHERE lr.status = ? ORDER BY lr.request_time DESC"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, status.name()); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + requests.add(mapResultSetToLeaveRequest(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return requests; + } + + @Override + public int updateStatus(int requestId, ApprovalStatus status, String comment) { + String sql = "UPDATE leave_requests SET status = ?, approval_comment = ?, approval_time = ? WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, status.name()); + stmt.setString(2, comment); + stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis())); + stmt.setInt(4, requestId); + + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + private LeaveRequest mapResultSetToLeaveRequest(ResultSet rs) throws SQLException { + LeaveRequest request = new LeaveRequest(); + request.setId(rs.getInt("id")); + request.setLocation(rs.getString("location")); + request.setStartTime(rs.getTimestamp("start_time")); + request.setEndTime(rs.getTimestamp("end_time")); + request.setStatus(ApprovalStatus.valueOf(rs.getString("status"))); + request.setDuration(rs.getDouble("duration")); + request.setReasonType(rs.getString("reason_type")); + request.setReasonDetail(rs.getString("reason_detail")); + request.setLeavingCity(rs.getBoolean("is_leaving_city")); + request.setSpecialSituation(rs.getString("special_situation")); + request.setRequestTime(rs.getTimestamp("request_time")); + + // 设置学生信息 + Student student = new Student(); + student.setId(rs.getInt("student_id")); + student.setStudentId(rs.getString("student_id")); + student.setName(rs.getString("name")); + student.setClassName(rs.getString("class_name")); + student.setContact(rs.getString("contact")); + request.setStudent(student); + + Timestamp approvalTime = rs.getTimestamp("approval_time"); + if (approvalTime != null) { + request.setApprovalTime(approvalTime); + } + + return request; + } +} diff --git a/src/dao/impl/StudentDAOImpl.java b/src/dao/impl/StudentDAOImpl.java new file mode 100644 index 0000000..6b8907b --- /dev/null +++ b/src/dao/impl/StudentDAOImpl.java @@ -0,0 +1,189 @@ +package dao.impl; + +import dao.StudentDAO; +import model.Student; +import util.DatabaseUtil; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * StudentDAO实现类 + */ +public class StudentDAOImpl implements StudentDAO { + + @Override + public int insert(Student student) { + String sql = "INSERT INTO students (student_id, name, class_name, contact, college, major, is_graduating) VALUES (?, ?, ?, ?, ?, ?, ?)"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + stmt.setString(1, student.getStudentId()); + stmt.setString(2, student.getName()); + stmt.setString(3, student.getClassName()); + stmt.setString(4, student.getContact()); + stmt.setString(5, student.getCollege()); + stmt.setString(6, student.getMajor()); + stmt.setBoolean(7, student.isGraduating()); + + int affectedRows = stmt.executeUpdate(); + if (affectedRows == 0) { + return 0; + } + + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) { + student.setId(generatedKeys.getInt(1)); + } + } + return affectedRows; + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int deleteById(int id) { + String sql = "DELETE FROM students WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int update(Student student) { + String sql = "UPDATE students SET student_id = ?, name = ?, class_name = ?, contact = ?, college = ?, major = ?, is_graduating = ? WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, student.getStudentId()); + stmt.setString(2, student.getName()); + stmt.setString(3, student.getClassName()); + stmt.setString(4, student.getContact()); + stmt.setString(5, student.getCollege()); + stmt.setString(6, student.getMajor()); + stmt.setBoolean(7, student.isGraduating()); + stmt.setInt(8, student.getId()); + + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public Student findById(int id) { + String sql = "SELECT * FROM students WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return mapResultSetToStudent(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public List findAll() { + List students = new ArrayList<>(); + String sql = "SELECT * FROM students"; + try (Connection conn = DatabaseUtil.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + students.add(mapResultSetToStudent(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return students; + } + + @Override + public Student findByStudentId(String studentId) { + String sql = "SELECT * FROM students WHERE student_id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, studentId); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return mapResultSetToStudent(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public List findByClassName(String className) { + List students = new ArrayList<>(); + String sql = "SELECT * FROM students WHERE class_name = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, className); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + students.add(mapResultSetToStudent(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return students; + } + + @Override + public List findByNameLike(String name) { + List students = new ArrayList<>(); + String sql = "SELECT * FROM students WHERE name LIKE ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, "%" + name + "%"); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + students.add(mapResultSetToStudent(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return students; + } + + /** + * 将ResultSet映射为Student对象 + */ + private Student mapResultSetToStudent(ResultSet rs) throws SQLException { + Student student = new Student(); + student.setId(rs.getInt("id")); + student.setStudentId(rs.getString("student_id")); + student.setName(rs.getString("name")); + student.setClassName(rs.getString("class_name")); + student.setContact(rs.getString("contact")); + student.setCollege(rs.getString("college")); + student.setMajor(rs.getString("major")); + student.setGraduating(rs.getBoolean("is_graduating")); + return student; + } +} diff --git a/src/dao/impl/TeacherDAOImpl.java b/src/dao/impl/TeacherDAOImpl.java new file mode 100644 index 0000000..b0b71b8 --- /dev/null +++ b/src/dao/impl/TeacherDAOImpl.java @@ -0,0 +1,180 @@ +package dao.impl; + +import dao.TeacherDAO; +import model.Teacher; +import util.DatabaseUtil; + +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * TeacherDAO实现类 + */ +public class TeacherDAOImpl implements TeacherDAO { + + @Override + public int insert(Teacher teacher) { + String sql = "INSERT INTO teachers (teacher_id, name, department, contact) VALUES (?, ?, ?, ?)"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { + + stmt.setString(1, teacher.getTeacherId()); + stmt.setString(2, teacher.getName()); + stmt.setString(3, teacher.getDepartment()); + stmt.setString(4, teacher.getContact()); + + int affectedRows = stmt.executeUpdate(); + if (affectedRows == 0) { + return 0; + } + + try (ResultSet generatedKeys = stmt.getGeneratedKeys()) { + if (generatedKeys.next()) { + teacher.setId(generatedKeys.getInt(1)); + } + } + return affectedRows; + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int deleteById(int id) { + String sql = "DELETE FROM teachers WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public int update(Teacher teacher) { + String sql = "UPDATE teachers SET teacher_id = ?, name = ?, department = ?, contact = ? WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, teacher.getTeacherId()); + stmt.setString(2, teacher.getName()); + stmt.setString(3, teacher.getDepartment()); + stmt.setString(4, teacher.getContact()); + stmt.setInt(5, teacher.getId()); + + return stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + return 0; + } + } + + @Override + public Teacher findById(int id) { + String sql = "SELECT * FROM teachers WHERE id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setInt(1, id); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return mapResultSetToTeacher(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public List findAll() { + List teachers = new ArrayList<>(); + String sql = "SELECT * FROM teachers"; + try (Connection conn = DatabaseUtil.getConnection(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + teachers.add(mapResultSetToTeacher(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return teachers; + } + + @Override + public Teacher findByTeacherId(String teacherId) { + String sql = "SELECT * FROM teachers WHERE teacher_id = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, teacherId); + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + return mapResultSetToTeacher(rs); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return null; + } + + @Override + public List findByDepartment(String department) { + List teachers = new ArrayList<>(); + String sql = "SELECT * FROM teachers WHERE department = ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, department); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + teachers.add(mapResultSetToTeacher(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return teachers; + } + + @Override + public List findByNameLike(String name) { + List teachers = new ArrayList<>(); + String sql = "SELECT * FROM teachers WHERE name LIKE ?"; + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, "%" + name + "%"); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + teachers.add(mapResultSetToTeacher(rs)); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return teachers; + } + + /** + * 将ResultSet映射为Teacher对象 + */ + private Teacher mapResultSetToTeacher(ResultSet rs) throws SQLException { + Teacher teacher = new Teacher(); + teacher.setId(rs.getInt("id")); + teacher.setTeacherId(rs.getString("teacher_id")); + teacher.setName(rs.getString("name")); + teacher.setDepartment(rs.getString("department")); + teacher.setContact(rs.getString("contact")); + return teacher; + } +} diff --git a/src/gui/LoginFrame.java b/src/gui/LoginFrame.java new file mode 100644 index 0000000..709401d --- /dev/null +++ b/src/gui/LoginFrame.java @@ -0,0 +1,94 @@ +package gui; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import util.DatabaseUtil; + +public class LoginFrame extends JFrame { + private JComboBox userTypeComboBox; + private JTextField idField; + private JPasswordField passwordField; + private JButton loginButton; + + public LoginFrame() { + setTitle("登录"); + setSize(300, 200); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setLocationRelativeTo(null); + + JPanel panel = new JPanel(); + panel.setLayout(new GridLayout(4, 2)); + + panel.add(new JLabel("用户类型:")); + userTypeComboBox = new JComboBox<>(new String[]{"学生", "教师"}); + panel.add(userTypeComboBox); + + panel.add(new JLabel("ID:")); + idField = new JTextField(); + panel.add(idField); + + panel.add(new JLabel("密码:")); + passwordField = new JPasswordField(); + panel.add(passwordField); + + loginButton = new JButton("登录"); + panel.add(loginButton); + + loginButton.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + handleLogin(); + } + }); + + add(panel); + } + + private void handleLogin() { + String userType = (String) userTypeComboBox.getSelectedItem(); + String id = idField.getText(); + String password = new String(passwordField.getPassword()); + + String tableName = "学生".equals(userType) ? "students" : "teachers"; + String idColumnName = "学生".equals(userType) ? "student_id" : "teacher_id"; + String sql = "SELECT * FROM " + tableName + " WHERE " + idColumnName + " = ? AND password = ?"; + + try (Connection conn = DatabaseUtil.getConnection(); + PreparedStatement stmt = conn.prepareStatement(sql)) { + + stmt.setString(1, id); + stmt.setString(2, password); + + ResultSet rs = stmt.executeQuery(); + + if (rs.next()) { + if ("教师".equals(userType)) { + TeacherMainFrame teacherMainFrame = new TeacherMainFrame(); + teacherMainFrame.setVisible(true); + } else { + // TODO: 打开学生主界面 + JOptionPane.showMessageDialog(this, "学生登录成功!", "提示", JOptionPane.INFORMATION_MESSAGE); + } + dispose(); + } else { + JOptionPane.showMessageDialog(this, "无效的ID或密码", "错误", JOptionPane.ERROR_MESSAGE); + } + } catch (SQLException e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(this, "数据库错误:" + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE); + } + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + LoginFrame loginFrame = new LoginFrame(); + loginFrame.setVisible(true); + }); + } +} diff --git a/src/gui/RequestDetailDialog.java b/src/gui/RequestDetailDialog.java new file mode 100644 index 0000000..ec0b55d --- /dev/null +++ b/src/gui/RequestDetailDialog.java @@ -0,0 +1,165 @@ +package gui; + +import model.ApprovalStatus; +import model.LeaveRequest; +import service.LeaveRequestService; +import service.ServiceFactory; + +import javax.swing.*; +import java.awt.*; +import java.text.SimpleDateFormat; +import java.util.List; + +public class RequestDetailDialog extends JDialog { + private final LeaveRequestService leaveRequestService; + private LeaveRequest currentRequest; + + public RequestDetailDialog(JFrame parent, String studentName) { + super(parent, "请假详情", true); + this.leaveRequestService = ServiceFactory.getLeaveRequestService(); + + // 根据学生姓名获取请假信息 + List requests = leaveRequestService.getAllLeaveRequests(); + this.currentRequest = requests.stream() + .filter(r -> r.getStudent().getName().equals(studentName)) + .findFirst() + .orElse(null); + + if (currentRequest == null) { + JOptionPane.showMessageDialog(parent, "未找到请假信息!", "错误", JOptionPane.ERROR_MESSAGE); + dispose(); + return; + } + + setSize(500, 700); + setLocationRelativeTo(parent); + setResizable(false); + + initComponents(); + } + + private void initComponents() { + // 主面板使用GridBagLayout + JPanel mainPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.gridwidth = GridBagConstraints.REMAINDER; + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 10, 5, 10); + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + // 学生基本信息 + addInfoField(mainPanel, gbc, "审核进度:", "班主任"); + addInfoField(mainPanel, gbc, "学院:", currentRequest.getStudent().getCollege()); + addInfoField(mainPanel, gbc, "专业:", currentRequest.getStudent().getMajor()); + addInfoField(mainPanel, gbc, "班级:", currentRequest.getStudent().getClassName()); + addInfoField(mainPanel, gbc, "姓名:", currentRequest.getStudent().getName()); + addInfoField(mainPanel, gbc, "学号:", currentRequest.getStudent().getStudentId()); + addInfoField(mainPanel, gbc, "手机号:", currentRequest.getStudent().getPhone()); + + // 请假信息 + addInfoField(mainPanel, gbc, "申请外出时间:", dateFormat.format(currentRequest.getStartTime())); + addInfoField(mainPanel, gbc, "预计返校时间:", dateFormat.format(currentRequest.getEndTime())); + addInfoField(mainPanel, gbc, "时长:", String.format("%.2f", currentRequest.getDuration())); + addInfoField(mainPanel, gbc, "外出地址:", currentRequest.getLocation()); + addInfoField(mainPanel, gbc, "外出事由:", currentRequest.getReasonType()); + addInfoField(mainPanel, gbc, "详细事由:", currentRequest.getReasonDetail()); + addInfoField(mainPanel, gbc, "是否离津:", currentRequest.isLeavingCity() ? "是" : "否"); + addInfoField(mainPanel, gbc, "其他特殊情况:", + currentRequest.getSpecialSituation() == null ? "" : currentRequest.getSpecialSituation()); + addInfoField(mainPanel, gbc, "发起时间:", dateFormat.format(currentRequest.getRequestTime())); + + // 如果已经审批过,显示审批信息 + if (currentRequest.getStatus() != ApprovalStatus.PENDING) { + addInfoField(mainPanel, gbc, "审批状态:", currentRequest.getStatus().getDescription()); + if (currentRequest.getApprovalComment() != null) { + addInfoField(mainPanel, gbc, "审批意见:", currentRequest.getApprovalComment()); + } + if (currentRequest.getApprovalTime() != null) { + addInfoField(mainPanel, gbc, "审批时间:", dateFormat.format(currentRequest.getApprovalTime())); + } + } + + // 审批按钮 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 20, 10)); + JButton approveButton = new JButton("通过"); + JButton rejectButton = new JButton("驳回"); + + // 如果已经审批过,禁用按钮 + if (currentRequest.getStatus() != ApprovalStatus.PENDING) { + approveButton.setEnabled(false); + rejectButton.setEnabled(false); + } + + approveButton.setPreferredSize(new Dimension(100, 30)); + rejectButton.setPreferredSize(new Dimension(100, 30)); + + // 设置按钮颜色 + approveButton.setBackground(new Color(39, 174, 96)); + approveButton.setForeground(Color.WHITE); + rejectButton.setBackground(new Color(231, 76, 60)); + rejectButton.setForeground(Color.WHITE); + + buttonPanel.add(approveButton); + buttonPanel.add(rejectButton); + + // 添加按钮面板 + gbc.insets = new Insets(20, 10, 10, 10); + mainPanel.add(buttonPanel, gbc); + + // 添加事件监听 + approveButton.addActionListener(e -> { + int result = JOptionPane.showConfirmDialog( + this, + "确定通过该请假申请吗?", + "确认", + JOptionPane.YES_NO_OPTION + ); + if (result == JOptionPane.YES_OPTION) { + leaveRequestService.approveLeaveRequest( + currentRequest.getId(), + ApprovalStatus.APPROVED, + "已通过" + ); + dispose(); + } + }); + + rejectButton.addActionListener(e -> { + String reason = JOptionPane.showInputDialog( + this, + "请输入驳回原因:", + "驳回原因", + JOptionPane.QUESTION_MESSAGE + ); + if (reason != null && !reason.trim().isEmpty()) { + leaveRequestService.approveLeaveRequest( + currentRequest.getId(), + ApprovalStatus.REJECTED, + reason + ); + dispose(); + } + }); + + // 添加滚动面板 + JScrollPane scrollPane = new JScrollPane(mainPanel); + scrollPane.setBorder(null); + add(scrollPane); + } + + private void addInfoField(JPanel panel, GridBagConstraints gbc, String label, String value) { + JPanel fieldPanel = new JPanel(new BorderLayout(10, 0)); + + JLabel labelComponent = new JLabel(label); + labelComponent.setFont(new Font("微软雅黑", Font.BOLD, 12)); + + JLabel valueComponent = new JLabel(value); + valueComponent.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + + fieldPanel.add(labelComponent, BorderLayout.WEST); + fieldPanel.add(valueComponent, BorderLayout.CENTER); + + panel.add(fieldPanel, gbc); + } +} diff --git a/src/gui/TeacherMainFrame.java b/src/gui/TeacherMainFrame.java new file mode 100644 index 0000000..74fc84e --- /dev/null +++ b/src/gui/TeacherMainFrame.java @@ -0,0 +1,189 @@ +package gui; + +import model.ApprovalStatus; +import model.LeaveRequest; +import service.LeaveRequestService; +import service.ServiceFactory; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.text.SimpleDateFormat; +import java.util.List; + +public class TeacherMainFrame extends JFrame { + private final LeaveRequestService leaveRequestService; + private JTable requestTable; + private DefaultTableModel tableModel; + private JTextField searchField; + private JComboBox statusFilter; + private int currentPage = 1; + private static final int PAGE_SIZE = 10; + + public TeacherMainFrame() { + leaveRequestService = ServiceFactory.getLeaveRequestService(); + initComponents(); + loadLeaveRequests(); + } + + private void initComponents() { + setTitle("平安校园 - 日常出校申请"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 600); + setLocationRelativeTo(null); + + // 顶部面板 + JPanel topPanel = new JPanel(new BorderLayout()); + JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); + + // 标题 + JLabel titleLabel = new JLabel("日常出校申请", SwingConstants.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.PLAIN, 18)); + topPanel.add(titleLabel, BorderLayout.CENTER); + + // 状态过滤器 + JPanel filterPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + String[] statuses = {"全部", "待审批", "已通过", "已驳回"}; + statusFilter = new JComboBox<>(statuses); + statusFilter.addActionListener(e -> loadLeaveRequests()); + filterPanel.add(statusFilter); + + // 搜索框 + searchField = new JTextField(15); + JButton searchButton = new JButton("筛选"); + searchPanel.add(new JLabel("请输入学号或姓名:")); + searchPanel.add(searchField); + searchPanel.add(searchButton); + + topPanel.add(searchPanel, BorderLayout.NORTH); + topPanel.add(filterPanel, BorderLayout.SOUTH); + + // 表格 + String[] columnNames = {"姓名", "班级", "状态", "申请时间", "外出事由"}; + tableModel = new DefaultTableModel(columnNames, 0) { + @Override + public boolean isCellEditable(int row, int column) { + return false; + } + }; + requestTable = new JTable(tableModel); + requestTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + // 设置表格样式 + requestTable.setRowHeight(30); + requestTable.getTableHeader().setFont(new Font("微软雅黑", Font.BOLD, 12)); + requestTable.setFont(new Font("微软雅黑", Font.PLAIN, 12)); + + // 设置列宽 + TableColumnModel columnModel = requestTable.getColumnModel(); + columnModel.getColumn(0).setPreferredWidth(50); // 姓名 + columnModel.getColumn(1).setPreferredWidth(90); // 班级 + columnModel.getColumn(2).setPreferredWidth(50); // 状态 + columnModel.getColumn(3).setPreferredWidth(100); // 申请时间 + columnModel.getColumn(4).setPreferredWidth(60); // 外出事由 + + // 分页控制 + JPanel pagePanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton prevButton = new JButton("上一页"); + JButton nextButton = new JButton("下一页"); + JLabel pageLabel = new JLabel("1/1"); + pagePanel.add(prevButton); + pagePanel.add(pageLabel); + pagePanel.add(nextButton); + + // 添加到主面板 + JPanel mainPanel = new JPanel(new BorderLayout()); + mainPanel.add(topPanel, BorderLayout.NORTH); + mainPanel.add(new JScrollPane(requestTable), BorderLayout.CENTER); + mainPanel.add(pagePanel, BorderLayout.SOUTH); + + // 添加事件监听 + searchButton.addActionListener(e -> loadLeaveRequests()); + + requestTable.getSelectionModel().addListSelectionListener(e -> { + if (!e.getValueIsAdjusting() && requestTable.getSelectedRow() != -1) { + showRequestDetails(requestTable.getSelectedRow()); + } + }); + + prevButton.addActionListener(e -> { + if (currentPage > 1) { + currentPage--; + loadLeaveRequests(); + } + }); + + nextButton.addActionListener(e -> { + currentPage++; + loadLeaveRequests(); + }); + + add(mainPanel); + } + + private void loadLeaveRequests() { + tableModel.setRowCount(0); + String searchText = searchField.getText().trim(); + String statusText = (String) statusFilter.getSelectedItem(); + + List requests; + if ("全部".equals(statusText)) { + requests = leaveRequestService.getAllLeaveRequests(); + } else { + ApprovalStatus status = null; + switch (statusText) { + case "待审批": + status = ApprovalStatus.PENDING; + break; + case "已通过": + status = ApprovalStatus.APPROVED; + break; + case "已驳回": + status = ApprovalStatus.REJECTED; + break; + } + requests = leaveRequestService.getLeaveRequestsByStatus(status); + } + + // 过滤搜索结果 + if (!searchText.isEmpty()) { + requests.removeIf(request -> + !request.getStudent().getName().contains(searchText) && + !request.getStudent().getStudentId().contains(searchText)); + } + + // 添加到表格 + for (LeaveRequest request : requests) { + Object[] row = { + request.getStudent().getName(), + request.getStudent().getClassName(), + request.getStatus().getDescription(), + new SimpleDateFormat("MM-dd HH:mm").format(request.getRequestTime()), + request.getReasonType() + }; + tableModel.addRow(row); + } + } + + private void showRequestDetails(int row) { + // 创建详情对话框 + RequestDetailDialog dialog = new RequestDetailDialog(this, tableModel.getValueAt(row, 0).toString()); + dialog.setVisible(true); + } + + public static void main(String[] args) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + + SwingUtilities.invokeLater(() -> { + TeacherMainFrame frame = new TeacherMainFrame(); + frame.setVisible(true); + }); + } +} diff --git a/src/model/ApprovalStatus.java b/src/model/ApprovalStatus.java new file mode 100644 index 0000000..e422a60 --- /dev/null +++ b/src/model/ApprovalStatus.java @@ -0,0 +1,20 @@ +package model; + +/** + * 请假审批状态枚举类 + */ +public enum ApprovalStatus { + PENDING("待审批"), // 等待审批 + APPROVED("已批准"), // 已经批准 + REJECTED("已驳回"); // 已经驳回 + + private final String description; // 状态描述 + + ApprovalStatus(String description) { + this.description = description; + } + + public String getDescription() { + return description; + } +} diff --git a/src/model/LeaveRequest.java b/src/model/LeaveRequest.java new file mode 100644 index 0000000..8b64866 --- /dev/null +++ b/src/model/LeaveRequest.java @@ -0,0 +1,151 @@ +package model; + +import java.util.Date; + +/** + * 请假条实体类 + */ +public class LeaveRequest { + private int id; // 数据库主键ID + private Student student; // 学生信息 + private Date startTime; // 开始时间 + private Date endTime; // 结束时间 + private double duration; // 时长 + private String location; // 外出地址 + private String reasonType; // 外出事由类型 + private String reasonDetail; // 详细事由 + private boolean isLeavingCity; // 是否离津 + private String specialSituation; // 其他特殊情况 + private ApprovalStatus status; // 审批状态 + private Teacher approver; // 审批人 + private String approvalComment; // 审批意见 + private Date requestTime; // 申请时间 + private Date approvalTime; // 审批时间 + + // Constructors + public LeaveRequest() { + this.status = ApprovalStatus.PENDING; + this.requestTime = new Date(); + } + + // Getters and Setters + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Student getStudent() { + return student; + } + + public void setStudent(Student student) { + this.student = student; + } + + public Date getStartTime() { + return startTime; + } + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public Date getEndTime() { + return endTime; + } + + public void setEndTime(Date endTime) { + this.endTime = endTime; + } + + public double getDuration() { + return duration; + } + + public void setDuration(double duration) { + this.duration = duration; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getReasonType() { + return reasonType; + } + + public void setReasonType(String reasonType) { + this.reasonType = reasonType; + } + + public String getReasonDetail() { + return reasonDetail; + } + + public void setReasonDetail(String reasonDetail) { + this.reasonDetail = reasonDetail; + } + + public boolean isLeavingCity() { + return isLeavingCity; + } + + public void setLeavingCity(boolean leavingCity) { + isLeavingCity = leavingCity; + } + + public String getSpecialSituation() { + return specialSituation; + } + + public void setSpecialSituation(String specialSituation) { + this.specialSituation = specialSituation; + } + + public ApprovalStatus getStatus() { + return status; + } + + public void setStatus(ApprovalStatus status) { + this.status = status; + } + + public Teacher getApprover() { + return approver; + } + + public void setApprover(Teacher approver) { + this.approver = approver; + } + + public String getApprovalComment() { + return approvalComment; + } + + public void setApprovalComment(String approvalComment) { + this.approvalComment = approvalComment; + } + + public Date getRequestTime() { + return requestTime; + } + + public void setRequestTime(Date requestTime) { + this.requestTime = requestTime; + } + + public Date getApprovalTime() { + return approvalTime; + } + + public void setApprovalTime(Date approvalTime) { + this.approvalTime = approvalTime; + } +} diff --git a/src/model/Student.java b/src/model/Student.java new file mode 100644 index 0000000..60b2009 --- /dev/null +++ b/src/model/Student.java @@ -0,0 +1,93 @@ +package model; + +/** + * 学生实体类 + */ +public class Student { + private int id; // 数据库主键ID + private String studentId; // 学号 + private String name; // 学生姓名 + private String className; // 班级 + private String contact; // 联系方式 + private String college; // 学院 + private String major; // 专业 + private boolean isGraduating; // 是否毕业班 + + // Constructors + public Student() {} + + public Student(String studentId, String name, String className, String contact, String college, String major, boolean isGraduating) { + this.studentId = studentId; + this.name = name; + this.className = className; + this.contact = contact; + this.college = college; + this.major = major; + this.isGraduating = isGraduating; + } + + // Getters and Setters + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getStudentId() { + return studentId; + } + + public void setStudentId(String studentId) { + this.studentId = studentId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getClassName() { + return className; + } + + public void setClassName(String className) { + this.className = className; + } + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } + + public String getCollege() { + return college; + } + + public void setCollege(String college) { + this.college = college; + } + + public String getMajor() { + return major; + } + + public void setMajor(String major) { + this.major = major; + } + + public boolean isGraduating() { + return isGraduating; + } + + public void setGraduating(boolean graduating) { + isGraduating = graduating; + } +} diff --git a/src/model/Teacher.java b/src/model/Teacher.java new file mode 100644 index 0000000..9fdf38a --- /dev/null +++ b/src/model/Teacher.java @@ -0,0 +1,63 @@ +package model; + +/** + * 教师实体类 + */ +public class Teacher { + private int id; // 数据库主键ID + private String teacherId; // 教师工号 + private String name; // 教师姓名 + private String department; // 所属部门 + private String contact; // 联系方式 + + // Constructors + public Teacher() {} + + public Teacher(String teacherId, String name, String department, String contact) { + this.teacherId = teacherId; + this.name = name; + this.department = department; + this.contact = contact; + } + + // Getters and Setters + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTeacherId() { + return teacherId; + } + + public void setTeacherId(String teacherId) { + this.teacherId = teacherId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDepartment() { + return department; + } + + public void setDepartment(String department) { + this.department = department; + } + + public String getContact() { + return contact; + } + + public void setContact(String contact) { + this.contact = contact; + } +} diff --git a/src/service/LeaveRequestService.java b/src/service/LeaveRequestService.java new file mode 100644 index 0000000..5e559e0 --- /dev/null +++ b/src/service/LeaveRequestService.java @@ -0,0 +1,116 @@ +package service; + +import dao.DAOFactory; +import dao.LeaveRequestDAO; +import model.LeaveRequest; +import model.Student; +import model.ApprovalStatus; +import java.util.Date; +import java.util.List; + +/** + * 请假申请服务类 + */ +public class LeaveRequestService { + private final LeaveRequestDAO leaveRequestDAO = DAOFactory.getLeaveRequestDAO(); + private final StudentService studentService = new StudentService(); + + /** + * 提交请假申请 + * @param request 请假申请信息 + * @return 是否提交成功 + */ + public boolean submitLeaveRequest(LeaveRequest request) { + // 检查学生是否存在 + Student student = studentService.getStudentById(request.getStudent().getId()); + if (student == null) { + return false; + } + + // 检查请假时间是否合理 + if (!isValidLeaveTime(request.getStartTime(), request.getEndTime())) { + return false; + } + + // 设置初始状态为待审批 + request.setStatus(ApprovalStatus.PENDING); + request.setRequestTime(new Date()); + + return leaveRequestDAO.insert(request) > 0; + } + + /** + * 审批请假申请 + * @param requestId 请假申请ID + * @param status 审批状态 + * @param comment 审批意见 + * @return 是否审批成功 + */ + public boolean approveLeaveRequest(int requestId, ApprovalStatus status, String comment) { + // 检查请假申请是否存在 + LeaveRequest request = leaveRequestDAO.findById(requestId); + if (request == null) { + return false; + } + + // 检查是否可以审批 + if (request.getStatus() != ApprovalStatus.PENDING) { + return false; + } + + return leaveRequestDAO.updateStatus(requestId, status, comment) > 0; + } + + /** + * 获取学生的请假记录 + * @param studentId 学生ID + * @return 请假记录列表 + */ + public List getStudentLeaveRequests(int studentId) { + return leaveRequestDAO.findByStudentId(studentId); + } + + /** + * 获取指定状态的请假申请 + * @param status 审批状态 + * @return 请假申请列表 + */ + public List getLeaveRequestsByStatus(ApprovalStatus status) { + return leaveRequestDAO.findByStatus(status); + } + + + /** + * 获取所有请假申请 + * @return 请假申请列表 + */ + public List getAllLeaveRequests() { + return leaveRequestDAO.findAll(); + } + + /** + * 检查请假时间是否合理 + * @param startTime 开始时间 + * @param endTime 结束时间 + * @return 是否合理 + */ + private boolean isValidLeaveTime(Date startTime, Date endTime) { + // 开始时间不能为空 + if (startTime == null || endTime == null) { + return false; + } + + // 结束时间必须在开始时间之后 + if (endTime.before(startTime)) { + return false; + } + + // 开始时间不能是过去的时间 + Date now = new Date(); + if (startTime.before(now)) { + return false; + } + + return true; + } +} diff --git a/src/service/ServiceFactory.java b/src/service/ServiceFactory.java new file mode 100644 index 0000000..239fac3 --- /dev/null +++ b/src/service/ServiceFactory.java @@ -0,0 +1,34 @@ +package service; + +/** + * Service工厂类,用于获取各种Service的实例 + */ +public class ServiceFactory { + private static final StudentService studentService = new StudentService(); + private static final TeacherService teacherService = new TeacherService(); + private static final LeaveRequestService leaveRequestService = new LeaveRequestService(); + + /** + * 获取StudentService实例 + * @return StudentService实例 + */ + public static StudentService getStudentService() { + return studentService; + } + + /** + * 获取TeacherService实例 + * @return TeacherService实例 + */ + public static TeacherService getTeacherService() { + return teacherService; + } + + /** + * 获取LeaveRequestService实例 + * @return LeaveRequestService实例 + */ + public static LeaveRequestService getLeaveRequestService() { + return leaveRequestService; + } +} diff --git a/src/service/StudentService.java b/src/service/StudentService.java new file mode 100644 index 0000000..1fb4295 --- /dev/null +++ b/src/service/StudentService.java @@ -0,0 +1,98 @@ +package service; + +import dao.DAOFactory; +import dao.StudentDAO; +import model.Student; +import java.util.List; + +/** + * 学生信息服务类 + */ +public class StudentService { + private final StudentDAO studentDAO = DAOFactory.getStudentDAO(); + + /** + * 添加学生 + * @param student 学生信息 + * @return 是否添加成功 + */ + public boolean addStudent(Student student) { + // 检查学号是否已存在 + if (studentDAO.findByStudentId(student.getStudentId()) != null) { + return false; + } + return studentDAO.insert(student) > 0; + } + + /** + * 更新学生信息 + * @param student 学生信息 + * @return 是否更新成功 + */ + public boolean updateStudent(Student student) { + // 检查是否存在 + Student existingStudent = studentDAO.findById(student.getId()); + if (existingStudent == null) { + return false; + } + // 检查学号是否被其他学生使用 + Student studentWithSameId = studentDAO.findByStudentId(student.getStudentId()); + if (studentWithSameId != null && studentWithSameId.getId() != student.getId()) { + return false; + } + return studentDAO.update(student) > 0; + } + + /** + * 删除学生 + * @param id 学生ID + * @return 是否删除成功 + */ + public boolean deleteStudent(int id) { + return studentDAO.deleteById(id) > 0; + } + + /** + * 根据ID查询学生 + * @param id 学生ID + * @return 学生信息 + */ + public Student getStudentById(int id) { + return studentDAO.findById(id); + } + + /** + * 根据学号查询学生 + * @param studentId 学号 + * @return 学生信息 + */ + public Student getStudentByStudentId(String studentId) { + return studentDAO.findByStudentId(studentId); + } + + /** + * 查询所有学生 + * @return 学生列表 + */ + public List getAllStudents() { + return studentDAO.findAll(); + } + + /** + * 根据班级查询学生 + * @param className 班级名称 + * @return 学生列表 + */ + public List getStudentsByClass(String className) { + return studentDAO.findByClassName(className); + } + + /** + * 根据姓名模糊查询学生 + * @param name 学生姓名 + * @return 学生列表 + */ + public List searchStudentsByName(String name) { + return studentDAO.findByNameLike(name); + } +} diff --git a/src/service/TeacherService.java b/src/service/TeacherService.java new file mode 100644 index 0000000..8a122b8 --- /dev/null +++ b/src/service/TeacherService.java @@ -0,0 +1,98 @@ +package service; + +import dao.DAOFactory; +import dao.TeacherDAO; +import model.Teacher; +import java.util.List; + +/** + * 教师信息服务类 + */ +public class TeacherService { + private final TeacherDAO teacherDAO = DAOFactory.getTeacherDAO(); + + /** + * 添加教师 + * @param teacher 教师信息 + * @return 是否添加成功 + */ + public boolean addTeacher(Teacher teacher) { + // 检查工号是否已存在 + if (teacherDAO.findByTeacherId(teacher.getTeacherId()) != null) { + return false; + } + return teacherDAO.insert(teacher) > 0; + } + + /** + * 更新教师信息 + * @param teacher 教师信息 + * @return 是否更新成功 + */ + public boolean updateTeacher(Teacher teacher) { + // 检查是否存在 + Teacher existingTeacher = teacherDAO.findById(teacher.getId()); + if (existingTeacher == null) { + return false; + } + // 检查工号是否被其他教师使用 + Teacher teacherWithSameId = teacherDAO.findByTeacherId(teacher.getTeacherId()); + if (teacherWithSameId != null && teacherWithSameId.getId() != teacher.getId()) { + return false; + } + return teacherDAO.update(teacher) > 0; + } + + /** + * 删除教师 + * @param id 教师ID + * @return 是否删除成功 + */ + public boolean deleteTeacher(int id) { + return teacherDAO.deleteById(id) > 0; + } + + /** + * 根据ID查询教师 + * @param id 教师ID + * @return 教师信息 + */ + public Teacher getTeacherById(int id) { + return teacherDAO.findById(id); + } + + /** + * 根据工号查询教师 + * @param teacherId 工号 + * @return 教师信息 + */ + public Teacher getTeacherByTeacherId(String teacherId) { + return teacherDAO.findByTeacherId(teacherId); + } + + /** + * 查询所有教师 + * @return 教师列表 + */ + public List getAllTeachers() { + return teacherDAO.findAll(); + } + + /** + * 根据部门查询教师 + * @param department 部门名称 + * @return 教师列表 + */ + public List getTeachersByDepartment(String department) { + return teacherDAO.findByDepartment(department); + } + + /** + * 根据姓名模糊查询教师 + * @param name 教师姓名 + * @return 教师列表 + */ + public List searchTeachersByName(String name) { + return teacherDAO.findByNameLike(name); + } +} diff --git a/src/sql/init.sql b/src/sql/init.sql new file mode 100644 index 0000000..5a656f7 --- /dev/null +++ b/src/sql/init.sql @@ -0,0 +1,76 @@ +-- 创建数据库 +CREATE DATABASE IF NOT EXISTS absence_manager DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; + +USE absence_manager; + +-- 创建学生表 +CREATE TABLE IF NOT EXISTS students ( + id INT PRIMARY KEY AUTO_INCREMENT, + student_id VARCHAR(20) UNIQUE NOT NULL, -- 学号 + name VARCHAR(50) NOT NULL, -- 姓名 + class_name VARCHAR(50) NOT NULL, -- 班级 + contact VARCHAR(20), -- 联系方式 + college VARCHAR(50) NOT NULL, -- 学院 + major VARCHAR(50) NOT NULL, -- 专业 + is_graduating BOOLEAN DEFAULT FALSE, -- 是否毕业班 + password VARCHAR(50) NOT NULL, -- 密码 + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生信息表'; + +-- 创建教师表 +CREATE TABLE IF NOT EXISTS teachers ( + id INT PRIMARY KEY AUTO_INCREMENT, + teacher_id VARCHAR(20) UNIQUE NOT NULL, -- 工号 + name VARCHAR(50) NOT NULL, -- 姓名 + department VARCHAR(50) NOT NULL, -- 部门 + contact VARCHAR(20), -- 联系方式 + password VARCHAR(50) NOT NULL, -- 密码 + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='教师信息表'; + +-- 创建请假申请表 +CREATE TABLE IF NOT EXISTS leave_requests ( + id INT PRIMARY KEY AUTO_INCREMENT, + student_id INT NOT NULL, -- 关联学生ID + start_time DATETIME NOT NULL, -- 开始时间 + end_time DATETIME NOT NULL, -- 结束时间 + duration DECIMAL(5,2) NOT NULL, -- 时长 + location VARCHAR(100) NOT NULL, -- 外出地址 + reason_type VARCHAR(50) NOT NULL, -- 外出事由类型 + reason_detail TEXT, -- 详细事由 + is_leaving_city BOOLEAN DEFAULT FALSE, -- 是否离津 + special_situation TEXT, -- 其他特殊情况 + status VARCHAR(20) NOT NULL DEFAULT 'PENDING', -- 审批状态 + approver_id INT, -- 审批人ID + approval_comment TEXT, -- 审批意见 + request_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, -- 申请时间 + approval_time TIMESTAMP NULL, -- 审批时间 + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + FOREIGN KEY (student_id) REFERENCES students(id), + FOREIGN KEY (approver_id) REFERENCES teachers(id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='请假申请表'; + +-- 插入示例数据 +INSERT INTO students (student_id, name, class_name, contact, college, major, is_graduating, password) VALUES +('2023208145', '李同学', '云计算G23-1', '15842087237', '信息工程学院', '云计算技术应用', false, '123456'), +('2023208146', '张同学', '云计算G23-1', '15842087238', '信息工程学院', '云计算技术应用', false, '123456'); + +INSERT INTO teachers (teacher_id, name, department, contact, password) VALUES +('2023001', '王老师', '信息工程学院', '13912345678', '123456'), +('2023002', '李老师', '信息工程学院', '13912345679', '123456'); + +-- 插入请假申请示例数据 +INSERT INTO leave_requests (student_id, start_time, end_time, duration, location, reason_type, reason_detail, is_leaving_city, status, approver_id, approval_comment, request_time) VALUES +(1, '2024-01-15 08:00:00', '2024-01-15 17:00:00', 9.00, '天津市河西区图书馆', '学习', '去图书馆学习准备考试', false, 'APPROVED', 1, '同意', '2024-01-14 10:00:00'), +(2, '2024-01-16 13:00:00', '2024-01-16 17:30:00', 4.50, '天津市南开医院', '就医', '牙科复诊', false, 'APPROVED', 1, '注意安全', '2024-01-15 09:30:00'), +(1, '2024-01-17 09:00:00', '2024-01-17 12:00:00', 3.00, '天津市档案馆', '办事', '办理个人档案', false, 'PENDING', null, null, '2024-01-16 16:20:00'), +(2, '2024-01-18 14:00:00', '2024-01-18 18:00:00', 4.00, '和平区文化中心', '活动', '参加志愿者活动', false, 'REJECTED', 2, '活动时间与课程冲突', '2024-01-17 11:15:00'), +(1, '2024-01-19 10:00:00', '2024-01-19 16:00:00', 6.00, '天津站', '返乡', '购买返乡车票', true, 'APPROVED', 2, '请注意防疫', '2024-01-18 14:40:00'), +(2, '2024-01-20 09:30:00', '2024-01-20 11:30:00', 2.00, '河西区人才市场', '求职', '参加招聘会', false, 'PENDING', null, null, '2024-01-19 17:00:00'), +(1, '2024-01-21 13:00:00', '2024-01-21 17:00:00', 4.00, '天津市第一中心医院', '就医', '例行体检', false, 'APPROVED', 1, '准假', '2024-01-20 10:25:00'), +(2, '2024-01-22 08:00:00', '2024-01-22 18:00:00', 10.00, '滨海新区图书馆', '实习', '企业实地考察', false, 'PENDING', null, null, '2024-01-21 15:30:00'), +(1, '2024-01-23 14:00:00', '2024-01-23 16:00:00', 2.00, '南开区政务中心', '办事', '办理身份证', false, 'APPROVED', 2, '同意', '2024-01-22 09:45:00'), +(2, '2024-01-24 09:00:00', '2024-01-24 18:00:00', 9.00, '天津市人民医院', '就医', '陪同父亲做检查', false, 'PENDING', null, null, '2024-01-23 16:50:00'); diff --git a/src/util/DatabaseUtil.java b/src/util/DatabaseUtil.java new file mode 100644 index 0000000..515b2e8 --- /dev/null +++ b/src/util/DatabaseUtil.java @@ -0,0 +1,46 @@ +package util; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +/** + * 数据库工具类 + */ +public class DatabaseUtil { + private static final String URL = "jdbc:mysql://localhost:3306/absence_manager?useSSL=false&serverTimezone=UTC&characterEncoding=UTF-8"; + private static final String USERNAME = "root"; + private static final String PASSWORD = "root"; + + static { + try { + // 加载MySQL驱动 + Class.forName("com.mysql.cj.jdbc.Driver"); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } + + /** + * 获取数据库连接 + * @return 数据库连接对象 + * @throws SQLException SQL异常 + */ + public static Connection getConnection() throws SQLException { + return DriverManager.getConnection(URL, USERNAME, PASSWORD); + } + + /** + * 关闭数据库连接 + * @param conn 要关闭的连接对象 + */ + public static void closeConnection(Connection conn) { + if (conn != null) { + try { + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + } +}