From cd54e2813e33af0b9bcc00f695aa017c1f27fafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=AA=20Th=C3=A0nh=20=C4=90=E1=BA=A1t?= <91755733+lds217@users.noreply.github.com> Date: Sat, 19 Jul 2025 16:32:59 +0700 Subject: [PATCH] [update] Enhance CheckUpPage and related dialogs by adding heart rate and blood pressure fields, improving date input handling, and implementing filter functionality in the queue management. Update data structures and server handling to accommodate new fields, ensuring comprehensive patient information management and better user experience. --- .vscode/launch.json | 7 + .../CheckUpPage/AddDialog/AddDialog.java | 56 ++- .../ui/component/CheckUpPage/CheckUpPage.java | 448 ++++++++++++++++-- .../HistoryViewDialog/HistoryViewDialog.java | 12 + .../MedicineDialog/MedicineDialog.java | 24 +- .../ServiceDialog/ServiceDialog.java | 25 +- .../TemplateDialog/TemplateDialog.java | 13 + .../component/common/DateLabelFormatter.java | 34 ++ src/main/java/BsK/common/entity/Patient.java | 18 +- .../common/packet/req/AddCheckupRequest.java | 1 + .../common/packet/req/SaveCheckupRequest.java | 2 + .../java/BsK/common/util/date/DateUtils.java | 4 +- .../server/network/handler/ServerHandler.java | 26 +- src/main/resources/database/BSK.db | Bin 1196032 -> 1196032 bytes 14 files changed, 613 insertions(+), 57 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 843411f..9eb8ca9 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,6 +1,13 @@ { "version": "0.2.0", "configurations": [ + { + "type": "java", + "name": "DateUtils", + "request": "launch", + "mainClass": "BsK.common.util.date.DateUtils", + "projectName": "ldS_BsK" + }, { "type": "java", "name": "test_ultrasound_print", diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/AddDialog/AddDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/AddDialog/AddDialog.java index 970f911..72eafac 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/AddDialog/AddDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/AddDialog/AddDialog.java @@ -335,12 +335,14 @@ public class AddDialog extends JDialog { gbc.gridx = 1; UtilDateModel model = new UtilDateModel(); Properties p = new Properties(); - p.put("text.today", "Hôm nay"); p.put("text.month", "Tháng"); p.put("text.year", "Năm"); + // Remove "text.today" since DOB shouldn't default to today JDatePanelImpl datePanel = new JDatePanelImpl(model, p); dobPicker = new JDatePickerImpl(datePanel, new DateLabelFormatter()); dobPicker.getJFormattedTextField().setFont(textFont); + dobPicker.getJFormattedTextField().setToolTipText("Nhập ngày theo định dạng dd/mm/yyyy"); + setupDateFieldForDirectInput(dobPicker); dobPicker.setPreferredSize(new Dimension(150, 30)); patientInfoPanel.add(dobPicker, gbc); @@ -629,13 +631,25 @@ public class AddDialog extends JDialog { int patientId = Integer.parseInt(patientIdField.getText()); int doctorId = doctorComboBox.getSelectedIndex()+ 1; String selectedCheckupType = (String) checkupTypeComboBox.getSelectedItem(); - NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new AddCheckupRequest(patientId, doctorId, LocalStorage.userId, selectedCheckupType)); + NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new AddCheckupRequest(patientId, doctorId, LocalStorage.userId,"ĐANG KHÁM", selectedCheckupType)); }); saveButton.setEnabled(false); ButtonPanel.add(saveButton); add(ButtonPanel, BorderLayout.SOUTH); + + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); } private void handleRowSelection(int selectedRow) { @@ -738,6 +752,44 @@ public class AddDialog extends JDialog { wardComboBox.setEnabled(true); // Enable ward combo box } + private void setupDateFieldForDirectInput(JDatePickerImpl datePicker) { + JFormattedTextField textField = datePicker.getJFormattedTextField(); + + // Make sure the field is editable + textField.setEditable(true); + + // Improve focus behavior for better tab navigation + textField.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + SwingUtilities.invokeLater(() -> { + if (textField.getText().isEmpty()) { + textField.setForeground(Color.BLACK); + } + textField.selectAll(); + }); + } + + @Override + public void focusLost(FocusEvent e) { + if (textField.getText().isEmpty()) { + textField.setForeground(Color.GRAY); + } + } + }); + + // Add key listener for better input handling + textField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + // Allow tab navigation + if (e.getKeyCode() == KeyEvent.VK_TAB) { + textField.transferFocus(); + } + } + }); + } + public static void main(String[] args) { // add a button to open the dialog diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java index e9d6ae4..10de395 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/CheckUpPage.java @@ -37,6 +37,12 @@ import javax.swing.*; import javax.swing.border.TitledBorder; import javax.swing.border.Border; import javax.swing.table.DefaultTableModel; +import javax.swing.RowSorter; +import javax.swing.SortOrder; +import javax.swing.table.TableRowSorter; +import java.util.Comparator; +import java.text.SimpleDateFormat; +import java.text.ParseException; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import java.awt.*; @@ -45,6 +51,9 @@ import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.KeyEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.datatransfer.*; @@ -129,6 +138,9 @@ import BsK.common.packet.res.RegisterSuccessResponse; import BsK.common.packet.res.SaveCheckupRes; import BsK.common.packet.res.UploadCheckupImageResponse; import BsK.common.util.date.DateUtils; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import javax.swing.text.JTextComponent; @Slf4j public class CheckUpPage extends JPanel { @@ -250,19 +262,22 @@ public class CheckUpPage extends JPanel { if (patients == null) { return new String[][]{}; } - String[][] tableData = new String[patients.size()][8]; + String[][] tableData = new String[patients.size()][7]; for (int i = 0; i < patients.size(); i++) { Patient p = patients.get(i); tableData[i][0] = p.getCheckupId(); - // Convert DOB to display format using utility function - tableData[i][1] = DateUtils.convertToDisplayFormat(p.getCustomerDob()); + // Convert checkup date to display format using utility function + tableData[i][1] = DateUtils.convertToDisplayFormat(p.getCheckupDate()); - tableData[i][2] = p.getCustomerLastName(); - tableData[i][3] = p.getCustomerFirstName(); - tableData[i][4] = p.getDoctorName(); - tableData[i][5] = p.getCheckupType(); + // Convert DOB to display format using utility function + tableData[i][2] = DateUtils.convertToDisplayFormat(p.getCustomerDob()); + + tableData[i][3] = p.getCustomerLastName(); + tableData[i][4] = p.getCustomerFirstName(); + tableData[i][5] = p.getDoctorName(); + tableData[i][6] = p.getCheckupType(); } return tableData; } @@ -502,6 +517,7 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 1; gbcPatient.weightx = 0.4; gbcPatient.gridwidth = 3; customerCccdDdcnField = new JTextField(15); customerCccdDdcnField.setFont(fieldFont); + addSelectAllOnFocus(customerCccdDdcnField); patientInfoInnerPanel.add(customerCccdDdcnField, gbcPatient); gbcPatient.gridwidth = 1; // Reset gridwidth @@ -514,6 +530,7 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 1; gbcPatient.weightx = 0.4; customerLastNameField = new JTextField(20); customerLastNameField.setFont(fieldFont); + addSelectAllOnFocus(customerLastNameField); patientInfoInnerPanel.add(customerLastNameField, gbcPatient); gbcPatient.gridx = 2; gbcPatient.weightx = 0.1; @@ -524,6 +541,7 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 3; gbcPatient.weightx = 0.4; customerFirstNameField = new JTextField(15); customerFirstNameField.setFont(fieldFont); + addSelectAllOnFocus(customerFirstNameField); patientInfoInnerPanel.add(customerFirstNameField, gbcPatient); // Row 2: ID and Phone @@ -551,6 +569,7 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 3; gbcPatient.weightx = 0.4; customerPhoneField = new JTextField(15); customerPhoneField.setFont(fieldFont); + addSelectAllOnFocus(customerPhoneField); patientInfoInnerPanel.add(customerPhoneField, gbcPatient); // Row 3: Gender and DOB @@ -573,12 +592,14 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 3; UtilDateModel dobModel = new UtilDateModel(); Properties dobProperties = new Properties(); - dobProperties.put("text.today", "Hôm nay"); dobProperties.put("text.month", "Tháng"); dobProperties.put("text.year", "Năm"); + // Remove "text.today" since these dates shouldn't default to today JDatePanelImpl dobPanel = new JDatePanelImpl(dobModel, dobProperties); dobPicker = new JDatePickerImpl(dobPanel, new DateLabelFormatter()); dobPicker.getJFormattedTextField().setFont(fieldFont); + dobPicker.getJFormattedTextField().setToolTipText("Nhập ngày theo định dạng dd/mm/yyyy"); + setupDateFieldForDirectInput(dobPicker); patientInfoInnerPanel.add(dobPicker, gbcPatient); // Row 4: Weight and Height @@ -593,7 +614,9 @@ public class CheckUpPage extends JPanel { customerWeightSpinner.setFont(fieldFont); JComponent weightEditor = customerWeightSpinner.getEditor(); if (weightEditor instanceof JSpinner.DefaultEditor) { - ((JSpinner.DefaultEditor)weightEditor).getTextField().setFont(fieldFont); + JFormattedTextField tf = ((JSpinner.DefaultEditor) weightEditor).getTextField(); + tf.setFont(fieldFont); + addSelectAllOnFocus(tf); } patientInfoInnerPanel.add(customerWeightSpinner, gbcPatient); @@ -608,7 +631,9 @@ public class CheckUpPage extends JPanel { customerHeightSpinner.setFont(fieldFont); JComponent heightEditor = customerHeightSpinner.getEditor(); if (heightEditor instanceof JSpinner.DefaultEditor) { - ((JSpinner.DefaultEditor)heightEditor).getTextField().setFont(fieldFont); + JFormattedTextField tf = ((JSpinner.DefaultEditor) heightEditor).getTextField(); + tf.setFont(fieldFont); + addSelectAllOnFocus(tf); } patientInfoInnerPanel.add(customerHeightSpinner, gbcPatient); @@ -620,12 +645,14 @@ public class CheckUpPage extends JPanel { patientInfoInnerPanel.add(heartRateLabel, gbcPatient); gbcPatient.gridx = 1; - SpinnerModel heartRateModel = new SpinnerNumberModel(80, 30, 250, 1); + SpinnerModel heartRateModel = new SpinnerNumberModel(80, 0, 250, 1); patientHeartRateSpinner = new JSpinner(heartRateModel); patientHeartRateSpinner.setFont(fieldFont); JComponent heartRateEditor = patientHeartRateSpinner.getEditor(); if (heartRateEditor instanceof JSpinner.DefaultEditor) { - ((JSpinner.DefaultEditor)heartRateEditor).getTextField().setFont(fieldFont); + JFormattedTextField tf = ((JSpinner.DefaultEditor) heartRateEditor).getTextField(); + tf.setFont(fieldFont); + addSelectAllOnFocus(tf); } patientInfoInnerPanel.add(patientHeartRateSpinner, gbcPatient); @@ -638,20 +665,24 @@ public class CheckUpPage extends JPanel { JPanel bloodPressurePanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0)); bloodPressurePanel.setOpaque(false); - SpinnerModel systolicModel = new SpinnerNumberModel(120, 50, 300, 1); + SpinnerModel systolicModel = new SpinnerNumberModel(120, 0, 300, 1); bloodPressureSystolicSpinner = new JSpinner(systolicModel); bloodPressureSystolicSpinner.setFont(fieldFont); JComponent systolicEditor = bloodPressureSystolicSpinner.getEditor(); if (systolicEditor instanceof JSpinner.DefaultEditor) { - ((JSpinner.DefaultEditor)systolicEditor).getTextField().setFont(fieldFont); + JFormattedTextField tf = ((JSpinner.DefaultEditor) systolicEditor).getTextField(); + tf.setFont(fieldFont); + addSelectAllOnFocus(tf); } - SpinnerModel diastolicModel = new SpinnerNumberModel(80, 30, 200, 1); + SpinnerModel diastolicModel = new SpinnerNumberModel(80, 0, 200, 1); bloodPressureDiastolicSpinner = new JSpinner(diastolicModel); bloodPressureDiastolicSpinner.setFont(fieldFont); JComponent diastolicEditor = bloodPressureDiastolicSpinner.getEditor(); if (diastolicEditor instanceof JSpinner.DefaultEditor) { - ((JSpinner.DefaultEditor)diastolicEditor).getTextField().setFont(fieldFont); + JFormattedTextField tf = ((JSpinner.DefaultEditor) diastolicEditor).getTextField(); + tf.setFont(fieldFont); + addSelectAllOnFocus(tf); } JLabel slashLabel = new JLabel(" / "); @@ -671,6 +702,7 @@ public class CheckUpPage extends JPanel { gbcPatient.gridx = 1; gbcPatient.gridwidth = 3; customerAddressField = new JTextField(40); customerAddressField.setFont(fieldFont); + addSelectAllOnFocus(customerAddressField); patientInfoInnerPanel.add(customerAddressField, gbcPatient); // Row 7: Location dropdowns @@ -802,13 +834,15 @@ public class CheckUpPage extends JPanel { // Initialize datePicker UtilDateModel dateModel = new UtilDateModel(); Properties p = new Properties(); - p.put("text.today", "Hôm nay"); p.put("text.month", "Tháng"); p.put("text.year", "Năm"); + // Remove "text.today" since these dates shouldn't default to today JDatePanelImpl datePanel = new JDatePanelImpl(dateModel, p); datePicker = new JDatePickerImpl(datePanel, new DateLabelFormatter()); datePicker.setPreferredSize(new Dimension(120, 30)); datePicker.getJFormattedTextField().setFont(fieldFont); + datePicker.getJFormattedTextField().setToolTipText("Nhập ngày theo định dạng dd/mm/yyyy"); + setupDateFieldForDirectInput(datePicker); gbcTop.gridx = 0; gbcTop.gridy = 0; JLabel doctorLabel = new JLabel("Bác Sĩ"); @@ -908,6 +942,7 @@ public class CheckUpPage extends JPanel { notesField = new JTextPane(); notesField.setContentType("text/rtf"); + addSelectAllOnFocus(notesField); // Set default font and size notesField.setFont(new Font("Times New Roman", Font.PLAIN, 16)); @@ -1076,6 +1111,7 @@ public class CheckUpPage extends JPanel { suggestionField.setFont(fieldFont); suggestionField.setLineWrap(true); suggestionField.setWrapStyleWord(true); + addSelectAllOnFocus(suggestionField); JScrollPane suggestionScrollPane = new JScrollPane(suggestionField); suggestionScrollPane.setPreferredSize(new Dimension(0, 200)); // Set fixed height suggestionPanel.add(suggestionScrollPane, BorderLayout.CENTER); @@ -1091,12 +1127,14 @@ public class CheckUpPage extends JPanel { UtilDateModel recheckupModel = new UtilDateModel(); Properties recheckupProps = new Properties(); - recheckupProps.put("text.today", "Hôm nay"); recheckupProps.put("text.month", "Tháng"); recheckupProps.put("text.year", "Năm"); + // Remove "text.today" since these dates shouldn't default to today JDatePanelImpl recheckupDatePanel = new JDatePanelImpl(recheckupModel, recheckupProps); recheckupDatePicker = new JDatePickerImpl(recheckupDatePanel, new DateLabelFormatter()); recheckupDatePicker.getJFormattedTextField().setFont(fieldFont); + recheckupDatePicker.getJFormattedTextField().setToolTipText("Nhập ngày theo định dạng dd/mm/yyyy"); + setupDateFieldForDirectInput(recheckupDatePicker); recheckupDatePicker.setPreferredSize(new Dimension(140, 30)); // Make it a bit smaller recheckupPanel.add(recheckupDatePicker); suggestionPanel.add(recheckupPanel, BorderLayout.SOUTH); @@ -1117,6 +1155,7 @@ public class CheckUpPage extends JPanel { diagnosisField.setFont(fieldFont); diagnosisField.setLineWrap(true); diagnosisField.setWrapStyleWord(true); + addSelectAllOnFocus(diagnosisField); diagnosisPanel.add(new JScrollPane(diagnosisField), BorderLayout.CENTER); // Conclusion Panel @@ -1132,6 +1171,7 @@ public class CheckUpPage extends JPanel { conclusionField.setFont(fieldFont); conclusionField.setLineWrap(true); conclusionField.setWrapStyleWord(true); + addSelectAllOnFocus(conclusionField); conclusionPanel.add(new JScrollPane(conclusionField), BorderLayout.CENTER); rightPanel.add(suggestionPanel); @@ -1350,6 +1390,82 @@ public class CheckUpPage extends JPanel { setupShortcuts(); } + private void addSelectAllOnFocus(JTextComponent textComponent) { + textComponent.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + SwingUtilities.invokeLater(textComponent::selectAll); + } + }); + } + + private void setupDateFieldForDirectInput(JDatePickerImpl datePicker) { + JFormattedTextField textField = datePicker.getJFormattedTextField(); + + // Make sure the field is editable + textField.setEditable(true); + + // Improve focus behavior for better tab navigation + textField.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + SwingUtilities.invokeLater(() -> { + if (textField.getText().isEmpty()) { + textField.setForeground(Color.BLACK); + } + textField.selectAll(); + }); + } + + @Override + public void focusLost(FocusEvent e) { + if (textField.getText().isEmpty()) { + textField.setForeground(Color.GRAY); + } + } + }); + + // Add key listener for better input handling + textField.addKeyListener(new KeyAdapter() { + @Override + public void keyPressed(KeyEvent e) { + // Allow tab navigation + if (e.getKeyCode() == KeyEvent.VK_TAB) { + textField.transferFocus(); + } + } + }); + } + + /** + * Creates a date comparator for table sorting that properly handles dd/MM/yyyy format dates + * @return Comparator for date strings in dd/MM/yyyy format + */ + private Comparator createDateComparator() { + return new Comparator() { + private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy"); + + @Override + public int compare(String date1, String date2) { + try { + if (date1 == null || date1.trim().isEmpty()) { + return date2 == null || date2.trim().isEmpty() ? 0 : 1; + } + if (date2 == null || date2.trim().isEmpty()) { + return -1; + } + + Date d1 = dateFormat.parse(date1.trim()); + Date d2 = dateFormat.parse(date2.trim()); + return d1.compareTo(d2); + } catch (ParseException e) { + // If parsing fails, fall back to string comparison + return date1.compareTo(date2); + } + } + }; + } + private JButton createActionButton(String iconName, String text, Color bgColor) { JButton button = new JButton(text); try { @@ -1740,7 +1856,7 @@ public class CheckUpPage extends JPanel { suggestionField.setText(selectedPatient.getSuggestion()); // De nghi diagnosisField.setText(selectedPatient.getDiagnosis()); // Chuan doan conclusionField.setText(selectedPatient.getConclusion()); // Ket luan - recheckupDatePicker.getJFormattedTextField().setText(selectedPatient.getReCheckupDate()); // Ngày khám lại + recheckupDatePicker.getJFormattedTextField().setText(DateUtils.convertToDisplayFormat(selectedPatient.getReCheckupDate())); // Ngày khám lại // Handle RTF notes content String notes = selectedPatient.getNotes(); @@ -1768,6 +1884,34 @@ public class CheckUpPage extends JPanel { customerPhoneField.setText(selectedPatient.getCustomerNumber()); try { customerWeightSpinner.setValue(Double.parseDouble(selectedPatient.getCustomerWeight())); } catch (NumberFormatException e) {log.warn("Invalid weight: {}", selectedPatient.getCustomerWeight()); customerWeightSpinner.setValue(0.0);} try { customerHeightSpinner.setValue(Double.parseDouble(selectedPatient.getCustomerHeight())); } catch (NumberFormatException e) {log.warn("Invalid height: {}", selectedPatient.getCustomerHeight()); customerHeightSpinner.setValue(0.0);} + try { patientHeartRateSpinner.setValue(Integer.parseInt(selectedPatient.getHeartBeat())); } catch (NumberFormatException e) {log.warn("Invalid heart beat: {}", selectedPatient.getHeartBeat()); patientHeartRateSpinner.setValue(0);} + //blood pressure is format as string 0/0 so we will need to split it first + String bloodPressure = selectedPatient.getBloodPressure(); + if (bloodPressure != null && bloodPressure.contains("/")) { + String[] bloodPressureParts = bloodPressure.split("/"); + if (bloodPressureParts.length == 2) { + try { + bloodPressureSystolicSpinner.setValue(Integer.parseInt(bloodPressureParts[0])); + } catch (NumberFormatException e) { + log.warn("Invalid systolic blood pressure: {}", bloodPressureParts[0]); + bloodPressureSystolicSpinner.setValue(0); + } + try { + bloodPressureDiastolicSpinner.setValue(Integer.parseInt(bloodPressureParts[1])); + } catch (NumberFormatException e) { + log.warn("Invalid diastolic blood pressure: {}", bloodPressureParts[1]); + bloodPressureDiastolicSpinner.setValue(0); + } + } else { + log.warn("Invalid blood pressure format: {}", bloodPressure); + bloodPressureSystolicSpinner.setValue(0); + bloodPressureDiastolicSpinner.setValue(0); + } + } else { + log.warn("Blood pressure data is missing or in wrong format: {}", bloodPressure); + bloodPressureSystolicSpinner.setValue(0); + bloodPressureDiastolicSpinner.setValue(0); + } genderComboBox.setSelectedItem(selectedPatient.getCustomerGender()); checkupTypeComboBox.setSelectedItem(selectedPatient.getCheckupType()); customerCccdDdcnField.setText(selectedPatient.getCccdDdcn() != null ? selectedPatient.getCccdDdcn() : ""); @@ -2860,6 +3004,18 @@ public class CheckUpPage extends JPanel { scrollPane.setBorder(BorderFactory.createEmptyBorder()); imageDialog.add(scrollPane, BorderLayout.CENTER); + // Add Escape key listener to close dialog + JRootPane rootPane = imageDialog.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + imageDialog.dispose(); + } + }); + // Set dialog size and position imageDialog.setSize(scaledWidth + 20, scaledHeight + 45); // Add padding for borders and title bar imageDialog.setLocationRelativeTo(this); @@ -2905,12 +3061,15 @@ public class CheckUpPage extends JPanel { private class QueueManagementPage extends JDialog { private JTable queueTable; private DefaultTableModel queueTableModel; + private JComboBox checkupTypeFilter; + private JTextField patientNameFilter; + private List filteredPatients; public QueueManagementPage() { super(mainFrame, "Danh sách chờ khám", true); // Set as modal dialog setIconImage(new ImageIcon("src/main/java/BsK/client/ui/assets/icon/database.png").getImage()); - setSize(800, 600); + setSize(1000, 700); // Increased size to accommodate filters and new column setLayout(new BorderLayout()); // Add window listener to handle minimize/restore events with parent @@ -2931,22 +3090,46 @@ public class CheckUpPage extends JPanel { @Override public void windowClosing(WindowEvent e) { + // Reset patient name filter when closing dialog + patientNameFilter.setText(""); + applyFilters(); // Hide instead of closing to maintain state setVisible(false); } }); - String[] columns = {"Mã khám bệnh", "Ngày sinh", "Họ", "Tên", "Bác Sĩ", "Loại khám"}; - queueTableModel = new DefaultTableModel(preprocessPatientDataForTable(patientQueue), columns) { + // Initialize filtered patients list + filteredPatients = new ArrayList<>(patientQueue); + + // Create filter panel + JPanel filterPanel = createFilterPanel(); + add(filterPanel, BorderLayout.NORTH); + + String[] columns = {"Mã khám bệnh", "Ngày khám", "Ngày sinh", "Họ", "Tên", "Bác Sĩ", "Loại khám"}; + queueTableModel = new DefaultTableModel(preprocessPatientDataForTable(filteredPatients), columns) { @Override public boolean isCellEditable(int row, int column) { return false; } }; queueTable = new JTable(queueTableModel); - queueTable.setPreferredScrollableViewportSize(new Dimension(750, 400)); - queueTable.getTableHeader().setFont(new Font("Arial", Font.BOLD, 14)); - queueTable.setFont(new Font("Arial", Font.PLAIN, 12)); - queueTable.setRowHeight(25); + queueTable.setPreferredScrollableViewportSize(new Dimension(850, 400)); // Increased width for new column + queueTable.getTableHeader().setFont(new Font("Arial", Font.BOLD, 18)); + queueTable.setFont(new Font("Arial", Font.PLAIN, 16)); + queueTable.setRowHeight(35); queueTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); + + // Create custom row sorter with date comparator for proper date sorting + TableRowSorter sorter = new TableRowSorter<>(queueTableModel); + + // Set up date comparator for column 1 (Ngày khám) and column 2 (Ngày sinh) + sorter.setComparator(1, createDateComparator()); // Checkup Date + sorter.setComparator(2, createDateComparator()); // Date of Birth + + queueTable.setRowSorter(sorter); + + // Sort by "Ngày khám" column in ascending order (earliest dates first) + List sortKeys = new ArrayList<>(); + sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING)); + sorter.setSortKeys(sortKeys); queueTable.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { @@ -2974,7 +3157,10 @@ public class CheckUpPage extends JPanel { } } // Call the parent class's method to handle the selection - CheckUpPage.this.handleRowSelection(selectedRow); + CheckUpPage.this.handleRowSelection(getSelectedRow()); + // Reset patient name filter when closing dialog after selection + patientNameFilter.setText(""); + applyFilters(); // Hide the dialog after selection QueueManagementPage.this.setVisible(false); } @@ -2989,6 +3175,171 @@ public class CheckUpPage extends JPanel { add(scrollPane, BorderLayout.CENTER); setLocationRelativeTo(mainFrame); setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE); + + // Add key bindings for Enter key to select patient + queueTable.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "selectPatient"); + queueTable.getActionMap().put("selectPatient", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + int selectedRow = queueTable.getSelectedRow(); + if (selectedRow != -1) { + // Simulate the mouse click logic + SwingUtilities.invokeLater(() -> { + String newlySelectedCheckupId = (String) queueTableModel.getValueAt(selectedRow, 0); + + // Check for unsaved changes before switching + if (selectedCheckupId != null && !selectedCheckupId.equals(newlySelectedCheckupId) && !saved) { + int confirm = JOptionPane.showConfirmDialog( + QueueManagementPage.this, + "Các thay đổi chưa được lưu. Bạn có chắc chắn muốn chuyển sang bệnh nhân khác không?", + "Xác nhận chuyển bệnh nhân", + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE); + if (confirm == JOptionPane.NO_OPTION) { + return; + } + } + // Call the parent class's method to handle the selection + CheckUpPage.this.handleRowSelection(getSelectedRow()); + // Reset patient name filter when closing dialog after selection + patientNameFilter.setText(""); + applyFilters(); + // Hide the dialog after selection + QueueManagementPage.this.setVisible(false); + }); + } + } + }); + + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + // Same logic as windowClosing event to ensure filters are cleared + patientNameFilter.setText(""); + applyFilters(); + setVisible(false); + } + }); + } + + private JPanel createFilterPanel() { + JPanel filterPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10)); + filterPanel.setBorder(BorderFactory.createTitledBorder( + BorderFactory.createEtchedBorder(), + "Bộ lọc", + TitledBorder.LEADING, TitledBorder.TOP, + new Font("Arial", Font.BOLD, 16), + new Color(63, 81, 181) + )); + filterPanel.setBackground(Color.WHITE); + + // Checkup Type Filter + JLabel checkupTypeLabel = new JLabel("Loại khám:"); + checkupTypeLabel.setFont(new Font("Arial", Font.BOLD, 14)); + filterPanel.add(checkupTypeLabel); + + checkupTypeFilter = new JComboBox<>(new String[]{"Tất cả", "BỆNH", "THAI", "KHÁC"}); + checkupTypeFilter.setFont(new Font("Arial", Font.PLAIN, 14)); + checkupTypeFilter.setPreferredSize(new Dimension(120, 30)); + checkupTypeFilter.addActionListener(e -> applyFilters()); + filterPanel.add(checkupTypeFilter); + + // Separator + filterPanel.add(Box.createHorizontalStrut(20)); + + // Patient Name Filter + JLabel nameLabel = new JLabel("Tên bệnh nhân:"); + nameLabel.setFont(new Font("Arial", Font.BOLD, 14)); + filterPanel.add(nameLabel); + + patientNameFilter = new JTextField(15); + patientNameFilter.setFont(new Font("Arial", Font.PLAIN, 14)); + patientNameFilter.setPreferredSize(new Dimension(200, 30)); + patientNameFilter.addKeyListener(new java.awt.event.KeyAdapter() { + @Override + public void keyReleased(java.awt.event.KeyEvent evt) { + applyFilters(); + } + }); + filterPanel.add(patientNameFilter); + + // Clear Filter Button + filterPanel.add(Box.createHorizontalStrut(20)); + JButton clearButton = new JButton("Xóa bộ lọc"); + clearButton.setFont(new Font("Arial", Font.BOLD, 14)); + clearButton.setBackground(new Color(255, 152, 0)); + clearButton.setForeground(Color.WHITE); + clearButton.setFocusPainted(false); + clearButton.addActionListener(e -> clearFilters()); + filterPanel.add(clearButton); + + return filterPanel; + } + + private void applyFilters() { + String selectedCheckupType = (String) checkupTypeFilter.getSelectedItem(); + String nameFilter = patientNameFilter.getText().trim(); + + filteredPatients = patientQueue.stream() + .filter(patient -> { + // Filter by checkup type + if (!"Tất cả".equals(selectedCheckupType)) { + if (!selectedCheckupType.equals(patient.getCheckupType())) { + return false; + } + } + + // Filter by patient first name (using remove accents) + if (!nameFilter.isEmpty()) { + String patientFirstName = patient.getCustomerFirstName(); + if (patientFirstName == null) { + return false; + } + String normalizedPatientName = TextUtils.removeAccents(patientFirstName.toLowerCase()); + String normalizedFilter = TextUtils.removeAccents(nameFilter.toLowerCase()); + if (!normalizedPatientName.contains(normalizedFilter)) { + return false; + } + } + + return true; + }) + .collect(Collectors.toList()); + + // Update table with filtered data + String[] columns = {"Mã khám bệnh", "Ngày khám", "Ngày sinh", "Họ", "Tên", "Bác Sĩ", "Loại khám"}; + queueTableModel.setDataVector(preprocessPatientDataForTable(filteredPatients), columns); + + // Recreate row sorter with date comparator after data update + TableRowSorter sorter = new TableRowSorter<>(queueTableModel); + + // Set up date comparator for column 1 (Ngày khám) and column 2 (Ngày sinh) + sorter.setComparator(1, createDateComparator()); // Checkup Date + sorter.setComparator(2, createDateComparator()); // Date of Birth + + queueTable.setRowSorter(sorter); + + // Apply sorting by checkup date + List sortKeys = new ArrayList<>(); + sortKeys.add(new RowSorter.SortKey(1, SortOrder.ASCENDING)); + sorter.setSortKeys(sortKeys); + + // Auto-select first row after applying filters + if (queueTable.getRowCount() > 0) { + queueTable.setRowSelectionInterval(0, 0); + queueTable.requestFocusInWindow(); // Ensure table gets focus + } + } + + private void clearFilters() { + checkupTypeFilter.setSelectedIndex(0); // "Tất cả" + patientNameFilter.setText(""); + applyFilters(); } private int findRowByCheckupId(String checkupId) { @@ -3006,10 +3357,11 @@ public class CheckUpPage extends JPanel { */ public void updateQueueTable() { SwingUtilities.invokeLater(() -> { - String[] columns = {"Mã khám bệnh", "Ngày sinh", "Họ", "Tên", "Bác Sĩ", "Loại khám"}; String previouslySelectedId = CheckUpPage.this.selectedCheckupId; - queueTableModel.setDataVector(preprocessPatientDataForTable(patientQueue), columns); + // Update filtered patients list and apply current filters + filteredPatients = new ArrayList<>(patientQueue); + applyFilters(); // This will update the table with filtered data and apply sorting if (previouslySelectedId != null) { int rowToSelect = findRowByCheckupId(previouslySelectedId); @@ -3020,17 +3372,44 @@ public class CheckUpPage extends JPanel { // The previously selected patient is no longer in the queue (e.g., status changed to "ĐÃ KHÁM") // Clear the details panel to avoid confusion clearPatientDetails(); + // Auto-select first row if available + if (queueTable.getRowCount() > 0) { + queueTable.setRowSelectionInterval(0, 0); + } + } + } else { + // No previously selected patient, auto-select first row if available + if (queueTable.getRowCount() > 0) { + queueTable.setRowSelectionInterval(0, 0); } } + + // Ensure table gets focus for keyboard navigation + queueTable.requestFocusInWindow(); }); } /** * Gets the currently selected row from the queue table. - * @return the selected row index, or -1 if no row is selected. + * @return the selected row index in the original patient queue, or -1 if no row is selected. */ public int getSelectedRow() { - return queueTable.getSelectedRow(); + int selectedRowInTable = queueTable.getSelectedRow(); + if (selectedRowInTable == -1 || selectedRowInTable >= filteredPatients.size()) { + return -1; + } + + // Get the patient from the filtered list + Patient selectedPatient = filteredPatients.get(selectedRowInTable); + + // Find the corresponding index in the original patient queue + for (int i = 0; i < patientQueue.size(); i++) { + if (patientQueue.get(i).getCheckupId().equals(selectedPatient.getCheckupId())) { + return i; + } + } + + return -1; } } @@ -3214,12 +3593,15 @@ public class CheckUpPage extends JPanel { log.info("servicePrescription: {}", (Object) servicePrescription); log.info("reCheckupDate: {}", reCheckupDate); log.info("customerCccdDdcn: {}", customerCccdDdcn); + log.info("heartBeat: {}", patientHeartRateSpinner.getValue()); + log.info("bloodPressure: {}", bloodPressureSystolicSpinner.getValue() + "/" + bloodPressureDiastolicSpinner.getValue()); log.info("=== End SaveCheckupRequest Data ==="); - + String bloodPressure = bloodPressureSystolicSpinner.getValue() + "/" + bloodPressureDiastolicSpinner.getValue(); Long customerDobLong = DateUtils.convertToDate(customerDob).getTime(); Long reCheckupDateLong = DateUtils.convertToDate(reCheckupDate).getTime(); Long checkupDateLong = DateUtils.convertToDate(checkupDate).getTime(); + Integer heartBeat = (Integer) patientHeartRateSpinner.getValue(); SaveCheckupRequest request = new SaveCheckupRequest( Integer.parseInt(checkupId), Integer.parseInt(customerId), @@ -3241,6 +3623,8 @@ public class CheckUpPage extends JPanel { Double.parseDouble(customerWeight), Double.parseDouble(customerHeight), customerCccdDdcn, + heartBeat, + bloodPressure, medicinePrescription, servicePrescription ); diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/HistoryViewDialog/HistoryViewDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/HistoryViewDialog/HistoryViewDialog.java index c0e1b2b..10c3262 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/HistoryViewDialog/HistoryViewDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/HistoryViewDialog/HistoryViewDialog.java @@ -185,6 +185,18 @@ public class HistoryViewDialog extends JDialog { mainPanel.add(centerPanel, BorderLayout.CENTER); add(mainPanel, BorderLayout.CENTER); + + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); } private JPanel createHeaderPanel() { diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java index 754276e..5b4173c 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/MedicineDialog/MedicineDialog.java @@ -197,6 +197,18 @@ public class MedicineDialog extends JDialog { mainGbc.weighty = 1.0; mainInputPanel.add(new JPanel(), mainGbc); + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; @@ -463,6 +475,14 @@ public class MedicineDialog extends JDialog { getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F1"), "addMedicineAction"); getRootPane().getActionMap().put("addMedicineAction", addAction); + medicineNameField.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + isSelectionLocked = false; + showOrUpdateSuggestions(); + } + }); + medicineNameField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { if (!isProgrammaticallySettingMedicineNameField) { @@ -614,7 +634,7 @@ public class MedicineDialog extends JDialog { return; } - if (filterText.isEmpty()) { + if (filterText.isEmpty() && !medicineNameField.isFocusOwner()) { suggestionPopup.setVisible(false); return; } @@ -624,7 +644,7 @@ public class MedicineDialog extends JDialog { String lowerCaseFilterText = TextUtils.removeAccents(filterText.toLowerCase()); for (Medicine med : medicines) { - if (TextUtils.removeAccents(med.getName().toLowerCase()).contains(lowerCaseFilterText)) { + if (filterText.isEmpty() || TextUtils.removeAccents(med.getName().toLowerCase()).contains(lowerCaseFilterText)) { filteredMedicines.add(med); filteredDisplayData.add(new String[]{ med.getName(), diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java index 1a5939b..0daa3f9 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/ServiceDialog/ServiceDialog.java @@ -172,6 +172,18 @@ public class ServiceDialog extends JDialog { mainGbc.weighty = 1.0; mainInputPanel.add(new JPanel(), mainGbc); + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + GridBagConstraints gbc = new GridBagConstraints(); gbc.fill = GridBagConstraints.HORIZONTAL; gbc.anchor = GridBagConstraints.WEST; @@ -352,6 +364,14 @@ public class ServiceDialog extends JDialog { getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("F1"), "addServiceAction"); getRootPane().getActionMap().put("addServiceAction", addAction); + serviceNameField.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + isSelectionLocked = false; + showOrUpdateSuggestions(); + } + }); + serviceNameField.getDocument().addDocumentListener(new DocumentListener() { public void changedUpdate(DocumentEvent e) { if (!isProgrammaticallySettingNameField) { @@ -496,7 +516,7 @@ public class ServiceDialog extends JDialog { return; } - if (filterText.isEmpty()) { + if (filterText.isEmpty() && !serviceNameField.isFocusOwner()) { suggestionPopup.setVisible(false); return; } @@ -506,7 +526,7 @@ public class ServiceDialog extends JDialog { String lowerCaseFilterText = TextUtils.removeAccents(filterText.toLowerCase()); for (Service service : services) { - if (TextUtils.removeAccents(service.getName().toLowerCase()).contains(lowerCaseFilterText)) { + if (filterText.isEmpty() || TextUtils.removeAccents(service.getName().toLowerCase()).contains(lowerCaseFilterText)) { filteredServices.add(service); filteredDisplayData.add(service.toStringArray()); } @@ -531,7 +551,6 @@ public class ServiceDialog extends JDialog { serviceNameField.requestFocusInWindow(); } else { suggestionPopup.setVisible(false); - clearInputFields(); } } diff --git a/src/main/java/BsK/client/ui/component/CheckUpPage/TemplateDialog/TemplateDialog.java b/src/main/java/BsK/client/ui/component/CheckUpPage/TemplateDialog/TemplateDialog.java index 44adf6c..b4be35e 100644 --- a/src/main/java/BsK/client/ui/component/CheckUpPage/TemplateDialog/TemplateDialog.java +++ b/src/main/java/BsK/client/ui/component/CheckUpPage/TemplateDialog/TemplateDialog.java @@ -34,6 +34,7 @@ import java.util.List; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.JColorChooser; +import java.awt.event.KeyEvent; @Slf4j public class TemplateDialog extends JDialog { @@ -190,6 +191,18 @@ public class TemplateDialog extends JDialog { mainSplitPane.setRightComponent(rightPanel); add(mainSplitPane, BorderLayout.CENTER); + + // Add Escape key listener to close dialog + JRootPane rootPane = this.getRootPane(); + InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "ESCAPE"); + ActionMap actionMap = rootPane.getActionMap(); + actionMap.put("ESCAPE", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); } private JPanel createLeftPanel() { diff --git a/src/main/java/BsK/client/ui/component/common/DateLabelFormatter.java b/src/main/java/BsK/client/ui/component/common/DateLabelFormatter.java index 00670a8..c8a3f98 100644 --- a/src/main/java/BsK/client/ui/component/common/DateLabelFormatter.java +++ b/src/main/java/BsK/client/ui/component/common/DateLabelFormatter.java @@ -14,8 +14,42 @@ public class DateLabelFormatter extends JFormattedTextField.AbstractFormatter { private String datePattern = "dd/MM/yyyy"; private SimpleDateFormat dateFormatter = new SimpleDateFormat(datePattern, Locale.ENGLISH); + public DateLabelFormatter() { + // Enable lenient parsing to be more flexible with user input + dateFormatter.setLenient(false); + } + @Override public Object stringToValue(String text) throws ParseException { + if (text == null || text.trim().isEmpty()) { + return null; + } + + // Clean up the input text + text = text.trim(); + + // Handle different input formats that users might type + if (text.matches("\\d{1,2}/\\d{1,2}/\\d{4}")) { + // Standard format: dd/mm/yyyy or d/m/yyyy + return dateFormatter.parseObject(text); + } else if (text.matches("\\d{1,2}-\\d{1,2}-\\d{4}")) { + // Handle dash format: dd-mm-yyyy + text = text.replace("-", "/"); + return dateFormatter.parseObject(text); + } else if (text.matches("\\d{1,2}\\.\\d{1,2}\\.\\d{4}")) { + // Handle dot format: dd.mm.yyyy + text = text.replace(".", "/"); + return dateFormatter.parseObject(text); + } else if (text.matches("\\d{8}")) { + // Handle compact format: ddmmyyyy + String day = text.substring(0, 2); + String month = text.substring(2, 4); + String year = text.substring(4, 8); + text = day + "/" + month + "/" + year; + return dateFormatter.parseObject(text); + } + + // If none of the formats match, try default parsing return dateFormatter.parseObject(text); } diff --git a/src/main/java/BsK/common/entity/Patient.java b/src/main/java/BsK/common/entity/Patient.java index 0b9e80e..32c915f 100644 --- a/src/main/java/BsK/common/entity/Patient.java +++ b/src/main/java/BsK/common/entity/Patient.java @@ -27,6 +27,8 @@ public class Patient { private String conclusion; private String reCheckupDate; private String cccdDdcn; + private String heartBeat; + private String bloodPressure; public Patient(String[][] array) { @@ -49,15 +51,15 @@ public class Patient { this.checkupType = array[0][16]; this.conclusion = array[0][17]; this.reCheckupDate = array[0][18]; - if (array[0].length > 19) { - this.cccdDdcn = array[0][19]; - } + this.cccdDdcn = array[0][19]; + this.heartBeat = array[0][20]; + this.bloodPressure = array[0][21]; } // New constructor for a single patient data row public Patient(String[] data) { - if (data.length < 19) { - throw new IllegalArgumentException("Patient data array must contain at least 19 elements to include a conclusion."); + if (data.length < 22) { + throw new IllegalArgumentException("Patient data array must contain at least 22 elements to include a conclusion."); } this.checkupId = data[0]; this.checkupDate = data[1]; @@ -78,8 +80,8 @@ public class Patient { this.checkupType = data[16]; this.conclusion = data[17]; this.reCheckupDate = data[18]; - if (data.length > 19) { - this.cccdDdcn = data[19]; - } + this.cccdDdcn = data[19]; + this.heartBeat = data[20]; + this.bloodPressure = data[21]; } } diff --git a/src/main/java/BsK/common/packet/req/AddCheckupRequest.java b/src/main/java/BsK/common/packet/req/AddCheckupRequest.java index 080ca41..ff3a07f 100644 --- a/src/main/java/BsK/common/packet/req/AddCheckupRequest.java +++ b/src/main/java/BsK/common/packet/req/AddCheckupRequest.java @@ -12,4 +12,5 @@ public class AddCheckupRequest implements Packet { int doctorId; int processedById; String checkupType; + String status; } diff --git a/src/main/java/BsK/common/packet/req/SaveCheckupRequest.java b/src/main/java/BsK/common/packet/req/SaveCheckupRequest.java index ea371f2..1429100 100644 --- a/src/main/java/BsK/common/packet/req/SaveCheckupRequest.java +++ b/src/main/java/BsK/common/packet/req/SaveCheckupRequest.java @@ -32,6 +32,8 @@ public class SaveCheckupRequest implements Packet { Double customerWeight; Double customerHeight; String customerCccdDdcn; + Integer heartBeat; + String bloodPressure; // format as string 0/0 // Prescriptions String[][] medicinePrescription; diff --git a/src/main/java/BsK/common/util/date/DateUtils.java b/src/main/java/BsK/common/util/date/DateUtils.java index 7228e5a..30e6179 100644 --- a/src/main/java/BsK/common/util/date/DateUtils.java +++ b/src/main/java/BsK/common/util/date/DateUtils.java @@ -77,6 +77,7 @@ public class DateUtils { } else { // Try to parse as dd/MM/yyyy format return DISPLAY_FORMAT.parse(dateInput); + } } catch (NumberFormatException | ParseException e) { System.err.println("Invalid date format: " + dateInput); @@ -112,6 +113,7 @@ public class DateUtils { System.out.println("Display format: " + convertToDisplayFormat(validTimestamp)); System.out.println("Display format: " + convertToDisplayFormat("15/06/2023")); System.out.println("Date object: " + convertToDate(validTimestamp)); - System.out.println("Date object: " + convertToDate("15/06/2023")); + System.out.println("Date object: " + convertToDate("15-06-2023")); + } } diff --git a/src/main/java/BsK/server/network/handler/ServerHandler.java b/src/main/java/BsK/server/network/handler/ServerHandler.java index bbc065c..039e232 100644 --- a/src/main/java/BsK/server/network/handler/ServerHandler.java +++ b/src/main/java/BsK/server/network/handler/ServerHandler.java @@ -110,7 +110,7 @@ public class ServerHandler extends SimpleChannelInboundHandler?zC_DfFmg2pqs)G#6AK88o zDMtDqqD%U^0$s9>TADe@Y%ZEN-p!t1{NULPR+FV^%$FDe2ib=J*e&R005Bu+&;tGo znRpM++tu_kE7gFI-7Mk9CMq0KUSoRjeVl@Jb!wMI=W}e$clpy-=Wsujrc1d3w@uQm zf6G1iA)eB?wdR8KQ3DHz9_@6Vl9LnnC&)}lbRVZx|7V`i}W93kahR*Dj0ISI81z-`o0Xl`^;vv*7rjZA|B+iSM#BQ-Zi&eYW>0NHEpeF$U zmji;J8mzBT8)|ApPE%(j);|~<*cuxR5B9TO`G#ta@2UChnIkDk(jb+FcwvVjl32NX^qr_V56#K4*zo7iVmXy z+z#Cd56~n~@Or~Y_}<8Hcqjsy-*zh?^Ql~&*|slgpeJZY=B<6(XmtR+-Rxq#emBtM zMP_S0-U92wzI(Ed|LW;toA6)Zq(Fp+`3D4zzrrj0Tl9^6Zq3Mt{wg$EA^mJx1ryCc zRi@=dZ}##bxsQ|=!!iTSd_=q0c}GO8rvVe-f+yi4!?S<`4ZZs~qxh_vKzDf!)LTvXSd zJ9a#w4CRX&JP>NSH`NcG>(uH3YE!9ApA&#bMuLzZCCmtt(CT?W-uxI>xYR}|ufTd% zQ3aYQebQJ|SU86jml|63tpYXh0|hr#D7le>R=Nw2&F86yf%BMit5eS661`8cJvFqK z=Izj(^g6O8m3VL~iO8?GB`zPgBaQfb;HP$`{0 zwn%ulu*4nz4DW>%s_r=to(0Gx%=6FRp1Y=R`RXzY)xX) z9srNgiZW{1bJs?b-S20f^pc%6+t%haZR^`Qx)h~9vLl=vN+^}BEnB)O#}e@!iNWDW zrO!L&t5$rmkw<-grDcmkb=R$5_Y=QTrPQjb>d#)hd_N>t?Y0$URhg}lJg6^E(8aJe zoQPyj4x8N?jfCTgp590}p^%WnR_^N^8X4*D8I4EA#**=fqI9kMDRt$V zGd?w-`YitG*%I5`j6NoW$=8zYzOp^Fi$S;&;ohM=9{SJaVxDwmp1Qo|rbgubzapCc zxx@BM5xRZHxyA1|vxNf6ag#sj;@l*Aj@bx~(r@nh=@akbH_hz1&9dpb7IlYhHO=}ii%-vFE}&&&V- delta 3032 zcmeHIeQXqE8h_uJ{hIB(^X|-a_OsiaWhrg1tUJ3~=m*uywumKsNwku?oV3e!4^Uc2 zEy0VT&8&*?q@b^t$*H*m%_Uxg0@=$oP3;{yIQ&dB)<2AzOTpX`Dp3haOn~Y;v)fXX z)0p^|akIbf>^{HudEV#ud~|4N<~h&b6l?%#ME<#VU3D)jfRF;2s2Ht}fOPow zEvLqRuXe0GHGa4iJVU02I~%&}0*C}46QSo~Agz=ro!hf3@_pHD`3x9IwzO#Rq!w=` zso}-dn{6eRb~#$V1f=B>f4S+h2^=8z4X^6N!=S;8YNt^{ARV|iD!4q^cmQPDwPY&Y z_&bO}K(?s0wb68>=8hAEel@c;+t)^&J-2UTT`x120-%g?3hib*4g4wDlF%9xDNSo4 zXCA+45mjrzbVu{G+|BoqsjxUVSobYaq$ zSXFmpMGYH*9b59byLayJxiK4n%eUtSw-4C(MQj*$?7U}idtZLQL8cO6=qt`7ST!JA z1}>oh@OyYbI3&D_R|y3i!-s_eEz(wjsr8Yg-3obnW9zy_l@(D)UnmqnD5a&A#I+{+ zj@lUJ)_i~O*8a_1{X4Q-d+`XU{WdR!Dj3^*UNP4FA62ILJJ1n;AH#LRNg*o;=m-t` zEFwqtZmeBzN3_zjbq3!k^fgr`+2Opched$AKD=>Z4})kIQBAD^ln+`JxK{q+WBZ=; zNc`*QJUW34bQk|Cl;&r6m0sb~3KBl_5=vD-0J#q2qr6Q z_+xw=zkxr(7w{zh0FTp(9>jj9jjAZP1nbj-Jl1E_R=H;~0Vx;?mcmA1r*Kd>DO?mB zg`1*+f~PrV*!Ph&gCM9s}%A~NMh1y116`rylsqw$`Z@y#e@sU1N zuVHAi5PnZ_#Da&jcU8=ZT0#FbG{8qY2D6*CjZVnYGRC&Yc8k-v ztVrv=&x`4E2}>gy$9z(~k&8$&xjci(&Sf EHBfoHvH$=8