[update] Remove unused image files and enhance CheckUpPage functionality. Increase maximum folders to scan, improve UI interactions for queue management, and refine patient selection handling. Update AddDialog for better UI dimensions and control states. Adjust TemplateDialog to allow zero image selection for printing.

This commit is contained in:
Lê Thành Đạt committed 2025-08-09 10:09:32 +07:00
1 parent 68c0395364
commit e3696765b2
18 files changed
+129 -58

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 321 KiB

@@ -0,0 +1,2 @@
[LocalizedFileNames]
faker.jpg=@faker,0
Binary file not shown.

Before

Width:  |  Height:  |  Size: 805 KiB

+2
View File
@@ -0,0 +1,2 @@
[LocalizedFileNames]
faker.jpg=@faker,0
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

@@ -147,7 +147,7 @@ public class CheckUpPage extends JPanel {
private ScheduledExecutorService folderScanExecutor;
private volatile boolean isScanning = false;
private static final int SCAN_INTERVAL_MILLISECONDS = 500; // Check every 1
private static final int MAX_FOLDERS_TO_SCAN = 4;
private static final int MAX_FOLDERS_TO_SCAN = 12;
private final Set<Path> processingFiles = ConcurrentHashMap.newKeySet();
private final Map<Path, FileAttributes> lastSeenFiles = new ConcurrentHashMap<>();
@@ -398,7 +398,14 @@ public class CheckUpPage extends JPanel {
openQueueButton.setBorder(BorderFactory.createEmptyBorder(8, 15, 8, 15)); // Reduced vertical padding from 10 to 8
openQueueButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
openQueueButton.addActionListener(e -> {
// Always fetch the latest queue to avoid cross-client mismatch
updateQueue();
// Reset filters to "Tất cả" to avoid index/filter/sort mismatch on open
if (queueManagementPage != null) {
queueManagementPage.checkupTypeFilter.setSelectedItem("Tất cả");
queueManagementPage.patientNameFilter.setText("");
queueManagementPage.applyFilters();
}
queueManagementPage.setVisible(true);
queueManagementPage.toFront();
});
@@ -1914,13 +1921,7 @@ public class CheckUpPage extends JPanel {
break;
case "ultrasound": // This case now handles "Lưu & In"
// Step 1: Validate conditions first.
if (selectedImagesForPrint.isEmpty()) {
JOptionPane.showMessageDialog(this,
"Vui lòng chọn ít nhất một hình ảnh để in kết quả.",
"Chưa chọn ảnh", JOptionPane.WARNING_MESSAGE);
return;
}
if (photoNum != 0 && selectedImagesForPrint.size() > photoNum) {
JOptionPane.showMessageDialog(this,
"Số lượng ảnh đã chọn (" + selectedImagesForPrint.size() + ") nhiều hơn số lượng cho phép trong mẫu (" + photoNum + ").",
@@ -1995,13 +1996,7 @@ public class CheckUpPage extends JPanel {
afterSaveActions(statusToSavePrint, "Đã lưu. Đang gửi lệnh in...");
break;
case "loupe": // This case now handles "Lưu & Xem"
// Step 1: Validate conditions first.
if (selectedImagesForPrint.isEmpty()) {
JOptionPane.showMessageDialog(this,
"Vui lòng chọn ít nhất một hình ảnh để xem kết quả.",
"Chưa chọn ảnh", JOptionPane.WARNING_MESSAGE);
return;
}
if (photoNum != 0 && selectedImagesForPrint.size() > photoNum) {
JOptionPane.showMessageDialog(this,
"Số lượng ảnh đã chọn (" + selectedImagesForPrint.size() + ") nhiều hơn số lượng cho phép trong mẫu (" + photoNum + ").",
@@ -2729,10 +2724,8 @@ public class CheckUpPage extends JPanel {
private JPanel createImageDisplayPanel() {
JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder(
BorderFactory.createEtchedBorder(), "Thư viện Hình ảnh",
TitledBorder.CENTER, TitledBorder.TOP,
new Font("Arial", Font.ITALIC, 14), new Color(50, 50, 50)));
// Remove inner title to avoid duplicate "Thư viện Hình ảnh" header and save vertical space
panel.setBorder(BorderFactory.createEmptyBorder());
imageGalleryPanel = new JPanel(new FlowLayout(FlowLayout.LEFT, 10, 10)); // Added more spacing
imageGalleryPanel.setBackground(Color.WHITE); // Set a background for the gallery
@@ -3192,14 +3185,14 @@ public class CheckUpPage extends JPanel {
return Collections.emptyList();
}
// Sort by creation time (newest first)
// Sort by last modified time (newest first)
folders.sort((path1, path2) -> {
try {
FileTime time1 = Files.readAttributes(path1, BasicFileAttributes.class).creationTime();
FileTime time2 = Files.readAttributes(path2, BasicFileAttributes.class).creationTime();
return time2.compareTo(time1); // Newest first
FileTime time1 = Files.getLastModifiedTime(path1);
FileTime time2 = Files.getLastModifiedTime(path2);
return time2.compareTo(time1);
} catch (Exception e) {
log.warn("Error comparing creation times for {} and {}: {}", path1, path2, e.getMessage());
log.warn("Error comparing last modified times for {} and {}: {}", path1, path2, e.getMessage());
return 0;
}
});
@@ -4303,8 +4296,13 @@ public class CheckUpPage extends JPanel {
return;
}
}
// Call the parent class's method to handle the selection with the model row index
CheckUpPage.this.handleRowSelection(modelRow, null);
// Resolve the selected patient by Checkup ID to avoid index mismatch after filtering/sorting
Patient selected = patientQueue.stream()
.filter(p -> newlySelectedCheckupId.equals(p.getCheckupId()))
.findFirst().orElse(null);
if (selected != null) {
CheckUpPage.this.handleRowSelection(-1, selected);
}
// Reset patient name filter when closing dialog after selection
patientNameFilter.setText("");
applyFilters();
@@ -4353,8 +4351,13 @@ public class CheckUpPage extends JPanel {
return;
}
}
// Call the parent class's method to handle the selection with the model row index
CheckUpPage.this.handleRowSelection(modelRow, null);
// Resolve patient by Checkup ID to avoid index mismatch
Patient selected = patientQueue.stream()
.filter(p -> newlySelectedCheckupId.equals(p.getCheckupId()))
.findFirst().orElse(null);
if (selected != null) {
CheckUpPage.this.handleRowSelection(-1, selected);
}
// Reset patient name filter when closing dialog after selection
patientNameFilter.setText("");
applyFilters();
@@ -4444,9 +4447,12 @@ public class CheckUpPage extends JPanel {
// 1. Filter your master list into a temporary list
filteredPatients = patientQueue.stream()
.filter(patient -> {
// ... (your existing filter logic remains the same) ...
// Checkup type filter with normalized comparison (accent-insensitive, case-insensitive)
if (!"Tất cả".equals(selectedCheckupType)) {
if (!selectedCheckupType.equals(patient.getCheckupType())) {
String normalizedSelected = TextUtils.removeAccents(selectedCheckupType).trim().toUpperCase();
String patientType = patient.getCheckupType();
String normalizedPatientType = TextUtils.removeAccents(patientType == null ? "" : patientType).trim().toUpperCase();
if (!normalizedSelected.equals(normalizedPatientType)) {
return false;
}
}
@@ -4522,17 +4528,45 @@ public class CheckUpPage extends JPanel {
queueTable.scrollRectToVisible(queueTable.getCellRect(viewRow, 0, true));
}
} else {
JOptionPane.showMessageDialog(
mainFrame,
"Trạng thái của bệnh nhân bạn đang chọn đã thay đổi và không còn trong hàng chờ.\n" +
"Giao diện của bạn sẽ được làm mới.",
"Cập Nhật Trạng Thái Bệnh Nhân",
JOptionPane.INFORMATION_MESSAGE
);
clearPatientDetails(); // Now clear the details
if (queueTable.getRowCount() > 0) {
queueTable.setRowSelectionInterval(0, 0);
// Not visible under current filters. Check if the patient still exists in the full queue.
Patient target = patientQueue.stream()
.filter(p -> previouslySelectedId.equals(p.getCheckupId()))
.findFirst().orElse(null);
if (target != null) {
// Adjust filters to include the target patient's type and re-apply
if (checkupTypeFilter != null) {
String type = target.getCheckupType();
checkupTypeFilter.setSelectedItem(type == null || type.isEmpty() ? "Tất cả" : type);
}
if (patientNameFilter != null) {
patientNameFilter.setText("");
}
applyFilters();
int rowAgain = findRowByCheckupId(previouslySelectedId);
if (rowAgain != -1) {
int viewRow = queueTable.convertRowIndexToView(rowAgain);
if (viewRow != -1) {
queueTable.setRowSelectionInterval(viewRow, viewRow);
queueTable.scrollRectToVisible(queueTable.getCellRect(viewRow, 0, true));
}
} else if (queueTable.getRowCount() > 0) {
// Fall back to first row without showing a misleading status-change message
queueTable.setRowSelectionInterval(0, 0);
}
} else {
// Patient truly no longer in queue; show message and clear
JOptionPane.showMessageDialog(
mainFrame,
"Trạng thái của bệnh nhân bạn đang chọn đã thay đổi và không còn trong hàng chờ.\n" +
"Giao diện của bạn sẽ được làm mới.",
"Cập Nhật Trạng Thái Bệnh Nhân",
JOptionPane.INFORMATION_MESSAGE
);
clearPatientDetails(); // Now clear the details
if (queueTable.getRowCount() > 0) {
queueTable.setRowSelectionInterval(0, 0);
}
}
}
} else {
@@ -248,12 +248,12 @@ public class AddDialog extends JDialog {
setLocationRelativeTo(parent);
setResizable(true);
// UI Fonts and Dimensions
Font labelFont = new Font("Arial", Font.BOLD, 15);
Font textFont = new Font("Arial", Font.PLAIN, 15);
Font titleFont = new Font("Arial", Font.BOLD, 16);
Dimension textFieldSize = new Dimension(100, 30);
Dimension comboBoxSize = new Dimension(100, 30);
// UI Fonts and Dimensions (labels bigger, fields smaller)
Font labelFont = new Font("Arial", Font.BOLD, 18);
Font textFont = new Font("Arial", Font.PLAIN, 14);
Font titleFont = new Font("Arial", Font.BOLD, 18);
Dimension textFieldSize = new Dimension(100, 26);
Dimension comboBoxSize = new Dimension(100, 26);
// Ensure modal behavior and proper parent relationship
setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
@@ -436,7 +436,7 @@ public class AddDialog extends JDialog {
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));
dobPicker.setPreferredSize(new Dimension(140, 26));
patientInfoPanel.add(dobPicker, gbc);
gbc.gridx = 2;
@@ -571,15 +571,15 @@ public class AddDialog extends JDialog {
gbc.anchor = GridBagConstraints.EAST;
gbc.gridy++; // Move to a new row
gbc.gridx = 0;
gbc.gridx = 2;
gbc.gridwidth = 2; // Span 2 columns
specifyQueueNumberCheckBox = new JCheckBox("Chỉ định STT");
specifyQueueNumberCheckBox.setFont(labelFont);
checkupInfoPanel.add(specifyQueueNumberCheckBox, gbc);
gbc.anchor = GridBagConstraints.WEST;
gbc.gridx = 2;
gbc.gridwidth = 2; // Span the other 2 columns
gbc.gridx = 1;
gbc.gridwidth = 1; // Span the other 2 columns
SpinnerNumberModel queueSpinnerModel = new SpinnerNumberModel(1, 1, 999, 1); // (defaultValue, min, max, step)
queueNumberSpinner = new JSpinner(queueSpinnerModel);
queueNumberSpinner.setFont(textFont);
@@ -636,9 +636,13 @@ public class AddDialog extends JDialog {
}
log.info("Sending AddCheckupRequest with queue number: {}", queueNumber);
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new AddCheckupRequest(patientId, doctorId, LocalStorage.userId, selectedCheckupType, "CHỜ KHÁM", queueNumber));
clearButton.doClick();
});
checkupInfoPanel.add(saveButton, gbc);
// Initially disable checkup controls until a patient is selected
setCheckupControlsEnabled(false);
// Reset insets and weights
gbc.insets = new Insets(5, 5, 5, 5);
gbc.weightx = 0.0;
@@ -717,7 +721,8 @@ public class AddDialog extends JDialog {
}
});
inputPanel.setMinimumSize(new Dimension(400, 0));
// Make the left panel narrower
inputPanel.setMinimumSize(new Dimension(300, 0));
// Wrap inputPanel in a JScrollPane
JScrollPane inputScrollPane = new JScrollPane(inputPanel);
@@ -752,7 +757,9 @@ public class AddDialog extends JDialog {
rightPanel.add(paginationPanel, BorderLayout.SOUTH);
JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, inputScrollPane, rightPanel);
splitPane.setResizeWeight(0.5); // Keep or adjust as needed
// Favor the right panel; set an initial divider position and resize weight
splitPane.setDividerLocation(0.25);
splitPane.setResizeWeight(0.2);
add(splitPane, BorderLayout.CENTER);
@@ -873,6 +880,7 @@ public class AddDialog extends JDialog {
// Update button states
saveButton.setEnabled(false);
addPatientButton.setEnabled(true);
setCheckupControlsEnabled(false);
setDefaultLocation();
// Reset table to show all patients
sendGetRecentPatientRequest();
@@ -1189,5 +1197,28 @@ private void setupDebounceSearch() {
// Enable the save button only if the patient ID field is not empty.
boolean isPatientSelected = !patientIdField.getText().trim().isEmpty();
saveButton.setEnabled(isPatientSelected);
setCheckupControlsEnabled(isPatientSelected);
}
private void setCheckupControlsEnabled(boolean enabled) {
// Guard against initialization order
if (doctorComboBox != null) {
doctorComboBox.setEnabled(enabled);
}
if (checkupTypeComboBox != null) {
checkupTypeComboBox.setEnabled(enabled);
}
if (specifyQueueNumberCheckBox != null) {
specifyQueueNumberCheckBox.setEnabled(enabled);
}
if (queueNumberSpinner != null) {
// Spinner enabled only when both the section is enabled and the checkbox is selected
boolean spinnerEnabled = enabled && specifyQueueNumberCheckBox != null && specifyQueueNumberCheckBox.isSelected();
queueNumberSpinner.setEnabled(spinnerEnabled);
}
if (saveButton != null) {
// Keep saveButton consistent with the enabled state as well
saveButton.setEnabled(enabled);
}
}
}
@@ -158,7 +158,7 @@ public class TemplateDialog extends JDialog {
diagnosisArea.setLineWrap(true);
diagnosisArea.setWrapStyleWord(true);
imageCountComboBox = new JComboBox<>(new String[]{"1", "2", "3", "4"});
imageCountComboBox = new JComboBox<>(new String[]{"0", "1", "2", "3", "4"});
printTypeComboBox = new JComboBox<>(new String[]{"Ngang", "Dọc"});
sttField = new JTextField(10);
@@ -618,7 +618,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
try (Connection conn = DatabaseManager.getConnection()) {
int generatedCheckupId = 0;
int queueNumber = addCheckupRequest.getQueueNumber();
boolean customQueue = (addCheckupRequest.getCustomerId() != -1);
try {
// 1. Bắt đầu một transaction trên kết nối CỤC BỘ (conn) này
conn.setAutoCommit(false);
@@ -694,9 +694,11 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
// Gửi phản hồi thành công và broadcast cập nhật
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(true, "Thêm bệnh nhân thành công", queueNumber));
broadcastQueueUpdate();
int maxCurId = SessionManager.getMaxSessionId();
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
UserUtil.sendPacket(sessionId, new SetCounterResponse(queueNumber));
if (!customQueue) { // Nếu STT không chỉ định, thì không cần gửi cho các client
int maxCurId = SessionManager.getMaxSessionId();
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
UserUtil.sendPacket(sessionId, new SetCounterResponse(queueNumber));
}
}
// Tạo thư mục Google Drive bất đồng bộ
createCheckupGoogleDriveFolderAsync(generatedCheckupId, addCheckupRequest.getCustomerId());
Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 B

After

Width:  |  Height:  |  Size: 102 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 514 B