#include "mainwindow.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "core/his_core.h" #include "core/doctor_service.h" class TitleComboDelegate : public QStyledItemDelegate { public: explicit TitleComboDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {} QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const override { auto* combo = new QComboBox(parent); QStringList titles = {tr("住院医师"), tr("主治医师"), tr("副主任医师"), tr("主任医师")}; combo->addItems(titles); return combo; } void setEditorData(QWidget* editor, const QModelIndex& index) const override { auto* combo = qobject_cast(editor); if (combo) { combo->setCurrentText(index.data(Qt::EditRole).toString()); } } void setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const override { auto* combo = qobject_cast(editor); if (combo) { model->setData(index, combo->currentText(), Qt::EditRole); } } }; void MainWindow::setupDoctorsTab() { doctorsTab_ = new QWidget(this); auto* layout = new QVBoxLayout(doctorsTab_); doctorSearchBox_ = new QLineEdit(doctorsTab_); doctorSearchBox_->setPlaceholderText(tr("搜索医生...")); connect(doctorSearchBox_, &QLineEdit::textChanged, this, &MainWindow::onDoctorSearch); auto* toolBar = new QHBoxLayout(); toolBar->addWidget(doctorSearchBox_); doctorAddButton_ = new QPushButton(tr("添加医生"), doctorsTab_); doctorEditButton_ = new QPushButton(tr("编辑医生"), doctorsTab_); doctorRemoveButton_ = new QPushButton(tr("删除医生"), doctorsTab_); toolBar->addWidget(doctorAddButton_); toolBar->addWidget(doctorEditButton_); toolBar->addWidget(doctorRemoveButton_); toolBar->addStretch(1); layout->addLayout(toolBar); doctorTable_ = new QTableWidget(0, 5, doctorsTab_); doctorTable_->setHorizontalHeaderLabels({tr("医生ID"), tr("姓名"), tr("科室"), tr("职务"), tr("出诊时间")}); doctorTable_->setSelectionBehavior(QAbstractItemView::SelectRows); doctorTable_->setEditTriggers(QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed); doctorTable_->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); doctorTable_->setSortingEnabled(true); layout->addWidget(doctorTable_); auto* titleDelegate = new TitleComboDelegate(this); doctorTable_->setItemDelegateForColumn(3, titleDelegate); connect(doctorAddButton_, &QPushButton::clicked, this, &MainWindow::handleAddDoctor); connect(doctorEditButton_, &QPushButton::clicked, this, &MainWindow::handleEditDoctor); connect(doctorRemoveButton_, &QPushButton::clicked, this, &MainWindow::handleRemoveDoctor); connect(doctorTable_, &QTableWidget::cellChanged, this, &MainWindow::onDoctorCellChanged); } void MainWindow::onDoctorCellChanged(int row, int column) { QTableWidgetItem* idItem = doctorTable_->item(row, 0); if (!idItem) return; QString did = idItem->text(); if (did.isEmpty()) return; auto* d = core_.doctorService.findDoctor(did.toStdString()); if (!d) return; QTableWidgetItem* nameItem = doctorTable_->item(row, 1); QTableWidgetItem* deptItem = doctorTable_->item(row, 2); QTableWidgetItem* titleItem = doctorTable_->item(row, 3); QTableWidgetItem* scheduleItem = doctorTable_->item(row, 4); std::string modifyDetails; if (nameItem && column == 1) { d->Name = nameItem->text().toStdString(); modifyDetails = "修改项: 姓名 | 新值: " + d->Name; } if (deptItem && column == 2) { d->DepartmentID = deptItem->text().toStdString(); modifyDetails = "修改项: 科室 | 新值: " + d->DepartmentID; } if (titleItem && column == 3) { d->Title = parseDoctorTitle(titleItem->text()); modifyDetails = "修改项: 职称 | 新值: " + titleItem->text().toStdString(); } if (scheduleItem && column == 4) { d->Schedule = scheduleItem->text().toStdString(); modifyDetails = "修改项: 出诊时间 | 新值: " + d->Schedule; } if (!modifyDetails.empty()) { std::string details = "医生ID: " + did.toStdString() + " | 医生名: " + d->Name + " | " + modifyDetails; logOperation(LogEntryType::DOCTOR_OPERATION, "MODIFY_DOCTOR", details, did.toStdString()); } } void MainWindow::refreshDoctorTable() { doctorTable_->blockSignals(true); doctorTable_->setSortingEnabled(false); // 【关键修复】填充前关闭排序 doctorTable_->setRowCount(0); int row = 0; core_.doctorService.for_eachDoctor([this, &row](const std::string&, const Doctor& doctor) { doctorTable_->insertRow(row); doctorTable_->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(doctor.DoctorID))); doctorTable_->setItem(row, 1, new QTableWidgetItem(QString::fromStdString(doctor.Name))); // 获取科室名称而不是ID QString deptName = QString::fromStdString(doctor.DepartmentID); auto* dept = core_.departmentService.findDepartment(doctor.DepartmentID); if (dept) { deptName = QString::fromStdString(dept->Name); } doctorTable_->setItem(row, 2, new QTableWidgetItem(deptName)); doctorTable_->setItem(row, 3, new QTableWidgetItem(doctorTitleToText(doctor.Title))); doctorTable_->setItem(row, 4, new QTableWidgetItem(QString::fromStdString(doctor.Schedule))); row++; }); doctorTable_->setSortingEnabled(true); // 【关键修复】填充后恢复排序 doctorTable_->blockSignals(false); } void MainWindow::handleAddDoctor() { 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 newDoctorId = QString::fromStdString(Doctor::generateUniqueId()); QLabel* doctorIdDisplay = new QLabel(newDoctorId, dialog); doctorIdDisplay->setEnabled(false); QLineEdit* nameEdit = new QLineEdit(dialog); // 科室选择改为下拉框 QComboBox* deptCombo = new QComboBox(dialog); deptCombo->addItem(tr("-- 请选择科室 --")); core_.departmentService.for_eachDepartment([deptCombo](const std::string& id, const Department& dept) { deptCombo->addItem(QString::fromStdString(dept.Name), QString::fromStdString(id)); }); QComboBox* titleCombo = new QComboBox(dialog); titleCombo->addItems({tr("主任医师"), tr("副主任医师"), tr("主治医师"), tr("住院医师")}); QLineEdit* scheduleEdit = new QLineEdit(dialog); QLabel* infoLabel = new QLabel(tr("医生ID将自动生成"), dialog); infoLabel->setStyleSheet("color: gray; font-size: 11px;"); form->addRow(tr("医生ID (自动生成):"), doctorIdDisplay); form->addRow(tr("姓名:"), nameEdit); form->addRow(tr("科室:"), deptCombo); form->addRow(tr("职称:"), titleCombo); form->addRow(tr("出诊时间:"), scheduleEdit); 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, deptCombo, titleCombo, scheduleEdit, newDoctorId]() { if (nameEdit->text().isEmpty()) { QMessageBox::warning(this, tr("错误"), tr("请填写姓名")); return; } if (deptCombo->currentIndex() == 0) { QMessageBox::warning(this, tr("错误"), tr("请选择科室")); return; } DoctorTitle title; QString titleStr = titleCombo->currentText(); if (titleStr == tr("主任医师")) title = DoctorTitle::Chief; else if (titleStr == tr("副主任医师")) title = DoctorTitle::AssociateChief; else if (titleStr == tr("主治医师")) title = DoctorTitle::Attending; else title = DoctorTitle::Resident; // 获取选中科室的ID QString deptId = deptCombo->currentData().toString(); Doctor d(newDoctorId.toStdString(), nameEdit->text().toStdString(), deptId.toStdString(), title, scheduleEdit->text().toStdString()); if (!core_.doctorService.addDoctor(d)) { QMessageBox::warning(this, tr("添加失败"), tr("医生 ID 已存在")); return; } // 记录详细日志 - 医生的完整信息 std::string doctorDetails = "医生ID: " + newDoctorId.toStdString() + " | 姓名: " + nameEdit->text().toStdString() + " | 科室: " + deptCombo->currentText().toStdString() + " | 科室ID: " + deptId.toStdString() + " | 职称: " + titleCombo->currentText().toStdString() + " | 出诊时间: " + scheduleEdit->text().toStdString(); logOperation(LogEntryType::DOCTOR_OPERATION, "ADD_DOCTOR", doctorDetails, newDoctorId.toStdString()); QMessageBox::information(this, tr("成功"), tr("已添加医生: %1 (%2)").arg(newDoctorId).arg(nameEdit->text())); refreshDoctorTable(); refreshDashboard(); dialog->accept(); }); connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject); dialog->exec(); } void MainWindow::handleRemoveDoctor() { QString did = safeCurrentTableId(doctorTable_); if (did.isEmpty()) { QMessageBox::warning(this, tr("删除医生"), tr("请先选择医生")); return; } // 获取医生完整信息用于日志记录和确认弹窗 auto* doctor = core_.doctorService.findDoctor(did.toStdString()); std::string doctorDetails; QString doctorName = tr("未知"); if (doctor) { doctorName = QString::fromStdString(doctor->Name); // 将医生职称转为字符串 std::string titleStr; switch (doctor->Title) { case DoctorTitle::Chief: titleStr = "主任医师"; break; case DoctorTitle::AssociateChief: titleStr = "副主任医师"; break; case DoctorTitle::Attending: titleStr = "主治医师"; break; case DoctorTitle::Resident: titleStr = "住院医师"; break; } doctorDetails = "医生ID: " + doctor->DoctorID + " | 姓名: " + doctor->Name + " | 科室ID: " + doctor->DepartmentID + " | 职称: " + titleStr + " | 出诊时间: " + doctor->Schedule; } // 确认删除弹窗 QMessageBox::StandardButton reply = QMessageBox::question( this, tr("确认删除"), tr("确定要删除医生 \"%1\" (ID: %2) 吗?\n此操作无法撤销。").arg(doctorName).arg(did), QMessageBox::Yes | QMessageBox::No); if (reply != QMessageBox::Yes) return; if (!core_.doctorService.removeDoctor(did.toStdString())) { QMessageBox::warning(this, tr("删除失败"), tr("无法删除医生")); return; } // 记录详细日志 - 包含被删除医生的完整信息 if (!doctorDetails.empty()) { logOperation(LogEntryType::DOCTOR_OPERATION, "REMOVE_DOCTOR", doctorDetails, did.toStdString()); } refreshDoctorTable(); refreshDashboard(); } void MainWindow::handleEditDoctor() { QString did = safeCurrentTableId(doctorTable_); if (did.isEmpty()) { QMessageBox::warning(this, tr("编辑医生"), tr("请先选择医生")); return; } auto* d = core_.doctorService.findDoctor(did.toStdString()); if (!d) return; QDialog* dialog = new QDialog(this); dialog->setWindowTitle(tr("编辑医生 - %1").arg(did)); 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); QLabel* doctorIdLabel = new QLabel(did, dialog); doctorIdLabel->setEnabled(false); QLineEdit* nameEdit = new QLineEdit(QString::fromStdString(d->Name), dialog); // 科室选择改为下拉框 QComboBox* deptCombo = new QComboBox(dialog); deptCombo->addItem(tr("-- 请选择科室 --")); core_.departmentService.for_eachDepartment([deptCombo](const std::string& id, const Department& dept) { deptCombo->addItem(QString::fromStdString(dept.Name), QString::fromStdString(id)); }); // 设置当前选中的科室 for (int i = 1; i < deptCombo->count(); ++i) { if (deptCombo->itemData(i).toString().toStdString() == d->DepartmentID) { deptCombo->setCurrentIndex(i); break; } } QComboBox* titleCombo = new QComboBox(dialog); titleCombo->addItems({tr("主任医师"), tr("副主任医师"), tr("主治医师"), tr("住院医师")}); // 设置当前职称 int titleIdx = 0; switch (d->Title) { case DoctorTitle::Chief: titleIdx = 0; break; case DoctorTitle::AssociateChief: titleIdx = 1; break; case DoctorTitle::Attending: titleIdx = 2; break; case DoctorTitle::Resident: titleIdx = 3; break; } titleCombo->setCurrentIndex(titleIdx); QLineEdit* scheduleEdit = new QLineEdit(QString::fromStdString(d->Schedule), dialog); form->addRow(tr("医生ID:"), doctorIdLabel); form->addRow(tr("姓名:"), nameEdit); form->addRow(tr("科室:"), deptCombo); form->addRow(tr("职称:"), titleCombo); form->addRow(tr("出诊时间:"), scheduleEdit); 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, did, dialog, d, nameEdit, deptCombo, titleCombo, scheduleEdit]() { if (nameEdit->text().isEmpty()) { QMessageBox::warning(this, tr("错误"), tr("请填写姓名")); return; } if (deptCombo->currentIndex() == 0) { QMessageBox::warning(this, tr("错误"), tr("请选择科室")); return; } DoctorTitle title; QString titleStr = titleCombo->currentText(); if (titleStr == tr("主任医师")) title = DoctorTitle::Chief; else if (titleStr == tr("副主任医师")) title = DoctorTitle::AssociateChief; else if (titleStr == tr("主治医师")) title = DoctorTitle::Attending; else title = DoctorTitle::Resident; // 获取选中科室的ID QString deptId = deptCombo->currentData().toString(); // 更新医生信息 d->Name = nameEdit->text().toStdString(); d->DepartmentID = deptId.toStdString(); d->Title = title; d->Schedule = scheduleEdit->text().toStdString(); // 记录详细日志 - 医生的完整信息 std::string doctorDetails = "医生ID: " + did.toStdString() + " | 姓名: " + nameEdit->text().toStdString() + " | 科室: " + deptCombo->currentText().toStdString() + " | 科室ID: " + deptId.toStdString() + " | 职称: " + titleCombo->currentText().toStdString() + " | 出诊时间: " + scheduleEdit->text().toStdString(); logOperation(LogEntryType::DOCTOR_OPERATION, "MODIFY_DOCTOR", doctorDetails, did.toStdString()); QMessageBox::information(this, tr("成功"), tr("已更新医生: %1 (%2)").arg(did).arg(nameEdit->text())); refreshDoctorTable(); dialog->accept(); }); connect(cancelButton, &QPushButton::clicked, dialog, &QDialog::reject); dialog->exec(); } void MainWindow::onDoctorSearch(const QString& text) { for (int i = 0; i < doctorTable_->rowCount(); ++i) { bool match = false; for (int j = 0; j < doctorTable_->columnCount(); ++j) { QTableWidgetItem* item = doctorTable_->item(i, j); if (item && item->text().contains(text, Qt::CaseInsensitive)) { match = true; break; } } doctorTable_->setRowHidden(i, !match); } }