From 5c4b2a53d10bb4a8cc8685fe348aa23baa205ef1 Mon Sep 17 00:00:00 2001 From: xfy Date: Mon, 29 Jun 2026 19:01:16 +0800 Subject: [PATCH] feat(admin): add data export tab (Axum streaming, SQL/CSV) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增 GET /api/database/export Axum 流式路由(镜像 upload.rs 的 cookie→admin 鉴权),支持按表/按查询导出。CSV 用 COPY ... TO STDOUT WITH CSV 流式 (大表不 OOM),SQL 逐行拼 INSERT(含类型化转义)。表名白名单 + 查询 AST 只读强制。前端 ExportTab 触发 window.open 下载。 --- src/api/database/export.rs | 234 +++++++++++++++++++++++++++++++++++++ src/api/database/mod.rs | 2 + src/main.rs | 17 ++- src/pages/admin/system.rs | 139 +++++++++++++++++++++- 4 files changed, 389 insertions(+), 3 deletions(-) create mode 100644 src/api/database/export.rs diff --git a/src/api/database/export.rs b/src/api/database/export.rs new file mode 100644 index 0000000..c292ec2 --- /dev/null +++ b/src/api/database/export.rs @@ -0,0 +1,234 @@ +//! 数据导出:Axum 流式路由(大文件不走 JSON 序列化)。 +//! +//! 鉴权镜像 [`crate::api::upload`]:从 cookie 取 session,校验管理员。 +//! 两种来源:按表导出(表名白名单)/ 按查询导出(强制只读,AST 校验)。 +//! 两种格式:CSV(COPY TO STDOUT 流式)/ SQL(逐行拼 INSERT)。 + +#![allow(clippy::unused_unit)] + +use axum::body::Body; +use axum::extract::Query; +use axum::http::{header, HeaderMap, StatusCode}; +use axum::response::IntoResponse; +use futures::StreamExt; +use serde::Deserialize; + +use crate::auth::session::parse_session_token; + +#[derive(Deserialize)] +pub struct ExportParams { + /// `table:` 或 `query: