//! 统一确认弹层状态机 — 抽自 Projects/ProjectDetail/Ideas/Settings 四处重复 //! //! 背景:原生 window.confirm 在 Tauri webview 带 localhost:port 来源信息无法去除, //! 改为自建弹层。四视图各自重复一份 {visible,msg,resolve} + Promise 机制,此处收敛。 //! //! 分工:本 composable 只管「状态 + Promise」,不渲染 UI —— //! - Projects/ProjectDetail/Ideas 复用 ../components/ConfirmDialog.vue //! - Settings 用内联模板(沿用其既有 toast/confirm 同框布局) //! 各视图绑定 confirmState 的 visible/msg 并把按钮点击回 answerConfirm 即可。 //! //! i18n:composable 在 setup 内调用,文案由调用方用各自 useI18n().t 翻译后传入 msg, //! 这里无需 i18n 依赖。dangerLabel 由 ConfirmDialog 组件侧兜底为 common.delete。 import { ref } from 'vue' export interface ConfirmState { visible: boolean msg: string resolve: null | ((v: boolean) => void) } /** 弹出确认对话框,返回 Promise;resolve(true) 表示用户确认,resolve(false) 表示取消 */ export type ConfirmFn = (msg: string) => Promise /** 关闭弹层并回传结果 */ export type AnswerFn = (ok: boolean) => void export function useConfirm() { const confirmState = ref({ visible: false, msg: '', resolve: null, }) function confirmDialog(msg: string): Promise { return new Promise(resolve => { // CR-260615-31:并发覆盖前一个 confirmDialog(连点删除/confirm 交错)时, // 前一个 Promise 永挂(resolve 被覆盖)→ 先 resolve?.(false) 打断前一个视为取消 confirmState.value.resolve?.(false) confirmState.value.msg = msg confirmState.value.visible = true confirmState.value.resolve = resolve }) } function answerConfirm(ok: boolean) { confirmState.value.visible = false confirmState.value.resolve?.(ok) confirmState.value.resolve = null } return { confirmState, confirmDialog, answerConfirm } }