feat: Upload multiple files and add overall and current file upload progress messages (#12327)

https://github.com/1Panel-dev/1Panel/issues/10593
This commit is contained in:
2026-03-25 07:30:19 +00:00
committed by GitHub
parent 096ec8edc7
commit 74ff7ddc19
11 changed files with 54 additions and 8 deletions
+2
View File
@@ -1671,6 +1671,8 @@ const message = {
searchHelper: 'Support wildcards such as *',
uploadFailed: '[{0}] File upload failed',
fileUploadStart: 'Uploading [{0}]...',
uploadOverallProgress: 'Overall progress',
uploadCurrentFileProgress: 'Current file',
currentSelect: 'Current selection: ',
unsupportedType: 'Unsupported file type',
deleteHelper:
+2
View File
@@ -1703,6 +1703,8 @@ const message = {
searchHelper: 'Soporta comodines como *',
uploadFailed: '[{0}] Fallo en la carga del archivo',
fileUploadStart: 'Cargando [{0}]...',
uploadOverallProgress: 'Progreso total',
uploadCurrentFileProgress: 'Archivo actual',
currentSelect: 'Selección actual: ',
unsupportedType: 'Tipo de archivo no soportado',
deleteHelper: '¿Está seguro de eliminar los siguientes archivos? Por defecto irán a la papelera de reciclaje.',
+2
View File
@@ -1682,6 +1682,8 @@ const message = {
searchHelper: '*などのワイルドカードをサポート',
uploadFailed: '[{0}] ファイルのアップロードに失敗しました',
fileUploadStart: 'アップロード[{0}]...',
uploadOverallProgress: '全体の進捗',
uploadCurrentFileProgress: '現在のファイル',
currentSelect: '現在の選択:',
unsupportedType: 'サポートされていないファイルタイプ',
deleteHelper: '次のファイルを削除したいですかデフォルトでは削除後にリサイクルビンに入ります',
+2
View File
@@ -1651,6 +1651,8 @@ const message = {
searchHelper: '* 등의 와일드카드를 지원합니다',
uploadFailed: '[{0}] 파일 업로드 실패',
fileUploadStart: '[{0}] 업로드 ...',
uploadOverallProgress: '전체 진행률',
uploadCurrentFileProgress: '현재 파일',
currentSelect: '현재 선택: ',
unsupportedType: '지원되지 않는 파일 유형',
deleteHelper: '다음 파일을 삭제하시겠습니까? 기본적으로 삭제 휴지통으로 이동합니다.',
+2
View File
@@ -1706,6 +1706,8 @@ const message = {
searchHelper: 'Sokong wildcard seperti *',
uploadFailed: '[{0}] Gagal memuat naik fail',
fileUploadStart: 'Memuat naik [{0}]...',
uploadOverallProgress: 'Kemajuan keseluruhan',
uploadCurrentFileProgress: 'Fail semasa',
currentSelect: 'Pilihan semasa: ',
unsupportedType: 'Jenis fail tidak disokong',
deleteHelper:
+2
View File
@@ -1819,6 +1819,8 @@ const message = {
searchHelper: 'Suporte a curingas como *',
uploadFailed: '[{0}] Falha no upload do arquivo',
fileUploadStart: 'Carregando [{0}]...',
uploadOverallProgress: 'Progresso geral',
uploadCurrentFileProgress: 'Arquivo atual',
currentSelect: 'Seleção atual: ',
unsupportedType: 'Tipo de arquivo não suportado',
deleteHelper:
+2
View File
@@ -1694,6 +1694,8 @@ const message = {
searchHelper: 'Поддерживает подстановочные знаки, такие как *',
uploadFailed: '[{0}] Ошибка загрузки файла',
fileUploadStart: 'Загрузка [{0}]...',
uploadOverallProgress: 'Общий прогресс',
uploadCurrentFileProgress: 'Текущий файл',
currentSelect: 'Текущий выбор: ',
unsupportedType: 'Неподдерживаемый тип файла',
deleteHelper: 'Вы уверены, что хотите удалить следующие файлы? По умолчанию они будут помещены в корзину',
+2
View File
@@ -1697,6 +1697,8 @@ const message = {
searchHelper: '* gibi joker karakterleri destekler',
uploadFailed: '[{0}] Dosya yükleme hatası',
fileUploadStart: '[{0}] yükleniyor...',
uploadOverallProgress: 'Genel ilerleme',
uploadCurrentFileProgress: 'Geçerli dosya',
currentSelect: 'Geçerli seçim: ',
unsupportedType: 'Desteklenmeyen dosya türü',
deleteHelper:
+2
View File
@@ -1576,6 +1576,8 @@ const message = {
searchHelper: '支援 * 等萬用字元',
uploadFailed: '{0} 檔案上傳失敗',
fileUploadStart: '正在上傳{0}...',
uploadOverallProgress: '總進度',
uploadCurrentFileProgress: '目前檔案',
currentSelect: '當前選中: ',
unsupportedType: '不支援的檔案類型',
deleteHelper: '確定刪除所選檔案 預設刪除之後將進入回收站',
+2
View File
@@ -1577,6 +1577,8 @@ const message = {
searchHelper: '支持 * 等通配符',
uploadFailed: '{0} 文件上传失败',
fileUploadStart: '正在上传{0}...',
uploadOverallProgress: '总进度',
uploadCurrentFileProgress: '当前文件',
currentSelect: '当前选中: ',
unsupportedType: '不支持的文件类型',
deleteHelper: '确定删除所选文件 默认删除之后将进入回收站',
@@ -51,12 +51,19 @@
>
<template #tip>
<el-text>{{ uploadHelper }}</el-text>
<el-progress
v-if="upLoading"
text-inside
:stroke-width="20"
:percentage="uploadPercent"
></el-progress>
<div v-if="upLoading && uploadTotalCount > 1" class="mt-3 space-y-1">
<div class="flex justify-between text-sm text-gray-500">
<span>{{ $t('file.uploadOverallProgress') }}</span>
<span>{{ uploadCurrentIndex + 1 }} / {{ uploadTotalCount }}</span>
</div>
<el-progress :stroke-width="20" :percentage="uploadOverallPercent" />
</div>
<div v-if="upLoading" :class="{ 'mt-3': upLoading && uploadTotalCount > 1 }" class="space-y-1">
<div v-if="uploadTotalCount > 1" class="text-sm text-gray-500">
{{ $t('file.uploadCurrentFileProgress') }}
</div>
<el-progress text-inside :stroke-width="16" :percentage="uploadPercent"></el-progress>
</div>
</template>
</el-upload>
@@ -101,7 +108,7 @@
</template>
<script setup lang="ts">
import { nextTick, reactive, ref } from 'vue';
import { computed, nextTick, reactive, ref } from 'vue';
import { UploadFile, UploadFiles, UploadInstance, UploadProps, UploadRawFile } from 'element-plus';
import { batchCheckFiles, chunkUploadFileData, uploadFileData } from '@/api/modules/files';
import i18n from '@/lang';
@@ -116,12 +123,22 @@ interface UploadFileProps {
const uploadRef = ref<UploadInstance>();
const loading = ref(false);
const upLoading = ref(false);
let uploadPercent = ref(0);
const uploadTotalCount = ref(0);
const uploadCurrentIndex = ref(0);
const uploadOverallPercent = computed(() => {
const total = uploadTotalCount.value;
if (!upLoading.value || total === 0) {
return 0;
}
const raw = (uploadCurrentIndex.value * 100 + uploadPercent.value) / total;
return Math.min(100, Math.round(raw));
});
const open = ref(false);
const path = ref();
let uploadHelper = ref('');
const dialogExistFileRef = ref();
const upLoading = ref(false);
const abortController = ref<AbortController | null>(null);
const em = defineEmits(['close']);
@@ -147,6 +164,8 @@ const handleClose = (done) => {
const closePage = () => {
open.value = false;
upLoading.value = false;
uploadTotalCount.value = 0;
uploadCurrentIndex.value = 0;
clearFiles();
em('close', false);
};
@@ -337,10 +356,13 @@ const uploadFile = async (files: any[]) => {
} else {
loading.value = true;
upLoading.value = true;
uploadTotalCount.value = files.length;
abortController.value = new AbortController();
let successCount = 0;
for (let i = 0; i < files.length; i++) {
const file = files[i];
uploadCurrentIndex.value = i;
uploadPercent.value = 0;
uploadHelper.value = i18n.global.t('file.fileUploadStart', [file.name]);
if (abortController.value.signal.aborted) {
@@ -360,6 +382,8 @@ const uploadFile = async (files: any[]) => {
loading.value = false;
upLoading.value = false;
uploadTotalCount.value = 0;
uploadCurrentIndex.value = 0;
uploadHelper.value = '';
if (successCount === files.length && !abortController.value.signal.aborted) {
@@ -441,6 +465,8 @@ const acceptParams = (props: UploadFileProps) => {
path.value = props.path;
open.value = true;
uploadPercent.value = 0;
uploadTotalCount.value = 0;
uploadCurrentIndex.value = 0;
uploadHelper.value = '';
nextTick(() => {