From 831a5cfa24563b40782e155ce6fc624304380d15 Mon Sep 17 00:00:00 2001 From: x1ao4 Date: Sun, 25 May 2025 00:22:56 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BA=E9=80=89=E6=8B=A9=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=A4=B9=E7=95=8C=E9=9D=A2=E5=A2=9E=E5=8A=A0=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E6=98=BE=E7=A4=BA=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E4=B8=BA=E5=88=A0=E9=99=A4=E6=96=87=E4=BB=B6=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=A4=9A=E9=80=89=E6=96=87=E4=BB=B6=E5=88=A0?= =?UTF-8?q?=E9=99=A4=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/static/css/main.css | 20 +++- app/templates/index.html | 228 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 230 insertions(+), 18 deletions(-) diff --git a/app/static/css/main.css b/app/static/css/main.css index 3c147cd..89c394a 100644 --- a/app/static/css/main.css +++ b/app/static/css/main.css @@ -1656,7 +1656,7 @@ button.close:focus, } #fileSelectModal .table td { - padding: 5.5px 12.5px 7px 12.5px !important; /* 单元格上右下左内边距 */ + padding: 5.5px 12.5px 7px 12px !important; /* 单元格上右下左内边距 */ vertical-align: middle; border-bottom: 1px solid var(--border-color); color: var(--dark-text-color); @@ -1722,8 +1722,14 @@ button.close:focus, padding-right: 12px; /* 右边距 */ } +/* 添加文件选择模态框左下角文件信息文本的左边距样式 */ +#fileSelectModal .modal-footer .file-selection-info { + margin-left: 0px; /* 与表格左边距保持一致 */ + font-size: 0.85rem !important; /* 覆盖内联样式 */ +} + #fileSelectModal .modal-footer span { - font-size: 0.9rem; + font-size: 0.85rem; color: var(--dark-text-color); margin-right: auto; } @@ -3899,3 +3905,13 @@ table.selectable-records .expand-button:hover { position: relative; top: 0px; /* 负值向上移动,正值向下移动 */ } + +/* 添加选中文件的样式 */ +.selected-file { + background-color: var(--button-gray-background-color); +} + +/* 确保文件选择模态框中的表格行在选中状态下保持可见 */ +#fileSelectModal .table tr.selected-file:hover { + background-color: var(--button-gray-background-color); +} diff --git a/app/templates/index.html b/app/templates/index.html index fe2363b..7c54034 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -912,7 +912,14 @@ - +
{{ file.include_items }} 项 {{file.size | size}} {{file.updated_at | ts2date}} - 删除 + + 删除 + @@ -953,6 +962,9 @@
@@ -1046,7 +1058,9 @@ selectShare: true, previewRegex: false, sortBy: "updated_at", // 默认排序字段 - sortOrder: "desc" // 默认排序顺序 + sortOrder: "desc", // 默认排序顺序 + selectedFiles: [], // 存储选中的文件ID + lastSelectedFileIndex: -1 // 记录最后选择的文件索引 }, historyParams: { sortBy: "transfer_time", @@ -1203,13 +1217,20 @@ this.checkNewVersion(); this.fetchUserInfo(); // 获取用户信息 - // 从本地存储中恢复之前的标签页状态 + // 添加点击事件监听 + document.addEventListener('click', this.handleOutsideClick); + document.addEventListener('click', this.handleModalOutsideClick); + + // 添加模态框关闭事件监听 + $('#fileSelectModal').on('hidden.bs.modal', () => { + this.fileSelect.selectedFiles = []; + this.fileSelect.lastSelectedFileIndex = -1; + }); + + // 检查本地存储中的标签页状态 const savedTab = localStorage.getItem('quarkAutoSave_activeTab'); if (savedTab) { this.activeTab = savedTab; - } else { - // 默认显示任务列表页面 - this.activeTab = 'tasklist'; } // 从本地存储中恢复侧边栏折叠状态 @@ -1251,6 +1272,15 @@ // 添加点击事件监听器,用于在点击表格外区域时取消选择记录 document.addEventListener('click', this.handleOutsideClick); + // 添加点击事件监听器,用于在点击模态框表格外区域时取消选择文件 + document.addEventListener('click', this.handleModalOutsideClick); + + // 添加模态框关闭事件监听,清空选中文件列表 + $('#fileSelectModal').on('hidden.bs.modal', () => { + this.fileSelect.selectedFiles = []; + this.fileSelect.lastSelectedFileIndex = -1; + }); + window.addEventListener('beforeunload', this.handleBeforeUnload); // 监听模态框显示事件,检查滚动条状态 @@ -2261,17 +2291,34 @@ } }, deleteFile(fid, fname, isDir) { - if (fid != "" && confirm(`确定要删除${isDir ? '目录' : '文件'} [${fname}] 吗?`)) - axios.post('/delete_file', { - fid: fid - }).then(response => { - if (response.data.code == 0) { - this.fileSelect.fileList = this.fileSelect.fileList.filter(item => item.fid != fid); + if (!confirm(`确定要删除此项目吗?`)) { + return; + } + + axios.post('/delete_file', { fid: fid }) + .then(response => { + if (response.data.code === 0) { + // 从列表中移除文件 + this.fileSelect.fileList = this.fileSelect.fileList.filter(item => item.fid !== fid); + + // 如果文件在选中列表中,也从选中列表中移除 + if (this.fileSelect.selectedFiles.includes(fid)) { + this.fileSelect.selectedFiles = this.fileSelect.selectedFiles.filter(id => id !== fid); + + // 如果选中列表为空,重置最后选择的索引 + if (this.fileSelect.selectedFiles.length === 0) { + this.fileSelect.lastSelectedFileIndex = -1; + } + } + + this.showToast('成功删除 1 个项目'); } else { - alert('删除失败:' + response.data.message); + alert('删除失败: ' + response.data.message); } - }).catch(error => { - // 错误处理 + }) + .catch(error => { + console.error('删除项目出错:', error); + alert('删除项目出错: ' + (error.response?.data?.message || error.message)); }); }, getSavepathDetail(params = 0) { @@ -3288,6 +3335,155 @@ this.lastSelectedRecordIndex = -1; } }, + selectFileItem(event, fileId) { + // 如果是在预览模式或选择分享模式,不允许选择 + if (this.fileSelect.previewRegex || this.fileSelect.selectShare) return; + + // 获取当前文件的索引 + const currentIndex = this.fileSelect.fileList.findIndex(file => file.fid === fileId); + if (currentIndex === -1) return; + + // 如果是Shift+点击,选择范围 + if (event.shiftKey && this.fileSelect.selectedFiles.length > 0) { + // 找出所有已选中文件的索引 + const selectedIndices = this.fileSelect.selectedFiles.map(id => + this.fileSelect.fileList.findIndex(file => file.fid === id) + ).filter(index => index !== -1); // 过滤掉未找到的文件 + + if (selectedIndices.length > 0) { + // 找出已选中文件中最靠前的索引 + const earliestSelectedIndex = Math.min(...selectedIndices); + // 确定最终的选择范围 + const startIndex = Math.min(earliestSelectedIndex, currentIndex); + const endIndex = Math.max(earliestSelectedIndex, currentIndex); + + // 获取范围内所有文件的ID(排除文件夹) + this.fileSelect.selectedFiles = this.fileSelect.fileList + .slice(startIndex, endIndex + 1) + .filter(file => !file.dir) // 只选择文件,不选择文件夹 + .map(file => file.fid); + } else { + // 如果没有有效的选中文件(可能是由于列表刷新),则只选择当前文件 + const file = this.fileSelect.fileList[currentIndex]; + if (!file.dir) { // 不选择文件夹 + this.fileSelect.selectedFiles = [fileId]; + } + } + } + // 如果是Ctrl/Cmd+点击,切换单个文件选择状态 + else if (event.ctrlKey || event.metaKey) { + const file = this.fileSelect.fileList[currentIndex]; + if (file.dir) return; // 不允许选择文件夹 + + if (this.fileSelect.selectedFiles.includes(fileId)) { + this.fileSelect.selectedFiles = this.fileSelect.selectedFiles.filter(id => id !== fileId); + } else { + this.fileSelect.selectedFiles.push(fileId); + } + } + // 普通点击,清除当前选择并选择当前文件 + else { + const file = this.fileSelect.fileList[currentIndex]; + if (file.dir) return; // 不允许选择文件夹 + + if (this.fileSelect.selectedFiles.length === 1 && this.fileSelect.selectedFiles.includes(fileId)) { + this.fileSelect.selectedFiles = []; + } else { + this.fileSelect.selectedFiles = [fileId]; + } + } + + // 更新最后选择的文件索引,只有在有选择文件时才更新 + if (this.fileSelect.selectedFiles.length > 0) { + this.fileSelect.lastSelectedFileIndex = currentIndex; + } else { + this.fileSelect.lastSelectedFileIndex = -1; + } + + // 阻止事件冒泡 + event.stopPropagation(); + }, + deleteSelectedFiles(clickedFid, clickedFname, isDir) { + // 如果是文件夹或者没有选中的文件,则按原来的方式删除单个文件 + if (isDir || this.fileSelect.selectedFiles.length === 0) { + this.deleteFile(clickedFid, clickedFname, isDir); + return; + } + + // 如果点击的文件不在选中列表中,也按原来的方式删除单个文件 + if (!this.fileSelect.selectedFiles.includes(clickedFid)) { + this.deleteFile(clickedFid, clickedFname, isDir); + return; + } + + // 多选删除 + const selectedCount = this.fileSelect.selectedFiles.length; + + // 根据选中数量使用不同的确认提示 + let confirmMessage = selectedCount === 1 + ? `确定要删除此项目吗?` + : `确定要删除选中的 ${selectedCount} 个项目吗?`; + + if (confirm(confirmMessage)) { + // 创建一个Promise数组来处理所有删除请求 + const deletePromises = this.fileSelect.selectedFiles.map(fid => { + return axios.post('/delete_file', { fid: fid }) + .then(response => { + return { fid: fid, success: response.data.code === 0 }; + }) + .catch(error => { + return { fid: fid, success: false }; + }); + }); + + // 等待所有删除请求完成 + Promise.all(deletePromises) + .then(results => { + // 统计成功和失败的数量 + const successCount = results.filter(r => r.success).length; + const failCount = results.length - successCount; + + // 从文件列表中移除成功删除的文件 + const successfullyDeletedFids = results.filter(r => r.success).map(r => r.fid); + this.fileSelect.fileList = this.fileSelect.fileList.filter(item => !successfullyDeletedFids.includes(item.fid)); + + // 清空选中文件列表 + this.fileSelect.selectedFiles = []; + this.fileSelect.lastSelectedFileIndex = -1; + + // 显示结果 + if (failCount > 0) { + alert(`成功删除 ${successCount} 个项目,${failCount} 个项目删除失败`); + } else { + this.showToast(`成功删除 ${successCount} 个项目`); + } + }); + } + }, + handleModalOutsideClick(event) { + // 如果当前不是文件选择模式或者没有选中的文件,则不处理 + if (this.fileSelect.previewRegex || this.fileSelect.selectShare || this.fileSelect.selectedFiles.length === 0) { + return; + } + + // 检查点击是否在表格内 + const tableElement = document.querySelector('#fileSelectModal .table'); + + // 如果点击不在表格内,则清除选择 + if (tableElement && !tableElement.contains(event.target)) { + this.fileSelect.selectedFiles = []; + this.fileSelect.lastSelectedFileIndex = -1; + } + }, + preventTextSelection(event, isDir) { + // 如果是文件夹,不阻止默认行为 + if (isDir) return; + + // 如果是Shift点击或Ctrl/Cmd点击,阻止文本选择 + if (event.shiftKey || event.ctrlKey || event.metaKey) { + event.preventDefault(); + } + }, } });