蓝牙调试页面初步完成

This commit is contained in:
2026-01-16 12:00:49 +08:00
parent d9f8358191
commit bbc4f205a3
60 changed files with 2201 additions and 51331 deletions

View File

@@ -15,7 +15,7 @@
|---------|------|-------------|---------|------| |---------|------|-------------|---------|------|
| B0~B1 | Head | 2 | 0xCC 0xC0 | 固定包头 | | B0~B1 | Head | 2 | 0xCC 0xC0 | 固定包头 |
| B2~B3 | Len | 2 | 00~548 | 数据的总长度包括包头和CRC校验低地址在前 | | B2~B3 | Len | 2 | 00~548 | 数据的总长度包括包头和CRC校验低地址在前 |
| B4~B5 | CRC | 2 | 00~FF | 整包CRC16校验 | | B4~B5 | CRC | 2 | 00~FF | 整包CRC16Modbus 校验 |
| B6~B7 | Frame | 2 | 00~FF | 帧号 | | B6~B7 | Frame | 2 | 00~FF | 帧号 |
| B8~B9 | FramNum | 2 | 00~FF | 帧总数 | | B8~B9 | FramNum | 2 | 00~FF | 帧总数 |
| B10 | Frame_Type | 1 | 00~FF | 帧类型,命令字 | | B10 | Frame_Type | 1 | 00~FF | 帧类型,命令字 |
@@ -54,18 +54,90 @@ sequenceDiagram
|------|-------|------|------| |------|-------|------|------|
| PC→MCU | 0x01 | P0: 0x00 | 读取版本号命令 | | PC→MCU | 0x01 | P0: 0x00 | 读取版本号命令 |
| MCU→PC | 0x01 | P0: 软件版本号<br>P1: 硬件版本号 | 返回版本信息 | | MCU→PC | 0x01 | P0: 软件版本号<br>P1: 硬件版本号 | 返回版本信息 |
CC C0 0D 00 54 08 01 00 01 00 01 04 04
### 3.2 设置无卡取电条件信息
### 3.2 设置无卡取电条件信息命令1 PC -> MCU
| 方向 | 命令字 | 参数 | 备注 |
|------|-------|------|------| 命令字: 0x08
| PC→MCU | 0x08 | P0: 有无逻辑标记<br>P1: 条件组<br>P2: 条件序号<br>P3~P4: 条件判定时间<br>P5: 条件判定时间单位<br>P6~P9: 端口1~10状态<br>P10: 触发阈值<br>P11~P12: 条件超时时间<br>P13: 条件超时时间单位 | 设置无卡取电条件 |
| MCU→PC | 0x08 | P0: 0x01(参数正确) / 0x02(参数错误) | 返回设置结果 | 参数说明 (P0..P13)
- P0: 有无人逻辑标记
- P1: 条件组号
- P2: 同一条件组内的条件序号
- P3~P4: 条件判定时间16-bit低地址在前
- P5: 条件判定时间单位
- P6~P10: 端口1~5 状态(共 5 个字节/项按顺序第1项为插卡状态暂未使用
- P11~P12: 条件组超时时间16-bit, 低地址在前)
- P13: 条件组超时时间单位取值1=秒2=分3=时)
有无人逻辑标志取值:
- 1: 无人至有人
- 2: 有人至无人
- 3: 短暂离开
- 4: 长时间离开
端口状态取值说明(每项):
- 0: 不判断
- 1: 触发
- 2: 释放
- 3: 关至开
- 4: 开至关
注意条件组超时时间必须大于或等于条件判定时间P11~P12 >= P3~P4否则设备应判定为参数错误。
MCU -> PC
命令字: 0x08响应
- P0: 返回码0x01 表示参数正确0x02 表示参数错误
### 3.3 设置无卡取电端口信息
PC -> MCU
命令字: 0x09
参数说明 (P0..P10)
- P0: 端口设备类型
- P1: 端口设备地址(暂未使用,默认 1
- P2~P3: 端口设备回路16-bit低地址在前取值 1..5
- P4: 有人->无人 阈值
- P5: 虚拟端口号1..5,对应物理端口含义见下)
- P6: 回路是否启用检测统计0/1
- P7~P8: 回路检测统计时间16-bit低地址在前
- P9: 回路检测统计时间单位1=秒2=分3=时)
- P10: 无人->有人 阈值
字段说明与取值:
- 端口设备类型:
- 插卡状态: 10
- 其他设备类型: 2默认
- 端口地址:暂未使用,默认填写 1
- 端口设备回路P2~P3可取 1~5含义如下
- 回路1: 插卡状态
- 回路2: 门磁状态
- 回路3: 洗手间状态
- 回路4: 卧室状态
- 回路5: 门口状态
- 虚拟端口号P5取值 1~5对应物理端口含义同上端口1=插卡,2=门磁,3=洗手间,4=卧室,5=门口)
- 回路检测统计最大时间8 小时(设备端限制)
注意:
- 请确保统计时间与单位P7~P9不会超过设备支持的最大值通常 8 小时);若超限设备可能返回参数错误。
MCU -> PC
命令字: 0x09响应
- P0: 返回码0x01 表示参数正确0x02 表示参数错误
### 3.3 设置无卡取电条件信息命令2
| 方向 | 命令字 | 参数 | 备注 |
|------|-------|------|------|
| PC→MCU | 0x09 | P0: 端口设备类型<br>P1: 端口设备地址<br>P2~P3: 端口设备回路<br>P4: 有人->无人阈值<br>P5: 虚拟端口号<br>P6: 回路是否启用检测统计<br>P7~P8: 回路检测统计时间<br>P9: 回路检测统计时间单位<br>P10: 无人->有人阈值 | 设置无卡取电条件 |
| MCU→PC | 0x09 | P0: 0x01(参数正确) / 0x02(参数错误) | 返回设置结果 |
### 3.4 OTA升级开始 ### 3.4 OTA升级开始
| 方向 | 命令字 | 参数 | 备注 | | 方向 | 命令字 | 参数 | 备注 |
@@ -88,17 +160,35 @@ sequenceDiagram
- 端口状态值0=释放1=触发。 - 端口状态值0=释放1=触发。
- 典型端口位含义bit0=端口1门磁bit1=端口2洗手间bit2=端口3卧室bit3=端口4门口后续端口依次类推。 - 典型端口位含义bit0=端口1门磁bit1=端口2洗手间bit2=端口3卧室bit3=端口4门口后续端口依次类推。
### 3.7 测试按键功能
### 3.7 测试按键功能 ### 3.7 测试按键功能
| 方向 | 命令字 | 参数 | 备注 | | 方向 | 命令字 | 参数 | 备注 |
|------|-------|------|------| |------|-------|------|------|
| PC→MCU | 0x13 | P0: 0x01(按键点按控制)<br>P1: bit0(按键1触发), bit1(按键2触发), bit2(按键3触发), bit3(按键4触发), bit4(按键5触发), bit5(按键6触发) | 测试按键功能(对应按键仅支持点按,不具备开关状态) | | PC→MCU | 0x13 | P0: 0x01(按键点按控制)<br>P1: 按键位掩码(位对应按键见下表) | 请求模拟按键点按P1 为按键位掩码,可同时置位多个按键以并行触发对应动作 |
| MCU→PC | 0x13 | P0: 0x01(参数正确) / 0x02(参数错误) | 返回设置结果 | | MCU→PC | 0x13 | P0: 0x01(参数正确) / 0x02(参数错误) | 返回设置结果 |
### 3.8 设置门磁开关走廊灯、卫浴雷达开关卫浴灯事件 按键映射说明:
- 按键1 (bit0): 无人→有人
- 按键2 (bit1): 有人→无人
- 按键3 (bit2): 门磁 开
- 按键4 (bit3): 门磁 关
- 按键5 (bit4): 洗手间雷达 开
- 按键6 (bit5): 洗手间雷达 关
组包示例与说明:
- 要模拟“按键3门磁 开”点按PC 发送命令帧 Frame_Type=0x13参数 P0=0x01P1=0x04bit2 = 1
- 要同时触发按键1与按键5P1 应为 (1<<0) | (1<<4) = 0x11。
- 设备在收到该命令后按位解析 P1并对被置位的按键逐一触发对应的内部动作或上报状态变化。若参数格式或范围非法设备返回 MCU→PC 的 P0=0x02 表示参数错误。
注意:这些测试按键仅用于模拟点按触发动作,不会改变设备的持续开/关逻辑(若需设置长期状态,请使用对应的控制命令)。
### 3.8 设置门磁开廊灯事件,卫浴雷达开卫浴灯事件触发、释放参数
| 方向 | 命令字 | 参数 | 备注 | | 方向 | 命令字 | 参数 | 备注 |
|------|-------|------|------| |------|-------|------|------|
| PC→MCU | 0x16 | P0: 控制位bit0=门磁开关廊灯事件bit1=卫浴灯开关事件<br>门磁开关廊灯事件:<br>P1: 事件触发延迟时间数值<br>P2: 时间单位1=秒2=分3=时<br>P3: 事件持续时间数值<br>P4: 时间单位1=秒2=分3=时<br>P5: 事件释放延迟时间数值<br>P6: 时间单位1=秒2=分3=时)<br>卫浴灯开关事件:<br>P7: 事件触发延迟时间数值<br>P8: 时间单位1=秒2=分3=时)<br>P9: 事件持续时间数值<br>P10: 时间单位1=秒,2=分3=时<br>P11: 事件释放延迟时间数值<br>P12: 时间单位1=秒2=分3=时 | 设置事件参数(用于控制门磁亮走廊灯、卫浴雷达亮卫浴灯等) | | PC→MCU | 0x16 | P0: 控制位<br> &nbsp;&nbsp;bit0: 设置门磁开关廊灯事件<br> &nbsp;&nbsp;bit1: 设置卫浴灯开关事件<br><br>门磁开关廊灯事件:<br> P1: 事件触发延迟时间数值<br> P2: 时间单位1=秒 2=分 3=时<br> P3: 事件释放延迟时间<br> P4: 时间单位1=秒 2=分 3=时<br><br>卫浴灯开关事件:<br> P5: 事件触发延迟时间数值<br> P6: 时间单位1=秒 2=分 3=时<br> P7: 事件释放延迟时间<br> P8: 时间单位1=秒 2=分 3=时 | 设置门磁与卫浴雷达的触发/释放时序参数 |
| MCU→PC | 0x16 | P0: 0x01(参数正确) / 0x02(参数错误) | 返回设置结果 | | MCU→PC | 0x16 | P0:<br> &nbsp;&nbsp;0x01: 参数正确<br> &nbsp;&nbsp;0x02: 参数错误 | 返回设置结果 |
## 4. 命令交互流程图 ## 4. 命令交互流程图

View File

