Merge pull request #2794 from xinnan-tech/20260104SSL

拓展首页的搜索栏-支持同时搜索设备mac和智能体名字
This commit is contained in:
hrz
2026-01-05 16:54:20 +08:00
committed by GitHub
14 changed files with 140 additions and 61 deletions
@@ -73,9 +73,13 @@ public class AgentController {
@GetMapping("/list") @GetMapping("/list")
@Operation(summary = "获取用户智能体列表") @Operation(summary = "获取用户智能体列表")
@RequiresPermissions("sys:role:normal") @RequiresPermissions("sys:role:normal")
public Result<List<AgentDTO>> getUserAgents() { public Result<List<AgentDTO>> getUserAgents(
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "searchType", defaultValue = "name") String searchType) {
UserDetail user = SecurityUser.getUser(); UserDetail user = SecurityUser.getUser();
List<AgentDTO> agents = agentService.getUserAgents(user.getId());
// 直接调用整合后的getUserAgents方法,无需再区分搜索和普通查询
List<AgentDTO> agents = agentService.getUserAgents(user.getId(), keyword, searchType);
return new Result<List<AgentDTO>>().ok(agents); return new Result<List<AgentDTO>>().ok(agents);
} }
@@ -271,4 +275,6 @@ public class AgentController {
.body(audioData); .body(audioData);
} }
} }
@@ -1,6 +1,7 @@
package xiaozhi.modules.agent.dto; package xiaozhi.modules.agent.dto;
import java.util.Date; import java.util.Date;
import java.util.List;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
@@ -54,9 +54,11 @@ public interface AgentService extends BaseService<AgentEntity> {
* 获取用户智能体列表 * 获取用户智能体列表
* *
* @param userId 用户ID * @param userId 用户ID
* @param keyword 搜索关键词
* @param searchType 搜索类型(name - 按名称搜索,mac - 按MAC地址搜索)
* @return 智能体列表 * @return 智能体列表
*/ */
List<AgentDTO> getUserAgents(Long userId); List<AgentDTO> getUserAgents(Long userId, String keyword, String searchType);
/** /**
* 根据智能体ID获取设备数量 * 根据智能体ID获取设备数量
@@ -98,4 +100,6 @@ public interface AgentService extends BaseService<AgentEntity> {
* @return 创建的智能体ID * @return 创建的智能体ID
*/ */
String createAgent(AgentCreateDTO dto); String createAgent(AgentCreateDTO dto);
} }
@@ -42,6 +42,7 @@ import xiaozhi.modules.agent.service.AgentPluginMappingService;
import xiaozhi.modules.agent.service.AgentService; import xiaozhi.modules.agent.service.AgentService;
import xiaozhi.modules.agent.service.AgentTemplateService; import xiaozhi.modules.agent.service.AgentTemplateService;
import xiaozhi.modules.agent.vo.AgentInfoVO; import xiaozhi.modules.agent.vo.AgentInfoVO;
import xiaozhi.modules.device.entity.DeviceEntity;
import xiaozhi.modules.device.service.DeviceService; import xiaozhi.modules.device.service.DeviceService;
import xiaozhi.modules.model.dto.ModelProviderDTO; import xiaozhi.modules.model.dto.ModelProviderDTO;
import xiaozhi.modules.model.dto.VoiceDTO; import xiaozhi.modules.model.dto.VoiceDTO;
@@ -88,13 +89,13 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode()); agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode());
} }
} }
// 查询上下文源配置 // 查询上下文源配置
AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(id); AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(id);
if (contextProviderEntity != null) { if (contextProviderEntity != null) {
agent.setContextProviders(contextProviderEntity.getContextProviders()); agent.setContextProviders(contextProviderEntity.getContextProviders());
} }
// 无需额外查询插件列表,已通过SQL查询出来 // 无需额外查询插件列表,已通过SQL查询出来
return agent; return agent;
} }
@@ -127,38 +128,75 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
} }
@Override @Override
public List<AgentDTO> getUserAgents(Long userId) { public List<AgentDTO> getUserAgents(Long userId, String keyword, String searchType) {
QueryWrapper<AgentEntity> wrapper = new QueryWrapper<>(); QueryWrapper<AgentEntity> queryWrapper = new QueryWrapper<>();
wrapper.eq("user_id", userId); queryWrapper.eq("user_id", userId);
List<AgentEntity> 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());
// 获取 TTS 模型名称 // 如果有搜索关键词,根据搜索类型添加相应的查询条件
dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId())); if (StringUtils.isNotBlank(keyword)) {
if ("mac".equals(searchType)) {
// 按MAC地址搜索:先搜索设备,再获取对应的智能体
List<DeviceEntity> devices = deviceService.searchDevicesByMacAddress(keyword, userId);
// 获取 LLM 模型名称 if (!devices.isEmpty()) {
dto.setLlmModelName(modelConfigService.getModelNameById(agent.getLlmModelId())); // 获取设备对应的智能体ID列表
List<String> agentIds = devices.stream()
.map(DeviceEntity::getAgentId)
.distinct()
.collect(Collectors.toList());
// 获取 VLLM 模型名称 if (!agentIds.isEmpty()) {
dto.setVllmModelName(modelConfigService.getModelNameById(agent.getVllmModelId())); queryWrapper.in("id", agentIds);
} else {
return new ArrayList<>();
}
} else {
return new ArrayList<>();
}
} else {
// 按名称搜索
queryWrapper.like("agent_name", keyword);
}
}
// 获取记忆模型名称 // 执行查询
dto.setMemModelId(agent.getMemModelId()); List<AgentEntity> agentEntities = baseDao.selectList(queryWrapper);
// 获取 TTS 音色名称 // 转换为DTO并设置所有必要字段
dto.setTtsVoiceName(timbreModelService.getTimbreNameById(agent.getTtsVoiceId())); 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());
// 获取设备数量 // 获取 TTS 模型名称
dto.setDeviceCount(getDeviceCountByAgentId(agent.getId())); dto.setTtsModelName(modelConfigService.getModelNameById(agent.getTtsModelId()));
return dto;
}).collect(Collectors.toList()); // 获取 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 @Override
@@ -468,4 +506,5 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
agentPluginMappingService.saveBatch(toInsert); agentPluginMappingService.saveBatch(toInsert);
return entity.getId(); return entity.getId();
} }
}
}
@@ -108,4 +108,13 @@ public interface DeviceService extends BaseService<DeviceEntity> {
*/ */
String generateWebSocketToken(String clientId, String username) throws Exception; String generateWebSocketToken(String clientId, String username) throws Exception;
/**
* 根据MAC地址搜索设备
*
* @param macAddress MAC地址关键词
* @param userId 用户ID
* @return 设备列表
*/
List<DeviceEntity> searchDevicesByMacAddress(String macAddress, Long userId);
} }
@@ -496,6 +496,14 @@ public class DeviceServiceImpl extends BaseServiceImpl<DeviceDao, DeviceEntity>
redisUtils.delete(RedisKeys.getAgentDeviceCountById(dto.getAgentId())); redisUtils.delete(RedisKeys.getAgentDeviceCountById(dto.getAgentId()));
} }
@Override
public List<DeviceEntity> searchDevicesByMacAddress(String macAddress, Long userId) {
QueryWrapper<DeviceEntity> wrapper = new QueryWrapper<>();
wrapper.like("mac_address", macAddress);
wrapper.eq("user_id", userId);
return deviceDao.selectList(wrapper);
}
/** /**
* 生成MQTT密码签名 * 生成MQTT密码签名
* *
+16
View File
@@ -382,4 +382,20 @@ export default {
}); });
}).send(); }).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();
},
} }
+2 -12
View File
@@ -408,18 +408,8 @@ export default {
// 保存搜索历史 // 保存搜索历史
this.saveSearchHistory(searchValue); this.saveSearchHistory(searchValue);
try { // 触发搜索事件,将搜索关键词传递给父组件
// 创建不区分大小写的正则表达式 this.$emit("search", searchValue);
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,
});
}
// 搜索完成后让输入框失去焦点,从而触发blur事件隐藏搜索历史 // 搜索完成后让输入框失去焦点,从而触发blur事件隐藏搜索历史
if (this.$refs.searchInput) { if (this.$refs.searchInput) {
+1 -1
View File
@@ -25,7 +25,7 @@ export default {
'header.featureManagement': 'Systemfunktionsverwaltung', 'header.featureManagement': 'Systemfunktionsverwaltung',
'header.changePassword': 'Passwort ändern', 'header.changePassword': 'Passwort ändern',
'header.logout': 'Abmelden', 'header.logout': 'Abmelden',
'header.searchPlaceholder': 'Nach Namen suchen..', 'header.searchPlaceholder': 'Namen oder MAC suchen',
// McpToolCallDialog component text // McpToolCallDialog component text
'mcpToolCall.title': 'Werkzeugaufruf', 'mcpToolCall.title': 'Werkzeugaufruf',
+1 -1
View File
@@ -25,7 +25,7 @@ export default {
'header.featureManagement': 'System Feature Management', 'header.featureManagement': 'System Feature Management',
'header.changePassword': 'Change Password', 'header.changePassword': 'Change Password',
'header.logout': 'Logout', 'header.logout': 'Logout',
'header.searchPlaceholder': 'Search by name..', 'header.searchPlaceholder': 'Search name or mac',
// McpToolCallDialog component text // McpToolCallDialog component text
'mcpToolCall.title': 'Tool Call', 'mcpToolCall.title': 'Tool Call',
+1 -1
View File
@@ -25,7 +25,7 @@ export default {
'header.featureManagement': 'Cấu hình chức năng hệ thống', 'header.featureManagement': 'Cấu hình chức năng hệ thống',
'header.changePassword': 'Đổi mật khẩu', 'header.changePassword': 'Đổi mật khẩu',
'header.logout': 'Đăng xuất', '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 // McpToolCallDialog component text
'mcpToolCall.title': 'Gọi công cụ', 'mcpToolCall.title': 'Gọi công cụ',
+1 -1
View File
@@ -25,7 +25,7 @@ export default {
'header.featureManagement': '系统功能配置', 'header.featureManagement': '系统功能配置',
'header.changePassword': '修改密码', 'header.changePassword': '修改密码',
'header.logout': '退出登录', 'header.logout': '退出登录',
'header.searchPlaceholder': '输入名称搜索..', 'header.searchPlaceholder': '输入名称或mac搜索',
// McpToolCallDialog组件文本 // McpToolCallDialog组件文本
'mcpToolCall.title': '工具调用', 'mcpToolCall.title': '工具调用',
+1 -1
View File
@@ -25,7 +25,7 @@ export default {
'header.featureManagement': '系統功能配置', 'header.featureManagement': '系統功能配置',
'header.changePassword': '修改密碼', 'header.changePassword': '修改密碼',
'header.logout': '退出登錄', 'header.logout': '退出登錄',
'header.searchPlaceholder': '輸入名稱搜索..', 'header.searchPlaceholder': '輸入名稱或mac搜索',
// McpToolCallDialog组件文本 // McpToolCallDialog组件文本
'mcpToolCall.title': '工具調用', 'mcpToolCall.title': '工具調用',
+19 -13
View File
@@ -119,26 +119,32 @@ export default {
handleDeviceManage() { handleDeviceManage() {
this.$router.push('/device-management'); this.$router.push('/device-management');
}, },
handleSearch(regex) { handleSearch(keyword) {
this.isSearching = true; this.isSearching = true;
this.searchRegex = regex; this.isLoading = true;
this.applySearchFilter(); // 检测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() { handleSearchReset() {
this.isSearching = false; this.isSearching = false;
this.searchRegex = null; // 直接将原始设备列表赋值给显示设备列表,避免重新加载数据
this.devices = [...this.originalDevices]; 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) { handleSearchResult(filteredList) {
this.devices = filteredList; // 更新设备列表 this.devices = filteredList; // 更新设备列表