status: done created: 2026-05-26 complexity: 🔴复杂
现有 AiCrudPage 已提供通用导出按钮,动态 CRUD 运行时也提供 /ai/crud/{configKey}/export,但当前链路是一次性查询全部导出数据并直接写响应。当数据量较大时,请求容易超时,后端也存在一次性构造数据集合导致 OOM 的风险。
本次目标是在通用 CRUD 页面增加智能导出能力:后端先按当前查询条件统计数据量,小数据仍同步下载;超过系统参数阈值时自动转为异步导出任务。异步任务后台分页查询、流式写 Excel、上传到文件服务,前端提供任务进度查询和文件下载入口。
forge-admin-ui/src/components/ai-form/AiCrudPage.vue#handleExport:当前导出按钮始终按 blob 响应下载文件,没有识别异步任务 JSON。forge-admin-ui/src/views/ai/crud-page.vue#crudProps:动态低代码 CRUD 会把 cfg.apiConfig.export 透传给 AiCrudPage。forge/forge-framework/forge-plugin-parent/forge-plugin-generator/src/main/java/com/mdframe/forge/plugin/generator/controller/DynamicCrudController.java#exportExcel:动态 CRUD 导出入口为 POST /ai/crud/{configKey}/export。forge/forge-framework/forge-plugin-parent/forge-plugin-generator/src/main/java/com/mdframe/forge/plugin/generator/service/DynamicCrudExcelService.java#exportExcel:当前读取最多 MAX_EXPORT_ROWS 行后一次性构造 List<List<Object>> 写 Excel。forge/forge-framework/forge-plugin-parent/forge-plugin-generator/src/main/java/com/mdframe/forge/plugin/generator/service/DynamicCrudService.java#selectExportRows:动态导出复用字段白名单、解密、字典翻译和脱敏链路。forge/forge-framework/forge-starter-parent/forge-starter-file/src/main/java/com/mdframe/forge/starter/file/core/FileManager.java:文件中心已有上传、下载、元数据持久化能力,但当前 FileManager 只暴露 MultipartFile 上传入口。forge/forge-framework/forge-plugin-system/src/main/java/com/mdframe/forge/plugin/system/entity/SysConfig.java:系统参数表 sys_config 已存在,可保存导出阈值和批量大小。columnsSchema 生成表头,并可读取 sys_excel_column_config 覆盖列顺序、表头和字典类型。NamedParameterJdbcTemplate + 表名/字段白名单拼接 SQL,不适合普通 Mapper XML,但新增任务分页查询应在 Mapper XML 中实现。AsyncExportServiceImpl,但该实现使用 ConcurrentHashMap 保存任务、ByteArrayOutputStream 缓存完整文件、写本地临时文件后再下载,不满足本次“持久任务、文件服务、避免 OOM”的要求。file_id 等元数据,前端使用现有 /api/file/download/{fileId} 链路下载。<= threshold 同步下载,> threshold 返回异步任务信息。AiCrudPage 支持识别异步导出响应,打开导出任务抽屉,轮询进度并提供下载按钮。5000 条,配置键:sys.export.async.threshold。1000 条,配置键:sys.export.batch.size。24 小时,配置键:sys.export.file.keepHours。PENDING、RUNNING、SUCCESS、FAILED。| 操作 | 表名 | 字段/索引 | 说明 |
|---|---|---|---|
| 新增 | ai_crud_export_task |
id, tenant_id, config_key, file_id, status, total_count, exported_count, progress, query_params, 标准审计字段 |
持久化动态 CRUD 异步导出任务 |
| 新增 | sys_config |
sys.export.async.threshold |
超过该行数自动异步导出 |
| 新增 | sys_config |
sys.export.batch.size |
异步导出每批查询和写入行数 |
| 新增 | sys_config |
sys.export.file.keepHours |
导出文件过期时间 |
| 操作 | 接口 | 方法 | 变更内容 |
|---|---|---|---|
| 修改 | /ai/crud/{configKey}/export |
POST | 自动判断同步/异步;同步写文件流,异步返回任务信息 |
| 新增 | /ai/crud/{configKey}/export/tasks |
GET | 查询当前用户在该配置下的导出任务 |
| 新增 | /ai/crud/{configKey}/export/tasks/{taskId} |
GET | 查询单个导出任务进度和文件信息 |
forge-plugin-generator:动态 CRUD 导出服务、导出任务实体/Mapper、动态查询分页能力、数据权限上下文复用。forge-starter-file:补充从 InputStream 上传到文件服务的管理方法。forge-admin-ui:AiCrudPage 导出按钮、任务抽屉、进度轮询和文件下载。forge/db/migration:新增任务表和系统参数初始化。FAILED,临时文件必须在 finally 中删除。sys_excel_export_config 反射导出后续可独立升级。/ai/crud/{configKey}/export,这是低代码/通用 CRUD 当前主链路。ai_crud_export_task,归属生成器/低代码运行时,避免把系统插件反向依赖生成器。downloadFile(fileId, fileName)。| Task | 状态 | 实际改动文件 | 备注 |
|---|---|---|---|
| Task 1 | completed | forge/db/migration/V1.0.23__add_common_crud_async_export.sql, AiCrudExportTask.java, AiCrudExportTaskMapper.java, AiCrudExportTaskMapper.xml |
新增异步导出任务表、系统参数和任务查询 SQL |
| Task 2 | completed | DynamicCrudRepository.java, DynamicCrudService.java, DynamicDataScopeService.java |
新增导出 count、分页读取和提交人数据权限上下文复用 |
| Task 3 | completed | DynamicCrudController.java, DynamicCrudExcelService.java, DynamicCrudAsyncExportWorker.java, DynamicCrudExportResult.java |
导出接口自动同步/异步决策,后台分批写 Excel 并更新任务进度 |
| Task 4 | completed | FileManager.java, FileStorage.java, RustfsFileStorage.java, TencentCosFileStorage.java, forge-plugin-generator/pom.xml |
文件中心支持已知大小的流式上传,异步导出上传到文件服务 |
| Task 5 | completed | AiCrudPage.vue, AiCrudPageProps.js |
通用 CRUD 增加导出任务入口、抽屉、轮询、下载和 Blob JSON 识别 |
| Task 6 | completed | spec.md, tasks.md |
已完成后端编译、前端 ESLint 和生产构建验证 |
已按 Spec 完成实现。同步导出保持文件流下载;超过 sys.export.async.threshold 时创建持久任务并返回 async=true/taskId;异步 worker 按 sys.export.batch.size 分批查询和写入,完成后上传文件中心并记录 fileId/fileSize。任务查询按当前租户、当前用户和 configKey 隔离。
验证记录:
JAVA_HOME=/opt/homebrew/Cellar/openjdk@17/17.0.13/libexec/openjdk.jdk/Contents/Home mvn -pl forge-framework/forge-plugin-parent/forge-plugin-generator -am compile -DskipTests 通过。JAVA_HOME=/opt/homebrew/Cellar/openjdk@17/17.0.13/libexec/openjdk.jdk/Contents/Home mvn -pl forge-admin-server -am compile -DskipTests 通过。source ~/.nvm/nvm.sh && nvm use v20.19.0 && pnpm exec eslint src/components/ai-form/AiCrudPage.vue src/components/ai-form/AiCrudPageProps.js 通过。source ~/.nvm/nvm.sh && nvm use v20.19.0 && NODE_OPTIONS=--max-old-space-size=8192 pnpm build 通过;仍有仓库既有 UnoCSS icon 加载警告、CSS // 注释警告和 chunk size 警告。