2025-04-05 13:33:15 +08:00
|
|
|
import type { ExtendedFormApi } from '@vben/common-ui';
|
|
|
|
import type { MaybePromise } from '@vben/types';
|
|
|
|
|
|
|
|
import { ref } from 'vue';
|
|
|
|
|
|
|
|
import { $t } from '@vben/locales';
|
|
|
|
|
|
|
|
import { Modal } from 'ant-design-vue';
|
|
|
|
import { isFunction } from 'lodash-es';
|
|
|
|
|
|
|
|
interface BeforeCloseDiffProps {
|
|
|
|
/**
|
|
|
|
* 初始化值如何获取
|
|
|
|
* @returns Promise<string>
|
|
|
|
*/
|
|
|
|
initializedGetter: () => MaybePromise<string>;
|
|
|
|
/**
|
|
|
|
* 当前值如何获取
|
|
|
|
* @returns Promise<string>
|
|
|
|
*/
|
|
|
|
currentGetter: () => MaybePromise<string>;
|
|
|
|
/**
|
|
|
|
* 自定义比较函数
|
|
|
|
* @param init 初始值
|
|
|
|
* @param current 当前值
|
|
|
|
* @returns boolean
|
|
|
|
*/
|
|
|
|
compare?: (init: string, current: string) => boolean;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-04-08 10:10:15 +08:00
|
|
|
* 用于Drawer/Modal使用 判断表单是否有变动来决定是否弹窗提示
|
2025-04-05 13:33:15 +08:00
|
|
|
* @param props props
|
|
|
|
* @returns hook
|
|
|
|
*/
|
|
|
|
export function useBeforeCloseDiff(props: BeforeCloseDiffProps) {
|
|
|
|
const { initializedGetter, currentGetter, compare } = props;
|
2025-04-08 10:10:15 +08:00
|
|
|
/**
|
|
|
|
* 记录初始值 json
|
|
|
|
*/
|
2025-04-05 13:33:15 +08:00
|
|
|
const initialized = ref<string>('');
|
2025-04-08 10:10:15 +08:00
|
|
|
/**
|
|
|
|
* 是否已经初始化了 通过这个值判断是否需要进行对比 为false直接关闭 不弹窗
|
|
|
|
*/
|
2025-04-05 13:33:15 +08:00
|
|
|
const isInitialized = ref(false);
|
|
|
|
|
2025-04-08 10:10:15 +08:00
|
|
|
/**
|
|
|
|
* 标记是否已经完成初始化 后续需要进行对比
|
|
|
|
* @param data 自定义初始化数据 可选
|
|
|
|
*/
|
|
|
|
async function markInitialized(data?: string) {
|
2025-04-05 13:33:15 +08:00
|
|
|
initialized.value = data || (await initializedGetter());
|
|
|
|
isInitialized.value = true;
|
|
|
|
}
|
|
|
|
|
2025-04-08 10:10:15 +08:00
|
|
|
/**
|
|
|
|
* 重置初始化状态 需要在closed前调用 或者打开窗口时
|
|
|
|
*/
|
2025-04-07 18:48:46 +08:00
|
|
|
function resetInitialized() {
|
|
|
|
initialized.value = '';
|
|
|
|
isInitialized.value = false;
|
|
|
|
}
|
|
|
|
|
2025-04-08 10:10:15 +08:00
|
|
|
/**
|
|
|
|
* 提供给useVbenForm/useVbenDrawer使用
|
|
|
|
* @returns 是否允许关闭
|
|
|
|
*/
|
2025-04-05 13:33:15 +08:00
|
|
|
async function onBeforeClose(): Promise<boolean> {
|
|
|
|
// 如果还未初始化,直接允许关闭
|
|
|
|
if (!isInitialized.value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2025-04-08 10:10:15 +08:00
|
|
|
// 获取当前表单数据
|
2025-04-05 13:33:15 +08:00
|
|
|
const current = await currentGetter();
|
2025-04-08 10:10:15 +08:00
|
|
|
// 自定义比较的情况
|
2025-04-05 13:33:15 +08:00
|
|
|
if (isFunction(compare) && compare(initialized.value, current)) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
// 如果数据没有变化,直接允许关闭
|
|
|
|
if (current === initialized.value) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 数据有变化,显示确认对话框
|
|
|
|
return new Promise<boolean>((resolve) => {
|
|
|
|
Modal.confirm({
|
|
|
|
title: $t('pages.common.tip'),
|
|
|
|
content: $t('您有未保存的更改,确认要退出吗?'),
|
|
|
|
centered: true,
|
|
|
|
okButtonProps: { danger: true },
|
|
|
|
cancelText: $t('common.cancel'),
|
|
|
|
okText: $t('common.confirm'),
|
|
|
|
onOk: () => {
|
|
|
|
resolve(true);
|
|
|
|
isInitialized.value = false;
|
|
|
|
},
|
|
|
|
onCancel: () => resolve(false),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
} catch (error) {
|
|
|
|
console.error('Failed to compare data:', error);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
onBeforeClose,
|
2025-04-08 10:10:15 +08:00
|
|
|
markInitialized,
|
2025-04-07 18:48:46 +08:00
|
|
|
resetInitialized,
|
2025-04-05 13:33:15 +08:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 给useVbenForm使用的 封装函数
|
|
|
|
* @param formApi 表单实例
|
|
|
|
* @returns getter
|
|
|
|
*/
|
|
|
|
export function defaultFormValueGetter(formApi: ExtendedFormApi) {
|
|
|
|
return async () => {
|
|
|
|
const v = await formApi.getValues();
|
|
|
|
return JSON.stringify(v);
|
|
|
|
};
|
|
|
|
}
|