// 变更追踪工具 import { MachineryRecord, MachineryChangeHistory } from '../types/machinery'; // 字段名称到中文标签的映射 export const FIELD_LABELS: Record = { // 基本信息 name: '设备名称', model: '型号规格', category: '农机类型', usage: '使用场景', manufacturer: '生产厂家', manufactureDate: '出厂日期', purchaseDate: '购买日期', // 技术参数 engineNumber: '发动机号', chassisNumber: '车架号', power: '额定功率', weight: '整机重量', workingWidth: '工作幅宽', // 购机信息 purchasePrice: '购机价格', supplier: '供应商', invoiceNumber: '发票号码', invoiceUrl: '购机发票', // 保险信息 insuranceCompany: '保险公司', insurancePolicyNumber: '保单号', insuranceStartDate: '保险起始日期', insuranceEndDate: '保险结束日期', insuranceAmount: '保险金额', // 使用信息 status: '设备状态', currentLocation: '当前位置', operator: '操作人员', department: '所属部门', // 保养信息 maintenanceCycle: '保养周期', maintenanceCycleUnit: '保养周期单位', // 其他信息 remarks: '备注', tags: '标签', }; // 需要排除的字段(不记录变更) const EXCLUDED_FIELDS = [ 'id', 'qrCode', 'createdAt', 'updatedAt', 'createdBy', 'updatedBy', ]; /** * 格式化字段值用于显示 */ export function formatFieldValue(fieldName: string, value: any): string { if (value === null || value === undefined || value === '') { return '(空)'; } // 日期字段 if (fieldName.includes('Date') || fieldName.includes('Time')) { try { return new Date(value).toLocaleDateString('zh-CN'); } catch { return String(value); } } // 金额字段 if (fieldName.includes('Price') || fieldName.includes('Amount')) { const num = parseFloat(value); return isNaN(num) ? String(value) : `¥${num.toLocaleString()}`; } // 保养周期单位 if (fieldName === 'maintenanceCycleUnit') { const unitMap: Record = { day: '天', month: '月', year: '年' }; return unitMap[value] || String(value); } // 数组字段(如标签) if (Array.isArray(value)) { return value.length > 0 ? value.join(', ') : '(空)'; } // 对象字段 if (typeof value === 'object') { return JSON.stringify(value); } // 布尔值 if (typeof value === 'boolean') { return value ? '是' : '否'; } return String(value); } /** * 比较两个值是否相同 */ function isEqual(oldValue: any, newValue: any): boolean { // 处理null/undefined/空字符串的情况 const isOldEmpty = oldValue === null || oldValue === undefined || oldValue === ''; const isNewEmpty = newValue === null || newValue === undefined || newValue === ''; if (isOldEmpty && isNewEmpty) return true; if (isOldEmpty !== isNewEmpty) return false; // 数组比较 if (Array.isArray(oldValue) && Array.isArray(newValue)) { if (oldValue.length !== newValue.length) return false; return oldValue.every((val, index) => val === newValue[index]); } // 对象比较 if (typeof oldValue === 'object' && typeof newValue === 'object') { return JSON.stringify(oldValue) === JSON.stringify(newValue); } // 基本类型比较 return oldValue === newValue; } /** * 追踪农机档案的变更 * @param oldRecord 旧记录 * @param newRecord 新记录 * @param operator 操作人 * @returns 变更历史记录数组 */ export function trackMachineryChanges( oldRecord: MachineryRecord | undefined, newRecord: Partial, operator: string ): MachineryChangeHistory[] { const changes: MachineryChangeHistory[] = []; const timestamp = new Date().toISOString(); // 如果是新建,不记录变更 if (!oldRecord) { return []; } // 遍历新记录的所有字段 Object.keys(newRecord).forEach((fieldName) => { // 跳过排除的字段 if (EXCLUDED_FIELDS.includes(fieldName)) { return; } const oldValue = (oldRecord as any)[fieldName]; const newValue = (newRecord as any)[fieldName]; // 检查值是否发生变化 if (!isEqual(oldValue, newValue)) { const fieldLabel = FIELD_LABELS[fieldName] || fieldName; changes.push({ id: `change-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, machineryId: oldRecord.id, fieldName, fieldLabel, oldValue, newValue, operator, operatedAt: timestamp, }); } }); return changes; } /** * 获取字段的变更描述 */ export function getChangeDescription(change: MachineryChangeHistory): string { const oldValueStr = formatFieldValue(change.fieldName, change.oldValue); const newValueStr = formatFieldValue(change.fieldName, change.newValue); return `将 ${change.fieldLabel} 从 "${oldValueStr}" 修改为 "${newValueStr}"`; } /** * 按日期分组变更记录 */ export function groupChangesByDate( changes: MachineryChangeHistory[] ): Record { const grouped: Record = {}; changes.forEach(change => { const date = new Date(change.operatedAt).toLocaleDateString('zh-CN'); if (!grouped[date]) { grouped[date] = []; } grouped[date].push(change); }); return grouped; } /** * 获取变更统计信息 */ export function getChangeStats(changes: MachineryChangeHistory[]) { const stats = { total: changes.length, byField: {} as Record, byOperator: {} as Record, recentChanges: changes .sort((a, b) => new Date(b.operatedAt).getTime() - new Date(a.operatedAt).getTime()) .slice(0, 5), }; changes.forEach(change => { // 按字段统计 const field = change.fieldLabel; stats.byField[field] = (stats.byField[field] || 0) + 1; // 按操作人统计 stats.byOperator[change.operator] = (stats.byOperator[change.operator] || 0) + 1; }); return stats; }