[update] Refactor CheckUpPage and AddDialog to remove district handling. Replace district-related logic with ward management, updating UI components and response handling accordingly. Adjust database requests to focus on wards, enhancing address handling and user experience.

This commit is contained in:
Lê Thành Đạt committed 2025-07-26 02:42:08 +07:00
1 parent 87425db642
commit 7fdfd4f729
11 files changed
+255 -301

No files matched your search

@@ -17,10 +17,7 @@ public class LocalStorage {
public static String ClinicPhone = "0123456789";
public static String[] doctorsName;
public static String[] provinces;
public static String[] districts;
public static String[] wards;
public static HashMap<String, String> provinceToId;
public static HashMap<String, String> districtToId;
public static HashMap<String, String[]> cachedDistricts; // cache local areas later will do
public static HashMap<String, String[]> cachedWards; // cache local areas later will do
}
@@ -37,29 +37,44 @@ public class AddDialog extends JDialog {
private JTextField patientPhoneField;
private JTextField cccdField;
private JComboBox patientGenderField;
private JComboBox wardComboBox, districtComboBox, provinceComboBox;
private JComboBox wardComboBox, provinceComboBox;
private JTextField customerAddressField;
private DefaultTableModel patientTableModel;
private JTable patientTable;
private String[] patientColumns = {"Mã BN", "Tên Bệnh Nhân", "Năm sinh", "Số điện thoại" ,"Địa chỉ"};
private String[][] patientData;
private final ResponseListener<GetRecentPatientResponse> getRecentPatientResponseListener = this::getRecentPatientHandler;
private final ResponseListener<GetDistrictResponse> districtResponseListener = this::handleGetDistrictResponse;
private final ResponseListener<GetWardResponse> wardResponseListener = this::handleGetWardResponse;
private final ResponseListener<AddPatientResponse> addPatientResponseListener = this::handleAddPatientResponse;
private final ResponseListener<AddCheckupResponse> addCheckupResponseListener = this::handleAddCheckupResponse;
private JComboBox doctorComboBox;
private JComboBox<String> checkupTypeComboBox;
JButton saveButton;
private DefaultComboBoxModel<String> districtModel, wardModel;
private DefaultComboBoxModel<String> wardModel;
private JDatePickerImpl dobPicker;
private JButton addPatientButton;
private JButton clearButton;
private String targetWard = null;
private void handleAddCheckupResponse(AddCheckupResponse response) {
log.info("Received AddCheckupResponse");
if (response.isSuccess()) {
JOptionPane.showMessageDialog(this, "Thêm bệnh nhân vào khám thành công");
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
JLabel messageLabel = new JLabel("Thêm bệnh nhân vào khám thành công");
messageLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
messageLabel.setFont(new Font("Arial", Font.PLAIN, 16));
JLabel queueLabel = new JLabel("Số thứ tự: " + response.getQueueNumber());
queueLabel.setFont(new Font("Arial", Font.BOLD, 28));
queueLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
panel.add(messageLabel);
panel.add(Box.createVerticalStrut(10));
panel.add(queueLabel);
JOptionPane.showMessageDialog(this, panel, "Thành công", JOptionPane.INFORMATION_MESSAGE);
} else {
JOptionPane.showMessageDialog(this, response.getError());
}
@@ -93,15 +108,6 @@ public class AddDialog extends JDialog {
return -1;
}
private int findDistrictIndex(String district) {
for (int i = 0; i < LocalStorage.districts.length; i++) {
if (TextUtils.removeAccents(LocalStorage.districts[i]).equals(TextUtils.removeAccents(district))) {
return i;
}
}
return -1;
}
private int findWardIndex(String ward) {
for (int i = 0; i < LocalStorage.wards.length; i++) {
if (TextUtils.removeAccents(LocalStorage.wards[i]).equals(TextUtils.removeAccents(ward))) {
@@ -111,6 +117,7 @@ public class AddDialog extends JDialog {
return -1;
}
@Override
public void dispose() {
// Clean up listeners
@@ -118,7 +125,6 @@ public class AddDialog extends JDialog {
ClientHandler.deleteListener(AddCheckupResponse.class, addCheckupResponseListener);
ClientHandler.deleteListener(AddPatientResponse.class, addPatientResponseListener);
ClientHandler.deleteListener(GetRecentPatientResponse.class, getRecentPatientResponseListener);
ClientHandler.deleteListener(GetDistrictResponse.class, districtResponseListener);
ClientHandler.deleteListener(GetWardResponse.class, wardResponseListener);
super.dispose();
}
@@ -218,7 +224,6 @@ public class AddDialog extends JDialog {
// Send request to get the latest 20 patients in the database
sendGetRecentPatientRequest();
ClientHandler.addResponseListener(GetDistrictResponse.class, districtResponseListener);
ClientHandler.addResponseListener(GetWardResponse.class, wardResponseListener);
ClientHandler.addResponseListener(AddPatientResponse.class, addPatientResponseListener);
ClientHandler.addResponseListener(AddCheckupResponse.class, addCheckupResponseListener);
@@ -479,7 +484,7 @@ public class AddDialog extends JDialog {
addressInfoPanel.add(customerAddressField, gbc);
gbc.weightx = 0.0;
// Province, District, Ward ComboBoxes on a single line (Row 1)
// Province, Ward, Ward ComboBoxes on a single line (Row 1)
gbc.gridy++;
gbc.gridx = 0; // Start from the first column for the combo boxes
gbc.gridwidth = 1; // Each combo box takes 1 logical column in this setup
@@ -490,20 +495,14 @@ public class AddDialog extends JDialog {
addressInfoPanel.add(provinceComboBox, gbc);
gbc.gridx = 1;
districtModel = new DefaultComboBoxModel<>(new String[]{"Quận/Huyện"});
districtComboBox = new JComboBox<>(districtModel);
districtComboBox.setFont(textFont);
districtComboBox.setPreferredSize(comboBoxSize);
districtComboBox.setEnabled(false);
addressInfoPanel.add(districtComboBox, gbc);
gbc.gridx = 2;
wardModel = new DefaultComboBoxModel<>(new String[]{"Phường/Xã"});
wardModel = new DefaultComboBoxModel<>(new String[]{"Quận/Huyện"});
wardComboBox = new JComboBox<>(wardModel);
wardComboBox.setFont(textFont);
wardComboBox.setPreferredSize(comboBoxSize);
wardComboBox.setEnabled(false);
addressInfoPanel.add(wardComboBox, gbc);
gbc.gridx = 2;
gbc.weightx = 0.0; // Reset weightx for any subsequent components in this panel
gbc.gridwidth = 1; // Reset gridwidth
@@ -552,35 +551,20 @@ public class AddDialog extends JDialog {
@Override
public void actionPerformed(ActionEvent e) {
int selectedIndex = provinceComboBox.getSelectedIndex();
districtModel = new DefaultComboBoxModel<>(new String[]{"Quận/Huyện"});
districtComboBox.setModel(districtModel); // Set district combo box model
wardModel = new DefaultComboBoxModel<>(new String[]{"Quận/Huyện"});
wardComboBox.setModel(wardModel); // Set ward combo box model
if (selectedIndex != 0) { // If the selected index is not 0 (which corresponds to "Tỉnh/Thành phố")
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetDistrictRequest(LocalStorage.provinceToId
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetWardRequest(LocalStorage.provinceToId
.get(provinceComboBox.getSelectedItem().toString())));
} else {
districtComboBox.setEnabled(false); // Disable district combo box if "Tỉnh/Thành phố" is selected
wardComboBox.setEnabled(false); // Disable ward combo box as well
wardComboBox.setEnabled(false); // Disable ward combo box if "Tỉnh/Thành phố" is selected
}
}
});
// District ComboBox Listener
districtComboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedIndex = districtComboBox.getSelectedIndex();
wardModel = new DefaultComboBoxModel<>(new String[]{"Xã/Phường"});
wardComboBox.setModel(wardModel); // Set district combo box model
if (selectedIndex != 0) { // If the selected index is not 0 (which corresponds to "Quận/Huyện")
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetWardRequest(LocalStorage.districtToId
.get(districtComboBox.getSelectedItem().toString())));
} else {
districtComboBox.setEnabled(false); // Disable district combo box if "Tỉnh/Thành phố" is selected
wardComboBox.setEnabled(false); // Disable ward combo box as well
}
}
});
// Ward ComboBox Listener
inputPanel.setMinimumSize(new Dimension(400, 0));
// Wrap inputPanel in a JScrollPane
@@ -634,15 +618,40 @@ public class AddDialog extends JDialog {
JOptionPane.showMessageDialog(this, "Bạn đã chọn bệnh nhân rồi");
return;
}
String patientName = patientNameField.getText();
String patientPhone = patientPhoneField.getText();
String patientName = patientNameField.getText().trim();
String patientPhone = patientPhoneField.getText().trim();
String patientGender = (String) patientGenderField.getSelectedItem();
String customerAddress = customerAddressField.getText();
String customerAddress = customerAddressField.getText().trim();
String province = (String) provinceComboBox.getSelectedItem();
String district = (String) districtComboBox.getSelectedItem();
String ward = (String) wardComboBox.getSelectedItem();
String address = String.join(", ", customerAddress, ward, district, province);
String cccd = cccdField.getText();
String cccd = cccdField.getText().trim();
// Validate required fields
if (patientName.isEmpty() || patientPhone.isEmpty() || customerAddress.isEmpty() ||
dobPicker.getJFormattedTextField().getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Vui lòng điền đầy đủ thông tin");
return;
}
// Check if province is selected
if (provinceComboBox.getSelectedIndex() <= 0) {
JOptionPane.showMessageDialog(this, "Vui lòng chọn tỉnh/thành phố");
return;
}
// Check if ward is selected and enabled
if (wardComboBox.isEnabled() && wardComboBox.getSelectedIndex() <= 0) {
JOptionPane.showMessageDialog(this, "Vui lòng chọn quận/huyện");
return;
}
// Build the full address with proper format
String address;
if (wardComboBox.isEnabled() && wardComboBox.getSelectedIndex() > 0) {
address = String.join(", ", customerAddress, ward, province);
} else {
address = String.join(", ", customerAddress, province);
}
//split name into first name and last name
String[] nameParts = patientName.split(" ");
@@ -656,12 +665,6 @@ public class AddDialog extends JDialog {
}
String lastNameStr = lastName.toString();
// check if dobPicker is not null
if (patientName.isEmpty() || patientPhone.isEmpty() || customerAddress.isEmpty() || dobPicker.getJFormattedTextField().getText().isEmpty()) {
JOptionPane.showMessageDialog(this, "Vui lòng điền đầy đủ thông tin");
return;
}
String dateText = dobPicker.getJFormattedTextField().getText();
SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
@@ -687,13 +690,14 @@ public class AddDialog extends JDialog {
// Reset combo boxes
patientGenderField.setSelectedIndex(0);
provinceComboBox.setSelectedIndex(0);
districtComboBox.setSelectedIndex(0);
districtComboBox.setEnabled(false);
wardComboBox.setSelectedIndex(0);
wardComboBox.setEnabled(false);
doctorComboBox.setSelectedIndex(0);
checkupTypeComboBox.setSelectedIndex(0);
// Reset targetWard
targetWard = null;
// Clear date picker
dobPicker.getModel().setValue(null);
dobPicker.getJFormattedTextField().setText("");
@@ -731,34 +735,41 @@ public class AddDialog extends JDialog {
patientGenderField.setSelectedItem(patientGender);
cccdField.setText(patientCccd);
// Extract province, district, ward from the address
String[] addressParts = patientAddress.split(", ");
if (addressParts.length == 4) {
String address = addressParts[0];
String ward = addressParts[1];
String district = addressParts[2];
String province = addressParts[3];
customerAddressField.setText(address);
provinceComboBox.setSelectedIndex(findProvinceIndex(province));
try {
Thread.sleep(100);
while(!districtComboBox.isEditable()) {
districtComboBox.setSelectedIndex(findDistrictIndex(district));
break;
// Reset targetWard
targetWard = null;
// Extract province, ward, and detailed address from the full address
if (patientAddress != null && !patientAddress.isEmpty()) {
String[] addressParts = patientAddress.split(", ");
if (addressParts.length >= 2) {
// Last part is province, second last is ward, everything else is address
String province = addressParts[addressParts.length - 1];
targetWard = addressParts[addressParts.length - 2];
// Combine remaining parts as the detailed address
StringBuilder detailedAddress = new StringBuilder();
for (int i = 0; i < addressParts.length - 2; i++) {
detailedAddress.append(addressParts[i]);
if (i < addressParts.length - 3) {
detailedAddress.append(", ");
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
try {
Thread.sleep(100);
while(!wardComboBox.isEditable()) {
wardComboBox.setSelectedIndex(findWardIndex(ward));
break;
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
customerAddressField.setText(detailedAddress.toString());
provinceComboBox.setSelectedIndex(findProvinceIndex(province));
// Ward will be set in the response handler using targetWard
} else {
// If address doesn't have enough parts, just use the whole address as detailed address
customerAddressField.setText(patientAddress);
provinceComboBox.setSelectedIndex(0); // Select default province
}
} else {
// Clear address fields if no address is available
customerAddressField.setText("");
provinceComboBox.setSelectedIndex(0);
}
SimpleDateFormat dobFormat;
try {
Date parsedDate;
@@ -797,24 +808,26 @@ public class AddDialog extends JDialog {
}
private void handleGetDistrictResponse(GetDistrictResponse response) {
log.info("Received dialog district data");
LocalStorage.districts = response.getDistricts();
LocalStorage.districtToId = response.getDistrictToId();
districtModel = new DefaultComboBoxModel<>(LocalStorage.districts);
districtComboBox.setModel(districtModel);
districtComboBox.setEnabled(true); // Enable district combo box
}
private void handleGetWardResponse(GetWardResponse response) {
log.info("Received dialog ward data");
LocalStorage.wards = response.getWards();
wardModel = new DefaultComboBoxModel<>(LocalStorage.wards);
wardComboBox.setModel(wardModel);
wardComboBox.setEnabled(true); // Enable ward combo box
// Set the ward after the ward data is loaded
if (targetWard != null) {
int wardIndex = findWardIndex(targetWard);
if (wardIndex >= 0) {
wardComboBox.setSelectedIndex(wardIndex);
}
// We've handled this targetWard, so clear it
targetWard = null;
}
}
private void setupDateFieldForDirectInput(JDatePickerImpl datePicker) {
JFormattedTextField textField = datePicker.getJFormattedTextField();
@@ -164,7 +164,6 @@ public class CheckUpPage extends JPanel {
private final ResponseListener<GetCheckUpQueueUpdateResponse> checkUpQueueUpdateListener = this::handleGetCheckUpQueueUpdateResponse;
private final ResponseListener<GetCheckUpQueueResponse> checkUpQueueListener = this::handleGetCheckUpQueueResponse;
private final ResponseListener<GetPatientHistoryResponse> patientHistoryListener = this::handleGetPatientHistoryResponse;
private final ResponseListener<GetDistrictResponse> districtResponseListener = this::handleGetDistrictResponse;
private final ResponseListener<GetWardResponse> wardResponseListener = this::handleGetWardResponse;
private final ResponseListener<CallPatientResponse> callPatientResponseListener = this::handleCallPatientResponse;
private final ResponseListener<GetOrderInfoByCheckupRes> orderInfoByCheckupListener = this::handleGetOrderInfoByCheckupResponse;
@@ -174,7 +173,7 @@ public class CheckUpPage extends JPanel {
private JTextField checkupIdField, customerLastNameField, customerFirstNameField,customerAddressField, customerPhoneField, customerIdField, customerCccdDdcnField;
private JTextArea suggestionField, diagnosisField, conclusionField; // Changed symptomsField to suggestionField
private JTextPane notesField;
private JComboBox<String> doctorComboBox, statusComboBox, genderComboBox, provinceComboBox, districtComboBox, wardComboBox, checkupTypeComboBox, templateComboBox, orientationComboBox; // Added orientationComboBox
private JComboBox<String> doctorComboBox, statusComboBox, genderComboBox, provinceComboBox, wardComboBox, checkupTypeComboBox, templateComboBox, orientationComboBox; // Added orientationComboBox
private JComboBox<String> ultrasoundDoctorComboBox;
private JCheckBox needRecheckupCheckbox; // Checkbox to indicate if re-checkup is needed
private JSpinner customerWeightSpinner, customerHeightSpinner, patientHeartRateSpinner, bloodPressureSystolicSpinner, bloodPressureDiastolicSpinner;
@@ -188,10 +187,9 @@ public class CheckUpPage extends JPanel {
private AddDialog addDialog = null;
private String selectedCheckupId = null; // Use checkupId to track selection instead of row index
private boolean saved = true; // Initially true, changed when patient selected or dialog opened.
private DefaultComboBoxModel<String> districtModel, wardModel;
private DefaultComboBoxModel<String> wardModel;
// Variables to store target district and ward when loading patient address
private String targetDistrict = null;
// Variables to store target ward and ward when loading patient address
private String targetWard = null;
private JComboBox<String> callRoomComboBox;
private JButton callPatientButton;
@@ -321,15 +319,6 @@ public class CheckUpPage extends JPanel {
return -1;
}
private int findDistrictIndex(String district) {
for (int i = 0; i < LocalStorage.districts.length; i++) {
if (TextUtils.removeAccents(LocalStorage.districts[i]).equals(TextUtils.removeAccents(district))) {
return i;
}
}
return -1;
}
private int findWardIndex(String ward) {
for (int i = 0; i < LocalStorage.wards.length; i++) {
if (TextUtils.removeAccents(LocalStorage.wards[i]).equals(TextUtils.removeAccents(ward))) {
@@ -358,7 +347,6 @@ public class CheckUpPage extends JPanel {
ClientHandler.addResponseListener(GetCheckUpQueueUpdateResponse.class, checkUpQueueUpdateListener);
ClientHandler.addResponseListener(GetPatientHistoryResponse.class, patientHistoryListener);
ClientHandler.addResponseListener(GetOrderInfoByCheckupRes.class, orderInfoByCheckupListener);
ClientHandler.addResponseListener(GetDistrictResponse.class, districtResponseListener);
ClientHandler.addResponseListener(GetWardResponse.class, wardResponseListener);
ClientHandler.addResponseListener(CallPatientResponse.class, callPatientResponseListener);
ClientHandler.addResponseListener(GetAllTemplatesRes.class, getAllTemplatesListener);
@@ -426,6 +414,9 @@ public class CheckUpPage extends JPanel {
addPatientButton.setBorder(BorderFactory.createEmptyBorder(8, 20, 8, 20)); // Reduced vertical padding from 10 to 8
addPatientButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
addPatientButton.addActionListener(e -> {
// Unregister the listener from the parent page to avoid conflicts
ClientHandler.deleteListener(GetWardResponse.class, wardResponseListener);
// Dispose any existing dialog to ensure clean listener removal
if (addDialog != null) {
addDialog.dispose();
@@ -435,9 +426,18 @@ public class CheckUpPage extends JPanel {
public void dispose() {
super.dispose();
addDialog = null; // Clear the reference when dialog is disposed
// Re-register the listener after the dialog is actually disposed
ClientHandler.addResponseListener(GetWardResponse.class, wardResponseListener);
log.info("AddDialog disposed, re-registered ward listener for CheckUpPage.");
}
};
addDialog.setVisible(true);
// Show the dialog without blocking the main thread
SwingUtilities.invokeLater(() -> {
addDialog.setVisible(true);
// The re-registration will now happen inside the dispose() override
});
updateUpdateQueue();
});
@@ -765,14 +765,7 @@ public class CheckUpPage extends JPanel {
patientInfoInnerPanel.add(provinceComboBox, gbcPatient);
gbcPatient.gridx = 2;
districtModel = new DefaultComboBoxModel<>(new String[]{"Huyện"});
districtComboBox = new JComboBox<>(districtModel);
districtComboBox.setFont(fieldFont);
districtComboBox.setEnabled(false);
patientInfoInnerPanel.add(districtComboBox, gbcPatient);
gbcPatient.gridx = 3;
wardModel = new DefaultComboBoxModel<>(new String[]{"Phường"});
wardModel = new DefaultComboBoxModel<>(new String[]{"Huyện"});
wardComboBox = new JComboBox<>(wardModel);
wardComboBox.setFont(fieldFont);
wardComboBox.setEnabled(false);
@@ -834,40 +827,19 @@ public class CheckUpPage extends JPanel {
if (selectedProvince != null && !selectedProvince.equals("Tỉnh/Thành phố")) {
String provinceId = LocalStorage.provinceToId.get(selectedProvince);
if (provinceId != null) {
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetDistrictRequest(provinceId));
districtComboBox.setEnabled(false);
districtModel.removeAllElements();
districtModel.addElement("Đang tải quận/huyện...");
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetWardRequest(provinceId));
wardComboBox.setEnabled(false);
wardModel.removeAllElements();
wardModel.addElement("Phường");
wardModel.addElement("Đang tải quận/huyện...");
}
} else {
districtComboBox.setEnabled(false);
districtModel.removeAllElements();
districtModel.addElement("Huyện");
wardComboBox.setEnabled(false);
wardModel.removeAllElements();
wardModel.addElement("Phường");
wardModel.addElement("Huyện");
}
});
districtComboBox.addActionListener(e -> {
String selectedDistrict = (String) districtComboBox.getSelectedItem();
if (selectedDistrict != null && LocalStorage.districtToId != null && LocalStorage.districtToId.containsKey(selectedDistrict)) {
String districtId = LocalStorage.districtToId.get(selectedDistrict);
if (districtId != null) {
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetWardRequest(districtId));
wardComboBox.setEnabled(false);
wardModel.removeAllElements();
wardModel.addElement("Đang tải phường/xã...");
}
} else {
wardComboBox.setEnabled(false);
wardModel.removeAllElements();
wardModel.addElement("Phường");
}
});
// Checkup Info Section
JPanel checkupInfoPanel = new JPanel(new BorderLayout(10, 5)); // Reduced vertical gap from 10 to 5
@@ -1810,7 +1782,7 @@ public class CheckUpPage extends JPanel {
customerLastNameField.getText() + " " + customerFirstNameField.getText(),
dobPicker.getJFormattedTextField().getText(), customerPhoneField.getText(),
genderComboBox.getSelectedItem().toString(),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
doctorComboBox.getSelectedItem().toString(), diagnosisField.getText(),
conclusionField.getText(),
regularMeds.toArray(new String[0][]),
@@ -1866,7 +1838,7 @@ public class CheckUpPage extends JPanel {
customerLastNameField.getText() + " " + customerFirstNameField.getText(),
dobPicker.getJFormattedTextField().getText(),
(String) genderComboBox.getSelectedItem(),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
(String) doctorComboBox.getSelectedItem(),
(String) ultrasoundDoctorComboBox.getSelectedItem(),
datePicker.getJFormattedTextField().getText(),
@@ -1941,7 +1913,7 @@ public class CheckUpPage extends JPanel {
customerLastNameField.getText() + " " + customerFirstNameField.getText(),
dobPicker.getJFormattedTextField().getText(),
(String) genderComboBox.getSelectedItem(),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (districtComboBox.getSelectedItem() != null ? districtComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
customerAddressField.getText() + ", " + (wardComboBox.getSelectedItem() != null ? wardComboBox.getSelectedItem().toString() : "") + ", " + (provinceComboBox.getSelectedItem() != null ? provinceComboBox.getSelectedItem().toString() : ""),
(String) doctorComboBox.getSelectedItem(),
(String) ultrasoundDoctorComboBox.getSelectedItem(),
datePicker.getJFormattedTextField().getText(),
@@ -2270,44 +2242,47 @@ public class CheckUpPage extends JPanel {
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new GetOrderInfoByCheckupReq(selectedPatient.getCheckupId()));
String fullAddress = selectedPatient.getCustomerAddress();
String[] addressParts = fullAddress.split(", ");
if (addressParts.length > 0) customerAddressField.setText(addressParts[0]);
else if (fullAddress != null) customerAddressField.setText(fullAddress);
if (addressParts.length == 4) {
String ward = addressParts[1];
String district = addressParts[2];
String province = addressParts[3];
// Reset target ward
targetWard = null;
if (addressParts.length >= 2) {
// Last part is province, second last is ward, everything else is address
String province = addressParts[addressParts.length - 1];
targetWard = addressParts[addressParts.length - 2];
log.info("Province: {}", province);
log.info("Target ward: {}", targetWard);
// Combine remaining parts as the detailed address
StringBuilder detailedAddress = new StringBuilder();
for (int i = 0; i < addressParts.length - 2; i++) {
detailedAddress.append(addressParts[i]);
if (i < addressParts.length - 3) {
detailedAddress.append(", ");
}
}
// Store target district and ward for later setting
targetDistrict = district;
targetWard = ward;
customerAddressField.setText(detailedAddress.toString());
int provinceIdx = findProvinceIndex(province);
if (provinceIdx != -1) {
provinceComboBox.setSelectedIndex(provinceIdx);
// The province selection will trigger district loading automatically
// District and ward will be set in the response handlers
// The province selection will trigger ward loading automatically
// Ward will be set in the response handler using targetWard
} else {
log.warn("Province not found: {}", province);
districtModel.removeAllElements(); districtModel.addElement("Huyện"); districtComboBox.setEnabled(false);
wardModel.removeAllElements(); wardModel.addElement("Phường"); wardComboBox.setEnabled(false);
targetDistrict = null;
wardModel.removeAllElements(); wardModel.addElement("Huyện"); wardComboBox.setEnabled(false);
targetWard = null;
}
} else if (addressParts.length > 1) { // Handle cases with partial address
provinceComboBox.setSelectedIndex(0);
districtModel.removeAllElements(); districtModel.addElement("Huyện"); districtComboBox.setEnabled(false);
wardModel.removeAllElements(); wardModel.addElement("Phường"); wardComboBox.setEnabled(false);
targetDistrict = null;
targetWard = null;
log.warn("Address format not fully standard ({} parts): {}", addressParts.length, fullAddress);
} else {
} else if (addressParts.length == 1) {
// Handle case with only one part
customerAddressField.setText(fullAddress);
provinceComboBox.setSelectedIndex(0);
districtModel.removeAllElements(); districtModel.addElement("Huyện"); districtComboBox.setEnabled(false);
wardModel.removeAllElements(); wardModel.addElement("Phường"); wardComboBox.setEnabled(false);
targetDistrict = null;
targetWard = null;
wardModel.removeAllElements(); wardModel.addElement("Huyện"); wardComboBox.setEnabled(false);
} else {
// Empty address case
customerAddressField.setText("");
provinceComboBox.setSelectedIndex(0);
wardModel.removeAllElements(); wardModel.addElement("Huyện"); wardComboBox.setEnabled(false);
}
// Setup for Supersonic View media for the NEWLY selected patient
@@ -2352,33 +2327,6 @@ public class CheckUpPage extends JPanel {
saved = false; // Data loaded, any change from now on is "unsaved" until save button.
}
private void handleGetDistrictResponse(GetDistrictResponse response) {
SwingUtilities.invokeLater(() -> {
log.info("Received district data");
LocalStorage.districts = response.getDistricts();
LocalStorage.districtToId = response.getDistrictToId();
districtModel.removeAllElements();
for (String district : LocalStorage.districts) { districtModel.addElement(district); }
districtComboBox.setEnabled(true);
// If we have a target district to set, try to set it now
if (targetDistrict != null) {
int districtIdx = findDistrictIndex(targetDistrict);
if (districtIdx != -1) {
log.info("Setting target district: {}", targetDistrict);
districtComboBox.setSelectedIndex(districtIdx);
// The district selection will trigger ward loading automatically
} else {
log.warn("Target district not found in loaded data: {}", targetDistrict);
targetDistrict = null;
targetWard = null;
}
}
wardModel.removeAllElements(); wardModel.addElement("Phường"); wardComboBox.setEnabled(false);
});
}
private void handleGetWardResponse(GetWardResponse response) {
SwingUtilities.invokeLater(() -> {
log.info("Received ward data");
@@ -2393,9 +2341,7 @@ public class CheckUpPage extends JPanel {
if (wardIdx != -1) {
log.info("Setting target ward: {}", targetWard);
wardComboBox.setSelectedIndex(wardIdx);
// Clear the target values since we've successfully set them
targetDistrict = null;
targetWard = null;
// The ward selection will trigger ward loading automatically
} else {
log.warn("Target ward not found in loaded data: {}", targetWard);
targetWard = null;
@@ -2404,6 +2350,7 @@ public class CheckUpPage extends JPanel {
});
}
private void handleGetPatientHistoryResponse(GetPatientHistoryResponse response) {
SwingUtilities.invokeLater(() -> {
log.info("Received patient history");
@@ -4537,12 +4484,10 @@ public class CheckUpPage extends JPanel {
// Construct full address
String address = customerAddressField.getText();
String ward = (String) wardComboBox.getSelectedItem();
String district = (String) districtComboBox.getSelectedItem();
String province = (String) provinceComboBox.getSelectedItem();
String fullAddress = String.format("%s, %s, %s, %s",
address,
ward != null && !ward.equals("Phường") ? ward : "",
district != null && !district.equals("Huyện") ? district : "",
ward != null && !ward.equals("Huyện") ? ward : "",
province != null && !province.equals("Tỉnh/Thành phố") ? province : ""
).replaceAll(", ,", ",").trim().replaceAll(",$", "");
@@ -4765,14 +4710,13 @@ public class CheckUpPage extends JPanel {
customerCccdDdcnField.setText("");
// Clear target address values
targetDistrict = null;
targetWard = null;
if (doctorComboBox.getItemCount() > 0) doctorComboBox.setSelectedIndex(0);
statusComboBox.setSelectedIndex(0);
genderComboBox.setSelectedIndex(0);
if (provinceComboBox.getItemCount() > 0) provinceComboBox.setSelectedIndex(0);
// district and ward will be cleared by province selection listener
// ward and ward will be cleared by province selection listener
checkupTypeComboBox.setSelectedIndex(0);
if (templateComboBox.getItemCount() > 0) templateComboBox.setSelectedIndex(0);
@@ -0,0 +1,49 @@
package BsK.client.ui.component.CheckUpPage;
import BsK.client.LocalStorage;
import BsK.client.network.handler.ClientHandler;
import BsK.common.packet.res.GetWardResponse;
import lombok.extern.slf4j.Slf4j;
/**
* Debug class to help troubleshoot ward loading issues
* This is just a test class and should be removed after fixing the issue
*/
@Slf4j
public class Debug {
/**
* Log ward data when received to help diagnose any issues
*/
public static void logWardInfo() {
log.info("DEBUG: Setting up ward monitoring");
ClientHandler.addResponseListener(GetWardResponse.class, (response) -> {
log.info("DEBUG: Received ward response with {} wards",
(response.getWards() != null ? response.getWards().length - 1 : 0));
if (response.getWards() == null || response.getWards().length <= 1) {
log.warn("DEBUG: Ward data is empty!");
return;
}
log.info("DEBUG: First 5 wards:");
for (int i = 0; i < Math.min(5, response.getWards().length); i++) {
log.info("DEBUG: Ward[{}] = '{}'", i, response.getWards()[i]);
}
log.info("DEBUG: First 5 ward IDs:");
int count = 0;
for (String ward : response.getWardToId().keySet()) {
if (count >= 5) break;
log.info("DEBUG: Ward '{}' -> ID '{}'", ward, response.getWardToId().get(ward));
count++;
}
// Check LocalStorage after processing
log.info("DEBUG: LocalStorage.wards now contains {} elements",
(LocalStorage.wards != null ? LocalStorage.wards.length : 0));
});
}
}
@@ -56,11 +56,11 @@ public class QueueViewPage extends JFrame {
clinicInfoPanel.setOpaque(false);
clinicNameLabel = new JLabel("Phòng khám: Đang tải...");
styleLabelForTv(clinicNameLabel, 28, Font.BOLD, Color.WHITE);
styleLabelForTv(clinicNameLabel, 40, Font.BOLD, Color.WHITE);
clinicAddressLabel = new JLabel("Địa chỉ: Đang tải...");
styleLabelForTv(clinicAddressLabel, 20, Font.PLAIN, Color.LIGHT_GRAY);
styleLabelForTv(clinicAddressLabel, 30, Font.PLAIN, Color.LIGHT_GRAY);
clinicPhoneLabel = new JLabel("Điện thoại: Đang tải...");
styleLabelForTv(clinicPhoneLabel, 20, Font.PLAIN, Color.LIGHT_GRAY);
styleLabelForTv(clinicPhoneLabel, 30, Font.PLAIN, Color.LIGHT_GRAY);
clinicInfoPanel.add(clinicNameLabel);
clinicInfoPanel.add(Box.createRigidArea(new Dimension(0, 5)));
@@ -81,13 +81,13 @@ public class QueueViewPage extends JFrame {
room1StatusLabel = new JLabel("PHÒNG 1", SwingConstants.CENTER);
styleRoomLabel(room1StatusLabel, room1Panel, Color.GREEN.darker(), "TRỐNG"); // Initial state: Room 1 Empty
room1Panel.add(room1StatusLabel, BorderLayout.CENTER);
room1Panel.setPreferredSize(new Dimension(220, 100));
room1Panel.setPreferredSize(new Dimension(280, 120));
room2Panel = new JPanel(new BorderLayout());
room2StatusLabel = new JLabel("PHÒNG 2", SwingConstants.CENTER);
styleRoomLabel(room2StatusLabel, room2Panel, Color.GREEN.darker(), "TRỐNG"); // Initial state: Room 2 Empty
room2Panel.add(room2StatusLabel, BorderLayout.CENTER);
room2Panel.setPreferredSize(new Dimension(220, 100));
room2Panel.setPreferredSize(new Dimension(280, 120));
roomsPanel.add(room1Panel);
roomsPanel.add(room2Panel);
@@ -103,16 +103,16 @@ public class QueueViewPage extends JFrame {
callingPatientDisplayPanel.setBorder(new EmptyBorder(15, 20, 15, 20)); // Padding
nowCallingTextLabel = new JLabel("ĐANG GỌI:");
styleLabelForTv(nowCallingTextLabel, 38, Font.BOLD, new Color(255, 215, 0)); // Gold color
styleLabelForTv(nowCallingTextLabel, 60, Font.BOLD, new Color(255, 215, 0)); // Gold color
nowCallingTextLabel.setAlignmentX(Component.CENTER_ALIGNMENT);
nowCallingTextLabel.setVisible(false); // Initially hidden
nowCallingInfoLine1Label = new JLabel("Phòng 1: TRỐNG"); // Default message
styleLabelForTv(nowCallingInfoLine1Label, 32, Font.BOLD, Color.WHITE);
styleLabelForTv(nowCallingInfoLine1Label, 50, Font.BOLD, Color.WHITE);
nowCallingInfoLine1Label.setAlignmentX(Component.CENTER_ALIGNMENT);
nowCallingInfoLine2Label = new JLabel("Phòng 2: TRỐNG"); // Default message
styleLabelForTv(nowCallingInfoLine2Label, 32, Font.BOLD, Color.WHITE);
styleLabelForTv(nowCallingInfoLine2Label, 50, Font.BOLD, Color.WHITE);
nowCallingInfoLine2Label.setAlignmentX(Component.CENTER_ALIGNMENT);
callingPatientDisplayPanel.add(nowCallingTextLabel);
@@ -135,17 +135,17 @@ public class QueueViewPage extends JFrame {
};
tvQueueTable = new JTable(tvQueueTableModel);
tvQueueTable.setFont(new Font("Arial", Font.BOLD, 26));
tvQueueTable.setRowHeight(45);
tvQueueTable.setFont(new Font("Arial", Font.BOLD, 50));
tvQueueTable.setRowHeight(80);
tvQueueTable.setFillsViewportHeight(true);
tvQueueTable.setBackground(new Color(220, 220, 220)); // Light gray for table background
tvQueueTable.setGridColor(Color.GRAY);
JTableHeader tableHeader = tvQueueTable.getTableHeader();
tableHeader.setFont(new Font("Arial", Font.BOLD, 28));
tableHeader.setFont(new Font("Arial", Font.BOLD, 52));
tableHeader.setBackground(new Color(63, 81, 181));
tableHeader.setForeground(Color.WHITE);
tableHeader.setPreferredSize(new Dimension(0, 50)); // Header height
tableHeader.setPreferredSize(new Dimension(0, 90)); // Header height
JScrollPane scrollPane = new JScrollPane(tvQueueTable);
scrollPane.setBorder(new EmptyBorder(10, 20, 20, 20)); // Padding around table
@@ -165,7 +165,7 @@ public class QueueViewPage extends JFrame {
String baseRoomText = label.getText().split("<br>")[0]; // Get "PHÒNG X"
if (baseRoomText.contains("html")) baseRoomText = (label == room1StatusLabel ? "PHÒNG 1" : "PHÒNG 2"); // Fallback if parsing fails
label.setFont(new Font("Segoe UI", Font.BOLD, 22));
label.setFont(new Font("Segoe UI", Font.BOLD, 32));
label.setForeground(Color.WHITE);
label.setText("<html><div style='text-align: center;'>" + baseRoomText + "<br>" + statusText + "</div></html>");
panel.setBackground(bgColor);
@@ -190,18 +190,18 @@ public class QueueViewPage extends JFrame {
if (room1Busy) {
nowCallingInfoLine1Label.setText("Phòng 1: " + room1PatientInfo);
styleLabelForTv(nowCallingInfoLine1Label, 32, Font.BOLD, Color.WHITE);
styleLabelForTv(nowCallingInfoLine1Label, 50, Font.BOLD, Color.WHITE);
} else {
nowCallingInfoLine1Label.setText("Phòng 1: TRỐNG");
styleLabelForTv(nowCallingInfoLine1Label, 32, Font.ITALIC, Color.LIGHT_GRAY);
styleLabelForTv(nowCallingInfoLine1Label, 50, Font.ITALIC, Color.LIGHT_GRAY);
}
if (room2Busy) {
nowCallingInfoLine2Label.setText("Phòng 2: " + room2PatientInfo);
styleLabelForTv(nowCallingInfoLine2Label, 32, Font.BOLD, Color.WHITE);
styleLabelForTv(nowCallingInfoLine2Label, 50, Font.BOLD, Color.WHITE);
} else {
nowCallingInfoLine2Label.setText("Phòng 2: TRỐNG");
styleLabelForTv(nowCallingInfoLine2Label, 32, Font.ITALIC, Color.LIGHT_GRAY);
styleLabelForTv(nowCallingInfoLine2Label, 50, Font.ITALIC, Color.LIGHT_GRAY);
}
if (room1Busy || room2Busy) {
@@ -321,6 +321,12 @@ public class QueueViewPage extends JFrame {
}
tvQueueTableModel.setDataVector(tvDataList.toArray(new Object[0][0]), tvQueueColumns);
// Set column widths for TV display
tvQueueTable.getColumnModel().getColumn(0).setPreferredWidth(150); // STT
tvQueueTable.getColumnModel().getColumn(0).setMaxWidth(200);
tvQueueTable.getColumnModel().getColumn(2).setPreferredWidth(250); // Năm sinh
tvQueueTable.getColumnModel().getColumn(2).setMaxWidth(300);
// The specific room status (patient ID in box) is now handled by updateSpecificRoomStatus
// and markRoomAsFree. The general updateQueueData should not override this detailed status.
// If no patients are called, updateNowCallingDisplay will reflect that rooms are free if their info is null.
@@ -1,13 +0,0 @@
package BsK.common.packet.req;
import BsK.common.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@AllArgsConstructor
@Data
public class GetDistrictRequest implements Packet {
String provinceId;
}
@@ -1,14 +1,13 @@
package BsK.common.packet.req;
import BsK.common.packet.Packet;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@AllArgsConstructor
@Data
@Slf4j
public class GetWardRequest implements Packet {
String districtId;
String provinceId;
}
@@ -9,4 +9,5 @@ import lombok.Data;
public class AddCheckupResponse implements Packet {
boolean success;
String error;
int queueNumber;
}
@@ -10,7 +10,6 @@ import java.util.HashMap;
@Slf4j
@Data
@AllArgsConstructor
public class GetDistrictResponse implements Packet {
String[] districts;
HashMap<String, String> districtToId;
public class GetWardResponse implements Packet {
String[] wards;
}
@@ -542,80 +542,39 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
}
}
if (packet instanceof GetDistrictRequest getDistrictRequest) {
log.debug("Received GetDistrictRequest");
if (packet instanceof GetWardRequest getWardRequest) {
log.debug("Received GetWardRequest");
try{
PreparedStatement preparedStatement = Server.connection.prepareStatement(
"SELECT districts.code, districts.name " +
" FROM districts " +
"SELECT wards.code, wards.name " +
" FROM wards " +
" WHERE province_code = ? " +
" ORDER BY districts.name"
" ORDER BY wards.name"
);
preparedStatement.setString(1, getDistrictRequest.getProvinceId());
preparedStatement.setString(1, getWardRequest.getProvinceId());
ResultSet rs = preparedStatement.executeQuery();
if (!rs.isBeforeFirst()) {
System.out.println("No data found in the district table.");
System.out.println("No data found in the ward table.");
} else {
ArrayList<String> resultList = new ArrayList<>();
HashMap<String, String> districtIdMap = new HashMap<>();
resultList.add("Quận/Huyện");
resultList.add("Phường/Xã");
while (rs.next()) {
String districtId = rs.getString("code");
String districtName = rs.getString("name");
districtIdMap.put(districtName, districtId);
resultList.add(districtName);
String wardName = rs.getString("name");
resultList.add(wardName);
}
String[] resultString = resultList.toArray(new String[0]);
UserUtil.sendPacket(currentUser.getSessionId(), new GetDistrictResponse(resultString, districtIdMap));
UserUtil.sendPacket(currentUser.getSessionId(), new GetWardResponse(resultString));
}
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
if (packet instanceof GetWardRequest getWardRequest) {
log.debug("Received GetWardRequest");
try{
PreparedStatement preparedStatement = Server.connection.prepareStatement(
"SELECT wards.code, wards.name \n" +
" FROM wards\n" +
" WHERE district_code = ? " +
" ORDER BY wards.name"
);
preparedStatement.setString(1, getWardRequest.getDistrictId());
ResultSet rs = preparedStatement.executeQuery();
if (!rs.isBeforeFirst()) {
System.out.println("No data found in the district table.");
} else {
ArrayList<String> resultList = new ArrayList<>();
HashMap<String, String> districtIdMap = new HashMap<>();
resultList.add("Xã/Phường");
while (rs.next()) {
String districtId = rs.getString("code");
String districtName = rs.getString("name");
districtIdMap.put(districtName, districtId);
resultList.add(districtName);
}
String[] resultString = resultList.toArray(new String[0]);
UserUtil.sendPacket(currentUser.getSessionId(), new GetWardResponse(resultString));
}
} catch (SQLException e) {
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
throw new RuntimeException(e);
}
}
if (packet instanceof AddPatientRequest addPatientRequest) {
log.debug("Received AddPatientRequest");
try {
@@ -753,7 +712,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
Server.connection.commit();
// Send immediate response to client
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(true, "Thêm bệnh nhân thành công"));
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(true, "Thêm bệnh nhân thành công", queueNumber));
// Create Google Drive folder asynchronously (don't block the response)
createCheckupGoogleDriveFolderAsync(generatedCheckupId, addCheckupRequest.getCustomerId());
@@ -766,7 +725,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
log.error("Error during rollback", rollbackEx);
}
String errorMessage = e.getMessage();
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(false, "Lỗi: " + errorMessage));
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(false, "Lỗi: " + errorMessage, -1));
throw new RuntimeException(e);
}
finally {
Binary file not shown.