Files
黄兆尉andCursor d9bf8b9c84 fix: GetCarStateInfo 空引用与枚举解析
holdingLocks/blockedBy/enums 为空时不再抛异常,CurrNodeCode 在无站点时返回 0。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 23:03:41 +08:00

2901 lines
120 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using MDCSToolBox.Clumsy.Movements;
using Nancy;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Simple3;
using Simple3.RCS;
using Simple3.RCS.CarTypes;
using Simple3.CADTools;
using Simple3.Props;
using Simple3.UI;
using SimpleCore;
using SimpleCore.Library;
using SimpleCore.PropType;
using StandardScene.Chained;
using StandardScene.Charge;
using StandardScene.Model;
using StandardScene.Utils;
using static StandardScene.Chained.ChainedDeliveryMission;
using Map = StandardScene.Model.Map;
using Nancy.Session;
using StandardScene.InterLock;
namespace StandardScene
{
/// <summary>
/// 【过渡期遗留】老平台 Nancy HTTP 接口(40+ 端点)。导航耦合极弱:仅二维码 QrMap(数据仍存
/// 本类静态字段,由 scene.qrlidar 插件的 SyncQrMap 工具写入)与 getLidarMap。
/// 拆分计划 §4.7:暂留 Core 维持现场兼容,后续逐步迁往 Simple3 的 EmbedIO 接口(MIGU-API),
/// 新功能请勿在此追加端点。
/// </summary>
public class ApiController : NancyModule
{
private static readonly HttpClient SharedHttpClient = new HttpClient();
private static readonly string ApiToken = Environment.GetEnvironmentVariable("STANDARDSCENE_API_TOKEN");
private static List<TaskRequest> _taskRequests = new List<TaskRequest>();
public static MyDict<int, (float, float, float)> QrMap =
new MyDict<int, (float, float, float)>();
public static string QrMapJson;
private string GetMethods(Type baseClassType)
{
var assembly = Assembly.GetExecutingAssembly();
var derivedTypes = assembly.GetTypes()
.Where(t => t.IsSubclassOf(baseClassType));
var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();
foreach (var type in derivedTypes)
{
// old-school MethodMember
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<MethodMember>() != null && m.GetCustomAttribute<NoReflectionApi>() == null)
.Select(m =>
{
var attr = m.GetCustomAttribute<MethodMember>();
var ret = new MethodInfoDetails() { MethodName = m.Name };
var nameField = attr.Name;
if (nameField != null) ret.ButtonName = nameField;
var descField = attr.Description;
if (descField != null) ret.ButtonDescription = descField;
return ret;
})
.ToList();
// Methods with parameters
var paramMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<ReflectionApiWithParameter>() != null)
.Select(m =>
{
var attr = m.GetCustomAttribute<ReflectionApiWithParameter>();
var ret = new MethodInfoDetails() { MethodName = m.Name };
var nameField = attr.name;
if (nameField != null) ret.ButtonName = nameField;
var descField = attr.desc;
if (descField != null) ret.ButtonDescription = descField;
var hintField = attr.Hint;
if (hintField != null) ret.ParamsHint = hintField;
ret.ParamsList = m.GetParameters().Select(mp => new ParamInfo(mp.Name, mp.ParameterType)).ToList();
return ret;
})
.ToList();
classMethodsDictionary[type.Name] = methods.Concat(paramMethods).ToList();
}
return JsonConvert.SerializeObject(
new { Success = true, Code = 200, Data = classMethodsDictionary, Message = "Success" },
Formatting.Indented);
}
//获取指定class所有方法的字典
private Dictionary<string, List<MethodInfoDetails>> GetTypeMethods(Type type)
{
string[] shieldMethodButtonNames = new[]
{ "导出小车日志", "前往站点", "重启通信进程", "手动下发指令", "计划重启", "抛出中断", "放行", "显示调试信息", "给逃逸路径的初始化","返厂检修" };
var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();
// old-school MethodMember
var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<MethodMember>() != null && m.GetCustomAttribute<NoReflectionApi>() == null)
.Where(m => !shieldMethodButtonNames.Any(n => m.GetCustomAttribute<MethodMember>().Name.Contains(n)))
.Select(m =>
{
var attr = m.GetCustomAttribute<MethodMember>();
var ret = new MethodInfoDetails() { MethodName = m.Name };
var nameField = attr.Name;
if (nameField != null) ret.ButtonName = nameField;
var descField = attr.Description;
if (descField != null) ret.ButtonDescription = descField;
return ret;
})
.ToList();
// Methods with parameters
var paramMethods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<ReflectionApiWithParameter>() != null)
.Select(m =>
{
var attr = m.GetCustomAttribute<ReflectionApiWithParameter>();
var ret = new MethodInfoDetails() { MethodName = m.Name };
var nameField = attr.name;
if (nameField != null) ret.ButtonName = nameField;
var descField = attr.desc;
if (descField != null) ret.ButtonDescription = descField;
var hintField = attr.Hint;
if (hintField != null) ret.ParamsHint = hintField;
ret.ParamsList = m.GetParameters().Select(mp => new ParamInfo(mp.Name, mp.ParameterType)).ToList();
return ret;
})
.ToList();
classMethodsDictionary[type.Name] = methods.Concat(paramMethods).ToList();
return classMethodsDictionary;
}
/// <summary>
/// 反射调用白名单:仅允许显式标注为可暴露的方法被 HTTP 反射调用,
/// 与 GetMethods 的暴露口径一致,避免“按名调用任意 public 方法”的远程执行风险。
/// </summary>
private static bool IsReflectionInvokable(MethodInfo methodInfo)
{
if (methodInfo == null) return false;
if (methodInfo.GetCustomAttribute<NoReflectionApi>() != null) return false;
return methodInfo.GetCustomAttribute<MethodMember>() != null
|| methodInfo.GetCustomAttribute<ReflectionApiWithParameter>() != null;
}
private static string ReflectionForbidden(object id, string method)
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 403,
Data = "null",
Message = $"method {method} of {id} is not exposed for reflection invocation"
}, Formatting.Indented);
}
private bool IsAuthorized()
{
if (string.IsNullOrEmpty(ApiToken)) return true;
try
{
var q = ((DynamicDictionary)Request.Query).ToDictionary();
return q.TryGetValue("token", out var t) && t != null && t.ToString() == ApiToken;
}
catch
{
return false;
}
}
private static string Unauthorized()
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 401,
Data = "null",
Message = "unauthorized: missing or invalid api token"
}, Formatting.Indented);
}
private dynamic CarReflectionExecute(dynamic parameters)
{
try
{
if (!IsAuthorized()) return Unauthorized();
var car = SimpleLib.GetCar((int)parameters.id);
if (car == null)
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = $"no car of id {parameters.id}" }, Formatting.Indented);
var queryParams = ((DynamicDictionary)Request.Query).ToDictionary();
queryParams.Remove("token");
MethodInfo methodInfo = null;
if (queryParams.Keys.Count == 0)
methodInfo = car.GetType().GetMethod((string)parameters.method, new Type[] { });
else
methodInfo = car.GetType().GetMethod((string)parameters.method);
if (methodInfo == null)
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = $"car {parameters.id} has no method {parameters.method}" }, Formatting.Indented);
if (!IsReflectionInvokable(methodInfo))
return ReflectionForbidden(parameters.id, (string)parameters.method);
return ExecuteMethod(methodInfo, car, queryParams);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
}
}
private dynamic MissionReflectionExecute(dynamic parameters)
{
try
{
if (!IsAuthorized()) return Unauthorized();
var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
if (mission == null)
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = $"no mission of id {parameters.id}" }, Formatting.Indented);
var methodInfo = mission.GetType().GetMethod((string)parameters.method);
if (methodInfo == null)
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = $"mission {parameters.id} has no method {parameters.method}" }, Formatting.Indented);
var queryParams = ((DynamicDictionary)Request.Query).ToDictionary();
queryParams.Remove("token");
if (!IsReflectionInvokable(methodInfo))
return ReflectionForbidden(parameters.id, (string)parameters.method);
return ExecuteMethod(methodInfo, mission, queryParams);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
}
}
private string ExecuteMethod(MethodInfo methodInfo, object instance, Dictionary<string, object> inputs)
{
var methodParam = methodInfo.GetParameters();
List<object> paramList = new List<object>();
if (methodParam.Length == 0)
{
methodInfo.Invoke(instance, null);
}
else
{
if (inputs.Count != methodParam.Length)
{
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"method need {methodParam.Length} params , but {inputs.Count}"
}, Formatting.Indented);
}
for (int i = 0; i < methodParam.Length; i++)
{
paramList.Add(Convert.ChangeType(inputs[methodParam[i].Name], methodParam[i].ParameterType));
}
var actualParam = paramList.ToArray();
methodInfo.Invoke(instance, actualParam);
}
return JsonConvert.SerializeObject(
new { Success = true, Code = 200, Data = "null", Message = "Success" }, Formatting.Indented);
}
public ApiController()
{
After.AddItemToEndOfPipeline(ctx =>
{
ctx.Response.WithHeader("Access-Control-Allow-Origin", "*")
.WithHeader("Access-Control-Allow-Methods", "POST,GET")
.WithHeader("Access-Control-Allow-Headers", "Accept, Origin, Content-Type");
});
// 反射接口共识:
// 所有simple的调度对象(包括车、进程)只有id是全局唯一的。
// 所有simple的调度对象可能有不同的class,class相同的可能有不同的name(name并非全局唯一)。
// 所有simple的调度对象都有属性(field)、状态(status)、动作(methodMember)。
// 属性是可读可写的字典(用户设定属性,并保存属性作为运行配置)。状态是只读的字典。动作是函数成员。
// 反射接口全部返回json字符串,包括success和result两个字段。
// success为true或者false,分别表示请求成功或失败。
// result为返回内容。success为false时,result是报错内容。
// 返回className
Get("/car_reflection/get_type/{id}", parameters =>
{
try
{
var car = SimpleLib.GetCar((int)parameters.id);
if (car == null)
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no car of id {parameters.id}"
}, Formatting.Indented);
return JsonConvert.SerializeObject(
new { Success = true, Code = 200, Data = car.GetType().Name, Message = "Success" },
Formatting.Indented);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
}
});
Get("/car_reflection/get_methods/{id}", parameters =>
{
try
{
var car = SimpleLib.GetCar((int)parameters.id);
if (car == null)
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no car of id {parameters.id}"
}, Formatting.Indented);
var classMethodsDictionary = GetTypeMethods(car.GetType());
if (classMethodsDictionary == null)
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 500,
Data = "null",
Message = $"未匹配到id[{parameters.id}] 的车辆"
},
Formatting.Indented);
}
return JsonConvert.SerializeObject(new
{
Success = true,
Code = 200,
Data = classMethodsDictionary.Values.FirstOrDefault(),
Message = "Success"
},
Formatting.Indented);
}
catch (Exception e)
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 500,
Data = "null",
Message = e.Message
},
Formatting.Indented);
}
});
// 返回每种className对应有哪些动作
Get("/car_reflection/get_type_methods", _ => GetMethods(typeof(GhostCar)));
// 执行动作(支持任意数量参数);执行类操作同时提供 POST 语义化入口,保留 GET 兼容旧前端
Get("/car_reflection/execute/{id}/{method}", parameters => CarReflectionExecute(parameters));
Post("/car_reflection/execute/{id}/{method}", parameters => CarReflectionExecute(parameters));
// 返回(id, name, className)的列表
Get("/mission_reflection/get_mission_list", _ =>
JsonConvert.SerializeObject(new
{
Success = true,
Code = 200,
Data = SimpleProject.proj.Missions.Select(mm =>
{
var mType = (MissionType)mm.GetType().GetCustomAttribute(typeof(MissionType));
return new { id = mm.id, name = mm.name, typeName = mType.Name, state = mm.status.status };
}),
Message = "Success"
}, Formatting.Indented));
Get("/mission_reflection/get_type_methods", _ => GetMethods(typeof(Mission)));
Get("/mission_reflection/execute/{id}/{method}", parameters => MissionReflectionExecute(parameters));
Post("/mission_reflection/execute/{id}/{method}", parameters => MissionReflectionExecute(parameters));
Get("/mission_reflection/get_status/{id}", parameters =>
{
try
{
var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
if (mission == null)
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no mission of id {parameters.id}"
}, Formatting.Indented);
return JsonConvert.SerializeObject(
new { success = true, Code = 200, Data = mission.status, Message = "Success" },
Formatting.Indented);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", result = ex.Message }, Formatting.Indented);
}
});
Get("/mission_reflection/get_fields/{id}", parameters =>
{
try
{
var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
if (mission == null)
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no mission of id {parameters.id}"
}, Formatting.Indented);
return JsonConvert.SerializeObject(
new
{
Success = true,
Code = 200,
Data = mission.fields.Select(x => { return new { Key = x.Key, Vaule = x.Value }; })
.ToList(),
Message = "Success"
},
Formatting.Indented);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", result = ex.Message }, Formatting.Indented);
}
});
Get("/mission_reflection/set_field/{id}/{field}/{value}", parameters =>
{
try
{
var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
if (mission == null)
return JsonConvert.SerializeObject(
new { success = false, Data = "null", Message = $"no mission of id {parameters.id}" },
Formatting.Indented);
var fieldName = (string)parameters.field;
var fieldValue = (string)parameters.value;
mission.fields[fieldName] = fieldValue;
return JsonConvert.SerializeObject(
new { Success = true, Code = 200, Data = "null", Message = "Success" }, Formatting.Indented);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(
new { Success = false, Code = 500, Data = "null", Message = ex.Message }, Formatting.Indented);
}
});
Get("/mission_reflection/delete_field/{id}/{field}", parameters =>
{
try
{
var mission = SimpleProject.proj.Missions.FirstOrDefault(mm => mm.id == (int)parameters.id);
if (mission == null)
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no mission of id {parameters.id}"
}, Formatting.Indented);
var fieldName = (string)parameters.field;
if (!mission.fields.ContainsKey(fieldName))
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 500,
Data = "null",
Message = $"mission not found field {parameters.field}"
}, Formatting.Indented);
}
mission.fields.Remove(fieldName);
return JsonConvert.SerializeObject(new
{
Success = true,
Code = 200,
Data = "null",
Message = "Success"
}, Formatting.Indented);
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new
{
Success = false,
Code = 500,
Data = "null",
Message = ex.Message
}, Formatting.Indented);
}
});
Get("/mission_reflection/get_mission/{id}", parameters =>
{
try
{
var classMethodsDictionary = new Dictionary<string, List<MethodInfoDetails>>();
var mission = SimpleProject.proj.Missions.FirstOrDefault(m => m.id == (int)parameters.id);
if (mission == null)
{
return JsonConvert.SerializeObject(
new
{
Success = false,
Code = 500,
Data = "null",
Message = $"no mission of id {parameters.id}"
},
Formatting.Indented);
}
var method = mission.GetType()
.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<MethodMember>() != null).Select(m =>
{
var attr = m.GetCustomAttribute<MethodMember>();
var param = m.GetParameters();
var ret = new MethodInfoDetails() { MethodName = m.Name };
var name = attr.Name;
if (name != null) ret.ButtonName = name;
var desc = attr.Description;
if (desc != null) ret.ButtonDescription = desc;
return ret;
}).ToList();
classMethodsDictionary[mission.name] = method;
return JsonConvert.SerializeObject(
new { Success = true, Code = 200, Data = classMethodsDictionary.Values.FirstOrDefault(), Message = "Success" });
}
catch (Exception e)
{
return JsonConvert.SerializeObject(new
{ Success = false, Code = 500, Data = "null", Message = e.Message });
}
});
// 需讨论如何实现
// Get["/save_parameters"] = _ => { };
#region 创建任务[Fass发布任务]
Post("/car/createTask", _ =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var req = jReq.JsonTo<TaskRequest>();
switch (req.MissionType)
{
case "Transport":
CreateTransportTask:
(
responseResult.Success,
responseResult.Code,
responseResult.Message,
var _
) = CreateTransportTask(req, true);
break;
default:
goto CreateTransportTask;
}
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
return response;
}
catch (Exception ex)
{
Diagnosis.Log(
$"起始站点匹配错误,请检查"
+ ExceptionFormatter.FormatEx(ex)
+ $"--time:{DateTime.Now.ToString()}",
"error",
true
);
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = ex.Message;
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
return response;
}
});
#endregion
#region 任务下发[Fass持续下发]
Post("/car/carTask", _ =>
{
Response response;
var responseResult = new BaseRespose<CarStateInfo>
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
Stopwatch sw = new Stopwatch();
sw.Start();
string jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
TaskRequest req = jReq.JsonTo<TaskRequest>();
switch (req.MissionType)
{
case "Transport":
CheckTransportTask:
(
responseResult.Success,
responseResult.Code,
responseResult.Message,
responseResult.Data
) = CreateTransportTask(req, false);
break;
default:
goto CheckTransportTask;
}
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
//Diagnosis.Log(
// $"carTask_Done:::consumeTime:{sw.ElapsedMilliseconds}",
// "Interface",
// true
//);
return response;
}
catch (Exception ex)
{
Diagnosis.Log(
$"起始站点匹配错误,请检查"
+ ExceptionFormatter.FormatEx(ex)
+ $"--time:{DateTime.Now.ToString()}",
"error",
true
);
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = ex.Message;
responseResult.Data = new CarStateInfo();
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
return response;
}
});
#endregion
#region 状态查询
Post("/car/carState", _ =>
{
Response response;
try
{
Stopwatch sw = new Stopwatch();
sw.Start();
var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var req = jReq.JsonTo<GetCar>();
if (req.CarCode != "0")
{
var responseResult = new BaseRespose<CarStateInfo>
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
var singleCar = SimpleLib
.GetAllCars()
.OfType<Car>()
.FirstOrDefault(e =>
e.id.ToString() == req.CarCode && e.GetLastSite() != -1
);
if (singleCar != null)
{
responseResult.Data = GetCarStateInfo(req.CarCode);
}
else
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"车辆carCode:{req.CarCode}不存在或未初始化";
responseResult.Data = new CarStateInfo();
}
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
//Diagnosis.Log(
// $"carState_Done:::consumeTime:{sw.ElapsedMilliseconds}",
// "Interface",
// true
//);
return response;
}
else
{
var responseResult = new BaseRespose<List<CarStateInfo>>
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
var carStateList = new List<CarStateInfo>();
var cars = SimpleLib.GetAllCars().OfType<Car>().ToList();
if (cars.Count > 0)
{
foreach (var car in cars)
{
var carStateInfo = GetCarStateInfo(car.name);
carStateList.Add(carStateInfo);
}
responseResult.Data = carStateList;
}
else
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = "当前系统中无启用调度车辆";
responseResult.Data = carStateList;
}
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
//Diagnosis.Log(
// $"carState_Done:::consumeTime:{sw.ElapsedMilliseconds}",
// "Interface",
// true
//);
return response;
}
}
catch (Exception ex)
{
Console.WriteLine($@"agv/getCar => ex: {ex.Message}");
var responseResult = new BaseRespose<CarStateInfo>
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = ex.Message;
responseResult.Data = new CarStateInfo();
response = Response.AsText(
responseResult.ToJson(),
"application/json;charset=UTF-8"
);
return response;
}
});
#endregion
#region 初始化小车
Get("/car/reset/{cartId}", _ =>
{
var resp = new BaseRespose();
try
{
int cartId = _.cartId;
Car car = (Car)SimpleLib.GetCar(cartId);
//如果有任务不允许初始化
if (!car.tags.Contains("occupied"))
{
car.Reset();
car.tags.Add("idle", DateTime.Now.ToString());
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 现场维修
Get("/car/repair/{cartId}", _ =>
{
var resp = new BaseRespose();
try
{
int cartId = _.cartId;
Car car = (Car)SimpleLib.GetCar(cartId);
car.Repair();
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 返厂维修
Get("/car/blown/{cartId}", _ =>
{
var resp = new BaseRespose();
try
{
int cartId = _.cartId;
Car car = (Car)SimpleLib.GetCar(cartId);
var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().First();
var deliver = cdm.GetDeliveries()
.Find(p => ((TransportDelivery)p).UsingCar.id == car.id);
if (deliver != null)
{
resp.Success = false;
resp.Code = 500;
resp.Message = "当前小车有任务需等任务结束后返厂";
}
else
{
car.AppendDebug("ui-blown");
Diagnosis.Post($"Car {car.name}({car.id}) blown");
car.NoSchedule();
car.siteID = -1;
car.tags.Clear();
car.status.usage.AddUsage(
"base",
new CarUsage.CarUsageInfo { scheduling = false, refreshing = false }
);
car.lstatus = "返厂检修";
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 站点启用
Get("/site/enable/{siteId}", _ =>
{
var resp = new BaseRespose();
try
{
int siteId = _.siteId;
Site site = SimpleLib.GetSite(siteId);
if (site.tags.Contains("unavailable"))
site.tags.Remove("unavailable");
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 站点禁用
Get("/site/disable/{siteId}", _ =>
{
var resp = new BaseRespose();
try
{
int siteId = _.siteId;
Site site = SimpleLib.GetSite(siteId);
if (!site.tags.Contains("unavailable"))
site.tags.Add("unavailable");
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 取消任务
Post("/car/cancelTask", param =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var req = jReq.JsonTo<TaskCancel>();
switch (req.MissionType)
{
case "Transport":
TransportCancel:
var cdm = SimpleProject
.proj.Missions.OfType<TransportMission>()
.First();
var deliver = cdm.GetDeliveries()
.Find(p => ((TransportDelivery)p).TaskId == req.TaskCode);
if (deliver != null)
{
deliver.Canceled = true;
if (!deliver.Cancel())
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = "任务取消失败";
return responseResult;
}
else
{
if (deliver.UsingCar != null)
{
var car = deliver.UsingCar;
new Thread(() =>
{
try
{
car.AppendDebug("Clumsy Restarted");
car.NoSchedule(true);
car.siteID = -1;
Commons.DeleteTag(car.tags, "occupied");
if (car.address != null && car.address != "")
{
SharedHttpClient.GetAsync(
$"http://{car.address}:8008/reset"
);
}
car.AppendDebug("restarting clumsy");
//car.Get("reset");
car.AppendDebug(
"wait for any pending task to flush."
);
car.status.programs.task.Wait();
//car.Reset();
}
catch (Exception)
{
responseResult.Message = "重启C失败";
}
}).Start();
}
}
}
else
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = $"CDM中不存在任务id[{req.TaskCode}]";
}
break;
default:
goto TransportCancel;
break;
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"任务取消失败! ex:{e.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
});
#endregion
#region 获取Simple地图
Get("/map/getMap", _ =>
{
var resp = new BaseRespose<Map>()
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
resp.Data = Map.GetMap();
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 获取雷达地图
Get("/map/getLidarMap", _ =>
{
var resp = new BaseRespose<LidarMap>()
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
resp.Data = LidarMap.GetLidarMap().Result;
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 获取所有小车信息
Get("/car/getAllCars", _ =>
{
var resp = new BaseRespose<List<CarBaseInfo>>();
try
{
resp.Data = new List<CarBaseInfo>();
foreach (var car in SimpleLib.GetAllCars())
{
resp.Data.Add(CarBaseInfo.FromCar((Car)car));
}
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 去某地
Get("/car/goSite", param =>
{
var carCode = Request.Query["carCode"];
var id = Request.Query["id"];
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
if (carCode != 0 && id != 0)
{
Car car = (Car)SimpleLib.GetCar(carCode);
Site site = SimpleLib.GetSite(id);
Commons.GoSite(car, site, 1);
}
var response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception)
{
return Response.AsText("调用小车去某地失败".ToJson(), "application/json");
}
});
#endregion
#region 获取任务列表
Get("/task/getTask", _ =>
{
Response response;
var resp = new BaseRespose<List<TaskRecord>>()
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var missions = SimpleProject
.proj.Missions.OfType<ChainedDeliveryMission>()
.ToList();
List<TaskRecord> deliveryList = new List<TaskRecord>();
if (missions.Count == 0)
return Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
foreach (var cdm in missions)
{
var finishTaskList = cdm.GetDeliveries(true, true)
.Where(e => e.FinishTime > DateTime.Now.AddMinutes(-30))
.ToList(); //30min内已完成完成任务
var executingTaskList = cdm.GetDeliveries(); //未完成任务
foreach (var delivery in finishTaskList)
{
var temp = (TransportDelivery)delivery;
deliveryList.Add(
new TaskRecord
{
TaskId = temp.TaskId,
Name = $"{temp.Src} =>{temp.Dst}",
CarId = temp.UsingCar.id.ToString(),
CarName = temp.UsingCar.name,
State = GetDeliveryStatus(temp),
SrcSiteId = temp.Src.ToString(),
DestSiteId = temp.Dst.ToString(),
Priority = temp.Priority,
StartTime = temp.StartTime,
EndTime = temp.FinishTime,
Created = temp.CreateTime
}
);
}
foreach (var delivery in executingTaskList)
{
var temp = (TransportDelivery)delivery;
deliveryList.Add(
new TaskRecord
{
TaskId = temp.TaskId,
Name = $"{temp.Src} =>{temp.Dst}",
CarId = temp.UsingCar.id.ToString(),
CarName = temp.UsingCar.name,
State = GetDeliveryStatus(temp),
SrcSiteId = temp.Src.ToString(),
DestSiteId = temp.Dst.ToString(),
Priority = temp.Priority,
StartTime = temp.StartTime,
EndTime = temp.FinishTime,
Created = temp.CreateTime
}
);
}
resp.Data = deliveryList;
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 强制结束
Get("/car/ForceStop/{cartId}", _ =>
{
#region
/* try
{
int cartId = _.cartId;
var car = (Car)SimpleLib.GetCar(cartId);
try
{
if (car == null)
{
resp.Success = false;
resp.Code = 500;
resp.Message = "小车在系统中没找到";
}
else
{
car.AppendDebug("ui-repair");
car.tags.Clear();
car.NoSchedule(makeUnavailable: false);
car.siteID = -1;
car.lstatus = "结束任务";
var cdm = SimpleProject
.proj.Missions.OfType<TransportMission>()
.First();
var deliver = cdm.GetDeliveries()
.Find(p => ((TransportDelivery)p).usingCar.id == car.id);
if (deliver != null)
{
deliver.canceled = true;
if (!deliver.Cancel())
{
deliver.usingCar.UIIntercept();
resp.Success = false;
resp.Code = 500;
resp.Message = "任务取消失败";
}
}
new Thread(() =>
{
try
{
//car.status.programs.task.Wait();
HttpClient client = new HttpClient();
client.GetAsync($"http://{car.address}:8008/reset");
}
catch
{
resp.Success = false;
resp.Code = 500;
resp.Message = "重启C失败";
}
}).Start();
resp.Success = true;
resp.Code = 200;
resp.Message = "强制结束任务成功";
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}*/
#endregion
var resp = new BaseRespose() { Message = "任务取消成功" };
try
{
int cartId = _.cartId;
var car = (Car)SimpleLib.GetCar(cartId);
car.NoSchedule(true);
car.siteID = -1;
Commons.ClearTags(car.tags);
car.tags.Clear();
var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().First();
var deliver = cdm.GetDeliveries()
.Find(p => ((TransportDelivery)p).UsingCar.id == car.id);
int count = 0;
if (deliver != null)
{
deliver.Canceled = true;
if (!deliver.Cancel())
{
resp.Success = false;
resp.Code = 400;
resp.Message = "任务取消失败";
var res = Response.AsText(
resp.ToJson(),
"application/json;charset=UTF-8"
);
return res;
}
}
new Thread(() =>
{
try
{
SharedHttpClient.GetAsync($"http://{car.address}:8008/reset");
car.AppendDebug("restarting clumsy");
//car.Get("reset");
car.AppendDebug("wait for any pending task to flush.");
car.status.programs.task.Wait();
car.AppendDebug("Clumsy Restarted");
car.NoSchedule();
car.siteID = -1;
Commons.DeleteTag(car.tags, "occupied");
// car.Reset();
}
catch (Exception)
{
resp.Message = "重启C失败";
}
})
{
Name = $"ForceStop:{car.name}({car.id})"
}.Start();
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 重启电脑
Get("/car/ReStart/{cartId}", _ =>
{
var resp = new BaseRespose();
int cartId = _.cartId;
var car = (Car)SimpleLib.GetCar(cartId);
var task = Task.Run(() =>
{
try
{
resp.Success = false;
resp.Code = 200;
resp.Message = "重启中";
// 创建一个Process对象
Process process = new Process();
// 设置启动信息
process.StartInfo.FileName = "shutdown";
process.StartInfo.Arguments = "/r /t 0"; // 重启电脑,立即执行
process.StartInfo.CreateNoWindow = true; // 不显示窗口
process.StartInfo.UseShellExecute = false; // 不使用操作系统外壳程序启动进程
// 启动进程
process.Start();
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 400;
resp.Message = e.Message;
}
});
task.Wait();
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 停接任务
Get("/car/stopReceiveTask/{cartId}", _ =>
{
var resp = new BaseRespose();
int cartId = _.cartId;
try
{
var car = (Car)SimpleLib.GetCar(cartId);
if (car != null)
{
if (!car.fields.ContainsKey("StopAccept"))
{
Commons.AddOrUpdateCarField(car, "StopAccept", "1");
}
else
{
Commons.DeleteCarField(car, "StopAccept");
}
}
else
{
resp.Success = false;
resp.Code = 500;
resp.Message = "找不到对应小车";
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 获取小车信息
Get("/car/carInfo/{cartId}", _ =>
{
var resp = new BaseRespose<CarInfo>();
int cartId = _.cartId;
try
{
var car = (Car)SimpleLib.GetCar(cartId);
if (car != null)
{
resp.Data = new CarInfo()
{
Name = car.name,
Address = car.address,
Speed = car.status.enums.TryGetValue(
"ActualLeftWheelVelocity",
out var statusEnum
)
? statusEnum
: car.speed.ToString(),
Voltage = car.status.enums.TryGetValue("soc", out var soc)
? float.Parse(soc)
: -1,
Code = car.id.ToString(),
siteId = car.GetLastSite()
};
}
}
catch (Exception e)
{
resp.Success = false;
resp.Code = 500;
resp.Message = e.Message;
}
var response = Response.AsText(resp.ToJson(), "application/json;charset=UTF-8");
return response;
});
#endregion
#region 去待命点
Get("/car/goToStandby", param =>
{
var CarCode = Request.Query["carCode"];
//var id = Request.Query["id"];
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var car = (Car)SimpleLib.GetCar(CarCode);
if (car != null)
{
var carGroup = car.fields.TryGetValue("group", out var value)
? value
: "all";
var targetPlan = Commons.GetNearestPlan(
(Car)car,
site =>
site.fields.ContainsKey("standby")
&& carGroup.Equals(
site.fields.TryGetValue("group", out var value) ? value : "all"
)
&& site.fields["standby"] == "true"
);
if (targetPlan != null)
{
Commons.GoSite(car, targetPlan.Destination, 1);
}
}
else
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = "没有找到任务小车";
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception)
{
return Response.AsText("调用小车去待命点失败".ToJson(), "application/json");
}
});
#endregion
#region 去充电点
Get("/car/goToCharge", param =>
{
var CarCode = Request.Query["carCode"];
//var id = Request.Query["id"];
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var car = (Car)SimpleLib.GetCar(CarCode);
if (car != null)
{
/* var carGroup = car.fields.TryGetValue("group", out var value) ? value : "all";
var targetPlan = Commons.GetNearestPlan((Car)car, site =>
site.fields.ContainsKey("charge")
&& site.fields["charge"] == "true" && carGroup.Equals(site.fields.TryGetValue("group", out var value) ? value : "all")
);
if (targetPlan != null)
{
Diagnosis.Post($"小车路径规划成功目标充电位{targetPlan.Destination}", "去充电",true);
Commons.GoSite(car, targetPlan.Destination, 1);
}
else
{
Diagnosis.Post("小车路径规划失败", "去充电", true);
}*/
Commons.AddOrUpdateTag(car.tags, "shouldCharge", "true");
}
else
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = "没有找到任务小车";
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception)
{
return Response.AsText("调用小车去充电电点失败".ToJson(), "application/json");
}
});
#endregion
#region 暂停恢复
Get("/car/startOrPause", param =>
{
var carCode = Request.Query["CarCode"];
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
if (carCode == 0)
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "没有找到任务小车";
return Response.AsJson(responseResult);
}
ClumsyCar car = SimpleLib.GetCar(carCode) as ClumsyCar;
if (car == null)
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.NotFound;
responseResult.Message = "未找到对应的小车";
return Response.AsJson(responseResult);
}
string releaseStatus = Commons.GetCarStatus(car, "ISRelease");
try
{
ToggleCarReleaseStatus(car, releaseStatus);
}
catch (Exception ex)
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}";
Diagnosis.Log($"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}");
}
return Response.AsJson(responseResult);
}
catch (Exception ex)
{
responseResult.Success = false;
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"暂停恢复失败 => ex:{ExceptionFormatter.FormatEx(ex)}";
return Response.AsJson(responseResult);
}
});
#endregion
#region 暂停任务/恢复任务
Post("/car/stopOrPauseTask", param =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var result = jReq.JsonTo<TaskCancel>();
var taskCode = result.TaskCode;
var cdms = SimpleProject
.proj.Missions.OfType<ChainedDeliveryMission>()
.ToList();
if (cdms.Count == 0)
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = "未找到CDM进程";
return Response.AsText(responseResult.ToJson(), "application/json");
}
Delivery deliver = null;
foreach (var cdm in cdms)
{
deliver = cdm.GetDeliveries(includeAborted: true)
.FirstOrDefault(p => p.TaskId == taskCode);
if (deliver != null)
break;
}
if (deliver == null)
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = $"CDM中不存在任务id[{taskCode}]";
return Response.AsText(responseResult.ToJson(), "application/json");
}
deliver.Terminated = result.TaskStatus == "1";
var status = 0;
if (deliver.UsingCar != null)
{
status = (deliver.OnTerminated?.Invoke(deliver, result.TaskStatus)).Result;
}
if (status != 1)
{
responseResult.Success = false;
responseResult.Code = 500;
responseResult.Message = deliver.Terminated ? "暂停任务停止小车失败" : "恢复任务失败";
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (JsonSerializationException jsonEx)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = $"JSON解析失败! ex:{jsonEx.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"任务取消失败! ex:{e.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
});
#endregion
#region 设置充电参数
Post("/car/setChargingSettings", param =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jReq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var chargingSetting = jReq.JsonTo<ChargingSetting>();
// 这里可以根据 ChargingSetting 的属性进行具体的业务逻辑处理
// 例如:
if (chargingSetting.CarMinBattery < 0 || chargingSetting.CarMaxBattery > 100)
{
responseResult.Success = false;
responseResult.Code = 400;
responseResult.Message = "充电电量范围不合法";
}
else
{
// 假设我们有一个方法来应用这些充电设置
ApplyChargingSettings(chargingSetting);
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"设置充电参数失败! ex:{e.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
});
#endregion
#region 设置包络参数
Post("/car/setEnvelopeSetting", param =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var envelopeSetting = jreq.JsonTo<EnvelopeSetting>();
// 读取本地 JSON 文件
var simpleFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
var simpleJson = File.ReadAllText(simpleFilePath);
var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
var jsonFilePath = "";
if (simpleConfig != null && simpleConfig.Autoload != null)
{
jsonFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
}
else
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "修改文件路径不对";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
//var jsonFilePath = $"{System.AppDomain.CurrentDomain.BaseDirectory}/0123.json";
var jsonData = File.ReadAllText(jsonFilePath);
var jsonObject = JObject.Parse(jsonData);
// 更新或添加属性
// 获取或创建 "conf" 节点
var confNode = jsonObject["conf"];
if (confNode == null || confNode.Type != JTokenType.Object)
{
confNode = new JObject();
jsonObject["conf"] = confNode;
}
// 更新 JSON 数据
confNode[envelopeSetting.Name] = envelopeSetting.Value;
;
// 将修改后的数据写回 JSON 文件
File.WriteAllText(jsonFilePath, jsonObject.ToString());
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"设置包络参数失败! ex:{e.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
});
#endregion
#region 设置交管参数
Post("/car/setTrafficControlSetting", param =>
{
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var trafficControlSetting = jreq.JsonTo<TrafficControlSetting>();
// 读取本地 JSON 文件
var simpleFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
var simpleJson = File.ReadAllText(simpleFilePath);
var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
var jsonFilePath = "";
if (simpleConfig != null && simpleConfig.Autoload != null)
{
jsonFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
}
else
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "修改文件路径不对";
}
// 读取本地 JSON 文件路径
// jsonFilePath = $"{System.AppDomain.CurrentDomain.BaseDirectory}/0123.json";
if (!File.Exists(jsonFilePath))
{
throw new FileNotFoundException(
$"JSON file not found at path: {jsonFilePath}"
);
}
// 读取并解析 JSON 文件
var jsonData = File.ReadAllText(jsonFilePath);
var jsonObject = JObject.Parse(jsonData);
// 获取或创建 "conf" 节点
var confNode = jsonObject["conf"];
if (confNode == null || confNode.Type != JTokenType.Object)
{
confNode = new JObject();
jsonObject["conf"] = confNode;
}
// 更新 JSON 数据
confNode[trafficControlSetting.Name] = trafficControlSetting.Value;
// 将修改后的数据写回 JSON 文件
File.WriteAllText(jsonFilePath, jsonObject.ToString());
return Response.AsJson(responseResult);
}
catch (JsonSerializationException jsonEx)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = $"JSON解析失败! ex:{jsonEx.Message}";
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"设置交管控制参数失败! ex:{e.Message}";
}
return Response.AsJson(responseResult);
});
#endregion
#region 删除配置参数
Post("/car/delControlSetting", param =>
{
Response response;
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var keysToRemove = jreq.JsonTo<List<string>>();
// 读取本地 JSON 文件
var simpleFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/simple.json";
var simpleJson = File.ReadAllText(simpleFilePath);
var simpleConfig = simpleJson.JsonTo<SimpleConfig>();
var jsonFilePath = "";
if (simpleConfig != null && simpleConfig.Autoload != null)
{
jsonFilePath =
$"{System.AppDomain.CurrentDomain.BaseDirectory}/{simpleConfig.Autoload}";
}
else
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "修改文件路径不对";
}
if (!File.Exists(jsonFilePath))
{
throw new FileNotFoundException(
$"JSON file not found at path: {jsonFilePath}"
);
}
var jsonData = File.ReadAllText(jsonFilePath);
var jsonObject = JObject.Parse(jsonData);
var confNode = jsonObject["conf"] as JObject;
if (confNode == null)
{
confNode = new JObject();
jsonObject["conf"] = confNode;
}
if (confNode != null)
{
foreach (var key in keysToRemove)
{
if (confNode.ContainsKey(key))
{
confNode.Remove(key);
}
}
// 将修改后的数据写回 JSON 文件
File.WriteAllText(jsonFilePath, jsonObject.ToString());
}
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (JsonSerializationException jsonEx)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = $"JSON解析失败! ex:{jsonEx.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (FileNotFoundException fnfEx)
{
responseResult.Code = (int)HttpStatusCode.NotFound;
responseResult.Message = $"文件未找到! ex:{fnfEx.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"设置控制参数失败! ex:{e.Message}";
response = Response.AsText(responseResult.ToJson(), "application/json");
return response;
}
});
#endregion
#region 删除路径规划参数设置
Post("/car/delPlanRulesControlSetting", param =>
{
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var planRulesSettings = jreq.JsonTo<List<PlanRulesSetting>>();
if (planRulesSettings.Count() < 0)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "没有需要删除的路径参数";
return Response.AsJson(responseResult);
}
foreach (var planRules in planRulesSettings)
{
//根据参数,站点ID 找到该站点,如果站点有这个字段则删除,没有不用管
Site site = SimpleLib.GetSite(int.Parse(planRules.NodeId));
if (site == null)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "需要修改属性的站点不存在";
return Response.AsJson(responseResult);
}
if (site.fields.TryGetValue(planRules.Name, out var value))
{
site.fields.Remove(planRules.Name);
}
}
return Response.AsJson(responseResult);
}
catch (JsonSerializationException jsonEx)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = $"JSON解析失败! ex:{jsonEx.Message}";
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"删除路径规划参数失败! ex:{e.Message}";
}
return Response.AsJson(responseResult);
});
#endregion
#region 设置路径规划参数
Post("/car/setPlanRulesControlSetting", param =>
{
var responseResult = new BaseRespose
{
Success = true,
Code = (int)HttpStatusCode.OK,
Message = "success"
};
try
{
var jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var planRulesSetting = jreq.JsonTo<PlanRulesSetting>();
if (planRulesSetting == null)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "需要修改属性的站点不存在";
return Response.AsJson(responseResult);
}
Site site = SimpleLib.GetSite(int.Parse(planRulesSetting.NodeId));
if (site == null)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = "需要修改属性的站点不存在";
return Response.AsJson(responseResult);
}
//判断站点属性是否存在,存在则修改,不存在则添加
if (site.fields.TryGetValue(planRulesSetting.Name, out var value))
{
site.fields[planRulesSetting.Name] = planRulesSetting.Value;
}
else
{
site.fields.Add(planRulesSetting.Name, planRulesSetting.Value);
}
return Response.AsJson(responseResult);
}
catch (JsonSerializationException jsonEx)
{
responseResult.Code = (int)HttpStatusCode.BadRequest;
responseResult.Message = $"JSON解析失败! ex:{jsonEx.Message}";
}
catch (Exception e)
{
responseResult.Code = (int)HttpStatusCode.InternalServerError;
responseResult.Message = $"设置路径规划参数失败! ex:{e.Message}";
}
return Response.AsJson(responseResult);
});
#endregion
Get("/api/QrMap", _ =>
{
return QrMapJson;
});
Post("/api/CreateSite", o =>
{
try
{
string jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
QrSite site = JsonConvert.DeserializeObject<QrSite>(jreq);
var newSite = new UISite() { x = site.X, y = site.Y };
Console.WriteLine($"x:{site.X},y:{site.Y}");
var d = SimpleLib
.GetAllSites()
.Select(p => LessMath.dist(site.X, site.Y, p.x, p.y));
if (d.Any() && d.Min() < 3)
{
Console.WriteLine($"重复设置站点?");
return JsonConvert.SerializeObject(
new { data = new { success = false, message = "设置站点失败,重复设置站点?" } }
);
}
SimpleLib.SetSite(newSite);
var ss = SimpleLib
.GetAllSites()
.OrderBy(p => LessMath.dist(site.X, site.Y, p.x, p.y))
.First();
ss.fields["th"] = (site.Th).ToString();
ss.fields["tag"] = (site.Tag).ToString();
return JsonConvert.SerializeObject(
new { data = new { success = true, message = "设置站点成功" } }
);
}
catch (Exception e)
{
Console.WriteLine(e);
return JsonConvert.SerializeObject(
new { data = new { success = false, message = "设置站点失败" + e } }
);
}
});
#region OTA获取车辆列表
Get("/api/agv/list", _ =>
{
List<Object> cars = new List<Object>();
foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
{
var station = SimpleLib
.GetAllSites()
.ToList()
.FirstOrDefault(site =>
site.id == car.status.holdingLocks.FirstOrDefault()
&& site.name.Contains("TaskStation")
);
var statusV = car.status.enums.ContainsKey("actualV")
? float.Parse(car.status.enums["actualV"])
: 0;
car.status.enums.TryGetValue("electricCurrent", out var electricCurrent);
var agv_status = "";
if (statusV == 0)
{
agv_status = "停止";
}
else if (statusV > 0)
{
agv_status = "运行中";
}
if (
statusV == 0
&& electricCurrent != null
&& electricCurrent != ""
&& float.Parse(electricCurrent) * 0.01f > 0
)
{
agv_status = "充电中";
}
cars.Add(
new
{
agv_id = car.id,
agv_name = car.name,
agv_ip = car.address,
//agv_status = car.tags["carStatu"],
//agv_status = car.tags.Contains("carStatu") ? car.tags["carStatu"] : "OFFLINE",
energy = car.status.enums.ContainsKey("soc")
? float.Parse(car.status.enums["soc"])
: -1,
/* x = tPos.Item1,
y = tPos.Item2,
th = tPos.Item3,*/
x = car.x,
y = car.y,
th = car.th,
speed = Commons.CarValue(car, "sendSpeed"),
fault = car.status.enums.ContainsKey("mAlarm")
? car.status.enums["mAlarm"]
: "正常",
siteId = car.GetLastSite(),
// materialinfo =new string[3] { "materialinfo1", "materialinfo2", "materialinfo3" }
stationInfo = station != null
? new { stationID = station.id, staionName = station.name }
: null,
agv_status = agv_status
}
);
}
return JsonConvert.SerializeObject(
new
{
code = 200,
message = "ok",
data = cars
}
);
});
#endregion
#region 第三方交管
Post("api/agv/traffic", _ =>
{
try
{
string jreq = new System.IO.StreamReader(Request.Body).ReadToEnd();
var Traffic = JsonConvert.DeserializeObject<TrafficRequestModel>(jreq);
var Area = TrafficInterlockMission.TrafficAreaList.Find(t => t.AreaName == Traffic.AreaName);
if (Traffic != null && Area != null)
{
if (Traffic.IsOccupy && !Area.IsOccupy)
{
lock (TrafficInterlockMission.TrafficAreaList)
{
Area.IsOccupy = true; Area.ControllerName = Traffic.ControllerName;
}
return JsonConvert.SerializeObject(new { data = new { success = true, message = "申请管制区成功" } });
}
else if (!Traffic.IsOccupy && Area.ControllerName == Traffic.ControllerName)
{
lock (TrafficInterlockMission.TrafficAreaList)
{
Area.IsOccupy = false; Area.ControllerName = string.Empty;
}
return JsonConvert.SerializeObject(new { data = new { success = true, message = "释放管制区成功" } });
}
}
return JsonConvert.SerializeObject(new { data = new { success = false, message = "失败" } });
}
catch (Exception e)
{
Console.WriteLine(e);
return JsonConvert.SerializeObject(new { data = new { success = false, message = "设置交管失败" + e } });
}
});
#endregion
}
private void ToggleCarReleaseStatus(ClumsyCar car, string currentStatus)
{
int targetStatus = (currentStatus == "1") ? 0 : 1;
string command = $"pilot.ISRelease={targetStatus};";
while (Commons.GetCarStatus(car, "ISRelease") == currentStatus)
{
car.ImmediateCommand(command);
Thread.Sleep(100);
}
}
private void ApplyChargingSettings(ChargingSetting settings)
{
Console.WriteLine("开始处理充电配置参数的逻辑");
// 这里是应用充电设置的具体逻辑
// 例如,更新设备的充电参数等
var chargeMission = SimpleProject
.proj.Missions.OfType<AbstractChargeLogiceMission>()
.FirstOrDefault();
if (chargeMission == null)
return;
Commons.AddOrUpdateMissionField(
chargeMission,
"mustChargeSoc",
settings.CarMinBattery.ToString()
);
Commons.AddOrUpdateMissionField(
chargeMission,
"fullChargeSoc",
settings.CarMaxBattery.ToString()
);
Commons.AddOrUpdateMissionField(
chargeMission,
"taskAvailableSoc",
settings.TaskAvailableBattery.ToString()
);
Commons.AddOrUpdateMissionField(
chargeMission,
"mustChargeSeconds",
settings.CarIdleSecond.ToString()
);
Commons.AddOrUpdateMissionField(
chargeMission,
"idleChargeSoc",
settings.CarIdleChargeBattery.ToString()
);
}
private (bool, int, string, CarStateInfo) CreateTransportTask(
TaskRequest req,
bool isCreate
)
{
var transportMission = SimpleProject.proj.Missions.OfType<TransportMission>().First();
//校验任务重复
if (
transportMission
.GetDeliveries(true)
.FindAll(p => ((TransportDelivery)p).TaskId == req.TaskCode)
.Count > 0
)
{
return (
false,
(int)HttpStatusCode.InternalServerError,
$"taskCode:{req.TaskCode}已经存在",
GetCarStateInfo(req.CarCode)
);
}
//判定指定车辆是否存在
Car car = null;
if (!string.IsNullOrWhiteSpace(req.CarCode))
{
car = SimpleLib
.GetAllCars()
.OfType<Car>()
.FirstOrDefault(e => e.id.ToString() == req.CarCode);
if (car == null || car.status.holdingLocks.FirstOrDefault() == -1)
{
return (
false,
(int)HttpStatusCode.InternalServerError,
$"传入车辆code{req.CarCode}不存在或没有初始化",
new CarStateInfo()
);
}
}
//判断node的个数
switch (req.Nodes.Count)
{
case 2:
Diagnosis.Log(
$"receiveTask:[TaskId ={req.TaskCode},carId = {req.CarCode},src = {req.Nodes[0].Code},dst = {req.Nodes[1].Code}",
"task",
true
);
break;
case 1:
if (car == null)
return (
false,
(int)HttpStatusCode.InternalServerError,
$"创建单点任务时,未指定车辆",
new CarStateInfo()
);
Diagnosis.Log(
$"receiveTask:[TaskId ={req.TaskCode},carId = {req.CarCode},dst = {req.Nodes[0].Code}",
"task",
true
);
break;
default:
return (
false,
(int)HttpStatusCode.InternalServerError,
$"创建任务时,传入站点个数不对",
new CarStateInfo()
);
}
//站点存在判断,默认都是双点任务
var siteCodes = req.Nodes.Select(e => e.Code).ToArray();
if (!Commons.IsSceneSiteByCode(siteCodes))
{
return (
false,
(int)HttpStatusCode.InternalServerError,
$"不存在设定站点 => taskCode:{req.TaskCode}",
new CarStateInfo()
);
}
var src =
req.Nodes.Count == 2
? SimpleLib.GetSite(req.Nodes[0].Code)
: SimpleLib.GetSite(car.status.holdingLocks.First()); //如果是单点任务,默认当前未知为起点
var dst =
req.Nodes.Count == 2
? SimpleLib.GetSite(req.Nodes[1].Code)
: SimpleLib.GetSite(req.Nodes[0].Code);
var d = new TransportDelivery
{
Src = src.id,
Dst = dst.id,
CarType = req.CarType,
TaskId = req.TaskCode,
TaskType = req.TaskType,
Material = req.Material,
Priority = req.priority,
MaterialLength = req.ContainerSize != null ? (float)req.ContainerSize.Length : -1,
MaterialWidth = req.ContainerSize != null ? (float)req.ContainerSize.Width : -1,
};
if (car != null)
{
d.UsingCar = car;
}
d.FetchPlanInfo["MaterialLength"] = d.MaterialLength + "";
d.FetchPlanInfo["MaterialWidth"] = d.MaterialWidth + "";
if (d.Src == d.Dst)
{
d.FetchPlanInfo["action"] = "/";
d.PutPlanInfo["action"] = "/";
}
// 初始化回调配置,确保任务在各阶段触发统一回调
d.ReportOnStarted = true;
d.ReportOnFetched = true;
d.ReportOnPut = true;
d.ReportOnFinished = true;
d.ReportOnFailed = true;
d.ReportOnTerminated = true;
// 根据 ReportOn* 写入 key 列表
if (d.ReportOnStarted)
d.OnStartCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnStarted);
if (d.ReportOnFetched)
d.DoneFetchCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFetched);
if (d.ReportOnPut)
d.DonePutCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnPut);
if (d.ReportOnFinished)
d.DoneMissionCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFinished);
if (d.ReportOnFailed)
d.FailedCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnFailed);
if (d.ReportOnTerminated)
d.OnTerminatedCallbackKeys.Add(TransportDeliveryCallbacks.KeyOnTerminated);
// 统一通过 Attacher 挂载回调,便于持久化与恢复
DeliveryCallbackAttacher.AttachAll(d);
transportMission.Enqueue(d);
Diagnosis.Log($"Add task =>{d.ToJson()}req:{req.ToJson()}");
return (true, (int)HttpStatusCode.OK, "success", GetCarStateInfo(req.CarCode));
}
private class GetCar
{
public string CarCode;
}
public CarStateInfo GetCarStateInfo(string carCode)
{
try
{
var transportMission = SimpleProject
.proj.Missions.OfType<TransportMission>()
.FirstOrDefault();
if (string.IsNullOrEmpty(carCode))
return new CarStateInfo();
var singleCar = SimpleLib
.GetAllCars()
.OfType<Car>()
.FirstOrDefault(e => e.id.ToString() == carCode && e.GetLastSite() != -1);
if (singleCar == null)
return new CarStateInfo();
var runningTask = (TransportDelivery)
transportMission
.GetDeliveries()
.FindAll(p =>
(
p.GetStatus() == DeliveryStatus.Fetching
|| p.GetStatus() == DeliveryStatus.Putting
)
&& p.UsingCar.id == singleCar.id
)
.FirstOrDefault(); //获取当前车辆正在运行的任务
var finishedTask = (TransportDelivery)
transportMission
.GetDeliveries(true)
.FindAll(p =>
p.GetStatus() == DeliveryStatus.Finished
&& p.UsingCar.id == singleCar.id
)
.OrderByDescending(e => e.FinishTime)
.FirstOrDefault(); //获取最近完成的任务
var waitingTask = (TransportDelivery)
transportMission
.GetDeliveries()
.FindAll(p =>
p.GetStatus() == DeliveryStatus.Waiting
&& p.UsingCar != null
&& p.UsingCar.id == singleCar.id
)
.OrderBy(e => e.CreateTime)
.FirstOrDefault();
var taskList = new List<TaskInfo>();
var actions = new List<TaskAction>();
//string carState = SwitchCarState(singleCar);
var isOnline = false;
string carState = SwitchCarState(singleCar, ref isOnline);
//var resNodes = new List<ResponseNode>();
if (finishedTask != null)
{
taskList.Add(
new TaskInfo()
{
Code = finishedTask.TaskId,
State = "Completed",
Nodes = new List<ResponseNode>()
{
new()
{
//Code = Commons.GetSiteCodeById(finishedTask.src)
Code = finishedTask.Src.ToString()
},
new()
{
//Code = Commons.GetSiteCodeById(finishedTask.dst)
Code = finishedTask.Dst.ToString()
}
}
}
);
}
if (runningTask != null)
{
taskList.Add(
new TaskInfo()
{
Code = runningTask.TaskId,
State = "Running",
Nodes = new List<ResponseNode>()
{
new()
{
//Code = Commons.GetSiteCodeById(runningTask.src)
Code = runningTask.Src.ToString()
},
new()
{
//Code = Commons.GetSiteCodeById(runningTask.dst)
Code = runningTask.Dst.ToString()
}
}
}
);
}
if (waitingTask != null)
{
taskList.Add(
new TaskInfo()
{
Code = waitingTask.TaskId,
State = "Distributed",
Nodes = new List<ResponseNode>()
{
new()
{
//Code = Commons.GetSiteCodeById(waittingTask.src)
Code = waitingTask.Src.ToString()
},
new()
{
//Code = Commons.GetSiteCodeById(waittingTask.dst)
Code = waitingTask.Dst.ToString()
}
}
}
);
}
var alarmsList = new List<CarAlarm>();
if (
singleCar.status.enums.ContainsKey("AlarmInfo")
&& !string.IsNullOrWhiteSpace(singleCar.status.enums["AlarmInfo"])
)
{
string alarmMessage = singleCar.status.enums["AlarmInfo"].TrimEnd(',');
string[] alarms = alarmMessage.Split(',');
foreach (string alarm in alarms)
{
string[] info = alarm.Split('.');
if (info.Length == 2)
{
alarmsList.Add(new CarAlarm() { Code = info[0], Name = info[1] });
}
}
}
var holdingLocks = singleCar.status.holdingLocks;
var currentSite = SimpleLib.GetSite(holdingLocks?.FirstOrDefault() ?? 0);
var blockedBy = (singleCar.status.blockedBy ?? Array.Empty<(int, int)>())
.ToHashSet();
List<BlockedByItem> blockedByItems = new List<BlockedByItem>();
foreach (var pair in blockedBy)
{
blockedByItems.Add(
new BlockedByItem
{
CarCode = pair.Item1.ToString(),
Type = pair.Item2
}
);
}
// 交管阻挡:报警优先;否则 CurrState 显示「被{name}车交管」(多车全部列出)
var hasAlarm =
singleCar.status.enums.TryGetValue("AlarmInfo", out var alarmInfo)
&& !string.IsNullOrWhiteSpace(alarmInfo);
if (!hasAlarm)
{
var blockerNames = blockedBy
.Where(p => p.Item1 >= 0)
.Select(p => p.Item1)
.Distinct()
.Select(id =>
{
var blocker = SimpleLib.GetCar(id);
return blocker != null && !string.IsNullOrWhiteSpace(blocker.name)
? blocker.name
: id.ToString();
})
.ToList();
if (blockerNames.Count > 0)
carState = $"被{string.Join("", blockerNames)}车交管";
}
var enums = singleCar.status.enums;
return new CarStateInfo()
{
Code = carCode,
Name = singleCar.name,
CurrState = carState,
IsOnline = isOnline,
Battery = TryParseEnumInt(enums, "Soc", 100),
Voltage = TryParseEnumDouble(enums, "Voltage", 0),
ElectricCurrent = TryParseEnumDouble(enums, "ElectricCurrent", 0),
X = singleCar.x,
Y = singleCar.y,
Theta = singleCar.th,
Speed = TryParseEnumDouble(enums, "ActualLeftWheelVelocity", singleCar.speed),
Load = TryParseEnumInt(enums, "loadStatus", 0),
CurrNodeCode = currentSite != null ? currentSite.id.ToString() : "0",
StartNodeCode = "0",
EndNodeCode = "0",
StartEdgeCode = "0",
EndEdgeCode = "0",
HoldingLocks = holdingLocks?.ToList() ?? new List<int>(),
PendingLocks = singleCar.status.pendingLocks?.ToList() ?? new List<int>(),
BlockedBy = blockedByItems,
// BlockingTime = singleCar.status.blockingTime.ToString("yyyy-MM-dd HH:mm:ss"),//没有了
TrafficMessage = singleCar.status.TCStat.ToString(),
AquiringLock = singleCar.status.aquiringLock,
Tasks = taskList,
Alarms = alarmsList,
StopAccept = singleCar.fields.ContainsKey("StopAccept"),
Actions = new List<TaskAction>()
};
}
catch (Exception ex)
{
Console.WriteLine($"getCarStateInfo => ex: {ex}");
return new CarStateInfo();
}
}
static int TryParseEnumInt(IDictionary<string, string> enums, string key, int fallback)
{
if (enums != null && enums.TryGetValue(key, out var text) && int.TryParse(text, out var value))
return value;
return fallback;
}
static double TryParseEnumDouble(IDictionary<string, string> enums, string key, double fallback)
{
if (enums != null && enums.TryGetValue(key, out var text) && double.TryParse(text, out var value))
return value;
return fallback;
}
public string SwitchCarState(Car car, ref bool isOnline)
{
string state = "Stopping";
if (car.GetLastSite() == -1)
{
isOnline = false;
return state;
}
if (Commons.GetVehicleStatus(car)!= VehicleStatus.Offline)
{
if (Commons.GetVehicleStatus(car) is VehicleStatus.Normal or VehicleStatus.NeedInit)
state = "Stopping"; //Idle
var lp = car.status.programs.latest;
if (lp != null)
{
if (
lp.status.state >= SimpleCore.Compiler.CarProgram.StatusEnum.Programming
&& lp.status.state <= SimpleCore.Compiler.CarProgram.StatusEnum.Running
)
{
state = "Running"; //Executing
}
}
//存在报警信息
if (car.status.enums.ContainsKey("AlarmInfo"))
{
if (!string.IsNullOrEmpty(car.status.enums["AlarmInfo"]))
{
state = "Faulting"; //Malfunction
}
}
if (car.tags.Contains("charging"))
state = "Charging";
isOnline = true;
}
else
{
isOnline = false;
}
return state;
}
public string GetDeliveryStatus(TransportDelivery delivery)
{
ChainedDeliveryMission.DeliveryStatus status =
(ChainedDeliveryMission.DeliveryStatus)delivery.GetStatus();
if (status == ChainedDeliveryMission.DeliveryStatus.Error)
{
return "Faulted";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Canceled)
{
return "Canceled";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Terminated)
{
return "Terminated";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Finished)
{
return "Completed";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Putting)
{
return "Putting";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Fetching)
{
return "Fetching";
}
else if (status == ChainedDeliveryMission.DeliveryStatus.Waiting)
{
return "Created";
}
else
{
return "UnKnown";
}
}
}
internal class MethodInfoDetails
{
public string MethodName;
public string ButtonName;
public string ButtonDescription;
public string ParamsHint;
public List<ParamInfo> ParamsList = new();
}
internal class ParamInfo
{
public ParamInfo(string name, Type type)
{
Name = name;
Type = type;
}
public string Name;
public Type Type;
}
public class HttpPostData
{
private HttpClient hc = new HttpClient() { Timeout = TimeSpan.FromSeconds(3) };
public void UploadSignal(string content)
{
try
{
//var json = JsonConvert.SerializeObject(new { });
//var data = new StringContent(json, Encoding.UTF8, "application/json");
StringContent stringContent = new StringContent(
JsonConvert.SerializeObject(content)
);
//ApiController._logger.Info($"DeviceNotifyPost:[{stringContent.ToString()}]");
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
//hc.Timeout = TimeSpan.FromSeconds(30);
var task = hc.PostAsync(
"http://localhost:20101/api/v1/SecuritySignal/GetSecuritySignal",
stringContent
);
var responseStr = task.Result.Content.ReadAsStringAsync().Result;
ResultMsg response = JsonConvert.DeserializeObject<ResultMsg>(responseStr);
}
catch (Exception e)
{
Diagnosis.Log("DeviceNotifyPost" + ExceptionFormatter.FormatEx(e), $"error", true);
}
}
public void UploadListNode(HashSet<int> contentList)
{
try
{
/* if (contentList == null || contentList.Count == 0)
{
throw new ArgumentException("Content list cannot be null or empty.");
}*/
// 序列化List为JSON字符串
var jsonContent = JsonConvert.SerializeObject(contentList);
StringContent stringContent = new StringContent(
jsonContent,
Encoding.UTF8,
"application/json"
);
// 设置内容类型为application/json
stringContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
// 发送POST请求
var task = hc.PostAsync(
"http://localhost:20101/api/v1/Node/NodeListDisable",
stringContent
);
// 读取响应内容
var responseStr = task.Result.Content.ReadAsStringAsync().Result;
// 反序列化响应
ResultMsg response = JsonConvert.DeserializeObject<ResultMsg>(responseStr);
}
catch (Exception e)
{
// 记录异常
Diagnosis.Log("DeviceNotifyPost" + ExceptionFormatter.FormatEx(e), "error", true);
}
}
}
public class QrSite
{
public float X;
public float Y;
public float Th;
public int Tag;
}
class ResultMsg
{
public string code { get; set; }
public string reqCode { get; set; }
public string msg { get; set; }
public int statu { get; set; }
}
public class TrafficRequestModel
{
/// <summary>
/// 区域名称
/// </summary>
public string AreaName { get; set; }
/// <summary>
/// 控制单位
/// </summary>
public string ControllerName { get; set; }
/// <summary>
/// 申请占用/释放区域,true为占用,false为释放
/// </summary>
public bool IsOccupy { get; set; }
}
}