@@ -1,5 +1,6 @@
{ {
"pages": [ "pages": [
"pages/autho/index", "pages/autho/index",
"pages/login/login", "pages/login/login",
"pages/index/index", "pages/index/index",

View File

@@ -23,7 +23,7 @@
border-radius: 12rpx; border-radius: 12rpx;
width: 47%; width: 47%;
margin: 0 1% 40rpx; margin: 0 1% 40rpx;
background-image: url(https://image.weilanwl.com/color2.0/cardBg.png); /* background-image: url(https://image.weilanwl.com/color2.0/cardBg.png); */
background-size: cover; background-size: cover;
background-position: center; background-position: center;
position: relative; position: relative;
@@ -34,7 +34,7 @@
border-radius: 12rpx; border-radius: 12rpx;
width: 32%; width: 32%;
margin: 0 5rpx 5rpx; margin: 0 5rpx 5rpx;
background-image: url(https://image.weilanwl.com/color2.0/cardBg.png); /* background-image: url(https://image.weilanwl.com/color2.0/cardBg.png); */
background-size: cover; background-size: cover;
background-position: center; background-position: center;
position: relative; position: relative;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

BIN
images/tabbar/chumen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

BIN
images/tabbar/jinmen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
images/tabbar/menguanbi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
images/tabbar/menkaiqi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

BIN
images/tabbar/youren.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 956 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -21,7 +21,7 @@ Page({
icon: 'colorlens' icon: 'colorlens'
}, },
{ {
title: '主机升级', title: '主机升级绑定',
name: 'HostUpgrade', name: 'HostUpgrade',
color: 'purple', color: 'purple',
icon: 'font' icon: 'font'

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,8 @@
<view slot="content">{{DevName || 'B13设备'}}</view> <view slot="content">{{DevName || 'B13设备'}}</view>
</cu-custom> </cu-custom>
<!-- 顶部标签:参考主机升级页面的切换方式 --> <!-- 顶部标签:参考主机升级页面的切换方式 -->
<scroll-view scroll-x class="bg-white nav text-center text-bold text-xl"> <scroll-view scroll-x class="bg-white nav text-center text-bold text-xl">
<view class="flex text-center"> <view class="flex text-center">
@@ -14,6 +16,17 @@
<!-- Tab: 蓝牙调试 --> <!-- Tab: 蓝牙调试 -->
<view wx:if="{{TabCur==1}}" class="content"> <view wx:if="{{TabCur==1}}" class="content">
<!-- 顶部操作按钮 -->
<view class="top-actions" style="display:flex; gap:6rpx; padding:4rpx 6rpx;">
<button size="mini" type="primary" bindtap="sendDoorEvent">设置门磁延时</button>
<button size="mini" type="primary" bindtap="sendBathEvent">设置卫浴延时</button>
<button size="mini" type="{{radarReading ? 'warn' : 'primary'}}" bindtap="toggleRadarRead">{{radarReading ? '停止读取' : '读雷达状态'}}</button>
<button size="mini" type="primary" bindtap="onStartOta">OTA升级</button>
</view>
<!-- 顶部设备分类 --> <!-- 顶部设备分类 -->
<view class="grid"> <view class="grid">
<view class="grid-item" wx:for="{{radarLights}}" wx:key="key"> <view class="grid-item" wx:for="{{radarLights}}" wx:key="key">
@@ -22,50 +35,98 @@
</view> </view>
</view> </view>
<!-- 状态功能块 --> <!-- 状态功能块:已改为测试按键按钮,点击发送测试按键命令 -->
<view class="cards"> <view class="cards">
<view class="card"> <view class="card {{pressedMask==1?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x01" data-masknum="1">
<view class="icon orange"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/jinmen.png" mode="aspectFill" />
</view>
<text class="card-title">房间有人</text> <text class="card-title">房间有人</text>
</view> </view>
<view class="card"> <view class="card {{pressedMask==2?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x02" data-masknum="2">
<view class="icon gray"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/chumen.png" mode="aspectFill" />
</view>
<text class="card-title">房间无人</text> <text class="card-title">房间无人</text>
</view> </view>
<view class="card"> <view class="card {{pressedMask==4?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x04" data-masknum="4">
<view class="icon red"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/menkaiqi.png" mode="aspectFill" />
</view>
<text class="card-title">门开</text> <text class="card-title">门开</text>
</view> </view>
<view class="card"> <view class="card {{pressedMask==8?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x08" data-masknum="8">
<view class="icon green"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/menguanbi.png" mode="aspectFill" />
</view>
<text class="card-title">门关</text> <text class="card-title">门关</text>
</view> </view>
<view class="card"> <view class="card {{pressedMask==16?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x10" data-masknum="16">
<view class="icon blue"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/youren.png" mode="aspectFill" />
</view>
<text class="card-title">卫浴有人</text> <text class="card-title">卫浴有人</text>
</view> </view>
<view class="card"> <view class="card {{pressedMask==32?'pressed':''}}" bindtap="onTestKeyTap" bindtouchstart="onTestKeyTouchStart" bindtouchend="onTestKeyTouchEnd" bindtouchcancel="onTestKeyTouchEnd" data-mask="0x20" data-masknum="32">
<view class="icon gray"></view> <view class="icon">
<image class="icon-img" src="../../../../images/tabbar/shiyourenkou.png" mode="aspectFill" />
</view>
<text class="card-title">卫浴无人</text> <text class="card-title">卫浴无人</text>
</view> </view>
</view> </view>
<!-- 延时滑块 --> <!-- 门磁/卫浴事件设置(替代原延时滑块 -->
<view class="slider-card"> <view class="cfg-card">
<view class="slider-head"> <view class="cfg-head head-row">
<text class="title">开门延时</text> <text>门磁开廊灯事件设置</text>
<text class="value">{{openDelay}}s</text> </view>
<view class="form-row">
<view class="form-inline">
<text class="label">触发延迟</text>
<picker class="inline-picker" mode="selector" range="{{doorTriggerOptions}}" value="{{doorTriggerIndex}}" bindchange="onDoorTriggerPickerChange">
<view class="picker-text">{{doorTriggerOptions[doorTriggerIndex]}}</view>
</picker>
<text class="label">单位</text>
<picker class="inline-picker" mode="selector" range="{{eventUnits}}" value="{{doorTriggerUnitIndex}}" bindchange="onDoorUnitChange" data-field="triggerUnit">
<view class="picker-text">{{eventUnits[doorTriggerUnitIndex]}}</view>
</picker>
<text class="label">释放延迟</text>
<picker class="inline-picker" mode="selector" range="{{doorReleaseOptions}}" value="{{doorReleaseIndex}}" bindchange="onDoorReleasePickerChange">
<view class="picker-text">{{doorReleaseOptions[doorReleaseIndex]}}</view>
</picker>
<text class="label">单位</text>
<picker class="inline-picker" mode="selector" range="{{eventUnits}}" value="{{doorReleaseUnitIndex}}" bindchange="onDoorUnitChange" data-field="releaseUnit">
<view class="picker-text">{{eventUnits[doorReleaseUnitIndex]}}</view>
</picker>
</view>
</view> </view>
<slider bindchange="onOpenDelayChange" value="{{openDelay}}" min="0" max="60" step="1"/>
</view> </view>
<view class="slider-card"> <view class="cfg-card">
<view class="slider-head"> <view class="cfg-head head-row">
<text class="title">卫浴延时</text> <text>卫浴雷达开卫浴灯事件设置</text>
<text class="value">{{bathDelay}}s</text> </view>
<view class="form-row">
<view class="form-inline">
<text class="label">触发延迟</text>
<picker class="inline-picker" mode="selector" range="{{bathTriggerOptions}}" value="{{bathTriggerIndex}}" bindchange="onBathTriggerPickerChange">
<view class="picker-text">{{bathTriggerOptions[bathTriggerIndex]}}</view>
</picker>
<text class="label">单位</text>
<picker class="inline-picker" mode="selector" range="{{eventUnits}}" value="{{bathTriggerUnitIndex}}" bindchange="onBathUnitChange" data-field="triggerUnit">
<view class="picker-text">{{eventUnits[bathTriggerUnitIndex]}}</view>
</picker>
<text class="label">释放延迟</text>
<picker class="inline-picker" mode="selector" range="{{bathReleaseOptions}}" value="{{bathReleaseIndex}}" bindchange="onBathReleasePickerChange">
<view class="picker-text">{{bathReleaseOptions[bathReleaseIndex]}}</view>
</picker>
<text class="label">单位</text>
<picker class="inline-picker" mode="selector" range="{{eventUnits}}" value="{{bathReleaseUnitIndex}}" bindchange="onBathUnitChange" data-field="releaseUnit">
<view class="picker-text">{{eventUnits[bathReleaseUnitIndex]}}</view>
</picker>
</view>
</view> </view>
<slider bindchange="onBathDelayChange" value="{{bathDelay}}" min="0" max="60" step="1"/>
</view> </view>
<!-- 通讯日志 --> <!-- 通讯日志 -->
@@ -122,13 +183,15 @@
<text class="dr-value">{{bleVersion || '-'}}</text> <text class="dr-value">{{bleVersion || '-'}}</text>
</view> </view>
</view> </view>
<view class="dr-btn dr-btn-view" bindtap="onSendReadVersion">读取蓝牙信息</view> <view class="dr-btn dr-btn-view dr-btn-small" bindtap="onSendReadVersion">读取蓝牙信息</view>
</view> </view>
<!-- 功能栏(保留导出/导入) --> <!-- 功能栏(保留导出/导入) -->
<view class="cfg-card"> <view class="cfg-card">
<view class="toolbar"> <view class="toolbar">
<!-- 文件名放左侧 -->
<view class="import-box">{{importFileName || '未选择文件'}}</view> <view class="import-box">{{importFileName || '未选择文件'}}</view>
<!-- 按钮放右侧 -->
<view class="toolbar-actions"> <view class="toolbar-actions">
<button size="mini" type="default" bindtap="onExport">导出文件</button> <button size="mini" type="default" bindtap="onExport">导出文件</button>
<button size="mini" type="default" bindtap="onImport">导入文件</button> <button size="mini" type="default" bindtap="onImport">导入文件</button>
@@ -142,8 +205,8 @@
<view class="cfg-head head-row"> <view class="cfg-head head-row">
<text>端口配置</text> <text>端口配置</text>
<view class="head-actions"> <view class="head-actions">
<button size="mini" type="default" bindtap="onReadPorts">读取配置</button> <button class="hide-btn" size="mini" type="default" bindtap="onReadPorts">读取配置</button>
<button size="mini" type="primary" bindtap="onSavePorts">保存配置</button> <button class="hide-btn" size="mini" type="primary" bindtap="onSavePorts">保存配置</button>
</view> </view>
</view> </view>
<view class="table header port"> <view class="table header port">
@@ -189,10 +252,10 @@
<view class="cfg-head head-row"> <view class="cfg-head head-row">
<text>条件配置</text> <text>条件配置</text>
<view class="head-actions"> <view class="head-actions">
<button size="mini" type="warn" bindtap="onDeleteCondGroup">删除条件组</button> <button class="hide-btn" size="mini" type="warn" bindtap="onDeleteCondGroup">删除条件组</button>
<button size="mini" type="warn" bindtap="onDeleteCondition">删除条件</button> <button class="hide-btn" size="mini" type="warn" bindtap="onDeleteCondition">删除条件</button>
<button size="mini" type="primary" bindtap="onAddCondGroup">添加条件组</button> <button class="hide-btn" size="mini" type="primary" bindtap="onAddCondGroup">添加条件组</button>
<button size="mini" type="primary" bindtap="onAddCondition">添加条件</button> <button class="hide-btn" size="mini" type="primary" bindtap="onAddCondition">添加条件</button>
</view> </view>
</view> </view>
<scroll-view scroll-y class="cond-scroll"> <scroll-view scroll-y class="cond-scroll">
@@ -204,9 +267,7 @@
<text class="group-seq">{{grp.group}}</text> <text class="group-seq">{{grp.group}}</text>
<view class="group-time"> <view class="group-time">
<text class="label">超时:</text> <text class="label">超时:</text>
<picker class="timeout-picker" mode="selector" range="{{ grp.timeoutUnit === 0 ? hourValues : msValues }}" value="{{ (grp.timeout || 1) - 1 }}" bindchange="onGroupPickerChange" data-idx="{{gidx}}" data-field="timeout"> <input class="picker-text" placeholder="超时时间" value="{{grp.timeout || 0}}" type="number" bindinput="onGroupNumberInput" data-idx="{{gidx}}" data-field="timeout" />
<view class="picker-text">{{grp.timeout || 1}}</view>
</picker>
<text class="label">单位:</text> <text class="label">单位:</text>
<picker class="unit-picker" mode="selector" range="{{timeUnits}}" value="{{grp.timeoutUnit}}" bindchange="onGroupPickerChange" data-idx="{{gidx}}" data-field="timeoutUnit"> <picker class="unit-picker" mode="selector" range="{{timeUnits}}" value="{{grp.timeoutUnit}}" bindchange="onGroupPickerChange" data-idx="{{gidx}}" data-field="timeoutUnit">
<view class="picker-text">{{timeUnits[grp.timeoutUnit]}}</view> <view class="picker-text">{{timeUnits[grp.timeoutUnit]}}</view>
@@ -230,9 +291,7 @@
</view> </view>
<view class="td"> <view class="td">
<text class="label">持续判定时间:</text> <text class="label">持续判定时间:</text>
<picker mode="selector" range="{{ it.judgeUnit === 0 ? hourValues : msValues }}" value="{{ (it.judgeTime || 1) - 1 }}" bindchange="onItemPickerChange" data-gidx="{{gidx}}" data-iidx="{{iidx}}" data-field="judgeTime"> <input class="picker-text" placeholder="持续判定时间" value="{{it.judgeTime || ''}}" type="number" bindinput="onItemNumberInput" data-gidx="{{gidx}}" data-iidx="{{iidx}}" data-field="judgeTime" />
<view class="picker-text">{{it.judgeTime || 1}}</view>
</picker>
</view> </view>
<view class="td"> <view class="td">
<text class="label">单位:</text> <text class="label">单位:</text>
@@ -245,10 +304,10 @@
<view class="tr tr-mid"> <view class="tr tr-mid">
<view class="th">有无人标记</view> <view class="th">有无人标记</view>
<view class="th">有卡取电</view> <view class="th">有卡取电</view>
<view class="th">门磁</view> <view class="th">门磁</view>
<view class="th">门口红外</view> <view class="th">门口</view>
<view class="th">卫红外</view> <view class="th">洗手间</view>
<view class="th">浴红外</view> <view class="th">卧室</view>
</view> </view>
<!-- 第三行:对应值 --> <!-- 第三行:对应值 -->
<view class="tr tr-bottom"> <view class="tr tr-bottom">
@@ -291,6 +350,52 @@
</view> </view>
</scroll-view> </scroll-view>
</view> </view>
<!-- 删除模态框 -->
<view wx:if="{{deleteDialogVisible}}" class="dialog-mask">
<view class="dialog">
<text class="dialog-title">{{deleteDialogMode === 'group' ? '删除条件组' : '删除条件'}}</text>
<view class="dialog-body">
<view wx:if="{{deleteDialogMode === 'group'}}">
<text class="label">选择条件组:</text>
<picker mode="selector" range="{{deleteDialogGroups}}" value="{{deleteDialogSelectedGroupIndex}}" bindchange="onDeleteDialogGroupChange">
<view class="picker-text">{{deleteDialogGroups[deleteDialogSelectedGroupIndex]}}</view>
</picker>
</view>
<view wx:if="{{deleteDialogMode === 'condition'}}">
<text class="label">选择条件组:</text>
<picker mode="selector" range="{{deleteDialogGroups}}" value="{{deleteDialogSelectedGroupIndex}}" bindchange="onDeleteDialogGroupChange">
<view class="picker-text">{{deleteDialogGroups[deleteDialogSelectedGroupIndex]}}</view>
</picker>
<text class="label">选择条件序号:</text>
<picker mode="selector" range="{{deleteDialogSeqs}}" value="{{deleteDialogSelectedSeqIndex}}" bindchange="onDeleteDialogSeqChange">
<view class="picker-text">{{deleteDialogSeqs[deleteDialogSelectedSeqIndex] || '无'}}</view>
</picker>
</view>
</view>
<view class="dialog-actions">
<button bindtap="onCancelDeleteDialog" type="default">取消</button>
<button bindtap="onConfirmDeleteDialog" type="primary">确定</button>
</view>
</view>
</view>
<!-- 添加模态框 -->
<view wx:if="{{addDialogVisible}}" class="dialog-mask">
<view class="dialog">
<text class="dialog-title">添加条件</text>
<view class="dialog-body">
<text class="label">选择条件组:</text>
<picker mode="selector" range="{{addDialogGroups}}" value="{{addDialogSelectedGroupIndex}}" bindchange="onAddDialogGroupChange">
<view class="picker-text">{{addDialogGroups[addDialogSelectedGroupIndex]}}</view>
</picker>
</view>
<view class="dialog-actions">
<button bindtap="onCancelAddDialog" type="default">取消</button>
<button bindtap="onConfirmAddDialog" type="primary">确定</button>
</view>
</view>
</view>
</view> </view>
</view> </view>

View File

@@ -17,15 +17,20 @@
.label { font-size: 24rpx; color: #606266; } .label { font-size: 24rpx; color: #606266; }
.cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8rpx; margin-bottom: 10rpx; } .cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8rpx; margin-bottom: 10rpx; }
.card { background: #fff; border-radius: 14rpx; padding: 14rpx 6rpx; display: flex; flex-direction: column; align-items: center; } .card { background: #fff; border-radius: 14rpx; padding: 24rpx 8rpx; display: flex; flex-direction: column; align-items: center; min-height: 140rpx; box-sizing: border-box; transition: transform 120ms ease, filter 120ms ease; }
.icon { width: 30rpx; height: 30rpx; border-radius: 8rpx; margin-bottom: 4rpx; } .icon { width: 48rpx; height: 48rpx; border-radius: 10rpx; margin-bottom: 8rpx; }
.icon.orange { background: #ff8f00; } .icon.orange { background: #ff8f00; }
.icon.red { background: #ff3b30; } .icon.red { background: #ff3b30; }
.icon.green { background: #21c161; } .icon.green { background: #21c161; }
.icon.blue { background: #0ea5e9; } .icon.blue { background: #0ea5e9; }
.icon.gray { background: #9aa0a6; } .icon.gray { background: #9aa0a6; }
.icon { overflow: hidden; display:flex; align-items:center; justify-content:center; }
.icon-img { width: 100%; height: 100%; display: block; }
.card-title { font-size: 24rpx; color: #555; } .card-title { font-size: 24rpx; color: #555; }
/* 按下效果 */
.card.pressed { transform: translateY(4rpx) scale(0.985); filter: brightness(0.94); box-shadow: none; }
.slider-card { background: #fff; border-radius: 14rpx; padding: 12rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); margin-bottom: 10rpx; } .slider-card { background: #fff; border-radius: 14rpx; padding: 12rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); margin-bottom: 10rpx; }
.slider-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6rpx; } .slider-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6rpx; }
.slider-head .title { font-size: 26rpx; color: #333; } .slider-head .title { font-size: 26rpx; color: #333; }
@@ -56,6 +61,26 @@
.dr-btn-view { background: #0ea5e9; color: #ffffff; border-radius: 12rpx; box-shadow: 0 2rpx 6rpx rgba(14,165,233,0.35); } .dr-btn-view { background: #0ea5e9; color: #ffffff; border-radius: 12rpx; box-shadow: 0 2rpx 6rpx rgba(14,165,233,0.35); }
.dr-btn-view:active { opacity: 0.85; } .dr-btn-view:active { opacity: 0.85; }
/* 顶部操作按钮:紧凑内间距,适配工具栏顶部的多个小按钮 */
.top-actions button {
padding: 0 10rpx;
height: 58rpx;
line-height: 58rpx;
border-radius: 10rpx;
font-size: 24rpx;
}
/* 确保 OTA 按钮为蓝色(优先覆盖可能的主题色) */
.top-actions .ota-btn {
background: #0ea5e9 !important;
color: #ffffff !important;
border: 1rpx solid rgba(14,165,233,0.9) !important;
box-shadow: 0 2rpx 6rpx rgba(14,165,233,0.25);
}
/* 小尺寸按钮,适用于工具栏中次级操作,如读取蓝牙信息 */
.dr-btn-small { padding: 0 12rpx; min-width: 120rpx; height: 64rpx; line-height: 64rpx; }
/* 配置表样式 */ /* 配置表样式 */
.cfg-card { background:#fff; border-radius: 14rpx; padding: 12rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); } .cfg-card { background:#fff; border-radius: 14rpx; padding: 12rpx; box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.04); }
.cfg-head { font-size: 26rpx; color:#333; margin-bottom: 10rpx; } .cfg-head { font-size: 26rpx; color:#333; margin-bottom: 10rpx; }
@@ -63,10 +88,41 @@
.head-actions { display:flex; gap: 10rpx; } .head-actions { display:flex; gap: 10rpx; }
.cond-card .head-actions { gap: 8rpx; } .cond-card .head-actions { gap: 8rpx; }
.cond-card .head-actions button { padding: 0 14rpx; height: 48rpx; line-height: 48rpx; } .cond-card .head-actions button { padding: 0 14rpx; height: 48rpx; line-height: 48rpx; }
.toolbar { display:flex; flex-wrap: wrap; gap: 8rpx; align-items: center; justify-content: space-between; } .toolbar {
.toolbar .import-box { min-width: 260rpx; padding: 6rpx 10rpx; border: 1rpx solid #e5e9f2; border-radius: 10rpx; background:#f7f8fa; font-size: 22rpx; color:#606266; } /* 单行布局:文件名在左,三个按钮在右 */
.toolbar .toolbar-actions { display:flex; align-items:center; gap: 6rpx; } display: flex;
.toolbar .toolbar-actions button { padding: 0 12rpx; } flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 8rpx;
}
.toolbar .import-box {
/* 文件名靠左,占用剩余空间 */
flex: 1 1 auto;
margin-right: 8rpx;
padding: 6rpx 10rpx;
border: 1rpx solid #e5e9f2;
border-radius: 10rpx;
background: #f7f8fa;
font-size: 22rpx;
color: #606266;
text-align: left;
/* 限制不换行、不扩展容器,溢出时截断并显示省略号 */
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.toolbar .toolbar-actions {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10rpx;
}
.toolbar .toolbar-actions button { padding: 0 12rpx; height: 54rpx; line-height: 54rpx; margin: 0; }
/* 隐藏特定按钮(通过在 WXML 上添加 class="hide-btn" 使用) */
.hide-btn { display: none !important; }
.table.header, .table.body { display:flex; flex-direction: column; gap: 6rpx; } .table.header, .table.body { display:flex; flex-direction: column; gap: 6rpx; }
.table.port .tr { display:grid; grid-template-columns: 1.4fr 1.2fr 1.4fr 1.4fr 0.8fr 1.1fr 1fr; gap: 6rpx; padding: 6rpx 0; } .table.port .tr { display:grid; grid-template-columns: 1.4fr 1.2fr 1.4fr 1.4fr 0.8fr 1.1fr 1fr; gap: 6rpx; padding: 6rpx 0; }
.table.body.port { gap: 2rpx; } .table.body.port { gap: 2rpx; }
@@ -102,6 +158,26 @@
.cond-scroll { max-height: 680rpx; border: 1rpx solid #e5e9f2; border-radius: 12rpx; padding: 6rpx; box-sizing: border-box; background: #fff; } .cond-scroll { max-height: 680rpx; border: 1rpx solid #e5e9f2; border-radius: 12rpx; padding: 6rpx; box-sizing: border-box; background: #fff; }
.group-card { background:#fafafa; border: 1rpx solid #edf0f5; border-radius: 12rpx; padding: 10rpx; } .group-card { background:#fafafa; border: 1rpx solid #edf0f5; border-radius: 12rpx; padding: 10rpx; }
.group-head .group-info { display:flex; align-items:center; gap: 12rpx; } .group-head .group-info { display:flex; align-items:center; gap: 12rpx; }
.dialog-mask {
position: fixed;
left: 0; right: 0; top: 0; bottom: 0;
background: rgba(0,0,0,0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.dialog {
width: 680rpx;
background: #fff;
border-radius: 12rpx;
padding: 24rpx;
}
.dialog-title { font-size: 32rpx; margin-bottom: 12rpx; }
.dialog-body { margin-bottom: 16rpx; }
.dialog-actions { display: flex; justify-content: flex-end; gap: 12rpx }
.dialog .picker-text { padding: 10rpx 6rpx; border: 1rpx solid #eee; border-radius: 6rpx }
.group-title { font-size: 24rpx; color:#1e3a8a; font-weight: 600; } .group-title { font-size: 24rpx; color:#1e3a8a; font-weight: 600; }
.group-seq { font-size: 24rpx; color:#1e3a8a; font-weight: 600; } .group-seq { font-size: 24rpx; color:#1e3a8a; font-weight: 600; }
.group-time { display:flex; align-items:center; gap: 8rpx; } .group-time { display:flex; align-items:center; gap: 8rpx; }
@@ -115,3 +191,17 @@
.log-time { display: block; font-size: 22rpx; color: #9aa0a6; margin-bottom: 4rpx; } .log-time { display: block; font-size: 22rpx; color: #9aa0a6; margin-bottom: 4rpx; }
.log-text { display: block; font-size: 24rpx; color: #333; word-break: break-all; } .log-text { display: block; font-size: 24rpx; color: #333; word-break: break-all; }
.log-empty { font-size: 24rpx; color: #9aa0a6; text-align: center; padding: 20rpx 0; } .log-empty { font-size: 24rpx; color: #9aa0a6; text-align: center; padding: 20rpx 0; }
/* Inline form for trigger/release delay - keep controls on one row on mobile */
.form-row { display:block; }
.form-inline { display:flex; align-items:center; gap: 10rpx; flex-wrap: nowrap; }
.form-inline .label { font-size: 22rpx; color:#606266; white-space: nowrap; }
.inline-input { width: 110rpx; height: 44rpx; padding: 0 8rpx; border: 1rpx solid #e5e9f2; border-radius: 8rpx; font-size: 24rpx; box-sizing: border-box; }
.inline-picker .picker-text { width: 90rpx; height: 44rpx; padding: 0 8rpx; border-radius: 8rpx; font-size: 22rpx; }
/* If screen too narrow, allow wrapping but keep label + control groups together */
@media (max-width: 360px) {
.form-inline { flex-wrap: wrap; }
.inline-input { width: 90rpx; }
.inline-picker .picker-text { width: 80rpx; }
}

View File

@@ -405,7 +405,7 @@ wx.createSelectorQuery()
that.setData({ that.setData({
faceSNCode: code faceSNCode: code
}); });
debugger // debugger
that.GetFaceSNOK(); that.GetFaceSNOK();
}, },
fail: (err) => { fail: (err) => {

View File

@@ -35,11 +35,13 @@
</view> </view>
<scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight}}rpx;" > <scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight}}rpx;" >
<view class='nav-list1 bg-white' style="margin-top: 20rpx;"> <view class='nav-list1' style="margin-top: 20rpx;">
<view bindtap="goFaceDetail" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}" <view bindtap="goFaceDetail" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}"
data-status="{{item.FaceStatus}}" data-faceSN="{{item.FaceSN}}" hover-class="navigator-hover" class="nav-li4 bg-{{item.FaceStatus===true? 'cyan':'gray'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key="index"> data-status="{{item.FaceStatus}}" data-faceSN="{{item.FaceSN}}" hover-class="navigator-hover" class="nav-li4 {{item.FaceStatus===true? 'online':'offline'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key="index">
<view style="font-size: 28rpx;justify-content:start" >{{item.RoomNumber}}</view> <view style="font-size: 28rpx;justify-content:start" >{{item.RoomNumber}}</view>
<view style="font-size: 18rpx;justify-content:start;color:{{item.FaceSN && !item.FaceStatus ? 'red' : 'gray'}}" >{{item.FaceSN || '未绑定'}}</view> <view style="font-size: 18rpx;justify-content:start; color: {{(!item.FaceSN && item.FaceStatus !== true) ? '#FF3B30' : (item.FaceSN && !item.FaceStatus ? 'red' : '#666666')}};" >
{{ item.FaceSN || (item.FaceStatus !== true ? '点击扫码绑定人脸机' : '') }}
</view>
</view> </view>
</view> </view>

View File

@@ -11,6 +11,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
padding: 0 10rpx; padding: 0 10rpx;
background-color: #F0F0F0; /* 房间卡片的大框背景色 */
} }
/* 房间项样式 */ /* 房间项样式 */
@@ -28,22 +29,14 @@
transform: scale(0.95); transform: scale(0.95);
} }
/* 在线状态样式 */ /* 在线/离线样式(改为 online/offline 以便跨页面复用) */
.bg-green { .nav-li4.online {
background-color: #4CD964; background-color: #FFFFFF; /* 在线高亮白 */
color: white; color: #111111;
} }
.nav-li4.offline {
/* 青色在线状态样式 */ background-color: #C9CBCA; /* 设备离线浅灰色 */
.bg-cyan { color: #111111;
background-color: #00BCD4;
color: white;
}
/* 离线状态样式 */
.bg-gray {
background-color: #E5E5EA;
color: #8E8E93;
} }
/* 搜索框样式 */ /* 搜索框样式 */

View File

@@ -24,6 +24,7 @@
</view> </view>
<view class="cubarN bg-white solid-bottom "> <!-- wx:if="{{devlist[index].show==0}}"> --> <view class="cubarN bg-white solid-bottom "> <!-- wx:if="{{devlist[index].show==0}}"> -->
<view class="flex-eight" style="font-size: 22rpx;" >固件版本:{{devNode.Version}}</view> <view class="flex-eight" style="font-size: 22rpx;" >固件版本:{{devNode.Version}}</view>
<view>{{CurrentUpgradeDevStart? CurrentUpgradeDevStart:""}}</view>
</view> </view>
</view> </view>
@@ -33,17 +34,17 @@
<view class="flex-eight" style="height: 100%;margin: 3rpx 5rpx; " > <view class="flex-eight" style="height: 100%;margin: 3rpx 5rpx; " >
<view class="flex-xis setborder line-grey text-cut" style="height: 45%;font-size: 22rpx; line-height: 50rpx;min-width: 0;margin: 3rpx 0rpx; "> <view class="flex-xis setborder line-grey text-cut padding-5" style="height: 45%;font-size: 22rpx; line-height: 50rpx;min-width: 0;margin: 3rpx 0rpx; ">
{{Gfilename}} {{Gfilename?Gfilename:'\u00A0'}}
</view> </view>
<view class="flex-xis setborder line-grey text-cut" style="height: 45%;font-size: 22rpx; line-height: 50rpx;min-width: 0;margin: 3rpx 0rpx;"> <view class="flex-xis setborder line-grey text-cut padding-5" style="height: 45%;font-size: 22rpx; line-height: 50rpx;min-width: 0;margin: 3rpx 0rpx;">
{{Pfilename}} {{Pfilename?Pfilename:'\u00A0'}}
</view> </view>
</view> </view>
<view class="flex-twice" style="height: 100%;margin: 3rpx 5rpx;" > <view class="flex-twice" style="height: 100%;margin: 3rpx 5rpx;" >
<button class=" "style=" margin: 3rpx 0rpx; font-size: 22rpx;height:45%;" data-id="1" bind:tap="UpgradeTheEquipment" disabled="{{Completed}}">固件升级</button> <button class=" padding-5"style=" margin: 3rpx 0rpx; font-size: 22rpx;height:45%;" data-id="1" bind:tap="UpgradeTheEquipment" disabled="{{Completed}}">固件升级</button>
<button class=""style=" margin: 3rpx 0rpx; font-size: 22rpx;height: 45%;" data-id="2" bind:tap="UpgradeTheEquipment" disabled="{{Completed}}">配置升级</button> <button class="padding-5"style=" margin: 3rpx 0rpx; font-size: 22rpx;height: 45%; " data-id="2" bind:tap="UpgradeTheEquipment" disabled="{{Completed}}">配置升级</button>
</view> </view>
</view> </view>

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +0,0 @@
{
"usingComponents": {
"loscom": "/components/logscom/logscom",
"HostUpgrade":"/pages/HostUpgrade/HostUpgrade",
"Upgrade":"/pages/Upgrade/Upgrade"
}
}

View File

@@ -1,668 +0,0 @@
<!-- pages/Hosts/Hosts.wxml{{isback}} -->
<cu-custom bgColor="bg-gradual-blue"
isBack="true">
<block bindtap="back" slot="backText" >返回</block>
<view slot="content">{{Hotelinfo.HotelName}}({{Hotelinfo.Code}})</view>
</cu-custom>
<view class="padding-sm bg-white radius shadow shadow-lg" style="padding-bottom:0;">
<!-- 头部区域 -->
<view>
<!-- 酒店信息 {{Hotelinfo.HotelId}}-->
<!-- <view class="margin-xs basis-xl">{{Hotelinfo.Code}}<span class="padding-left-xs">{{Hotelinfo.HotelName}}</span></view> -->
<!-- <view class="flex justify-end basis-xs">
<view class="text-green" bindtap="HelpClick">{{Help?'关闭':'帮助'}}</view>
</view> -->
<!---->
<!-- 导航栏 -->
<view class="flex flex-wrap">
<!-- 分类显示 -->
<view class="basis-xxxl ">
<button style="margin-right: 2px;" data-index="0" bindtap="GetshowinfoClick" class="cu-btn bg-{{showinfo==0?'green':'grey'}} ">全部</button>
<button style="margin-right: 2px;" data-index="1" bindtap="GetshowinfoClick" class="cu-btn bg-{{showinfo==1?'green':'grey'}} ">主机绑定</button>
<button style="margin-right: 2px;" data-index="2" bindtap="GetshowinfoClick" class="cu-btn bg-{{showinfo==2?'green':'grey'}} ">人脸机</button>
<button style="margin-right: 2px;" data-index="4" bindtap="GetshowinfoClick" class="cu-btn bg-{{showinfo==4?'green':'grey'}} ">主机蓝牙升级</button>
<button style="margin-right: 2px;" data-index="5" bindtap="GetshowinfoClick" class="cu-btn bg-{{showinfo==5?'green':'grey'}} ">主机升级</button>
<button style="margin-right: 2px;" data-index="3" bindtap="GetshowinfoClick1" class="cu-btn bg-{{showinfo==3?'green':'grey'}} ">刷新</button>
</view>
<view>
<view class="text-green" bindtap="HelpClick">{{Help?'关闭':'帮助'}}</view>
</view>
<!-- 标识区域 -->
<!-- <view class="basis-lg">
<view class="flex flex-wrap margin-left-xs">
<view class="basis-df flex">
<view style="width:0rpx;height:0rpx;margin-top:12rpx;" class="padding-xs bg-green"></view>
<text class="text-black text-df margin-left-xs margin-right-xs">绑定成功<text class="margin-left-xs"></text>{{statusdata[0]}}</text>
</view>
<view class="basis-df flex">
<view style="width:0rpx;height:0rpx;margin-top:12rpx;" class="padding-xs bg-red"></view>
<text class="text-black text-df margin-left-xs margin-right-xs">绑定失败<text class="margin-left-xs"></text>{{statusdata[1]}}</text>
</view>
<view class="basis-df flex">
<view style="width:0rpx;height:0rpx;margin-top:12rpx;" class="padding-xs bg-yellow"></view>
<text class="text-black text-df margin-left-xs margin-right-xs">解除绑定<text class="margin-left-xs"></text>{{statusdata[2]}}</text>
</view>
<view class="basis-df flex">
<view style="width:0rpx;height:0rpx;margin-top:12rpx;" class="padding-xs bg-grey"></view>
<text class="text-black text-df margin-left-xs margin-right-xs">未操作<text class="margin-left-xs"></text>{{statusdata[3]}}</text>
</view>
</view>
</view> -->
<!-- 按钮区域 -->
<!-- <view class="basis-sm flex flex-wrap">
<view class="flex flex-wrap text-center ">
<view class="basis-df" bindtap="islogsClick">
<view class=" radius bg-red">
<text class=" text-df text-white" >{{islogs?'退出':'操作记录'}}<text class="text-lg"></text></text>
</view>
</view>
<view class="basis-df">
<view data-index="0" bindtap="GetClick" class=" margin-left-xs radius bg-{{sel==0?'green':'grey'}} ">
<text class=" text-df text-white">全部<text class="margin-left-xs text-lg">{{HostsData.length}}</text></text>
</view>
</view>
<view class="basis-df">
<view data-index="2" bindtap="GetClick" class="margin-top-xs radius bg-{{sel==2?'green':'grey'}} ">
<text class=" text-df text-white">未绑<text class="margin-left-xs text-lg">{{NMac}}</text></text>
</view>
</view>
<view class="basis-df ">
<view data-index="1" bindtap="GetClick" class=" margin-top-xs margin-left-xs radius bg-{{sel==1?'green':'grey'}} ">
<text class="text-df text-white">已绑<text class="margin-left-xs text-lg">{{YMac}}</text></text>
</view>
</view>
</view>
</view> -->
</view>
<view class="bg-gray margin-xs" style="padding:2rpx"></view>
</view>
<!-- 房间显示区域 -->
<scroll-view id="scroll" wx:if="{{!Help && !islogs && showinfo!=4&& showinfo!=5}}" style="height:{{top_height==null?'600rpx':top_height+'px'}} ;padding-bottom:10rpx" scroll-y="true">
<view class="grid col-4 text-center" wx:if="{{showinfo<4}}">
<view wx:for="{{HostsDataFilters}}">
<view class="padding-xs">
<view style="font:bold;white-space: nowrap;overflow: hidden;" class="text-df {{item.xg!=null?(item.xg==0?'bg-green':(item.xg==1?'bg-red':'bg-yellow')):'bg-grey'}}">
{{item.RoomNumber}}
</view>
<view class="light bg-grey " style="height:{{showinfo==0?'170rpx':showinfo==3?'170rpx':'85rpx'}}">
<!-- rcu主机 -->
<view wx:if="{{showinfo!=2}}" bindtouchstart="handleTouchStart"
bindtouchend="handleTouchEnd"
data-index="{{index}}" bindlongtap="GetMAC_long" bindtap="GetMAC">
<block wx:if="{{item.MAC.length==17}}">
<view class="text-sm">M:{{item.MAC[0]}}{{item.MAC[1]}}{{item.MAC[2]}}{{item.MAC[3]}}{{item.MAC[4]}}{{item.MAC[5]}}{{item.MAC[6]}}{{item.MAC[7]}}{{item.MAC[8]}}
</view>
<view class="text-df">{{item.MAC[9]}}{{item.MAC[10]}}{{item.MAC[11]}}{{item.MAC[12]}}{{item.MAC[13]}}{{item.MAC[14]}}{{item.MAC[15]}}{{item.MAC[16]}}
</view>
</block>
<block wx:if="{{item.MAC.length<17 || !item.MAC || item.MAC.length==0}}" >
<!-- 两个 view 是因为 mac 是两行 -->
<view class="text-sm light" >
<!-- xiaoxi --> RCU
</view> <!-- style="opacity:0" -->
<view class="text-sm light" style="color: #e7ebee;">
<!-- xiaoxi -->绑定
</view>
</block>
</view>
<view class=" bg-white" style="height: 2rpx;" wx:if="{{showinfo==0}}"></view>
<!-- 人脸机 -->
<view wx:if="{{showinfo!=1 }}" bindtouchstart="handleTouchStart"
bindtouchend="handleTouchEnd"
data-index="{{index}}" bindlongtap="GetFaceSN_long" bindtap="GetFaceSN">
<block wx:if="{{item.FaceStatus==true}}">
<block wx:if="{{item.FaceSN.length>0}}">
<view style="color: #17852d;" class="text-df">s:{{item.FaceSN[0]}}{{item.FaceSN[1]}}{{item.FaceSN[2]}}{{item.FaceSN[3]}}{{item.FaceSN[4]}}{{item.FaceSN[5]}}{{item.FaceSN[6]}}{{item.FaceSN[7]}}
</view>
<view style="color: #17852d;" class="text-df">{{item.FaceSN[8]}}{{item.FaceSN[9]}}{{item.FaceSN[10]}}{{item.FaceSN[11]}}{{item.FaceSN[12]}}{{item.FaceSN[13]}}{{item.FaceSN[14]}}{{item.FaceSN[15]}}
</view>
</block>
<!-- <block wx:if="{{item.FaceSN.length==0}}">
style="opacity:0"
<view class="text-sm light">
xiaoxi
</view>
class="text-df light" style="opacity:0"
<view class="text-sm light">
xiaoxi
</view>
</block> -->
</block>
<block wx:else="{{item.FaceStatus==false}}">
<block wx:if="{{item.FaceSN.length>0}}">
<view style="color: #d11515;" class="text-df">s:{{item.FaceSN[0]}}{{item.FaceSN[1]}}{{item.FaceSN[2]}}{{item.FaceSN[3]}}{{item.FaceSN[4]}}{{item.FaceSN[5]}}{{item.FaceSN[6]}}{{item.FaceSN[7]}}
</view>
<view style="color:#d11515;" class="text-df">{{item.FaceSN[8]}}{{item.FaceSN[9]}}{{item.FaceSN[10]}}{{item.FaceSN[11]}}{{item.FaceSN[12]}}{{item.FaceSN[13]}}{{item.FaceSN[14]}}{{item.FaceSN[15]}}
</view>
</block>
<block wx:if="{{item.FaceSN.length==0}}">
<!-- class="text-sm light" style="opacity:0" -->
<view class="text-sm light">
<!-- xiaoxi -->人脸机
</view>
<!-- class="text-df light" style="opacity:0" -->
<view class="text-sm light" style="color: #e7ebed;">
绑定
</view>
</block>
</block>
</view>
</view>
</view>
</view>
<view wx:if="{{HostsDataFilters.length<=0}}">
暂无数据~
</view>
</view>
</scroll-view>
<HostUpgrade wx:if="{{showinfo==4}}" paramA="{{showinfo}}" myProperty="{{roomtype}}" nheight="{{top_height==null?'600':top_height}}" style="height:{{top_height==null?'600rpx':top_height+'rpx'}} ;padding-bottom:10rpx"></HostUpgrade>
<Upgrade wx:if="{{showinfo==5}}" style="height:{{top_height==null?'600rpx':top_height+'px'}} ;padding-top:10rpx;"></Upgrade>
<!-- 帮助区域 -->
<view wx:if="{{Help}}" class="padding-xs">
<view class="cu-card article">
<view class="cu-item shadow " style="margin:0;padding-bottom:0;">
<view class="title" style="line-height:initial;"><view class="text-cut">颜色指示块</view></view>
<view class="content">
<view class="desc">
<view class="text-content text-df">
指示块,仅针对本次进入页面有效,不代表历史操作记录,刷新或者重新进入页面都会执行重置操作。
</view>
</view>
</view>
</view>
</view>
<view class="cu-card article">
<view class="cu-item shadow " style="margin:0;padding-bottom:0;">
<view class="title" style="line-height:initial;"><view class="text-cut">MAC绑定操作</view></view>
<view class="content">
<view class="desc">
<view class="text-content text-df" style="height: auto;">
<view class="text-df text-green">点击</view>
点击房间如果已经绑定MAC会弹出提示语句点击继续继续执行扫码绑定扫码后,会有普通的MAC矫正如果MAC已经被绑定会再次弹出提示语句
如果MAC绑定的酒店有权限就会有提示语句然后可以点击继续执行绑定这将解除原有绑定绑定当前MAC;如果MAC绑定的酒店没有权限就仅有提示语而没有继续绑定按钮。
<view class="text-df text-green">长按</view>
长按会执行手动输入MAC后续与点击扫码绑定一致~
</view>
</view>
</view>
</view>
</view>
</view>
<!-- 操作日志 -->
<view wx:if="{{islogs}}" >
<loscom hotelsid="{{Hotelinfo.HotelId}}"></loscom>
</view>
</view>
<!-- 房间已经绑定弹窗提示 -->
<view class="cu-modal {{modal==1?'show':''}}">
<view class="cu-Ndialog">
<view class="cu-bar bg-white ">
<view>
<view class="action " bindtap="GetReturnSet" wx:if="{{ISLoopDebugging>0}}">
<text class="cuIcon-back"></text>
</view>
</view>
<view>
<view class="content text-{{selHosts.Status == 1 ? 'green':'red'}}}" >{{selHosts.RoomNumber}}已经绑定MAC({{selHosts.Status == 1 ? '在线':'离线'}})</view>
</view>
<view class="justify-end">
<view class="action justify-end" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
</view>
<view wx:if="{{ISLoopDebugging===0}}">
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">酒店:</view><view class="text-left basis-lg">{{Hotelinfo.HotelName}}</view>
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{message[1]}}</view>
<view class="basis-sm text-right">MAC地址</view><view class="basis-lg text-left">{{message[0]}}</view>
<view class="basis-sm text-right">当前固件:</view><view class="basis-lg text-left">{{roomGfilename}}</view>
<view class="basis-sm text-right">当前配置:</view><view class="basis-lg text-left">{{roomPfilename}}</view>
<view class=" text-left flex-sub text-sm text-gray">房间已经绑定MAC点击继续将执行扫描绑定点击取消将不会执行任何操作~</view>
</view>
<view class=" bg-white">
<view class="Ncu-bar bg-white">
<view class="action margin-0 flex-sub text-green " data-type="0" bindtap="ConfigurationUpgrade">固件升级</view>
<view class="action margin-0 flex-sub text-green solid-left" bindtap="FirmwareUpgrade" >配置升级</view>
<view class="action margin-0 flex-sub solid-left" bindtap="LoopDebugging" >回路调试</view>
</view>
<view class="Ncu-bar bg-white">
<view class="action margin-0 flex-sub text-green " data-type="0" bindtap="ErrorInfo">反馈错误</view>
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view class="action margin-0 flex-sub solid-left" bindtap="{{input == 0?'GetCode':'ShowInput'}}" >继续</view>
</view>
</view>
</view>
<view wx:if="{{ISLoopDebugging===1}}" style="height:95%" class="bg-white" >
<scroll-view style="height:90%" id="LoopDebugging" scroll-y="true" scroll-top="true">
<view class="bg-white ">
<!-- <view style="text-align: left;font-weight: bold">播放测试:</view> -->
<!-- <view style="text-align: left;font-weight: bold">播放测试:</view> -->
<view class="Ncu-bar bg-white">
<button bindtap="GetshowinfoClick" class="cu-btn round1 ulg margin-5" style="font-weight: bold;">播放欢迎词</button>
<!-- <view style="text-align: left;font-weight: bold" class=" margin-xs radius ">音量:</view> -->
<slider style="width:50%;" min="30" max="100" step="1" value="{{VolumeLevel}}" bindchange="changeVolumeLevel" ></slider>
<view>{{VolumeLevel}}</view>
</view>
<view class="ControlLine"></view>
</view>
<view class="bg-white " wx:for="{{roomtypeInfoNodeinfo}}" wx:for-item="row" wx:for-index="rowIndex">
<view class=" bg-white " wx:if="{{row[0]===1}}" >
<!-- <view style="text-align: left;font-weight: bold">设置设备开关状态:</view> -->
<view class="Ncu-bar bg-white flex-sub" wx:for="{{row[1].length/4 }}" wx:for-index="colIndex" >
<view class="Ncu-bar bg-white" wx:if="{{colIndex*4<row[1].length}}">
<button id="1" class="cu-btn round1 margin-3 vlg" data-value="1" data-index="{{row[1][colIndex*4][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*4<row[1].length}}" style="background-color: {{row[1][colIndex*4][2][0][2]===0 ? '#E6E6E6 ':'#39b54a'}};" >{{row[1][colIndex*4][1] }}</button>
<button id="1" class="cu-btn round1 margin-3 vlg" data-value="1" data-index="{{row[1][colIndex*4+1][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*4+1<row[1].length}}" style="background-color: {{row[1][colIndex*4+1][2][0][2]===0 ? '#E6E6E6':'#39b54a'}};">{{row[1][colIndex*4+1][1] }}</button>
<button id="1" class="cu-btn round1 margin-3 vlg" data-value="1" data-index="{{row[1][colIndex*4+2][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*4+2<row[1].length}}" style="background-color: {{row[1][colIndex*4+2][2][0][2]===0 ? '#E6E6E6':'#39b54a'}};">{{row[1][colIndex*4+2][1] }}</button>
<button id="1" class="cu-btn round1 margin-3 vlg" data-value="1" data-index="{{row[1][colIndex*4+3][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*4+3<row[1].length}}" style="background-color: {{row[1][colIndex*4+3][2][0][2]===0 ? '#E6E6E6':'#39b54a'}};">{{row[1][colIndex*4+3][1] }}</button>
<!-- <button class="cu-btn round margin-3 nlg" data-index="{{row[1][colIndex*5+4][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*4+4<row[1].length}}">{{row[1][colIndex*4+4][1] }}</button> -->
<!-- <button class="cu-btn round margin-3 nlg" data-index="{{row[1][colIndex*6+5][0]}}" bindtap="SetDeviceSwitchStatus" wx:if="{{colIndex*6+5<row[1].length}}">{{row[1][colIndex*6+5][1] }}</button> -->
</view>
</view>
<view class="ControlLine"></view>
</view>
<view class="bg-white" wx:if="{{row[0]===23}}">
<!-- <view style="text-align: left;font-weight: bold">设置调光亮度:</view> -->
<view class="bg-white" wx:for="{{row[1].length}}" wx:for-index="DimIndex" >
<view class="Ncu-bar bg-white">
<view class="flex-twice">{{row[1][DimIndex][1]}}</view>
<slider id="23" data-index="{{row[1][DimIndex][0]}}" class="flex-eight" min="10" max="90" step="1" value="{{row[1][DimIndex][2][0][2]}}" bindchange="SetDeviceSwitchStatusslider" ></slider>
<view class="flex-sub">{{row[1][DimIndex][2][0][2]}}</view>
</view>
</view>
<view class="ControlLine"></view>
</view>
<view class="bg-white" wx:if="{{row[0]===52}}">
<!-- <view style="text-align: left;font-weight: bold">色温控制:</view> -->
<view class="Ncu-bar bg-white">
<view class="action margin-0 flex-twice text-green " >开关</view>
<view class="action margin-0 flex-xis text-green solid-left" >色温</view>
<view class="action margin-0 flex-xis text-green solid-left" >亮度</view>
</view>
<view class=" bg-white" wx:for="{{row[1].length}}" wx:for-index="coloIndex" >
<view class="Ncu-bar bg-white">
<view class=" flex-twice margin-3 " >
<button id="52" data-type="1" data-value="1" data-index="{{row[1][coloIndex][0]}}" class="cu-btn round1 Elg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][0][2]===0 ? '#E6E6E6 ':'#39b54a'}};" >{{row[1][coloIndex][1]}}</button>
</view>
<view class=" flex-xis Ncubar1 solid-left " >
<button id="52" data-type="2" data-value="20" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][1][2]===20 ? '#39b54a':'#E6E6E6 '}};">20</button>
<button id="52" data-type="2" data-value="50" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][1][2]===50 ? '#39b54a':'#E6E6E6 '}};">50</button>
<button id="52" data-type="2" data-value="80" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][1][2]===80 ? '#39b54a':'#E6E6E6 '}};">80</button>
</view>
<view class="ControlLine_h"></view>
<view class=" flex-xis Ncubar1 " >
<button id="52" data-type="3" data-value="20" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][2][2]===20 ? '#39b54a':'#E6E6E6 '}};">20</button>
<button id="52" data-type="3" data-value="50" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][2][2]===50 ? '#39b54a':'#E6E6E6 '}};">50</button>
<button id="52" data-type="3" data-value="80" data-index="{{row[1][coloIndex][0]}}" class="margin-3 cu-btn round1 EElg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][2][2]===80 ? '#39b54a':'#E6E6E6 '}};">80</button>
</view>
</view>
<!-- <view class="Ncubar1 bg-white" style="text-align: left;">
<view class="flex-twice">
<view style="text-align: left;font-weight: bold">{{row[1][coloIndex][1]}}:</view>
</view>
<view class="flex-8">
<switch class="Green" data-index="{{item}}" bindchange="Loopswitch"></switch>
</view>
</view> -->
<!-- <view class="Ncu-bar bg-white flex-eight">
<button class="cu-btn round vlg">亮度20</button>
<button class="cu-btn round vlg">亮度80</button>
<button class="cu-btn round vlg">色温20</button>
<button class="cu-btn round vlg">色温80</button>
</view> -->
</view>
<view class="ControlLine"></view>
</view>
<view class="bg-white" wx:if="{{row[0]===5}}">
<!-- <view style="text-align: left;font-weight: bold">设置设备开停关状态:</view> -->
<view class="bg-white" wx:for="{{row[1].length}}" wx:for-index="coloIndex">
<view class="Ncu-bar bg-white">
<view class="flex-treble" style="font-weight: bold">{{row[1][coloIndex][1]}}</view>
<view class="Ncubar1 bg-white flex-eight">
<button id="5" data-value="1" class="margin-3 cu-btn round1 clg" style="background-color:{{row[1][coloIndex][2][0][2]===1 ? '#39b54a':'#E6E6E6'}};" data-index="{{row[1][coloIndex][0]}}" bindtap="SetDeviceSwitchStatus" >开</button>
<button id="5" data-value="2" class="margin-3 cu-btn round1 clg" style="background-color:{{row[1][coloIndex][2][0][2]===2 ? '#39b54a':'#E6E6E6'}};" data-index="{{row[1][coloIndex][0]}}" bindtap="SetDeviceSwitchStatus" >关</button>
<button id="5" data-value="6" class="margin-3 cu-btn round1 clg" style="background-color:{{row[1][coloIndex][2][0][2]===6 ? '#39b54a':'#E6E6E6'}};" data-index="{{row[1][coloIndex][0]}}" bindtap="SetDeviceSwitchStatus">停</button>
</view>
</view>
<view class="ControlLine"></view>
</view>
<view class="ControlLine"></view>
</view>
<view class="bg-white" wx:if="{{row[0]===7}}">
<!-- <view style="text-align: left;font-weight: bold">设置温控设备状态:</view> -->
<view class=" bg-white" wx:for="{{row[1].length}}" wx:for-index="coloIndex">
<view class="Ncu-bar bg-white">
<view class=" flex-twice margin-xs " >
<!-- <button class="cu-btn round1 Elg">{{row[1][coloIndex][1]}}</button> -->
<button id="7" data-type="1" data-value="1" data-index="{{row[1][coloIndex][0]}}" class="cu-btn round1 Elg" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][0][2]===0 ? '#E6E6E6 ':'#39b54a'}};" >{{row[1][coloIndex][1]}}</button>
</view>
<view class=" flex-8 Ncubar1 solid-left " >
<button id="7" data-type="2" data-value="1" data-index="{{row[1][coloIndex][0]}}" class=" cu-btn round1 clg margin-3" bindtap="SetDeviceSwitchStatus" style="background-color: {{row[1][coloIndex][2][1][2]===4 ? '#E6E6E6 ':row[1][coloIndex][2][1][2]===3 ? '#1cbbb4':row[1][coloIndex][2][1][2]===2 ? '#e54d42':'#0081ff'}};" >{{row[1][coloIndex][2][1][2]===4 ? '自动':row[1][coloIndex][2][1][2]===3 ? '送风':row[1][coloIndex][2][1][2]===2 ? '制热':'制冷'}}</button>
<button id="7" data-type="3" data-value="1" data-index="{{row[1][coloIndex][0]}}" class=" cu-btn round1 clg margin-3" bindtap="SetDeviceSwitchStatus" >{{row[1][coloIndex][2][2][2]===4 ? '自动':row[1][coloIndex][2][2][2]===3 ? '高风速':row[1][coloIndex][2][2][2]===2 ? '中风速':'低风速'}}</button>
<button id="7" data-type="4" data-value="1" data-index="{{row[1][coloIndex][0]}}" bindtap="SetDeviceSwitchStatus" class=" cu-btn round1 vvlg margin-3">-</button>
<text class=" textvlg">{{row[1][coloIndex][2][3][2]}}</text>
<button id="7" data-type="5" data-value="1" data-index="{{row[1][coloIndex][0]}}" bindtap="SetDeviceSwitchStatus" class=" cu-btn round1 vvlg margin-3">+</button>
</view>
</view>
<!-- <view class="Ncubar1 bg-white" style="text-align: left;">
<view class="flex-twice">
<view style="text-align: left;font-weight: bold">{{row[1][coloIndex][1]}}:</view>
</view>
<view class="flex-8">
<switch class="Green" data-index="{{item}}" bindchange="Loopswitch"></switch>
</view>
</view>
<view class=" bg-white flex-eight">
<view class="Ncu-bar bg-white flex-eight">
<button class=" cu-btn round1 vlg margin-3">制冷</button>
<button class=" cu-btn round1 vlg margin-3">制热</button>
<button class=" cu-btn round1 vlg margin-3">20度</button>
<button class=" cu-btn round1 vlg margin-3">30度</button>
</view>
<view class="Ncu-bar bg-white flex-eight">
<button class="cu-btn round1 vlg margin-3">风速高</button>
<button class="cu-btn round1 vlg margin-3">风速中</button>
<button class="cu-btn round1 vlg margin-3">风速低</button>
<button class="cu-btn round1 vlg margin-3">自动</button>
</view>
</view> -->
<view class="ControlLine"></view>
</view>
<view class="ControlLine"></view>
</view>
</view>
</scroll-view>
</view>
<view wx:if="{{ISLoopDebugging===2}}" class="bg-white" >
<view style="text-align: left;font-weight: bold">设备当前版本:</view>
<view>{{UpgradestIstrue == 0? Upgradenode.Gfilename:Upgradenode.Pfilename}}</view>
<view style="text-align: left;font-weight: bold">准备升级版本:</view>
<view>{{UpgradestIstrue == 0? Upgradenode.App_Cfg_For_L4:Upgradenode.CONFIG_BIN}}</view>
<view class="Ncubar1 bg-white">
<view class=" text-left " wx:if="{{Upgradestatus.length>0}}" >升级状态:</view>
<view class=" text-left " style="font-weight: bold;">{{Upgradestatus}}</view>
</view>
</view>
</view>
</view>
<!-- MAC已经被绑定弹窗提示 -->
<view class="cu-modal {{modal==3 || modal==4?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">{{code}}已经被绑定</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-xs flex flex-wrap justify-center " >
<view class="basis-xl text-sm" wx:for="{{bdHosts}}" >
<text class=" text-right ">酒店:</text><text class="text-left text-red">{{item.HotelName}}</text>
<text class="padding-left-xs text-right " >房间:</text><text class="text-left text-red">{{item.RoomNumber}}</text>
<button class="cu-btn margin-left-xs sm bg-red" wx:if="{{item.qx == 0}}" data-index="{{index}}" type="" bindtap="Jb" >解绑</button>
<button class="cu-btn margin-left-xs sm bg-red" wx:if="{{item.qx != 0}}" disabled >解绑</button>
</view>
<view class="basis-xl">MAC地址<text class="text-left">{{code}}</text></view>
<view class="basis-xl text-left text-sm text-gray">MAC已经被其他房间绑定点击继续将取消原有绑定执行新的绑定点击取消将不会执行任何操作~</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green " data-type="1" bindtap="ErrorInfo">反馈错误</view>
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view wx:if="{{bdHosts.length<=0}}" class="action margin-0 flex-sub solid-left" data-type="false" bindtap="GetMacOKend" >继续</view>
</view>
</view>
</view>
<!-- 手动输入mac地址 -->
<view class="cu-modal {{modal==1000?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">为{{selHosts.RoomNumber}}绑定MAC</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{selHosts.RoomNumber}}</view>
<view class="basis-sm text-right">MAC地址</view>
<view class="basis-lg text-left">
<input placeholder="手动输入MAC" model:value="{{code}}" name="input"></input>
</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view class="action margin-0 flex-sub solid-left" bindtap="GetMACOK" >确认</view>
</view>
</view>
</view>
<!-- 确定绑定 -->
<view class="cu-modal {{modal==521?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">绑定确认</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">酒店:</view><view class="text-left basis-lg">{{Hotelinfo.HotelName}}</view>
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{selHosts.RoomNumber}}</view>
<view class="basis-sm text-right">MAC地址</view><view class="basis-lg text-left">{{code}}</view>
<view class=" text-left flex-sub text-sm text-gray">确定为房间绑定MAC点击继续将执行扫描绑定点击取消将不会执行任何操作~</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view class="action margin-0 flex-sub solid-left" data-type="true" bindtap="GetMacOKend" >继续</view>
</view>
</view>
</view>
<!-- 无效条形码 -->
<view class="cu-modal {{modal==520?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">无效条码</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">无效条码:</view><view class="basis-lg text-left">{{code}}</view>
<view class=" text-left flex-sub text-sm text-gray">扫描的条码为无效条码~</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >确定</view>
</view>
</view>
</view>
<!-- 确定绑定 -->
<view class="cu-modal {{modal==-521?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">绑定确认</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">酒店:</view><view class="text-left basis-lg">{{Hotelinfo.HotelName}}</view>
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{selHosts.RoomNumber}}</view>
<view class="basis-sm text-right">人脸机SN</view><view class="basis-lg text-left">{{code}}</view>
<view class=" text-left flex-sub text-sm text-gray">确定为房间绑定SN点击继续将执行扫描绑定点击取消将不会执行任何操作~</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view class="action margin-0 flex-sub solid-left" data-type="true" bindtap="GetFaceSNend" >继续</view>
</view>
</view>
</view>
<!-- 房间已经绑定人脸机弹窗提示 -->
<view class="cu-modal {{modal==-1?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">{{selHosts.RoomNumber}}已经绑定人脸机</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">酒店:</view><view class="text-left basis-lg">{{Hotelinfo.HotelName}}</view>
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{message[1]}}</view>
<view class="basis-sm text-right">人脸机SN</view><view class="basis-lg text-left">{{message[0]}}</view>
<view class=" text-left flex-sub text-sm text-gray">房间已经绑定人脸机,点击继续将执行扫描绑定;点击取消,将不会执行任何操作~</view>
</view>
<view class="cu-bar bg-white">
<!-- <view class="action margin-0 flex-sub " data-type="0" bindtap="ErrorInfo">反馈错误</view>text-red -->
<view id="{{Hotelinfo.HotelName}}_{{message[1]}}_{{message[0]}}_{{Hotelinfo.Code}}_{{Hotelinfo.HotelId}}" class="action margin-0 flex-sub text-green solid-left" style="font-weight: 600;" bindtap="testinfo" >设置</view>
<view id="{{Hotelinfo.HotelName}}_{{message[1]}}_{{message[0]}}_{{Hotelinfo.Code}}" class="action margin-0 flex-sub text-green solid-left" style="font-weight: 600;" bindtap="OpenDoor" >开门</view>
<!-- <view class="action margin-0 flex-sub {{selHosts.FaceSN!=''?'show':''}} text-red solid-left" bindtap="JbSn" >解绑</view> -->
<!-- <view class="action margin-0 flex-sub solid-left" bindtap="GetHide" >取消</view> -->
<!-- <view class="action margin-0 flex-sub text-green solid-left" bindtap="{{FaceSNinput == 0?'GetFaceCode':'ShowInputsn'}}" >继续</view> -->
</view>
</view>
</view>
<!-- SN已经被绑定弹窗提示 -->
<view class="cu-modal {{modal==-200?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">{{code}}已经被绑定
</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-xs flex flex-wrap justify-center " >
<view class="basis-xl text-sm" wx:for="{{bdHosts}}" >
<text class=" text-right ">酒店:</text><text class="text-left text-red">{{item.HotelName}}</text>
<text class="padding-left-xs text-right " >房间:</text><text class="text-left text-red">{{item.RoomNumber}}</text>
<button class="cu-btn margin-left-xs sm bg-red" wx:if="{{item.qx == 0}}" data-index="{{index}}" type="" bindtap="JbSn" >解绑</button>
<button class="cu-btn margin-left-xs sm bg-red" wx:if="{{item.qx != 0}}" disabled >解绑</button>
</view>
<view class="basis-xl">SN<text class="text-left">{{code}}</text></view>
<view class="basis-xl text-left text-sm text-gray">SN已经被其他房间绑定点击继续将取消原有绑定执行新的绑定点击取消将不会执行任何操作~</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view wx:if="{{bdHosts.length<=0}}" class="action margin-0 flex-sub solid-left" data-type="false" bindtap="GetFaceSNend" >继续</view>
</view>
</view>
</view>
<!-- 手动输入SN地址 -->
<view class="cu-modal {{modal==-1000?'show':''}}">
<view class="cu-dialog">
<view class="cu-bar bg-white justify-end">
<view class="content">为{{selHosts.RoomNumber}}绑定人脸机SN</view>
<view class="action" bindtap="GetHide" >
<text class="cuIcon-close text-red"></text>
</view>
</view>
<view class="padding-lg flex flex-wrap " >
<view class="basis-sm text-right">房间:</view><view class="basis-lg text-left">{{selHosts.RoomNumber}}</view>
<view class="basis-sm text-right">人脸机SN</view>
<view class="basis-lg text-left">
<input placeholder="手动输入SN" model:value="{{code}}" name="input"></input>
</view>
</view>
<view class="cu-bar bg-white">
<view class="action margin-0 flex-sub text-green solid-left" bindtap="GetHide" >取消</view>
<view class="action margin-0 flex-sub solid-left" bindtap="GetFaceSNOK" >确认</view>
</view>
</view>
</view>

View File

@@ -1,42 +0,0 @@
.Ncu-bar {
display: flex;
position: relative;
align-items: center;
min-height: 70rpx ;
justify-content: space-between;
}
.Ncu-bar1 {
display: flex;
position: relative;
align-items: center;
min-height: 70rpx ;
}
.Ncubar1 {
display: flex;
position: relative;
align-items:flex-start;
min-height: 70rpx ;
}
.ControlLine{
background-color: gray;
height: 1rpx;
width: 100%;
}
.ControlLine_h{
background-color: lightgray;
height: 80rpx;
width: 1rpx;
}
.textvlg {
display: inline-flex;
align-items: center;
justify-content: center;
text-align:center;
padding: 0 5rpx;
font-size:28rpx;
height: 80rpx;
width: 70rpx;
text-decoration: none;
}

View File

@@ -62,6 +62,10 @@ Page({
bdHosts: [], bdHosts: [],
address: "", address: "",
UpgradeType:"", UpgradeType:"",
checkedCount: 0,
totalCount: 0,
successCount: 0,
failCount: 0,
}, },
/** /**
@@ -145,13 +149,33 @@ Page({
upgrader.on('progress', p => { upgrader.on('progress', p => {
console.log(p) console.log('upgrader progress:', p)
this.setData({ CurrentUpgradeDevStart: p }) // 实时刷新 UI try {
// 支持数字或对象 {percent:xx} 或字符串数字
let prog = p && typeof p === 'object' && p.percent != null ? p.percent : (typeof p === 'number' ? p : (typeof p === 'string' && !isNaN(Number(p)) ? Number(p) : p));
const cur = this.data.CurrentUpgradeDev;
if (cur && this.data.devlist && Array.isArray(this.data.devlist)) {
const devlist = this.data.devlist.slice();
const idx = devlist.findIndex(d => String(d.RoomNumber) === String(cur) || String(d.ID) === String(cur));
if (idx >= 0) {
devlist[idx].UpgradeProgress = prog;
if (!devlist[idx].UpgradeStatus || devlist[idx].UpgradeStatus === 0) devlist[idx].UpgradeStatus = 1; // 进行中
this.setData({ devlist });
}
}
this.setData({ CurrentUpgradeDevStart: p });
} catch (e) {
console.log(e)
this.setData({ CurrentUpgradeDevStart: p });
}
}) })
upgrader.on('error', e => { upgrader.on('error', e => {
wx.showToast({ title: '升级失败', icon: 'none' }) wx.showToast({ title: '升级失败', icon: 'none' })
}) })
// 初始化计数
try { this.updateCounts && this.updateCounts(); } catch (e) { console.log('init counts error', e); }
}, },
/** /**
@@ -575,6 +599,7 @@ Page({
for (let i = 0; i < this.data.devlist.length; i++) { for (let i = 0; i < this.data.devlist.length; i++) {
devlist[i].UpgradeStatus = 0 devlist[i].UpgradeStatus = 0
devlist[i].UpgradeProgress = "";
if (devlist[i].checkbox) { //勾选 if (devlist[i].checkbox) { //勾选
if (devlist[i].Status) { //离在线 if (devlist[i].Status) { //离在线
@@ -618,30 +643,63 @@ Page({
hotelid:HotelId hotelid:HotelId
}) })
.then(res => { .then(res => {
_this.setData({ // 标记对应设备为已完成,并更新进度,取消勾选
UpgradeCount:_this.data.UpgradeCount+1, //升级计数 try {
}) const devlist = _this.data.devlist.slice();
const idx = devlist.findIndex(d => String(d.ID) === String(element.ID) || String(d.RoomNumber) === String(element.RoomNumber));
if (idx >= 0) {
devlist[idx].UpgradeProgress = 100;
devlist[idx].UpgradeStatus = 2; // 完成
devlist[idx].checkbox = false;
_this.setData({ devlist, UpgradeCount: _this.data.UpgradeCount + 1 }, () => { _this.updateCounts && _this.updateCounts(); });
} else {
_this.setData({ UpgradeCount: _this.data.UpgradeCount + 1 }, () => { _this.updateCounts && _this.updateCounts(); });
}
} catch (err) {
console.log('update dev progress error', err);
_this.setData({ UpgradeCount: _this.data.UpgradeCount + 1 });
}
console.log('升级完成', res) console.log('升级完成', res)
}) })
.catch(err =>{ .catch(err =>{
// 标记对应设备为失败,取消勾选,并继续下一个
try {
const devlist = _this.data.devlist.slice();
const idx = devlist.findIndex(d => String(d.ID) === String(element.ID) || String(d.RoomNumber) === String(element.RoomNumber));
if (idx >= 0) {
devlist[idx].UpgradeProgress = "";
devlist[idx].UpgradeStatus = 3; // 失败
// 保持勾选状态(不取消),以便用户查看/重试
_this.setData({ devlist }, () => { _this.updateCounts && _this.updateCounts(); });
}
} catch (err2) {
console.log('update dev fail state error', err2);
}
console.log('升级失败', err) console.log('升级失败', err)
}); });
}catch (error) { }catch (error) {
_this.setData({ // 如果 startUpgrade 抛出异常,标记该设备为失败并继续下一个
//升级计数 try {
CurrentUpgradeDev:element.RoomNumber, //当前升级设备 const devlist2 = _this.data.devlist.slice();
CurrentUpgradeDevStart:errstr+',服务器响应异常',//当前升级设备状态 const idx2 = devlist2.findIndex(d => String(d.ID) === String(element.ID) || String(d.RoomNumber) === String(element.RoomNumber));
Completed:false if (idx2 >= 0) {
}) devlist2[idx2].UpgradeProgress = "";
//this.DisplayPrompt(errstr+',服务器响应异常',1000) devlist2[idx2].UpgradeStatus = 3; // 失败
return // 保持勾选状态(不取消),以便用户查看/重试
_this.setData({ devlist: devlist2 }, () => { _this.updateCounts && _this.updateCounts(); });
}
} catch (err2) {
console.log('handle thrown upgrade error', err2);
}
console.log('升级异常', error);
// 不 return继续下一个设备
} }
} }
this.DisplayPrompt2("升级完成!", 1000) this.DisplayPrompt2("升级完成!", 1000)
// 所有设备处理完毕,取消批量升级标记
_this.setData({ Completed:false });
}, },
DisplayPrompt2(tipstr, showtime) DisplayPrompt2(tipstr, showtime)
@@ -665,7 +723,7 @@ Page({
this.setData({ this.setData({
devlist:devlist, devlist:devlist,
Allcheckbox:values Allcheckbox:values
}); }, () => { this.updateCounts && this.updateCounts(); });
}, },
checkboxSub(e){ checkboxSub(e){
let devlist =this.data.devlist let devlist =this.data.devlist
@@ -691,7 +749,7 @@ Page({
devlist:devlist, devlist:devlist,
Allcheckbox:values, Allcheckbox:values,
checksun:checksun checksun:checksun
}); }, () => { this.updateCounts && this.updateCounts(); });
}, },
SearchForHotels(e){ SearchForHotels(e){
//debugger //debugger
@@ -889,6 +947,7 @@ Page({
devlist[nindex].show=1 devlist[nindex].show=1
devlist[nindex].checkbox=0 devlist[nindex].checkbox=0
devlist[nindex].UpgradeStatus=0 devlist[nindex].UpgradeStatus=0
devlist[nindex].UpgradeProgress = "";
devlist[nindex].Model =_this.removeNullCharsAndInvisibleChars(devlist[nindex].Model) devlist[nindex].Model =_this.removeNullCharsAndInvisibleChars(devlist[nindex].Model)
} }
} }
@@ -926,7 +985,7 @@ if (Nres.Status==200) {
Pfilename:Pfilename, Pfilename:Pfilename,
Gfilename:Gfilename, Gfilename:Gfilename,
Upgradenode:Upgradenode Upgradenode:Upgradenode
}); }, () => { this.updateCounts && this.updateCounts(); });
console.log(devlist) console.log(devlist)
} catch (err) { } catch (err) {
console.log('GetRoomTypeNode error', err); console.log('GetRoomTypeNode error', err);
@@ -940,6 +999,18 @@ if (Nres.Status==200) {
return "NULL" return "NULL"
} }
},
updateCounts() {
try {
const devlist = Array.isArray(this.data.devlist) ? this.data.devlist : [];
const total = devlist.length;
const checked = devlist.filter(d => d && d.checkbox).length;
const success = devlist.filter(d => d && Number(d.UpgradeStatus) === 2).length;
const fail = devlist.filter(d => d && Number(d.UpgradeStatus) === 3).length;
this.setData({ checkedCount: checked, totalCount: total, successCount: success, failCount: fail });
} catch (e) {
console.log('updateCounts error', e);
}
}, },
tabSelect(e) { tabSelect(e) {
this.setData({ this.setData({

View File

@@ -48,13 +48,17 @@
</view> </view>
<scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight}}rpx;" > <scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight-30}}rpx;" >
<view class='nav-list1 bg-white' bindtouchstart="handleTouchStart" <view class='nav-list1' bindtouchstart="handleTouchStart"
bindtouchend="handleTouchEnd" style="margin-top: 20rpx;"> bindtouchend="handleTouchEnd" style="margin-bottom: 30rpx;">
<view bindtap="goProcess" bindlongtap="GetMAC_long" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}" <view bindtap="goProcess" bindlongtap="GetMAC_long" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}"
data-status="{{item.Status}}" data-HotelCode="{{Hotelinfo.Code}}" data-roomtypeid="{{item.RoomTypeID}}" hover-class="navigator-hover" class="nav-li4 bg-{{item.Status===1? 'cyan':'gray'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key> data-status="{{item.Status}}" data-HotelCode="{{Hotelinfo.Code}}" data-roomtypeid="{{item.RoomTypeID}}" hover-class="navigator-hover" class="nav-li4 {{item.Status===1? 'online':'offline'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key>
<view style="font-size: 32rpx;justify-content:start" >{{item.RoomNumber}}</view> <view style="font-size: 32rpx;justify-content:start" >{{item.RoomNumber}}</view>
<view style="font-size: 20rpx;justify-content:start" >{{item.MAC}}</view> <view style="font-size: 20rpx;justify-content:start; color: {{(!item.MAC && item.Status !== 1) ? '#FF3B30' : '#666666'}};" >
{{item.MAC || (item.Status !== 1 ? '点击扫码绑定主机' : '')}}
</view>
<!-- 升级进度显示(若当前正在升级此房间) -->
<view wx:if="{{CurrentUpgradeDev == item.RoomNumber}}" class="upgrade-badge">升级: {{CurrentUpgradeDevStart}}</view>
</view> </view>
</view> </view>
@@ -103,30 +107,47 @@ bindtouchend="handleTouchEnd" style="margin-top: 20rpx;">
</view> </view>
<view class=" flex align-center " style="height: 70rpx;background: aquamarine;" > <view class=" flex align-center " style="height: 70rpx;background: aquamarine;" >
<view class="flex-treble margin-xs" style="height: 50rpx;" bindtap="ALLcheckboxSub" > <view class="flex-treble margin-xs" style="height: 50rpx;" bindtap="ALLcheckboxSub" >
<checkbox checked="{{Allcheckbox}}" ></checkbox> <checkbox checked="{{Allcheckbox}}" ></checkbox>
<text >全选</text> <text >全选</text>
</view> </view>
<view class="flex-eight" >正在升级房号:{{CurrentUpgradeDev}}:{{CurrentUpgradeDevStart}}</view>
<view class="flex-treble " style="justify-content: flex-end">已升级设备: {{UpgradeCount}} </view> <view class="flex" style="margin-left: 12rpx; align-items: center;">
<text style="margin-right:12rpx">已勾选: {{checkedCount}}/{{totalCount}}</text>
<text style="margin-right:12rpx">成功: {{successCount}}</text>
<text>失败: {{failCount}}</text>
</view>
</view> </view>
<!-- 排序卡片 -->
<view class=" flex align-center " style="height: 40rpx;background: aquamarine; justify-content:flex-end; padding-right:12rpx;" >
<view style="display:flex; align-items:center; margin-left:12rpx;">
<checkbox checked="{{Allcheckbox}}"></checkbox>
<text style="margin-left:6rpx;">房号排序</text>
</view>
<view style="display:flex; align-items:center; margin-left:12rpx;">
<checkbox checked="{{Allcheckbox}}"></checkbox>
<text style="margin-left:6rpx;">固件版本排序</text>
</view>
<view style="display:flex; align-items:center; margin-left:12rpx;">
<checkbox checked="{{Allcheckbox}}"></checkbox>
<text style="margin-left:6rpx;">配置版本排序</text>
</view>
</view>
<scroll-view id="myScroll" scroll-into-view="{{toView}}" scroll-y="true" style="height:{{scrollHeight-100}}rpx;" > <scroll-view id="myScroll" scroll-into-view="{{toView}}" scroll-y="true" style="height:{{scrollHeight-100}}rpx;" >
<view wx:for="{{devlist.length}}" wx:key="index" class=" bg-white padding-5" > <view wx:for="{{devlist.length}}" wx:key="index" class=" nav-list1 padding-5" >
<view class="bg-white" > <view style="width: 98%;" >
<view class="cubarN bg-white" > <view class="cubarN bg-white" >
<view class="flex-xsub margin-xs" data-id ="{{index}}" bindtap="checkboxSub" > <view class="flex-xsub margin-xs" data-id ="{{index}}" bindtap="checkboxSub" >
<checkbox style="top:25%;" checked="{{devlist[index].checkbox}}" ></checkbox> <checkbox style="top:25%;" checked="{{devlist[index].checkbox}}" ></checkbox>
</view> </view>
<view class="cubarN bg-white flex-9" data-id ="{{index}}" bindtap="HideOrOpen" style="background:{{devlist[index].UpgradeStatus ==0? 'white':devlist[index].UpgradeStatus ==1? 'green':'red' }} ;"> <view class="cubarN flex-9" data-id ="{{index}}" bindtap="HideOrOpen" style="background:{{devlist[index].UpgradeStatus ==0? 'white':devlist[index].UpgradeStatus ==1? 'green':'red' }} ;">
<view class="flex-5" style="font-weight: bold;" >房号:{{devlist[index].RoomNumber}}</view> <view class="flex-5" style="font-weight: bold;" >房号:{{devlist[index].RoomNumber}}</view>
<view class="flex flex-xis"> <view class="flex flex-xis">
<view class="flex-xis" > <view class="flex-xis" >
@@ -147,6 +168,20 @@ bindtouchend="handleTouchEnd" style="margin-top: 20rpx;">
</view> </view>
<view class="cubarN bg-white solid-bottom "> <!-- wx:if="{{devlist[index].show==0}}"> --> <view class="cubarN bg-white solid-bottom "> <!-- wx:if="{{devlist[index].show==0}}"> -->
<view class="flex-eight" style="font-size: 22rpx;" >固件版本:{{devlist[index].Version}}</view> <view class="flex-eight" style="font-size: 22rpx;" >固件版本:{{devlist[index].Version}}</view>
<view >
<view wx:if="{{devlist[index].UpgradeStatus==2}}">
<text class="text-green">升级完成</text>
</view>
<view wx:elif="{{devlist[index].UpgradeStatus==3}}">
<text class="text-red">升级失败</text>
</view>
<view wx:elif="{{devlist[index].UpgradeStatus==1}}">
<text class="text-green">升级中{{devlist[index].UpgradeProgress}}{{devlist[index].UpgradeProgress? '%':''}}</text>
</view>
<view wx:else>
<text></text>
</view>
</view>
</view> </view>
</view> </view>

View File

@@ -110,3 +110,32 @@
min-height: 50rpx ; min-height: 50rpx ;
justify-content: space-between; justify-content: space-between;
} }
/* 房间列表项在线/离线样式(与查房页面保持一致) */
.nav-li4.online {
background-color: #FFFFFF; /* 在线高亮白 */
color: #111111;
}
.nav-li4.offline {
background-color: #C9CBCA; /* 设备离线浅灰色 */
color: #111111;
}
/* 房间卡片的大框背景色与响应式布局 */
.nav-list1 {
background-color: #F0F0F0;
display: flex;
flex-wrap: wrap;
justify-content: center;
padding: 10rpx;
}
/* 单列卡片(默认,手机)
.nav-list1 .nav-li4 {
width: 98%;
margin: 10rpx 0;
box-sizing: border-box;
} */

View File

@@ -35,9 +35,9 @@
</view> </view>
<scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight}}rpx;" > <scroll-view scroll-y scroll-into-view="{{toView}}" id="myScroll" style="height:{{scrollHeight}}rpx;" >
<view class='nav-list1 bg-white' style="margin-top: 20rpx;"> <view class='nav-list1' style="margin-top: 20rpx;">
<view bindtap="goProcess" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}" <view bindtap="goProcess" data-room="{{item.RoomNumber}}" data-hotel="{{Hotelinfo.HotelName}}"
data-status="{{item.Status}}" hover-class="navigator-hover" class="nav-li4 bg-{{item.Status===1? 'cyan':'gray'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key> data-status="{{item.Status}}" hover-class="navigator-hover" class="nav-li4 {{item.Status===1? 'online':'offline'}}" wx:for="{{HostsDataFilters}}" id="msg-{{index}}" wx:key>
<view style="font-size: 32rpx;justify-content:start" >{{item.RoomNumber}}</view> <view style="font-size: 32rpx;justify-content:start" >{{item.RoomNumber}}</view>
<view style="font-size: 20rpx;justify-content:start" >{{item.MAC}}</view> <view style="font-size: 20rpx;justify-content:start" >{{item.MAC}}</view>
</view> </view>

View File

@@ -99,3 +99,18 @@
transform: translate(0rpx, 0rpx); transform: translate(0rpx, 0rpx);
margin-right: initial; margin-right: initial;
} }
/* 查房列表项在线/离线样式 */
.nav-li4.online {
background-color: #FFFFFF; /* 在线高亮白 */
color: #111111;
}
.nav-li4.offline {
background-color: #C9CBCA; /* 设备离线浅灰色 */
color: #111111;
}
/* 房间卡片的大框背景色 */
.nav-list1 {
background-color: #F0F0F0;
}

