diff --git a/package/components/NetworkPopup.qml b/package/components/NetworkPopup.qml index abf1a7f..e1d3286 100644 --- a/package/components/NetworkPopup.qml +++ b/package/components/NetworkPopup.qml @@ -43,6 +43,14 @@ Control { readonly property string ipv6Address: applet ? (applet.ipv6Address || "") : "" readonly property var networkInterfaces: applet ? (applet.networkInterfaces || []) : [] + // 活动接口的收发包/错误/丢包累计统计(自开机起),由 C++ 后端持续更新 + readonly property real rxPackets: applet ? (applet.rxPackets || 0) : 0 + readonly property real txPackets: applet ? (applet.txPackets || 0) : 0 + readonly property real rxErrors: applet ? (applet.rxErrors || 0) : 0 + readonly property real txErrors: applet ? (applet.txErrors || 0) : 0 + readonly property real rxDropped: applet ? (applet.rxDropped || 0) : 0 + readonly property real txDropped: applet ? (applet.txDropped || 0) : 0 + // 用户自定义字体色:非空时覆盖 primaryText,空串回退 DTK 调色板派生 // 仅作用于主要文字(接口名、速度数值、累计数值、chip 未选中文字) // secondaryText/tertiaryText/强调色不跟随,保持系统主题层次不崩 @@ -292,6 +300,38 @@ Control { } } + // 包统计:收发包 + 错误/丢包(累计值,自开机起) + // 设计原因:包总数始终显示;错误/丢包仅在存在时显示,避免正常网卡信息过载; + // 箭头遵循应用惯例:↓=接收(rx)、↑=发送(tx),与弹窗速度区/累计区一致 + RowLayout { + Layout.alignment: Qt.AlignHCenter + spacing: 6 + visible: popup.ready + + // 收发包总数:始终显示,格式 "包 {rx}↓ {tx}↑" + Text { + text: "包 " + popup.rxPackets.toFixed(0) + "↓ " + popup.txPackets.toFixed(0) + "↑" + font.pixelSize: Math.round(12 * popup.fontScale) + color: popup.tertiaryText + } + + // 错误数:仅在存在错误或丢包时显示,格式 "错误 {rxE}/{txE}" + Text { + text: "错误 " + popup.rxErrors.toFixed(0) + "/" + popup.txErrors.toFixed(0) + font.pixelSize: Math.round(12 * popup.fontScale) + color: popup.tertiaryText + visible: popup.rxErrors > 0 || popup.txErrors > 0 || popup.rxDropped > 0 || popup.txDropped > 0 + } + + // 丢包数:仅在存在错误或丢包时显示,格式 "丢包 {rxD}/{txD}" + Text { + text: "丢包 " + popup.rxDropped.toFixed(0) + "/" + popup.txDropped.toFixed(0) + font.pixelSize: Math.round(12 * popup.fontScale) + color: popup.tertiaryText + visible: popup.rxErrors > 0 || popup.txErrors > 0 || popup.rxDropped > 0 || popup.txDropped > 0 + } + } + // 分隔线1 Rectangle { Layout.fillWidth: true diff --git a/src/networkmonitorapplet.cpp b/src/networkmonitorapplet.cpp index a17feda..ec9b59d 100644 --- a/src/networkmonitorapplet.cpp +++ b/src/networkmonitorapplet.cpp @@ -30,6 +30,12 @@ NetworkMonitorApplet::NetworkMonitorApplet(QObject *parent) , m_uploadSpeed(0) , m_totalDownload(0) , m_totalUpload(0) + , m_rxPackets(0) + , m_txPackets(0) + , m_rxErrors(0) + , m_txErrors(0) + , m_rxDropped(0) + , m_txDropped(0) , m_ipDetectCounter(4) , m_ready(false) , m_firstUpdate(true) @@ -141,6 +147,15 @@ QString NetworkMonitorApplet::ipv6Address() const return m_ipv6Address; } +// ---- 活动接口包统计 getter(累计值,自开机起)---- +// 供弹窗接口信息区展示收发包/错误/丢包数 +quint64 NetworkMonitorApplet::rxPackets() const { return m_rxPackets; } +quint64 NetworkMonitorApplet::txPackets() const { return m_txPackets; } +quint64 NetworkMonitorApplet::rxErrors() const { return m_rxErrors; } +quint64 NetworkMonitorApplet::txErrors() const { return m_txErrors; } +quint64 NetworkMonitorApplet::rxDropped() const { return m_rxDropped; } +quint64 NetworkMonitorApplet::txDropped() const { return m_txDropped; } + // 返回插件版本号,从 dde-shell 插件元数据(metadata.json)读取 // 版本唯一源为 CMakeLists.txt 的 project(VERSION),经 configure_file 写入 metadata.json, // dde-shell 加载时存入 DPluginMetaData,此处通过继承自 DApplet 的 pluginMetaData() 读取 @@ -253,6 +268,16 @@ void NetworkMonitorApplet::setActiveInterface(const QString &interface) // 接口切换后历史数据变化,标记脏缓存让趋势图立即重建 m_historyDirty = true; + // 接口切换后包统计指向新接口,旧值不再有效,重置并通知 QML + // 设计原因:包统计为各接口独立的累计值,切换后应显示新接口的数据 + m_rxPackets = 0; + m_txPackets = 0; + m_rxErrors = 0; + m_txErrors = 0; + m_rxDropped = 0; + m_txDropped = 0; + emit packetStatsChanged(); + // 持久化到配置文件,下次启动自动加载用户选择的网卡 // 设计原因:弹窗 chip 和设置窗口都调用此方法,统一持久化保证两处选择一致 const QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) @@ -419,6 +444,26 @@ void NetworkMonitorApplet::calculateSpeed() m_lastTxBytes = currentTxBytes; } + // ---- 活动接口包统计(累计值,自开机起)---- + // 直接从当前活动接口读取收发包/错误/丢包计数,任一值变化时发射 packetStatsChanged + if (!m_activeInterface.isEmpty() && m_interfaces.contains(m_activeInterface)) { + const NetworkInterface &iface = m_interfaces[m_activeInterface]; + if (m_rxPackets != static_cast(iface.rxPackets) + || m_txPackets != static_cast(iface.txPackets) + || m_rxErrors != static_cast(iface.rxErrors) + || m_txErrors != static_cast(iface.txErrors) + || m_rxDropped != static_cast(iface.rxDropped) + || m_txDropped != static_cast(iface.txDropped)) { + m_rxPackets = static_cast(iface.rxPackets); + m_txPackets = static_cast(iface.txPackets); + m_rxErrors = static_cast(iface.rxErrors); + m_txErrors = static_cast(iface.txErrors); + m_rxDropped = static_cast(iface.rxDropped); + m_txDropped = static_cast(iface.txDropped); + emit packetStatsChanged(); + } + } + // ---- 为所有接口采集速度历史(非仅活动接口)---- // 设计原因:原仅采集活动接口,切换到非活动接口时趋势图为空需等待数分钟。 // 改为遍历所有接口计算各自速度并追加历史,切换接口时趋势图立即有数据。 diff --git a/src/networkmonitorapplet.h b/src/networkmonitorapplet.h index e8562b0..7f216c2 100644 --- a/src/networkmonitorapplet.h +++ b/src/networkmonitorapplet.h @@ -57,6 +57,14 @@ class NetworkMonitorApplet : public DApplet Q_PROPERTY(QString ipAddress READ ipAddress NOTIFY ipAddressChanged) // 活动接口的 IPv6 全球地址(已过滤 link-local 和 loopback),供 QML 显示 Q_PROPERTY(QString ipv6Address READ ipv6Address NOTIFY ipv6AddressChanged) + // 活动接口的收发包/错误/丢包累计统计(自开机起累计值),供弹窗接口信息区展示 + // 全部用 quint64 类型,QML 侧可直接读取;任一值变化时统一发射 packetStatsChanged + Q_PROPERTY(quint64 rxPackets READ rxPackets NOTIFY packetStatsChanged) + Q_PROPERTY(quint64 txPackets READ txPackets NOTIFY packetStatsChanged) + Q_PROPERTY(quint64 rxErrors READ rxErrors NOTIFY packetStatsChanged) + Q_PROPERTY(quint64 txErrors READ txErrors NOTIFY packetStatsChanged) + Q_PROPERTY(quint64 rxDropped READ rxDropped NOTIFY packetStatsChanged) + Q_PROPERTY(quint64 txDropped READ txDropped NOTIFY packetStatsChanged) // 插件版本号,从 dde-shell 元数据读取,版本唯一源为 CMakeLists.txt project(VERSION) Q_PROPERTY(QString version READ version CONSTANT) // 任务栏网速数值字体颜色,空串表示跟随系统主题(由 QML 回退到 primaryText), @@ -84,6 +92,13 @@ public: QString activeInterface() const; QString ipAddress() const; QString ipv6Address() const; + // 返回活动接口的收发包/错误/丢包累计值(自开机起),供弹窗接口信息区展示 + quint64 rxPackets() const; + quint64 txPackets() const; + quint64 rxErrors() const; + quint64 txErrors() const; + quint64 rxDropped() const; + quint64 txDropped() const; // 返回当前活动接口的下行速度历史(QPointF 列表),供 QML 趋势图绘制 QVariantList speedHistoryDownload() const; // 返回当前活动接口的上行速度历史(QPointF 列表),供 QML 趋势图绘制 @@ -108,6 +123,8 @@ signals: void activeInterfaceChanged(); void ipAddressChanged(); void ipv6AddressChanged(); + // 活动接口包统计(收发包/错误/丢包)变化时通知 QML 更新 + void packetStatsChanged(); void speedHistoryChanged(); // 任务栏网速字体颜色变化时通知 QML 更新 void textColorChanged(); @@ -148,6 +165,15 @@ private: qint64 m_totalDownload; qint64 m_totalUpload; + // 活动接口包统计缓存(自开机起累计值),供弹窗接口信息区展示 + // 设计原因:/proc/net/dev 已解析包计数但此前直接丢弃,现缓存并暴露给 QML + quint64 m_rxPackets; + quint64 m_txPackets; + quint64 m_rxErrors; + quint64 m_txErrors; + quint64 m_rxDropped; + quint64 m_txDropped; + // IP 地址检测降频计数器:IP 变化频率极低,每 5 次 refresh 才检测一次 // 初始化 4 使首次 refresh 立即检测,避免启动后 IP 显示延迟 int m_ipDetectCounter;