[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.
No files matched your search
|
Before Width: | Height: | Size: 321 KiB |
@@ -0,0 +1,2 @@
|
||||
[LocalizedFileNames]
|
||||
faker.jpg=@faker,0
|
||||
|
Before Width: | Height: | Size: 805 KiB |
@@ -0,0 +1,2 @@
|
||||
[LocalizedFileNames]
|
||||
faker.jpg=@faker,0
|
||||
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 228 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
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());
|
||||
|
||||
|
Before Width: | Height: | Size: 103 B After Width: | Height: | Size: 102 B |
|
Before Width: | Height: | Size: 520 B After Width: | Height: | Size: 514 B |