317 lines
10 KiB
C++
317 lines
10 KiB
C++
#include "mainwindow.h"
|
|
|
|
#include <QAction>
|
|
#include <QComboBox>
|
|
#include <QCoreApplication>
|
|
#include <QDialog>
|
|
#include <QDir>
|
|
#include <QFileDialog>
|
|
#include <QFormLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QHeaderView>
|
|
#include <QInputDialog>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QListWidget>
|
|
#include <QMenuBar>
|
|
#include <QMessageBox>
|
|
#include <QPushButton>
|
|
#include <QSpinBox>
|
|
#include <QStackedWidget>
|
|
#include <QTabWidget>
|
|
#include <QTableWidget>
|
|
#include <QTableWidgetItem>
|
|
#include <QTextEdit>
|
|
#include <QToolBar>
|
|
#include <QTreeWidget>
|
|
#include <QTreeWidgetItem>
|
|
#include <QVBoxLayout>
|
|
#include <QGroupBox>
|
|
#include <QTextCursor>
|
|
#include <QFont>
|
|
|
|
#include <vector>
|
|
#include <ctime>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
|
|
#include "core/his_core.h"
|
|
#include "core/ward_service.h"
|
|
#include "core/patient_service.h"
|
|
#include "core/doctor_service.h"
|
|
#include "core/medicine_service.h"
|
|
#include "core/check_service.h"
|
|
#include "utils/file_manager.h"
|
|
#include "utils/logger.h"
|
|
#include "utils/input_validator.h"
|
|
#include "dialogs/patient_dialog.h"
|
|
#include "dialogs/department_detail_dialog.h"
|
|
#include "dialogs/payment_dialog.h"
|
|
#include "dialogs/payment_management_dialog.h"
|
|
#include "dialogs/settlement_dialog.h"
|
|
|
|
// ============ 全局常量定义 ============
|
|
const int MAX_MEDICINE_STOCK = 10000;
|
|
|
|
// ============ 工具函数 ============
|
|
|
|
static QString wardTypeToText(WardType t) {
|
|
switch (t) {
|
|
case WardType::Normal:
|
|
return QObject::tr("普通病房");
|
|
case WardType::Special:
|
|
return QObject::tr("特需病房");
|
|
case WardType::ICU:
|
|
return QObject::tr("ICU");
|
|
}
|
|
return QObject::tr("未知");
|
|
}
|
|
|
|
static WardType parseWardType(const QString& s) {
|
|
if (s.contains("ICU", Qt::CaseInsensitive)) return WardType::ICU;
|
|
if (s.contains("特需", Qt::CaseInsensitive)) return WardType::Special;
|
|
return WardType::Normal;
|
|
}
|
|
|
|
static QString patientStatusToText(PatientStatus st) {
|
|
switch (st) {
|
|
case PatientStatus::Unregistered:
|
|
return QObject::tr("未挂号");
|
|
case PatientStatus::Outpatient:
|
|
return QObject::tr("门诊");
|
|
case PatientStatus::Emergency:
|
|
return QObject::tr("急诊");
|
|
case PatientStatus::Visited:
|
|
return QObject::tr("已就诊");
|
|
case PatientStatus::Inpatient:
|
|
return QObject::tr("住院");
|
|
case PatientStatus::Discharged:
|
|
return QObject::tr("出院");
|
|
}
|
|
return QObject::tr("未挂号");
|
|
}
|
|
|
|
static PatientStatus parsePatientStatus(const QString& s) {
|
|
if (s.contains("Unregistered", Qt::CaseInsensitive)) return PatientStatus::Unregistered;
|
|
if (s.contains("Emergency", Qt::CaseInsensitive)) return PatientStatus::Emergency;
|
|
if (s.contains("Inpatient", Qt::CaseInsensitive)) return PatientStatus::Inpatient;
|
|
if (s.contains("Discharged", Qt::CaseInsensitive)) return PatientStatus::Discharged;
|
|
if (s.contains("Visited", Qt::CaseInsensitive)) return PatientStatus::Visited;
|
|
if (s.contains("Outpatient", Qt::CaseInsensitive)) return PatientStatus::Outpatient;
|
|
return PatientStatus::Unregistered;
|
|
}
|
|
|
|
static QString doctorTitleToText(DoctorTitle t) {
|
|
switch (t) {
|
|
case DoctorTitle::Chief:
|
|
return QObject::tr("主任医师");
|
|
case DoctorTitle::AssociateChief:
|
|
return QObject::tr("副主任医师");
|
|
case DoctorTitle::Attending:
|
|
return QObject::tr("主治医师");
|
|
case DoctorTitle::Resident:
|
|
return QObject::tr("住院医师");
|
|
}
|
|
return QObject::tr("未知");
|
|
}
|
|
|
|
static DoctorTitle parseDoctorTitle(const QString& s) {
|
|
if (s.contains("主任", Qt::CaseInsensitive)) return DoctorTitle::Chief;
|
|
if (s.contains("副主任", Qt::CaseInsensitive)) return DoctorTitle::AssociateChief;
|
|
if (s.contains("主治", Qt::CaseInsensitive)) return DoctorTitle::Attending;
|
|
return DoctorTitle::Resident;
|
|
}
|
|
|
|
static QString formatDate(time_t t) {
|
|
if (t == 0) return "-";
|
|
struct tm timeinfo;
|
|
localtime_r(&t, &timeinfo);
|
|
char buffer[30];
|
|
strftime(buffer, 30, "%Y-%m-%d %H:%M", &timeinfo);
|
|
return QString(buffer);
|
|
}
|
|
|
|
static QString formatCurrentDate() {
|
|
time_t now = time(nullptr);
|
|
struct tm timeinfo;
|
|
localtime_r(&now, &timeinfo);
|
|
char buffer[30];
|
|
strftime(buffer, 30, "%Y-%m-%d %H:%M", &timeinfo);
|
|
return QString(buffer);
|
|
}
|
|
|
|
static std::vector<Ward> collectExistingWardsFromCore(core::HisCore& core) {
|
|
std::vector<Ward> wards;
|
|
core.ctx_.wards.for_each([&wards](const std::string&, const Ward& w) { wards.push_back(w); });
|
|
return wards;
|
|
}
|
|
|
|
static std::vector<std::string> collectExistingPatientIdsFromCore(core::HisCore& core) {
|
|
std::vector<std::string> ids;
|
|
core.ctx_.patients.for_each([&ids](const std::string& k, const Patient&) { ids.push_back(k); });
|
|
return ids;
|
|
}
|
|
|
|
static std::vector<std::string> collectExistingDoctorIdsFromCore(core::HisCore& core) {
|
|
std::vector<std::string> ids;
|
|
core.ctx_.doctors.for_each([&ids](const std::string& k, const Doctor&) { ids.push_back(k); });
|
|
return ids;
|
|
}
|
|
|
|
static std::vector<std::string> collectExistingMedicineIdsFromCore(core::HisCore& core) {
|
|
std::vector<std::string> ids;
|
|
core.ctx_.medicines.for_each([&ids](const std::string& k, const Medicine&) { ids.push_back(k); });
|
|
return ids;
|
|
}
|
|
|
|
static QString safeCurrentTableId(QTableWidget* table) {
|
|
if (table->currentRow() < 0) return QString();
|
|
QTableWidgetItem* item = table->item(table->currentRow(), 0);
|
|
return item ? item->text() : QString();
|
|
}
|
|
|
|
// ============ 构造函数 / 析构函数 / UI 初始化 ============
|
|
|
|
MainWindow::MainWindow(core::HisCore& core, QWidget* parent)
|
|
: QMainWindow(parent), core_(core), logger_("", true) {
|
|
QDir logsDir(QCoreApplication::applicationDirPath() + "/logs");
|
|
if (!logsDir.exists()) {
|
|
logsDir.mkpath(".");
|
|
}
|
|
logger_.setLogFilePath((logsDir.path() + "/his_operation.log").toStdString());
|
|
logger_.log(LogEntryType::SYSTEM_EVENT, "SYSTEM_START", "HIS GUI系统启动");
|
|
|
|
setWindowIcon(QIcon("gui/favicon/favicon.ico"));
|
|
|
|
setupUI();
|
|
if (!loadDataFromFiles()) {
|
|
QMessageBox::warning(this, tr("数据加载失败"), tr("请检查 data 目录是否存在并包含 wards.txt/patients.txt/doctors.txt/medicines.txt。"));
|
|
}
|
|
refreshDashboard();
|
|
refreshWardTable();
|
|
refreshPatientTable();
|
|
refreshDoctorTable();
|
|
refreshMedicineTable();
|
|
refreshCheckTable();
|
|
refreshDepartmentTable();
|
|
refreshLogDisplay();
|
|
}
|
|
|
|
MainWindow::~MainWindow() = default;
|
|
|
|
void MainWindow::closeEvent(QCloseEvent* event) {
|
|
QMessageBox::StandardButton reply = QMessageBox::question(
|
|
this,
|
|
tr("保存数据"),
|
|
tr("是否保存当前数据到文件?"),
|
|
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel,
|
|
QMessageBox::Save
|
|
);
|
|
|
|
if (reply == QMessageBox::Save) {
|
|
handleSaveData();
|
|
event->accept();
|
|
} else if (reply == QMessageBox::Discard) {
|
|
event->accept();
|
|
} else {
|
|
event->ignore();
|
|
}
|
|
}
|
|
|
|
void MainWindow::setupUI() {
|
|
currentRole_ = ViewRole::Admin;
|
|
|
|
navList_ = new QListWidget(this);
|
|
navList_->setMinimumWidth(180);
|
|
navList_->setMaximumWidth(220);
|
|
navList_->addItem(tr("仪表盘"));
|
|
navList_->addItem(tr("病房"));
|
|
navList_->addItem(tr("患者"));
|
|
navList_->addItem(tr("医生"));
|
|
navList_->addItem(tr("药房"));
|
|
navList_->addItem(tr("检查"));
|
|
navList_->addItem(tr("科室"));
|
|
navList_->addItem(tr("记录"));
|
|
navList_->setCurrentRow(0);
|
|
navList_->setSpacing(4);
|
|
navList_->setStyleSheet("QListWidget { padding: 10px 0; } QListWidget::item { padding: 12px 20px; margin: 2px 8px; }");
|
|
|
|
contentStack_ = new QStackedWidget(this);
|
|
|
|
setupDashboardTab();
|
|
setupWardsTab();
|
|
setupPatientsTab();
|
|
setupDoctorsTab();
|
|
setupMedicinesTab();
|
|
setupChecksTab();
|
|
setupDepartmentsTab();
|
|
setupLogsTab();
|
|
|
|
contentStack_->addWidget(dashboardTab_);
|
|
contentStack_->addWidget(wardsTab_);
|
|
contentStack_->addWidget(patientsTab_);
|
|
contentStack_->addWidget(doctorsTab_);
|
|
contentStack_->addWidget(medicinesTab_);
|
|
contentStack_->addWidget(checksTab_);
|
|
contentStack_->addWidget(departmentsTab_);
|
|
contentStack_->addWidget(logsTab_);
|
|
|
|
auto* mainLayout = new QHBoxLayout();
|
|
mainLayout->setContentsMargins(0, 0, 0, 0);
|
|
mainLayout->setSpacing(0);
|
|
mainLayout->addWidget(navList_, 1);
|
|
mainLayout->addWidget(contentStack_, 5);
|
|
|
|
auto* central = new QWidget(this);
|
|
central->setLayout(mainLayout);
|
|
setCentralWidget(central);
|
|
|
|
connect(navList_, &QListWidget::currentRowChanged, contentStack_, &QStackedWidget::setCurrentIndex);
|
|
|
|
auto* reloadAction = new QAction(tr("重新载入"), this);
|
|
reloadAction->setShortcut(Qt::Key_F5);
|
|
connect(reloadAction, &QAction::triggered, this, &MainWindow::handleReloadAction);
|
|
menuBar()->addAction(reloadAction);
|
|
|
|
auto* saveAction = new QAction(tr("保存回文件"), this);
|
|
saveAction->setShortcut(Qt::CTRL | Qt::Key_S);
|
|
connect(saveAction, &QAction::triggered, this, &MainWindow::handleSaveData);
|
|
menuBar()->addAction(saveAction);
|
|
|
|
auto* toolbar = addToolBar(tr("工具"));
|
|
toolbar->addSeparator();
|
|
|
|
auto* roleLabel = new QLabel(tr(" 视角: "), this);
|
|
toolbar->addWidget(roleLabel);
|
|
|
|
roleComboBox_ = new QComboBox(this);
|
|
roleComboBox_->addItem(tr("管理视角"), static_cast<int>(ViewRole::Admin));
|
|
roleComboBox_->addItem(tr("病人视角"), static_cast<int>(ViewRole::Patient));
|
|
roleComboBox_->addItem(tr("医护视角"), static_cast<int>(ViewRole::Medical));
|
|
connect(roleComboBox_, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &MainWindow::onRoleChanged);
|
|
toolbar->addWidget(roleComboBox_);
|
|
|
|
QPushButton* paymentMgmtButton = new QPushButton(tr("支付管理"), this);
|
|
connect(paymentMgmtButton, &QPushButton::clicked, [this]() {
|
|
PaymentManagementDialog dialog(core_, this);
|
|
dialog.exec();
|
|
});
|
|
toolbar->addWidget(paymentMgmtButton);
|
|
|
|
setWindowTitle(tr("HIS GUI") + " - " + tr("医院信息系统"));
|
|
resize(1200, 720);
|
|
}
|
|
|
|
// ============ 包含各页面实现文件 ============
|
|
|
|
#include "pages/dashboard_page.cpp"
|
|
#include "pages/wards_page.cpp"
|
|
#include "pages/patients_page.cpp"
|
|
#include "pages/doctors_page.cpp"
|
|
#include "pages/medicines_page.cpp"
|
|
#include "pages/checks_page.cpp"
|
|
#include "pages/departments_page.cpp"
|
|
#include "pages/logs_page.cpp"
|
|
#include "pages/role_page.cpp"
|