fastbee/yack-mini/miniprogram/pages/device/detail/detail.wxml
2026-09-27 15:17:17 +08:00

161 lines
8.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- 设备详情页:上部信息区(可滚动) + 底部固定收发控制台(串口调试工具风格) -->
<view class="page">
<!-- ===== 上半屏:设备信息与配置(可滚动) ===== -->
<scroll-view class="body-scroll" scroll-y>
<!-- 设备信息 -->
<view class="device-info card">
<view class="info-row">
<text class="info-label">设备编号</text>
<text class="info-value">{{device.serialNumber || '-'}}</text>
</view>
<view class="info-row">
<text class="info-label">BLE 地址</text>
<text class="info-value">{{device.deviceId || '-'}}</text>
</view>
<view class="info-row">
<text class="info-label">BLE 状态</text>
<!-- 未连接时可点击手动重连:自动重连卡死(连续连接超时后 native 半开连接)时的确定性出口 -->
<view class="status-tag {{bleConnected ? 'online' : 'offline'}} {{canRetryBle ? 'retryable' : ''}}"
bindtap="onRetryBle">
{{bleConnected ? '已连接' : (canRetryBle ? '未连接 · 点击重连' : '未连接')}}
</view>
</view>
<view class="info-row">
<text class="info-label">MQTT 状态</text>
<!-- MQTT 为账号/产品级自动连接(凭证在「我的」页):
正常情况下点击小程序即自动连上,这里只在异常/手动断开时提供一键重连 -->
<view class="status-tag {{mqttConnected ? 'online' : 'offline'}} {{canRetryMqtt ? 'retryable' : ''}}"
bindtap="onRetryMqtt">
<block wx:if="{{mqttConnected}}">已连接</block>
<block wx:elif="{{mqttConnecting}}">连接中…</block>
<block wx:elif="{{mqttUserDisconnected}}">已手动断开 · 点击重连</block>
<block wx:elif="{{canRetryMqtt}}">未连接 · 点击重连</block>
<block wx:else>未连接</block>
</view>
</view>
</view>
<!-- 测点与模式 -->
<view class="measure-card card">
<view class="measure-item">
<text class="measure-label">测点ID</text>
<!-- 只用正则把关,**刻意不用 type="number"**:测点ID 是数据唯一归属("0001" ≠ "1"),
数字键盘在部分平台/输入法会做数值归一化或吞前导零,静默改写主键的代价大于键盘便利 -->
<input class="measure-input {{measurePointIdValid ? '' : 'invalid'}}"
maxlength="64"
placeholder="纯数字, 1-64位"
value="{{measurePointId}}"
bindinput="onMeasurePointInput" />
</view>
<view class="measure-hint error" wx:if="{{!measurePointIdValid}}">测点ID格式非法:仅支持纯数字,长度1-64</view>
<view class="measure-item">
<text class="measure-label">采集模式</text>
<radio-group class="mode-group" bindchange="onModeChange">
<label class="mode-option">
<radio value="1" checked="{{collectMode === 1}}" color="#1890ff" />
<text>手动确认</text>
</label>
<label class="mode-option">
<radio value="2" checked="{{collectMode === 2}}" color="#1890ff" />
<text>自动上传</text>
</label>
</radio-group>
</view>
<view class="measure-hint" wx:if="{{collectMode === 1}}">手动模式:采集到的数据需点击「确认」后才上传</view>
<view class="measure-hint" wx:else>自动模式:采集到数据即上传到平台</view>
</view>
</scroll-view>
<!-- ===== 底部:固定收发区 ===== -->
<view class="console">
<view wx:if="{{lastError}}" class="notice-text">{{lastError}}</view>
<!-- 数据接收:标题 + 工具区(清空 / 滚动 / Hex / 上传离线)同排,控件统一 52rpx 高。
注意:button 的宽度会被基础库强制成 184px,靠 wxss 里的「父容器+类名」提权压回,详见 detail.wxss -->
<view class="console-header">
<text class="console-title">数据接收:</text>
<view class="console-tools">
<button class="btn-clear-mini" bindtap="handleClearData">清空</button>
<!-- ⚠️ 勾选框必须由 checkbox-group 包裹:bindchange 是 checkbox-group 的事件,
checkbox 自身没有该事件(裸挂要么不派发、要么 detail.value 是布尔值而非数组,
两种情况都会让开关恒定失效)。group 的 detail.value 才是「选中项 value 数组」 -->
<checkbox-group class="chk-item" bindchange="onAutoScrollToggle">
<label class="chk-item">
<checkbox class="chk-box" value="scroll" checked="{{autoScroll}}" color="#07c160" />
<text>滚动</text>
</label>
</checkbox-group>
<checkbox-group class="chk-item" bindchange="onRecvHexToggle">
<label class="chk-item">
<checkbox class="chk-box" value="hex" checked="{{recvHex}}" color="#07c160" />
<text>Hex</text>
</label>
</checkbox-group>
<!-- 离线补传:排在接收行末位;禁用态走 class(button[disabled]:not([type]) 会压掉属性选择器) -->
<button class="btn-flush {{canFlush ? '' : 'is-disabled'}}"
bindtap="handleFlushOffline"
disabled="{{!canFlush}}">
上传离线({{offlineCount}})
</button>
</view>
</view>
<view class="log-wrap">
<scroll-view class="log-scroll" scroll-y
scroll-into-view="{{scrollIntoView}}"
bindscroll="onLogScroll"
bindscrolltolower="onLogToLower"
lower-threshold="60">
<block wx:if="{{displayList.length > 0}}">
<!-- 最新在后:自动滚动锚定最后一行 -->
<view class="log-line" wx:for="{{displayList}}" wx:key="id" id="log-{{item.id}}">
<text class="log-text">[{{item.time}}]:{{item.text}}</text>
<text wx:if="{{item.uploaded}}" class="log-flag uploaded">↑已上报</text>
<text wx:elif="{{item.offline}}" class="log-flag cached">已缓存</text>
<text wx:elif="{{modeManual && !item.confirmed}}" class="log-flag confirm-btn" catchtap="onConfirmData" data-id="{{item.id}}">确认</text>
<text wx:elif="{{modeManual && item.confirmed}}" class="log-flag confirmed">已确认</text>
<text wx:elif="{{item.pendingReason}}" class="log-flag pending">{{item.pendingReason}}</text>
</view>
</block>
<view wx:else class="log-empty">
<text>{{enabled ? '等待设备上报数据…' : '启用网关采集后可查看实时数据'}}</text>
</view>
</scroll-view>
<!-- 手动上翻回看时的"回到底部"快捷入口 -->
<view class="follow-btn" wx:if="{{autoScroll && !logFollowing && displayList.length > 0}}"
bindtap="onFollowTap">↓ 最新</view>
</view>
<!-- 统计 -->
<view class="console-stats">
<text class="stat-chip">接收 {{stats.received}}</text>
<text class="stat-chip">已上报 {{stats.uploaded}}</text>
<text class="stat-chip">失败 {{stats.failed}}</text>
<text class="stat-chip">离线 {{offlineCount}}</text>
</view>
<!-- 数据发送 -->
<view class="console-header send-header">
<text class="console-title">数据发送:</text>
<checkbox-group class="chk-item" bindchange="onSendHexToggle">
<label class="chk-item">
<checkbox class="chk-box" value="hex" checked="{{sendHex}}" color="#07c160" />
<text>Hex</text>
</label>
</checkbox-group>
</view>
<view class="send-row">
<input class="send-input"
placeholder="{{sendHex ? '如:00 60 00 FF 00 FF F0' : '发送 ASCII 文本'}}"
placeholder-class="send-placeholder"
value="{{sendInput}}"
bindinput="onSendInput"
confirm-type="send" confirm-hold
bindconfirm="handleSend" />
<button class="btn-send {{canSend ? '' : 'is-disabled'}}"
bindtap="handleSend"
disabled="{{!canSend}}">发送</button>
</view>
</view>
</view>