feat(desktop): add drag-and-drop upload for file view

This commit is contained in:
2026-02-18 19:46:11 +08:00
parent 2b36275c4a
commit 09043e8059
4 changed files with 292 additions and 21 deletions

View File

@@ -595,6 +595,82 @@ async fn api_native_download(
})
}
#[tauri::command]
async fn api_upload_file(
state: tauri::State<'_, ApiState>,
base_url: String,
file_path: String,
target_path: String,
) -> Result<BridgeResponse, String> {
let trimmed_path = file_path.trim().to_string();
if trimmed_path.is_empty() {
return Err("上传文件路径不能为空".to_string());
}
let source_path = PathBuf::from(trimmed_path);
if !source_path.exists() {
return Err("上传文件不存在".to_string());
}
if !source_path.is_file() {
return Err("仅支持上传文件,不支持文件夹".to_string());
}
let file_name = source_path
.file_name()
.and_then(|name| name.to_str())
.map(|name| name.to_string())
.ok_or_else(|| "无法识别文件名".to_string())?;
let file_bytes = fs::read(&source_path).map_err(|err| format!("读取文件失败: {}", err))?;
let normalized_target = if target_path.trim().is_empty() {
"/".to_string()
} else {
target_path
};
let csrf_token = fetch_csrf_token(&state.client, &base_url).await?;
let upload_url = join_api_url(&base_url, "/api/upload");
if upload_url.trim().is_empty() {
return Err("API 地址不能为空".to_string());
}
let multipart = reqwest::multipart::Form::new()
.text("path", normalized_target)
.part("file", reqwest::multipart::Part::bytes(file_bytes).file_name(file_name));
let mut request = state
.client
.post(&upload_url)
.header("Accept", "application/json")
.timeout(Duration::from_secs(60 * 30))
.multipart(multipart);
if let Some(csrf) = csrf_token {
request = request.header("X-CSRF-Token", csrf);
}
let response = request
.send()
.await
.map_err(|err| format!("上传请求失败: {}", err))?;
let status = response.status();
let text = response
.text()
.await
.map_err(|err| format!("读取响应失败: {}", err))?;
let data = match serde_json::from_str::<Value>(&text) {
Ok(parsed) => parsed,
Err(_) => fallback_json(status, &text),
};
Ok(BridgeResponse {
ok: status.is_success(),
status: status.as_u16(),
data,
})
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let client = reqwest::Client::builder()
@@ -620,7 +696,8 @@ pub fn run() {
api_create_share,
api_delete_share,
api_create_direct_link,
api_native_download
api_native_download,
api_upload_file
])
.run(tauri::generate_context!())
.expect("error while running tauri application");