Files
StandardSence/StandardScene.Core/WebApi.cs
T

2879 lines
120 KiB
C#
Raw Normal View History

2026-06-14 11:19:15 +08:00
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 SimpleLite;
using SimpleLite.RCS;
using SimpleLite.RCS.CarTypes;
using SimpleLite.CADTools;
using SimpleLite.Props;
using SimpleLite.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 维持现场兼容,后续逐步迁往 SimpleLite 的 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 carId = singleCar.id;
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 currentSite = SimpleLib.GetSite(singleCar.status.holdingLocks.FirstOrDefault());
// HashSet<Tuple<int, int>> blockedBy = singleCar.status.blockedBy;
var blockedBy = singleCar.status.blockedBy.ToHashSet();
List<BlockedByItem> blockedByItems = new List<BlockedByItem>();
//var BlockedBy = string.Empty;
for (int i = 0; i < blockedBy.Count; i++)
{
//BlockedBy += $"({blockedBy.ElementAt(i).Item1 + "," + blockedBy.ElementAt(i).Item2});";
blockedByItems.Add(
new BlockedByItem
{
CarCode = blockedBy.ElementAt(i).Item1.ToString(),
Type = blockedBy.ElementAt(i).Item2
}
);
}
//BlockedBy = BlockedBy.TrimEnd(';');
return new CarStateInfo()
{
Code = carCode,
Name = singleCar.name,
CurrState = carState,
IsOnline = isOnline,
Battery = singleCar.status.enums.ContainsKey("Soc")
? int.Parse(singleCar.status.enums["Soc"])
: 100,
Voltage = singleCar.status.enums.ContainsKey("Voltage")
? double.Parse(singleCar.status.enums["Voltage"])
: 0,
ElectricCurrent = singleCar.status.enums.ContainsKey("ElectricCurrent")
? double.Parse(singleCar.status.enums["ElectricCurrent"])
: 0,
X = singleCar.x,
Y = singleCar.y,
Theta = singleCar.th,
Speed = singleCar.status.enums.ContainsKey("ActualLeftWheelVelocity")
? double.Parse(
SimpleLib.GetCar(carId).status.enums["ActualLeftWheelVelocity"]
)
: singleCar.speed,
//CurrNodeCode = currentSite.fields.ContainsKey("code") ? currentSite.fields["code"] : currentSite.id.ToString(),
Load = singleCar.status.enums.TryGetValue("loadStatus", out var statusEnum)
? int.Parse(statusEnum)
: 0,
CurrNodeCode = currentSite.id.ToString(),
StartNodeCode = "0",
EndNodeCode = "0",
StartEdgeCode = "0",
EndEdgeCode = "0",
HoldingLocks = singleCar.status.holdingLocks.ToList(),
PendingLocks = singleCar.status.pendingLocks.ToList(),
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();
}
}
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; }
}
}