View File

@@ -1,149 +0,0 @@
// pages/device.js
const ecUI = require('../../utils/ecUI.js')
const ecBLE = require('../../utils/ecBLE.js')
let ctx
let isCheckScroll = true
let isCheckRevHex = false
let isCheckSendHex = false
let sendData = ''
Page({
/**
* 页面的初始数据
*/
data: {
textRevData: '',
scrollIntoView: 'scroll-view-bottom',
},
/**
* 生命周期函数--监听页面加载
*/
onLoad() {
ctx = this
isCheckScroll = true
isCheckRevHex = false
isCheckSendHex = false
sendData = ''
ecBLE.setChineseType(ecBLE.ECBLEChineseTypeGBK)
//on disconnect
ecBLE.onBLEConnectionStateChange(() => {
ecUI.showModal('提示', '设备断开连接')
})
//receive data
ecBLE.onBLECharacteristicValueChange((str, strHex) => {
let data =
ctx.data.textRevData +
ctx.dateFormat('[hh:mm:ss,S]:', new Date()) +
(isCheckRevHex ? strHex.replace(/[0-9a-fA-F]{2}/g, ' $&') : str) +
'\r\n'
// console.log(data)
ctx.setData({ textRevData: data })
if (isCheckScroll) {
if (ctx.data.scrollIntoView === "scroll-view-bottom") {
ctx.setData({ scrollIntoView: "scroll-view-bottom2" })
} else {
ctx.setData({ scrollIntoView: "scroll-view-bottom" })
}
}
})
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
ecBLE.onBLEConnectionStateChange(() => { })
ecBLE.onBLECharacteristicValueChange(() => { })
ecBLE.closeBLEConnection()
},
checkScroll(e) {
if (e.detail.value.length) isCheckScroll = true
else isCheckScroll = false
},
checkRevHex(e) {
if (e.detail.value.length) isCheckRevHex = true
else isCheckRevHex = false
},
checkSendHex(e) {
if (e.detail.value.length) isCheckSendHex = true
else isCheckSendHex = false
},
inputSendData(e) {
sendData = e.detail.value
},
btClearTap() {
this.setData({ textRevData: '' })
},
btSendTap() {
if (isCheckSendHex) {
let data = sendData
.replace(/\s*/g, '')
.replace(/\n/g, '')
.replace(/\r/g, '')
if (data.length === 0) {
ecUI.showModal('提示', '请输入要发送的数据')
return
}
if (data.length % 2 != 0) {
ecUI.showModal('提示', '数据长度只能是双数')
return
}
if (data.length > 488) {
ecUI.showModal('提示', '最多只能发送244字节')
return
}
if (!new RegExp('^[0-9a-fA-F]*$').test(data)) {
ecUI.showModal('提示', '数据格式错误只能是0-9,a-f,A-F')
return
}
ecBLE.writeBLECharacteristicValue(data, true)
} else {
if (sendData.length === 0) {
ecUI.showModal('提示', '请输入要发送的数据')
return
}
let tempSendData = sendData.replace(/\n/g, '\r\n')
if (tempSendData.length > 244) {
ecUI.showModal('提示', '最多只能发送244字节')
return
}
ecBLE.writeBLECharacteristicValue(tempSendData, false)
}
},
dateFormat(fmt, date) {
let o = {
'M+': date.getMonth() + 1, //月份
'd+': date.getDate(), //日
'h+': date.getHours(), //小时
'm+': date.getMinutes(), //分
's+': date.getSeconds(), //秒
'q+': Math.floor((date.getMonth() + 3) / 3), //季度
S: date.getMilliseconds(), //毫秒
}
if (/(y+)/.test(fmt))
fmt = fmt.replace(
RegExp.$1,
(date.getFullYear() + '').substr(4 - RegExp.$1.length)
)
for (var k in o)
if (new RegExp('(' + k + ')').test(fmt)) {
// console.log(RegExp.$1.length)
// console.log(o[k])
fmt = fmt.replace(
RegExp.$1,
RegExp.$1.length == 1
? (o[k] + '').padStart(3, '0')
: ('00' + o[k]).substr(('' + o[k]).length)
)
}
return fmt
},
checkChinese(e){
if(e.detail.value==='gbk'){
ecBLE.setChineseType(ecBLE.ECBLEChineseTypeGBK)
}else{
ecBLE.setChineseType(ecBLE.ECBLEChineseTypeUTF8)
}
}
})

