fix: Resolve file renaming and other operational conflicts

This commit is contained in:
lan-yonghui 2025-08-27 12:24:06 +08:00
parent c0a0f4c801
commit 370354bac5
10 changed files with 46 additions and 15 deletions

View file

@ -112,7 +112,7 @@ const rightClick = ref({
currentRow: null,
});
const handleRightClick = (row, column, event) => {
tableRef.value.refElTable.clearSelection();
clearSelects();
tableRef.value.refElTable.toggleRowSelection(row);
if (!props.rightButtons) {
return;
@ -128,7 +128,7 @@ const handleRightClick = (row, column, event) => {
};
const closeRightClick = () => {
rightClick.value.visible = false;
tableRef.value.refElTable.clearSelection();
clearSelects();
document.removeEventListener('click', closeRightClick);
};
const disabled = computed(() => {

View file

@ -1509,6 +1509,7 @@ const message = {
noShowHide: 'Dont show hidden files',
cancelUpload: 'Cancel Upload',
cancelUploadHelper: 'Whether to cancel the upload, after cancellation the upload list will be cleared.',
keepOneTab: 'Keep at least one tab',
},
ssh: {
autoStart: 'Auto start',
@ -3660,7 +3661,7 @@ const message = {
taskName: 'Task Name',
cronJobType: 'Task Type',
clamPath: 'Scan Directory',
cronjob: 'Cronjob',
cronjob: 'Cronjob execution {0} failed',
app: 'Backup App',
web: 'Backup Website',
database: 'Backup Database',

View file

@ -1453,6 +1453,7 @@ const message = {
noShowHide: '隠しファイルを表示しない',
cancelUpload: 'アップロードをキャンセル',
cancelUploadHelper: 'アップロードをキャンセルするかどうかキャンセル後アップロードリストはクリアされます',
keepOneTab: '少なくとも1つのタブを保持してください',
},
ssh: {
autoStart: 'オートスタート',
@ -3538,7 +3539,7 @@ const message = {
taskName: 'タスク名',
cronJobType: 'タスクタイプ',
clamPath: 'スキャンディレクトリ',
cronjob: 'Cronジョブ',
cronjob: 'スケジュールタスクの実行{0}で異常が発生しました',
app: 'アプリバックアップ',
web: 'ウェブサイトバックアップ',
database: 'データベースバックアップ',

View file

@ -1438,6 +1438,7 @@ const message = {
noShowHide: '숨김 파일 숨기기',
cancelUpload: '업로드 취소',
cancelUploadHelper: '업로드를 취소할지 여부, 취소 업로드 목록이 비워집니다.',
keepOneTab: '최소한 하나의 탭을 유지하세요',
},
ssh: {
autoStart: '자동 시작',
@ -3476,7 +3477,7 @@ const message = {
taskName: '작업 이름',
cronJobType: '작업 유형',
clamPath: '검사 디렉토리',
cronjob: '크론 작업',
cronjob: '예약 작업 실행 {0} 오류가 발생했습니다',
app: '백업 애플리케이션',
web: '백업 웹사이트',
database: '백업 데이터베이스',

View file

@ -1496,6 +1496,7 @@ const message = {
cancelUpload: 'Batalkan Muat Naik',
cancelUploadHelper:
'Adakah hendak membatalkan muat naik, selepas pembatalan senarai muat naik akan dikosongkan.',
keepOneTab: 'Pastikan sekurang-kurangnya satu tab dikekalkan',
},
ssh: {
autoStart: 'Mula automatik',
@ -3624,7 +3625,7 @@ const message = {
taskName: 'Nama Tugas',
cronJobType: 'Jenis Tugas',
clamPath: 'Direktori Imbasan',
cronjob: 'Cronjob',
cronjob: 'Pelaksanaan tugas berjadual {0} gagal',
app: 'Sandaran Aplikasi',
web: 'Sandaran Laman Web',
database: 'Sandaran Pangkalan Data',

View file

@ -1483,6 +1483,7 @@ const message = {
noShowHide: 'Não mostrar arquivos ocultos',
cancelUpload: 'Cancelar Upload',
cancelUploadHelper: 'Deseja cancelar o upload, após o cancelamento, a lista de upload será limpa.',
keepOneTab: 'Mantenha pelo menos uma aba',
},
ssh: {
autoStart: 'Início automático',
@ -3632,7 +3633,7 @@ const message = {
taskName: 'Nome da Tarefa',
cronJobType: 'Tipo de Tarefa',
clamPath: 'Diretório de Varredura',
cronjob: 'Tarefa Cron',
cronjob: 'Tarefa Cron agendada {0} falhou',
app: 'Backup do Aplicativo',
web: 'Backup do Site',
database: 'Backup do Banco de Dados',

View file

@ -1484,6 +1484,7 @@ const message = {
noShowHide: 'Не показывать скрытые файлы',
cancelUpload: 'Отменить загрузку',
cancelUploadHelper: 'Отменить загрузку или нет, после отмены список загрузок будет очищен.',
keepOneTab: 'Необходимо оставить как минимум одну вкладку',
},
ssh: {
autoStart: 'Автозапуск',
@ -3618,7 +3619,7 @@ const message = {
taskName: 'Имя задачи',
cronJobType: 'Тип задачи',
clamPath: 'Директория проверки',
cronjob: 'Задача Cron',
cronjob: 'Ошибка при выполнении Задача cron {0}',
app: 'Резервное копирование приложения',
web: 'Резервное копирование сайта',
database: 'Резервное копирование базы данных',

View file

@ -1526,6 +1526,7 @@ const message = {
noShowHide: 'Gizli dosyaları gösterme',
cancelUpload: 'Yüklemeyi İptal Et',
cancelUploadHelper: 'Yüklemeyi iptal etmek ister misiniz, iptal sonrası yükleme listesi temizlenecektir.',
keepOneTab: 'En az bir sekme ık kalmalıdır',
},
ssh: {
autoStart: 'Otomatik başlat',
@ -3693,7 +3694,7 @@ const message = {
success: 'Uyarı Başarılı',
pushing: 'Gönderiliyor...',
error: 'Uyarı Başarısız',
cleanLog: 'Günlükleri Temizle',
cleanLog: 'Zamanlanmış görev yürütmesi {0} hatası',
cleanAlertLogs: 'Uyarı Günlüklerini Temizle',
daily: 'Günlük Uyarı Sayısı: {0}',
cumulative: 'Toplam Uyarı Sayısı: {0}',

View file

@ -1438,6 +1438,7 @@ const message = {
noShowHide: '不顯示隱藏檔案',
cancelUpload: '取消上傳',
cancelUploadHelper: '是否取消上傳取消後將清空上傳列表',
keepOneTab: '至少保留一個標籤頁',
},
ssh: {
autoStart: '開機自啟',
@ -3405,7 +3406,7 @@ const message = {
taskName: '任務名稱',
cronJobType: '任務類型',
clamPath: '掃描目錄',
cronjob: '計劃任務',
cronjob: '計劃任務執行{0}異常',
app: '備份應用',
web: '備份網站',
database: '備份資料庫',

View file

@ -471,7 +471,8 @@
:autofocus="isEdit"
class="table-link table-input"
placeholder="file name"
@blur="handleRename(row)"
@keydown.enter="handleRename(row)"
@blur="onRenameBlur($event, row)"
/>
<span v-else class="table-link" @click="open(row)" type="primary">
{{ row.name }}
@ -584,7 +585,7 @@
</LayoutContent>
</div>
</el-tab-pane>
<el-tab-pane :closable="false">
<el-tab-pane :closable="false" v-if="editableTabs.length < 6">
<template #label>
<el-icon @click="addTab()"><Plus /></el-icon>
</template>
@ -906,8 +907,8 @@ const updateButtons = async () => {
const handlePath = () => {
nextTick(function () {
let breadCrumbWidth = breadCrumbRef.value.offsetWidth;
let pathWidth = toolRef.value.offsetWidth;
let breadCrumbWidth = breadCrumbRef.value?.offsetWidth;
let pathWidth = toolRef.value?.offsetWidth;
if (pathWidth - breadCrumbWidth < 50 && paths.value.length > 1) {
const removed = paths.value.shift();
if (removed) hidePaths.value.push(removed);
@ -1281,6 +1282,20 @@ const openRename = (item: File.File) => {
hideRightMenu();
};
const onRenameBlur = (e: FocusEvent, row: File.File) => {
const related = e.relatedTarget as HTMLElement | null;
if (
related &&
(related.closest('.fu-table-more-button') || related.closest('.fu-table-more-button .el-dropdown__item'))
) {
setTimeout(() => {
getCurrentRename()?.focus();
}, 0);
return;
}
handleRename(row);
};
const handleRename = async (row: File.File): Promise<void> => {
if (fileRename.newName === fileRename.oldName) {
isEdit.value = false;
@ -1584,7 +1599,7 @@ onMounted(() => {
req.path = globalStore.lastFilePath;
getPaths(req.path);
}
pathWidth.value = getCurrentPath().offsetWidth;
pathWidth.value = getCurrentPath()?.offsetWidth;
paths.value = [];
const segments = editableTabsValue.value.split('/').filter(Boolean);
@ -1670,6 +1685,9 @@ function updateTab(newPath?: string) {
const addTab = () => {
let tabIndex = editableTabs.value.length;
if (tabIndex >= 6) {
return;
}
const newTabId = `${++tabIndex}`;
editableTabs.value.push({
id: newTabId,
@ -1695,6 +1713,11 @@ const changeTab = (targetPath: TabPaneName) => {
};
const removeTab = (targetPath: TabPaneName) => {
let tabIndex = editableTabs.value.length;
if (tabIndex === 1) {
MsgWarning(i18n.global.t('file.keepOneTab'));
return;
}
editableTabsKey.value = targetPath.toString();
const tabs = editableTabs.value;
let activeKey = editableTabsKey.value;