From a660493cf358098592a0080a02d0a3ebda5ecebf Mon Sep 17 00:00:00 2001 From: En Date: Wed, 8 Apr 2026 09:36:42 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/views/Dubbing.vue | 117 +++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/lesingle-aicreate-client/src/views/Dubbing.vue b/lesingle-aicreate-client/src/views/Dubbing.vue index 9a74104..513dceb 100644 --- a/lesingle-aicreate-client/src/views/Dubbing.vue +++ b/lesingle-aicreate-client/src/views/Dubbing.vue @@ -125,6 +125,18 @@
{{ toast }}
+ + +
+
+
{{ confirmTitle }}
+
{{ confirmContent }}
+
+ + +
+
+
@@ -179,6 +191,39 @@ function showToast(msg) { setTimeout(() => { toast.value = '' }, 2500) } +// ── 确认弹窗(替代原生 confirm) ── +const confirmVisible = ref(false) +const confirmTitle = ref('') +const confirmContent = ref('') +const confirmOkText = ref('确认') +const confirmCancelText = ref('取消') +let confirmResolve = null + +/** + * 显示确认弹窗(替代原生 confirm) + * @returns {Promise} + */ +function showConfirm(content, options = {}) { + confirmTitle.value = options.title || '确认操作' + confirmContent.value = content + confirmOkText.value = options.okText || '确认' + confirmCancelText.value = options.cancelText || '取消' + confirmVisible.value = true + return new Promise((resolve) => { confirmResolve = resolve }) +} + +function handleConfirmOk() { + confirmVisible.value = false + confirmResolve?.(true) + confirmResolve = null +} + +function handleConfirmCancel() { + confirmVisible.value = false + confirmResolve?.(false) + confirmResolve = null +} + function formatTime(sec) { if (!sec || isNaN(sec)) return '0:00' const m = Math.floor(sec / 60) @@ -348,7 +393,12 @@ async function voiceSingle() { } async function voiceAllConfirm() { - if (!confirm('将为所有未配音的页面生成AI语音,预计需要30-60秒,确认继续?')) return + const confirmed = await showConfirm('将为所有未配音的页面生成AI语音,预计需要30-60秒,确认继续?', { + title: 'AI 配音', + okText: '开始生成', + cancelText: '再想想', + }) + if (!confirmed) return voicingAll.value = true try { const res = await voicePage({ workId: workId.value, voiceAll: true }) @@ -838,4 +888,69 @@ onBeforeUnmount(() => { } .fade-enter-active, .fade-leave-active { transition: opacity 0.3s; } .fade-enter-from, .fade-leave-to { opacity: 0; } + +/* ── 确认弹窗(Ant Design 风格) ── */ +.confirm-overlay { + position: fixed; + top: 0; left: 0; right: 0; bottom: 0; + background: rgba(0, 0, 0, 0.45); + z-index: 1100; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; +} +.confirm-modal { + background: #fff; + border-radius: 8px; + padding: 24px; + min-width: 280px; + max-width: 400px; + box-shadow: 0 6px 30px rgba(0, 0, 0, 0.12); + animation: confirmFadeIn 0.2s ease; +} +@keyframes confirmFadeIn { + from { opacity: 0; transform: scale(0.95); } + to { opacity: 1; transform: scale(1); } +} +.confirm-title { + font-size: 16px; + font-weight: 600; + color: #1f2937; + margin-bottom: 8px; +} +.confirm-content { + font-size: 14px; + color: #6b7280; + line-height: 1.6; + margin-bottom: 24px; +} +.confirm-actions { + display: flex; + gap: 8px; + justify-content: flex-end; +} +.confirm-btn { + padding: 5px 16px; + border-radius: 6px; + font-size: 14px; + cursor: pointer; + height: 32px; + line-height: 1; + transition: all 0.2s; + + &.cancel { + border: 1px solid #d1d5db; + background: #fff; + color: #374151; + &:hover { border-color: #6366f1; color: #6366f1; } + } + &.ok { + border: none; + background: #6366f1; + color: #fff; + font-weight: 500; + &:hover { background: #4f46e5; } + } +}