View File

@@ -1,5 +0,0 @@
{
"usingComponents": {},
"enablePullDownRefresh": false,
"disableScroll": true
}

View File

@@ -1,47 +0,0 @@
<!--pages/device.wxml-->
<view class="device-container">
<view class="control-rev">
<text class="title-rev">数据接收 : </text>
<button class="bt-clear" type="primary" bindtap="btClearTap" hover-start-time="0">清空</button>
<checkbox-group bindchange="checkScroll" class="checkbox-scroll">
<checkbox checked="true"></checkbox>
<text>滚动</text>
</checkbox-group>
<checkbox-group bindchange="checkRevHex" class="checkbox-rev-hex">
<checkbox></checkbox>
<text>Hex</text>
</checkbox-group>
</view>
<view class="scroll-view-container">
<scroll-view class="scroll-view-rev" scroll-y="true" scroll-into-view="{{scrollIntoView}}">
<view class="view-rev-gap"></view>
<text class="text-rev" user-select="true" selectable="true">{{textRevData}}</text>
<view class="view-rev-gap"></view>
<view id="scroll-view-bottom"></view>
<view id="scroll-view-bottom2"></view>
</scroll-view>
</view>
<view class="control-send">
<text class="title-send">数据发送 : </text>
<checkbox-group bindchange="checkSendHex" class="checkbox-send-hex">
<checkbox></checkbox>
<text>Hex</text>
</checkbox-group>
</view>
<view class="view-input-send">
<textarea class="input-send" maxlength="-1" bindblur="inputSendData" bindinput="inputSendData" />
</view>
<view class="view-bt-send">
<button class="bt-send" type="primary" bindtap="btSendTap" hover-start-time="0">发送</button>
</view>
<view class="control-chinese">
<text class="title-chinese">中文字符集 : </text>
<radio-group bindchange="checkChinese" class="checkbox-chinese">
<radio value="utf8" />
<text class="checkbox-chinese-first-item">UTF-8</text>
<radio value="gbk" checked="true"/>
<text>GBK</text>
</radio-group>
</view>
<view><text class="text-support">技术支持https://eciot.com</text></view>
</view>

