Phase 2.7完成:文件浏览模块完善(SQLite查询 + Tree展示)
Phase 2.7.1成果: - 实现SQLite数据库查询(file_registry/file_nodes表) - get_tree():构建完整虚拟Tree结构 - list_files():列出文件节点 - search_files():文件名模糊搜索 - download_file():查询物理文件路径 - build_tree():递归构建Tree辅助函数 Phase 2.7.2成果: - Element Plus Tree组件集成 - 双虚拟目录切换(中文/英文) - 文件节点点击打开功能 - 文件大小格式化显示(KB/MB/GB) - 文件夹/文件图标区分 技术实现: - 添加rusqlite依赖到Cargo.toml - 修复Tauri features配置 - Home.vue完整Tree展示UI - 编译成功(8警告,0错误) 状态:Phase 2总进度98%完成
This commit is contained in:
@@ -1,17 +1,70 @@
|
||||
<script setup>
|
||||
import { ref, onMounted } from 'vue'
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
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'
|
||||
|
||||
const router = useRouter()
|
||||
const appStore = useAppStore()
|
||||
|
||||
const treeData = ref([])
|
||||
const treeProps = {
|
||||
label: 'name',
|
||||
children: 'children',
|
||||
isLeaf: (data) => data.node_type === 'file'
|
||||
}
|
||||
|
||||
const currentTreeType = ref('demo_library_zh')
|
||||
|
||||
const navigateTo = (path) => {
|
||||
router.push(path)
|
||||
}
|
||||
|
||||
const formatFileSize = (bytes) => {
|
||||
if (bytes < 1024) return bytes + ' B'
|
||||
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(2) + ' KB'
|
||||
if (bytes < 1024 * 1024 * 1024) return (bytes / 1024 / 1024).toFixed(2) + ' MB'
|
||||
return (bytes / 1024 / 1024 / 1024).toFixed(2) + ' GB'
|
||||
}
|
||||
|
||||
const loadTree = async () => {
|
||||
try {
|
||||
const tree = await invoke('get_tree', {
|
||||
userId: 'demo',
|
||||
treeType: currentTreeType.value
|
||||
})
|
||||
treeData.value = [tree]
|
||||
ElMessage.success('Tree loaded successfully')
|
||||
} catch (error) {
|
||||
ElMessage.error(`Failed to load tree: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
const handleNodeClick = async (data) => {
|
||||
if (data.node_type === 'file') {
|
||||
try {
|
||||
const filePath = await invoke('download_file', {
|
||||
userId: 'demo',
|
||||
fileUuid: data.id
|
||||
})
|
||||
|
||||
await invoke('open_file', { filePath })
|
||||
ElMessage.success(`Opening file: ${data.name}`)
|
||||
} catch (error) {
|
||||
ElMessage.error(`Failed to open file: ${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
watch(currentTreeType, () => {
|
||||
loadTree()
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
await appStore.initializeApp()
|
||||
await loadTree()
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -30,7 +83,28 @@ onMounted(async () => {
|
||||
</div>
|
||||
</template>
|
||||
<div class="tree-container">
|
||||
<el-empty description="File tree will be displayed here" />
|
||||
<el-tree
|
||||
:data="treeData"
|
||||
:props="treeProps"
|
||||
:expand-on-click-node="false"
|
||||
:highlight-current="true"
|
||||
@node-click="handleNodeClick"
|
||||
>
|
||||
<template #default="{ node, data }">
|
||||
<span class="custom-tree-node">
|
||||
<el-icon v-if="data.node_type === 'folder'">
|
||||
<Folder />
|
||||
</el-icon>
|
||||
<el-icon v-else-if="data.node_type === 'file'">
|
||||
<Document />
|
||||
</el-icon>
|
||||
<span>{{ data.name }}</span>
|
||||
<span class="file-size" v-if="data.size">
|
||||
{{ formatFileSize(data.size) }}
|
||||
</span>
|
||||
</span>
|
||||
</template>
|
||||
</el-tree>
|
||||
</div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
@@ -109,6 +183,22 @@ onMounted(async () => {
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.custom-tree-node {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.custom-tree-node .el-icon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.file-size {
|
||||
margin-left: 10px;
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.management-cards {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
Reference in New Issue
Block a user