90 lines
2.6 KiB
TypeScript
90 lines
2.6 KiB
TypeScript
/**
|
||
* uiStore — 菜单/对话框状态管理
|
||
* 替代 useUI.ts 中的状态管理部分
|
||
*/
|
||
import { defineStore } from 'pinia'
|
||
import { ref } from 'vue'
|
||
import type { MenuItem } from '@/types/app'
|
||
import type { DialogConfig } from '@/types/ui'
|
||
|
||
export const useUIStore = defineStore('ui', () => {
|
||
// ---- 弹出菜单 ----
|
||
const menuVisible = ref(false)
|
||
const menuItems = ref<MenuItem[]>([])
|
||
const menuPosition = ref({ x: 0, y: 0 })
|
||
const menuSub = ref(false)
|
||
let menuOnClose: (() => void) | null = null
|
||
|
||
function showMenu(items: MenuItem[], x: number, y: number, opts: { sub?: boolean; onClose?: () => void } = {}) {
|
||
hideMenu()
|
||
menuItems.value = items
|
||
menuPosition.value = { x, y }
|
||
menuSub.value = !!opts.sub
|
||
menuVisible.value = true
|
||
menuOnClose = opts.onClose ?? null
|
||
}
|
||
|
||
function hideMenu() {
|
||
menuOnClose?.()
|
||
menuOnClose = null
|
||
menuVisible.value = false
|
||
}
|
||
|
||
function showContextMenu(items: MenuItem[], e: MouseEvent) {
|
||
e.preventDefault(); e.stopPropagation()
|
||
showMenu(items, e.clientX, e.clientY)
|
||
}
|
||
|
||
// ---- 对话框 ----
|
||
const dialogVisible = ref(false)
|
||
const dialogConfig = ref<DialogConfig>({ title: '', msg: '' })
|
||
let dialogResolve: ((v: string | boolean) => void) | null = null
|
||
|
||
function showDialog(config: DialogConfig): Promise<string | boolean> {
|
||
return new Promise(resolve => {
|
||
dialogConfig.value = config
|
||
dialogVisible.value = true
|
||
dialogResolve = resolve
|
||
})
|
||
}
|
||
|
||
function resolveDialog(value: string | boolean) {
|
||
dialogVisible.value = false
|
||
dialogResolve?.(value)
|
||
dialogResolve = null
|
||
}
|
||
|
||
async function alert(title: string, msg: string, icon?: string): Promise<boolean> {
|
||
return showDialog({ icon, title, msg, buttons: ['好'] }).then(() => true)
|
||
}
|
||
|
||
async function confirm(
|
||
title: string, msg: string,
|
||
opts: { ok?: string; danger?: boolean; icon?: string } = {}
|
||
): Promise<boolean> {
|
||
const result = await showDialog({
|
||
icon: opts.icon, title, msg,
|
||
ok: opts.ok || '确定', danger: opts.danger,
|
||
})
|
||
return result === 'ok' || result === true
|
||
}
|
||
|
||
async function prompt(title: string, msg: string, defaultValue?: string): Promise<string | null> {
|
||
const result = await showDialog({
|
||
title, msg: msg + (defaultValue ? `\n\n默认值:${defaultValue}` : ''),
|
||
ok: '确定',
|
||
})
|
||
return typeof result === 'string' ? result : null
|
||
}
|
||
|
||
return {
|
||
// menu
|
||
menuVisible, menuItems, menuPosition, menuSub,
|
||
showMenu, hideMenu, showContextMenu,
|
||
// dialog
|
||
dialogVisible, dialogConfig,
|
||
showDialog, resolveDialog,
|
||
alert, confirm, prompt,
|
||
}
|
||
})
|