View File

@@ -1,130 +0,0 @@
/* pages/device.wxss */
.device-container {
height: 100vh;
}
.control-rev{
height: 45px;
display: flex;
align-items: center;
padding: 0 20px;
}
.title-rev {
font-size: 17px;
flex:1;
}
.bt-clear {
width: 55px !important;
height: 29px;
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
margin-right: 15px !important;
}
.checkbox-scroll {
font-size: 15px;
display: flex;
align-items: center;
margin-right: 10px;
}
.checkbox-rev-hex {
font-size: 15px;
display: flex;
align-items: center;
}
.scroll-view-container {
margin: 0 20px;
padding: 0 3px 0 5px;
background-color: #F5F5F5;
}
.scroll-view-rev {
height: 150px;
}
.view-rev-gap{
height: 5px;
}
.text-rev {
font-size: 14px;
word-break: break-all;
font-family: Monospace;
}
.control-send{
height: 45px;
display: flex;
align-items: center;
padding: 0 20px;
margin-top: 5px;
}
.title-send {
font-size: 17px;
flex:1;
}
.checkbox-send-hex {
font-size: 15px;
display: flex;
align-items: center;
}
.view-input-send {
margin: 0 20px;
padding: 2px 3px;
background-color: #F5F5F5;
}
.input-send {
height: 84px;
width: 100%;
word-break: break-all;
}
.view-bt-send {
margin: 15px 20px 0px 20px;
display: flex;
}
.bt-send {
flex: 1;
height: 45px;
display: flex;
justify-content: center;
align-items: center;
}
.control-chinese{
height: 45px;
display: flex;
align-items: center;
padding: 0 20px;
margin-top: 5px;
}
.title-chinese{
font-size: 17px;
flex:1;
}
.checkbox-chinese{
font-size: 15px;
display: flex;
align-items: center;
}
.checkbox-chinese-first-item{
margin-right: 10px;
}
.text-support{
font-size: 14px;
color: #909399;
margin-left: 20px;
}

