初始化
This commit is contained in:
32
easyflow-api/easyflow-api-admin/pom.xml
Normal file
32
easyflow-api/easyflow-api-admin/pom.xml
Normal file
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-api-admin</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-ai</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-job</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-common-captcha</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import tech.easyflow.ai.entity.BotCategory;
|
||||
import tech.easyflow.ai.service.BotCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* bot分类 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botCategory")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
||||
public BotCategoryController(BotCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,372 @@
|
||||
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.easyagents.core.model.chat.ChatModel;
|
||||
import com.easyagents.core.model.chat.ChatOptions;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import tech.easyflow.ai.easyagents.listener.PromptChoreChatStreamListener;
|
||||
import tech.easyflow.ai.entity.*;
|
||||
import tech.easyflow.ai.service.*;
|
||||
import tech.easyflow.ai.service.impl.BotServiceImpl;
|
||||
import tech.easyflow.common.audio.core.AudioServiceManager;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.core.chat.protocol.sse.ChatSseEmitter;
|
||||
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/bot")
|
||||
public class BotController extends BaseCurdController<BotService, Bot> {
|
||||
|
||||
private final ModelService modelService;
|
||||
private final BotWorkflowService botWorkflowService;
|
||||
private final BotDocumentCollectionService botDocumentCollectionService;
|
||||
private final BotMessageService botMessageService;
|
||||
@Resource
|
||||
private BotService botService;
|
||||
@Autowired
|
||||
@Qualifier("defaultCache") // 指定 Bean 名称
|
||||
private Cache<String, Object> cache;
|
||||
@Resource
|
||||
private AudioServiceManager audioServiceManager;
|
||||
|
||||
public BotController(BotService service, ModelService modelService, BotWorkflowService botWorkflowService,
|
||||
BotDocumentCollectionService botDocumentCollectionService, BotMessageService botMessageService) {
|
||||
super(service);
|
||||
this.modelService = modelService;
|
||||
this.botWorkflowService = botWorkflowService;
|
||||
this.botDocumentCollectionService = botDocumentCollectionService;
|
||||
this.botMessageService = botMessageService;
|
||||
}
|
||||
|
||||
@Resource
|
||||
private BotPluginService botPluginService;
|
||||
|
||||
@GetMapping("/generateConversationId")
|
||||
public Result<Long> generateConversationId() {
|
||||
long nextId = new SnowFlakeIDKeyGenerator().nextId();
|
||||
return Result.ok(nextId);
|
||||
}
|
||||
|
||||
@PostMapping("updateOptions")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateOptions(@JsonBody("id") BigInteger id,
|
||||
@JsonBody("options") Map<String, Object> options) {
|
||||
Bot aiBot = service.getById(id);
|
||||
Map<String, Object> existOptions = aiBot.getOptions();
|
||||
if (existOptions == null) {
|
||||
existOptions = new HashMap<>();
|
||||
}
|
||||
if (options != null) {
|
||||
existOptions.putAll(options);
|
||||
}
|
||||
aiBot.setOptions(existOptions);
|
||||
service.updateById(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("updateLlmOptions")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateLlmOptions(@JsonBody("id")
|
||||
BigInteger id, @JsonBody("llmOptions")
|
||||
Map<String, Object> llmOptions) {
|
||||
Bot aiBot = service.getById(id);
|
||||
Map<String, Object> existLlmOptions = aiBot.getModelOptions();
|
||||
if (existLlmOptions == null) {
|
||||
existLlmOptions = new HashMap<>();
|
||||
}
|
||||
if (llmOptions != null) {
|
||||
existLlmOptions.putAll(llmOptions);
|
||||
}
|
||||
aiBot.setModelOptions(existLlmOptions);
|
||||
service.updateById(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("voiceInput")
|
||||
@SaIgnore
|
||||
public Result<String> voiceInput(@RequestParam("audio")
|
||||
MultipartFile audioFile) {
|
||||
|
||||
String recognize = null;
|
||||
try {
|
||||
recognize = audioServiceManager.audioToText(audioFile.getInputStream());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return Result.ok("", recognize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理聊天请求的接口方法
|
||||
*
|
||||
* @param prompt 用户输入的聊天内容,必须提供
|
||||
* @param botId 聊天机器人的唯一标识符,必须提供
|
||||
* @param conversationId 会话ID,用于标识当前对话会话,必须提供
|
||||
* @param messages 历史消息,用于提供上下文,可选
|
||||
* @return 返回SseEmitter对象,用于服务器向客户端推送聊天响应数据
|
||||
*/
|
||||
@PostMapping("chat")
|
||||
@SaIgnore
|
||||
public SseEmitter chat(
|
||||
@JsonBody(value = "prompt", required = true) String prompt,
|
||||
@JsonBody(value = "botId", required = true) BigInteger botId,
|
||||
@JsonBody(value = "conversationId", required = true) BigInteger conversationId,
|
||||
@JsonBody(value = "messages") List<Map<String, String>> messages,
|
||||
@JsonBody(value = "attachments") List<String> attachments
|
||||
|
||||
) {
|
||||
BotServiceImpl.ChatCheckResult chatCheckResult = new BotServiceImpl.ChatCheckResult();
|
||||
|
||||
// 前置校验:失败则直接返回错误SseEmitter
|
||||
SseEmitter errorEmitter = botService.checkChatBeforeStart(botId, prompt, conversationId.toString(), chatCheckResult);
|
||||
if (errorEmitter != null) {
|
||||
return errorEmitter;
|
||||
}
|
||||
return botService.startChat(botId, prompt, conversationId, messages, chatCheckResult, attachments);
|
||||
}
|
||||
|
||||
@PostMapping("updateLlmId")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateBotLlmId(@RequestBody
|
||||
Bot aiBot) {
|
||||
service.updateBotLlmId(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("getDetail")
|
||||
@SaIgnore
|
||||
public Result<Bot> getDetail(String id) {
|
||||
return Result.ok(botService.getDetail(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SaIgnore
|
||||
public Result<Bot> detail(String id) {
|
||||
Bot data = botService.getDetail(id);
|
||||
if (data == null) {
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
Map<String, Object> llmOptions = data.getModelOptions();
|
||||
if (llmOptions == null) {
|
||||
llmOptions = new HashMap<>();
|
||||
}
|
||||
|
||||
if (data.getModelId() == null) {
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
BigInteger llmId = data.getModelId();
|
||||
Model llm = modelService.getById(llmId);
|
||||
|
||||
if (llm == null) {
|
||||
data.setModelId(null);
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
Map<String, Object> options = llm.getOptions();
|
||||
|
||||
if (options != null && !options.isEmpty()) {
|
||||
|
||||
// 获取是否多模态
|
||||
Boolean multimodal = (Boolean) options.get("multimodal");
|
||||
llmOptions.put("multimodal", multimodal != null && multimodal);
|
||||
|
||||
}
|
||||
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
||||
|
||||
String alias = entity.getAlias();
|
||||
|
||||
if (StringUtils.hasLength(alias)) {
|
||||
Bot aiBot = service.getByAlias(alias);
|
||||
|
||||
|
||||
if (aiBot != null && isSave) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
if (aiBot != null && aiBot.getId().compareTo(entity.getId()) != 0) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (isSave) {
|
||||
// 设置默认值
|
||||
entity.setModelOptions(getDefaultLlmOptions());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
private ChatOptions getChatOptions(Map<String, Object> llmOptions) {
|
||||
ChatOptions defaultOptions = new ChatOptions();
|
||||
if (llmOptions != null) {
|
||||
Object topK = llmOptions.get("topK");
|
||||
Object maxReplyLength = llmOptions.get("maxReplyLength");
|
||||
Object temperature = llmOptions.get("temperature");
|
||||
Object topP = llmOptions.get("topP");
|
||||
Object thinkingEnabled = llmOptions.get("thinkingEnabled");
|
||||
|
||||
if (topK != null) {
|
||||
defaultOptions.setTopK(Integer.parseInt(String.valueOf(topK)));
|
||||
}
|
||||
if (maxReplyLength != null) {
|
||||
defaultOptions.setMaxTokens(Integer.parseInt(String.valueOf(maxReplyLength)));
|
||||
}
|
||||
if (temperature != null) {
|
||||
defaultOptions.setTemperature(Float.parseFloat(String.valueOf(temperature)));
|
||||
}
|
||||
if (topP != null) {
|
||||
defaultOptions.setTopP(Float.parseFloat(String.valueOf(topP)));
|
||||
}
|
||||
if (thinkingEnabled != null) {
|
||||
defaultOptions.setThinkingEnabled(Boolean.parseBoolean(String.valueOf(thinkingEnabled)));
|
||||
}
|
||||
|
||||
}
|
||||
return defaultOptions;
|
||||
}
|
||||
|
||||
private Map<String, Object> getDefaultLlmOptions() {
|
||||
Map<String, Object> defaultLlmOptions = new HashMap<>();
|
||||
defaultLlmOptions.put("temperature", 0.7);
|
||||
defaultLlmOptions.put("topK", 4);
|
||||
defaultLlmOptions.put("maxReplyLength", 2048);
|
||||
defaultLlmOptions.put("topP", 0.7);
|
||||
defaultLlmOptions.put("maxMessageCount", 10);
|
||||
return defaultLlmOptions;
|
||||
}
|
||||
|
||||
private Map<String, Object> errorRespnseMsg(int errorCode, String message) {
|
||||
HashMap<String, Object> result = new HashMap<>();
|
||||
result.put("error", errorCode);
|
||||
result.put("message", message);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
QueryWrapper queryWrapperKnowledge = QueryWrapper.create().in(BotDocumentCollection::getBotId, ids);
|
||||
botDocumentCollectionService.remove(queryWrapperKnowledge);
|
||||
QueryWrapper queryWrapperBotWorkflow = QueryWrapper.create().in(BotWorkflow::getBotId, ids);
|
||||
botWorkflowService.remove(queryWrapperBotWorkflow);
|
||||
QueryWrapper queryWrapperBotPlugins = QueryWrapper.create().in(BotPlugin::getBotId, ids);
|
||||
botPluginService.remove(queryWrapperBotPlugins);
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统提示词优化
|
||||
*
|
||||
* @param prompt
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("prompt/chore/chat")
|
||||
@SaIgnore
|
||||
public SseEmitter chat(
|
||||
@JsonBody(value = "prompt", required = true) String prompt,
|
||||
@JsonBody(value = "botId", required = true) BigInteger botId
|
||||
){
|
||||
if (!StringUtils.hasLength(prompt)) {
|
||||
throw new BusinessException("提示词不能为空!");
|
||||
}
|
||||
String promptChore = "# 角色与目标\n" +
|
||||
"\n" +
|
||||
"你是一位专业的提示词工程师(Prompt Engineer)。你的任务是,分析我提供的“用户原始提示词”,并将其优化成一个结构清晰、指令明确、效果最优的“系统提示词(System Prompt)”。\n" +
|
||||
"\n" +
|
||||
"这个优化后的系统提示词将直接用于引导一个AI助手,使其能够精准、高效地完成用户的请求。\n" +
|
||||
"\n" +
|
||||
"# 优化指南 (请严格遵循)\n" +
|
||||
"\n" +
|
||||
"在优化过程中,请遵循以下原则,以确保最终提示词的质量:\n" +
|
||||
"\n" +
|
||||
"1. **角色定义 (Role Definition)**:\n" +
|
||||
" * 为AI助手明确一个具体、专业的角色。这个角色应该与任务高度相关。\n" +
|
||||
" * 例如:“你是一位资深的软件架构师”、“你是一位经验丰富的产品经理”。\n" +
|
||||
"\n" +
|
||||
"2. **任务与目标 (Task & Goal)**:\n" +
|
||||
" * 清晰、具体地描述AI需要完成的任务。\n" +
|
||||
" * 明确指出期望的最终输出是什么,以及输出的目标和用途。\n" +
|
||||
" * 避免模糊不清的指令。\n" +
|
||||
"\n" +
|
||||
"3. **输入输出格式 (Input/Output Format)**:\n" +
|
||||
" * 如果任务涉及到处理特定格式的数据,请明确说明输入数据的格式。\n" +
|
||||
" * **至关重要**:请为AI的输出指定一个清晰、结构化的格式。这能极大地提升结果的可用性。\n" +
|
||||
" * 例如:“请以Markdown表格的形式输出”、“请分点列出,每点不超过20字”。\n" +
|
||||
"\n" +
|
||||
"4. **背景与上下文 (Context & Background)**:\n" +
|
||||
" * 提供完成任务所必需的背景信息。\n" +
|
||||
" * 例如:项目的阶段、目标用户、使用的技术栈、相关的约束条件等。\n" +
|
||||
"\n" +
|
||||
"5. **语气与风格 (Tone & Style)**:\n" +
|
||||
" * 指定AI回答时应采用的语气和风格。\n" +
|
||||
" * 例如:“专业且简洁”、“通俗易懂,避免使用专业术语”。\n" +
|
||||
"\n" +
|
||||
"6. **约束与规则 (Constraints & Rules)**:\n" +
|
||||
" * 设定AI在回答时必须遵守的规则和限制。\n" +
|
||||
" * 例如:“回答必须基于提供的文档”、“禁止猜测用户未提及的信息”。\n" +
|
||||
"\n" +
|
||||
"7. **思考过程 (Chain-of-Thought)**:\n" +
|
||||
" * 对于复杂的推理任务,可以引导AI展示其思考过程。\n" +
|
||||
" * 例如:“请先分析问题的关键点,然后给出解决方案,并解释你的推理步骤。”\n" +
|
||||
"\n" +
|
||||
"# 输出要求\n" +
|
||||
"\n" +
|
||||
"请你直接输出优化后的完整系统提示词。不要包含任何额外的解释或说明。\n" +
|
||||
"\n" +
|
||||
"---\n" +
|
||||
"\n" +
|
||||
"## 用户原始提示词\n" +
|
||||
"[" + prompt + "]\n";
|
||||
Bot aiBot = service.getById(botId);
|
||||
if (aiBot == null) {
|
||||
return ChatSseUtil.sendSystemError(null, "聊天助手不存在");
|
||||
}
|
||||
ChatSseEmitter sseEmitter = new ChatSseEmitter();
|
||||
Model model = modelService.getModelInstance(aiBot.getModelId());
|
||||
if (model == null) {
|
||||
return ChatSseUtil.sendSystemError(null, "模型不存在");
|
||||
}
|
||||
ChatModel chatModel = model.toChatModel();
|
||||
if (chatModel == null) {
|
||||
return ChatSseUtil.sendSystemError(null, "模型不存在");
|
||||
}
|
||||
PromptChoreChatStreamListener promptChoreChatStreamListener = new PromptChoreChatStreamListener(sseEmitter);
|
||||
chatModel.chatStream(promptChore, promptChoreChatStreamListener);
|
||||
return sseEmitter.getEmitter();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.service.BotDocumentCollectionService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botKnowledge")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotDocumentCollectionController extends BaseCurdController<BotDocumentCollectionService, BotDocumentCollection> {
|
||||
public BotDocumentCollectionController(BotDocumentCollectionService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
@Override
|
||||
public Result<List<BotDocumentCollection>> list(BotDocumentCollection entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<BotDocumentCollection> botDocumentCollections = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
return Result.ok(botDocumentCollections);
|
||||
}
|
||||
|
||||
@PostMapping("updateBotKnowledgeIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("knowledgeIds") BigInteger [] knowledgeIds) {
|
||||
service.saveBotAndKnowledge(botId, knowledgeIds);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.ai.entity.BotMcp;
|
||||
import tech.easyflow.ai.service.BotMcpService;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2026-01-05
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botMcp")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotMcpController extends BaseCurdController<BotMcpService, BotMcp> {
|
||||
public BotMcpController(BotMcpService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("updateBotMcpToolIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId,
|
||||
@JsonBody("mcpSelectedData") List<Map<String, List<List<String>>>> mcpSelectedData) {
|
||||
service.updateBotMcpToolIds(botId, mcpSelectedData);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotMessage;
|
||||
import tech.easyflow.ai.service.BotMessageService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
/**
|
||||
* Bot 消息记录表 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-11-04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botMessage")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotMessageController extends BaseCurdController<BotMessageService, BotMessage> {
|
||||
|
||||
private final BotMessageService botMessageService;
|
||||
|
||||
public BotMessageController(BotMessageService service, BotMessageService botMessageService) {
|
||||
super(service);
|
||||
this.botMessageService = botMessageService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(BotMessage entity, boolean isSave) {
|
||||
entity.setAccountId(SaTokenUtil.getLoginAccount().getId());
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import tech.easyflow.ai.entity.BotModel;
|
||||
import tech.easyflow.ai.service.BotModelService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botLlm")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotModelController extends BaseCurdController<BotModelService, BotModel> {
|
||||
public BotModelController(BotModelService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.Plugin;
|
||||
import tech.easyflow.ai.entity.BotPlugin;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.ai.service.BotPluginService;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2025-04-07
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botPlugins")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotPluginController extends BaseCurdController<BotPluginService, BotPlugin> {
|
||||
|
||||
public BotPluginController(BotPluginService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private BotPluginService botPluginService;
|
||||
|
||||
@GetMapping("list")
|
||||
public Result<List<BotPlugin>> list(BotPlugin entity, Boolean asTree, String sortKey, String sortType){
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
|
||||
List<BotPlugin> botPlugins = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
|
||||
List<BotPlugin> list = Tree.tryToTree(botPlugins, asTree);
|
||||
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
@PostMapping("/getList")
|
||||
public Result<List<Plugin>> getList(@JsonBody(value = "botId", required = true) String botId){
|
||||
return Result.ok(botPluginService.getList(botId));
|
||||
}
|
||||
|
||||
@PostMapping("/getBotPluginToolIds")
|
||||
public Result<List<BigInteger>> getBotPluginToolIds(@JsonBody(value = "botId", required = true) String botId){
|
||||
return Result.ok(botPluginService.getBotPluginToolIds(botId));
|
||||
}
|
||||
|
||||
@PostMapping("/doRemove")
|
||||
public Result<Boolean> doRemove(@JsonBody(value = "botId", required = true) String botId,
|
||||
@JsonBody(value = "pluginToolId", required = true) String pluginToolId){
|
||||
return Result.ok(botPluginService.doRemove(botId, pluginToolId));
|
||||
}
|
||||
|
||||
@PostMapping("updateBotPluginToolIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("pluginToolIds") BigInteger [] pluginToolIds) {
|
||||
service.saveBotAndPluginTool(botId, pluginToolIds);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import tech.easyflow.ai.entity.BotRecentlyUsed;
|
||||
import tech.easyflow.ai.service.BotRecentlyUsedService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 最近使用 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botRecentlyUsed")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotRecentlyUsedController extends BaseCurdController<BotRecentlyUsedService, BotRecentlyUsed> {
|
||||
public BotRecentlyUsedController(BotRecentlyUsedService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.BotWorkflow;
|
||||
import tech.easyflow.ai.service.BotWorkflowService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-28
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/botWorkflow")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class BotWorkflowController extends BaseCurdController<BotWorkflowService, BotWorkflow> {
|
||||
public BotWorkflowController(BotWorkflowService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("list")
|
||||
@Override
|
||||
public Result<List<BotWorkflow>> list(BotWorkflow entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<BotWorkflow> botWorkflows = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
List<BotWorkflow> list = Tree.tryToTree(botWorkflows, asTree);
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
@PostMapping("updateBotWorkflowIds")
|
||||
public Result<?> save(@JsonBody("botId") BigInteger botId, @JsonBody("workflowIds") BigInteger [] workflowIds) {
|
||||
service.saveBotAndWorkflowTool(botId, workflowIds);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.core.model.embedding.EmbeddingModel;
|
||||
import tech.easyflow.ai.entity.DocumentChunk;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import tech.easyflow.ai.service.DocumentChunkService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.easyagents.core.store.DocumentStore;
|
||||
import com.easyagents.core.store.StoreOptions;
|
||||
import com.easyagents.core.store.StoreResult;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/documentChunk")
|
||||
@UsePermission(moduleName = "/api/v1/documentCollection")
|
||||
public class DocumentChunkController extends BaseCurdController<DocumentChunkService, DocumentChunk> {
|
||||
|
||||
@Resource
|
||||
DocumentCollectionService documentCollectionService;
|
||||
|
||||
@Resource
|
||||
ModelService modelService;
|
||||
|
||||
@Resource
|
||||
DocumentChunkService documentChunkService;
|
||||
|
||||
public DocumentChunkController(DocumentChunkService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@PostMapping("update")
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<?> update(@JsonBody DocumentChunk documentChunk) {
|
||||
boolean success = service.updateById(documentChunk);
|
||||
if (success){
|
||||
DocumentChunk record = documentChunkService.getById(documentChunk.getId());
|
||||
DocumentCollection knowledge = documentCollectionService.getById(record.getDocumentCollectionId());
|
||||
if (knowledge == null) {
|
||||
return Result.fail(1, "知识库不存在");
|
||||
}
|
||||
DocumentStore documentStore = knowledge.toDocumentStore();
|
||||
if (documentStore == null) {
|
||||
return Result.fail(2, "知识库没有配置向量库");
|
||||
}
|
||||
// 设置向量模型
|
||||
Model model = modelService.getModelInstance(knowledge.getVectorEmbedModelId());
|
||||
if (model == null) {
|
||||
return Result.fail(3, "知识库没有配置向量模型");
|
||||
}
|
||||
EmbeddingModel embeddingModel = model.toEmbeddingModel();
|
||||
documentStore.setEmbeddingModel(embeddingModel);
|
||||
StoreOptions options = StoreOptions.ofCollectionName(knowledge.getVectorStoreCollection());
|
||||
Document document = Document.of(documentChunk.getContent());
|
||||
document.setId(documentChunk.getId());
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.put("keywords", documentChunk.getMetadataKeyWords());
|
||||
metadata.put("questions", documentChunk.getMetadataQuestions());
|
||||
document.setMetadataMap(metadata);
|
||||
StoreResult result = documentStore.update(document, options); // 更新已有记录
|
||||
return Result.ok(result);
|
||||
}
|
||||
return Result.ok(false);
|
||||
}
|
||||
|
||||
@PostMapping("removeChunk")
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) BigInteger chunkId) {
|
||||
DocumentChunk docChunk = documentChunkService.getById(chunkId);
|
||||
if (docChunk == null) {
|
||||
return Result.fail(1, "记录不存在");
|
||||
}
|
||||
DocumentCollection knowledge = documentCollectionService.getById(docChunk.getDocumentCollectionId());
|
||||
if (knowledge == null) {
|
||||
return Result.fail(2, "知识库不存在");
|
||||
}
|
||||
DocumentStore documentStore = knowledge.toDocumentStore();
|
||||
if (documentStore == null) {
|
||||
return Result.fail(3, "知识库没有配置向量库");
|
||||
}
|
||||
// 设置向量模型
|
||||
Model model = modelService.getModelInstance(knowledge.getVectorEmbedModelId());
|
||||
if (model == null) {
|
||||
return Result.fail(4, "知识库没有配置向量模型");
|
||||
}
|
||||
EmbeddingModel embeddingModel = model.toEmbeddingModel();
|
||||
documentStore.setEmbeddingModel(embeddingModel);
|
||||
StoreOptions options = StoreOptions.ofCollectionName(knowledge.getVectorStoreCollection());
|
||||
List<BigInteger> deleteList = new ArrayList<>();
|
||||
deleteList.add(chunkId);
|
||||
documentStore.delete(deleteList, options);
|
||||
documentChunkService.removeChunk(knowledge, chunkId);
|
||||
|
||||
return super.remove(chunkId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollectionCategory;
|
||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
||||
import tech.easyflow.ai.mapper.DocumentCollectionMapper;
|
||||
import tech.easyflow.ai.service.DocumentCollectionCategoryService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2026-01-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/documentCollectionCategory")
|
||||
@UsePermission(moduleName = "/api/v1/documentCollection")
|
||||
public class DocumentCollectionCategoryController extends BaseCurdController<DocumentCollectionCategoryService, DocumentCollectionCategory> {
|
||||
|
||||
@Resource
|
||||
private DocumentCollectionMapper documentCollectionMapper;
|
||||
|
||||
public DocumentCollectionCategoryController(DocumentCollectionCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
ids.forEach(id -> {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create().eq(DocumentCollection::getCategoryId, id);
|
||||
List<DocumentCollection> documentCollections = documentCollectionMapper.selectListByQuery(queryWrapper);
|
||||
if (!documentCollections.isEmpty()) {
|
||||
throw new BusinessException("请先删除该分类下的所有知识库");
|
||||
}
|
||||
});
|
||||
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.core.document.Document;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.util.StringUtils;
|
||||
import tech.easyflow.ai.entity.BotDocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.service.BotDocumentCollectionService;
|
||||
import tech.easyflow.ai.service.DocumentChunkService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/documentCollection")
|
||||
public class DocumentCollectionController extends BaseCurdController<DocumentCollectionService, DocumentCollection> {
|
||||
|
||||
private final DocumentChunkService chunkService;
|
||||
private final ModelService llmService;
|
||||
|
||||
@Resource
|
||||
private BotDocumentCollectionService botDocumentCollectionService;
|
||||
|
||||
public DocumentCollectionController(DocumentCollectionService service, DocumentChunkService chunkService, ModelService llmService) {
|
||||
super(service);
|
||||
this.chunkService = chunkService;
|
||||
this.llmService = llmService;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(DocumentCollection entity, boolean isSave) {
|
||||
|
||||
String alias = entity.getAlias();
|
||||
|
||||
if (StringUtils.hasLength(alias)){
|
||||
DocumentCollection knowledge = service.getByAlias(alias);
|
||||
|
||||
if (knowledge != null && isSave){
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
if (knowledge != null && knowledge.getId().compareTo(entity.getId()) != 0){
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
} else {
|
||||
entity.setAlias(null);
|
||||
}
|
||||
|
||||
|
||||
if (isSave){
|
||||
Map<String, Object> options = new HashMap<>();
|
||||
if (entity.getSearchEngineEnable() == null){
|
||||
entity.setSearchEngineEnable(false);
|
||||
}
|
||||
options.put("canUpdateEmbeddingModel", true);
|
||||
entity.setOptions(options);
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@GetMapping("search")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
public Result<List<Document>> search(@RequestParam BigInteger knowledgeId, @RequestParam String keyword) {
|
||||
return Result.ok(service.search(knowledgeId, keyword));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Result<Void> onRemoveBefore(Collection<Serializable> ids) {
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.in(BotDocumentCollection::getId, ids);
|
||||
|
||||
boolean exists = botDocumentCollectionService.exists(queryWrapper);
|
||||
if (exists){
|
||||
throw new BusinessException("此知识库还关联着bot,请先取消关联!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<DocumentCollection> detail(String id) {
|
||||
return Result.ok(service.getDetail(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.entity.Document;
|
||||
import tech.easyflow.ai.entity.DocumentCollection;
|
||||
import tech.easyflow.ai.entity.DocumentCollectionSplitParams;
|
||||
import tech.easyflow.ai.service.DocumentChunkService;
|
||||
import tech.easyflow.ai.service.DocumentCollectionService;
|
||||
import tech.easyflow.ai.service.DocumentService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
import tech.easyflow.common.util.RequestUtil;
|
||||
import tech.easyflow.common.util.StringUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/document")
|
||||
@UsePermission(moduleName = "/api/v1/documentCollection")
|
||||
public class DocumentController extends BaseCurdController<DocumentService, Document> {
|
||||
|
||||
private final DocumentCollectionService knowledgeService;
|
||||
|
||||
|
||||
@Autowired
|
||||
private DocumentService documentService;
|
||||
|
||||
|
||||
@Value("${easyflow.storage.local.root}")
|
||||
private String fileUploadPath;
|
||||
|
||||
|
||||
public DocumentController(DocumentService service,
|
||||
DocumentCollectionService knowledgeService,
|
||||
DocumentChunkService documentChunkService, ModelService modelService) {
|
||||
super(service);
|
||||
this.knowledgeService = knowledgeService;
|
||||
}
|
||||
@PostMapping("removeDoc")
|
||||
@Transactional
|
||||
@SaCheckPermission("/api/v1/documentCollection/remove")
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) String id) {
|
||||
List<Serializable> ids = Collections.singletonList(id);
|
||||
Result<?> result = onRemoveBefore(ids);
|
||||
if (result != null) return result;
|
||||
boolean isSuccess = documentService.removeDoc(id);
|
||||
if (!isSuccess){
|
||||
return Result.ok(false);
|
||||
}
|
||||
boolean success = service.removeById(id);
|
||||
onRemoveAfter(ids);
|
||||
return Result.ok(success);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 查询所有所有数据
|
||||
*
|
||||
* @param entity
|
||||
* @param asTree
|
||||
* @param sortKey
|
||||
* @param sortType
|
||||
* @return 所有数据
|
||||
*/
|
||||
@GetMapping("list")
|
||||
@Override
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
public Result<List<Document>> list(Document entity, Boolean asTree, String sortKey, String sortType) {
|
||||
String kbSlug = RequestUtil.getParamAsString("id");
|
||||
if (StringUtil.noText(kbSlug)) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
|
||||
DocumentCollection knowledge = StringUtil.isNumeric(kbSlug)
|
||||
? knowledgeService.getById(kbSlug)
|
||||
: knowledgeService.getOne(QueryWrapper.create().eq(DocumentCollection::getSlug, kbSlug));
|
||||
|
||||
if (knowledge == null) {
|
||||
throw new BusinessException("知识库不存在");
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.eq(Document::getCollectionId, knowledge.getId());
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<Document> documents = service.list(queryWrapper);
|
||||
List<Document> list = Tree.tryToTree(documents, asTree);
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
@GetMapping("documentList")
|
||||
@SaCheckPermission("/api/v1/documentCollection/query")
|
||||
public Result<Page<Document>> documentList(@RequestParam(name="title", required = false) String fileName, @RequestParam(name="pageSize") int pageSize, @RequestParam(name = "pageNumber") int pageNumber) {
|
||||
String kbSlug = RequestUtil.getParamAsString("id");
|
||||
if (StringUtil.noText(kbSlug)) {
|
||||
throw new BusinessException("知识库id不能为空");
|
||||
}
|
||||
Page<Document> documentList = documentService.getDocumentList(kbSlug, pageSize, pageNumber,fileName);
|
||||
return Result.ok(documentList);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getDefaultOrderBy() {
|
||||
return "order_no asc";
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("update")
|
||||
@Override
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<Boolean> update(@JsonBody Document entity) {
|
||||
super.update(entity);
|
||||
return Result.ok(updatePosition(entity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 文本拆分/保存
|
||||
*
|
||||
*/
|
||||
@PostMapping(value = {"textSplit", "/saveText"})
|
||||
@SaCheckPermission("/api/v1/documentCollection/save")
|
||||
public Result<?> textSplit(@JsonBody DocumentCollectionSplitParams documentCollectionSplitParams) {
|
||||
return documentService.textSplit(documentCollectionSplitParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新 entity
|
||||
*
|
||||
* @param entity
|
||||
* @return Result
|
||||
*/
|
||||
private boolean updatePosition(Document entity) {
|
||||
Integer orderNo = entity.getOrderNo();
|
||||
if (orderNo != null) {
|
||||
if (orderNo <= 0) orderNo = 0;
|
||||
BigInteger knowledgeId = service.getById(entity.getId()).getCollectionId();
|
||||
List<Document> list = service.list(QueryWrapper.create()
|
||||
.eq(Document::getCollectionId, knowledgeId)
|
||||
.orderBy(getDefaultOrderBy())
|
||||
);
|
||||
|
||||
list.removeIf(item -> item.getId().equals(entity.getId()));
|
||||
if (orderNo >= list.size()) {
|
||||
list.add(entity);
|
||||
} else {
|
||||
list.add(orderNo, entity);
|
||||
}
|
||||
|
||||
List<Document> updateList = new ArrayList<>();
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
Document updateItem = new Document();
|
||||
updateItem.setId(list.get(i).getId());
|
||||
updateItem.setOrderNo(i);
|
||||
updateList.add(updateItem);
|
||||
}
|
||||
|
||||
service.updateBatch(updateList);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public String getRootPath() {
|
||||
if (StringUtil.hasText(this.fileUploadPath)) {
|
||||
return this.fileUploadPath;
|
||||
}
|
||||
ClassPathResource fileResource = new ClassPathResource("/");
|
||||
try {
|
||||
return new File(fileResource.getFile(), "/public").getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import tech.easyflow.ai.entity.DocumentHistory;
|
||||
import tech.easyflow.ai.service.DocumentHistoryService;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/documentHistory")
|
||||
public class DocumentHistoryController extends BaseCurdController<DocumentHistoryService, DocumentHistory> {
|
||||
public DocumentHistoryController(DocumentHistoryService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.servlet.HandlerMapping;
|
||||
import tech.easyflow.common.util.StringUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
|
||||
@RestController
|
||||
public class FilePreviewController {
|
||||
|
||||
// 定义图片存储的基础路径
|
||||
@Value("${easyflow.storage.local.root}")
|
||||
private String fileUploadPath;
|
||||
|
||||
@SaIgnore
|
||||
@GetMapping("/api/images/**")
|
||||
public ResponseEntity<byte[]> getImage(HttpServletRequest request) throws IOException {
|
||||
// 获取完整的路径
|
||||
String fullPath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||||
String basePath = "/api/images/";
|
||||
String filePath = fullPath.substring(basePath.length()-1);
|
||||
String imagePath = getRootPath() + filePath;
|
||||
File imageFile = new File(imagePath);
|
||||
|
||||
if (!imageFile.exists()) {
|
||||
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
|
||||
}
|
||||
|
||||
// 读取文件内容
|
||||
byte[] fileContent = Files.readAllBytes(imageFile.toPath());
|
||||
|
||||
// 返回文件内容
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_TYPE, getContentType(imageFile))
|
||||
.body(fileContent);
|
||||
}
|
||||
|
||||
// 根据文件扩展名获取 MIME 类型
|
||||
private String getContentType(File file) {
|
||||
String fileName = file.getName().toLowerCase();
|
||||
if (fileName.endsWith(".jpg") || fileName.endsWith(".jpeg")) {
|
||||
return "image/jpeg";
|
||||
} else if (fileName.endsWith(".png")) {
|
||||
return "image/png";
|
||||
} else if (fileName.endsWith(".gif")) {
|
||||
return "image/gif";
|
||||
}
|
||||
return "application/octet-stream"; // 默认类型
|
||||
}
|
||||
|
||||
public String getRootPath() {
|
||||
if (StringUtil.hasText(this.fileUploadPath)) {
|
||||
return this.fileUploadPath;
|
||||
}
|
||||
ClassPathResource fileResource = new ClassPathResource("/");
|
||||
try {
|
||||
return new File(fileResource.getFile(), "/public").getAbsolutePath();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotMcp;
|
||||
import tech.easyflow.ai.entity.Mcp;
|
||||
import tech.easyflow.ai.service.BotMcpService;
|
||||
import tech.easyflow.ai.service.McpService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2026-01-04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/mcp")
|
||||
public class McpController extends BaseCurdController<McpService, Mcp> {
|
||||
public McpController(McpService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private BotMcpService botMcpService;
|
||||
@Override
|
||||
public Result<?> save(Mcp entity) {
|
||||
return service.saveMcp(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<?> update(Mcp entity) {
|
||||
return service.updateMcp(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Result<?> remove(Serializable id) {
|
||||
service.removeMcp(id);
|
||||
botMcpService.remove(QueryWrapper.create().eq(BotMcp::getMcpId, id));
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Page<Mcp>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
Result<Page<Mcp>> page = super.page(request, sortKey, sortType, pageNumber, pageSize);
|
||||
return service.pageMcp(page);
|
||||
}
|
||||
|
||||
@PostMapping("/getMcpTools")
|
||||
public Result<Mcp> getMcpTools(@JsonBody("id") String id) {
|
||||
|
||||
return Result.ok(service.getMcpTools(id));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("pageTools")
|
||||
public Result<Page<Mcp>> pageTools(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
Page<Mcp> mcpPage = queryPage(new Page<>(pageNumber, pageSize), queryWrapper);
|
||||
|
||||
return Result.ok(service.pageTools(mcpPage));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import tech.easyflow.ai.entity.ModelProvider;
|
||||
import tech.easyflow.ai.entity.table.ModelTableDef;
|
||||
import tech.easyflow.ai.mapper.ModelMapper;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/model")
|
||||
public class ModelController extends BaseCurdController<ModelService, Model> {
|
||||
|
||||
public ModelController(ModelService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
ModelService modelService;
|
||||
|
||||
@Resource
|
||||
ModelMapper modelMapper;
|
||||
|
||||
@GetMapping("list")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
public Result<List<Model>> list(Model entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<Model> list = Tree.tryToTree(modelMapper.selectListWithRelationsByQuery(queryWrapper), asTree);
|
||||
list.forEach(item -> {
|
||||
String providerName = Optional.ofNullable(item.getModelProvider())
|
||||
.map(ModelProvider::getProviderName)
|
||||
.orElse("-");
|
||||
item.setTitle(providerName + "/" + item.getTitle());
|
||||
});
|
||||
return Result.ok(list);
|
||||
}
|
||||
|
||||
@GetMapping("getList")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
public Result<Map<String, Map<String, List<Model>>>> getList(Model entity) {
|
||||
return Result.ok(modelService.getList(entity));
|
||||
}
|
||||
|
||||
@PostMapping("/addAiLlm")
|
||||
@SaCheckPermission("/api/v1/model/save")
|
||||
public Result<Boolean> addAiLlm(Model entity) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
commonFiled(entity, account.getId(), account.getTenantId(), account.getDeptId());
|
||||
return Result.ok(modelService.addAiLlm(entity));
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("verifyLlmConfig")
|
||||
@SaCheckPermission("/api/v1/model/save")
|
||||
public Result<?> verifyLlmConfig(@RequestParam BigInteger id) {
|
||||
Model model = service.getModelInstance(id);
|
||||
return Result.ok(modelService.verifyModelConfig(model));
|
||||
}
|
||||
|
||||
@PostMapping("/removeByEntity")
|
||||
@SaCheckPermission("/api/v1/model/remove")
|
||||
public Result<?> removeByEntity(@RequestBody Model entity) {
|
||||
modelService.removeByEntity(entity);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/updateByEntity")
|
||||
@SaCheckPermission("/api/v1/model/save")
|
||||
public Result<?> updateByEntity(@RequestBody Model entity) {
|
||||
modelService.updateByEntity(entity);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/selectLlmByProviderCategory")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
public Result<Map<String, List<Model>>> selectLlmByProviderCategory(Model entity, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
BaseMapper<Model> mapper = service.getMapper();
|
||||
List<Model> totalList = mapper.selectListWithRelationsByQuery(queryWrapper);
|
||||
Map<String, List<Model>> groupList = totalList.stream().collect(Collectors.groupingBy(Model::getGroupName));
|
||||
return Result.ok(groupList);
|
||||
}
|
||||
|
||||
@GetMapping("/selectLlmByProviderAndModelType")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
public Result<Map<String, List<Model>>> selectLlmByProviderAndModelType(
|
||||
@RequestParam String modelType,
|
||||
@RequestParam BigInteger providerId,
|
||||
@RequestParam(required = false) String selectText
|
||||
) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.eq(Model::getProviderId, providerId);
|
||||
queryWrapper.eq(Model::getModelType, modelType);
|
||||
if (StringUtils.hasLength(selectText)) {
|
||||
queryWrapper.and(ModelTableDef.MODEL.TITLE.like(selectText).or(ModelTableDef.MODEL.MODEL_NAME.like(selectText)));
|
||||
}
|
||||
List<Model> totalList = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
|
||||
Map<String, List<Model>> groupList = totalList.stream().collect(Collectors.groupingBy(Model::getGroupName));
|
||||
return Result.ok(groupList);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 添加所有模型
|
||||
*
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("addAllLlm")
|
||||
public Result<?> addAllLlm(@JsonBody Model entity) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create().eq(Model::getProviderId, entity.getProviderId());
|
||||
service.update(entity, queryWrapper);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/selectLlmList")
|
||||
@SaCheckPermission("/api/v1/model/query")
|
||||
public Result<List<Model>> selectLlmList(Model entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<Model> totalList = Tree.tryToTree(modelMapper.selectListWithRelationsByQuery(queryWrapper), asTree);
|
||||
totalList.forEach(aiLlm -> {
|
||||
aiLlm.setTitle(aiLlm.getModelProvider().getProviderName() + "/" + aiLlm.getTitle());
|
||||
});
|
||||
return Result.ok(totalList);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Model entity, boolean isSave) {
|
||||
if (isSave) {
|
||||
entity.setWithUsed(true);
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("removeLlmByIds")
|
||||
@Transactional
|
||||
public Result<?> removeLlm(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
List<Serializable> ids = Collections.singletonList(id);
|
||||
QueryWrapper queryWrapper = QueryWrapper.create().in(Model::getId, ids);
|
||||
service.remove(queryWrapper);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.Model;
|
||||
import tech.easyflow.ai.entity.ModelProvider;
|
||||
import tech.easyflow.ai.service.ModelProviderService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author 12076
|
||||
* @since 2025-12-16
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/modelProvider")
|
||||
@UsePermission(moduleName = "/api/v1/model")
|
||||
public class ModelProviderController extends BaseCurdController<ModelProviderService, ModelProvider> {
|
||||
private final ModelService modelService;
|
||||
|
||||
public ModelProviderController(ModelProviderService service, ModelService modelService) {
|
||||
super(service);
|
||||
this.modelService = modelService;
|
||||
}
|
||||
|
||||
@Override
|
||||
@PostMapping("remove")
|
||||
@Transactional
|
||||
public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
|
||||
QueryWrapper modelQueryWrapper = QueryWrapper.create()
|
||||
.in(Model::getProviderId, id);
|
||||
if (modelService.count(modelQueryWrapper) > 0) {
|
||||
throw new BusinessException("Delete all child models before removing this Model Provider");
|
||||
}
|
||||
return Result.ok(service.removeById(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.PluginCategory;
|
||||
import tech.easyflow.ai.service.PluginCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2025-05-21
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/pluginCategory")
|
||||
@UsePermission(moduleName = "/api/v1/plugin")
|
||||
public class PluginCategoryController extends BaseCurdController<PluginCategoryService, PluginCategory> {
|
||||
public PluginCategoryController(PluginCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private PluginCategoryService pluginCategoryService;
|
||||
|
||||
@GetMapping("/doRemoveCategory")
|
||||
@SaCheckPermission("/api/v1/plugin/remove")
|
||||
public Result<Boolean> doRemoveCategory(@RequestParam("id") BigInteger id){
|
||||
|
||||
return Result.ok(pluginCategoryService.doRemoveCategory(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.entity.PluginCategory;
|
||||
import tech.easyflow.ai.entity.PluginCategoryMapping;
|
||||
import tech.easyflow.ai.service.PluginCategoryMappingService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2025-05-21
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/pluginCategoryMapping")
|
||||
public class PluginCategoryMappingController extends BaseCurdController<PluginCategoryMappingService, PluginCategoryMapping> {
|
||||
public PluginCategoryMappingController(PluginCategoryMappingService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private PluginCategoryMappingService relationService;
|
||||
|
||||
@PostMapping("/updateRelation")
|
||||
public Result<Boolean> updateRelation(
|
||||
@JsonBody(value="pluginId") BigInteger pluginId,
|
||||
@JsonBody(value="categoryIds") ArrayList<BigInteger> categoryIds
|
||||
){
|
||||
return Result.ok(relationService.updateRelation(pluginId, categoryIds));
|
||||
}
|
||||
|
||||
@GetMapping("/getPluginCategories")
|
||||
public Result<List<PluginCategory>> getPluginCategories(@RequestParam(value="pluginId") BigInteger pluginId
|
||||
){
|
||||
return Result.ok(relationService.getPluginCategories(pluginId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import tech.easyflow.ai.entity.Plugin;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.ai.service.PluginService;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author Administrator
|
||||
* @since 2025-04-25
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/plugin")
|
||||
public class PluginController extends BaseCurdController<PluginService, Plugin> {
|
||||
public PluginController(PluginService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
PluginService pluginService;
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Plugin entity, boolean isSave) {
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@PostMapping("/plugin/save")
|
||||
@SaCheckPermission("/api/v1/plugin/save")
|
||||
public Result<Boolean> savePlugin(@JsonBody Plugin plugin){
|
||||
|
||||
return Result.ok(pluginService.savePlugin(plugin));
|
||||
}
|
||||
|
||||
@PostMapping("/plugin/update")
|
||||
@SaCheckPermission("/api/v1/plugin/save")
|
||||
public Result<Boolean> updatePlugin(@JsonBody Plugin plugin){
|
||||
|
||||
return Result.ok(pluginService.updatePlugin(plugin));
|
||||
}
|
||||
|
||||
@PostMapping("/plugin/remove")
|
||||
@SaCheckPermission("/api/v1/plugin/remove")
|
||||
public Result<Boolean> removePlugin(@JsonBody(value = "id", required = true) String id){
|
||||
|
||||
return Result.ok(pluginService.removePlugin(id));
|
||||
}
|
||||
|
||||
@PostMapping("/getList")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<List<Plugin>> getList(){
|
||||
return Result.ok(pluginService.getList());
|
||||
}
|
||||
|
||||
@GetMapping("/pageByCategory")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<Page<Plugin>> pageByCategory(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize, int category) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
if (category == 0){
|
||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
|
||||
} else {
|
||||
return pluginService.pageByCategory(pageNumber, pageSize, category);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<Plugin> queryPage(Page<Plugin> page, QueryWrapper queryWrapper) {
|
||||
return service.getMapper().paginateWithRelations(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotPlugin;
|
||||
import tech.easyflow.ai.entity.PluginItem;
|
||||
import tech.easyflow.ai.service.BotPluginService;
|
||||
import tech.easyflow.ai.service.PluginItemService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author WangGangqiang
|
||||
* @since 2025-04-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/pluginItem")
|
||||
@UsePermission(moduleName = "/api/v1/plugin")
|
||||
public class PluginItemController extends BaseCurdController<PluginItemService, PluginItem> {
|
||||
public PluginItemController(PluginItemService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private PluginItemService pluginItemService;
|
||||
|
||||
@Resource
|
||||
private BotPluginService botPluginService;
|
||||
|
||||
@PostMapping("/tool/save")
|
||||
@SaCheckPermission("/api/v1/plugin/save")
|
||||
public Result<Boolean> savePlugin(@JsonBody PluginItem pluginItem){
|
||||
|
||||
return Result.ok(pluginItemService.savePluginTool(pluginItem));
|
||||
}
|
||||
|
||||
// 插件工具修改页面查询
|
||||
@PostMapping("/tool/search")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<?> searchPlugin(@JsonBody(value = "aiPluginToolId", required = true) BigInteger aiPluginToolId){
|
||||
return pluginItemService.searchPlugin(aiPluginToolId);
|
||||
}
|
||||
|
||||
@PostMapping("/toolsList")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<List<PluginItem>> searchPluginToolByPluginId(@JsonBody(value = "pluginId", required = true) BigInteger pluginId,
|
||||
@JsonBody(value = "botId", required = false) BigInteger botId){
|
||||
return Result.ok(pluginItemService.searchPluginToolByPluginId(pluginId, botId));
|
||||
}
|
||||
|
||||
@PostMapping("/tool/update")
|
||||
@SaCheckPermission("/api/v1/plugin/save")
|
||||
public Result<Boolean> updatePlugin(@JsonBody PluginItem pluginItem){
|
||||
return Result.ok(pluginItemService.updatePlugin(pluginItem));
|
||||
}
|
||||
|
||||
@PostMapping("/tool/list")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<List<PluginItem>> getPluginToolList(@JsonBody(value = "botId", required = true) BigInteger botId){
|
||||
return Result.ok(pluginItemService.getPluginToolList(botId));
|
||||
}
|
||||
|
||||
@GetMapping("/getTinyFlowData")
|
||||
@SaCheckPermission("/api/v1/plugin/query")
|
||||
public Result<?> getTinyFlowData(BigInteger id) {
|
||||
JSONObject nodeData = new JSONObject();
|
||||
PluginItem record = pluginItemService.getById(id);
|
||||
if (record == null) {
|
||||
return Result.ok(nodeData);
|
||||
}
|
||||
nodeData.put("pluginId", record.getId().toString());
|
||||
nodeData.put("pluginName", record.getName());
|
||||
|
||||
JSONArray parameters = new JSONArray();
|
||||
JSONArray outputDefs = new JSONArray();
|
||||
String inputData = record.getInputData();
|
||||
if (StrUtil.isNotEmpty(inputData)) {
|
||||
JSONArray array = JSON.parseArray(inputData);
|
||||
handleArray(array);
|
||||
parameters = array;
|
||||
}
|
||||
String outputData = record.getOutputData();
|
||||
if (StrUtil.isNotEmpty(outputData)) {
|
||||
JSONArray array = JSON.parseArray(outputData);
|
||||
handleArray(array);
|
||||
outputDefs = array;
|
||||
}
|
||||
nodeData.put("parameters", parameters);
|
||||
nodeData.put("outputDefs", outputDefs);
|
||||
return Result.ok(nodeData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 插件试运行接口
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/test")
|
||||
public Result<?> pluginToolTest(@JsonBody(value = "inputData", required = true) String inputData,
|
||||
@JsonBody(value = "pluginToolId", required = true) BigInteger pluginToolId){
|
||||
return pluginItemService.pluginToolTest(inputData, pluginToolId);
|
||||
}
|
||||
|
||||
private void handleArray(JSONArray array) {
|
||||
for (Object o : array) {
|
||||
JSONObject obj = (JSONObject) o;
|
||||
obj.put("id", IdUtil.simpleUUID());
|
||||
obj.put("nameDisabled", true);
|
||||
obj.put("dataTypeDisabled", true);
|
||||
obj.put("deleteDisabled", true);
|
||||
obj.put("addChildDisabled", true);
|
||||
JSONArray children = obj.getJSONArray("children");
|
||||
if (children != null) {
|
||||
handleArray(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.in(BotPlugin::getPluginItemId, ids);
|
||||
|
||||
boolean exists = botPluginService.exists(queryWrapper);
|
||||
if (exists){
|
||||
return Result.fail(1, "此工具还关联着bot,请先取消关联!");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.ResourceCategory;
|
||||
import tech.easyflow.ai.service.ResourceCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
/**
|
||||
* 素材分类
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/resourceCategory")
|
||||
@UsePermission(moduleName = "/api/v1/resource")
|
||||
public class ResourceCategoryController extends BaseCurdController<ResourceCategoryService, ResourceCategory> {
|
||||
|
||||
public ResourceCategoryController(ResourceCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.Resource;
|
||||
import tech.easyflow.ai.service.ResourceService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 素材库
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-06-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/resource")
|
||||
public class ResourceController extends BaseCurdController<ResourceService, Resource> {
|
||||
public ResourceController(ResourceService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Resource entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
String resourceUrl = entity.getResourceUrl();
|
||||
byte[] bytes = HttpUtil.downloadBytes(resourceUrl);
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
||||
String suffix = FileTypeUtil.getType(stream, resourceUrl);
|
||||
entity.setSuffix(suffix);
|
||||
entity.setFileSize(BigInteger.valueOf(bytes.length));
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
||||
queryWrapper.eq(Resource::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
||||
return super.queryPage(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.easyagents.flow.core.chain.ChainDefinition;
|
||||
import com.easyagents.flow.core.chain.Node;
|
||||
import com.easyagents.flow.core.node.ConfirmNode;
|
||||
import com.easyagents.flow.core.node.EndNode;
|
||||
import com.easyagents.flow.core.node.StartNode;
|
||||
import com.easyagents.flow.core.parser.ChainParser;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RequestMapping("/api/v1/workflowNode")
|
||||
@RestController
|
||||
public class WorkFlowNodeController {
|
||||
|
||||
@Resource
|
||||
private WorkflowService workflowService;
|
||||
@Resource
|
||||
private ChainParser chainParser;
|
||||
|
||||
@GetMapping("/getChainParams")
|
||||
public Result<?> getChainParams(String currentId, String workflowId) {
|
||||
if (workflowId.equals(currentId)) {
|
||||
throw new BusinessException("工作流不能作为自身子节点");
|
||||
}
|
||||
JSONObject nodeData = new JSONObject();
|
||||
Workflow workflow = workflowService.getById(workflowId);
|
||||
if (workflow == null) {
|
||||
throw new BusinessException("工作流不存在: " + workflowId);
|
||||
}
|
||||
nodeData.put("workflowId", workflow.getId());
|
||||
nodeData.put("workflowName", workflow.getTitle());
|
||||
|
||||
ChainDefinition definition = chainParser.parse(workflow.getContent());
|
||||
List<Node> nodes = definition.getNodes();
|
||||
JSONArray inputs = new JSONArray();
|
||||
JSONArray outputs = new JSONArray();
|
||||
for (Node node : nodes) {
|
||||
if (node instanceof StartNode) {
|
||||
inputs = JSON.parseArray(JSON.toJSONString(node.getParameters()));
|
||||
handleArray(inputs);
|
||||
}
|
||||
if (node instanceof EndNode) {
|
||||
outputs = JSON.parseArray(JSON.toJSONString(((EndNode) node).getOutputDefs()));
|
||||
handleArray(outputs);
|
||||
}
|
||||
if (node instanceof ConfirmNode) {
|
||||
throw new BusinessException("工作流存在【确认节点】,暂不支持作为子节点");
|
||||
}
|
||||
}
|
||||
nodeData.put("parameters", inputs);
|
||||
nodeData.put("outputDefs", outputs);
|
||||
return Result.ok(nodeData);
|
||||
}
|
||||
|
||||
private void handleArray(JSONArray array) {
|
||||
if (array != null) {
|
||||
for (Object o : array) {
|
||||
JSONObject obj = (JSONObject) o;
|
||||
obj.put("id", IdUtil.simpleUUID());
|
||||
obj.put("nameDisabled", true);
|
||||
obj.put("dataTypeDisabled", true);
|
||||
obj.put("deleteDisabled", true);
|
||||
obj.put("addChildDisabled", true);
|
||||
obj.put("refType", "ref");
|
||||
JSONArray children = obj.getJSONArray("children");
|
||||
if (children != null) {
|
||||
handleArray(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-11
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/workflowCategory")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class WorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
||||
|
||||
public WorkflowCategoryController(WorkflowCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.core.io.IoUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.easyagents.flow.core.chain.*;
|
||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||
import com.easyagents.flow.core.parser.ChainParser;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.service.BotWorkflowService;
|
||||
import tech.easyflow.ai.service.ModelService;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.InputStream;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/workflow")
|
||||
public class WorkflowController extends BaseCurdController<WorkflowService, Workflow> {
|
||||
private final ModelService modelService;
|
||||
|
||||
@Resource
|
||||
private SysApiKeyService apiKeyService;
|
||||
@Resource
|
||||
private BotWorkflowService botWorkflowService;
|
||||
@Resource
|
||||
private ChainExecutor chainExecutor;
|
||||
@Resource
|
||||
private ChainParser chainParser;
|
||||
@Resource
|
||||
private TinyFlowService tinyFlowService;
|
||||
|
||||
public WorkflowController(WorkflowService service, ModelService modelService) {
|
||||
super(service);
|
||||
this.modelService = modelService;
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点单独运行
|
||||
*/
|
||||
@PostMapping("/singleRun")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<?> singleRun(
|
||||
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
||||
@JsonBody(value = "nodeId", required = true) String nodeId,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
|
||||
Workflow workflow = service.getById(workflowId);
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "工作流不存在");
|
||||
}
|
||||
Map<String, Object> res = chainExecutor.executeNode(workflowId.toString(), nodeId, variables);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行工作流 - v2
|
||||
*/
|
||||
@PostMapping("/runAsync")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
if (variables == null) {
|
||||
variables = new HashMap<>();
|
||||
}
|
||||
Workflow workflow = service.getById(id);
|
||||
if (workflow == null) {
|
||||
throw new RuntimeException("工作流不存在");
|
||||
}
|
||||
if (StpUtil.isLogin()) {
|
||||
variables.put(Constants.LOGIN_USER_KEY, SaTokenUtil.getLoginAccount());
|
||||
}
|
||||
String executeId = chainExecutor.executeAsync(id.toString(), variables);
|
||||
return Result.ok(executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作流运行状态 - v2
|
||||
*/
|
||||
@PostMapping("/getChainStatus")
|
||||
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复工作流运行 - v2
|
||||
*/
|
||||
@PostMapping("/resume")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/importWorkFlow")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> importWorkFlow(Workflow workflow, MultipartFile jsonFile) throws Exception {
|
||||
InputStream is = jsonFile.getInputStream();
|
||||
String content = IoUtil.read(is, StandardCharsets.UTF_8);
|
||||
workflow.setContent(content);
|
||||
save(workflow);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/exportWorkFlow")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<String> exportWorkFlow(BigInteger id) {
|
||||
Workflow workflow = service.getById(id);
|
||||
return Result.ok("", workflow.getContent());
|
||||
}
|
||||
|
||||
@GetMapping("getRunningParameters")
|
||||
@SaCheckPermission("/api/v1/workflow/query")
|
||||
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
||||
Workflow workflow = service.getById(id);
|
||||
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "can not find the workflow by id: " + id);
|
||||
}
|
||||
|
||||
ChainDefinition definition = chainParser.parse(workflow.getContent());
|
||||
if (definition == null) {
|
||||
return Result.fail(2, "节点配置错误,请检查! ");
|
||||
}
|
||||
List<Parameter> chainParameters = definition.getStartParameters();
|
||||
Map<String, Object> res = new HashMap<>();
|
||||
res.put("parameters", chainParameters);
|
||||
res.put("title", workflow.getTitle());
|
||||
res.put("description", workflow.getDescription());
|
||||
res.put("icon", workflow.getIcon());
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<Workflow> detail(String id) {
|
||||
Workflow workflow = service.getDetail(id);
|
||||
return Result.ok(workflow);
|
||||
}
|
||||
|
||||
@GetMapping("/copy")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> copy(BigInteger id) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
Workflow workflow = service.getById(id);
|
||||
workflow.setId(null);
|
||||
workflow.setAlias(IdUtil.fastSimpleUUID());
|
||||
commonFiled(workflow, account.getId(), account.getTenantId(), account.getDeptId());
|
||||
service.save(workflow);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(Workflow entity, boolean isSave) {
|
||||
|
||||
String alias = entity.getAlias();
|
||||
if (StringUtils.hasLength(alias)) {
|
||||
Workflow workflow = service.getByAlias(alias);
|
||||
if (workflow == null) {
|
||||
return null;
|
||||
}
|
||||
if (isSave) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
BigInteger id = entity.getId();
|
||||
if (id.compareTo(workflow.getId()) != 0) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
} else {
|
||||
entity.setAlias(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create();
|
||||
queryWrapper.in("workflow_id", ids);
|
||||
boolean exists = botWorkflowService.exists(queryWrapper);
|
||||
if (exists) {
|
||||
return Result.fail(1, "此工作流还关联有bot,请先取消关联后再删除!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.entity.WorkflowExecStep;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.ai.service.WorkflowExecStepService;
|
||||
import tech.easyflow.ai.utils.WorkFlowUtil;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* 工作流执行记录
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/workflowExecResult")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class WorkflowExecResultController extends BaseCurdController<WorkflowExecResultService, WorkflowExecResult> {
|
||||
|
||||
@Resource
|
||||
private WorkflowExecStepService recordStepService;
|
||||
|
||||
public WorkflowExecResultController(WorkflowExecResultService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("/del")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@SaCheckPermission("/api/v1/workflow/remove")
|
||||
public Result<Void> del(BigInteger id) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
WorkflowExecResult record = service.getById(id);
|
||||
if (!account.getId().toString().equals(record.getCreatedBy())) {
|
||||
return Result.fail(1, "非法请求");
|
||||
}
|
||||
service.removeById(id);
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(WorkflowExecStep::getRecordId, id);
|
||||
recordStepService.remove(w);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<WorkflowExecResult> queryPage(Page<WorkflowExecResult> page, QueryWrapper queryWrapper) {
|
||||
queryWrapper.eq(WorkflowExecResult::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
||||
Page<WorkflowExecResult> res = super.queryPage(page, queryWrapper);
|
||||
for (WorkflowExecResult record : res.getRecords()) {
|
||||
record.setWorkflowJson(WorkFlowUtil.removeSensitiveInfo(record.getWorkflowJson()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package tech.easyflow.admin.controller.ai;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.entity.WorkflowExecStep;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.ai.service.WorkflowExecStepService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 执行记录步骤
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/workflowExecStep")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class WorkflowExecStepController extends BaseCurdController<WorkflowExecStepService, WorkflowExecStep> {
|
||||
|
||||
@Resource
|
||||
private WorkflowExecResultService execRecordService;
|
||||
|
||||
public WorkflowExecStepController(WorkflowExecStepService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("/getListByRecordId")
|
||||
public Result<List<WorkflowExecStep>> getListByRecordId(BigInteger recordId) {
|
||||
if (recordId == null) {
|
||||
throw new BusinessException("recordId不能为空!");
|
||||
}
|
||||
WorkflowExecResult record = execRecordService.getById(recordId);
|
||||
String workflowJson = record.getWorkflowJson();
|
||||
JSONObject workflow = JSON.parseObject(workflowJson);
|
||||
Map<String, String> idTypeMap = new HashMap<>();
|
||||
JSONArray nodes = workflow.getJSONArray("nodes");
|
||||
for (Object node : nodes) {
|
||||
JSONObject nodeObj = (JSONObject) node;
|
||||
idTypeMap.put(nodeObj.getString("id"), nodeObj.getString("type"));
|
||||
}
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(WorkflowExecStep::getRecordId, recordId);
|
||||
List<WorkflowExecStep> list = service.list(w);
|
||||
for (WorkflowExecStep step : list) {
|
||||
step.setNodeData(null);
|
||||
step.setNodeType(idTypeMap.get(step.getNodeId()));
|
||||
}
|
||||
return Result.ok(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package tech.easyflow.admin.controller.auth;
|
||||
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import tech.easyflow.auth.entity.LoginDTO;
|
||||
import tech.easyflow.auth.entity.LoginVO;
|
||||
import tech.easyflow.auth.service.AuthService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/auth/")
|
||||
public class AuthController {
|
||||
|
||||
@Resource
|
||||
private AuthService authService;
|
||||
|
||||
@PostMapping("login")
|
||||
public Result<LoginVO> login(@JsonBody LoginDTO loginDTO) {
|
||||
LoginVO res = authService.login(loginDTO);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
@PostMapping("logout")
|
||||
public Result<Void> logout() {
|
||||
StpUtil.logout();
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("getPermissions")
|
||||
public Result<List<String>> getPermissions() {
|
||||
List<String> permissionList = StpUtil.getPermissionList();
|
||||
return Result.ok(permissionList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package tech.easyflow.admin.controller.common;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.dict.Dict;
|
||||
import tech.easyflow.common.dict.DictItem;
|
||||
import tech.easyflow.common.dict.DictLoader;
|
||||
import tech.easyflow.common.dict.DictManager;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/dict/")
|
||||
public class DictController {
|
||||
|
||||
@Resource
|
||||
DictManager dictManager;
|
||||
|
||||
@GetMapping("/items/{code}")
|
||||
public Result<List<DictItem>> items(@PathVariable("code") String code, String keyword, HttpServletRequest request) {
|
||||
DictLoader loader = dictManager.getLoader(code);
|
||||
if (loader == null) {
|
||||
return Result.ok(Collections.emptyList());
|
||||
}
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
Dict dict = loader.load(keyword, parameterMap);
|
||||
if (dict == null) {
|
||||
return Result.ok(Collections.emptyList());
|
||||
}
|
||||
return Result.ok(dict.getItems());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package tech.easyflow.admin.controller.common;
|
||||
|
||||
import cloud.tianai.captcha.application.ImageCaptchaApplication;
|
||||
import cloud.tianai.captcha.application.vo.ImageCaptchaVO;
|
||||
import cloud.tianai.captcha.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.common.response.ApiResponse;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.captcha.tainai.CaptchaData;
|
||||
import tech.easyflow.system.entity.SysOption;
|
||||
import tech.easyflow.system.service.SysOptionService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 公共接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/public")
|
||||
public class PublicController {
|
||||
|
||||
@Resource
|
||||
private ImageCaptchaApplication application;
|
||||
@Resource
|
||||
private SysOptionService sysOptionService;
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
@RequestMapping(value = "/getCaptcha", produces = "application/json")
|
||||
public ApiResponse<ImageCaptchaVO> getCaptcha() {
|
||||
return application.generateCaptcha(CaptchaTypeConstant.SLIDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码校验
|
||||
*/
|
||||
@PostMapping(value = "/check", produces = "application/json")
|
||||
public ApiResponse<String> checkCaptcha(@RequestBody CaptchaData data) {
|
||||
ApiResponse<?> response = application.matching(data.getId(), data.getData());
|
||||
if (!response.isSuccess()) {
|
||||
return ApiResponse.ofError("验证码错误");
|
||||
}
|
||||
return ApiResponse.ofSuccess(data.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package tech.easyflow.admin.controller.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
|
||||
import tech.easyflow.common.vo.UploadResVo;
|
||||
import tech.easyflow.common.filestorage.FileStorageService;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/commons/")
|
||||
public class UploadController {
|
||||
|
||||
@Resource(name = "default")
|
||||
FileStorageService storageService;
|
||||
|
||||
@PostMapping(value = "/upload", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Result<UploadResVo> upload(MultipartFile file) {
|
||||
String path = storageService.save(file);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/uploadAntd", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Result<UploadResVo> uploadAntd(MultipartFile file) {
|
||||
String path = storageService.save(file);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/uploadPrePath",produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@SaIgnore
|
||||
public Result<UploadResVo> uploadPrePath(MultipartFile file, String prePath) {
|
||||
String path = storageService.save(file,prePath);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package tech.easyflow.admin.controller.datacenter;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.idev.excel.EasyExcel;
|
||||
import cn.idev.excel.FastExcel;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.row.Row;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.DatacenterQuery;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.datacenter.entity.DatacenterTable;
|
||||
import tech.easyflow.datacenter.entity.DatacenterTableField;
|
||||
import tech.easyflow.datacenter.entity.vo.HeaderVo;
|
||||
import tech.easyflow.datacenter.excel.ReadDataListener;
|
||||
import tech.easyflow.datacenter.excel.ReadResVo;
|
||||
import tech.easyflow.datacenter.service.DatacenterTableFieldService;
|
||||
import tech.easyflow.datacenter.service.DatacenterTableService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据中枢表 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-07-10
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/datacenterTable")
|
||||
public class DatacenterTableController extends BaseCurdController<DatacenterTableService, DatacenterTable> {
|
||||
|
||||
@Resource
|
||||
private DatacenterTableFieldService fieldsService;
|
||||
|
||||
public DatacenterTableController(DatacenterTableService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(DatacenterTable entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@PostMapping("/saveTable")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/save")
|
||||
public Result<Void> saveTable(@RequestBody DatacenterTable entity) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
List<DatacenterTableField> fields = entity.getFields();
|
||||
if (CollectionUtil.isEmpty(fields)) {
|
||||
return Result.fail(99, "字段不能为空");
|
||||
}
|
||||
BigInteger id = entity.getId();
|
||||
if (id == null) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
service.saveTable(entity, loginUser);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/detailInfo")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/query")
|
||||
public Result<DatacenterTable> detailInfo(BigInteger tableId) {
|
||||
DatacenterTable table = service.getById(tableId);
|
||||
QueryWrapper wrapper = QueryWrapper.create();
|
||||
wrapper.eq(DatacenterTableField::getTableId, tableId);
|
||||
wrapper.orderBy("id");
|
||||
List<DatacenterTableField> fields = fieldsService.list(wrapper);
|
||||
table.setFields(fields);
|
||||
return Result.ok(table);
|
||||
}
|
||||
|
||||
@GetMapping("/removeTable")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/remove")
|
||||
public Result<Void> removeTable(BigInteger tableId) {
|
||||
service.removeTable(tableId);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/getHeaders")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/query")
|
||||
public Result<List<HeaderVo>> getHeaders(BigInteger tableId) {
|
||||
List<HeaderVo> res = service.getHeaders(tableId);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
@GetMapping("/getPageData")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/query")
|
||||
public Result<Page<Row>> getPageData(DatacenterQuery where) {
|
||||
Page<Row> res = service.getPageData(where);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
@PostMapping("/saveValue")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/save")
|
||||
public Result<Void> saveValue(@RequestParam Map<String, Object> map) {
|
||||
JSONObject object = new JSONObject(map);
|
||||
BigInteger tableId = object.getBigInteger("tableId");
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
if (tableId == null) {
|
||||
return Result.fail(99, "参数错误");
|
||||
}
|
||||
service.saveValue(tableId, object, account);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/removeValue")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/remove")
|
||||
public Result<Void> removeValue(@RequestParam Map<String, Object> map) {
|
||||
JSONObject object = new JSONObject(map);
|
||||
BigInteger tableId = object.getBigInteger("tableId");
|
||||
BigInteger id = object.getBigInteger("id");
|
||||
if (tableId == null || id == null) {
|
||||
return Result.fail(99, "参数错误");
|
||||
}
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
service.removeValue(tableId, id, account);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入数据
|
||||
*/
|
||||
@PostMapping("/importData")
|
||||
@SaCheckPermission("/api/v1/datacenterTable/save")
|
||||
public Result<ReadResVo> importData(MultipartFile file, @RequestParam Map<String, Object> map) throws Exception {
|
||||
Object tableId = map.get("tableId");
|
||||
DatacenterTable record = service.getById(tableId.toString());
|
||||
if (record == null) {
|
||||
throw new RuntimeException("数据表不存在");
|
||||
}
|
||||
InputStream is = file.getInputStream();
|
||||
List<DatacenterTableField> fields = service.getFields(record.getId());
|
||||
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
ReadDataListener listener = new ReadDataListener(record.getId(), fields, account);
|
||||
FastExcel.read(is, listener)
|
||||
.sheet()
|
||||
.doRead();
|
||||
int totalCount = listener.getTotalCount();
|
||||
int errorCount = listener.getErrorCount();
|
||||
int successCount = listener.getSuccessCount();
|
||||
List<JSONObject> errorRows = listener.getErrorRows();
|
||||
return Result.ok(new ReadResVo(successCount, errorCount, totalCount, errorRows));
|
||||
}
|
||||
|
||||
@GetMapping("/getTemplate")
|
||||
public void getTemplate(BigInteger tableId, HttpServletResponse response) throws Exception {
|
||||
List<DatacenterTableField> fields = service.getFields(tableId);
|
||||
// 设置响应内容类型
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
|
||||
// 设置文件名
|
||||
String fileName = URLEncoder.encode("导入模板", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
|
||||
|
||||
// 动态表头数据
|
||||
List<List<String>> headList = new ArrayList<>();
|
||||
|
||||
for (DatacenterTableField field : fields) {
|
||||
List<String> head = new ArrayList<>();
|
||||
head.add(field.getFieldName());
|
||||
headList.add(head);
|
||||
}
|
||||
|
||||
// 写入Excel
|
||||
EasyExcel.write(response.getOutputStream())
|
||||
.head(headList)
|
||||
.sheet("模板")
|
||||
.doWrite(new ArrayList<>()); // 写入空数据,只生成模板
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package tech.easyflow.admin.controller.datacenter;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.datacenter.entity.DatacenterTableField;
|
||||
import tech.easyflow.datacenter.service.DatacenterTableFieldService;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-07-10
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/datacenterTableFields")
|
||||
@UsePermission(moduleName = "/api/v1/datacenterTable")
|
||||
public class DatacenterTableFieldsController extends BaseCurdController<DatacenterTableFieldService, DatacenterTableField> {
|
||||
|
||||
public DatacenterTableFieldsController(DatacenterTableFieldService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(DatacenterTableField entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package tech.easyflow.admin.controller.job;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import org.quartz.CronExpression;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.constant.enums.EnumJobStatus;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.job.entity.SysJob;
|
||||
import tech.easyflow.job.service.SysJobService;
|
||||
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统任务表 控制层。
|
||||
*
|
||||
* @author xiaoma
|
||||
* @since 2025-05-20
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysJob")
|
||||
public class SysJobController extends BaseCurdController<SysJobService, SysJob> {
|
||||
public SysJobController(SysJobService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("/start")
|
||||
@SaCheckPermission("/api/v1/sysJob/save")
|
||||
public Result<Void> start(BigInteger id) {
|
||||
SysJob sysJob = service.getById(id);
|
||||
sysJob.setStatus(EnumJobStatus.RUNNING.getCode());
|
||||
service.addJob(sysJob);
|
||||
service.updateById(sysJob);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/stop")
|
||||
@SaCheckPermission("/api/v1/sysJob/save")
|
||||
public Result<Void> stop(BigInteger id) {
|
||||
SysJob sysJob = new SysJob();
|
||||
sysJob.setId(id);
|
||||
sysJob.setStatus(EnumJobStatus.STOP.getCode());
|
||||
ArrayList<Serializable> ids = new ArrayList<>();
|
||||
ids.add(id);
|
||||
service.deleteJob(ids);
|
||||
service.updateById(sysJob);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/getNextTimes")
|
||||
public Result<List<String>> getNextTimes(String cronExpression) throws Exception{
|
||||
CronExpression ex = new CronExpression(cronExpression);
|
||||
List<String> times = new ArrayList<>();
|
||||
Date date = new Date();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Date next = ex.getNextValidTimeAfter(date);
|
||||
times.add(DateUtil.formatDateTime(next));
|
||||
date = next;
|
||||
}
|
||||
return Result.ok(times);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysJob entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
service.deleteJob(ids);
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package tech.easyflow.admin.controller.job;
|
||||
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.job.entity.SysJobLog;
|
||||
import tech.easyflow.job.service.SysJobLogService;
|
||||
|
||||
/**
|
||||
* 系统任务日志 控制层。
|
||||
*
|
||||
* @author xiaoma
|
||||
* @since 2025-05-20
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysJobLog")
|
||||
@UsePermission(moduleName = "/api/v1/sysJob")
|
||||
public class SysJobLogController extends BaseCurdController<SysJobLogService, SysJobLog> {
|
||||
public SysJobLogController(SysJobLogService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysJobLog entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.constant.enums.EnumAccountType;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.util.StringUtil;
|
||||
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.log.annotation.LogRecord;
|
||||
import tech.easyflow.system.entity.SysAccount;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 用户表 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController("sysAccountController")
|
||||
@RequestMapping("/api/v1/sysAccount")
|
||||
public class SysAccountController extends BaseCurdController<SysAccountService, SysAccount> {
|
||||
public SysAccountController(SysAccountService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
@LogRecord("分页查询")
|
||||
protected Page<SysAccount> queryPage(Page<SysAccount> page, QueryWrapper queryWrapper) {
|
||||
return service.getMapper().paginateWithRelations(page, queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysAccount entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
BigInteger tenantId = loginUser.getTenantId();
|
||||
if (isSave) {
|
||||
commonFiled(entity, loginUser.getId(), tenantId, loginUser.getDeptId());
|
||||
// 查询用户名是否存在
|
||||
// long count = Db.selectCount(SqlPrepare.COUNT_ACCOUNT_BY_UNI_KEY, entity.getLoginName(), tenantId);
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(SysAccount::getLoginName, entity.getLoginName());
|
||||
long count = service.count(w);
|
||||
if (count > 0) {
|
||||
return Result.fail(1, "用户名已存在");
|
||||
}
|
||||
String password = entity.getPassword();
|
||||
if (StringUtil.hasText(password)) {
|
||||
entity.setPassword(BCrypt.hashpw(password));
|
||||
}
|
||||
Integer status = entity.getStatus();
|
||||
if (status == null) {
|
||||
entity.setStatus(EnumDataStatus.AVAILABLE.getCode());
|
||||
}
|
||||
} else {
|
||||
SysAccount record = service.getById(entity.getId());
|
||||
// 如果修改了部门,就将用户踢下线,避免用户操作数据造成数据错误
|
||||
if (record.getDeptId() != null && !record.getDeptId().equals(entity.getDeptId())) {
|
||||
StpUtil.kickout(record.getId());
|
||||
}
|
||||
// 不让修改用户名/密码,浏览器记住密码有可能会带上来
|
||||
entity.setLoginName(null);
|
||||
entity.setPassword(null);
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveOrUpdateAfter(SysAccount entity, boolean isSave) {
|
||||
service.syncRelations(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
List<SysAccount> sysAccounts = service.listByIds(ids);
|
||||
for (SysAccount account : sysAccounts) {
|
||||
Integer accountType = account.getAccountType();
|
||||
if (EnumAccountType.SUPER_ADMIN.getCode().equals(accountType)) {
|
||||
return Result.fail(1, "不能删除超级管理员");
|
||||
}
|
||||
if (EnumAccountType.TENANT_ADMIN.getCode().equals(accountType)) {
|
||||
return Result.fail(1, "不能删除租户管理员");
|
||||
}
|
||||
}
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
|
||||
@GetMapping("/myProfile")
|
||||
public Result<SysAccount> myProfile() {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
SysAccount sysAccount = service.getById(account.getId());
|
||||
return Result.ok(sysAccount);
|
||||
}
|
||||
|
||||
@PostMapping("/updateProfile")
|
||||
public Result<Void> updateProfile(@JsonBody SysAccount account) {
|
||||
BigInteger loginAccountId = SaTokenUtil.getLoginAccount().getId();
|
||||
SysAccount update = new SysAccount();
|
||||
update.setId(loginAccountId);
|
||||
update.setNickname(account.getNickname());
|
||||
update.setMobile(account.getMobile());
|
||||
update.setEmail(account.getEmail());
|
||||
update.setAvatar(account.getAvatar());
|
||||
update.setModified(new Date());
|
||||
update.setModifiedBy(loginAccountId);
|
||||
service.updateById(update);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码,用于修改用户自己的密码
|
||||
*
|
||||
* @param password 用户的旧密码
|
||||
* @param newPassword 新密码
|
||||
* @param confirmPassword 确认密码
|
||||
*/
|
||||
@PostMapping("/updatePassword")
|
||||
public Result<Void> updatePassword(@JsonBody(value = "password", required = true) String password,
|
||||
@JsonBody(value = "newPassword", required = true) String newPassword,
|
||||
@JsonBody(value = "confirmPassword", required = true) String confirmPassword) {
|
||||
BigInteger loginAccountId = SaTokenUtil.getLoginAccount().getId();
|
||||
SysAccount record = service.getById(loginAccountId);
|
||||
if (record == null) {
|
||||
return Result.fail("修改失败");
|
||||
}
|
||||
String pwdDb = record.getPassword();
|
||||
if (!BCrypt.checkpw(password, pwdDb)) {
|
||||
return Result.fail(1, "密码不正确");
|
||||
}
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
return Result.fail(2, "两次密码不一致");
|
||||
}
|
||||
SysAccount update = new SysAccount();
|
||||
update.setId(loginAccountId);
|
||||
update.setPassword(BCrypt.hashpw(newPassword));
|
||||
update.setModified(new Date());
|
||||
update.setModifiedBy(loginAccountId);
|
||||
service.updateById(update);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.table.TableInfo;
|
||||
import com.mybatisflex.core.table.TableInfoFactory;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.util.IdUtil;
|
||||
import tech.easyflow.common.vo.PkVo;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.system.entity.SysApiKey;
|
||||
import tech.easyflow.system.entity.SysApiKeyResourceMapping;
|
||||
import tech.easyflow.system.service.SysApiKeyResourceMappingService;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author wangGangQiang
|
||||
* @since 2025-04-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysApiKey")
|
||||
public class SysApiKeyController extends BaseCurdController<SysApiKeyService, SysApiKey> {
|
||||
public SysApiKeyController(SysApiKeyService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Resource
|
||||
private SysApiKeyResourceMappingService sysApiKeyResourceMappingService;
|
||||
/**
|
||||
* 添加(保存)数据
|
||||
*
|
||||
* @return {@code Result.errorCode == 0} 添加成功,否则添加失败
|
||||
*/
|
||||
@PostMapping("/key/save")
|
||||
@SaCheckPermission("/api/v1/sysApiKey/save")
|
||||
public Result<PkVo> save() {
|
||||
String apiKey = IdUtil.generateUUID();
|
||||
SysApiKey entity = new SysApiKey();
|
||||
entity.setApiKey(apiKey);
|
||||
entity.setCreated(new Date());
|
||||
entity.setStatus(1);
|
||||
// 将Date转换为LocalDate
|
||||
LocalDate localDate = new Date().toInstant()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toLocalDate();
|
||||
|
||||
// 添加30天
|
||||
LocalDate newLocalDate = localDate.plusDays(30);
|
||||
// 转换回Date
|
||||
Date expireDate = Date.from(newLocalDate.atStartOfDay()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.toInstant());
|
||||
entity.setExpiredAt(expireDate);
|
||||
LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
|
||||
commonFiled(entity,loginAccount.getId(),loginAccount.getTenantId(),loginAccount.getDeptId());
|
||||
service.save(entity);
|
||||
onSaveOrUpdateAfter(entity, true);
|
||||
TableInfo tableInfo = TableInfoFactory.ofEntityClass(entity.getClass());
|
||||
Object[] pkArgs = tableInfo.buildPkSqlArgs(entity);
|
||||
return Result.ok(new PkVo(pkArgs));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveOrUpdateAfter(SysApiKey entity, boolean isSave) {
|
||||
if (!isSave && entity.getPermissionIds() != null && !entity.getPermissionIds().isEmpty()) {
|
||||
// 修改的时候绑定授权接口
|
||||
sysApiKeyResourceMappingService.authInterface(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("/page")
|
||||
public Result<Page<SysApiKey>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
Result<Page<SysApiKey>> pageResult = (Result<Page<SysApiKey>>) super.page(request, sortKey, sortType, pageNumber, pageSize);
|
||||
Page<SysApiKey> data = pageResult.getData();
|
||||
List<SysApiKey> records = data.getRecords();
|
||||
records.forEach(record -> {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create().select(SysApiKeyResourceMapping::getApiKeyResourceId).eq(SysApiKeyResourceMapping::getApiKeyId, record.getId());
|
||||
List<BigInteger> resourceIds = sysApiKeyResourceMappingService.listAs(queryWrapper, BigInteger.class);
|
||||
record.setPermissionIds(resourceIds);
|
||||
});
|
||||
return pageResult;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.system.entity.SysApiKeyResource;
|
||||
import tech.easyflow.system.service.SysApiKeyResourceService;
|
||||
|
||||
/**
|
||||
* 请求接口表 控制层。
|
||||
*
|
||||
* @author 12076
|
||||
* @since 2025-12-01
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysApiKeyResourcePermission")
|
||||
@UsePermission(moduleName = "/api/v1/sysApiKey")
|
||||
public class SysApiKeyResourceController extends BaseCurdController<SysApiKeyResourceService, SysApiKeyResource> {
|
||||
public SysApiKeyResourceController(SysApiKeyResourceService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.system.entity.SysApiKeyResourceMapping;
|
||||
import tech.easyflow.system.service.SysApiKeyResourceMappingService;
|
||||
|
||||
/**
|
||||
* apikey-请求接口表 控制层。
|
||||
*
|
||||
* @author 12076
|
||||
* @since 2025-12-01
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysApiKeyResourcePermissionRelationship")
|
||||
@UsePermission(moduleName = "/api/v1/sysApiKey")
|
||||
public class SysApiKeyResourceMappingController extends BaseCurdController<SysApiKeyResourceMappingService, SysApiKeyResourceMapping> {
|
||||
public SysApiKeyResourceMappingController(SysApiKeyResourceMappingService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.system.entity.SysAccount;
|
||||
import tech.easyflow.system.entity.SysDept;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
import tech.easyflow.system.service.SysDeptService;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 部门表 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController("sysDeptController")
|
||||
@RequestMapping("/api/v1/sysDept")
|
||||
public class SysDeptController extends BaseCurdController<SysDeptService, SysDept> {
|
||||
|
||||
@Resource
|
||||
private SysAccountService sysAccountService;
|
||||
|
||||
public SysDeptController(SysDeptService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultOrderBy() {
|
||||
return "sort_no asc";
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("list")
|
||||
public Result<List<SysDept>> list(SysDept entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<SysDept> sysMenus = service.list(queryWrapper);
|
||||
return Result.ok(Tree.tryToTree(sysMenus, "id", "parentId"));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysDept entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
BigInteger parentId = entity.getParentId();
|
||||
if (parentId.equals(BigInteger.ZERO)) {
|
||||
entity.setAncestors(parentId.toString());
|
||||
} else {
|
||||
SysDept parent = service.getById(parentId);
|
||||
entity.setAncestors(parent.getAncestors() + "," + parentId);
|
||||
}
|
||||
if (isSave) {
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
List<SysDept> records = service.listByIds(ids);
|
||||
for (SysDept dept : records) {
|
||||
if (Constants.ROOT_DEPT.equals(dept.getDeptCode())) {
|
||||
return Result.fail(1, "无法删除根部门");
|
||||
}
|
||||
}
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.in(SysAccount::getDeptId, ids);
|
||||
long count = sysAccountService.count(w);
|
||||
if (count > 0) {
|
||||
return Result.fail(1, "该部门下有员工,不能删除");
|
||||
}
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.util.SpringContextUtil;
|
||||
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.dict.DictManager;
|
||||
import tech.easyflow.system.entity.SysDict;
|
||||
import tech.easyflow.system.service.SysDictService;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统配置表 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-03-05
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysDict")
|
||||
public class SysDictController extends BaseCurdController<SysDictService, SysDict> {
|
||||
|
||||
public SysDictController(SysDictService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveOrUpdateAfter(SysDict entity, boolean isSave) {
|
||||
DictManager dictManager = SpringContextUtil.getBean(DictManager.class);
|
||||
dictManager.putLoader(entity.buildLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
List<SysDict> sysDicts = service.list(QueryWrapper.create().in("id", ids));
|
||||
if (sysDicts != null) {
|
||||
DictManager dictManager = SpringContextUtil.getBean(DictManager.class);
|
||||
sysDicts.forEach(sysDict -> dictManager.removeLoader(sysDict.getCode()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.system.entity.SysDictItem;
|
||||
import tech.easyflow.system.service.SysDictItemService;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 数据字典内容 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-03-06
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysDictItem")
|
||||
@UsePermission(moduleName = "/api/v1/sysDict")
|
||||
public class SysDictItemController extends BaseCurdController<SysDictItemService, SysDictItem> {
|
||||
public SysDictItemController(SysDictItemService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.stp.SaLoginModel;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import cn.dev33.satoken.util.SaResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.util.IdUtil;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/token")
|
||||
public class SysGenerateTokenController {
|
||||
// 手动生成 Token 并绑定账号
|
||||
@GetMapping("/generateToken")
|
||||
public SaResult generateToken() {
|
||||
long loginId = StpUtil.getLoginIdAsLong(); // 假设这是你要绑定的账号ID
|
||||
String customToken = IdUtil.generateUUID();; // 自定义的 Token 字符串
|
||||
SaLoginModel saLoginModel = new SaLoginModel();
|
||||
saLoginModel.setToken(customToken);
|
||||
saLoginModel.setTimeout(-1);
|
||||
// 将 loginId 与 customToken 关联,并设置有效期(单位:秒)
|
||||
StpUtil.createLoginSession(loginId, saLoginModel); // 24小时有效期
|
||||
System.out.println("生成了token: " + customToken);
|
||||
return SaResult.ok("Token 已生成").setData(customToken);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.log.annotation.LogRecord;
|
||||
import tech.easyflow.system.entity.SysLog;
|
||||
import tech.easyflow.system.service.SysLogService;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.relation.RelationManager;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 操作日志表 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-03-06
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysLog")
|
||||
public class SysLogController extends BaseCurdController<SysLogService, SysLog> {
|
||||
public SysLogController(SysLogService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
@LogRecord("分页查询")
|
||||
protected Page<SysLog> queryPage(Page<SysLog> page, QueryWrapper queryWrapper) {
|
||||
RelationManager.setQueryRelations(Collections.singleton("account"));
|
||||
return service.getMapper().paginateWithRelations(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.tree.Tree;
|
||||
|
||||
import tech.easyflow.common.vo.MenuVo;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.system.entity.SysMenu;
|
||||
import tech.easyflow.system.entity.SysRoleMenu;
|
||||
import tech.easyflow.system.service.SysAccountRoleService;
|
||||
import tech.easyflow.system.service.SysMenuService;
|
||||
import tech.easyflow.system.service.SysRoleMenuService;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 菜单表 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController("sysMenuController")
|
||||
@RequestMapping("/api/v1/sysMenu")
|
||||
public class SysMenuController extends BaseCurdController<SysMenuService, SysMenu> {
|
||||
|
||||
@Resource
|
||||
private SysRoleMenuService sysRoleMenuService;
|
||||
@Resource
|
||||
private SysAccountRoleService sysAccountRoleService;
|
||||
|
||||
public SysMenuController(SysMenuService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDefaultOrderBy() {
|
||||
return "sort_no asc";
|
||||
}
|
||||
|
||||
@Override
|
||||
@GetMapping("list")
|
||||
public Result<List<SysMenu>> list(SysMenu entity, Boolean asTree, String sortKey, String sortType) {
|
||||
QueryWrapper queryWrapper = QueryWrapper.create(entity, buildOperators(entity));
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
List<SysMenu> sysMenus = service.list(queryWrapper);
|
||||
return Result.ok(Tree.tryToTree(sysMenus, "id", "parentId"));
|
||||
}
|
||||
|
||||
@GetMapping("tree")
|
||||
public Result<List<SysMenu>> tree(SysMenu entity) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
BigInteger accountId = account.getId();
|
||||
List<SysMenu> sysMenus = service.getMenusByAccountId(entity,accountId);
|
||||
return Result.ok(Tree.tryToTree(sysMenus, "id", "parentId"));
|
||||
}
|
||||
|
||||
@GetMapping("treeV2")
|
||||
public Result<List<MenuVo>> treeV2(SysMenu entity) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
BigInteger accountId = account.getId();
|
||||
List<SysMenu> sysMenus = service.getMenusByAccountId(entity,accountId);
|
||||
List<MenuVo> menuVos = buildMenuVos(sysMenus);
|
||||
return Result.ok(Tree.tryToTree(menuVos, "id", "parentId"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据角色id获取菜单树
|
||||
*/
|
||||
@GetMapping("getCheckedByRoleId/{roleId}")
|
||||
public Result<List<BigInteger>> getCheckedByRoleId(@PathVariable BigInteger roleId) {
|
||||
QueryWrapper rmWrapper = QueryWrapper.create();
|
||||
rmWrapper.eq("role_id", roleId);
|
||||
List<SysRoleMenu> list = sysRoleMenuService.list(rmWrapper);
|
||||
List<BigInteger> menuIds = list.stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
|
||||
if (CollectionUtil.isEmpty(menuIds)) {
|
||||
return Result.ok(new ArrayList<>());
|
||||
}
|
||||
QueryWrapper wrapper = QueryWrapper.create();
|
||||
wrapper.in(SysMenu::getId,menuIds);
|
||||
List<SysMenu> sysMenus = service.list(wrapper);
|
||||
return Result.ok(sysMenus.stream().map(SysMenu::getId).collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存后,给超级管理员角色添加权限
|
||||
*/
|
||||
@Override
|
||||
protected void onSaveOrUpdateAfter(SysMenu entity, boolean isSave) {
|
||||
if (isSave) {
|
||||
SysRoleMenu admin = new SysRoleMenu();
|
||||
admin.setRoleId(Constants.SUPER_ADMIN_ROLE_ID);
|
||||
admin.setMenuId(entity.getId());
|
||||
sysRoleMenuService.save(admin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除后,删除角色菜单对应关系
|
||||
*/
|
||||
@Override
|
||||
protected void onRemoveAfter(Collection<Serializable> ids) {
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.in(SysRoleMenu::getMenuId, ids);
|
||||
sysRoleMenuService.remove(w);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysMenu entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<MenuVo> buildMenuVos(List<SysMenu> sysMenus) {
|
||||
List<MenuVo> menuVos = new ArrayList<>();
|
||||
for (SysMenu sysMenu : sysMenus) {
|
||||
if (sysMenu.getIsShow() != 1) {
|
||||
continue;
|
||||
}
|
||||
if (sysMenu.getMenuType() == 1) {
|
||||
continue;
|
||||
}
|
||||
MenuVo menuVo = new MenuVo();
|
||||
menuVo.setId(sysMenu.getId());
|
||||
menuVo.setParentId(sysMenu.getParentId());
|
||||
|
||||
MenuVo.MetaVo metaVo = new MenuVo.MetaVo();
|
||||
metaVo.setTitle(sysMenu.getMenuTitle());
|
||||
metaVo.setIcon(sysMenu.getMenuIcon());
|
||||
metaVo.setOrder(sysMenu.getSortNo());
|
||||
|
||||
menuVo.setMeta(metaVo);
|
||||
menuVo.setName(sysMenu.getId().toString());
|
||||
menuVo.setPath(sysMenu.getMenuUrl());
|
||||
menuVo.setComponent(sysMenu.getComponent());
|
||||
menuVos.add(menuVo);
|
||||
}
|
||||
return menuVos;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.options.SysOptions;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysOption;
|
||||
import tech.easyflow.system.service.SysOptionService;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 系统配置信息表。 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-03-13
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysOption")
|
||||
public class SysOptionController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private SysOptionService service;
|
||||
|
||||
@GetMapping("/list")
|
||||
public Result<Map<String, Object>> list(String[] keys) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
if (keys == null || keys.length == 0) {
|
||||
return Result.ok(data);
|
||||
}
|
||||
List<SysOption> list = service.list(QueryWrapper.create().in(SysOption::getKey, (Object[]) keys));
|
||||
for (SysOption sysOption : list) {
|
||||
data.put(sysOption.getKey(), sysOption.getValue());
|
||||
}
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
@PostMapping("/save")
|
||||
public Result<Void> save(@JsonBody Map<String, String> map) {
|
||||
if (map == null || map.isEmpty()) {
|
||||
return Result.ok();
|
||||
}
|
||||
map.forEach(SysOptions::set);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("/saveOption")
|
||||
@SaCheckPermission("/api/v1/sysOption/save")
|
||||
public Result<Void> saveOption(@JsonBody SysOption sysOption) {
|
||||
String key = sysOption.getKey();
|
||||
if (key == null || key.isEmpty()) {
|
||||
throw new BusinessException("key is empty");
|
||||
}
|
||||
sysOption.setTenantId(SaTokenUtil.getLoginAccount().getTenantId());
|
||||
SysOption record = service.getByOptionKey(key);
|
||||
if (record == null) {
|
||||
service.save(sysOption);
|
||||
} else {
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(SysOption::getKey, key);
|
||||
service.update(sysOption, w);
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("/getByKey")
|
||||
public Result<SysOption> getByKey(String key) {
|
||||
if (key == null || key.isEmpty()) {
|
||||
throw new BusinessException("key is empty");
|
||||
}
|
||||
return Result.ok(service.getByOptionKey(key));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.util.StringUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysPosition;
|
||||
import tech.easyflow.system.service.SysPositionService;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import static tech.easyflow.system.entity.table.SysPositionTableDef.SYS_POSITION;
|
||||
|
||||
/**
|
||||
* 职位表 控制层。
|
||||
* <p>
|
||||
* 提供岗位的增删改查及状态管理功能。
|
||||
* </p>
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController("sysPositionController")
|
||||
@RequestMapping("/api/v1/sysPosition")
|
||||
public class SysPositionController extends BaseCurdController<SysPositionService, SysPosition> {
|
||||
public SysPositionController(SysPositionService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询岗位列表
|
||||
* <p>
|
||||
* 支持按岗位名称模糊查询,按状态、编码精确查询。
|
||||
* </p>
|
||||
*
|
||||
* @param request 请求对象
|
||||
* @param sortKey 排序字段
|
||||
* @param sortType 排序类型 (asc/desc)
|
||||
* @param pageNumber 当前页码
|
||||
* @param pageSize 每页条数
|
||||
* @return 分页结果
|
||||
*/
|
||||
@Override
|
||||
@GetMapping("page")
|
||||
public Result<Page<SysPosition>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
|
||||
// 构建自定义查询条件
|
||||
QueryWrapper queryWrapper = QueryWrapper.create()
|
||||
.select(SYS_POSITION.ALL_COLUMNS)
|
||||
.from(SYS_POSITION);
|
||||
|
||||
// 获取查询参数
|
||||
String positionName = request.getParameter("positionName");
|
||||
String positionCode = request.getParameter("positionCode");
|
||||
String status = request.getParameter("status");
|
||||
|
||||
// 岗位名称 - 模糊查询
|
||||
if (StringUtil.hasText(positionName)) {
|
||||
queryWrapper.where(SYS_POSITION.POSITION_NAME.like(positionName));
|
||||
}
|
||||
// 岗位编码 - 精确查询
|
||||
if (StringUtil.hasText(positionCode)) {
|
||||
queryWrapper.where(SYS_POSITION.POSITION_CODE.eq(positionCode));
|
||||
}
|
||||
// 状态 - 精确查询
|
||||
if (StringUtil.hasText(status)) {
|
||||
queryWrapper.where(SYS_POSITION.STATUS.eq(status));
|
||||
}
|
||||
|
||||
// 处理排序
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
|
||||
return Result.ok(service.page(new Page<>(pageNumber, pageSize), queryWrapper));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改岗位状态(启用/禁用)
|
||||
*
|
||||
* @param body 包含 id 和 status 的 JSON 对象
|
||||
* @return 操作结果
|
||||
*/
|
||||
@PostMapping("changeStatus")
|
||||
public Result<?> changeStatus(@RequestBody Map<String, Object> body) {
|
||||
String idStr = (String) body.get("id");
|
||||
Integer status = (Integer) body.get("status");
|
||||
|
||||
if (StringUtil.noText(idStr) || status == null) {
|
||||
return Result.fail("参数错误:id 和 status 不能为空");
|
||||
}
|
||||
|
||||
SysPosition position = new SysPosition();
|
||||
position.setId(new java.math.BigInteger(idStr));
|
||||
position.setStatus(status);
|
||||
|
||||
// 设置修改信息
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
position.setModified(new Date());
|
||||
position.setModifiedBy(loginUser.getId());
|
||||
|
||||
boolean success = service.updateById(position);
|
||||
return success ? Result.ok() : Result.fail("状态修改失败");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysPosition entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), entity.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysRole;
|
||||
import tech.easyflow.system.entity.SysRoleDept;
|
||||
import tech.easyflow.system.entity.SysRoleMenu;
|
||||
import tech.easyflow.system.service.SysRoleDeptService;
|
||||
import tech.easyflow.system.service.SysRoleMenuService;
|
||||
import tech.easyflow.system.service.SysRoleService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 系统角色 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController("sysRoleController")
|
||||
@RequestMapping("/api/v1/sysRole/")
|
||||
public class SysRoleController extends BaseCurdController<SysRoleService, SysRole> {
|
||||
|
||||
@Resource
|
||||
private SysRoleMenuService sysRoleMenuService;
|
||||
@Resource
|
||||
private SysRoleDeptService sysRoleDeptService;
|
||||
|
||||
public SysRoleController(SysRoleService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@PostMapping("saveRoleMenu/{roleId}")
|
||||
@SaCheckPermission("/api/v1/sysRole/save")
|
||||
@Deprecated
|
||||
public Result<Void> saveRoleMenu(@PathVariable("roleId") BigInteger roleId, @JsonBody List<String> keys) {
|
||||
service.saveRoleMenu(roleId, keys);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色菜单id
|
||||
*/
|
||||
@GetMapping("/getRoleMenuIds")
|
||||
@SaCheckPermission("/api/v1/sysRole/query")
|
||||
public Result<List<BigInteger>> getRoleMenuIds(BigInteger roleId) {
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq("role_id", roleId);
|
||||
List<BigInteger> res = sysRoleMenuService.list(w).stream().map(SysRoleMenu::getMenuId).collect(Collectors.toList());
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取角色部门id
|
||||
*/
|
||||
@GetMapping("/getRoleDeptIds")
|
||||
@SaCheckPermission("/api/v1/sysRole/query")
|
||||
public Result<List<BigInteger>> getRoleDeptIds(BigInteger roleId) {
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq("role_id", roleId);
|
||||
List<BigInteger> res = sysRoleDeptService.list(w).stream().map(SysRoleDept::getDeptId).collect(Collectors.toList());
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存角色
|
||||
*/
|
||||
@PostMapping("saveRole")
|
||||
@SaCheckPermission("/api/v1/sysRole/save")
|
||||
public Result<Void> saveRole(@JsonBody SysRole entity) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (entity.getId() == null) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
}
|
||||
service.saveRole(entity);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onSaveOrUpdateBefore(SysRole entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
commonFiled(entity, loginUser.getId(), loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result onRemoveBefore(Collection<Serializable> ids) {
|
||||
List<SysRole> sysRoles = service.listByIds(ids);
|
||||
for (SysRole sysRole : sysRoles) {
|
||||
String roleKey = sysRole.getRoleKey();
|
||||
if (Constants.SUPER_ADMIN_ROLE_CODE.equals(roleKey)) {
|
||||
return Result.fail(1, "超级管理员角色不能删除");
|
||||
}
|
||||
if (Constants.TENANT_ADMIN_ROLE_CODE.equals(roleKey)) {
|
||||
return Result.fail(1, "租户管理员角色不能删除");
|
||||
}
|
||||
}
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/temp-token")
|
||||
public class SysTempTokenController {
|
||||
|
||||
@GetMapping("/create")
|
||||
@SaIgnore
|
||||
public Result<String> createTempToken() {
|
||||
|
||||
StpUtil.login(0);
|
||||
String tokenValue = StpUtil.getTokenValue();
|
||||
LoginAccount loginAccount = new LoginAccount();
|
||||
loginAccount.setId(BigInteger.valueOf(0));
|
||||
loginAccount.setLoginName("匿名用户");
|
||||
StpUtil.getSession().set(Constants.LOGIN_USER_KEY, loginAccount);
|
||||
|
||||
return Result.ok("", tokenValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.system.entity.SysUserFeedback;
|
||||
import tech.easyflow.system.service.SysUserFeedbackService;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author 12076
|
||||
* @since 2025-12-30
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/sysUserFeedback")
|
||||
public class SysUserFeedbackController extends BaseCurdController<SysUserFeedbackService, SysUserFeedback> {
|
||||
public SysUserFeedbackController(SysUserFeedbackService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(SysUserFeedback entity, boolean isSave) {
|
||||
if (!isSave) {
|
||||
entity.setHandlerId(new BigInteger(StpUtil.getLoginIdAsString()));
|
||||
entity.setModified(new Date());
|
||||
entity.setHandleTime(new Date());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
}
|
||||
14
easyflow-api/easyflow-api-mcp/pom.xml
Normal file
14
easyflow-api/easyflow-api-mcp/pom.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-api-mcp</artifactId>
|
||||
|
||||
</project>
|
||||
37
easyflow-api/easyflow-api-public/pom.xml
Normal file
37
easyflow-api/easyflow-api-public/pom.xml
Normal file
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-api-public</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-ai</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-system</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.javaparser</groupId>
|
||||
<artifactId>javaparser-core</artifactId>
|
||||
<version>3.25.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,188 @@
|
||||
package tech.easyflow.publicapi;
|
||||
|
||||
import com.github.javaparser.StaticJavaParser;
|
||||
import com.github.javaparser.ast.CompilationUnit;
|
||||
import com.github.javaparser.ast.body.ClassOrInterfaceDeclaration;
|
||||
import com.github.javaparser.ast.expr.AnnotationExpr;
|
||||
import com.github.javaparser.ast.expr.MemberValuePair;
|
||||
import com.github.javaparser.ast.expr.NormalAnnotationExpr;
|
||||
import com.github.javaparser.ast.expr.SingleMemberAnnotationExpr;
|
||||
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.zaxxer.hikari.HikariDataSource;
|
||||
import tech.easyflow.system.entity.SysApiKeyResource;
|
||||
import tech.easyflow.system.mapper.SysApiKeyResourceMapper;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* 同步接口到数据库
|
||||
*/
|
||||
public class SyncApis {
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
try (HikariDataSource dataSource = new HikariDataSource()) {
|
||||
dataSource.setJdbcUrl("jdbc:mysql://192.168.2.10:3306/easyflow-v2?useInformationSchema=true&characterEncoding=utf-8");
|
||||
dataSource.setUsername("root");
|
||||
dataSource.setPassword("123456");
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance();
|
||||
bootstrap.setDataSource(dataSource);
|
||||
bootstrap.addMapper(SysApiKeyResourceMapper.class);
|
||||
bootstrap.start();
|
||||
|
||||
SysApiKeyResourceMapper mapper = bootstrap.getMapper(SysApiKeyResourceMapper.class);
|
||||
String dir = System.getProperty("user.dir") + "/easyflow-api/easyflow-api-public/src/main/java/tech/easyflow/publicapi/controller";
|
||||
List<String> filePath = getAllFilePaths(dir);
|
||||
for (String path : filePath) {
|
||||
extractCommentsFromFile(path, mapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getAllFilePaths(String directoryPath) throws IOException {
|
||||
Path startPath = Paths.get(directoryPath);
|
||||
|
||||
try (Stream<Path> stream = Files.walk(startPath)) {
|
||||
return stream
|
||||
.filter(Files::isRegularFile) // 只获取文件,排除目录
|
||||
.map(Path::toAbsolutePath) // 转换为绝对路径
|
||||
.map(Path::toString) // 转换为字符串
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
public static void extractCommentsFromFile(String filePath, SysApiKeyResourceMapper mapper) throws Exception {
|
||||
System.out.println("正在解析文件: " + filePath);
|
||||
FileInputStream in = new FileInputStream(filePath);
|
||||
com.github.javaparser.JavaParser parser = new com.github.javaparser.JavaParser();
|
||||
parser.getParserConfiguration().setLanguageLevel(com.github.javaparser.ParserConfiguration.LanguageLevel.JAVA_17);
|
||||
CompilationUnit cu = parser.parse(in).getResult().orElseThrow();
|
||||
|
||||
cu.findAll(ClassOrInterfaceDeclaration.class).forEach(c -> {
|
||||
// 1. 获取类级别的 RequestMapping 路径
|
||||
String classPath = "";
|
||||
Optional<AnnotationExpr> classMapping = c.getAnnotationByName("RequestMapping");
|
||||
if (classMapping.isPresent()) {
|
||||
classPath = getAnnotationValue(classMapping.get());
|
||||
}
|
||||
|
||||
String finalClassPath = classPath; //用于lambda中使用
|
||||
String className = c.getNameAsString();
|
||||
String classComment = c.getJavadoc().map(d -> d.getDescription().toText()).orElse("");
|
||||
|
||||
System.out.println("=========================================");
|
||||
System.out.println("类名: " + className);
|
||||
System.out.println("类注释: " + classComment);
|
||||
System.out.println("类路径: " + finalClassPath);
|
||||
|
||||
// 2. 遍历方法
|
||||
c.getMethods().forEach(method -> {
|
||||
// 查找常见的 Mapping 注解
|
||||
String[] mappingTypes = {"GetMapping", "PostMapping", "PutMapping", "DeleteMapping", "PatchMapping", "RequestMapping"};
|
||||
|
||||
for (String mappingType : mappingTypes) {
|
||||
Optional<AnnotationExpr> methodMapping = method.getAnnotationByName(mappingType);
|
||||
if (methodMapping.isPresent()) {
|
||||
// 获取方法上的路径
|
||||
String methodPath = getAnnotationValue(methodMapping.get());
|
||||
|
||||
// 拼接完整 URI
|
||||
String fullUri = combinePaths(finalClassPath, methodPath);
|
||||
|
||||
// 获取请求方式 (如果是 RequestMapping,通常默认为 All 或者需要进一步解析 method 属性,这里简单处理)
|
||||
String httpMethod = mappingType.replace("Mapping", "").toUpperCase();
|
||||
if (httpMethod.equals("REQUEST")) httpMethod = "ALL";
|
||||
|
||||
// 获取方法注释
|
||||
String methodComment = method.getJavadoc().map(doc -> doc.getDescription().toText()).orElse("");
|
||||
|
||||
System.out.println("--------------------------------");
|
||||
System.out.println(" 方法名: " + method.getNameAsString());
|
||||
System.out.println(" 类型: " + httpMethod);
|
||||
System.out.println(" 完整URI: " + fullUri);
|
||||
System.out.println(" 方法注释: " + methodComment);
|
||||
|
||||
// 可以在这里调用 mapper 存入数据库
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(SysApiKeyResource::getRequestInterface, fullUri);
|
||||
SysApiKeyResource record = mapper.selectOneByQuery(w);
|
||||
if (record != null) {
|
||||
record.setTitle(methodComment);
|
||||
mapper.insertOrUpdate(record);
|
||||
} else {
|
||||
record = new SysApiKeyResource();
|
||||
record.setRequestInterface(fullUri);
|
||||
record.setTitle(methodComment);
|
||||
mapper.insert(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析注解中的 value 或 path 值
|
||||
* 处理几种情况:
|
||||
* 1. @GetMapping("/api") -> SingleMemberAnnotationExpr
|
||||
* 2. @GetMapping(value = "/api") -> NormalAnnotationExpr
|
||||
* 3. @GetMapping(path = "/api") -> NormalAnnotationExpr
|
||||
* 4. @GetMapping -> 默认为空字符串
|
||||
*/
|
||||
private static String getAnnotationValue(AnnotationExpr annotation) {
|
||||
// 情况 1: @GetMapping("/path")
|
||||
if (annotation instanceof SingleMemberAnnotationExpr) {
|
||||
String value = ((SingleMemberAnnotationExpr) annotation).getMemberValue().toString();
|
||||
return removeQuotes(value);
|
||||
}
|
||||
// 情况 2: @GetMapping(value="/path") 或 @GetMapping(path="/path")
|
||||
else if (annotation instanceof NormalAnnotationExpr) {
|
||||
NormalAnnotationExpr normal = (NormalAnnotationExpr) annotation;
|
||||
for (MemberValuePair pair : normal.getPairs()) {
|
||||
String key = pair.getNameAsString();
|
||||
if ("value".equals(key) || "path".equals(key)) {
|
||||
return removeQuotes(pair.getValue().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
// 情况 3: @GetMapping (没有参数)
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 去除 JavaParser 解析出的字符串中的双引号
|
||||
*/
|
||||
private static String removeQuotes(String value) {
|
||||
if (value == null) return "";
|
||||
return value.replace("\"", "").trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* 拼接类路径和方法路径,处理斜杠
|
||||
*/
|
||||
private static String combinePaths(String classPath, String methodPath) {
|
||||
if (classPath == null) classPath = "";
|
||||
if (methodPath == null) methodPath = "";
|
||||
|
||||
// 确保以 / 开头
|
||||
if (!classPath.startsWith("/") && !classPath.isEmpty()) classPath = "/" + classPath;
|
||||
if (!methodPath.startsWith("/") && !methodPath.isEmpty()) methodPath = "/" + methodPath;
|
||||
|
||||
// 如果 classPath 只有 /,去掉它,避免 //method
|
||||
if (classPath.equals("/")) classPath = "";
|
||||
|
||||
String full = classPath + methodPath;
|
||||
// 处理重复斜杠 (例如 class=/api/ method=/list -> /api//list)
|
||||
return full.replace("//", "/");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package tech.easyflow.publicapi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.easyagents.core.message.UserMessage;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import tech.easyflow.ai.entity.Bot;
|
||||
import tech.easyflow.ai.entity.ChatRequestParams;
|
||||
import tech.easyflow.ai.service.BotService;
|
||||
import tech.easyflow.ai.service.impl.BotServiceImpl;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.core.chat.protocol.sse.ChatSseUtil;
|
||||
import tech.easyflow.system.entity.SysApiKey;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* bot 接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/public-api/bot")
|
||||
public class PublicBotController {
|
||||
|
||||
@Resource
|
||||
private BotService botService;
|
||||
@Resource
|
||||
private SysApiKeyService sysApiKeyService;
|
||||
|
||||
/**
|
||||
* 根据id或别名获取bot详情
|
||||
*/
|
||||
@GetMapping("/getByIdOrAlias")
|
||||
public Result<Bot> getByIdOrAlias(@NotBlank(message = "key不能为空") String key) {
|
||||
return Result.ok(botService.getDetail(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 第三方调用聊天助手
|
||||
*
|
||||
* @return 返回SseEmitter对象,用于服务器向客户端推送聊天响应数据
|
||||
*/
|
||||
@PostMapping("chat")
|
||||
public SseEmitter chat(@RequestBody ChatRequestParams chatRequestParams, HttpServletRequest request) {
|
||||
String apikey = request.getHeader(SysApiKey.KEY_Apikey);
|
||||
String requestURI = request.getRequestURI();
|
||||
if (!StringUtils.hasText(apikey)) {
|
||||
return ChatSseUtil.sendSystemError(null, "Apikey不能为空!");
|
||||
}
|
||||
sysApiKeyService.checkApikeyPermission(apikey, requestURI);
|
||||
BotServiceImpl.ChatCheckResult chatCheckResult = new BotServiceImpl.ChatCheckResult();
|
||||
int size = chatRequestParams.getMessages().size();
|
||||
String prompt = null;
|
||||
if (chatRequestParams.getMessages().get(size - 1) instanceof UserMessage) {
|
||||
prompt = ((UserMessage) chatRequestParams.getMessages().get(size - 1)).getContent();
|
||||
}
|
||||
// 前置校验:失败则直接返回错误SseEmitter
|
||||
SseEmitter errorEmitter = botService.checkChatBeforeStart(chatRequestParams.getBotId(), prompt, chatRequestParams.getConversationId(), chatCheckResult);
|
||||
if (errorEmitter != null) {
|
||||
return errorEmitter;
|
||||
}
|
||||
return botService.startPublicChat(chatRequestParams.getBotId(), prompt, chatRequestParams.getMessages(), chatCheckResult);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package tech.easyflow.publicapi.controller;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import com.easyagents.flow.core.chain.ChainDefinition;
|
||||
import com.easyagents.flow.core.chain.Parameter;
|
||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||
import com.easyagents.flow.core.parser.ChainParser;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 工作流
|
||||
*/
|
||||
@RequestMapping("/public-api/workflow")
|
||||
@RestController
|
||||
public class PublicWorkflowController {
|
||||
|
||||
@Resource
|
||||
private WorkflowService workflowService;
|
||||
@Resource
|
||||
private ChainExecutor chainExecutor;
|
||||
@Resource
|
||||
private ChainParser chainParser;
|
||||
@Resource
|
||||
private TinyFlowService tinyFlowService;
|
||||
|
||||
/**
|
||||
* 通过id或别名获取工作流详情
|
||||
*
|
||||
* @param key id或者别名
|
||||
* @return 工作流详情
|
||||
*/
|
||||
@GetMapping(value = "/getByIdOrAlias")
|
||||
public Result<Workflow> getByIdOrAlias(
|
||||
@RequestParam
|
||||
@NotBlank(message = "key不能为空") String key) {
|
||||
Workflow workflow = workflowService.getDetail(key);
|
||||
return Result.ok(workflow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点单独运行
|
||||
*/
|
||||
@PostMapping("/singleRun")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<?> singleRun(
|
||||
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
||||
@JsonBody(value = "nodeId", required = true) String nodeId,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
|
||||
Workflow workflow = workflowService.getById(workflowId);
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "工作流不存在");
|
||||
}
|
||||
Map<String, Object> res = chainExecutor.executeNode(workflowId.toString(), nodeId, variables);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行工作流 - v2
|
||||
*/
|
||||
@PostMapping("/runAsync")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
if (variables == null) {
|
||||
variables = new HashMap<>();
|
||||
}
|
||||
Workflow workflow = workflowService.getById(id);
|
||||
if (workflow == null) {
|
||||
throw new RuntimeException("工作流不存在");
|
||||
}
|
||||
String executeId = chainExecutor.executeAsync(id.toString(), variables);
|
||||
return Result.ok(executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作流运行状态 - v2
|
||||
*/
|
||||
@PostMapping("/getChainStatus")
|
||||
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复工作流运行 - v2
|
||||
*/
|
||||
@PostMapping("/resume")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("getRunningParameters")
|
||||
@SaCheckPermission("/api/v1/workflow/query")
|
||||
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
||||
Workflow workflow = workflowService.getById(id);
|
||||
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "can not find the workflow by id: " + id);
|
||||
}
|
||||
|
||||
ChainDefinition definition = chainParser.parse(workflow.getContent());
|
||||
if (definition == null) {
|
||||
return Result.fail(2, "节点配置错误,请检查! ");
|
||||
}
|
||||
List<Parameter> chainParameters = definition.getStartParameters();
|
||||
Map<String, Object> res = new HashMap<>();
|
||||
res.put("parameters", chainParameters);
|
||||
res.put("title", workflow.getTitle());
|
||||
res.put("description", workflow.getDescription());
|
||||
res.put("icon", workflow.getIcon());
|
||||
return Result.ok(res);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package tech.easyflow.publicapi.interceptor;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
@Configuration
|
||||
public class PublicApiConfig implements WebMvcConfigurer {
|
||||
|
||||
@Resource
|
||||
private PublicApiInterceptor publicApiInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
|
||||
registry.addInterceptor(publicApiInterceptor)
|
||||
.addPathPatterns("/public-api/**")
|
||||
.excludePathPatterns("/public-api/bot/chat")
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package tech.easyflow.publicapi.interceptor;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.util.ResponseUtil;
|
||||
import tech.easyflow.system.service.SysApiKeyService;
|
||||
|
||||
@Component
|
||||
public class PublicApiInterceptor implements HandlerInterceptor {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PublicApiInterceptor.class);
|
||||
|
||||
@Resource
|
||||
private SysApiKeyService sysApiKeyService;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
|
||||
String requestURI = request.getRequestURI();
|
||||
String apiKey = request.getHeader("ApiKey");
|
||||
|
||||
if (apiKey == null || apiKey.isEmpty()) {
|
||||
Result<Void> failed = Result.fail(401, "密钥不正确");
|
||||
ResponseUtil.renderJson(response, failed);
|
||||
return false;
|
||||
}
|
||||
sysApiKeyService.checkApikeyPermission(apiKey, requestURI);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
29
easyflow-api/easyflow-api-usercenter/pom.xml
Normal file
29
easyflow-api/easyflow-api-usercenter/pom.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-api-usercenter</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-auth</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-module-ai</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow-common-captcha</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotCategory;
|
||||
import tech.easyflow.ai.service.BotCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
/**
|
||||
* bot分类 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/botCategory")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class UcBotCategoryController extends BaseCurdController<BotCategoryService, BotCategory> {
|
||||
public UcBotCategoryController(BotCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.mybatisflex.core.keygen.impl.SnowFlakeIDKeyGenerator;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
|
||||
import tech.easyflow.ai.entity.*;
|
||||
import tech.easyflow.ai.service.*;
|
||||
import tech.easyflow.ai.service.impl.BotServiceImpl;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.audio.core.AudioServiceManager;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-08-23
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/bot")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class UcBotController extends BaseCurdController<BotService, Bot> {
|
||||
|
||||
private final ModelService modelService;
|
||||
private final BotWorkflowService botWorkflowService;
|
||||
private final BotDocumentCollectionService botDocumentCollectionService;
|
||||
@Resource
|
||||
private BotService botService;
|
||||
@Autowired
|
||||
@Qualifier("defaultCache") // 指定 Bean 名称
|
||||
private Cache<String, Object> cache;
|
||||
@Resource
|
||||
private AudioServiceManager audioServiceManager;
|
||||
|
||||
public UcBotController(BotService service, ModelService modelService, BotWorkflowService botWorkflowService,
|
||||
BotDocumentCollectionService botDocumentCollectionService) {
|
||||
super(service);
|
||||
this.modelService = modelService;
|
||||
this.botWorkflowService = botWorkflowService;
|
||||
this.botDocumentCollectionService = botDocumentCollectionService;
|
||||
}
|
||||
|
||||
@Resource
|
||||
private BotPluginService botPluginService;
|
||||
@Resource
|
||||
private BotConversationService conversationMessageService;
|
||||
|
||||
@GetMapping("/generateConversationId")
|
||||
public Result<Long> generateConversationId() {
|
||||
long nextId = new SnowFlakeIDKeyGenerator().nextId();
|
||||
return Result.ok(nextId);
|
||||
}
|
||||
|
||||
@PostMapping("updateOptions")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateOptions(@JsonBody("id") BigInteger id,
|
||||
@JsonBody("options") Map<String, Object> options) {
|
||||
Bot aiBot = service.getById(id);
|
||||
Map<String, Object> existOptions = aiBot.getOptions();
|
||||
if (existOptions == null) {
|
||||
existOptions = new HashMap<>();
|
||||
}
|
||||
if (options != null) {
|
||||
existOptions.putAll(options);
|
||||
}
|
||||
aiBot.setOptions(existOptions);
|
||||
service.updateById(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("updateLlmOptions")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateLlmOptions(@JsonBody("id")
|
||||
BigInteger id, @JsonBody("llmOptions")
|
||||
Map<String, Object> llmOptions) {
|
||||
Bot aiBot = service.getById(id);
|
||||
Map<String, Object> existLlmOptions = aiBot.getModelOptions();
|
||||
if (existLlmOptions == null) {
|
||||
existLlmOptions = new HashMap<>();
|
||||
}
|
||||
if (llmOptions != null) {
|
||||
existLlmOptions.putAll(llmOptions);
|
||||
}
|
||||
aiBot.setModelOptions(existLlmOptions);
|
||||
service.updateById(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@PostMapping("voiceInput")
|
||||
@SaIgnore
|
||||
public Result<String> voiceInput(@RequestParam("audio")
|
||||
MultipartFile audioFile) {
|
||||
|
||||
String recognize = null;
|
||||
try {
|
||||
recognize = audioServiceManager.audioToText(audioFile.getInputStream());
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return Result.ok("", recognize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理聊天请求的接口方法
|
||||
*
|
||||
* @param prompt 用户输入的聊天内容,必须提供
|
||||
* @param botId 聊天机器人的唯一标识符,必须提供
|
||||
* @param conversationId 会话ID,用于标识当前对话会话,必须提供
|
||||
* @param messages 历史消息,用于提供上下文,可选
|
||||
* @return 返回SseEmitter对象,用于服务器向客户端推送聊天响应数据
|
||||
*/
|
||||
@PostMapping("chat")
|
||||
@SaIgnore
|
||||
public SseEmitter chat(
|
||||
@JsonBody(value = "prompt", required = true) String prompt,
|
||||
@JsonBody(value = "botId", required = true) BigInteger botId,
|
||||
@JsonBody(value = "conversationId", required = true) BigInteger conversationId,
|
||||
@JsonBody(value = "messages") List<Map<String, String>> messages,
|
||||
@JsonBody(value = "attachments") List<String> attachments
|
||||
|
||||
) {
|
||||
BotServiceImpl.ChatCheckResult chatCheckResult = new BotServiceImpl.ChatCheckResult();
|
||||
|
||||
// 前置校验:失败则直接返回错误SseEmitter
|
||||
SseEmitter errorEmitter = botService.checkChatBeforeStart(botId, prompt, conversationId.toString(), chatCheckResult);
|
||||
if (errorEmitter != null) {
|
||||
return errorEmitter;
|
||||
}
|
||||
BotConversation conversation = conversationMessageService.getById(conversationId);
|
||||
if (conversation == null) {
|
||||
conversation = new BotConversation();
|
||||
conversation.setId(conversationId);
|
||||
if (prompt.length() > 200) {
|
||||
conversation.setTitle(prompt.substring(0, 200));
|
||||
} else {
|
||||
conversation.setTitle(prompt);
|
||||
}
|
||||
conversation.setBotId(botId);
|
||||
conversation.setAccountId(SaTokenUtil.getLoginAccount().getId());
|
||||
commonFiled(conversation, SaTokenUtil.getLoginAccount().getId(), SaTokenUtil.getLoginAccount().getTenantId(), SaTokenUtil.getLoginAccount().getDeptId());
|
||||
conversationMessageService.save(conversation);
|
||||
}
|
||||
|
||||
return botService.startChat(botId, prompt, conversationId, messages, chatCheckResult, attachments);
|
||||
|
||||
}
|
||||
|
||||
@PostMapping("updateLlmId")
|
||||
@SaCheckPermission("/api/v1/bot/save")
|
||||
public Result<Void> updateBotLlmId(@RequestBody
|
||||
Bot aiBot) {
|
||||
service.updateBotLlmId(aiBot);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("getDetail")
|
||||
@SaIgnore
|
||||
public Result<Bot> getDetail(String id) {
|
||||
return Result.ok(botService.getDetail(id));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SaIgnore
|
||||
public Result<Bot> detail(String id) {
|
||||
Bot data = botService.getDetail(id);
|
||||
if (data == null) {
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
Map<String, Object> llmOptions = data.getModelOptions();
|
||||
if (llmOptions == null) {
|
||||
llmOptions = new HashMap<>();
|
||||
}
|
||||
|
||||
if (data.getModelId() == null) {
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
BigInteger llmId = data.getModelId();
|
||||
Model llm = modelService.getById(llmId);
|
||||
|
||||
if (llm == null) {
|
||||
data.setModelId(null);
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
Map<String, Object> options = llm.getOptions();
|
||||
|
||||
if (options != null && !options.isEmpty()) {
|
||||
|
||||
// 获取是否多模态
|
||||
Boolean multimodal = (Boolean) options.get("multimodal");
|
||||
llmOptions.put("multimodal", multimodal != null && multimodal);
|
||||
|
||||
}
|
||||
|
||||
return Result.ok(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Bot entity, boolean isSave) {
|
||||
|
||||
String alias = entity.getAlias();
|
||||
|
||||
if (StringUtils.hasLength(alias)) {
|
||||
Bot aiBot = service.getByAlias(alias);
|
||||
|
||||
if (aiBot != null && isSave) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
if (aiBot != null && aiBot.getId().compareTo(entity.getId()) != 0) {
|
||||
throw new BusinessException("别名已存在!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (isSave) {
|
||||
// 设置默认值
|
||||
entity.setModelOptions(getDefaultLlmOptions());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
private Map<String, Object> getDefaultLlmOptions() {
|
||||
Map<String, Object> defaultLlmOptions = new HashMap<>();
|
||||
defaultLlmOptions.put("temperature", 0.7);
|
||||
defaultLlmOptions.put("topK", 4);
|
||||
defaultLlmOptions.put("maxReplyLength", 2048);
|
||||
defaultLlmOptions.put("topP", 0.7);
|
||||
defaultLlmOptions.put("maxMessageCount", 10);
|
||||
return defaultLlmOptions;
|
||||
}
|
||||
|
||||
private Map<String, Object> errorRespnseMsg(int errorCode, String message) {
|
||||
HashMap<String, Object> result = new HashMap<>();
|
||||
result.put("error", errorCode);
|
||||
result.put("message", message);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
QueryWrapper queryWrapperKnowledge = QueryWrapper.create().in(BotDocumentCollection::getBotId, ids);
|
||||
botDocumentCollectionService.remove(queryWrapperKnowledge);
|
||||
QueryWrapper queryWrapperBotWorkflow = QueryWrapper.create().in(BotWorkflow::getBotId, ids);
|
||||
botWorkflowService.remove(queryWrapperBotWorkflow);
|
||||
QueryWrapper queryWrapperBotPlugins = QueryWrapper.create().in(BotPlugin::getBotId, ids);
|
||||
botPluginService.remove(queryWrapperBotPlugins);
|
||||
return super.onRemoveBefore(ids);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotConversation;
|
||||
import tech.easyflow.ai.service.BotConversationService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/botConversation")
|
||||
@SaIgnore
|
||||
public class UcBotConversationController extends BaseCurdController<BotConversationService, BotConversation> {
|
||||
|
||||
@Resource
|
||||
private BotConversationService conversationMessageService;
|
||||
|
||||
public UcBotConversationController(BotConversationService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定会话
|
||||
*/
|
||||
@GetMapping("/deleteConversation")
|
||||
public Result<Void> deleteConversation(String botId, String conversationId) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
conversationMessageService.deleteConversation(botId, conversationId, account.getId());
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新会话标题
|
||||
*/
|
||||
@GetMapping("/updateConversation")
|
||||
public Result<Void> updateConversation(String botId, String conversationId, String title) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
conversationMessageService.updateConversation(botId, conversationId, title, account.getId());
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<BotConversation>> list(BotConversation entity, Boolean asTree, String sortKey, String sortType) {
|
||||
entity.setAccountId(SaTokenUtil.getLoginAccount().getId());
|
||||
sortKey = "created";
|
||||
sortType = "desc";
|
||||
return super.list(entity, asTree, sortKey, sortType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(BotConversation entity, boolean isSave) {
|
||||
entity.setAccountId(SaTokenUtil.getLoginAccount().getId());
|
||||
entity.setCreated(new Date());
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询会话列表
|
||||
*
|
||||
* @param request 查询数据
|
||||
* @param sortKey 排序字段
|
||||
* @param sortType 排序方式 asc | desc
|
||||
* @param pageNumber 当前页码
|
||||
* @param pageSize 每页的数据量
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("pageList")
|
||||
public Result<Page<BotConversation>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
Page<BotConversation> botConversationPage = service.getMapper().paginateWithRelations(pageNumber, pageSize, queryWrapper);
|
||||
return Result.ok(botConversationPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据表主键查询数据详情。
|
||||
*
|
||||
* @param id 主键值
|
||||
* @return 内容详情
|
||||
*/
|
||||
@GetMapping("detail")
|
||||
@SaIgnore
|
||||
public Result<BotConversation> detail(String id) {
|
||||
if (tech.easyflow.common.util.StringUtil.noText(id)) {
|
||||
throw new BusinessException("id must not be null");
|
||||
}
|
||||
return Result.ok(service.getMapper().selectOneWithRelationsById(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.BotMessage;
|
||||
import tech.easyflow.ai.service.BotMessageService;
|
||||
import tech.easyflow.ai.vo.ChatMessageVO;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Bot 消息记录表 控制层。
|
||||
*
|
||||
* @author michael
|
||||
* @since 2024-11-04
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/botMessage")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class UcBotMessageController extends BaseCurdController<BotMessageService, BotMessage> {
|
||||
private final BotMessageService botMessageService;
|
||||
|
||||
public UcBotMessageController(BotMessageService service, BotMessageService botMessageService) {
|
||||
super(service);
|
||||
this.botMessageService = botMessageService;
|
||||
}
|
||||
|
||||
@GetMapping("/getMessages")
|
||||
@SaIgnore
|
||||
public Result<List<ChatMessageVO>> getMessages(BigInteger botId, BigInteger conversationId) {
|
||||
List<ChatMessageVO> res = new ArrayList<>();
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(BotMessage::getBotId, botId);
|
||||
w.eq(BotMessage::getConversationId, conversationId);
|
||||
List<BotMessage> list = botMessageService.list(w);
|
||||
if (CollectionUtil.isNotEmpty(list)) {
|
||||
for (BotMessage message : list) {
|
||||
ChatMessageVO vo = new ChatMessageVO();
|
||||
vo.setKey(message.getId().toString());
|
||||
vo.setRole(message.getRole());
|
||||
vo.setContent(JSON.parseObject(message.getContent()).getString("textContent"));
|
||||
vo.setPlacement("user".equals(message.getRole()) ? "end" : "start");
|
||||
vo.setCreated(message.getCreated());
|
||||
res.add(vo);
|
||||
}
|
||||
}
|
||||
return Result.ok(res);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.Bot;
|
||||
import tech.easyflow.ai.entity.BotRecentlyUsed;
|
||||
import tech.easyflow.ai.service.BotRecentlyUsedService;
|
||||
import tech.easyflow.ai.service.BotService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 最近使用 控制层。
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/botRecentlyUsed")
|
||||
@UsePermission(moduleName = "/api/v1/bot")
|
||||
public class UcBotRecentlyUsedController extends BaseCurdController<BotRecentlyUsedService, BotRecentlyUsed> {
|
||||
|
||||
@Resource
|
||||
private BotService botService;
|
||||
|
||||
public UcBotRecentlyUsedController(BotRecentlyUsedService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@GetMapping("/getRecentlyBot")
|
||||
public Result<List<Bot>> getRecentlyBot() {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(BotRecentlyUsed::getCreatedBy,account.getId());
|
||||
w.orderBy(BotRecentlyUsed::getSortNo,true);
|
||||
List<BotRecentlyUsed> list = service.list(w);
|
||||
if (CollectionUtil.isNotEmpty(list)) {
|
||||
List<BigInteger> botIds = list.stream().map(BotRecentlyUsed::getBotId).collect(Collectors.toList());
|
||||
QueryWrapper botQw = QueryWrapper.create();
|
||||
botQw.in(Bot::getId,botIds);
|
||||
List<Bot> listBot = botService.list(botQw);
|
||||
listBot.sort(Comparator.comparing(bot -> botIds.indexOf(bot.getId())));
|
||||
return Result.ok(listBot);
|
||||
}
|
||||
return Result.ok(new ArrayList<>());
|
||||
}
|
||||
|
||||
@GetMapping("/removeByBotId")
|
||||
public Result<Void> removeByBotId(BigInteger botId) {
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(BotRecentlyUsed::getBotId,botId);
|
||||
w.eq(BotRecentlyUsed::getCreatedBy,SaTokenUtil.getLoginAccount().getId());
|
||||
service.remove(w);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Result<List<BotRecentlyUsed>> list(BotRecentlyUsed entity, Boolean asTree, String sortKey, String sortType) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
entity.setCreatedBy(account.getId());
|
||||
return super.list(entity, asTree, sortKey, sortType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(BotRecentlyUsed entity, boolean isSave) {
|
||||
entity.setCreated(new Date());
|
||||
entity.setCreatedBy(SaTokenUtil.getLoginAccount().getId());
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.hutool.core.io.FileTypeUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.Resource;
|
||||
import tech.easyflow.ai.service.ResourceService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 素材库
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-06-27
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/resource")
|
||||
@UsePermission(moduleName = "/api/v1/resource")
|
||||
public class UcResourceController extends BaseCurdController<ResourceService, Resource> {
|
||||
public UcResourceController(ResourceService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Resource entity, boolean isSave) {
|
||||
LoginAccount loginUser = SaTokenUtil.getLoginAccount();
|
||||
if (isSave) {
|
||||
String resourceUrl = entity.getResourceUrl();
|
||||
byte[] bytes = HttpUtil.downloadBytes(resourceUrl);
|
||||
ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
|
||||
String suffix = FileTypeUtil.getType(stream, resourceUrl);
|
||||
entity.setSuffix(suffix);
|
||||
entity.setFileSize(BigInteger.valueOf(bytes.length));
|
||||
commonFiled(entity,loginUser.getId(),loginUser.getTenantId(), loginUser.getDeptId());
|
||||
} else {
|
||||
entity.setModified(new Date());
|
||||
entity.setModifiedBy(loginUser.getId());
|
||||
}
|
||||
return super.onSaveOrUpdateBefore(entity, isSave);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<Resource> queryPage(Page<Resource> page, QueryWrapper queryWrapper) {
|
||||
queryWrapper.eq(Resource::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
||||
return super.queryPage(page, queryWrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.WorkflowCategory;
|
||||
import tech.easyflow.ai.service.WorkflowCategoryService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 工作流分类
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-12-11
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/workflowCategory")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class UcWorkflowCategoryController extends BaseCurdController<WorkflowCategoryService, WorkflowCategory> {
|
||||
|
||||
public UcWorkflowCategoryController(WorkflowCategoryService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(WorkflowCategory entity, boolean isSave) {
|
||||
return Result.fail("-");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
return Result.fail("-");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import com.easyagents.flow.core.chain.*;
|
||||
import com.easyagents.flow.core.chain.runtime.ChainExecutor;
|
||||
import com.easyagents.flow.core.parser.ChainParser;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.ai.entity.Workflow;
|
||||
import tech.easyflow.ai.service.WorkflowService;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.ChainInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.entity.NodeInfo;
|
||||
import tech.easyflow.ai.easyagentsflow.service.TinyFlowService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 工作流
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/workflow")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class UcWorkflowController extends BaseCurdController<WorkflowService, Workflow> {
|
||||
|
||||
@Resource
|
||||
private ChainExecutor chainExecutor;
|
||||
@Resource
|
||||
private ChainParser chainParser;
|
||||
@Resource
|
||||
private TinyFlowService tinyFlowService;
|
||||
|
||||
public UcWorkflowController(WorkflowService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点单独运行
|
||||
*/
|
||||
@PostMapping("/singleRun")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<?> singleRun(
|
||||
@JsonBody(value = "workflowId", required = true) BigInteger workflowId,
|
||||
@JsonBody(value = "nodeId", required = true) String nodeId,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
|
||||
Workflow workflow = service.getById(workflowId);
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "工作流不存在");
|
||||
}
|
||||
Map<String, Object> res = chainExecutor.executeNode(workflowId.toString(), nodeId, variables);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 运行工作流 - v2
|
||||
*/
|
||||
@PostMapping("/runAsync")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<String> runAsync(@JsonBody(value = "id", required = true) BigInteger id,
|
||||
@JsonBody("variables") Map<String, Object> variables) {
|
||||
if (variables == null) {
|
||||
variables = new HashMap<>();
|
||||
}
|
||||
Workflow workflow = service.getById(id);
|
||||
if (workflow == null) {
|
||||
throw new RuntimeException("工作流不存在");
|
||||
}
|
||||
if (StpUtil.isLogin()) {
|
||||
variables.put(Constants.LOGIN_USER_KEY, SaTokenUtil.getLoginAccount());
|
||||
}
|
||||
String executeId = chainExecutor.executeAsync(id.toString(), variables);
|
||||
return Result.ok(executeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作流运行状态 - v2
|
||||
*/
|
||||
@PostMapping("/getChainStatus")
|
||||
public Result<ChainInfo> getChainStatus(@JsonBody(value = "executeId") String executeId,
|
||||
@JsonBody("nodes") List<NodeInfo> nodes) {
|
||||
ChainInfo res = tinyFlowService.getChainStatus(executeId, nodes);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复工作流运行 - v2
|
||||
*/
|
||||
@PostMapping("/resume")
|
||||
@SaCheckPermission("/api/v1/workflow/save")
|
||||
public Result<Void> resume(@JsonBody(value = "executeId", required = true) String executeId,
|
||||
@JsonBody("confirmParams") Map<String, Object> confirmParams) {
|
||||
chainExecutor.resumeAsync(executeId, confirmParams);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作流参数 - v2
|
||||
*/
|
||||
@GetMapping("getRunningParameters")
|
||||
@SaCheckPermission("/api/v1/workflow/query")
|
||||
public Result<?> getRunningParameters(@RequestParam BigInteger id) {
|
||||
Workflow workflow = service.getById(id);
|
||||
|
||||
if (workflow == null) {
|
||||
return Result.fail(1, "can not find the workflow by id: " + id);
|
||||
}
|
||||
|
||||
ChainDefinition definition = chainParser.parse(workflow.getContent());
|
||||
if (definition == null) {
|
||||
return Result.fail(2, "节点配置错误,请检查! ");
|
||||
}
|
||||
List<Parameter> chainParameters = definition.getStartParameters();
|
||||
Map<String, Object> res = new HashMap<>();
|
||||
res.put("parameters", chainParameters);
|
||||
res.put("title", workflow.getTitle());
|
||||
res.put("description", workflow.getDescription());
|
||||
res.put("icon", workflow.getIcon());
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onSaveOrUpdateBefore(Workflow entity, boolean isSave) {
|
||||
return Result.fail("-");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Result<?> onRemoveBefore(Collection<Serializable> ids) {
|
||||
return Result.fail("-");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaCheckPermission;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.entity.WorkflowExecStep;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.ai.service.WorkflowExecStepService;
|
||||
import tech.easyflow.ai.utils.WorkFlowUtil;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
|
||||
/**
|
||||
* 工作流执行记录
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/workflowExecResult")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class UcWorkflowExecResultController extends BaseCurdController<WorkflowExecResultService, WorkflowExecResult> {
|
||||
|
||||
@Resource
|
||||
private WorkflowExecStepService recordStepService;
|
||||
|
||||
public UcWorkflowExecResultController(WorkflowExecResultService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
@GetMapping("/del")
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@SaCheckPermission("/api/v1/workflow/remove")
|
||||
public Result<Void> del(BigInteger id) {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
WorkflowExecResult record = service.getById(id);
|
||||
if (!account.getId().toString().equals(record.getCreatedBy())) {
|
||||
return Result.fail(1, "非法请求");
|
||||
}
|
||||
service.removeById(id);
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(WorkflowExecStep::getRecordId, id);
|
||||
recordStepService.remove(w);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
@GetMapping("getPage")
|
||||
public Result<Page<WorkflowExecResult>> getPage(HttpServletRequest request,
|
||||
String sortKey,
|
||||
String sortType,
|
||||
Long pageNumber,
|
||||
Long pageSize,
|
||||
String queryBegin,
|
||||
String queryEnd) {
|
||||
if (pageNumber == null || pageNumber < 1) {
|
||||
pageNumber = 1L;
|
||||
}
|
||||
if (pageSize == null || pageSize < 1) {
|
||||
pageSize = 10L;
|
||||
}
|
||||
|
||||
QueryWrapper queryWrapper = buildQueryWrapper(request);
|
||||
if (StrUtil.isNotEmpty(queryBegin) && StrUtil.isNotEmpty(queryEnd)) {
|
||||
queryWrapper.between(WorkflowExecResult::getStartTime, queryBegin, queryEnd);
|
||||
}
|
||||
queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
|
||||
return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Page<WorkflowExecResult> queryPage(Page<WorkflowExecResult> page, QueryWrapper queryWrapper) {
|
||||
queryWrapper.eq(WorkflowExecResult::getCreatedBy, SaTokenUtil.getLoginAccount().getId().toString());
|
||||
Page<WorkflowExecResult> res = super.queryPage(page, queryWrapper);
|
||||
for (WorkflowExecResult record : res.getRecords()) {
|
||||
record.setWorkflowJson(WorkFlowUtil.removeSensitiveInfo(record.getWorkflowJson()));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package tech.easyflow.usercenter.controller.ai;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.ai.entity.WorkflowExecResult;
|
||||
import tech.easyflow.ai.entity.WorkflowExecStep;
|
||||
import tech.easyflow.ai.service.WorkflowExecResultService;
|
||||
import tech.easyflow.ai.service.WorkflowExecStepService;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.exceptions.BusinessException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 执行记录步骤
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/workflowExecStep")
|
||||
@UsePermission(moduleName = "/api/v1/workflow")
|
||||
public class UcWorkflowExecStepController extends BaseCurdController<WorkflowExecStepService, WorkflowExecStep> {
|
||||
|
||||
@Resource
|
||||
private WorkflowExecResultService execRecordService;
|
||||
|
||||
public UcWorkflowExecStepController(WorkflowExecStepService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据执行记录id获取执行记录步骤列表
|
||||
*/
|
||||
@GetMapping("/getListByRecordId")
|
||||
public Result<List<WorkflowExecStep>> getListByRecordId(BigInteger recordId) {
|
||||
if (recordId == null) {
|
||||
throw new BusinessException("recordId不能为空!");
|
||||
}
|
||||
WorkflowExecResult record = execRecordService.getById(recordId);
|
||||
String workflowJson = record.getWorkflowJson();
|
||||
JSONObject workflow = JSON.parseObject(workflowJson);
|
||||
Map<String, String> idTypeMap = new HashMap<>();
|
||||
JSONArray nodes = workflow.getJSONArray("nodes");
|
||||
for (Object node : nodes) {
|
||||
JSONObject nodeObj = (JSONObject) node;
|
||||
idTypeMap.put(nodeObj.getString("id"), nodeObj.getString("type"));
|
||||
}
|
||||
QueryWrapper w = QueryWrapper.create();
|
||||
w.eq(WorkflowExecStep::getRecordId, recordId);
|
||||
List<WorkflowExecStep> list = service.list(w);
|
||||
for (WorkflowExecStep step : list) {
|
||||
step.setNodeData(null);
|
||||
step.setNodeType(idTypeMap.get(step.getNodeId()));
|
||||
}
|
||||
return Result.ok(list);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package tech.easyflow.usercenter.controller.auth;
|
||||
|
||||
import cn.dev33.satoken.stp.StpUtil;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import tech.easyflow.auth.entity.LoginDTO;
|
||||
import tech.easyflow.auth.entity.LoginVO;
|
||||
import tech.easyflow.auth.service.AuthService;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 认证
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/auth/")
|
||||
public class UcAuthController {
|
||||
|
||||
@Resource
|
||||
private AuthService authService;
|
||||
|
||||
/**
|
||||
* 登录
|
||||
* @param loginDTO 登录参数
|
||||
*/
|
||||
@PostMapping("login")
|
||||
public Result<LoginVO> login(@JsonBody LoginDTO loginDTO) {
|
||||
LoginVO res = authService.login(loginDTO);
|
||||
return Result.ok(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* 登出
|
||||
*/
|
||||
@PostMapping("logout")
|
||||
public Result<Void> logout() {
|
||||
StpUtil.logout();
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取权限
|
||||
*/
|
||||
@GetMapping("getPermissions")
|
||||
public Result<List<String>> getPermissions() {
|
||||
List<String> permissionList = StpUtil.getPermissionList();
|
||||
return Result.ok(permissionList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package tech.easyflow.usercenter.controller.common;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.dict.Dict;
|
||||
import tech.easyflow.common.dict.DictItem;
|
||||
import tech.easyflow.common.dict.DictLoader;
|
||||
import tech.easyflow.common.dict.DictManager;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 字典
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/dict/")
|
||||
public class UcDictController {
|
||||
|
||||
@Resource
|
||||
DictManager dictManager;
|
||||
|
||||
/**
|
||||
* 获取字典项
|
||||
*/
|
||||
@GetMapping("/items/{code}")
|
||||
public Result<List<DictItem>> items(@PathVariable("code") String code, String keyword, HttpServletRequest request) {
|
||||
DictLoader loader = dictManager.getLoader(code);
|
||||
if (loader == null) {
|
||||
return Result.ok(Collections.emptyList());
|
||||
}
|
||||
Map<String, String[]> parameterMap = request.getParameterMap();
|
||||
Dict dict = loader.load(keyword, parameterMap);
|
||||
if (dict == null) {
|
||||
return Result.ok(Collections.emptyList());
|
||||
}
|
||||
return Result.ok(dict.getItems());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package tech.easyflow.usercenter.controller.common;
|
||||
|
||||
import cloud.tianai.captcha.application.ImageCaptchaApplication;
|
||||
import cloud.tianai.captcha.application.vo.ImageCaptchaVO;
|
||||
import cloud.tianai.captcha.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.common.response.ApiResponse;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.captcha.tainai.CaptchaData;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 公共接口
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/public")
|
||||
public class UcPublicController {
|
||||
|
||||
@Resource
|
||||
private ImageCaptchaApplication application;
|
||||
|
||||
/**
|
||||
* 获取验证码
|
||||
*/
|
||||
@RequestMapping(value = "/getCaptcha", produces = "application/json")
|
||||
public ApiResponse<ImageCaptchaVO> getCaptcha() {
|
||||
return application.generateCaptcha(CaptchaTypeConstant.SLIDER);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证码校验
|
||||
*/
|
||||
@PostMapping(value = "/check", produces = "application/json")
|
||||
public ApiResponse<String> checkCaptcha(@RequestBody CaptchaData data) {
|
||||
ApiResponse<?> response = application.matching(data.getId(), data.getData());
|
||||
if (!response.isSuccess()) {
|
||||
return ApiResponse.ofError("验证码错误");
|
||||
}
|
||||
return ApiResponse.ofSuccess(data.getId());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package tech.easyflow.usercenter.controller.common;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.vo.UploadResVo;
|
||||
import tech.easyflow.common.filestorage.FileStorageService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/commons/")
|
||||
public class UcUploadController {
|
||||
|
||||
@Resource(name = "default")
|
||||
private FileStorageService storageService;
|
||||
|
||||
/**
|
||||
* 上传
|
||||
*/
|
||||
@PostMapping(value = "/upload", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Result<UploadResVo> upload(MultipartFile file) {
|
||||
String path = storageService.save(file);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@PostMapping(value = "/uploadAntd", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public Result<UploadResVo> uploadAntd(MultipartFile file) {
|
||||
String path = storageService.save(file);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ignore
|
||||
*/
|
||||
@PostMapping(value = "/uploadPrePath",produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@SaIgnore
|
||||
public Result<UploadResVo> uploadPrePath(MultipartFile file, String prePath) {
|
||||
String path = storageService.save(file,prePath);
|
||||
UploadResVo resVo = new UploadResVo();
|
||||
resVo.setPath(path);
|
||||
return Result.ok(resVo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package tech.easyflow.usercenter.controller.system;
|
||||
|
||||
import cn.hutool.crypto.digest.BCrypt;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysAccount;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 用户
|
||||
*
|
||||
* @author ArkLight
|
||||
* @since 2025-03-14
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/sysAccount")
|
||||
public class UcSysAccountController {
|
||||
|
||||
@Resource
|
||||
private SysAccountService service;
|
||||
|
||||
/**
|
||||
* 获取用户的信息
|
||||
*/
|
||||
@GetMapping("/myProfile")
|
||||
public Result<SysAccount> myProfile() {
|
||||
LoginAccount account = SaTokenUtil.getLoginAccount();
|
||||
SysAccount sysAccount = service.getById(account.getId());
|
||||
return Result.ok(sysAccount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改用户信息
|
||||
*/
|
||||
@PostMapping("/updateProfile")
|
||||
public Result<Void> updateProfile(@JsonBody SysAccount account) {
|
||||
BigInteger loginAccountId = SaTokenUtil.getLoginAccount().getId();
|
||||
SysAccount update = new SysAccount();
|
||||
update.setId(loginAccountId);
|
||||
update.setNickname(account.getNickname());
|
||||
update.setMobile(account.getMobile());
|
||||
update.setEmail(account.getEmail());
|
||||
update.setAvatar(account.getAvatar());
|
||||
update.setModified(new Date());
|
||||
update.setModifiedBy(loginAccountId);
|
||||
service.updateById(update);
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改密码
|
||||
*
|
||||
* @param password 用户的旧密码
|
||||
* @param newPassword 新密码
|
||||
* @param confirmPassword 确认密码
|
||||
*/
|
||||
@PostMapping("/updatePassword")
|
||||
public Result<Void> updatePassword(@JsonBody(value = "password", required = true) String password,
|
||||
@JsonBody(value = "newPassword", required = true) String newPassword,
|
||||
@JsonBody(value = "confirmPassword", required = true) String confirmPassword) {
|
||||
BigInteger loginAccountId = SaTokenUtil.getLoginAccount().getId();
|
||||
SysAccount record = service.getById(loginAccountId);
|
||||
if (record == null) {
|
||||
return Result.fail("修改失败");
|
||||
}
|
||||
String pwdDb = record.getPassword();
|
||||
if (!BCrypt.checkpw(password, pwdDb)) {
|
||||
return Result.fail(1, "密码不正确");
|
||||
}
|
||||
if (!newPassword.equals(confirmPassword)) {
|
||||
return Result.fail(2, "两次密码不一致");
|
||||
}
|
||||
SysAccount update = new SysAccount();
|
||||
update.setId(loginAccountId);
|
||||
update.setPassword(BCrypt.hashpw(newPassword));
|
||||
update.setModified(new Date());
|
||||
update.setModifiedBy(loginAccountId);
|
||||
service.updateById(update);
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package tech.easyflow.usercenter.controller.system;
|
||||
|
||||
import cn.dev33.satoken.annotation.SaIgnore;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import tech.easyflow.common.annotation.UsePermission;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.web.controller.BaseCurdController;
|
||||
import tech.easyflow.common.web.jsonbody.JsonBody;
|
||||
import tech.easyflow.system.entity.SysUserFeedback;
|
||||
import tech.easyflow.system.service.SysUserFeedbackService;
|
||||
|
||||
|
||||
/**
|
||||
* 控制层。
|
||||
*
|
||||
* @author 12076
|
||||
* @since 2025-12-30
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/userCenter/sysUserFeedback")
|
||||
@UsePermission(moduleName = "/api/v1/sysUserFeedback")
|
||||
public class UcUserFeedbackController extends BaseCurdController<SysUserFeedbackService, SysUserFeedback> {
|
||||
|
||||
@PostMapping("/save")
|
||||
@SaIgnore
|
||||
public Result<?> save(@JsonBody SysUserFeedback entity) {
|
||||
return super.save(entity);
|
||||
}
|
||||
|
||||
public UcUserFeedbackController(SysUserFeedbackService service) {
|
||||
super(service);
|
||||
}
|
||||
|
||||
}
|
||||
22
easyflow-api/pom.xml
Normal file
22
easyflow-api/pom.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>tech.easyflow</groupId>
|
||||
<artifactId>easyflow</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>easyflow-api</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>easyflow-api-admin</module>
|
||||
<module>easyflow-api-mcp</module>
|
||||
<module>easyflow-api-public</module>
|
||||
<module>easyflow-api-usercenter</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
||||
Reference in New Issue
Block a user