docs 补充项目注释

This commit is contained in:
AprilWind
2026-06-01 13:58:13 +08:00
parent 107d3326b4
commit e49f3b2260
94 changed files with 2328 additions and 68 deletions
@@ -46,13 +46,22 @@ import java.util.concurrent.atomic.AtomicBoolean;
OpenApiConversationClient.class, OpenApiUserClient.class})
public class SnailAiController extends BaseController {
/**
* Snail AI 成功状态码。
*/
private static final int SNAIL_AI_SUCCESS = 1;
/**
* SSE 超时时间。
*/
private static final long SSE_TIMEOUT = 300000L;
private final OpenApiAgentClient agentClient;
private final OpenApiChatClient chatClient;
private final OpenApiConversationClient conversationClient;
private final OpenApiUserClient userClient;
/**
* 聊天模式。
*/
@Value("${snail-ai.chat-mode:stream}")
private String chatMode;
@@ -97,8 +106,8 @@ public class SnailAiController extends BaseController {
*/
@PostMapping("/agent/{agentId}/conversation")
public R<OpenApiConversationVO> createConversation(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiCreateConversationRequest request) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiCreateConversationRequest request) {
request.setAgentId(agentId);
request.setOpenId(ensureOpenId());
return toR(conversationClient.createConversation(request));
@@ -109,9 +118,9 @@ public class SnailAiController extends BaseController {
*/
@GetMapping("/agent/{agentId}/conversations")
public R<PageResult<OpenApiConversationVO>> listConversations(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@Min(value = 1, message = "页码不能小于1") @RequestParam(defaultValue = "1") int page,
@Min(value = 1, message = "每页条数不能小于1") @RequestParam(defaultValue = "10") int size) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@Min(value = 1, message = "页码不能小于1") @RequestParam(defaultValue = "1") int page,
@Min(value = 1, message = "每页条数不能小于1") @RequestParam(defaultValue = "10") int size) {
OpenApiConversationQueryRequest request = new OpenApiConversationQueryRequest();
request.setAgentId(agentId);
request.setOpenId(ensureOpenId());
@@ -125,8 +134,8 @@ public class SnailAiController extends BaseController {
*/
@GetMapping("/agent/{agentId}/conversation/{conversationId}/messages")
public R<List<OpenApiMessageVO>> getMessages(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@NotBlank(message = "会话ID不能为空") @PathVariable String conversationId) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@NotBlank(message = "会话ID不能为空") @PathVariable String conversationId) {
OpenApiConversationIdentityRequest request = new OpenApiConversationIdentityRequest();
request.setAgentId(agentId);
request.setConversationId(conversationId);
@@ -139,8 +148,8 @@ public class SnailAiController extends BaseController {
*/
@DeleteMapping("/agent/{agentId}/conversation/{conversationId}")
public R<Void> deleteConversation(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@NotBlank(message = "会话ID不能为空") @PathVariable String conversationId) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@NotBlank(message = "会话ID不能为空") @PathVariable String conversationId) {
OpenApiConversationIdentityRequest request = new OpenApiConversationIdentityRequest();
request.setAgentId(agentId);
request.setConversationId(conversationId);
@@ -162,8 +171,8 @@ public class SnailAiController extends BaseController {
*/
@PostMapping("/agent/{agentId}/chat/sync")
public R<OpenApiChatSyncResponse> chatSync(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiChatRequest request) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiChatRequest request) {
request.setAgentId(agentId);
request.setOpenId(ensureOpenId());
log.info("Sync chat request: agentId={}", agentId);
@@ -175,9 +184,9 @@ public class SnailAiController extends BaseController {
*/
@PostMapping(value = "/agent/{agentId}/chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public SseEmitter chatStream(
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiChatRequest request,
HttpServletResponse response) {
@NotNull(message = "智能体ID不能为空") @PathVariable Long agentId,
@RequestBody OpenApiChatRequest request,
HttpServletResponse response) {
prepareSseResponse(response);
SseEmitter emitter = new SseEmitter(SSE_TIMEOUT);
AtomicBoolean closed = new AtomicBoolean(false);
@@ -202,16 +211,31 @@ public class SnailAiController extends BaseController {
log.info("Stream chat request: agentId={}", agentId);
try {
chatClient.chatStream(request, new SseEventListener() {
/**
* 推送普通文本片段。
*
* @param text 文本片段
*/
@Override
public void onText(String text) {
safeSend(emitter, closed, "text", text);
}
/**
* 推送思考内容片段。
*
* @param thinking 思考内容
*/
@Override
public void onThinking(String thinking) {
safeSend(emitter, closed, "thinking", thinking);
}
/**
* 处理流式对话完成事件。
*
* @param data 完成数据
*/
@Override
public void onComplete(String data) {
if (!closed.get()) {
@@ -223,6 +247,11 @@ public class SnailAiController extends BaseController {
}
}
/**
* 处理流式对话异常事件。
*
* @param errorMessage 错误信息
*/
@Override
public void onError(String errorMessage) {
log.error("Stream chat error: {}", errorMessage);
@@ -12,9 +12,22 @@ import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class PriorityDemo implements Comparable<PriorityDemo> {
/**
* 队列元素名称。
*/
private String name;
/**
* 优先级排序值。
*/
private Integer orderNum;
/**
* 按排序值比较优先级。
*
* @param other 另一个队列元素
* @return 比较结果
*/
@Override
public int compareTo(PriorityDemo other) {
return Integer.compare(getOrderNum(), other.getOrderNum());
@@ -18,11 +18,20 @@ import java.util.List;
*/
public class ExportDemoListener extends DefaultExcelListener<ExportDemoVo> {
/**
* 创建下拉框导入解析监听器。
*/
public ExportDemoListener() {
// 显示使用构造函数,否则将导致空指针
super(true);
}
/**
* 解析并校验一行下拉框演示数据。
*
* @param data 行数据
* @param context 解析上下文
*/
@Override
public void invoke(ExportDemoVo data, AnalysisContext context) {
// 先校验必填
@@ -23,12 +23,26 @@ import java.util.List;
*/
public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
/**
* 自定义分页查询演示数据。
*
* @param page 分页对象
* @param wrapper 查询条件
* @return 分页结果
*/
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@DataColumn(key = "userName", value = "user_id")
})
Page<TestDemoVo> customPageList(@Param("page") Page<TestDemo> page, @Param("ew") Wrapper<TestDemo> wrapper);
/**
* 分页查询演示 VO 列表并应用数据权限。
*
* @param page 分页对象
* @param wrapper 查询条件
* @return 分页结果
*/
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@@ -38,6 +52,12 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
return selectVoPage(page, wrapper, this.currentVoClass());
}
/**
* 查询演示 VO 列表并应用数据权限。
*
* @param wrapper 查询条件
* @return 演示 VO 列表
*/
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@@ -47,6 +67,12 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
return selectVoList(wrapper, this.currentVoClass());
}
/**
* 按主键集合查询演示数据并应用数据权限。
*
* @param idList 主键集合
* @return 演示数据列表
*/
@Override
@DataPermission(value = {
@DataColumn(key = "deptName", value = "dept_id"),
@@ -54,6 +80,12 @@ public interface TestDemoMapper extends BaseMapperPlus<TestDemo, TestDemoVo> {
}, joinStr = "AND")
List<TestDemo> selectByIds(@Param(Constants.COLL) Collection<? extends Serializable> idList);
/**
* 按主键更新演示数据并应用数据权限。
*
* @param entity 演示数据实体
* @return 更新行数
*/
@Override
@DataPermission({
@DataColumn(key = "deptName", value = "dept_id"),
@@ -1,9 +1,9 @@
package org.dromara.demo.mcp;
import lombok.RequiredArgsConstructor;
import org.dromara.common.mcp.core.McpClientTemplate;
import org.dromara.common.mcp.core.McpResourceReadResult;
import org.dromara.common.mcp.core.McpToolCallResult;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.stereotype.Service;
@@ -42,7 +42,7 @@ public class McpDemoClientService {
/**
* 调用外部 MCP 工具接收数据。
*
* @param toolName 工具名称
* @param toolName 工具名称
* @param arguments 工具参数
* @return 工具返回内容
*/
@@ -65,7 +65,7 @@ public class McpDemoClientService {
* <p>
* MCP 返回数据不建议直接入库,应先转换成业务 BO/DTO,再进入业务 Service。
*
* @param toolName 工具名称
* @param toolName 工具名称
* @param arguments 工具参数
* @return 处理结果
*/
@@ -73,6 +73,13 @@ public class McpDemoClientService {
return new McpDemoHandleResult("MCP", true, callRemoteTool(toolName, arguments));
}
/**
* 执行 MCP Client 操作。
*
* @param action MCP Client 操作
* @param <T> 返回值类型
* @return 操作结果
*/
private <T> T execute(Function<McpClientTemplate, T> action) {
McpClientTemplate template = mcpClientTemplateProvider.getIfAvailable();
if (template == null) {
@@ -85,8 +92,8 @@ public class McpDemoClientService {
* MCP 数据处理结果。
*
* @param sourceType 数据来源类型
* @param handled 是否已处理
* @param data MCP 原始返回数据
* @param handled 是否已处理
* @param data MCP 原始返回数据
*/
public record McpDemoHandleResult(
String sourceType,
@@ -28,6 +28,11 @@ import java.util.Map;
@RequiredArgsConstructor
public class ExportExcelServiceImpl implements IExportExcelService {
/**
* 导出带下拉框选项的 Excel 示例文件。
*
* @param response HTTP 响应
*/
@Override
public void exportWithOptions(HttpServletResponse response) {
// 创建表格数据,业务中一般通过数据库查询
@@ -106,6 +111,13 @@ public class ExportExcelServiceImpl implements IExportExcelService {
.toResponse(response);
}
/**
* 构建下拉框显示值。
*
* @param cityDataList 城市演示数据列表
* @param id 选项 id
* @return 下拉框显示值
*/
private String buildOptions(List<DemoCityData> cityDataList, Integer id) {
Map<Integer, List<DemoCityData>> groupByIdMap =
StreamUtils.groupByKey(cityDataList, DemoCityData::getId);
@@ -246,6 +258,11 @@ public class ExportExcelServiceImpl implements IExportExcelService {
}
/**
* 自定义写入多个工作表。
*
* @param response HTTP 响应
*/
@Override
public void customExport(HttpServletResponse response) {
ExcelBuilder.writer(ExportDemoVo.class).sheetName("自定义导出").toResponse(response, wrapper -> {
@@ -460,8 +460,8 @@ public class GenTableServiceImpl implements IGenTableService {
/**
* 模板渲染上下文。
*
* @param table 生成表信息
* @param context 模板上下文
* @param table 生成表信息
* @param context 模板上下文
* @param templates 待渲染模板
*/
private record RenderContext(GenTable table, Dict context, List<PathNamedTemplate> templates) {
@@ -488,6 +488,11 @@ public class GenTableServiceImpl implements IGenTableService {
}
}
/**
* 校验生成选项中配置的字段是否存在。
*
* @param genTable 业务表信息
*/
private void validateOptionColumns(GenTable genTable) {
Map<String, Object> params = genTable.getParams();
if (CollUtil.isEmpty(params) || CollUtil.isEmpty(genTable.getColumns())) {
@@ -510,6 +515,13 @@ public class GenTableServiceImpl implements IGenTableService {
}
}
/**
* 校验单个选项字段。
*
* @param validFields 有效字段集合
* @param field 待校验字段
* @param label 字段显示名称
*/
private void validateOptionField(Set<String> validFields, Object field, String label) {
if (ObjectUtil.isNull(field)) {
return;
@@ -523,6 +535,11 @@ public class GenTableServiceImpl implements IGenTableService {
}
}
/**
* 规范化字段扩展配置。
*
* @param columns 表字段列表
*/
private void normalizeColumnOptions(List<GenTableColumn> columns) {
if (CollUtil.isEmpty(columns)) {
return;
@@ -134,6 +134,15 @@ public class GenUtils {
}
}
/**
* 解析数值类型对应的 Java 类型。
*
* @param dataType 数据库字段类型
* @param columnLength 字段长度
* @param columnScale 小数位数
* @param columnName 字段名称
* @return Java 类型
*/
private static String resolveNumberJavaType(String dataType, Integer columnLength, Integer columnScale, String columnName) {
if (isBooleanColumn(dataType, columnLength, columnScale, columnName)) {
return GenConstants.TYPE_BOOLEAN;
@@ -159,6 +168,12 @@ public class GenUtils {
return GenConstants.TYPE_LONG;
}
/**
* 根据整数字段长度解析 Java 类型。
*
* @param columnLength 字段长度
* @return Java 类型
*/
private static String resolveIntegerJavaType(Integer columnLength) {
if (columnLength > 0 && columnLength <= 9) {
return GenConstants.TYPE_INTEGER;
@@ -166,6 +181,15 @@ public class GenUtils {
return GenConstants.TYPE_LONG;
}
/**
* 判断字段是否适合按布尔类型生成。
*
* @param dataType 数据库字段类型
* @param columnLength 字段长度
* @param columnScale 小数位数
* @param columnName 字段名称
* @return 是否布尔字段
*/
private static boolean isBooleanColumn(String dataType, Integer columnLength, Integer columnScale, String columnName) {
if (columnScale > 0) {
return false;
@@ -180,6 +204,12 @@ public class GenUtils {
return false;
}
/**
* 判断字段名称是否为开关类字段。
*
* @param columnName 字段名称
* @return 是否开关类字段
*/
private static boolean isSwitchColumn(String columnName) {
return StringUtils.endsWithAny(columnName, "status", "flag", "enabled", "disabled", "available", "visible")
|| columnName.startsWith("is_")
@@ -188,6 +218,12 @@ public class GenUtils {
|| columnName.startsWith("disable_");
}
/**
* 判断字段名称是否为排序字段。
*
* @param columnName 字段名称
* @return 是否排序字段
*/
private static boolean isSortColumn(String columnName) {
return StringUtils.endsWithAny(columnName, "sort", "order_num", "order", "rank", "seq", "sequence");
}
@@ -140,9 +140,9 @@ public class TemplateEngineUtils {
/**
* 向树形模板上下文写入树字段相关变量。
*
* @param context 模板上下文
* @param genTable 代码生成业务表对象
* @param paramsObj 已解析的 options 参数(避免重复解析)
* @param context 模板上下文
* @param genTable 代码生成业务表对象
* @param paramsObj 已解析的 options 参数(避免重复解析)
*/
public static void setTreeContext(Dict context, GenTable genTable, Dict paramsObj) {
String treeCode = getTreeCode(paramsObj);
@@ -328,7 +328,7 @@ public class TemplateEngineUtils {
/**
* 添加字典列表
*
* @param dicts 字典列表
* @param dicts 字典列表
* @param columns 列集合
*/
public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) {
@@ -408,7 +408,7 @@ public class TemplateEngineUtils {
/**
* 获取树根节点值。
*
* @param paramsObj 其他选项
* @param paramsObj 其他选项
* @param treeParentColumn 父节点字段
* @return 树根节点值
*/
@@ -423,6 +423,14 @@ public class TemplateEngineUtils {
return defaultValue;
}
/**
* 读取布尔类型生成选项。
*
* @param paramsObj 生成选项
* @param key 选项键
* @param defaultValue 默认值
* @return 选项值
*/
private static boolean getBooleanOption(Dict paramsObj, String key, boolean defaultValue) {
if (CollUtil.isEmpty(paramsObj) || !paramsObj.containsKey(key)) {
return defaultValue;
@@ -430,6 +438,13 @@ public class TemplateEngineUtils {
return Convert.toBool(paramsObj.get(key), defaultValue);
}
/**
* 根据字段名查找业务表字段。
*
* @param genTable 业务表
* @param field 字段名称或 Java 属性名
* @return 业务表字段
*/
private static GenTableColumn getColumn(GenTable genTable, String field) {
if (StringUtils.isBlank(field) || CollUtil.isEmpty(genTable.getColumns())) {
return null;
@@ -442,6 +457,13 @@ public class TemplateEngineUtils {
return null;
}
/**
* 根据字段配置查找业务表字段列表。
*
* @param genTable 业务表
* @param fieldValues 字段配置值
* @return 业务表字段列表
*/
private static List<GenTableColumn> getColumns(GenTable genTable, Object fieldValues) {
List<String> fields = new ArrayList<>();
if (fieldValues instanceof Collection<?> collection) {
@@ -459,6 +481,13 @@ public class TemplateEngineUtils {
return columns;
}
/**
* 转换为 Java 字面量。
*
* @param column 业务表字段
* @param value 字段值
* @return Java 字面量
*/
private static String getJavaLiteral(GenTableColumn column, String value) {
if (ObjectUtil.isNull(column) || StringUtils.isBlank(value)) {
return "null";
@@ -472,6 +501,13 @@ public class TemplateEngineUtils {
return "\"" + value + "\"";
}
/**
* 转换为 TypeScript 字面量。
*
* @param column 业务表字段
* @param value 字段值
* @return TypeScript 字面量
*/
private static String getTsLiteral(GenTableColumn column, String value) {
if (ObjectUtil.isNull(column) || StringUtils.isBlank(value)) {
return "undefined";
@@ -23,26 +23,56 @@ public class PathNamedTemplate implements Template {
private final Template delegate;
/**
* 创建基于路径命名的模板。
*
* @param pathName 路径名称
* @param delegate 委托模板
*/
private PathNamedTemplate(String pathName, Template delegate) {
this.pathName = pathName;
this.delegate = delegate;
}
/**
* 渲染模板到字符输出器。
*
* @param bindingMap 模板绑定数据
* @param writer 字符输出器
*/
@Override
public void render(Map<?, ?> bindingMap, Writer writer) {
delegate.render(bindingMap, writer);
}
/**
* 渲染模板到输出流。
*
* @param bindingMap 模板绑定数据
* @param out 输出流
*/
@Override
public void render(Map<?, ?> bindingMap, OutputStream out) {
delegate.render(bindingMap, out);
}
/**
* 渲染模板到文件。
*
* @param bindingMap 模板绑定数据
* @param file 输出文件
*/
@Override
public void render(Map<?, ?> bindingMap, File file) {
delegate.render(bindingMap, file);
}
/**
* 渲染模板为字符串。
*
* @param bindingMap 模板绑定数据
* @return 渲染结果
*/
@Override
public String render(Map<?, ?> bindingMap) {
return delegate.render(bindingMap);
@@ -66,8 +96,8 @@ public class PathNamedTemplate implements Template {
* @param pathName 路径名称
* @return 带路径名称的模板
*/
public static PathNamedTemplate form(TemplateEngine templateEngine,String pathName) {
return new PathNamedTemplate(pathName,templateEngine.getTemplate(pathName));
public static PathNamedTemplate form(TemplateEngine templateEngine, String pathName) {
return new PathNamedTemplate(pathName, templateEngine.getTemplate(pathName));
}
/**
@@ -20,6 +20,9 @@ import org.springframework.stereotype.Component;
@JobExecutor(name = "testBroadcastJob")
public class TestBroadcastJob {
/**
* 客户端端口。
*/
@Value("${snail-job.port}")
private int clientPort;
@@ -12,6 +12,12 @@ import org.springframework.stereotype.Component;
@Component
public class TestClassJobExecutor extends AbstractJobExecutor {
/**
* 执行测试类任务。
*
* @param jobArgs 任务参数
* @return 任务执行结果
*/
@Override
protected ExecuteResult doJobExecute(JobArgs jobArgs) {
return ExecuteResult.success("TestJobExecutor测试成功");
@@ -37,23 +37,51 @@ public class MetaVo {
*/
private String activeMenu;
/**
* 构造路由显示信息。
*
* @param title 路由标题
* @param icon 路由图标
*/
public MetaVo(String title, String icon) {
this.title = title;
this.icon = icon;
}
/**
* 构造路由显示信息。
*
* @param title 路由标题
* @param icon 路由图标
* @param noCache 是否不缓存
*/
public MetaVo(String title, String icon, Boolean noCache) {
this.title = title;
this.icon = icon;
this.noCache = noCache;
}
/**
* 构造带内链地址的路由显示信息。
*
* @param title 路由标题
* @param icon 路由图标
* @param link 内链地址
*/
public MetaVo(String title, String icon, String link) {
this.title = title;
this.icon = icon;
this.link = link;
}
/**
* 构造带缓存配置和内链地址的路由显示信息。
*
* @param title 路由标题
* @param icon 路由图标
* @param noCache 是否不缓存
* @param link 内链地址
*/
public MetaVo(String title, String icon, Boolean noCache, String link) {
this.title = title;
this.icon = icon;
@@ -63,6 +91,15 @@ public class MetaVo {
}
}
/**
* 构造带激活菜单的路由显示信息。
*
* @param title 路由标题
* @param icon 路由图标
* @param noCache 是否不缓存
* @param link 内链地址
* @param activeMenu 激活菜单路径
*/
public MetaVo(String title, String icon, Boolean noCache, String link, String activeMenu) {
this.title = title;
this.icon = icon;
@@ -37,6 +37,11 @@ public class DeptExcelConverter implements Converter<Long> {
.expireAfterWrite(30, TimeUnit.SECONDS)
.build();
/**
* 获取部门导入导出映射缓存。
*
* @return 部门 ID 与部门路径名称互转映射
*/
private DeptMaps getDeptMaps() {
ISysDeptService deptService = SpringUtils.getBean(ISysDeptService.class);
return DEPT_CACHE.get(CACHE_KEY, k -> {
@@ -47,6 +47,11 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
private final StringBuilder successMsg = new StringBuilder();
private final StringBuilder failureMsg = new StringBuilder();
/**
* 构造用户导入监听器。
*
* @param isUpdateSupport 是否允许更新已存在用户
*/
public SysUserImportListener(Boolean isUpdateSupport) {
String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword");
this.userService = SpringUtils.getBean(ISysUserService.class);
@@ -55,6 +60,12 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
this.operUserId = LoginHelper.getUserId();
}
/**
* 逐行处理用户导入数据。
*
* @param userVo 导入用户数据
* @param context Excel 解析上下文
*/
@Override
public void invoke(SysUserImportVo userVo, AnalysisContext context) {
SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName());
@@ -95,15 +106,30 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
}
}
/**
* 所有数据解析完成后的回调。
*
* @param context Excel 解析上下文
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
/**
* 获取用户导入结果。
*
* @return Excel 导入结果
*/
@Override
public ExcelResult<SysUserImportVo> getExcelResult() {
return new ExcelResult<>() {
/**
* 获取导入结果分析消息。
*
* @return 导入结果消息
*/
@Override
public String getAnalysis() {
if (failureNum > 0) {
@@ -115,11 +141,21 @@ public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo
return successMsg.toString();
}
/**
* 获取导入成功数据列表。
*
* @return 导入成功数据列表
*/
@Override
public List<SysUserImportVo> getList() {
return null;
}
/**
* 获取导入错误信息列表。
*
* @return 导入错误信息列表
*/
@Override
public List<String> getErrorList() {
return null;
@@ -19,6 +19,9 @@ public class FlowDefinitionVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 流程定义主键
*/
private Long id;
/**
@@ -23,6 +23,9 @@ public class FlowHisTaskVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 历史任务主键
*/
private Long id;
/**
@@ -34,7 +34,11 @@ import org.dromara.workflow.service.IFlwNodeExtService;
import org.dromara.workflow.service.IFlwTaskService;
import org.springframework.stereotype.Component;
import java.util.*;
import java.io.Serial;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* 工作流全局监听器,处理任务流转中的扩展变量、消息和事件发布。
@@ -48,6 +52,8 @@ import java.util.*;
public class WorkflowGlobalListener implements GlobalListener {
private static final String NODE_KEY_SEPARATOR = ":";
@Serial
private static final long serialVersionUID = -5133036757491932497L;
private final IFlwTaskService flwTaskService;
private final IFlwInstanceService flwInstanceService;
@@ -256,6 +262,14 @@ public class WorkflowGlobalListener implements GlobalListener {
);
}
/**
* 判断是否需要发送后续待办消息。
*
* @param flowParams 流程参数
* @param definition 流程定义
* @param nextTasks 后续任务列表
* @return 是否发送待办消息
*/
private boolean shouldSendTaskMessage(FlowParams flowParams, Definition definition, List<Task> nextTasks) {
if (flowParams == null || !TaskStatusEnum.BACK.getStatus().equals(flowParams.getHisStatus())) {
return true;
@@ -268,6 +282,14 @@ public class WorkflowGlobalListener implements GlobalListener {
return !StringUtils.equals(applyNodeCode, nextTasks.get(0).getNodeCode());
}
/**
* 在流程完成或退回时通知发起人。
*
* @param definition 流程定义
* @param instance 流程实例
* @param status 业务状态
* @param variable 流程变量
*/
private void notifyInitiatorIfNeeded(Definition definition, Instance instance, String status, Map<String, Object> variable) {
if (!StringUtils.equalsAny(status, BusinessStatusEnum.FINISH.getStatus(), BusinessStatusEnum.BACK.getStatus())) {
return;
@@ -24,6 +24,15 @@ import java.util.Map;
*/
public interface FlwHisTaskMapper extends BaseMapperPlus<FlowHisTask, FlowHisTaskVo>, MPJBaseMapper<FlowHisTask> {
/**
* 分页查询已办任务列表。
*
* @param page 分页对象
* @param bo 查询条件
* @param categoryIds 流程分类 ID 集合
* @param userId 当前用户 ID
* @return 已办任务分页结果
*/
default Page<FlowHisTaskVo> getListFinishTask(Page<FlowHisTaskVo> page, FlowTaskBo bo, List<String> categoryIds, String userId) {
Map<String, Object> params = bo.getParams();
return QueryBuilder.lambdaJoin("a", FlowHisTask.class)
@@ -22,6 +22,15 @@ import java.util.Map;
*/
public interface FlwTaskMapper extends BaseMapperPlus<FlowTask, FlowTaskVo>, MPJBaseMapper<FlowTask> {
/**
* 分页查询运行中的待办任务。
*
* @param page 分页对象
* @param bo 查询条件
* @param categoryIds 流程分类 id 列表
* @param userId 当前用户 id
* @return 待办任务分页结果
*/
default Page<FlowTaskVo> getListRunTask(Page<FlowTaskVo> page, FlowTaskBo bo, List<String> categoryIds, String userId) {
Map<String, Object> params = bo.getParams();
return QueryBuilder.lambdaJoin("t", FlowTask.class)
@@ -54,6 +63,15 @@ public interface FlwTaskMapper extends BaseMapperPlus<FlowTask, FlowTaskVo>, MPJ
.page(page, FlowTaskVo.class);
}
/**
* 分页查询抄送任务。
*
* @param page 分页对象
* @param bo 查询条件
* @param categoryIds 流程分类 id 列表
* @param userId 当前用户 id
* @return 抄送任务分页结果
*/
default Page<FlowTaskVo> getTaskCopyByPage(Page<FlowTaskVo> page, FlowTaskBo bo, List<String> categoryIds, String userId) {
Map<String, Object> params = bo.getParams();
return QueryBuilder.lambdaJoin("a", FlowUser.class)
@@ -89,6 +89,14 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
sendMessage(messageType, message, subject, userList, null);
}
/**
* 发送流程结果通知。
*
* @param flowName 流程名称
* @param status 业务状态
* @param messageType 消息类型列表
* @param userList 接收用户列表
*/
@Override
public void sendResultMessage(String flowName, BusinessStatusEnum status, List<String> messageType, List<UserDTO> userList) {
if (status == null || CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) {
@@ -99,6 +107,15 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
sendMessage(messageType, message, DEFAULT_SUBJECT, userList, PATH_MY_DOCUMENT);
}
/**
* 发送消息给指定用户列表。
*
* @param messageType 消息类型列表
* @param message 消息内容
* @param subject 邮件标题
* @param userList 接收用户列表
* @param path 前端跳转路径
*/
@Override
public void sendMessage(List<String> messageType, String message, String subject, List<UserDTO> userList, String path) {
if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) {
@@ -114,6 +131,17 @@ public class FlwCommonServiceImpl implements IFlwCommonService {
ThreadUtils.virtualInvokeAll(sendTasks);
}
/**
* 按消息类型执行具体发送逻辑。
*
* @param code 消息类型编码
* @param message 消息内容
* @param subject 邮件标题
* @param path 前端跳转路径
* @param userIds 接收用户 id 列表
* @param emails 接收邮箱集合
* @param userCount 接收用户数量
*/
private void sendMessageByType(String code, String message, String subject, String path, List<Long> userIds, Set<String> emails, int userCount) {
MessageTypeEnum messageTypeEnum = MessageTypeEnum.getByCode(code);
if (ObjectUtil.isEmpty(messageTypeEnum)) {
@@ -273,6 +273,11 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
}
/**
* 校验当前用户是否有权限删除流程实例,并发布删除事件。
*
* @param flowInstances 待删除流程实例列表
*/
private void processDeleteHandler(List<FlowInstance> flowInstances) {
String userId = LoginHelper.getUserIdStr();
@@ -120,7 +120,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
/**
* 根据办理人类型查询右侧候选数据。
*
* @param type 办理人类型
* @param type 办理人类型
* @param taskQuery 查询条件
* @return 办理人数据
*/
@@ -180,7 +180,7 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
/**
* 构建设计器右侧办理人列表数据。
*
* @param dto 办理人数据
* @param dto 办理人数据
* @param type 办理人类型
* @return 办理人列表构建器
*/
@@ -218,6 +218,12 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
.toList();
}
/**
* 按任务分配类型批量查询用户。
*
* @param typeIdMap 任务分配类型与 id 列表映射
* @return 用户列表
*/
private List<UserDTO> getUsersByTypes(Map<TaskAssigneeEnum, List<String>> typeIdMap) {
return typeIdMap.entrySet().stream()
.map(entry -> this.getUsersByType(entry.getKey(), entry.getValue()))
@@ -226,6 +232,12 @@ public class FlwTaskAssigneeServiceImpl implements IFlwTaskAssigneeService, Hand
.toList();
}
/**
* 按任务分配类型批量查询名称映射。
*
* @param typeIdMap 任务分配类型与 id 列表映射
* @return 任务分配类型与名称映射
*/
private Map<TaskAssigneeEnum, Map<String, String>> getNamesByTypes(Map<TaskAssigneeEnum, List<String>> typeIdMap) {
Map<TaskAssigneeEnum, Map<String, String>> nameMap = new EnumMap<>(TaskAssigneeEnum.class);
typeIdMap.forEach((type, ids) -> nameMap.put(type, this.getNamesByType(type, ids)));