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;
|
2026-08-26 11:20:03 +08:00
|
|
|
|
using Simple3;
|
|
|
|
|
|
using Simple3.RCS;
|
|
|
|
|
|
using Simple3.RCS.CarTypes;
|
|
|
|
|
|
using Simple3.CADTools;
|
|
|
|
|
|
using Simple3.Props;
|
|
|
|
|
|
using Simple3.UI;
|
2026-06-14 11:19:15 +08:00
|
|
|
|
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。
|
2026-08-26 11:20:03 +08:00
|
|
|
|
/// 拆分计划 §4.7:暂留 Core 维持现场兼容,后续逐步迁往 Simple3 的 EmbedIO 接口(MIGU-API),
|
2026-06-14 11:19:15 +08:00
|
|
|
|
/// 新功能请勿在此追加端点。
|
|
|
|
|
|
/// </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] });
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-26 23:03:41 +08:00
|
|
|
|
var holdingLocks = singleCar.status.holdingLocks;
|
|
|
|
|
|
var currentSite = SimpleLib.GetSite(holdingLocks?.FirstOrDefault() ?? 0);
|
|
|
|
|
|
var blockedBy = (singleCar.status.blockedBy ?? Array.Empty<(int, int)>())
|
|
|
|
|
|
.ToHashSet();
|
2026-06-14 11:19:15 +08:00
|
|
|
|
List<BlockedByItem> blockedByItems = new List<BlockedByItem>();
|
2026-08-26 23:03:41 +08:00
|
|
|
|
foreach (var pair in blockedBy)
|
2026-06-14 11:19:15 +08:00
|
|
|
|
{
|
|
|
|
|
|
blockedByItems.Add(
|
|
|
|
|
|
new BlockedByItem
|
|
|
|
|
|
{
|
2026-08-26 23:03:41 +08:00
|
|
|
|
CarCode = pair.Item1.ToString(),
|
|
|
|
|
|
Type = pair.Item2
|
2026-06-14 11:19:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
2026-08-26 11:20:03 +08:00
|
|
|
|
|
|
|
|
|
|
// 交管阻挡:报警优先;否则 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)}车交管";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-26 23:03:41 +08:00
|
|
|
|
var enums = singleCar.status.enums;
|
2026-06-14 11:19:15 +08:00
|
|
|
|
return new CarStateInfo()
|
|
|
|
|
|
{
|
|
|
|
|
|
Code = carCode,
|
|
|
|
|
|
Name = singleCar.name,
|
|
|
|
|
|
CurrState = carState,
|
|
|
|
|
|
IsOnline = isOnline,
|
2026-08-26 23:03:41 +08:00
|
|
|
|
Battery = TryParseEnumInt(enums, "Soc", 100),
|
|
|
|
|
|
Voltage = TryParseEnumDouble(enums, "Voltage", 0),
|
|
|
|
|
|
ElectricCurrent = TryParseEnumDouble(enums, "ElectricCurrent", 0),
|
2026-06-14 11:19:15 +08:00
|
|
|
|
X = singleCar.x,
|
|
|
|
|
|
Y = singleCar.y,
|
|
|
|
|
|
Theta = singleCar.th,
|
2026-08-26 23:03:41 +08:00
|
|
|
|
Speed = TryParseEnumDouble(enums, "ActualLeftWheelVelocity", singleCar.speed),
|
|
|
|
|
|
Load = TryParseEnumInt(enums, "loadStatus", 0),
|
|
|
|
|
|
CurrNodeCode = currentSite != null ? currentSite.id.ToString() : "0",
|
2026-06-14 11:19:15 +08:00
|
|
|
|
StartNodeCode = "0",
|
|
|
|
|
|
EndNodeCode = "0",
|
|
|
|
|
|
StartEdgeCode = "0",
|
|
|
|
|
|
EndEdgeCode = "0",
|
2026-08-26 23:03:41 +08:00
|
|
|
|
HoldingLocks = holdingLocks?.ToList() ?? new List<int>(),
|
|
|
|
|
|
PendingLocks = singleCar.status.pendingLocks?.ToList() ?? new List<int>(),
|
2026-06-14 11:19:15 +08:00
|
|
|
|
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();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-26 23:03:41 +08:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-06-14 11:19:15 +08:00
|
|
|
|
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; }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|