View File

@@ -0,0 +1,47 @@
const fs = require('fs');
const path = require('path');
const root = path.resolve(__dirname, '..');
function walk(dir) {
const res = [];
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const it of items) {
const full = path.join(dir, it.name);
if (it.isDirectory()) {
// skip virtual env and node_modules
if (['.venv', 'node_modules', '.git'].includes(it.name)) continue;
res.push(...walk(full));
} else {
res.push(full);
}
}
return res;
}
function isImage(f) {
return /\.(png|jpe?g|gif|svg|webp|ico)$/i.test(f);
}
function isTextFile(f) {
return /\.(js|jsx|ts|tsx|json|html|htm|wxml|wxss|css|md|vue|py|java|xml|txt|scss|less|styl|mdx|yaml|yml)$/i.test(f);
}
const all = walk(root);
const images = all.filter(isImage);
const textFiles = all.filter(isTextFile);
const unused = [];
for (const img of images) {
const name = path.basename(img);
let found = false;
for (const tf of textFiles) {
try {
const content = fs.readFileSync(tf, 'utf8');
if (content.indexOf(name) !== -1) { found = true; break; }
} catch (e) {
// ignore
}
}
if (!found) unused.push(img);
}
console.log(JSON.stringify({ images: images, unused: unused }, null, 2));

