690 lines
28 KiB
C++
690 lines
28 KiB
C++
#include "payment_management_dialog.h"
|
|
|
|
#include "core/his_core.h"
|
|
#include "models/payment.h"
|
|
#include "models/settlement.h"
|
|
#include "models/patient.h"
|
|
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QTableWidget>
|
|
#include <QTableWidgetItem>
|
|
#include <QPushButton>
|
|
#include <QTabWidget>
|
|
#include <QMessageBox>
|
|
#include <QTextEdit>
|
|
#include <QLineEdit>
|
|
#include <QHeaderView>
|
|
#include <QTreeWidget>
|
|
#include <QTreeWidgetItem>
|
|
#include <QStackedWidget>
|
|
#include <QtCharts/QChartView>
|
|
#include <QtCharts/QBarSeries>
|
|
#include <QtCharts/QBarSet>
|
|
#include <QtCharts/QBarCategoryAxis>
|
|
#include <QtCharts/QValueAxis>
|
|
#include <QtCharts/QPieSeries>
|
|
#include <QtCharts/QPieSlice>
|
|
#include <QFont>
|
|
#include <QColor>
|
|
#include <ctime>
|
|
#include <iomanip>
|
|
#include <sstream>
|
|
#include <map>
|
|
|
|
PaymentManagementDialog::PaymentManagementDialog(core::HisCore& core, QWidget* parent)
|
|
: QDialog(parent), core_(core) {
|
|
setWindowTitle("支付管理");
|
|
setModal(false);
|
|
setMinimumSize(1000, 600);
|
|
setupUI();
|
|
onRefreshPayments();
|
|
}
|
|
|
|
void PaymentManagementDialog::setupUI() {
|
|
QVBoxLayout* mainLayout = new QVBoxLayout(this);
|
|
|
|
// Create tab widget
|
|
tabWidget_ = new QTabWidget();
|
|
connect(tabWidget_, &QTabWidget::currentChanged, this, &PaymentManagementDialog::onTabChanged);
|
|
|
|
// ========== Payment Tab ==========
|
|
QWidget* paymentWidget = new QWidget();
|
|
QVBoxLayout* paymentLayout = new QVBoxLayout(paymentWidget);
|
|
|
|
// Payment table
|
|
paymentTable_ = new QTableWidget();
|
|
paymentTable_->setColumnCount(9);
|
|
paymentTable_->setHorizontalHeaderLabels(
|
|
{"支付ID", "患者ID", "患者姓名", "金额", "支付方式", "类型", "时间", "状态", "描述"});
|
|
paymentTable_->horizontalHeader()->setStretchLastSection(true);
|
|
paymentTable_->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
paymentTable_->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
connect(paymentTable_, &QTableWidget::itemSelectionChanged,
|
|
this, &PaymentManagementDialog::onPaymentSelectionChanged);
|
|
paymentLayout->addWidget(paymentTable_);
|
|
|
|
// Search filter
|
|
QHBoxLayout* filterLayout = new QHBoxLayout();
|
|
filterLayout->addWidget(new QLabel("搜索:"));
|
|
statusFilterEdit_ = new QLineEdit();
|
|
statusFilterEdit_->setPlaceholderText("输入关键词搜索任意字段...");
|
|
filterLayout->addWidget(statusFilterEdit_);
|
|
QPushButton* filterButton = new QPushButton("搜索");
|
|
connect(filterButton, &QPushButton::clicked, this, &PaymentManagementDialog::onFilterByStatus);
|
|
filterLayout->addWidget(filterButton);
|
|
QPushButton* clearButton = new QPushButton("清除");
|
|
connect(clearButton, &QPushButton::clicked, [this]() {
|
|
statusFilterEdit_->clear();
|
|
loadPaymentRecords();
|
|
});
|
|
filterLayout->addWidget(clearButton);
|
|
paymentLayout->addLayout(filterLayout);
|
|
|
|
// Button layout
|
|
QHBoxLayout* paymentButtonLayout = new QHBoxLayout();
|
|
refreshButton_ = new QPushButton("刷新");
|
|
connect(refreshButton_, &QPushButton::clicked, this, &PaymentManagementDialog::onRefreshPayments);
|
|
paymentButtonLayout->addWidget(refreshButton_);
|
|
|
|
refundButton_ = new QPushButton("退款");
|
|
connect(refundButton_, &QPushButton::clicked, this, &PaymentManagementDialog::onRefundPayment);
|
|
paymentButtonLayout->addWidget(refundButton_);
|
|
|
|
paymentButtonLayout->addStretch();
|
|
paymentLayout->addLayout(paymentButtonLayout);
|
|
|
|
// Statistics label
|
|
statisticsLabel_ = new QLabel("统计信息: 加载中...");
|
|
paymentLayout->addWidget(statisticsLabel_);
|
|
|
|
tabWidget_->addTab(paymentWidget, "支付记录");
|
|
|
|
// ========== Settlement Tab ==========
|
|
QWidget* settlementWidget = new QWidget();
|
|
QVBoxLayout* settlementLayout = new QVBoxLayout(settlementWidget);
|
|
|
|
// Search layout
|
|
QHBoxLayout* settlementSearchLayout = new QHBoxLayout();
|
|
settlementSearchLayout->addWidget(new QLabel("搜索病人(ID/姓名/手机号):"));
|
|
settlementSearchEdit_ = new QLineEdit();
|
|
settlementSearchEdit_->setPlaceholderText("请输入搜索关键词...");
|
|
settlementSearchLayout->addWidget(settlementSearchEdit_);
|
|
settlementSearchButton_ = new QPushButton("搜索");
|
|
connect(settlementSearchButton_, &QPushButton::clicked,
|
|
this, &PaymentManagementDialog::onSearchSettlements);
|
|
settlementSearchLayout->addWidget(settlementSearchButton_);
|
|
settlementLayout->addLayout(settlementSearchLayout);
|
|
|
|
// 使用树形结构显示每个患者的支付记录
|
|
settlementTree_ = new QTreeWidget();
|
|
settlementTree_->setColumnCount(5);
|
|
settlementTree_->setHeaderLabels({"支付ID", "支付类型", "支付金额", "支付方式", "状态"});
|
|
settlementTree_->header()->setStretchLastSection(true);
|
|
settlementTree_->setAlternatingRowColors(true);
|
|
settlementLayout->addWidget(settlementTree_);
|
|
|
|
// Button layout
|
|
QHBoxLayout* settlementButtonLayout = new QHBoxLayout();
|
|
settlementRefreshButton_ = new QPushButton("刷新");
|
|
connect(settlementRefreshButton_, &QPushButton::clicked,
|
|
this, [this]() { loadSettlementRecords(); });
|
|
settlementButtonLayout->addWidget(settlementRefreshButton_);
|
|
settlementButtonLayout->addStretch();
|
|
settlementLayout->addLayout(settlementButtonLayout);
|
|
|
|
tabWidget_->addTab(settlementWidget, "结算单");
|
|
|
|
// ========== Reports Tab ==========
|
|
QWidget* reportWidget = new QWidget();
|
|
QVBoxLayout* reportLayout = new QVBoxLayout(reportWidget);
|
|
|
|
// 创建按钮让用户刷新图表数据
|
|
QHBoxLayout* reportButtonLayout = new QHBoxLayout();
|
|
dailyReportButton_ = new QPushButton("每日报表");
|
|
dailyReportButton_->setStyleSheet("QPushButton { background-color: #4CAF50; color: white; padding: 8px 16px; border-radius: 4px; font-weight: bold; }");
|
|
connect(dailyReportButton_, &QPushButton::clicked,
|
|
this, &PaymentManagementDialog::onGenerateDailyReport);
|
|
reportButtonLayout->addWidget(dailyReportButton_);
|
|
|
|
monthlyReportButton_ = new QPushButton("月报表");
|
|
monthlyReportButton_->setStyleSheet("QPushButton { background-color: #2196F3; color: white; padding: 8px 16px; border-radius: 4px; font-weight: bold; }");
|
|
connect(monthlyReportButton_, &QPushButton::clicked,
|
|
this, &PaymentManagementDialog::onGenerateMonthlyReport);
|
|
reportButtonLayout->addWidget(monthlyReportButton_);
|
|
|
|
revenueReportButton_ = new QPushButton("收入总报表");
|
|
revenueReportButton_->setStyleSheet("QPushButton { background-color: #FF9800; color: white; padding: 8px 16px; border-radius: 4px; font-weight: bold; }");
|
|
connect(revenueReportButton_, &QPushButton::clicked,
|
|
this, &PaymentManagementDialog::onGenerateRevenueReport);
|
|
reportButtonLayout->addWidget(revenueReportButton_);
|
|
|
|
reportButtonLayout->addStretch();
|
|
reportLayout->addLayout(reportButtonLayout);
|
|
|
|
// 创建带图表的stacked widget
|
|
QTabWidget* chartTabWidget = new QTabWidget();
|
|
|
|
// ===== 每日收入图表 =====
|
|
dailyChartWidget_ = new QWidget();
|
|
QVBoxLayout* dailyChartLayout = new QVBoxLayout(dailyChartWidget_);
|
|
|
|
// 每日报表标题
|
|
QLabel* dailyTitleLabel = new QLabel("📊 每日收入报表");
|
|
dailyTitleLabel->setStyleSheet("font-size: 18px; font-weight: bold; color: #333; padding: 10px;");
|
|
dailyTitleLabel->setAlignment(Qt::AlignCenter);
|
|
dailyChartLayout->addWidget(dailyTitleLabel);
|
|
|
|
// 创建条形图显示每日收入
|
|
QChart* dailyChart = new QChart();
|
|
dailyChart->setTitle("最近7天收入趋势");
|
|
dailyChart->setAnimationDuration(500);
|
|
dailyChart->setAnimationOptions(QChart::AllAnimations);
|
|
|
|
QBarSeries* dailyBarSeries = new QBarSeries();
|
|
QBarSet* dailyBarSet = new QBarSet("每日收入");
|
|
|
|
// 从真实数据获取最近7天收入
|
|
auto dailyData = core_.paymentManagementService.getDailyRevenueData(7);
|
|
for (const auto& pair : dailyData) {
|
|
*dailyBarSet << pair.second;
|
|
}
|
|
|
|
dailyBarSeries->append(dailyBarSet);
|
|
dailyChart->addSeries(dailyBarSeries);
|
|
|
|
QStringList dailyCategories;
|
|
for (const auto& pair : dailyData) {
|
|
dailyCategories << QString::fromStdString(pair.first);
|
|
}
|
|
QBarCategoryAxis* dailyAxisX = new QBarCategoryAxis();
|
|
dailyAxisX->append(dailyCategories);
|
|
dailyChart->addAxis(dailyAxisX, Qt::AlignBottom);
|
|
dailyBarSeries->attachAxis(dailyAxisX);
|
|
|
|
QValueAxis* dailyAxisY = new QValueAxis();
|
|
dailyAxisY->setTitleText("收入 (¥)");
|
|
dailyAxisY->setMin(0);
|
|
dailyChart->addAxis(dailyAxisY, Qt::AlignLeft);
|
|
dailyBarSeries->attachAxis(dailyAxisY);
|
|
|
|
QChartView* dailyChartView = new QChartView(dailyChart);
|
|
dailyChartView->setRenderHint(QPainter::Antialiasing);
|
|
dailyChartView->setMinimumSize(600, 350);
|
|
dailyChartLayout->addWidget(dailyChartView);
|
|
|
|
// 计算本周总收入和今日收入
|
|
double weekTotal = 0.0;
|
|
double todayRevenue = 0.0;
|
|
if (!dailyData.empty()) {
|
|
todayRevenue = dailyData.back().second;
|
|
for (const auto& pair : dailyData) {
|
|
weekTotal += pair.second;
|
|
}
|
|
}
|
|
|
|
// 每日统计信息
|
|
QLabel* dailyStatsLabel = new QLabel(QString("📈 今日收入: ¥%1 | 本周总收入: ¥%2 | 共 %3 笔交易")
|
|
.arg(todayRevenue, 0, 'f', 2)
|
|
.arg(weekTotal, 0, 'f', 2)
|
|
.arg(dailyData.size()));
|
|
dailyStatsLabel->setStyleSheet("font-size: 14px; padding: 10px; background-color: #E8F5E9; border-radius: 5px;");
|
|
dailyStatsLabel->setAlignment(Qt::AlignCenter);
|
|
dailyChartLayout->addWidget(dailyStatsLabel);
|
|
|
|
chartTabWidget->addTab(dailyChartWidget_, "每日");
|
|
|
|
// ===== 月度收入图表 =====
|
|
monthlyChartWidget_ = new QWidget();
|
|
QVBoxLayout* monthlyChartLayout = new QVBoxLayout(monthlyChartWidget_);
|
|
|
|
// 月报表标题
|
|
QLabel* monthlyTitleLabel = new QLabel("📊 月度收入报表");
|
|
monthlyTitleLabel->setStyleSheet("font-size: 18px; font-weight: bold; color: #333; padding: 10px;");
|
|
monthlyTitleLabel->setAlignment(Qt::AlignCenter);
|
|
monthlyChartLayout->addWidget(monthlyTitleLabel);
|
|
|
|
// 创建条形图显示月度收入
|
|
QChart* monthlyChart = new QChart();
|
|
monthlyChart->setTitle("最近6个月收入趋势");
|
|
monthlyChart->setAnimationDuration(500);
|
|
monthlyChart->setAnimationOptions(QChart::AllAnimations);
|
|
|
|
QBarSeries* monthlyBarSeries = new QBarSeries();
|
|
QBarSet* monthlyBarSet = new QBarSet("月度收入");
|
|
|
|
// 从真实数据获取最近6个月收入
|
|
auto monthlyData = core_.paymentManagementService.getMonthlyRevenueData(6);
|
|
for (const auto& pair : monthlyData) {
|
|
*monthlyBarSet << pair.second;
|
|
}
|
|
|
|
monthlyBarSeries->append(monthlyBarSet);
|
|
monthlyChart->addSeries(monthlyBarSeries);
|
|
|
|
QStringList monthlyCategories;
|
|
for (const auto& pair : monthlyData) {
|
|
monthlyCategories << QString::fromStdString(pair.first);
|
|
}
|
|
QBarCategoryAxis* monthlyAxisX = new QBarCategoryAxis();
|
|
monthlyAxisX->append(monthlyCategories);
|
|
monthlyChart->addAxis(monthlyAxisX, Qt::AlignBottom);
|
|
monthlyBarSeries->attachAxis(monthlyAxisX);
|
|
|
|
QValueAxis* monthlyAxisY = new QValueAxis();
|
|
monthlyAxisY->setTitleText("收入 (¥)");
|
|
monthlyAxisY->setMin(0);
|
|
monthlyChart->addAxis(monthlyAxisY, Qt::AlignLeft);
|
|
monthlyBarSeries->attachAxis(monthlyAxisY);
|
|
|
|
QChartView* monthlyChartView = new QChartView(monthlyChart);
|
|
monthlyChartView->setRenderHint(QPainter::Antialiasing);
|
|
monthlyChartView->setMinimumSize(600, 350);
|
|
monthlyChartLayout->addWidget(monthlyChartView);
|
|
|
|
// 计算本月收入
|
|
double monthTotal = 0.0;
|
|
for (const auto& pair : monthlyData) {
|
|
monthTotal += pair.second;
|
|
}
|
|
|
|
// 月度统计信息
|
|
QLabel* monthlyStatsLabel = new QLabel(QString("📈 本月收入: ¥%1 | 统计月份: %2 个月")
|
|
.arg(monthTotal, 0, 'f', 2)
|
|
.arg(monthlyData.size()));
|
|
monthlyStatsLabel->setStyleSheet("font-size: 14px; padding: 10px; background-color: #E3F2FD; border-radius: 5px;");
|
|
monthlyStatsLabel->setAlignment(Qt::AlignCenter);
|
|
monthlyChartLayout->addWidget(monthlyStatsLabel);
|
|
|
|
chartTabWidget->addTab(monthlyChartWidget_, "每月");
|
|
|
|
// ===== 收入分类饼图 =====
|
|
revenueChartWidget_ = new QWidget();
|
|
QVBoxLayout* revenueChartLayout = new QVBoxLayout(revenueChartWidget_);
|
|
|
|
// 总报表标题
|
|
QLabel* revenueTitleLabel = new QLabel("📊 收入分类总报表");
|
|
revenueTitleLabel->setStyleSheet("font-size: 18px; font-weight: bold; color: #333; padding: 10px;");
|
|
revenueTitleLabel->setAlignment(Qt::AlignCenter);
|
|
revenueChartLayout->addWidget(revenueTitleLabel);
|
|
|
|
// 创建饼图显示收入分类
|
|
QChart* revenueChart = new QChart();
|
|
revenueChart->setTitle("收入来源分布");
|
|
revenueChart->setAnimationDuration(500);
|
|
revenueChart->setAnimationOptions(QChart::AllAnimations);
|
|
|
|
QPieSeries* pieSeries = new QPieSeries();
|
|
pieSeries->setHoleSize(0.35);
|
|
|
|
// 从真实数据获取收入分类
|
|
auto revenueByType = core_.paymentManagementService.getRevenueByType();
|
|
|
|
// 颜色数组
|
|
QColor colors[] = {
|
|
QColor("#4CAF50"), QColor("#2196F3"), QColor("#FF9800"),
|
|
QColor("#9C27B0"), QColor("#F44336"), QColor("#00BCD4"),
|
|
QColor("#795548"), QColor("#607D8B")
|
|
};
|
|
|
|
int colorIndex = 0;
|
|
double totalRevenue = 0.0;
|
|
for (const auto& pair : revenueByType) {
|
|
totalRevenue += pair.second;
|
|
}
|
|
|
|
for (const auto& pair : revenueByType) {
|
|
double percentage = totalRevenue > 0 ? (pair.second / totalRevenue * 100) : 0;
|
|
QPieSlice* slice = new QPieSlice(
|
|
QString::fromStdString(pair.first) + QString(" ¥%1 (%2%)")
|
|
.arg(pair.second, 0, 'f', 2)
|
|
.arg(percentage, 0, 'f', 1),
|
|
pair.second);
|
|
slice->setBrush(colors[colorIndex % 8]);
|
|
slice->setLabelVisible(true);
|
|
slice->setLabelPosition(QPieSlice::LabelOutside);
|
|
pieSeries->append(slice);
|
|
colorIndex++;
|
|
}
|
|
|
|
revenueChart->addSeries(pieSeries);
|
|
revenueChart->legend()->setVisible(true);
|
|
revenueChart->legend()->setAlignment(Qt::AlignRight);
|
|
|
|
QChartView* revenueChartView = new QChartView(revenueChart);
|
|
revenueChartView->setRenderHint(QPainter::Antialiasing);
|
|
revenueChartView->setMinimumSize(600, 350);
|
|
revenueChartLayout->addWidget(revenueChartView);
|
|
|
|
// 计算总统计数据
|
|
auto stats = core_.paymentManagementService.getPaymentStatistics();
|
|
|
|
// 总收入统计信息
|
|
QLabel* revenueStatsLabel = new QLabel(QString("💰 总收入: ¥%1 | 已完成支付: %2笔 | 待支付: %3笔 | 已退款: %4笔")
|
|
.arg(stats.TotalRevenue, 0, 'f', 2)
|
|
.arg(stats.CompletedPayments)
|
|
.arg(stats.PendingPayments)
|
|
.arg(stats.RefundedPayments));
|
|
revenueStatsLabel->setStyleSheet("font-size: 14px; padding: 10px; background-color: #FFF3E0; border-radius: 5px;");
|
|
revenueStatsLabel->setAlignment(Qt::AlignCenter);
|
|
revenueChartLayout->addWidget(revenueStatsLabel);
|
|
|
|
chartTabWidget->addTab(revenueChartWidget_, "总收入");
|
|
|
|
reportLayout->addWidget(chartTabWidget);
|
|
|
|
reportLabel_ = new QLabel("报表内容将在此显示");
|
|
|
|
tabWidget_->addTab(reportWidget, "报表");
|
|
|
|
mainLayout->addWidget(tabWidget_);
|
|
setLayout(mainLayout);
|
|
}
|
|
|
|
void PaymentManagementDialog::loadPaymentRecords() {
|
|
paymentTable_->setRowCount(0);
|
|
|
|
int row = 0;
|
|
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
|
paymentTable_->insertRow(row);
|
|
|
|
paymentTable_->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(payment.PaymentID)));
|
|
paymentTable_->setItem(row, 1, new QTableWidgetItem(QString::fromStdString(payment.PatientID)));
|
|
|
|
// 获取患者姓名
|
|
const Patient* patient = core_.patientService.findPatient(payment.PatientID);
|
|
QString patientName = patient ? QString::fromStdString(patient->Name) : "未知患者";
|
|
paymentTable_->setItem(row, 2, new QTableWidgetItem(patientName));
|
|
|
|
paymentTable_->setItem(row, 3, new QTableWidgetItem(QString::number(payment.Amount, 'f', 2)));
|
|
paymentTable_->setItem(row, 4, new QTableWidgetItem(QString::fromStdString(payment.getMethodString())));
|
|
paymentTable_->setItem(row, 5, new QTableWidgetItem(QString::fromStdString(payment.PaymentType)));
|
|
paymentTable_->setItem(row, 6, new QTableWidgetItem(QString::number(payment.PaymentTime)));
|
|
paymentTable_->setItem(row, 7, new QTableWidgetItem(QString::fromStdString(payment.Status)));
|
|
paymentTable_->setItem(row, 8, new QTableWidgetItem(QString::fromStdString(payment.Description)));
|
|
|
|
row++;
|
|
});
|
|
|
|
updateStatistics();
|
|
}
|
|
|
|
void PaymentManagementDialog::loadSettlementRecords() {
|
|
settlementTree_->clear();
|
|
|
|
// 使用map按患者ID分组存储支付记录
|
|
std::map<std::string, std::vector<const Payment*>> patientPayments;
|
|
|
|
// 收集所有已完成的支付记录并按患者分组
|
|
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
|
// 只显示已完成的支付记录
|
|
if (payment.Status == "Completed") {
|
|
patientPayments[payment.PatientID].push_back(&payment);
|
|
}
|
|
});
|
|
|
|
// 构建树形结构
|
|
for (const auto& pair : patientPayments) {
|
|
const std::string& patientId = pair.first;
|
|
const std::vector<const Payment*>& payments = pair.second;
|
|
|
|
// 获取患者信息
|
|
const Patient* patient = core_.patientService.findPatient(patientId);
|
|
QString patientName = patient ? QString::fromStdString(patient->Name) : "未知患者";
|
|
QString contact = patient ? QString::fromStdString(patient->Contact) : "";
|
|
|
|
// 创建患者节点(父节点)
|
|
QString patientInfo = QString("%1 (%2) 手机: %3, 共%4笔支付")
|
|
.arg(QString::fromStdString(patientId))
|
|
.arg(patientName)
|
|
.arg(contact)
|
|
.arg(payments.size());
|
|
|
|
QTreeWidgetItem* patientItem = new QTreeWidgetItem(QStringList() << patientInfo);
|
|
patientItem->setData(0, Qt::UserRole, QString::fromStdString(patientId));
|
|
patientItem->setExpanded(true); // 默认展开
|
|
|
|
// 添加患者节点的汇总信息
|
|
double totalAmount = 0.0;
|
|
|
|
for (const Payment* p : payments) {
|
|
totalAmount += p->Amount;
|
|
|
|
// 创建支付记录子节点
|
|
QTreeWidgetItem* paymentItem = new QTreeWidgetItem(patientItem);
|
|
paymentItem->setText(0, QString::fromStdString(p->PaymentID));
|
|
paymentItem->setText(1, QString::fromStdString(p->PaymentType));
|
|
paymentItem->setText(2, QString::number(p->Amount, 'f', 2));
|
|
paymentItem->setText(3, QString::fromStdString(p->getMethodString()));
|
|
paymentItem->setText(4, QString::fromStdString(p->Status));
|
|
}
|
|
|
|
// 在父节点中添加汇总信息
|
|
patientItem->setText(2, QString::number(totalAmount, 'f', 2));
|
|
|
|
settlementTree_->addTopLevelItem(patientItem);
|
|
}
|
|
|
|
// 设置患者列宽以显示完整信息
|
|
settlementTree_->setColumnWidth(0, 400);
|
|
}
|
|
|
|
void PaymentManagementDialog::onSearchSettlements() {
|
|
QString keyword = settlementSearchEdit_->text();
|
|
settlementTree_->clear();
|
|
|
|
// 收集支付记录
|
|
std::map<std::string, std::vector<const Payment*>> patientPayments;
|
|
|
|
if (keyword.isEmpty()) {
|
|
// 如果关键词为空,显示所有已完成支付记录
|
|
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
|
if (payment.Status == "Completed") {
|
|
patientPayments[payment.PatientID].push_back(&payment);
|
|
}
|
|
});
|
|
} else {
|
|
// 搜索匹配的患者,然后显示其支付记录
|
|
std::string keywordStd = keyword.toStdString();
|
|
|
|
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
|
if (payment.Status == "Completed") {
|
|
// 获取患者信息进行匹配
|
|
const Patient* patient = core_.patientService.findPatient(payment.PatientID);
|
|
if (patient) {
|
|
// 检查患者ID、姓名、手机号是否包含关键词
|
|
if (patient->PatientID.find(keywordStd) != std::string::npos ||
|
|
patient->Name.find(keywordStd) != std::string::npos ||
|
|
patient->Contact.find(keywordStd) != std::string::npos) {
|
|
patientPayments[payment.PatientID].push_back(&payment);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 构建树形结构
|
|
for (const auto& pair : patientPayments) {
|
|
const std::string& patientId = pair.first;
|
|
const std::vector<const Payment*>& payments = pair.second;
|
|
|
|
const Patient* patient = core_.patientService.findPatient(patientId);
|
|
QString patientName = patient ? QString::fromStdString(patient->Name) : "未知患者";
|
|
QString contact = patient ? QString::fromStdString(patient->Contact) : "";
|
|
|
|
QString patientInfo = QString("%1 (%2) 手机: %3, 共%4笔支付")
|
|
.arg(QString::fromStdString(patientId))
|
|
.arg(patientName)
|
|
.arg(contact)
|
|
.arg(payments.size());
|
|
|
|
QTreeWidgetItem* patientItem = new QTreeWidgetItem(QStringList() << patientInfo);
|
|
patientItem->setData(0, Qt::UserRole, QString::fromStdString(patientId));
|
|
patientItem->setExpanded(true);
|
|
|
|
double totalAmount = 0.0;
|
|
|
|
for (const Payment* p : payments) {
|
|
totalAmount += p->Amount;
|
|
|
|
QTreeWidgetItem* paymentItem = new QTreeWidgetItem(patientItem);
|
|
paymentItem->setText(0, QString::fromStdString(p->PaymentID));
|
|
paymentItem->setText(1, QString::fromStdString(p->PaymentType));
|
|
paymentItem->setText(2, QString::number(p->Amount, 'f', 2));
|
|
paymentItem->setText(3, QString::fromStdString(p->getMethodString()));
|
|
paymentItem->setText(4, QString::fromStdString(p->Status));
|
|
}
|
|
|
|
patientItem->setText(2, QString::number(totalAmount, 'f', 2));
|
|
|
|
settlementTree_->addTopLevelItem(patientItem);
|
|
}
|
|
|
|
settlementTree_->setColumnWidth(0, 400);
|
|
}
|
|
|
|
void PaymentManagementDialog::updateStatistics() {
|
|
auto stats = core_.paymentManagementService.getPaymentStatistics();
|
|
|
|
std::stringstream ss;
|
|
ss << "总收入: ¥" << std::fixed << std::setprecision(2) << stats.TotalRevenue
|
|
<< " | 已完成支付: " << stats.CompletedPayments << "笔 (¥" << stats.CompletedAmount
|
|
<< ") | 待支付: " << stats.PendingPayments << "笔 (¥" << stats.PendingAmount
|
|
<< ") | 已退款: " << stats.RefundedPayments << "笔 (¥" << stats.RefundedAmount << ")";
|
|
|
|
statisticsLabel_->setText(QString::fromStdString(ss.str()));
|
|
}
|
|
|
|
void PaymentManagementDialog::onRefreshPayments() {
|
|
loadPaymentRecords();
|
|
}
|
|
|
|
void PaymentManagementDialog::onRefundPayment() {
|
|
if (paymentTable_->currentRow() < 0) {
|
|
QMessageBox::warning(this, "警告", "请先选择一条支付记录");
|
|
return;
|
|
}
|
|
|
|
int row = paymentTable_->currentRow();
|
|
QString paymentID = paymentTable_->item(row, 0)->text();
|
|
|
|
// TODO: Add reason dialog
|
|
std::string reason = "Manual refund";
|
|
|
|
if (core_.paymentManagementService.processRefund(paymentID.toStdString(), reason)) {
|
|
QMessageBox::information(this, "退款成功", "支付记录已退款");
|
|
onRefreshPayments();
|
|
} else {
|
|
QMessageBox::warning(this, "退款失败", "无法退款该支付记录");
|
|
}
|
|
}
|
|
|
|
void PaymentManagementDialog::onPaymentSelectionChanged() {
|
|
// Update any details when selection changes
|
|
}
|
|
|
|
void PaymentManagementDialog::onFilterByStatus() {
|
|
QString keyword = statusFilterEdit_->text();
|
|
if (keyword.isEmpty()) {
|
|
loadPaymentRecords();
|
|
return;
|
|
}
|
|
|
|
paymentTable_->setRowCount(0);
|
|
int row = 0;
|
|
std::string keywordStd = keyword.toStdString();
|
|
|
|
// 使用 getAllPayments 并匹配所有字段
|
|
core_.paymentManagementService.getAllPayments([&](const Payment& payment) {
|
|
// 检查所有字段是否包含关键词
|
|
bool matches = false;
|
|
|
|
// 检查支付ID
|
|
if (payment.PaymentID.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查患者ID
|
|
else if (payment.PatientID.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查患者姓名
|
|
else {
|
|
const Patient* patient = core_.patientService.findPatient(payment.PatientID);
|
|
if (patient && patient->Name.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查金额
|
|
else if (std::to_string(payment.Amount).find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查支付方式
|
|
else if (payment.getMethodString().find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查支付类型
|
|
else if (payment.PaymentType.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查状态
|
|
else if (payment.Status.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
// 检查描述
|
|
else if (payment.Description.find(keywordStd) != std::string::npos) {
|
|
matches = true;
|
|
}
|
|
}
|
|
|
|
if (matches) {
|
|
paymentTable_->insertRow(row);
|
|
|
|
paymentTable_->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(payment.PaymentID)));
|
|
paymentTable_->setItem(row, 1, new QTableWidgetItem(QString::fromStdString(payment.PatientID)));
|
|
|
|
// 获取患者姓名
|
|
const Patient* patient = core_.patientService.findPatient(payment.PatientID);
|
|
QString patientName = patient ? QString::fromStdString(patient->Name) : "未知患者";
|
|
paymentTable_->setItem(row, 2, new QTableWidgetItem(patientName));
|
|
|
|
paymentTable_->setItem(row, 3, new QTableWidgetItem(QString::number(payment.Amount, 'f', 2)));
|
|
paymentTable_->setItem(row, 4, new QTableWidgetItem(QString::fromStdString(payment.getMethodString())));
|
|
paymentTable_->setItem(row, 5, new QTableWidgetItem(QString::fromStdString(payment.PaymentType)));
|
|
paymentTable_->setItem(row, 6, new QTableWidgetItem(QString::number(payment.PaymentTime)));
|
|
paymentTable_->setItem(row, 7, new QTableWidgetItem(QString::fromStdString(payment.Status)));
|
|
paymentTable_->setItem(row, 8, new QTableWidgetItem(QString::fromStdString(payment.Description)));
|
|
|
|
row++;
|
|
}
|
|
});
|
|
}
|
|
|
|
void PaymentManagementDialog::onTabChanged(int index) {
|
|
if (index == 1) {
|
|
loadSettlementRecords();
|
|
}
|
|
}
|
|
|
|
void PaymentManagementDialog::onGenerateDailyReport() {
|
|
auto report = core_.paymentManagementService.generateDailyReport("Today");
|
|
displayStatistics("每日报表", QString::fromStdString(report));
|
|
}
|
|
|
|
void PaymentManagementDialog::onGenerateMonthlyReport() {
|
|
auto report = core_.paymentManagementService.generateMonthlyReport("This Month");
|
|
displayStatistics("月报表", QString::fromStdString(report));
|
|
}
|
|
|
|
void PaymentManagementDialog::onGenerateRevenueReport() {
|
|
auto report = core_.paymentManagementService.generateRevenueReport();
|
|
displayStatistics("收入总报表", QString::fromStdString(report));
|
|
}
|
|
|
|
void PaymentManagementDialog::displayStatistics(const QString& title, const QString& content) {
|
|
QMessageBox msgBox(this);
|
|
msgBox.setWindowTitle(title);
|
|
msgBox.setText(content);
|
|
msgBox.setTextFormat(Qt::PlainText);
|
|
msgBox.exec();
|
|
}
|