#include "washbase.h" #include "titlebar.h" #include "alarmbanner.h" #include "datacard.h" #include "ledindicator.h" #include "car.h" #include "confirmdialog.h" #include #include #include #include #include "global.h" WashBasePage::WashBasePage(AppContext* ctx, const QString& title, const QString& washTitle, QWidget* parent) : BasePage(ctx, parent) { QVBoxLayout* root = new QVBoxLayout(this); root->setContentsMargins(0, 0, 0, 0); root->setSpacing(0); m_titleBar = new TitleBar(ctx, this); m_titleBar->setTitle(title); root->addWidget(m_titleBar); m_banner = new AlarmBanner(this); root->addWidget(m_banner); QHBoxLayout* main = new QHBoxLayout(); main->setContentsMargins(36, 16, 36, 16); main->setSpacing(28); // 左侧状态卡(底盘/机械臂/气体检测仪) QWidget* left = new QWidget(this); QVBoxLayout* leftLay = new QVBoxLayout(left); leftLay->setContentsMargins(0, 0, 0, 0); leftLay->setSpacing(10); m_chassisCard = new DataCard("底盘", left); m_chassisCard->addField("电量", "85%"); m_chassisCard->addField("电压", "360V"); m_chassisCard->addField("故障", "无"); m_armCard = new DataCard("机械臂", left); m_armCard->addField("末端位置", "XYZ"); m_armCard->addField("姿态", "RX/RY/RZ"); m_gasCard = new DataCard("气体检测仪", left); m_gasCard->addField("主机状态", "待机"); m_gasCard->addField("浓度", "0 ppb"); leftLay->addWidget(m_chassisCard, 1); leftLay->addWidget(m_armCard, 1); leftLay->addWidget(m_gasCard, 1); left->setFixedWidth(280); main->addWidget(left); // 中央洗消卡 m_washCard = new DataCard(washTitle, this); m_fMode = m_washCard->addField("洗消模式", "--"); m_fLevelA = m_washCard->addField("A组分液位", "100L"); m_fLevelFoam = m_washCard->addField("泡沫箱液位", "30L"); m_fFlowA = m_washCard->addField("A药剂流量", "0 L/min"); m_fFlowB = m_washCard->addField("B药剂流量", "0 L/min"); m_fGasFlow = m_washCard->addField("气体流量", "0 L/min"); m_fPress = m_washCard->addField("管路压力", "0 MPa"); m_fAirPress = m_washCard->addField("空压机压力", "0 MPa"); m_fFoam = m_washCard->addField("发泡倍数", "0"); m_fAirFault = m_washCard->addField("空压机故障代码", ""); m_fPlungerFault = m_washCard->addField("柱塞泵故障代码", ""); m_washCard->indentRows(); // 行文字缩进到中间偏左(卡片很宽,贴左缘会显得空) main->addWidget(m_washCard, 1); // 右侧操作列 QWidget* right = new QWidget(this); QVBoxLayout* rightLay = new QVBoxLayout(right); rightLay->setContentsMargins(0, 0, 0, 0); rightLay->setSpacing(10); m_start = button("启动", "primary", right); m_start->setFixedSize(354, 112); connect(m_start, &QPushButton::clicked, this, &WashBasePage::onStart); m_stop = button("停止", "danger", right); m_stop->setFixedSize(354, 112); connect(m_stop, &QPushButton::clicked, this, &WashBasePage::onStop); rightLay->addWidget(m_start); rightLay->addWidget(m_stop); // 参数区(子类填充) m_paramsLayout = new QVBoxLayout(); m_paramsLayout->setSpacing(8); rightLay->addLayout(m_paramsLayout); rightLay->addStretch(1); right->setFixedWidth(380); main->addWidget(right); root->addLayout(main, 1); // 底部指示灯条 QWidget* bottom = new QWidget(this); bottom->setFixedHeight(94); bottom->setStyleSheet(QString("background-color:%1;border-top:1px solid %2;") .arg(C::PANEL, C::BORDER)); QHBoxLayout* bottomLay = new QHBoxLayout(bottom); bottomLay->setContentsMargins(24, 0, 24, 0); bottomLay->setSpacing(18); m_factory = button("恢复出厂值", "", bottom); m_factory->setFixedSize(220, 64); m_factory->setStyleSheet(cancelButtonStyle(40)); // 选中(悬停/按下/焦点)红底白字 connect(m_factory, &QPushButton::clicked, this, &WashBasePage::onFactory); bottomLay->addWidget(m_factory); bottomLay->addSpacing(20); m_ledRun = new LedIndicator("启停", bottom); m_ledPlunger = new LedIndicator("柱塞泵", bottom); m_ledAir = new LedIndicator("空压机", bottom); m_ledLeaf = new LedIndicator("叶片泵", bottom); m_ledLevel = new LedIndicator("液位低", bottom); m_ledD1 = new LedIndicator("D1", bottom); m_ledD2 = new LedIndicator("D2", bottom); m_ledFault = new LedIndicator("系统故障", bottom); bottomLay->addWidget(m_ledRun); bottomLay->addWidget(m_ledPlunger); bottomLay->addWidget(m_ledAir); bottomLay->addWidget(m_ledLeaf); bottomLay->addWidget(m_ledLevel); bottomLay->addWidget(m_ledD1); bottomLay->addWidget(m_ledD2); bottomLay->addWidget(m_ledFault); bottomLay->addStretch(1); m_back = button("返回", "", bottom); m_back->setFixedSize(144, 76); m_back->setStyleSheet(cancelButtonStyle(40)); // 选中(悬停/按下/焦点)红底白字 connect(m_back, &QPushButton::clicked, this, &WashBasePage::onBack); bottomLay->addWidget(m_back); root->addWidget(bottom); // 故障代码轮流循环显示(2s/条) m_faultTimer = new QTimer(this); m_faultTimer->setInterval(2000); connect(m_faultTimer, &QTimer::timeout, this, &WashBasePage::rotateFaults); m_faultTimer->start(); connect(ctx->comm(), &CarCommunication::telemetryUpdated, this, &WashBasePage::refresh); updateGating(); refresh(); } void WashBasePage::onStart() { ctx()->comm()->sendWashStart(washModeTag()); ctx()->washRunning = true; updateGating(); onWashStateChanged(true); } void WashBasePage::onStop() { ctx()->comm()->sendWashStop(); ctx()->washRunning = false; updateGating(); onWashStateChanged(false); } void WashBasePage::onBack() { if (ctx()->washRunning) { ConfirmDialog::toast(this, "请先停止"); return; } emit navigate(PageJob); } void WashBasePage::onFactory() { if (ConfirmDialog::confirm(this, "恢复出厂值", "确定将参数恢复为出厂值?")) resetFactory(); } void WashBasePage::updateGating() { bool running = ctx()->washRunning; m_start->setEnabled(!running); m_stop->setEnabled(running); m_back->setEnabled(!running); } void WashBasePage::refresh() { const Telemetry& t = ctx()->telemetry; if (!t.commOk) m_banner->showAlarm("通信异常"); else m_banner->clear(); // 以泵状态同步运行状态 if (t.plunger || t.air || t.leaf) ctx()->washRunning = true; else if (t.washMode == "--") ctx()->washRunning = false; updateGating(); m_chassisCard->setField(0, QString("%1%").arg(t.soc)); m_chassisCard->setField(1, QString("%1V").arg(t.volt, 0, 'f', 0)); m_chassisCard->setField(2, t.chassisFaults.isEmpty() ? "无" : t.chassisFaults.join(";")); m_armCard->setField(0, t.pos); m_armCard->setField(1, t.pose); m_gasCard->setField(0, t.gasHost == "detecting" ? "检测中" : (t.gasHost == "fault" ? "故障" : "待机")); m_gasCard->setField(1, QString("%1 ppb").arg(t.gasConc, 0, 'f', 0)); m_washCard->setField(m_fMode, t.washMode); m_washCard->setField(m_fLevelA, QString("%1L").arg(t.levelA, 0, 'f', 0)); m_washCard->setField(m_fLevelFoam, QString("%1L").arg(t.levelFoam, 0, 'f', 0)); m_washCard->setField(m_fFlowA, QString("%1 L/min").arg(t.flowA, 0, 'f', 1)); m_washCard->setField(m_fFlowB, QString("%1 L/min").arg(t.flowB, 0, 'f', 1)); m_washCard->setField(m_fGasFlow, QString("%1 L/min").arg(t.gasFlow, 0, 'f', 1)); m_washCard->setField(m_fPress, QString("%1 MPa").arg(t.press, 0, 'f', 2)); m_washCard->setField(m_fAirPress, QString("%1 MPa").arg(t.airPress, 0, 'f', 2)); m_washCard->setField(m_fFoam, QString("%1").arg(t.foam, 0, 'f', 1)); // 指示灯 m_ledRun->setState(ctx()->washRunning ? LedIndicator::Green : LedIndicator::Off); m_ledPlunger->setState(t.plunger ? LedIndicator::Green : LedIndicator::Off); m_ledAir->setState(t.air ? LedIndicator::Green : LedIndicator::Off); m_ledLeaf->setState(t.leaf ? LedIndicator::Green : LedIndicator::Off); m_ledLevel->setState(t.levelA < 10 ? LedIndicator::RedBlink : LedIndicator::Off); m_ledD1->setState(t.d1open ? LedIndicator::Green : LedIndicator::Off); m_ledD2->setState(t.d2open ? LedIndicator::Green : LedIndicator::Off); m_ledFault->setState((!t.washFaults.isEmpty() || !t.pumpFaults.isEmpty()) ? LedIndicator::RedBlink : LedIndicator::Off); // 故障代码显示(静态更新,循环由 rotateFaults 驱动) rotateFaults(); } void WashBasePage::rotateFaults() { const Telemetry& t = ctx()->telemetry; QStringList all = t.washFaults + t.pumpFaults; if (all.isEmpty()) { m_washCard->setField(m_fAirFault, ""); m_washCard->setField(m_fPlungerFault, ""); return; } m_faultIndex = m_faultIndex % all.size(); QString code = all[m_faultIndex]; m_washCard->setField(m_fAirFault, code); m_washCard->setField(m_fPlungerFault, code); m_faultIndex = (m_faultIndex + 1) % all.size(); }