/** * 通用表单配置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 = = Record>( config: FormConfig[], data: T, rules?: FormRules, ) => { const ruleFormConfig = ref(config); const ruleFormData = reactive(cloneDeep(data)); const initRuleFormData = ref(cloneDeep(data)); const formRules = reactive>(rules || {}); const routeLeaveGuardRegistered = ref(false); let stopAutoSyncWatch: (() => void) | null = null; let autoSyncTimer: ReturnType | 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 = ['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, }; };