import QtQuick 2.12 import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 Item { id: page readonly property color fg: "#ffffff" readonly property color muted: "#aaaaaa" readonly property color rowBg: "#222236" readonly property color headerBg: "#2a2a40" ColumnLayout { anchors.fill: parent anchors.margins: 4 spacing: 6 Text { Layout.fillWidth: true text: "Датчики BLE" + (sensorsBridge.poolFull ? " · пул заполнен" : "") color: page.fg font.pixelSize: 16 font.bold: true } RowLayout { Layout.fillWidth: true spacing: 6 Text { text: "Интервал, мин" color: page.muted font.pixelSize: 12 } TextField { id: intervalField Layout.preferredWidth: 72 inputMethodHints: Qt.ImhDigitsOnly color: page.fg font.pixelSize: 13 Component.onCompleted: text = String(sensorsBridge.reportIntervalMin) background: Rectangle { color: "#1a1a28" border.color: "#555570" radius: 2 } } Connections { target: sensorsBridge onChanged: { // Не затирать поле, пока пользователь печатает. if (!intervalField.activeFocus) intervalField.text = String(sensorsBridge.reportIntervalMin) } } Button { text: "Сохранить" Layout.preferredHeight: 32 onClicked: { var v = parseInt(intervalField.text, 10) if (isNaN(v) || v < 1) v = 1 if (v > 65535) v = 65535 if (!sensorsBridge.saveReportIntervalMin(v)) console.warn("save interval failed") } background: Rectangle { radius: 3 color: parent.down ? "#3a3a58" : "#2a2a40" border.color: "#555570" } contentItem: Text { text: parent.text color: page.fg horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 12 } } Item { Layout.fillWidth: true } } // Table header Rectangle { Layout.fillWidth: true Layout.preferredHeight: 28 color: page.headerBg radius: 2 RowLayout { anchors.fill: parent anchors.leftMargin: 4 anchors.rightMargin: 4 spacing: 2 Text { Layout.preferredWidth: parent.width * 0.18; text: "Имя"; color: page.muted; font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.26; text: "MAC"; color: page.muted; font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.12; text: "Аккум."; color: page.muted; font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.18; text: "Показание"; color: page.muted; font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.12; text: "RSSI"; color: page.muted; font.pixelSize: 11 } Text { Layout.fillWidth: true; text: "Давно"; color: page.muted; font.pixelSize: 11 } } } ListView { id: table Layout.fillWidth: true Layout.preferredHeight: Math.min(160, contentHeight + 4) clip: true model: sensorsBridge.sensorSlots spacing: 2 delegate: Rectangle { width: table.width height: 28 color: page.rowBg radius: 2 opacity: modelData.empty ? 0.45 : 1.0 RowLayout { anchors.fill: parent anchors.leftMargin: 4 anchors.rightMargin: 4 spacing: 2 Text { Layout.preferredWidth: parent.width * 0.18 text: modelData.empty ? ("слот " + modelData.slot) : (modelData.name || "—") color: page.fg font.pixelSize: 11 elide: Text.ElideRight } Text { Layout.preferredWidth: parent.width * 0.26 text: modelData.empty ? "—" : modelData.mac color: page.fg font.pixelSize: 11 elide: Text.ElideRight } Text { Layout.preferredWidth: parent.width * 0.12 text: modelData.empty ? "—" : modelData.battery color: page.fg font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.18 text: modelData.empty ? "—" : modelData.reading color: page.fg font.pixelSize: 11 } Text { Layout.preferredWidth: parent.width * 0.12 text: modelData.empty ? "—" : modelData.rssi color: page.fg font.pixelSize: 11 } Text { Layout.fillWidth: true text: modelData.empty ? "—" : modelData.age color: page.fg font.pixelSize: 11 } } } Text { anchors.centerIn: parent visible: table.count === 0 text: "Нет данных коллектора" color: page.muted font.pixelSize: 13 } } Text { Layout.fillWidth: true text: "Лог" color: page.fg font.pixelSize: 14 font.bold: true } Rectangle { Layout.fillWidth: true Layout.fillHeight: true color: "#141422" radius: 2 border.color: "#333348" ListView { id: logView anchors.fill: parent anchors.margins: 4 clip: true model: sensorsBridge.logEntries delegate: Text { width: logView.width wrapMode: Text.Wrap color: modelData.level === "warn" ? "#ffcc66" : page.muted font.pixelSize: 11 text: (modelData.ts || "") + " " + (modelData.msg || "") + (modelData.detail ? (" " + modelData.detail) : "") } } } Button { Layout.fillWidth: true Layout.preferredHeight: 40 text: "Отправить рекламу" onClicked: { if (!sensorsBridge.advertise()) console.warn("advertise cmd failed") } background: Rectangle { radius: 4 color: parent.down ? "#3a3a58" : "#2a2a40" border.color: "#555570" } contentItem: Text { text: parent.text color: page.fg horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter font.pixelSize: 14 } } } }