View File

@@ -0,0 +1,51 @@
$root = 'E:\ForkSync\Wx_BLWConfigTools_V02_Prod'
$backup = Join-Path $root 'trash_images_backup'
if (-not (Test-Path $backup)) { New-Item -Path $backup -ItemType Directory | Out-Null }
$files = @(
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\vacant.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\住宿.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\开门.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\设备编号.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\退房.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\酒店.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\icon\重启.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\BasicsBg.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\cjkz.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\componentBg.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\logo.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\share.jpg',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\about.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\about_cur.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\basics.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\basics_cur.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\component.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\component_cur.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\plugin.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\tabbar\plugin_cur.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\wave.gif',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\images\zanCode.jpg',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\back.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\ble.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\ecble.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\logo.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\s1.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\s2.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\s3.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\s4.png',
'E:\ForkSync\Wx_BLWConfigTools_V02_Prod\img\s5.png'
)
$moved = @()
foreach ($f in $files) {
if (Test-Path -Path $f) {
try {
Move-Item -Path $f -Destination $backup -Force
$moved += $f
} catch {
Write-Error "Failed to move $f : $_"
}
}
}
Write-Output "Moved files:`n"
$moved
Write-Output "`nBackup dir contents:`n"
Get-ChildItem -Path $backup -Recurse | ForEach-Object { $_.FullName }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,8 @@ export const COMMANDS = {
SET_CONDITION_2: 0x09, SET_CONDITION_2: 0x09,
OTA_START: 0x0B, OTA_START: 0x0B,
ENABLE_BLE_LOG: 0x0C, ENABLE_BLE_LOG: 0x0C,
// 设置门磁/卫浴事件触发/释放参数
SET_DOOR_BATH_EVENT: 0x16,
RADAR_STATUS: 0x11, RADAR_STATUS: 0x11,
TEST_KEYS: 0x13, TEST_KEYS: 0x13,
}; };
@@ -24,6 +26,22 @@ function ensureUint8Array(data) {
if (data instanceof Uint8Array) return data; if (data instanceof Uint8Array) return data;
if (Array.isArray(data)) return Uint8Array.from(data.map(x => x & 0xFF)); if (Array.isArray(data)) return Uint8Array.from(data.map(x => x & 0xFF));
if (typeof data === 'string') { if (typeof data === 'string') {
// 如果是十六进制字符串包含空格或连续十六进制则按hex解析
const hexOnly = data.trim();
if (/^[0-9a-fA-F\s]+$/.test(hexOnly)) {
const parts = hexOnly.split(/\s+/).filter(Boolean);
let bytes = [];
if (parts.length > 1) {
bytes = parts.map(p => parseInt(p, 16) & 0xFF);
} else {
const s = parts[0];
for (let i = 0; i < s.length; i += 2) {
const hex = s.substr(i, 2);
if (hex.length === 2) bytes.push(parseInt(hex, 16) & 0xFF);
}
}
return Uint8Array.from(bytes);
}
// 默认按ASCII编码如需GBK请先外部转换后传入字节数组 // 默认按ASCII编码如需GBK请先外部转换后传入字节数组
const arr = new Uint8Array(data.length); const arr = new Uint8Array(data.length);
for (let i = 0; i < data.length; i++) arr[i] = data.charCodeAt(i) & 0xFF; for (let i = 0; i < data.length; i++) arr[i] = data.charCodeAt(i) & 0xFF;
@@ -85,7 +103,8 @@ export function buildPacket(opts) {
const framNum = (opts && opts.framNum) != null ? (opts.framNum >>> 0) : 1; const framNum = (opts && opts.framNum) != null ? (opts.framNum >>> 0) : 1;
const type = (opts && opts.type) != null ? (opts.type & 0xFF) : 0x00; const type = (opts && opts.type) != null ? (opts.type & 0xFF) : 0x00;
const params = ensureUint8Array(opts && opts.params); const params = ensureUint8Array(opts && opts.params);
const crcType = (opts && opts.crcType) === 'MODBUS' ? 'MODBUS' : 'CCITT'; // 默认CRC方式改为 MODBUS可显式传 'CCITT' 使用CCITT-FALSE
const crcType = (opts && opts.crcType) === 'CCITT' ? 'CCITT' : 'MODBUS';
// 预分配:固定头(2) + 长度(2) + CRC(2) + Frame(2) + FramNum(2) + Type(1) + 参数 // 预分配:固定头(2) + 长度(2) + CRC(2) + Frame(2) + FramNum(2) + Type(1) + 参数
const fixedLen = 2 + 2 + 2 + 2 + 2 + 1; const fixedLen = 2 + 2 + 2 + 2 + 2 + 1;
@@ -149,7 +168,7 @@ export function buildCommand(cmd, payload, options = {}) {
framNum: options.framNum != null ? options.framNum : 1, framNum: options.framNum != null ? options.framNum : 1,
type: cmd & 0xFF, type: cmd & 0xFF,
params: payload, params: payload,
crcType: options.crcType === 'MODBUS' ? 'MODBUS' : 'CCITT', crcType: options.crcType === 'CCITT' ? 'CCITT' : 'MODBUS',
head: options.head || DEFAULT_HEAD, head: options.head || DEFAULT_HEAD,
}); });
} }
@@ -161,3 +180,73 @@ export function buildCommand(cmd, payload, options = {}) {
export function buildReadVersion() { export function buildReadVersion() {
return buildCommand(COMMANDS.READ_VERSION, [0x00]); return buildCommand(COMMANDS.READ_VERSION, [0x00]);
} }
/**
* 构造:设置门磁开廊灯事件与卫浴雷达开卫浴灯事件 (Frame_Type=0x16)
* 参数布局P0..P8
* P0: 控制位 bit0=门磁事件启用, bit1=卫浴事件启用
* 门磁事件(当 bit0=1 启用)
* P1: 触发延迟数值
* P2: 时间单位(1=秒,2=分,3=时)
* P3: 释放延迟数值
* P4: 时间单位(1=秒,2=分,3=时)
* 卫浴事件(当 bit1=1 启用)
* P5: 触发延迟数值
* P6: 时间单位(1=秒,2=分,3=时)
* P7: 释放延迟数值
* P8: 时间单位(1=秒,2=分,3=时)
* 注意:当仅设置某一侧事件时,另一侧对应的参数必须填 0。
*
* @param {{
* door?: {triggerDelay?:number, triggerUnit?:number, releaseDelay?:number, releaseUnit?:number},
* bath?: {triggerDelay?:number, triggerUnit?:number, releaseDelay?:number, releaseUnit?:number}
* }} opts
* @param {{frame?:number, framNum?:number, crcType?:('CCITT'|'MODBUS'), head?:number[]}} [options]
*/
export function buildSetDoorBathEvent(opts = {}, options = {}) {
const door = opts.door || null;
const bath = opts.bath || null;
const doorEnabled = !!door;
const bathEnabled = !!bath;
const P0 = (doorEnabled ? 0x01 : 0x00) | (bathEnabled ? 0x02 : 0x00);
const p1 = doorEnabled ? (door.triggerDelay || 0) & 0xFF : 0x00;
const p2 = doorEnabled ? (door.triggerUnit || 0) & 0xFF : 0x00;
const p3 = doorEnabled ? (door.releaseDelay || 0) & 0xFF : 0x00;
const p4 = doorEnabled ? (door.releaseUnit || 0) & 0xFF : 0x00;
const p5 = bathEnabled ? (bath.triggerDelay || 0) & 0xFF : 0x00;
const p6 = bathEnabled ? (bath.triggerUnit || 0) & 0xFF : 0x00;
const p7 = bathEnabled ? (bath.releaseDelay || 0) & 0xFF : 0x00;
const p8 = bathEnabled ? (bath.releaseUnit || 0) & 0xFF : 0x00;
const payload = [P0, p1, p2, p3, p4, p5, p6, p7, p8];
return buildCommand(COMMANDS.SET_DOOR_BATH_EVENT, payload, options);
}
/**
* 验证十六进制字符串包并计算/写入 CRC默认 MODBUS返回完整包与CRC值
* @param {string} hexStr 如 'CC C0 0C 00 00 00 01 00 02 00 0C 08' 或连续hex
* @param {'MODBUS'|'CCITT'} [crcType='MODBUS']
* @returns {{crc:number, low:number, high:number, packetHex:string, packet:Array<number>}}
*/
export function verifyHexPacket(hexStr, crcType = 'MODBUS') {
if (typeof hexStr !== 'string') throw new TypeError('hexStr must be a string');
const params = ensureUint8Array(hexStr);
if (params.length < 6) throw new RangeError('Packet too short');
// 将输入视为完整包先把CRC位置清0再计算
const buf = new Uint8Array(params.length);
buf.set(params);
const crcPos = 4;
buf[crcPos] = 0x00;
buf[crcPos + 1] = 0x00;
const crc = computeCrc(buf, crcType, [0, buf.length]);
const crcLE = toUint16LE(crc);
buf[crcPos] = crcLE[0];
buf[crcPos + 1] = crcLE[1];
const packetHex = Array.from(buf).map(b => b.toString(16).toUpperCase().padStart(2, '0')).join(' ');
return { crc: crc & 0xFFFF, low: crcLE[0], high: crcLE[1], packetHex, packet: Array.from(buf) };
}