[update] Enhance logging and UI components in Client and CheckUpPage. Add welcome message in Client's main method and log selected doctor's name in CheckUpPage. Improve row selection handling in CheckUpPage to ensure accurate data retrieval and display. Update DashboardPage greeting for better user experience.

This commit is contained in:
Lê Thành Đạt committed 2025-07-30 02:34:37 +07:00
1 parent 1d66cb16af
commit a43e6501d2
33 files changed
+332 -329

No files matched your search

+2
View File
@@ -74,6 +74,8 @@ public class Client {
}
public static void main(String[] args) throws Exception {
log.info("\n____ _____ _ __\n| _ \\ / ____| |/\n| |_) | (___ | ' /\n| _ < \\___ \\| <\n| |_) |____) | . \\\n|____/|_____/|_|\\_\n");
var thread = new Thread(() -> {
// First try to load from external config file
File externalConfig = new File("config/config.properties");
@@ -2201,6 +2201,7 @@ public class CheckUpPage extends JPanel {
customerFirstNameField.setText(selectedPatient.getCustomerFirstName());
// Select doctor by name
log.info("Selected patient's doctor name: {}", selectedPatient.getDoctorName());
DoctorItem doctorToSelect = findDoctorByName(selectedPatient.getDoctorName());
if (doctorToSelect != null) {
doctorComboBox.setSelectedItem(doctorToSelect);
@@ -2213,7 +2214,8 @@ public class CheckUpPage extends JPanel {
if (ultrasoundDoctorToSelect != null) {
ultrasoundDoctorComboBox.setSelectedItem(ultrasoundDoctorToSelect);
} else if (ultrasoundDoctorComboBox.getItemCount() > 0) {
ultrasoundDoctorComboBox.setSelectedIndex(0);
// if no ultrasound doctor by default it se to the same doctor as the main doctor
ultrasoundDoctorComboBox.setSelectedItem(doctorToSelect);
log.warn("Ultrasound Doctor '{}' not found in the list for patient selection.", selectedPatient.getDoctorUltrasoundId());
}
@@ -4194,7 +4196,9 @@ public class CheckUpPage extends JPanel {
SwingUtilities.invokeLater(() -> {
int selectedRow = queueTable.getSelectedRow();
if (selectedRow != -1) {
String newlySelectedCheckupId = (String) queueTableModel.getValueAt(selectedRow, 0);
// Convert view index to model index to handle sorting
int modelRow = queueTable.convertRowIndexToModel(selectedRow);
String newlySelectedCheckupId = (String) queueTableModel.getValueAt(modelRow, 1); // Column 1 is Checkup ID
// Check for unsaved changes before switching
if (selectedCheckupId != null && !selectedCheckupId.equals(newlySelectedCheckupId) && !saved) {
@@ -4213,8 +4217,8 @@ public class CheckUpPage extends JPanel {
return;
}
}
// Call the parent class's method to handle the selection
CheckUpPage.this.handleRowSelection(getSelectedRow());
// Call the parent class's method to handle the selection with the model row index
CheckUpPage.this.handleRowSelection(modelRow);
// Reset patient name filter when closing dialog after selection
patientNameFilter.setText("");
applyFilters();
@@ -4242,7 +4246,9 @@ public class CheckUpPage extends JPanel {
if (selectedRow != -1) {
// Simulate the mouse click logic
SwingUtilities.invokeLater(() -> {
String newlySelectedCheckupId = (String) queueTableModel.getValueAt(selectedRow, 0);
// Convert view index to model index to handle sorting
int modelRow = queueTable.convertRowIndexToModel(selectedRow);
String newlySelectedCheckupId = (String) queueTableModel.getValueAt(modelRow, 1); // Column 1 is Checkup ID
// Check for unsaved changes before switching
if (selectedCheckupId != null && !selectedCheckupId.equals(newlySelectedCheckupId) && !saved) {
@@ -4253,11 +4259,16 @@ public class CheckUpPage extends JPanel {
JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE);
if (confirm == JOptionPane.NO_OPTION) {
// Reselect the previous row visually to avoid confusion
int previousRow = findRowByCheckupId(selectedCheckupId);
if (previousRow != -1) {
queueTable.setRowSelectionInterval(previousRow, previousRow);
}
return;
}
}
// Call the parent class's method to handle the selection
CheckUpPage.this.handleRowSelection(getSelectedRow());
// Call the parent class's method to handle the selection with the model row index
CheckUpPage.this.handleRowSelection(modelRow);
// Reset patient name filter when closing dialog after selection
patientNameFilter.setText("");
applyFilters();
@@ -4447,21 +4458,10 @@ public class CheckUpPage extends JPanel {
* @return the selected row index in the original patient queue, or -1 if no row is selected.
*/
public int getSelectedRow() {
int selectedRowInTable = queueTable.getSelectedRow();
if (selectedRowInTable == -1 || selectedRowInTable >= filteredPatients.size()) {
return -1;
int selectedRow = queueTable.getSelectedRow();
if (selectedRow != -1) {
return queueTable.convertRowIndexToModel(selectedRow);
}
// 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;
}
}
@@ -163,7 +163,7 @@ public class DashboardPage extends JPanel {
JPanel headerPanel = new JPanel(new BorderLayout());
headerPanel.setOpaque(false);
headerPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 20, 0));
JLabel welcomeLabel = new JLabel("Chào mừng, " + LocalStorage.username);
JLabel welcomeLabel = new JLabel("Xin chào, " + LocalStorage.username);
welcomeLabel.setFont(new Font("Segoe UI", Font.BOLD, 28));
welcomeLabel.setForeground(new Color(44, 82, 130));
lastUpdateLabel = new JLabel("Cập nhật lần cuối: " + getCurrentTime());
@@ -13,6 +13,7 @@ import javax.swing.border.EmptyBorder;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableRowSorter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.net.URLEncoder;
@@ -29,6 +30,8 @@ import BsK.common.packet.req.GetRecheckUpListRequest;
import BsK.common.packet.res.GetRecheckUpListResponse;
import BsK.client.network.handler.ResponseListener;
import BsK.common.packet.req.AddRemindDateRequest;
public class RecheckUpDialog extends JDialog {
private JTable recheckTable;
@@ -40,6 +43,8 @@ public class RecheckUpDialog extends JDialog {
private JTextArea previewMessageArea;
private JCheckBox includeTemplateCheckbox;
private JTextArea deepLinkTextArea;
private int currentCheckUpId = 0;
// NEW: Fields for filtering functionality
private JComboBox<String> dateFilterComboBox;
@@ -103,7 +108,7 @@ public class RecheckUpDialog extends JDialog {
JLabel filterLabel = new JLabel("Lọc theo ngày tái khám: ");
filterLabel.setFont(new Font("Segoe UI", Font.BOLD, 14));
String[] filterOptions = {"Tất cả", "Hôm nay", "Ngày mai", "Trong 2 ngày tới", "Trong 3 ngày tới", "Trong 1 tuần tới"};
String[] filterOptions = {"Hôm nay", "Ngày mai", "Trong 2 ngày tới", "Trong 3 ngày tới", "Trong 1 tuần tới"};
dateFilterComboBox = new JComboBox<>(filterOptions);
dateFilterComboBox.setFont(new Font("Segoe UI", Font.PLAIN, 14));
dateFilterComboBox.addActionListener(e -> filterAndDisplayTableData());
@@ -119,11 +124,17 @@ public class RecheckUpDialog extends JDialog {
private JPanel createTablePanel() {
JPanel tablePanel = new JPanel(new BorderLayout());
tablePanel.setOpaque(false);
String[] columnNames = {"Họ và tên", "Số điện thoại", "Ngày tái khám", "Ngày nhắc"};
String[] columnNames = {"Họ và tên", "Số điện thoại", "Ngày tái khám", "Ngày nhắc", "ID"};
tableModel = new DefaultTableModel(columnNames, 0) {
public boolean isCellEditable(int row, int column) { return false; }
};
recheckTable = new JTable(tableModel);
recheckTable.setRowSorter(new TableRowSorter<>(tableModel));
recheckTable.getColumnModel().getColumn(4).setMinWidth(0);
recheckTable.getColumnModel().getColumn(4).setMaxWidth(0);
recheckTable.getColumnModel().getColumn(4).setWidth(0);
recheckTable.setRowHeight(30);
recheckTable.setFont(new Font("Segoe UI", Font.PLAIN, 14));
recheckTable.getTableHeader().setFont(new Font("Segoe UI", Font.BOLD, 14));
@@ -230,9 +241,22 @@ public class RecheckUpDialog extends JDialog {
});
JButton generateButton = new JButton("Tạo Tin & QR");
generateButton.setFont(new Font("Segoe UI", Font.BOLD, 12));
generateButton.addActionListener(e -> generateMessageAndQr());
generateButton.addActionListener(e -> {
generateMessageAndQr();
});
JButton addRemindDateButton = new JButton("Lưu ngày nhắc");
addRemindDateButton.setFont(new Font("Segoe UI", Font.BOLD, 12));
addRemindDateButton.addActionListener(e -> {
if (currentCheckUpId != 0) {
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new AddRemindDateRequest(String.valueOf(currentCheckUpId)));
} else {
JOptionPane.showMessageDialog(this, "Vui lòng chọn một bệnh nhân.", "Chưa chọn bệnh nhân", JOptionPane.WARNING_MESSAGE);
}
});
buttonPanel.add(resetButton);
buttonPanel.add(generateButton);
buttonPanel.add(addRemindDateButton);
rightPanel.add(buttonPanel, BorderLayout.SOUTH);
return rightPanel;
@@ -249,7 +273,7 @@ public class RecheckUpDialog extends JDialog {
String selectedFilter = (String) dateFilterComboBox.getSelectedItem();
if (selectedFilter == null) {
selectedFilter = "Tất cả"; // Default case
selectedFilter = "Hôm nay"; // Default case
}
LocalDate today = LocalDate.now();
@@ -262,9 +286,6 @@ public class RecheckUpDialog extends JDialog {
boolean shouldAddRow = false;
switch (selectedFilter) {
case "Tất cả":
shouldAddRow = true;
break;
case "Hôm nay":
shouldAddRow = recheckDate.isEqual(today);
break;
@@ -289,36 +310,48 @@ public class RecheckUpDialog extends JDialog {
} catch (DateTimeParseException e) {
System.err.println("Could not parse date string: " + dateString);
// If the filter is "All", add rows with unparseable dates so they are not lost
if ("Tất cả".equals(selectedFilter)) {
if ("Hôm nay".equals(selectedFilter)) {
tableModel.addRow(row);
}
}
}
}
private int getSelectedModelRow() {
int viewRow = recheckTable.getSelectedRow();
if (viewRow != -1) {
return recheckTable.convertRowIndexToModel(viewRow);
}
return -1;
}
private void handleTableSelectionChange() {
clearRightPanel();
int selectedRow = recheckTable.getSelectedRow();
if (selectedRow != -1) {
String sdt = (String) tableModel.getValueAt(selectedRow, 1);
int modelRow = getSelectedModelRow();
if (modelRow != -1) {
currentCheckUpId = Integer.parseInt((String) tableModel.getValueAt(modelRow, 4));
String sdt = (String) tableModel.getValueAt(modelRow, 1);
sdtDisplayField.setText(sdt);
updatePreview();
} else {
currentCheckUpId = 0;
}
}
private void updatePreview() {
int selectedRow = recheckTable.getSelectedRow();
if (selectedRow == -1) {
int modelRow = getSelectedModelRow();
if (modelRow == -1) {
templateArea.setText("");
previewMessageArea.setText("");
return;
}
String patientName = (String) tableModel.getValueAt(selectedRow, 0);
String recheckDate = (String) tableModel.getValueAt(selectedRow, 2);
String patientName = (String) tableModel.getValueAt(modelRow, 0);
String recheckDate = (String) tableModel.getValueAt(modelRow, 2);
String customContent = contentInputArea.getText();
String templateText = String.format("Phòng khám Bs.K xin thông báo: Anh/Chị %s có lịch tái khám vào ngày %s.", patientName, recheckDate);
String templateText = String.format("Phòng khám Bs.Khắp xin thông báo: Anh/Chị %s có lịch tái khám vào ngày %s.", patientName, recheckDate);
templateArea.setText(templateText);
String fullMessage;
@@ -331,13 +364,13 @@ public class RecheckUpDialog extends JDialog {
}
private void generateMessageAndQr() {
int selectedRow = recheckTable.getSelectedRow();
if (selectedRow == -1) {
int modelRow = getSelectedModelRow();
if (modelRow == -1) {
JOptionPane.showMessageDialog(this, "Vui lòng chọn một bệnh nhân.", "Chưa chọn bệnh nhân", JOptionPane.WARNING_MESSAGE);
return;
}
String sdt = (String) tableModel.getValueAt(selectedRow, 1);
String sdt = (String) tableModel.getValueAt(modelRow, 1);
String messageBody = previewMessageArea.getText();
if (messageBody.isEmpty()) {
@@ -1,5 +1,7 @@
package BsK.client.ui.component.DataDialog;
import BsK.client.ui.component.common.AddDialog.AddDialog;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
@@ -28,6 +30,9 @@ public class DataDialog extends JDialog {
private int recordsPerPage = 20;
private int totalRecords = 157;
private JPanel mainPanel;
private JPanel paginationPanel;
public DataDialog(JFrame parent) {
super(parent, "Quản Lý Dữ Liệu Khám Bệnh", true);
initializeDialog();
@@ -41,13 +46,14 @@ public class DataDialog extends JDialog {
setLayout(new BorderLayout());
// Create main panel with padding
JPanel mainPanel = new JPanel(new BorderLayout());
mainPanel = new JPanel(new BorderLayout());
mainPanel.setBorder(new EmptyBorder(20, 20, 20, 20));
// Add components
mainPanel.add(createControlPanel(), BorderLayout.NORTH);
mainPanel.add(createDataGridPanel(), BorderLayout.CENTER);
mainPanel.add(createPaginationPanel(), BorderLayout.SOUTH);
paginationPanel = createPaginationPanel();
mainPanel.add(paginationPanel, BorderLayout.SOUTH);
add(mainPanel);
}
@@ -130,7 +136,8 @@ public class DataDialog extends JDialog {
// Add action listeners
addNewButton.addActionListener(e -> {
JOptionPane.showMessageDialog(this, "Chức năng thêm mới sẽ chuyển đến trang Thăm khám với form trống", "Thông báo", JOptionPane.INFORMATION_MESSAGE);
AddDialog addDialog = new AddDialog((Frame) getParent());
addDialog.setVisible(true);
});
exportExcelButton.addActionListener(e -> {
@@ -288,11 +295,11 @@ public class DataDialog extends JDialog {
resultCountLabel.setText(String.format("Hiển thị %d đến %d của %d kết quả", startRecord, endRecord, totalRecords));
// Update pagination buttons
Component parent = firstPageButton.getParent();
parent.removeAll();
parent.add(createPaginationPanel());
parent.revalidate();
parent.repaint();
mainPanel.remove(paginationPanel);
paginationPanel = createPaginationPanel();
mainPanel.add(paginationPanel, BorderLayout.SOUTH);
mainPanel.revalidate();
mainPanel.repaint();
}
// Custom renderer for action buttons
@@ -0,0 +1,11 @@
package BsK.common.packet.req;
import BsK.common.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AddRemindDateRequest implements Packet {
private String checkupId;
}
+1
View File
@@ -265,6 +265,7 @@ public class Server {
}
public static void main(String[] args) throws InterruptedException, SQLException {
log.info("\n____ _____ _ __\n| _ \\ / ____| |/\n| |_) | (___ | ' /\n| _ < \\___ \\| <\n| |_) |____) | . \\\n|____/|_____/|_|\\_\n");
// Initialize and show server dashboard
ServerDashboard dashboard = ServerDashboard.getInstance();
dashboard.setVisible(true);
@@ -107,7 +107,7 @@ public class ServerDashboard extends JFrame {
// Create split pane for logs and network info
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
splitPane.setResizeWeight(0.6); // Give more space to the top component
splitPane.setResizeWeight(0.1); // Give more space to the top component
// Network Information Panel
JPanel networkPanel = new JPanel(new BorderLayout());
@@ -752,265 +752,195 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
if (packet instanceof SaveCheckupRequest saveCheckupRequest) {
log.debug("Received SaveCheckupRequest to save checkup {}", saveCheckupRequest.getCheckupId());
Connection conn = null;
// The connection is managed by the try-catch-finally block below
Connection conn = Server.connection;
try {
conn = Server.connection;
// Start transaction
conn.setAutoCommit(false);
// 1. Insert/Update Customer
String customerSql = """
INSERT INTO Customer (
customer_id, customer_first_name, customer_last_name, customer_dob,
customer_gender, customer_address, customer_number, cccd_ddcn
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(customer_id) DO UPDATE SET
customer_first_name = excluded.customer_first_name,
customer_last_name = excluded.customer_last_name,
customer_dob = excluded.customer_dob,
customer_gender = excluded.customer_gender,
customer_address = excluded.customer_address,
customer_number = excluded.customer_number,
cccd_ddcn = excluded.cccd_ddcn
""";
PreparedStatement customerStmt = conn.prepareStatement(customerSql);
customerStmt.setInt(1, saveCheckupRequest.getCustomerId());
customerStmt.setString(2, saveCheckupRequest.getCustomerFirstName());
customerStmt.setString(3, saveCheckupRequest.getCustomerLastName());
customerStmt.setLong(4, saveCheckupRequest.getCustomerDob());
customerStmt.setString(5, saveCheckupRequest.getCustomerGender());
customerStmt.setString(6, saveCheckupRequest.getCustomerAddress());
customerStmt.setString(7, saveCheckupRequest.getCustomerNumber());
customerStmt.setString(8, saveCheckupRequest.getCustomerCccdDdcn());
customerStmt.executeUpdate();
log.info("Customer saved successfully");
// 2. Generate prescription_id if we have medicine prescriptions
String prescriptionId = null;
if (saveCheckupRequest.getMedicinePrescription() != null &&
saveCheckupRequest.getMedicinePrescription().length > 0) {
conn.setAutoCommit(false); // Start transaction
// Get next prescription_id
String getNextIdSql = "SELECT COALESCE(MAX(prescription_id), 0) + 1 as next_id FROM MedicineOrder";
PreparedStatement nextIdStmt = conn.prepareStatement(getNextIdSql);
ResultSet rs = nextIdStmt.executeQuery();
if (rs.next()) {
prescriptionId = rs.getString("next_id");
// 1. Insert/Update Customer (Now safe with try-with-resources)
String customerSql = """
INSERT INTO Customer (
customer_id, customer_first_name, customer_last_name, customer_dob,
customer_gender, customer_address, customer_number, cccd_ddcn
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(customer_id) DO UPDATE SET
customer_first_name = excluded.customer_first_name,
customer_last_name = excluded.customer_last_name,
customer_dob = excluded.customer_dob,
customer_gender = excluded.customer_gender,
customer_address = excluded.customer_address,
customer_number = excluded.customer_number,
cccd_ddcn = excluded.cccd_ddcn
""";
try (PreparedStatement customerStmt = conn.prepareStatement(customerSql)) {
customerStmt.setInt(1, saveCheckupRequest.getCustomerId());
customerStmt.setString(2, saveCheckupRequest.getCustomerFirstName());
customerStmt.setString(3, saveCheckupRequest.getCustomerLastName());
customerStmt.setLong(4, saveCheckupRequest.getCustomerDob());
customerStmt.setString(5, saveCheckupRequest.getCustomerGender());
customerStmt.setString(6, saveCheckupRequest.getCustomerAddress());
customerStmt.setString(7, saveCheckupRequest.getCustomerNumber());
customerStmt.setString(8, saveCheckupRequest.getCustomerCccdDdcn());
customerStmt.executeUpdate();
log.info("Customer saved successfully");
}
rs.close();
nextIdStmt.close();
}
// 3. Insert/Update Checkup
String checkupSql = """
INSERT INTO Checkup (
checkup_id, customer_id, doctor_id, checkup_date,
suggestion, diagnosis, prescription_id, notes, status, checkup_type, conclusion, reCheckupDate, customer_weight, customer_height,
heart_beat, blood_pressure, doctor_ultrasound_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(checkup_id) DO UPDATE SET
suggestion = excluded.suggestion,
diagnosis = excluded.diagnosis,
prescription_id = excluded.prescription_id,
notes = excluded.notes,
status = excluded.status,
checkup_type = excluded.checkup_type,
conclusion = excluded.conclusion,
reCheckupDate = excluded.reCheckupDate,
customer_weight = excluded.customer_weight,
customer_height = excluded.customer_height,
heart_beat = excluded.heart_beat,
blood_pressure = excluded.blood_pressure,
doctor_ultrasound_id = excluded.doctor_ultrasound_id,
doctor_id = excluded.doctor_id
""";
PreparedStatement checkupStmt = conn.prepareStatement(checkupSql);
checkupStmt.setInt(1, saveCheckupRequest.getCheckupId());
checkupStmt.setInt(2, saveCheckupRequest.getCustomerId());
checkupStmt.setInt(3, saveCheckupRequest.getDoctorId());
checkupStmt.setLong(4, saveCheckupRequest.getCheckupDate());
checkupStmt.setString(5, saveCheckupRequest.getSuggestions());
checkupStmt.setString(6, saveCheckupRequest.getDiagnosis());
checkupStmt.setString(7, prescriptionId);
checkupStmt.setString(8, saveCheckupRequest.getNotes());
checkupStmt.setString(9, saveCheckupRequest.getStatus());
checkupStmt.setString(10, saveCheckupRequest.getCheckupType());
checkupStmt.setString(11, saveCheckupRequest.getConclusion());
checkupStmt.setLong(12, saveCheckupRequest.getReCheckupDate());
checkupStmt.setDouble(13, saveCheckupRequest.getCustomerWeight());
checkupStmt.setDouble(14, saveCheckupRequest.getCustomerHeight());
checkupStmt.setInt(15, saveCheckupRequest.getHeartBeat());
checkupStmt.setString(16, saveCheckupRequest.getBloodPressure());
checkupStmt.setInt(17, saveCheckupRequest.getDoctorUltrasoundId());
checkupStmt.executeUpdate();
log.info("Prescription ID generated or edited: {}", prescriptionId);
log.info("Checkup saved successfully");
// 4. Handle Medicine Prescriptions
// First, delete all existing items for this checkup to handle edits/removals
try (PreparedStatement deleteOrderItemsStmt = conn.prepareStatement("DELETE FROM OrderItem WHERE checkup_id = ?")) {
deleteOrderItemsStmt.setInt(1, saveCheckupRequest.getCheckupId());
deleteOrderItemsStmt.executeUpdate();
}
try (PreparedStatement deleteMedicineOrderStmt = conn.prepareStatement("DELETE FROM MedicineOrder WHERE checkup_id = ?")) {
deleteMedicineOrderStmt.setInt(1, saveCheckupRequest.getCheckupId());
deleteMedicineOrderStmt.executeUpdate();
}
log.info("Cleared previous medicine prescription for checkup_id: {}", saveCheckupRequest.getCheckupId());
if (saveCheckupRequest.getMedicinePrescription() != null &&
saveCheckupRequest.getMedicinePrescription().length > 0 && prescriptionId != null) {
// Calculate total amount for medicine order
double totalMedicineAmount = 0;
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
if (medicine.length > 8) {
try {
totalMedicineAmount += Double.parseDouble(medicine[8]); // total_price
} catch (NumberFormatException e) {
log.warn("Invalid medicine total price: {}", medicine[8]);
// This will hold the new ID generated by the database.
Integer newPrescriptionId = null;
// 2. Handle Medicine Prescriptions
if (saveCheckupRequest.getMedicinePrescription() != null &&
saveCheckupRequest.getMedicinePrescription().length > 0) {
// First, clear old data for this checkup
try (PreparedStatement deleteOrderItemsStmt = conn.prepareStatement("DELETE FROM OrderItem WHERE checkup_id = ?")) {
deleteOrderItemsStmt.setInt(1, saveCheckupRequest.getCheckupId());
deleteOrderItemsStmt.executeUpdate();
}
}
}
// Insert/Update MedicineOrder
String medicineOrderSql = """
INSERT INTO MedicineOrder (
prescription_id, checkup_id, customer_id,
total_amount, payment_method, status,
payment_status, processed_by, notes, datetime
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_DATE)
ON CONFLICT(prescription_id, checkup_id) DO UPDATE SET
customer_id = excluded.customer_id,
total_amount = excluded.total_amount,
payment_method = excluded.payment_method,
status = excluded.status,
payment_status = excluded.payment_status,
processed_by = excluded.processed_by,
notes = excluded.notes,
datetime = CURRENT_DATE
""";
PreparedStatement medicineOrderStmt = conn.prepareStatement(medicineOrderSql);
medicineOrderStmt.setString(1, prescriptionId);
medicineOrderStmt.setInt(2, saveCheckupRequest.getCheckupId());
medicineOrderStmt.setInt(3, saveCheckupRequest.getCustomerId());
medicineOrderStmt.setDouble(4, totalMedicineAmount);
medicineOrderStmt.setString(5, ""); // payment_method
medicineOrderStmt.setString(6, "Pending"); // status
medicineOrderStmt.setString(7, "Unpaid"); // payment_status
medicineOrderStmt.setString(8, ""); // processed_by
medicineOrderStmt.setString(9, ""); // notes
medicineOrderStmt.executeUpdate();
log.info("MedicineOrder saved successfully");
// Insert OrderItems
String orderItemSql = """
INSERT INTO OrderItem (
prescription_id, med_id, quantity_ordered,
dosage, duration, price_per_unit, total_price, checkup_id, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(order_item_id) DO UPDATE SET
quantity_ordered = excluded.quantity_ordered,
dosage = excluded.dosage,
duration = excluded.duration,
price_per_unit = excluded.price_per_unit,
total_price = excluded.total_price,
checkup_id = excluded.checkup_id,
notes = excluded.notes
""";
log.info("OrderItem saved successfully");
PreparedStatement orderItemStmt = conn.prepareStatement(orderItemSql);
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
if (medicine.length >= 10) {
orderItemStmt.setString(1, prescriptionId);
orderItemStmt.setString(2, medicine[0]); // med_id
orderItemStmt.setString(3, medicine[2]); // quantity
try (PreparedStatement deleteMedicineOrderStmt = conn.prepareStatement("DELETE FROM MedicineOrder WHERE checkup_id = ?")) {
deleteMedicineOrderStmt.setInt(1, saveCheckupRequest.getCheckupId());
deleteMedicineOrderStmt.executeUpdate();
}
log.info("Cleared previous medicine prescription for checkup_id: {}", saveCheckupRequest.getCheckupId());
// A. Insert a new MedicineOrder record to get the auto-generated ID
String medicineOrderSql = """
INSERT INTO MedicineOrder (
checkup_id, customer_id, total_amount, payment_method,
status, payment_status, processed_by, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
""";
// Build dosage string from morning, noon, evening
String dosage = String.format("Sáng %s, Trưa %s, Chiều %s",
medicine[4], medicine[5], medicine[6]);
orderItemStmt.setString(4, dosage);
orderItemStmt.setString(5, ""); // duration - could be calculated or added to request
orderItemStmt.setString(6, medicine[7]); // unit_price
orderItemStmt.setString(7, medicine[8]); // total_price
orderItemStmt.setInt(8, saveCheckupRequest.getCheckupId());
orderItemStmt.setString(9, medicine[9]); // notes
orderItemStmt.addBatch();
}
// Use RETURN_GENERATED_KEYS to get the new ID back
try (PreparedStatement medicineOrderStmt = conn.prepareStatement(medicineOrderSql, PreparedStatement.RETURN_GENERATED_KEYS)) {
// ... (your existing totalMedicineAmount calculation) ...
double totalMedicineAmount = 0;
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
if (medicine.length > 8) { totalMedicineAmount += Double.parseDouble(medicine[8]); }
}
medicineOrderStmt.setInt(1, saveCheckupRequest.getCheckupId());
medicineOrderStmt.setInt(2, saveCheckupRequest.getCustomerId());
medicineOrderStmt.setDouble(3, totalMedicineAmount);
medicineOrderStmt.setString(4, ""); // payment_method
medicineOrderStmt.setString(5, "Pending"); // status
medicineOrderStmt.setString(6, "Unpaid"); // payment_status
medicineOrderStmt.setString(7, ""); // processed_by
medicineOrderStmt.setString(8, ""); // notes
medicineOrderStmt.executeUpdate();
// B. Retrieve the generated key
try (ResultSet generatedKeys = medicineOrderStmt.getGeneratedKeys()) {
if (generatedKeys.next()) {
newPrescriptionId = generatedKeys.getInt(1);
log.info("New prescription_id generated: {}", newPrescriptionId);
} else {
throw new SQLException("Creating medicine order failed, no ID obtained.");
}
}
}
// C. Insert OrderItems using the new prescription_id
String orderItemSql = """
INSERT INTO OrderItem (
prescription_id, med_id, quantity_ordered, dosage, duration,
price_per_unit, total_price, checkup_id, notes
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
""";
try (PreparedStatement orderItemStmt = conn.prepareStatement(orderItemSql)) {
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
if (medicine.length >= 10) {
orderItemStmt.setInt(1, newPrescriptionId); // Use the new ID
orderItemStmt.setString(2, medicine[0]); // med_id
orderItemStmt.setString(3, medicine[2]); // quantity
String dosage = String.format("Sáng %s, Trưa %s, Chiều %s", medicine[4], medicine[5], medicine[6]);
orderItemStmt.setString(4, dosage);
orderItemStmt.setString(5, ""); // duration
orderItemStmt.setString(6, medicine[7]); // unit_price
orderItemStmt.setString(7, medicine[8]); // total_price
orderItemStmt.setInt(8, saveCheckupRequest.getCheckupId());
orderItemStmt.setString(9, medicine[9]); // notes
orderItemStmt.addBatch();
}
}
orderItemStmt.executeBatch();
log.info("OrderItems saved for prescription_id: {}", newPrescriptionId);
}
}
orderItemStmt.executeBatch();
}
log.info("Medicine prescriptions saved successfully");
// 5. Handle Service Prescriptions
// First, delete all existing services for this checkup
try (PreparedStatement deleteServiceStmt = conn.prepareStatement("DELETE FROM CheckupService WHERE checkup_id = ?")) {
deleteServiceStmt.setInt(1, saveCheckupRequest.getCheckupId());
deleteServiceStmt.executeUpdate();
}
log.info("Cleared previous service prescription for checkup_id: {}", saveCheckupRequest.getCheckupId());
if (saveCheckupRequest.getServicePrescription() != null &&
saveCheckupRequest.getServicePrescription().length > 0) {
// 3. Insert/Update Checkup with the correct newPrescriptionId
String checkupSql = """
INSERT INTO Checkup (
checkup_id, customer_id, doctor_id, checkup_date, suggestion, diagnosis,
prescription_id, notes, status, checkup_type, conclusion, reCheckupDate,
customer_weight, customer_height, heart_beat, blood_pressure, doctor_ultrasound_id
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
ON CONFLICT(checkup_id) DO UPDATE SET
suggestion = excluded.suggestion, diagnosis = excluded.diagnosis,
prescription_id = excluded.prescription_id, notes = excluded.notes,
status = excluded.status, checkup_type = excluded.checkup_type,
conclusion = excluded.conclusion, reCheckupDate = excluded.reCheckupDate,
customer_weight = excluded.customer_weight, customer_height = excluded.customer_height,
heart_beat = excluded.heart_beat, blood_pressure = excluded.blood_pressure,
doctor_ultrasound_id = excluded.doctor_ultrasound_id, doctor_id = excluded.doctor_id
""";
String serviceSql = """
INSERT INTO CheckupService (
checkup_id, service_id, quantity,
total_cost, status, checkup_date
) VALUES (?, ?, ?, ?, ?, CURRENT_DATE)
ON CONFLICT(order_id) DO UPDATE SET
quantity = excluded.quantity,
total_cost = excluded.total_cost,
status = excluded.status
""";
PreparedStatement serviceStmt = conn.prepareStatement(serviceSql);
for (String[] service : saveCheckupRequest.getServicePrescription()) {
if (service.length >= 6) {
serviceStmt.setInt(1, saveCheckupRequest.getCheckupId());
serviceStmt.setString(2, service[0]); // service_id
serviceStmt.setString(3, service[2]); // quantity
serviceStmt.setString(4, service[4]); // total_cost
serviceStmt.setString(5, "PENDING"); // status
serviceStmt.addBatch();
}
try (PreparedStatement checkupStmt = conn.prepareStatement(checkupSql)) {
checkupStmt.setInt(1, saveCheckupRequest.getCheckupId());
checkupStmt.setInt(2, saveCheckupRequest.getCustomerId());
checkupStmt.setInt(3, saveCheckupRequest.getDoctorId());
checkupStmt.setLong(4, saveCheckupRequest.getCheckupDate());
checkupStmt.setString(5, saveCheckupRequest.getSuggestions());
checkupStmt.setString(6, saveCheckupRequest.getDiagnosis());
// Use setObject to handle the case where newPrescriptionId is null
checkupStmt.setObject(7, newPrescriptionId);
checkupStmt.setString(8, saveCheckupRequest.getNotes());
checkupStmt.setString(9, saveCheckupRequest.getStatus());
checkupStmt.setString(10, saveCheckupRequest.getCheckupType());
checkupStmt.setString(11, saveCheckupRequest.getConclusion());
if (saveCheckupRequest.getReCheckupDate() != null) {
checkupStmt.setLong(12, saveCheckupRequest.getReCheckupDate());
} else {
checkupStmt.setLong(12, 0);
}
checkupStmt.setDouble(13, saveCheckupRequest.getCustomerWeight());
checkupStmt.setDouble(14, saveCheckupRequest.getCustomerHeight());
checkupStmt.setInt(15, saveCheckupRequest.getHeartBeat());
checkupStmt.setString(16, saveCheckupRequest.getBloodPressure());
checkupStmt.setInt(17, saveCheckupRequest.getDoctorUltrasoundId());
checkupStmt.executeUpdate();
log.info("Checkup saved successfully");
}
serviceStmt.executeBatch();
}
log.info("Service prescriptions saved successfully");
// Commit transaction
conn.commit();
log.info("Successfully saved checkup {} with all related data", saveCheckupRequest.getCheckupId());
UserUtil.sendPacket(currentUser.getSessionId(), new SaveCheckupRes(true, "Checkup saved successfully"));
// 4. Handle Service Prescriptions (Now safe with try-with-resources)
// ... (your existing service handling logic is fine, just wrap it) ...
conn.commit(); // Commit the entire transaction
log.info("Successfully saved checkup {} with all related data", saveCheckupRequest.getCheckupId());
UserUtil.sendPacket(currentUser.getSessionId(), new SaveCheckupRes(true, "Checkup saved successfully"));
} catch (Exception e) {
log.error("Error saving checkup transaction", e);
// Rollback transaction on error
if (conn != null) {
try {
conn.rollback();
log.info("Transaction rolled back due to error");
} catch (SQLException rollbackEx) {
log.error("Error rolling back transaction", rollbackEx);
log.error("Error saving checkup transaction", e);
if (conn != null) {
try {
conn.rollback();
log.info("Transaction rolled back due to error");
} catch (SQLException rollbackEx) {
log.error("Error rolling back transaction", rollbackEx);
}
}
}
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
} finally {
// Restore auto-commit
if (conn != null) {
try {
conn.setAutoCommit(true);
} catch (SQLException e) {
log.error("Error restoring auto-commit", e);
if (conn != null) {
try {
conn.setAutoCommit(true); // Restore auto-commit mode
} catch (SQLException e) {
log.error("Error restoring auto-commit", e);
}
}
}
}
}
}
if (packet instanceof GetOrderInfoByCheckupReq getOrderInfoByCheckupReq) {
log.debug("Received GetOrderInfoByCheckupReq for checkupId: {}", getOrderInfoByCheckupReq.getCheckupId());
@@ -1402,46 +1332,65 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
if (packet instanceof GetRecheckUpListRequest getRecheckUpListRequest) {
log.debug("Received GetRecheckUpListRequest");
getRecheckUpList(currentUser.getSessionId());
}
if (packet instanceof AddRemindDateRequest addRemindDateRequest) {
log.debug("Received AddRemindDateRequest");
try {
String sql = "SELECT c.customer_last_name, c.customer_first_name, c.customer_number, ch.reCheckupDate, ch.remind_date, ch.checkup_id " +
"FROM Checkup ch " +
"JOIN Customer c ON ch.customer_id = c.customer_id " +
"WHERE ch.reCheckupDate BETWEEN ? AND ?";
long fromDate = System.currentTimeMillis();
long toDate = fromDate + (7L * 24 * 60 * 60 * 1000);
String sql = "UPDATE Checkup SET remind_date = ? WHERE checkup_id = ?";
PreparedStatement stmt = Server.connection.prepareStatement(sql);
stmt.setLong(1, fromDate);
stmt.setLong(2, toDate);
ResultSet rs = stmt.executeQuery();
List<String[]> results = new ArrayList<>();
while (rs.next()) {
String[] row = new String[5];
row[0] = rs.getString("customer_last_name") + " " + rs.getString("customer_first_name");
row[1] = rs.getString("customer_number");
long recheckTimestamp = rs.getLong("reCheckupDate");
long remindTimestamp = rs.getLong("remind_date");
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
row[2] = sdf.format(new Date(recheckTimestamp));
row[3] = sdf.format(new Date(remindTimestamp));
row[4] = rs.getString("checkup_id");
results.add(row);
}
UserUtil.sendPacket(currentUser.getSessionId(), new GetRecheckUpListResponse(results.toArray(new String[0][])));
stmt.setLong(1, System.currentTimeMillis());
stmt.setString(2, addRemindDateRequest.getCheckupId());
stmt.executeUpdate();
log.info("Updated remind_date for checkup_id: {}", addRemindDateRequest.getCheckupId());
getRecheckUpList(currentUser.getSessionId());
} catch (SQLException e) {
log.error("Error fetching recheck-up list", e);
log.error("Error updating remind_date", e);
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
}
}
}
}
private void getRecheckUpList(int sessionId) {
try {
String sql = "SELECT c.customer_last_name, c.customer_first_name, c.customer_number, ch.reCheckupDate, ch.remind_date, ch.checkup_id " +
"FROM Checkup ch " +
"JOIN Customer c ON ch.customer_id = c.customer_id " +
"WHERE ch.reCheckupDate BETWEEN ? AND ?";
long fromDate = System.currentTimeMillis();
long toDate = fromDate + (7L * 24 * 60 * 60 * 1000);
PreparedStatement stmt = Server.connection.prepareStatement(sql);
stmt.setLong(1, fromDate);
stmt.setLong(2, toDate);
ResultSet rs = stmt.executeQuery();
List<String[]> results = new ArrayList<>();
while (rs.next()) {
String[] row = new String[5];
row[0] = rs.getString("customer_last_name") + " " + rs.getString("customer_first_name");
row[1] = rs.getString("customer_number");
long recheckTimestamp = rs.getLong("reCheckupDate");
long remindTimestamp = rs.getLong("remind_date");
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
row[2] = sdf.format(new Date(recheckTimestamp));
row[3] = sdf.format(new Date(remindTimestamp));
row[4] = rs.getString("checkup_id");
results.add(row);
}
UserUtil.sendPacket(sessionId, new GetRecheckUpListResponse(results.toArray(new String[0][])));
} catch (SQLException e) {
log.error("Error fetching recheck-up list", e);
UserUtil.sendPacket(sessionId, new ErrorResponse(Error.SQL_EXCEPTION));
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
if (cause instanceof IOException) {
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 427 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 302 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 474 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 461 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 393 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 423 KiB

+3 -3
View File
@@ -3,13 +3,13 @@
<Appenders>
<Console name="ConsoleAppender" target="SYSTEM_OUT">
<PatternLayout
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.} : %m%n"/>
pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.}:%L : %m%n"/>
</Console>
<RollingFile name="ServerFileAppender" fileName="logs/bsk_server.log"
filePattern="logs/bsk_server-%i.log.gz">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.} : %m%n</Pattern>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.}:%L : %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="50 MB" />
@@ -20,7 +20,7 @@
<RollingFile name="ClientFileAppender" fileName="logs/bsk_client.log"
filePattern="logs/bsk_client-%i.log.gz">
<PatternLayout>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.} : %m%n</Pattern>
<Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %5p - %-40.40c{1.}:%L : %m%n</Pattern>
</PatternLayout>
<Policies>
<SizeBasedTriggeringPolicy size="50 MB" />