chore: adjust zip upload logical #90
This commit is contained in:
@@ -13,6 +13,8 @@ import { PATHS, FILE_RUNNERS } from '@/constants'
|
||||
import FileSidebar from './components/FileSidebar.vue'
|
||||
import RunConfigDialog from './components/RunConfigDialog.vue'
|
||||
import FileActionDialogs from './components/FileActionDialogs.vue'
|
||||
import BaihuDialog from '@/components/ui/BaihuDialog.vue'
|
||||
import { AlertCircle } from 'lucide-vue-next'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -31,6 +33,12 @@ const isRefreshing = ref(false)
|
||||
const isEditMode = ref(false)
|
||||
const hasChanges = computed(() => fileContent.value !== originalContent.value)
|
||||
|
||||
const confirmLeave = ref({
|
||||
show: false,
|
||||
path: '',
|
||||
onConfirm: () => {}
|
||||
})
|
||||
|
||||
// Component Refs
|
||||
const dialogsRef = ref<InstanceType<typeof FileActionDialogs> | null>(null)
|
||||
const terminalRef = ref<InstanceType<typeof XTerminal> | null>(null)
|
||||
@@ -166,7 +174,17 @@ async function handleSelect(node: FileNode) {
|
||||
expandedDirs.value = new Set(expandedDirs.value)
|
||||
selectedFile.value = null
|
||||
} else {
|
||||
if (hasChanges.value && !confirm('当前文件有未保存的更改,是否放弃?')) return
|
||||
if (hasChanges.value) {
|
||||
confirmLeave.value = {
|
||||
show: true,
|
||||
path: node.path,
|
||||
onConfirm: () => {
|
||||
originalContent.value = fileContent.value // 假装保存或标记为已确认放弃
|
||||
loadFile(node.path)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
await loadFile(node.path)
|
||||
}
|
||||
}
|
||||
@@ -528,5 +546,28 @@ onUnmounted(() => {
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<BaihuDialog v-model:open="confirmLeave.show" title="未保存的更改" icon="AlertCircle" size="sm">
|
||||
<div class="flex flex-col sm:flex-row items-center sm:items-start gap-4 p-1">
|
||||
<div class="h-12 w-12 rounded-full bg-yellow-500/10 flex items-center justify-center shrink-0">
|
||||
<AlertCircle class="h-6 w-6 text-yellow-500" />
|
||||
</div>
|
||||
<div class="flex-1 text-center sm:text-left">
|
||||
<p class="text-sm text-foreground/90 leading-relaxed font-medium">文件尚未保存</p>
|
||||
<p class="text-[13px] text-muted-foreground mt-1">
|
||||
当前文件有未保存的更改。如果现在离开,您的更改将会丢失。
|
||||
</p>
|
||||
<div class="mt-3 px-2 py-1.5 bg-muted/50 rounded text-[11px] font-mono text-muted-foreground break-all border border-muted">
|
||||
{{ confirmLeave.path }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex flex-col-reverse sm:flex-row gap-2 w-full sm:w-auto mt-2 sm:mt-0">
|
||||
<Button variant="outline" @click="confirmLeave.show = false" class="w-full sm:w-24">继续编辑</Button>
|
||||
<Button variant="destructive" @click="confirmLeave.show = false; confirmLeave.onConfirm()" class="w-full sm:w-auto px-6">放弃更改</Button>
|
||||
</div>
|
||||
</template>
|
||||
</BaihuDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { ref, computed } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { RefreshCw, FolderUp, Upload, Plus } from 'lucide-vue-next'
|
||||
import { RefreshCw, FolderUp, Upload, Plus, AlertCircle } from 'lucide-vue-next'
|
||||
import FileTreeNode from '@/components/FileTreeNode.vue'
|
||||
import BaihuDialog from '@/components/ui/BaihuDialog.vue'
|
||||
import { type FileNode } from '@/api'
|
||||
|
||||
defineProps<{
|
||||
const props = defineProps<{
|
||||
fileTree: FileNode[]
|
||||
expandedDirs: Set<string>
|
||||
selectedPath: string | null
|
||||
@@ -29,6 +30,45 @@ const archiveInputRef = ref<HTMLInputElement | null>(null)
|
||||
const filesInputRef = ref<HTMLInputElement | null>(null)
|
||||
const uploadTargetDir = ref('')
|
||||
|
||||
// 确认框状态
|
||||
const confirmUpload = ref<{
|
||||
show: boolean
|
||||
title: string
|
||||
message: string
|
||||
onConfirm: () => void
|
||||
}>({
|
||||
show: false,
|
||||
title: '',
|
||||
message: '',
|
||||
onConfirm: () => {}
|
||||
})
|
||||
|
||||
const currentTargetDir = computed(() => {
|
||||
if (!props.selectedPath) return ''
|
||||
|
||||
// 深度优先搜索以确定选中的是目录还是文件
|
||||
const findNode = (nodes: FileNode[], path: string): FileNode | null => {
|
||||
for (const n of nodes) {
|
||||
if (n.path === path) return n
|
||||
if (n.children) {
|
||||
const found = findNode(n.children, path)
|
||||
if (found) return found
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const node = findNode(props.fileTree, props.selectedPath)
|
||||
if (node && node.isDir) {
|
||||
return node.path
|
||||
}
|
||||
|
||||
// 如果选中的是文件,则返回它所在的目录
|
||||
const parts = props.selectedPath.split('/')
|
||||
parts.pop() // 移除文件名
|
||||
return parts.join('/')
|
||||
})
|
||||
|
||||
function triggerArchiveUpload(targetDir = '') {
|
||||
uploadTargetDir.value = targetDir
|
||||
if (archiveInputRef.value) archiveInputRef.value.click()
|
||||
@@ -42,7 +82,17 @@ function triggerFilesUpload(targetDir = '') {
|
||||
function handleArchiveUpload(e: Event) {
|
||||
const input = e.target as HTMLInputElement
|
||||
const file = input.files?.[0]
|
||||
if (file) emit('uploadArchive', file, uploadTargetDir.value)
|
||||
if (file) {
|
||||
const dirName = uploadTargetDir.value || '根目录'
|
||||
confirmUpload.value = {
|
||||
show: true,
|
||||
title: '确认导入压缩包',
|
||||
message: `即将把压缩包 [${file.name}] 导入到目录 [ ${dirName} ]。确认导入吗?`,
|
||||
onConfirm: () => {
|
||||
emit('uploadArchive', file, uploadTargetDir.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
input.value = ''
|
||||
}
|
||||
|
||||
@@ -50,14 +100,22 @@ function handleFilesUpload(e: Event) {
|
||||
const input = e.target as HTMLInputElement
|
||||
const files = input.files
|
||||
if (files && files.length > 0) {
|
||||
const paths: string[] = []
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const f = files.item(i)
|
||||
if (f) {
|
||||
paths.push((f as any).webkitRelativePath || f.name)
|
||||
}
|
||||
const dirName = uploadTargetDir.value || '根目录'
|
||||
confirmUpload.value = {
|
||||
show: true,
|
||||
title: '确认上传文件',
|
||||
message: `即将把 ${files.length} 个文件/文件夹上传到目录 [ ${dirName} ]。确认上传吗?`,
|
||||
onConfirm: () => {
|
||||
const paths: string[] = []
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const f = files.item(i)
|
||||
if (f) {
|
||||
paths.push((f as any).webkitRelativePath || f.name)
|
||||
}
|
||||
}
|
||||
emit('uploadFiles', files, paths, uploadTargetDir.value)
|
||||
}
|
||||
}
|
||||
emit('uploadFiles', files, paths, uploadTargetDir.value)
|
||||
}
|
||||
input.value = ''
|
||||
}
|
||||
@@ -71,13 +129,13 @@ function handleFilesUpload(e: Event) {
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="emit('refresh')" :disabled="isRefreshing" title="刷新">
|
||||
<RefreshCw class="h-3 w-3" :class="{ 'animate-spin': isRefreshing }" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="triggerFilesUpload('')" title="上传文件/文件夹(放在根目录)">
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="triggerFilesUpload(currentTargetDir)" :title="currentTargetDir ? `上传到: ${currentTargetDir}` : '上传到根目录'">
|
||||
<FolderUp class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="triggerArchiveUpload('')" title="导入压缩包(放在根目录)">
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="triggerArchiveUpload(currentTargetDir)" :title="currentTargetDir ? `导入压缩包到: ${currentTargetDir}` : '导入压缩包到根目录'">
|
||||
<Upload class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="emit('create', '')" title="新建">
|
||||
<Button variant="ghost" size="icon" class="h-6 w-6" @click="emit('create', currentTargetDir)" :title="currentTargetDir ? `在 ${currentTargetDir} 中新建` : '在根目录新建'">
|
||||
<Plus class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
@@ -98,5 +156,26 @@ function handleFilesUpload(e: Event) {
|
||||
@rename="p => emit('rename', p)"
|
||||
@duplicate="p => emit('duplicate', p)" />
|
||||
</div>
|
||||
|
||||
<!-- 上传确认对话框 -->
|
||||
<BaihuDialog v-model:open="confirmUpload.show" :title="confirmUpload.title" icon="Upload" size="sm">
|
||||
<div class="flex flex-col sm:flex-row items-center sm:items-start gap-4 p-1">
|
||||
<div class="h-12 w-12 rounded-full bg-primary/10 flex items-center justify-center shrink-0">
|
||||
<AlertCircle class="h-6 w-6 text-primary" />
|
||||
</div>
|
||||
<div class="flex-1 text-center sm:text-left">
|
||||
<p class="text-sm text-foreground/90 leading-relaxed font-medium">确认操作?</p>
|
||||
<p class="text-[13px] text-muted-foreground mt-1 break-all">
|
||||
{{ confirmUpload.message }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="flex flex-col-reverse sm:flex-row gap-2 w-full sm:w-auto mt-2 sm:mt-0">
|
||||
<Button variant="outline" @click="confirmUpload.show = false" class="w-full sm:w-24">取消</Button>
|
||||
<Button @click="confirmUpload.show = false; confirmUpload.onConfirm()" class="w-full sm:w-auto px-6">立即开始</Button>
|
||||
</div>
|
||||
</template>
|
||||
</BaihuDialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user