mirror of
https://github.com/tiennm99/BSK-All-in-One-Clinic-Management-System.git
synced 2026-10-14 10:17:53 +00:00
[update] Enhance CheckUpPage and TemplateDialog with new features. Add template information labels for image count and gender display, implement sorting for templates, and introduce undo/redo functionality in the RTF editor. Update AddDialog to support localized text and improve patient table layout. Modify NavBar for better navigation and update Template entity to include visibility and order number (STT) attributes.
This commit is contained in:
1 parent
9e7741351f
commit
ae803484e0
16 files changed
+444
-77
No files matched your search
@@ -0,0 +1,17 @@
|
||||
#BSK Client Application Settings
|
||||
#Wed Jul 23 13:22:55 ICT 2025
|
||||
app.auto_save=false
|
||||
app.auto_save_interval=5
|
||||
app.language=Ti\u1EBFng Vi\u1EC7t
|
||||
app.theme=T\u1ED1i
|
||||
backup.auto_enabled=false
|
||||
backup.frequency=H\u1EB1ng ng\u00E0y
|
||||
backup.path=
|
||||
clinic.address=Khu v\u1EF1c 5, th\u1ECB tr\u1EA5n \u0110\u1EE9c H\u00F2a, huy\u1EC7n \u0110\u1EE9c H\u00F2a, t\u1EC9nh Long An
|
||||
clinic.name=Ph\u00F2ng kh\u00E1m B\u00E1c S\u0129 Kh\u1EAFp
|
||||
clinic.phone=0912345678
|
||||
server.address=
|
||||
server.auto_connect=false
|
||||
server.port=1999
|
||||
storage.image_path=
|
||||
storage.pdf_path=
|
||||
@@ -0,0 +1,11 @@
|
||||
#BSK Clinic Management System Configuration - Updated via Settings Dialog
|
||||
#Wed Jul 23 13:42:36 ICT 2025
|
||||
clinic.address=S\u1ED1 ABC, \u0110\u01B0\u1EDDng XYZ, Qu\u1EADn 1, TP.HCM
|
||||
clinic.name=Ph\u00F2ng kh\u00E1m BSK
|
||||
clinic.phone=0123456789
|
||||
google.drive.enabled=true
|
||||
google.drive.root.folder=BSK_Clinic_Patient_Files
|
||||
server.address=127.0.0.1
|
||||
server.port=1999
|
||||
storage.checkup_media_base_dir=src/main/resources/image/checkup_media
|
||||
storage.image_db_path=img_db
|
||||
Binary file not shown.
@@ -21,6 +21,6 @@ public class LocalStorage {
|
||||
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
|
||||
public static HashMap<String, String[]> cachedWards; // cache local areas
|
||||
public static HashMap<String, String[]> cachedDistricts; // cache local areas later will do
|
||||
public static HashMap<String, String[]> cachedWards; // cache local areas later will do
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
@@ -41,7 +41,7 @@ public class AddDialog extends JDialog {
|
||||
private JTextField customerAddressField;
|
||||
private DefaultTableModel patientTableModel;
|
||||
private JTable patientTable;
|
||||
private String[] patientColumns = {"Patient ID", "Patient Name", "Patient Year", "Patient Phone" ,"Patient Address"};
|
||||
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;
|
||||
@@ -77,6 +77,11 @@ public class AddDialog extends JDialog {
|
||||
patientData = response.getPatientData();
|
||||
|
||||
patientTableModel.setDataVector(patientData, patientColumns);
|
||||
// Set column widths: id, name, birthyear, sdt, address
|
||||
int[] columnWidths = {60, 180, 70, 120, 300};
|
||||
for (int i = 0; i < columnWidths.length; i++) {
|
||||
patientTable.getColumnModel().getColumn(i).setPreferredWidth(columnWidths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private int findProvinceIndex(String province) {
|
||||
@@ -172,7 +177,7 @@ public class AddDialog extends JDialog {
|
||||
}
|
||||
|
||||
public AddDialog(Frame parent) {
|
||||
super(parent, "Add Patient", true);
|
||||
super(parent, "Thêm Bệnh Nhân", true);
|
||||
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
|
||||
|
||||
// Set size of the dialog
|
||||
@@ -229,6 +234,11 @@ public class AddDialog extends JDialog {
|
||||
patientTable.setFont(textFont);
|
||||
patientTable.setRowHeight(35);
|
||||
patientTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
// Set column widths: id, name, birthyear, sdt, address
|
||||
int[] columnWidths = {60, 180, 70, 120, 300};
|
||||
for (int i = 0; i < columnWidths.length; i++) {
|
||||
patientTable.getColumnModel().getColumn(i).setPreferredWidth(columnWidths[i]);
|
||||
}
|
||||
JScrollPane scrollPane = new JScrollPane(patientTable);
|
||||
|
||||
patientTable.addMouseListener(new MouseAdapter() {
|
||||
@@ -441,7 +451,7 @@ public class AddDialog extends JDialog {
|
||||
gbc.gridx = 2;
|
||||
gbc.gridwidth = 2;
|
||||
gbc.weightx = 0.5;
|
||||
clearButton = new JButton("Clear");
|
||||
clearButton = new JButton("Làm mới");
|
||||
clearButton.setFont(textFont);
|
||||
checkupInfoPanel.add(clearButton, gbc);
|
||||
gbc.weightx = 0.0; // Reset weightx
|
||||
@@ -583,14 +593,14 @@ public class AddDialog extends JDialog {
|
||||
|
||||
|
||||
JPanel ButtonPanel = new JPanel();
|
||||
JButton closeButton = new JButton("Close");
|
||||
JButton closeButton = new JButton("Đóng");
|
||||
closeButton.setFont(labelFont);
|
||||
closeButton.addActionListener(e -> {
|
||||
setVisible(false);
|
||||
});
|
||||
ButtonPanel.add(closeButton);
|
||||
|
||||
saveButton = new JButton("Add to Checkup");
|
||||
saveButton = new JButton("Thêm vào khám");
|
||||
saveButton.setFont(labelFont);
|
||||
saveButton.addActionListener(e -> {
|
||||
int patientId = Integer.parseInt(patientIdField.getText());
|
||||
@@ -646,7 +656,7 @@ 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, "Please fill in all fields");
|
||||
JOptionPane.showMessageDialog(this, "Vui lòng điền đầy đủ thông tin");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -660,7 +670,7 @@ public class AddDialog extends JDialog {
|
||||
patientPhone, address, patientGender, cccd));
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "Invalid date format: " + dateText);
|
||||
JOptionPane.showMessageDialog(null, "Định dạng ngày không hợp lệ: " + dateText);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -765,7 +775,7 @@ public class AddDialog extends JDialog {
|
||||
dobPicker.getModel().setSelected(true);
|
||||
} catch (ParseException | NumberFormatException exception) {
|
||||
exception.printStackTrace();
|
||||
JOptionPane.showMessageDialog(null, "Invalid date format: " + patientDob);
|
||||
JOptionPane.showMessageDialog(null, "Định dạng ngày không hợp lệ: " + patientDob);
|
||||
}
|
||||
saveButton.setEnabled(true); // Enable button after successfully populating fields
|
||||
addPatientButton.setEnabled(false); // Disable add patient button when a patient is selected
|
||||
@@ -850,7 +860,7 @@ public class AddDialog extends JDialog {
|
||||
frame.setLayout(new BorderLayout());
|
||||
frame.setVisible(true);
|
||||
|
||||
JButton openDialogButton = new JButton("Open Dialog");
|
||||
JButton openDialogButton = new JButton("Mở Dialog");
|
||||
openDialogButton.addActionListener(e -> {
|
||||
AddDialog dialog = new AddDialog(frame);
|
||||
dialog.setVisible(true);
|
||||
|
||||
@@ -192,6 +192,10 @@ public class CheckUpPage extends JPanel {
|
||||
private JButton openQueueButton;
|
||||
private JButton addPatientButton;
|
||||
private JButton[] actionButtons;
|
||||
|
||||
// Template info labels
|
||||
private JLabel imageCountValueLabel;
|
||||
private JLabel genderValueLabel;
|
||||
|
||||
private QueueViewPage tvQueueFrame;
|
||||
private QueueManagementPage queueManagementPage; // The new queue window
|
||||
@@ -934,15 +938,40 @@ public class CheckUpPage extends JPanel {
|
||||
templateComboBox.addActionListener(e -> handleTemplateSelection());
|
||||
templatePanel.add(templateComboBox, gbcTemplate);
|
||||
|
||||
// Add template info labels between template selection and orientation
|
||||
gbcTemplate.gridx = 2; gbcTemplate.weightx = 0.0;
|
||||
JLabel imageCountInfoLabel = new JLabel("SL ảnh:");
|
||||
imageCountInfoLabel.setFont(new Font("Arial", Font.PLAIN, 12));
|
||||
imageCountInfoLabel.setForeground(new Color(100, 100, 100));
|
||||
templatePanel.add(imageCountInfoLabel, gbcTemplate);
|
||||
|
||||
gbcTemplate.gridx = 3;
|
||||
imageCountValueLabel = new JLabel("-");
|
||||
imageCountValueLabel.setFont(new Font("Arial", Font.BOLD, 12));
|
||||
imageCountValueLabel.setForeground(new Color(63, 81, 181));
|
||||
templatePanel.add(imageCountValueLabel, gbcTemplate);
|
||||
|
||||
gbcTemplate.gridx = 4;
|
||||
JLabel genderInfoLabel = new JLabel("Giới:");
|
||||
genderInfoLabel.setFont(new Font("Arial", Font.PLAIN, 12));
|
||||
genderInfoLabel.setForeground(new Color(100, 100, 100));
|
||||
templatePanel.add(genderInfoLabel, gbcTemplate);
|
||||
|
||||
gbcTemplate.gridx = 5;
|
||||
genderValueLabel = new JLabel("-");
|
||||
genderValueLabel.setFont(new Font("Arial", Font.BOLD, 12));
|
||||
genderValueLabel.setForeground(new Color(63, 81, 181));
|
||||
templatePanel.add(genderValueLabel, gbcTemplate);
|
||||
|
||||
|
||||
// Add "Thêm mẫu" button next to template combobox
|
||||
// Add orientation dropdown
|
||||
gbcTemplate.gridx = 2; gbcTemplate.weightx = 0.0;
|
||||
gbcTemplate.gridx = 6; gbcTemplate.weightx = 0.0;
|
||||
JLabel orientationLabel = new JLabel("Hướng in:");
|
||||
orientationLabel.setFont(labelFont);
|
||||
templatePanel.add(orientationLabel, gbcTemplate);
|
||||
|
||||
gbcTemplate.gridx = 3;
|
||||
gbcTemplate.gridx = 7;
|
||||
orientationComboBox = new JComboBox<>(new String[]{"ngang", "dọc"});
|
||||
orientationComboBox.setFont(fieldFont);
|
||||
orientationComboBox.setPreferredSize(new Dimension(80, 25));
|
||||
@@ -952,7 +981,7 @@ public class CheckUpPage extends JPanel {
|
||||
templatePanel.add(orientationComboBox, gbcTemplate);
|
||||
|
||||
// Add template button
|
||||
gbcTemplate.gridx = 4; gbcTemplate.weightx = 0.0;
|
||||
gbcTemplate.gridx = 8; gbcTemplate.weightx = 0.0;
|
||||
JButton addTemplateButton = new JButton("Thêm mẫu");
|
||||
addTemplateButton.setFont(fieldFont);
|
||||
addTemplateButton.setBackground(new Color(63, 81, 181));
|
||||
@@ -986,7 +1015,7 @@ public class CheckUpPage extends JPanel {
|
||||
|
||||
notesField = new JTextPane();
|
||||
notesField.setContentType("text/rtf");
|
||||
addSelectAllOnFocus(notesField);
|
||||
// addSelectAllOnFocus(notesField); // Do NOT select all for notes field
|
||||
|
||||
// Set default font and size
|
||||
notesField.setFont(new Font("Times New Roman", Font.PLAIN, 16));
|
||||
@@ -4379,6 +4408,9 @@ public class CheckUpPage extends JPanel {
|
||||
if (selectedTemplateName == null || allTemplates == null || selectedTemplateName.equals("Không sử dụng mẫu")) {
|
||||
// Reset orientation to landscape when no template is selected
|
||||
orientationComboBox.setSelectedItem("ngang");
|
||||
// Clear template info when no template is selected
|
||||
imageCountValueLabel.setText("-");
|
||||
genderValueLabel.setText("-");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4409,12 +4441,28 @@ public class CheckUpPage extends JPanel {
|
||||
templateContent = template.getContent();
|
||||
templateConclusion = template.getConclusion();
|
||||
templateSuggestion = template.getSuggestion();
|
||||
|
||||
// Update template info labels
|
||||
imageCountValueLabel.setText(template.getPhotoNum());
|
||||
genderValueLabel.setText(template.getTemplateGender());
|
||||
}
|
||||
|
||||
private void handleGetAllTemplatesResponse(GetAllTemplatesRes response) {
|
||||
log.info("Get all templates response");
|
||||
this.allTemplates = response.getTemplates();
|
||||
List<Template> templates = response.getTemplates();
|
||||
|
||||
// Sort templates by STT first (ascending), then by name (alphabetical)
|
||||
templates.sort((t1, t2) -> {
|
||||
// First compare by STT (smaller numbers first)
|
||||
int sttCompare = Integer.compare(t1.getStt(), t2.getStt());
|
||||
if (sttCompare != 0) {
|
||||
return sttCompare;
|
||||
}
|
||||
// If STT is the same, compare by template name alphabetically
|
||||
return t1.getTemplateName().compareToIgnoreCase(t2.getTemplateName());
|
||||
});
|
||||
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
templateComboBox.removeAllItems();
|
||||
templateComboBox.addItem("Không sử dụng mẫu");
|
||||
|
||||
+28
-38
@@ -1,15 +1,6 @@
|
||||
<!-- Created with Jaspersoft Studio version 7.0.3.final using JasperReports Library version 7.0.3-41034ca841d452f3305ba55b9042260aaa1ab5dd -->
|
||||
<jasperReport name="Blank_A4_Landscape" language="java" columnCount="1" pageWidth="842" pageHeight="595" columnWidth="802" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e7f9ca7e-f0db-48b0-bef9-93be21b3b0a3">
|
||||
<jasperReport name="Blank_A4_Landscape" language="java" columnCount="1" pageWidth="842" pageHeight="595" orientation="Landscape" columnWidth="802" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="e7f9ca7e-f0db-48b0-bef9-93be21b3b0a3">
|
||||
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="One Empty Record"/>
|
||||
<property name="com.jaspersoft.studio.unit." value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageHeight" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.pageWidth" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.topMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.bottomMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.leftMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.rightMargin" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnWidth" value="pixel"/>
|
||||
<property name="com.jaspersoft.studio.unit.columnSpacing" value="pixel"/>
|
||||
<parameter name="checkupNote" class="java.lang.String"/>
|
||||
<parameter name="checkupDate" class="java.lang.String"/>
|
||||
<parameter name="patientDiagnos" class="java.lang.String"/>
|
||||
@@ -44,6 +35,7 @@
|
||||
<parameter name="checkupBloodPressure" class="java.lang.String"/>
|
||||
<parameter name="checkupHeartBeat" class="java.lang.String"/>
|
||||
<parameter name="checkupWeight" class="java.lang.String"/>
|
||||
<parameter name="templateTitle" class="java.lang.String"/>
|
||||
<parameter name="driveURL" class="java.lang.String"/>
|
||||
<query language="sql"><![CDATA[]]></query>
|
||||
<background splitType="Stretch"/>
|
||||
@@ -52,26 +44,20 @@
|
||||
<columnHeader splitType="Stretch"/>
|
||||
<detail>
|
||||
<band height="540" splitType="Stretch">
|
||||
<element kind="frame" uuid="2b7ec588-953c-4145-87b7-1d861c272fe0" x="0" y="0" width="400" height="525">
|
||||
<element kind="frame" uuid="2b7ec588-953c-4145-87b7-1d861c272fe0" x="0" y="0" width="400" height="539">
|
||||
<element kind="image" uuid="fd80ab38-4cae-409b-84b9-356220d2b1e5" x="0" y="-5" width="70" height="64">
|
||||
<expression><![CDATA[$P{logoImage}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="eb56d4c8-2a0d-45fa-89a2-ad6528f9a99b" x="70" y="0" width="233" height="20" fontName="Times New Roman" fontSize="14.0" bold="true">
|
||||
<element kind="textField" uuid="eb56d4c8-2a0d-45fa-89a2-ad6528f9a99b" x="70" y="0" width="233" height="20" forecolor="#FF0905" fontName="Times New Roman" fontSize="14.0" bold="true">
|
||||
<expression><![CDATA[$P{clinicName}]]></expression>
|
||||
</element>
|
||||
<element kind="staticText" uuid="2677daaf-d0fb-40ad-afaa-513efa16055c" x="70" y="20" width="150" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[Địa chỉ: ]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="796d9ffd-6d2e-4ae3-bdfb-b08183d7d9c0" x="106" y="20" width="193" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="796d9ffd-6d2e-4ae3-bdfb-b08183d7d9c0" x="70" y="20" width="217" height="22" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{clinicAddress}]]></expression>
|
||||
</element>
|
||||
<element kind="staticText" uuid="1a1405ee-b3e4-4e98-ac08-6818bc29e902" x="70" y="36" width="150" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[SĐT:]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="260bb33d-1d11-4178-aceb-3fbf8fcb4b45" x="106" y="36" width="231" height="15" fontName="Times New Roman" fontSize="8.0">
|
||||
<element kind="textField" uuid="260bb33d-1d11-4178-aceb-3fbf8fcb4b45" x="70" y="42" width="162" height="15" fontName="Times New Roman" fontSize="8.0">
|
||||
<expression><![CDATA[$P{clinicPhone}]]></expression>
|
||||
</element>
|
||||
<element kind="staticText" uuid="6f89a93f-2d10-4506-baa5-226bdd047b17" x="0" y="59" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="15.0" bold="true">
|
||||
<element kind="staticText" uuid="6f89a93f-2d10-4506-baa5-226bdd047b17" x="0" y="65" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="14.0" bold="true">
|
||||
<text><![CDATA[I.Thông tin]]></text>
|
||||
</element>
|
||||
<element kind="staticText" uuid="b8dfca43-cf97-49e5-b58d-4667143dba62" x="0" y="79" width="50" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
@@ -86,25 +72,25 @@
|
||||
<element kind="staticText" uuid="bcbb614e-7a4d-48a3-83c2-198e4fb62c5f" x="1" y="109" width="49" height="15" fontName="Times New Roman" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[Địa chỉ:]]></text>
|
||||
</element>
|
||||
<element kind="staticText" uuid="45fe4be1-9e21-459b-aeee-2efc8354f372" x="221" y="80" width="50" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[Bác sĩ:]]></text>
|
||||
<element kind="staticText" uuid="45fe4be1-9e21-459b-aeee-2efc8354f372" x="221" y="80" width="68" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[Bác sĩ chỉ định:]]></text>
|
||||
</element>
|
||||
<element kind="staticText" uuid="f2ff4b17-63cc-4e8c-a3b0-2523f534f21a" x="221" y="94" width="60" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
<text><![CDATA[Ngày khám:]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="1511f53a-b282-41b1-b233-612b6106c07a" x="60" y="79" width="161" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="1511f53a-b282-41b1-b233-612b6106c07a" x="48" y="79" width="172" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{patientName}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="5bdac267-523d-4931-926b-76233ce9b84d" x="60" y="94" width="80" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="5bdac267-523d-4931-926b-76233ce9b84d" x="50" y="94" width="80" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{patientDOB}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="f4df20b4-920c-491e-882b-6e0733cb4866" x="184" y="94" width="36" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{patientGender}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="3b8ac40e-85aa-4ab8-8445-64bcddb8b267" x="60" y="109" width="200" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="3b8ac40e-85aa-4ab8-8445-64bcddb8b267" x="39" y="109" width="361" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{patientAddress}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="db40cdb0-2850-4d66-8430-addc54f90321" x="277" y="80" width="122" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="db40cdb0-2850-4d66-8430-addc54f90321" x="290" y="80" width="110" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{doctorName}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="eb9cf54a-3b50-43c5-8696-cfc1e21bddfe" x="276" y="94" width="124" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
@@ -116,10 +102,10 @@
|
||||
<element kind="textField" uuid="5ae67e13-7a79-437f-bfb8-c720d896720d" x="60" y="124" width="340" height="26" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{patientDiagnos}]]></expression>
|
||||
</element>
|
||||
<element kind="staticText" uuid="b1fa845a-48da-4e45-82b8-8b9d972650f6" x="0" y="184" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="15.0" bold="true">
|
||||
<element kind="staticText" uuid="b1fa845a-48da-4e45-82b8-8b9d972650f6" x="0" y="162" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="14.0" bold="true">
|
||||
<text><![CDATA[II.Nội dung]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="6d652a25-b701-45bd-91ba-750842650004" x="0" y="200" width="400" height="340" markup="rtf" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="6d652a25-b701-45bd-91ba-750842650004" x="0" y="177" width="398" height="362" markup="rtf" fontName="Times New Roman" fontSize="14.0">
|
||||
<expression><![CDATA[$P{checkupNote}]]></expression>
|
||||
</element>
|
||||
<element kind="staticText" uuid="8f720f6a-0257-4556-b3bc-3b81ad4f8099" x="1" y="150" width="59" height="16" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Left">
|
||||
@@ -137,7 +123,7 @@
|
||||
<element kind="textField" uuid="3e1069a6-daea-45c2-b21f-935b49baba45" x="50" y="150" width="50" height="16" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{checkupWeight} +" cm"]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="fb080012-3196-4535-bcd2-e87274c66fa5" x="150" y="150" width="50" height="16" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="fb080012-3196-4535-bcd2-e87274c66fa5" x="147" y="150" width="53" height="16" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{checkupWeight} + " kg"]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="e4185ffe-8712-41e3-a9ff-2be6569dff15" x="243" y="150" width="47" height="16" fontName="Times New Roman" fontSize="10.0">
|
||||
@@ -146,11 +132,15 @@
|
||||
<element kind="textField" uuid="6b0b21be-2ca3-4594-bbe9-34868e13eb1e" x="335" y="150" width="63" height="16" fontName="Times New Roman" fontSize="10.0">
|
||||
<expression><![CDATA[$P{checkupBloodPressure} +" mmHg"]]></expression>
|
||||
</element>
|
||||
<element kind="component" uuid="e8842007-3343-4399-a101-76a302d0755d" x="354" y="8" width="41" height="38">
|
||||
<element kind="component" uuid="e8842007-3343-4399-a101-76a302d0755d" x="352" y="19" width="40" height="37">
|
||||
<component kind="barcode4j:QRCode">
|
||||
<codeExpression><![CDATA[$P{driveURL}]]></codeExpression>
|
||||
</component>
|
||||
</element>
|
||||
<element kind="textField" uuid="9763a634-05c2-4f64-a903-c914455b7ee6" x="70" y="57" width="282" height="20" forecolor="#FF0905" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Center">
|
||||
<printWhenExpression><![CDATA[$P{templateTitle} != null && !$P{templateTitle}.trim().isEmpty()]]></printWhenExpression>
|
||||
<expression><![CDATA["PHIẾU " + $P{templateTitle}]]></expression>
|
||||
</element>
|
||||
</element>
|
||||
<element kind="frame" uuid="a72ffc70-007e-43af-a566-b34e6e07b312" x="400" y="0" width="400" height="540">
|
||||
<element kind="staticText" uuid="246a04b0-2565-4987-b7f3-dd369703035c" x="0" y="340" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="15.0" bold="true">
|
||||
@@ -159,10 +149,10 @@
|
||||
<element kind="staticText" uuid="c53ef0ab-a702-47fc-9b7c-24307a495b30" x="0" y="430" width="100" height="30" forecolor="#FF0905" fontName="Times New Roman" fontSize="15.0" bold="true">
|
||||
<text><![CDATA[Đề nghị:]]></text>
|
||||
</element>
|
||||
<element kind="staticText" uuid="a38b1187-ddb8-4410-9b52-dc041f894b7b" x="247" y="442" width="96" height="15" fontName="Times New Roman" fontSize="10.0" bold="true" hTextAlign="Center">
|
||||
<element kind="staticText" uuid="a38b1187-ddb8-4410-9b52-dc041f894b7b" x="247" y="442" width="96" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Center">
|
||||
<text><![CDATA[Bác sĩ siêu âm]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="b548d99d-bedf-4e90-b13b-bdbc763aa974" x="200" y="516" width="200" height="15" fontName="Times New Roman" fontSize="12.0" bold="true" hTextAlign="Center">
|
||||
<element kind="textField" uuid="b548d99d-bedf-4e90-b13b-bdbc763aa974" x="200" y="513" width="200" height="21" fontName="Times New Roman" fontSize="14.0" bold="true" hTextAlign="Center">
|
||||
<expression><![CDATA[$P{doctorName}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="8bca58ab-0958-40fe-8e51-2a39a9d379a5" x="200" y="521" width="200" height="19" fontName="Times New Roman" pattern="MMMMM dd, yyyy" hTextAlign="Center" vTextAlign="Bottom">
|
||||
@@ -171,18 +161,18 @@
|
||||
<element kind="staticText" uuid="c062ce0e-80cb-4e67-a5d9-d85e769c6c4e" x="0" y="525" width="110" height="14" forecolor="#FF0905" fontName="Times New Roman" fontSize="10.0" bold="true">
|
||||
<text><![CDATA[Tái khám:]]></text>
|
||||
</element>
|
||||
<element kind="textField" uuid="e90ad772-4425-482d-9e75-f2bc66b9084d" x="0" y="358" width="400" height="70" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="e90ad772-4425-482d-9e75-f2bc66b9084d" x="0" y="358" width="400" height="70" fontName="Times New Roman" fontSize="12.0">
|
||||
<expression><![CDATA[$P{checkupConclusion}]]></expression>
|
||||
</element>
|
||||
<element kind="component" uuid="cb28d811-1328-45dc-9461-cfbb88b7eeae" x="-97" y="9" width="50" height="39">
|
||||
<element kind="component" uuid="cb28d811-1328-45dc-9461-cfbb88b7eeae" x="-113" y="19" width="64" height="40">
|
||||
<component kind="barcode4j:Code128">
|
||||
<codeExpression><![CDATA[$P{barcodeNumber}]]></codeExpression>
|
||||
</component>
|
||||
</element>
|
||||
<element kind="textField" uuid="d63165c2-19e2-43ad-8a3f-004e00bffdfe" x="0" y="450" width="230" height="55" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="d63165c2-19e2-43ad-8a3f-004e00bffdfe" x="0" y="450" width="240" height="66" fontName="Times New Roman" fontSize="12.0">
|
||||
<expression><![CDATA[$P{checkupSuggestion}]]></expression>
|
||||
</element>
|
||||
<element kind="textField" uuid="cece8e5b-67db-4019-b52a-bf73abae535e" x="48" y="525" width="150" height="15" fontName="Times New Roman" fontSize="10.0">
|
||||
<element kind="textField" uuid="cece8e5b-67db-4019-b52a-bf73abae535e" x="48" y="525" width="150" height="15" fontName="Times New Roman" fontSize="12.0">
|
||||
<expression><![CDATA[$P{reCheckupDate}]]></expression>
|
||||
</element>
|
||||
<element kind="frame" uuid="2f301804-acfa-4b6f-9f52-236c04fd1197" x="0" y="0" width="400" height="344">
|
||||
@@ -269,7 +259,7 @@
|
||||
<expression><![CDATA[$P{image1}]]></expression>
|
||||
</element>
|
||||
</element>
|
||||
<element kind="staticText" uuid="8f35aa72-22a4-45f0-a35e-8e35e832404e" x="-55" y="46" width="55" height="14" fontName="Times New Roman" fontSize="8.0" bold="false" hTextAlign="Center">
|
||||
<element kind="staticText" uuid="8f35aa72-22a4-45f0-a35e-8e35e832404e" x="-55" y="54" width="55" height="14" fontName="Times New Roman" fontSize="8.0" bold="false" hTextAlign="Center">
|
||||
<printWhenExpression><![CDATA[$P{driveURL} != null && !$P{driveURL}.trim().isEmpty()]]></printWhenExpression>
|
||||
<text><![CDATA[Xem KQ online]]></text>
|
||||
</element>
|
||||
|
||||
+265
-5
@@ -21,6 +21,8 @@ import javax.swing.text.StyledEditorKit;
|
||||
import javax.swing.text.MutableAttributeSet;
|
||||
import javax.swing.text.SimpleAttributeSet;
|
||||
import javax.swing.text.StyleConstants;
|
||||
import javax.swing.undo.UndoManager;
|
||||
import javax.swing.undo.UndoableEditSupport;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
@@ -31,10 +33,12 @@ import BsK.client.network.handler.ClientHandler;
|
||||
import BsK.client.network.handler.ResponseListener;
|
||||
import java.io.StringReader;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import javax.swing.SpinnerModel;
|
||||
import javax.swing.SpinnerNumberModel;
|
||||
import javax.swing.JColorChooser;
|
||||
import java.awt.event.KeyEvent;
|
||||
import javax.swing.text.Document;
|
||||
|
||||
@Slf4j
|
||||
public class TemplateDialog extends JDialog {
|
||||
@@ -45,6 +49,19 @@ public class TemplateDialog extends JDialog {
|
||||
private final ResponseListener<DeleteTemplateRes> deleteTemplateResListener;
|
||||
private List<Template> templates;
|
||||
|
||||
// RTF Enhancement components
|
||||
private UndoManager undoManager;
|
||||
private static List<Color> recentColors = new ArrayList<>();
|
||||
private static final Color[] COMMON_COLORS = {
|
||||
Color.BLACK, Color.RED, Color.BLUE, Color.GREEN,
|
||||
Color.ORANGE, Color.MAGENTA, new Color(128, 0, 128), // Purple
|
||||
new Color(165, 42, 42), // Brown
|
||||
new Color(0, 128, 128), // Teal
|
||||
new Color(128, 128, 0), // Olive
|
||||
new Color(255, 20, 147), // Deep Pink
|
||||
new Color(30, 144, 255) // Dodger Blue
|
||||
};
|
||||
|
||||
// Left panel components
|
||||
private JTextField idField;
|
||||
private JComboBox<String> genderComboBox;
|
||||
@@ -53,6 +70,8 @@ public class TemplateDialog extends JDialog {
|
||||
private JTextArea diagnosisArea;
|
||||
private JComboBox<String> imageCountComboBox;
|
||||
private JComboBox<String> printTypeComboBox;
|
||||
private JTextField sttField;
|
||||
private JCheckBox visibleCheckBox;
|
||||
private JTable templateTable;
|
||||
private DefaultTableModel tableModel;
|
||||
|
||||
@@ -142,8 +161,14 @@ public class TemplateDialog extends JDialog {
|
||||
imageCountComboBox = new JComboBox<>(new String[]{"1", "2", "3", "4", "5", "6"});
|
||||
printTypeComboBox = new JComboBox<>(new String[]{"Ngang", "Dọc"});
|
||||
|
||||
sttField = new JTextField(10);
|
||||
sttField.setToolTipText("Số thứ tự để sắp xếp mẫu (0 = mặc định)");
|
||||
|
||||
visibleCheckBox = new JCheckBox("Ẩn");
|
||||
visibleCheckBox.setToolTipText("Đánh dấu để ẩn mẫu này khỏi danh sách hiển thị");
|
||||
|
||||
// Table for template list
|
||||
String[] columnNames = {"ID", "Tên mẫu"};
|
||||
String[] columnNames = {"ID", "STT", "Tên mẫu"};
|
||||
tableModel = new DefaultTableModel(columnNames, 0) {
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
@@ -153,12 +178,32 @@ public class TemplateDialog extends JDialog {
|
||||
templateTable = new JTable(tableModel);
|
||||
templateTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
// Set bigger font for better visibility
|
||||
templateTable.setFont(new Font("Arial", Font.PLAIN, 14));
|
||||
templateTable.getTableHeader().setFont(new Font("Arial", Font.BOLD, 14));
|
||||
templateTable.setRowHeight(25); // Increase row height for better readability
|
||||
|
||||
// Initialize recent colors if empty
|
||||
if (recentColors.isEmpty()) {
|
||||
recentColors.add(Color.BLACK);
|
||||
recentColors.add(Color.RED);
|
||||
recentColors.add(Color.BLUE);
|
||||
}
|
||||
|
||||
// Right panel components
|
||||
contentRTFField = new JTextPane();
|
||||
contentRTFField.setContentType("text/rtf");
|
||||
contentRTFField.setEditorKit(new RTFEditorKit());
|
||||
contentRTFField.setFont(new Font("Times New Roman", Font.PLAIN, 16)); // Set default font
|
||||
|
||||
// Set up undo manager
|
||||
undoManager = new UndoManager();
|
||||
Document doc = contentRTFField.getDocument();
|
||||
doc.addUndoableEditListener(undoManager);
|
||||
|
||||
// Add keyboard shortcuts for formatting and undo/redo
|
||||
setupRTFKeyboardShortcuts();
|
||||
|
||||
conclusionField = new JTextArea(5, 20);
|
||||
conclusionField.setLineWrap(true);
|
||||
conclusionField.setWrapStyleWord(true);
|
||||
@@ -279,6 +324,15 @@ public class TemplateDialog extends JDialog {
|
||||
gbc.gridx = 3;
|
||||
infoPanel.add(printTypeComboBox, gbc);
|
||||
|
||||
// Row 7: STT and Visible checkbox
|
||||
gbc.gridx = 0; gbc.gridy = 7; gbc.gridwidth = 1;
|
||||
infoPanel.add(new JLabel("STT:"), gbc);
|
||||
gbc.gridx = 1;
|
||||
infoPanel.add(sttField, gbc);
|
||||
|
||||
gbc.gridx = 2; gbc.gridwidth = 2;
|
||||
infoPanel.add(visibleCheckBox, gbc);
|
||||
|
||||
leftPanel.add(infoPanel, BorderLayout.CENTER);
|
||||
|
||||
// Template table at bottom
|
||||
@@ -314,6 +368,13 @@ public class TemplateDialog extends JDialog {
|
||||
new Color(63, 81, 181)
|
||||
));
|
||||
|
||||
// Add recommendation label
|
||||
JLabel recommendLabel = new JLabel("Chú thích: Nên dùng font từ 20 đến 24, font chữ Times New Roman.");
|
||||
recommendLabel.setFont(new Font("Arial", Font.ITALIC, 13));
|
||||
recommendLabel.setForeground(new Color(200, 60, 60));
|
||||
recommendLabel.setBorder(BorderFactory.createEmptyBorder(2, 4, 2, 4));
|
||||
contentPanel.add(recommendLabel, BorderLayout.SOUTH);
|
||||
|
||||
// Create formatting toolbar for RTF content
|
||||
JToolBar contentToolbar = createContentToolbar();
|
||||
contentPanel.add(contentToolbar, BorderLayout.NORTH);
|
||||
@@ -421,6 +482,29 @@ public class TemplateDialog extends JDialog {
|
||||
underlineButton.setToolTipText("Gạch chân (Ctrl+U)");
|
||||
underlineButton.setPreferredSize(new Dimension(30, 25));
|
||||
|
||||
// Undo and Redo buttons
|
||||
JButton undoButton = new JButton("↶");
|
||||
undoButton.setFont(new Font("Arial", Font.BOLD, 14));
|
||||
undoButton.setFocusPainted(false);
|
||||
undoButton.setToolTipText("Hoàn tác (Ctrl+Z)");
|
||||
undoButton.setPreferredSize(new Dimension(30, 25));
|
||||
undoButton.addActionListener(e -> {
|
||||
if (undoManager.canUndo()) {
|
||||
undoManager.undo();
|
||||
}
|
||||
});
|
||||
|
||||
JButton redoButton = new JButton("↷");
|
||||
redoButton.setFont(new Font("Arial", Font.BOLD, 14));
|
||||
redoButton.setFocusPainted(false);
|
||||
redoButton.setToolTipText("Làm lại (Ctrl+Y)");
|
||||
redoButton.setPreferredSize(new Dimension(30, 25));
|
||||
redoButton.addActionListener(e -> {
|
||||
if (undoManager.canRedo()) {
|
||||
undoManager.redo();
|
||||
}
|
||||
});
|
||||
|
||||
// Color chooser button
|
||||
JButton colorButton = new JButton("Màu");
|
||||
colorButton.setFont(new Font("Arial", Font.PLAIN, 11));
|
||||
@@ -428,16 +512,21 @@ public class TemplateDialog extends JDialog {
|
||||
colorButton.setToolTipText("Chọn màu chữ");
|
||||
colorButton.setPreferredSize(new Dimension(50, 25));
|
||||
colorButton.addActionListener(e -> {
|
||||
Color newColor = JColorChooser.showDialog(TemplateDialog.this, "Chọn màu chữ", contentRTFField.getForeground());
|
||||
Color newColor = showCustomColorChooser();
|
||||
if (newColor != null) {
|
||||
MutableAttributeSet attr = new SimpleAttributeSet();
|
||||
StyleConstants.setForeground(attr, newColor);
|
||||
contentRTFField.setCharacterAttributes(attr, false);
|
||||
addToRecentColors(newColor);
|
||||
}
|
||||
});
|
||||
|
||||
// Add components to toolbar with spacing
|
||||
contentToolbar.add(Box.createHorizontalStrut(3));
|
||||
contentToolbar.add(undoButton);
|
||||
contentToolbar.addSeparator(new Dimension(3, 0));
|
||||
contentToolbar.add(redoButton);
|
||||
contentToolbar.addSeparator(new Dimension(8, 0));
|
||||
contentToolbar.add(fontFamilyComboBox);
|
||||
contentToolbar.addSeparator(new Dimension(5, 0));
|
||||
contentToolbar.add(sizeSpinner);
|
||||
@@ -466,6 +555,137 @@ public class TemplateDialog extends JDialog {
|
||||
return contentToolbar;
|
||||
}
|
||||
|
||||
private void setupRTFKeyboardShortcuts() {
|
||||
InputMap inputMap = contentRTFField.getInputMap(JComponent.WHEN_FOCUSED);
|
||||
ActionMap actionMap = contentRTFField.getActionMap();
|
||||
|
||||
// Undo/Redo shortcuts
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Z, KeyEvent.CTRL_DOWN_MASK), "undo");
|
||||
actionMap.put("undo", new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (undoManager.canUndo()) {
|
||||
undoManager.undo();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_Y, KeyEvent.CTRL_DOWN_MASK), "redo");
|
||||
actionMap.put("redo", new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
if (undoManager.canRedo()) {
|
||||
undoManager.redo();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Format shortcuts - Bold, Italic, Underline
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_B, KeyEvent.CTRL_DOWN_MASK), "bold");
|
||||
actionMap.put("bold", new StyledEditorKit.BoldAction());
|
||||
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_DOWN_MASK), "italic");
|
||||
actionMap.put("italic", new StyledEditorKit.ItalicAction());
|
||||
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_U, KeyEvent.CTRL_DOWN_MASK), "underline");
|
||||
actionMap.put("underline", new StyledEditorKit.UnderlineAction());
|
||||
}
|
||||
|
||||
private Color showCustomColorChooser() {
|
||||
JDialog colorDialog = new JDialog(this, "Chọn màu chữ", true);
|
||||
colorDialog.setSize(400, 300);
|
||||
colorDialog.setLocationRelativeTo(this);
|
||||
colorDialog.setResizable(false);
|
||||
|
||||
JPanel mainPanel = new JPanel(new BorderLayout(10, 10));
|
||||
mainPanel.setBorder(BorderFactory.createEmptyBorder(15, 15, 15, 15));
|
||||
|
||||
// Recent colors panel
|
||||
JPanel recentPanel = new JPanel(new GridLayout(1, Math.min(recentColors.size(), 6), 5, 5));
|
||||
recentPanel.setBorder(BorderFactory.createTitledBorder("Màu gần đây"));
|
||||
|
||||
final Color[] selectedColor = new Color[1];
|
||||
|
||||
for (Color color : recentColors) {
|
||||
JButton colorBtn = createColorButton(color, selectedColor, colorDialog);
|
||||
recentPanel.add(colorBtn);
|
||||
}
|
||||
|
||||
// Common colors panel
|
||||
JPanel commonPanel = new JPanel(new GridLayout(3, 4, 5, 5));
|
||||
commonPanel.setBorder(BorderFactory.createTitledBorder("Màu thông dụng"));
|
||||
|
||||
for (Color color : COMMON_COLORS) {
|
||||
JButton colorBtn = createColorButton(color, selectedColor, colorDialog);
|
||||
commonPanel.add(colorBtn);
|
||||
}
|
||||
|
||||
// More colors button
|
||||
JPanel buttonPanel = new JPanel(new FlowLayout());
|
||||
JButton moreColorsBtn = new JButton("Màu khác...");
|
||||
moreColorsBtn.addActionListener(e -> {
|
||||
Color customColor = JColorChooser.showDialog(colorDialog, "Chọn màu tùy chỉnh", Color.BLACK);
|
||||
if (customColor != null) {
|
||||
selectedColor[0] = customColor;
|
||||
colorDialog.dispose();
|
||||
}
|
||||
});
|
||||
buttonPanel.add(moreColorsBtn);
|
||||
|
||||
JButton cancelBtn = new JButton("Hủy");
|
||||
cancelBtn.addActionListener(e -> {
|
||||
selectedColor[0] = null;
|
||||
colorDialog.dispose();
|
||||
});
|
||||
buttonPanel.add(cancelBtn);
|
||||
|
||||
mainPanel.add(recentPanel, BorderLayout.NORTH);
|
||||
mainPanel.add(commonPanel, BorderLayout.CENTER);
|
||||
mainPanel.add(buttonPanel, BorderLayout.SOUTH);
|
||||
|
||||
colorDialog.add(mainPanel);
|
||||
colorDialog.setVisible(true);
|
||||
|
||||
return selectedColor[0];
|
||||
}
|
||||
|
||||
private JButton createColorButton(Color color, Color[] selectedColor, JDialog parentDialog) {
|
||||
JButton colorBtn = new JButton();
|
||||
colorBtn.setBackground(color);
|
||||
colorBtn.setPreferredSize(new Dimension(40, 30));
|
||||
colorBtn.setBorder(BorderFactory.createCompoundBorder(
|
||||
BorderFactory.createLineBorder(Color.GRAY, 1),
|
||||
BorderFactory.createEmptyBorder(2, 2, 2, 2)
|
||||
));
|
||||
colorBtn.setToolTipText(getColorName(color));
|
||||
colorBtn.addActionListener(e -> {
|
||||
selectedColor[0] = color;
|
||||
parentDialog.dispose();
|
||||
});
|
||||
return colorBtn;
|
||||
}
|
||||
|
||||
private String getColorName(Color color) {
|
||||
if (color.equals(Color.BLACK)) return "Đen";
|
||||
if (color.equals(Color.RED)) return "Đỏ";
|
||||
if (color.equals(Color.BLUE)) return "Xanh dương";
|
||||
if (color.equals(Color.GREEN)) return "Xanh lá";
|
||||
if (color.equals(Color.ORANGE)) return "Cam";
|
||||
if (color.equals(Color.MAGENTA)) return "Tím hồng";
|
||||
return String.format("RGB(%d,%d,%d)", color.getRed(), color.getGreen(), color.getBlue());
|
||||
}
|
||||
|
||||
private void addToRecentColors(Color newColor) {
|
||||
// Remove if already exists
|
||||
recentColors.remove(newColor);
|
||||
// Add to front
|
||||
recentColors.add(0, newColor);
|
||||
// Keep only last 6 colors
|
||||
if (recentColors.size() > 6) {
|
||||
recentColors.remove(recentColors.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
// TODO: Add listeners for all buttons and table selection
|
||||
|
||||
@@ -488,6 +708,7 @@ public class TemplateDialog extends JDialog {
|
||||
}
|
||||
String templatePrintType = printTypeComboBox.getSelectedItem().toString();
|
||||
String templateGender = genderComboBox.getSelectedItem().toString();
|
||||
int templateStt = Integer.parseInt(sttField.getText().trim().isEmpty() ? "0" : sttField.getText().trim());
|
||||
log.info("Template name: {}", templateName);
|
||||
log.info("Template title: {}", templateTitle);
|
||||
log.info("Template diagnosis: {}", templateDiagnosis);
|
||||
@@ -497,9 +718,10 @@ public class TemplateDialog extends JDialog {
|
||||
log.info("Template print type: {}", templatePrintType);
|
||||
log.info("Template gender: {}", templateGender);
|
||||
log.info("Template content: {}", templateContent);
|
||||
log.info("Template STT: {}", templateStt);
|
||||
|
||||
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new AddTemplateReq(templateName, templateTitle, templateDiagnosis, templateConclusion,
|
||||
templateSuggestion, templateImageCount, templatePrintType, templateGender, templateContent));
|
||||
templateSuggestion, templateImageCount, templatePrintType, templateGender, templateContent, !visibleCheckBox.isSelected(), templateStt));
|
||||
|
||||
});
|
||||
|
||||
@@ -543,7 +765,26 @@ public class TemplateDialog extends JDialog {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
tableModel.setRowCount(0);
|
||||
for (Template template : templates) {
|
||||
tableModel.addRow(new Object[]{template.getTemplateId(), template.getTemplateName()});
|
||||
tableModel.addRow(new Object[]{template.getTemplateId(), template.getStt(), template.getTemplateName()});
|
||||
}
|
||||
|
||||
// Set column widths after data is loaded - ID and STT much smaller
|
||||
if (templateTable.getColumnCount() >= 3) {
|
||||
templateTable.getColumnModel().getColumn(0).setPreferredWidth(50); // ID column - much smaller
|
||||
templateTable.getColumnModel().getColumn(0).setMaxWidth(60);
|
||||
templateTable.getColumnModel().getColumn(0).setMinWidth(40);
|
||||
|
||||
templateTable.getColumnModel().getColumn(1).setPreferredWidth(50); // STT column - much smaller
|
||||
templateTable.getColumnModel().getColumn(1).setMaxWidth(60);
|
||||
templateTable.getColumnModel().getColumn(1).setMinWidth(40);
|
||||
|
||||
templateTable.getColumnModel().getColumn(2).setPreferredWidth(200); // Template name - larger
|
||||
|
||||
// Center align ID and STT columns for better appearance
|
||||
javax.swing.table.DefaultTableCellRenderer centerRenderer = new javax.swing.table.DefaultTableCellRenderer();
|
||||
centerRenderer.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
|
||||
templateTable.getColumnModel().getColumn(0).setCellRenderer(centerRenderer); // ID
|
||||
templateTable.getColumnModel().getColumn(1).setCellRenderer(centerRenderer); // STT
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -556,6 +797,8 @@ public class TemplateDialog extends JDialog {
|
||||
diagnosisArea.setText(template.getDiagnosis());
|
||||
imageCountComboBox.setSelectedItem(template.getPhotoNum());
|
||||
printTypeComboBox.setSelectedItem(template.getPrintType());
|
||||
sttField.setText(String.valueOf(template.getStt()));
|
||||
visibleCheckBox.setSelected(!template.isVisible()); // Checkbox is "Ẩn" so inverted logic
|
||||
conclusionField.setText(template.getConclusion());
|
||||
suggestionField.setText(template.getSuggestion());
|
||||
|
||||
@@ -564,9 +807,15 @@ public class TemplateDialog extends JDialog {
|
||||
RTFEditorKit rtfEditorKit = (RTFEditorKit) contentRTFField.getEditorKit();
|
||||
StringReader reader = new StringReader(template.getContent());
|
||||
rtfEditorKit.read(reader, contentRTFField.getDocument(), 0);
|
||||
|
||||
// Reset undo manager after loading new content
|
||||
undoManager.discardAllEdits();
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to load RTF content for template ID {}", template.getTemplateId(), ex);
|
||||
contentRTFField.setText(template.getContent()); // Fallback to plain text
|
||||
|
||||
// Reset undo manager even in fallback case
|
||||
undoManager.discardAllEdits();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -586,6 +835,8 @@ public class TemplateDialog extends JDialog {
|
||||
log.error("Could not get RTF text from contentRTFField", ex);
|
||||
}
|
||||
|
||||
int templateStt = Integer.parseInt(sttField.getText().trim().isEmpty() ? "0" : sttField.getText().trim());
|
||||
|
||||
Template template = new Template(
|
||||
Integer.parseInt(idField.getText()),
|
||||
genderComboBox.getSelectedItem().toString(),
|
||||
@@ -596,7 +847,9 @@ public class TemplateDialog extends JDialog {
|
||||
templateContent,
|
||||
conclusionField.getText(),
|
||||
suggestionField.getText(),
|
||||
diagnosisArea.getText()
|
||||
diagnosisArea.getText(),
|
||||
!visibleCheckBox.isSelected(), // Checkbox is "Ẩn" so inverted logic
|
||||
templateStt
|
||||
);
|
||||
|
||||
NetworkUtil.sendPacket(ClientHandler.ctx.channel(), new EditTemplateReq(template));
|
||||
@@ -652,8 +905,15 @@ public class TemplateDialog extends JDialog {
|
||||
diagnosisArea.setText("");
|
||||
imageCountComboBox.setSelectedIndex(0);
|
||||
printTypeComboBox.setSelectedIndex(0);
|
||||
sttField.setText("0"); // Default STT to 0
|
||||
visibleCheckBox.setSelected(false); // Default to visible (not hidden)
|
||||
contentRTFField.setText("");
|
||||
conclusionField.setText("");
|
||||
suggestionField.setText("");
|
||||
|
||||
// Reset undo manager when clearing fields
|
||||
if (undoManager != null) {
|
||||
undoManager.discardAllEdits();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,9 +71,9 @@ public class NavBar extends JPanel {
|
||||
welcomePanel.add(welcomeLabel);
|
||||
userPanel.add(welcomePanel, new GridBagConstraints());
|
||||
|
||||
String[] navBarItems = {"Thống kê", "Thăm khám", "Dữ liệu", "Kho", "Thanh toán", "Người dùng", "Thông tin"};
|
||||
String[] destination = {"DashboardPage", "CheckUpPage", "PatientDataPage", "InventoryPage", "CheckoutPage", "UserPage", "InfoPage"};
|
||||
String[] iconFiles = {"dashboard.png", "health-check.png", "database.png", "warehouse.png", "cashier-machine.png", "user.png", "info.png"};
|
||||
String[] navBarItems = {"Thống kê", "Thăm khám", "Dữ liệu", "Kho", "Thanh toán", "Cài đặt", "Thông tin"};
|
||||
String[] destination = {"DashboardPage", "CheckUpPage", "PatientDataPage", "InventoryPage", "CheckoutPage", "SettingsPage", "InfoPage"};
|
||||
String[] iconFiles = {"dashboard.png", "health-check.png", "database.png", "warehouse.png", "cashier-machine.png", "settings.png", "info.png"};
|
||||
Color[] navItemColors = {
|
||||
new Color(51, 135, 204), // Darker Blue
|
||||
new Color(66, 157, 21), // Darker Green
|
||||
|
||||
@@ -18,4 +18,6 @@ public class Template {
|
||||
private String conclusion;
|
||||
private String suggestion;
|
||||
private String diagnosis;
|
||||
private boolean visible = true; // Default to true (visible)
|
||||
private int stt = 0; // STT (số thứ tự) - order number, default to 0
|
||||
}
|
||||
@@ -18,4 +18,6 @@ public class AddTemplateReq implements Packet {
|
||||
private String templatePrintType;
|
||||
private String templateGender;
|
||||
private String templateContent;
|
||||
private boolean visible = true; // Default to true (visible)
|
||||
private int stt = 0; // STT (số thứ tự) - order number, default to 0
|
||||
}
|
||||
@@ -40,6 +40,8 @@ public class Server {
|
||||
public static GoogleDriveServiceOAuth googleDriveService;
|
||||
private static boolean googleDriveEnabled = true; // Can be configured
|
||||
private static String googleDriveRootFolderName = "BSK_Clinic_Patient_Files"; // Default
|
||||
public static String imageDbPath = "img_db"; // Default
|
||||
public static String checkupMediaBaseDir = "src/main/resources/image/checkup_media"; // Default
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -99,6 +101,20 @@ public class Server {
|
||||
log.info("Google Drive integration enabled: {}", googleDriveEnabled);
|
||||
log.info("Google Drive root folder: {}", googleDriveRootFolderName);
|
||||
|
||||
// Get Storage paths configuration
|
||||
String imageDbPathStr = props.getProperty("storage.image_db_path");
|
||||
if (imageDbPathStr != null && !imageDbPathStr.trim().isEmpty()) {
|
||||
imageDbPath = imageDbPathStr.trim();
|
||||
}
|
||||
|
||||
String checkupMediaBaseDirStr = props.getProperty("storage.checkup_media_base_dir");
|
||||
if (checkupMediaBaseDirStr != null && !checkupMediaBaseDirStr.trim().isEmpty()) {
|
||||
checkupMediaBaseDir = checkupMediaBaseDirStr.trim();
|
||||
}
|
||||
|
||||
log.info("Image DB path: {}", imageDbPath);
|
||||
log.info("Checkup media base dir: {}", checkupMediaBaseDir);
|
||||
|
||||
// Directly use the provided database path
|
||||
String dbPath = "src/main/resources/database/BSK.db";
|
||||
connection = DriverManager.getConnection("jdbc:sqlite:" + dbPath);
|
||||
|
||||
@@ -50,9 +50,6 @@ import static BsK.server.Server.statement;
|
||||
@Slf4j
|
||||
public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
||||
|
||||
private static final String IMAGE_DB_PATH = "img_db";
|
||||
private static final String CHECKUP_MEDIA_BASE_DIR = "src/main/resources/image/checkup_media";
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
|
||||
log.debug("Received message: {}", frame.text());
|
||||
@@ -1129,11 +1126,13 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
String templatePrintType = addTemplateReq.getTemplatePrintType();
|
||||
String templateGender = addTemplateReq.getTemplateGender();
|
||||
String templateContent = addTemplateReq.getTemplateContent();
|
||||
boolean templateVisible = addTemplateReq.isVisible();
|
||||
int templateStt = addTemplateReq.getStt();
|
||||
try {
|
||||
PreparedStatement templateStmt = Server.connection.prepareStatement(
|
||||
"""
|
||||
INSERT INTO CheckupTemplate (template_gender, template_name, template_title, photo_num, print_type, content, conclusion, suggestion, diagnosis)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO CheckupTemplate (template_gender, template_name, template_title, photo_num, print_type, content, conclusion, suggestion, diagnosis, visible, stt)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""");
|
||||
templateStmt.setString(1, templateGender);
|
||||
templateStmt.setString(2, templateName);
|
||||
@@ -1144,6 +1143,8 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
templateStmt.setString(7, templateConclusion);
|
||||
templateStmt.setString(8, templateSuggestion);
|
||||
templateStmt.setString(9, templateDiagnosis);
|
||||
templateStmt.setBoolean(10, templateVisible);
|
||||
templateStmt.setInt(11, templateStt);
|
||||
templateStmt.executeUpdate();
|
||||
log.info("Template saved successfully");
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new AddTemplateRes(true, "Template saved successfully"));
|
||||
@@ -1169,7 +1170,9 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
rs.getString("content"),
|
||||
rs.getString("conclusion"),
|
||||
rs.getString("suggestion"),
|
||||
rs.getString("diagnosis")
|
||||
rs.getString("diagnosis"),
|
||||
rs.getBoolean("visible"),
|
||||
rs.getInt("stt")
|
||||
));
|
||||
}
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new GetAllTemplatesRes(templates));
|
||||
@@ -1184,7 +1187,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
try {
|
||||
PreparedStatement stmt = Server.connection.prepareStatement(
|
||||
"""
|
||||
UPDATE CheckupTemplate SET template_gender = ?, template_name = ?, template_title = ?, photo_num = ?, print_type = ?, content = ?, conclusion = ?, suggestion = ?, diagnosis = ?
|
||||
UPDATE CheckupTemplate SET template_gender = ?, template_name = ?, template_title = ?, photo_num = ?, print_type = ?, content = ?, conclusion = ?, suggestion = ?, diagnosis = ?, visible = ?, stt = ?
|
||||
WHERE template_id = ?
|
||||
"""
|
||||
);
|
||||
@@ -1197,7 +1200,9 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
stmt.setString(7, template.getConclusion());
|
||||
stmt.setString(8, template.getSuggestion());
|
||||
stmt.setString(9, template.getDiagnosis());
|
||||
stmt.setInt(10, template.getTemplateId());
|
||||
stmt.setBoolean(10, template.isVisible());
|
||||
stmt.setInt(11, template.getStt());
|
||||
stmt.setInt(12, template.getTemplateId());
|
||||
stmt.executeUpdate();
|
||||
log.info("Template updated successfully");
|
||||
UserUtil.sendPacket(currentUser.getSessionId(), new EditTemplateRes(true, "Template updated successfully"));
|
||||
@@ -1234,7 +1239,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
try {
|
||||
// 1. Define and create storage directory
|
||||
Path storageDir = Paths.get(IMAGE_DB_PATH, checkupId.trim());
|
||||
Path storageDir = Paths.get(Server.imageDbPath, checkupId.trim());
|
||||
Files.createDirectories(storageDir); // Create dirs if they don't exist
|
||||
|
||||
// 2. Save the file
|
||||
@@ -1275,7 +1280,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
try {
|
||||
// 1. Define and create storage directory (use same img_db structure)
|
||||
Path storageDir = Paths.get(IMAGE_DB_PATH, checkupId.trim());
|
||||
Path storageDir = Paths.get(Server.imageDbPath, checkupId.trim());
|
||||
Files.createDirectories(storageDir); // Create dirs if they don't exist
|
||||
|
||||
// 2. Save the PDF file (with override behavior - same name = override)
|
||||
@@ -1305,7 +1310,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
List<String> imageNames = new ArrayList<>();
|
||||
List<byte[]> imageDatas = new ArrayList<>();
|
||||
|
||||
Path checkupDir = Paths.get(IMAGE_DB_PATH, checkupId);
|
||||
Path checkupDir = Paths.get(Server.imageDbPath, checkupId);
|
||||
if (Files.exists(checkupDir) && Files.isDirectory(checkupDir)) {
|
||||
try {
|
||||
List<Path> imagePaths = Files.list(checkupDir)
|
||||
@@ -1582,8 +1587,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
// Get checkup's Google Drive folder ID from database
|
||||
PreparedStatement checkupStmt = Server.connection.prepareStatement(
|
||||
"SELECT drive_folder_id FROM Checkup WHERE checkup_id = ?"
|
||||
);
|
||||
"SELECT drive_folder_id FROM Checkup WHERE checkup_id = ?");
|
||||
checkupStmt.setString(1, checkupId);
|
||||
ResultSet checkupRs = checkupStmt.executeQuery();
|
||||
|
||||
@@ -1682,8 +1686,7 @@ public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFram
|
||||
|
||||
// Get checkup's Google Drive folder ID from database
|
||||
PreparedStatement checkupStmt = Server.connection.prepareStatement(
|
||||
"SELECT drive_folder_id FROM Checkup WHERE checkup_id = ?"
|
||||
);
|
||||
"SELECT drive_folder_id FROM Checkup WHERE checkup_id = ?");
|
||||
checkupStmt.setString(1, checkupId);
|
||||
ResultSet checkupRs = checkupStmt.executeQuery();
|
||||
|
||||
|
||||
@@ -20,4 +20,12 @@ google.drive.enabled=true
|
||||
# Root folder name in Google Drive where all patient folders will be created
|
||||
# This folder will remain private, only individual patient folders will be shared
|
||||
# Use alphanumeric characters, dots, dashes, and underscores only
|
||||
google.drive.root.folder=BSK_Clinic_Patient_Files
|
||||
google.drive.root.folder=BSK_Clinic_Patient_Files
|
||||
|
||||
# Storage paths
|
||||
# -------------
|
||||
# The local path for storing checkup-related images and PDFs.
|
||||
storage.image_db_path=img_db
|
||||
|
||||
# The base directory for checkup media resources (currently unused but defined for future use).
|
||||
storage.checkup_media_base_dir=src/main/resources/image/checkup_media
|
||||
Binary file not shown.
Reference in new issue
Block a user