fix: 中文全部换成英文。
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -10,3 +10,7 @@ docs/_book
|
||||
test/
|
||||
|
||||
node_modules
|
||||
/.idea/.gitignore
|
||||
/.idea/intc-mixer-app.iml
|
||||
/.idea/modules.xml
|
||||
/.idea/vcs.xml
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
<template>
|
||||
<view class="bluetooth-page">
|
||||
<!-- 导航栏 -->
|
||||
<uni-navbar title="搅拌器设备连接" :border="false" background-color="rgba(102, 126, 234, 0.9)" color="#fff" />
|
||||
<!-- Navigation Bar -->
|
||||
<uni-navbar title="Mixer Device Connection" :border="false" background-color="rgba(102, 126, 234, 0.9)" color="#fff" />
|
||||
|
||||
<view class="bluetooth-container">
|
||||
|
||||
<!-- 搜索状态和设置 -->
|
||||
<!-- Search Status and Settings -->
|
||||
<view class="search-status">
|
||||
<view class="status-row">
|
||||
<view class="status-item">
|
||||
<text class="status-label">蓝牙状态:</text>
|
||||
<text class="status-label">Bluetooth:</text>
|
||||
<text :class="['status-value', bluetoothEnabled ? 'status-on' : 'status-off']">
|
||||
{{ bluetoothEnabled ? '已开启' : '未开启' }}
|
||||
{{ bluetoothEnabled ? 'On' : 'Off' }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="status-item">
|
||||
<text class="status-label">搜索状态:</text>
|
||||
<text class="status-label">Search:</text>
|
||||
<text :class="['status-value', isSearching ? 'status-on' : 'status-off']">
|
||||
{{ isSearching ? '搜索中...' : '未搜索' }}
|
||||
{{ isSearching ? 'Searching...' : 'Idle' }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<!-- Action Buttons -->
|
||||
<view class="action-buttons">
|
||||
<u-button
|
||||
type="primary"
|
||||
@@ -31,7 +31,7 @@
|
||||
@click="startBluetoothSearch"
|
||||
:disabled="!bluetoothEnabled"
|
||||
>
|
||||
{{ isSearching ? '搜索中...' : '开始搜索' }}
|
||||
{{ isSearching ? 'Searching...' : 'Start Search' }}
|
||||
</u-button>
|
||||
<u-button
|
||||
type="warning"
|
||||
@@ -40,11 +40,11 @@
|
||||
:disabled="!isSearching"
|
||||
style="margin-left: 20rpx;"
|
||||
>
|
||||
停止搜索
|
||||
Stop Search
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
<!-- 预览按钮 -->
|
||||
<!-- Preview Button -->
|
||||
<view class="preview-button-wrapper">
|
||||
<u-button
|
||||
type="success"
|
||||
@@ -52,15 +52,15 @@
|
||||
@click="previewMixerPage"
|
||||
>
|
||||
<uni-icons type="eye" color="#52c41a" size="20" style="margin-right: 8rpx;"></uni-icons>
|
||||
预览搅拌器页面
|
||||
Preview Mixer Page
|
||||
</u-button>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 设备列表 -->
|
||||
<!-- Device List -->
|
||||
<view class="device-list">
|
||||
<view class="list-header">
|
||||
<text class="header-title">附近的设备</text>
|
||||
<text class="header-title">Nearby Devices</text>
|
||||
<text class="device-count">({{ deviceList.length }})</text>
|
||||
</view>
|
||||
|
||||
@@ -72,7 +72,7 @@
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
<text class="empty-text">暂无设备,点击上方按钮开始搜索</text>
|
||||
<text class="empty-text">No devices found, click above to start searching</text>
|
||||
</view>
|
||||
|
||||
<view v-else class="device-items">
|
||||
@@ -95,20 +95,20 @@
|
||||
/>
|
||||
</view>
|
||||
<text class="name-text">
|
||||
{{ device.name || device.localName || `未命名设备 (${device.deviceId.slice(-8)})` }}
|
||||
{{ device.name || device.localName || `Unnamed Device (${device.deviceId.slice(-8)})` }}
|
||||
</text>
|
||||
</view>
|
||||
<view class="device-details">
|
||||
<text class="detail-text">设备ID: {{ device.deviceId }}</text>
|
||||
<text class="detail-text">信号强度: {{ device.RSSI }} dBm</text>
|
||||
<text class="detail-text">Device ID: {{ device.deviceId }}</text>
|
||||
<text class="detail-text">Signal: {{ device.RSSI }} dBm</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="device-action">
|
||||
<view v-if="device.deviceId === connectedDeviceId" class="connected-badge">
|
||||
<text class="badge-text">已连接</text>
|
||||
<text class="badge-text">Connected</text>
|
||||
</view>
|
||||
<view v-else-if="device.deviceId === connectingDeviceId" class="connecting-badge">
|
||||
<text class="connecting-text">连接中...</text>
|
||||
<text class="connecting-text">Connecting...</text>
|
||||
</view>
|
||||
<u-button
|
||||
v-else
|
||||
@@ -116,15 +116,15 @@
|
||||
size="small"
|
||||
@click.stop="connectDevice(device)"
|
||||
>
|
||||
连接
|
||||
Connect
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 已连接设备的详细信息,显示在对应设备下方 -->
|
||||
<!-- Connected device details, displayed below the corresponding device -->
|
||||
<view v-if="device.deviceId === connectedDeviceId && connectedDevice" class="device-connected-detail">
|
||||
<view class="detail-header">
|
||||
<text class="detail-title">连接成功,准备跳转...</text>
|
||||
<text class="detail-title">Connected successfully, preparing to navigate...</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -366,22 +366,22 @@ const guideToEnableGPS = () => {
|
||||
let content = ''
|
||||
|
||||
if (androidVersion >= 12) {
|
||||
content = '检测到您使用的是 Android 12+,不需要开启GPS即可使用蓝牙功能。'
|
||||
content = 'You are using Android 12+, GPS is not required for Bluetooth.'
|
||||
} else if (androidVersion >= 10) {
|
||||
content = `检测到您使用的是 Android ${androidVersion},系统要求必须开启位置服务(GPS)才能搜索蓝牙设备。
|
||||
content = `You are using Android ${androidVersion}. The system requires location service (GPS) to be enabled for Bluetooth device scanning.
|
||||
|
||||
这是 Android 系统的强制要求,即使不会真正定位您的位置。
|
||||
This is a mandatory Android system requirement, even though it won't actually track your location.
|
||||
|
||||
是否前往设置开启?`
|
||||
Go to settings to enable?`
|
||||
} else {
|
||||
content = '建议开启位置服务(GPS)以确保蓝牙搜索功能正常使用。\n\n是否前往设置开启?'
|
||||
content = 'It is recommended to enable location service (GPS) to ensure Bluetooth search function works properly.\n\nGo to settings to enable?'
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: androidVersion >= 12 ? '提示' : '需要开启GPS',
|
||||
title: androidVersion >= 12 ? 'Notice' : 'GPS Required',
|
||||
content: content,
|
||||
showCancel: androidVersion < 12,
|
||||
confirmText: androidVersion >= 12 ? '知道了' : '去设置',
|
||||
confirmText: androidVersion >= 12 ? 'OK' : 'Go to Settings',
|
||||
success: (res) => {
|
||||
if (res.confirm && androidVersion < 12) {
|
||||
// 跳转到位置设置页面
|
||||
@@ -395,7 +395,7 @@ const guideToEnableGPS = () => {
|
||||
} catch (e) {
|
||||
console.error('跳转设置失败:', e)
|
||||
uni.showToast({
|
||||
title: '请手动前往设置开启GPS',
|
||||
title: 'Please go to settings manually to enable GPS',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
@@ -411,14 +411,14 @@ const saveLastDevice = (device) => {
|
||||
try {
|
||||
const deviceInfo = {
|
||||
deviceId: device.deviceId,
|
||||
name: device.name || device.localName || '未命名设备',
|
||||
name: device.name || device.localName || 'Unnamed Device',
|
||||
localName: device.localName,
|
||||
RSSI: device.RSSI
|
||||
}
|
||||
uni.setStorageSync(LAST_DEVICE_KEY, JSON.stringify(deviceInfo))
|
||||
console.log('已保存上次连接的设备:', deviceInfo)
|
||||
console.log('Saved last connected device:', deviceInfo)
|
||||
} catch (e) {
|
||||
console.error('保存设备信息失败:', e)
|
||||
console.error('Failed to save device info:', e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -428,11 +428,11 @@ const getLastDevice = () => {
|
||||
const deviceStr = uni.getStorageSync(LAST_DEVICE_KEY)
|
||||
if (deviceStr) {
|
||||
const device = JSON.parse(deviceStr)
|
||||
console.log('读取到上次连接的设备:', device)
|
||||
console.log('Read last connected device:', device)
|
||||
return device
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('读取设备信息失败:', e)
|
||||
console.error('Failed to read device info:', e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -441,7 +441,7 @@ const getLastDevice = () => {
|
||||
const tryAutoReconnectLastDevice = async () => {
|
||||
// 防止重复尝试
|
||||
if (hasTriedAutoReconnect) {
|
||||
console.log('已经尝试过自动重连,跳过')
|
||||
console.log('Already tried auto-reconnect, skipping')
|
||||
startBluetoothSearch()
|
||||
return
|
||||
}
|
||||
@@ -451,15 +451,15 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
// 获取上次连接的设备
|
||||
const lastDevice = getLastDevice()
|
||||
if (!lastDevice) {
|
||||
console.log('没有上次连接的设备记录,开始正常搜索')
|
||||
console.log('No last connected device record, starting normal search')
|
||||
startBluetoothSearch()
|
||||
return
|
||||
}
|
||||
|
||||
console.log('尝试自动重连上次的设备:', lastDevice.name)
|
||||
console.log('Trying to auto-reconnect to last device:', lastDevice.name)
|
||||
|
||||
uni.showLoading({
|
||||
title: `正在连接 ${lastDevice.name}...`,
|
||||
title: `Connecting ${lastDevice.name}...`,
|
||||
mask: true
|
||||
})
|
||||
|
||||
@@ -468,7 +468,7 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
await checkLocationService()
|
||||
} catch (e) {
|
||||
uni.hideLoading()
|
||||
console.log('GPS未开启,无法自动重连')
|
||||
console.log('GPS not enabled, cannot auto-reconnect')
|
||||
guideToEnableGPS()
|
||||
return
|
||||
}
|
||||
@@ -483,7 +483,7 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
})
|
||||
})
|
||||
|
||||
console.log('开始搜索上次连接的设备...')
|
||||
console.log('Starting to search for last connected device...')
|
||||
|
||||
// 等待3秒搜索设备
|
||||
await new Promise(resolve => setTimeout(resolve, 3000))
|
||||
@@ -500,7 +500,7 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
const targetDevice = devices.find(d => d.deviceId === lastDevice.deviceId)
|
||||
|
||||
if (targetDevice) {
|
||||
console.log('找到上次连接的设备,尝试连接:', targetDevice)
|
||||
console.log('Found last connected device, trying to connect:', targetDevice)
|
||||
|
||||
// 尝试连接
|
||||
try {
|
||||
@@ -514,7 +514,7 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
})
|
||||
|
||||
// 连接成功
|
||||
console.log('自动重连成功')
|
||||
console.log('Auto-reconnect successful')
|
||||
connectingDeviceId.value = ''
|
||||
connectedDeviceId.value = targetDevice.deviceId
|
||||
connectedDevice.value = targetDevice
|
||||
@@ -528,7 +528,7 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: '自动连接成功',
|
||||
title: 'Auto-connect successful',
|
||||
icon: 'success',
|
||||
duration: 1500
|
||||
})
|
||||
@@ -536,16 +536,16 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
// 自动跳转到控制页面
|
||||
setTimeout(() => {
|
||||
const url = buildMixerPageUrl(targetDevice, bleInfo)
|
||||
console.log('🚀 跳转到搅拌器页面:', url)
|
||||
console.log('🚀 Navigating to mixer page:', url)
|
||||
uni.navigateTo({ url })
|
||||
}, 1500)
|
||||
|
||||
} catch (connectErr) {
|
||||
console.error('自动重连失败:', connectErr)
|
||||
console.error('Auto-reconnect failed:', connectErr)
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: '自动连接失败,请手动选择',
|
||||
title: 'Auto-connect failed, please select manually',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
@@ -558,11 +558,11 @@ const tryAutoReconnectLastDevice = async () => {
|
||||
}, 2000)
|
||||
}
|
||||
} else {
|
||||
console.log('未找到上次连接的设备,继续正常搜索')
|
||||
console.log('Last device not found, continuing normal search')
|
||||
uni.hideLoading()
|
||||
|
||||
uni.showToast({
|
||||
title: '未找到上次设备',
|
||||
title: 'Last device not found',
|
||||
icon: 'none',
|
||||
duration: 1500
|
||||
})
|
||||
@@ -722,11 +722,13 @@ const connectDevice = (device) => {
|
||||
return
|
||||
}
|
||||
|
||||
// 如果已经连接了其他设备,先提示用户
|
||||
// If already connected to another device, prompt user first
|
||||
if (connectedDeviceId.value && connectedDeviceId.value !== device.deviceId) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '已连接其他设备,是否断开并连接新设备?',
|
||||
title: 'Notice',
|
||||
content: 'Already connected to another device. Disconnect and connect to new device?',
|
||||
confirmText: 'Confirm',
|
||||
cancelText: 'Cancel',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 先断开当前连接
|
||||
@@ -754,19 +756,19 @@ const connectDevice = (device) => {
|
||||
const doConnect = (device) => {
|
||||
connectingDeviceId.value = device.deviceId
|
||||
|
||||
console.log('开始连接设备:', device)
|
||||
console.log('Starting to connect device:', device)
|
||||
|
||||
uni.createBLEConnection({
|
||||
deviceId: device.deviceId,
|
||||
timeout: 10000, // 设置10秒超时
|
||||
timeout: 10000, // 10 seconds timeout
|
||||
success: async (res) => {
|
||||
console.log('连接成功', res)
|
||||
console.log('Connection successful', res)
|
||||
connectingDeviceId.value = ''
|
||||
connectedDeviceId.value = device.deviceId
|
||||
connectedDevice.value = device
|
||||
|
||||
uni.showToast({
|
||||
title: '连接成功',
|
||||
title: 'Connected',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
@@ -782,41 +784,41 @@ const doConnect = (device) => {
|
||||
// 连接成功后跳转到控制页面
|
||||
setTimeout(() => {
|
||||
const url = buildMixerPageUrl(device, bleInfo)
|
||||
console.log('🚀 跳转到搅拌器页面:', url)
|
||||
console.log('🚀 Navigating to mixer page:', url)
|
||||
uni.navigateTo({ url })
|
||||
}, 800)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('连接失败', err)
|
||||
console.error('Connection failed', err)
|
||||
connectingDeviceId.value = ''
|
||||
|
||||
// 根据错误码提供更详细的错误信息
|
||||
let errorMsg = '无法连接到该设备'
|
||||
// Provide detailed error information based on error code
|
||||
let errorMsg = 'Unable to connect to this device'
|
||||
|
||||
if (err.errCode === 10003) {
|
||||
errorMsg = '连接失败:设备未找到或已关闭'
|
||||
errorMsg = 'Connection failed: Device not found or turned off'
|
||||
} else if (err.errCode === 10012) {
|
||||
errorMsg = '连接失败:连接超时,设备可能距离太远'
|
||||
errorMsg = 'Connection failed: Connection timeout, device may be too far away'
|
||||
} else if (err.errCode === 10004) {
|
||||
errorMsg = '连接失败:设备不支持连接'
|
||||
errorMsg = 'Connection failed: Device does not support connection'
|
||||
} else if (err.errCode === -1) {
|
||||
errorMsg = '连接失败:系统错误,请重启蓝牙后重试'
|
||||
errorMsg = 'Connection failed: System error, please restart Bluetooth and retry'
|
||||
} else if (err.errMsg) {
|
||||
errorMsg = `连接失败:${err.errMsg}`
|
||||
errorMsg = `Connection failed: ${err.errMsg}`
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '连接失败',
|
||||
title: 'Connection Failed',
|
||||
content: `${errorMsg}
|
||||
|
||||
错误码: ${err.errCode || '未知'}
|
||||
Error Code: ${err.errCode || 'Unknown'}
|
||||
|
||||
提示:
|
||||
1. 确保设备在可连接范围内
|
||||
2. 确保设备未被其他应用连接
|
||||
3. 尝试重启设备蓝牙`,
|
||||
Tips:
|
||||
1. Ensure device is within connection range
|
||||
2. Ensure device is not connected by other apps
|
||||
3. Try restarting device Bluetooth`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
confirmText: 'OK'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -826,7 +828,7 @@ const doConnect = (device) => {
|
||||
const disconnectDevice = () => {
|
||||
if (!connectedDeviceId.value) {
|
||||
uni.showToast({
|
||||
title: '没有已连接的设备',
|
||||
title: 'No connected device',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -844,14 +846,14 @@ const disconnectDevice = () => {
|
||||
characteristicId: char.uuid,
|
||||
state: false,
|
||||
success: () => {
|
||||
console.log('关闭notify成功:', char.uuid)
|
||||
console.log('Notify disabled successfully:', char.uuid)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('关闭notify失败:', char.uuid, err)
|
||||
console.error('Failed to disable notify:', char.uuid, err)
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
console.error('关闭notify异常:', err)
|
||||
console.error('Notify exception:', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -859,20 +861,20 @@ const disconnectDevice = () => {
|
||||
uni.closeBLEConnection({
|
||||
deviceId: deviceId,
|
||||
success: (res) => {
|
||||
console.log('断开连接成功', res)
|
||||
// 清空连接状态和服务信息
|
||||
console.log('Disconnected successfully', res)
|
||||
// Clear connection status and service info
|
||||
cleanupConnection()
|
||||
uni.showToast({
|
||||
title: '已断开连接',
|
||||
title: 'Disconnected',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('断开连接失败', err)
|
||||
// 即使断开失败,也清空状态(可能设备已经离线)
|
||||
console.error('Failed to disconnect', err)
|
||||
// Clear status even if disconnection fails (device may already be offline)
|
||||
cleanupConnection()
|
||||
uni.showToast({
|
||||
title: '断开连接',
|
||||
title: 'Disconnected',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -901,7 +903,7 @@ const getBLEDeviceServices = async (deviceId) => {
|
||||
})
|
||||
})
|
||||
|
||||
console.log('获取到的服务列表', res.services)
|
||||
console.log('Retrieved service list', res.services)
|
||||
services.value = res.services
|
||||
|
||||
// 计算所有服务的特征值总数
|
||||
@@ -1530,7 +1532,7 @@ const addToHistory = (type, data, hex, characteristicId = '') => {
|
||||
const toggleHistory = () => {
|
||||
if (dataHistory.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '暂无历史记录',
|
||||
title: 'No history records',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
@@ -1538,18 +1540,20 @@ const toggleHistory = () => {
|
||||
showHistory.value = !showHistory.value
|
||||
}
|
||||
|
||||
// 清空历史记录
|
||||
// Clear history
|
||||
const clearHistory = () => {
|
||||
uni.showModal({
|
||||
title: '确认',
|
||||
content: '确定要清空所有历史记录吗?',
|
||||
title: 'Confirm',
|
||||
content: 'Are you sure to clear all history records?',
|
||||
confirmText: 'Confirm',
|
||||
cancelText: 'Cancel',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
sendHistory.value = []
|
||||
receiveHistory.value = []
|
||||
showHistory.value = false
|
||||
uni.showToast({
|
||||
title: '已清空',
|
||||
title: 'Cleared',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -1560,12 +1564,12 @@ const clearHistory = () => {
|
||||
// 监听蓝牙适配器状态变化
|
||||
const onBluetoothAdapterStateChange = () => {
|
||||
uni.onBluetoothAdapterStateChange((res) => {
|
||||
console.log('蓝牙适配器状态变化', res)
|
||||
console.log('Bluetooth adapter state changed', res)
|
||||
bluetoothEnabled.value = res.available
|
||||
if (!res.available) {
|
||||
isSearching.value = false
|
||||
uni.showToast({
|
||||
title: '蓝牙已关闭',
|
||||
title: 'Bluetooth turned off',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -1577,10 +1581,10 @@ onMounted(() => {
|
||||
// 判断是否为H5环境
|
||||
// #ifdef H5
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: 'H5平台不支持蓝牙功能,请使用App或小程序版本',
|
||||
title: 'Notice',
|
||||
content: 'Bluetooth is not supported on H5 platform, please use App or Mini Program version',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
confirmText: 'OK'
|
||||
})
|
||||
bluetoothEnabled.value = false
|
||||
// #endif
|
||||
@@ -1620,10 +1624,10 @@ const cleanup = () => {
|
||||
// 关闭蓝牙适配器
|
||||
uni.closeBluetoothAdapter({
|
||||
success: (res) => {
|
||||
console.log('关闭蓝牙适配器成功', res)
|
||||
console.log('Bluetooth adapter closed successfully', res)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('关闭蓝牙适配器失败', err)
|
||||
console.error('Failed to close Bluetooth adapter', err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -12,17 +12,17 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 标题 -->
|
||||
<!-- Title -->
|
||||
<view class="title-section">
|
||||
<text class="main-title">搅拌器控制连接</text>
|
||||
<text class="sub-title">快速搜索并连接附近搅拌器蓝牙设备</text>
|
||||
<text class="main-title">Mixer Control Connection</text>
|
||||
<text class="sub-title">Quickly search and connect to nearby mixer Bluetooth devices</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<view class="btn-section">
|
||||
<button @click="handleLogin" class="login-btn">
|
||||
<uni-icons type="right" size="24" color="#667eea" style="margin-right: 12rpx;"></uni-icons>
|
||||
<text class="btn-text">进入</text>
|
||||
<text class="btn-text">Enter</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
<template>
|
||||
<view class="mixer-page">
|
||||
<!-- 顶部蓝牙状态栏 -->
|
||||
<!-- Top Bluetooth Status Bar -->
|
||||
<view class="custom-navbar">
|
||||
<view class="navbar-content">
|
||||
<view class="nav-left" @click="goBack">
|
||||
<uni-icons type="back" color="#fff" size="20"></uni-icons>
|
||||
</view>
|
||||
<view class="nav-center">
|
||||
<text class="nav-title">{{ deviceName || '六通道搅拌器' }}</text>
|
||||
<text class="nav-title">{{ deviceName || 'Six-Channel Mixer' }}</text>
|
||||
</view>
|
||||
<view class="nav-right">
|
||||
<view class="bluetooth-status" @click="showDeviceInfo">
|
||||
<uni-icons type="bluetooth-filled" color="#fff" size="20"></uni-icons>
|
||||
<text class="status-text">{{ connected ? '已连接' : '未连接' }}</text>
|
||||
<text class="status-text">{{ connected ? 'Connected' : 'Disconnected' }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="mixer-container">
|
||||
<!-- 选择状态栏 -->
|
||||
<!-- Selection Status Bar -->
|
||||
<view class="selection-status">
|
||||
<view class="status-row">
|
||||
<view class="status-item">
|
||||
<text class="status-label">已选择:</text>
|
||||
<text class="status-label">Selected:</text>
|
||||
<text :class="['status-value', selectedChannels.length > 0 ? 'status-on' : 'status-off']">
|
||||
{{ selectedChannels.length }}/{{ channels.length }} 通道
|
||||
{{ selectedChannels.length }}/{{ channels.length }} Channels
|
||||
</text>
|
||||
</view>
|
||||
<view class="select-actions">
|
||||
<text class="action-link" @click="selectAll">全选</text>
|
||||
<text class="action-link" @click="selectAll">Select All</text>
|
||||
<text class="action-divider">|</text>
|
||||
<text class="action-link" @click="clearSelection">清空</text>
|
||||
<text class="action-link" @click="clearSelection">Clear</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通道卡片网格 -->
|
||||
<!-- Channel Cards Grid -->
|
||||
<view class="channel-grid">
|
||||
<view
|
||||
v-for="channel in channels"
|
||||
:key="channel.id"
|
||||
:class="['channel-card', { 'selected': isChannelSelected(channel.id) }]"
|
||||
>
|
||||
<!-- 通道标题 -->
|
||||
<!-- Channel Title -->
|
||||
<view class="card-header">
|
||||
<!-- 选择复选框(内联在标题左侧) -->
|
||||
<!-- Selection Checkbox (Inline on the left side of title) -->
|
||||
<view class="channel-checkbox-inline" @click.stop="toggleChannelSelection(channel.id)">
|
||||
<view :class="['checkbox-icon', { 'checked': isChannelSelected(channel.id) }]">
|
||||
<text v-if="isChannelSelected(channel.id)" class="check-mark">✓</text>
|
||||
@@ -59,11 +59,11 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 运行模式控制 -->
|
||||
<!-- Run Mode Control -->
|
||||
<view class="mode-controls">
|
||||
<!-- 转速调节滑块 -->
|
||||
<!-- Speed Adjustment Slider -->
|
||||
<view class="slider-group" @click.stop>
|
||||
<text class="slider-label">转速</text>
|
||||
<text class="slider-label">Speed</text>
|
||||
<text class="slider-min-value">0</text>
|
||||
<slider
|
||||
:value="channel.runValue"
|
||||
@@ -78,43 +78,43 @@
|
||||
<text class="slider-max-value">400</text>
|
||||
</view>
|
||||
|
||||
<!-- 转速数值显示 -->
|
||||
<!-- Speed Value Display -->
|
||||
<view class="speed-display">
|
||||
<text class="speed-value">{{ calculateSpeed(channel.runValue) }}</text>
|
||||
<text class="speed-unit">转/分</text>
|
||||
<text class="speed-unit">RPM</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 定时设置 -->
|
||||
<!-- Timer Setting -->
|
||||
<view class="timer-setting" @click.stop="setTimer(channel.id)">
|
||||
<text class="timer-emoji">⏱</text>
|
||||
<text class="timer-label">{{ channel.timerMode }}:</text>
|
||||
<text class="timer-label">Timer:</text>
|
||||
<text class="timer-value">{{ channel.timerValue }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 启停按钮 -->
|
||||
<!-- Start/Stop Buttons -->
|
||||
<view class="card-footer">
|
||||
<view
|
||||
v-if="channel.status === 'stopped'"
|
||||
class="start-btn"
|
||||
@click.stop="handleChannelStart(channel.id)"
|
||||
>
|
||||
<text class="btn-text">启动</text>
|
||||
<text class="btn-text">Start</text>
|
||||
</view>
|
||||
<view
|
||||
v-else
|
||||
class="stop-btn"
|
||||
@click.stop="handleChannelStop(channel.id)"
|
||||
>
|
||||
<text class="btn-text">停止</text>
|
||||
<text class="btn-text">Stop</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部控制区 -->
|
||||
<!-- Bottom Control Area -->
|
||||
<view class="bottom-controls">
|
||||
<!-- 批量操作按钮 -->
|
||||
<!-- Batch Operation Buttons -->
|
||||
<view class="batch-buttons">
|
||||
<u-button
|
||||
type="primary"
|
||||
@@ -123,7 +123,7 @@
|
||||
:custom-style="{flex: 1, height: '88rpx', fontSize: '28rpx', fontWeight: '600', borderRadius: '16rpx'}"
|
||||
>
|
||||
<uni-icons type="checkmarkempty" color="#fff" size="24" style="margin-right: 8rpx;"></uni-icons>
|
||||
启动选中({{ selectedChannels.length }})
|
||||
Start Selected({{ selectedChannels.length }})
|
||||
</u-button>
|
||||
<u-button
|
||||
type="error"
|
||||
@@ -132,7 +132,7 @@
|
||||
:custom-style="{flex: 1, height: '88rpx', fontSize: '28rpx', fontWeight: '600', borderRadius: '16rpx', marginLeft: '20rpx'}"
|
||||
>
|
||||
<uni-icons type="closeempty" color="#fff" size="24" style="margin-right: 8rpx;"></uni-icons>
|
||||
停止选中({{ selectedChannels.length }})
|
||||
Stop Selected({{ selectedChannels.length }})
|
||||
</u-button>
|
||||
</view>
|
||||
</view>
|
||||
@@ -178,8 +178,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 60,
|
||||
controlType: 'speed', // speed, status
|
||||
timerMode: '定时', // 定时, 格式
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0, // 剩余秒数
|
||||
timerHours: 0 // 设置的小时数
|
||||
},
|
||||
@@ -191,8 +191,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 65,
|
||||
controlType: 'speed',
|
||||
timerMode: '定时',
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0,
|
||||
timerHours: 0
|
||||
},
|
||||
@@ -204,8 +204,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 70,
|
||||
controlType: 'speed',
|
||||
timerMode: '定时',
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0,
|
||||
timerHours: 0
|
||||
},
|
||||
@@ -217,8 +217,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 75,
|
||||
controlType: 'speed',
|
||||
timerMode: '定时',
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0,
|
||||
timerHours: 0
|
||||
},
|
||||
@@ -230,8 +230,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 80,
|
||||
controlType: 'speed',
|
||||
timerMode: '定时',
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0,
|
||||
timerHours: 0
|
||||
},
|
||||
@@ -243,8 +243,8 @@ const channels = ref([
|
||||
currentValue: '0-400',
|
||||
runValue: 50,
|
||||
controlType: 'speed',
|
||||
timerMode: '定时',
|
||||
timerValue: '未设置',
|
||||
timerMode: 'Timer',
|
||||
timerValue: 'Not Set',
|
||||
remainingTime: 0,
|
||||
timerHours: 0
|
||||
}
|
||||
@@ -254,7 +254,7 @@ const channels = ref([
|
||||
onLoad((options) => {
|
||||
if (options.deviceId) {
|
||||
deviceId.value = options.deviceId
|
||||
deviceName.value = decodeURIComponent(options.deviceName || '') || '六通道搅拌器'
|
||||
deviceName.value = decodeURIComponent(options.deviceName || '') || 'Six-Channel Mixer'
|
||||
connected.value = true
|
||||
|
||||
// 获取蓝牙服务和特征值信息
|
||||
@@ -300,12 +300,12 @@ const loadChannelData = (channelId) => {
|
||||
channel.status = 'stopped'
|
||||
|
||||
if (channel.timerHours > 0) {
|
||||
channel.timerValue = `设置 ${channel.timerHours} 小时`
|
||||
channel.timerValue = `Set ${channel.timerHours} hours`
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('加载通道数据失败:', e)
|
||||
console.error('Failed to load channel data:', e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +321,7 @@ const saveChannelData = (channelId) => {
|
||||
uni.setStorageSync(STORAGE_KEY_PREFIX + channelId, JSON.stringify(data))
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('保存通道数据失败:', e)
|
||||
console.error('Failed to save channel data:', e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ const isChannelSelected = (channelId) => {
|
||||
const selectAll = () => {
|
||||
selectedChannels.value = channels.value.map(c => c.id)
|
||||
uni.showToast({
|
||||
title: '已全选',
|
||||
title: 'All Selected',
|
||||
icon: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
@@ -354,7 +354,7 @@ const selectAll = () => {
|
||||
const clearSelection = () => {
|
||||
selectedChannels.value = []
|
||||
uni.showToast({
|
||||
title: '已清空选择',
|
||||
title: 'Selection Cleared',
|
||||
icon: 'success',
|
||||
duration: 1000
|
||||
})
|
||||
@@ -363,11 +363,11 @@ const clearSelection = () => {
|
||||
// 获取状态文本
|
||||
const getStatusText = (status) => {
|
||||
const statusMap = {
|
||||
running: '运行中',
|
||||
stopped: '已停止',
|
||||
timing: '定时中'
|
||||
running: 'Running',
|
||||
stopped: 'Stopped',
|
||||
timing: 'Timing'
|
||||
}
|
||||
return statusMap[status] || '未知'
|
||||
return statusMap[status] || 'Unknown'
|
||||
}
|
||||
|
||||
// 返回
|
||||
@@ -378,9 +378,10 @@ const goBack = () => {
|
||||
// 显示设备信息
|
||||
const showDeviceInfo = () => {
|
||||
uni.showModal({
|
||||
title: '设备信息',
|
||||
content: `设备名称:${deviceName.value}\n设备ID:${deviceId.value}\n连接状态:${connected.value ? '已连接' : '未连接'}`,
|
||||
showCancel: false
|
||||
title: 'Device Info',
|
||||
content: `Device Name: ${deviceName.value}\nDevice ID: ${deviceId.value}\nConnection: ${connected.value ? 'Connected' : 'Disconnected'}`,
|
||||
showCancel: false,
|
||||
confirmText: 'OK'
|
||||
})
|
||||
}
|
||||
|
||||
@@ -405,35 +406,37 @@ const setTimer = (channelId) => {
|
||||
if (!channel) return
|
||||
|
||||
uni.showModal({
|
||||
title: '定时设置',
|
||||
title: 'Timer Setting',
|
||||
editable: true,
|
||||
placeholderText: '请输入小时数(0-99)',
|
||||
placeholderText: 'Enter hours (0-99)',
|
||||
content: channel.timerHours > 0 ? String(channel.timerHours) : '',
|
||||
cancelText: 'Cancel',
|
||||
confirmText: 'OK',
|
||||
success: (res) => {
|
||||
if (res.confirm && res.content) {
|
||||
const hours = parseInt(res.content)
|
||||
if (isNaN(hours) || hours < 0 || hours > 99) {
|
||||
uni.showToast({
|
||||
title: '请输入0-99的数字',
|
||||
title: 'Please enter 0-99',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
channel.timerHours = hours
|
||||
channel.remainingTime = hours * 3600 // 转为秒(小时*3600)
|
||||
channel.remainingTime = hours * 3600 // Convert to seconds (hours*3600)
|
||||
|
||||
if (hours > 0) {
|
||||
channel.timerValue = `设置 ${hours} 小时`
|
||||
channel.timerValue = `Set ${hours} hours`
|
||||
} else {
|
||||
channel.timerValue = '未设置'
|
||||
channel.timerValue = 'Not Set'
|
||||
}
|
||||
|
||||
saveChannelData(channelId)
|
||||
sendBluetoothCommand('setTimer', channelId, hours)
|
||||
|
||||
uni.showToast({
|
||||
title: `定时设置成功`,
|
||||
title: `Timer Set Successfully`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -467,7 +470,7 @@ const startChannel = (channelId) => {
|
||||
|
||||
sendBluetoothCommand('start', channelId)
|
||||
uni.showToast({
|
||||
title: `${channel.name} 已启动`,
|
||||
title: `${channel.name} Started`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -481,7 +484,7 @@ const stopChannel = (channelId) => {
|
||||
stopTimer(channelId)
|
||||
sendBluetoothCommand('stop', channelId)
|
||||
uni.showToast({
|
||||
title: `${channel.name} 已停止`,
|
||||
title: `${channel.name} Stopped`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -491,22 +494,24 @@ const stopChannel = (channelId) => {
|
||||
const batchStart = () => {
|
||||
if (selectedChannels.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请先选择通道',
|
||||
title: 'Please select channels first',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '确认启动',
|
||||
content: `是否启动选中的 ${selectedChannels.value.length} 个通道?`,
|
||||
title: 'Confirm Start',
|
||||
content: `Start ${selectedChannels.value.length} selected channels?`,
|
||||
confirmText: 'Confirm',
|
||||
cancelText: 'Cancel',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
selectedChannels.value.forEach(channelId => {
|
||||
startChannel(channelId)
|
||||
})
|
||||
uni.showToast({
|
||||
title: `已启动 ${selectedChannels.value.length} 个通道`,
|
||||
title: `Started ${selectedChannels.value.length} channels`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -518,22 +523,24 @@ const batchStart = () => {
|
||||
const batchStop = () => {
|
||||
if (selectedChannels.value.length === 0) {
|
||||
uni.showToast({
|
||||
title: '请先选择通道',
|
||||
title: 'Please select channels first',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
uni.showModal({
|
||||
title: '确认停止',
|
||||
content: `是否停止选中的 ${selectedChannels.value.length} 个通道?`,
|
||||
title: 'Confirm Stop',
|
||||
content: `Stop ${selectedChannels.value.length} selected channels?`,
|
||||
confirmText: 'Confirm',
|
||||
cancelText: 'Cancel',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
selectedChannels.value.forEach(channelId => {
|
||||
stopChannel(channelId)
|
||||
})
|
||||
uni.showToast({
|
||||
title: `已停止 ${selectedChannels.value.length} 个通道`,
|
||||
title: `Stopped ${selectedChannels.value.length} channels`,
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
@@ -563,7 +570,7 @@ const startTimer = (channelId) => {
|
||||
sendBluetoothCommand('stop', channelId)
|
||||
|
||||
uni.showToast({
|
||||
title: `${channel.name} 定时已到,自动停止`,
|
||||
title: `${channel.name} Timer expired, auto-stopped`,
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
})
|
||||
@@ -584,14 +591,14 @@ const stopTimer = (channelId) => {
|
||||
const sendBluetoothCommand = (command, channelId, value) => {
|
||||
if (!connected.value) {
|
||||
uni.showToast({
|
||||
title: '蓝牙未连接',
|
||||
title: 'Bluetooth Disconnected',
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!characteristicId.value) {
|
||||
console.error('未找到可写入的特征值')
|
||||
console.error('Characteristic not found for writing')
|
||||
return
|
||||
}
|
||||
|
||||
@@ -604,7 +611,7 @@ const sendBluetoothCommand = (command, channelId, value) => {
|
||||
}
|
||||
|
||||
const jsonStr = JSON.stringify(commandData)
|
||||
console.log('发送蓝牙命令:', jsonStr, `(${jsonStr.length} 字节)`)
|
||||
console.log('Sending Bluetooth command:', jsonStr, `(${jsonStr.length} bytes)`)
|
||||
|
||||
// 检查是否需要分包
|
||||
if (jsonStr.length <= 20) {
|
||||
@@ -615,7 +622,7 @@ const sendBluetoothCommand = (command, channelId, value) => {
|
||||
sendMultiplePackets(jsonStr)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('构造蓝牙命令失败:', error)
|
||||
console.error('Failed to construct Bluetooth command:', error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -629,12 +636,12 @@ const sendSinglePacket = (data) => {
|
||||
characteristicId: characteristicId.value,
|
||||
value: buffer,
|
||||
success: (res) => {
|
||||
console.log('✅ 蓝牙数据发送成功')
|
||||
console.log('✅ Bluetooth data sent successfully')
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('❌ 蓝牙数据发送失败:', err)
|
||||
console.error('❌ Bluetooth data send failed:', err)
|
||||
uni.showToast({
|
||||
title: '发送失败',
|
||||
title: 'Send Failed',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
@@ -651,7 +658,7 @@ const sendMultiplePackets = (data) => {
|
||||
packets.push(data.slice(i, i + maxPacketSize))
|
||||
}
|
||||
|
||||
console.log(`📦 数据需要分 ${packets.length} 包发送`)
|
||||
console.log(`📦 Data needs to be sent in ${packets.length} packets`)
|
||||
|
||||
// 依次发送每个包(间隔 100ms)
|
||||
packets.forEach((packet, index) => {
|
||||
@@ -664,10 +671,10 @@ const sendMultiplePackets = (data) => {
|
||||
characteristicId: characteristicId.value,
|
||||
value: buffer,
|
||||
success: () => {
|
||||
console.log(`✅ 第 ${index + 1}/${packets.length} 包发送成功`)
|
||||
console.log(`✅ Packet ${index + 1}/${packets.length} sent successfully`)
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error(`❌ 第 ${index + 1}/${packets.length} 包发送失败:`, err)
|
||||
console.error(`❌ Packet ${index + 1}/${packets.length} send failed:`, err)
|
||||
}
|
||||
})
|
||||
}, index * 100)
|
||||
@@ -705,7 +712,7 @@ const initBluetoothCommunication = () => {
|
||||
|
||||
if (!res.connected) {
|
||||
uni.showToast({
|
||||
title: '蓝牙已断开',
|
||||
title: 'Bluetooth Disconnected',
|
||||
icon: 'none'
|
||||
})
|
||||
// 停止数据查询
|
||||
|
||||
Reference in New Issue
Block a user