提交1 bmad搭建与项目启动 - ok

This commit is contained in:
2025-10-17 17:24:56 +08:00
commit ec58562661
686 changed files with 149750 additions and 0 deletions

273
src/lib/geoFenceTestData.ts Normal file
View File

@@ -0,0 +1,273 @@
import { GeoFence, GeoFenceAlert } from '../types/equipment';
/**
* 生成测试用的电子围栏数据
*/
export function generateTestGeoFences(machineryIds: string[]): GeoFence[] {
const now = new Date().toISOString();
return [
// 矩形作业区
{
id: 'fence-test-1',
name: '1号作业区',
type: 'polygon',
points: [
{ latitude: 36.6512, longitude: 117.1201 },
{ latitude: 36.6532, longitude: 117.1201 },
{ latitude: 36.6532, longitude: 117.1251 },
{ latitude: 36.6512, longitude: 117.1251 },
],
machineryIds: machineryIds.slice(0, 2),
alertOnExit: true,
alertOnEnter: false,
countWorkHours: true,
enabled: true,
createdAt: now,
updatedAt: now,
createdBy: '系统管理员',
},
// 圆形禁入区
{
id: 'fence-test-2',
name: '东侧水塘禁入区',
type: 'circle',
center: { latitude: 36.6500, longitude: 117.1200 },
radius: 200,
machineryIds: machineryIds,
alertOnExit: false,
alertOnEnter: true,
countWorkHours: false,
enabled: true,
createdAt: now,
updatedAt: now,
createdBy: '系统管理员',
},
// 大型多边形作业区
{
id: 'fence-test-3',
name: '2号地块-西区',
type: 'polygon',
points: [
{ latitude: 36.6480, longitude: 117.1150 },
{ latitude: 36.6500, longitude: 117.1150 },
{ latitude: 36.6510, longitude: 117.1180 },
{ latitude: 36.6500, longitude: 117.1200 },
{ latitude: 36.6480, longitude: 117.1190 },
],
machineryIds: machineryIds.slice(0, 1),
alertOnExit: true,
alertOnEnter: false,
countWorkHours: true,
enabled: true,
createdAt: now,
updatedAt: now,
createdBy: '系统管理员',
},
// 休息区(圆形)
{
id: 'fence-test-4',
name: '农机停放区',
type: 'circle',
center: { latitude: 36.6550, longitude: 117.1100 },
radius: 100,
machineryIds: machineryIds,
alertOnExit: false,
alertOnEnter: false,
countWorkHours: false,
enabled: true,
createdAt: now,
updatedAt: now,
createdBy: '系统管理员',
},
];
}
/**
* 生成测试用的围栏报警数据
*/
export function generateTestGeoFenceAlerts(
fences: GeoFence[],
machineryData: { id: string; name: string }[]
): GeoFenceAlert[] {
const alerts: GeoFenceAlert[] = [];
// 生成一些历史报警
if (fences.length > 0 && machineryData.length > 0) {
const fence1 = fences[0];
const machinery1 = machineryData[0];
alerts.push({
id: 'alert-test-1',
fenceId: fence1.id,
fenceName: fence1.name,
machineryId: machinery1.id,
machineryName: machinery1.name,
alertType: 'exit',
location: { latitude: 36.6510, longitude: 117.1252 },
alertedAt: new Date(Date.now() - 2 * 60 * 60 * 1000).toISOString(), // 2小时前
acknowledged: false,
});
}
if (fences.length > 1 && machineryData.length > 1) {
const fence2 = fences[1];
const machinery2 = machineryData[1];
alerts.push({
id: 'alert-test-2',
fenceId: fence2.id,
fenceName: fence2.name,
machineryId: machinery2.id,
machineryName: machinery2.name,
alertType: 'enter',
location: { latitude: 36.6501, longitude: 117.1201 },
alertedAt: new Date(Date.now() - 30 * 60 * 1000).toISOString(), // 30分钟前
acknowledged: true,
acknowledgedBy: '值班员张三',
acknowledgedAt: new Date(Date.now() - 25 * 60 * 1000).toISOString(),
});
}
return alerts;
}
/**
* 验证围栏坐标是否有效
*/
export function validateGeoFence(fence: Partial<GeoFence>): { valid: boolean; errors: string[] } {
const errors: string[] = [];
if (!fence.name || fence.name.trim() === '') {
errors.push('围栏名称不能为空');
}
if (!fence.type) {
errors.push('必须选择围栏类型');
}
if (fence.type === 'circle') {
if (!fence.center) {
errors.push('圆形围栏必须设置中心点');
} else {
if (!isValidLatitude(fence.center.latitude)) {
errors.push('中心点纬度无效(应在-90到90之间');
}
if (!isValidLongitude(fence.center.longitude)) {
errors.push('中心点经度无效(应在-180到180之间');
}
}
if (!fence.radius || fence.radius <= 0) {
errors.push('圆形围栏半径必须大于0');
}
}
if (fence.type === 'polygon') {
if (!fence.points || fence.points.length < 3) {
errors.push('多边形围栏至少需要3个顶点');
} else {
fence.points.forEach((point, index) => {
if (!isValidLatitude(point.latitude)) {
errors.push(`顶点${index + 1}的纬度无效`);
}
if (!isValidLongitude(point.longitude)) {
errors.push(`顶点${index + 1}的经度无效`);
}
});
}
}
if (!fence.machineryIds || fence.machineryIds.length === 0) {
errors.push('必须至少关联一台农机');
}
if (!fence.alertOnEnter && !fence.alertOnExit) {
errors.push('建议至少启用一种报警方式(进入或离开)');
}
return {
valid: errors.length === 0,
errors,
};
}
/**
* 验证纬度是否有效
*/
function isValidLatitude(lat: number): boolean {
return !isNaN(lat) && lat >= -90 && lat <= 90;
}
/**
* 验证经度是否有效
*/
function isValidLongitude(lng: number): boolean {
return !isNaN(lng) && lng >= -180 && lng <= 180;
}
/**
* 计算两点之间的距离(米)
* 使用 Haversine 公式
*/
export function calculateDistance(
point1: { latitude: number; longitude: number },
point2: { latitude: number; longitude: number }
): number {
const R = 6371000; // 地球半径,米
const lat1 = (point1.latitude * Math.PI) / 180;
const lat2 = (point2.latitude * Math.PI) / 180;
const deltaLat = ((point2.latitude - point1.latitude) * Math.PI) / 180;
const deltaLng = ((point2.longitude - point1.longitude) * Math.PI) / 180;
const a =
Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLng / 2) * Math.sin(deltaLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
/**
* 判断点是否在圆形围栏内
*/
export function isPointInCircle(
point: { latitude: number; longitude: number },
center: { latitude: number; longitude: number },
radius: number
): boolean {
const distance = calculateDistance(point, center);
return distance <= radius;
}
/**
* 判断点是否在多边形围栏内
* 使用射线法Ray Casting Algorithm
*/
export function isPointInPolygon(
point: { latitude: number; longitude: number },
polygon: { latitude: number; longitude: number }[]
): boolean {
let inside = false;
const x = point.longitude;
const y = point.latitude;
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].longitude;
const yi = polygon[i].latitude;
const xj = polygon[j].longitude;
const yj = polygon[j].latitude;
const intersect = yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi;
if (intersect) {
inside = !inside;
}
}
return inside;
}