task-245(admin.html观感对齐): 二次确认共享组件(文案规则对齐 admin-interactions + 并发锁)
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue'
|
||||
import { openAdminConfirm } from './admin-confirm'
|
||||
|
||||
/**
|
||||
* AdminConfirm 共享确认组件(module 13 task 245):renderless 单例承载。
|
||||
* 使用:<AdminConfirm ref="confirmRef" />,需确认时 await confirmRef.open({...})。
|
||||
*/
|
||||
export default defineComponent({
|
||||
name: 'AdminConfirm',
|
||||
setup(_props, { expose }) {
|
||||
expose({ open: openAdminConfirm })
|
||||
return () => null
|
||||
},
|
||||
})
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* 二次确认模型(module 13 task 245):文案/按钮键规则对齐 admin-interactions.js ——
|
||||
* 优先显式 message,否则由行名拼接「确认删除“X”吗?此操作可能影响已有数据。」;
|
||||
* danger(删除/清空/删除导入类)默认标题「删除前确认」、确认键「确认删除」。
|
||||
* 纯逻辑、无 UI 依赖,便于单测;打开入口见 admin-confirm.ts / AdminConfirm.vue。
|
||||
*/
|
||||
export const ADMIN_CONFIRM = {
|
||||
dangerTitle: '删除前确认',
|
||||
defaultTitle: '请确认操作',
|
||||
confirmDeleteOk: '确认删除',
|
||||
confirmOk: '确认操作',
|
||||
cancel: '取消',
|
||||
deleteMessageSuffix: '此操作可能影响已有数据。',
|
||||
} as const
|
||||
|
||||
export interface AdminConfirmPlan {
|
||||
danger: boolean
|
||||
title: string
|
||||
message: string
|
||||
confirmText: string
|
||||
cancelText: string
|
||||
type: 'warning' | 'info'
|
||||
}
|
||||
|
||||
/** 由目标名称生成删除确认文案;无名称时退化为「该项」。 */
|
||||
export function confirmMessageFor(targetName?: string): string {
|
||||
const name = typeof targetName === 'string' && targetName.trim() ? `“${targetName.trim()}”` : '该项'
|
||||
return `确认删除${name}吗?${ADMIN_CONFIRM.deleteMessageSuffix}`
|
||||
}
|
||||
|
||||
export interface AdminConfirmOptions {
|
||||
danger?: boolean
|
||||
targetName?: string
|
||||
message?: string
|
||||
title?: string
|
||||
confirmText?: string
|
||||
}
|
||||
|
||||
/** 归一出二次确认计划:显式字段优先,否则按 danger/目标名落默认值。 */
|
||||
export function createConfirmPlan(opts: AdminConfirmOptions): AdminConfirmPlan {
|
||||
const danger = opts.danger !== false
|
||||
const message = opts.message && opts.message.trim() ? opts.message.trim() : confirmMessageFor(opts.targetName)
|
||||
return {
|
||||
danger,
|
||||
title: opts.title ?? (danger ? ADMIN_CONFIRM.dangerTitle : ADMIN_CONFIRM.defaultTitle),
|
||||
message,
|
||||
confirmText: opts.confirmText ?? (danger ? ADMIN_CONFIRM.confirmDeleteOk : ADMIN_CONFIRM.confirmOk),
|
||||
cancelText: ADMIN_CONFIRM.cancel,
|
||||
type: danger ? 'warning' : 'info',
|
||||
}
|
||||
}
|
||||
|
||||
// 并发防护:同一时刻只允许一个确认框在途(拒绝重复弹出)。
|
||||
let confirmLocked = false
|
||||
|
||||
export function acquireConfirmLock(): boolean {
|
||||
if (confirmLocked) return false
|
||||
confirmLocked = true
|
||||
return true
|
||||
}
|
||||
|
||||
export function releaseConfirmLock(): void {
|
||||
confirmLocked = false
|
||||
}
|
||||
|
||||
export function isConfirmLocked(): boolean {
|
||||
return confirmLocked
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 二次确认打开入口(module 13 task 245):把模型计划交给 ElMessageBox,并对
|
||||
* 确认/取消统一归约为 boolean;并发锁拒绝重复弹出。
|
||||
*/
|
||||
import { ElMessageBox } from 'element-plus'
|
||||
import {
|
||||
acquireConfirmLock,
|
||||
createConfirmPlan,
|
||||
releaseConfirmLock,
|
||||
type AdminConfirmOptions,
|
||||
} from './admin-confirm-model'
|
||||
|
||||
export async function openAdminConfirm(options: AdminConfirmOptions = {}): Promise<boolean> {
|
||||
const plan = createConfirmPlan(options)
|
||||
if (!acquireConfirmLock()) return false
|
||||
try {
|
||||
return await ElMessageBox.confirm(plan.message, plan.title, {
|
||||
confirmButtonText: plan.confirmText,
|
||||
cancelButtonText: plan.cancelText,
|
||||
type: plan.type,
|
||||
}).then(
|
||||
() => true,
|
||||
() => false,
|
||||
)
|
||||
} finally {
|
||||
releaseConfirmLock()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user