From ed41de7b8e82b48297716228c14e42365d052573 Mon Sep 17 00:00:00 2001 From: zhuoqinglian <1035449612@qq.com> Date: Tue, 10 Mar 2026 11:37:51 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20mobile=20=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=AE=BE=E5=A4=87=E6=B7=BB=E5=8A=A0=E9=80=BB=E8=BE=91=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=89=8B=E5=8A=A8=E6=B7=BB=E5=8A=A0=E8=AE=BE?= =?UTF-8?q?=E5=A4=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-mobile/src/api/device/device.ts | 16 + main/manager-mobile/src/i18n/de.ts | 21 +- main/manager-mobile/src/i18n/en.ts | 21 +- main/manager-mobile/src/i18n/pt_BR.ts | 21 +- main/manager-mobile/src/i18n/vi.ts | 21 +- main/manager-mobile/src/i18n/zh_CN.ts | 21 +- main/manager-mobile/src/i18n/zh_TW.ts | 21 +- .../manager-mobile/src/pages/device/index.vue | 337 ++++++++++++++++-- 8 files changed, 453 insertions(+), 26 deletions(-) diff --git a/main/manager-mobile/src/api/device/device.ts b/main/manager-mobile/src/api/device/device.ts index fc9d5f69..e5a2f9c7 100644 --- a/main/manager-mobile/src/api/device/device.ts +++ b/main/manager-mobile/src/api/device/device.ts @@ -33,6 +33,22 @@ export function bindDevice(agentId: string, code: string) { return http.Post(`/device/bind/${agentId}/${code}`, null) } +/** + * 手动添加设备 + * @param agentId 智能体ID + * @param board 设备类型 + * @param appVersion 固件版本 + * @param macAddress MAC地址 + */ +export function bindDeviceManual(data: { + agentId: string + board: string + appVersion: string + macAddress: string +}) { + return http.Post('/device/manual-add', data) +} + /** * 设置设备OTA升级开关 * @param deviceId 设备ID (MAC地址) diff --git a/main/manager-mobile/src/i18n/de.ts b/main/manager-mobile/src/i18n/de.ts index eee1d3b8..546838cd 100644 --- a/main/manager-mobile/src/i18n/de.ts +++ b/main/manager-mobile/src/i18n/de.ts @@ -150,6 +150,25 @@ export default { 'contextProviderDialog.cancel': 'Abbrechen', 'contextProviderDialog.confirm': 'Bestätigen', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Manuell Gerät hinzufügen', + 'manualAddDeviceDialog.deviceType': 'Gerätetyp', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Bitte Gerätetyp auswählen', + 'manualAddDeviceDialog.firmwareVersion': 'Firmware-Version', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Bitte Firmware-Version eingeben', + 'manualAddDeviceDialog.macAddress': 'Mac-Adresse', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Bitte Mac-Adresse eingeben', + 'manualAddDeviceDialog.confirm': 'Bestätigen', + 'manualAddDeviceDialog.cancel': 'Abbrechen', + 'manualAddDeviceDialog.requiredMacAddress': 'Bitte Mac-Adresse eingeben', + 'manualAddDeviceDialog.invalidMacAddress': 'Bitte korrektes Mac-Adressformat eingeben, z.B.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Bitte Gerätetyp auswählen', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Bitte Firmware-Version eingeben', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Firmware-Typ konnte nicht abgerufen werden', + 'manualAddDeviceDialog.addSuccess': 'Gerät erfolgreich hinzugefügt', + 'manualAddDeviceDialog.addFailed': 'Hinzufügen fehlgeschlagen', + 'manualAddDeviceDialog.bindWithCode': 'Mit 6-stelligem Code binden', + // Chat-Verlauf Seite 'chatHistory.getChatSessions': 'Chat-Sitzungsliste abrufen', 'chatHistory.noSelectedAgent': 'Kein Agent ausgewählt', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': 'Entbinden fehlgeschlagen', 'message.networkError': 'Netzwerkfehler, bitte Verbindung prüfen', 'message.serverError': 'Serverfehler, bitte später erneut versuchen', - 'message.invalidAddress': 'Ungültige Adresse, bitte prüfen ob Server gestartet oder Netzwerkverbindung normal ist', + 'message.invalidAddress': 'Die Adresse kann ungültig sein. Bitte überprüfen Sie, ob der Server gestartet ist oder ob die Netzwerkverbindung funktioniert. Es kann auch sein, dass die Anfrage aufgrund eines Problems mit dem HTTPS-Protokoll nicht gesendet werden kann.', 'message.languageChanged': 'Sprache geändert', 'message.passwordError': 'Konto oder Passwort Fehler', 'message.phoneRegistered': 'Diese Handynummer wurde bereits registriert', diff --git a/main/manager-mobile/src/i18n/en.ts b/main/manager-mobile/src/i18n/en.ts index 20d42d54..9ccaad1d 100644 --- a/main/manager-mobile/src/i18n/en.ts +++ b/main/manager-mobile/src/i18n/en.ts @@ -150,6 +150,25 @@ export default { 'contextProviderDialog.cancel': 'Cancel', 'contextProviderDialog.confirm': 'Confirm', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Manual Add Device', + 'manualAddDeviceDialog.deviceType': 'Device Type', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Please select device type', + 'manualAddDeviceDialog.firmwareVersion': 'Firmware Version', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Please enter firmware version', + 'manualAddDeviceDialog.macAddress': 'Mac Address', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Please enter Mac address', + 'manualAddDeviceDialog.confirm': 'Confirm', + 'manualAddDeviceDialog.cancel': 'Cancel', + 'manualAddDeviceDialog.requiredMacAddress': 'Please enter Mac address', + 'manualAddDeviceDialog.invalidMacAddress': 'Please enter correct Mac address format, e.g.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Please select device type', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Please enter firmware version', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Failed to get firmware type', + 'manualAddDeviceDialog.addSuccess': 'Device added successfully', + 'manualAddDeviceDialog.addFailed': 'Failed to add', + 'manualAddDeviceDialog.bindWithCode': 'Bind with 6-digit code', + // Chat History Page 'chatHistory.getChatSessions': 'Get chat session list', 'chatHistory.noSelectedAgent': 'No agent selected', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': 'Unbinding failed', 'message.networkError': 'Network error, please check your connection', 'message.serverError': 'Server error, please try again later', - 'message.invalidAddress': 'Invalid address, please check if the server is started or network connection is normal', + 'message.invalidAddress': 'The address may be invalid. Please check if the server is started or if the network connection is normal; It is also possible that requests cannot be sent due to HTTPS protocol issues', 'message.languageChanged': 'Language changed', 'message.passwordError': 'Account or password error', 'message.phoneRegistered': 'This phone number has been registered', diff --git a/main/manager-mobile/src/i18n/pt_BR.ts b/main/manager-mobile/src/i18n/pt_BR.ts index bd218234..e4594603 100644 --- a/main/manager-mobile/src/i18n/pt_BR.ts +++ b/main/manager-mobile/src/i18n/pt_BR.ts @@ -150,6 +150,25 @@ export default { 'contextProviderDialog.cancel': 'Cancelar', 'contextProviderDialog.confirm': 'Confirmar', + // Diálogo de adição manual de dispositivo + 'manualAddDeviceDialog.title': 'Adicionar Dispositivo Manualmente', + 'manualAddDeviceDialog.deviceType': 'Tipo de Dispositivo', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Por favor, selecione o tipo de dispositivo', + 'manualAddDeviceDialog.firmwareVersion': 'Versão do Firmware', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Por favor, insira a versão do firmware', + 'manualAddDeviceDialog.macAddress': 'Endereço MAC', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Por favor, insira o endereço MAC', + 'manualAddDeviceDialog.confirm': 'Confirmar', + 'manualAddDeviceDialog.cancel': 'Cancelar', + 'manualAddDeviceDialog.requiredMacAddress': 'Por favor, insira o endereço MAC', + 'manualAddDeviceDialog.invalidMacAddress': 'Por favor, insira o formato correto de endereço MAC, ex.: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Por favor, selecione o tipo de dispositivo', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Por favor, insira a versão do firmware', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Falha ao obter tipo de firmware', + 'manualAddDeviceDialog.addSuccess': 'Dispositivo adicionado com sucesso', + 'manualAddDeviceDialog.addFailed': 'Falha ao adicionar', + 'manualAddDeviceDialog.bindWithCode': 'Vincular com Código de 6 Dígitos', + // Chat History Page 'chatHistory.getChatSessions': 'Obter lista de sessões de conversa', 'chatHistory.noSelectedAgent': 'Nenhum agente selecionado', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': 'Falha na desvinculação', 'message.networkError': 'Erro de rede, por favor verifique sua conexão', 'message.serverError': 'Erro no servidor, por favor tente novamente mais tarde', - 'message.invalidAddress': 'Endereço inválido, por favor verifique se o servidor está iniciado ou se a conexão de rede está normal', + 'message.invalidAddress': 'O endereço pode ser inválido, verifique se o servidor está iniciado ou se a conexão de rede está correta; Também pode ser impossível enviar solicitações devido a problemas com o protocolo HTTPS', 'message.languageChanged': 'Idioma alterado', 'message.passwordError': 'Conta ou senha incorretos', 'message.phoneRegistered': 'Este número de telefone já está cadastrado', diff --git a/main/manager-mobile/src/i18n/vi.ts b/main/manager-mobile/src/i18n/vi.ts index 3c0fd4f6..059663f2 100644 --- a/main/manager-mobile/src/i18n/vi.ts +++ b/main/manager-mobile/src/i18n/vi.ts @@ -150,6 +150,25 @@ export default { 'contextProviderDialog.cancel': 'Hủy bỏ', 'contextProviderDialog.confirm': 'Xác nhận', + // Manual add device dialog related + 'manualAddDeviceDialog.title': 'Thêm thiết bị thủ công', + 'manualAddDeviceDialog.deviceType': 'Loại thiết bị', + 'manualAddDeviceDialog.deviceTypePlaceholder': 'Vui lòng chọn loại thiết bị', + 'manualAddDeviceDialog.firmwareVersion': 'Phiên bản firmware', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': 'Vui lòng nhập phiên bản firmware', + 'manualAddDeviceDialog.macAddress': 'Địa chỉ Mac', + 'manualAddDeviceDialog.macAddressPlaceholder': 'Vui lòng nhập địa chỉ Mac', + 'manualAddDeviceDialog.confirm': 'Xác nhận', + 'manualAddDeviceDialog.cancel': 'Hủy bỏ', + 'manualAddDeviceDialog.requiredMacAddress': 'Vui lòng nhập địa chỉ Mac', + 'manualAddDeviceDialog.invalidMacAddress': 'Vui lòng nhập đúng định dạng địa chỉ Mac, ví dụ: 00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': 'Vui lòng chọn loại thiết bị', + 'manualAddDeviceDialog.requiredFirmwareVersion': 'Vui lòng nhập phiên bản firmware', + 'manualAddDeviceDialog.getFirmwareTypeFailed': 'Không thể lấy loại firmware', + 'manualAddDeviceDialog.addSuccess': 'Đã thêm thiết bị thành công', + 'manualAddDeviceDialog.addFailed': 'Thêm thất bại', + 'manualAddDeviceDialog.bindWithCode': 'Liên kết bằng mã xác minh 6 chữ số', + // Trang lịch sử trò chuyện 'chatHistory.getChatSessions': 'Lấy danh sách phiên trò chuyện', 'chatHistory.noSelectedAgent': 'Chưa chọn đại lý', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': 'Hủy liên kết thất bại', 'message.networkError': 'Lỗi mạng, vui lòng kiểm tra kết nối', 'message.serverError': 'Lỗi máy chủ, vui lòng thử lại sau', - 'message.invalidAddress': 'Địa chỉ không hợp lệ, vui lòng kiểm tra máy chủ đã khởi động hoặc kết nối mạng bình thường', + 'message.invalidAddress': 'Địa chỉ có thể không hợp lệ. Vui lòng kiểm tra xem máy chủ đã khởi động hay kết nối mạng chưa; Có thể không gửi được yêu cầu do lỗi giao thức HTTPS', 'message.languageChanged': 'Đã thay đổi ngôn ngữ', 'message.passwordError': 'Lỗi tài khoản hoặc mật khẩu', 'message.phoneRegistered': 'Số điện thoại này đã được đăng ký', diff --git a/main/manager-mobile/src/i18n/zh_CN.ts b/main/manager-mobile/src/i18n/zh_CN.ts index aef7d223..10865328 100644 --- a/main/manager-mobile/src/i18n/zh_CN.ts +++ b/main/manager-mobile/src/i18n/zh_CN.ts @@ -150,6 +150,25 @@ export default { 'contextProviderDialog.cancel': '取消', 'contextProviderDialog.confirm': '确定', + // 手動添加設備對話框相關 + 'manualAddDeviceDialog.title': '手动添加设备', + 'manualAddDeviceDialog.deviceType': '设备型号', + 'manualAddDeviceDialog.deviceTypePlaceholder': '请选择设备型号', + 'manualAddDeviceDialog.firmwareVersion': '固件版本', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': '请输入固件版本', + 'manualAddDeviceDialog.macAddress': 'Mac地址', + 'manualAddDeviceDialog.macAddressPlaceholder': '请输入Mac地址', + 'manualAddDeviceDialog.confirm': '确定', + 'manualAddDeviceDialog.cancel': '取消', + 'manualAddDeviceDialog.requiredMacAddress': '请输入Mac地址', + 'manualAddDeviceDialog.invalidMacAddress': '请输入正确的Mac地址格式,例如:00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': '请选择设备型号', + 'manualAddDeviceDialog.requiredFirmwareVersion': '请输入固件版本', + 'manualAddDeviceDialog.getFirmwareTypeFailed': '获取固件类型失败', + 'manualAddDeviceDialog.addSuccess': '设备添加成功', + 'manualAddDeviceDialog.addFailed': '添加失败', + 'manualAddDeviceDialog.bindWithCode': '6位验证码绑定', + // 聊天历史页面 'chatHistory.getChatSessions': '获取聊天会话列表', 'chatHistory.noSelectedAgent': '没有选中的智能体', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': '解绑失败', 'message.networkError': '网络错误,请检查网络连接', 'message.serverError': '服务器错误,请稍后再试', - 'message.invalidAddress': '无效地址,请检查服务端是否启动或网络连接是否正常', + 'message.invalidAddress': '地址可能无效,请检查服务端是否启动或网络连接是否正常;也可能因 HTTPS 协议问题导致无法发送请求', 'message.languageChanged': '语言已切换', 'message.passwordError': '账号或密码错误', 'message.phoneRegistered': '此手机号码已经注册过', diff --git a/main/manager-mobile/src/i18n/zh_TW.ts b/main/manager-mobile/src/i18n/zh_TW.ts index 5fd942b0..f428878f 100644 --- a/main/manager-mobile/src/i18n/zh_TW.ts +++ b/main/manager-mobile/src/i18n/zh_TW.ts @@ -171,6 +171,25 @@ export default { 'contextProviderDialog.cancel': '取消', 'contextProviderDialog.confirm': '確定', + // 手動添加設備對話框相關 + 'manualAddDeviceDialog.title': '手動添加設備', + 'manualAddDeviceDialog.deviceType': '設備型號', + 'manualAddDeviceDialog.deviceTypePlaceholder': '請選擇設備型號', + 'manualAddDeviceDialog.firmwareVersion': '固件版本', + 'manualAddDeviceDialog.firmwareVersionPlaceholder': '請輸入固件版本', + 'manualAddDeviceDialog.macAddress': 'Mac地址', + 'manualAddDeviceDialog.macAddressPlaceholder': '請輸入Mac地址', + 'manualAddDeviceDialog.confirm': '確定', + 'manualAddDeviceDialog.cancel': '取消', + 'manualAddDeviceDialog.requiredMacAddress': '請輸入Mac地址', + 'manualAddDeviceDialog.invalidMacAddress': '請輸入正確的Mac地址格式,例如:00:1A:2B:3C:4D:5E', + 'manualAddDeviceDialog.requiredDeviceType': '請選擇設備型號', + 'manualAddDeviceDialog.requiredFirmwareVersion': '請輸入固件版本', + 'manualAddDeviceDialog.getFirmwareTypeFailed': '獲取固件類型失敗', + 'manualAddDeviceDialog.addSuccess': '設備添加成功', + 'manualAddDeviceDialog.addFailed': '添加失敗', + 'manualAddDeviceDialog.bindWithCode': '6位驗證碼綁定', + // 聊天歷史頁面 'chatHistory.getChatSessions': '獲取聊天會話列表', 'chatHistory.noSelectedAgent': '沒有選中的智能體', @@ -335,7 +354,7 @@ export default { 'message.unbindFail': '解除綁定失敗', 'message.networkError': '網絡錯誤,請檢查網絡連接', 'message.serverError': '服務器錯誤,請稍後再試', - 'message.invalidAddress': '無效地址,請檢查服務端是否啟動或網絡連接是否正常', + 'message.invalidAddress': '地址可能無效,請檢查服務端是否啟動或網絡連接是否正常; 也可能因HTTPS協定問題導致無法發送請求常', 'message.languageChanged': '語言已切換', 'message.passwordError': '帳號或密碼錯誤', 'message.phoneRegistered': '此手機號已經註冊過', diff --git a/main/manager-mobile/src/pages/device/index.vue b/main/manager-mobile/src/pages/device/index.vue index e592f58c..f1fdcc26 100644 --- a/main/manager-mobile/src/pages/device/index.vue +++ b/main/manager-mobile/src/pages/device/index.vue @@ -2,23 +2,28 @@ import type { Device, FirmwareType } from '@/api/device' import { computed, onMounted, ref } from 'vue' import { useMessage } from 'wot-design-uni' -import { bindDevice, getBindDevices, getFirmwareTypes, unbindDevice, updateDeviceAutoUpdate } from '@/api/device' -import { toast } from '@/utils/toast' +import { bindDevice, bindDeviceManual, getBindDevices, getFirmwareTypes, unbindDevice, updateDeviceAutoUpdate } from '@/api/device' import { t } from '@/i18n' +import { toast } from '@/utils/toast' defineOptions({ name: 'DeviceManage', }) +const props = withDefaults(defineProps(), { + agentId: 'default', +}) + +const actions = [ + { key: 'code', name: t('manualAddDeviceDialog.bindWithCode') }, + { key: 'manual', name: t('manualAddDeviceDialog.title') }, +] + // 接收props interface Props { agentId?: string } -const props = withDefaults(defineProps(), { - agentId: 'default' -}) - // 获取屏幕边界到安全区域距离 let safeAreaInsets: any let systemInfo: any @@ -44,6 +49,45 @@ safeAreaInsets = systemInfo.safeAreaInsets const deviceList = ref([]) const firmwareTypes = ref([]) const loading = ref(false) +const isBindDevice = ref(false) + +// 手动绑定弹窗 +const isManualBindDialog = ref(false) +const manualBindForm = ref({ + board: '', + appVersion: '', + macAddress: '', +}) + +// 表单校验错误提示 +const formErrors = ref({ + board: '', + appVersion: '', + macAddress: '', +}) + +// MAC地址正则校验 +const macRegex = /^(?:[0-9A-F]{2}[:-]){5}[0-9A-F]{2}$/i + +function selectBindMode(row) { + if (row.item.key === 'code') { + openBindDialog() + } + else if (row.item.key === 'manual') { + // 打开弹窗前重置表单和错误提示 + manualBindForm.value = { + board: '', + appVersion: '', + macAddress: '', + } + formErrors.value = { + board: '', + appVersion: '', + macAddress: '', + } + isManualBindDialog.value = true + } +} // 消息组件 const message = useMessage() @@ -56,11 +100,8 @@ const currentAgentId = computed(() => { // 获取设备列表 async function loadDeviceList() { try { - console.log('获取设备列表') - // 检查是否有当前选中的智能体 if (!currentAgentId.value) { - console.warn('没有选中的智能体') deviceList.value = [] return } @@ -164,8 +205,8 @@ async function handleBindDevice(code: string) { } catch (error: any) { console.error('绑定设备失败:', error) - const errorMessage = error?.message || '绑定失败,请检查验证码是否正确' - toast.error(errorMessage || t('device.bindFailed')) + const errorMessage = error?.message || t('device.bindFailed') + toast.error(errorMessage) } } @@ -190,6 +231,128 @@ function openBindDialog() { }) } +// 手动绑定设备 +async function handleManualBind() { + try { + // 先校验整个表单 + const isValid = validateForm() + if (!isValid) { + return + } + + if (!currentAgentId.value) { + toast.error(t('device.pleaseSelectAgent')) + return + } + + await bindDeviceManual({ + agentId: currentAgentId.value, + board: manualBindForm.value.board, + appVersion: manualBindForm.value.appVersion, + macAddress: manualBindForm.value.macAddress, + }) + await loadDeviceList() + toast.success(t('manualAddDeviceDialog.addSuccess')) + isManualBindDialog.value = false + // 重置表单和错误提示 + manualBindForm.value = { + board: '', + appVersion: '', + macAddress: '', + } + formErrors.value = { + board: '', + appVersion: '', + macAddress: '', + } + } + catch (error: any) { + const errorMessage = error?.message || t('manualAddDeviceDialog.addFailed') + toast.error(errorMessage) + } +} + +// 校验单个字段 +function validateField(field: string) { + switch (field) { + case 'board': + if (!manualBindForm.value.board) { + formErrors.value.board = t('manualAddDeviceDialog.deviceTypePlaceholder') + } + else { + formErrors.value.board = '' + } + break + case 'appVersion': + if (!manualBindForm.value.appVersion) { + formErrors.value.appVersion = t('manualAddDeviceDialog.firmwareVersionPlaceholder') + } + else { + formErrors.value.appVersion = '' + } + break + case 'macAddress': + if (!manualBindForm.value.macAddress) { + formErrors.value.macAddress = t('manualAddDeviceDialog.macAddressPlaceholder') + } + else if (!macRegex.test(manualBindForm.value.macAddress)) { + formErrors.value.macAddress = t('manualAddDeviceDialog.invalidMacAddress') + } + else { + formErrors.value.macAddress = '' + } + break + } +} + +// 清除字段错误提示 +function clearFieldError(field: string) { + formErrors.value[field] = '' +} + +// 处理选择器变化 +function handlePickerChange() { + clearFieldError('board') +} + +// 校验整个表单 +function validateForm(): boolean { + let isValid = true + + // 校验设备类型 + if (!manualBindForm.value.board) { + formErrors.value.board = t('manualAddDeviceDialog.deviceTypePlaceholder') + isValid = false + } + else { + formErrors.value.board = '' + } + + // 校验固件版本 + if (!manualBindForm.value.appVersion) { + formErrors.value.appVersion = t('manualAddDeviceDialog.firmwareVersionPlaceholder') + isValid = false + } + else { + formErrors.value.appVersion = '' + } + + // 校验MAC地址 + if (!manualBindForm.value.macAddress) { + formErrors.value.macAddress = t('manualAddDeviceDialog.macAddressPlaceholder') + isValid = false + } + else if (!macRegex.test(manualBindForm.value.macAddress)) { + formErrors.value.macAddress = t('manualAddDeviceDialog.invalidMacAddress') + isValid = false + } + else { + formErrors.value.macAddress = '' + } + + return isValid +} + // 获取设备类型列表 async function loadFirmwareTypes() { try { @@ -241,14 +404,14 @@ defineExpose({ - {{ t('device.macAddress') }}:{{ device.macAddress }} - - - {{ t('device.firmwareVersion') }}:{{ device.appVersion }} - - - {{ t('device.lastConnection') }}:{{ formatTime(device.lastConnectedAt) }} - + {{ t('device.macAddress') }}:{{ device.macAddress }} + + + {{ t('device.firmwareVersion') }}:{{ device.appVersion }} + + + {{ t('device.lastConnection') }}:{{ formatTime(device.lastConnectedAt) }} + @@ -295,10 +458,88 @@ defineExpose({ - + + + + + + + + + {{ t('manualAddDeviceDialog.title') }} + + + + + + + + {{ t('manualAddDeviceDialog.deviceType') }} + + * + + + + + {{ formErrors.board }} + + + + + + {{ t('manualAddDeviceDialog.firmwareVersion') }} + + * + + + + + {{ formErrors.appVersion }} + + + + + + {{ t('manualAddDeviceDialog.macAddress') }} + + * + + + + + {{ formErrors.macAddress }} + + + + + + + {{ t('manualAddDeviceDialog.confirm') }} + + + + @@ -327,8 +568,64 @@ defineExpose({ box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04); border: 1rpx solid #eeeeee; } +::v-deep .wd-action-sheet__popup, +::v-deep .wd-popup { + z-index: 100 !important; +} +.custom-wd-picker ::v-deep .wd-picker__cell { + padding-left: 0 !important; +} :deep(.wd-icon) { font-size: 32rpx; } + +.manual-bind-dialog { + padding: 32rpx; + background: #ffffff; +} + +.dialog-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 32rpx; +} + +.dialog-title { + font-size: 36rpx; + font-weight: 600; + color: #232338; +} + +.dialog-content { + margin-bottom: 32rpx; +} + +.form-item { + margin-bottom: 24rpx; +} + +.form-label { + display: block; + font-size: 28rpx; + color: #65686f; + margin-bottom: 12rpx; +} + +.required { + color: #ff4d4f; + margin-left: 4rpx; +} + +.error-text { + display: block; + font-size: 24rpx; + color: #ff4d4f; + margin-top: 8rpx; +} + +.dialog-footer { + padding-top: 16rpx; +} From ff1076deac7e7c1a393dd9be0da3ac6e38ffe3c4 Mon Sep 17 00:00:00 2001 From: zhuoqinglian <1035449612@qq.com> Date: Tue, 10 Mar 2026 16:14:04 +0800 Subject: [PATCH 2/6] =?UTF-8?q?update:=20mobile=20=E6=9C=8D=E5=8A=A1?= =?UTF-8?q?=E7=AB=AF=E6=8E=A5=E5=8F=A3=E5=9C=B0=E5=9D=80=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=AD=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-mobile/src/http/request/alova.ts | 14 +++++++++++--- main/manager-mobile/src/http/request/enum.ts | 4 ++++ main/manager-mobile/src/pages/settings/index.vue | 10 ++++++++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/main/manager-mobile/src/http/request/alova.ts b/main/manager-mobile/src/http/request/alova.ts index 752987b4..3120cfed 100644 --- a/main/manager-mobile/src/http/request/alova.ts +++ b/main/manager-mobile/src/http/request/alova.ts @@ -42,6 +42,14 @@ const alovaInstance = createAlova({ statesHook: VueHook, beforeRequest: onAuthRequired((method) => { + // 检查混合内容错误(HTTPS页面请求HTTP接口) + const currentProtocol = typeof window !== 'undefined' && window.location.protocol + const requestProtocol = method.baseURL?.split(':')[0] + if (currentProtocol === 'https:' && requestProtocol === 'http') { + const errorMessage = '无法配置http协议地址,请检查接口地址' + throw new Error(errorMessage) + } + // 设置默认 Content-Type method.config.headers = { 'Content-Type': ContentTypeEnum.JSON, @@ -55,14 +63,14 @@ const alovaInstance = createAlova({ // 处理认证信息 if (!ignoreAuth) { - const token = uni.getStorageSync('token') - if (!token) { + const authInfo = JSON.parse(uni.getStorageSync('token') || '{}') + if (!authInfo.token) { // 跳转到登录页 uni.reLaunch({ url: '/pages/login/index' }) throw new Error('[请求错误]:未登录') } // 添加 Authorization 头 - method.config.headers.Authorization = `Bearer ${token}` + method.config.headers.Authorization = `Bearer ${authInfo.token}` } // 处理动态域名 diff --git a/main/manager-mobile/src/http/request/enum.ts b/main/manager-mobile/src/http/request/enum.ts index 1868fe08..048b5617 100644 --- a/main/manager-mobile/src/http/request/enum.ts +++ b/main/manager-mobile/src/http/request/enum.ts @@ -12,6 +12,7 @@ export enum ResultEnum { ServiceUnavailable = 503, // 服务不可用(原为serviceUnavailable) GatewayTimeout = 504, // 网关超时(原为gatewayTimeout) HttpVersionNotSupported = 505, // HTTP版本不支持(原为httpVersionNotSupported) + MixedContent = 600, // 混合内容错误(HTTPS页面请求HTTP接口) } export enum ContentTypeEnum { JSON = 'application/json;charset=UTF-8', @@ -59,6 +60,9 @@ export function ShowMessage(status: number | string): string { case 505: message = 'HTTP版本不受支持(505)' break + case 600: + message = '混合内容错误(600)' + break default: message = `连接出错(${status})!` } diff --git a/main/manager-mobile/src/pages/settings/index.vue b/main/manager-mobile/src/pages/settings/index.vue index 02436948..34871eca 100644 --- a/main/manager-mobile/src/pages/settings/index.vue +++ b/main/manager-mobile/src/pages/settings/index.vue @@ -87,12 +87,18 @@ async function testServerBaseUrl() { if (response.statusCode === 200) { return true } else { - toast.error(t('message.invalidAddress')) + toast.error({ + msg: t('message.invalidAddress'), + duration: 3000, + }) return false } } catch (error) { console.error('测试服务端地址失败:', error) - toast.error(t('message.invalidAddress')) + toast.error({ + msg: t('message.invalidAddress'), + duration: 3000, + }) return false } } From d86387971a34513e2adf60609d099c285ddf6de5 Mon Sep 17 00:00:00 2001 From: zhuoqinglian <1035449612@qq.com> Date: Tue, 10 Mar 2026 16:15:09 +0800 Subject: [PATCH 3/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dweb=E3=80=81h5?= =?UTF-8?q?=E5=90=8C=E6=97=B6=E6=89=93=E5=BC=80token=E5=A4=B1=E6=95=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-mobile/src/pages/login/index.vue | 75 ++++++++++--------- main/manager-mobile/src/store/user.ts | 3 +- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/main/manager-mobile/src/pages/login/index.vue b/main/manager-mobile/src/pages/login/index.vue index 462dccee..4729ccc2 100644 --- a/main/manager-mobile/src/pages/login/index.vue +++ b/main/manager-mobile/src/pages/login/index.vue @@ -9,17 +9,16 @@ - - - - diff --git a/main/manager-mobile/src/components/VoiceSettingsDialog.vue b/main/manager-mobile/src/components/VoiceSettingsDialog.vue deleted file mode 100644 index b4ce25a5..00000000 --- a/main/manager-mobile/src/components/VoiceSettingsDialog.vue +++ /dev/null @@ -1,270 +0,0 @@ - - - - - diff --git a/main/manager-mobile/src/http/request/alova.ts b/main/manager-mobile/src/http/request/alova.ts index 3120cfed..e7887120 100644 --- a/main/manager-mobile/src/http/request/alova.ts +++ b/main/manager-mobile/src/http/request/alova.ts @@ -42,6 +42,12 @@ const alovaInstance = createAlova({ statesHook: VueHook, beforeRequest: onAuthRequired((method) => { + // h5动态获取最新的 baseURL,确保使用用户设置的服务器地址 + const currentBaseUrl = getEnvBaseUrl() + if (currentBaseUrl !== method.baseURL) { + method.baseURL = currentBaseUrl + } + // 检查混合内容错误(HTTPS页面请求HTTP接口) const currentProtocol = typeof window !== 'undefined' && window.location.protocol const requestProtocol = method.baseURL?.split(':')[0] diff --git a/main/manager-mobile/src/pages/agent/edit.vue b/main/manager-mobile/src/pages/agent/edit.vue index 107fe7b8..ca74ac09 100644 --- a/main/manager-mobile/src/pages/agent/edit.vue +++ b/main/manager-mobile/src/pages/agent/edit.vue @@ -2,10 +2,8 @@ import type { AgentDetail, ModelOption, PluginDefinition, RoleTemplate } from '@/api/agent/types' import { computed, nextTick, onMounted, ref, watch } from 'vue' import { getAgentDetail, getAgentTags, getAllLanguage, getModelOptions, getPluginFunctions, getRoleTemplates, updateAgent, updateAgentTags } from '@/api/agent/agent' -import ContextProviderDialog from '@/components/ContextProviderDialog.vue' -import VoiceSettingsDialog from '@/components/VoiceSettingsDialog.vue' import { t } from '@/i18n' -import { usePluginStore } from '@/store' +import { usePluginStore, useProvider, useSpeedPitch } from '@/store' import { toast } from '@/utils/toast' defineOptions({ @@ -105,29 +103,17 @@ const pickerShow = ref<{ report: false, }) -const ttsSettings = ref({ - volume: 0, - speed: 0, - pitch: 0, -}) - const allFunctions = ref([]) const dynamicTags = ref([]) const inputValue = ref('') const inputVisible = ref(false) -const showContextProviderDialog = ref(false) -const currentContextProviders = ref([]) -const showVoiceSettingsDialog = ref(false) -const voiceSettings = ref({ - volume: 0, - speed: 0, - pitch: 0, -}) const languageOptions = ref([]) const isVisibleReport = ref(false) // 使用插件store const pluginStore = usePluginStore() +const speedPitchStore = useSpeedPitch() +const providerStore = useProvider() // tabs const tabList = [ @@ -174,27 +160,15 @@ function handleInputConfirm() { // 打开上下文源编辑弹窗 function openContextProviderDialog() { - showContextProviderDialog.value = true -} - -// 处理上下文源更新 -function handleUpdateContext(providers: any[]) { - currentContextProviders.value = providers -} - -function openVoiceSettingsDialog() { - showVoiceSettingsDialog.value = true -} - -function handleUpdateVoiceSettings(settings: any) { - ttsSettings.value = settings - formData.value.ttsVolume = settings.volume - formData.value.ttsRate = settings.speed - formData.value.ttsPitch = settings.pitch + uni.navigateTo({ + url: '/pages/agent/provider', + }) } function handleRegulate() { - openVoiceSettingsDialog() + uni.navigateTo({ + url: '/pages/agent/speedPitch', + }) } // 加载智能体详情 @@ -211,14 +185,15 @@ async function loadAgentDetail() { pluginStore.setCurrentAgentId(agentId.value) pluginStore.setCurrentFunctions(detail.functions || []) + // 更新语速音调 + speedPitchStore.updateSpeedPitch({ + ttsVolume: detail.ttsVolume || 0, + ttsRate: detail.ttsRate || 0, + ttsPitch: detail.ttsPitch || 0, + }) + // 加载上下文配置 - currentContextProviders.value = (detail as any).contextProviders || [] - // 加载语音设置 - voiceSettings.value = { - volume: (detail as any).volume || 0, - speed: (detail as any).speed || 0, - pitch: (detail as any).pitch || 0, - } + providerStore.updateProviders(detail.contextProviders || []) // 如果有TTS模型,加载对应的音色选项 if (detail.ttsModelId) { @@ -373,17 +348,17 @@ function filterVoicesByLanguage() { } // 同步到ttsSettings(如果值为null,使用0作为显示默认值,但不修改form中的值) - ttsSettings.value = { - volume: formData.value.ttsVolume !== null && formData.value.ttsVolume !== undefined ? formData.value.ttsVolume : 0, - speed: formData.value.ttsRate !== null && formData.value.ttsRate !== undefined ? formData.value.ttsRate : 0, - pitch: formData.value.ttsPitch !== null && formData.value.ttsPitch !== undefined ? formData.value.ttsPitch : 0, - } + speedPitchStore.updateSpeedPitch({ + ttsVolume: formData.value.ttsVolume !== null && formData.value.ttsVolume !== undefined ? formData.value.ttsVolume : 0, + ttsRate: formData.value.ttsRate !== null && formData.value.ttsRate !== undefined ? formData.value.ttsRate : 0, + ttsPitch: formData.value.ttsPitch !== null && formData.value.ttsPitch !== undefined ? formData.value.ttsPitch : 0, + }) } // 根据语音合成模型加载语言 async function fetchAllLanguag(ttsModelId: string) { try { - const res = await getAllLanguage(ttsModelId, '') as any[] + const res = await getAllLanguage(ttsModelId) // 保存完整的音色信息 voiceDetails.value = res.reduce((acc, voice) => { acc[voice.id] = voice @@ -564,8 +539,9 @@ async function saveAgent() { // 构建保存数据,包含上下文配置和语音设置 const saveData = { ...formData.value, + ...speedPitchStore.speedPitch, ttsLanguage: formData.value.language, - contextProviders: currentContextProviders.value, + contextProviders: providerStore.providers, } await updateAgent(agentId.value, saveData) loadAgentDetail() @@ -726,7 +702,7 @@ onMounted(async () => { - {{ t('agent.contextProviderSuccess', { count: currentContextProviders.length }) }} + {{ t('agent.contextProviderSuccess', { count: providerStore.providers.length }) }} {{ t('agent.contextProviderDocLink') }} @@ -994,16 +970,6 @@ onMounted(async () => { @close="onPickerCancel('report')" @select="({ item }) => onPickerConfirm('report', item.value, item.name)" /> - - diff --git a/main/manager-mobile/src/pages/agent/provider.vue b/main/manager-mobile/src/pages/agent/provider.vue new file mode 100644 index 00000000..47bd56e0 --- /dev/null +++ b/main/manager-mobile/src/pages/agent/provider.vue @@ -0,0 +1,208 @@ + +{ + "layout": "default", + "style": { + "navigationBarTitleText": "编辑源", + "navigationStyle": "custom" + } +} + + + + + + + diff --git a/main/manager-mobile/src/pages/agent/speedPitch.vue b/main/manager-mobile/src/pages/agent/speedPitch.vue new file mode 100644 index 00000000..c8b7514a --- /dev/null +++ b/main/manager-mobile/src/pages/agent/speedPitch.vue @@ -0,0 +1,153 @@ + +{ + "layout": "default", + "style": { + "navigationBarTitleText": "语音设置", + "navigationStyle": "custom" + } +} + + + + + + + diff --git a/main/manager-mobile/src/pages/login/index.vue b/main/manager-mobile/src/pages/login/index.vue index 4729ccc2..a093694c 100644 --- a/main/manager-mobile/src/pages/login/index.vue +++ b/main/manager-mobile/src/pages/login/index.vue @@ -77,11 +77,6 @@ const areaCodeList = computed(() => { return configStore.config.mobileAreaList || [{ name: '中国大陆', key: '+86' }] }) -// SM2公钥 -const sm2PublicKey = computed(() => { - return configStore.config.sm2PublicKey -}) - // 切换登录方式 function toggleLoginType() { loginType.value = loginType.value === 'username' ? 'mobile' : 'username' @@ -131,8 +126,6 @@ function generateUUID() { }) } -let skipReLaunch = false // 全局或组件作用域 - // 跳转至服务端设置页面 function goToServerSetting() { uni.switchTab({ @@ -178,7 +171,8 @@ async function handleLogin() { } // 检查SM2公钥是否配置 - if (!sm2PublicKey.value) { + const sm2PublicKey = configStore.config.sm2PublicKey + if (!sm2PublicKey) { toast.warning(t('sm2.publicKeyNotConfigured')) return } @@ -191,7 +185,7 @@ async function handleLogin() { try { // 拼接验证码和密码 const captchaAndPassword = formData.value.captcha + formData.value.password - encryptedPassword = sm2Encrypt(sm2PublicKey.value, captchaAndPassword) + encryptedPassword = sm2Encrypt(sm2PublicKey, captchaAndPassword) } catch (error) { console.error('密码加密失败:', error) diff --git a/main/manager-mobile/src/pages/settings/index.vue b/main/manager-mobile/src/pages/settings/index.vue index 34871eca..e6bb5605 100644 --- a/main/manager-mobile/src/pages/settings/index.vue +++ b/main/manager-mobile/src/pages/settings/index.vue @@ -1,18 +1,21 @@ -{ + +{ "layout": "default", "style": { "navigationBarTitleText": "设置", "navigationStyle": "custom" } -} +} + + + diff --git a/main/manager-mobile/src/pages/login/privacy-policy-zh.vue b/main/manager-mobile/src/pages/login/privacy-policy-zh.vue new file mode 100644 index 00000000..3fffa070 --- /dev/null +++ b/main/manager-mobile/src/pages/login/privacy-policy-zh.vue @@ -0,0 +1,402 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "隐私政策" + } +} + + + + + diff --git a/main/manager-mobile/src/pages/login/user-agreement-en.vue b/main/manager-mobile/src/pages/login/user-agreement-en.vue new file mode 100644 index 00000000..be9369a1 --- /dev/null +++ b/main/manager-mobile/src/pages/login/user-agreement-en.vue @@ -0,0 +1,539 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "User Agreement" + } +} + + + + + diff --git a/main/manager-mobile/src/pages/login/user-agreement-zh.vue b/main/manager-mobile/src/pages/login/user-agreement-zh.vue new file mode 100644 index 00000000..e612a187 --- /dev/null +++ b/main/manager-mobile/src/pages/login/user-agreement-zh.vue @@ -0,0 +1,542 @@ + +{ + "layout": "default", + "style": { + "navigationStyle": "custom", + "navigationBarTitleText": "用户协议" + } +} + + + + + + + From 469f836a82cdcce71266e563a0e0762b8d3910dc Mon Sep 17 00:00:00 2001 From: zhuoqinglian <1035449612@qq.com> Date: Thu, 12 Mar 2026 17:36:51 +0800 Subject: [PATCH 6/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20mobile=20?= =?UTF-8?q?=E7=9F=AD=E4=BF=A1=E9=AA=8C=E8=AF=81=E7=A0=81=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E6=8F=90=E7=A4=BA=E3=80=81=E6=99=BA=E8=83=BD?= =?UTF-8?q?=E4=BD=93=E6=8F=92=E4=BB=B6=E4=BF=9D=E5=AD=98=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/manager-mobile/src/pages/agent/edit.vue | 16 ++---- main/manager-mobile/src/pages/agent/tools.vue | 56 ++++++++++--------- main/manager-mobile/src/pages/login/index.vue | 8 --- 3 files changed, 34 insertions(+), 46 deletions(-) diff --git a/main/manager-mobile/src/pages/agent/edit.vue b/main/manager-mobile/src/pages/agent/edit.vue index ca74ac09..734c2722 100644 --- a/main/manager-mobile/src/pages/agent/edit.vue +++ b/main/manager-mobile/src/pages/agent/edit.vue @@ -587,15 +587,6 @@ function handleTools() { }) } -// 监听插件配置更新 -function watchPluginUpdates() { - // 监听store中的插件配置变化 - watch(() => pluginStore.currentFunctions, (newFunctions) => { - console.log('插件配置已更新:', newFunctions) - formData.value.functions = newFunctions - }, { deep: true }) -} - // 获取智能体标签 async function loadAgentTags() { try { @@ -611,9 +602,12 @@ async function handleUpdateAgentTags() { await updateAgentTags(agentId.value, { tagNames }) } +// 监听store中的插件配置变化 +watch(() => pluginStore.currentFunctions, (newFunctions) => { + formData.value.functions = newFunctions +}, { deep: true }) + onMounted(async () => { - // 初始化插件配置监听 - watchPluginUpdates() loadAgentTags() // 先加载模型选项和角色模板 diff --git a/main/manager-mobile/src/pages/agent/tools.vue b/main/manager-mobile/src/pages/agent/tools.vue index deeda0c5..45a845bb 100644 --- a/main/manager-mobile/src/pages/agent/tools.vue +++ b/main/manager-mobile/src/pages/agent/tools.vue @@ -11,8 +11,8 @@