mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-21 22:53:56 +08:00
fix: resolve mobile type and lint errors
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { onHide, onLaunch, onShow } from '@dcloudio/uni-app'
|
||||
import { watch, onMounted } from 'vue'
|
||||
import { onMounted, watch } from 'vue'
|
||||
import { usePageAuth } from '@/hooks/usePageAuth'
|
||||
import { useConfigStore } from '@/store'
|
||||
import { t } from '@/i18n'
|
||||
import { useConfigStore } from '@/store'
|
||||
import { useLangStore } from '@/store/lang'
|
||||
import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
|
||||
|
||||
@@ -37,7 +37,7 @@ function updateTabBarText() {
|
||||
success: () => {},
|
||||
fail: (err) => {
|
||||
console.log('设置首页tabBar文本失败:', err)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// 设置配网tabBar文本
|
||||
@@ -47,7 +47,7 @@ function updateTabBarText() {
|
||||
success: () => {},
|
||||
fail: (err) => {
|
||||
console.log('设置配网tabBar文本失败:', err)
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// 设置系统tabBar文本
|
||||
@@ -57,9 +57,10 @@ function updateTabBarText() {
|
||||
success: () => {},
|
||||
fail: (err) => {
|
||||
console.log('设置系统tabBar文本失败:', err)
|
||||
}
|
||||
},
|
||||
})
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
console.log('更新tabBar文本时出错:', error)
|
||||
}
|
||||
}
|
||||
|
||||
+547
-547
File diff suppressed because it is too large
Load Diff
@@ -1,23 +1,23 @@
|
||||
import type { Language } from '@/store/lang'
|
||||
import { ref } from 'vue'
|
||||
import { useLangStore } from '@/store/lang'
|
||||
import type { Language } from '@/store/lang'
|
||||
|
||||
import de from './de'
|
||||
import en from './en'
|
||||
import pt_BR from './pt_BR'
|
||||
import vi from './vi'
|
||||
// 导入各个语言的翻译文件
|
||||
import zh_CN from './zh_CN'
|
||||
import en from './en'
|
||||
import zh_TW from './zh_TW'
|
||||
import de from './de'
|
||||
import vi from './vi'
|
||||
import pt_BR from './pt_BR'
|
||||
|
||||
// 语言包映射
|
||||
const messages = {
|
||||
zh_CN: zh_CN,
|
||||
zh_CN,
|
||||
en,
|
||||
zh_TW: zh_TW,
|
||||
zh_TW,
|
||||
de,
|
||||
vi,
|
||||
pt_BR: pt_BR,
|
||||
pt_BR,
|
||||
}
|
||||
|
||||
// 当前使用的语言
|
||||
@@ -42,7 +42,7 @@ export function t(key: string, params?: Record<string, string | number>): string
|
||||
|
||||
// 直接查找扁平键名
|
||||
if (langMessages && typeof langMessages === 'object' && key in langMessages) {
|
||||
let value = langMessages[key]
|
||||
const value = langMessages[key]
|
||||
if (typeof value === 'string') {
|
||||
// 处理参数替换
|
||||
if (params) {
|
||||
|
||||
@@ -29,9 +29,9 @@ export default {
|
||||
'login.requiredCaptcha': 'O código de verificação não pode estar vazio',
|
||||
'login.requiredMobile': 'Por favor, insira um número de telefone válido',
|
||||
'login.captchaError': 'Erro no código de verificação gráfico',
|
||||
'login.forgotPassword': 'Esqueceu a Senha',
|
||||
'login.userAgreement': 'Termos de Uso',
|
||||
'login.privacyPolicy': 'Política de Privacidade',
|
||||
'login.forgotPassword': 'Esqueceu a Senha',
|
||||
'login.userAgreement': 'Termos de Uso',
|
||||
'login.privacyPolicy': 'Política de Privacidade',
|
||||
|
||||
// Register page
|
||||
'register.pageTitle': 'Cadastro',
|
||||
|
||||
+547
-547
File diff suppressed because it is too large
Load Diff
@@ -29,9 +29,9 @@ export default {
|
||||
'login.requiredCaptcha': '驗證碼不能為空',
|
||||
'login.requiredMobile': '請輸入正確的手機號碼',
|
||||
'login.captchaError': '圖形驗證碼錯誤',
|
||||
'login.forgotPassword': '忘記密碼',
|
||||
'login.userAgreement': '用戶協議',
|
||||
'login.privacyPolicy': '隱私政策',
|
||||
'login.forgotPassword': '忘記密碼',
|
||||
'login.userAgreement': '用戶協議',
|
||||
'login.privacyPolicy': '隱私政策',
|
||||
|
||||
// 忘記密碼頁面
|
||||
'retrievePassword.title': '重置密碼',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni/components/wd-config-provider/types'
|
||||
|
||||
const themeVars: ConfigProviderThemeVars = {
|
||||
// colorTheme: 'red',
|
||||
|
||||
@@ -38,10 +38,8 @@ onLoad(() => {
|
||||
<wd-tabbar
|
||||
v-if="customTabbarEnable"
|
||||
v-model="tabbarStore.curIdx"
|
||||
bordered
|
||||
safe-area-inset-bottom
|
||||
placeholder
|
||||
fixed
|
||||
|
||||
safe-area-inset-bottom bordered placeholder fixed
|
||||
@change="selectTabBar"
|
||||
>
|
||||
<block v-for="(item, idx) in tabbarList" :key="item.path">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni'
|
||||
import type { ConfigProviderThemeVars } from 'wot-design-uni/components/wd-config-provider/types'
|
||||
import FgTabbar from './fg-tabbar/fg-tabbar.vue'
|
||||
|
||||
const themeVars: ConfigProviderThemeVars = {
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
import { VueQueryPlugin } from '@tanstack/vue-query'
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { routeInterceptor } from './router/interceptor'
|
||||
|
||||
import store from './store'
|
||||
import '@/style/index.scss'
|
||||
import 'virtual:uno.css'
|
||||
|
||||
// 导入国际化相关功能
|
||||
import { initI18n } from './i18n'
|
||||
import { useLangStore } from './store/lang'
|
||||
|
||||
import { routeInterceptor } from './router/interceptor'
|
||||
import store from './store'
|
||||
|
||||
import '@/style/index.scss'
|
||||
import 'virtual:uno.css'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { AgentSnapshot, AgentSnapshotData } from '@/api/agent/types'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import { useMessage } from 'wot-design-uni/components/wd-message-box'
|
||||
import {
|
||||
deleteAgentSnapshot,
|
||||
getAgentDetail,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import CustomTabs from '@/components/custom-tabs/index.vue'
|
||||
import { t } from '@/i18n'
|
||||
import ChatHistory from '@/pages/chat-history/index.vue'
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import { useMessage } from 'wot-design-uni/components/wd-message-box'
|
||||
import { getMcpAddress, getMcpTools } from '@/api/agent/agent'
|
||||
import { t } from '@/i18n'
|
||||
import { usePluginStore } from '@/store'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from 'vue'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { useToast } from 'wot-design-uni/components/wd-toast'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
// 类型定义
|
||||
@@ -228,15 +228,15 @@ async function generateAndPlay() {
|
||||
generating.value = true
|
||||
|
||||
try {
|
||||
console.log(t('deviceConfig.generatingUltrasonicConfigAudio') + '...')
|
||||
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(t('deviceConfig.configData') + ':', { ssid: props.selectedNetwork.ssid, password: props.password })
|
||||
console.log(t('deviceConfig.dataBytesLength') + ':', textBytes.length)
|
||||
console.log(`${t('deviceConfig.configData')}:`, { ssid: props.selectedNetwork.ssid, password: props.password })
|
||||
console.log(`${t('deviceConfig.dataBytesLength')}:`, textBytes.length)
|
||||
|
||||
// 转换为比特流
|
||||
let bits: number[] = []
|
||||
@@ -244,7 +244,7 @@ async function generateAndPlay() {
|
||||
bits = bits.concat(toBits(b))
|
||||
})
|
||||
|
||||
console.log(t('deviceConfig.bitStreamLength') + ':', bits.length)
|
||||
console.log(`${t('deviceConfig.bitStreamLength')}:`, bits.length)
|
||||
|
||||
// AFSK调制 - 减少采样率降低文件大小
|
||||
const reducedSampleRate = 22050 // 降低采样率
|
||||
@@ -267,7 +267,7 @@ async function generateAndPlay() {
|
||||
const base64 = arrayBufferToBase64(wavBuffer)
|
||||
const dataUri = `data:audio/wav;base64,${base64}`
|
||||
|
||||
console.log(t('deviceConfig.base64Length') + ':', base64.length, t('deviceConfig.about'), 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
|
||||
@@ -277,7 +277,7 @@ async function generateAndPlay() {
|
||||
audioFilePath.value = dataUri
|
||||
audioGenerated.value = true
|
||||
|
||||
console.log(t('deviceConfig.audioGenerationSuccess') + ',比特流长度:', bits.length, t('deviceConfig.samplePoints') + ':', floatBuf.length)
|
||||
console.log(`${t('deviceConfig.audioGenerationSuccess')},比特流长度:`, bits.length, `${t('deviceConfig.samplePoints')}:`, floatBuf.length)
|
||||
|
||||
toast.success(t('deviceConfig.soundWaveGenerationSuccess'))
|
||||
|
||||
@@ -287,8 +287,8 @@ async function generateAndPlay() {
|
||||
}, 800) // 增加延迟时间
|
||||
}
|
||||
catch (error) {
|
||||
console.error(t('deviceConfig.audioGenerationFailed') + ':', error)
|
||||
toast.error(`${t('deviceConfig.soundWaveGenerationFailed')}: ${error.message || error}`)
|
||||
console.error(`${t('deviceConfig.audioGenerationFailed')}:`, error)
|
||||
toast.error(`${t('deviceConfig.soundWaveGenerationFailed')}: ${error.message || error}`)
|
||||
}
|
||||
finally {
|
||||
generating.value = false
|
||||
@@ -384,7 +384,7 @@ async function playAudio() {
|
||||
})
|
||||
|
||||
innerAudioContext.onError((error) => {
|
||||
console.error(t('deviceConfig.audioPlaybackFailed') + ':', error)
|
||||
console.error(`${t('deviceConfig.audioPlaybackFailed')}:`, error)
|
||||
playing.value = false
|
||||
|
||||
let errorMsg = t('deviceConfig.audioPlaybackFailed')
|
||||
@@ -417,10 +417,10 @@ async function playAudio() {
|
||||
}, 300)
|
||||
}
|
||||
catch (error) {
|
||||
console.error(t('deviceConfig.audioPlaybackError') + ':', error)
|
||||
playing.value = false
|
||||
await cleanupAudio()
|
||||
toast.error(`${t('deviceConfig.playbackFailed')}: ${error.message}`)
|
||||
console.error(`${t('deviceConfig.audioPlaybackError')}:`, error)
|
||||
playing.value = false
|
||||
await cleanupAudio()
|
||||
toast.error(`${t('deviceConfig.playbackFailed')}: ${error.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -433,7 +433,7 @@ async function cleanupAudio() {
|
||||
console.log(t('deviceConfig.cleaningUpAudioContext'))
|
||||
}
|
||||
catch (e) {
|
||||
console.log(t('deviceConfig.cleaningUpAudioContextFailed') + ':', e)
|
||||
console.log(`${t('deviceConfig.cleaningUpAudioContextFailed')}:`, e)
|
||||
}
|
||||
finally {
|
||||
audioContext.value = null
|
||||
@@ -483,38 +483,38 @@ async function stopAudio() {
|
||||
:disabled="!canGenerate"
|
||||
@click="generateAndPlay"
|
||||
>
|
||||
{{ generating ? t('deviceConfig.generating') : '🎵 ' + t('deviceConfig.generateAndPlaySoundWave') }}
|
||||
</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 ? t('deviceConfig.playing') : '🔊 ' + t('deviceConfig.playSoundWave') }}
|
||||
</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"
|
||||
>
|
||||
⏹️ {{ t('deviceConfig.stopPlaying') }}
|
||||
</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">
|
||||
{{ t('deviceConfig.autoLoopPlaySoundWave') }}
|
||||
</wd-checkbox>
|
||||
</view>
|
||||
<wd-checkbox v-model="autoLoop">
|
||||
{{ t('deviceConfig.autoLoopPlaySoundWave') }}
|
||||
</wd-checkbox>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 音频播放器 -->
|
||||
@@ -531,33 +531,33 @@ async function stopAudio() {
|
||||
|
||||
<!-- 使用说明 -->
|
||||
<view class="help-section">
|
||||
<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 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>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { useToast } from 'wot-design-uni/components/wd-toast'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
// 类型定义
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { t } from '@/i18n'
|
||||
import UltrasonicConfig from './components/ultrasonic-config.vue'
|
||||
import WifiConfig from './components/wifi-config.vue'
|
||||
@@ -68,12 +68,10 @@ 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')
|
||||
title: t('deviceConfig.pageTitle'),
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@@ -86,18 +84,18 @@ onMounted(() => {
|
||||
<!-- 配网方式选择 -->
|
||||
<view class="pb-[20rpx] first:pt-[20rpx]">
|
||||
<text class="text-[32rpx] text-[#232338] font-bold">
|
||||
{{ t('deviceConfig.configMethod') }}
|
||||
</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">
|
||||
{{ 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>
|
||||
{{ 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>
|
||||
@@ -105,8 +103,8 @@ onMounted(() => {
|
||||
<!-- WiFi网络选择 -->
|
||||
<view class="pb-[20rpx]">
|
||||
<text class="text-[32rpx] text-[#232338] font-bold">
|
||||
{{ t('deviceConfig.networkConfig') }}
|
||||
</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);">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Device, FirmwareType } from '@/api/device'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import { useMessage } from 'wot-design-uni/components/wd-message-box'
|
||||
import { bindDevice, bindDeviceManual, getBindDevices, getFirmwareTypes, unbindDevice, updateDeviceAutoUpdate } from '@/api/device'
|
||||
import { t } from '@/i18n'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
@@ -9,23 +9,23 @@
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import { useConfigStore } from "@/store";
|
||||
import { getEnvBaseUrl, sm2Encrypt } from "@/utils";
|
||||
import { toast } from "@/utils/toast";
|
||||
// 导入国际化相关功能
|
||||
import { t, initI18n } from "@/i18n";
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
// 导入API接口
|
||||
import { retrievePassword, sendSmsCode } from "@/api/auth";
|
||||
import { retrievePassword, sendSmsCode } from '@/api/auth'
|
||||
// 导入国际化相关功能
|
||||
import { initI18n, t } from '@/i18n'
|
||||
import { useConfigStore } from '@/store'
|
||||
import { getEnvBaseUrl, sm2Encrypt } from '@/utils'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
// 获取屏幕边界到安全区域距离
|
||||
let safeAreaInsets;
|
||||
let systemInfo;
|
||||
let safeAreaInsets
|
||||
let systemInfo
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
// 微信小程序使用新的API
|
||||
systemInfo = uni.getWindowInfo();
|
||||
systemInfo = uni.getWindowInfo()
|
||||
safeAreaInsets = systemInfo.safeArea
|
||||
? {
|
||||
top: systemInfo.safeArea.top,
|
||||
@@ -33,147 +33,148 @@ safeAreaInsets = systemInfo.safeArea
|
||||
bottom: systemInfo.windowHeight - systemInfo.safeArea.bottom,
|
||||
left: systemInfo.safeArea.left,
|
||||
}
|
||||
: null;
|
||||
: null
|
||||
// #endif
|
||||
|
||||
// #ifndef MP-WEIXIN
|
||||
// 其他平台继续使用uni API
|
||||
systemInfo = uni.getSystemInfoSync();
|
||||
safeAreaInsets = systemInfo.safeAreaInsets;
|
||||
systemInfo = uni.getSystemInfoSync()
|
||||
safeAreaInsets = systemInfo.safeAreaInsets
|
||||
// #endif
|
||||
|
||||
// 表单数据
|
||||
interface ForgotPasswordData {
|
||||
mobile: string;
|
||||
captcha: string;
|
||||
captchaId: string;
|
||||
mobileCaptcha: string;
|
||||
newPassword: string;
|
||||
confirmPassword: string;
|
||||
areaCode: string;
|
||||
mobile: string
|
||||
captcha: string
|
||||
captchaId: string
|
||||
mobileCaptcha: string
|
||||
newPassword: string
|
||||
confirmPassword: string
|
||||
areaCode: string
|
||||
}
|
||||
|
||||
const formData = ref<ForgotPasswordData>({
|
||||
mobile: "",
|
||||
captcha: "",
|
||||
captchaId: "",
|
||||
mobileCaptcha: "",
|
||||
newPassword: "",
|
||||
confirmPassword: "",
|
||||
areaCode: "+86",
|
||||
});
|
||||
mobile: '',
|
||||
captcha: '',
|
||||
captchaId: '',
|
||||
mobileCaptcha: '',
|
||||
newPassword: '',
|
||||
confirmPassword: '',
|
||||
areaCode: '+86',
|
||||
})
|
||||
|
||||
// 验证码图片
|
||||
const captchaImage = ref("");
|
||||
const loading = ref(false);
|
||||
const captchaImage = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
// 获取配置store
|
||||
const configStore = useConfigStore();
|
||||
const configStore = useConfigStore()
|
||||
|
||||
// State for area code action sheet
|
||||
const showAreaCodeSheet = ref(false);
|
||||
const selectedAreaCode = ref("+86");
|
||||
const showAreaCodeSheet = ref(false)
|
||||
const selectedAreaCode = ref('+86')
|
||||
// 短信验证码倒计时
|
||||
const smsCountdown = ref(0)
|
||||
const smsLoading = ref(false)
|
||||
const areaCodeList = computed(() =>
|
||||
(configStore.config.mobileAreaList || []).map((item) => {
|
||||
return {
|
||||
value: item.key,
|
||||
label: `${item.name} (${item.key})`,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
}),
|
||||
)
|
||||
|
||||
const canSendMobileCaptcha = computed(() => {
|
||||
const mobile = formData.value.mobile;
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
return phoneRegex.test(mobile) && smsCountdown.value === 0;
|
||||
});
|
||||
const mobile = formData.value.mobile
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
return phoneRegex.test(mobile) && smsCountdown.value === 0
|
||||
})
|
||||
|
||||
// SM2公钥
|
||||
const sm2PublicKey = computed(() => {
|
||||
return configStore.config.sm2PublicKey;
|
||||
});
|
||||
|
||||
// 短信验证码倒计时
|
||||
const smsCountdown = ref(0);
|
||||
const smsLoading = ref(false);
|
||||
return configStore.config.sm2PublicKey
|
||||
})
|
||||
|
||||
// 打开区号选择弹窗
|
||||
function openAreaCodeSheet() {
|
||||
showAreaCodeSheet.value = true;
|
||||
showAreaCodeSheet.value = true
|
||||
}
|
||||
|
||||
// 选择区号
|
||||
function selectAreaCode(item: { value: string; label: string }) {
|
||||
selectedAreaCode.value = item.value;
|
||||
formData.value.areaCode = item.value;
|
||||
showAreaCodeSheet.value = false;
|
||||
function selectAreaCode(item: { value: string, label: string }) {
|
||||
selectedAreaCode.value = item.value
|
||||
formData.value.areaCode = item.value
|
||||
showAreaCodeSheet.value = false
|
||||
}
|
||||
|
||||
// 关闭区号选择弹窗
|
||||
function closeAreaCodeSheet() {
|
||||
showAreaCodeSheet.value = false;
|
||||
showAreaCodeSheet.value = false
|
||||
}
|
||||
|
||||
// 生成UUID
|
||||
function generateUUID() {
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0;
|
||||
const v = c === "x" ? r : (r & 0x3) | 0x8;
|
||||
return v.toString(16);
|
||||
});
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
|
||||
const r = (Math.random() * 16) | 0
|
||||
const v = c === 'x' ? r : (r & 0x3) | 0x8
|
||||
return v.toString(16)
|
||||
})
|
||||
}
|
||||
|
||||
// 获取图形验证码
|
||||
async function refreshCaptcha() {
|
||||
const uuid = generateUUID();
|
||||
formData.value.captchaId = uuid;
|
||||
captchaImage.value = `${getEnvBaseUrl()}/user/captcha?uuid=${uuid}&t=${Date.now()}`;
|
||||
const uuid = generateUUID()
|
||||
formData.value.captchaId = uuid
|
||||
captchaImage.value = `${getEnvBaseUrl()}/user/captcha?uuid=${uuid}&t=${Date.now()}`
|
||||
}
|
||||
|
||||
// 发送短信验证码
|
||||
async function handleSendSmsCode() {
|
||||
// 手机号格式验证
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(formData.value.mobile)) {
|
||||
toast.warning(t("retrievePassword.inputCorrectMobile"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.inputCorrectMobile'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!formData.value.captcha) {
|
||||
toast.warning(t("retrievePassword.captchaRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.captchaRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
smsLoading.value = true;
|
||||
smsLoading.value = true
|
||||
// 将手机号转换为国际格式
|
||||
const internationalPhone = formData.value.areaCode + formData.value.mobile;
|
||||
const internationalPhone = formData.value.areaCode + formData.value.mobile
|
||||
// 调用发送短信验证码API
|
||||
await sendSmsCode({
|
||||
phone: internationalPhone,
|
||||
captcha: formData.value.captcha,
|
||||
captchaId: formData.value.captchaId
|
||||
captchaId: formData.value.captchaId,
|
||||
})
|
||||
|
||||
toast.success(t("retrievePassword.captchaSendSuccess"));
|
||||
toast.success(t('retrievePassword.captchaSendSuccess'))
|
||||
|
||||
// 开始倒计时
|
||||
smsCountdown.value = 60;
|
||||
smsCountdown.value = 60
|
||||
const timer = setInterval(() => {
|
||||
smsCountdown.value--;
|
||||
smsCountdown.value--
|
||||
if (smsCountdown.value <= 0) {
|
||||
clearInterval(timer);
|
||||
clearInterval(timer)
|
||||
}
|
||||
}, 1000);
|
||||
} catch (error: any) {
|
||||
}, 1000)
|
||||
}
|
||||
catch (error: any) {
|
||||
// 处理验证码错误
|
||||
if (error.message.includes("请求错误[10067]")) {
|
||||
toast.warning(t("login.captchaError"));
|
||||
if (error.message.includes('请求错误[10067]')) {
|
||||
toast.warning(t('login.captchaError'))
|
||||
}
|
||||
// 发送失败重新获取图形验证码
|
||||
refreshCaptcha();
|
||||
} finally {
|
||||
smsLoading.value = false;
|
||||
refreshCaptcha()
|
||||
}
|
||||
finally {
|
||||
smsLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,64 +182,65 @@ async function handleSendSmsCode() {
|
||||
async function handleResetPassword() {
|
||||
// 表单验证
|
||||
if (!formData.value.mobile) {
|
||||
toast.warning(t("retrievePassword.mobileRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.mobileRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
// 手机号格式验证
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
const phoneRegex = /^1[3-9]\d{9}$/
|
||||
if (!phoneRegex.test(formData.value.mobile)) {
|
||||
toast.warning(t("retrievePassword.inputCorrectMobile"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.inputCorrectMobile'))
|
||||
return
|
||||
}
|
||||
|
||||
// 将手机号转换为国际格式
|
||||
const internationalPhone = formData.value.areaCode + formData.value.mobile;
|
||||
const internationalPhone = formData.value.areaCode + formData.value.mobile
|
||||
|
||||
if (!formData.value.captcha) {
|
||||
toast.warning(t("retrievePassword.captchaRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.captchaRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!formData.value.mobileCaptcha) {
|
||||
toast.warning(t("retrievePassword.mobileCaptchaRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.mobileCaptchaRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!formData.value.newPassword) {
|
||||
toast.warning(t("retrievePassword.newPasswordRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.newPasswordRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!formData.value.confirmPassword) {
|
||||
toast.warning(t("retrievePassword.confirmNewPasswordRequired"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.confirmNewPasswordRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (formData.value.newPassword !== formData.value.confirmPassword) {
|
||||
toast.warning(t("retrievePassword.passwordsNotMatch"));
|
||||
return;
|
||||
toast.warning(t('retrievePassword.passwordsNotMatch'))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
loading.value = true;
|
||||
loading.value = true
|
||||
|
||||
// 检查SM2公钥是否配置
|
||||
if (!sm2PublicKey.value) {
|
||||
toast.warning(t("sm2.publicKeyNotConfigured"));
|
||||
return;
|
||||
toast.warning(t('sm2.publicKeyNotConfigured'))
|
||||
return
|
||||
}
|
||||
|
||||
// 加密密码
|
||||
let encryptedPassword;
|
||||
let encryptedPassword
|
||||
try {
|
||||
// 拼接图形验证码和新密码进行加密
|
||||
const captchaAndPassword = formData.value.captcha + formData.value.newPassword;
|
||||
encryptedPassword = sm2Encrypt(sm2PublicKey.value, captchaAndPassword);
|
||||
} catch (error) {
|
||||
console.error("密码加密失败:", error);
|
||||
toast.warning(t("sm2.encryptionFailed"));
|
||||
return;
|
||||
const captchaAndPassword = formData.value.captcha + formData.value.newPassword
|
||||
encryptedPassword = sm2Encrypt(sm2PublicKey.value, captchaAndPassword)
|
||||
}
|
||||
catch (error) {
|
||||
console.error('密码加密失败:', error)
|
||||
toast.warning(t('sm2.encryptionFailed'))
|
||||
return
|
||||
}
|
||||
|
||||
// 调用重置密码API
|
||||
@@ -246,53 +248,56 @@ async function handleResetPassword() {
|
||||
phone: internationalPhone,
|
||||
code: formData.value.mobileCaptcha,
|
||||
password: encryptedPassword,
|
||||
captchaId: formData.value.captchaId
|
||||
captchaId: formData.value.captchaId,
|
||||
})
|
||||
|
||||
toast.success(t("retrievePassword.passwordUpdateSuccess"));
|
||||
toast.success(t('retrievePassword.passwordUpdateSuccess'))
|
||||
|
||||
// 跳转到登录页
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
}, 1000);
|
||||
} catch (error: any) {
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
catch (error: any) {
|
||||
// 处理验证码错误
|
||||
if (error.message.includes("请求错误[10067]")) {
|
||||
toast.warning(t("login.captchaError"));
|
||||
if (error.message.includes('请求错误[10067]')) {
|
||||
toast.warning(t('login.captchaError'))
|
||||
}
|
||||
// 重置失败重新获取验证码
|
||||
refreshCaptcha();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
refreshCaptcha()
|
||||
}
|
||||
finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 返回登录
|
||||
function goBack() {
|
||||
uni.redirectTo({
|
||||
url: "/pages/login/index",
|
||||
});
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
}
|
||||
|
||||
// 页面加载时获取验证码
|
||||
onLoad(() => {
|
||||
refreshCaptcha();
|
||||
});
|
||||
refreshCaptcha()
|
||||
})
|
||||
|
||||
// 组件挂载时确保配置已加载
|
||||
onMounted(async () => {
|
||||
if (!configStore.config.name) {
|
||||
try {
|
||||
await configStore.fetchPublicConfig();
|
||||
} catch (error) {
|
||||
console.error("获取配置失败:", error);
|
||||
await configStore.fetchPublicConfig()
|
||||
}
|
||||
catch (error) {
|
||||
console.error('获取配置失败:', error)
|
||||
}
|
||||
}
|
||||
// 初始化国际化
|
||||
initI18n();
|
||||
});
|
||||
initI18n()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -471,7 +476,7 @@ onMounted(async () => {
|
||||
min-height: 100vh;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -50%;
|
||||
left: -50%;
|
||||
@@ -713,10 +718,7 @@ onMounted(async () => {
|
||||
margin-bottom: 30rpx;
|
||||
box-shadow: 0 8rpx 24rpx rgba(102, 126, 234, 0.3);
|
||||
transition: all 0.3s ease;
|
||||
background-color: var(
|
||||
--wot-button-primary-bg-color,
|
||||
var(--wot-color-theme, #4d80f0)
|
||||
);
|
||||
background-color: var(--wot-button-primary-bg-color, var(--wot-color-theme, #4d80f0));
|
||||
text-align: center;
|
||||
line-height: 80rpx;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
import type { Agent } from '@/api/agent/types'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
// 在组件挂载后设置导航栏标题
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import { useMessage } from 'wot-design-uni/components/wd-message-box'
|
||||
import useZPaging from 'z-paging/components/z-paging/js/hooks/useZPaging.js'
|
||||
import { createAgent, deleteAgent, getAgentList } from '@/api/agent/agent'
|
||||
import { t } from '@/i18n'
|
||||
@@ -167,7 +167,7 @@ function openCreateDialog() {
|
||||
msg: '',
|
||||
inputPlaceholder: t('home.inputPlaceholder'),
|
||||
inputValue: '',
|
||||
inputPattern: /^.{1,64}$/i,
|
||||
inputPattern: /^.{1,64}$/,
|
||||
inputError: t('home.createError'),
|
||||
confirmButtonText: t('home.createNow'),
|
||||
cancelButtonText: t('common.cancel'),
|
||||
|
||||
@@ -401,7 +401,9 @@ onMounted(async () => {
|
||||
<text class="policy-link" @click="goToUserAgreement">
|
||||
{{ t('login.userAgreement') }}
|
||||
</text>
|
||||
<text class="policy-divider">|</text>
|
||||
<text class="policy-divider">
|
||||
{{ '|' }}
|
||||
</text>
|
||||
<text class="policy-link" @click="goToPrivacyPolicy">
|
||||
{{ t('login.privacyPolicy') }}
|
||||
</text>
|
||||
|
||||
@@ -9,15 +9,14 @@
|
||||
</route>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { register, sendSmsCode } from '@/api/auth';
|
||||
import { useConfigStore } from '@/store';
|
||||
import { getEnvBaseUrl } from '@/utils';
|
||||
import { toast } from '@/utils/toast';
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { register, sendSmsCode } from '@/api/auth'
|
||||
// 导入国际化相关功能
|
||||
import { t, initI18n } from '@/i18n';
|
||||
import { initI18n, t } from '@/i18n'
|
||||
import { useConfigStore } from '@/store'
|
||||
// 导入SM2加密工具
|
||||
import { sm2Encrypt } from '@/utils';
|
||||
import { getEnvBaseUrl, sm2Encrypt } from '@/utils'
|
||||
import { toast } from '@/utils/toast'
|
||||
|
||||
// 获取屏幕边界到安全区域距离
|
||||
let safeAreaInsets
|
||||
@@ -135,9 +134,9 @@ function generateUUID() {
|
||||
|
||||
// 获取验证码
|
||||
async function refreshCaptcha() {
|
||||
const uuid = generateUUID();
|
||||
formData.value.captchaId = uuid;
|
||||
captchaImage.value = `${getEnvBaseUrl()}/user/captcha?uuid=${uuid}&t=${Date.now()}`;
|
||||
const uuid = generateUUID()
|
||||
formData.value.captchaId = uuid
|
||||
captchaImage.value = `${getEnvBaseUrl()}/user/captcha?uuid=${uuid}&t=${Date.now()}`
|
||||
}
|
||||
|
||||
// 发送短信验证码
|
||||
@@ -253,7 +252,8 @@ async function handleRegister() {
|
||||
// 拼接验证码和密码
|
||||
const captchaAndPassword = formData.value.captcha + formData.value.password
|
||||
encryptedPassword = sm2Encrypt(sm2PublicKey.value, captchaAndPassword)
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
console.error('密码加密失败:', error)
|
||||
toast.warning(t('sm2.encryptionFailed'))
|
||||
return
|
||||
@@ -275,7 +275,7 @@ async function handleRegister() {
|
||||
// 跳转到登录页
|
||||
setTimeout(() => {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
@@ -299,7 +299,7 @@ async function handleRegister() {
|
||||
// 返回登录
|
||||
function goBack() {
|
||||
uni.redirectTo({
|
||||
url: '/pages/login/index'
|
||||
url: '/pages/login/index',
|
||||
})
|
||||
}
|
||||
|
||||
@@ -321,8 +321,6 @@ onMounted(async () => {
|
||||
// 初始化国际化
|
||||
initI18n()
|
||||
})
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -385,41 +383,41 @@ onMounted(async () => {
|
||||
<view class="input-group">
|
||||
<view class="input-wrapper">
|
||||
<wd-input
|
||||
v-model="formData.password"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterPassword')"
|
||||
show-password
|
||||
:maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
v-model="formData.password"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterPassword')"
|
||||
show-password
|
||||
:maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<view class="input-wrapper">
|
||||
<wd-input
|
||||
v-model="formData.confirmPassword"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.confirmPassword')"
|
||||
show-password
|
||||
:maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
v-model="formData.confirmPassword"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.confirmPassword')"
|
||||
show-password
|
||||
:maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<view class="input-wrapper captcha-wrapper">
|
||||
<wd-input
|
||||
v-model="formData.captcha"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterCode')"
|
||||
:maxlength="6"
|
||||
/>
|
||||
<view class="captcha-image" @click="refreshCaptcha">
|
||||
<image :src="captchaImage" class="captcha-img" />
|
||||
</view>
|
||||
v-model="formData.captcha"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterCode')"
|
||||
:maxlength="6"
|
||||
/>
|
||||
<view class="captcha-image" @click="refreshCaptcha">
|
||||
<image :src="captchaImage" class="captcha-img" />
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -427,21 +425,21 @@ onMounted(async () => {
|
||||
<view v-if="enableMobileRegister" class="input-group">
|
||||
<view class="input-wrapper sms-wrapper">
|
||||
<wd-input
|
||||
v-model="formData.mobileCaptcha"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterCode')"
|
||||
type="number"
|
||||
:maxlength="6"
|
||||
/>
|
||||
<wd-button
|
||||
:loading="smsLoading"
|
||||
:disabled="smsCountdown > 0"
|
||||
custom-class="sms-btn"
|
||||
@click="sendSmsVerification"
|
||||
>
|
||||
{{ smsCountdown > 0 ? `${smsCountdown}s` : t('register.getCode') }}
|
||||
</wd-button>
|
||||
v-model="formData.mobileCaptcha"
|
||||
custom-class="styled-input"
|
||||
no-border
|
||||
:placeholder="t('register.enterCode')"
|
||||
type="number"
|
||||
:maxlength="6"
|
||||
/>
|
||||
<wd-button
|
||||
:loading="smsLoading"
|
||||
:disabled="smsCountdown > 0"
|
||||
custom-class="sms-btn"
|
||||
@click="sendSmsVerification"
|
||||
>
|
||||
{{ smsCountdown > 0 ? `${smsCountdown}s` : t('register.getCode') }}
|
||||
</wd-button>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -462,7 +460,6 @@ onMounted(async () => {
|
||||
{{ t('register.loginNow') }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -508,8 +505,6 @@ onMounted(async () => {
|
||||
</view>
|
||||
</view>
|
||||
</wd-action-sheet>
|
||||
|
||||
|
||||
</view>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { Language } from '@/store/lang'
|
||||
import { computed, onMounted, reactive, ref } from 'vue'
|
||||
import { useToast } from 'wot-design-uni'
|
||||
import { useToast } from 'wot-design-uni/components/wd-toast'
|
||||
import { changeLanguage, getCurrentLanguage, getSupportedLanguages, t } from '@/i18n'
|
||||
import { useConfigStore } from '@/store'
|
||||
import { clearServerBaseUrlOverride, getEnvBaseUrl, getServerBaseUrlOverride, setServerBaseUrlOverride } from '@/utils'
|
||||
@@ -265,7 +265,7 @@ function showAbout() {
|
||||
title: t('settings.aboutApp', { appName: import.meta.env.VITE_APP_TITLE }),
|
||||
content: t('settings.aboutContent', {
|
||||
appName: import.meta.env.VITE_APP_TITLE,
|
||||
version: '0.9.5'
|
||||
version: '0.9.5',
|
||||
}),
|
||||
showCancel: false,
|
||||
confirmText: t('common.confirm'),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import type { ChatHistory, CreateSpeakerData, VoicePrint } from '@/api/voiceprint'
|
||||
import { computed, onMounted, ref } from 'vue'
|
||||
import { useMessage } from 'wot-design-uni'
|
||||
import { useMessage } from 'wot-design-uni/components/wd-message-box'
|
||||
import { useToast } from 'wot-design-uni/components/wd-toast'
|
||||
import { createVoicePrint, deleteVoicePrint, getAudioDownloadId, getChatHistory, getVoicePrintList, updateVoicePrint } from '@/api/voiceprint'
|
||||
import { t } from '@/i18n'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { PublicConfig } from '@/api/auth'
|
||||
import { getPublicConfig } from '@/api/auth'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getPublicConfig } from '@/api/auth'
|
||||
|
||||
// 初始化状态
|
||||
const initialConfigState: PublicConfig = {
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { ref } from 'vue'
|
||||
import type { Ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
|
||||
// 支持的语言类型
|
||||
export type Language = 'zh_CN' | 'en' | 'zh_TW' | 'de' | 'vi' | 'pt_BR'
|
||||
|
||||
export interface LangStore {
|
||||
currentLang: Language
|
||||
currentLang: Ref<Language>
|
||||
changeLang: (lang: Language) => void
|
||||
}
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ export function getEnvBaseUploadUrl() {
|
||||
|
||||
/**
|
||||
* 生成SM2密钥对(十六进制格式)
|
||||
* @returns {Object} 包含公钥和私钥的对象
|
||||
* @returns {object} 包含公钥和私钥的对象
|
||||
*/
|
||||
export function generateSm2KeyPairHex() {
|
||||
// 使用sm-crypto库生成SM2密钥对
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
import type { Component } from 'vue'
|
||||
|
||||
// wot-design-uni 1.9.1 exposes raw Vue source through its global declarations.
|
||||
// Keep the components used by this app recognizable without pulling that source into vue-tsc.
|
||||
declare module 'vue' {
|
||||
export interface GlobalComponents {
|
||||
WdActionSheet: Component
|
||||
WdButton: Component
|
||||
WdCheckbox: Component
|
||||
WdConfigProvider: Component
|
||||
WdFab: Component
|
||||
WdIcon: Component
|
||||
WdImg: Component
|
||||
WdInput: Component
|
||||
WdLoading: Component
|
||||
WdMessageBox: Component
|
||||
WdNavbar: Component
|
||||
WdPicker: Component
|
||||
WdPopup: Component
|
||||
WdSegmented: Component
|
||||
WdSlider: Component
|
||||
WdStatusTip: Component
|
||||
WdSwipeAction: Component
|
||||
WdSwitch: Component
|
||||
WdTabbar: Component
|
||||
WdTabbarItem: Component
|
||||
WdTag: Component
|
||||
WdToast: Component
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
"@dcloudio/types",
|
||||
"@uni-helper/uni-types",
|
||||
"@types/wechat-miniprogram",
|
||||
"wot-design-uni/global.d.ts",
|
||||
"z-paging/types",
|
||||
"./src/typings.d.ts"
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user