fix: 中文全部换成英文。

This commit is contained in:
tianyongbao
2025-12-19 00:22:58 +08:00
parent 9df9dbdea9
commit 4cc3be6727
4 changed files with 194 additions and 179 deletions

4
.gitignore vendored
View File

@@ -10,3 +10,7 @@ docs/_book
test/ test/
node_modules node_modules
/.idea/.gitignore
/.idea/intc-mixer-app.iml
/.idea/modules.xml
/.idea/vcs.xml

View File

@@ -1,29 +1,29 @@
<template> <template>
<view class="bluetooth-page"> <view class="bluetooth-page">
<!-- 导航栏 --> <!-- Navigation Bar -->
<uni-navbar title="搅拌器设备连接" :border="false" background-color="rgba(102, 126, 234, 0.9)" color="#fff" /> <uni-navbar title="Mixer Device Connection" :border="false" background-color="rgba(102, 126, 234, 0.9)" color="#fff" />
<view class="bluetooth-container"> <view class="bluetooth-container">
<!-- 搜索状态和设置 --> <!-- Search Status and Settings -->
<view class="search-status"> <view class="search-status">
<view class="status-row"> <view class="status-row">
<view class="status-item"> <view class="status-item">
<text class="status-label">蓝牙状态</text> <text class="status-label">Bluetooth:</text>
<text :class="['status-value', bluetoothEnabled ? 'status-on' : 'status-off']"> <text :class="['status-value', bluetoothEnabled ? 'status-on' : 'status-off']">
{{ bluetoothEnabled ? '已开启' : '未开启' }} {{ bluetoothEnabled ? 'On' : 'Off' }}
</text> </text>
</view> </view>
<view class="status-item"> <view class="status-item">
<text class="status-label">搜索状态</text> <text class="status-label">Search:</text>
<text :class="['status-value', isSearching ? 'status-on' : 'status-off']"> <text :class="['status-value', isSearching ? 'status-on' : 'status-off']">
{{ isSearching ? '搜索中...' : '未搜索' }} {{ isSearching ? 'Searching...' : 'Idle' }}
</text> </text>
</view> </view>
</view> </view>
</view> </view>
<!-- 操作按钮 --> <!-- Action Buttons -->
<view class="action-buttons"> <view class="action-buttons">
<u-button <u-button
type="primary" type="primary"
@@ -31,7 +31,7 @@
@click="startBluetoothSearch" @click="startBluetoothSearch"
:disabled="!bluetoothEnabled" :disabled="!bluetoothEnabled"
> >
{{ isSearching ? '搜索中...' : '开始搜索' }} {{ isSearching ? 'Searching...' : 'Start Search' }}
</u-button> </u-button>
<u-button <u-button
type="warning" type="warning"
@@ -40,11 +40,11 @@
:disabled="!isSearching" :disabled="!isSearching"
style="margin-left: 20rpx;" style="margin-left: 20rpx;"
> >
停止搜索 Stop Search
</u-button> </u-button>
</view> </view>
<!-- 预览按钮 --> <!-- Preview Button -->
<view class="preview-button-wrapper"> <view class="preview-button-wrapper">
<u-button <u-button
type="success" type="success"
@@ -52,15 +52,15 @@
@click="previewMixerPage" @click="previewMixerPage"
> >
<uni-icons type="eye" color="#52c41a" size="20" style="margin-right: 8rpx;"></uni-icons> <uni-icons type="eye" color="#52c41a" size="20" style="margin-right: 8rpx;"></uni-icons>
预览搅拌器页面 Preview Mixer Page
</u-button> </u-button>
</view> </view>
<!-- 设备列表 --> <!-- Device List -->
<view class="device-list"> <view class="device-list">
<view class="list-header"> <view class="list-header">
<text class="header-title">附近的设备</text> <text class="header-title">Nearby Devices</text>
<text class="device-count">({{ deviceList.length }})</text> <text class="device-count">({{ deviceList.length }})</text>
</view> </view>
@@ -72,7 +72,7 @@
mode="aspectFit" mode="aspectFit"
/> />
</view> </view>
<text class="empty-text">暂无设备,点击上方按钮开始搜索</text> <text class="empty-text">No devices found, click above to start searching</text>
</view> </view>
<view v-else class="device-items"> <view v-else class="device-items">
@@ -95,20 +95,20 @@
/> />
</view> </view>
<text class="name-text"> <text class="name-text">
{{ device.name || device.localName || `未命名设备 (${device.deviceId.slice(-8)})` }} {{ device.name || device.localName || `Unnamed Device (${device.deviceId.slice(-8)})` }}
</text> </text>
</view> </view>
<view class="device-details"> <view class="device-details">
<text class="detail-text">设备ID: {{ device.deviceId }}</text> <text class="detail-text">Device ID: {{ device.deviceId }}</text>
<text class="detail-text">信号强度: {{ device.RSSI }} dBm</text> <text class="detail-text">Signal: {{ device.RSSI }} dBm</text>
</view> </view>
</view> </view>
<view class="device-action"> <view class="device-action">
<view v-if="device.deviceId === connectedDeviceId" class="connected-badge"> <view v-if="device.deviceId === connectedDeviceId" class="connected-badge">
<text class="badge-text">已连接</text> <text class="badge-text">Connected</text>
</view> </view>
<view v-else-if="device.deviceId === connectingDeviceId" class="connecting-badge"> <view v-else-if="device.deviceId === connectingDeviceId" class="connecting-badge">
<text class="connecting-text">连接中...</text> <text class="connecting-text">Connecting...</text>
</view> </view>
<u-button <u-button
v-else v-else
@@ -116,15 +116,15 @@
size="small" size="small"
@click.stop="connectDevice(device)" @click.stop="connectDevice(device)"
> >
连接 Connect
</u-button> </u-button>
</view> </view>
</view> </view>
<!-- 已连接设备的详细信息显示在对应设备下方 --> <!-- Connected device details, displayed below the corresponding device -->
<view v-if="device.deviceId === connectedDeviceId && connectedDevice" class="device-connected-detail"> <view v-if="device.deviceId === connectedDeviceId && connectedDevice" class="device-connected-detail">
<view class="detail-header"> <view class="detail-header">
<text class="detail-title">连接成功准备跳转...</text> <text class="detail-title">Connected successfully, preparing to navigate...</text>
</view> </view>
</view> </view>
</view> </view>
@@ -366,22 +366,22 @@ const guideToEnableGPS = () => {
let content = '' let content = ''
if (androidVersion >= 12) { if (androidVersion >= 12) {
content = '检测到您使用的是 Android 12+不需要开启GPS即可使用蓝牙功能。' content = 'You are using Android 12+, GPS is not required for Bluetooth.'
} else if (androidVersion >= 10) { } 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 { } 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({ uni.showModal({
title: androidVersion >= 12 ? '提示' : '需要开启GPS', title: androidVersion >= 12 ? 'Notice' : 'GPS Required',
content: content, content: content,
showCancel: androidVersion < 12, showCancel: androidVersion < 12,
confirmText: androidVersion >= 12 ? '知道了' : '去设置', confirmText: androidVersion >= 12 ? 'OK' : 'Go to Settings',
success: (res) => { success: (res) => {
if (res.confirm && androidVersion < 12) { if (res.confirm && androidVersion < 12) {
// 跳转到位置设置页面 // 跳转到位置设置页面
@@ -395,7 +395,7 @@ const guideToEnableGPS = () => {
} catch (e) { } catch (e) {
console.error('跳转设置失败:', e) console.error('跳转设置失败:', e)
uni.showToast({ uni.showToast({
title: '请手动前往设置开启GPS', title: 'Please go to settings manually to enable GPS',
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}) })
@@ -411,14 +411,14 @@ const saveLastDevice = (device) => {
try { try {
const deviceInfo = { const deviceInfo = {
deviceId: device.deviceId, deviceId: device.deviceId,
name: device.name || device.localName || '未命名设备', name: device.name || device.localName || 'Unnamed Device',
localName: device.localName, localName: device.localName,
RSSI: device.RSSI RSSI: device.RSSI
} }
uni.setStorageSync(LAST_DEVICE_KEY, JSON.stringify(deviceInfo)) uni.setStorageSync(LAST_DEVICE_KEY, JSON.stringify(deviceInfo))
console.log('已保存上次连接的设备:', deviceInfo) console.log('Saved last connected device:', deviceInfo)
} catch (e) { } 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) const deviceStr = uni.getStorageSync(LAST_DEVICE_KEY)
if (deviceStr) { if (deviceStr) {
const device = JSON.parse(deviceStr) const device = JSON.parse(deviceStr)
console.log('读取到上次连接的设备:', device) console.log('Read last connected device:', device)
return device return device
} }
} catch (e) { } catch (e) {
console.error('读取设备信息失败:', e) console.error('Failed to read device info:', e)
} }
return null return null
} }
@@ -441,7 +441,7 @@ const getLastDevice = () => {
const tryAutoReconnectLastDevice = async () => { const tryAutoReconnectLastDevice = async () => {
// 防止重复尝试 // 防止重复尝试
if (hasTriedAutoReconnect) { if (hasTriedAutoReconnect) {
console.log('已经尝试过自动重连,跳过') console.log('Already tried auto-reconnect, skipping')
startBluetoothSearch() startBluetoothSearch()
return return
} }
@@ -451,15 +451,15 @@ const tryAutoReconnectLastDevice = async () => {
// 获取上次连接的设备 // 获取上次连接的设备
const lastDevice = getLastDevice() const lastDevice = getLastDevice()
if (!lastDevice) { if (!lastDevice) {
console.log('没有上次连接的设备记录,开始正常搜索') console.log('No last connected device record, starting normal search')
startBluetoothSearch() startBluetoothSearch()
return return
} }
console.log('尝试自动重连上次的设备:', lastDevice.name) console.log('Trying to auto-reconnect to last device:', lastDevice.name)
uni.showLoading({ uni.showLoading({
title: `正在连接 ${lastDevice.name}...`, title: `Connecting ${lastDevice.name}...`,
mask: true mask: true
}) })
@@ -468,7 +468,7 @@ const tryAutoReconnectLastDevice = async () => {
await checkLocationService() await checkLocationService()
} catch (e) { } catch (e) {
uni.hideLoading() uni.hideLoading()
console.log('GPS未开启,无法自动重连') console.log('GPS not enabled, cannot auto-reconnect')
guideToEnableGPS() guideToEnableGPS()
return return
} }
@@ -483,7 +483,7 @@ const tryAutoReconnectLastDevice = async () => {
}) })
}) })
console.log('开始搜索上次连接的设备...') console.log('Starting to search for last connected device...')
// 等待3秒搜索设备 // 等待3秒搜索设备
await new Promise(resolve => setTimeout(resolve, 3000)) await new Promise(resolve => setTimeout(resolve, 3000))
@@ -500,7 +500,7 @@ const tryAutoReconnectLastDevice = async () => {
const targetDevice = devices.find(d => d.deviceId === lastDevice.deviceId) const targetDevice = devices.find(d => d.deviceId === lastDevice.deviceId)
if (targetDevice) { if (targetDevice) {
console.log('找到上次连接的设备,尝试连接:', targetDevice) console.log('Found last connected device, trying to connect:', targetDevice)
// 尝试连接 // 尝试连接
try { try {
@@ -514,7 +514,7 @@ const tryAutoReconnectLastDevice = async () => {
}) })
// 连接成功 // 连接成功
console.log('自动重连成功') console.log('Auto-reconnect successful')
connectingDeviceId.value = '' connectingDeviceId.value = ''
connectedDeviceId.value = targetDevice.deviceId connectedDeviceId.value = targetDevice.deviceId
connectedDevice.value = targetDevice connectedDevice.value = targetDevice
@@ -528,7 +528,7 @@ const tryAutoReconnectLastDevice = async () => {
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '自动连接成功', title: 'Auto-connect successful',
icon: 'success', icon: 'success',
duration: 1500 duration: 1500
}) })
@@ -536,16 +536,16 @@ const tryAutoReconnectLastDevice = async () => {
// 自动跳转到控制页面 // 自动跳转到控制页面
setTimeout(() => { setTimeout(() => {
const url = buildMixerPageUrl(targetDevice, bleInfo) const url = buildMixerPageUrl(targetDevice, bleInfo)
console.log('🚀 跳转到搅拌器页面:', url) console.log('🚀 Navigating to mixer page:', url)
uni.navigateTo({ url }) uni.navigateTo({ url })
}, 1500) }, 1500)
} catch (connectErr) { } catch (connectErr) {
console.error('自动重连失败:', connectErr) console.error('Auto-reconnect failed:', connectErr)
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '自动连接失败,请手动选择', title: 'Auto-connect failed, please select manually',
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}) })
@@ -558,11 +558,11 @@ const tryAutoReconnectLastDevice = async () => {
}, 2000) }, 2000)
} }
} else { } else {
console.log('未找到上次连接的设备,继续正常搜索') console.log('Last device not found, continuing normal search')
uni.hideLoading() uni.hideLoading()
uni.showToast({ uni.showToast({
title: '未找到上次设备', title: 'Last device not found',
icon: 'none', icon: 'none',
duration: 1500 duration: 1500
}) })
@@ -722,11 +722,13 @@ const connectDevice = (device) => {
return return
} }
// 如果已经连接了其他设备,先提示用户 // If already connected to another device, prompt user first
if (connectedDeviceId.value && connectedDeviceId.value !== device.deviceId) { if (connectedDeviceId.value && connectedDeviceId.value !== device.deviceId) {
uni.showModal({ uni.showModal({
title: '提示', title: 'Notice',
content: '已连接其他设备,是否断开并连接新设备?', content: 'Already connected to another device. Disconnect and connect to new device?',
confirmText: 'Confirm',
cancelText: 'Cancel',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
// 先断开当前连接 // 先断开当前连接
@@ -754,19 +756,19 @@ const connectDevice = (device) => {
const doConnect = (device) => { const doConnect = (device) => {
connectingDeviceId.value = device.deviceId connectingDeviceId.value = device.deviceId
console.log('开始连接设备:', device) console.log('Starting to connect device:', device)
uni.createBLEConnection({ uni.createBLEConnection({
deviceId: device.deviceId, deviceId: device.deviceId,
timeout: 10000, // 设置10秒超时 timeout: 10000, // 10 seconds timeout
success: async (res) => { success: async (res) => {
console.log('连接成功', res) console.log('Connection successful', res)
connectingDeviceId.value = '' connectingDeviceId.value = ''
connectedDeviceId.value = device.deviceId connectedDeviceId.value = device.deviceId
connectedDevice.value = device connectedDevice.value = device
uni.showToast({ uni.showToast({
title: '连接成功', title: 'Connected',
icon: 'success' icon: 'success'
}) })
@@ -782,41 +784,41 @@ const doConnect = (device) => {
// 连接成功后跳转到控制页面 // 连接成功后跳转到控制页面
setTimeout(() => { setTimeout(() => {
const url = buildMixerPageUrl(device, bleInfo) const url = buildMixerPageUrl(device, bleInfo)
console.log('🚀 跳转到搅拌器页面:', url) console.log('🚀 Navigating to mixer page:', url)
uni.navigateTo({ url }) uni.navigateTo({ url })
}, 800) }, 800)
}, },
fail: (err) => { fail: (err) => {
console.error('连接失败', err) console.error('Connection failed', err)
connectingDeviceId.value = '' connectingDeviceId.value = ''
// 根据错误码提供更详细的错误信息 // Provide detailed error information based on error code
let errorMsg = '无法连接到该设备' let errorMsg = 'Unable to connect to this device'
if (err.errCode === 10003) { if (err.errCode === 10003) {
errorMsg = '连接失败:设备未找到或已关闭' errorMsg = 'Connection failed: Device not found or turned off'
} else if (err.errCode === 10012) { } else if (err.errCode === 10012) {
errorMsg = '连接失败:连接超时,设备可能距离太远' errorMsg = 'Connection failed: Connection timeout, device may be too far away'
} else if (err.errCode === 10004) { } else if (err.errCode === 10004) {
errorMsg = '连接失败:设备不支持连接' errorMsg = 'Connection failed: Device does not support connection'
} else if (err.errCode === -1) { } else if (err.errCode === -1) {
errorMsg = '连接失败:系统错误,请重启蓝牙后重试' errorMsg = 'Connection failed: System error, please restart Bluetooth and retry'
} else if (err.errMsg) { } else if (err.errMsg) {
errorMsg = `连接失败:${err.errMsg}` errorMsg = `Connection failed: ${err.errMsg}`
} }
uni.showModal({ uni.showModal({
title: '连接失败', title: 'Connection Failed',
content: `${errorMsg} content: `${errorMsg}
错误码: ${err.errCode || '未知'} Error Code: ${err.errCode || 'Unknown'}
提示: Tips:
1. 确保设备在可连接范围内 1. Ensure device is within connection range
2. 确保设备未被其他应用连接 2. Ensure device is not connected by other apps
3. 尝试重启设备蓝牙`, 3. Try restarting device Bluetooth`,
showCancel: false, showCancel: false,
confirmText: '知道了' confirmText: 'OK'
}) })
} }
}) })
@@ -826,7 +828,7 @@ const doConnect = (device) => {
const disconnectDevice = () => { const disconnectDevice = () => {
if (!connectedDeviceId.value) { if (!connectedDeviceId.value) {
uni.showToast({ uni.showToast({
title: '没有已连接的设备', title: 'No connected device',
icon: 'none' icon: 'none'
}) })
return return
@@ -844,14 +846,14 @@ const disconnectDevice = () => {
characteristicId: char.uuid, characteristicId: char.uuid,
state: false, state: false,
success: () => { success: () => {
console.log('关闭notify成功:', char.uuid) console.log('Notify disabled successfully:', char.uuid)
}, },
fail: (err) => { fail: (err) => {
console.error('关闭notify失败:', char.uuid, err) console.error('Failed to disable notify:', char.uuid, err)
} }
}) })
} catch (err) { } catch (err) {
console.error('关闭notify异常:', err) console.error('Notify exception:', err)
} }
}) })
} }
@@ -859,20 +861,20 @@ const disconnectDevice = () => {
uni.closeBLEConnection({ uni.closeBLEConnection({
deviceId: deviceId, deviceId: deviceId,
success: (res) => { success: (res) => {
console.log('断开连接成功', res) console.log('Disconnected successfully', res)
// 清空连接状态和服务信息 // Clear connection status and service info
cleanupConnection() cleanupConnection()
uni.showToast({ uni.showToast({
title: '已断开连接', title: 'Disconnected',
icon: 'success' icon: 'success'
}) })
}, },
fail: (err) => { fail: (err) => {
console.error('断开连接失败', err) console.error('Failed to disconnect', err)
// 即使断开失败,也清空状态(可能设备已经离线) // Clear status even if disconnection fails (device may already be offline)
cleanupConnection() cleanupConnection()
uni.showToast({ uni.showToast({
title: '断开连接', title: 'Disconnected',
icon: 'success' 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 services.value = res.services
// 计算所有服务的特征值总数 // 计算所有服务的特征值总数
@@ -1530,7 +1532,7 @@ const addToHistory = (type, data, hex, characteristicId = '') => {
const toggleHistory = () => { const toggleHistory = () => {
if (dataHistory.value.length === 0) { if (dataHistory.value.length === 0) {
uni.showToast({ uni.showToast({
title: '暂无历史记录', title: 'No history records',
icon: 'none' icon: 'none'
}) })
return return
@@ -1538,18 +1540,20 @@ const toggleHistory = () => {
showHistory.value = !showHistory.value showHistory.value = !showHistory.value
} }
// 清空历史记录 // Clear history
const clearHistory = () => { const clearHistory = () => {
uni.showModal({ uni.showModal({
title: '确认', title: 'Confirm',
content: '确定要清空所有历史记录吗?', content: 'Are you sure to clear all history records?',
confirmText: 'Confirm',
cancelText: 'Cancel',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
sendHistory.value = [] sendHistory.value = []
receiveHistory.value = [] receiveHistory.value = []
showHistory.value = false showHistory.value = false
uni.showToast({ uni.showToast({
title: '已清空', title: 'Cleared',
icon: 'success' icon: 'success'
}) })
} }
@@ -1560,12 +1564,12 @@ const clearHistory = () => {
// 监听蓝牙适配器状态变化 // 监听蓝牙适配器状态变化
const onBluetoothAdapterStateChange = () => { const onBluetoothAdapterStateChange = () => {
uni.onBluetoothAdapterStateChange((res) => { uni.onBluetoothAdapterStateChange((res) => {
console.log('蓝牙适配器状态变化', res) console.log('Bluetooth adapter state changed', res)
bluetoothEnabled.value = res.available bluetoothEnabled.value = res.available
if (!res.available) { if (!res.available) {
isSearching.value = false isSearching.value = false
uni.showToast({ uni.showToast({
title: '蓝牙已关闭', title: 'Bluetooth turned off',
icon: 'none' icon: 'none'
}) })
} }
@@ -1577,10 +1581,10 @@ onMounted(() => {
// 判断是否为H5环境 // 判断是否为H5环境
// #ifdef H5 // #ifdef H5
uni.showModal({ uni.showModal({
title: '提示', title: 'Notice',
content: 'H5平台不支持蓝牙功能请使用App或小程序版本', content: 'Bluetooth is not supported on H5 platform, please use App or Mini Program version',
showCancel: false, showCancel: false,
confirmText: '我知道了' confirmText: 'OK'
}) })
bluetoothEnabled.value = false bluetoothEnabled.value = false
// #endif // #endif
@@ -1620,10 +1624,10 @@ const cleanup = () => {
// 关闭蓝牙适配器 // 关闭蓝牙适配器
uni.closeBluetoothAdapter({ uni.closeBluetoothAdapter({
success: (res) => { success: (res) => {
console.log('关闭蓝牙适配器成功', res) console.log('Bluetooth adapter closed successfully', res)
}, },
fail: (err) => { fail: (err) => {
console.error('关闭蓝牙适配器失败', err) console.error('Failed to close Bluetooth adapter', err)
} }
}) })
} }

View File

@@ -12,17 +12,17 @@
</view> </view>
</view> </view>
<!-- 标题 --> <!-- Title -->
<view class="title-section"> <view class="title-section">
<text class="main-title">搅拌器控制连接</text> <text class="main-title">Mixer Control Connection</text>
<text class="sub-title">快速搜索并连接附近搅拌器蓝牙设备</text> <text class="sub-title">Quickly search and connect to nearby mixer Bluetooth devices</text>
</view> </view>
<!-- 登录按钮 --> <!-- 登录按钮 -->
<view class="btn-section"> <view class="btn-section">
<button @click="handleLogin" class="login-btn"> <button @click="handleLogin" class="login-btn">
<uni-icons type="right" size="24" color="#667eea" style="margin-right: 12rpx;"></uni-icons> <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> </button>
</view> </view>

View File

@@ -1,51 +1,51 @@
<template> <template>
<view class="mixer-page"> <view class="mixer-page">
<!-- 顶部蓝牙状态栏 --> <!-- Top Bluetooth Status Bar -->
<view class="custom-navbar"> <view class="custom-navbar">
<view class="navbar-content"> <view class="navbar-content">
<view class="nav-left" @click="goBack"> <view class="nav-left" @click="goBack">
<uni-icons type="back" color="#fff" size="20"></uni-icons> <uni-icons type="back" color="#fff" size="20"></uni-icons>
</view> </view>
<view class="nav-center"> <view class="nav-center">
<text class="nav-title">{{ deviceName || '六通道搅拌器' }}</text> <text class="nav-title">{{ deviceName || 'Six-Channel Mixer' }}</text>
</view> </view>
<view class="nav-right"> <view class="nav-right">
<view class="bluetooth-status" @click="showDeviceInfo"> <view class="bluetooth-status" @click="showDeviceInfo">
<uni-icons type="bluetooth-filled" color="#fff" size="20"></uni-icons> <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> </view>
</view> </view>
<view class="mixer-container"> <view class="mixer-container">
<!-- 选择状态栏 --> <!-- Selection Status Bar -->
<view class="selection-status"> <view class="selection-status">
<view class="status-row"> <view class="status-row">
<view class="status-item"> <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']"> <text :class="['status-value', selectedChannels.length > 0 ? 'status-on' : 'status-off']">
{{ selectedChannels.length }}/{{ channels.length }} 通道 {{ selectedChannels.length }}/{{ channels.length }} Channels
</text> </text>
</view> </view>
<view class="select-actions"> <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-divider">|</text>
<text class="action-link" @click="clearSelection">清空</text> <text class="action-link" @click="clearSelection">Clear</text>
</view> </view>
</view> </view>
</view> </view>
<!-- 通道卡片网格 --> <!-- Channel Cards Grid -->
<view class="channel-grid"> <view class="channel-grid">
<view <view
v-for="channel in channels" v-for="channel in channels"
:key="channel.id" :key="channel.id"
:class="['channel-card', { 'selected': isChannelSelected(channel.id) }]" :class="['channel-card', { 'selected': isChannelSelected(channel.id) }]"
> >
<!-- 通道标题 --> <!-- Channel Title -->
<view class="card-header"> <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="channel-checkbox-inline" @click.stop="toggleChannelSelection(channel.id)">
<view :class="['checkbox-icon', { 'checked': isChannelSelected(channel.id) }]"> <view :class="['checkbox-icon', { 'checked': isChannelSelected(channel.id) }]">
<text v-if="isChannelSelected(channel.id)" class="check-mark"></text> <text v-if="isChannelSelected(channel.id)" class="check-mark"></text>
@@ -59,11 +59,11 @@
</view> </view>
</view> </view>
<!-- 运行模式控制 --> <!-- Run Mode Control -->
<view class="mode-controls"> <view class="mode-controls">
<!-- 转速调节滑块 --> <!-- Speed Adjustment Slider -->
<view class="slider-group" @click.stop> <view class="slider-group" @click.stop>
<text class="slider-label">转速</text> <text class="slider-label">Speed</text>
<text class="slider-min-value">0</text> <text class="slider-min-value">0</text>
<slider <slider
:value="channel.runValue" :value="channel.runValue"
@@ -78,43 +78,43 @@
<text class="slider-max-value">400</text> <text class="slider-max-value">400</text>
</view> </view>
<!-- 转速数值显示 --> <!-- Speed Value Display -->
<view class="speed-display"> <view class="speed-display">
<text class="speed-value">{{ calculateSpeed(channel.runValue) }}</text> <text class="speed-value">{{ calculateSpeed(channel.runValue) }}</text>
<text class="speed-unit">/</text> <text class="speed-unit">RPM</text>
</view> </view>
</view> </view>
<!-- 定时设置 --> <!-- Timer Setting -->
<view class="timer-setting" @click.stop="setTimer(channel.id)"> <view class="timer-setting" @click.stop="setTimer(channel.id)">
<text class="timer-emoji"></text> <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> <text class="timer-value">{{ channel.timerValue }}</text>
</view> </view>
<!-- 启停按钮 --> <!-- Start/Stop Buttons -->
<view class="card-footer"> <view class="card-footer">
<view <view
v-if="channel.status === 'stopped'" v-if="channel.status === 'stopped'"
class="start-btn" class="start-btn"
@click.stop="handleChannelStart(channel.id)" @click.stop="handleChannelStart(channel.id)"
> >
<text class="btn-text">启动</text> <text class="btn-text">Start</text>
</view> </view>
<view <view
v-else v-else
class="stop-btn" class="stop-btn"
@click.stop="handleChannelStop(channel.id)" @click.stop="handleChannelStop(channel.id)"
> >
<text class="btn-text">停止</text> <text class="btn-text">Stop</text>
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<!-- 底部控制区 --> <!-- Bottom Control Area -->
<view class="bottom-controls"> <view class="bottom-controls">
<!-- 批量操作按钮 --> <!-- Batch Operation Buttons -->
<view class="batch-buttons"> <view class="batch-buttons">
<u-button <u-button
type="primary" type="primary"
@@ -123,7 +123,7 @@
:custom-style="{flex: 1, height: '88rpx', fontSize: '28rpx', fontWeight: '600', borderRadius: '16rpx'}" :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> <uni-icons type="checkmarkempty" color="#fff" size="24" style="margin-right: 8rpx;"></uni-icons>
启动选中({{ selectedChannels.length }}) Start Selected({{ selectedChannels.length }})
</u-button> </u-button>
<u-button <u-button
type="error" type="error"
@@ -132,7 +132,7 @@
:custom-style="{flex: 1, height: '88rpx', fontSize: '28rpx', fontWeight: '600', borderRadius: '16rpx', marginLeft: '20rpx'}" :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> <uni-icons type="closeempty" color="#fff" size="24" style="margin-right: 8rpx;"></uni-icons>
停止选中({{ selectedChannels.length }}) Stop Selected({{ selectedChannels.length }})
</u-button> </u-button>
</view> </view>
</view> </view>
@@ -178,8 +178,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 60, runValue: 60,
controlType: 'speed', // speed, status controlType: 'speed', // speed, status
timerMode: '定时', // 定时, 格式 timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, // 剩余秒数 remainingTime: 0, // 剩余秒数
timerHours: 0 // 设置的小时数 timerHours: 0 // 设置的小时数
}, },
@@ -191,8 +191,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 65, runValue: 65,
controlType: 'speed', controlType: 'speed',
timerMode: '定时', timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, remainingTime: 0,
timerHours: 0 timerHours: 0
}, },
@@ -204,8 +204,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 70, runValue: 70,
controlType: 'speed', controlType: 'speed',
timerMode: '定时', timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, remainingTime: 0,
timerHours: 0 timerHours: 0
}, },
@@ -217,8 +217,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 75, runValue: 75,
controlType: 'speed', controlType: 'speed',
timerMode: '定时', timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, remainingTime: 0,
timerHours: 0 timerHours: 0
}, },
@@ -230,8 +230,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 80, runValue: 80,
controlType: 'speed', controlType: 'speed',
timerMode: '定时', timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, remainingTime: 0,
timerHours: 0 timerHours: 0
}, },
@@ -243,8 +243,8 @@ const channels = ref([
currentValue: '0-400', currentValue: '0-400',
runValue: 50, runValue: 50,
controlType: 'speed', controlType: 'speed',
timerMode: '定时', timerMode: 'Timer',
timerValue: '未设置', timerValue: 'Not Set',
remainingTime: 0, remainingTime: 0,
timerHours: 0 timerHours: 0
} }
@@ -254,7 +254,7 @@ const channels = ref([
onLoad((options) => { onLoad((options) => {
if (options.deviceId) { if (options.deviceId) {
deviceId.value = options.deviceId deviceId.value = options.deviceId
deviceName.value = decodeURIComponent(options.deviceName || '') || '六通道搅拌器' deviceName.value = decodeURIComponent(options.deviceName || '') || 'Six-Channel Mixer'
connected.value = true connected.value = true
// 获取蓝牙服务和特征值信息 // 获取蓝牙服务和特征值信息
@@ -300,12 +300,12 @@ const loadChannelData = (channelId) => {
channel.status = 'stopped' channel.status = 'stopped'
if (channel.timerHours > 0) { if (channel.timerHours > 0) {
channel.timerValue = `设置 ${channel.timerHours} 小时` channel.timerValue = `Set ${channel.timerHours} hours`
} }
} }
} }
} catch (e) { } 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)) uni.setStorageSync(STORAGE_KEY_PREFIX + channelId, JSON.stringify(data))
} }
} catch (e) { } catch (e) {
console.error('保存通道数据失败:', e) console.error('Failed to save channel data:', e)
} }
} }
@@ -344,7 +344,7 @@ const isChannelSelected = (channelId) => {
const selectAll = () => { const selectAll = () => {
selectedChannels.value = channels.value.map(c => c.id) selectedChannels.value = channels.value.map(c => c.id)
uni.showToast({ uni.showToast({
title: '已全选', title: 'All Selected',
icon: 'success', icon: 'success',
duration: 1000 duration: 1000
}) })
@@ -354,7 +354,7 @@ const selectAll = () => {
const clearSelection = () => { const clearSelection = () => {
selectedChannels.value = [] selectedChannels.value = []
uni.showToast({ uni.showToast({
title: '已清空选择', title: 'Selection Cleared',
icon: 'success', icon: 'success',
duration: 1000 duration: 1000
}) })
@@ -363,11 +363,11 @@ const clearSelection = () => {
// 获取状态文本 // 获取状态文本
const getStatusText = (status) => { const getStatusText = (status) => {
const statusMap = { const statusMap = {
running: '运行中', running: 'Running',
stopped: '已停止', stopped: 'Stopped',
timing: '定时中' timing: 'Timing'
} }
return statusMap[status] || '未知' return statusMap[status] || 'Unknown'
} }
// 返回 // 返回
@@ -378,9 +378,10 @@ const goBack = () => {
// 显示设备信息 // 显示设备信息
const showDeviceInfo = () => { const showDeviceInfo = () => {
uni.showModal({ uni.showModal({
title: '设备信息', title: 'Device Info',
content: `设备名称:${deviceName.value}\n设备ID${deviceId.value}\n连接状态:${connected.value ? '已连接' : '未连接'}`, content: `Device Name: ${deviceName.value}\nDevice ID: ${deviceId.value}\nConnection: ${connected.value ? 'Connected' : 'Disconnected'}`,
showCancel: false showCancel: false,
confirmText: 'OK'
}) })
} }
@@ -405,35 +406,37 @@ const setTimer = (channelId) => {
if (!channel) return if (!channel) return
uni.showModal({ uni.showModal({
title: '定时设置', title: 'Timer Setting',
editable: true, editable: true,
placeholderText: '请输入小时数(0-99)', placeholderText: 'Enter hours (0-99)',
content: channel.timerHours > 0 ? String(channel.timerHours) : '', content: channel.timerHours > 0 ? String(channel.timerHours) : '',
cancelText: 'Cancel',
confirmText: 'OK',
success: (res) => { success: (res) => {
if (res.confirm && res.content) { if (res.confirm && res.content) {
const hours = parseInt(res.content) const hours = parseInt(res.content)
if (isNaN(hours) || hours < 0 || hours > 99) { if (isNaN(hours) || hours < 0 || hours > 99) {
uni.showToast({ uni.showToast({
title: '请输入0-99的数字', title: 'Please enter 0-99',
icon: 'none' icon: 'none'
}) })
return return
} }
channel.timerHours = hours channel.timerHours = hours
channel.remainingTime = hours * 3600 // 转为秒(小时*3600 channel.remainingTime = hours * 3600 // Convert to seconds (hours*3600)
if (hours > 0) { if (hours > 0) {
channel.timerValue = `设置 ${hours} 小时` channel.timerValue = `Set ${hours} hours`
} else { } else {
channel.timerValue = '未设置' channel.timerValue = 'Not Set'
} }
saveChannelData(channelId) saveChannelData(channelId)
sendBluetoothCommand('setTimer', channelId, hours) sendBluetoothCommand('setTimer', channelId, hours)
uni.showToast({ uni.showToast({
title: `定时设置成功`, title: `Timer Set Successfully`,
icon: 'success' icon: 'success'
}) })
} }
@@ -467,7 +470,7 @@ const startChannel = (channelId) => {
sendBluetoothCommand('start', channelId) sendBluetoothCommand('start', channelId)
uni.showToast({ uni.showToast({
title: `${channel.name} 已启动`, title: `${channel.name} Started`,
icon: 'success' icon: 'success'
}) })
} }
@@ -481,7 +484,7 @@ const stopChannel = (channelId) => {
stopTimer(channelId) stopTimer(channelId)
sendBluetoothCommand('stop', channelId) sendBluetoothCommand('stop', channelId)
uni.showToast({ uni.showToast({
title: `${channel.name} 已停止`, title: `${channel.name} Stopped`,
icon: 'success' icon: 'success'
}) })
} }
@@ -491,22 +494,24 @@ const stopChannel = (channelId) => {
const batchStart = () => { const batchStart = () => {
if (selectedChannels.value.length === 0) { if (selectedChannels.value.length === 0) {
uni.showToast({ uni.showToast({
title: '请先选择通道', title: 'Please select channels first',
icon: 'none' icon: 'none'
}) })
return return
} }
uni.showModal({ uni.showModal({
title: '确认启动', title: 'Confirm Start',
content: `是否启动选中的 ${selectedChannels.value.length} 个通道?`, content: `Start ${selectedChannels.value.length} selected channels?`,
confirmText: 'Confirm',
cancelText: 'Cancel',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
selectedChannels.value.forEach(channelId => { selectedChannels.value.forEach(channelId => {
startChannel(channelId) startChannel(channelId)
}) })
uni.showToast({ uni.showToast({
title: `已启动 ${selectedChannels.value.length} 个通道`, title: `Started ${selectedChannels.value.length} channels`,
icon: 'success' icon: 'success'
}) })
} }
@@ -518,22 +523,24 @@ const batchStart = () => {
const batchStop = () => { const batchStop = () => {
if (selectedChannels.value.length === 0) { if (selectedChannels.value.length === 0) {
uni.showToast({ uni.showToast({
title: '请先选择通道', title: 'Please select channels first',
icon: 'none' icon: 'none'
}) })
return return
} }
uni.showModal({ uni.showModal({
title: '确认停止', title: 'Confirm Stop',
content: `是否停止选中的 ${selectedChannels.value.length} 个通道?`, content: `Stop ${selectedChannels.value.length} selected channels?`,
confirmText: 'Confirm',
cancelText: 'Cancel',
success: (res) => { success: (res) => {
if (res.confirm) { if (res.confirm) {
selectedChannels.value.forEach(channelId => { selectedChannels.value.forEach(channelId => {
stopChannel(channelId) stopChannel(channelId)
}) })
uni.showToast({ uni.showToast({
title: `已停止 ${selectedChannels.value.length} 个通道`, title: `Stopped ${selectedChannels.value.length} channels`,
icon: 'success' icon: 'success'
}) })
} }
@@ -563,7 +570,7 @@ const startTimer = (channelId) => {
sendBluetoothCommand('stop', channelId) sendBluetoothCommand('stop', channelId)
uni.showToast({ uni.showToast({
title: `${channel.name} 定时已到,自动停止`, title: `${channel.name} Timer expired, auto-stopped`,
icon: 'none', icon: 'none',
duration: 2000 duration: 2000
}) })
@@ -584,14 +591,14 @@ const stopTimer = (channelId) => {
const sendBluetoothCommand = (command, channelId, value) => { const sendBluetoothCommand = (command, channelId, value) => {
if (!connected.value) { if (!connected.value) {
uni.showToast({ uni.showToast({
title: '蓝牙未连接', title: 'Bluetooth Disconnected',
icon: 'none' icon: 'none'
}) })
return return
} }
if (!characteristicId.value) { if (!characteristicId.value) {
console.error('未找到可写入的特征值') console.error('Characteristic not found for writing')
return return
} }
@@ -604,7 +611,7 @@ const sendBluetoothCommand = (command, channelId, value) => {
} }
const jsonStr = JSON.stringify(commandData) const jsonStr = JSON.stringify(commandData)
console.log('发送蓝牙命令:', jsonStr, `(${jsonStr.length} 字节)`) console.log('Sending Bluetooth command:', jsonStr, `(${jsonStr.length} bytes)`)
// 检查是否需要分包 // 检查是否需要分包
if (jsonStr.length <= 20) { if (jsonStr.length <= 20) {
@@ -615,7 +622,7 @@ const sendBluetoothCommand = (command, channelId, value) => {
sendMultiplePackets(jsonStr) sendMultiplePackets(jsonStr)
} }
} catch (error) { } catch (error) {
console.error('构造蓝牙命令失败:', error) console.error('Failed to construct Bluetooth command:', error)
} }
} }
@@ -629,12 +636,12 @@ const sendSinglePacket = (data) => {
characteristicId: characteristicId.value, characteristicId: characteristicId.value,
value: buffer, value: buffer,
success: (res) => { success: (res) => {
console.log('✅ 蓝牙数据发送成功') console.log('✅ Bluetooth data sent successfully')
}, },
fail: (err) => { fail: (err) => {
console.error('❌ 蓝牙数据发送失败:', err) console.error('❌ Bluetooth data send failed:', err)
uni.showToast({ uni.showToast({
title: '发送失败', title: 'Send Failed',
icon: 'none' icon: 'none'
}) })
} }
@@ -651,7 +658,7 @@ const sendMultiplePackets = (data) => {
packets.push(data.slice(i, i + maxPacketSize)) packets.push(data.slice(i, i + maxPacketSize))
} }
console.log(`📦 数据需要分 ${packets.length} 包发送`) console.log(`📦 Data needs to be sent in ${packets.length} packets`)
// 依次发送每个包(间隔 100ms // 依次发送每个包(间隔 100ms
packets.forEach((packet, index) => { packets.forEach((packet, index) => {
@@ -664,10 +671,10 @@ const sendMultiplePackets = (data) => {
characteristicId: characteristicId.value, characteristicId: characteristicId.value,
value: buffer, value: buffer,
success: () => { success: () => {
console.log(` ${index + 1}/${packets.length} 包发送成功`) console.log(`Packet ${index + 1}/${packets.length} sent successfully`)
}, },
fail: (err) => { fail: (err) => {
console.error(` ${index + 1}/${packets.length} 包发送失败:`, err) console.error(`Packet ${index + 1}/${packets.length} send failed:`, err)
} }
}) })
}, index * 100) }, index * 100)
@@ -705,7 +712,7 @@ const initBluetoothCommunication = () => {
if (!res.connected) { if (!res.connected) {
uni.showToast({ uni.showToast({
title: '蓝牙已断开', title: 'Bluetooth Disconnected',
icon: 'none' icon: 'none'
}) })
// 停止数据查询 // 停止数据查询