新增: 全局对话框服务 AppDialog,Promise 风格 appAlert/appConfirm/appPrompt 替代原生弹窗

This commit is contained in:
lxy
2026-08-25 12:30:12 +08:00
parent 0907a104cf
commit 8eef4606c5
9 changed files with 253 additions and 25 deletions
+66
View File
@@ -0,0 +1,66 @@
/* =====================================================================
* dialog.ts — 全局对话框服务(替代原生 alert/confirm/prompt)
*
* Promise 风格:await appConfirm('删除?') → boolean
* 渲染走 AppDialogHost(主 app 内 Teleport 到 body),
* App.vue 模板放置 <AppDialogHost /> 即接线,无需手动 mount
* ===================================================================== */
import { ref } from 'vue'
export interface DialogOptions {
type: 'alert' | 'confirm' | 'prompt'
title: string
message?: string
/** prompt 默认值 */
defaultValue?: string
/** input placeholder */
placeholder?: string
/** 确认按钮文案(默认「确定」) */
okText?: string
/** 危险操作样式(确认按钮红色) */
danger?: boolean
}
interface DialogResult { ok: boolean; value: string }
type Resolver = (r: DialogResult) => void
/* ---------- 模块级响应式状态(AppDialogHost 渲染消费) ---------- */
export const dialogState = {
open: ref(false),
options: ref<DialogOptions | null>(null)
}
let resolver: Resolver | null = null
/** 由 AppDialogHost 的 close 事件回调 */
export function resolveDialog(r: DialogResult) {
dialogState.open.value = false
dialogState.options.value = null
if (resolver) { resolver(r); resolver = null }
}
function show(opts: DialogOptions): Promise<DialogResult> {
return new Promise(resolve => {
resolver = resolve
dialogState.options.value = opts
dialogState.open.value = true
})
}
/* ---------- 对外 API ---------- */
/** 信息提示(替代 alert) */
export function appAlert(title: string, message?: string) {
return show({ type: 'alert', title, message })
}
/** 确认(替代 confirm)→ Promise<boolean> */
export function appConfirm(title: string, message?: string, opts?: { okText?: string; danger?: boolean }) {
return show({ type: 'confirm', title, message, okText: opts?.okText, danger: opts?.danger }).then(r => r.ok)
}
/** 输入(替代 prompt)→ Promise<string | null>(取消为 null) */
export function appPrompt(title: string, opts?: { message?: string; defaultValue?: string; placeholder?: string }) {
return show({ type: 'prompt', title, message: opts?.message, defaultValue: opts?.defaultValue, placeholder: opts?.placeholder })
.then(r => (r.ok ? r.value : null))
}