优化PUT请求传参机制,实现最小化传参以减少网络传输和提高性能,在请求拦截器中自动计算差异只传递修改过的字段,同时新增通用的表单差异比较工具函数,
This commit is contained in:
152
src/utils/diffUtils.ts
Normal file
152
src/utils/diffUtils.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 差异比较工具函数
|
||||
* 用于编辑时最小化传参,只传递修改过的字段
|
||||
*/
|
||||
|
||||
/**
|
||||
* 深度比较两个值是否相等
|
||||
* @param val1 值1
|
||||
* @param val2 值2
|
||||
* @returns 是否相等
|
||||
*/
|
||||
export function isEqual(val1: any, val2: any): boolean {
|
||||
// 处理 null 和 undefined
|
||||
if (val1 === val2) return true;
|
||||
if (val1 == null || val2 == null) return val1 == val2;
|
||||
|
||||
// 处理基本类型
|
||||
if (typeof val1 !== 'object' || typeof val2 !== 'object') {
|
||||
return val1 === val2;
|
||||
}
|
||||
|
||||
// 处理数组
|
||||
if (Array.isArray(val1) && Array.isArray(val2)) {
|
||||
if (val1.length !== val2.length) return false;
|
||||
return val1.every((item, index) => isEqual(item, val2[index]));
|
||||
}
|
||||
|
||||
// 处理对象
|
||||
if (Array.isArray(val1) !== Array.isArray(val2)) return false;
|
||||
|
||||
const keys1 = Object.keys(val1);
|
||||
const keys2 = Object.keys(val2);
|
||||
if (keys1.length !== keys2.length) return false;
|
||||
|
||||
return keys1.every((key) => isEqual(val1[key], val2[key]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个对象,返回差异部分
|
||||
* @param original 原始数据
|
||||
* @param current 当前数据
|
||||
* @param options 配置选项
|
||||
* @returns 差异数据对象
|
||||
*/
|
||||
export function getChangedFields<T extends Record<string, any>>(
|
||||
original: T,
|
||||
current: T,
|
||||
options?: {
|
||||
/** 需要包含的字段(即使没有变化也会包含) */
|
||||
alwaysInclude?: string[];
|
||||
/** 需要排除的字段(即使有变化也不会包含) */
|
||||
exclude?: string[];
|
||||
/** 字段值转换器,用于提交前转换值 */
|
||||
transformers?: Record<string, (value: any) => any>;
|
||||
}
|
||||
): Partial<T> {
|
||||
const { alwaysInclude = [], exclude = [], transformers = {} } = options || {};
|
||||
const changed: Partial<T> = {};
|
||||
|
||||
// 遍历当前数据的所有字段
|
||||
const allKeys = new Set([...Object.keys(original), ...Object.keys(current)]);
|
||||
|
||||
allKeys.forEach((key) => {
|
||||
// 排除指定字段
|
||||
if (exclude.includes(key)) return;
|
||||
|
||||
const originalValue = original[key];
|
||||
const currentValue = current[key];
|
||||
|
||||
// 检查是否需要始终包含
|
||||
if (alwaysInclude.includes(key)) {
|
||||
const value = transformers[key] ? transformers[key](currentValue) : currentValue;
|
||||
(changed as any)[key] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
// 比较值是否变化
|
||||
if (!isEqual(originalValue, currentValue)) {
|
||||
const value = transformers[key] ? transformers[key](currentValue) : currentValue;
|
||||
(changed as any)[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个用于保存和比较表单数据的工具
|
||||
* @returns 工具对象
|
||||
*/
|
||||
export function createFormDiff<T extends Record<string, any>>() {
|
||||
let originalData: T | null = null;
|
||||
|
||||
return {
|
||||
/**
|
||||
* 保存原始数据
|
||||
* @param data 原始数据
|
||||
*/
|
||||
saveOriginal(data: T) {
|
||||
// 深拷贝保存原始数据
|
||||
originalData = JSON.parse(JSON.stringify(data));
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取原始数据
|
||||
* @returns 原始数据
|
||||
*/
|
||||
getOriginal(): T | null {
|
||||
return originalData;
|
||||
},
|
||||
|
||||
/**
|
||||
* 获取变化的字段
|
||||
* @param current 当前数据
|
||||
* @param options 配置选项
|
||||
* @returns 差异数据对象
|
||||
*/
|
||||
getChanges(
|
||||
current: T,
|
||||
options?: {
|
||||
alwaysInclude?: string[];
|
||||
exclude?: string[];
|
||||
transformers?: Record<string, (value: any) => any>;
|
||||
}
|
||||
): Partial<T> {
|
||||
if (!originalData) {
|
||||
// 如果没有原始数据,返回所有当前数据
|
||||
return { ...current };
|
||||
}
|
||||
return getChangedFields(originalData, current, options);
|
||||
},
|
||||
|
||||
/**
|
||||
* 检查是否有变化
|
||||
* @param current 当前数据
|
||||
* @param exclude 排除的字段
|
||||
* @returns 是否有变化
|
||||
*/
|
||||
hasChanges(current: T, exclude?: string[]): boolean {
|
||||
if (!originalData) return true;
|
||||
const changes = getChangedFields(originalData, current, { exclude });
|
||||
return Object.keys(changes).length > 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* 重置原始数据
|
||||
*/
|
||||
reset() {
|
||||
originalData = null;
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user