diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java index 0052c7cc..76669e67 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java @@ -73,9 +73,13 @@ public class AgentController { @GetMapping("/list") @Operation(summary = "获取用户智能体列表") @RequiresPermissions("sys:role:normal") - public Result> getUserAgents() { + public Result> getUserAgents( + @RequestParam(value = "keyword", required = false) String keyword, + @RequestParam(value = "searchType", defaultValue = "name") String searchType) { UserDetail user = SecurityUser.getUser(); - List agents = agentService.getUserAgents(user.getId()); + + // 直接调用整合后的getUserAgents方法,无需再区分搜索和普通查询 + List agents = agentService.getUserAgents(user.getId(), keyword, searchType); return new Result>().ok(agents); } @@ -271,4 +275,6 @@ public class AgentController { .body(audioData); } + + } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java index 218ee1eb..edad88db 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentDTO.java @@ -1,6 +1,7 @@ package xiaozhi.modules.agent.dto; import java.util.Date; +import java.util.List; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java index a9d4e5bb..22e8a2e0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentService.java @@ -54,9 +54,11 @@ public interface AgentService extends BaseService { * 获取用户智能体列表 * * @param userId 用户ID + * @param keyword 搜索关键词 + * @param searchType 搜索类型(name - 按名称搜索,mac - 按MAC地址搜索) * @return 智能体列表 */ - List getUserAgents(Long userId); + List getUserAgents(Long userId, String keyword, String searchType); /** * 根据智能体ID获取设备数量 @@ -98,4 +100,6 @@ public interface AgentService extends BaseService { * @return 创建的智能体ID */ String createAgent(AgentCreateDTO dto); + + } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java index 0adf0873..71a4641a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java @@ -42,6 +42,7 @@ import xiaozhi.modules.agent.service.AgentPluginMappingService; import xiaozhi.modules.agent.service.AgentService; import xiaozhi.modules.agent.service.AgentTemplateService; import xiaozhi.modules.agent.vo.AgentInfoVO; +import xiaozhi.modules.device.entity.DeviceEntity; import xiaozhi.modules.device.service.DeviceService; import xiaozhi.modules.model.dto.ModelProviderDTO; import xiaozhi.modules.model.dto.VoiceDTO; @@ -88,13 +89,13 @@ public class AgentServiceImpl extends BaseServiceImpl imp agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode()); } } - + // 查询上下文源配置 AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(id); if (contextProviderEntity != null) { agent.setContextProviders(contextProviderEntity.getContextProviders()); } - + // 无需额外查询插件列表,已通过SQL查询出来 return agent; } @@ -127,38 +128,75 @@ public class AgentServiceImpl extends BaseServiceImpl imp } @Override - public List getUserAgents(Long userId) { - QueryWrapper wrapper = new QueryWrapper<>(); - wrapper.eq("user_id", userId); - List agents = agentDao.selectList(wrapper); - return agents.stream().map(agent -> { - AgentDTO dto = new AgentDTO(); - dto.setId(agent.getId()); - dto.setAgentName(agent.getAgentName()); - dto.setSystemPrompt(agent.getSystemPrompt()); + public List getUserAgents(Long userId, String keyword, String searchType) { + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("user_id", userId); - // 获取 TTS 模型名称 - dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId())); + // 如果有搜索关键词,根据搜索类型添加相应的查询条件 + if (StringUtils.isNotBlank(keyword)) { + if ("mac".equals(searchType)) { + // 按MAC地址搜索:先搜索设备,再获取对应的智能体 + List devices = deviceService.searchDevicesByMacAddress(keyword, userId); - // 获取 LLM 模型名称 - dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId())); + if (!devices.isEmpty()) { + // 获取设备对应的智能体ID列表 + List agentIds = devices.stream() + .map(DeviceEntity::getAgentId) + .distinct() + .collect(Collectors.toList()); - // 获取 VLLM 模型名称 - dto.setVllmModelName(modelConfigService.getModelNameById(agent.getVllmModelId())); + if (!agentIds.isEmpty()) { + queryWrapper.in("id", agentIds); + } else { + return new ArrayList<>(); + } + } else { + return new ArrayList<>(); + } + } else { + // 按名称搜索 + queryWrapper.like("agent_name", keyword); + } + } - // 获取记忆模型名称 - dto.setMemModelId(agent.getMemModelId()); + // 执行查询 + List agentEntities = baseDao.selectList(queryWrapper); - // 获取 TTS 音色名称 - dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId())); + // 转换为DTO并设置所有必要字段 + return agentEntities.stream().map(this::buildAgentDTO).collect(Collectors.toList()); + } - // 获取智能体最近的最后连接时长 - dto.setLastConnectedAt(deviceService.getLatestLastConnectionTime(agent.getId())); + /** + * 将AgentEntity转换为AgentDTO + */ + private AgentDTO buildAgentDTO(AgentEntity agent) { + AgentDTO dto = new AgentDTO(); + dto.setId(agent.getId()); + dto.setAgentName(agent.getAgentName()); + dto.setSystemPrompt(agent.getSystemPrompt()); - // 获取设备数量 - dto.setDeviceCount(getDeviceCountByAgentId(agent.getId())); - return dto; - }).collect(Collectors.toList()); + // 获取 TTS 模型名称 + dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId())); + + // 获取 LLM 模型名称 + dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId())); + + // 获取 VLLM 模型名称 + dto.setVllmModelName(modelConfigService.getModelNameById(agent.getVllmModelId())); + + // 获取记忆模型名称 + dto.setMemModelId(agent.getMemModelId()); + + // 获取 TTS 音色名称 + dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId())); + + // 获取智能体最近的最后连接时长 + dto.setLastConnectedAt(deviceService.getLatestLastConnectionTime(agent.getId())); + + // 获取设备数量 + dto.setDeviceCount(getDeviceCountByAgentId(agent.getId())); + + return dto; } @Override @@ -468,4 +506,5 @@ public class AgentServiceImpl extends BaseServiceImpl imp agentPluginMappingService.saveBatch(toInsert); return entity.getId(); } -} + +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java index 5b56161f..f4debba9 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/device/service/DeviceService.java @@ -108,4 +108,13 @@ public interface DeviceService extends BaseService { */ String generateWebSocketToken(String clientId, String username) throws Exception; + /** + * 根据MAC地址搜索设备 + * + * @param macAddress MAC地址关键词 + * @param userId 用户ID + * @return 设备列表 + */ + List searchDevicesByMacAddress(String macAddress, Long userId); + } \ 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 5c807645..ea0d20eb 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 @@ -496,6 +496,14 @@ public class DeviceServiceImpl extends BaseServiceImpl redisUtils.delete(RedisKeys.getAgentDeviceCountById(dto.getAgentId())); } + @Override + public List searchDevicesByMacAddress(String macAddress, Long userId) { + QueryWrapper wrapper = new QueryWrapper<>(); + wrapper.like("mac_address", macAddress); + wrapper.eq("user_id", userId); + return deviceDao.selectList(wrapper); + } + /** * 生成MQTT密码签名 * diff --git a/main/manager-web/src/apis/module/agent.js b/main/manager-web/src/apis/module/agent.js index 4a76514c..b90c932c 100644 --- a/main/manager-web/src/apis/module/agent.js +++ b/main/manager-web/src/apis/module/agent.js @@ -382,4 +382,20 @@ export default { }); }).send(); }, + + // 搜索智能体 + searchAgent(keyword, searchType, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/agent/list?keyword=${encodeURIComponent(keyword)}&searchType=${searchType}`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime(); + callback(res); + }) + .networkFail(() => { + RequestService.reAjaxFun(() => { + this.searchAgent(keyword, searchType, callback); + }); + }).send(); + }, } diff --git a/main/manager-web/src/components/HeaderBar.vue b/main/manager-web/src/components/HeaderBar.vue index add7e221..c661f6fc 100644 --- a/main/manager-web/src/components/HeaderBar.vue +++ b/main/manager-web/src/components/HeaderBar.vue @@ -408,18 +408,8 @@ export default { // 保存搜索历史 this.saveSearchHistory(searchValue); - try { - // 创建不区分大小写的正则表达式 - const regex = new RegExp(searchValue, "i"); - // 触发搜索事件,将正则表达式传递给父组件 - this.$emit("search", regex); - } catch (error) { - console.error("正则表达式创建失败:", error); - this.$message.error({ - message: this.$t("message.error"), - showClose: true, - }); - } + // 触发搜索事件,将搜索关键词传递给父组件 + this.$emit("search", searchValue); // 搜索完成后让输入框失去焦点,从而触发blur事件隐藏搜索历史 if (this.$refs.searchInput) { diff --git a/main/manager-web/src/i18n/de.js b/main/manager-web/src/i18n/de.js index 22512e8c..2ecfca59 100644 --- a/main/manager-web/src/i18n/de.js +++ b/main/manager-web/src/i18n/de.js @@ -25,7 +25,7 @@ export default { 'header.featureManagement': 'Systemfunktionsverwaltung', 'header.changePassword': 'Passwort ändern', 'header.logout': 'Abmelden', - 'header.searchPlaceholder': 'Nach Namen suchen..', + 'header.searchPlaceholder': 'Namen oder MAC suchen', // McpToolCallDialog component text 'mcpToolCall.title': 'Werkzeugaufruf', diff --git a/main/manager-web/src/i18n/en.js b/main/manager-web/src/i18n/en.js index 9bcc1f7d..76876b42 100644 --- a/main/manager-web/src/i18n/en.js +++ b/main/manager-web/src/i18n/en.js @@ -25,7 +25,7 @@ export default { 'header.featureManagement': 'System Feature Management', 'header.changePassword': 'Change Password', 'header.logout': 'Logout', - 'header.searchPlaceholder': 'Search by name..', + 'header.searchPlaceholder': 'Search name or mac', // McpToolCallDialog component text 'mcpToolCall.title': 'Tool Call', diff --git a/main/manager-web/src/i18n/vi.js b/main/manager-web/src/i18n/vi.js index c9d9e1cf..9e6cb17d 100644 --- a/main/manager-web/src/i18n/vi.js +++ b/main/manager-web/src/i18n/vi.js @@ -25,7 +25,7 @@ export default { 'header.featureManagement': 'Cấu hình chức năng hệ thống', 'header.changePassword': 'Đổi mật khẩu', 'header.logout': 'Đăng xuất', - 'header.searchPlaceholder': 'Tìm kiếm theo tên..', + 'header.searchPlaceholder': 'Tìm tên hoặc MAC', // McpToolCallDialog component text 'mcpToolCall.title': 'Gọi công cụ', diff --git a/main/manager-web/src/i18n/zh_CN.js b/main/manager-web/src/i18n/zh_CN.js index 44d8e400..bc655d32 100644 --- a/main/manager-web/src/i18n/zh_CN.js +++ b/main/manager-web/src/i18n/zh_CN.js @@ -25,7 +25,7 @@ export default { 'header.featureManagement': '系统功能配置', 'header.changePassword': '修改密码', 'header.logout': '退出登录', - 'header.searchPlaceholder': '输入名称搜索..', + 'header.searchPlaceholder': '输入名称或mac搜索', // McpToolCallDialog组件文本 'mcpToolCall.title': '工具调用', diff --git a/main/manager-web/src/i18n/zh_TW.js b/main/manager-web/src/i18n/zh_TW.js index ca5a5221..c5ea5b19 100644 --- a/main/manager-web/src/i18n/zh_TW.js +++ b/main/manager-web/src/i18n/zh_TW.js @@ -25,7 +25,7 @@ export default { 'header.featureManagement': '系統功能配置', 'header.changePassword': '修改密碼', 'header.logout': '退出登錄', - 'header.searchPlaceholder': '輸入名稱搜索..', + 'header.searchPlaceholder': '輸入名稱或mac搜索', // McpToolCallDialog组件文本 'mcpToolCall.title': '工具調用', diff --git a/main/manager-web/src/views/home.vue b/main/manager-web/src/views/home.vue index fea5af89..07d46f01 100644 --- a/main/manager-web/src/views/home.vue +++ b/main/manager-web/src/views/home.vue @@ -119,26 +119,32 @@ export default { handleDeviceManage() { this.$router.push('/device-management'); }, - handleSearch(regex) { + handleSearch(keyword) { this.isSearching = true; - this.searchRegex = regex; - this.applySearchFilter(); + this.isLoading = true; + // 检测MAC地址格式:包含4个冒号 + const isMac = /^([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}$/.test(keyword) + const searchType = isMac ? 'mac' : 'name'; + Api.agent.searchAgent(keyword, searchType, ({ data }) => { + if (data?.data) { + this.devices = data.data.map(item => ({ + ...item, + agentId: item.id + })); + } + this.isLoading = false; + }, (error) => { + console.error('搜索智能体失败:', error); + this.isLoading = false; + this.$message.error(this.$t('message.searchFailed')); + }); }, handleSearchReset() { this.isSearching = false; - this.searchRegex = null; + // 直接将原始设备列表赋值给显示设备列表,避免重新加载数据 this.devices = [...this.originalDevices]; }, - applySearchFilter() { - if (!this.isSearching || !this.searchRegex) { - this.devices = [...this.originalDevices]; - return; - } - this.devices = this.originalDevices.filter(device => { - return this.searchRegex.test(device.agentName); - }); - }, // 搜索更新智能体列表 handleSearchResult(filteredList) { this.devices = filteredList; // 更新设备列表