From 58770558790931baaf9b45713baa5ae01c155dd3 Mon Sep 17 00:00:00 2001 From: seahi Date: Tue, 17 Dec 2024 10:47:10 +0800 Subject: [PATCH] feat: add student page fix: resolve login issues --- src/dao/impl/StudentDAOImpl.java | 9 +- src/dao/impl/TeacherDAOImpl.java | 9 +- src/gui/LoginFrame.java | 151 ++++++++---- src/gui/RequestDetailDialog.java | 263 +++++++++++--------- src/gui/StudentMainFrame.java | 344 +++++++++++++++++++++++++++ src/gui/TeacherMainFrame.java | 3 +- src/model/Student.java | 20 ++ src/model/Teacher.java | 17 ++ src/service/LeaveRequestService.java | 51 +++- src/service/StudentService.java | 21 ++ src/service/TeacherService.java | 21 ++ 11 files changed, 729 insertions(+), 180 deletions(-) create mode 100644 src/gui/StudentMainFrame.java diff --git a/src/dao/impl/StudentDAOImpl.java b/src/dao/impl/StudentDAOImpl.java index 6b8907b..16da868 100644 --- a/src/dao/impl/StudentDAOImpl.java +++ b/src/dao/impl/StudentDAOImpl.java @@ -15,7 +15,7 @@ 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 (?, ?, ?, ?, ?, ?, ?)"; + String sql = "INSERT INTO students (student_id, name, class_name, contact, college, major, is_graduating, password) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; try (Connection conn = DatabaseUtil.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { @@ -26,6 +26,7 @@ public class StudentDAOImpl implements StudentDAO { stmt.setString(5, student.getCollege()); stmt.setString(6, student.getMajor()); stmt.setBoolean(7, student.isGraduating()); + stmt.setString(8, student.getPassword()); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { @@ -60,7 +61,7 @@ public class StudentDAOImpl implements StudentDAO { @Override public int update(Student student) { - String sql = "UPDATE students SET student_id = ?, name = ?, class_name = ?, contact = ?, college = ?, major = ?, is_graduating = ? WHERE id = ?"; + String sql = "UPDATE students SET student_id = ?, name = ?, class_name = ?, contact = ?, college = ?, major = ?, is_graduating = ?, password = ? WHERE id = ?"; try (Connection conn = DatabaseUtil.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) { @@ -71,7 +72,8 @@ public class StudentDAOImpl implements StudentDAO { stmt.setString(5, student.getCollege()); stmt.setString(6, student.getMajor()); stmt.setBoolean(7, student.isGraduating()); - stmt.setInt(8, student.getId()); + stmt.setString(8, student.getPassword()); + stmt.setInt(9, student.getId()); return stmt.executeUpdate(); } catch (SQLException e) { @@ -184,6 +186,7 @@ public class StudentDAOImpl implements StudentDAO { student.setCollege(rs.getString("college")); student.setMajor(rs.getString("major")); student.setGraduating(rs.getBoolean("is_graduating")); + student.setPassword(rs.getString("password")); return student; } } diff --git a/src/dao/impl/TeacherDAOImpl.java b/src/dao/impl/TeacherDAOImpl.java index b0b71b8..5e6dc66 100644 --- a/src/dao/impl/TeacherDAOImpl.java +++ b/src/dao/impl/TeacherDAOImpl.java @@ -15,7 +15,7 @@ public class TeacherDAOImpl implements TeacherDAO { @Override public int insert(Teacher teacher) { - String sql = "INSERT INTO teachers (teacher_id, name, department, contact) VALUES (?, ?, ?, ?)"; + String sql = "INSERT INTO teachers (teacher_id, name, department, contact, password) VALUES (?, ?, ?, ?, ?)"; try (Connection conn = DatabaseUtil.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) { @@ -23,6 +23,7 @@ public class TeacherDAOImpl implements TeacherDAO { stmt.setString(2, teacher.getName()); stmt.setString(3, teacher.getDepartment()); stmt.setString(4, teacher.getContact()); + stmt.setString(5, teacher.getPassword()); int affectedRows = stmt.executeUpdate(); if (affectedRows == 0) { @@ -57,7 +58,7 @@ public class TeacherDAOImpl implements TeacherDAO { @Override public int update(Teacher teacher) { - String sql = "UPDATE teachers SET teacher_id = ?, name = ?, department = ?, contact = ? WHERE id = ?"; + String sql = "UPDATE teachers SET teacher_id = ?, name = ?, department = ?, contact = ?, password = ? WHERE id = ?"; try (Connection conn = DatabaseUtil.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)) { @@ -65,7 +66,8 @@ public class TeacherDAOImpl implements TeacherDAO { stmt.setString(2, teacher.getName()); stmt.setString(3, teacher.getDepartment()); stmt.setString(4, teacher.getContact()); - stmt.setInt(5, teacher.getId()); + stmt.setString(5, teacher.getPassword()); + stmt.setInt(6, teacher.getId()); return stmt.executeUpdate(); } catch (SQLException e) { @@ -175,6 +177,7 @@ public class TeacherDAOImpl implements TeacherDAO { teacher.setName(rs.getString("name")); teacher.setDepartment(rs.getString("department")); teacher.setContact(rs.getString("contact")); + teacher.setPassword(rs.getString("password")); return teacher; } } diff --git a/src/gui/LoginFrame.java b/src/gui/LoginFrame.java index 709401d..0383a7c 100644 --- a/src/gui/LoginFrame.java +++ b/src/gui/LoginFrame.java @@ -1,91 +1,144 @@ package gui; +import model.Student; +import model.Teacher; +import service.StudentService; +import service.TeacherService; +import service.ServiceFactory; + 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; + + private final StudentService studentService = ServiceFactory.getStudentService(); + private final TeacherService teacherService = ServiceFactory.getTeacherService(); public LoginFrame() { - setTitle("登录"); - setSize(300, 200); + setTitle("平安校园 - 登录"); + setSize(350, 300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); - JPanel panel = new JPanel(); - panel.setLayout(new GridLayout(4, 2)); + // 创建主面板,使用BorderLayout + JPanel mainPanel = new JPanel(new BorderLayout(20, 20)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(20, 30, 20, 30)); - panel.add(new JLabel("用户类型:")); + // 标题面板 + JPanel titlePanel = new JPanel(); + JLabel titleLabel = new JLabel("日常出校申请系统"); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 20)); + titlePanel.add(titleLabel); + + // 登录表单面板 + JPanel formPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(8, 8, 8, 8); + gbc.weightx = 1.0; + + // 用户类型 + gbc.gridx = 0; + gbc.gridy = 0; + JLabel userTypeLabel = new JLabel("用户类型:"); + userTypeLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(userTypeLabel, gbc); + + gbc.gridx = 1; userTypeComboBox = new JComboBox<>(new String[]{"学生", "教师"}); - panel.add(userTypeComboBox); + userTypeComboBox.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(userTypeComboBox, gbc); - panel.add(new JLabel("ID:")); - idField = new JTextField(); - panel.add(idField); + // ID输入框 + gbc.gridx = 0; + gbc.gridy = 1; + JLabel idLabel = new JLabel("ID:"); + idLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(idLabel, gbc); - panel.add(new JLabel("密码:")); - passwordField = new JPasswordField(); - panel.add(passwordField); + gbc.gridx = 1; + idField = new JTextField(20); + idField.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(idField, gbc); + // 密码输入框 + gbc.gridx = 0; + gbc.gridy = 2; + JLabel passwordLabel = new JLabel("密码:"); + passwordLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(passwordLabel, gbc); + + gbc.gridx = 1; + passwordField = new JPasswordField(20); + passwordField.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + formPanel.add(passwordField, gbc); + + // 登录按钮面板 + JPanel buttonPanel = new JPanel(); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0)); loginButton = new JButton("登录"); - panel.add(loginButton); + loginButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + loginButton.setPreferredSize(new Dimension(100, 35)); + loginButton.setBackground(new Color(52, 152, 219)); +// loginButton.setForeground(Color.WHITE); + loginButton.setFocusPainted(false); + buttonPanel.add(loginButton); - loginButton.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - handleLogin(); - } - }); + // 添加事件监听 + loginButton.addActionListener(e -> handleLogin()); - add(panel); + // 组装界面 + mainPanel.add(titlePanel, BorderLayout.NORTH); + mainPanel.add(formPanel, BorderLayout.CENTER); + mainPanel.add(buttonPanel, BorderLayout.SOUTH); + + add(mainPanel); } private void handleLogin() { String userType = (String) userTypeComboBox.getSelectedItem(); - String id = idField.getText(); + String id = idField.getText().trim(); 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 = ?"; + if (id.isEmpty() || password.isEmpty()) { + JOptionPane.showMessageDialog(this, "请输入ID和密码", "提示", JOptionPane.WARNING_MESSAGE); + return; + } - 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); - } + if ("学生".equals(userType)) { + Student student = studentService.login(id, password); + if (student != null) { + StudentMainFrame studentMainFrame = new StudentMainFrame(student); + studentMainFrame.setVisible(true); dispose(); } else { - JOptionPane.showMessageDialog(this, "无效的ID或密码", "错误", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(this, "无效的学号或密码", "错误", JOptionPane.ERROR_MESSAGE); + } + } else { + Teacher teacher = teacherService.login(id, password); + if (teacher != null) { + TeacherMainFrame teacherMainFrame = new TeacherMainFrame(); + teacherMainFrame.setVisible(true); + 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) { + try { + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + SwingUtilities.invokeLater(() -> { LoginFrame loginFrame = new LoginFrame(); loginFrame.setVisible(true); diff --git a/src/gui/RequestDetailDialog.java b/src/gui/RequestDetailDialog.java index 580675d..e2a60d9 100644 --- a/src/gui/RequestDetailDialog.java +++ b/src/gui/RequestDetailDialog.java @@ -14,11 +14,13 @@ public class RequestDetailDialog extends JDialog { private final LeaveRequestService leaveRequestService; private LeaveRequest currentRequest; private Runnable onApprovalComplete; // 添加回调接口 + private boolean isStudent; // 添加标识是否为学生 - public RequestDetailDialog(JFrame parent, int requestId, Runnable onApprovalComplete) { + public RequestDetailDialog(JFrame parent, int requestId, Runnable onApprovalComplete, boolean isStudent) { super(parent, "请假详情", true); this.leaveRequestService = ServiceFactory.getLeaveRequestService(); this.onApprovalComplete = onApprovalComplete; + this.isStudent = isStudent; // 根据ID获取请假信息 this.currentRequest = leaveRequestService.getLeaveRequestById(requestId); @@ -78,130 +80,155 @@ public class RequestDetailDialog extends JDialog { // 审批按钮 JPanel actionButtonPanel = 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); + if (isStudent) { + // 学生只能看到撤销按钮,且仅在待审批状态下可用 + if (currentRequest.getStatus() == ApprovalStatus.PENDING) { + JButton cancelButton = new JButton("撤销申请"); + cancelButton.setPreferredSize(new Dimension(100, 30)); + cancelButton.setBackground(new Color(231, 76, 60)); + cancelButton.addActionListener(e -> { + int confirm = JOptionPane.showConfirmDialog( + this, + "确定要撤销这条请假申请吗?", + "确认撤销", + JOptionPane.YES_NO_OPTION + ); + if (confirm == JOptionPane.YES_OPTION) { + leaveRequestService.cancelLeaveRequest(currentRequest.getId()); + dispose(); + if (onApprovalComplete != null) { + onApprovalComplete.run(); + } + JOptionPane.showMessageDialog(getParent(), "申请已撤销", "提示", JOptionPane.INFORMATION_MESSAGE); + } + }); + actionButtonPanel.add(cancelButton); + } + } else { + // 教师可以看到通过和驳回按钮 + 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)); + rejectButton.setBackground(new Color(231, 76, 60)); + + actionButtonPanel.add(approveButton); + actionButtonPanel.add(rejectButton); + + // 添加教师审批按钮的事件监听 + approveButton.addActionListener(e -> { + // 创建一个自定义对话框 + JDialog approveDialog = new JDialog(this, "审批意见", true); + approveDialog.setLayout(new BorderLayout()); + approveDialog.setSize(300, 200); + approveDialog.setLocationRelativeTo(this); + + JPanel inputPanel = new JPanel(new BorderLayout(10, 10)); + inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + JLabel label = new JLabel("请输入审批意见:"); + JTextArea commentArea = new JTextArea(4, 20); + commentArea.setLineWrap(true); + commentArea.setWrapStyleWord(true); + commentArea.setText("同意"); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton confirmButton = new JButton("确定"); + JButton cancelButton = new JButton("取消"); + + confirmButton.addActionListener(event -> { + String comment = commentArea.getText().trim(); + if (!comment.isEmpty()) { + leaveRequestService.approveLeaveRequest( + currentRequest.getId(), + ApprovalStatus.APPROVED, + comment + ); + approveDialog.dispose(); + dispose(); + if (onApprovalComplete != null) { + onApprovalComplete.run(); + } + } + }); + + cancelButton.addActionListener(event -> approveDialog.dispose()); + + buttonPanel.add(confirmButton); + buttonPanel.add(cancelButton); + + inputPanel.add(label, BorderLayout.NORTH); + inputPanel.add(new JScrollPane(commentArea), BorderLayout.CENTER); + inputPanel.add(buttonPanel, BorderLayout.SOUTH); + + approveDialog.add(inputPanel); + approveDialog.setVisible(true); + }); + + rejectButton.addActionListener(e -> { + // 创建一个自定义对话框 + JDialog rejectDialog = new JDialog(this, "驳回原因", true); + rejectDialog.setLayout(new BorderLayout()); + rejectDialog.setSize(300, 200); + rejectDialog.setLocationRelativeTo(this); + + JPanel inputPanel = new JPanel(new BorderLayout(10, 10)); + inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + JLabel label = new JLabel("请输入驳回原因:"); + JTextArea commentArea = new JTextArea(4, 20); + commentArea.setLineWrap(true); + commentArea.setWrapStyleWord(true); + + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton confirmButton = new JButton("确定"); + JButton cancelButton = new JButton("取消"); + + confirmButton.addActionListener(event -> { + String comment = commentArea.getText().trim(); + if (!comment.isEmpty()) { + leaveRequestService.approveLeaveRequest( + currentRequest.getId(), + ApprovalStatus.REJECTED, + comment + ); + rejectDialog.dispose(); + dispose(); + if (onApprovalComplete != null) { + onApprovalComplete.run(); + } + } + }); + + cancelButton.addActionListener(event -> rejectDialog.dispose()); + + buttonPanel.add(confirmButton); + buttonPanel.add(cancelButton); + + inputPanel.add(label, BorderLayout.NORTH); + inputPanel.add(new JScrollPane(commentArea), BorderLayout.CENTER); + inputPanel.add(buttonPanel, BorderLayout.SOUTH); + + rejectDialog.add(inputPanel); + rejectDialog.setVisible(true); + }); } - - 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); - - actionButtonPanel.add(approveButton); - actionButtonPanel.add(rejectButton); // 添加按钮面板 gbc.insets = new Insets(20, 10, 10, 10); mainPanel.add(actionButtonPanel, gbc); - // 添加事件监听 - approveButton.addActionListener(e -> { - // 创建一个自定义对话框 - JDialog approveDialog = new JDialog(this, "审批意见", true); - approveDialog.setLayout(new BorderLayout()); - approveDialog.setSize(300, 200); - approveDialog.setLocationRelativeTo(this); - - JPanel inputPanel = new JPanel(new BorderLayout(10, 10)); - inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - JLabel label = new JLabel("请输入审批意见:"); - JTextArea commentArea = new JTextArea(4, 20); - commentArea.setLineWrap(true); - commentArea.setWrapStyleWord(true); - commentArea.setText("同意"); - - JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); - JButton confirmButton = new JButton("确定"); - JButton cancelButton = new JButton("取消"); - - confirmButton.addActionListener(event -> { - String comment = commentArea.getText().trim(); - if (!comment.isEmpty()) { - leaveRequestService.approveLeaveRequest( - currentRequest.getId(), - ApprovalStatus.APPROVED, - comment - ); - approveDialog.dispose(); - dispose(); - if (onApprovalComplete != null) { - onApprovalComplete.run(); - } - } - }); - - cancelButton.addActionListener(event -> approveDialog.dispose()); - - buttonPanel.add(confirmButton); - buttonPanel.add(cancelButton); - - inputPanel.add(label, BorderLayout.NORTH); - inputPanel.add(new JScrollPane(commentArea), BorderLayout.CENTER); - inputPanel.add(buttonPanel, BorderLayout.SOUTH); - - approveDialog.add(inputPanel); - approveDialog.setVisible(true); - }); - - rejectButton.addActionListener(e -> { - // 创建一个自定义对话框 - JDialog rejectDialog = new JDialog(this, "驳回原因", true); - rejectDialog.setLayout(new BorderLayout()); - rejectDialog.setSize(300, 200); - rejectDialog.setLocationRelativeTo(this); - - JPanel inputPanel = new JPanel(new BorderLayout(10, 10)); - inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); - - JLabel label = new JLabel("请输入驳回原因:"); - JTextArea commentArea = new JTextArea(4, 20); - commentArea.setLineWrap(true); - commentArea.setWrapStyleWord(true); - - JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); - JButton confirmButton = new JButton("确定"); - JButton cancelButton = new JButton("取消"); - - confirmButton.addActionListener(event -> { - String comment = commentArea.getText().trim(); - if (!comment.isEmpty()) { - leaveRequestService.approveLeaveRequest( - currentRequest.getId(), - ApprovalStatus.REJECTED, - comment - ); - rejectDialog.dispose(); - dispose(); - if (onApprovalComplete != null) { - onApprovalComplete.run(); - } - } - }); - - cancelButton.addActionListener(event -> rejectDialog.dispose()); - - buttonPanel.add(confirmButton); - buttonPanel.add(cancelButton); - - inputPanel.add(label, BorderLayout.NORTH); - inputPanel.add(new JScrollPane(commentArea), BorderLayout.CENTER); - inputPanel.add(buttonPanel, BorderLayout.SOUTH); - - rejectDialog.add(inputPanel); - rejectDialog.setVisible(true); - }); - // 添加滚动面板 JScrollPane scrollPane = new JScrollPane(mainPanel); scrollPane.setBorder(null); diff --git a/src/gui/StudentMainFrame.java b/src/gui/StudentMainFrame.java new file mode 100644 index 0000000..ab60e3c --- /dev/null +++ b/src/gui/StudentMainFrame.java @@ -0,0 +1,344 @@ +package gui; + +import model.ApprovalStatus; +import model.LeaveRequest; +import model.Student; +import service.LeaveRequestService; +import service.ServiceFactory; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import javax.swing.table.TableColumnModel; +import java.awt.*; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +public class StudentMainFrame extends JFrame { + private final LeaveRequestService leaveRequestService; + private final Student currentStudent; + private JTable requestTable; + private DefaultTableModel tableModel; + private int currentPage = 1; + private static final int PAGE_SIZE = 10; + + public StudentMainFrame(Student student) { + this.currentStudent = student; + leaveRequestService = ServiceFactory.getLeaveRequestService(); + initComponents(); + loadLeaveRequests(); + } + + private void initComponents() { + setTitle("平安校园 - 日常出校申请"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(400, 600); + setLocationRelativeTo(null); + + // 主面板 + JPanel mainPanel = new JPanel(new BorderLayout(10, 10)); + mainPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10)); + + // 顶部面板 + JPanel topPanel = new JPanel(new BorderLayout()); + + // 标题 + JLabel titleLabel = new JLabel("日常出校申请记录", SwingConstants.CENTER); + titleLabel.setFont(new Font("微软雅黑", Font.BOLD, 18)); + topPanel.add(titleLabel, BorderLayout.CENTER); + + // 学生信息和申请按钮面板 + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 20, 5)); + + // 添加学生信息 + JLabel studentInfoLabel = new JLabel(String.format("%s - %s", currentStudent.getClassName(), currentStudent.getName())); + studentInfoLabel.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + buttonPanel.add(studentInfoLabel); + + // 申请按钮 + JButton newRequestButton = new JButton("日常出校申请"); + newRequestButton.setFont(new Font("微软雅黑", Font.PLAIN, 14)); + newRequestButton.setBackground(new Color(52, 152, 219)); + // newRequestButton.setForeground(Color.WHITE); + newRequestButton.setFocusPainted(false); + newRequestButton.addActionListener(e -> showNewRequestDialog()); + + buttonPanel.add(newRequestButton); + topPanel.add(buttonPanel, BorderLayout.NORTH); + + // 表格 + String[] columnNames = {"ID", "状态", "申请时间", "外出开始时间", "外出结束时间", "外出事由"}; + 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(40); // ID + columnModel.getColumn(1).setPreferredWidth(60); // 状态 + columnModel.getColumn(2).setPreferredWidth(100); // 申请时间 + columnModel.getColumn(3).setPreferredWidth(100); // 开始时间 + columnModel.getColumn(4).setPreferredWidth(100); // 结束时间 + columnModel.getColumn(5).setPreferredWidth(100); // 外出事由 + + // 添加表格点击事件 + requestTable.addMouseListener(new java.awt.event.MouseAdapter() { + @Override + public void mouseClicked(java.awt.event.MouseEvent evt) { + if (evt.getClickCount() == 2) { + int row = requestTable.getSelectedRow(); + if (row != -1) { + showRequestDetails(row); + } + } + } + }); + + // 分页控制 + 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); + + // 分页按钮事件 + prevButton.addActionListener(e -> { + if (currentPage > 1) { + currentPage--; + loadLeaveRequests(); + } + }); + + nextButton.addActionListener(e -> { + List requests = leaveRequestService.getStudentLeaveRequests(currentStudent.getId()); + int totalPages = (requests.size() + PAGE_SIZE - 1) / PAGE_SIZE; + if (currentPage < totalPages) { + currentPage++; + loadLeaveRequests(); + } + }); + + // 布局 + mainPanel.add(topPanel, BorderLayout.NORTH); + mainPanel.add(new JScrollPane(requestTable), BorderLayout.CENTER); + mainPanel.add(pagePanel, BorderLayout.SOUTH); + + add(mainPanel); + } + + private void showNewRequestDialog() { + JDialog dialog = new JDialog(this, "新建日常出校申请", true); + dialog.setSize(400, 500); + dialog.setLocationRelativeTo(this); + + JPanel panel = new JPanel(new GridBagLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.fill = GridBagConstraints.HORIZONTAL; + gbc.insets = new Insets(5, 5, 5, 5); + + // 开始时间 + gbc.gridx = 0; + gbc.gridy = 0; + panel.add(new JLabel("开始时间:"), gbc); + + gbc.gridx = 1; + SpinnerDateModel startModel = new SpinnerDateModel(); + JSpinner startTimeSpinner = new JSpinner(startModel); + startTimeSpinner.setEditor(new JSpinner.DateEditor(startTimeSpinner, "yyyy-MM-dd HH:mm")); + panel.add(startTimeSpinner, gbc); + + // 结束时间 + gbc.gridx = 0; + gbc.gridy = 1; + panel.add(new JLabel("结束时间:"), gbc); + + gbc.gridx = 1; + SpinnerDateModel endModel = new SpinnerDateModel(); + JSpinner endTimeSpinner = new JSpinner(endModel); + endTimeSpinner.setEditor(new JSpinner.DateEditor(endTimeSpinner, "yyyy-MM-dd HH:mm")); + panel.add(endTimeSpinner, gbc); + + // 外出地址 + gbc.gridx = 0; + gbc.gridy = 2; + panel.add(new JLabel("外出地址:"), gbc); + + gbc.gridx = 1; + JTextField locationField = new JTextField(20); + panel.add(locationField, gbc); + + // 事由类型 + gbc.gridx = 0; + gbc.gridy = 3; + panel.add(new JLabel("事由类型:"), gbc); + + gbc.gridx = 1; + String[] reasonTypes = {"学习", "就医", "办事", "活动", "返乡", "实习", "其他"}; + JComboBox reasonTypeCombo = new JComboBox<>(reasonTypes); + panel.add(reasonTypeCombo, gbc); + + // 详细事由 + gbc.gridx = 0; + gbc.gridy = 4; + panel.add(new JLabel("详细事由:"), gbc); + + gbc.gridx = 1; + JTextArea reasonArea = new JTextArea(4, 20); + reasonArea.setLineWrap(true); + reasonArea.setWrapStyleWord(true); + JScrollPane scrollPane = new JScrollPane(reasonArea); + panel.add(scrollPane, gbc); + + // 是否离津 + gbc.gridx = 0; + gbc.gridy = 5; + panel.add(new JLabel("是否离津:"), gbc); + + gbc.gridx = 1; + JCheckBox leavingCityCheckBox = new JCheckBox(); + panel.add(leavingCityCheckBox, gbc); + + // 按钮面板 + gbc.gridx = 0; + gbc.gridy = 6; + gbc.gridwidth = 2; + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER)); + JButton submitButton = new JButton("提交"); + JButton cancelButton = new JButton("取消"); + + submitButton.addActionListener(e -> { + Date startTime = (Date) startTimeSpinner.getValue(); + Date endTime = (Date) endTimeSpinner.getValue(); + String location = locationField.getText().trim(); + String reasonType = (String) reasonTypeCombo.getSelectedItem(); + String reasonDetail = reasonArea.getText().trim(); + boolean isLeavingCity = leavingCityCheckBox.isSelected(); + + if (location.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "请填写外出地址", "提示", JOptionPane.WARNING_MESSAGE); + return; + } + + if (reasonDetail.isEmpty()) { + JOptionPane.showMessageDialog(dialog, "请填写详细事由", "提示", JOptionPane.WARNING_MESSAGE); + return; + } + + if (startTime.after(endTime)) { + JOptionPane.showMessageDialog(dialog, "开始时间不能晚于结束时间", "提示", JOptionPane.WARNING_MESSAGE); + return; + } + + LeaveRequest request = new LeaveRequest(); + request.setStudent(currentStudent); + request.setStartTime(startTime); + request.setEndTime(endTime); + request.setLocation(location); + request.setReasonType(reasonType); + request.setReasonDetail(reasonDetail); + request.setLeavingCity(isLeavingCity); + request.setStatus(ApprovalStatus.PENDING); + request.setRequestTime(new Date()); + + // 计算请假时长(小时) + double duration = (endTime.getTime() - startTime.getTime()) / (1000.0 * 60 * 60); + request.setDuration(duration); + + if (leaveRequestService.submitLeaveRequest(request)) { + loadLeaveRequests(); + dialog.dispose(); + JOptionPane.showMessageDialog(this, "申请提交成功", "提示", JOptionPane.INFORMATION_MESSAGE); + } else { + JOptionPane.showMessageDialog(this, "申请提交失败,请稍后重试", "错误", JOptionPane.ERROR_MESSAGE); + } + }); + + cancelButton.addActionListener(e -> dialog.dispose()); + + buttonPanel.add(submitButton); + buttonPanel.add(cancelButton); + panel.add(buttonPanel, gbc); + + dialog.add(panel); + dialog.setVisible(true); + } + + private void showRequestDetails(int row) { + Long requestId = (Long) tableModel.getValueAt(row, 0); + RequestDetailDialog dialog = new RequestDetailDialog(this, requestId.intValue(), this::loadLeaveRequests, true); + dialog.setVisible(true); + } + + private void loadLeaveRequests() { + tableModel.setRowCount(0); + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm"); + + List requests = leaveRequestService.getStudentLeaveRequests(currentStudent.getId()); + + // Calculate total pages + int totalRequests = requests.size(); + int totalPages = (totalRequests + PAGE_SIZE - 1) / PAGE_SIZE; + + // Update page label + Component[] components = getContentPane().getComponents(); + for (Component comp : components) { + if (comp instanceof JPanel) { + JPanel panel = (JPanel) comp; + for (Component innerComp : panel.getComponents()) { + if (innerComp instanceof JPanel && ((JPanel) innerComp).getComponentCount() == 3) { + JPanel pagePanel = (JPanel) innerComp; + JLabel pageLabel = (JLabel) pagePanel.getComponent(1); + pageLabel.setText(currentPage + "/" + totalPages); + break; + } + } + } + } + + // Get current page's requests + int fromIndex = (currentPage - 1) * PAGE_SIZE; + int toIndex = Math.min(fromIndex + PAGE_SIZE, totalRequests); + List pageRequests = fromIndex < totalRequests ? requests.subList(fromIndex, toIndex) : requests; + + for (LeaveRequest request : pageRequests) { + tableModel.addRow(new Object[]{ + Long.valueOf(request.getId()), + request.getStatus().getDescription(), + sdf.format(request.getRequestTime()), + sdf.format(request.getStartTime()), + sdf.format(request.getEndTime()), + request.getReasonDetail() + }); + } + } + + public static void main(String[] args) { + SwingUtilities.invokeLater(() -> { + try { + // 使用实际学生数据 + Student student = ServiceFactory.getStudentService().login("2023208145", "123456"); + if (student != null) { + new StudentMainFrame(student).setVisible(true); + } else { + JOptionPane.showMessageDialog(null, "无法加载学生信息", "错误", JOptionPane.ERROR_MESSAGE); + } + } catch (Exception e) { + e.printStackTrace(); + JOptionPane.showMessageDialog(null, "系统错误: " + e.getMessage(), "错误", JOptionPane.ERROR_MESSAGE); + } + }); + } +} diff --git a/src/gui/TeacherMainFrame.java b/src/gui/TeacherMainFrame.java index 9f2101c..4310128 100644 --- a/src/gui/TeacherMainFrame.java +++ b/src/gui/TeacherMainFrame.java @@ -229,7 +229,8 @@ public class TeacherMainFrame extends JFrame { RequestDetailDialog dialog = new RequestDetailDialog( this, ((Number)tableModel.getValueAt(row, 0)).intValue(), // 获取ID - () -> loadLeaveRequests() // 添加刷新列表的回调 + () -> loadLeaveRequests(), // 添加刷新列表的回调 + false // 教师视角 ); dialog.setVisible(true); } diff --git a/src/model/Student.java b/src/model/Student.java index 60b2009..0fbc932 100644 --- a/src/model/Student.java +++ b/src/model/Student.java @@ -12,6 +12,7 @@ public class Student { private String college; // 学院 private String major; // 专业 private boolean isGraduating; // 是否毕业班 + private String password; // 登录密码 // Constructors public Student() {} @@ -26,6 +27,17 @@ public class Student { this.isGraduating = isGraduating; } + public Student(String studentId, String name, String className, String contact, String college, String major, boolean isGraduating, String password) { + this.studentId = studentId; + this.name = name; + this.className = className; + this.contact = contact; + this.college = college; + this.major = major; + this.isGraduating = isGraduating; + this.password = password; + } + // Getters and Setters public int getId() { return id; @@ -90,4 +102,12 @@ public class Student { public void setGraduating(boolean graduating) { isGraduating = graduating; } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/model/Teacher.java b/src/model/Teacher.java index 9fdf38a..367f7e2 100644 --- a/src/model/Teacher.java +++ b/src/model/Teacher.java @@ -9,6 +9,7 @@ public class Teacher { private String name; // 教师姓名 private String department; // 所属部门 private String contact; // 联系方式 + private String password; // 登录密码 // Constructors public Teacher() {} @@ -20,6 +21,14 @@ public class Teacher { this.contact = contact; } + public Teacher(String teacherId, String name, String department, String contact, String password) { + this.teacherId = teacherId; + this.name = name; + this.department = department; + this.contact = contact; + this.password = password; + } + // Getters and Setters public int getId() { return id; @@ -60,4 +69,12 @@ public class Teacher { public void setContact(String contact) { this.contact = contact; } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } } diff --git a/src/service/LeaveRequestService.java b/src/service/LeaveRequestService.java index 1332a30..d27ea87 100644 --- a/src/service/LeaveRequestService.java +++ b/src/service/LeaveRequestService.java @@ -7,6 +7,7 @@ import model.Student; import model.ApprovalStatus; import java.util.Date; import java.util.List; +import java.util.Calendar; /** * 请假申请服务类 @@ -24,11 +25,13 @@ public class LeaveRequestService { // 检查学生是否存在 Student student = studentService.getStudentById(request.getStudent().getId()); if (student == null) { + System.out.println("提交请假失败:学生不存在,ID=" + request.getStudent().getId()); return false; } // 检查请假时间是否合理 if (!isValidLeaveTime(request.getStartTime(), request.getEndTime())) { + System.out.println("提交请假失败:请假时间不合理,开始时间=" + request.getStartTime() + ",结束时间=" + request.getEndTime()); return false; } @@ -36,7 +39,13 @@ public class LeaveRequestService { request.setStatus(ApprovalStatus.PENDING); request.setRequestTime(new Date()); - return leaveRequestDAO.insert(request) > 0; + int result = leaveRequestDAO.insert(request); + if (result == 0) { + System.out.println("提交请假失败:数据库插入失败"); + return false; + } + System.out.println("提交请假成功:ID=" + request.getId()); + return true; } /** @@ -96,6 +105,27 @@ public class LeaveRequestService { return leaveRequestDAO.findById(requestId); } + /** + * 撤销请假申请 + * @param requestId 请假申请ID + * @return 是否撤销成功 + */ + public boolean cancelLeaveRequest(int requestId) { + // 检查请假申请是否存在 + LeaveRequest request = leaveRequestDAO.findById(requestId); + if (request == null) { + return false; + } + + // 检查是否可以撤销(只有待审批状态可以撤销) + if (request.getStatus() != ApprovalStatus.PENDING) { + return false; + } + + // 删除请假申请 + return leaveRequestDAO.deleteById(requestId) > 0; + } + /** * 检查请假时间是否合理 * @param startTime 开始时间 @@ -103,19 +133,28 @@ public class LeaveRequestService { * @return 是否合理 */ private boolean isValidLeaveTime(Date startTime, Date endTime) { - // 开始时间不能为空 + // 开始时间和结束时间不能为空 if (startTime == null || endTime == null) { return false; } // 结束时间必须在开始时间之后 - if (endTime.before(startTime)) { + if (endTime.before(startTime) || endTime.equals(startTime)) { return false; } - // 开始时间不能是过去的时间 - Date now = new Date(); - if (startTime.before(now)) { + // 开始时间不能是过去24小时以前的时间 + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.HOUR, -24); + Date oneDayAgo = cal.getTime(); + + if (startTime.before(oneDayAgo)) { + return false; + } + + // 请假时长不能超过30天 + long durationInDays = (endTime.getTime() - startTime.getTime()) / (1000 * 60 * 60 * 24); + if (durationInDays > 30) { return false; } diff --git a/src/service/StudentService.java b/src/service/StudentService.java index 1fb4295..531251d 100644 --- a/src/service/StudentService.java +++ b/src/service/StudentService.java @@ -95,4 +95,25 @@ public class StudentService { public List searchStudentsByName(String name) { return studentDAO.findByNameLike(name); } + + /** + * 学生登录 + * @param studentId 学号 + * @param password 密码 + * @return 登录成功返回学生信息,失败返回null + */ + public Student login(String studentId, String password) { + Student student = studentDAO.findByStudentId(studentId); + System.out.println("Login attempt - StudentID: " + studentId); + System.out.println("Student found: " + (student != null)); + if (student != null) { + System.out.println("Stored password: " + student.getPassword()); + System.out.println("Input password: " + password); + System.out.println("Password match: " + password.equals(student.getPassword())); + } + if (student != null && password.equals(student.getPassword())) { + return student; + } + return null; + } } diff --git a/src/service/TeacherService.java b/src/service/TeacherService.java index 8a122b8..6eec486 100644 --- a/src/service/TeacherService.java +++ b/src/service/TeacherService.java @@ -95,4 +95,25 @@ public class TeacherService { public List searchTeachersByName(String name) { return teacherDAO.findByNameLike(name); } + + /** + * 教师登录 + * @param teacherId 教师工号 + * @param password 密码 + * @return 登录成功返回教师信息,失败返回null + */ + public Teacher login(String teacherId, String password) { + Teacher teacher = teacherDAO.findByTeacherId(teacherId); + System.out.println("Login attempt - TeacherID: " + teacherId); + System.out.println("Teacher found: " + (teacher != null)); + if (teacher != null) { + System.out.println("Stored password: " + teacher.getPassword()); + System.out.println("Input password: " + password); + System.out.println("Password match: " + password.equals(teacher.getPassword())); + } + if (teacher != null && password.equals(teacher.getPassword())) { + return teacher; + } + return null; + } }