updata:移动端添加语言切换功能

This commit is contained in:
rainv123
2025-09-26 14:33:06 +08:00
parent d022dd385a
commit dfcac51312
23 changed files with 2248 additions and 589 deletions
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { t } from '@/i18n'
// 类型定义
interface WiFiNetwork {
@@ -53,7 +54,7 @@ const audioLengthText = computed(() => {
const textBytes = stringToBytes(dataStr)
const totalBits = (START_BYTES.length + textBytes.length + 1 + END_BYTES.length) * 8
const duration = Math.ceil(totalBits / BIT_RATE)
return `${duration}`
return `${t('deviceConfig.about')}${duration}${t('deviceConfig.seconds')}`
})
// 字符串转字节数组 - uniapp兼容版本
@@ -227,15 +228,15 @@ async function generateAndPlay() {
generating.value = true
try {
console.log('生成超声波配网音频...')
console.log(t('deviceConfig.generatingUltrasonicConfigAudio') + '...')
// 准备配网数据 - 参考HTML文件格式
const dataStr = `${props.selectedNetwork.ssid}\n${props.password}`
const textBytes = stringToBytes(dataStr)
const fullBytes = [...START_BYTES, ...textBytes, checksum(textBytes), ...END_BYTES]
console.log('配网数据:', { ssid: props.selectedNetwork.ssid, password: props.password })
console.log('数据字节长度:', textBytes.length)
console.log(t('deviceConfig.configData') + ':', { ssid: props.selectedNetwork.ssid, password: props.password })
console.log(t('deviceConfig.dataBytesLength') + ':', textBytes.length)
// 转换为比特流
let bits: number[] = []
@@ -243,7 +244,7 @@ async function generateAndPlay() {
bits = bits.concat(toBits(b))
})
console.log('比特流长度:', bits.length)
console.log(t('deviceConfig.bitStreamLength') + ':', bits.length)
// AFSK调制 - 减少采样率降低文件大小
const reducedSampleRate = 22050 // 降低采样率
@@ -266,19 +267,19 @@ async function generateAndPlay() {
const base64 = arrayBufferToBase64(wavBuffer)
const dataUri = `data:audio/wav;base64,${base64}`
console.log('base64长度:', base64.length, '约', Math.round(base64.length / 1024), 'KB')
console.log(t('deviceConfig.base64Length') + ':', base64.length, t('deviceConfig.about'), Math.round(base64.length / 1024), 'KB')
// 检查数据大小
if (base64.length > 1024 * 1024) { // 超过1MB
throw new Error('音频文件过大,请缩短SSID或密码长度')
throw new Error(t('deviceConfig.audioFileTooLarge'))
}
audioFilePath.value = dataUri
audioGenerated.value = true
console.log('音频生成成功,比特流长度:', bits.length, '采样点数:', floatBuf.length)
console.log(t('deviceConfig.audioGenerationSuccess') + ',比特流长度:', bits.length, t('deviceConfig.samplePoints') + ':', floatBuf.length)
toast.success('声波生成成功')
toast.success(t('deviceConfig.soundWaveGenerationSuccess'))
// 延迟播放
setTimeout(async () => {
@@ -286,8 +287,8 @@ async function generateAndPlay() {
}, 800) // 增加延迟时间
}
catch (error) {
console.error('音频生成失败:', error)
toast.error(`声波生成失败: ${error.message || error}`)
console.error(t('deviceConfig.audioGenerationFailed') + ':', error)
toast.error(`${t('deviceConfig.soundWaveGenerationFailed')}: ${error.message || error}`)
}
finally {
generating.value = false
@@ -344,7 +345,7 @@ function buildWavOptimized(pcm: Uint8Array, sampleRate: number): ArrayBuffer {
// 播放音频
async function playAudio() {
if (!audioFilePath.value) {
toast.error('请先生成音频')
toast.error(t('deviceConfig.pleaseGenerateAudioFirst'))
return
}
@@ -356,7 +357,7 @@ async function playAudio() {
await new Promise(resolve => setTimeout(resolve, 200))
playing.value = true
console.log('开始播放超声波配网音频')
console.log(t('deviceConfig.startPlayingUltrasonicConfigAudio'))
// 创建新的音频上下文
const innerAudioContext = uni.createInnerAudioContext()
@@ -370,12 +371,12 @@ async function playAudio() {
// 简化的事件监听
innerAudioContext.onPlay(() => {
console.log('超声波音频开始播放')
toast.success('开始播放配网声波')
console.log(t('deviceConfig.ultrasonicAudioStartedPlaying'))
toast.success(t('deviceConfig.startPlayingConfigSoundWave'))
})
innerAudioContext.onEnded(() => {
console.log('超声波音频播放结束')
console.log(t('deviceConfig.ultrasonicAudioPlaybackEnded'))
if (!autoLoop.value) {
playing.value = false
cleanupAudio()
@@ -383,18 +384,18 @@ async function playAudio() {
})
innerAudioContext.onError((error) => {
console.error('音频播放失败:', error)
console.error(t('deviceConfig.audioPlaybackFailed') + ':', error)
playing.value = false
let errorMsg = '音频播放失败'
let errorMsg = t('deviceConfig.audioPlaybackFailed')
if (error.errCode === -99) {
errorMsg = '音频资源繁忙,请稍后重试'
errorMsg = t('deviceConfig.audioResourceBusy')
}
else if (error.errCode === 10004) {
errorMsg = '音频格式不支持,可能是data URI问题'
errorMsg = t('deviceConfig.audioFormatNotSupported')
}
else if (error.errCode === 10003) {
errorMsg = '音频文件错误'
errorMsg = t('deviceConfig.audioFileError')
}
toast.error(errorMsg)
@@ -416,10 +417,10 @@ async function playAudio() {
}, 300)
}
catch (error) {
console.error('播放音频异常:', error)
playing.value = false
await cleanupAudio()
toast.error(`播放失败: ${error.message}`)
console.error(t('deviceConfig.audioPlaybackError') + ':', error)
playing.value = false
await cleanupAudio()
toast.error(`${t('deviceConfig.playbackFailed')}: ${error.message}`)
}
}
@@ -429,10 +430,10 @@ async function cleanupAudio() {
try {
audioContext.value.pause()
audioContext.value.destroy()
console.log('清理音频上下文')
console.log(t('deviceConfig.cleaningUpAudioContext'))
}
catch (e) {
console.log('清理音频上下文失败:', e)
console.log(t('deviceConfig.cleaningUpAudioContextFailed') + ':', e)
}
finally {
audioContext.value = null
@@ -445,8 +446,8 @@ async function stopAudio() {
playing.value = false
await cleanupAudio()
console.log('停止播放超声波音频')
toast.success('已停止播放')
console.log(t('deviceConfig.stoppedPlayingUltrasonicAudio'))
toast.success(t('deviceConfig.stoppedPlaying'))
}
</script>
@@ -456,18 +457,18 @@ async function stopAudio() {
<view v-if="props.selectedNetwork" class="selected-network">
<view class="network-info">
<view class="network-name">
选中网络: {{ props.selectedNetwork.ssid }}
{{ t('deviceConfig.selectedNetwork') }}: {{ props.selectedNetwork.ssid }}
</view>
<view class="network-details">
<text class="network-signal">
信号: {{ props.selectedNetwork.rssi }}dBm
{{ t('deviceConfig.signal') }}: {{ props.selectedNetwork.rssi }}dBm
</text>
<text class="network-security">
{{ props.selectedNetwork.authmode === 0 ? '开放网络' : '加密网络' }}
{{ props.selectedNetwork.authmode === 0 ? t('deviceConfig.openNetwork') : t('deviceConfig.encryptedNetwork') }}
</text>
</view>
<view v-if="props.password" class="network-password">
密码: {{ '*'.repeat(props.password.length) }}
{{ t('deviceConfig.password') }}: {{ '*'.repeat(props.password.length) }}
</view>
</view>
</view>
@@ -482,81 +483,81 @@ async function stopAudio() {
:disabled="!canGenerate"
@click="generateAndPlay"
>
{{ generating ? '生成中...' : '🎵 生成并播放声波' }}
</wd-button>
{{ generating ? t('deviceConfig.generating') : '🎵 ' + t('deviceConfig.generateAndPlaySoundWave') }}
</wd-button>
<wd-button
v-if="audioGenerated"
type="success"
size="large"
block
:loading="playing"
@click="playAudio"
>
{{ playing ? '播放中...' : '🔊 播放声波' }}
</wd-button>
<wd-button
v-if="audioGenerated"
type="success"
size="large"
block
:loading="playing"
@click="playAudio"
>
{{ playing ? t('deviceConfig.playing') : '🔊 ' + t('deviceConfig.playSoundWave') }}
</wd-button>
<wd-button
v-if="playing"
type="warning"
size="large"
block
@click="stopAudio"
>
停止播放
</wd-button>
<wd-button
v-if="playing"
type="warning"
size="large"
block
@click="stopAudio"
>
{{ t('deviceConfig.stopPlaying') }}
</wd-button>
</view>
<!-- 音频控制选项 -->
<view v-if="audioGenerated" class="audio-options">
<view class="option-item">
<wd-checkbox v-model="autoLoop">
自动循环播放声波
</wd-checkbox>
</view>
<wd-checkbox v-model="autoLoop">
{{ t('deviceConfig.autoLoopPlaySoundWave') }}
</wd-checkbox>
</view>
</view>
<!-- 音频播放器 -->
<view v-if="audioGenerated" class="audio-player">
<view class="player-info">
<text class="audio-title">
配网音频文件
{{ t('deviceConfig.configAudioFile') }}
</text>
<text class="audio-duration">
时长: {{ audioLengthText }}
{{ t('deviceConfig.duration') }}: {{ audioLengthText }}
</text>
</view>
</view>
<!-- 使用说明 -->
<view class="help-section">
<view class="help-title">
超声波配网说明
<view class="help-title">
{{ t('deviceConfig.ultrasonicConfigInstructions') }}
</view>
<view class="help-content">
<text class="help-item">
1. {{ t('deviceConfig.ensureWifiNetworkSelectedAndPasswordEntered') }}
</text>
<text class="help-item">
2. {{ t('deviceConfig.clickGenerateAndPlaySoundWave') }}
</text>
<text class="help-item">
3. {{ t('deviceConfig.bringPhoneCloseToXiaozhiDevice') }}
</text>
<text class="help-item">
4. {{ t('deviceConfig.duringAudioPlaybackXiaozhiWillReceive') }}
</text>
<text class="help-item">
5. {{ t('deviceConfig.afterConfigSuccessDeviceWillConnect') }}
</text>
<text class="help-tip">
{{ t('deviceConfig.usesAfskModulation') }}
</text>
<text class="help-tip">
{{ t('deviceConfig.ensureModeratePhoneVolume') }}
</text>
</view>
</view>
<view class="help-content">
<text class="help-item">
1. 确保已选择WiFi网络并输入密码
</text>
<text class="help-item">
2. 点击生成并播放声波系统会将配网信息编码为音频
</text>
<text class="help-item">
3. 将手机靠近xiaozhi设备距离1-2
</text>
<text class="help-item">
4. 音频播放时xiaozhi会接收并解码配网信息
</text>
<text class="help-item">
5. 配网成功后设备会自动连接WiFi网络
</text>
<text class="help-tip">
使用AFSK调制技术通过1800Hz和1500Hz频率传输数据
</text>
<text class="help-tip">
请确保手机音量适中避免环境噪音干扰
</text>
</view>
</view>
</view>
</template>
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { t } from '@/i18n'
// 类型定义
interface WiFiNetwork {
@@ -44,7 +45,7 @@ async function checkESP32Connection() {
return response.statusCode === 200
}
catch (error) {
console.log('ESP32连接检查失败:', error)
console.log(t('deviceConfig.esp32ConnectionCheckFailed') + ':', error)
return false
}
}
@@ -57,12 +58,12 @@ async function submitConfig() {
// 检查ESP32连接
const connected = await checkESP32Connection()
if (!connected) {
toast.error('请先连接xiaozhi热点')
return
}
toast.error(t('deviceConfig.connectXiaozhiHotspot'))
return
}
configuring.value = true
console.log('开始WiFi配网:', props.selectedNetwork.ssid)
console.log(t('deviceConfig.startWifiConfig') + ':', props.selectedNetwork.ssid)
try {
const response = await uni.request({
@@ -81,16 +82,16 @@ async function submitConfig() {
console.log('WiFi配网响应:', response)
if (response.statusCode === 200 && (response.data as any)?.success) {
toast.success(`配网成功!设备将连接到 ${props.selectedNetwork.ssid},设备会自动重启。请断开xiaozhi热点连接。`)
toast.success(`${t('deviceConfig.configSuccess')}${t('deviceConfig.deviceWillConnectTo')} ${props.selectedNetwork.ssid}${t('deviceConfig.deviceWillRestart')}${t('deviceConfig.pleaseDisconnectXiaozhiHotspot')}`)
}
else {
const errorMsg = (response.data as any)?.error || '配网失败'
const errorMsg = (response.data as any)?.error || t('deviceConfig.configFailed')
toast.error(errorMsg)
}
}
catch (error) {
console.error('WiFi配网失败:', error)
toast.error('配网失败,请检查网络连接')
console.error(t('deviceConfig.wifiConfigFailed') + ':', error)
toast.error(`${t('deviceConfig.configFailed')}${t('deviceConfig.pleaseCheckNetworkConnection')}`)
}
finally {
configuring.value = false
@@ -104,14 +105,14 @@ async function submitConfig() {
<view v-if="props.selectedNetwork" class="selected-network">
<view class="network-info">
<view class="network-name">
选中网络: {{ props.selectedNetwork.ssid }}
{{ t('deviceConfig.selectedNetwork') }}: {{ props.selectedNetwork.ssid }}
</view>
<view class="network-details">
<text class="network-signal">
信号: {{ props.selectedNetwork.rssi }}dBm
{{ t('deviceConfig.signal') }}: {{ props.selectedNetwork.rssi }}dBm
</text>
<text class="network-security">
{{ props.selectedNetwork.authmode === 0 ? '开放网络' : '加密网络' }}
{{ props.selectedNetwork.authmode === 0 ? t('deviceConfig.openNetwork') : t('deviceConfig.encryptedNetwork') }}
</text>
</view>
</view>
@@ -127,30 +128,30 @@ async function submitConfig() {
:disabled="!canSubmit"
@click="submitConfig"
>
{{ configuring ? '配网中...' : '开始WiFi配网' }}
{{ configuring ? t('deviceConfig.configuring') : t('deviceConfig.startWifiConfigButton') }}
</wd-button>
</view>
<!-- 使用说明 -->
<view class="help-section">
<view class="help-title">
WiFi配网说明
</view>
<view class="help-title">
{{ t('deviceConfig.wifiConfigInstructions') }}
</view>
<view class="help-content">
<text class="help-item">
1. 手机连接xiaozhi热点 (xiaozhi-XXXXXX)
1. {{ t('deviceConfig.phoneConnectXiaozhiHotspot') }} (xiaozhi-XXXXXX)
</text>
<text class="help-item">
2. 选择要配网的目标WiFi网络
2. {{ t('deviceConfig.selectTargetWifiNetwork') }}
</text>
<text class="help-item">
3. 输入WiFi密码如果需要
3. {{ t('deviceConfig.enterWifiPasswordIfNeeded') }}
</text>
<text class="help-item">
4. 点击开始配网等待设备连接
4. {{ t('deviceConfig.clickStartConfigAndWait') }}
</text>
<text class="help-tip">
配网成功后设备会自动重启并连接目标WiFi
{{ t('deviceConfig.afterConfigSuccessDeviceWillRestart') }}
</text>
</view>
</view>
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { computed, defineEmits, defineExpose, onMounted, ref } from 'vue'
import { useToast } from 'wot-design-uni'
import { t } from '@/i18n'
// 类型定义
interface WiFiNetwork {
@@ -40,7 +41,7 @@ const selectorExpanded = ref(false)
// 计算属性
const networkDisplayText = computed(() => {
if (!selectedNetwork.value)
return '请选择WiFi网络'
return t('deviceConfig.selectWifiNetwork')
return selectedNetwork.value.ssid
})
@@ -55,7 +56,7 @@ async function checkESP32Connection() {
})
isConnectedToESP32.value = response.statusCode === 200
emit('connection-status', isConnectedToESP32.value)
console.log('xiaozhi连接状态:', isConnectedToESP32.value)
console.log(`${t('deviceConfig.xiaozhi')}连接状态:`, isConnectedToESP32.value)
}
catch (error) {
isConnectedToESP32.value = false
@@ -70,9 +71,9 @@ async function checkESP32Connection() {
// 扫描WiFi网络
async function scanWifi() {
if (!isConnectedToESP32.value) {
toast.error('请先连接xiaozhi热点')
return
}
toast.error(t('deviceConfig.connectXiaozhiHotspot'))
return
}
scanning.value = true
console.log('开始扫描WiFi网络')
@@ -84,13 +85,13 @@ async function scanWifi() {
timeout: 10000,
})
console.log('WiFi扫描响应:', response)
console.log(t('deviceConfig.wifiScanResponse') + ':', response)
if (response.statusCode === 200 && response.data) {
const data = response.data as any
if (data.success && Array.isArray(data.networks)) {
wifiNetworks.value = data.networks
console.log(`扫描成功,发现 ${data.networks.length} 个网络`)
console.log(`${t('deviceConfig.scanSuccess')},发现 ${data.networks.length} ${t('deviceConfig.networks')}`)
}
else if (Array.isArray(response.data)) {
// 兼容旧格式
@@ -110,8 +111,8 @@ async function scanWifi() {
}
}
catch (error) {
console.error('WiFi扫描失败:', error)
toast.error('扫描失败,请检查xiaozhi连接')
console.error(t('deviceConfig.wifiScanFailed') + ':', error)
toast.error(t('deviceConfig.scanFailedCheckConnection'))
}
finally {
scanning.value = false
@@ -124,9 +125,9 @@ async function showNetworkSelector() {
await checkESP32Connection()
if (!isConnectedToESP32.value) {
toast.error('请先连接xiaozhi热点')
return
}
toast.error(t('deviceConfig.connectXiaozhiHotspot'))
return
}
selectorExpanded.value = true
@@ -172,12 +173,12 @@ function reset() {
// 获取信号强度描述
function getSignalStrength(rssi: number): string {
if (rssi >= -50)
return '信号强'
return t('deviceConfig.signalStrong')
if (rssi >= -60)
return '信号良好'
return t('deviceConfig.signalGood')
if (rssi >= -70)
return '信号一般'
return '信号弱'
return t('deviceConfig.signalFair')
return t('deviceConfig.signalWeak')
}
// 获取信号强度颜色
@@ -212,81 +213,81 @@ onMounted(() => {
<!-- Xiaozhi连接状态 -->
<view v-if="props.autoConnect" class="connection-status">
<view v-if="!isConnectedToESP32" class="status-warning">
<view class="status-content">
<text class="warning-text">
请先连接xiaozhi热点 (xiaozhi-XXXXXX)
</text>
<wd-button
size="small"
type="primary"
:loading="checkingConnection"
@click="checkESP32Connection"
>
{{ checkingConnection ? '检测中...' : '重新检测' }}
</wd-button>
<view class="status-content">
<text class="warning-text">
{{ t('deviceConfig.connectXiaozhiHotspot') }} (xiaozhi-XXXXXX)
</text>
<wd-button
size="small"
type="primary"
:loading="checkingConnection"
@click="checkESP32Connection"
>
{{ checkingConnection ? t('deviceConfig.checking') : t('deviceConfig.reCheck') }}
</wd-button>
</view>
</view>
</view>
<view v-else class="status-success">
<view class="status-content">
<text class="success-text">
已连接xiaozhi热点
</text>
<wd-button
size="small"
:loading="checkingConnection"
@click="checkESP32Connection"
>
{{ checkingConnection ? '检测中...' : '刷新状态' }}
</wd-button>
<view class="status-content">
<text class="success-text">
{{ t('deviceConfig.connectedXiaozhiHotspot') }}
</text>
<wd-button
size="small"
:loading="checkingConnection"
@click="checkESP32Connection"
>
{{ checkingConnection ? t('deviceConfig.checking') : t('deviceConfig.refreshStatus') }}
</wd-button>
</view>
</view>
</view>
</view>
<!-- WiFi网络选择器 -->
<view class="network-selector">
<view class="selector-item" @click="showNetworkSelector">
<text class="selector-label">
WiFi网络
</text>
<text class="selector-value">
{{ networkDisplayText }}
</text>
<wd-icon name="arrow-right" custom-class="arrow-icon" />
<view class="selector-item" @click="showNetworkSelector">
<text class="selector-label">
{{ t('deviceConfig.wifiNetwork') }}
</text>
<text class="selector-value">
{{ networkDisplayText }}
</text>
<wd-icon name="arrow-right" custom-class="arrow-icon" />
</view>
</view>
</view>
<!-- 展开的网络列表 -->
<view v-if="selectorExpanded" class="network-list-overlay">
<view class="network-list-container">
<view class="list-header">
<text class="list-title">
选择WiFi网络
</text>
<view class="list-actions">
<wd-button
type="primary"
size="small"
:loading="scanning"
@click="scanWifi"
>
{{ scanning ? '扫描中...' : '刷新扫描' }}
</wd-button>
<wd-button
size="small"
@click="selectorExpanded = false"
>
取消
</wd-button>
<text class="list-title">
{{ t('deviceConfig.selectWifiNetwork') }}
</text>
<view class="list-actions">
<wd-button
type="primary"
size="small"
:loading="scanning"
@click="scanWifi"
>
{{ scanning ? t('deviceConfig.scanning') : t('deviceConfig.refreshScan') }}
</wd-button>
<wd-button
size="small"
@click="selectorExpanded = false"
>
{{ t('deviceConfig.cancel') }}
</wd-button>
</view>
</view>
</view>
<view class="network-list">
<view v-if="wifiNetworks.length === 0 && !scanning" class="empty-state">
<text class="empty-text">
暂无WiFi网络
{{ t('deviceConfig.noWifiNetworks') }}
</text>
<text class="empty-tip">
请点击刷新扫描
{{ t('deviceConfig.clickRefreshScan') }}
</text>
</view>
@@ -303,16 +304,16 @@ onMounted(() => {
</view>
<view class="wifi-details">
<text class="wifi-signal">
信号: {{ network.rssi }}dBm
{{ t('deviceConfig.signal') }}: {{ network.rssi }}dBm
</text>
<text class="wifi-channel">
频道: {{ network.channel }}
{{ t('deviceConfig.channel') }}: {{ network.channel }}
</text>
</view>
</view>
<view class="wifi-security">
<text class="security-icon">
{{ network.authmode === 0 ? '开放' : '加密' }}
{{ network.authmode === 0 ? t('deviceConfig.open') : t('deviceConfig.encrypted') }}
</text>
</view>
</view>
@@ -324,17 +325,17 @@ onMounted(() => {
<!-- 密码输入 -->
<view v-if="selectedNetwork && selectedNetwork.authmode > 0" class="password-section">
<view class="password-item">
<text class="password-label">
网络密码
</text>
<wd-input
v-model="password"
placeholder="请输入WiFi密码"
show-password
clearable
@input="onPasswordChange"
/>
</view>
<text class="password-label">
{{ t('deviceConfig.networkPassword') }}
</text>
<wd-input
v-model="password"
:placeholder="t('deviceConfig.enterWifiPassword')"
show-password
clearable
@input="onPasswordChange"
/>
</view>
</view>
</view>
</template>
@@ -1,5 +1,6 @@
<script setup lang="ts">
import { ref } from 'vue'
import { t } from '@/i18n'
import UltrasonicConfig from './components/ultrasonic-config.vue'
import WifiConfig from './components/wifi-config.vue'
import WifiSelector from './components/wifi-selector.vue'
@@ -33,11 +34,11 @@ const selectedWifiInfo = ref<{
// 配网模式选项
const configTypeOptions = [
{
name: 'WiFi配网',
name: t('deviceConfig.wifiConfig'),
value: 'wifi' as const,
},
// {
// name: '超声波配网',
// name: t('deviceConfig.ultrasonicConfig'),
// value: 'ultrasonic' as const,
// },
]
@@ -67,28 +68,36 @@ function onNetworkSelected(network: WiFiNetwork | null, password: string) {
function onConnectionStatusChange(connected: boolean) {
console.log('ESP32连接状态:', connected)
}
// 在组件挂载后设置导航栏标题
import { onMounted } from 'vue'
onMounted(() => {
uni.setNavigationBarTitle({
title: t('deviceConfig.pageTitle')
})
})
</script>
<template>
<view class="min-h-screen bg-[#f5f7fb]">
<wd-navbar title="设备配网" safe-area-inset-top />
<wd-navbar :title="t('deviceConfig.pageTitle')" safe-area-inset-top />
<view class="box-border px-[20rpx]">
<!-- 配网方式选择 -->
<view class="pb-[20rpx] first:pt-[20rpx]">
<text class="text-[32rpx] text-[#232338] font-bold">
配网方式
</text>
{{ t('deviceConfig.configMethod') }}
</text>
</view>
<view class="mb-[24rpx] border border-[#eeeeee] rounded-[20rpx] bg-[#fbfbfb] p-[24rpx]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
<view class="flex cursor-pointer items-center justify-between border border-[#eeeeee] rounded-[12rpx] bg-[#f5f7fb] p-[20rpx] transition-all duration-300 active:border-[#336cff] active:bg-[#eef3ff]" @click="showConfigTypeSelector">
<text class="text-[28rpx] text-[#232338] font-medium">
配网方式
</text>
<text class="mx-[16rpx] flex-1 text-right text-[26rpx] text-[#65686f]">
{{ configType === 'wifi' ? 'WiFi配网' : '超声波配网' }}
</text>
{{ t('deviceConfig.configMethod') }}
</text>
<text class="mx-[16rpx] flex-1 text-right text-[26rpx] text-[#65686f]">
{{ configType === 'wifi' ? t('deviceConfig.wifiConfig') : t('deviceConfig.ultrasonicConfig') }}
</text>
<wd-icon name="arrow-right" custom-class="text-[20rpx] text-[#9d9ea3]" />
</view>
</view>
@@ -96,8 +105,8 @@ function onConnectionStatusChange(connected: boolean) {
<!-- WiFi网络选择 -->
<view class="pb-[20rpx]">
<text class="text-[32rpx] text-[#232338] font-bold">
网络配置
</text>
{{ t('deviceConfig.networkConfig') }}
</text>
</view>
<view class="mb-[24rpx] border border-[#eeeeee] rounded-[20rpx] bg-[#fbfbfb] p-[24rpx]" style="box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);">
@@ -139,7 +148,7 @@ function onConnectionStatusChange(connected: boolean) {
<route lang="jsonc" type="page">
{
"style": {
"navigationBarTitleText": "设备配",
"navigationBarTitleText": "设备配",
"navigationStyle": "custom"
}
}