diff --git a/main/manager-api/src/main/java/xiaozhi/common/utils/ResultUtils.java b/main/manager-api/src/main/java/xiaozhi/common/utils/ResultUtils.java new file mode 100644 index 00000000..3f9fe27d --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/common/utils/ResultUtils.java @@ -0,0 +1,31 @@ +package xiaozhi.common.utils; + +/** + * 返回响应体工具类 + */ +public class ResultUtils +{ + public static Result success(T data) { + return new Result().ok(data); + } + + public static Result error() { + return new Result().error(); + } + + public static Result error(String msg) { + return new Result().error(msg); + } + + public static Result error(int errorCode, String msg) { + return new Result().error(errorCode, msg); + } + + public static Result error(int errorCode) { + return new Result().error(errorCode); + } + + public static Result empty() { + return new Result(); + } +} 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 54f3fa8c..c9cefce8 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 @@ -4,6 +4,7 @@ import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; @@ -34,7 +35,9 @@ import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.user.UserDetail; import xiaozhi.common.utils.ConvertUtils; +import xiaozhi.common.utils.JsonUtils; import xiaozhi.common.utils.Result; +import xiaozhi.common.utils.ResultUtils; import xiaozhi.modules.agent.dto.AgentChatHistoryDTO; import xiaozhi.modules.agent.dto.AgentChatSessionDTO; import xiaozhi.modules.agent.dto.AgentCreateDTO; @@ -42,13 +45,14 @@ import xiaozhi.modules.agent.dto.AgentDTO; import xiaozhi.modules.agent.dto.AgentMemoryDTO; import xiaozhi.modules.agent.dto.AgentUpdateDTO; import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.entity.AgentPluginMapping; import xiaozhi.modules.agent.entity.AgentTemplateEntity; -import xiaozhi.modules.agent.service.AgentChatAudioService; -import xiaozhi.modules.agent.service.AgentChatHistoryService; -import xiaozhi.modules.agent.service.AgentService; -import xiaozhi.modules.agent.service.AgentTemplateService; +import xiaozhi.modules.agent.service.*; +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.service.ModelProviderService; import xiaozhi.modules.security.user.SecurityUser; @Tag(name = "智能体管理") @@ -88,9 +92,9 @@ public class AgentController { @GetMapping("/{id}") @Operation(summary = "获取智能体详情") @RequiresPermissions("sys:role:normal") - public Result getAgentById(@PathVariable("id") String id) { - AgentEntity agent = agentService.getAgentById(id); - return new Result().ok(agent); + public Result getAgentById(@PathVariable("id") String id) { + AgentInfoVO agent = agentService.getAgentById(id); + return ResultUtils.success(agent); } @PostMapping @@ -138,88 +142,19 @@ public class AgentController { } AgentUpdateDTO agentUpdateDTO = new AgentUpdateDTO(); agentUpdateDTO.setSummaryMemory(dto.getSummaryMemory()); - return updateAgentById(device.getAgentId(), agentUpdateDTO); + agentService.updateAgentById(device.getAgentId(), agentUpdateDTO); + return new Result<>(); } @PutMapping("/{id}") @Operation(summary = "更新智能体") @RequiresPermissions("sys:role:normal") public Result update(@PathVariable String id, @RequestBody @Valid AgentUpdateDTO dto) { - return updateAgentById(id, dto); - } - - private Result updateAgentById(String id, AgentUpdateDTO dto) { - // 先查询现有实体 - AgentEntity existingEntity = agentService.getAgentById(id); - if (existingEntity == null) { - return new Result().error("智能体不存在"); - } - - // 只更新提供的非空字段 - if (dto.getAgentName() != null) { - existingEntity.setAgentName(dto.getAgentName()); - } - if (dto.getAgentCode() != null) { - existingEntity.setAgentCode(dto.getAgentCode()); - } - if (dto.getAsrModelId() != null) { - existingEntity.setAsrModelId(dto.getAsrModelId()); - } - if (dto.getVadModelId() != null) { - existingEntity.setVadModelId(dto.getVadModelId()); - } - if (dto.getLlmModelId() != null) { - existingEntity.setLlmModelId(dto.getLlmModelId()); - } - if (dto.getTtsModelId() != null) { - existingEntity.setTtsModelId(dto.getTtsModelId()); - } - if (dto.getTtsVoiceId() != null) { - existingEntity.setTtsVoiceId(dto.getTtsVoiceId()); - } - if (dto.getMemModelId() != null) { - existingEntity.setMemModelId(dto.getMemModelId()); - } - if (dto.getIntentModelId() != null) { - existingEntity.setIntentModelId(dto.getIntentModelId()); - } - if (dto.getSystemPrompt() != null) { - existingEntity.setSystemPrompt(dto.getSystemPrompt()); - } - if (dto.getSummaryMemory() != null) { - existingEntity.setSummaryMemory(dto.getSummaryMemory()); - } - if (dto.getChatHistoryConf() != null) { - existingEntity.setChatHistoryConf(dto.getChatHistoryConf()); - } - if (dto.getLangCode() != null) { - existingEntity.setLangCode(dto.getLangCode()); - } - if (dto.getLanguage() != null) { - existingEntity.setLanguage(dto.getLanguage()); - } - if (dto.getSort() != null) { - existingEntity.setSort(dto.getSort()); - } - - // 设置更新者信息 - UserDetail user = SecurityUser.getUser(); - existingEntity.setUpdater(user.getId()); - existingEntity.setUpdatedAt(new Date()); - - // 更新记忆策略 - if (existingEntity.getMemModelId() == null || existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) { - // 删除所有记录 - agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, true); - existingEntity.setSummaryMemory(""); - } else if (existingEntity.getChatHistoryConf() != null && existingEntity.getChatHistoryConf() == 1) { - // 删除音频数据 - agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false); - } - agentService.updateById(existingEntity); + agentService.updateAgentById(id, dto); return new Result<>(); } + @DeleteMapping("/{id}") @Operation(summary = "删除智能体") @RequiresPermissions("sys:role:normal") diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java index 3b4be452..03e569cd 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentDao.java @@ -6,6 +6,7 @@ import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Select; import xiaozhi.common.dao.BaseDao; import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.vo.AgentInfoVO; @Mapper public interface AgentDao extends BaseDao { @@ -28,4 +29,11 @@ public interface AgentDao extends BaseDao { " WHERE d.mac_address = #{macAddress} " + " ORDER BY d.id DESC LIMIT 1") AgentEntity getDefaultAgentByMacAddress(@Param("macAddress") String macAddress); + + /** + * 根据id查询agent信息,包括插件信息 + * + * @param agentId 智能体ID + */ + AgentInfoVO selectAgentInfoById(@Param("agentId") String agentId); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentPluginMappingMapper.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentPluginMappingMapper.java new file mode 100644 index 00000000..2fe81753 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentPluginMappingMapper.java @@ -0,0 +1,22 @@ +package xiaozhi.modules.agent.dao; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import xiaozhi.modules.agent.entity.AgentPluginMapping; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +import java.util.List; + +/** +* @description 针对表【ai_agent_plugin_mapping(Agent与插件的唯一映射表)】的数据库操作Mapper +* @createDate 2025-05-25 22:33:17 +* @Entity xiaozhi.modules.agent.entity.AgentPluginMapping +*/ +@Mapper +public interface AgentPluginMappingMapper extends BaseMapper { + List selectPluginsByAgentId(@Param("agentId") String agentId); +} + + + + diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java index ccfbd53f..dabcf322 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java @@ -1,6 +1,9 @@ package xiaozhi.modules.agent.dto; +import java.io.Serial; import java.io.Serializable; +import java.util.HashMap; +import java.util.List; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; @@ -15,49 +18,63 @@ import lombok.Data; public class AgentUpdateDTO implements Serializable { private static final long serialVersionUID = 1L; - @Schema(description = "智能体编码", example = "AGT_1234567890", required = false) + @Schema(description = "智能体编码", example = "AGT_1234567890", nullable = true) private String agentCode; - @Schema(description = "智能体名称", example = "客服助手", required = false) + @Schema(description = "智能体名称", example = "客服助手", nullable = true) private String agentName; - @Schema(description = "语音识别模型标识", example = "asr_model_02", required = false) + @Schema(description = "语音识别模型标识", example = "asr_model_02", nullable = true) private String asrModelId; - @Schema(description = "语音活动检测标识", example = "vad_model_02", required = false) + @Schema(description = "语音活动检测标识", example = "vad_model_02", nullable = true) private String vadModelId; - @Schema(description = "大语言模型标识", example = "llm_model_02", required = false) + @Schema(description = "大语言模型标识", example = "llm_model_02", nullable = true) private String llmModelId; - @Schema(description = "语音合成模型标识", example = "tts_model_02", required = false) + @Schema(description = "语音合成模型标识", example = "tts_model_02", nullable = true) private String ttsModelId; - @Schema(description = "音色标识", example = "voice_02", required = false) + @Schema(description = "音色标识", example = "voice_02", nullable = true) private String ttsVoiceId; - @Schema(description = "记忆模型标识", example = "mem_model_02", required = false) + @Schema(description = "记忆模型标识", example = "mem_model_02", nullable = true) private String memModelId; - @Schema(description = "意图模型标识", example = "intent_model_02", required = false) + @Schema(description = "意图模型标识", example = "intent_model_02", nullable = true) private String intentModelId; - @Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助", required = false) + @Schema(description = "插件函数信息", nullable = true) + private List functions; + + @Schema(description = "角色设定参数", example = "你是一个专业的客服助手,负责回答用户问题并提供帮助", nullable = true) private String systemPrompt; - @Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" + - "根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", required = false) + @Schema(description = "总结记忆", example = "构建可生长的动态记忆网络,在有限空间内保留关键信息的同时,智能维护信息演变轨迹\n" + "根据对话记录,总结user的重要信息,以便在未来的对话中提供更个性化的服务", nullable = true) private String summaryMemory; - @Schema(description = "聊天记录配置(0不记录 1仅记录文本 2记录文本和语音)", example = "3", required = false) + @Schema(description = "聊天记录配置(0不记录 1仅记录文本 2记录文本和语音)", example = "3", nullable = true) private Integer chatHistoryConf; - @Schema(description = "语言编码", example = "zh_CN", required = false) + @Schema(description = "语言编码", example = "zh_CN", nullable = true) private String langCode; - @Schema(description = "交互语种", example = "中文", required = false) + @Schema(description = "交互语种", example = "中文", nullable = true) private String language; - @Schema(description = "排序", example = "1", required = false) + @Schema(description = "排序", example = "1", nullable = true) private Integer sort; + + @Data + @Schema(description = "插件函数信息") + public static class FunctionInfo implements Serializable { + @Schema(description = "插件ID", example = "plugin_01") + private String pluginId; + + @Schema(description = "函数参数信息", nullable = true) + private HashMap paramInfo; + + private static final long serialVersionUID = 1L; + } } \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentPluginMapping.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentPluginMapping.java new file mode 100644 index 00000000..d0597590 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentPluginMapping.java @@ -0,0 +1,53 @@ +package xiaozhi.modules.agent.entity; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import java.io.Serializable; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * Agent与插件的唯一映射表 + * @TableName ai_agent_plugin_mapping + */ +@Data +@TableName(value ="ai_agent_plugin_mapping") +@Schema(description = "Agent与插件的唯一映射表") +public class AgentPluginMapping implements Serializable { + /** + * 主键 + */ + @TableId(type = IdType.ASSIGN_ID) + @Schema(description = "映射信息主键ID") + private Long id; + + /** + * 智能体ID + */ + @Schema(description = "智能体ID") + private String agentId; + + /** + * 插件ID + */ + @Schema(description = "插件ID") + private String pluginId; + + /** + * 插件参数(Json)格式 + */ + @Schema(description = "插件参数(Json)格式") + private String paramInfo; + + + // 冗余字段,用于方便在根据id查询插件时,对照查出插件的Provider_code,详见dao层xml文件 + @TableField(exist = false) + @Schema(description = "插件provider_code, 对应表ai_model_provider") + private String providerCode; + + @TableField(exist = false) + private static final long serialVersionUID = 1L; +} \ No newline at end of file diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentPluginMappingService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentPluginMappingService.java new file mode 100644 index 00000000..c2de4ea6 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentPluginMappingService.java @@ -0,0 +1,15 @@ +package xiaozhi.modules.agent.service; + +import xiaozhi.modules.agent.entity.AgentPluginMapping; +import com.baomidou.mybatisplus.extension.service.IService; + +import java.util.List; + +/** +* @description 针对表【ai_agent_plugin_mapping(Agent与插件的唯一映射表)】的数据库操作Service +* @createDate 2025-05-25 22:33:17 +*/ +public interface AgentPluginMappingService extends IService { + + List agentPluginParamsByAgentId(String agentId); +} 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 2104d353..990ac61e 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 @@ -6,7 +6,9 @@ import java.util.Map; import xiaozhi.common.page.PageData; import xiaozhi.common.service.BaseService; import xiaozhi.modules.agent.dto.AgentDTO; +import xiaozhi.modules.agent.dto.AgentUpdateDTO; import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.vo.AgentInfoVO; /** * 智能体表处理service @@ -30,7 +32,7 @@ public interface AgentService extends BaseService { * @param id 智能体ID * @return 智能体实体 */ - AgentEntity getAgentById(String id); + AgentInfoVO getAgentById(String id); /** * 插入智能体 @@ -79,4 +81,6 @@ public interface AgentService extends BaseService { * @return 是否有权限 */ boolean checkAgentPermission(String agentId, Long userId); + + void updateAgentById(String agentId, AgentUpdateDTO dto); } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentPluginMappingServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentPluginMappingServiceImpl.java new file mode 100644 index 00000000..38d01915 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentPluginMappingServiceImpl.java @@ -0,0 +1,32 @@ +package xiaozhi.modules.agent.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import xiaozhi.modules.agent.entity.AgentPluginMapping; +import xiaozhi.modules.agent.service.AgentPluginMappingService; +import xiaozhi.modules.agent.dao.AgentPluginMappingMapper; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** +* @description 针对表【ai_agent_plugin_mapping(Agent与插件的唯一映射表)】的数据库操作Service实现 +* @createDate 2025-05-25 22:33:17 +*/ +@Service +@RequiredArgsConstructor +public class AgentPluginMappingServiceImpl extends ServiceImpl + implements AgentPluginMappingService{ + private final AgentPluginMappingMapper agentPluginMappingMapper; + + @Override + public List agentPluginParamsByAgentId(String agentId) { + return agentPluginMappingMapper.selectPluginsByAgentId(agentId); + } + +} + + + + 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 37bb7d93..4fb4e09c 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 @@ -1,10 +1,11 @@ package xiaozhi.modules.agent.service.impl; -import java.util.List; -import java.util.Map; -import java.util.UUID; +import java.util.*; +import java.util.function.Function; import java.util.stream.Collectors; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -13,17 +14,29 @@ import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import lombok.AllArgsConstructor; +import org.springframework.transaction.annotation.Transactional; import xiaozhi.common.constant.Constant; +import xiaozhi.common.exception.RenException; import xiaozhi.common.page.PageData; import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.service.impl.BaseServiceImpl; +import xiaozhi.common.user.UserDetail; +import xiaozhi.common.utils.JsonUtils; +import xiaozhi.common.utils.Result; import xiaozhi.modules.agent.dao.AgentDao; import xiaozhi.modules.agent.dto.AgentDTO; +import xiaozhi.modules.agent.dto.AgentUpdateDTO; import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.entity.AgentPluginMapping; +import xiaozhi.modules.agent.service.AgentChatHistoryService; +import xiaozhi.modules.agent.service.AgentPluginMappingService; import xiaozhi.modules.agent.service.AgentService; +import xiaozhi.modules.agent.vo.AgentInfoVO; import xiaozhi.modules.device.service.DeviceService; +import xiaozhi.modules.model.dto.ModelProviderDTO; import xiaozhi.modules.model.service.ModelConfigService; +import xiaozhi.modules.model.service.ModelProviderService; import xiaozhi.modules.security.user.SecurityUser; import xiaozhi.modules.sys.enums.SuperAdminEnum; import xiaozhi.modules.timbre.service.TimbreService; @@ -36,6 +49,10 @@ public class AgentServiceImpl extends BaseServiceImpl imp private final ModelConfigService modelConfigService; private final RedisUtils redisUtils; private final DeviceService deviceService; + private final AgentPluginMappingService agentPluginMappingService; + private final ModelProviderService modelProviderService; + private final AgentChatHistoryService agentChatHistoryService; + @Override public PageData adminAgentList(Map params) { @@ -46,15 +63,20 @@ public class AgentServiceImpl extends BaseServiceImpl imp } @Override - public AgentEntity getAgentById(String id) { - AgentEntity agent = agentDao.selectById(id); - if (agent != null && agent.getMemModelId() != null && agent.getMemModelId().equals(Constant.MEMORY_NO_MEM)) { - agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.IGNORE.getCode()); - } else if (agent != null && agent.getMemModelId() != null - && !agent.getMemModelId().equals(Constant.MEMORY_NO_MEM) - && agent.getChatHistoryConf() == null) { - agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode()); + public AgentInfoVO getAgentById(String id) { + AgentInfoVO agent = agentDao.selectAgentInfoById(id); + + if (agent == null) { + throw new RenException("智能体不存在"); } + + if (agent.getMemModelId() != null && agent.getMemModelId().equals(Constant.MEMORY_NO_MEM)) { + agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.IGNORE.getCode()); + if (agent.getChatHistoryConf() == null) { + agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode()); + } + } + // 无需额外查询插件列表,已通过SQL查询出来 return agent; } @@ -164,4 +186,134 @@ public class AgentServiceImpl extends BaseServiceImpl imp // 检查是否是智能体的所有者 return userId.equals(agent.getUserId()); } + + // 根据id更新智能体信息 + @Override + @Transactional(rollbackFor = Exception.class) + public void updateAgentById(String agentId, AgentUpdateDTO dto) { + // 先查询现有实体 + AgentEntity existingEntity = this.getAgentById(agentId); + if (existingEntity == null) { + throw new RuntimeException("智能体不存在"); + } + + // 只更新提供的非空字段 + if (dto.getAgentName() != null) { + existingEntity.setAgentName(dto.getAgentName()); + } + if (dto.getAgentCode() != null) { + existingEntity.setAgentCode(dto.getAgentCode()); + } + if (dto.getAsrModelId() != null) { + existingEntity.setAsrModelId(dto.getAsrModelId()); + } + if (dto.getVadModelId() != null) { + existingEntity.setVadModelId(dto.getVadModelId()); + } + if (dto.getLlmModelId() != null) { + existingEntity.setLlmModelId(dto.getLlmModelId()); + } + if (dto.getTtsModelId() != null) { + existingEntity.setTtsModelId(dto.getTtsModelId()); + } + if (dto.getTtsVoiceId() != null) { + existingEntity.setTtsVoiceId(dto.getTtsVoiceId()); + } + if (dto.getMemModelId() != null) { + existingEntity.setMemModelId(dto.getMemModelId()); + } + if (dto.getIntentModelId() != null) { + existingEntity.setIntentModelId(dto.getIntentModelId()); + } + if (dto.getSystemPrompt() != null) { + existingEntity.setSystemPrompt(dto.getSystemPrompt()); + } + if (dto.getSummaryMemory() != null) { + existingEntity.setSummaryMemory(dto.getSummaryMemory()); + } + if (dto.getChatHistoryConf() != null) { + existingEntity.setChatHistoryConf(dto.getChatHistoryConf()); + } + if (dto.getLangCode() != null) { + existingEntity.setLangCode(dto.getLangCode()); + } + if (dto.getLanguage() != null) { + existingEntity.setLanguage(dto.getLanguage()); + } + if (dto.getSort() != null) { + existingEntity.setSort(dto.getSort()); + } + + // 更新函数插件信息 + List functions = dto.getFunctions(); + if (functions != null) { + // 1. 收集本次提交的 pluginId + // TODO: 提交的参数信息里,这里是允许为空,后续可以扩展required字段限制避免为空 + List newPluginIds = functions.stream() + .map(AgentUpdateDTO.FunctionInfo::getPluginId) + .toList(); + + // 2. 查询当前agent现有的所有映射 + List existing = agentPluginMappingService.list( + new QueryWrapper() + .eq("agent_id", agentId) + ); + Map existMap = existing.stream() + .collect(Collectors.toMap(AgentPluginMapping::getPluginId, Function.identity())); + + // 3. 构造所有要 保存或更新 的实体 + List allToPersist = functions.stream().map(info -> { + AgentPluginMapping m = new AgentPluginMapping(); + m.setAgentId(agentId); + m.setPluginId(info.getPluginId()); + m.setParamInfo(JsonUtils.toJsonString(info.getParamInfo())); + AgentPluginMapping old = existMap.get(info.getPluginId()); + if (old != null) { + // 已存在,设置id表示更新 + m.setId(old.getId()); + } + return m; + }).toList(); + + // 4. 拆分:已有ID的走更新,无ID的走插入 + List toUpdate = allToPersist.stream() + .filter(m -> m.getId() != null) + .toList(); + List toInsert = allToPersist.stream() + .filter(m -> m.getId() == null) + .toList(); + + if (!toUpdate.isEmpty()) { + agentPluginMappingService.updateBatchById(toUpdate); + } + if (!toInsert.isEmpty()) { + agentPluginMappingService.saveBatch(toInsert); + } + + // 5. 删除本次不在提交列表里的插件映射 + List toDelete = existing.stream() + .filter(old -> !newPluginIds.contains(old.getPluginId())) + .map(AgentPluginMapping::getId) + .toList(); + if (!toDelete.isEmpty()) { + agentPluginMappingService.removeBatchByIds(toDelete); + } + } + + // 设置更新者信息 + UserDetail user = SecurityUser.getUser(); + existingEntity.setUpdater(user.getId()); + existingEntity.setUpdatedAt(new Date()); + + // 更新记忆策略 + if (existingEntity.getMemModelId() == null || existingEntity.getMemModelId().equals(Constant.MEMORY_NO_MEM)) { + // 删除所有记录 + agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, true); + existingEntity.setSummaryMemory(""); + } else if (existingEntity.getChatHistoryConf() != null && existingEntity.getChatHistoryConf() == 1) { + // 删除音频数据 + agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false); + } + this.updateById(existingEntity); + } } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java new file mode 100644 index 00000000..d56c8bb4 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java @@ -0,0 +1,24 @@ +package xiaozhi.modules.agent.vo; + +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.entity.AgentPluginMapping; + +import java.util.List; + +/** + * Agent信息返回体VO + * 这里直接extend了Agent实体类AgentEntity,后续需要规范返回字段可以copy字段出来 + */ +@EqualsAndHashCode(callSuper = true) +@Data +public class AgentInfoVO extends AgentEntity +{ + @Schema(description = "插件列表Id") + @TableField(typeHandler = JacksonTypeHandler.class) + private List functions; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java b/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java index f83efb3a..f21795a3 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/controller/ConfigController.java @@ -27,7 +27,7 @@ public class ConfigController { private final ConfigService configService; @PostMapping("server-base") - @Operation(summary = "获取配置") + @Operation(summary = "服务端获取配置接口") public Result getConfig() { Object config = configService.getConfig(true); return new Result().ok(config); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index 592b3c1d..b8ab988a 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -1,9 +1,6 @@ package xiaozhi.modules.config.service.impl; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -16,7 +13,9 @@ import xiaozhi.common.redis.RedisKeys; import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.utils.JsonUtils; import xiaozhi.modules.agent.entity.AgentEntity; +import xiaozhi.modules.agent.entity.AgentPluginMapping; import xiaozhi.modules.agent.entity.AgentTemplateEntity; +import xiaozhi.modules.agent.service.AgentPluginMappingService; import xiaozhi.modules.agent.service.AgentService; import xiaozhi.modules.agent.service.AgentTemplateService; import xiaozhi.modules.config.service.ConfigService; @@ -39,6 +38,7 @@ public class ConfigServiceImpl implements ConfigService { private final AgentTemplateService agentTemplateService; private final RedisUtils redisUtils; private final TimbreService timbreService; + private final AgentPluginMappingService agentPluginMappingService; @Override public Object getConfig(Boolean isCache) { @@ -131,6 +131,19 @@ public class ConfigServiceImpl implements ConfigService { agent.setAsrModelId(null); } + // 添加函数调用参数信息 + if (!Objects.equals(agent.getIntentModelId(), "Intent_nointent")) { + String agentId = agent.getId(); + List pluginMappings = agentPluginMappingService.agentPluginParamsByAgentId(agentId); + if (pluginMappings != null && !pluginMappings.isEmpty()) { + Map pluginParams = new HashMap<>(); + for (AgentPluginMapping pluginMapping : pluginMappings) { + pluginParams.put(pluginMapping.getProviderCode(), pluginMapping.getParamInfo()); + } + result.put("plugins", pluginParams); + } + } + // 构建模块配置 buildModuleConfig( agent.getAgentName(), @@ -280,6 +293,7 @@ public class ConfigServiceImpl implements ConfigService { map.put("functions", functions); } } + System.out.println("map: " + map); } // 如果是LLM类型,且intentLLMModelId不为空,则添加附加模型 if ("LLM".equals(modelTypes[i]) && intentLLMModelId != null) { diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelProviderController.java b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelProviderController.java index fc534a0a..24a7c7ca 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelProviderController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/controller/ModelProviderController.java @@ -18,6 +18,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.AllArgsConstructor; import xiaozhi.common.page.PageData; import xiaozhi.common.utils.Result; +import xiaozhi.common.utils.ResultUtils; import xiaozhi.common.validator.group.UpdateGroup; import xiaozhi.modules.model.dto.ModelProviderDTO; import xiaozhi.modules.model.service.ModelProviderService; @@ -65,4 +66,10 @@ public class ModelProviderController { return new Result<>(); } + @GetMapping("/plugin/names") + @Tag(name = "获取插件名称列表") + public Result> getPluginNameList() { + return ResultUtils.success(modelProviderService.getPluginList()); + } + } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java index d41766f6..92a8da80 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/ModelProviderService.java @@ -1,5 +1,6 @@ package xiaozhi.modules.model.service; +import java.util.Collection; import java.util.List; import xiaozhi.common.page.PageData; @@ -9,6 +10,10 @@ public interface ModelProviderService { // List getModelNames(String modelType, String modelName); + List getPluginList(); + + List getPluginListByIds(Collection ids); + List getListByModelType(String modelType); ModelProviderDTO add(ModelProviderDTO modelProviderDTO); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java index ffeec288..392454a0 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/model/service/impl/ModelProviderServiceImpl.java @@ -1,10 +1,8 @@ package xiaozhi.modules.model.service.impl; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; @@ -32,6 +30,24 @@ public class ModelProviderServiceImpl extends BaseServiceImpl getPluginList() { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ModelProviderEntity::getModelType, "Plugin"); + List providerEntities = modelProviderDao.selectList(queryWrapper); + return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class); + } + + @Override + public List getPluginListByIds(Collection ids) { + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.in(ModelProviderEntity::getId, ids); + queryWrapper.eq(ModelProviderEntity::getModelType, "Plugin"); + List providerEntities = modelProviderDao.selectList(queryWrapper); + return ConvertUtils.sourceToTarget(providerEntities, ModelProviderDTO.class); + } + + @Override public List getListByModelType(String modelType) { diff --git a/main/manager-api/src/main/resources/db/changelog/202505232203.sql b/main/manager-api/src/main/resources/db/changelog/202505232203.sql new file mode 100644 index 00000000..6b0f03ee --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202505232203.sql @@ -0,0 +1,181 @@ +-- =============================== +-- 一、在ai_model_provider中插入plugin 记录 +-- =============================== +START TRANSACTION; + +-- 1. 天气查询 +INSERT INTO ai_model_provider (id, model_type, provider_code, name, fields, + sort, creator, create_date, updater, update_date) +VALUES ('SYSTEM_PLUGIN_WEATHER', + 'Plugin', + 'get_weather', + '天气查询', + JSON_ARRAY( + JSON_OBJECT( + 'key', 'api_key', + 'type', 'string', + 'label', '天气插件 API 密钥', + 'default', (SELECT param_value FROM sys_params WHERE param_code = 'plugins.get_weather.api_key') + ), + JSON_OBJECT( + 'key', 'default_location', + 'type', 'string', + 'label', '默认查询城市', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.get_weather.default_location') + ), + JSON_OBJECT( + 'key', 'api_host', + 'type', 'string', + 'label', '开发者 API Host', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.get_weather.api_host') + ) + ), + 10, 0, NOW(), 0, NOW()); + +-- 2. 新闻订阅 +INSERT INTO ai_model_provider (id, model_type, provider_code, name, fields, + sort, creator, create_date, updater, update_date) +VALUES ('SYSTEM_PLUGIN_NEWS', + 'Plugin', + 'get_news_from_newsnow', + '新闻订阅', + JSON_ARRAY( + JSON_OBJECT( + 'key', 'default_rss_url', + 'type', 'string', + 'label', '默认 RSS 源', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.get_news.default_rss_url') + ), + JSON_OBJECT( + 'key', 'category_urls', + 'type', 'json', + 'label', '分类 RSS 地址映射', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.get_news.category_urls') + ) + ), + 20, 0, NOW(), 0, NOW()); + +-- 3. HomeAssistant 状态查询 +INSERT INTO ai_model_provider (id, model_type, provider_code, name, fields, + sort, creator, create_date, updater, update_date) +VALUES ('SYSTEM_PLUGIN_HA_GET_STATE', + 'Plugin', + 'hass_get_state', + 'HomeAssistant 状态查询', + JSON_ARRAY( + JSON_OBJECT( + 'key', 'base_url', + 'type', 'string', + 'label', 'HA 服务器地址', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.base_url') + ), + JSON_OBJECT( + 'key', 'api_key', + 'type', 'string', + 'label', 'HA API 访问令牌', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.api_key') + ), + JSON_OBJECT( + 'key', 'devices', + 'type', 'array', + 'label', '设备列表(名称,实体ID;…)', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.devices') + ) + ), + 30, 0, NOW(), 0, NOW()); + +-- 4. HomeAssistant 状态写入 +INSERT INTO ai_model_provider (id, model_type, provider_code, name, fields, + sort, creator, create_date, updater, update_date) +VALUES ('SYSTEM_PLUGIN_HA_SET_STATE', + 'Plugin', + 'hass_set_state', + 'HomeAssistant 状态写入', + JSON_ARRAY( + JSON_OBJECT( + 'key', 'base_url', + 'type', 'string', + 'label', 'HA 服务器地址', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.base_url') + ), + JSON_OBJECT( + 'key', 'api_key', + 'type', 'string', + 'label', 'HA API 访问令牌', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.api_key') + ), + JSON_OBJECT( + 'key', 'devices', + 'type', 'array', + 'label', '设备列表(名称,实体ID;…)', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.home_assistant.devices') + ) + ), + 40, 0, NOW(), 0, NOW()); + +-- 5. 本地播放 +INSERT INTO ai_model_provider (id, model_type, provider_code, name, fields, + sort, creator, create_date, updater, update_date) +VALUES ('SYSTEM_PLUGIN_MUSIC', + 'Plugin', + 'play_music', + '本地播放', + JSON_ARRAY( + JSON_OBJECT( + 'key', 'music_dir', + 'type', 'string', + 'label', '音乐文件根目录', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.play_music.music_dir') + ), + JSON_OBJECT( + 'key', 'music_ext', + 'type', 'array', + 'label', '支持的文件后缀', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.play_music.music_ext') + ), + JSON_OBJECT( + 'key', 'refresh_time', + 'type', 'number', + 'label', '列表刷新间隔(秒)', + 'default', + (SELECT param_value FROM sys_params WHERE param_code = 'plugins.play_music.refresh_time') + ) + ), + 50, 0, NOW(), 0, NOW()); + + +-- =============================== +-- 二、删除sys_params中旧的plugins.*参数 +-- =============================== +DELETE +FROM sys_params +WHERE param_code LIKE 'plugins.%'; + + +-- =============================== +-- 三、添加智能体插件id字段 +-- =============================== +CREATE TABLE IF NOT EXISTS ai_agent_plugin_mapping +( + id BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键', + agent_id VARCHAR(32) NOT NULL COMMENT '智能体ID', + plugin_id VARCHAR(32) NOT NULL COMMENT '插件ID', + param_info JSON NOT NULL COMMENT '参数信息', + UNIQUE KEY uk_agent_provider (agent_id, plugin_id) +) COMMENT 'Agent与插件的唯一映射表'; + + +COMMIT; + 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 9d3808da..77b8d869 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 @@ -162,4 +162,11 @@ databaseChangeLog: changes: - sqlFile: encoding: utf8 - path: classpath:db/changelog/202505151451.sql \ No newline at end of file + path: classpath:db/changelog/202505151451.sql + - changeSet: + id: 202505232203 + author: CAIXYPROMISE + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202505232203.sql \ No newline at end of file diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml index 322ca172..0dc7deab 100644 --- a/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml +++ b/main/manager-api/src/main/resources/mapper/agent/AgentDao.xml @@ -5,4 +5,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/main/manager-api/src/main/resources/mapper/agent/AgentPluginMappingMapper.xml b/main/manager-api/src/main/resources/mapper/agent/AgentPluginMappingMapper.xml new file mode 100644 index 00000000..659fcd6e --- /dev/null +++ b/main/manager-api/src/main/resources/mapper/agent/AgentPluginMappingMapper.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + id,agent_id,plugin_id + + + + + + + diff --git a/main/manager-web/src/apis/module/model.js b/main/manager-web/src/apis/module/model.js index badf4174..7db2b288 100644 --- a/main/manager-web/src/apis/module/model.js +++ b/main/manager-web/src/apis/module/model.js @@ -305,4 +305,20 @@ export default { }) }).send() }, + // 获取插件列表 + getPluginFunctionList(params, callback) { + RequestService.sendRequest() + .url(`${getServiceUrl()}/models/provider/plugin/names`) + .method('GET') + .success((res) => { + RequestService.clearRequestTime() + callback(res) + }) + .networkFail((err) => { + this.$message.error(err.msg || '获取插件列表失败') + RequestService.reAjaxFun(() => { + this.getPluginFunctionList(params, callback) + }) + }).send() + } } diff --git a/main/manager-web/src/components/FunctionDialog.vue b/main/manager-web/src/components/FunctionDialog.vue index b4fec417..e1999cc7 100644 --- a/main/manager-web/src/components/FunctionDialog.vue +++ b/main/manager-web/src/components/FunctionDialog.vue @@ -16,15 +16,21 @@ 全选
-
- -
-
- {{ func.name }} +
+
+ +
+
+ {{ func.name }} +
+ + +
- - - +
+
+
@@ -36,26 +42,83 @@ 全选
-
- -
-
- {{ func.name }} +
+
+ +
+
+ {{ func.name }} +
+
+ +

参数配置 - {{ currentFunction.name }}

-
- - - - - -
+
+ + + + + + + + + + + + + + + + + + + + +
请选择已配置的功能进行参数设置
@@ -74,24 +137,19 @@ export default { functions: { type: Array, default: () => [] + }, + allFunctions: { + type: Array, + default: () => [] } }, data() { return { + textCache: {}, dialogVisible: this.value, selectedNames: [], currentFunction: null, modifiedFunctions: {}, - allFunctions: [ - {name: '天气', params: {city: '北京'}, description: '查看指定城市的天气情况'}, - {name: '新闻', params: {type: '科技'}, description: '获取最新科技类新闻资讯'}, - {name: '工具', params: {category: '常用'}, description: '提供常用工具集合'}, - {name: '退出', params: {}, description: '退出当前系统'}, - {name: '音乐', params: {genre: '流行'}, description: '播放流行音乐'}, - {name: '翻译', params: {from: '中文', to: '英文'}, description: '提供中英文互译功能'}, - {name: '计算', params: {precision: '2'}, description: '提供精确计算功能'}, - {name: '日历', params: {view: '月'}, description: '查看月历视图'} - ], functionColorMap: [ '#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEEAD', '#D4A5A5', '#A2836E' @@ -111,10 +169,37 @@ export default { } }, watch: { - value(newVal) { - this.dialogVisible = newVal; - if (newVal) { + currentFunction(newFn) { + if (!newFn) return; + // 对每个字段,如果是 array 或 json,就在 textCache 里生成初始字符串 + newFn.fieldsMeta.forEach(f => { + const v = newFn.params[f.key]; + if (f.type === 'array') { + this.$set(this.textCache, f.key, Array.isArray(v) ? v.join('\n') : ''); + } + else if (f.type === 'json') { + try { + this.$set(this.textCache, f.key, JSON.stringify(v ?? {}, null, 2)); + } catch { + this.$set(this.textCache, f.key, ''); + } + } + }); + }, + value(v) { + this.dialogVisible = v; + if (v) { + // 对话框打开时,初始化选中态 this.selectedNames = this.functions.map(f => f.name); + // 把后端传来的 this.functions(带 params)merge 到 allFunctions 上 + this.functions.forEach(saved => { + const idx = this.allFunctions.findIndex(f => f.name === saved.name); + if (idx >= 0) { + // 保留用户之前在 saved.params 上的改动 + this.allFunctions[idx].params = {...saved.params}; + } + }); + // 右侧默认指向第一个 this.currentFunction = this.selectedList[0] || null; } }, @@ -123,14 +208,33 @@ export default { } }, methods: { + flushArray(key) { + const text = this.textCache[key] || ''; + const arr = text + .split('\n') + .map(s => s.trim()) + .filter(Boolean); + this.handleParamChange(this.currentFunction, key, arr); + }, + + flushJson(field) { + const key = field.key; + if (!key) { + return; + } + console.log(field); + const text = this.textCache[key] || ''; + try { + const obj = JSON.parse(text); + this.handleParamChange(this.currentFunction, key, obj); + } catch { + this.$message.error(`${this.currentFunction.name}的${key}字段格式错误:JSON格式有误`); + } + }, handleFunctionClick(func) { if (this.selectedNames.includes(func.name)) { - this.loading = true; - setTimeout(() => { - const tempFunc = this.tempFunctions[func.name]; - this.currentFunction = tempFunc ? tempFunc : JSON.parse(JSON.stringify(func)); - this.loading = false; - }, 300); + const tempFunc = this.tempFunctions[func.name]; + this.currentFunction = tempFunc ? tempFunc : func; } }, handleParamChange(func, key, value) { @@ -185,11 +289,15 @@ export default { const selected = this.selectedList.map(f => { const modified = this.modifiedFunctions[f.name]; - return modified || f; - }).map(f => ({ - ...f, - params: JSON.parse(JSON.stringify(f.params)) - })); + return { + id: f.id, + name: f.name, + params: modified + ? {...modified.params} + : {...f.params} + } + }); + console.log(selected); this.$emit('update-functions', selected); this.dialogVisible = false; @@ -197,11 +305,17 @@ export default { // 通知父组件对话框已关闭且已保存 this.$emit('dialog-closed', true); }, - getFunctionColor(name) { const hash = [...name].reduce((acc, char) => acc + char.charCodeAt(0), 0); - return this.functionColorMap[hash % 7]; - } + return this.functionColorMap[hash % this.functionColorMap.length]; + }, + fieldRemark(field) { + let description = (field && field.label) ? field.label : ''; + if (field.default) { + description += `(默认值:${field.default})`; + } + return description; + }, } } @@ -209,7 +323,7 @@ export default {