diff --git a/markbase-tauri/src-tauri/Cargo.lock b/markbase-tauri/src-tauri/Cargo.lock index a4838f6..6487e2c 100644 --- a/markbase-tauri/src-tauri/Cargo.lock +++ b/markbase-tauri/src-tauri/Cargo.lock @@ -1993,6 +1993,7 @@ dependencies = [ "tauri-build", "thiserror", "tokio", + "uuid", ] [[package]] diff --git a/markbase-tauri/src-tauri/Cargo.toml b/markbase-tauri/src-tauri/Cargo.toml index e364188..615fd23 100644 --- a/markbase-tauri/src-tauri/Cargo.toml +++ b/markbase-tauri/src-tauri/Cargo.toml @@ -25,6 +25,7 @@ chrono = { version = "0.4", features = ["serde"] } anyhow = "1.0" thiserror = "1.0" rusqlite = { version = "0.30", features = ["bundled"] } +uuid = { version = "1.0", features = ["v4"] } [features] custom-protocol = [ "tauri/custom-protocol" ] diff --git a/markbase-tauri/src-tauri/src/commands/file_ops.rs b/markbase-tauri/src-tauri/src/commands/file_ops.rs index 902209f..f7fcc40 100644 --- a/markbase-tauri/src-tauri/src/commands/file_ops.rs +++ b/markbase-tauri/src-tauri/src/commands/file_ops.rs @@ -1,7 +1,5 @@ use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use tauri::State; -use std::sync::Mutex; +use std::path::{Path, PathBuf}; use rusqlite::Connection; #[derive(Debug, Serialize, Deserialize, Clone)] @@ -116,10 +114,42 @@ pub async fn upload_file( target_path: String, tree_type: String, ) -> Result { + use std::fs; + use uuid::Uuid; + + let demo_dir = "/Users/accusys/momentry/var/sftpgo/data/demo"; + let target_file = PathBuf::from(demo_dir).join(&target_path); + + if !Path::new(&source_path).exists() { + return Err(format!("Source file not found: {}", source_path)); + } + + fs::copy(&source_path, &target_file) + .map_err(|e| format!("Failed to copy file: {}", e))?; + + let db_path = PathBuf::from("data/users") + .join(format!("{}.sqlite", user_id)); + + let conn = Connection::open(&db_path) + .map_err(|e| format!("Failed to open database: {}", e))?; + + let file_uuid = Uuid::new_v4().to_string(); + let file_name = Path::new(&target_path) + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("unknown") + .to_string(); + + conn.execute( + "INSERT INTO file_registry (file_uuid, original_name, file_path, file_size, registered_at, last_seen_at, status) + VALUES (?1, ?2, ?3, ?4, datetime('now'), datetime('now'), 'active')", + rusqlite::params![&file_uuid, &file_name, target_file.to_string_lossy().to_string(), fs::metadata(&target_file).map(|m| m.len() as i64).unwrap_or(0)] + ).map_err(|e| format!("Failed to register file: {}", e))?; + Ok(FileUploadResult { success: true, - message: "File uploaded successfully".to_string(), - file_id: Some("file-001".to_string()), + message: format!("File uploaded to: {}", target_path), + file_id: Some(file_uuid), }) } diff --git a/markbase-tauri/src/src/views/Home.vue b/markbase-tauri/src/src/views/Home.vue index ce739b2..98285c2 100644 --- a/markbase-tauri/src/src/views/Home.vue +++ b/markbase-tauri/src/src/views/Home.vue @@ -4,7 +4,8 @@ import { useRouter } from 'vue-router' import { useAppStore } from '../stores/app' import { invoke } from '@tauri-apps/api/tauri' import { ElMessage } from 'element-plus' -import { Folder, Document } from '@element-plus/icons-vue' +import { Folder, Document, Upload } from '@element-plus/icons-vue' +import { open } from '@tauri-apps/api/dialog' const router = useRouter() const appStore = useAppStore() @@ -17,6 +18,8 @@ const treeProps = { } const currentTreeType = ref('demo_library_zh') +const uploading = ref(false) +const uploadProgress = ref(0) const navigateTo = (path) => { router.push(path) @@ -58,6 +61,52 @@ const handleNodeClick = async (data) => { } } +const handleUpload = async () => { + try { + const selected = await open({ + multiple: false, + filters: [{ + name: 'All Files', + extensions: ['*'] + }] + }) + + if (!selected) { + return + } + + uploading.value = true + uploadProgress.value = 0 + + const sourcePath = selected + const fileName = sourcePath.split('/').pop() + const targetPath = `uploads/${fileName}` + + ElMessage.info(`Uploading ${fileName}...`) + + const result = await invoke('upload_file', { + userId: 'demo', + sourcePath: sourcePath, + targetPath: targetPath, + treeType: currentTreeType.value + }) + + uploadProgress.value = 100 + + if (result.success) { + ElMessage.success(result.message) + await loadTree() + } else { + ElMessage.error(result.message) + } + } catch (error) { + ElMessage.error(`Upload failed: ${error}`) + } finally { + uploading.value = false + uploadProgress.value = 0 + } +} + watch(currentTreeType, () => { loadTree() }) @@ -76,10 +125,21 @@ onMounted(async () => {
@@ -178,6 +238,12 @@ onMounted(async () => { align-items: center; } +.header-actions { + display: flex; + gap: 10px; + align-items: center; +} + .tree-container { height: calc(100% - 60px); overflow-y: auto; diff --git a/markbase-tauri/src/vite.config.js b/markbase-tauri/src/vite.config.js index b875b3b..266092d 100644 --- a/markbase-tauri/src/vite.config.js +++ b/markbase-tauri/src/vite.config.js @@ -5,7 +5,7 @@ export default defineConfig({ plugins: [vue()], build: { rolldownOptions: { - external: ['@tauri-apps/api', '@tauri-apps/api/tauri'] + external: ['@tauri-apps/api', '@tauri-apps/api/tauri', '@tauri-apps/api/dialog'] } } })