| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- /**
- * 通用表单配置hook
- * @param config 表单配置
- * @param data 表单数据
- * @param rules 表单规则
- * @returns initRuleFormData 初始化表单数据
- * @returns ruleFormData 表单数据
- * @returns formRules 表单规则
- * @returns cloneRuleFormData 克隆表单数据
- * @returns validateFormData 验证表单数据
- * @returns beforeRouteLeave 离开页面前的确认
- * @description 用于RuleForm的配置
- * @author Chauncey
- */
- import { ref, reactive, watch, onUnmounted } from 'vue';
- import type { FormRules } from 'element-plus';
- import { cloneDeep, isEqual } from 'lodash-es';
- import { onBeforeRouteLeave } from 'vue-router';
- import type { FormConfig } from '@/types/basic-form';
- import { msgConfirm } from '@/utils/element-plus/messageBox';
- export const useFormConfigHook = <T extends Record<string, any> = Record<string, any>>(
- config: FormConfig[],
- data: T,
- rules?: FormRules<T>,
- ) => {
- const ruleFormConfig = ref<FormConfig[]>(config);
- const ruleFormData = reactive<T>(cloneDeep(data));
- const initRuleFormData = ref<T>(cloneDeep(data));
- const formRules = reactive<FormRules<T>>(rules || {});
- const routeLeaveGuardRegistered = ref(false);
- let stopAutoSyncWatch: (() => void) | null = null;
- let autoSyncTimer: ReturnType<typeof setTimeout> | null = null;
- let removeInteractionListeners: (() => void) | null = null;
- const stopAutoSyncBaseline = () => {
- if (stopAutoSyncWatch) {
- stopAutoSyncWatch();
- stopAutoSyncWatch = null;
- }
- if (autoSyncTimer) {
- clearTimeout(autoSyncTimer);
- autoSyncTimer = null;
- }
- if (removeInteractionListeners) {
- removeInteractionListeners();
- removeInteractionListeners = null;
- }
- };
- const startAutoSyncBaseline = () => {
- stopAutoSyncBaseline();
- stopAutoSyncWatch = watch(
- () => ruleFormData,
- () => {
- initRuleFormData.value = cloneDeep(ruleFormData as T);
- },
- { deep: true, flush: 'post' },
- );
- const stopByUserInteraction = () => {
- stopAutoSyncBaseline();
- };
- if (typeof window !== 'undefined') {
- const events: Array<keyof WindowEventMap> = ['input', 'change', 'keydown', 'compositionend'];
- events.forEach((eventName) => {
- window.addEventListener(eventName, stopByUserInteraction, true);
- });
- removeInteractionListeners = () => {
- events.forEach((eventName) => {
- window.removeEventListener(eventName, stopByUserInteraction, true);
- });
- };
- }
- autoSyncTimer = setTimeout(() => {
- stopAutoSyncBaseline();
- }, 1500);
- };
- const cloneRuleFormData = () => {
- if (routeLeaveGuardRegistered.value) return;
- initRuleFormData.value = cloneDeep(ruleFormData as T);
- };
- const hasFormChanged = () => {
- return !isEqual(initRuleFormData.value, ruleFormData);
- };
- const beforeRouteLeave = () => {
- if (routeLeaveGuardRegistered.value) return;
- initRuleFormData.value = cloneDeep(ruleFormData as T);
- routeLeaveGuardRegistered.value = true;
- startAutoSyncBaseline();
- onBeforeRouteLeave((to, from, next) => {
- const hasChange = hasFormChanged();
- if (!hasChange) {
- next();
- return;
- }
- setTimeout(() => {
- msgConfirm('当前页面存在修改,是否确认离开当前页面?', '提示', {
- confirmButtonText: '确认',
- cancelButtonText: '取消',
- customClass: 'customMessageBox--warning',
- })
- .then(() => {
- next();
- })
- .catch(() => {
- next(false);
- });
- }, 200);
- });
- };
- onUnmounted(() => {
- stopAutoSyncBaseline();
- });
- return {
- ruleFormConfig,
- ruleFormData,
- formRules,
- cloneRuleFormData,
- beforeRouteLeave,
- };
- };
|