diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java index b0320e3c..e476dc32 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/controller/DeviceController.java @@ -5,6 +5,10 @@ import java.util.List; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.BeanUtils; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -12,32 +16,45 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; -import lombok.AllArgsConstructor; import xiaozhi.common.exception.ErrorCode; import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.Result; +import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.dto.DeviceRegisterDTO; import xiaozhi.modules.device.dto.DeviceUnBindDTO; import xiaozhi.modules.device.dto.DeviceUpdateDTO; -import xiaozhi.modules.device.dto.DeviceManualAddDTO; import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.service.DeviceService; import xiaozhi.modules.security.user.SecurityUser; +import xiaozhi.modules.sys.service.SysParamsService; @Tag(name = "设备管理") -@AllArgsConstructor @RestController @RequestMapping("/device") public class DeviceController { private final DeviceService deviceService; - private final RedisUtils redisUtils; + private final SysParamsService sysParamsService; + private final RestTemplate restTemplate; + private final ObjectMapper objectMapper; + + public DeviceController(DeviceService deviceService, RedisUtils redisUtils, SysParamsService sysParamsService, + RestTemplate restTemplate, ObjectMapper objectMapper) { + this.deviceService = deviceService; + this.redisUtils = redisUtils; + this.sysParamsService = sysParamsService; + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + } @PostMapping("/bind/{agentId}/{deviceCode}") @Operation(summary = "绑定设备") @@ -75,6 +92,88 @@ public class DeviceController { return new Result>().ok(devices); } + @PostMapping("/bind/{agentId}") + @Operation(summary = "转发POST请求到MQTT网关") + @RequiresPermissions("sys:role:normal") + public Result forwardToMqttGateway(@PathVariable String agentId, @RequestBody String requestBody) { + try { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { + return new Result<>(); + } + + // 获取当前用户的设备列表 + UserDetail user = SecurityUser.getUser(); + List devices = deviceService.getUserDevices(user.getId(), agentId); + + // 构建deviceIds数组 + java.util.List deviceIds = new java.util.ArrayList<>(); + for (DeviceEntity device : devices) { + String macAddress = device.getMacAddress() != null ? device.getMacAddress() : "unknown"; + String groupId = device.getBoard() != null ? device.getBoard() : "GID_default"; + + // 替换冒号为下划线 + groupId = groupId.replace(":", "_"); + macAddress = macAddress.replace(":", "_"); + + // 构建mqtt客户端ID格式:groupId@@@macAddress@@@macAddress + String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress; + deviceIds.add(mqttClientId); + } + + // 构建完整的URL + String url = "http://" + mqttGatewayUrl + "/api/devices/status"; + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + + // 生成Bearer令牌 + String token = generateBearerToken(); + if (token == null) { + return new Result().error("令牌生成失败"); + } + headers.set("Authorization", "Bearer " + token); + + // 构建请求体JSON + String jsonBody = "{\"clientIds\":" + objectMapper.writeValueAsString(deviceIds) + "}"; + HttpEntity requestEntity = new HttpEntity<>(jsonBody, headers); + + // 发送POST请求 + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + + // 返回响应 + return new Result().ok(response.getBody()); + } catch (Exception e) { + return new Result().error("转发请求失败: " + e.getMessage()); + } + } + + private String generateBearerToken() { + try { + // 获取当前日期,格式为yyyy-MM-dd + String dateStr = java.time.LocalDate.now() + .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + + // 获取MQTT签名密钥 + String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); + if (StringUtils.isBlank(signatureKey)) { + return null; + } + + // 将日期字符串与MQTT_SIGNATURE_KEY连接 + String tokenContent = dateStr + signatureKey; + + // 对连接后的字符串进行SHA256哈希计算 + String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent); + + return token; + } catch (Exception e) { + return null; + } + } + @PostMapping("/unbind") @Operation(summary = "解绑设备") @RequiresPermissions("sys:role:normal") @@ -109,4 +208,63 @@ public class DeviceController { deviceService.manualAddDevice(user.getId(), dto); return new Result<>(); } + + @PostMapping("/commands/{deviceId}") + @Operation(summary = "发送设备指令") + @RequiresPermissions("sys:role:normal") + public Result sendDeviceCommand(@PathVariable String deviceId, @RequestBody String command) { + try { + // 从系统参数中获取MQTT网关地址 + String mqttGatewayUrl = sysParamsService.getValue("server.mqtt_manager_api", true); + if (StringUtils.isBlank(mqttGatewayUrl) || "null".equals(mqttGatewayUrl)) { + return new Result().error("MQTT网关地址未配置"); + } + + // 构建完整的URL + // 获取设备信息以构建mqttClientId + DeviceEntity deviceById = deviceService.selectById(deviceId); + + if (!deviceById.getUserId().equals(SecurityUser.getUser().getId())) { + return new Result().error("设备不存在"); + } + String macAddress = deviceById != null ? deviceById.getMacAddress() : "unknown"; + String groupId = deviceById != null ? deviceById.getBoard() : null; + if (groupId == null) { + groupId = "GID_default"; + } + groupId = groupId.replace(":", "_"); + macAddress = macAddress.replace(":", "_"); + + // 拼接为groupId@@@macAddress@@@deviceId格式 + String mqttClientId = groupId + "@@@" + macAddress + "@@@" + macAddress; + + String url = "http://" + mqttGatewayUrl + "/api/commands/" + mqttClientId; + + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.set("Content-Type", "application/json"); + + // 生成Bearer令牌 + String dateStr = java.time.LocalDate.now() + .format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); + if (StringUtils.isBlank(signatureKey)) { + return new Result().error("MQTT签名密钥未配置"); + } + String tokenContent = dateStr + signatureKey; + String token = org.apache.commons.codec.digest.DigestUtils.sha256Hex(tokenContent); + headers.set("Authorization", "Bearer " + token); + + // 构建请求体 + HttpEntity requestEntity = new HttpEntity<>(command, headers); + + // 发送POST请求 + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + + // 返回响应 + return new Result().ok(response.getBody()); + } catch (Exception e) { + return new Result().error("发送指令失败: " + e.getMessage()); + } + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java index 9c6f0629..f0603519 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/impl/DeviceServiceImpl.java @@ -189,7 +189,7 @@ public class DeviceServiceImpl extends BaseServiceImpl try { String groupId = deviceById != null && deviceById.getBoard() != null ? deviceById.getBoard() : "GID_default"; - DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, clientId, groupId); + DeviceReportRespDTO.MQTT mqtt = buildMqttConfig(macAddress, groupId); if (mqtt != null) { mqtt.setEndpoint(mqttUdpConfig); response.setMqtt(mqtt); @@ -480,11 +480,10 @@ public class DeviceServiceImpl extends BaseServiceImpl * 构建MQTT配置信息 * * @param macAddress MAC地址 - * @param clientId 客户端ID (UUID) * @param groupId 分组ID * @return MQTT配置对象 */ - private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String clientId, String groupId) + private DeviceReportRespDTO.MQTT buildMqttConfig(String macAddress, String groupId) throws Exception { // 从环境变量或系统参数获取签名密钥 String signatureKey = sysParamsService.getValue("server.mqtt_signature_key", false); @@ -496,8 +495,7 @@ public class DeviceServiceImpl extends BaseServiceImpl // 构建客户端ID格式:groupId@@@macAddress@@@uuid String groupIdSafeStr = groupId.replace(":", "_"); String deviceIdSafeStr = macAddress.replace(":", "_"); - String clientIdSafeStr = clientId.replace(":", "_"); - String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, clientIdSafeStr); + String mqttClientId = String.format("%s@@@%s@@@%s", groupIdSafeStr, deviceIdSafeStr, deviceIdSafeStr); // 构建用户数据(包含IP等信息) Map userData = new HashMap<>(); diff --git a/main/manager-api/src/main/resources/db/changelog/202509161610.sql b/main/manager-api/src/main/resources/db/changelog/202509161610.sql new file mode 100644 index 00000000..df4b1fcb --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202509161610.sql @@ -0,0 +1,3 @@ +delete from `sys_params` where param_code = 'server.mqtt_manager_api'; +INSERT INTO `sys_params` (id, param_code, param_value, value_type, param_type, remark) +VALUES (119, 'server.mqtt_manager_api', 'null', 'string', 1, 'MQTT网关管理API的地址'); diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index d69b2bbd..934f7314 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -345,6 +345,13 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202509080922.sql + - changeSet: + id: 202509161610 + author: fyb + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202509161610.sql - changeSet: id: 202509161701 author: RanChen diff --git a/main/manager-web/src/apis/module/device.js b/main/manager-web/src/apis/module/device.js index 233c764b..03ed3519 100644 --- a/main/manager-web/src/apis/module/device.js +++ b/main/manager-web/src/apis/module/device.js @@ -85,4 +85,38 @@ export default { }); }).send(); }, + // 获取设备状态 + getDeviceStatus(agentId, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/device/bind/${agentId}`) + .method('POST') + .data({}) // 发送空对象作为请求体 + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .networkFail((err) => { + console.error('获取设备状态失败:', err); + RequestService.reAjaxFun(() => { + this.getDeviceStatus(agentId, callback); + }); + }).send(); + }, + // 发送设备指令 + sendDeviceCommand(deviceId, mcpData, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/device/commands/${deviceId}`) + .method('POST') + .data(mcpData) + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .networkFail((err) => { + console.error('发送设备指令失败:', err); + RequestService.reAjaxFun(() => { + this.sendDeviceCommand(deviceId, mcpData, callback); + }); + }).send(); + }, } \ No newline at end of file diff --git a/main/manager-web/src/components/McpToolCallDialog.vue b/main/manager-web/src/components/McpToolCallDialog.vue new file mode 100644 index 00000000..d271c3ff --- /dev/null +++ b/main/manager-web/src/components/McpToolCallDialog.vue @@ -0,0 +1,1604 @@ + + + + + diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 54d25ccb..14d735e0 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -15,6 +15,137 @@ export default { 'header.paramManagement': 'Params Management', 'header.dictManagement': 'Dict Management', + // McpToolCallDialog component text + 'mcpToolCall.title': 'Tool Call', + 'mcpToolCall.execute': 'Execute', + 'mcpToolCall.chooseFunction': '1、Choose Function', + 'mcpToolCall.searchFunction': 'Search Function', + 'mcpToolCall.noResults': 'No matching functions found', + 'mcpToolCall.settings': '2、Parameter Settings', + 'mcpToolCall.inputPlaceholder': 'Please enter {label}', + 'mcpToolCall.valueRange': 'Value range: {min} - {max}', + 'mcpToolCall.selectPlaceholder': 'Please select {label}', + 'mcpToolCall.lightTheme': 'Light Theme', + 'mcpToolCall.darkTheme': 'Dark Theme', + 'mcpToolCall.pleaseSelect': 'Please select a function', + 'mcpToolCall.cancel': 'Cancel', + 'mcpToolCall.requiredField': 'Please enter {field}', + 'mcpToolCall.minValue': 'Minimum value is {value}', + 'mcpToolCall.maxValue': 'Maximum value is {value}', + 'mcpToolCall.selectTool': 'Please select a tool to execute', + 'mcpToolCall.executionResult': '3、Execution Result', + 'mcpToolCall.copyResult': 'Copy Result', + 'mcpToolCall.noResultYet': 'No result yet', + 'mcpToolCall.loadingToolList': 'Loading tool list...', + + // Tool names + 'mcpToolCall.toolName.getDeviceStatus': 'View Device Status', + 'mcpToolCall.toolName.setVolume': 'Set Volume', + 'mcpToolCall.toolName.setBrightness': 'Set Brightness', + 'mcpToolCall.toolName.setTheme': 'Set Theme', + 'mcpToolCall.toolName.takePhoto': 'Take Photo & Recognize', + 'mcpToolCall.toolName.getSystemInfo': 'System Info', + 'mcpToolCall.toolName.reboot': 'Reboot Device', + 'mcpToolCall.toolName.upgradeFirmware': 'Upgrade Firmware', + 'mcpToolCall.toolName.getScreenInfo': 'Screen Info', + 'mcpToolCall.toolName.snapshot': 'Screen Snapshot', + 'mcpToolCall.toolName.previewImage': 'Preview Image', + 'mcpToolCall.toolName.setDownloadUrl': 'Set Download URL', + + // Tool categories + 'mcpToolCall.category.audio': 'Audio', + 'mcpToolCall.category.display': 'Display', + 'mcpToolCall.category.camera': 'Camera', + 'mcpToolCall.category.system': 'System', + 'mcpToolCall.category.assets': 'Assets', + 'mcpToolCall.category.deviceInfo': 'Device Info', + + // Table categories and properties + 'mcpToolCall.table.audioSpeaker': 'Audio Speaker', + 'mcpToolCall.table.screen': 'Screen', + 'mcpToolCall.table.network': 'Network', + 'mcpToolCall.table.audioControl': 'Audio Control', + 'mcpToolCall.table.screenControl': 'Screen Control', + 'mcpToolCall.table.systemControl': 'System Control', + 'mcpToolCall.table.screenInfo': 'Screen Info', + 'mcpToolCall.table.hardwareInfo': 'Hardware Info', + 'mcpToolCall.table.memoryInfo': 'Memory Info', + 'mcpToolCall.table.applicationInfo': 'Application Info', + 'mcpToolCall.table.networkInfo': 'Network Info', + 'mcpToolCall.table.displayInfo': 'Display Info', + 'mcpToolCall.table.deviceInfo': 'Device Info', + 'mcpToolCall.table.systemInfo': 'System Info', + // Table column headers + 'mcpToolCall.table.component': 'Component', + 'mcpToolCall.table.property': 'Property', + 'mcpToolCall.table.value': 'Value', + + 'mcpToolCall.prop.volume': 'Volume', + 'mcpToolCall.prop.brightness': 'Brightness', + 'mcpToolCall.prop.theme': 'Theme', + 'mcpToolCall.prop.type': 'Type', + 'mcpToolCall.prop.ssid': 'SSID', + 'mcpToolCall.prop.signalStrength': 'Signal Strength', + 'mcpToolCall.prop.operationResult': 'Operation Result', + 'mcpToolCall.prop.width': 'Width', + 'mcpToolCall.prop.height': 'Height', + 'mcpToolCall.prop.screenType': 'Type', + 'mcpToolCall.prop.chipModel': 'Chip Model', + 'mcpToolCall.prop.cpuCores': 'CPU Cores', + 'mcpToolCall.prop.chipVersion': 'Chip Version', + 'mcpToolCall.prop.flashSize': 'Flash Size', + 'mcpToolCall.prop.minFreeHeap': 'Minimum Free Heap', + 'mcpToolCall.prop.applicationName': 'Application Name', + 'mcpToolCall.prop.applicationVersion': 'Application Version', + 'mcpToolCall.prop.compileTime': 'Compile Time', + 'mcpToolCall.prop.idfVersion': 'IDF Version', + 'mcpToolCall.prop.macAddress': 'MAC Address', + 'mcpToolCall.prop.ipAddress': 'IP Address', + 'mcpToolCall.prop.wifiName': 'WiFi Name', + 'mcpToolCall.prop.wifiChannel': 'WiFi Channel', + 'mcpToolCall.prop.screenSize': 'Screen Size', + 'mcpToolCall.prop.deviceUuid': 'Device UUID', + 'mcpToolCall.prop.systemLanguage': 'System Language', + 'mcpToolCall.prop.currentOtaPartition': 'Current OTA Partition', + 'mcpToolCall.prop.getResult': 'Get Result', + 'mcpToolCall.prop.url': 'URL', + 'mcpToolCall.prop.quality': 'Quality', + 'mcpToolCall.prop.question': 'Question', + + // Tool help texts + 'mcpToolCall.help.getDeviceStatus': 'View the current running status of the device, including volume, screen, battery and other information.', + 'mcpToolCall.help.setVolume': 'Adjust the volume of the device, please enter a value between 0-100.', + 'mcpToolCall.help.setBrightness': 'Adjust the brightness of the device screen, please enter a value between 0-100.', + 'mcpToolCall.help.setTheme': 'Switch the display theme of the device screen, you can choose light or dark mode.', + 'mcpToolCall.help.takePhoto': 'Take photos with the device camera and perform recognition analysis, please enter the question you want to ask.', + 'mcpToolCall.help.getSystemInfo': 'Get the system information of the device, including hardware specifications, software version, etc.', + 'mcpToolCall.help.reboot': 'Reboot the device, the device will restart after execution.', + 'mcpToolCall.help.upgradeFirmware': 'Download and upgrade the device firmware from the specified URL, the device will restart automatically after the upgrade.', + 'mcpToolCall.help.getScreenInfo': 'Get detailed information about the screen, such as resolution, size and other parameters.', + 'mcpToolCall.help.snapshot': 'Take a screenshot of the current screen and upload it to the specified URL.', + 'mcpToolCall.help.previewImage': 'Preview images from the specified URL on the device screen.', + 'mcpToolCall.help.setDownloadUrl': 'Set the download address for device resource files.', + + // Other text + 'mcpToolCall.text.strong': 'Strong', + 'mcpToolCall.text.medium': 'Medium', + 'mcpToolCall.text.weak': 'Weak', + 'mcpToolCall.text.dark': 'Dark', + 'mcpToolCall.text.light': 'Light', + 'mcpToolCall.text.setSuccess': 'Setting successful', + 'mcpToolCall.text.setFailed': 'Setting failed', + 'mcpToolCall.text.brightnessSetSuccess': 'Brightness setting successful', + 'mcpToolCall.text.brightnessSetFailed': 'Brightness setting failed', + 'mcpToolCall.text.themeSetSuccess': 'Theme setting successful', + 'mcpToolCall.text.themeSetFailed': 'Theme setting failed', + 'mcpToolCall.text.rebootCommandSent': 'Reboot command sent', + 'mcpToolCall.text.rebootFailed': 'Reboot failed', + 'mcpToolCall.text.monochrome': 'Monochrome Screen', + 'mcpToolCall.text.color': 'Color Screen', + 'mcpToolCall.text.getSuccessParseFailed': 'Get successful, but parse failed', + 'mcpToolCall.text.getFailed': 'Get failed', + 'mcpToolCall.text.getSuccessFormatError': 'Get successful, but data format is abnormal', + // Dictionary data dialog related 'dictDataDialog.addDictData': 'Add Dictionary Data', 'dictDataDialog.dictLabel': 'Dictionary Label', @@ -327,6 +458,7 @@ export default { 'device.bindWithCode': '6-digit Verification Code Binding', 'device.manualAdd': 'Manual Add', 'device.unbind': 'Unbind', + 'device.toolCall': 'Tool Call', 'device.selectAtLeastOne': 'Please select at least one record', 'device.confirmBatchUnbind': 'Are you sure you want to unbind {count} selected devices?', 'device.batchUnbindSuccess': 'Successfully unbound {count} devices', @@ -342,6 +474,9 @@ export default { 'device.autoUpdateDisabled': 'Auto update disabled', 'device.batchUnbindSuccess': 'Successfully unbound {count} devices', 'device.getFirmwareTypeFailed': 'Failed to fetch firmware type', + 'device.deviceStatus': 'Status', + 'device.online': 'Online', + 'device.offline': 'Offline', // Message tips 'message.success': 'Operation Successful', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index ee338f6b..e80cefe1 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -15,6 +15,137 @@ export default { 'header.paramManagement': '参数管理', 'header.dictManagement': '字典管理', + // McpToolCallDialog组件文本 + 'mcpToolCall.title': '工具调用', + 'mcpToolCall.execute': '执行', + 'mcpToolCall.chooseFunction': '1、选择功能', + 'mcpToolCall.searchFunction': '搜索功能', + 'mcpToolCall.noResults': '未找到匹配的功能', + 'mcpToolCall.settings': '2、参数设置', + 'mcpToolCall.inputPlaceholder': '请输入{label}', + 'mcpToolCall.valueRange': '取值范围:{min} - {max}', + 'mcpToolCall.selectPlaceholder': '请选择{label}', + 'mcpToolCall.lightTheme': '浅色主题', + 'mcpToolCall.darkTheme': '深色主题', + 'mcpToolCall.pleaseSelect': '请选择一个功能', + 'mcpToolCall.cancel': '取消', + 'mcpToolCall.requiredField': '请输入{field}', + 'mcpToolCall.minValue': '最小值为{value}', + 'mcpToolCall.maxValue': '最大值为{value}', + 'mcpToolCall.selectTool': '请选择要执行的工具', + 'mcpToolCall.executionResult': '3、执行结果', + 'mcpToolCall.copyResult': '复制结果', + 'mcpToolCall.noResultYet': '暂无执行结果', + 'mcpToolCall.loadingToolList': '正在获取工具列表...', + + // 工具名称 + 'mcpToolCall.toolName.getDeviceStatus': '查看设备状态', + 'mcpToolCall.toolName.setVolume': '设置音量', + 'mcpToolCall.toolName.setBrightness': '设置亮度', + 'mcpToolCall.toolName.setTheme': '设置主题', + 'mcpToolCall.toolName.takePhoto': '拍照识别', + 'mcpToolCall.toolName.getSystemInfo': '系统信息', + 'mcpToolCall.toolName.reboot': '重启设备', + 'mcpToolCall.toolName.upgradeFirmware': '升级固件', + 'mcpToolCall.toolName.getScreenInfo': '屏幕信息', + 'mcpToolCall.toolName.snapshot': '屏幕截图', + 'mcpToolCall.toolName.previewImage': '预览图片', + 'mcpToolCall.toolName.setDownloadUrl': '设置下载地址', + + // 工具分类 + 'mcpToolCall.category.audio': '音频', + 'mcpToolCall.category.display': '显示', + 'mcpToolCall.category.camera': '拍摄', + 'mcpToolCall.category.system': '系统', + 'mcpToolCall.category.assets': '资源', + 'mcpToolCall.category.deviceInfo': '设备信息', + + // 表格分类和属性 + 'mcpToolCall.table.audioSpeaker': '音频扬声器', + 'mcpToolCall.table.screen': '屏幕', + 'mcpToolCall.table.network': '网络', + 'mcpToolCall.table.audioControl': '音频控制', + 'mcpToolCall.table.screenControl': '屏幕控制', + 'mcpToolCall.table.systemControl': '系统控制', + 'mcpToolCall.table.screenInfo': '屏幕信息', + 'mcpToolCall.table.hardwareInfo': '硬件信息', + 'mcpToolCall.table.memoryInfo': '内存信息', + 'mcpToolCall.table.applicationInfo': '应用信息', + 'mcpToolCall.table.networkInfo': '网络信息', + 'mcpToolCall.table.displayInfo': '显示信息', + 'mcpToolCall.table.deviceInfo': '设备信息', + 'mcpToolCall.table.systemInfo': '系统信息', + // 表格列标题 + 'mcpToolCall.table.component': '组件', + 'mcpToolCall.table.property': '属性', + 'mcpToolCall.table.value': '值', + + 'mcpToolCall.prop.volume': '音量', + 'mcpToolCall.prop.brightness': '亮度', + 'mcpToolCall.prop.theme': '主题', + 'mcpToolCall.prop.type': '类型', + 'mcpToolCall.prop.ssid': 'SSID', + 'mcpToolCall.prop.signalStrength': '信号强度', + 'mcpToolCall.prop.operationResult': '操作结果', + 'mcpToolCall.prop.width': '宽度', + 'mcpToolCall.prop.height': '高度', + 'mcpToolCall.prop.screenType': '类型', + 'mcpToolCall.prop.chipModel': '芯片型号', + 'mcpToolCall.prop.cpuCores': 'CPU核心数', + 'mcpToolCall.prop.chipVersion': '芯片版本', + 'mcpToolCall.prop.flashSize': 'Flash大小', + 'mcpToolCall.prop.minFreeHeap': '最小可用堆', + 'mcpToolCall.prop.applicationName': '应用名称', + 'mcpToolCall.prop.applicationVersion': '应用版本', + 'mcpToolCall.prop.compileTime': '编译时间', + 'mcpToolCall.prop.idfVersion': 'IDF版本', + 'mcpToolCall.prop.macAddress': 'MAC地址', + 'mcpToolCall.prop.ipAddress': 'IP地址', + 'mcpToolCall.prop.wifiName': 'WiFi名称', + 'mcpToolCall.prop.wifiChannel': 'WiFi信道', + 'mcpToolCall.prop.screenSize': '屏幕尺寸', + 'mcpToolCall.prop.deviceUuid': '设备UUID', + 'mcpToolCall.prop.systemLanguage': '系统语言', + 'mcpToolCall.prop.currentOtaPartition': '当前OTA分区', + 'mcpToolCall.prop.getResult': '获取结果', + 'mcpToolCall.prop.url': 'URL', + 'mcpToolCall.prop.quality': '质量', + 'mcpToolCall.prop.question': '问题', + + // 工具帮助文本 + 'mcpToolCall.help.getDeviceStatus': '查看设备的当前运行状态,包括音量、屏幕、电池等信息。', + 'mcpToolCall.help.setVolume': '调整设备的音量大小,请输入0-100之间的数值。', + 'mcpToolCall.help.setBrightness': '调整设备屏幕的亮度,请输入0-100之间的数值。', + 'mcpToolCall.help.setTheme': '切换设备屏幕的显示主题,可以选择浅色或深色模式。', + 'mcpToolCall.help.takePhoto': '使用设备摄像头拍摄照片并进行识别分析,请输入要询问的问题。', + 'mcpToolCall.help.getSystemInfo': '获取设备的系统信息,包括硬件规格、软件版本等。', + 'mcpToolCall.help.reboot': '重启设备,执行后设备将重新启动。', + 'mcpToolCall.help.upgradeFirmware': '从指定URL下载并升级设备固件,升级后设备会自动重启。', + 'mcpToolCall.help.getScreenInfo': '获取屏幕的详细信息,如分辨率、尺寸等参数。', + 'mcpToolCall.help.snapshot': '对当前屏幕进行截图并上传到指定URL。', + 'mcpToolCall.help.previewImage': '在设备屏幕上预览指定URL的图片。', + 'mcpToolCall.help.setDownloadUrl': '设置设备资源文件的下载地址。', + + // 其他文本 + 'mcpToolCall.text.strong': '强', + 'mcpToolCall.text.medium': '中', + 'mcpToolCall.text.weak': '弱', + 'mcpToolCall.text.dark': '深色', + 'mcpToolCall.text.light': '浅色', + 'mcpToolCall.text.setSuccess': '设置成功', + 'mcpToolCall.text.setFailed': '设置失败', + 'mcpToolCall.text.brightnessSetSuccess': '亮度设置成功', + 'mcpToolCall.text.brightnessSetFailed': '亮度设置失败', + 'mcpToolCall.text.themeSetSuccess': '主题设置成功', + 'mcpToolCall.text.themeSetFailed': '主题设置失败', + 'mcpToolCall.text.rebootCommandSent': '重启指令已发送', + 'mcpToolCall.text.rebootFailed': '重启失败', + 'mcpToolCall.text.monochrome': '单色屏', + 'mcpToolCall.text.color': '彩色屏', + 'mcpToolCall.text.getSuccessParseFailed': '获取成功,但解析失败', + 'mcpToolCall.text.getFailed': '获取失败', + 'mcpToolCall.text.getSuccessFormatError': '获取成功,但数据格式异常', + // 字典数据对话框相关 'dictDataDialog.addDictData': '新增字典数据', 'dictDataDialog.dictLabel': '字典标签', @@ -328,6 +459,7 @@ export default { 'device.bindWithCode': '6位验证码绑定', 'device.manualAdd': '手动添加', 'device.unbind': '解绑', + 'device.toolCall': '工具调用', 'device.selectAtLeastOne': '请至少选择一条记录', 'device.confirmBatchUnbind': '确认要解绑选中的 {count} 台设备吗?', 'device.batchUnbindSuccess': '成功解绑 {count} 台设备', @@ -343,6 +475,9 @@ export default { 'device.autoUpdateDisabled': '已关闭自动升级', 'device.batchUnbindSuccess': '成功解绑 {count} 台设备', 'device.getFirmwareTypeFailed': '获取固件类型失败', + 'device.deviceStatus': '状态', + 'device.online': '在线', + 'device.offline': '离线', // 消息提示 'message.success': '操作成功', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index 97cccba6..ebefb838 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -15,6 +15,137 @@ export default { 'header.paramManagement': '參數管理', 'header.dictManagement': '字典管理', + // McpToolCallDialog组件文本 + 'mcpToolCall.title': '工具調用', + 'mcpToolCall.execute': '執行', + 'mcpToolCall.chooseFunction': '1、選擇功能', + 'mcpToolCall.searchFunction': '搜索功能', + 'mcpToolCall.noResults': '未找到匹配的功能', + 'mcpToolCall.settings': '2、參數設置', + 'mcpToolCall.inputPlaceholder': '請輸入{label}', + 'mcpToolCall.valueRange': '取值範圍:{min} - {max}', + 'mcpToolCall.selectPlaceholder': '請選擇{label}', + 'mcpToolCall.lightTheme': '淺色主題', + 'mcpToolCall.darkTheme': '深色主題', + 'mcpToolCall.pleaseSelect': '請選擇一個功能', + 'mcpToolCall.cancel': '取消', + 'mcpToolCall.requiredField': '請輸入{field}', + 'mcpToolCall.minValue': '最小值為{value}', + 'mcpToolCall.maxValue': '最大值為{value}', + 'mcpToolCall.selectTool': '請選擇要執行的工具', + 'mcpToolCall.executionResult': '3、執行結果', + 'mcpToolCall.copyResult': '複製結果', + 'mcpToolCall.noResultYet': '暫無執行結果', + 'mcpToolCall.loadingToolList': '正在獲取工具列表...', + + // 工具名稱 + 'mcpToolCall.toolName.getDeviceStatus': '查看設備狀態', + 'mcpToolCall.toolName.setVolume': '設置音量', + 'mcpToolCall.toolName.setBrightness': '設置亮度', + 'mcpToolCall.toolName.setTheme': '設置主題', + 'mcpToolCall.toolName.takePhoto': '拍照識別', + 'mcpToolCall.toolName.getSystemInfo': '系統資訊', + 'mcpToolCall.toolName.reboot': '重啟設備', + 'mcpToolCall.toolName.upgradeFirmware': '升級固件', + 'mcpToolCall.toolName.getScreenInfo': '螢幕資訊', + 'mcpToolCall.toolName.snapshot': '螢幕截圖', + 'mcpToolCall.toolName.previewImage': '預覽圖片', + 'mcpToolCall.toolName.setDownloadUrl': '設置下載地址', + + // 工具分類 + 'mcpToolCall.category.audio': '音頻', + 'mcpToolCall.category.display': '顯示', + 'mcpToolCall.category.camera': '拍攝', + 'mcpToolCall.category.system': '系統', + 'mcpToolCall.category.assets': '資源', + 'mcpToolCall.category.deviceInfo': '設備資訊', + + // 表格分類和屬性 + 'mcpToolCall.table.audioSpeaker': '音頻揚聲器', + 'mcpToolCall.table.screen': '螢幕', + 'mcpToolCall.table.network': '網路', + 'mcpToolCall.table.audioControl': '音頻控制', + 'mcpToolCall.table.screenControl': '螢幕控制', + 'mcpToolCall.table.systemControl': '系統控制', + 'mcpToolCall.table.screenInfo': '螢幕資訊', + 'mcpToolCall.table.hardwareInfo': '硬體資訊', + 'mcpToolCall.table.memoryInfo': '記憶體資訊', + 'mcpToolCall.table.applicationInfo': '應用資訊', + 'mcpToolCall.table.networkInfo': '網路資訊', + 'mcpToolCall.table.displayInfo': '顯示資訊', + 'mcpToolCall.table.deviceInfo': '設備資訊', + 'mcpToolCall.table.systemInfo': '系統資訊', + // 表格列標題 + 'mcpToolCall.table.component': '組件', + 'mcpToolCall.table.property': '屬性', + 'mcpToolCall.table.value': '值', + + 'mcpToolCall.prop.volume': '音量', + 'mcpToolCall.prop.brightness': '亮度', + 'mcpToolCall.prop.theme': '主題', + 'mcpToolCall.prop.type': '類型', + 'mcpToolCall.prop.ssid': 'SSID', + 'mcpToolCall.prop.signalStrength': '信號強度', + 'mcpToolCall.prop.operationResult': '操作結果', + 'mcpToolCall.prop.width': '寬度', + 'mcpToolCall.prop.height': '高度', + 'mcpToolCall.prop.screenType': '類型', + 'mcpToolCall.prop.chipModel': '晶片型號', + 'mcpToolCall.prop.cpuCores': 'CPU核心數', + 'mcpToolCall.prop.chipVersion': '晶片版本', + 'mcpToolCall.prop.flashSize': 'Flash大小', + 'mcpToolCall.prop.minFreeHeap': '最小可用堆', + 'mcpToolCall.prop.applicationName': '應用名稱', + 'mcpToolCall.prop.applicationVersion': '應用版本', + 'mcpToolCall.prop.compileTime': '編譯時間', + 'mcpToolCall.prop.idfVersion': 'IDF版本', + 'mcpToolCall.prop.macAddress': 'MAC地址', + 'mcpToolCall.prop.ipAddress': 'IP地址', + 'mcpToolCall.prop.wifiName': 'WiFi名稱', + 'mcpToolCall.prop.wifiChannel': 'WiFi信道', + 'mcpToolCall.prop.screenSize': '螢幕尺寸', + 'mcpToolCall.prop.deviceUuid': '設備UUID', + 'mcpToolCall.prop.systemLanguage': '系統語言', + 'mcpToolCall.prop.currentOtaPartition': '當前OTA分區', + 'mcpToolCall.prop.getResult': '獲取結果', + 'mcpToolCall.prop.url': 'URL', + 'mcpToolCall.prop.quality': '品質', + 'mcpToolCall.prop.question': '問題', + + // 工具幫助文本 + 'mcpToolCall.help.getDeviceStatus': '查看設備的當前運行狀態,包括音量、螢幕、電池等資訊。', + 'mcpToolCall.help.setVolume': '調整設備的音量大小,請輸入0-100之間的數值。', + 'mcpToolCall.help.setBrightness': '調整設備螢幕的亮度,請輸入0-100之間的數值。', + 'mcpToolCall.help.setTheme': '切換設備螢幕的顯示主題,可以選擇淺色或深色模式。', + 'mcpToolCall.help.takePhoto': '使用設備攝像頭拍攝照片並進行識別分析,請輸入要詢問的問題。', + 'mcpToolCall.help.getSystemInfo': '獲取設備的系統資訊,包括硬體規格、軟體版本等。', + 'mcpToolCall.help.reboot': '重啟設備,執行後設備將重新啟動。', + 'mcpToolCall.help.upgradeFirmware': '從指定URL下載並升級設備固件,升級後設備會自動重啟。', + 'mcpToolCall.help.getScreenInfo': '獲取螢幕的詳細資訊,如解析度、尺寸等參數。', + 'mcpToolCall.help.snapshot': '對當前螢幕進行截圖並上傳到指定URL。', + 'mcpToolCall.help.previewImage': '在設備螢幕上預覽指定URL的圖片。', + 'mcpToolCall.help.setDownloadUrl': '設置設備資源文件的下載地址。', + + // 其他文本 + 'mcpToolCall.text.strong': '強', + 'mcpToolCall.text.medium': '中', + 'mcpToolCall.text.weak': '弱', + 'mcpToolCall.text.dark': '深色', + 'mcpToolCall.text.light': '淺色', + 'mcpToolCall.text.setSuccess': '設置成功', + 'mcpToolCall.text.setFailed': '設置失敗', + 'mcpToolCall.text.brightnessSetSuccess': '亮度設置成功', + 'mcpToolCall.text.brightnessSetFailed': '亮度設置失敗', + 'mcpToolCall.text.themeSetSuccess': '主題設置成功', + 'mcpToolCall.text.themeSetFailed': '主題設置失敗', + 'mcpToolCall.text.rebootCommandSent': '重啟指令已發送', + 'mcpToolCall.text.rebootFailed': '重啟失敗', + 'mcpToolCall.text.monochrome': '單色屏', + 'mcpToolCall.text.color': '彩色屏', + 'mcpToolCall.text.getSuccessParseFailed': '獲取成功,但解析失敗', + 'mcpToolCall.text.getFailed': '獲取失敗', + 'mcpToolCall.text.getSuccessFormatError': '獲取成功,但數據格式異常', + // 字典數據對話框相關 'dictDataDialog.addDictData': '新增字典數據', 'dictDataDialog.dictLabel': '字典標籤', @@ -327,6 +458,7 @@ export default { 'device.bindWithCode': '6位驗證碼綁定', 'device.manualAdd': '手動添加', 'device.unbind': '解綁', + 'device.toolCall': '工具調用', 'device.selectAtLeastOne': '請至少選擇一條記錄', 'device.confirmBatchUnbind': '確認要解綁選中的 {count} 台設備嗎?', 'device.batchUnbindSuccess': '成功解綁 {count} 台設備', @@ -342,6 +474,9 @@ export default { 'device.autoUpdateDisabled': '已關閉自動升級', 'device.batchUnbindSuccess': '成功解綁 {count} 台設備', 'device.getFirmwareTypeFailed': '獲取固件類型失敗', + 'device.deviceStatus': '狀態', + 'device.online': '在線', + 'device.offline': '離線', // 消息提示 'message.success': '操作成功', diff --git a/main/manager-web/src/views/DeviceManagement.vue b/main/manager-web/src/views/DeviceManagement.vue index 65945eb8..053fcbc6 100644 --- a/main/manager-web/src/views/DeviceManagement.vue +++ b/main/manager-web/src/views/DeviceManagement.vue @@ -1,12 +1,12 @@ @@ -115,19 +125,23 @@