//! 统一确认弹层状态机 — 抽自 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.confirm //! (语义中性,删除/清空等场景应显式传 common.delete / 「清空」等)。 import { ref } from 'vue' export interface ConfirmState { visible: boolean msg: string /** 危险按钮文案;空串回退到 ConfirmDialog 组件兜底(common.confirm) */ dangerLabel: string resolve: null | ((v: boolean) => void) } export function useConfirm() { const confirmState = ref({ visible: false, msg: '', dangerLabel: '', resolve: null, }) function confirmDialog(msg: string, dangerLabel = ''): Promise { return new Promise(resolve => { // CR-260615-31:并发覆盖前一个 confirmDialog(连点删除/confirm 交错)时, // 前一个 Promise 永挂(resolve 被覆盖)→ 先 resolve?.(false) 打断前一个视为取消 confirmState.value.resolve?.(false) confirmState.value.msg = msg confirmState.value.dangerLabel = dangerLabel 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 } }