生产管理系统前端 - 更新瓦力提交的产品原型到参考目录
This commit is contained in:
232
src/lib/fieldVersionManager.ts
Normal file
232
src/lib/fieldVersionManager.ts
Normal file
@@ -0,0 +1,232 @@
|
||||
import { Field, FieldVersion, FieldVersionChange } from '../types/field';
|
||||
|
||||
/**
|
||||
* 地块版本管理工具
|
||||
*/
|
||||
|
||||
// 生成唯一ID
|
||||
const generateId = () => {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
};
|
||||
|
||||
// 比较两个值是否不同
|
||||
const isDifferent = (oldValue: any, newValue: any): boolean => {
|
||||
if (Array.isArray(oldValue) && Array.isArray(newValue)) {
|
||||
return JSON.stringify(oldValue) !== JSON.stringify(newValue);
|
||||
}
|
||||
return oldValue !== newValue;
|
||||
};
|
||||
|
||||
// 检测字段变更
|
||||
const detectChanges = (oldField: Partial<Field>, newField: Partial<Field>): FieldVersionChange[] => {
|
||||
const changes: FieldVersionChange[] = [];
|
||||
|
||||
// 需要监控的字段
|
||||
const monitoredFields = [
|
||||
'name',
|
||||
'code',
|
||||
'area',
|
||||
'perimeter',
|
||||
'location',
|
||||
'soilType',
|
||||
'landUseType',
|
||||
'plantingMode',
|
||||
'owner',
|
||||
'ownerPhone',
|
||||
'contractPeriod',
|
||||
'certificateNumber',
|
||||
'tags',
|
||||
'status',
|
||||
'elevation',
|
||||
'slope',
|
||||
'aspect',
|
||||
'waterSource',
|
||||
'remarks',
|
||||
];
|
||||
|
||||
for (const field of monitoredFields) {
|
||||
const oldValue = (oldField as any)[field];
|
||||
const newValue = (newField as any)[field];
|
||||
|
||||
if (isDifferent(oldValue, newValue)) {
|
||||
changes.push({
|
||||
field,
|
||||
oldValue,
|
||||
newValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
};
|
||||
|
||||
// 检测边界变更
|
||||
const isBoundaryChanged = (oldCoordinates: any[], newCoordinates: any[]): boolean => {
|
||||
if (!oldCoordinates || !newCoordinates) return false;
|
||||
if (oldCoordinates.length !== newCoordinates.length) return true;
|
||||
return JSON.stringify(oldCoordinates) !== JSON.stringify(newCoordinates);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建版本记录
|
||||
*/
|
||||
export const createFieldVersion = (
|
||||
oldField: Field | null,
|
||||
newField: Field,
|
||||
changeType: FieldVersion['changeType'],
|
||||
changedBy: string,
|
||||
remarks?: string
|
||||
): FieldVersion | null => {
|
||||
// 如果是新建,创建初始版本
|
||||
if (changeType === 'create') {
|
||||
return {
|
||||
id: generateId(),
|
||||
fieldId: newField.id,
|
||||
version: 1,
|
||||
changeType: 'create',
|
||||
changes: [],
|
||||
coordinates: newField.coordinates,
|
||||
attributes: { ...newField },
|
||||
changedBy,
|
||||
changedAt: new Date().toISOString(),
|
||||
remarks: remarks || '创建地块',
|
||||
};
|
||||
}
|
||||
|
||||
// 如果没有旧数据,无法比较
|
||||
if (!oldField) return null;
|
||||
|
||||
// 检测变更
|
||||
const attributeChanges = detectChanges(oldField, newField);
|
||||
const boundaryChanged = isBoundaryChanged(oldField.coordinates, newField.coordinates);
|
||||
|
||||
// 如果有边界变更,添加到变更列表
|
||||
if (boundaryChanged) {
|
||||
attributeChanges.push({
|
||||
field: 'coordinates',
|
||||
oldValue: oldField.coordinates.length,
|
||||
newValue: newField.coordinates.length,
|
||||
});
|
||||
}
|
||||
|
||||
// 如果没有任何变更,不创建版本
|
||||
if (attributeChanges.length === 0 && !boundaryChanged) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 确定变更类型
|
||||
let finalChangeType = changeType;
|
||||
if (changeType === 'update-boundary' || changeType === 'update-attributes') {
|
||||
// 自动检测
|
||||
if (boundaryChanged && attributeChanges.length > 1) {
|
||||
finalChangeType = 'update-boundary'; // 边界变更优先
|
||||
} else if (boundaryChanged) {
|
||||
finalChangeType = 'update-boundary';
|
||||
} else {
|
||||
finalChangeType = 'update-attributes';
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
id: generateId(),
|
||||
fieldId: newField.id,
|
||||
version: (oldField.currentVersion || 0) + 1,
|
||||
changeType: finalChangeType,
|
||||
changes: attributeChanges,
|
||||
coordinates: boundaryChanged ? newField.coordinates : undefined,
|
||||
attributes: { ...newField },
|
||||
changedBy,
|
||||
changedAt: new Date().toISOString(),
|
||||
remarks,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 保存版本到localStorage
|
||||
*/
|
||||
export const saveFieldVersion = (version: FieldVersion): void => {
|
||||
try {
|
||||
const key = `field_versions_${version.fieldId}`;
|
||||
const data = localStorage.getItem(key);
|
||||
let versions: FieldVersion[] = data ? JSON.parse(data) : [];
|
||||
|
||||
// 添加新版本
|
||||
versions.push(version);
|
||||
|
||||
// 保存
|
||||
localStorage.setItem(key, JSON.stringify(versions));
|
||||
} catch (error) {
|
||||
console.error('保存版本失败:', error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载地块的所有版本
|
||||
*/
|
||||
export const loadFieldVersions = (fieldId: string): FieldVersion[] => {
|
||||
try {
|
||||
const key = `field_versions_${fieldId}`;
|
||||
const data = localStorage.getItem(key);
|
||||
return data ? JSON.parse(data) : [];
|
||||
} catch (error) {
|
||||
console.error('加载版本失败:', error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取特定版本
|
||||
*/
|
||||
export const getFieldVersion = (fieldId: string, version: number): FieldVersion | null => {
|
||||
const versions = loadFieldVersions(fieldId);
|
||||
return versions.find(v => v.version === version) || null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 从版本恢复地块数据
|
||||
*/
|
||||
export const restoreFromVersion = (version: FieldVersion): Partial<Field> => {
|
||||
if (!version.attributes) {
|
||||
throw new Error('版本数据不完整');
|
||||
}
|
||||
|
||||
const restored: Partial<Field> = { ...version.attributes };
|
||||
|
||||
// 如果有边界数据,使用版本的边界
|
||||
if (version.coordinates) {
|
||||
restored.coordinates = version.coordinates;
|
||||
}
|
||||
|
||||
return restored;
|
||||
};
|
||||
|
||||
/**
|
||||
* 删除地块的所有版本记录
|
||||
*/
|
||||
export const deleteFieldVersions = (fieldId: string): void => {
|
||||
try {
|
||||
const key = `field_versions_${fieldId}`;
|
||||
localStorage.removeItem(key);
|
||||
} catch (error) {
|
||||
console.error('删除版本失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取版本统计信息
|
||||
*/
|
||||
export const getVersionStatistics = (fieldId: string) => {
|
||||
const versions = loadFieldVersions(fieldId);
|
||||
|
||||
return {
|
||||
total: versions.length,
|
||||
byType: versions.reduce((acc, v) => {
|
||||
acc[v.changeType] = (acc[v.changeType] || 0) + 1;
|
||||
return acc;
|
||||
}, {} as Record<FieldVersion['changeType'], number>),
|
||||
latestVersion: versions.length > 0
|
||||
? Math.max(...versions.map(v => v.version))
|
||||
: 0,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user