Update 更新文档

This commit is contained in:
2026-02-25 23:01:42 +08:00
parent 40aff32fb0
commit 80518309a7
679 changed files with 4611263 additions and 0 deletions

View File

@@ -0,0 +1,285 @@
#include "qbigorderviewer.h"
#include "qbigordermanager.h"
#include "qhistoryorderdialog.h"
#include <QHeaderView>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QFileDialog>
#include <QTextStream>
#include <QLineEdit>
#include <QComboBox>
#include <QTableView>
#include <QPushButton>
#include <QWidget>
#include <QCheckBox>
QBigOrderViewer::QBigOrderViewer(QWidget *parent)
: QWidget(parent),
m_model(new QStandardItemModel(0, 8, this)),
m_proxyModel(new QSortFilterProxyModel(this)),
m_typeDelegate(new OrderTypeDelegate(this)),
m_lastOrderDelegate(new HighlightDelegate(this))
{
initUI();
initConnections();
QBigOrderManager* manager = QBigOrderManager::instance();
connect(manager, &QBigOrderManager::bigOrderAdded,
this, &QBigOrderViewer::onBigOrderAdded);
connect(manager, &QBigOrderManager::saveOverRefreshView,
this, [this]() {
m_model->removeRows(0, m_model->rowCount());
}, Qt::QueuedConnection
);
}
QBigOrderViewer::~QBigOrderViewer()
{
delete m_model;
delete m_proxyModel;
delete m_typeDelegate;
}
void QBigOrderViewer::initUI()
{
QVBoxLayout *mainLayout = new QVBoxLayout(this);
QHBoxLayout *filterLayout = new QHBoxLayout();
QCheckBox *cboAutoSave = new QCheckBox("自动保存数据");
cboAutoSave->setChecked(true);
filterLayout->addWidget(cboAutoSave);
filterLayout->addWidget(new QLabel("股票代码:"));
m_stockCodeFilter = new QLineEdit();
m_stockCodeFilter->setPlaceholderText("支持模糊搜索");
filterLayout->addWidget(m_stockCodeFilter);
filterLayout->addWidget(new QLabel("订单类型:"));
m_orderTypeFilter = new QComboBox();
m_orderTypeFilter->addItem("全部", "");
m_orderTypeFilter->addItem("买入", "BID");
m_orderTypeFilter->addItem("卖出", "ASK");
filterLayout->addWidget(m_orderTypeFilter);
filterLayout->addStretch();
QPushButton *historyButton = new QPushButton("历史查询");
filterLayout->addWidget(historyButton);
m_exportButton = new QPushButton("导出数据");
filterLayout->addWidget(m_exportButton);
mainLayout->addLayout(filterLayout);
m_tableView = new QTableView();
m_proxyModel->setSourceModel(m_model);
m_tableView->setModel(m_proxyModel);
m_tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
QStringList headers;
headers << "股票代码" << "股票名称" << "订单类型"
<< "股票数量" << "股票价格" << "订单档位"
<< "时间"<< "Timestamp";
m_model->setHorizontalHeaderLabels(headers);
m_tableView->setColumnHidden(7, true);
for (int col = 0; col < m_model->columnCount(); ++col) {
m_model->setHeaderData(col, Qt::Horizontal, Qt::AlignCenter, Qt::TextAlignmentRole);
}
m_tableView->setItemDelegateForColumn(2, m_typeDelegate);
m_tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
m_tableView->setSortingEnabled(true);
m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
m_tableView->setItemDelegate(m_lastOrderDelegate);
const int timeColumnIndex = 6;
m_proxyModel->sort(timeColumnIndex, Qt::DescendingOrder);
mainLayout->addWidget(m_tableView);
connect(historyButton, &QPushButton::clicked, this, [this] {
QHistoryOrderDialog *dialog = new QHistoryOrderDialog(this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
dialog->show();
});
connect(cboAutoSave, &QCheckBox::stateChanged, [](int state) {
if (state == Qt::Checked) {
QBigOrderManager::instance()->setAutoSave(true);
}
else if (state == Qt::Unchecked) {
QBigOrderManager::instance()->setAutoSave(false);
}
});
}
void QBigOrderViewer::initConnections()
{
connect(m_stockCodeFilter, &QLineEdit::textChanged,
this, &QBigOrderViewer::onFilterChanged);
connect(m_orderTypeFilter, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &QBigOrderViewer::onFilterChanged);
connect(m_exportButton, &QPushButton::clicked,
this, &QBigOrderViewer::onExportClicked);
connect(m_tableView->horizontalHeader(), &QHeaderView::sectionClicked,
[this](int logicalIndex) {
Qt::SortOrder currentOrder = m_proxyModel->sortOrder();
m_proxyModel->sort(logicalIndex,
currentOrder == Qt::AscendingOrder
? Qt::AscendingOrder
: Qt::DescendingOrder);
});
QObject::connect(m_tableView->selectionModel(), &QItemSelectionModel::selectionChanged,
[&](const QItemSelection &selected, const QItemSelection &deselected) {
Q_UNUSED(deselected);
QModelIndexList selectedIndexes = m_tableView->selectionModel()->selectedIndexes();
if (selectedIndexes.isEmpty()) {
return;
}
emit sendStockCodeToMainForm(m_proxyModel->index(selectedIndexes.at(0).row(), selectedIndexes.at(0).column()).data().toString());
});
}
void QBigOrderViewer::updateView()
{
m_model->removeRows(0, m_model->rowCount());
for (const auto& order : m_currentOrders) {
QList<QStandardItem*> rowItems;
QStandardItem* codeItem = new QStandardItem(order->code);
codeItem->setTextAlignment(Qt::AlignCenter);
rowItems << codeItem;
QStandardItem* nameItem = new QStandardItem(order->name);
nameItem->setTextAlignment(Qt::AlignCenter);
rowItems << nameItem;
int nType = order->nBigOrderType;
QStandardItem* typeItem = new QStandardItem(nType ? "多单" : "空单");
typeItem->setTextAlignment(Qt::AlignCenter);
rowItems << typeItem;
QStandardItem* volumeItem = new QStandardItem(QString::number(std::fabs(order->volume / 1000)) + "K");
volumeItem->setTextAlignment(Qt::AlignCenter);
rowItems << volumeItem;
QStandardItem* priceItem = new QStandardItem(QString::number(order->price, 'f', 2));
priceItem->setTextAlignment(Qt::AlignCenter);
rowItems << priceItem;
QStandardItem* levelItem = new QStandardItem(QString::number(order->level));
levelItem->setTextAlignment(Qt::AlignCenter);
rowItems << levelItem;
QString str = order->svrRecvTime.mid(11);
if (str == nullptr)
{
QDateTime dateTime = QDateTime::currentDateTime();
str = dateTime.toString("hh:mm:ss");
}
QStandardItem* timeItem = new QStandardItem(str);
timeItem->setTextAlignment(Qt::AlignCenter);
rowItems << timeItem;
QStandardItem* timestampItem = new QStandardItem(order->svrRecvTime);
timestampItem->setTextAlignment(Qt::AlignCenter);
rowItems << timestampItem;
m_model->appendRow(rowItems);
}
}
void QBigOrderViewer::applyFilters()
{
QString stockCode = m_stockCodeFilter->text().trimmed();
QString orderType = m_orderTypeFilter->currentData().toString();
m_currentOrders.clear();
for (const auto& order : m_allOrders) {
bool match = true;
if (!stockCode.isEmpty() && !order->code.contains(stockCode, Qt::CaseInsensitive)) {
match = false;
}
if (!orderType.isEmpty() && order->nBigOrderType != orderType) {
match = false;
}
if (match) m_currentOrders.append(order);
}
}
void QBigOrderViewer::onBigOrderAdded(const BigOrderInfo &order)
{
auto newOrder = QSharedPointer<BigOrderInfo>::create(order);
m_allOrders.append(newOrder);
if (matchesFilter(newOrder)) {
m_currentOrders.append(newOrder);
int row = 0 ;
m_model->insertRow(row);
setRowData(row, newOrder);
QString orderId = QString("%1_%2_%3")
.arg(order.code)
.arg(QString::number(order.price, 'f', 2))
.arg(QDateTime::currentMSecsSinceEpoch());
for (int col = 0; col < m_model->columnCount(); ++col) {
QModelIndex index = m_model->index(row, col);
m_model->setData(index, true, IsHighlightedRole);
m_model->setData(index, orderId, Qt::UserRole + 102);
}
QModelIndex topLeft = m_model->index(row, 0);
QModelIndex bottomRight = m_model->index(row, m_model->columnCount() - 1);
emit m_model->dataChanged(topLeft, bottomRight);
QTimer::singleShot(2000, this, [this, orderId]() {
for (int row = 0; row < m_model->rowCount(); ++row) {
QModelIndex index = m_model->index(row, 0);
m_model->setData(index, false, IsHighlightedRole);
QString currentOrderId = index.data(Qt::UserRole + 102).toString();
if (currentOrderId == orderId) {
for (int col = 0; col < m_model->columnCount(); ++col) {
QModelIndex cellIndex = m_model->index(row, col);
m_model->setData(cellIndex, false, IsHighlightedRole);
}
QModelIndex topLeft = m_model->index(row, 0);
QModelIndex bottomRight = m_model->index(row, m_model->columnCount() - 1);
emit m_model->dataChanged(topLeft, bottomRight);
break;
}
}
});
m_proxyModel->sort(6, Qt::DescendingOrder);
}
}
void QBigOrderViewer::setRowData(int row, QSharedPointer<BigOrderInfo> order)
{
m_model->setData(m_model->index(row, 0), order->code);
m_model->setData(m_model->index(row, 1), order->name);
m_model->setData(m_model->index(row, 2),
order->nBigOrderType == 0 ? "卖出" : "买入");
m_model->setData(m_model->index(row, 3),
QString::number(std::fabs(order->volume / 1000)) + "K");
m_model->setData(m_model->index(row, 4),
QString::number(order->price, 'f', 2));
m_model->setData(m_model->index(row, 5),
QString::number(order->level));
QString timeStr;
if (order->svrRecvTime.length() >= 11) {
timeStr = order->svrRecvTime.mid(11);
}
else {
QDateTime dateTime = QDateTime::currentDateTime();
timeStr = dateTime.toString("hh:mm:ss");
}
m_model->setData(m_model->index(row, 6), timeStr);
m_model->setData(m_model->index(row, 7), order->svrRecvTime);
QDateTime fullDateTime;
if (order->svrRecvTime.length() >= 19) {
fullDateTime = QDateTime::fromString(order->svrRecvTime.left(19), "yyyy-MM-dd hh:mm:ss");
}
else {
fullDateTime = QDateTime::currentDateTime();
}
m_model->setData(m_model->index(row, 6), fullDateTime, Qt::UserRole + 101);
}
bool QBigOrderViewer::matchesFilter(QSharedPointer<BigOrderInfo> order)
{
QString stockCode = m_stockCodeFilter->text().trimmed();
QString orderType = m_orderTypeFilter->currentData().toString();
return (stockCode.isEmpty() || order->code.contains(stockCode, Qt::CaseInsensitive))
&& (orderType.isEmpty() || order->nBigOrderType == orderType);
}
void QBigOrderViewer::onFilterChanged()
{
applyFilters();
updateView();
}
void QBigOrderViewer::onExportClicked()
{
QString fileName = QFileDialog::getSaveFileName(this, "导出CSV", "", "CSV文件 (*.csv)");
if (fileName.isEmpty()) return;
QFile file(fileName);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return;
QTextStream out(&file);
out.setCodec("GBK");
for (int col = 0; col < m_model->columnCount(); ++col) {
out << m_model->headerData(col, Qt::Horizontal).toString();
if (col < m_model->columnCount() - 1) out << ",";
}
out << "\n";
for (int row = 0; row < m_proxyModel->rowCount(); ++row) {
for (int col = 0; col < m_proxyModel->columnCount(); ++col) {
out << m_proxyModel->index(row, col).data().toString();
if (col < m_proxyModel->columnCount() - 1) out << ",";
}
out << "\n";
}
file.close();
}