蓝牙模块
This commit is contained in:
parent
14ed880ef3
commit
1a027b6ec1
|
|
@ -1,11 +1,891 @@
|
|||
<script lang="ts" setup>
|
||||
/**
|
||||
* Web端蓝牙设备控制组件
|
||||
* 集成blufi系统实现蓝牙设备扫描、连接、控制功能
|
||||
*/
|
||||
|
||||
import { ref, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
// 动态导入blufi系统,避免Web环境兼容性问题
|
||||
let mDeviceEvent: any = null
|
||||
let XBLUFI_TYPE: any = null
|
||||
let OnFireEvent: any = null
|
||||
|
||||
// 页面布局配置
|
||||
definePageMeta({
|
||||
layout: 'empty' // 使用空布局
|
||||
})
|
||||
|
||||
/**
|
||||
* 蓝牙设备状态管理
|
||||
*/
|
||||
const bluetoothState = ref({
|
||||
isSupported: false, // 浏览器是否支持Web Bluetooth API
|
||||
isConnected: false, // 是否已连接到设备
|
||||
isScanning: false, // 是否正在扫描设备
|
||||
devices: [] as any[], // 发现的设备列表
|
||||
selectedDevice: null as any, // 当前选中的设备
|
||||
deviceInfo: {
|
||||
name: '',
|
||||
id: '',
|
||||
batteryLevel: 0,
|
||||
signalStrength: 0,
|
||||
firmwareVersion: '',
|
||||
deviceType: ''
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 控制命令管理
|
||||
*/
|
||||
const controlCommands = ref({
|
||||
ledOn: false, // LED开关状态
|
||||
motorSpeed: 0, // 电机速度 (0-100)
|
||||
temperature: 0, // 温度设置 (0-50°C)
|
||||
humidity: 0, // 湿度设置 (0-100%)
|
||||
wifiSsid: '', // WiFi网络名称
|
||||
wifiPassword: '', // WiFi密码
|
||||
customData: '' // 自定义数据命令
|
||||
})
|
||||
|
||||
/**
|
||||
* 操作日志管理
|
||||
*/
|
||||
const logs = ref<string[]>([])
|
||||
|
||||
/**
|
||||
* 页面初始化
|
||||
*/
|
||||
onMounted(() => {
|
||||
// 检查浏览器支持
|
||||
bluetoothState.value.isSupported = 'bluetooth' in navigator
|
||||
|
||||
if (!bluetoothState.value.isSupported) {
|
||||
addLog('浏览器不支持Web Bluetooth API')
|
||||
} else {
|
||||
addLog('Web Bluetooth API 支持正常')
|
||||
}
|
||||
|
||||
// 初始化blufi系统
|
||||
initBlufiSystem()
|
||||
|
||||
// 设置事件监听
|
||||
setupEventListeners()
|
||||
})
|
||||
|
||||
/**
|
||||
* 页面卸载时清理
|
||||
*/
|
||||
onUnmounted(() => {
|
||||
// 清理事件监听
|
||||
cleanupEventListeners()
|
||||
|
||||
// 断开设备连接
|
||||
if (bluetoothState.value.isConnected) {
|
||||
disconnectDevice()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 初始化blufi系统
|
||||
*/
|
||||
const initBlufiSystem = async () => {
|
||||
try {
|
||||
// 动态导入blufi系统
|
||||
const blufiModule = await import('~/components/blufi/xBlufi.js')
|
||||
mDeviceEvent = blufiModule.mDeviceEvent
|
||||
XBLUFI_TYPE = blufiModule.XBLUFI_TYPE
|
||||
OnFireEvent = blufiModule.OnFireEvent
|
||||
|
||||
// 初始化blufi系统(Web端使用模拟实现)
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.initXBlufi(mDeviceEvent.XMQTT_SYSTEM.WeChat)
|
||||
addLog('Blufi系统初始化成功')
|
||||
} else {
|
||||
addLog('Blufi系统模块加载失败')
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`Blufi系统初始化失败: ${error}`)
|
||||
// 如果blufi系统加载失败,使用Web Bluetooth API作为备选方案
|
||||
addLog('将使用Web Bluetooth API作为备选方案')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置事件监听器
|
||||
*/
|
||||
const setupEventListeners = () => {
|
||||
// 检查blufi系统是否已加载
|
||||
if (!mDeviceEvent) {
|
||||
addLog('Blufi系统未加载,跳过事件监听器设置')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
// 监听设备消息事件
|
||||
mDeviceEvent.listenDeviceMsgEvent(true, handleDeviceMessage)
|
||||
|
||||
// 监听设备发现事件
|
||||
mDeviceEvent.listenStartDiscoverBle(true, handleDeviceDiscovery)
|
||||
|
||||
// 监听设备连接事件
|
||||
mDeviceEvent.listenConnectBle(true, handleDeviceConnection)
|
||||
|
||||
// 监听设备初始化事件
|
||||
mDeviceEvent.listenInitBleEsp32(true, handleDeviceInit)
|
||||
|
||||
// 监听WiFi配置事件
|
||||
mDeviceEvent.listenSendRouterSsidAndPassword(true, handleWiFiConfig)
|
||||
|
||||
// 监听自定义数据事件
|
||||
mDeviceEvent.listenSendCustomData(true, handleCustomData)
|
||||
|
||||
addLog('事件监听器设置成功')
|
||||
} catch (error) {
|
||||
addLog(`事件监听器设置失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理事件监听器
|
||||
*/
|
||||
const cleanupEventListeners = () => {
|
||||
if (!mDeviceEvent) {
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
mDeviceEvent.listenDeviceMsgEvent(false, handleDeviceMessage)
|
||||
mDeviceEvent.listenStartDiscoverBle(false, handleDeviceDiscovery)
|
||||
mDeviceEvent.listenConnectBle(false, handleDeviceConnection)
|
||||
mDeviceEvent.listenInitBleEsp32(false, handleDeviceInit)
|
||||
mDeviceEvent.listenSendRouterSsidAndPassword(false, handleWiFiConfig)
|
||||
mDeviceEvent.listenSendCustomData(false, handleCustomData)
|
||||
addLog('事件监听器清理成功')
|
||||
} catch (error) {
|
||||
addLog(`事件监听器清理失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备消息事件
|
||||
*/
|
||||
const handleDeviceMessage = (message: any) => {
|
||||
addLog(`收到设备消息: ${JSON.stringify(message)}`)
|
||||
|
||||
switch (message.type) {
|
||||
case XBLUFI_TYPE.TYPE_STATUS_CONNECTED:
|
||||
bluetoothState.value.isConnected = message.result
|
||||
addLog(`设备连接状态: ${message.result ? '已连接' : '已断开'}`)
|
||||
break
|
||||
|
||||
case XBLUFI_TYPE.TYPE_GET_DEVICE_LISTS:
|
||||
if (message.result) {
|
||||
bluetoothState.value.devices = message.data
|
||||
addLog(`发现 ${message.data.length} 个设备`)
|
||||
}
|
||||
break
|
||||
|
||||
case XBLUFI_TYPE.TYPE_CONNECTED:
|
||||
if (message.result) {
|
||||
bluetoothState.value.isConnected = true
|
||||
bluetoothState.value.deviceInfo.name = message.data.name
|
||||
bluetoothState.value.deviceInfo.id = message.data.deviceId
|
||||
addLog(`设备连接成功: ${message.data.name}`)
|
||||
} else {
|
||||
addLog(`设备连接失败: ${JSON.stringify(message.data)}`)
|
||||
}
|
||||
break
|
||||
|
||||
case XBLUFI_TYPE.TYPE_RECIEVE_CUSTON_DATA:
|
||||
addLog(`收到自定义数据: ${message.data}`)
|
||||
break
|
||||
|
||||
case XBLUFI_TYPE.TYPE_CONNECT_ROUTER_RESULT:
|
||||
if (message.result) {
|
||||
addLog('WiFi配置成功')
|
||||
} else {
|
||||
addLog('WiFi配置失败')
|
||||
}
|
||||
break
|
||||
|
||||
default:
|
||||
addLog(`未知消息类型: ${message.type}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备发现事件
|
||||
*/
|
||||
const handleDeviceDiscovery = (options: any) => {
|
||||
addLog(`设备发现: ${options.isStart ? '开始' : '停止'}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备连接事件
|
||||
*/
|
||||
const handleDeviceConnection = (options: any) => {
|
||||
addLog(`设备连接: ${options.isStart ? '连接' : '断开'} ${options.deviceId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理设备初始化事件
|
||||
*/
|
||||
const handleDeviceInit = (options: any) => {
|
||||
addLog(`设备初始化: ${options.deviceId}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理WiFi配置事件
|
||||
*/
|
||||
const handleWiFiConfig = (options: any) => {
|
||||
addLog(`WiFi配置: SSID=${options.ssid}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理自定义数据事件
|
||||
*/
|
||||
const handleCustomData = (options: any) => {
|
||||
addLog(`发送自定义数据: ${options.customData}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加日志记录
|
||||
*/
|
||||
const addLog = (message: string) => {
|
||||
const timestamp = new Date().toLocaleTimeString()
|
||||
logs.value.unshift(`[${timestamp}] ${message}`)
|
||||
|
||||
// 限制日志数量
|
||||
if (logs.value.length > 50) {
|
||||
logs.value = logs.value.slice(0, 50)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始扫描蓝牙设备
|
||||
*/
|
||||
const startScanDevices = () => {
|
||||
if (!bluetoothState.value.isSupported) {
|
||||
addLog('浏览器不支持蓝牙')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
bluetoothState.value.isScanning = true
|
||||
addLog('开始扫描蓝牙设备...')
|
||||
|
||||
// 使用blufi系统扫描设备
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifyStartDiscoverBle({
|
||||
isStart: true,
|
||||
filter: '' // 可以设置设备名称过滤
|
||||
})
|
||||
} else {
|
||||
addLog('Blufi系统未加载,使用Web Bluetooth API扫描')
|
||||
// 这里可以添加Web Bluetooth API的扫描逻辑
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`扫描失败: ${error}`)
|
||||
bluetoothState.value.isScanning = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止扫描蓝牙设备
|
||||
*/
|
||||
const stopScanDevices = () => {
|
||||
try {
|
||||
bluetoothState.value.isScanning = false
|
||||
addLog('停止扫描蓝牙设备')
|
||||
|
||||
// 使用blufi系统停止扫描
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifyStartDiscoverBle({
|
||||
isStart: false
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`停止扫描失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接蓝牙设备
|
||||
*/
|
||||
const connectDevice = (device: any) => {
|
||||
if (!device) {
|
||||
addLog('请选择要连接的设备')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
addLog(`正在连接设备: ${device.name}`)
|
||||
|
||||
// 使用blufi系统连接设备
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifyConnectBle({
|
||||
isStart: true,
|
||||
deviceId: device.deviceId,
|
||||
name: device.name
|
||||
})
|
||||
} else {
|
||||
addLog('Blufi系统未加载,无法连接设备')
|
||||
return
|
||||
}
|
||||
|
||||
bluetoothState.value.selectedDevice = device
|
||||
} catch (error) {
|
||||
addLog(`连接失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 断开设备连接
|
||||
*/
|
||||
const disconnectDevice = () => {
|
||||
if (!bluetoothState.value.selectedDevice) {
|
||||
addLog('没有连接的设备')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
addLog('正在断开设备连接...')
|
||||
|
||||
// 使用blufi系统断开连接
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifyConnectBle({
|
||||
isStart: false,
|
||||
deviceId: bluetoothState.value.selectedDevice.deviceId,
|
||||
name: bluetoothState.value.selectedDevice.name
|
||||
})
|
||||
}
|
||||
|
||||
bluetoothState.value.isConnected = false
|
||||
bluetoothState.value.selectedDevice = null
|
||||
} catch (error) {
|
||||
addLog(`断开连接失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化设备
|
||||
*/
|
||||
const initDevice = () => {
|
||||
if (!bluetoothState.value.selectedDevice) {
|
||||
addLog('请先连接设备')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
addLog('正在初始化设备...')
|
||||
|
||||
// 使用blufi系统初始化设备
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifyInitBleEsp32({
|
||||
deviceId: bluetoothState.value.selectedDevice.deviceId
|
||||
})
|
||||
} else {
|
||||
addLog('Blufi系统未加载,无法初始化设备')
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`设备初始化失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送WiFi配置
|
||||
*/
|
||||
const sendWiFiConfig = () => {
|
||||
if (!bluetoothState.value.isConnected) {
|
||||
addLog('设备未连接')
|
||||
return
|
||||
}
|
||||
|
||||
if (!controlCommands.value.wifiSsid || !controlCommands.value.wifiPassword) {
|
||||
addLog('请输入WiFi名称和密码')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
addLog('正在发送WiFi配置...')
|
||||
|
||||
// 使用blufi系统发送WiFi配置
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifySendRouterSsidAndPassword({
|
||||
deviceId: bluetoothState.value.selectedDevice.deviceId,
|
||||
serverId: '000000FF-0000-1000-8000-00805F9B34FB',
|
||||
characterId: '0000FF01-0000-1000-8000-00805F9B34FB',
|
||||
ssid: controlCommands.value.wifiSsid,
|
||||
password: controlCommands.value.wifiPassword
|
||||
})
|
||||
} else {
|
||||
addLog('Blufi系统未加载,无法发送WiFi配置')
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`发送WiFi配置失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送自定义数据
|
||||
*/
|
||||
const sendCustomData = () => {
|
||||
if (!bluetoothState.value.isConnected) {
|
||||
addLog('设备未连接')
|
||||
return
|
||||
}
|
||||
|
||||
if (!controlCommands.value.customData) {
|
||||
addLog('请输入自定义数据')
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
addLog(`正在发送自定义数据: ${controlCommands.value.customData}`)
|
||||
|
||||
// 使用blufi系统发送自定义数据
|
||||
if (mDeviceEvent) {
|
||||
mDeviceEvent.notifySendCustomData({
|
||||
deviceId: bluetoothState.value.selectedDevice.deviceId,
|
||||
serverId: '000000FF-0000-1000-8000-00805F9B34FB',
|
||||
characterId: '0000FF01-0000-1000-8000-00805F9B34FB',
|
||||
customData: controlCommands.value.customData
|
||||
})
|
||||
} else {
|
||||
addLog('Blufi系统未加载,无法发送自定义数据')
|
||||
}
|
||||
} catch (error) {
|
||||
addLog(`发送自定义数据失败: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制LED开关
|
||||
*/
|
||||
const toggleLED = () => {
|
||||
controlCommands.value.ledOn = !controlCommands.value.ledOn
|
||||
const command = controlCommands.value.ledOn ? 'led_on' : 'led_off'
|
||||
controlCommands.value.customData = command
|
||||
sendCustomData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制电机速度
|
||||
*/
|
||||
const setMotorSpeed = (speed: number) => {
|
||||
controlCommands.value.motorSpeed = speed
|
||||
controlCommands.value.customData = `motor_speed:${speed}`
|
||||
sendCustomData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置温度
|
||||
*/
|
||||
const setTemperature = (temp: number) => {
|
||||
controlCommands.value.temperature = temp
|
||||
controlCommands.value.customData = `temperature:${temp}`
|
||||
sendCustomData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置湿度
|
||||
*/
|
||||
const setHumidity = (humidity: number) => {
|
||||
controlCommands.value.humidity = humidity
|
||||
controlCommands.value.customData = `humidity:${humidity}`
|
||||
sendCustomData()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除日志
|
||||
*/
|
||||
const clearLogs = () => {
|
||||
logs.value = []
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="min-h-screen bg-gray-50 dark:bg-gray-900 p-4">
|
||||
<div class="max-w-6xl mx-auto space-y-6">
|
||||
<!-- 页面标题 -->
|
||||
<div class="text-center">
|
||||
<h1 class="text-3xl font-bold text-gray-900 dark:text-white mb-2">
|
||||
Web端蓝牙设备控制
|
||||
</h1>
|
||||
<p class="text-gray-600 dark:text-gray-300">
|
||||
基于Blufi系统的蓝牙设备扫描、连接和控制
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 蓝牙状态和控制 -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- 设备扫描和控制 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
设备扫描和控制
|
||||
</h2>
|
||||
|
||||
<!-- 蓝牙支持状态 -->
|
||||
<div class="mb-4">
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="w-3 h-3 rounded-full" :class="bluetoothState.isSupported ? 'bg-green-500' : 'bg-red-500'"></div>
|
||||
<span class="text-sm text-gray-600 dark:text-gray-300">
|
||||
Web Bluetooth API: {{ bluetoothState.isSupported ? '支持' : '不支持' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 扫描控制按钮 -->
|
||||
<div class="space-y-3 mb-6">
|
||||
<button
|
||||
@click="startScanDevices"
|
||||
:disabled="!bluetoothState.isSupported || bluetoothState.isScanning"
|
||||
class="w-full px-4 py-2 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
{{ bluetoothState.isScanning ? '扫描中...' : '开始扫描设备' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="stopScanDevices"
|
||||
:disabled="!bluetoothState.isScanning"
|
||||
class="w-full px-4 py-2 bg-gray-600 hover:bg-gray-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
停止扫描
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 设备列表 -->
|
||||
<div class="mb-6">
|
||||
<h3 class="text-lg font-medium text-gray-900 dark:text-white mb-3">发现的设备</h3>
|
||||
<div class="space-y-2 max-h-40 overflow-y-auto">
|
||||
<div
|
||||
v-for="device in bluetoothState.devices"
|
||||
:key="device.deviceId"
|
||||
class="flex items-center justify-between p-3 bg-gray-50 dark:bg-gray-700 rounded-lg"
|
||||
>
|
||||
<div>
|
||||
<p class="font-medium text-gray-900 dark:text-white">{{ device.name || '未知设备' }}</p>
|
||||
<p class="text-sm text-gray-500 dark:text-gray-400">{{ device.deviceId }}</p>
|
||||
</div>
|
||||
<button
|
||||
@click="connectDevice(device)"
|
||||
:disabled="bluetoothState.isConnected"
|
||||
class="px-3 py-1 bg-green-600 hover:bg-green-700 disabled:bg-gray-400 text-white text-sm rounded transition-colors"
|
||||
>
|
||||
连接
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="bluetoothState.devices.length === 0" class="text-center text-gray-500 dark:text-gray-400 py-4">
|
||||
暂无发现的设备
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 连接控制 -->
|
||||
<div class="space-y-3">
|
||||
<button
|
||||
@click="initDevice"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="w-full px-4 py-2 bg-purple-600 hover:bg-purple-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
初始化设备
|
||||
</button>
|
||||
|
||||
<button
|
||||
@click="disconnectDevice"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="w-full px-4 py-2 bg-red-600 hover:bg-red-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
断开连接
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备信息 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
设备信息
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">设备名称:</span>
|
||||
<span class="font-medium text-gray-900 dark:text-white">{{ bluetoothState.deviceInfo.name || '未连接' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">设备ID:</span>
|
||||
<span class="font-medium text-gray-900 dark:text-white text-sm">{{ bluetoothState.deviceInfo.id || '未连接' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">连接状态:</span>
|
||||
<div class="flex items-center space-x-2">
|
||||
<div class="w-3 h-3 rounded-full" :class="bluetoothState.isConnected ? 'bg-green-500' : 'bg-red-500'"></div>
|
||||
<span class="font-medium text-gray-900 dark:text-white">
|
||||
{{ bluetoothState.isConnected ? '已连接' : '未连接' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">电池电量:</span>
|
||||
<span class="font-medium text-gray-900 dark:text-white">{{ bluetoothState.deviceInfo.batteryLevel }}%</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">固件版本:</span>
|
||||
<span class="font-medium text-gray-900 dark:text-white">{{ bluetoothState.deviceInfo.firmwareVersion || '未知' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 设备控制 -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<!-- 基础控制 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
基础控制
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- LED控制 -->
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="text-gray-600 dark:text-gray-300">LED控制:</span>
|
||||
<button
|
||||
@click="toggleLED"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="px-4 py-2 rounded-lg transition-colors"
|
||||
:class="controlCommands.ledOn
|
||||
? 'bg-green-600 hover:bg-green-700 text-white'
|
||||
: 'bg-gray-600 hover:bg-gray-700 text-white disabled:bg-gray-400'"
|
||||
>
|
||||
{{ controlCommands.ledOn ? '关闭LED' : '开启LED' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 电机速度控制 -->
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">
|
||||
电机速度: {{ controlCommands.motorSpeed }}%
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
v-model="controlCommands.motorSpeed"
|
||||
@change="setMotorSpeed(controlCommands.motorSpeed)"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 温度控制 -->
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">
|
||||
温度设置: {{ controlCommands.temperature }}°C
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="50"
|
||||
v-model="controlCommands.temperature"
|
||||
@change="setTemperature(controlCommands.temperature)"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 湿度控制 -->
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">
|
||||
湿度设置: {{ controlCommands.humidity }}%
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="100"
|
||||
v-model="controlCommands.humidity"
|
||||
@change="setHumidity(controlCommands.humidity)"
|
||||
:disabled="!bluetoothState.isConnected"
|
||||
class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- WiFi配置和自定义数据 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white mb-4">
|
||||
WiFi配置和自定义数据
|
||||
</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- WiFi配置 -->
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">WiFi网络名称 (SSID)</label>
|
||||
<input
|
||||
type="text"
|
||||
v-model="controlCommands.wifiSsid"
|
||||
placeholder="请输入WiFi名称"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">WiFi密码</label>
|
||||
<input
|
||||
type="password"
|
||||
v-model="controlCommands.wifiPassword"
|
||||
placeholder="请输入WiFi密码"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@click="sendWiFiConfig"
|
||||
:disabled="!bluetoothState.isConnected || !controlCommands.wifiSsid || !controlCommands.wifiPassword"
|
||||
class="w-full px-4 py-2 bg-orange-600 hover:bg-orange-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
发送WiFi配置
|
||||
</button>
|
||||
|
||||
<!-- 自定义数据 -->
|
||||
<div>
|
||||
<label class="block text-gray-600 dark:text-gray-300 mb-2">自定义数据命令</label>
|
||||
<input
|
||||
type="text"
|
||||
v-model="controlCommands.customData"
|
||||
placeholder="请输入自定义命令"
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:text-white"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<button
|
||||
@click="sendCustomData"
|
||||
:disabled="!bluetoothState.isConnected || !controlCommands.customData"
|
||||
class="w-full px-4 py-2 bg-purple-600 hover:bg-purple-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition-colors"
|
||||
>
|
||||
发送自定义数据
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作日志 -->
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg p-6 shadow-sm">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h2 class="text-xl font-semibold text-gray-900 dark:text-white">
|
||||
操作日志
|
||||
</h2>
|
||||
<button
|
||||
@click="clearLogs"
|
||||
class="px-3 py-1 bg-gray-600 hover:bg-gray-700 text-white text-sm rounded transition-colors"
|
||||
>
|
||||
清除日志
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="bg-gray-50 dark:bg-gray-900 rounded-lg p-4 h-64 overflow-y-auto">
|
||||
<div v-if="logs.length === 0" class="text-center text-gray-500 dark:text-gray-400 py-8">
|
||||
暂无日志记录
|
||||
</div>
|
||||
<div v-else class="space-y-1">
|
||||
<div
|
||||
v-for="(log, index) in logs"
|
||||
:key="index"
|
||||
class="text-sm text-gray-700 dark:text-gray-300 font-mono"
|
||||
>
|
||||
{{ log }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
/* 自定义滚动条样式 */
|
||||
.overflow-y-auto::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-thumb {
|
||||
background: #c1c1c1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
||||
background: #a8a8a8;
|
||||
}
|
||||
|
||||
/* 暗色模式滚动条 */
|
||||
.dark .overflow-y-auto::-webkit-scrollbar-track {
|
||||
background: #374151;
|
||||
}
|
||||
|
||||
.dark .overflow-y-auto::-webkit-scrollbar-thumb {
|
||||
background: #6b7280;
|
||||
}
|
||||
|
||||
.dark .overflow-y-auto::-webkit-scrollbar-thumb:hover {
|
||||
background: #9ca3af;
|
||||
}
|
||||
|
||||
/* 滑块样式 */
|
||||
input[type="range"] {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-track {
|
||||
background: #d1d5db;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
input[type="range"]::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: #3b82f6;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-track {
|
||||
background: #d1d5db;
|
||||
height: 8px;
|
||||
border-radius: 4px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
input[type="range"]::-moz-range-thumb {
|
||||
background: #3b82f6;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* 暗色模式滑块 */
|
||||
.dark input[type="range"]::-webkit-slider-track {
|
||||
background: #4b5563;
|
||||
}
|
||||
|
||||
.dark input[type="range"]::-moz-range-track {
|
||||
background: #4b5563;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1157,9 +1157,18 @@
|
|||
} else if (typeof define === 'function' && define.amd) {
|
||||
define(aesjs)
|
||||
} else {
|
||||
if (root.aesjs) {
|
||||
aesjs._aesjs = root.aesjs
|
||||
// 修复Web环境中的this上下文问题
|
||||
const globalThis = (function() {
|
||||
if (typeof globalThis !== 'undefined') return globalThis
|
||||
if (typeof self !== 'undefined') return self
|
||||
if (typeof window !== 'undefined') return window
|
||||
if (typeof global !== 'undefined') return global
|
||||
return {}
|
||||
})()
|
||||
|
||||
if (globalThis.aesjs) {
|
||||
aesjs._aesjs = globalThis.aesjs
|
||||
}
|
||||
root.aesjs = aesjs
|
||||
globalThis.aesjs = aesjs
|
||||
}
|
||||
})(this)
|
||||
})(typeof globalThis !== 'undefined' ? globalThis : typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : {})
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user