416 lines
17 KiB
C++
416 lines
17 KiB
C++
#include "mainwindow.h"
|
|
|
|
#include <QComboBox>
|
|
#include <QDialog>
|
|
#include <QFormLayout>
|
|
#include <QHeaderView>
|
|
#include <QLabel>
|
|
#include <QLineEdit>
|
|
#include <QMessageBox>
|
|
#include <QPushButton>
|
|
#include <QStyledItemDelegate>
|
|
#include <QTableWidget>
|
|
#include <QTableWidgetItem>
|
|
#include <QVBoxLayout>
|
|
|
|
#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<QComboBox*>(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<QComboBox*>(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);
|
|
}
|
|
}
|