holdingLocks/blockedBy/enums 为空时不再抛异常,CurrNodeCode 在无站点时返回 0。 Co-authored-by: Cursor <cursoragent@cursor.com>
2901 lines
120 KiB
C#
2901 lines
120 KiB
C#
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; }
|
||
}
|
||
}
|