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; }
+ }
+}