diff --git a/web/src/pages/app/dialogs.css b/web/src/pages/app/dialogs.css index 291d814..43dd822 100644 --- a/web/src/pages/app/dialogs.css +++ b/web/src/pages/app/dialogs.css @@ -79,6 +79,22 @@ word-break: break-all; } +.upload-status { + padding: 8px 10px; + border: 1px solid #b9d7c1; + border-radius: 6px; + background: #eef8f1; + color: #27613a; + font-size: 13px; + line-height: 1.45; + word-break: break-all; +} + +.upload-popup-form.is-uploading .drop-zone { + cursor: progress; + opacity: 0.72; +} + .upload-target-path { display: grid; grid-template-columns: 64px minmax(0, 1fr); diff --git a/web/src/pages/app/modules/models.ts b/web/src/pages/app/modules/models.ts index 1c94db5..a008e73 100644 --- a/web/src/pages/app/modules/models.ts +++ b/web/src/pages/app/modules/models.ts @@ -509,6 +509,7 @@ async function openUploadModelDialog() { +
${dictionaryDatalistHtml()} `, @@ -527,22 +528,38 @@ async function openUploadModelDialog() { const properties = { model: String(form.get("model") ?? "") }; - for (const file of state.files) { - await uploadModelToBackend({ - file, - name: state.files.length === 1 ? name ?? "" : modelNameFromFile(file.name), - fileName: file.name, - brandName, - typeName, - operationTree: defaultOperationTree, - properties - }); + let completedCount = 0; + setUploadDialogBusy(state, true); + try { + for (const [index, file] of state.files.entries()) { + updateUploadStatus(`正在上传 ${index + 1}/${state.files.length}:${file.name}`); + await waitForUploadStatusPaint(); + await uploadModelToBackend({ + file, + name: state.files.length === 1 ? name ?? "" : modelNameFromFile(file.name), + fileName: file.name, + brandName, + typeName, + operationTree: defaultOperationTree, + properties + }); + completedCount += 1; + updateUploadStatus(`已完成 ${completedCount}/${state.files.length}`); + } + } catch (error) { + updateUploadStatus(`上传失败,已完成 ${completedCount}/${state.files.length},请处理后重试。`); + throw error; + } finally { + if (completedCount < state.files.length) { + setUploadDialogBusy(state, false); + } } return true; } }); if (result) { + notify("模型上传完成"); invalidateDictionaries(); await reloadFoldersAndModels(); } @@ -674,6 +691,28 @@ function bindUploadDialogEvents(state: UploadFormState) { }); } +function updateUploadStatus(message: string) { + const status = document.querySelector