From 86842f8bc1a1a47ce6072c16f96671cc2b8dd714 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Sat, 17 Jan 2026 01:33:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=BC=98=E5=8C=96=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=A9=BA=E7=99=BD=E5=8C=BA=E5=9F=9F=E7=9A=84?= =?UTF-8?q?=E5=8F=B3=E9=94=AE=E8=8F=9C=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/views/file/ListView.vue | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/web/src/views/file/ListView.vue b/web/src/views/file/ListView.vue index a2b32ecd..2cf697f9 100644 --- a/web/src/views/file/ListView.vue +++ b/web/src/views/file/ListView.vue @@ -282,7 +282,25 @@ const toggleCheckbox = (item: any) => { } } +// 空白区域右键菜单是否激活 +const isEmptyContextMenu = ref(false) + const options = computed(() => { + // 空白区域右键菜单 + if (isEmptyContextMenu.value) { + const options: DropdownOption[] = [ + { label: $gettext('New File'), key: 'new-file' }, + { label: $gettext('New Folder'), key: 'new-folder' } + ] + if (marked.value.length) { + options.unshift({ + label: $gettext('Paste'), + key: 'paste' + }) + } + return options + } + // 多选情况下显示简化菜单 if (isMultiSelect.value) { const options: DropdownOption[] = [ @@ -485,6 +503,7 @@ const handleContextMenu = (item: any, event: MouseEvent) => { } nextTick().then(() => { + isEmptyContextMenu.value = false showDropdown.value = true selectedRow.value = item dropdownX.value = event.clientX @@ -492,6 +511,29 @@ const handleContextMenu = (item: any, event: MouseEvent) => { }) } +// 处理空白区域右键菜单 +const handleEmptyContextMenu = (event: MouseEvent) => { + // 如果点击的是文件项,不处理 + const target = event.target as HTMLElement + if (target.closest('.file-item')) return + // 列表视图表头不触发 + if (target.closest('.list-header')) return + + event.preventDefault() + showDropdown.value = false + + // 清除选中 + selected.value = [] + + nextTick().then(() => { + isEmptyContextMenu.value = true + showDropdown.value = true + selectedRow.value = null + dropdownX.value = event.clientX + dropdownY.value = event.clientY + }) +} + // 框选开始 const onSelectionStart = (event: MouseEvent) => { // 只响应左键,且不在项目上 @@ -857,6 +899,23 @@ const handlePaste = () => { } const handleSelect = (key: string) => { + // 空白区域菜单选项 + if (isEmptyContextMenu.value) { + switch (key) { + case 'paste': + handlePaste() + break + case 'new-file': + startInlineCreate(false) + break + case 'new-folder': + startInlineCreate(true) + break + } + onCloseDropdown() + return + } + const items = isMultiSelect.value ? getSelectedItems() : [selectedRow.value] switch (key) { @@ -1284,6 +1343,7 @@ onUnmounted(() => { 'list-mode': fileStore.viewType === 'list' }" @mousedown="onSelectionStart" + @contextmenu="handleEmptyContextMenu" >