#include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 collectExistingWardsFromCore(core::HisCore& core) { std::vector wards; core.ctx_.wards.for_each([&wards](const std::string&, const Ward& w) { wards.push_back(w); }); return wards; } static std::vector collectExistingPatientIdsFromCore(core::HisCore& core) { std::vector ids; core.ctx_.patients.for_each([&ids](const std::string& k, const Patient&) { ids.push_back(k); }); return ids; } static std::vector collectExistingDoctorIdsFromCore(core::HisCore& core) { std::vector ids; core.ctx_.doctors.for_each([&ids](const std::string& k, const Doctor&) { ids.push_back(k); }); return ids; } static std::vector collectExistingMedicineIdsFromCore(core::HisCore& core) { std::vector 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(ViewRole::Admin)); roleComboBox_->addItem(tr("病人视角"), static_cast(ViewRole::Patient)); roleComboBox_->addItem(tr("医护视角"), static_cast(ViewRole::Medical)); connect(roleComboBox_, QOverload::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"