mirror of
https://github.com/tiennm99/BSK-All-in-One-Clinic-Management-System.git
synced 2026-10-11 14:13:07 +00:00
2394 lines
124 KiB
Java
2394 lines
124 KiB
Java
package BsK.server.network.handler;
|
|
|
|
import BsK.common.packet.Packet;
|
|
import BsK.server.database.DatabaseManager;
|
|
import BsK.common.packet.PacketSerializer;
|
|
import BsK.common.packet.req.*;
|
|
import BsK.common.packet.res.*;
|
|
import BsK.common.Error;
|
|
import BsK.common.entity.Status;
|
|
import BsK.common.util.date.DateUtils;
|
|
import BsK.server.Server;
|
|
import BsK.server.ServerDashboard;
|
|
import BsK.server.network.manager.SessionManager;
|
|
import BsK.server.network.util.UserUtil;
|
|
import BsK.server.network.entity.Role;
|
|
import BsK.server.network.entity.User;
|
|
import io.netty.channel.ChannelHandlerContext;
|
|
import io.netty.channel.SimpleChannelInboundHandler;
|
|
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
|
|
import io.netty.handler.codec.http.websocketx.Utf8FrameValidator;
|
|
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.HandshakeComplete;
|
|
import io.netty.handler.timeout.IdleState;
|
|
import io.netty.handler.timeout.IdleStateEvent;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import javax.imageio.ImageIO;
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Timestamp;
|
|
import java.text.SimpleDateFormat;
|
|
import java.util.ArrayList;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.time.ZoneId;
|
|
import java.time.LocalDate;
|
|
import java.util.stream.Collectors;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
import BsK.common.entity.Medicine;
|
|
import BsK.common.entity.Service;
|
|
import BsK.common.entity.PatientHistory;
|
|
import BsK.common.entity.Template;
|
|
import BsK.common.util.text.TextUtils;
|
|
import java.time.Instant;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
|
|
|
|
|
|
@Slf4j
|
|
public class ServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
|
|
|
|
@Override
|
|
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) {
|
|
// Update last activity time for the client
|
|
var connectedUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
if (connectedUser != null) {
|
|
ServerDashboard.getInstance().refreshNetworkTable();
|
|
}
|
|
|
|
Packet packet = PacketSerializer.GSON.fromJson(frame.text(), Packet.class);
|
|
|
|
|
|
if (packet instanceof LoginRequest loginRequest) {
|
|
log.debug(
|
|
"Received login request: {}, {}", loginRequest.getUsername(), loginRequest.getPassword());
|
|
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
user.authenticate(loginRequest.getUsername(), loginRequest.getPassword());
|
|
|
|
if (user.isAuthenticated()) {
|
|
UserUtil.sendPacket(user.getSessionId(), new LoginSuccessResponse(user.getUserId(), user.getRole()));
|
|
log.info("Send response to client User {} authenticated, role {}, session {}", user.getUserId(), user.getRole(), user.getSessionId());
|
|
// Update client connection info
|
|
SessionManager.updateUserRole(ctx.channel().id().asLongText(), user.getRole().toString(), user.getUserId());
|
|
} else {
|
|
log.info("User {} failed to authenticate", user.getUserId());
|
|
UserUtil.sendPacket(user.getSessionId(), new ErrorResponse(Error.INVALID_CREDENTIALS));
|
|
}
|
|
} else if (packet instanceof RegisterRequest registerRequest) {
|
|
log.debug(
|
|
"Received register request: {}, {}",
|
|
registerRequest.getUsername(),
|
|
registerRequest.getPassword());
|
|
// Tạo user trong database hoặc check exist
|
|
boolean isUserExist = false;
|
|
} else if (packet instanceof LogoutRequest) {
|
|
var logoutUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
if (logoutUser != null) {
|
|
log.info("User {} (Session {}) requested logout.", logoutUser.getUserId(), logoutUser.getSessionId());
|
|
logoutUser.resetAuthentication();
|
|
} else {
|
|
log.warn("Received LogoutRequest from a channel with no active user session: {}", ctx.channel().id().asLongText());
|
|
}
|
|
} else {
|
|
// Check if user is authenticated
|
|
var currentUser = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
if (currentUser == null || !currentUser.isAuthenticated()) {
|
|
log.warn("Received packet from unauthenticated user: {}", packet);
|
|
return;
|
|
}
|
|
|
|
if (packet instanceof GetCheckUpQueueRequest) {
|
|
log.debug("Received GetCheckUpQueueRequest");
|
|
|
|
String sql = """
|
|
SELECT
|
|
a.checkup_id, a.checkup_date, c.customer_last_name, c.customer_first_name,
|
|
d.doctor_first_name, d.doctor_last_name, a.suggestion, a.diagnosis, a.notes,
|
|
a.status, a.customer_id, c.customer_number, c.customer_address,
|
|
a.customer_weight, a.customer_height, c.customer_gender, c.customer_dob,
|
|
a.checkup_type, a.conclusion, a.reCheckupDate, c.cccd_ddcn, a.heart_beat,
|
|
a.blood_pressure, c.drive_url, a.doctor_ultrasound_id, a.queue_number
|
|
FROM
|
|
checkup AS a
|
|
JOIN
|
|
customer AS c ON a.customer_id = c.customer_id
|
|
JOIN
|
|
Doctor D ON a.doctor_id = D.doctor_id
|
|
WHERE
|
|
date(a.checkup_date / 1000, 'unixepoch', '+7 hours') = date('now', '+7 hours')""";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
if (!rs.isBeforeFirst()) {
|
|
log.warn("No data found in the checkup table for today.");
|
|
// Gửi về một mảng rỗng thay vì không gửi gì
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetCheckUpQueueResponse(new String[0][0]));
|
|
} else {
|
|
// Phần code xử lý logic bên trong không thay đổi
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String checkupId = rs.getString("checkup_id");
|
|
String checkupDate = rs.getString("checkup_date");
|
|
long checkupDateLong = Long.parseLong(checkupDate);
|
|
Timestamp timestamp = new Timestamp(checkupDateLong);
|
|
Date date = new Date(timestamp.getTime());
|
|
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
|
|
checkupDate = sdf.format(date);
|
|
String customerLastName = rs.getString("customer_last_name");
|
|
String customerFirstName = rs.getString("customer_first_name");
|
|
String doctorFirstName = rs.getString("doctor_first_name");
|
|
String doctorLastName = rs.getString("doctor_last_name");
|
|
String suggestion = rs.getString("suggestion");
|
|
String diagnosis = rs.getString("diagnosis");
|
|
String notes = rs.getString("notes");
|
|
String status = rs.getString("status");
|
|
String customerId = rs.getString("customer_id");
|
|
String customerNumber = rs.getString("customer_number");
|
|
String customerAddress = rs.getString("customer_address");
|
|
String customerWeight = rs.getString("customer_weight");
|
|
String customerHeight = rs.getString("customer_height");
|
|
String customerGender = rs.getString("customer_gender");
|
|
String customerDob = rs.getString("customer_dob");
|
|
String checkupType = rs.getString("checkup_type");
|
|
String conclusion = rs.getString("conclusion");
|
|
String reCheckupDate = rs.getString("reCheckupDate");
|
|
String cccdDdcn = rs.getString("cccd_ddcn");
|
|
String heartBeat = rs.getString("heart_beat");
|
|
String bloodPressure = rs.getString("blood_pressure");
|
|
String driveUrl = rs.getString("drive_url");
|
|
String doctorUltrasoundId = rs.getString("doctor_ultrasound_id");
|
|
String queueNumber = String.format("%02d", rs.getInt("queue_number"));
|
|
if (driveUrl == null) {
|
|
driveUrl = "";
|
|
}
|
|
String result = String.join("|", checkupId,
|
|
checkupDate, customerLastName, customerFirstName,
|
|
doctorLastName + " " + doctorFirstName, suggestion,
|
|
diagnosis, notes, status, customerId, customerNumber, customerAddress, customerWeight, customerHeight,
|
|
customerGender, customerDob, checkupType, conclusion, reCheckupDate, cccdDdcn, heartBeat, bloodPressure,
|
|
driveUrl, doctorUltrasoundId, queueNumber
|
|
);
|
|
resultList.add(result);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetCheckUpQueueResponse(resultArray));
|
|
}
|
|
} catch (SQLException e) {
|
|
|
|
log.error("Error processing GetCheckUpQueueRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetCheckUpQueueUpdateRequest) {
|
|
log.debug("Received GetCheckUpQueueUpdateRequest");
|
|
broadcastQueueUpdate();
|
|
}
|
|
|
|
if (packet instanceof GetDoctorGeneralInfo) {
|
|
log.debug("Received GetDoctorGeneralInfo");
|
|
String sql = "SELECT doctor_last_name || ' ' || doctor_first_name, doctor_id FROM Doctor";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
if (!rs.isBeforeFirst()) {
|
|
log.warn("No data found in the doctor table.");
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetDoctorGeneralInfoResponse(new String[0][0]));
|
|
} else {
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String doctorName = rs.getString(1); // Lấy theo chỉ số cột
|
|
String doctorId = rs.getString(2); // Lấy theo chỉ số cột
|
|
resultList.add(doctorName + "|" + doctorId);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetDoctorGeneralInfoResponse(resultArray));
|
|
log.info("Sent response to client GetDoctorGeneralInfo");
|
|
}
|
|
} catch (SQLException e) {
|
|
log.error("Error processing GetDoctorGeneralInfo", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetPatientHistoryRequest getPatientHistoryRequest) {
|
|
log.debug("Received GetPatientHistoryRequest for patientId: {}", getPatientHistoryRequest.getPatientId());
|
|
|
|
String sql = """
|
|
SELECT
|
|
C.checkup_date,
|
|
C.checkup_id,
|
|
C.suggestion,
|
|
C.diagnosis,
|
|
C.prescription_id,
|
|
C.notes,
|
|
C.checkup_type,
|
|
C.conclusion,
|
|
C.reCheckupDate,
|
|
D.doctor_last_name,
|
|
D.doctor_first_name,
|
|
C.customer_height,
|
|
C.customer_weight,
|
|
C.heart_beat,
|
|
C.blood_pressure
|
|
FROM Checkup C JOIN Doctor D ON C.doctor_id = D.doctor_id
|
|
WHERE C.status = ? AND C.customer_id = ?
|
|
ORDER BY C.checkup_date DESC;
|
|
""";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement historyStmt = conn.prepareStatement(sql)) {
|
|
|
|
historyStmt.setString(1, "ĐÃ KHÁM");
|
|
historyStmt.setInt(2, getPatientHistoryRequest.getPatientId());
|
|
|
|
try (ResultSet rs = historyStmt.executeQuery()) {
|
|
if (!rs.isBeforeFirst()) {
|
|
log.info("No history data found for patientId: {}", getPatientHistoryRequest.getPatientId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetPatientHistoryResponse(new String[0][0]));
|
|
} else {
|
|
ArrayList<String[]> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String[] historyEntry = new String[15];
|
|
|
|
String checkupDateStr = rs.getString("checkup_date");
|
|
try {
|
|
long checkupDateLong = Long.parseLong(checkupDateStr);
|
|
Timestamp timestamp = new Timestamp(checkupDateLong);
|
|
Date date = new Date(timestamp.getTime());
|
|
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
|
|
historyEntry[0] = sdf.format(date);
|
|
} catch (Exception e) {
|
|
historyEntry[0] = checkupDateStr;
|
|
}
|
|
|
|
historyEntry[1] = rs.getString("checkup_id");
|
|
historyEntry[2] = rs.getString("suggestion");
|
|
historyEntry[3] = rs.getString("diagnosis");
|
|
historyEntry[4] = rs.getString("prescription_id");
|
|
historyEntry[5] = rs.getString("notes");
|
|
historyEntry[6] = rs.getString("checkup_type");
|
|
historyEntry[7] = rs.getString("conclusion");
|
|
historyEntry[8] = rs.getString("reCheckupDate");
|
|
historyEntry[9] = rs.getString("doctor_last_name");
|
|
historyEntry[10] = rs.getString("doctor_first_name");
|
|
historyEntry[11] = rs.getString("customer_height");
|
|
historyEntry[12] = rs.getString("customer_weight");
|
|
historyEntry[13] = rs.getString("heart_beat");
|
|
historyEntry[14] = rs.getString("blood_pressure");
|
|
resultList.add(historyEntry);
|
|
}
|
|
|
|
String[][] resultArray = resultList.toArray(new String[0][]);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetPatientHistoryResponse(resultArray));
|
|
log.info("Sent patient history for patientId: {}", getPatientHistoryRequest.getPatientId());
|
|
}
|
|
}
|
|
} catch (SQLException e) {
|
|
|
|
log.error("Error fetching patient history for patientId: {}", getPatientHistoryRequest.getPatientId(), e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetMedInfoRequest getMedInfoRequest) {
|
|
log.debug("Received GetMedInfoRequest");
|
|
getMedInfo(currentUser.getSessionId());
|
|
}
|
|
|
|
if (packet instanceof GetSerInfoRequest getSerInfoRequest) {
|
|
log.debug("Received GetSerInfoRequest");
|
|
getSerInfo(currentUser.getSessionId());
|
|
}
|
|
|
|
if (packet instanceof ClinicInfoRequest clinicInfoRequest) {
|
|
log.debug("Received ClinicInfoRequest");
|
|
|
|
// Thêm LIMIT 1 vì ta chỉ mong đợi 1 dòng kết quả
|
|
String sql = "SELECT name, address, phone, prefix FROM Clinic LIMIT 1";
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
// SỬA ĐỔI: Dùng if (rs.next()) là cách làm chuẩn và an toàn hơn
|
|
if (rs.next()) {
|
|
String clinicName = rs.getString("name");
|
|
String clinicAddress = rs.getString("address");
|
|
String clinicPhone = rs.getString("phone");
|
|
String clinicPrefix = rs.getString("prefix");
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ClinicInfoResponse(clinicName, clinicAddress, clinicPhone, clinicPrefix));
|
|
} else {
|
|
// Ghi log nếu không tìm thấy thông tin phòng khám
|
|
log.warn("No data found in the Clinic table. Cannot send clinic info.");
|
|
// Bạn có thể gửi một response lỗi ở đây nếu cần, nhưng thường thì client có thể xử lý thông tin rỗng.
|
|
}
|
|
} catch (SQLException e) {
|
|
// SỬA ĐỔI: Xử lý lỗi an toàn
|
|
log.error("Error processing ClinicInfoRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetRecentPatientRequest getRecentPatientRequest) {
|
|
log.debug("Received GetRecentPatientRequest");
|
|
|
|
// Sử dụng try-with-resources cho Connection để quản lý toàn bộ thao tác
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
// --- 1. Xây dựng câu truy vấn động ---
|
|
StringBuilder queryBuilder = new StringBuilder();
|
|
queryBuilder.append("SELECT customer_id, customer_last_name, customer_first_name, customer_dob, customer_number, ")
|
|
.append("customer_address, customer_gender, cccd_ddcn FROM Customer");
|
|
|
|
boolean hasNameSearch = getRecentPatientRequest.getSearchName() != null && !getRecentPatientRequest.getSearchName().trim().isEmpty();
|
|
boolean hasPhoneSearch = getRecentPatientRequest.getSearchPhone() != null && !getRecentPatientRequest.getSearchPhone().trim().isEmpty();
|
|
|
|
if (hasNameSearch || hasPhoneSearch) {
|
|
queryBuilder.append(" WHERE ");
|
|
if (hasNameSearch) {
|
|
// SỬA LỖI SQL: Dùng || thay vì CONCAT cho SQLite
|
|
queryBuilder.append("(LOWER(customer_first_name) LIKE ? OR LOWER(customer_last_name) LIKE ? OR ")
|
|
.append("LOWER(customer_last_name || ' ' || customer_first_name) LIKE ?)");
|
|
}
|
|
if (hasNameSearch && hasPhoneSearch) {
|
|
queryBuilder.append(" AND ");
|
|
}
|
|
if (hasPhoneSearch) {
|
|
queryBuilder.append("customer_number LIKE ?");
|
|
}
|
|
}
|
|
|
|
queryBuilder.append(" ORDER BY customer_id DESC");
|
|
|
|
// --- 2. Đếm tổng số bản ghi để phân trang ---
|
|
int totalCount = 0;
|
|
String countQuery = queryBuilder.toString().replace(
|
|
"SELECT customer_id, customer_last_name, customer_first_name, customer_dob, customer_number, customer_address, customer_gender, cccd_ddcn",
|
|
"SELECT COUNT(*)"
|
|
);
|
|
|
|
try (PreparedStatement countStmt = conn.prepareStatement(countQuery)) {
|
|
int paramIndex = 1;
|
|
if (hasNameSearch) {
|
|
String searchName = "%" + getRecentPatientRequest.getSearchName().toLowerCase().trim() + "%";
|
|
countStmt.setString(paramIndex++, searchName);
|
|
countStmt.setString(paramIndex++, searchName);
|
|
countStmt.setString(paramIndex++, searchName);
|
|
}
|
|
if (hasPhoneSearch) {
|
|
String searchPhone = "%" + getRecentPatientRequest.getSearchPhone().trim() + "%";
|
|
countStmt.setString(paramIndex++, searchPhone);
|
|
}
|
|
|
|
try (ResultSet countRs = countStmt.executeQuery()) {
|
|
if (countRs.next()) {
|
|
totalCount = countRs.getInt(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- 3. Tính toán thông tin phân trang ---
|
|
int pageSize = getRecentPatientRequest.getPageSize();
|
|
int currentPage = getRecentPatientRequest.getPage();
|
|
int totalPages = (int) Math.ceil((double) totalCount / pageSize);
|
|
int offset = (currentPage - 1) * pageSize;
|
|
|
|
// --- 4. Truy vấn lấy dữ liệu của trang hiện tại ---
|
|
queryBuilder.append(" LIMIT ? OFFSET ?");
|
|
|
|
try (PreparedStatement stmt = conn.prepareStatement(queryBuilder.toString())) {
|
|
int paramIndex = 1;
|
|
if (hasNameSearch) {
|
|
String searchName = "%" + getRecentPatientRequest.getSearchName().toLowerCase().trim() + "%";
|
|
stmt.setString(paramIndex++, searchName);
|
|
stmt.setString(paramIndex++, searchName);
|
|
stmt.setString(paramIndex++, searchName);
|
|
}
|
|
if (hasPhoneSearch) {
|
|
String searchPhone = "%" + getRecentPatientRequest.getSearchPhone().trim() + "%";
|
|
stmt.setString(paramIndex++, searchPhone);
|
|
}
|
|
stmt.setInt(paramIndex++, pageSize);
|
|
stmt.setInt(paramIndex, offset); // Sửa lại: Dùng paramIndex thay vì paramIndex++
|
|
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
// Xử lý kết quả (phần này không thay đổi)
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String customerId = rs.getString("customer_id");
|
|
String customerLastName = rs.getString("customer_last_name");
|
|
String customerFirstName = rs.getString("customer_first_name");
|
|
String customerDob = rs.getString("customer_dob");
|
|
String year = Integer.toString(DateUtils.extractYearFromTimestamp(customerDob));
|
|
String customerNumber = rs.getString("customer_number");
|
|
String customerAddress = rs.getString("customer_address");
|
|
String customerGender = rs.getString("customer_gender");
|
|
String cccdDdcn = rs.getString("cccd_ddcn");
|
|
|
|
String result = String.join("|", customerId, customerLastName + " " + customerFirstName,
|
|
year, customerNumber, customerAddress, customerGender, customerDob, cccdDdcn);
|
|
resultList.add(result);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetRecentPatientResponse(resultArray, totalCount, currentPage, totalPages, pageSize));
|
|
}
|
|
}
|
|
} catch (SQLException e) {
|
|
// Xử lý lỗi an toàn
|
|
log.error("Error processing GetRecentPatientRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetProvinceRequest getProvinceRequest) {
|
|
log.debug("Received GetProvinceRequest");
|
|
|
|
String sql = "SELECT code, name FROM provinces ORDER BY name";
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources để quản lý kết nối và tài nguyên
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
HashMap<String, String> provinceIdMap = new HashMap<>();
|
|
|
|
// Luôn thêm giá trị mặc định cho ComboBox ở client
|
|
resultList.add("Tỉnh/Thành phố");
|
|
|
|
// Vòng lặp while sẽ tự xử lý trường hợp không có dữ liệu
|
|
while (rs.next()) {
|
|
String provinceId = rs.getString("code");
|
|
String provinceName = rs.getString("name");
|
|
provinceIdMap.put(provinceName, provinceId);
|
|
resultList.add(provinceName);
|
|
}
|
|
|
|
if (resultList.size() <= 1) {
|
|
log.warn("No data found in the province table.");
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetProvinceResponse(resultString, provinceIdMap));
|
|
|
|
} catch (SQLException e) {
|
|
// SỬA ĐỔI: Xử lý lỗi an toàn
|
|
log.error("Error processing GetProvinceRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetWardRequest getWardRequest) {
|
|
log.debug("Received GetWardRequest for province {}", getWardRequest.getProvinceId());
|
|
String sql = "SELECT name FROM wards WHERE province_code = ? ORDER BY name";
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources cho Connection và đổi 'Server.connection' thành 'conn'
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement preparedStatement = conn.prepareStatement(sql)) {
|
|
|
|
preparedStatement.setString(1, getWardRequest.getProvinceId());
|
|
|
|
try (ResultSet rs = preparedStatement.executeQuery()) {
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
// Luôn thêm giá trị mặc định cho ComboBox ở client
|
|
resultList.add("Phường/Xã");
|
|
|
|
// Vòng lặp while sẽ tự xử lý trường hợp không có dữ liệu
|
|
while (rs.next()) {
|
|
resultList.add(rs.getString("name"));
|
|
}
|
|
|
|
if (resultList.size() <= 1) {
|
|
log.warn("No data found in the ward table for province_code: {}", getWardRequest.getProvinceId());
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetWardResponse(resultString));
|
|
}
|
|
} catch (SQLException e) {
|
|
// SỬA ĐỔI: Xử lý lỗi an toàn
|
|
log.error("Error fetching wards for province {}: {}", getWardRequest.getProvinceId(), e.getMessage());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
if (packet instanceof AddPatientRequest addPatientRequest) {
|
|
log.debug("Received AddPatientRequest");
|
|
|
|
String sql = "INSERT INTO Customer (customer_last_name, customer_first_name, customer_dob, customer_number, customer_address, customer_gender, cccd_ddcn) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
|
|
|
// SỬA ĐỔI: Bắt đầu bằng try-with-resources để lấy Connection từ pool
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
|
|
// 1. Bắt đầu transaction trên kết nối vừa mượn
|
|
conn.setAutoCommit(false);
|
|
|
|
try (PreparedStatement preparedStatement = conn.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS)) {
|
|
|
|
preparedStatement.setString(1, addPatientRequest.getPatientLastName());
|
|
preparedStatement.setString(2, addPatientRequest.getPatientFirstName());
|
|
preparedStatement.setLong(3, addPatientRequest.getPatientDob());
|
|
preparedStatement.setString(4, addPatientRequest.getPatientPhone());
|
|
preparedStatement.setString(5, addPatientRequest.getPatientAddress());
|
|
preparedStatement.setString(6, addPatientRequest.getPatientGender());
|
|
preparedStatement.setString(7, addPatientRequest.getPatientCccdDdcn());
|
|
preparedStatement.executeUpdate();
|
|
|
|
// Lấy customerId vừa được tạo ra
|
|
int customerId = 0;
|
|
try (ResultSet generatedKeys = preparedStatement.getGeneratedKeys()) {
|
|
if (generatedKeys.next()) {
|
|
customerId = generatedKeys.getInt(1);
|
|
} else {
|
|
// Nếu không lấy được ID, ném lỗi để kích hoạt rollback
|
|
throw new SQLException("Creating patient failed, no ID obtained.");
|
|
}
|
|
}
|
|
|
|
// 2. Nếu mọi thứ thành công, commit transaction
|
|
conn.commit();
|
|
|
|
// 3. Gửi phản hồi thành công và thực hiện các tác vụ bất đồng bộ
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddPatientResponse(true, customerId, "Thêm bệnh nhân thành công"));
|
|
createPatientGoogleDriveFolderAsync(customerId, addPatientRequest.getPatientLastName(), addPatientRequest.getPatientFirstName());
|
|
|
|
} catch (SQLException e) {
|
|
// 4. Nếu có bất kỳ lỗi nào xảy ra trong khối try bên trong, rollback lại
|
|
log.error("Error during AddPatient transaction, rolling back.", e);
|
|
conn.rollback();
|
|
|
|
// Gửi phản hồi lỗi về client
|
|
String errorMessage = e.getMessage();
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddPatientResponse(false, -1, "Lỗi: " + errorMessage));
|
|
} finally {
|
|
// 5. Rất quan trọng: Luôn trả lại trạng thái auto-commit về true
|
|
// trước khi kết nối được trả về pool bởi try-with-resources
|
|
conn.setAutoCommit(true);
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
// Khối catch này chỉ bắt lỗi khi không thể lấy được kết nối từ pool
|
|
log.error("Failed to get DB connection for AddPatientRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddPatientResponse(false, -1, "Lỗi: Không thể kết nối CSDL."));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof AddCheckupRequest addCheckupRequest) {
|
|
log.debug("Received AddCheckupRequest to add for customer {}", addCheckupRequest.getCustomerId());
|
|
|
|
// --- SỬA ĐỔI QUAN TRỌNG: Sử dụng một kết nối riêng từ pool cho toàn bộ giao dịch ---
|
|
// try-with-resources sẽ đảm bảo kết nối được trả về pool ngay cả khi có lỗi.
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
int generatedCheckupId = 0;
|
|
int queueNumber = 0;
|
|
|
|
try {
|
|
// 1. Bắt đầu một transaction trên kết nối CỤC BỘ (conn) này
|
|
conn.setAutoCommit(false);
|
|
|
|
// 2. LẤY SỐ THỨ TỰ (QUEUE NUMBER)
|
|
// Sử dụng UPSERT để đảm bảo thao tác là nguyên tử
|
|
String queueSql = """
|
|
INSERT INTO DailyQueueCounter (date, current_count)
|
|
VALUES (date('now', 'localtime'), 1)
|
|
ON CONFLICT(date) DO UPDATE SET current_count = current_count + 1
|
|
RETURNING current_count
|
|
""";
|
|
|
|
try (PreparedStatement queueStmt = conn.prepareStatement(queueSql);
|
|
ResultSet rs = queueStmt.executeQuery()) {
|
|
if (rs.next()) {
|
|
queueNumber = rs.getInt(1);
|
|
} else {
|
|
throw new SQLException("Failed to get or update queue number.");
|
|
}
|
|
}
|
|
|
|
// 3. CHÈN VÀO BẢNG CHECKUP VÀ LẤY LẠI CHECKUP_ID
|
|
String checkupSql = "INSERT INTO Checkup (customer_id, doctor_id, checkup_type, status, queue_number) VALUES (?, ?, ?, ?, ?)";
|
|
try (PreparedStatement checkupStmt = conn.prepareStatement(checkupSql, PreparedStatement.RETURN_GENERATED_KEYS)) {
|
|
checkupStmt.setInt(1, addCheckupRequest.getCustomerId());
|
|
checkupStmt.setInt(2, addCheckupRequest.getDoctorId());
|
|
checkupStmt.setString(3, addCheckupRequest.getCheckupType());
|
|
checkupStmt.setString(4, addCheckupRequest.getStatus());
|
|
checkupStmt.setInt(5, queueNumber);
|
|
checkupStmt.executeUpdate();
|
|
|
|
try (ResultSet generatedKeys = checkupStmt.getGeneratedKeys()) {
|
|
if (generatedKeys.next()) {
|
|
generatedCheckupId = generatedKeys.getInt(1);
|
|
} else {
|
|
throw new SQLException("Creating checkup failed, no ID obtained.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// 4. CHÈN VÀO BẢNG MEDICINEORDER VÀ LẤY LẠI PRESCRIPTION_ID
|
|
int generatedPrescriptionId = 0;
|
|
String medOrderSql = "INSERT INTO MedicineOrder (checkup_id, customer_id, processed_by) VALUES (?, ?, ?)";
|
|
try (PreparedStatement medOrderStmt = conn.prepareStatement(medOrderSql, PreparedStatement.RETURN_GENERATED_KEYS)) {
|
|
medOrderStmt.setInt(1, generatedCheckupId);
|
|
medOrderStmt.setInt(2, addCheckupRequest.getCustomerId());
|
|
medOrderStmt.setInt(3, addCheckupRequest.getProcessedById());
|
|
medOrderStmt.executeUpdate();
|
|
|
|
try (ResultSet generatedKeys = medOrderStmt.getGeneratedKeys()) {
|
|
if (generatedKeys.next()) {
|
|
generatedPrescriptionId = generatedKeys.getInt(1);
|
|
} else {
|
|
throw new SQLException("Creating medicine order failed, no ID obtained.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// 5. CẬP NHẬT BẢNG CHECKUP VỚI PRESCRIPTION_ID
|
|
String updateSql = "UPDATE Checkup SET prescription_id = ? WHERE checkup_id = ?";
|
|
try (PreparedStatement updateStmt = conn.prepareStatement(updateSql)) {
|
|
updateStmt.setInt(1, generatedPrescriptionId);
|
|
updateStmt.setInt(2, generatedCheckupId);
|
|
updateStmt.executeUpdate();
|
|
}
|
|
|
|
// 6. Nếu tất cả các bước thành công, commit transaction
|
|
conn.commit();
|
|
|
|
// 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();
|
|
|
|
// Tạo thư mục Google Drive bất đồng bộ
|
|
createCheckupGoogleDriveFolderAsync(generatedCheckupId, addCheckupRequest.getCustomerId());
|
|
|
|
} catch (SQLException e) {
|
|
// Nếu có bất kỳ lỗi nào trong khối try ở trên, rollback transaction
|
|
log.error("SQLException during AddCheckupRequest, rolling back transaction.", e);
|
|
conn.rollback(); // Quan trọng: rollback trên kết nối cục bộ
|
|
|
|
// Gửi phản hồi lỗi về client
|
|
String errorMessage = e.getMessage();
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(false, "Lỗi Server: " + errorMessage, -1));
|
|
}
|
|
// KHÔNG CẦN khối `finally` để `setAutoCommit(true)`.
|
|
// HikariCP sẽ tự động reset trạng thái của kết nối khi nó được trả về pool.
|
|
|
|
} catch (SQLException e) {
|
|
// Lỗi này xảy ra nếu không thể lấy kết nối từ pool, hoặc có lỗi nghiêm trọng khi rollback
|
|
log.error("Critical error during database transaction management for AddCheckupRequest.", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddCheckupResponse(false, "Lỗi hệ thống: Không thể xử lý giao dịch CSDL.", -1));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof CallPatientRequest callPatientRequest) {
|
|
log.debug("Received CallPatientRequest to call patient checkup_id: {}", callPatientRequest.getPatientId());
|
|
int checkupId = callPatientRequest.getPatientId(); // This is the checkup_id
|
|
int roomId = callPatientRequest.getRoomId();
|
|
Status status = callPatientRequest.getStatus();
|
|
String queueNumber = callPatientRequest.getQueueNumber();
|
|
// send to all clients with the queue number included
|
|
int maxCurId = SessionManager.getMaxSessionId();
|
|
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
|
|
UserUtil.sendPacket(sessionId, new CallPatientResponse(checkupId, roomId, queueNumber, status));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof SaveCheckupRequest saveCheckupRequest) {
|
|
log.debug("Received SaveCheckupRequest to save checkup {}", saveCheckupRequest.getCheckupId());
|
|
|
|
// --- SỬA ĐỔI QUAN TRỌNG: Lấy một kết nối riêng từ pool cho toàn bộ giao dịch ---
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
try {
|
|
// 1. Bắt đầu transaction trên kết nối CỤC BỘ (conn)
|
|
conn.setAutoCommit(false);
|
|
|
|
// 2. CẬP NHẬT THÔNG TIN KHÁCH HÀNG (CUSTOMER)
|
|
String customerSql = """
|
|
INSERT INTO Customer (
|
|
customer_id, customer_first_name, customer_last_name, customer_dob,
|
|
customer_gender, customer_address, customer_number, cccd_ddcn
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT(customer_id) DO UPDATE SET
|
|
customer_first_name = excluded.customer_first_name,
|
|
customer_last_name = excluded.customer_last_name,
|
|
customer_dob = excluded.customer_dob,
|
|
customer_gender = excluded.customer_gender,
|
|
customer_address = excluded.customer_address,
|
|
customer_number = excluded.customer_number,
|
|
cccd_ddcn = excluded.cccd_ddcn
|
|
""";
|
|
try (PreparedStatement customerStmt = conn.prepareStatement(customerSql)) {
|
|
customerStmt.setInt(1, saveCheckupRequest.getCustomerId());
|
|
customerStmt.setString(2, saveCheckupRequest.getCustomerFirstName());
|
|
customerStmt.setString(3, saveCheckupRequest.getCustomerLastName());
|
|
customerStmt.setLong(4, saveCheckupRequest.getCustomerDob());
|
|
customerStmt.setString(5, saveCheckupRequest.getCustomerGender());
|
|
customerStmt.setString(6, saveCheckupRequest.getCustomerAddress());
|
|
customerStmt.setString(7, saveCheckupRequest.getCustomerNumber());
|
|
customerStmt.setString(8, saveCheckupRequest.getCustomerCccdDdcn());
|
|
customerStmt.executeUpdate();
|
|
}
|
|
|
|
// 3. XỬ LÝ ĐƠN THUỐC (MEDICINE PRESCRIPTION)
|
|
Integer newPrescriptionId = null;
|
|
|
|
// Xóa dữ liệu cũ của đơn thuốc liên quan đến lần khám này
|
|
try (PreparedStatement deleteStmt = conn.prepareStatement("DELETE FROM OrderItem WHERE checkup_id = ?")) {
|
|
deleteStmt.setInt(1, saveCheckupRequest.getCheckupId());
|
|
deleteStmt.executeUpdate();
|
|
}
|
|
try (PreparedStatement deleteStmt = conn.prepareStatement("DELETE FROM MedicineOrder WHERE checkup_id = ?")) {
|
|
deleteStmt.setInt(1, saveCheckupRequest.getCheckupId());
|
|
deleteStmt.executeUpdate();
|
|
}
|
|
log.info("Cleared previous medicine prescription for checkup_id: {}", saveCheckupRequest.getCheckupId());
|
|
|
|
// Nếu có đơn thuốc mới, tạo lại từ đầu
|
|
if (saveCheckupRequest.getMedicinePrescription() != null && saveCheckupRequest.getMedicinePrescription().length > 0) {
|
|
// A. Chèn vào MedicineOrder để lấy prescription_id mới
|
|
String medicineOrderSql = "INSERT INTO MedicineOrder (checkup_id, customer_id, total_amount, status, payment_status) VALUES (?, ?, ?, ?, ?)";
|
|
try (PreparedStatement medicineOrderStmt = conn.prepareStatement(medicineOrderSql, PreparedStatement.RETURN_GENERATED_KEYS)) {
|
|
double totalMedicineAmount = 0;
|
|
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
|
|
if (medicine.length > 8) totalMedicineAmount += Double.parseDouble(medicine[8]);
|
|
}
|
|
medicineOrderStmt.setInt(1, saveCheckupRequest.getCheckupId());
|
|
medicineOrderStmt.setInt(2, saveCheckupRequest.getCustomerId());
|
|
medicineOrderStmt.setDouble(3, totalMedicineAmount);
|
|
medicineOrderStmt.setString(4, "Pending"); // status
|
|
medicineOrderStmt.setString(5, "Unpaid"); // payment_status
|
|
medicineOrderStmt.executeUpdate();
|
|
|
|
try (ResultSet generatedKeys = medicineOrderStmt.getGeneratedKeys()) {
|
|
if (generatedKeys.next()) {
|
|
newPrescriptionId = generatedKeys.getInt(1);
|
|
} else {
|
|
throw new SQLException("Creating medicine order failed, no ID obtained.");
|
|
}
|
|
}
|
|
}
|
|
|
|
// B. Chèn các chi tiết thuốc vào OrderItem bằng batch
|
|
String orderItemSql = "INSERT INTO OrderItem (prescription_id, med_id, quantity_ordered, dosage, price_per_unit, total_price, checkup_id, notes) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
|
|
try (PreparedStatement orderItemStmt = conn.prepareStatement(orderItemSql)) {
|
|
for (String[] medicine : saveCheckupRequest.getMedicinePrescription()) {
|
|
if (medicine.length >= 10) {
|
|
orderItemStmt.setInt(1, newPrescriptionId);
|
|
orderItemStmt.setString(2, medicine[0]); // med_id
|
|
orderItemStmt.setString(3, medicine[2]); // quantity
|
|
String dosage = String.format("Sáng %s, Trưa %s, Chiều %s", medicine[4], medicine[5], medicine[6]);
|
|
orderItemStmt.setString(4, dosage);
|
|
orderItemStmt.setString(5, medicine[7]); // unit_price
|
|
orderItemStmt.setString(6, medicine[8]); // total_price
|
|
orderItemStmt.setInt(7, saveCheckupRequest.getCheckupId());
|
|
orderItemStmt.setString(8, medicine[9]); // notes
|
|
orderItemStmt.addBatch();
|
|
}
|
|
}
|
|
orderItemStmt.executeBatch();
|
|
}
|
|
}
|
|
|
|
// 4. CẬP NHẬT THÔNG TIN LẦN KHÁM (CHECKUP)
|
|
String checkupSql = """
|
|
UPDATE Checkup SET
|
|
suggestion = ?, diagnosis = ?, prescription_id = ?, notes = ?, status = ?,
|
|
checkup_type = ?, conclusion = ?, reCheckupDate = ?, customer_weight = ?,
|
|
customer_height = ?, heart_beat = ?, blood_pressure = ?,
|
|
doctor_ultrasound_id = ?, doctor_id = ?, checkup_date = ?
|
|
WHERE checkup_id = ?
|
|
""";
|
|
try (PreparedStatement checkupStmt = conn.prepareStatement(checkupSql)) {
|
|
checkupStmt.setString(1, saveCheckupRequest.getSuggestions());
|
|
checkupStmt.setString(2, saveCheckupRequest.getDiagnosis());
|
|
checkupStmt.setObject(3, newPrescriptionId); // setObject an toàn cho giá trị null
|
|
checkupStmt.setString(4, saveCheckupRequest.getNotes());
|
|
checkupStmt.setString(5, saveCheckupRequest.getStatus());
|
|
checkupStmt.setString(6, saveCheckupRequest.getCheckupType());
|
|
checkupStmt.setString(7, saveCheckupRequest.getConclusion());
|
|
checkupStmt.setObject(8, saveCheckupRequest.getReCheckupDate()); // setObject an toàn cho null
|
|
checkupStmt.setDouble(9, saveCheckupRequest.getCustomerWeight());
|
|
checkupStmt.setDouble(10, saveCheckupRequest.getCustomerHeight());
|
|
checkupStmt.setInt(11, saveCheckupRequest.getHeartBeat());
|
|
checkupStmt.setString(12, saveCheckupRequest.getBloodPressure());
|
|
checkupStmt.setInt(13, saveCheckupRequest.getDoctorUltrasoundId());
|
|
checkupStmt.setInt(14, saveCheckupRequest.getDoctorId());
|
|
checkupStmt.setLong(15, saveCheckupRequest.getCheckupDate());
|
|
checkupStmt.setInt(16, saveCheckupRequest.getCheckupId()); // WHERE clause
|
|
checkupStmt.executeUpdate();
|
|
}
|
|
|
|
// 5. XỬ LÝ DỊCH VỤ (SERVICES)
|
|
try (PreparedStatement deleteStmt = conn.prepareStatement("DELETE FROM CheckupService WHERE checkup_id = ?")) {
|
|
deleteStmt.setInt(1, saveCheckupRequest.getCheckupId());
|
|
deleteStmt.executeUpdate();
|
|
}
|
|
log.info("Cleared previous services for checkup_id: {}", saveCheckupRequest.getCheckupId());
|
|
|
|
// TỐI ƯU: Dùng batch để chèn dịch vụ
|
|
if (saveCheckupRequest.getServicePrescription() != null && saveCheckupRequest.getServicePrescription().length > 0) {
|
|
String serviceSql = "INSERT INTO CheckupService (checkup_id, service_id, quantity, total_cost, notes) VALUES (?, ?, ?, ?, ?)";
|
|
try (PreparedStatement serviceStmt = conn.prepareStatement(serviceSql)) {
|
|
for (String[] service : saveCheckupRequest.getServicePrescription()) {
|
|
serviceStmt.setInt(1, saveCheckupRequest.getCheckupId());
|
|
serviceStmt.setString(2, service[0]);
|
|
serviceStmt.setInt(3, Integer.parseInt(service[2]));
|
|
serviceStmt.setDouble(4, Double.parseDouble(service[4]));
|
|
serviceStmt.setString(5, service[5]);
|
|
serviceStmt.addBatch();
|
|
}
|
|
serviceStmt.executeBatch();
|
|
}
|
|
}
|
|
|
|
// 6. Hoàn tất và COMMIT giao dịch
|
|
conn.commit();
|
|
log.info("Successfully saved checkup transaction for checkup_id: {}", saveCheckupRequest.getCheckupId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new SaveCheckupRes(true, "Lưu thông tin khám bệnh thành công."));
|
|
|
|
} catch (SQLException e) {
|
|
// Nếu có lỗi, ROLLBACK toàn bộ giao dịch
|
|
log.error("Error during save checkup transaction, rolling back.", e);
|
|
conn.rollback();
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
// Không cần khối `finally` để reset auto-commit. HikariCP sẽ tự lo việc này.
|
|
|
|
} catch (SQLException e) {
|
|
// Lỗi này xảy ra nếu không thể lấy kết nối từ pool hoặc có lỗi khi rollback
|
|
log.error("Critical error during database transaction management for SaveCheckupRequest.", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetOrderInfoByCheckupReq getOrderInfoByCheckupReq) {
|
|
log.debug("Received GetOrderInfoByCheckupReq for checkupId: {}", getOrderInfoByCheckupReq.getCheckupId());
|
|
|
|
String checkupId = getOrderInfoByCheckupReq.getCheckupId();
|
|
String[][] medicinePrescription = null;
|
|
String[][] servicePrescription = null;
|
|
|
|
// --- SỬA ĐỔI: Lấy thông tin đơn thuốc (Medicine Prescription) ---
|
|
// Sử dụng try-with-resources để quản lý TẤT CẢ tài nguyên JDBC (Connection, PreparedStatement, ResultSet)
|
|
String medSql = """
|
|
SELECT M.med_id, M.med_name, OI.quantity_ordered, M.med_unit, OI.dosage,
|
|
OI.price_per_unit, OI.total_price, OI.notes, M.supplement, M.route
|
|
FROM OrderItem OI
|
|
JOIN Medicine M ON OI.med_id = M.med_id
|
|
WHERE OI.checkup_id = ?
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement medStmt = conn.prepareStatement(medSql)) {
|
|
|
|
medStmt.setString(1, checkupId);
|
|
try (ResultSet medRs = medStmt.executeQuery()) {
|
|
ArrayList<String[]> medList = new ArrayList<>();
|
|
while(medRs.next()) {
|
|
String[] med = new String[12];
|
|
med[0] = medRs.getString("med_id");
|
|
med[1] = medRs.getString("med_name");
|
|
med[2] = medRs.getString("quantity_ordered");
|
|
med[3] = medRs.getString("med_unit");
|
|
|
|
// Parse dosage: "Sáng 1, Trưa 1, Chiều 1"
|
|
String dosage = medRs.getString("dosage");
|
|
String morning = "0", noon = "0", evening = "0";
|
|
if (dosage != null && !dosage.isEmpty()) {
|
|
String[] parts = dosage.split(", ");
|
|
for (String part : parts) {
|
|
String[] dosagePart = part.split(" ");
|
|
if (dosagePart.length == 2) {
|
|
if ("Sáng".equals(dosagePart[0])) morning = dosagePart[1];
|
|
else if ("Trưa".equals(dosagePart[0])) noon = dosagePart[1];
|
|
else if ("Chiều".equals(dosagePart[0])) evening = dosagePart[1];
|
|
}
|
|
}
|
|
}
|
|
med[4] = morning;
|
|
med[5] = noon;
|
|
med[6] = evening;
|
|
|
|
med[7] = medRs.getString("price_per_unit");
|
|
med[8] = medRs.getString("total_price");
|
|
med[9] = medRs.getString("notes");
|
|
med[10] = medRs.getString("supplement");
|
|
med[11] = medRs.getString("route");
|
|
medList.add(med);
|
|
}
|
|
medicinePrescription = medList.toArray(new String[0][]);
|
|
}
|
|
} catch (SQLException e) {
|
|
log.error("Error getting medicine prescription for checkupId: " + checkupId, e);
|
|
// Nếu có lỗi, medicinePrescription sẽ vẫn là null
|
|
}
|
|
|
|
// --- SỬA ĐỔI: Lấy thông tin dịch vụ (Service Prescription) ---
|
|
String serSql = """
|
|
SELECT S.service_id, S.service_name, CS.quantity,
|
|
S.service_cost, CS.total_cost, CS.notes
|
|
FROM CheckupService CS
|
|
JOIN Service S ON CS.service_id = S.service_id
|
|
WHERE CS.checkup_id = ?
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement serStmt = conn.prepareStatement(serSql)) {
|
|
|
|
serStmt.setString(1, checkupId);
|
|
try (ResultSet serRs = serStmt.executeQuery()) {
|
|
ArrayList<String[]> serList = new ArrayList<>();
|
|
while(serRs.next()) {
|
|
String[] ser = new String[6];
|
|
ser[0] = serRs.getString("service_id");
|
|
ser[1] = serRs.getString("service_name");
|
|
ser[2] = serRs.getString("quantity");
|
|
ser[3] = serRs.getString("service_cost");
|
|
ser[4] = serRs.getString("total_cost");
|
|
ser[5] = serRs.getString("notes");
|
|
serList.add(ser);
|
|
}
|
|
servicePrescription = serList.toArray(new String[0][]);
|
|
}
|
|
} catch (SQLException e) {
|
|
log.error("Error getting service prescription for checkupId: " + checkupId, e);
|
|
// Nếu có lỗi, servicePrescription sẽ vẫn là null
|
|
}
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetOrderInfoByCheckupRes(medicinePrescription, servicePrescription));
|
|
log.info("Sent order info for checkup {} to client", checkupId);
|
|
}
|
|
|
|
if (packet instanceof AddTemplateReq addTemplateReq) {
|
|
log.debug("Received AddTemplateReq: {}", addTemplateReq);
|
|
|
|
// --- SỬA ĐỔI: Sử dụng try-with-resources để đảm bảo an toàn và tự động đóng tài nguyên ---
|
|
String sql = """
|
|
INSERT INTO CheckupTemplate (template_gender, template_name, template_title, photo_num,
|
|
print_type, content, conclusion, suggestion, diagnosis,
|
|
visible, stt)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement templateStmt = conn.prepareStatement(sql)) {
|
|
|
|
templateStmt.setString(1, addTemplateReq.getTemplateGender());
|
|
templateStmt.setString(2, addTemplateReq.getTemplateName());
|
|
templateStmt.setString(3, addTemplateReq.getTemplateTitle());
|
|
templateStmt.setString(4, addTemplateReq.getTemplateImageCount());
|
|
templateStmt.setString(5, addTemplateReq.getTemplatePrintType());
|
|
templateStmt.setString(6, addTemplateReq.getTemplateContent());
|
|
templateStmt.setString(7, addTemplateReq.getTemplateConclusion());
|
|
templateStmt.setString(8, addTemplateReq.getTemplateSuggestion());
|
|
templateStmt.setString(9, addTemplateReq.getTemplateDiagnosis());
|
|
templateStmt.setBoolean(10, addTemplateReq.isVisible());
|
|
templateStmt.setInt(11, addTemplateReq.getStt());
|
|
templateStmt.executeUpdate();
|
|
|
|
log.info("Template saved successfully");
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new AddTemplateRes(true, "Template saved successfully"));
|
|
} catch (SQLException e) {
|
|
log.error("Error saving template", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
if (packet instanceof GetAllTemplatesReq) {
|
|
log.debug("Received GetAllTemplatesReq");
|
|
|
|
// --- SỬA ĐỔI: Sử dụng try-with-resources để quản lý TẤT CẢ tài nguyên ---
|
|
String sql = "SELECT * FROM CheckupTemplate ORDER BY stt"; // Thêm ORDER BY để sắp xếp
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
List<Template> templates = new ArrayList<>();
|
|
while (rs.next()) {
|
|
templates.add(new Template(
|
|
rs.getInt("template_id"),
|
|
rs.getString("template_gender"),
|
|
rs.getString("template_name"),
|
|
rs.getString("template_title"),
|
|
rs.getString("photo_num"),
|
|
rs.getString("print_type"),
|
|
rs.getString("content"),
|
|
rs.getString("conclusion"),
|
|
rs.getString("suggestion"),
|
|
rs.getString("diagnosis"),
|
|
rs.getBoolean("visible"),
|
|
rs.getInt("stt")
|
|
));
|
|
}
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetAllTemplatesRes(templates));
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching templates", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof EditTemplateReq editTemplateReq) {
|
|
log.debug("Received EditTemplateReq for templateId: {}", editTemplateReq.getTemplate().getTemplateId());
|
|
Template template = editTemplateReq.getTemplate();
|
|
|
|
// --- SỬA ĐỔI: Sử dụng try-with-resources ---
|
|
String sql = """
|
|
UPDATE CheckupTemplate
|
|
SET template_gender = ?, template_name = ?, template_title = ?,
|
|
photo_num = ?, print_type = ?, content = ?, conclusion = ?,
|
|
suggestion = ?, diagnosis = ?, visible = ?, stt = ?
|
|
WHERE template_id = ?
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, template.getTemplateGender());
|
|
stmt.setString(2, template.getTemplateName());
|
|
stmt.setString(3, template.getTemplateTitle());
|
|
stmt.setString(4, template.getPhotoNum());
|
|
stmt.setString(5, template.getPrintType());
|
|
stmt.setString(6, template.getContent());
|
|
stmt.setString(7, template.getConclusion());
|
|
stmt.setString(8, template.getSuggestion());
|
|
stmt.setString(9, template.getDiagnosis());
|
|
stmt.setBoolean(10, template.isVisible());
|
|
stmt.setInt(11, template.getStt());
|
|
stmt.setInt(12, template.getTemplateId());
|
|
|
|
int affectedRows = stmt.executeUpdate();
|
|
if (affectedRows > 0) {
|
|
log.info("Template {} updated successfully", template.getTemplateId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new EditTemplateRes(true, "Cập nhật mẫu thành công."));
|
|
} else {
|
|
log.warn("Template {} not found for update.", template.getTemplateId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new EditTemplateRes(false, "Không tìm thấy mẫu để cập nhật."));
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error updating template {}", template.getTemplateId(), e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new EditTemplateRes(false, "Lỗi khi cập nhật mẫu: " + e.getMessage()));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof DeleteTemplateReq deleteTemplateReq) {
|
|
log.debug("Received DeleteTemplateReq for templateId: {}", deleteTemplateReq.getTemplateId());
|
|
|
|
// --- SỬA ĐỔI: Sử dụng try-with-resources ---
|
|
String sql = "DELETE FROM CheckupTemplate WHERE template_id = ?";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setInt(1, deleteTemplateReq.getTemplateId());
|
|
int affectedRows = stmt.executeUpdate();
|
|
|
|
if (affectedRows > 0) {
|
|
log.info("Template {} deleted successfully", deleteTemplateReq.getTemplateId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new DeleteTemplateRes(true, "Xóa mẫu thành công."));
|
|
} else {
|
|
log.warn("Template {} not found for deletion.", deleteTemplateReq.getTemplateId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new DeleteTemplateRes(false, "Không tìm thấy mẫu để xóa."));
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error deleting template {}", deleteTemplateReq.getTemplateId(), e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new DeleteTemplateRes(false, "Lỗi khi xóa mẫu: " + e.getMessage()));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof UploadCheckupImageRequest uploadCheckupImageRequest) {
|
|
log.info("Received UploadCheckupImageRequest for checkupId: {}", uploadCheckupImageRequest.getCheckupId());
|
|
|
|
String checkupId = uploadCheckupImageRequest.getCheckupId();
|
|
String fileName = uploadCheckupImageRequest.getFileName();
|
|
byte[] imageData = uploadCheckupImageRequest.getImageData();
|
|
|
|
if (checkupId == null || checkupId.trim().isEmpty()) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new UploadCheckupImageResponse(false, "CheckupID không hợp lệ.", fileName));
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// 1. Xác định và tạo thư mục lưu trữ
|
|
Path storageDir = Paths.get(Server.imageDbPath, checkupId.trim());
|
|
Files.createDirectories(storageDir);
|
|
|
|
// 2. Chuyển đổi và lưu ảnh dưới dạng PNG để đồng nhất
|
|
String pngFileName = fileName.substring(0, fileName.lastIndexOf('.')) + ".png";
|
|
Path filePath = storageDir.resolve(pngFileName);
|
|
|
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData)) {
|
|
BufferedImage image = ImageIO.read(bais);
|
|
if (image != null) {
|
|
ImageIO.write(image, "PNG", filePath.toFile());
|
|
log.info("Successfully converted and saved image as PNG to {}", filePath);
|
|
} else {
|
|
throw new IOException("Could not decode image data.");
|
|
}
|
|
}
|
|
|
|
// 4. Gửi phản hồi thành công cho client
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new UploadCheckupImageResponse(true, "Tải ảnh lên thành công.", fileName));
|
|
|
|
// 5. Tải lên Google Drive bất đồng bộ
|
|
uploadCheckupImageToGoogleDriveAsync(checkupId, fileName, imageData);
|
|
|
|
} catch (IOException e) {
|
|
log.error("Failed to process uploaded image for checkupId {}: {}", checkupId, e.getMessage());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new UploadCheckupImageResponse(false, "Lỗi máy chủ khi lưu ảnh: " + e.getMessage(), fileName));
|
|
}
|
|
}
|
|
|
|
|
|
if (packet instanceof GetImagesByCheckupIdReq getImagesByCheckupIdReq) {
|
|
String checkupId = getImagesByCheckupIdReq.getCheckupId();
|
|
log.info("Received GetImagesByCheckupIdReq for checkupId: {}", checkupId);
|
|
|
|
List<String> imageNames = new ArrayList<>();
|
|
List<byte[]> imageDatas = new ArrayList<>();
|
|
|
|
Path checkupDir = Paths.get(Server.imageDbPath, checkupId);
|
|
if (Files.exists(checkupDir) && Files.isDirectory(checkupDir)) {
|
|
try {
|
|
List<Path> imagePaths = Files.list(checkupDir)
|
|
.filter(path -> {
|
|
String filename = path.toString().toLowerCase();
|
|
return filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png") || filename.endsWith(".gif") || filename.endsWith(".bmp");
|
|
})
|
|
.collect(Collectors.toList());
|
|
|
|
for (Path imagePath : imagePaths) {
|
|
try {
|
|
imageDatas.add(Files.readAllBytes(imagePath));
|
|
imageNames.add(imagePath.getFileName().toString());
|
|
} catch (IOException e) {
|
|
log.error("Failed to read image file: {}", imagePath, e);
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
log.error("Failed to list images for checkupId: {}", checkupId, e);
|
|
}
|
|
} else {
|
|
log.warn("Image directory not found for checkupId: {}", checkupId);
|
|
}
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetImagesByCheckupIdRes(checkupId, imageNames, imageDatas));
|
|
log.info("Sent {} images for checkupId: {}", imageDatas.size(), checkupId);
|
|
}
|
|
|
|
if (packet instanceof SyncCheckupImagesRequest syncCheckupImagesRequest) {
|
|
String checkupId = syncCheckupImagesRequest.getCheckupId();
|
|
log.info("Received SyncCheckupImagesRequest for checkupId: {}", checkupId);
|
|
|
|
List<String> imageNames = new ArrayList<>();
|
|
List<byte[]> imageDatas = new ArrayList<>();
|
|
boolean success = false;
|
|
String message = "";
|
|
|
|
Path checkupDir = Paths.get(Server.imageDbPath, checkupId);
|
|
if (Files.exists(checkupDir) && Files.isDirectory(checkupDir)) {
|
|
try {
|
|
List<Path> imagePaths = Files.list(checkupDir)
|
|
.filter(path -> {
|
|
String filename = path.toString().toLowerCase();
|
|
return filename.endsWith(".jpg") || filename.endsWith(".jpeg") || filename.endsWith(".png") || filename.endsWith(".gif") || filename.endsWith(".bmp");
|
|
})
|
|
.collect(Collectors.toList());
|
|
|
|
for (Path imagePath : imagePaths) {
|
|
try {
|
|
imageDatas.add(Files.readAllBytes(imagePath));
|
|
imageNames.add(imagePath.getFileName().toString());
|
|
} catch (IOException e) {
|
|
log.error("Failed to read image file: {}", imagePath, e);
|
|
}
|
|
}
|
|
|
|
success = true;
|
|
message = String.format("Successfully synced %d images for checkup %s", imageDatas.size(), checkupId);
|
|
log.info("Successfully synced {} images for checkupId: {}", imageDatas.size(), checkupId);
|
|
|
|
} catch (IOException e) {
|
|
log.error("Failed to list images for checkupId: {}", checkupId, e);
|
|
message = "Failed to read images from server: " + e.getMessage();
|
|
}
|
|
} else {
|
|
log.warn("Image directory not found for checkupId: {}", checkupId);
|
|
message = "No images found for this checkup on server";
|
|
success = true; // Not finding images is still a successful response
|
|
}
|
|
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new SyncCheckupImagesResponse(checkupId, imageNames, imageDatas, success, message));
|
|
log.info("Sent sync response with {} images for checkupId: {}", imageDatas.size(), checkupId);
|
|
}
|
|
|
|
if (packet instanceof GetRecheckUpListRequest getRecheckUpListRequest) {
|
|
log.debug("Received GetRecheckUpListRequest");
|
|
getRecheckUpList(currentUser.getSessionId());
|
|
}
|
|
|
|
if (packet instanceof AddRemindDateRequest addRemindDateRequest) {
|
|
log.debug("Received AddRemindDateRequest for checkupId: {}", addRemindDateRequest.getCheckupId());
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources để quản lý kết nối và statement an toàn
|
|
String sql = "UPDATE Checkup SET remind_date = ? WHERE checkup_id = ?";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setLong(1, System.currentTimeMillis());
|
|
stmt.setString(2, addRemindDateRequest.getCheckupId());
|
|
|
|
int affectedRows = stmt.executeUpdate();
|
|
if (affectedRows > 0) {
|
|
log.info("Updated remind_date for checkup_id: {}", addRemindDateRequest.getCheckupId());
|
|
// Giả sử hàm getRecheckUpList đã được triển khai an toàn
|
|
getRecheckUpList(currentUser.getSessionId());
|
|
} else {
|
|
log.warn("No checkup found with id {} to update remind_date.", addRemindDateRequest.getCheckupId());
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error updating remind_date", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
if (packet instanceof EmergencyRequest emergencyRequest) {
|
|
log.info("Received EmergencyRequest from user_id: {}", currentUser.getUserId());
|
|
String senderName = "Không xác định";
|
|
|
|
// SỬA ĐỔI: Lấy tên người gửi một cách an toàn với try-with-resources
|
|
String sql = "SELECT user_name FROM User WHERE user_id = ?";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setInt(1, currentUser.getUserId());
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
|
|
if (rs.next()) {
|
|
senderName = rs.getString("user_name");
|
|
} else {
|
|
log.warn("Could not find user_name for user_id: {}", currentUser.getUserId());
|
|
}
|
|
}
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching sender name for emergency, will use default.", e);
|
|
}
|
|
int maxCurId = SessionManager.getMaxSessionId();
|
|
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
|
|
UserUtil.sendPacket(sessionId, new EmergencyResponse(senderName));
|
|
}
|
|
}
|
|
if (packet instanceof GetCheckupDataRequest getCheckupDataRequest) {
|
|
if (currentUser.getRole() != Role.ADMIN) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Processing GetCheckupDataRequest for page {} with all info.", getCheckupDataRequest.getPage());
|
|
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
String baseSelect = "SELECT a.checkup_id, a.checkup_date, c.customer_last_name, c.customer_first_name, " +
|
|
"d.doctor_first_name, d.doctor_last_name, a.suggestion, a.diagnosis, a.notes, a.status, a.customer_id, " +
|
|
"c.customer_number, c.customer_address, a.customer_weight, a.customer_height, c.customer_gender, c.customer_dob, " +
|
|
"a.checkup_type, a.conclusion, a.reCheckupDate, c.cccd_ddcn, a.heart_beat, a.blood_pressure, c.drive_url, a.doctor_ultrasound_id, a.queue_number ";
|
|
|
|
String fromAndJoin = "FROM checkup AS a " +
|
|
"JOIN customer AS c ON a.customer_id = c.customer_id " +
|
|
"JOIN Doctor AS d ON a.doctor_id = d.doctor_id ";
|
|
|
|
StringBuilder whereClause = new StringBuilder();
|
|
java.util.List<Object> params = new java.util.ArrayList<>();
|
|
boolean hasWhere = false;
|
|
|
|
String checkupIdSearch = getCheckupDataRequest.getCheckupIdSearch();
|
|
if (checkupIdSearch != null && !checkupIdSearch.trim().isEmpty()) {
|
|
whereClause.append("WHERE a.checkup_id = ?");
|
|
try {
|
|
params.add(Integer.parseInt(checkupIdSearch.trim()));
|
|
} catch (NumberFormatException e) {
|
|
params.add(-1);
|
|
}
|
|
hasWhere = true;
|
|
}
|
|
else if (getCheckupDataRequest.getSearchTerm() != null && !getCheckupDataRequest.getSearchTerm().trim().isEmpty()) {
|
|
// SỬA LỖI: SQLite dùng || để nối chuỗi, không phải CONCAT()
|
|
whereClause.append("WHERE (LOWER(c.customer_first_name) LIKE ? OR LOWER(c.customer_last_name) LIKE ? OR " +
|
|
"LOWER(c.customer_last_name || ' ' || c.customer_first_name) LIKE ? OR c.customer_number LIKE ?)");
|
|
String searchTerm = "%" + getCheckupDataRequest.getSearchTerm().toLowerCase().trim() + "%";
|
|
params.add(searchTerm);
|
|
params.add(searchTerm);
|
|
params.add(searchTerm);
|
|
params.add(searchTerm);
|
|
hasWhere = true;
|
|
}
|
|
|
|
if (getCheckupDataRequest.getFromDate() != null && getCheckupDataRequest.getToDate() != null) {
|
|
whereClause.append(hasWhere ? " AND " : "WHERE ").append("a.checkup_date BETWEEN ? AND ?");
|
|
params.add(getCheckupDataRequest.getFromDate());
|
|
params.add(getCheckupDataRequest.getToDate());
|
|
hasWhere = true;
|
|
}
|
|
|
|
if (getCheckupDataRequest.getDoctorId() != null && getCheckupDataRequest.getDoctorId() > 0) {
|
|
whereClause.append(hasWhere ? " AND " : "WHERE ").append("a.doctor_id = ?");
|
|
params.add(getCheckupDataRequest.getDoctorId());
|
|
}
|
|
|
|
int totalRecords = 0;
|
|
String countQuery = "SELECT COUNT(*) " + fromAndJoin + whereClause;
|
|
try (PreparedStatement countStmt = conn.prepareStatement(countQuery)) {
|
|
for (int i = 0; i < params.size(); i++) {
|
|
countStmt.setObject(i + 1, params.get(i));
|
|
}
|
|
try (ResultSet countRs = countStmt.executeQuery()) {
|
|
if (countRs.next()) {
|
|
totalRecords = countRs.getInt(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
int pageSize = getCheckupDataRequest.getPageSize();
|
|
int currentPage = getCheckupDataRequest.getPage();
|
|
int totalPages = (totalRecords == 0) ? 0 : (int) Math.ceil((double) totalRecords / pageSize);
|
|
int offset = (currentPage - 1) * pageSize;
|
|
|
|
String finalQuery = baseSelect + fromAndJoin + whereClause + " ORDER BY a.checkup_date DESC, a.checkup_id DESC LIMIT ? OFFSET ?";
|
|
java.util.List<String[]> resultList = new java.util.ArrayList<>();
|
|
try (PreparedStatement stmt = conn.prepareStatement(finalQuery)) {
|
|
int paramIndex = 1;
|
|
for (Object param : params) {
|
|
stmt.setObject(paramIndex++, param);
|
|
}
|
|
stmt.setInt(paramIndex++, pageSize);
|
|
stmt.setInt(paramIndex, offset);
|
|
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
while (rs.next()) {
|
|
String checkupId = rs.getString("checkup_id");
|
|
String checkupDate = String.valueOf(rs.getLong("checkup_date"));
|
|
String customerLastName = rs.getString("customer_last_name");
|
|
String customerFirstName = rs.getString("customer_first_name");
|
|
String doctorName = "BS. " + rs.getString("doctor_last_name") + " " + rs.getString("doctor_first_name");
|
|
String suggestion = rs.getString("suggestion");
|
|
String diagnosis = rs.getString("diagnosis");
|
|
String notes = rs.getString("notes");
|
|
String status = rs.getString("status");
|
|
String customerId = rs.getString("customer_id");
|
|
String customerNumber = rs.getString("customer_number");
|
|
String customerAddress = rs.getString("customer_address");
|
|
String customerWeight = String.valueOf(rs.getBigDecimal("customer_weight"));
|
|
String customerHeight = String.valueOf(rs.getBigDecimal("customer_height"));
|
|
String customerGender = rs.getString("customer_gender");
|
|
String customerDob = String.valueOf(rs.getLong("customer_dob"));
|
|
String checkupType = rs.getString("checkup_type");
|
|
String conclusion = rs.getString("conclusion");
|
|
String reCheckupDate = String.valueOf(rs.getLong("reCheckupDate"));
|
|
String cccdDdcn = rs.getString("cccd_ddcn");
|
|
String heartBeat = String.valueOf(rs.getInt("heart_beat"));
|
|
String bloodPressure = rs.getString("blood_pressure");
|
|
String driveUrl = rs.getString("drive_url");
|
|
String doctorUltrasoundId = String.valueOf(rs.getInt("doctor_ultrasound_id"));
|
|
String queueNumber = String.valueOf(rs.getInt("queue_number"));
|
|
|
|
resultList.add(new String[]{
|
|
checkupId != null ? checkupId : "",
|
|
checkupDate != null ? checkupDate : "0",
|
|
customerLastName != null ? customerLastName : "",
|
|
customerFirstName != null ? customerFirstName : "",
|
|
doctorName,
|
|
suggestion != null ? suggestion : "",
|
|
diagnosis != null ? diagnosis : "",
|
|
notes != null ? notes : "",
|
|
status != null ? status : "",
|
|
customerId != null ? customerId : "",
|
|
customerNumber != null ? customerNumber : "",
|
|
customerAddress != null ? customerAddress : "",
|
|
customerWeight != null ? customerWeight : "0.0",
|
|
customerHeight != null ? customerHeight : "0.0",
|
|
customerGender != null ? customerGender : "",
|
|
customerDob != null ? customerDob : "0",
|
|
checkupType != null ? checkupType : "",
|
|
conclusion != null ? conclusion : "",
|
|
reCheckupDate != null ? reCheckupDate : "0",
|
|
cccdDdcn != null ? cccdDdcn : "",
|
|
heartBeat != null ? heartBeat : "0",
|
|
bloodPressure != null ? bloodPressure : "0/0",
|
|
driveUrl != null ? driveUrl : "",
|
|
doctorUltrasoundId != null ? doctorUltrasoundId : "0",
|
|
queueNumber != null ? queueNumber : "0"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
String[][] resultArray = resultList.toArray(new String[0][]);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetCheckupDataResponse(resultArray, totalRecords, currentPage, totalPages, pageSize));
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error processing GetCheckupDataRequest", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new GetCheckupDataResponse(new String[0][0], 0, 1, 0, getCheckupDataRequest.getPageSize()));
|
|
}
|
|
}
|
|
if (packet instanceof SimpleMessageRequest simpleMessageRequest) {
|
|
log.info("Received SimpleMessageRequest from {}", simpleMessageRequest.getSenderName());
|
|
SimpleMessageResponse response = new SimpleMessageResponse(simpleMessageRequest.getSenderName(), simpleMessageRequest.getMessage());
|
|
int maxCurId = SessionManager.getMaxSessionId();
|
|
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
|
|
UserUtil.sendPacket(sessionId, response);
|
|
}
|
|
log.info("Sent SimpleMessageResponse to all sessions");
|
|
}
|
|
if (packet instanceof AddMedicineRequest addMedicineRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received AddMedicineRequest for medicine: {}", addMedicineRequest.getName());
|
|
|
|
String sql = """
|
|
INSERT INTO Medicine (med_name, med_company, med_description, med_unit,
|
|
med_selling_price, preferred_note, supplement, deleted, route)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, addMedicineRequest.getName());
|
|
stmt.setString(2, addMedicineRequest.getCompany());
|
|
stmt.setString(3, addMedicineRequest.getDescription());
|
|
stmt.setString(4, addMedicineRequest.getUnit());
|
|
stmt.setDouble(5, addMedicineRequest.getPrice());
|
|
stmt.setString(6, addMedicineRequest.getPreferredNote());
|
|
stmt.setBoolean(7, addMedicineRequest.getSupplement());
|
|
stmt.setBoolean(8, addMedicineRequest.getDeleted());
|
|
stmt.setString(9, addMedicineRequest.getRoute());
|
|
|
|
stmt.executeUpdate();
|
|
log.info("Added medicine successfully: {}", addMedicineRequest.getName());
|
|
getMedInfo(currentUser.getSessionId());
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error adding medicine", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
if (packet instanceof EditMedicineRequest editMedicineRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received EditMedicineRequest for medicine ID: {}", editMedicineRequest.getId());
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources để quản lý kết nối và statement an toàn
|
|
String sql = """
|
|
UPDATE Medicine
|
|
SET med_name = ?, med_company = ?, med_description = ?, med_unit = ?,
|
|
med_selling_price = ?, preferred_note = ?, supplement = ?, deleted = ?, route = ?
|
|
WHERE med_id = ?
|
|
""";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, editMedicineRequest.getName());
|
|
stmt.setString(2, editMedicineRequest.getCompany());
|
|
stmt.setString(3, editMedicineRequest.getDescription());
|
|
stmt.setString(4, editMedicineRequest.getUnit());
|
|
stmt.setDouble(5, editMedicineRequest.getPrice());
|
|
stmt.setString(6, editMedicineRequest.getPreferredNote());
|
|
stmt.setBoolean(7, editMedicineRequest.getSupplement());
|
|
stmt.setBoolean(8, editMedicineRequest.getDeleted());
|
|
stmt.setString(9, editMedicineRequest.getRoute());
|
|
stmt.setString(10, editMedicineRequest.getId());
|
|
|
|
int affectedRows = stmt.executeUpdate();
|
|
if (affectedRows > 0) {
|
|
log.info("Updated medicine successfully: {}", editMedicineRequest.getName());
|
|
// Giả sử hàm getMedInfo đã được triển khai an toàn
|
|
getMedInfo(currentUser.getSessionId());
|
|
} else {
|
|
log.warn("No medicine found with ID {} to update.", editMedicineRequest.getId());
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error updating medicine", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
if (packet instanceof AddServiceRequest addServiceRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received AddServiceRequest for service: {}", addServiceRequest.getName());
|
|
|
|
String sql = "INSERT INTO Service (service_name, service_cost, deleted) VALUES (?, ?, ?)";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, addServiceRequest.getName());
|
|
stmt.setDouble(2, addServiceRequest.getPrice());
|
|
stmt.setBoolean(3, addServiceRequest.getDeleted());
|
|
stmt.executeUpdate();
|
|
|
|
log.info("Added service successfully: {}", addServiceRequest.getName());
|
|
// Giả sử hàm getSerInfo đã được triển khai an toàn
|
|
getSerInfo(currentUser.getSessionId());
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error adding service", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof EditServiceRequest editServiceRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received EditServiceRequest for service ID: {}", editServiceRequest.getId());
|
|
|
|
String sql = "UPDATE Service SET service_name = ?, service_cost = ?, deleted = ? WHERE service_id = ?";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, editServiceRequest.getName());
|
|
stmt.setDouble(2, editServiceRequest.getPrice());
|
|
stmt.setBoolean(3, editServiceRequest.getDeleted());
|
|
stmt.setString(4, editServiceRequest.getId());
|
|
|
|
int affectedRows = stmt.executeUpdate();
|
|
if (affectedRows > 0) {
|
|
log.info("Updated service successfully: {}", editServiceRequest.getName());
|
|
getSerInfo(currentUser.getSessionId());
|
|
} else {
|
|
log.warn("No service found with ID {} to update.", editServiceRequest.getId());
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error updating service", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
if (packet instanceof GetAllUserInfoRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received GetAllUserInfoRequest");
|
|
// Gọi hàm trợ giúp đã được viết lại một cách an toàn
|
|
getAllUser(currentUser.getSessionId());
|
|
}
|
|
|
|
if (packet instanceof AddUserRequest addUserRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received AddUserRequest for username: {}", addUserRequest.getUserName());
|
|
|
|
String sql = "INSERT INTO User (user_name, password, last_name, first_name, role_name, deleted) VALUES (?, ?, ?, ?, ?, ?)";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, addUserRequest.getUserName());
|
|
stmt.setString(2, addUserRequest.getPassword()); // Cân nhắc mã hóa mật khẩu trước khi lưu
|
|
stmt.setString(3, addUserRequest.getLastName());
|
|
stmt.setString(4, addUserRequest.getFirstName());
|
|
stmt.setString(5, addUserRequest.getRole());
|
|
stmt.setBoolean(6, addUserRequest.getDeleted());
|
|
|
|
stmt.executeUpdate();
|
|
|
|
log.info("Added user successfully: {}", addUserRequest.getUserName());
|
|
getAllUser(currentUser.getSessionId());
|
|
|
|
} catch (SQLException e) {
|
|
// Xử lý lỗi nếu username đã tồn tại
|
|
if (e.getErrorCode() == 19 && e.getMessage().contains("UNIQUE constraint failed: User.user_name")) {
|
|
log.warn("Attempted to add a user with a duplicate username: {}", addUserRequest.getUserName());
|
|
// Bạn có thể gửi một gói tin lỗi cụ thể hơn ở đây
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.USERNAME_EXISTS));
|
|
} else {
|
|
log.error("Error adding user", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
}
|
|
|
|
if (packet instanceof EditUserRequest editUserRequest) {
|
|
if (!currentUser.getRole().equals(Role.ADMIN)) {
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.ACCESS_DENIED));
|
|
return;
|
|
}
|
|
log.info("Received EditUserRequest for user ID: {}", editUserRequest.getId());
|
|
|
|
// SỬA ĐỔI: Sử dụng try-with-resources cho kết nối và statement
|
|
String sql;
|
|
boolean isPasswordIncluded;
|
|
|
|
// Kiểm tra xem client có gửi mật khẩu mới không. Nếu không, không cập nhật mật khẩu.
|
|
if (editUserRequest.getPassword() != null && !editUserRequest.getPassword().isEmpty()) {
|
|
sql = "UPDATE User SET user_name = ?, password = ?, last_name = ?, first_name = ?, role_name = ?, deleted = ? WHERE user_id = ?";
|
|
isPasswordIncluded = true;
|
|
} else {
|
|
sql = "UPDATE User SET user_name = ?, last_name = ?, first_name = ?, role_name = ?, deleted = ? WHERE user_id = ?";
|
|
isPasswordIncluded = false;
|
|
}
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
if (isPasswordIncluded) {
|
|
stmt.setString(1, editUserRequest.getUserName());
|
|
stmt.setString(2, editUserRequest.getPassword()); // Cân nhắc mã hóa mật khẩu
|
|
stmt.setString(3, editUserRequest.getLastName());
|
|
stmt.setString(4, editUserRequest.getFirstName());
|
|
stmt.setString(5, editUserRequest.getRole());
|
|
stmt.setBoolean(6, editUserRequest.getDeleted());
|
|
stmt.setInt(7, Integer.parseInt(editUserRequest.getId())); // SỬA LỖI: Chuyển ID sang kiểu int
|
|
} else {
|
|
stmt.setString(1, editUserRequest.getUserName());
|
|
stmt.setString(2, editUserRequest.getLastName());
|
|
stmt.setString(3, editUserRequest.getFirstName());
|
|
stmt.setString(4, editUserRequest.getRole());
|
|
stmt.setBoolean(5, editUserRequest.getDeleted());
|
|
stmt.setInt(6, Integer.parseInt(editUserRequest.getId())); // SỬA LỖI: Chuyển ID sang kiểu int
|
|
}
|
|
|
|
int affectedRows = stmt.executeUpdate();
|
|
|
|
if (affectedRows > 0) {
|
|
log.info("Updated user successfully: {}", editUserRequest.getUserName());
|
|
getAllUser(currentUser.getSessionId());
|
|
} else {
|
|
log.warn("No user found with ID {} to update.", editUserRequest.getId());
|
|
}
|
|
|
|
} catch (NumberFormatException e) {
|
|
log.error("Invalid user ID format for EditUserRequest: {}", editUserRequest.getId());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.INVALID_INPUT));
|
|
} catch (SQLException e) {
|
|
if (e.getErrorCode() == 19 && e.getMessage().contains("UNIQUE constraint failed: User.user_name")) {
|
|
log.warn("Attempted to update a user with a duplicate username: {}", editUserRequest.getUserName());
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.USERNAME_EXISTS));
|
|
} else {
|
|
log.error("Error updating user", e);
|
|
UserUtil.sendPacket(currentUser.getSessionId(), new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void getAllUser(int sessionId) {
|
|
log.debug("Fetching all users for session: {}", sessionId);
|
|
// SỬA LỖI BẢO MẬT: Đã loại bỏ cột 'password' khỏi câu truy vấn
|
|
String sql = "SELECT user_id, user_name, last_name, password, first_name, role_name, deleted FROM User ORDER BY user_id";
|
|
|
|
// SỬA LỖI QUAN TRỌNG: Sử dụng try-with-resources để quản lý tài nguyên an toàn
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
// GIỮ NGUYÊN LOGIC GỐC: Xây dựng mảng String[][] qua các bước join và split
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String userId = rs.getString("user_id");
|
|
String userName = rs.getString("user_name");
|
|
String password = rs.getString("password");
|
|
String lastName = rs.getString("last_name");
|
|
String firstName = rs.getString("first_name");
|
|
String role = rs.getString("role_name");
|
|
String deleted = String.valueOf(rs.getBoolean("deleted")); // Lấy giá trị boolean an toàn
|
|
|
|
// Mật khẩu đã được cố ý loại bỏ khỏi câu truy vấn để bảo mật
|
|
String result = String.join("|", userId, userName, lastName, firstName, password, role, deleted);
|
|
resultList.add(result);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
|
|
UserUtil.sendPacket(sessionId, new GetAllUserInfoResponse(resultArray));
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching all users", e);
|
|
// SỬA LỖI: Gửi gói tin lỗi thay vì làm sập server
|
|
UserUtil.sendPacket(sessionId, new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lấy danh sách tất cả dịch vụ và gửi cho một session cụ thể.
|
|
*
|
|
* @param sessionId ID của session sẽ nhận dữ liệu.
|
|
*/
|
|
private void getSerInfo(int sessionId) {
|
|
log.debug("Fetching all services for session: {}", sessionId);
|
|
String sql = "SELECT service_id, service_name, service_cost, deleted FROM Service";
|
|
|
|
// SỬA LỖI QUAN TRỌNG: Sử dụng try-with-resources để quản lý tài nguyên an toàn
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
// GIỮ NGUYÊN LOGIC GỐC: Xây dựng mảng String[][] qua các bước join và split
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String serId = rs.getString("service_id");
|
|
String serName = rs.getString("service_name");
|
|
String serPrice = rs.getString("service_cost");
|
|
// Lấy giá trị boolean một cách an toàn và chuyển thành String
|
|
String deleted = rs.getBoolean("deleted") ? "1" : "0";
|
|
|
|
String result = String.join("|", serId, serName, serPrice, deleted);
|
|
resultList.add(result);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
log.debug("service info: {}", resultArray);
|
|
UserUtil.sendPacket(sessionId, new GetSerInfoResponse(resultArray));
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching services", e);
|
|
// SỬA LỖI: Gửi gói tin lỗi thay vì làm sập server
|
|
UserUtil.sendPacket(sessionId, new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lấy danh sách tất cả các loại thuốc và gửi cho một session cụ thể.
|
|
*
|
|
* @param sessionId ID của session sẽ nhận dữ liệu.
|
|
*/
|
|
private void getMedInfo(int sessionId) {
|
|
log.debug("Fetching all medicines for session: {}", sessionId);
|
|
String sql = """
|
|
SELECT med_id, med_name, med_company, med_description, med_unit,
|
|
med_selling_price, preferred_note, supplement, deleted, route
|
|
FROM Medicine
|
|
ORDER BY med_id
|
|
""";
|
|
|
|
// SỬA LỖI QUAN TRỌNG: Sử dụng try-with-resources để quản lý tài nguyên an toàn
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
// GIỮ NGUYÊN LOGIC GỐC: Xây dựng mảng String[][] qua các bước join và split
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String medId = rs.getString("med_id");
|
|
String medName = rs.getString("med_name");
|
|
String medCompany = rs.getString("med_company");
|
|
String medDescription = rs.getString("med_description");
|
|
String medUnit = rs.getString("med_unit");
|
|
String medSellingPrice = rs.getString("med_selling_price");
|
|
String preferredNote = rs.getString("preferred_note");
|
|
String route = rs.getString("route");
|
|
|
|
// Lấy giá trị boolean một cách an toàn và chuyển thành String "1" hoặc "0"
|
|
String supplement = rs.getBoolean("supplement") ? "1" : "0";
|
|
String deleted = rs.getBoolean("deleted") ? "1" : "0";
|
|
|
|
String result = String.join("|",
|
|
medId,
|
|
medName,
|
|
medCompany != null ? medCompany : "",
|
|
medDescription != null ? medDescription : "",
|
|
medUnit,
|
|
medSellingPrice,
|
|
preferredNote != null ? preferredNote : "",
|
|
supplement,
|
|
deleted,
|
|
route != null ? route : ""
|
|
);
|
|
resultList.add(result);
|
|
}
|
|
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
String[][] resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
// Giữ nguyên tham số -1 để đảm bảo số cột chính xác
|
|
resultArray[i] = resultString[i].split("\\|", -1);
|
|
}
|
|
|
|
UserUtil.sendPacket(sessionId, new GetMedInfoResponse(resultArray));
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching medicines", e);
|
|
// SỬA LỖI: Gửi gói tin lỗi thay vì làm sập server
|
|
UserUtil.sendPacket(sessionId, new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lấy danh sách bệnh nhân cần tái khám trong vòng 7 ngày tới và gửi cho một session cụ thể.
|
|
*
|
|
* @param sessionId ID của session sẽ nhận dữ liệu.
|
|
*/
|
|
private void getRecheckUpList(int sessionId) {
|
|
log.debug("Fetching re-checkup list for session: {}", sessionId);
|
|
|
|
// CẢI TIẾN: Sử dụng múi giờ cụ thể ("Asia/Ho_Chi_Minh") thay vì múi giờ mặc định của server.
|
|
// Điều này đảm bảo tính nhất quán dù server chạy ở bất kỳ đâu.
|
|
ZoneId zoneId = ZoneId.of("Asia/Ho_Chi_Minh");
|
|
|
|
// Sử dụng java.time API để tính toán ngày tháng một cách rõ ràng và an toàn.
|
|
long fromDate = LocalDate.now(zoneId).atStartOfDay(zoneId).toInstant().toEpochMilli();
|
|
// Lấy đến cuối ngày thứ 7 kể từ hôm nay để bao trọn 7 ngày.
|
|
long toDate = LocalDate.now(zoneId).plusDays(7).atTime(23, 59, 59).atZone(zoneId).toInstant().toEpochMilli();
|
|
|
|
String sql = """
|
|
SELECT c.customer_last_name, c.customer_first_name, c.customer_number,
|
|
ch.reCheckupDate, ch.remind_date, ch.checkup_id
|
|
FROM Checkup ch
|
|
JOIN Customer c ON ch.customer_id = c.customer_id
|
|
WHERE ch.reCheckupDate IS NOT NULL AND ch.reCheckupDate BETWEEN ? AND ?
|
|
ORDER BY ch.reCheckupDate ASC
|
|
""";
|
|
|
|
// SỬA LỖI QUAN TRỌNG: Sử dụng try-with-resources để quản lý tài nguyên an toàn
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setLong(1, fromDate);
|
|
stmt.setLong(2, toDate);
|
|
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
List<String[]> results = new ArrayList<>();
|
|
|
|
// CẢI TIẾN: Tạo đối tượng formatter một lần ngoài vòng lặp để tăng hiệu năng.
|
|
// Sử dụng DateTimeFormatter (thread-safe) thay cho SimpleDateFormat.
|
|
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy").withZone(zoneId);
|
|
|
|
while (rs.next()) {
|
|
String[] row = new String[5];
|
|
row[0] = rs.getString("customer_last_name") + " " + rs.getString("customer_first_name");
|
|
row[1] = rs.getString("customer_number");
|
|
|
|
// Câu lệnh SQL đã đảm bảo reCheckupDate không null
|
|
long recheckTimestamp = rs.getLong("reCheckupDate");
|
|
row[2] = formatter.format(Instant.ofEpochMilli(recheckTimestamp));
|
|
|
|
// Xử lý an toàn cho trường remind_date có thể là null
|
|
long remindTimestamp = rs.getLong("remind_date");
|
|
if (rs.wasNull() || remindTimestamp == 0) {
|
|
row[3] = "Chưa đặt"; // Hoặc có thể để là ""
|
|
} else {
|
|
row[3] = formatter.format(Instant.ofEpochMilli(remindTimestamp));
|
|
}
|
|
|
|
row[4] = rs.getString("checkup_id");
|
|
results.add(row);
|
|
}
|
|
|
|
UserUtil.sendPacket(sessionId, new GetRecheckUpListResponse(results.toArray(new String[0][])));
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Error fetching recheck-up list", e);
|
|
// Giữ nguyên logic xử lý lỗi đã tốt của bạn
|
|
UserUtil.sendPacket(sessionId, new ErrorResponse(Error.SQL_EXCEPTION));
|
|
}
|
|
}
|
|
@Override
|
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
|
if (cause instanceof IOException) {
|
|
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
if (user != null) {
|
|
ServerDashboard.getInstance().addLog("Client disconnected: Session " + user.getSessionId());
|
|
}
|
|
SessionManager.onUserDisconnect(ctx.channel());
|
|
} else {
|
|
log.error("ERROR: ", cause);
|
|
ServerDashboard.getInstance().addLog("Error: " + cause.getMessage());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
|
|
if (evt instanceof IdleStateEvent event) {
|
|
if (event.state() == IdleState.READER_IDLE) {
|
|
try {
|
|
var user = SessionManager.getUserByChannel(ctx.channel().id().asLongText());
|
|
if (user != null) {
|
|
ServerDashboard.getInstance().addLog("Client timed out: Session " + user.getSessionId());
|
|
}
|
|
SessionManager.onUserDisconnect(ctx.channel());
|
|
if (user != null) {
|
|
user.resetAuthentication();
|
|
}
|
|
ctx.channel().close();
|
|
} catch (Exception e) {
|
|
ServerDashboard.getInstance().addLog("Error during client timeout: " + e.getMessage());
|
|
}
|
|
}
|
|
} else if (evt instanceof HandshakeComplete) {
|
|
int SessionId = SessionManager.onUserLogin(ctx.channel());
|
|
log.info("Session {} logged in", SessionId);
|
|
ServerDashboard.getInstance().addLog("New client connected: Session " + SessionId);
|
|
ServerDashboard.incrementClients();
|
|
|
|
UserUtil.sendPacket(SessionId, new HandshakeCompleteResponse());
|
|
} else {
|
|
super.userEventTriggered(ctx, evt);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a Google Drive folder for a patient asynchronously and updates the drive_url in database.
|
|
* This method runs in a background thread to avoid blocking the patient creation response.
|
|
*/
|
|
private void createPatientGoogleDriveFolderAsync(int patientId, String patientLastName, String patientFirstName) {
|
|
// Run in background thread to avoid blocking
|
|
new Thread(() -> {
|
|
try {
|
|
// Check if Google Drive is connected
|
|
if (!Server.isGoogleDriveConnected()) {
|
|
log.info("Google Drive not connected - skipping folder creation for patient {}", patientId);
|
|
return;
|
|
}
|
|
|
|
log.info("Creating Google Drive folder for patient {} ({} {})", patientId, patientLastName, patientFirstName);
|
|
|
|
// Create English name (without Patient_ prefix since createPatientFolder will add it)
|
|
String fullName = (patientLastName + " " + patientFirstName).trim();
|
|
String englishPatientName = TextUtils.vietnameseToEnglishName(fullName);
|
|
|
|
// Create patient folder in Google Drive
|
|
String patientFolderId = Server.getGoogleDriveService().createPatientFolder(
|
|
String.valueOf(patientId),
|
|
englishPatientName
|
|
);
|
|
|
|
// Make the folder public and get sharing URL
|
|
String folderUrl = Server.getGoogleDriveService().getFolderSharingUrl(patientFolderId);
|
|
|
|
// Update both drive_url and drive_folder_id in database
|
|
updatePatientDriveInfo(patientId, folderUrl, patientFolderId);
|
|
|
|
log.info("Google Drive folder created successfully for patient {}: {}", patientId, folderUrl);
|
|
|
|
// Notify dashboard
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Created Google Drive folder for patient %d: %s", patientId, englishPatientName)
|
|
);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("Failed to create Google Drive folder for patient {}: {}", patientId, e.getMessage());
|
|
|
|
// Notify dashboard about the error
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Failed to create Google Drive folder for patient %d: %s", patientId, e.getMessage())
|
|
);
|
|
}
|
|
}
|
|
}).start();
|
|
}
|
|
|
|
/**
|
|
* Updates both the drive_url and drive_folder_id columns for a patient in the database.
|
|
*/
|
|
private void updatePatientDriveInfo(int patientId, String driveUrl, String driveFolderId) throws SQLException {
|
|
String sql = "UPDATE Customer SET drive_url = ?, drive_folder_id = ? WHERE customer_id = ?";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement updateStmt = conn.prepareStatement(sql)) {
|
|
|
|
updateStmt.setString(1, driveUrl);
|
|
updateStmt.setString(2, driveFolderId);
|
|
updateStmt.setInt(3, patientId);
|
|
|
|
int rowsUpdated = updateStmt.executeUpdate();
|
|
|
|
if (rowsUpdated > 0) {
|
|
log.info("Updated Google Drive info for patient {}: URL={}, FolderID={}", patientId, driveUrl, driveFolderId);
|
|
} else {
|
|
log.warn("Could not find patient with ID {} to update Google Drive info.", patientId);
|
|
}
|
|
|
|
} catch (SQLException e) {
|
|
log.error("Failed to update Google Drive info for patient {}: {}", patientId, e.getMessage());
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tạo thư mục Google Drive cho một lần khám trong một luồng nền (bất đồng bộ).
|
|
* Phiên bản này sử dụng CompletableFuture cho xử lý bất đồng bộ hiện đại và JDBC an toàn.
|
|
*
|
|
* @param checkupId ID của lần khám.
|
|
* @param customerId ID của bệnh nhân liên quan.
|
|
*/
|
|
private void createCheckupGoogleDriveFolderAsync(int checkupId, int customerId) {
|
|
// Sử dụng CompletableFuture để xử lý bất đồng bộ, hiện đại hơn new Thread().
|
|
CompletableFuture.runAsync(() -> {
|
|
try {
|
|
if (!Server.isGoogleDriveConnected()) {
|
|
log.info("Google Drive not connected - skipping checkup folder creation for checkup {}", checkupId);
|
|
return;
|
|
}
|
|
|
|
// Lấy thông tin bệnh nhân từ CSDL một cách an toàn
|
|
String patientLastName = "";
|
|
String patientFirstName = "";
|
|
String patientDriveFolderId = null;
|
|
|
|
String sql = "SELECT customer_last_name, customer_first_name, drive_folder_id FROM Customer WHERE customer_id = ?";
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setInt(1, customerId);
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
if (rs.next()) {
|
|
patientLastName = rs.getString("customer_last_name");
|
|
patientFirstName = rs.getString("customer_first_name");
|
|
patientDriveFolderId = rs.getString("drive_folder_id");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (patientDriveFolderId == null || patientDriveFolderId.trim().isEmpty()) {
|
|
log.warn("Patient {} has no Google Drive folder ID - cannot create checkup folder", customerId);
|
|
return;
|
|
}
|
|
|
|
log.info("Creating Google Drive checkup folder for checkup {} (patient: {} {})", checkupId, patientLastName, patientFirstName);
|
|
|
|
// Giả sử các hàm này đã được triển khai và hoạt động đúng
|
|
String checkupFolderName = TextUtils.createCheckupFolderNameWithId(checkupId, patientLastName, patientFirstName);
|
|
String checkupFolderId = createCheckupFolderDirectly(patientDriveFolderId, checkupFolderName);
|
|
String folderUrl = Server.getGoogleDriveService().getFolderSharingUrl(checkupFolderId);
|
|
|
|
// Gọi hàm cập nhật an toàn
|
|
updateCheckupDriveInfo(checkupId, folderUrl, checkupFolderId);
|
|
|
|
log.info("Google Drive checkup folder created successfully for checkup {}: {}", checkupId, folderUrl);
|
|
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Created Google Drive checkup folder for checkup %d: %s", checkupId, checkupFolderName)
|
|
);
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
log.error("Failed to create Google Drive checkup folder for checkup {}: {}", checkupId, e.getMessage(), e);
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Failed to create Google Drive checkup folder for checkup %d: %s", checkupId, e.getMessage())
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates a checkup folder directly under patient folder using Google Drive API
|
|
*/
|
|
private String createCheckupFolderDirectly(String parentFolderId, String folderName) throws Exception {
|
|
return Server.getGoogleDriveService().createFolderUnderParent(parentFolderId, folderName);
|
|
}
|
|
|
|
/**
|
|
* Cập nhật thông tin Google Drive (drive_url và drive_folder_id) cho một lần khám trong CSDL.
|
|
*
|
|
* @param checkupId ID của lần khám cần cập nhật.
|
|
* @param driveUrl URL của thư mục Google Drive.
|
|
* @param driveFolderId ID của thư mục Google Drive.
|
|
* @throws SQLException nếu có lỗi truy cập cơ sở dữ liệu xảy ra.
|
|
*/
|
|
private void updateCheckupDriveInfo(int checkupId, String driveUrl, String driveFolderId) throws SQLException {
|
|
String sql = "UPDATE Checkup SET drive_url = ?, drive_folder_id = ? WHERE checkup_id = ?";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
stmt.setString(1, driveUrl);
|
|
stmt.setString(2, driveFolderId);
|
|
stmt.setInt(3, checkupId);
|
|
|
|
int rowsUpdated = stmt.executeUpdate();
|
|
if (rowsUpdated == 0) {
|
|
log.warn("Could not find checkup with ID {} to update Google Drive info.", checkupId);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Tải ảnh của lần khám lên Google Drive một cách bất đồng bộ.
|
|
*
|
|
* @param checkupId ID của lần khám (dưới dạng String).
|
|
* @param fileName Tên của tệp ảnh.
|
|
* @param imageData Dữ liệu của tệp ảnh.
|
|
*/
|
|
private void uploadCheckupImageToGoogleDriveAsync(String checkupId, String fileName, byte[] imageData) {
|
|
// CẢI TIẾN: Sử dụng CompletableFuture để xử lý bất đồng bộ, hiệu quả hơn new Thread().
|
|
log.info("uploadCheckupImageToGoogleDriveAsync");
|
|
CompletableFuture.runAsync(() -> {
|
|
try {
|
|
if (!Server.isGoogleDriveConnected()) {
|
|
log.info("Google Drive not connected - skipping image upload for checkup {}", checkupId);
|
|
return;
|
|
}
|
|
|
|
// --- SỬA LỖI: Lấy thông tin drive_folder_id từ CSDL một cách an toàn ---
|
|
String checkupDriveFolderId = null;
|
|
String sql = "SELECT drive_folder_id FROM Checkup WHERE checkup_id = ?";
|
|
|
|
try (Connection conn = DatabaseManager.getConnection();
|
|
PreparedStatement stmt = conn.prepareStatement(sql)) {
|
|
|
|
// Giả định checkup_id trong CSDL là kiểu số (integer), an toàn hơn là String.
|
|
stmt.setInt(1, Integer.parseInt(checkupId));
|
|
|
|
try (ResultSet rs = stmt.executeQuery()) {
|
|
if (rs.next()) {
|
|
checkupDriveFolderId = rs.getString("drive_folder_id");
|
|
}
|
|
}
|
|
}
|
|
|
|
if (checkupDriveFolderId == null || checkupDriveFolderId.trim().isEmpty()) {
|
|
log.warn("Checkup {} has no Google Drive folder ID - cannot upload image", checkupId);
|
|
return;
|
|
}
|
|
|
|
log.info("Uploading image {} to Google Drive for checkup {}", fileName, checkupId);
|
|
|
|
// Logic tạo file tạm và xóa sau khi dùng của bạn đã tốt, chúng ta sẽ giữ lại.
|
|
java.io.File tempFile = null;
|
|
try {
|
|
tempFile = createTempFileFromBytes(imageData, fileName);
|
|
|
|
String uploadedFileId = Server.getGoogleDriveService().uploadFileToFolder(
|
|
checkupDriveFolderId, tempFile, fileName
|
|
);
|
|
|
|
log.info("Image uploaded successfully to Google Drive for checkup {}: FileID={}", checkupId, uploadedFileId);
|
|
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Uploaded image %s to Google Drive for checkup %s", fileName, checkupId)
|
|
);
|
|
}
|
|
} finally {
|
|
if (tempFile != null && tempFile.exists()) {
|
|
if (tempFile.delete()) {
|
|
log.debug("Cleaned up temporary file: {}", tempFile.getAbsolutePath());
|
|
} else {
|
|
log.warn("Could not delete temporary file: {}", tempFile.getAbsolutePath());
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (NumberFormatException e) {
|
|
log.error("Invalid checkupId format '{}' for Google Drive upload.", checkupId);
|
|
} catch (Exception e) {
|
|
log.error("Failed to upload image to Google Drive for checkup {}: {}", checkupId, e.getMessage(), e);
|
|
if (ServerDashboard.getInstance() != null) {
|
|
ServerDashboard.getInstance().addLog(
|
|
String.format("Failed to upload image %s to Google Drive for checkup %s: %s", fileName, checkupId, e.getMessage())
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates a temporary file from byte array for Google Drive upload
|
|
*/
|
|
private java.io.File createTempFileFromBytes(byte[] data, String originalFileName) throws IOException {
|
|
// Get file extension
|
|
String extension = "";
|
|
int dotIndex = originalFileName.lastIndexOf('.');
|
|
if (dotIndex > 0) {
|
|
extension = originalFileName.substring(dotIndex);
|
|
}
|
|
|
|
// Create temporary file
|
|
java.io.File tempFile = java.io.File.createTempFile("checkup_image_", extension);
|
|
|
|
// Write byte data to temporary file
|
|
try (java.io.FileOutputStream fos = new java.io.FileOutputStream(tempFile)) {
|
|
fos.write(data);
|
|
}
|
|
|
|
return tempFile;
|
|
}
|
|
|
|
|
|
private void broadcastQueueUpdate() {
|
|
// SỬA ĐỔI: Sử dụng một kết nối duy nhất, an toàn cho tất cả các truy vấn bên trong
|
|
try (Connection conn = DatabaseManager.getConnection()) {
|
|
|
|
// --- LOGIC GỐC CHO HÀNG CHỜ (KHÔNG THAY ĐỔI THUẬT TOÁN) ---
|
|
String[][] resultArray;
|
|
String queueSql = """
|
|
SELECT
|
|
a.checkup_id, a.checkup_date, c.customer_last_name, c.customer_first_name,
|
|
d.doctor_first_name, d.doctor_last_name, a.suggestion, a.diagnosis, a.notes,
|
|
a.status, a.customer_id, c.customer_number, c.customer_address,
|
|
a.customer_weight, a.customer_height, c.customer_gender, c.customer_dob,
|
|
a.checkup_type, a.conclusion, a.reCheckupDate, c.cccd_ddcn, a.heart_beat,
|
|
a.blood_pressure, c.drive_url, a.doctor_ultrasound_id, a.queue_number
|
|
FROM
|
|
checkup AS a
|
|
JOIN
|
|
customer AS c ON a.customer_id = c.customer_id
|
|
JOIN
|
|
Doctor D ON a.doctor_id = D.doctor_id
|
|
WHERE
|
|
date(a.checkup_date / 1000, 'unixepoch', '+7 hours') = date('now', '+7 hours')
|
|
""";
|
|
|
|
// SỬA ĐỔI: Thay thế statement.executeQuery bằng PreparedStatement an toàn
|
|
try (PreparedStatement stmt = conn.prepareStatement(queueSql);
|
|
ResultSet rs = stmt.executeQuery()) {
|
|
|
|
if (!rs.isBeforeFirst()) {
|
|
System.out.println("No data found in the checkup table.");
|
|
resultArray = new String[0][0];
|
|
} else {
|
|
ArrayList<String> resultList = new ArrayList<>();
|
|
while (rs.next()) {
|
|
String checkupId = rs.getString("checkup_id");
|
|
String checkupDate = rs.getString("checkup_date");
|
|
long checkupDateLong = Long.parseLong(checkupDate);
|
|
Timestamp timestamp = new Timestamp(checkupDateLong);
|
|
Date date = new Date(timestamp.getTime());
|
|
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
|
|
checkupDate = sdf.format(date);
|
|
String customerLastName = rs.getString("customer_last_name");
|
|
String customerFirstName = rs.getString("customer_first_name");
|
|
String doctorFirstName = rs.getString("doctor_first_name");
|
|
String doctorLastName = rs.getString("doctor_last_name");
|
|
String suggestion = rs.getString("suggestion");
|
|
String diagnosis = rs.getString("diagnosis");
|
|
String notes = rs.getString("notes");
|
|
String status = rs.getString("status");
|
|
String customerId = rs.getString("customer_id");
|
|
String customerNumber = rs.getString("customer_number");
|
|
String customerAddress = rs.getString("customer_address");
|
|
String customerWeight = rs.getString("customer_weight");
|
|
String customerHeight = rs.getString("customer_height");
|
|
String customerGender = rs.getString("customer_gender");
|
|
String customerDob = rs.getString("customer_dob");
|
|
String checkupType = rs.getString("checkup_type");
|
|
String conclusion = rs.getString("conclusion");
|
|
String reCheckupDate = rs.getString("reCheckupDate");
|
|
String cccdDdcn = rs.getString("cccd_ddcn");
|
|
String heartBeat = rs.getString("heart_beat");
|
|
String bloodPressure = rs.getString("blood_pressure");
|
|
String driveUrl = rs.getString("drive_url");
|
|
String doctorUltrasoundId = rs.getString("doctor_ultrasound_id");
|
|
String queueNumber = String.format("%02d", rs.getInt("queue_number"));
|
|
if (driveUrl == null) { driveUrl = ""; }
|
|
String result = String.join("|", checkupId, checkupDate, customerLastName, customerFirstName,
|
|
doctorLastName + " " + doctorFirstName, suggestion, diagnosis, notes, status, customerId, customerNumber, customerAddress, customerWeight, customerHeight,
|
|
customerGender, customerDob, checkupType, conclusion, reCheckupDate, cccdDdcn, heartBeat, bloodPressure,
|
|
driveUrl, doctorUltrasoundId, queueNumber
|
|
);
|
|
resultList.add(result);
|
|
}
|
|
String[] resultString = resultList.toArray(new String[0]);
|
|
resultArray = new String[resultString.length][];
|
|
for (int i = 0; i < resultString.length; i++) {
|
|
resultArray[i] = resultString[i].split("\\|");
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- LOGIC GỐC ĐẾM SỐ BỆNH NHÂN TRONG NGÀY ---
|
|
ZoneId zoneId = ZoneId.of("Asia/Ho_Chi_Minh");
|
|
LocalDate today = LocalDate.now(zoneId);
|
|
long startOfTodayMillis = today.atStartOfDay(zoneId).toInstant().toEpochMilli();
|
|
long endOfTodayMillis = today.plusDays(1).atStartOfDay(zoneId).toInstant().toEpochMilli() - 1;
|
|
|
|
int totalPatientsToday = 0;
|
|
String countQuery = "SELECT COUNT(DISTINCT a.customer_id) as patient_count FROM checkup as a WHERE a.checkup_date >= ? AND a.checkup_date <= ?";
|
|
|
|
// SỬA ĐỔI: Thay thế String.format và statement.executeQuery bằng PreparedStatement an toàn
|
|
try (PreparedStatement countStmt = conn.prepareStatement(countQuery)) {
|
|
countStmt.setLong(1, startOfTodayMillis);
|
|
countStmt.setLong(2, endOfTodayMillis);
|
|
try (ResultSet countRs = countStmt.executeQuery()) {
|
|
if (countRs.next()) {
|
|
totalPatientsToday = countRs.getInt("patient_count");
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- LOGIC GỐC ĐẾM SỐ LƯỢT TÁI KHÁM ---
|
|
int totalRecheckToday = 0;
|
|
String recheckQuery = "SELECT COUNT(*) as recheck_count FROM checkup WHERE reCheckupDate >= ? AND reCheckupDate <= ?";
|
|
|
|
// SỬA ĐỔI: Thay thế String.format và statement.executeQuery bằng PreparedStatement an toàn
|
|
try (PreparedStatement recheckStmt = conn.prepareStatement(recheckQuery)) {
|
|
recheckStmt.setLong(1, startOfTodayMillis);
|
|
recheckStmt.setLong(2, endOfTodayMillis);
|
|
try (ResultSet recheckRs = recheckStmt.executeQuery()) {
|
|
if (recheckRs.next()) {
|
|
totalRecheckToday = recheckRs.getInt("recheck_count");
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- LOGIC GỐC GỬI GÓI TIN ---
|
|
int maxCurId = SessionManager.getMaxSessionId();
|
|
for (int sessionId = 1; sessionId <= maxCurId; sessionId++) {
|
|
UserUtil.sendPacket(sessionId, new GetCheckUpQueueUpdateResponse(resultArray));
|
|
UserUtil.sendPacket(sessionId, new TodayPatientCountResponse(totalPatientsToday));
|
|
UserUtil.sendPacket(sessionId, new RecheckCountResponse(totalRecheckToday));
|
|
}
|
|
log.info("send checkup queue update response to all clients");
|
|
log.info("send today patient count response to all clients");
|
|
log.info("send recheck count response to all clients");
|
|
|
|
} catch (SQLException e) {
|
|
// Giữ nguyên cách xử lý lỗi gốc
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
} |