235 lines
7.5 KiB
Vue
235 lines
7.5 KiB
Vue
<script setup lang="ts">
|
|
import { useFilesPageContext } from '@/composables/files/filesPageContext'
|
|
|
|
const p = useFilesPageContext()
|
|
</script>
|
|
|
|
<template>
|
|
<v-card
|
|
elevation="0"
|
|
border
|
|
rounded="lg"
|
|
:class="{ 'files-drop-active': p.dropActive }"
|
|
@dragenter.prevent="p.dropActive = true"
|
|
@dragover.prevent="p.dropActive = true"
|
|
@dragleave.prevent="p.dropActive = false"
|
|
@drop.prevent="p.onDropFiles"
|
|
>
|
|
<v-data-table
|
|
v-model="p.selectedFiles"
|
|
:items="p.displayedFiles"
|
|
:headers="p.fileHeaders"
|
|
:loading="p.loading"
|
|
show-select
|
|
return-object
|
|
hover
|
|
density="comfortable"
|
|
item-value="name"
|
|
:row-props="p.fileRowProps"
|
|
>
|
|
<template #item.name="{ item }">
|
|
<div class="d-flex align-center ga-2 min-w-0">
|
|
<v-icon :color="p.entryIconColor(item)" size="20">
|
|
{{ p.entryIcon(item) }}
|
|
</v-icon>
|
|
<v-icon
|
|
v-if="p.isEntryLikelyUnreadable(item, p.sshUserForFiles)"
|
|
size="18"
|
|
color="warning"
|
|
title="当前 SSH 用户可能无法读取"
|
|
>
|
|
mdi-shield-lock
|
|
</v-icon>
|
|
<div class="min-w-0">
|
|
<span :class="{ 'font-weight-medium': item.type === 'directory' }">{{ item.name }}</span>
|
|
<div
|
|
v-if="item.type === 'symlink' && item.link_target"
|
|
class="text-caption text-medium-emphasis text-truncate"
|
|
>
|
|
→ {{ item.link_target }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<template #item.owner="{ item }">
|
|
<v-tooltip :text="p.permissionTooltip(item)" location="top">
|
|
<template #activator="{ props: tipProps }">
|
|
<v-chip
|
|
v-bind="tipProps"
|
|
size="small"
|
|
variant="tonal"
|
|
:color="p.ownerChipColor(item.owner || '')"
|
|
class="text-none"
|
|
>
|
|
{{ p.formatOwnerChip(item) }}
|
|
</v-chip>
|
|
</template>
|
|
</v-tooltip>
|
|
</template>
|
|
|
|
<template #item.size="{ item }">
|
|
<span class="text-medium-emphasis">
|
|
{{ item.type === 'directory' ? '—' : p.formatSize(item.size) }}
|
|
</span>
|
|
</template>
|
|
|
|
<template #item.modified="{ item }">
|
|
<span class="text-medium-emphasis">{{ item.modified || '—' }}</span>
|
|
</template>
|
|
|
|
<template #item.actions="{ item }">
|
|
<div class="d-flex ga-1">
|
|
<v-btn
|
|
v-if="p.isRegularFile(item)"
|
|
variant="text"
|
|
size="x-small"
|
|
density="compact"
|
|
color="primary"
|
|
@click.stop="p.editFile(item)"
|
|
>
|
|
编辑
|
|
</v-btn>
|
|
<v-btn
|
|
v-if="p.isRegularFile(item)"
|
|
variant="text"
|
|
size="x-small"
|
|
density="compact"
|
|
@click.stop="p.previewFile(item)"
|
|
>
|
|
查看
|
|
</v-btn>
|
|
<v-btn
|
|
v-if="p.isRegularFile(item)"
|
|
variant="text"
|
|
size="x-small"
|
|
density="compact"
|
|
@click.stop="p.downloadFile(item)"
|
|
>
|
|
下载
|
|
</v-btn>
|
|
<v-btn
|
|
variant="text"
|
|
size="x-small"
|
|
color="error"
|
|
density="compact"
|
|
@click.stop="p.confirmDeleteFile(item)"
|
|
>
|
|
删除
|
|
</v-btn>
|
|
</div>
|
|
</template>
|
|
|
|
<template #no-data>
|
|
<div v-if="p.pageReady && !p.loading" class="text-center text-medium-emphasis py-8">
|
|
<v-icon size="40" class="mb-2">mdi-folder-open-outline</v-icon>
|
|
<div>{{ p.emptyHint }}</div>
|
|
<div v-if="p.selectedServer" class="text-caption mt-2 text-disabled">
|
|
单击目录进入 · 双击文件编辑 · Ctrl+A 全选 · Ctrl+C/V 复制粘贴
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</v-data-table>
|
|
</v-card>
|
|
|
|
<v-menu v-model="p.showContextMenu" :target="[p.contextX, p.contextY]" location="bottom start">
|
|
<v-list density="compact" nav>
|
|
<v-list-item
|
|
v-if="p.contextFile && p.contextFile.type === 'directory'"
|
|
prepend-icon="mdi-folder-open"
|
|
@click="p.contextAction('open')"
|
|
>
|
|
<v-list-item-title>打开</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile && p.isRegularFile(p.contextFile)"
|
|
prepend-icon="mdi-pencil"
|
|
@click="p.contextAction('edit')"
|
|
>
|
|
<v-list-item-title>编辑</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile && p.isRegularFile(p.contextFile)"
|
|
prepend-icon="mdi-eye"
|
|
@click="p.contextAction('preview')"
|
|
>
|
|
<v-list-item-title>查看</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile && p.isRegularFile(p.contextFile)"
|
|
prepend-icon="mdi-download"
|
|
@click="p.contextAction('download')"
|
|
>
|
|
<v-list-item-title>下载</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile"
|
|
prepend-icon="mdi-content-copy"
|
|
@click="p.contextAction('copy')"
|
|
>
|
|
<v-list-item-title>复制 (Ctrl+C)</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile"
|
|
prepend-icon="mdi-content-cut"
|
|
@click="p.contextAction('cut')"
|
|
>
|
|
<v-list-item-title>剪切 (Ctrl+X)</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
prepend-icon="mdi-content-paste"
|
|
:disabled="!p.canPasteHere"
|
|
@click="p.contextAction('paste')"
|
|
>
|
|
<v-list-item-title>粘贴到当前目录 (Ctrl+V)</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile?.type === 'directory' && p.canPasteHere"
|
|
prepend-icon="mdi-folder-arrow-down"
|
|
@click="p.contextAction('pasteInto')"
|
|
>
|
|
<v-list-item-title>粘贴到「{{ p.contextFile.name }}」</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item prepend-icon="mdi-link-variant" @click="p.contextAction('copyPath')">
|
|
<v-list-item-title>复制路径</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item prepend-icon="mdi-console" @click="p.contextAction('terminal')">
|
|
<v-list-item-title>终端</v-list-item-title>
|
|
</v-list-item>
|
|
<v-divider />
|
|
<v-list-item
|
|
v-if="p.contextFile && (p.isRegularFile(p.contextFile) || p.contextFile.type === 'directory')"
|
|
prepend-icon="mdi-zip-box"
|
|
@click="p.contextAction('compress')"
|
|
>
|
|
<v-list-item-title>压缩</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item
|
|
v-if="p.contextFile && p.isArchiveName(p.contextFile.name)"
|
|
prepend-icon="mdi-package-up"
|
|
@click="p.contextAction('decompress')"
|
|
>
|
|
<v-list-item-title>解压</v-list-item-title>
|
|
</v-list-item>
|
|
<v-divider />
|
|
<v-list-item prepend-icon="mdi-file-rename-box" @click="p.contextAction('rename')">
|
|
<v-list-item-title>重命名</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item prepend-icon="mdi-lock" @click="p.contextAction('chmod')">
|
|
<v-list-item-title>修改权限</v-list-item-title>
|
|
</v-list-item>
|
|
<v-divider />
|
|
<v-list-item prepend-icon="mdi-delete" @click="p.contextAction('delete')">
|
|
<v-list-item-title class="text-error">删除</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-menu>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.files-drop-active {
|
|
outline: 2px dashed rgb(var(--v-theme-primary));
|
|
outline-offset: -2px;
|
|
}
|
|
</style>
|