Merge branch 'main' of https://github.com/vbenjs/vue-vben-admin into v-next-dev
This commit is contained in:
@@ -7,7 +7,7 @@ import type { AlertProps, BeforeCloseScope, PromptProps } from './alert';
|
||||
import { h, nextTick, ref, render } from 'vue';
|
||||
|
||||
import { useSimpleLocale } from '@vben-core/composables';
|
||||
import { Input } from '@vben-core/shadcn-ui';
|
||||
import { Input, VbenRenderContent } from '@vben-core/shadcn-ui';
|
||||
import { isFunction, isString } from '@vben-core/shared/utils';
|
||||
|
||||
import Alert from './alert.vue';
|
||||
@@ -146,11 +146,7 @@ export async function vbenPrompt<T = any>(
|
||||
const inputComponentRef = ref<null | VNode>(null);
|
||||
const staticContents: Component[] = [];
|
||||
|
||||
if (isString(content)) {
|
||||
staticContents.push(h('span', content));
|
||||
} else if (content) {
|
||||
staticContents.push(content as Component);
|
||||
}
|
||||
staticContents.push(h(VbenRenderContent, { content, renderBr: true }));
|
||||
|
||||
const modelPropName = _modelPropName || 'modelValue';
|
||||
const componentProps = { ..._componentProps };
|
||||
|
||||
@@ -2,6 +2,8 @@ import type { Component, VNode, VNodeArrayChildren } from 'vue';
|
||||
|
||||
import type { Recordable } from '@vben-core/typings';
|
||||
|
||||
import { createContext } from '@vben-core/shadcn-ui';
|
||||
|
||||
export type IconType = 'error' | 'info' | 'question' | 'success' | 'warning';
|
||||
|
||||
export type BeforeCloseScope = {
|
||||
@@ -70,3 +72,28 @@ export type PromptProps<T = any> = {
|
||||
/** 输入组件的值属性名 */
|
||||
modelPropName?: string;
|
||||
} & Omit<AlertProps, 'beforeClose'>;
|
||||
|
||||
/**
|
||||
* Alert上下文
|
||||
*/
|
||||
export type AlertContext = {
|
||||
/** 执行取消操作 */
|
||||
doCancel: () => void;
|
||||
/** 执行确认操作 */
|
||||
doConfirm: () => void;
|
||||
};
|
||||
|
||||
export const [injectAlertContext, provideAlertContext] =
|
||||
createContext<AlertContext>('VbenAlertContext');
|
||||
|
||||
/**
|
||||
* 获取Alert上下文
|
||||
* @returns AlertContext
|
||||
*/
|
||||
export function useAlertContext() {
|
||||
const context = injectAlertContext();
|
||||
if (!context) {
|
||||
throw new Error('useAlertContext must be used within an AlertProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
import { globalShareState } from '@vben-core/shared/global-state';
|
||||
import { cn } from '@vben-core/shared/utils';
|
||||
|
||||
import { provideAlertContext } from './alert';
|
||||
|
||||
const props = withDefaults(defineProps<AlertProps>(), {
|
||||
bordered: true,
|
||||
buttonAlign: 'end',
|
||||
@@ -87,6 +89,22 @@ const getIconRender = computed(() => {
|
||||
}
|
||||
return iconRender;
|
||||
});
|
||||
|
||||
function doCancel() {
|
||||
handleCancel();
|
||||
handleOpenChange(false);
|
||||
}
|
||||
|
||||
function doConfirm() {
|
||||
handleConfirm();
|
||||
handleOpenChange(false);
|
||||
}
|
||||
|
||||
provideAlertContext({
|
||||
doCancel,
|
||||
doConfirm,
|
||||
});
|
||||
|
||||
function handleConfirm() {
|
||||
isConfirm.value = true;
|
||||
emits('confirm');
|
||||
@@ -98,11 +116,13 @@ function handleCancel() {
|
||||
|
||||
const loading = ref(false);
|
||||
async function handleOpenChange(val: boolean) {
|
||||
const confirmState = isConfirm.value;
|
||||
isConfirm.value = false;
|
||||
await nextTick();
|
||||
if (!val && props.beforeClose) {
|
||||
loading.value = true;
|
||||
try {
|
||||
const res = await props.beforeClose({ isConfirm: isConfirm.value });
|
||||
const res = await props.beforeClose({ isConfirm: confirmState });
|
||||
if (res !== false) {
|
||||
open.value = false;
|
||||
}
|
||||
@@ -152,7 +172,7 @@ async function handleOpenChange(val: boolean) {
|
||||
</div>
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
<div class="m-4 mb-6 min-h-[30px]">
|
||||
<div class="m-4 min-h-[30px]">
|
||||
<VbenRenderContent :content="content" render-br />
|
||||
</div>
|
||||
<VbenLoading v-if="loading && contentMasking" :spinning="loading" />
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
export * from './alert';
|
||||
|
||||
export type {
|
||||
AlertProps,
|
||||
BeforeCloseScope,
|
||||
IconType,
|
||||
PromptProps,
|
||||
} from './alert';
|
||||
export { useAlertContext } from './alert';
|
||||
export { default as Alert } from './alert.vue';
|
||||
export {
|
||||
vbenAlert as alert,
|
||||
|
||||
@@ -54,7 +54,6 @@ describe('drawerApi', () => {
|
||||
});
|
||||
|
||||
it('should close the drawer if onBeforeClose allows it', () => {
|
||||
drawerApi.open();
|
||||
drawerApi.close();
|
||||
expect(drawerApi.store.state.isOpen).toBe(false);
|
||||
});
|
||||
|
||||
@@ -86,12 +86,13 @@ export class DrawerApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭弹窗
|
||||
* 关闭抽屉
|
||||
* @description 关闭抽屉时会调用 onBeforeClose 钩子函数,如果 onBeforeClose 返回 false,则不关闭弹窗
|
||||
*/
|
||||
close() {
|
||||
async close() {
|
||||
// 通过 onBeforeClose 钩子函数来判断是否允许关闭弹窗
|
||||
// 如果 onBeforeClose 返回 false,则不关闭弹窗
|
||||
const allowClose = this.api.onBeforeClose?.() ?? true;
|
||||
const allowClose = (await this.api.onBeforeClose?.()) ?? true;
|
||||
if (allowClose) {
|
||||
this.store.setState((prev) => ({
|
||||
...prev,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { Component, Ref } from 'vue';
|
||||
|
||||
import type { ClassType } from '@vben-core/typings';
|
||||
import type { ClassType, MaybePromise } from '@vben-core/typings';
|
||||
|
||||
import type { DrawerApi } from './drawer-api';
|
||||
|
||||
@@ -151,7 +151,7 @@ export interface DrawerApiOptions extends DrawerState {
|
||||
* 关闭前的回调,返回 false 可以阻止关闭
|
||||
* @returns
|
||||
*/
|
||||
onBeforeClose?: () => void;
|
||||
onBeforeClose?: () => MaybePromise<boolean | undefined>;
|
||||
/**
|
||||
* 点击取消按钮的回调
|
||||
*/
|
||||
|
||||
@@ -274,7 +274,7 @@ const getAppendTo = computed(() => {
|
||||
{{ cancelText || $t('cancel') }}
|
||||
</slot>
|
||||
</component>
|
||||
|
||||
<slot name="center-footer"></slot>
|
||||
<component
|
||||
:is="components.PrimaryButton || VbenButton"
|
||||
v-if="showConfirmButton"
|
||||
|
||||
@@ -103,7 +103,7 @@ const { dragging, transform } = useModalDraggable(
|
||||
);
|
||||
|
||||
const firstOpened = ref(false);
|
||||
const isClosed = ref(false);
|
||||
const isClosed = ref(true);
|
||||
|
||||
watch(
|
||||
() => state?.value?.isOpen,
|
||||
@@ -186,7 +186,7 @@ const getAppendTo = computed(() => {
|
||||
});
|
||||
|
||||
const getForceMount = computed(() => {
|
||||
return !unref(destroyOnClose);
|
||||
return !unref(destroyOnClose) && unref(firstOpened);
|
||||
});
|
||||
|
||||
function handleClosed() {
|
||||
@@ -321,7 +321,7 @@ function handleClosed() {
|
||||
{{ cancelText || $t('cancel') }}
|
||||
</slot>
|
||||
</component>
|
||||
|
||||
<slot name="center-footer"></slot>
|
||||
<component
|
||||
:is="components.PrimaryButton || VbenButton"
|
||||
v-if="showConfirmButton"
|
||||
|
||||
@@ -70,6 +70,13 @@ export function useVbenModal<TParentModalProps extends ModalProps = ModalProps>(
|
||||
injectData.options?.onOpenChange?.(isOpen);
|
||||
};
|
||||
|
||||
mergedOptions.onClosed = () => {
|
||||
options.onClosed?.();
|
||||
if (options.destroyOnClose) {
|
||||
injectData.reCreateModal?.();
|
||||
}
|
||||
};
|
||||
|
||||
const api = new ModalApi(mergedOptions);
|
||||
|
||||
const extendedApi: ExtendedModalApi = api as never;
|
||||
|
||||
Reference in New Issue
Block a user