1685 lines
70 KiB
C++
1685 lines
70 KiB
C++
#include "mainwindow.h"
|
||
|
||
#include <QComboBox>
|
||
#include <QDialog>
|
||
#include <QFormLayout>
|
||
#include <QGroupBox>
|
||
#include <QHeaderView>
|
||
#include <QHBoxLayout>
|
||
#include <QInputDialog>
|
||
#include <QLabel>
|
||
#include <QLineEdit>
|
||
#include <QMessageBox>
|
||
#include <QPushButton>
|
||
#include <QSpinBox>
|
||
#include <QTableWidget>
|
||
#include <QTableWidgetItem>
|
||
#include <QTextEdit>
|
||
#include <QVBoxLayout>
|
||
|
||
#include <vector>
|
||
#include <ctime>
|
||
#include <algorithm>
|
||
|
||
#include "core/his_core.h"
|
||
#include "models/patient.h"
|
||
#include "utils/logger.h"
|
||
#include "utils/input_validator.h"
|
||
#include "dialogs/patient_dialog.h"
|
||
#include "dialogs/payment_dialog.h"
|
||
#include "dialogs/settlement_dialog.h"
|
||
|
||
void MainWindow::setupPatientsTab() {
|
||
patientsTab_ = new QWidget(this);
|
||
auto* layout = new QVBoxLayout(patientsTab_);
|
||
|
||
patientSearchBox_ = new QLineEdit(patientsTab_);
|
||
patientSearchBox_->setPlaceholderText(tr("搜索患者..."));
|
||
connect(patientSearchBox_, &QLineEdit::textChanged, this, &MainWindow::onPatientSearch);
|
||
|
||
auto* toolBar1 = new QHBoxLayout();
|
||
toolBar1->addWidget(patientSearchBox_);
|
||
|
||
patientAddButton_ = new QPushButton(tr("添加患者"), patientsTab_);
|
||
patientEditButton_ = new QPushButton(tr("编辑患者"), patientsTab_);
|
||
patientRemoveButton_ = new QPushButton(tr("删除患者"), patientsTab_);
|
||
patientViewCaseButton_ = new QPushButton(tr("查看病例信息"), patientsTab_);
|
||
|
||
toolBar1->addWidget(patientAddButton_);
|
||
toolBar1->addWidget(patientEditButton_);
|
||
toolBar1->addWidget(patientRemoveButton_);
|
||
toolBar1->addWidget(patientViewCaseButton_);
|
||
toolBar1->addStretch(1);
|
||
layout->addLayout(toolBar1);
|
||
|
||
auto* toolBar2 = new QHBoxLayout();
|
||
patientRegistrationButton_ = new QPushButton(tr("挂号"), patientsTab_);
|
||
patientAddCheckRecordButton_ = new QPushButton(tr("添加检查记录"), patientsTab_);
|
||
patientAddDiagnosisButton_ = new QPushButton(tr("添加诊断记录"), patientsTab_);
|
||
patientAddMedicineRecordButton_ = new QPushButton(tr("添加用药记录"), patientsTab_);
|
||
patientAdmitButton_ = new QPushButton(tr("入院"), patientsTab_);
|
||
patientAddSurgeryRecordButton_ = new QPushButton(tr("添加手术记录"), patientsTab_);
|
||
patientDischargeButton_ = new QPushButton(tr("出院"), patientsTab_);
|
||
patientPaymentButton_ = new QPushButton(tr("缴费"), patientsTab_);
|
||
|
||
toolBar2->addWidget(patientRegistrationButton_);
|
||
toolBar2->addWidget(patientAddCheckRecordButton_);
|
||
toolBar2->addWidget(patientAddDiagnosisButton_);
|
||
toolBar2->addWidget(patientAddMedicineRecordButton_);
|
||
toolBar2->addWidget(patientAdmitButton_);
|
||
toolBar2->addWidget(patientAddSurgeryRecordButton_);
|
||
toolBar2->addWidget(patientDischargeButton_);
|
||
toolBar2->addWidget(patientPaymentButton_);
|
||
toolBar2->addStretch(1);
|
||
layout->addLayout(toolBar2);
|
||
|
||
auto* rowLayout = new QHBoxLayout();
|
||
patientTable_ = new QTableWidget(0, 6, patientsTab_);
|
||
patientTable_->setHorizontalHeaderLabels({tr("患者ID"), tr("姓名"), tr("性别"), tr("年龄"), tr("手机号"), tr("状态")});
|
||
patientTable_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||
patientTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||
patientTable_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||
patientTable_->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
|
||
patientTable_->horizontalHeader()->setStretchLastSection(false);
|
||
patientTable_->setSortingEnabled(true);
|
||
patientTable_->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||
|
||
patientCaseDetail_ = new QTextEdit(patientsTab_);
|
||
patientCaseDetail_->setReadOnly(true);
|
||
patientCaseDetail_->setPlaceholderText(tr("选择患者以查看详细病例记录..."));
|
||
|
||
rowLayout->addWidget(patientTable_, 3);
|
||
rowLayout->addWidget(patientCaseDetail_, 2);
|
||
layout->addLayout(rowLayout);
|
||
|
||
connect(patientAddButton_, &QPushButton::clicked, this, &MainWindow::handleAddPatient);
|
||
connect(patientEditButton_, &QPushButton::clicked, this, &MainWindow::handleEditPatient);
|
||
connect(patientRemoveButton_, &QPushButton::clicked, this, &MainWindow::handleRemovePatient);
|
||
connect(patientViewCaseButton_, &QPushButton::clicked, this, &MainWindow::handleViewPatientCase);
|
||
connect(patientAdmitButton_, &QPushButton::clicked, this, &MainWindow::handleAdmitPatient);
|
||
connect(patientDischargeButton_, &QPushButton::clicked, this, &MainWindow::handleDischargePatient);
|
||
connect(patientPaymentButton_, &QPushButton::clicked, this, &MainWindow::handlePatientPayment);
|
||
connect(patientAddDiagnosisButton_, &QPushButton::clicked, this, &MainWindow::handleAddDiagnosisRecord);
|
||
connect(patientAddSurgeryRecordButton_, &QPushButton::clicked, this, &MainWindow::handleAddSurgeryRecord);
|
||
connect(patientAddMedicineRecordButton_, &QPushButton::clicked, this, &MainWindow::handleAddMedicineRecord);
|
||
connect(patientAddCheckRecordButton_, &QPushButton::clicked, this, &MainWindow::handleAddCheckRecord);
|
||
connect(patientRegistrationButton_, &QPushButton::clicked, this, &MainWindow::handleRegistration);
|
||
connect(patientTable_, &QTableWidget::itemSelectionChanged, this, &MainWindow::updatePatientCaseDetail);
|
||
connect(patientTable_, &QTableWidget::cellChanged, this, &MainWindow::onPatientCellChanged);
|
||
}
|
||
|
||
void MainWindow::onPatientCellChanged(int row, int column) {
|
||
QTableWidgetItem* idItem = patientTable_->item(row, 0);
|
||
if (!idItem) return;
|
||
QString pid = idItem->text();
|
||
if (pid.isEmpty()) return;
|
||
|
||
auto* p = core_.patientService.findPatient(pid.toStdString());
|
||
if (!p) return;
|
||
|
||
QTableWidgetItem* nameItem = patientTable_->item(row, 1);
|
||
QTableWidgetItem* genderItem = patientTable_->item(row, 2);
|
||
QTableWidgetItem* ageItem = patientTable_->item(row, 3);
|
||
QTableWidgetItem* contactItem = patientTable_->item(row, 4);
|
||
QTableWidgetItem* statusItem = patientTable_->item(row, 5);
|
||
|
||
std::string modifyDetails;
|
||
if (nameItem && column == 1) {
|
||
p->Name = nameItem->text().toStdString();
|
||
modifyDetails = "修改项: 姓名 | 新值: " + p->Name;
|
||
}
|
||
if (genderItem && column == 2) {
|
||
p->Gender = genderItem->text().toStdString();
|
||
modifyDetails = "修改项: 性别 | 新值: " + p->Gender;
|
||
}
|
||
if (ageItem && column == 3) {
|
||
p->Age = ageItem->text().toInt();
|
||
modifyDetails = "修改项: 年龄 | 新值: " + std::to_string(p->Age);
|
||
}
|
||
if (contactItem && column == 4) {
|
||
p->Contact = contactItem->text().toStdString();
|
||
modifyDetails = "修改项: 手机号 | 新值: " + p->Contact;
|
||
}
|
||
if (statusItem && column == 5) {
|
||
p->Status = parsePatientStatus(statusItem->text());
|
||
modifyDetails = "修改项: 状态 | 新值: " + patientStatusToText(p->Status).toStdString();
|
||
}
|
||
|
||
if (!modifyDetails.empty()) {
|
||
std::string details = "患者ID: " + pid.toStdString() + " | 患者名: " + p->Name + " | " + modifyDetails;
|
||
logOperation(LogEntryType::PATIENT_OPERATION, "MODIFY_PATIENT", details, pid.toStdString());
|
||
}
|
||
}
|
||
|
||
void MainWindow::refreshPatientTable() {
|
||
patientTable_->blockSignals(true);
|
||
patientTable_->setSortingEnabled(false);
|
||
patientTable_->setRowCount(0);
|
||
|
||
int row = 0;
|
||
core_.patientService.for_eachPatient([this, &row](const std::string&, const Patient& patient) {
|
||
patientTable_->insertRow(row);
|
||
patientTable_->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(patient.PatientID)));
|
||
patientTable_->setItem(row, 1, new QTableWidgetItem(QString::fromStdString(patient.Name)));
|
||
patientTable_->setItem(row, 2, new QTableWidgetItem(QString::fromStdString(patient.Gender)));
|
||
|
||
QTableWidgetItem* ageItem = new QTableWidgetItem();
|
||
ageItem->setData(Qt::DisplayRole, patient.Age);
|
||
patientTable_->setItem(row, 3, ageItem);
|
||
|
||
patientTable_->setItem(row, 4, new QTableWidgetItem(QString::fromStdString(patient.Contact)));
|
||
|
||
patientTable_->setItem(row, 5, new QTableWidgetItem(patientStatusToText(patient.Status)));
|
||
row++;
|
||
});
|
||
|
||
patientTable_->setSortingEnabled(true);
|
||
patientTable_->blockSignals(false);
|
||
}
|
||
|
||
void MainWindow::updatePatientCaseDetail() {
|
||
QString patientId = safeCurrentTableId(patientTable_);
|
||
if (patientId.isEmpty()) {
|
||
patientCaseDetail_->setText(tr("请选择患者以查看病例。"));
|
||
return;
|
||
}
|
||
|
||
PatientCase* pc = core_.patientCaseService.getCase(patientId.toStdString());
|
||
if (!pc) {
|
||
patientCaseDetail_->setText(tr("当前患者没有病例记录。"));
|
||
return;
|
||
}
|
||
|
||
QString text;
|
||
text += tr("PatientID: %1\n").arg(patientId);
|
||
text += tr("预约记录数量: %1\n").arg((int)pc->getAppointmentRecordCount());
|
||
text += tr("检查记录数量: %1\n").arg((int)pc->getCheckRecordCount());
|
||
text += tr("诊断记录数量: %1\n").arg((int)pc->getDiagnosisRecordCount());
|
||
text += tr("用药记录数量: %1\n").arg((int)pc->getMedicineRecordCount());
|
||
text += tr("手术记录数量: %1\n").arg((int)pc->getSurgeryRecordCount());
|
||
text += tr("住院记录数量: %1\n\n").arg((int)pc->getAdmissionRecordCount());
|
||
|
||
text += tr("--- 预约记录 ---\n");
|
||
for (const auto& r : pc->AppointmentRecords) {
|
||
text += tr("医生: %1, 患者: %2, 日期: %3, 备注: %4, 时间: %5\n")
|
||
.arg(QString::fromStdString(r.DoctorID))
|
||
.arg(QString::fromStdString(r.PatientID))
|
||
.arg(QString::fromStdString(r.AppointmentDate))
|
||
.arg(QString::fromStdString(r.Notes))
|
||
.arg(formatDate(r.Timestamp));
|
||
}
|
||
|
||
text += tr("\n--- 检查记录 ---\n");
|
||
for (const auto& r : pc->CheckRecords) {
|
||
text += tr("检查: %1, 价格: %2, 医生: %3, 时间: %4\n")
|
||
.arg(QString::fromStdString(r.CheckName))
|
||
.arg(r.Price)
|
||
.arg(QString::fromStdString(r.DoctorID))
|
||
.arg(formatDate(r.Timestamp));
|
||
}
|
||
|
||
text += tr("\n--- 诊断记录 ---\n");
|
||
for (const auto& r : pc->DiagnosisRecords) {
|
||
text += tr("医生: %1, 诊断: %2, 处方: %3, 备注: %4, 时间: %5\n")
|
||
.arg(QString::fromStdString(r.DoctorID))
|
||
.arg(QString::fromStdString(r.Diagnosis))
|
||
.arg(QString::fromStdString(r.Prescription))
|
||
.arg(QString::fromStdString(r.Remarks))
|
||
.arg(formatDate(r.Timestamp));
|
||
}
|
||
|
||
text += tr("\n--- 用药记录 ---\n");
|
||
for (const auto& r : pc->MedicineRecords) {
|
||
text += tr("药品: %1, 数量: %2, 用法: %3, 单价: %4, 医生: %5, 时间: %6\n")
|
||
.arg(QString::fromStdString(r.MedicineName))
|
||
.arg(r.Quantity)
|
||
.arg(QString::fromStdString(r.Usage))
|
||
.arg(r.UnitPrice)
|
||
.arg(QString::fromStdString(r.DoctorID))
|
||
.arg(formatDate(r.Timestamp));
|
||
}
|
||
|
||
text += tr("\n--- 手术记录 ---\n");
|
||
for (const auto& r : pc->SurgeryRecords) {
|
||
text += tr("手术名称: %1, 类型: %2, 主刀医生: %3\n")
|
||
.arg(QString::fromStdString(r.SurgeryName))
|
||
.arg(QString::fromStdString(r.SurgeryType))
|
||
.arg(QString::fromStdString(r.SurgeonID));
|
||
text += tr(" 麻醉方式: %1, 麻醉医生: %2\n")
|
||
.arg(QString::fromStdString(r.AnesthesiaType))
|
||
.arg(QString::fromStdString(r.AnesthesiologistID));
|
||
text += tr(" 术前诊断: %1\n").arg(QString::fromStdString(r.Diagnosis));
|
||
text += tr(" 手术时长: %1分钟, 出血量: %2\n").arg(r.Duration).arg(QString::fromStdString(r.BloodLoss));
|
||
if (!r.Complications.empty()) {
|
||
text += tr(" 并发症: %1\n").arg(QString::fromStdString(r.Complications));
|
||
}
|
||
text += tr(" 手术时间: %1\n").arg(formatDate(r.SurgeryTime));
|
||
if (!r.Remarks.empty()) {
|
||
text += tr(" 备注: %1\n").arg(QString::fromStdString(r.Remarks));
|
||
}
|
||
}
|
||
|
||
text += tr("\n--- 住院记录 ---\n");
|
||
for (const auto& r : pc->AdmissionRecords) {
|
||
text += tr("病房: %1, 床位: %2, 原因: %3\n").arg(QString::fromStdString(r.WardID)).arg(QString::fromStdString(r.BedID)).arg(QString::fromStdString(r.Reason));
|
||
text += tr(" 入院时间: %1, 出院时间: %2\n").arg(formatDate(r.AdmissionTime)).arg(formatDate(r.DischargeTime));
|
||
if (!r.DischargeSummary.empty()) {
|
||
text += tr(" 出院小结: %1\n").arg(QString::fromStdString(r.DischargeSummary));
|
||
}
|
||
}
|
||
|
||
patientCaseDetail_->setText(text);
|
||
}
|
||
|
||
void MainWindow::handleAddPatient() {
|
||
QDialog* dialog = new QDialog(this);
|
||
dialog->setWindowTitle(tr("添加患者"));
|
||
dialog->setModal(true);
|
||
dialog->resize(450, 300);
|
||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
QFormLayout* form = new QFormLayout(dialog);
|
||
form->setSpacing(10);
|
||
form->setContentsMargins(20, 20, 20, 20);
|
||
|
||
QString newPatientId = QString::fromStdString(Patient::generateUniqueId());
|
||
QLabel* patientIdDisplay = new QLabel(newPatientId, dialog);
|
||
patientIdDisplay->setEnabled(false);
|
||
|
||
QLineEdit* nameEdit = new QLineEdit(dialog);
|
||
QSpinBox* ageSpin = new QSpinBox(dialog);
|
||
ageSpin->setRange(0, 200);
|
||
ageSpin->setValue(0);
|
||
|
||
QComboBox* genderCombo = new QComboBox(dialog);
|
||
genderCombo->addItems({tr("Male"), tr("Female")});
|
||
|
||
QLineEdit* contactEdit = new QLineEdit(dialog);
|
||
|
||
QLabel* infoLabel = new QLabel(tr("患者ID将自动生成"), dialog);
|
||
infoLabel->setStyleSheet("color: gray; font-size: 11px;");
|
||
|
||
form->addRow(tr("患者ID (自动生成):"), patientIdDisplay);
|
||
form->addRow(tr("姓名:"), nameEdit);
|
||
form->addRow(tr("年龄:"), ageSpin);
|
||
form->addRow(tr("性别:"), genderCombo);
|
||
form->addRow(tr("联系方式:"), contactEdit);
|
||
form->addRow(infoLabel);
|
||
|
||
auto* buttonLayout = new QHBoxLayout();
|
||
auto* okButton = new QPushButton(tr("添加"), dialog);
|
||
auto* cancelButton = new QPushButton(tr("取消"), dialog);
|
||
buttonLayout->addWidget(okButton);
|
||
buttonLayout->addWidget(cancelButton);
|
||
buttonLayout->addStretch();
|
||
form->addRow(buttonLayout);
|
||
|
||
connect(okButton, &QPushButton::clicked, [this, dialog, nameEdit, ageSpin, genderCombo, contactEdit, newPatientId]() {
|
||
if (nameEdit->text().isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请填写姓名"));
|
||
return;
|
||
}
|
||
|
||
// 验证手机号格式
|
||
QString contact = contactEdit->text().trimmed();
|
||
if (!contact.isEmpty() && !input_validator::validatePhoneNumber(contact)) {
|
||
QMessageBox::warning(this, tr("手机号格式错误"),
|
||
tr("手机号格式不正确!\n\n要求:\n- 只能包含数字和 \"-\"\n- \"-\" 不能放在开头或结尾\n- 总长度不超过24个字符\n\n例如:010-88889999 或 13812345678"));
|
||
return;
|
||
}
|
||
|
||
Patient p(newPatientId.toStdString(), nameEdit->text().toStdString(), ageSpin->value(),
|
||
genderCombo->currentText().toStdString(), contactEdit->text().toStdString(),
|
||
PatientStatus::Unregistered);
|
||
if (!core_.patientService.addPatient(p)) {
|
||
QMessageBox::warning(this, tr("添加失败"), tr("患者 ID 已存在"));
|
||
return;
|
||
}
|
||
|
||
if (!core_.patientCaseService.addPatientCase(newPatientId.toStdString())) {
|
||
std::string err;
|
||
core_.patientService.removePatient(newPatientId.toStdString(), err);
|
||
QMessageBox::warning(this, tr("添加失败"), tr("病例创建失败"));
|
||
return;
|
||
}
|
||
|
||
std::string patientDetails =
|
||
"患者ID: " + newPatientId.toStdString() +
|
||
" | 姓名: " + nameEdit->text().toStdString() +
|
||
" | 年龄: " + std::to_string(ageSpin->value()) +
|
||
" | 性别: " + genderCombo->currentText().toStdString() +
|
||
" | 联系方式: " + contactEdit->text().toStdString() +
|
||
" | 状态: 未挂号";
|
||
logOperation(LogEntryType::PATIENT_OPERATION, "ADD_PATIENT", patientDetails, newPatientId.toStdString());
|
||
|
||
QMessageBox::information(this, tr("成功"), tr("已添加患者: %1 (%2)").arg(newPatientId).arg(nameEdit->text()));
|
||
refreshPatientTable();
|
||
refreshDashboard();
|
||
dialog->accept();
|
||
});
|
||
|
||
connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::handleEditPatient() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("编辑患者"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
auto* p = core_.patientService.findPatient(pid.toStdString());
|
||
if (!p) return;
|
||
|
||
QDialog* dialog = new QDialog(this);
|
||
dialog->setWindowTitle(tr("编辑患者 - %1").arg(pid));
|
||
dialog->setModal(true);
|
||
dialog->resize(450, 300);
|
||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
QFormLayout* form = new QFormLayout(dialog);
|
||
|
||
QLabel* patientIdLabel = new QLabel(pid, dialog);
|
||
patientIdLabel->setEnabled(false);
|
||
|
||
QLineEdit* nameEdit = new QLineEdit(QString::fromStdString(p->Name), dialog);
|
||
QSpinBox* ageSpin = new QSpinBox(dialog);
|
||
ageSpin->setRange(0, 200);
|
||
ageSpin->setValue(p->Age);
|
||
QComboBox* genderCombo = new QComboBox(dialog);
|
||
genderCombo->addItems({tr("Male"), tr("Female")});
|
||
int genderIdx = (p->Gender == "Female") ? 1 : 0;
|
||
genderCombo->setCurrentIndex(genderIdx);
|
||
|
||
QLineEdit* contactEdit = new QLineEdit(QString::fromStdString(p->Contact), dialog);
|
||
|
||
QComboBox* statusCombo = new QComboBox(dialog);
|
||
statusCombo->addItems({tr("Unregistered"), tr("Outpatient"), tr("Emergency"), tr("Visited"), tr("Inpatient"), tr("Discharged")});
|
||
int statusIdx = 0;
|
||
switch (p->Status) {
|
||
case PatientStatus::Unregistered: statusIdx = 0; break;
|
||
case PatientStatus::Outpatient: statusIdx = 1; break;
|
||
case PatientStatus::Emergency: statusIdx = 2; break;
|
||
case PatientStatus::Visited: statusIdx = 3; break;
|
||
case PatientStatus::Inpatient: statusIdx = 4; break;
|
||
case PatientStatus::Discharged: statusIdx = 5; break;
|
||
}
|
||
statusCombo->setCurrentIndex(statusIdx);
|
||
|
||
form->addRow(tr("患者ID:"), patientIdLabel);
|
||
form->addRow(tr("姓名:"), nameEdit);
|
||
form->addRow(tr("年龄:"), ageSpin);
|
||
form->addRow(tr("性别:"), genderCombo);
|
||
form->addRow(tr("联系方式:"), contactEdit);
|
||
form->addRow(tr("状态:"), statusCombo);
|
||
|
||
auto* buttonLayout = new QHBoxLayout();
|
||
auto* okButton = new QPushButton(tr("保存"), dialog);
|
||
auto* cancelButton = new QPushButton(tr("取消"), dialog);
|
||
buttonLayout->addWidget(okButton);
|
||
buttonLayout->addWidget(cancelButton);
|
||
buttonLayout->addStretch();
|
||
form->addRow(buttonLayout);
|
||
|
||
connect(okButton, &QPushButton::clicked, [this, pid, dialog, p, nameEdit, ageSpin, genderCombo, contactEdit, statusCombo]() {
|
||
// 验证手机号格式
|
||
QString contact = contactEdit->text().trimmed();
|
||
if (!contact.isEmpty() && !input_validator::validatePhoneNumber(contact)) {
|
||
QMessageBox::warning(this, tr("手机号格式错误"),
|
||
tr("手机号格式不正确!\n\n要求:\n- 只能包含数字和 \"-\"\n- \"-\" 不能放在开头或结尾\n- 总长度不超过24个字符\n\n例如:010-88889999 或 13812345678"));
|
||
return;
|
||
}
|
||
|
||
std::string oldDetails =
|
||
"修改前 - 姓名: " + p->Name +
|
||
" | 年龄: " + std::to_string(p->Age) +
|
||
" | 性别: " + p->Gender +
|
||
" | 联系方式: " + p->Contact +
|
||
" | 状态: " + patientStatusToText(p->Status).toStdString();
|
||
|
||
if (!core_.patientService.updatePatient(pid.toStdString(), nameEdit->text().toStdString(), ageSpin->value(),
|
||
genderCombo->currentText().toStdString(), contactEdit->text().toStdString(),
|
||
parsePatientStatus(statusCombo->currentText()))) {
|
||
QMessageBox::warning(this, tr("编辑失败"), tr("更新失败"));
|
||
return;
|
||
}
|
||
|
||
std::string newDetails =
|
||
"修改后 - 姓名: " + nameEdit->text().toStdString() +
|
||
" | 年龄: " + std::to_string(ageSpin->value()) +
|
||
" | 性别: " + genderCombo->currentText().toStdString() +
|
||
" | 联系方式: " + contactEdit->text().toStdString() +
|
||
" | 状态: " + statusCombo->currentText().toStdString();
|
||
|
||
std::string fullDetails = "患者ID: " + pid.toStdString() + " | " + oldDetails + "\n" + newDetails;
|
||
logOperation(LogEntryType::PATIENT_OPERATION, "MODIFY_PATIENT", fullDetails, pid.toStdString());
|
||
|
||
QMessageBox::information(this, tr("成功"), tr("已成功更新患者 %1").arg(pid));
|
||
refreshPatientTable();
|
||
dialog->accept();
|
||
});
|
||
|
||
connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::handleRemovePatient() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("删除患者"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
std::string patientDetails;
|
||
QString patientName = tr("未知");
|
||
if (patient) {
|
||
patientName = QString::fromStdString(patient->Name);
|
||
patientDetails =
|
||
"患者ID: " + patient->PatientID +
|
||
" | 姓名: " + patient->Name +
|
||
" | 年龄: " + std::to_string(patient->Age) +
|
||
" | 性别: " + patient->Gender +
|
||
" | 联系方式: " + patient->Contact +
|
||
" | 状态: " + patientStatusToText(patient->Status).toStdString();
|
||
}
|
||
|
||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||
this, tr("确认删除"),
|
||
tr("确定要删除患者 \"%1\" (ID: %2) 吗?\n此操作无法撤销,将同时删除该患者的所有病例记录。").arg(patientName).arg(pid),
|
||
QMessageBox::Ok | QMessageBox::Cancel,
|
||
QMessageBox::Cancel);
|
||
if (reply != QMessageBox::Ok) return;
|
||
|
||
std::string err;
|
||
if (!core_.patientService.removePatient(pid.toStdString(), err)) {
|
||
QMessageBox::warning(this, tr("删除失败"), QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
core_.patientCaseService.removeCase(pid.toStdString());
|
||
|
||
if (!patientDetails.empty()) {
|
||
logOperation(LogEntryType::PATIENT_OPERATION, "REMOVE_PATIENT", patientDetails, pid.toStdString());
|
||
}
|
||
|
||
refreshPatientTable();
|
||
refreshDashboard();
|
||
}
|
||
|
||
void MainWindow::handleViewPatientCase() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("查看病例信息"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* dialog = new PatientCaseViewDialog(core_, pid, this);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::handleAdmitPatient() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("入院"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (patient && patient->Status == PatientStatus::Inpatient) {
|
||
QMessageBox::warning(this, tr("入院"), tr("该患者 %1 已经入院,不能重复入院。").arg(pid));
|
||
return;
|
||
}
|
||
|
||
QDialog* dialog = new QDialog(this);
|
||
dialog->setWindowTitle(tr("入院 - %1").arg(pid));
|
||
dialog->setModal(true);
|
||
dialog->resize(550, 450);
|
||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
QFormLayout* form = new QFormLayout(dialog);
|
||
form->setSpacing(10);
|
||
form->setContentsMargins(20, 20, 20, 20);
|
||
|
||
QLabel* patientIdLabel = new QLabel(pid, dialog);
|
||
patientIdLabel->setEnabled(false);
|
||
|
||
QString currentDate = formatCurrentDate();
|
||
QLabel* dateLabel = new QLabel(currentDate, dialog);
|
||
dateLabel->setEnabled(false);
|
||
|
||
QComboBox* wardCombo = new QComboBox(dialog);
|
||
wardCombo->addItem(tr("-- 选择病房 --"));
|
||
core_.wardService.for_eachWard([&wardCombo](const std::string&, const Ward& ward) {
|
||
QString display = QString("%1 (%2) - 空床: %3/%4")
|
||
.arg(QString::fromStdString(ward.WardID))
|
||
.arg(QString::fromStdString(ward.DepartmentID))
|
||
.arg(ward.freeBedCount())
|
||
.arg(ward.MaxBeds);
|
||
wardCombo->addItem(display, QString::fromStdString(ward.WardID));
|
||
});
|
||
|
||
QComboBox* bedCombo = new QComboBox(dialog);
|
||
bedCombo->addItem(tr("-- 先选择病房 --"));
|
||
|
||
QTextEdit* reasonEdit = new QTextEdit(dialog);
|
||
reasonEdit->setMaximumHeight(80);
|
||
reasonEdit->setPlaceholderText(tr("入院原因"));
|
||
|
||
form->addRow(tr("患者ID:"), patientIdLabel);
|
||
form->addRow(tr("入院日期:"), dateLabel);
|
||
form->addRow(tr("选择病房:"), wardCombo);
|
||
form->addRow(tr("选择床位:"), bedCombo);
|
||
form->addRow(tr("入院原因:"), reasonEdit);
|
||
|
||
auto* buttonLayout = new QHBoxLayout();
|
||
auto* okButton = new QPushButton(tr("确认入院"), dialog);
|
||
auto* cancelButton = new QPushButton(tr("取消"), dialog);
|
||
buttonLayout->addWidget(okButton);
|
||
buttonLayout->addWidget(cancelButton);
|
||
buttonLayout->addStretch();
|
||
form->addRow(buttonLayout);
|
||
|
||
connect(wardCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), [wardCombo, bedCombo, &core = core_](int index) {
|
||
bedCombo->clear();
|
||
if (index == 0) {
|
||
bedCombo->addItem(tr("-- 先选择病房 --"));
|
||
return;
|
||
}
|
||
QString wardId = wardCombo->currentData().toString();
|
||
auto* ward = core.wardService.findWard(wardId.toStdString());
|
||
if (!ward) return;
|
||
|
||
bedCombo->addItem(tr("-- 选择床位 --"));
|
||
const auto* wardPtr = ward;
|
||
for (const auto& bed : wardPtr->Beds) {
|
||
if (bed.Status == BedStatus::Free) {
|
||
bedCombo->addItem(QString::fromStdString(bed.BedID), QString::fromStdString(bed.BedID));
|
||
}
|
||
}
|
||
});
|
||
|
||
connect(okButton, &QPushButton::clicked, [this, pid, wardCombo, bedCombo, dateLabel, reasonEdit, dialog]() {
|
||
if (wardCombo->currentIndex() == 0 || bedCombo->currentIndex() == 0) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择病房和床位"));
|
||
return;
|
||
}
|
||
|
||
QString wardId = wardCombo->currentData().toString();
|
||
QString bedId = bedCombo->currentData().toString();
|
||
|
||
std::string actualBedId;
|
||
if (!core_.patientService.admitPatient(wardId.toStdString(), pid.toStdString(), actualBedId)) {
|
||
QMessageBox::warning(this, tr("入院失败"), tr("无法分配床位,请确认病房和床位是否正确"));
|
||
return;
|
||
}
|
||
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (patient) {
|
||
core_.patientService.updatePatient(pid.toStdString(), patient->Name, patient->Age, patient->Gender, patient->Contact, PatientStatus::Inpatient);
|
||
}
|
||
|
||
AdmissionRecord ar(wardId.toStdString(), actualBedId, reasonEdit->toPlainText().toStdString());
|
||
core_.patientCaseService.addAdmissionRecord(pid.toStdString(), ar);
|
||
|
||
std::string paymentId;
|
||
double admissionFee = 1000.0;
|
||
if (core_.paymentService.createPayment(pid.toStdString(), admissionFee,
|
||
PaymentMethod::Cash, "入院", wardId.toStdString(),
|
||
"入院押金 - 病房: " + wardId.toStdString() + ", 床位: " + actualBedId, paymentId)) {
|
||
if (!core_.paymentService.completePayment(paymentId)) {
|
||
core_.paymentService.removePayment(paymentId);
|
||
QMessageBox::warning(this, tr("支付失败"), tr("入院押金支付失败,请重试"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
std::string admitDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 患者姓名: " + (patient ? patient->Name : "未知") +
|
||
" | 病房ID: " + wardId.toStdString() +
|
||
" | 床位ID: " + actualBedId +
|
||
" | 入院原因: " + reasonEdit->toPlainText().toStdString() +
|
||
" | 入院日期: " + dateLabel->text().toStdString() +
|
||
" | 患者状态: 住院" +
|
||
" | 入院押金: " + std::to_string(admissionFee) +
|
||
" | 支付ID: " + paymentId +
|
||
" | 支付状态: 已完成";
|
||
logOperation(LogEntryType::ADMISSION_RECORD, "ADMIT", admitDetails, pid.toStdString());
|
||
|
||
// 获取患者姓名和科室名称用于显示
|
||
auto* patientPtr = core_.patientService.findPatient(pid.toStdString());
|
||
QString patientName = patientPtr ? QString::fromStdString(patientPtr->Name) : pid;
|
||
auto* ward = core_.wardService.findWard(wardId.toStdString());
|
||
QString deptName = ward ? QString::fromStdString(ward->DepartmentID) : wardId;
|
||
if (ward) {
|
||
auto* dept = core_.departmentService.findDepartment(ward->DepartmentID);
|
||
if (dept) {
|
||
deptName = QString::fromStdString(dept->Name);
|
||
}
|
||
}
|
||
|
||
QMessageBox::information(this, tr("成功"),
|
||
tr("%1(%2) 已成功入院到病房 %3(%4)\n床位: %5\n入院押金: %6 元 (已自动完成支付)")
|
||
.arg(patientName)
|
||
.arg(pid)
|
||
.arg(wardId)
|
||
.arg(deptName)
|
||
.arg(QString::fromStdString(actualBedId))
|
||
.arg(QString::number(admissionFee, 'f', 2)));
|
||
refreshWardTable();
|
||
refreshPatientTable();
|
||
refreshDashboard();
|
||
dialog->accept();
|
||
});
|
||
|
||
connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::handleDischargePatient() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("出院"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* p = core_.patientService.findPatient(pid.toStdString());
|
||
if (!p || p->Status != PatientStatus::Inpatient) {
|
||
QMessageBox::warning(this, tr("出院"), tr("该患者不是住院状态"));
|
||
return;
|
||
}
|
||
|
||
Ward* patientWard = nullptr;
|
||
std::string bedName;
|
||
core_.wardService.for_eachWard([&](const std::string&, const Ward& ward) {
|
||
for (const auto& bed : ward.Beds) {
|
||
if (bed.PatientID == pid.toStdString()) {
|
||
patientWard = const_cast<Ward*>(&ward);
|
||
bedName = bed.BedID;
|
||
return;
|
||
}
|
||
}
|
||
});
|
||
|
||
if (!patientWard) {
|
||
QMessageBox::warning(this, tr("出院"), tr("未找到该患者的床位信息"));
|
||
return;
|
||
}
|
||
|
||
QString currentDate = formatCurrentDate();
|
||
|
||
if (!core_.patientService.releasePatient(patientWard->WardID, pid.toStdString())) {
|
||
QMessageBox::warning(this, tr("出院失败"), tr("无法释放床位"));
|
||
return;
|
||
}
|
||
|
||
core_.patientService.updatePatient(pid.toStdString(), p->Name, p->Age, p->Gender, p->Contact, PatientStatus::Discharged);
|
||
|
||
auto* pc = core_.patientCaseService.getCase(pid.toStdString());
|
||
if (pc) {
|
||
for (auto& ar : pc->AdmissionRecords) {
|
||
if (ar.isCurrentlyAdmitted() && ar.BedID == bedName) {
|
||
ar.DischargeTime = time(nullptr);
|
||
ar.DischargeSummary = tr("自动出院").toStdString();
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
std::string dischargeDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 患者姓名: " + (p ? p->Name : "未知") +
|
||
" | 病房ID: " + patientWard->WardID +
|
||
" | 床位ID: " + bedName +
|
||
" | 入院日期: " + formatDate(pc && !pc->AdmissionRecords.empty() ? pc->AdmissionRecords.back().AdmissionTime : 0).toStdString() +
|
||
" | 出院日期: " + currentDate.toStdString() +
|
||
" | 患者状态: 出院" +
|
||
" | 出院原因: 自动出院";
|
||
logOperation(LogEntryType::DISCHARGE_RECORD, "DISCHARGE", dischargeDetails, pid.toStdString());
|
||
|
||
QMessageBox::information(this, tr("出院成功"),
|
||
tr("患者 %1 已出院,入院日期: %2\n请使用\"缴费\"按钮进行结算。")
|
||
.arg(pid).arg(formatDate(pc && !pc->AdmissionRecords.empty() ? pc->AdmissionRecords.back().AdmissionTime : 0)));
|
||
|
||
refreshWardTable();
|
||
refreshPatientTable();
|
||
refreshDashboard();
|
||
updatePatientCaseDetail();
|
||
}
|
||
|
||
void MainWindow::handleAddDiagnosisRecord() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("新增诊断"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
// 检查患者状态:未挂号或已出院禁止添加诊断记录
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (!patient) {
|
||
QMessageBox::warning(this, tr("新增诊断"), tr("患者不存在"));
|
||
return;
|
||
}
|
||
if (patient->Status == PatientStatus::Unregistered) {
|
||
QMessageBox::warning(this, tr("新增诊断"),
|
||
tr("该患者当前状态为\"未挂号\",禁止添加诊断记录。\n请先为该患者进行挂号操作。"));
|
||
return;
|
||
}
|
||
if (patient->Status == PatientStatus::Discharged) {
|
||
QMessageBox::warning(this, tr("新增诊断"),
|
||
tr("该患者当前状态为\"已出院\",禁止添加诊断记录。"));
|
||
return;
|
||
}
|
||
|
||
struct DoctorInfo {
|
||
std::string id;
|
||
std::string name;
|
||
std::string dept;
|
||
};
|
||
std::vector<DoctorInfo> doctors;
|
||
core_.doctorService.for_eachDoctor([&doctors](const std::string&, const Doctor& d) {
|
||
doctors.push_back({d.DoctorID, d.Name, d.DepartmentID});
|
||
});
|
||
|
||
if (doctors.empty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("系统中没有医生,请先添加医生"));
|
||
return;
|
||
}
|
||
|
||
QDialog* dialog = new QDialog(this);
|
||
dialog->setWindowTitle(tr("添加诊断记录 - %1").arg(pid));
|
||
dialog->setModal(true);
|
||
dialog->resize(500, 400);
|
||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
QFormLayout* form = new QFormLayout(dialog);
|
||
form->setSpacing(10);
|
||
form->setContentsMargins(20, 20, 20, 20);
|
||
|
||
QComboBox* doctorCombo = new QComboBox(dialog);
|
||
doctorCombo->addItem(tr("-- 请选择医生 --"), QVariant());
|
||
for (const auto& doc : doctors) {
|
||
QString deptName = QString::fromStdString(doc.dept);
|
||
auto* dept = core_.departmentService.findDepartment(doc.dept);
|
||
if (dept) {
|
||
deptName = QString::fromStdString(dept->Name);
|
||
}
|
||
QString display = QString("%1 (%2) - %3").arg(QString::fromStdString(doc.name)).arg(deptName).arg(QString::fromStdString(doc.id));
|
||
doctorCombo->addItem(display, QString::fromStdString(doc.id));
|
||
}
|
||
|
||
QString currentDate = formatCurrentDate();
|
||
QLabel* dateLabel = new QLabel(currentDate, dialog);
|
||
dateLabel->setEnabled(false);
|
||
|
||
QTextEdit* diagnosisEdit = new QTextEdit(dialog);
|
||
diagnosisEdit->setMinimumHeight(60);
|
||
|
||
QTextEdit* prescriptionEdit = new QTextEdit(dialog);
|
||
prescriptionEdit->setMinimumHeight(60);
|
||
|
||
QLineEdit* remarksEdit = new QLineEdit(dialog);
|
||
|
||
form->addRow(tr("选择医生:"), doctorCombo);
|
||
form->addRow(tr("诊断日期:"), dateLabel);
|
||
form->addRow(tr("诊断:"), diagnosisEdit);
|
||
form->addRow(tr("处方:"), prescriptionEdit);
|
||
form->addRow(tr("备注:"), remarksEdit);
|
||
|
||
auto* buttonLayout = new QHBoxLayout();
|
||
auto* okButton = new QPushButton(tr("保存"), dialog);
|
||
auto* cancelButton = new QPushButton(tr("取消"), dialog);
|
||
buttonLayout->addWidget(okButton);
|
||
buttonLayout->addWidget(cancelButton);
|
||
buttonLayout->addStretch();
|
||
form->addRow(buttonLayout);
|
||
|
||
connect(okButton, &QPushButton::clicked, [this, pid, doctorCombo, diagnosisEdit, prescriptionEdit, remarksEdit, dialog]() {
|
||
if (doctorCombo->currentIndex() <= 0) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择医生"));
|
||
return;
|
||
}
|
||
if (diagnosisEdit->toPlainText().isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请填写诊断内容"));
|
||
return;
|
||
}
|
||
|
||
QString doctorId = doctorCombo->itemData(doctorCombo->currentIndex()).toString();
|
||
|
||
DiagnosisRecord record(
|
||
doctorId.toStdString(),
|
||
diagnosisEdit->toPlainText().toStdString(),
|
||
prescriptionEdit->toPlainText().toStdString(),
|
||
remarksEdit->text().toStdString()
|
||
);
|
||
|
||
if (!core_.patientCaseService.addDiagnosisRecord(pid.toStdString(), record)) {
|
||
QMessageBox::warning(this, tr("新增失败"), tr("诊断记录添加失败"));
|
||
return;
|
||
}
|
||
|
||
std::string diagDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 医生ID: " + doctorId.toStdString() +
|
||
" | 诊断内容: " + diagnosisEdit->toPlainText().toStdString() +
|
||
" | 处方: " + prescriptionEdit->toPlainText().toStdString() +
|
||
" | 备注: " + remarksEdit->text().toStdString();
|
||
logOperation(LogEntryType::DIAGNOSIS_RECORD, "ADD_DIAGNOSIS", diagDetails, pid.toStdString());
|
||
|
||
// 获取患者和医生信息用于显示
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
QString patientName = patient ? QString::fromStdString(patient->Name) : pid;
|
||
auto* doctor = core_.doctorService.findDoctor(doctorId.toStdString());
|
||
QString doctorName = doctor ? QString::fromStdString(doctor->Name) : doctorId;
|
||
|
||
QMessageBox::information(this, tr("成功"),
|
||
tr("%1(%2) 已成功诊断\n医生: %3(%4)\n诊断内容: %5")
|
||
.arg(patientName)
|
||
.arg(pid)
|
||
.arg(doctorName)
|
||
.arg(doctorId)
|
||
.arg(diagnosisEdit->toPlainText()));
|
||
|
||
if (patient && (patient->Status == PatientStatus::Outpatient ||
|
||
patient->Status == PatientStatus::Emergency ||
|
||
patient->Status == PatientStatus::Visited)) {
|
||
core_.patientService.updatePatient(pid.toStdString(), patient->Name, patient->Age,
|
||
patient->Gender, patient->Contact, PatientStatus::Unregistered);
|
||
refreshPatientTable();
|
||
QMessageBox::information(this, tr("诊断完成"),
|
||
tr("诊断已完成,患者 %1(%2) 已回到\"未挂号\"状态。\n如需继续就诊,请重新挂号。")
|
||
.arg(patientName)
|
||
.arg(pid));
|
||
}
|
||
|
||
updatePatientCaseDetail();
|
||
dialog->accept();
|
||
});
|
||
|
||
connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::handleAddCheckRecord() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("添加检查记录"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
// 检查患者状态:未挂号或已出院禁止添加检查记录
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (!patient) {
|
||
QMessageBox::warning(this, tr("添加检查记录"), tr("患者不存在"));
|
||
return;
|
||
}
|
||
if (patient->Status == PatientStatus::Unregistered) {
|
||
QMessageBox::warning(this, tr("添加检查记录"),
|
||
tr("该患者当前状态为\"未挂号\",禁止添加检查记录。\n请先为该患者进行挂号操作。"));
|
||
return;
|
||
}
|
||
if (patient->Status == PatientStatus::Discharged) {
|
||
QMessageBox::warning(this, tr("添加检查记录"),
|
||
tr("该患者当前状态为\"已出院\",禁止添加检查记录。"));
|
||
return;
|
||
}
|
||
|
||
auto* pc = core_.patientCaseService.getCase(pid.toStdString());
|
||
if (!pc) {
|
||
QMessageBox::warning(this, tr("添加检查记录"),
|
||
tr("该患者没有病例记录。\n请先为该患者创建病例后再添加检查记录。"));
|
||
return;
|
||
}
|
||
|
||
auto* dialog = new CheckRecordAddDialog(core_, pid, this);
|
||
int result = dialog->exec();
|
||
|
||
QString checkId;
|
||
QString doctorId;
|
||
|
||
if (result == QDialog::Accepted) {
|
||
checkId = dialog->getCheckId();
|
||
doctorId = dialog->getDoctorId();
|
||
}
|
||
|
||
delete dialog;
|
||
|
||
if (result != QDialog::Accepted) {
|
||
return;
|
||
}
|
||
|
||
if (checkId.isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择检查项目"));
|
||
return;
|
||
}
|
||
|
||
if (doctorId.isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择医生"));
|
||
return;
|
||
}
|
||
|
||
auto* check = core_.checkService.findCheck(checkId.toStdString());
|
||
if (!check) {
|
||
QMessageBox::warning(this, tr("错误"), tr("检查项目不存在"));
|
||
return;
|
||
}
|
||
|
||
CheckRecord record(
|
||
checkId.toStdString(),
|
||
check->Name,
|
||
check->DepartmentID,
|
||
check->Price,
|
||
doctorId.toStdString()
|
||
);
|
||
|
||
if (!core_.patientCaseService.addCheckRecord(pid.toStdString(), record)) {
|
||
QMessageBox::warning(this, tr("错误"), tr("检查记录添加失败"));
|
||
return;
|
||
}
|
||
|
||
std::string paymentId;
|
||
if (core_.paymentService.createPayment(pid.toStdString(), check->Price,
|
||
PaymentMethod::Cash, "检查", checkId.toStdString(),
|
||
"检查: " + check->Name, paymentId)) {
|
||
if (!core_.paymentService.completePayment(paymentId)) {
|
||
core_.paymentService.removePayment(paymentId);
|
||
QMessageBox::warning(this, tr("支付失败"), tr("检查费用支付失败,请重试"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
std::string checkDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 检查ID: " + checkId.toStdString() +
|
||
" | 检查名: " + check->Name +
|
||
" | 科室ID: " + check->DepartmentID +
|
||
" | 价格: " + std::to_string(check->Price) +
|
||
" | 医生ID: " + doctorId.toStdString() +
|
||
" | 支付ID: " + paymentId +
|
||
" | 支付状态: 已完成";
|
||
|
||
logOperation(LogEntryType::CHECK_RECORD, "ADD_CHECK_RECORD", checkDetails, pid.toStdString());
|
||
|
||
QMessageBox::information(this, tr("成功"),
|
||
tr("检查记录已添加\n检查: %1\n科室: %2\n价格: %3\n已自动完成支付")
|
||
.arg(QString::fromStdString(check->Name))
|
||
.arg(QString::fromStdString(check->DepartmentID))
|
||
.arg(QString::number(check->Price, 'f', 2)));
|
||
|
||
updatePatientCaseDetail();
|
||
}
|
||
|
||
void MainWindow::handleRegistration() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("挂号"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
const auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (!patient) {
|
||
QMessageBox::warning(this, tr("挂号"), tr("患者不存在"));
|
||
return;
|
||
}
|
||
|
||
RegistrationDialog dialog(core_, pid, this);
|
||
int result = dialog.exec();
|
||
|
||
if (result == QDialog::Accepted) {
|
||
QString deptId = dialog.getDepartmentId();
|
||
QString doctorId = dialog.getDoctorId();
|
||
int regType = dialog.getRegistrationType();
|
||
|
||
if (!deptId.isEmpty() && !doctorId.isEmpty()) {
|
||
const auto* doctor = core_.doctorService.findDoctor(doctorId.toStdString());
|
||
const auto* dept = core_.departmentService.findDepartment(deptId.toStdString());
|
||
|
||
if (doctor && dept) {
|
||
double registrationFee = (regType == 1) ? 50.0 : 10.0;
|
||
QString regTypeName = (regType == 1) ? tr("急诊") : tr("门诊");
|
||
PatientStatus newStatus = (regType == 1) ? PatientStatus::Emergency : PatientStatus::Outpatient;
|
||
|
||
auto* patientPtr = core_.patientService.findPatient(pid.toStdString());
|
||
if (patientPtr) {
|
||
core_.patientService.updatePatient(pid.toStdString(), patientPtr->Name, patientPtr->Age,
|
||
patientPtr->Gender, patientPtr->Contact, newStatus);
|
||
}
|
||
|
||
std::string regDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 患者姓名: " + patient->Name +
|
||
" | 挂号类型: " + regTypeName.toStdString() +
|
||
" | 科室: " + dept->Name +
|
||
" | 医生ID: " + doctorId.toStdString() +
|
||
" | 医生姓名: " + doctor->Name +
|
||
" | 医生职称: " +
|
||
(doctor->Title == DoctorTitle::Chief ? std::string("主任医师") :
|
||
doctor->Title == DoctorTitle::AssociateChief ? std::string("副主任医师") :
|
||
doctor->Title == DoctorTitle::Attending ? std::string("主治医师") :
|
||
std::string("住院医师"));
|
||
|
||
std::string paymentId;
|
||
if (core_.paymentService.createPayment(pid.toStdString(), registrationFee,
|
||
PaymentMethod::Cash, "挂号", doctorId.toStdString(),
|
||
"挂号 - 类型: " + regTypeName.toStdString() + ", 科室: " + dept->Name + ", 医生: " + doctor->Name, paymentId)) {
|
||
if (!core_.paymentService.completePayment(paymentId)) {
|
||
core_.paymentService.removePayment(paymentId);
|
||
QMessageBox::warning(this, tr("支付失败"), tr("挂号费支付失败,请重试"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
regDetails += " | 挂号费: " + std::to_string(registrationFee) +
|
||
" | 支付ID: " + paymentId + " | 支付状态: 已完成";
|
||
logOperation(LogEntryType::PATIENT_OPERATION, "REGISTRATION", regDetails, pid.toStdString());
|
||
|
||
// 获取患者姓名用于显示
|
||
QString patientName = patient ? QString::fromStdString(patient->Name) : pid;
|
||
|
||
QMessageBox::information(this, tr("挂号成功"),
|
||
tr("%1(%2) 已成功挂号\n挂号类型: %3\n医生: %4(%5)\n科室: %6\n挂号费: %7 元 (已自动完成支付)")
|
||
.arg(patientName)
|
||
.arg(pid)
|
||
.arg(regTypeName)
|
||
.arg(QString::fromStdString(doctor->Name))
|
||
.arg(QString::fromStdString(doctorId.toStdString()))
|
||
.arg(QString::fromStdString(dept->Name))
|
||
.arg(QString::number(registrationFee, 'f', 2)));
|
||
|
||
refreshPatientTable();
|
||
updatePatientCaseDetail();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
void MainWindow::handleAddMedicineRecord() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("添加用药记录"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* pc = core_.patientCaseService.getCase(pid.toStdString());
|
||
if (!pc || pc->AppointmentRecords.empty()) {
|
||
QMessageBox::warning(this, tr("添加用药记录"),
|
||
tr("该患者尚未挂号(没有预约记录)。\n请先为该患者进行挂号操作后再添加用药记录。"));
|
||
return;
|
||
}
|
||
|
||
auto* dialog = new MedicineRecordAddDialog(core_, pid, this);
|
||
int result = dialog->exec();
|
||
|
||
QString medicineId;
|
||
int quantity;
|
||
QString usage;
|
||
QString doctorId;
|
||
|
||
if (result == QDialog::Accepted) {
|
||
medicineId = dialog->getMedicineId();
|
||
quantity = dialog->getQuantity();
|
||
usage = dialog->getUsage();
|
||
doctorId = dialog->getDoctorId();
|
||
}
|
||
|
||
delete dialog;
|
||
|
||
if (result != QDialog::Accepted) {
|
||
return;
|
||
}
|
||
|
||
if (medicineId.isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择药品"));
|
||
return;
|
||
}
|
||
|
||
if (doctorId.isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择医生"));
|
||
return;
|
||
}
|
||
|
||
auto* med = core_.medicineService.findMedicine(medicineId.toStdString());
|
||
if (!med) {
|
||
QMessageBox::warning(this, tr("错误"), tr("药品不存在"));
|
||
return;
|
||
}
|
||
|
||
if (med->StockQuantity < quantity) {
|
||
QMessageBox::warning(this, tr("库存不足"),
|
||
tr("药品 %1 库存不足,当前库存: %2,需要: %3")
|
||
.arg(QString::fromStdString(med->GenericName))
|
||
.arg(med->StockQuantity)
|
||
.arg(quantity));
|
||
return;
|
||
}
|
||
|
||
MedicineRecord record(
|
||
medicineId.toStdString(),
|
||
med->GenericName,
|
||
quantity,
|
||
usage.toStdString(),
|
||
med->UnitPrice,
|
||
doctorId.toStdString()
|
||
);
|
||
|
||
std::string paymentId;
|
||
double totalPrice = record.getTotalPrice();
|
||
if (!core_.paymentService.createPayment(pid.toStdString(), totalPrice,
|
||
PaymentMethod::Cash, "用药", medicineId.toStdString(),
|
||
"药品: " + med->GenericName + ", 数量: " + std::to_string(quantity), paymentId)) {
|
||
QMessageBox::warning(this, tr("支付失败"), tr("创建支付记录失败"));
|
||
return;
|
||
}
|
||
|
||
if (!core_.paymentService.completePayment(paymentId)) {
|
||
core_.paymentService.removePayment(paymentId);
|
||
QMessageBox::warning(this, tr("支付失败"), tr("药品费用支付失败,请重试"));
|
||
return;
|
||
}
|
||
|
||
if (!core_.medicineService.decreaseStock(medicineId.toStdString(), quantity)) {
|
||
core_.paymentService.refundPayment(paymentId);
|
||
QMessageBox::warning(this, tr("错误"), tr("库存扣除失败,已退款"));
|
||
return;
|
||
}
|
||
|
||
if (!core_.patientCaseService.addMedicineRecord(pid.toStdString(), record)) {
|
||
core_.medicineService.increaseStock(medicineId.toStdString(), quantity);
|
||
QMessageBox::warning(this, tr("错误"), tr("用药记录添加失败"));
|
||
return;
|
||
}
|
||
|
||
std::string medDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 药品ID: " + medicineId.toStdString() +
|
||
" | 药品名: " + std::string(med->GenericName.c_str()) +
|
||
" | 数量: " + std::to_string(quantity) +
|
||
" | 用法: " + usage.toStdString() +
|
||
" | 单价: " + std::to_string(med->UnitPrice) +
|
||
" | 总价: " + std::to_string(totalPrice) +
|
||
" | 医生ID: " + doctorId.toStdString() +
|
||
" | 支付ID: " + paymentId +
|
||
" | 支付状态: 已完成" +
|
||
" | 变更库存: " + std::to_string(quantity) + "份 (扣除)";
|
||
|
||
logOperation(LogEntryType::MEDICINE_RECORD, "ADD_MEDICINE", medDetails, pid.toStdString());
|
||
|
||
QMessageBox::information(this, tr("成功"),
|
||
tr("用药记录已添加\n药品: %1\n数量: %2\n总价: %3\n已自动完成支付")
|
||
.arg(QString::fromStdString(med->GenericName))
|
||
.arg(quantity)
|
||
.arg(QString::number(totalPrice, 'f', 2)));
|
||
|
||
if (pc && pc->getDiagnosisRecordCount() > 0 && pc->getMedicineRecordCount() > 0) {
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (patient && patient->Status == PatientStatus::Outpatient) {
|
||
core_.patientService.updatePatient(pid.toStdString(), patient->Name, patient->Age,
|
||
patient->Gender, patient->Contact, PatientStatus::Visited);
|
||
refreshPatientTable();
|
||
}
|
||
}
|
||
|
||
refreshMedicineTable();
|
||
updatePatientCaseDetail();
|
||
}
|
||
|
||
void MainWindow::handlePatientPayment() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("缴费"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
auto* p = core_.patientService.findPatient(pid.toStdString());
|
||
if (!p) {
|
||
QMessageBox::warning(this, tr("缴费"), tr("患者不存在"));
|
||
return;
|
||
}
|
||
|
||
// 检查患者状态:只有出院或门诊状态才能缴费
|
||
if (p->Status != PatientStatus::Discharged && p->Status != PatientStatus::Outpatient &&
|
||
p->Status != PatientStatus::Visited && p->Status != PatientStatus::Emergency) {
|
||
QString statusText = patientStatusToText(p->Status);
|
||
QString message;
|
||
if (p->Status == PatientStatus::Inpatient) {
|
||
message = tr("该患者当前状态为\"%1\",请先办理出院后再缴费。").arg(statusText);
|
||
} else {
|
||
message = tr("该患者当前状态为\"%1\",请先进行挂号后再缴费。").arg(statusText);
|
||
}
|
||
QMessageBox::warning(this, tr("缴费"), message);
|
||
return;
|
||
}
|
||
|
||
auto* pc = core_.patientCaseService.getCase(pid.toStdString());
|
||
if (!pc) {
|
||
QMessageBox::warning(this, tr("缴费"), tr("该患者没有病例记录"));
|
||
return;
|
||
}
|
||
|
||
QString currentDate = formatCurrentDate();
|
||
QString patientName = p ? QString::fromStdString(p->Name) : QString();
|
||
|
||
double totalAmount = 0.0;
|
||
std::vector<std::pair<QString, double>> feeItems;
|
||
|
||
for (const auto& record : pc->AppointmentRecords) {
|
||
bool hasPayment = false;
|
||
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
||
if (payment.PatientID == pid.toStdString() &&
|
||
payment.OperationID == record.DoctorID &&
|
||
payment.PaymentType == "挂号") {
|
||
hasPayment = true;
|
||
}
|
||
});
|
||
if (!hasPayment) {
|
||
double regFee = 10.0;
|
||
totalAmount += regFee;
|
||
feeItems.push_back({tr("挂号费"), regFee});
|
||
}
|
||
}
|
||
|
||
for (const auto& record : pc->CheckRecords) {
|
||
bool hasPayment = false;
|
||
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
||
if (payment.PatientID == pid.toStdString() &&
|
||
payment.OperationID == record.CheckID) {
|
||
hasPayment = true;
|
||
}
|
||
});
|
||
if (!hasPayment) {
|
||
totalAmount += record.Price;
|
||
feeItems.push_back({QString::fromStdString(record.CheckName), record.Price});
|
||
}
|
||
}
|
||
|
||
for (const auto& record : pc->MedicineRecords) {
|
||
double itemTotal = record.UnitPrice * record.Quantity;
|
||
bool hasPayment = false;
|
||
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
||
if (payment.PatientID == pid.toStdString() &&
|
||
payment.OperationID == record.MedicineID) {
|
||
hasPayment = true;
|
||
}
|
||
});
|
||
if (!hasPayment) {
|
||
totalAmount += itemTotal;
|
||
feeItems.push_back({QString::fromStdString(record.MedicineName), itemTotal});
|
||
}
|
||
}
|
||
|
||
std::vector<std::string> depositPaymentIds;
|
||
for (const auto& record : pc->AdmissionRecords) {
|
||
double days = 1.0;
|
||
if (record.DischargeTime > 0 && record.AdmissionTime > 0) {
|
||
days = std::max(1.0, std::difftime(record.DischargeTime, record.AdmissionTime) / 86400.0);
|
||
}
|
||
double hospitalFee = days * 100.0;
|
||
|
||
double admissionDeposit = 0.0;
|
||
std::string depositPaymentId;
|
||
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
||
if (payment.PatientID == pid.toStdString() &&
|
||
payment.PaymentType == "入院" &&
|
||
payment.OperationID == record.WardID &&
|
||
payment.Status == "Completed") {
|
||
admissionDeposit = payment.Amount;
|
||
depositPaymentId = payment.PaymentID;
|
||
}
|
||
});
|
||
|
||
double netFee = hospitalFee - admissionDeposit;
|
||
totalAmount += netFee;
|
||
feeItems.push_back({tr("住院费"), hospitalFee});
|
||
if (admissionDeposit > 0) {
|
||
feeItems.push_back({tr("押金退回"), -admissionDeposit});
|
||
if (!depositPaymentId.empty()) {
|
||
depositPaymentIds.push_back(depositPaymentId);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 处理手术费用(从手术记录中读取费用)
|
||
for (size_t i = 0; i < pc->SurgeryRecords.size(); ++i) {
|
||
const auto& record = pc->SurgeryRecords[i];
|
||
if (record.Fee > 0) {
|
||
totalAmount += record.Fee;
|
||
feeItems.push_back({QString::fromStdString(record.SurgeryName), record.Fee});
|
||
}
|
||
}
|
||
|
||
if (feeItems.empty()) {
|
||
QMessageBox::information(this, tr("缴费"), tr("患者 %1 当前没有需要结算的费用。").arg(pid));
|
||
return;
|
||
}
|
||
|
||
std::string settlementId;
|
||
if (!core_.settlementService.generateSettlement(pid.toStdString(), patientName.toStdString(), currentDate.toStdString(), settlementId)) {
|
||
QMessageBox::warning(this, tr("缴费"), tr("结算单生成失败"));
|
||
return;
|
||
}
|
||
|
||
for (const auto& item : feeItems) {
|
||
SettlementItem settlementItem(item.first.toStdString(), "费用", "", 1, item.second, "");
|
||
core_.settlementService.addItemToSettlement(settlementId, settlementItem);
|
||
}
|
||
|
||
core_.settlementService.calculateSettlement(settlementId);
|
||
|
||
const Settlement* finalSettlement = core_.settlementService.findSettlement(settlementId);
|
||
double finalAmount = finalSettlement ? finalSettlement->TotalAmount : totalAmount;
|
||
|
||
std::string paymentId;
|
||
if (core_.paymentService.createPayment(pid.toStdString(), finalAmount,
|
||
PaymentMethod::Cash, "结算", settlementId,
|
||
"综合结算 - 患者: " + patientName.toStdString(), paymentId)) {
|
||
if (!core_.paymentService.completePayment(paymentId)) {
|
||
core_.paymentService.removePayment(paymentId);
|
||
QMessageBox::warning(this, tr("支付失败"), tr("结算支付失败,请重试"));
|
||
return;
|
||
}
|
||
}
|
||
|
||
core_.settlementService.completeSettlement(settlementId);
|
||
|
||
for (const auto& depositPaymentId : depositPaymentIds) {
|
||
core_.paymentManagementService.processRefund(depositPaymentId, "入院押金退款-出院结算");
|
||
}
|
||
|
||
std::string paymentDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 患者姓名: " + patientName.toStdString() +
|
||
" | 结算单ID: " + settlementId +
|
||
" | 支付ID: " + paymentId +
|
||
" | 总金额: " + std::to_string(totalAmount) +
|
||
" | 费用项数量: " + std::to_string(feeItems.size()) +
|
||
" | 押金退款记录数: " + std::to_string(depositPaymentIds.size()) +
|
||
" | 操作: 缴费结算";
|
||
logOperation(LogEntryType::SYSTEM_EVENT, "SETTLEMENT", paymentDetails, pid.toStdString());
|
||
|
||
QMessageBox::StandardButton reply = QMessageBox::question(
|
||
this, tr("缴费成功"),
|
||
tr("患者 %1 缴费成功\n总金额: ¥%2\n费用项: %3项\n是否查看结算单?")
|
||
.arg(pid)
|
||
.arg(QString::number(totalAmount, 'f', 2))
|
||
.arg(feeItems.size()),
|
||
QMessageBox::Yes | QMessageBox::No);
|
||
|
||
if (reply == QMessageBox::Yes) {
|
||
SettlementDialog dialog(core_, this);
|
||
dialog.displaySettlement(QString::fromStdString(settlementId));
|
||
dialog.exec();
|
||
}
|
||
|
||
core_.patientService.updatePatient(pid.toStdString(), p->Name, p->Age,
|
||
p->Gender, p->Contact, PatientStatus::Unregistered);
|
||
|
||
refreshPatientTable();
|
||
refreshDashboard();
|
||
}
|
||
|
||
void MainWindow::handleAddAdmissionRecord() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("添加入院记录"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
QMessageBox::information(this, tr("添加入院记录"), tr("功能开发中..."));
|
||
}
|
||
|
||
void MainWindow::handleAddSurgeryRecord() {
|
||
QString pid = safeCurrentTableId(patientTable_);
|
||
if (pid.isEmpty()) {
|
||
QMessageBox::warning(this, tr("添加手术记录"), tr("请先选择患者"));
|
||
return;
|
||
}
|
||
|
||
// 检查患者状态:只有入院状态才允许添加手术记录
|
||
auto* patient = core_.patientService.findPatient(pid.toStdString());
|
||
if (!patient) {
|
||
QMessageBox::warning(this, tr("添加手术记录"), tr("患者不存在"));
|
||
return;
|
||
}
|
||
if (patient->Status != PatientStatus::Inpatient) {
|
||
QMessageBox::warning(this, tr("添加手术记录"),
|
||
tr("该患者当前状态为\"%1\",禁止添加手术记录。\n只有入院状态的患者才能添加手术记录。")
|
||
.arg(patientStatusToText(patient->Status)));
|
||
return;
|
||
}
|
||
|
||
struct DoctorInfo {
|
||
std::string id;
|
||
std::string name;
|
||
std::string dept;
|
||
};
|
||
std::vector<DoctorInfo> doctors;
|
||
core_.doctorService.for_eachDoctor([&doctors](const std::string&, const Doctor& d) {
|
||
doctors.push_back({d.DoctorID, d.Name, d.DepartmentID});
|
||
});
|
||
|
||
if (doctors.empty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("系统中没有医生,请先添加医生"));
|
||
return;
|
||
}
|
||
|
||
QDialog* dialog = new QDialog(this);
|
||
dialog->setWindowTitle(tr("添加手术记录 - %1").arg(pid));
|
||
dialog->setModal(true);
|
||
dialog->resize(600, 500);
|
||
dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||
|
||
QFormLayout* form = new QFormLayout(dialog);
|
||
form->setSpacing(10);
|
||
form->setContentsMargins(20, 20, 20, 20);
|
||
|
||
// 主刀医生选择
|
||
QComboBox* surgeonCombo = new QComboBox(dialog);
|
||
surgeonCombo->addItem(tr("-- 请选择主刀医生 --"), QVariant());
|
||
for (const auto& doc : doctors) {
|
||
QString deptName = QString::fromStdString(doc.dept);
|
||
auto* dept = core_.departmentService.findDepartment(doc.dept);
|
||
if (dept) {
|
||
deptName = QString::fromStdString(dept->Name);
|
||
}
|
||
QString display = QString("%1 (%2) - %3").arg(QString::fromStdString(doc.name)).arg(deptName).arg(QString::fromStdString(doc.id));
|
||
surgeonCombo->addItem(display, QString::fromStdString(doc.id));
|
||
}
|
||
|
||
// 助手医生选择(可选)
|
||
QComboBox* assistantCombo = new QComboBox(dialog);
|
||
assistantCombo->addItem(tr("-- 助手医生(可选) --"), QVariant());
|
||
for (const auto& doc : doctors) {
|
||
QString deptName = QString::fromStdString(doc.dept);
|
||
auto* dept = core_.departmentService.findDepartment(doc.dept);
|
||
if (dept) {
|
||
deptName = QString::fromStdString(dept->Name);
|
||
}
|
||
QString display = QString("%1 (%2) - %3").arg(QString::fromStdString(doc.name)).arg(deptName).arg(QString::fromStdString(doc.id));
|
||
assistantCombo->addItem(display, QString::fromStdString(doc.id));
|
||
}
|
||
|
||
// 麻醉医生选择
|
||
QComboBox* anesthesiologistCombo = new QComboBox(dialog);
|
||
anesthesiologistCombo->addItem(tr("-- 请选择麻醉医生 --"), QVariant());
|
||
for (const auto& doc : doctors) {
|
||
QString deptName = QString::fromStdString(doc.dept);
|
||
auto* dept = core_.departmentService.findDepartment(doc.dept);
|
||
if (dept) {
|
||
deptName = QString::fromStdString(dept->Name);
|
||
}
|
||
QString display = QString("%1 (%2) - %3").arg(QString::fromStdString(doc.name)).arg(deptName).arg(QString::fromStdString(doc.id));
|
||
anesthesiologistCombo->addItem(display, QString::fromStdString(doc.id));
|
||
}
|
||
|
||
QString currentDate = formatCurrentDate();
|
||
QLabel* dateLabel = new QLabel(currentDate, dialog);
|
||
dateLabel->setEnabled(false);
|
||
|
||
// 手术名称
|
||
QLineEdit* surgeryNameEdit = new QLineEdit(dialog);
|
||
surgeryNameEdit->setPlaceholderText(tr("如:阑尾切除术"));
|
||
|
||
// 手术类型
|
||
QComboBox* surgeryTypeCombo = new QComboBox(dialog);
|
||
surgeryTypeCombo->addItems({tr("开放手术"), tr("微创手术"), tr("腔镜手术"), tr("介入手术"), tr("其他")});
|
||
|
||
// 麻醉方式
|
||
QComboBox* anesthesiaTypeCombo = new QComboBox(dialog);
|
||
anesthesiaTypeCombo->addItems({tr("全身麻醉"), tr("局部麻醉"), tr("椎管内麻醉"), tr("神经阻滞麻醉"), tr("复合麻醉"), tr("其他")});
|
||
|
||
// 术前诊断
|
||
QTextEdit* diagnosisEdit = new QTextEdit(dialog);
|
||
diagnosisEdit->setMinimumHeight(50);
|
||
diagnosisEdit->setPlaceholderText(tr("术前诊断"));
|
||
|
||
// 手术过程
|
||
QTextEdit* procedureEdit = new QTextEdit(dialog);
|
||
procedureEdit->setMinimumHeight(80);
|
||
procedureEdit->setPlaceholderText(tr("详细描述手术过程"));
|
||
|
||
// 术中并发症
|
||
QLineEdit* complicationsEdit = new QLineEdit(dialog);
|
||
complicationsEdit->setPlaceholderText(tr("如无并发症请填写'无'"));
|
||
|
||
// 出血量
|
||
QLineEdit* bloodLossEdit = new QLineEdit(dialog);
|
||
bloodLossEdit->setPlaceholderText(tr("如:200ml"));
|
||
|
||
// 手术时长
|
||
QSpinBox* durationSpin = new QSpinBox(dialog);
|
||
durationSpin->setRange(0, 1440);
|
||
durationSpin->setSuffix(tr(" 分钟"));
|
||
durationSpin->setValue(60);
|
||
|
||
// 备注
|
||
QLineEdit* remarksEdit = new QLineEdit(dialog);
|
||
remarksEdit->setPlaceholderText(tr("其他备注"));
|
||
|
||
// 手术金额
|
||
QLineEdit* surgeryFeeEdit = new QLineEdit(dialog);
|
||
surgeryFeeEdit->setPlaceholderText(tr("手术费用(元)"));
|
||
surgeryFeeEdit->setValidator(new QDoubleValidator(0, 999999, 2, dialog));
|
||
surgeryFeeEdit->setText("0.00");
|
||
|
||
form->addRow(tr("主刀医生:"), surgeonCombo);
|
||
form->addRow(tr("助手医生:"), assistantCombo);
|
||
form->addRow(tr("麻醉医生:"), anesthesiologistCombo);
|
||
form->addRow(tr("手术日期:"), dateLabel);
|
||
form->addRow(tr("手术名称:"), surgeryNameEdit);
|
||
form->addRow(tr("手术类型:"), surgeryTypeCombo);
|
||
form->addRow(tr("麻醉方式:"), anesthesiaTypeCombo);
|
||
form->addRow(tr("术前诊断:"), diagnosisEdit);
|
||
form->addRow(tr("手术过程:"), procedureEdit);
|
||
form->addRow(tr("术中并发症:"), complicationsEdit);
|
||
form->addRow(tr("出血量:"), bloodLossEdit);
|
||
form->addRow(tr("手术时长:"), durationSpin);
|
||
form->addRow(tr("手术金额:"), surgeryFeeEdit);
|
||
form->addRow(tr("备注:"), remarksEdit);
|
||
|
||
auto* buttonLayout = new QHBoxLayout();
|
||
auto* okButton = new QPushButton(tr("保存"), dialog);
|
||
auto* cancelButton = new QPushButton(tr("取消"), dialog);
|
||
buttonLayout->addWidget(okButton);
|
||
buttonLayout->addWidget(cancelButton);
|
||
buttonLayout->addStretch();
|
||
form->addRow(buttonLayout);
|
||
|
||
connect(okButton, &QPushButton::clicked, [this, pid, dialog, surgeonCombo, assistantCombo, anesthesiologistCombo,
|
||
surgeryNameEdit, surgeryTypeCombo, anesthesiaTypeCombo, diagnosisEdit, procedureEdit,
|
||
complicationsEdit, bloodLossEdit, durationSpin, remarksEdit, surgeryFeeEdit]() {
|
||
if (surgeonCombo->currentIndex() <= 0) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择主刀医生"));
|
||
return;
|
||
}
|
||
if (surgeryNameEdit->text().isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请填写手术名称"));
|
||
return;
|
||
}
|
||
if (diagnosisEdit->toPlainText().isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请填写术前诊断"));
|
||
return;
|
||
}
|
||
if (procedureEdit->toPlainText().isEmpty()) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请填写手术过程"));
|
||
return;
|
||
}
|
||
if (anesthesiologistCombo->currentIndex() <= 0) {
|
||
QMessageBox::warning(this, tr("错误"), tr("请选择麻醉医生"));
|
||
return;
|
||
}
|
||
|
||
QString surgeonId = surgeonCombo->itemData(surgeonCombo->currentIndex()).toString();
|
||
QString assistantId = assistantCombo->currentIndex() > 0 ? assistantCombo->itemData(assistantCombo->currentIndex()).toString() : "";
|
||
QString anesthesiologistId = anesthesiologistCombo->itemData(anesthesiologistCombo->currentIndex()).toString();
|
||
|
||
// 获取手术费用
|
||
double surgeryFee = surgeryFeeEdit->text().toDouble();
|
||
|
||
SurgeryRecord record;
|
||
record.SurgeryName = surgeryNameEdit->text().toStdString();
|
||
record.SurgeryType = surgeryTypeCombo->currentText().toStdString();
|
||
record.SurgeonID = surgeonId.toStdString();
|
||
record.AssistantDoctorID = assistantId.toStdString();
|
||
record.AnesthesiaType = anesthesiaTypeCombo->currentText().toStdString();
|
||
record.AnesthesiologistID = anesthesiologistId.toStdString();
|
||
record.Diagnosis = diagnosisEdit->toPlainText().toStdString();
|
||
record.Procedure = procedureEdit->toPlainText().toStdString();
|
||
record.Complications = complicationsEdit->text().isEmpty() ? "无" : complicationsEdit->text().toStdString();
|
||
record.BloodLoss = bloodLossEdit->text().isEmpty() ? "未知" : bloodLossEdit->text().toStdString();
|
||
record.Duration = durationSpin->value();
|
||
record.Remarks = remarksEdit->text().toStdString();
|
||
record.SurgeryTime = std::time(nullptr);
|
||
record.Fee = surgeryFee; // 保存手术费用到记录中
|
||
|
||
if (!core_.patientCaseService.addSurgeryRecord(pid.toStdString(), record)) {
|
||
QMessageBox::warning(this, tr("新增失败"), tr("手术记录添加失败"));
|
||
return;
|
||
}
|
||
|
||
std::string surgeryDetails =
|
||
"患者ID: " + pid.toStdString() +
|
||
" | 手术名称: " + record.SurgeryName +
|
||
" | 手术类型: " + record.SurgeryType +
|
||
" | 主刀医生ID: " + record.SurgeonID +
|
||
" | 助手医生ID: " + record.AssistantDoctorID +
|
||
" | 麻醉方式: " + record.AnesthesiaType +
|
||
" | 麻醉医生ID: " + record.AnesthesiologistID +
|
||
" | 术前诊断: " + record.Diagnosis +
|
||
" | 手术时长: " + std::to_string(record.Duration) + "分钟" +
|
||
" | 出血量: " + record.BloodLoss +
|
||
" | 并发症: " + record.Complications +
|
||
" | 手术费用: " + std::to_string(surgeryFee) +
|
||
" | 备注: " + record.Remarks;
|
||
logOperation(LogEntryType::SURGERY_RECORD, "ADD_SURGERY", surgeryDetails, pid.toStdString());
|
||
|
||
QString successMsg = tr("手术记录已添加\n手术名称: %1\n手术时长: %2分钟\n手术费用: ¥%3")
|
||
.arg(surgeryNameEdit->text())
|
||
.arg(durationSpin->value())
|
||
.arg(QString::number(surgeryFee, 'f', 2));
|
||
if (surgeryFee > 0) {
|
||
successMsg += tr("\n(手术费用将在\"缴费\"时一并结算)");
|
||
}
|
||
QMessageBox::information(this, tr("成功"), successMsg);
|
||
|
||
updatePatientCaseDetail();
|
||
dialog->accept();
|
||
});
|
||
|
||
connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject);
|
||
dialog->exec();
|
||
}
|
||
|
||
void MainWindow::onPatientSearch(const QString& text) {
|
||
for (int i = 0; i < patientTable_->rowCount(); ++i) {
|
||
bool match = false;
|
||
for (int j = 0; j < patientTable_->columnCount(); ++j) {
|
||
QTableWidgetItem* item = patientTable_->item(i, j);
|
||
if (item && item->text().contains(text, Qt::CaseInsensitive)) {
|
||
match = true;
|
||
break;
|
||
}
|
||
}
|
||
patientTable_->setRowHidden(i, !match);
|
||
}
|
||
}
|