377 lines
14 KiB
C++
377 lines
14 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 <QDebug>
|
||
#include <QAbstractItemView>
|
||
|
||
#include <QFile>
|
||
#include <QTextStream>
|
||
#include <QDateTime>
|
||
#include <QSettings>
|
||
#include <QTimer>
|
||
#include <QHeaderView>
|
||
|
||
bool MainWindow::loadDataFromFiles() {
|
||
QStringList possiblePaths = {
|
||
QDir(QCoreApplication::applicationDirPath()).absoluteFilePath("../data"),
|
||
"/home/e2hang/code/HIS-GUI/data",
|
||
QDir::currentPath() + "/../data",
|
||
QDir::currentPath() + "/data"
|
||
};
|
||
|
||
QString dataPath;
|
||
for (const QString& path : possiblePaths) {
|
||
if (QDir(path).exists() && QFile::exists(path + "/patients.txt")) {
|
||
dataPath = path;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (dataPath.isEmpty()) {
|
||
QMessageBox::warning(this, tr("数据文件夹未找到"), tr("无法找到数据文件夹。"));
|
||
return false;
|
||
}
|
||
|
||
dataFolder_ = dataPath;
|
||
qDebug() << "Using data folder:" << dataFolder_;
|
||
|
||
std::vector<std::string> wardKeys;
|
||
core_.ctx_.wards.for_each([&wardKeys](const std::string& k, const Ward&) { wardKeys.push_back(k); });
|
||
for (const auto& k : wardKeys) core_.ctx_.wards.remove(k);
|
||
|
||
std::vector<std::string> patientKeys;
|
||
core_.ctx_.patients.for_each([&patientKeys](const std::string& k, const Patient&) { patientKeys.push_back(k); });
|
||
for (const auto& k : patientKeys) core_.ctx_.patients.remove(k);
|
||
|
||
std::vector<std::string> doctorKeys;
|
||
core_.ctx_.doctors.for_each([&doctorKeys](const std::string& k, const Doctor&) { doctorKeys.push_back(k); });
|
||
for (const auto& k : doctorKeys) core_.ctx_.doctors.remove(k);
|
||
|
||
std::vector<std::string> medicineKeys;
|
||
core_.ctx_.medicines.for_each([&medicineKeys](const std::string& k, const Medicine&) { medicineKeys.push_back(k); });
|
||
for (const auto& k : medicineKeys) core_.ctx_.medicines.remove(k);
|
||
|
||
std::vector<std::string> caseKeys;
|
||
core_.ctx_.patientCases.for_each([&caseKeys](const std::string& k, const PatientCase&) { caseKeys.push_back(k); });
|
||
for (const auto& k : caseKeys) core_.ctx_.patientCases.remove(k);
|
||
|
||
std::vector<std::string> departmentKeys;
|
||
core_.ctx_.departments.for_each([&departmentKeys](const std::string& k, const Department&) { departmentKeys.push_back(k); });
|
||
for (const auto& k : departmentKeys) core_.ctx_.departments.remove(k);
|
||
|
||
std::vector<std::string> checkKeys;
|
||
core_.ctx_.checks.for_each([&checkKeys](const std::string& k, const Check&) { checkKeys.push_back(k); });
|
||
for (const auto& k : checkKeys) core_.ctx_.checks.remove(k);
|
||
|
||
std::vector<std::string> paymentKeys;
|
||
core_.ctx_.payments.for_each([&paymentKeys](const std::string& k, const Payment&) { paymentKeys.push_back(k); });
|
||
for (const auto& k : paymentKeys) core_.ctx_.payments.remove(k);
|
||
|
||
std::vector<std::string> settlementKeys;
|
||
core_.ctx_.settlements.for_each([&settlementKeys](const std::string& k, const Settlement&) { settlementKeys.push_back(k); });
|
||
for (const auto& k : settlementKeys) core_.ctx_.settlements.remove(k);
|
||
|
||
std::string err;
|
||
if (!core_.loadDataFromFolder(dataFolder_.toStdString(), err)) {
|
||
qWarning("Failed to load data from folder: %s", err.c_str());
|
||
QMessageBox::warning(this, tr("数据加载失败"), tr("无法加载数据: ") + QString::fromStdString(err));
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
void MainWindow::handleReloadAction() {
|
||
wardTreeView_->clear();
|
||
patientTable_->setRowCount(0);
|
||
doctorTable_->setRowCount(0);
|
||
medicineTable_->setRowCount(0);
|
||
checkTable_->setRowCount(0);
|
||
departmentTable_->setRowCount(0);
|
||
patientCaseDetail_->setText(tr("正在重新加载数据..."));
|
||
summaryLabel_->setText(tr("正在重新加载数据..."));
|
||
logDisplay_->clear();
|
||
|
||
if (!loadDataFromFiles()) {
|
||
QMessageBox::warning(this, tr("重载失败"), tr("数据重新加载失败"));
|
||
return;
|
||
}
|
||
|
||
refreshDashboard();
|
||
refreshWardTable();
|
||
refreshPatientTable();
|
||
refreshDoctorTable();
|
||
refreshMedicineTable();
|
||
refreshCheckTable();
|
||
refreshDepartmentTable();
|
||
|
||
QMessageBox::information(this, tr("重载成功"), tr("数据已重新加载"));
|
||
}
|
||
|
||
void MainWindow::handleSaveData() {
|
||
if (dataFolder_.isEmpty()) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("数据文件夹路径未设置。请先重新加载数据。"));
|
||
return;
|
||
}
|
||
|
||
std::string err;
|
||
|
||
if (!core_.wardService.saveToFile((dataFolder_ + "/wards.txt").toStdString(), err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("病房保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
err.clear();
|
||
if (!FileManager::savePatientListToFile(
|
||
(dataFolder_ + "/patients.txt").toStdString(),
|
||
core_.ctx_.patients,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("患者保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
err.clear();
|
||
if (!FileManager::saveDoctorListToFile(
|
||
(dataFolder_ + "/doctors.txt").toStdString(),
|
||
core_.ctx_.doctors,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("医生保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
err.clear();
|
||
if (!FileManager::saveMedicineListToFile(
|
||
(dataFolder_ + "/medicines.txt").toStdString(),
|
||
core_.ctx_.medicines,
|
||
err, 2)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("药品保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
err.clear();
|
||
if (!FileManager::savePatientCaseListToFile(
|
||
(dataFolder_ + "/patient_cases.txt").toStdString(),
|
||
core_.ctx_.patientCases,
|
||
err, 2)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("病例保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
// 保存支付记录
|
||
err.clear();
|
||
if (!FileManager::savePaymentListToFile(
|
||
(dataFolder_ + "/payments.txt").toStdString(),
|
||
core_.ctx_.payments,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("支付记录保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
// 保存结算单
|
||
err.clear();
|
||
if (!FileManager::saveSettlementListToFile(
|
||
(dataFolder_ + "/settlements.txt").toStdString(),
|
||
core_.ctx_.settlements,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("结算单保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
// 保存科室
|
||
err.clear();
|
||
if (!FileManager::saveDepartmentListToFile(
|
||
(dataFolder_ + "/departments.txt").toStdString(),
|
||
core_.ctx_.departments,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("科室保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
// 保存检查项目
|
||
err.clear();
|
||
if (!FileManager::saveCheckListToFile(
|
||
(dataFolder_ + "/checks.txt").toStdString(),
|
||
core_.ctx_.checks,
|
||
err)) {
|
||
QMessageBox::warning(this, tr("保存失败"), tr("检查项目保存失败: ") + QString::fromStdString(err));
|
||
return;
|
||
}
|
||
|
||
QMessageBox::information(this, tr("保存成功"), tr("所有数据已保存到文件: ") + dataFolder_);
|
||
}
|
||
|
||
void MainWindow::onRoleChanged(int index) {
|
||
currentRole_ = static_cast<ViewRole>(roleComboBox_->currentData().toInt());
|
||
updateUIForRole();
|
||
}
|
||
|
||
void MainWindow::updateUIForRole() {
|
||
bool isAdmin = (currentRole_ == ViewRole::Admin);
|
||
bool isPatient = (currentRole_ == ViewRole::Patient);
|
||
bool isMedical = (currentRole_ == ViewRole::Medical);
|
||
|
||
// 根据视角显示/隐藏不同的标签页
|
||
// Dashboard - 所有视角都可以看到
|
||
int dashboardIndex = navList_->row(navList_->item(0));
|
||
|
||
// Wards - 管理视角和医护视角可以看到
|
||
int wardsIndex = navList_->row(navList_->item(1));
|
||
navList_->item(1)->setHidden(!isAdmin && !isMedical);
|
||
|
||
// Patients - 管理视角和医护视角可以看到
|
||
int patientsIndex = navList_->row(navList_->item(2));
|
||
navList_->item(2)->setHidden(!isAdmin && !isMedical);
|
||
|
||
// Doctors - 所有视角都可以看到
|
||
int doctorsIndex = navList_->row(navList_->item(3));
|
||
|
||
// Medicines - 只有管理视角可以看到
|
||
int medicinesIndex = navList_->row(navList_->item(4));
|
||
navList_->item(4)->setHidden(!isAdmin);
|
||
|
||
// Departments - 所有视角都可以看到(新增:病人可以查看科室)
|
||
int departmentsIndex = navList_->row(navList_->item(5));
|
||
navList_->item(5)->setHidden(false);
|
||
|
||
// 如果当前选中的标签页被隐藏,切换到第一个可见的标签页
|
||
bool switched = false;
|
||
for (int i = 0; i < navList_->count(); ++i) {
|
||
if (!navList_->item(i)->isHidden()) {
|
||
if (navList_->item(i)->isSelected() || !switched) {
|
||
navList_->setCurrentRow(i);
|
||
switched = true;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 根据视角设置按钮可见性
|
||
// 病房相关按钮 - 管理视角和医护视角
|
||
wardAddButton_->setEnabled(isAdmin || isMedical);
|
||
wardEditButton_->setEnabled(isAdmin || isMedical);
|
||
wardDeleteButton_->setEnabled(isAdmin || isMedical);
|
||
wardAddBedButton_->setEnabled(isAdmin || isMedical);
|
||
wardDeleteBedButton_->setEnabled(isAdmin || isMedical);
|
||
wardOccupancyButton_->setEnabled(isAdmin || isMedical);
|
||
|
||
// 患者相关按钮 - 管理视角和医护视角
|
||
patientAddButton_->setEnabled(isAdmin || isMedical);
|
||
patientEditButton_->setEnabled(isAdmin || isMedical);
|
||
patientRemoveButton_->setEnabled(isAdmin);
|
||
patientViewCaseButton_->setEnabled(isAdmin || isMedical);
|
||
patientAdmitButton_->setEnabled(isAdmin || isMedical);
|
||
patientDischargeButton_->setEnabled(isAdmin || isMedical);
|
||
patientAddDiagnosisButton_->setEnabled(isAdmin || isMedical);
|
||
patientAddMedicineRecordButton_->setEnabled(isAdmin || isMedical);
|
||
|
||
// ============ 问题3 权限控制 ============
|
||
// 设置患者表格编辑权限
|
||
if (isPatient) {
|
||
// 病人视角:完全不可编辑
|
||
patientTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
doctorTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
wardTreeView_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
medicineTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
departmentTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
|
||
// 病人视角:禁用所有修改按钮
|
||
wardAddButton_->setEnabled(false);
|
||
wardEditButton_->setEnabled(false);
|
||
wardDeleteButton_->setEnabled(false);
|
||
wardAddBedButton_->setEnabled(false);
|
||
wardDeleteBedButton_->setEnabled(false);
|
||
wardOccupancyButton_->setEnabled(false);
|
||
|
||
// 医生编辑按钮禁用
|
||
doctorEditButton_->setEnabled(false);
|
||
|
||
patientAddButton_->setEnabled(false);
|
||
patientEditButton_->setEnabled(false);
|
||
patientRemoveButton_->setEnabled(false);
|
||
patientAdmitButton_->setEnabled(false);
|
||
patientDischargeButton_->setEnabled(false);
|
||
patientAddDiagnosisButton_->setEnabled(false);
|
||
patientAddMedicineRecordButton_->setEnabled(false);
|
||
|
||
// 病人视角:科室修改按钮禁用,但查看详情按钮可用
|
||
departmentAddButton_->setEnabled(false);
|
||
departmentEditButton_->setEnabled(false);
|
||
departmentRemoveButton_->setEnabled(false);
|
||
} else if (isMedical) {
|
||
// 医护视角:患者ID列不可编辑,其他列可编辑
|
||
patientTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||
// 第0列是患者ID,设置为不可编辑
|
||
for (int i = 0; i < patientTable_->rowCount(); ++i) {
|
||
QTableWidgetItem* item = patientTable_->item(i, 0);
|
||
if (item) {
|
||
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
|
||
}
|
||
}
|
||
doctorTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
medicineTable_->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
} else {
|
||
// 管理视角:全部可编辑
|
||
patientTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||
doctorTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||
medicineTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed);
|
||
}
|
||
|
||
// 医生相关按钮 - 只有管理视角可以添加/编辑/删除
|
||
doctorAddButton_->setEnabled(isAdmin);
|
||
doctorEditButton_->setEnabled(isAdmin);
|
||
doctorRemoveButton_->setEnabled(isAdmin);
|
||
|
||
// 药品相关按钮 - 只有管理视角
|
||
medicineAddButton_->setEnabled(isAdmin);
|
||
medicineUpdateButton_->setEnabled(isAdmin);
|
||
medicineRemoveButton_->setEnabled(isAdmin);
|
||
medicineIncreaseStockButton_->setEnabled(isAdmin);
|
||
medicineDecreaseStockButton_->setEnabled(isAdmin);
|
||
|
||
// 科室相关按钮 - 管理视角可以添加/编辑/删除
|
||
departmentAddButton_->setEnabled(isAdmin);
|
||
departmentEditButton_->setEnabled(isAdmin);
|
||
departmentRemoveButton_->setEnabled(isAdmin);
|
||
|
||
// 更新窗口标题以显示当前视角
|
||
QString roleText;
|
||
switch (currentRole_) {
|
||
case ViewRole::Admin:
|
||
roleText = tr("管理视角");
|
||
break;
|
||
case ViewRole::Patient:
|
||
roleText = tr("病人视角");
|
||
break;
|
||
case ViewRole::Medical:
|
||
roleText = tr("医护视角");
|
||
break;
|
||
}
|
||
setWindowTitle(tr("HIS GUI") + " - " + tr("医院信息系统") + " [" + roleText + "]");
|
||
}
|