| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- import type { Component, VNode } from 'vue';
- import type { Recordable } from '@vben-core/typings';
- import type { AlertProps, BeforeCloseScope, PromptProps } from './alert';
- import { h, nextTick, ref, render } from 'vue';
- import { useSimpleLocale } from '@vben-core/composables';
- import { Input, VbenRenderContent } from '@vben-core/shadcn-ui';
- import { isFunction, isString } from '@vben-core/shared/utils';
- import Alert from './alert.vue';
- const alerts = ref<Array<{ container: HTMLElement; instance: Component }>>([]);
- const { $t } = useSimpleLocale();
- export function vbenAlert(options: AlertProps): Promise<void>;
- export function vbenAlert(
- message: string,
- options?: Partial<AlertProps>,
- ): Promise<void>;
- export function vbenAlert(
- message: string,
- title?: string,
- options?: Partial<AlertProps>,
- ): Promise<void>;
- export function vbenAlert(
- arg0: AlertProps | string,
- arg1?: Partial<AlertProps> | string,
- arg2?: Partial<AlertProps>,
- ): Promise<void> {
- return new Promise((resolve, reject) => {
- const options: AlertProps = isString(arg0)
- ? {
- content: arg0,
- }
- : { ...arg0 };
- if (arg1) {
- if (isString(arg1)) {
- options.title = arg1;
- } else if (!isString(arg1)) {
- // 如果第二个参数是对象,则合并到选项中
- Object.assign(options, arg1);
- }
- }
- if (arg2 && !isString(arg2)) {
- Object.assign(options, arg2);
- }
- // 创建容器元素
- const container = document.createElement('div');
- document.body.append(container);
- // 创建一个引用,用于在回调中访问实例
- const alertRef = { container, instance: null as any };
- const props: AlertProps & Recordable<any> = {
- onClosed: (isConfirm: boolean) => {
- // 移除组件实例以及创建的所有dom(恢复页面到打开前的状态)
- // 从alerts数组中移除该实例
- alerts.value = alerts.value.filter((item) => item !== alertRef);
- // 从DOM中移除容器
- render(null, container);
- if (container.parentNode) {
- container.remove();
- }
- // 解析 Promise,传递用户操作结果
- if (isConfirm) {
- resolve();
- } else {
- reject(new Error('dialog cancelled'));
- }
- },
- ...options,
- open: true,
- title: options.title ?? $t.value('prompt'),
- };
- // 创建Alert组件的VNode
- const vnode = h(Alert, props);
- // 渲染组件到容器
- render(vnode, container);
- // 保存组件实例引用
- alertRef.instance = vnode.component?.proxy as Component;
- // 将实例和容器添加到alerts数组中
- alerts.value.push(alertRef);
- });
- }
- export function vbenConfirm(options: AlertProps): Promise<void>;
- export function vbenConfirm(
- message: string,
- options?: Partial<AlertProps>,
- ): Promise<void>;
- export function vbenConfirm(
- message: string,
- title?: string,
- options?: Partial<AlertProps>,
- ): Promise<void>;
- export function vbenConfirm(
- arg0: AlertProps | string,
- arg1?: Partial<AlertProps> | string,
- arg2?: Partial<AlertProps>,
- ): Promise<void> {
- const defaultProps: Partial<AlertProps> = {
- showCancel: true,
- };
- if (!arg1) {
- return isString(arg0)
- ? vbenAlert(arg0, defaultProps)
- : vbenAlert({ ...defaultProps, ...arg0 });
- } else if (!arg2) {
- return isString(arg1)
- ? vbenAlert(arg0 as string, arg1, defaultProps)
- : vbenAlert(arg0 as string, { ...defaultProps, ...arg1 });
- }
- return vbenAlert(arg0 as string, arg1 as string, {
- ...defaultProps,
- ...arg2,
- });
- }
- export async function vbenPrompt<T = any>(
- options: PromptProps<T>,
- ): Promise<T | undefined> {
- const {
- component: _component,
- componentProps: _componentProps,
- componentSlots,
- content,
- defaultValue,
- modelPropName: _modelPropName,
- ...delegated
- } = options;
- const modelValue = ref<T | undefined>(defaultValue);
- const inputComponentRef = ref<null | VNode>(null);
- const staticContents: Component[] = [];
- staticContents.push(h(VbenRenderContent, { content, renderBr: true }));
- const modelPropName = _modelPropName || 'modelValue';
- const componentProps = { ..._componentProps };
- // 每次渲染时都会重新计算的内容函数
- const contentRenderer = () => {
- const currentProps = { ...componentProps };
- // 设置当前值
- currentProps[modelPropName] = modelValue.value;
- // 设置更新处理函数
- currentProps[`onUpdate:${modelPropName}`] = (val: T) => {
- modelValue.value = val;
- };
- // 创建输入组件
- inputComponentRef.value = h(
- _component || Input,
- currentProps,
- componentSlots,
- );
- // 返回包含静态内容和输入组件的数组
- return h(
- 'div',
- { class: 'flex flex-col gap-2' },
- { default: () => [...staticContents, inputComponentRef.value] },
- );
- };
- const props: AlertProps & Recordable<any> = {
- ...delegated,
- async beforeClose(scope: BeforeCloseScope) {
- if (delegated.beforeClose) {
- return await delegated.beforeClose({
- ...scope,
- value: modelValue.value,
- });
- }
- },
- // 使用函数形式,每次渲染都会重新计算内容
- content: contentRenderer,
- contentMasking: true,
- async onOpened() {
- await nextTick();
- const componentRef: null | VNode = inputComponentRef.value;
- if (componentRef) {
- if (
- componentRef.component?.exposed &&
- isFunction(componentRef.component.exposed.focus)
- ) {
- componentRef.component.exposed.focus();
- } else {
- if (componentRef.el) {
- if (
- isFunction(componentRef.el.focus) &&
- ['BUTTON', 'INPUT', 'SELECT', 'TEXTAREA'].includes(
- componentRef.el.tagName,
- )
- ) {
- componentRef.el.focus();
- } else if (isFunction(componentRef.el.querySelector)) {
- const focusableElement = componentRef.el.querySelector(
- 'input, select, textarea, button',
- );
- if (focusableElement && isFunction(focusableElement.focus)) {
- focusableElement.focus();
- }
- } else if (
- componentRef.el.nextElementSibling &&
- isFunction(componentRef.el.nextElementSibling.focus)
- ) {
- componentRef.el.nextElementSibling.focus();
- }
- }
- }
- }
- },
- };
- await vbenConfirm(props);
- return modelValue.value;
- }
- export function clearAllAlerts() {
- alerts.value.forEach((alert) => {
- // 从DOM中移除容器
- render(null, alert.container);
- if (alert.container.parentNode) {
- alert.container.remove();
- }
- });
- alerts.value = [];
- }
|