init commit
This commit is contained in:
@@ -0,0 +1,599 @@
|
||||
using Newtonsoft.Json;
|
||||
using SimpleLite;
|
||||
using SimpleLite.RCS;
|
||||
using SimpleLite.RCS.CarTypes;
|
||||
using SimpleLite.RCS.Signal;
|
||||
using SimpleLite.CADTools;
|
||||
using SimpleLite.Props;
|
||||
using SimpleLite.UI;
|
||||
using SimpleCore;
|
||||
using SimpleCore.Compiler;
|
||||
using SimpleCore.Library;
|
||||
using SimpleCore.PropType;
|
||||
using StandardScene.Model;
|
||||
using StandardScene;
|
||||
using StandardScene.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace StandardScene.Chained
|
||||
{
|
||||
/// <summary>
|
||||
/// 任务类型枚举
|
||||
/// </summary>
|
||||
public enum TaskType
|
||||
{
|
||||
移动 = 1, // 移动任务(当前未使用)
|
||||
搬运 = 2, // 搬运任务
|
||||
装车 = 3, // 装车任务
|
||||
卸车 = 4, // 卸车任务
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 运输任务类
|
||||
/// 继承自AbstractDelivery,实现具体的运输任务功能
|
||||
/// </summary>
|
||||
/// public class TransportDelivery : AbstractChainedDeliveryMission.AbstractDelivery
|
||||
public class TransportDelivery : ChainedDeliveryMission.Delivery
|
||||
{
|
||||
/// <summary>任务类型(枚举值)</summary>
|
||||
public TaskType Type;
|
||||
/// <summary>任务类型(字符串形式)</summary>
|
||||
public string TaskType;
|
||||
/// <summary>使用的小车名称</summary>
|
||||
public string UsingCarName = "/";
|
||||
/// <summary>物料信息</summary>
|
||||
public string Material = "";
|
||||
/// <summary>占车站点</summary>
|
||||
public string HoldCarSite = "";
|
||||
/// <summary>阶段任务代码(用于标记阶段任务)</summary>
|
||||
public string MGTaskCode = "";
|
||||
/// <summary>任务ID字符串(用于标记阶段任务,可包含多个任务ID,用逗号分隔)</summary>
|
||||
public string TaskIdsString = "";
|
||||
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// 注册任务生命周期回调函数
|
||||
/// </summary>
|
||||
public TransportDelivery()
|
||||
{
|
||||
// 注册任务开始回调
|
||||
OnStart += d => { TransportOnStart((TransportDelivery)d); };
|
||||
// 注册取货完成回调
|
||||
DoneFetch += d => { TransportDoneFetch((TransportDelivery)d); };
|
||||
// 注册放货完成回调
|
||||
DonePut += d => { TransportDonePut((TransportDelivery)d); };
|
||||
// 注册任务完成回调
|
||||
DoneMission += d => { TransportDoneMission((TransportDelivery)d); };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务开始时的回调处理
|
||||
/// </summary>
|
||||
/// <param name="d">运输任务对象</param>
|
||||
private void TransportOnStart(TransportDelivery d)
|
||||
{
|
||||
Diagnosis.Post($"{d.TaskId}___{d.Src}->{d.Dst}: step-onStart");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取货完成时的回调处理
|
||||
/// </summary>
|
||||
/// <param name="d">运输任务对象</param>
|
||||
private void TransportDoneFetch(TransportDelivery d)
|
||||
{
|
||||
Diagnosis.Post($"{d.TaskId}___{d.Src}->{d.Dst}: step-doneFetch");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 放货完成时的回调处理
|
||||
/// </summary>
|
||||
/// <param name="d">运输任务对象</param>
|
||||
private void TransportDonePut(TransportDelivery d)
|
||||
{
|
||||
Diagnosis.Post($"{d.TaskId}___{d.Src}->{d.Dst}: step-donePut");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 任务完成时的回调处理
|
||||
/// </summary>
|
||||
/// <param name="d">运输任务对象</param>
|
||||
private void TransportDoneMission(TransportDelivery d)
|
||||
{
|
||||
Diagnosis.Post($"{d.TaskId}___{d.Src}->{d.Dst}: step-doneMission");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 搬运任务进程类
|
||||
/// 继承自AbstractChainedDeliveryMission,实现具体的搬运任务调度
|
||||
/// </summary>
|
||||
[MissionType(Name = "搬运任务进程", editor = typeof(TransportMission))]
|
||||
internal class TransportMission : ChainedDeliveryMission
|
||||
{
|
||||
/// <summary>是否启用就近任务策略("1"=启用,"0"=禁用)</summary>
|
||||
private static readonly string NearestTask = "1";
|
||||
|
||||
/// <summary>任务查看器窗口对象</summary>
|
||||
private DeliveryViewer dv;
|
||||
|
||||
public TransportMission()
|
||||
{
|
||||
// 确保回调静态类已完成注册
|
||||
TransportDeliveryCallbacks.EnsureInitialized();
|
||||
|
||||
// 根据配置的 MissionCallbackURL 设置回调地址(若有)
|
||||
var p = Param;
|
||||
if (p != null && !string.IsNullOrWhiteSpace(p.MissionCallbackURL))
|
||||
{
|
||||
if (Commons.IsValidHttpUrl(p.MissionCallbackURL))
|
||||
{
|
||||
_lastCallbackUrl = p.MissionCallbackURL;
|
||||
TransportDeliveryCallbacks.ConfigureCallbackUrl(_lastCallbackUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnosis.Log($"无效的 MissionCallbackURL 配置: {p.MissionCallbackURL}", "TransportMission");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class TransportMissionParam
|
||||
{
|
||||
/// <summary>
|
||||
/// 递送任务状态回调地址。
|
||||
/// </summary>
|
||||
public string MissionCallbackURL;
|
||||
}
|
||||
|
||||
public TransportMissionParam Param => StringDictConvert<TransportMissionParam>.Convert(fields);
|
||||
|
||||
private readonly bool _onDisplay = true;
|
||||
private string _lastCallbackUrl;
|
||||
|
||||
protected override Delivery CreateDeliveryFromSnapshot(DeliveryStateSnapshot snap)
|
||||
{
|
||||
var usingCar = SimpleLib.GetCar(snap.UsingCarId);
|
||||
if (snap.UsingCarId != -1 && usingCar == null)
|
||||
{
|
||||
Diagnosis.Post($"CreateDeliveryFromSnapshot[{snap.Id}] failed:usingCar[{snap.UsingCarId}] not found");
|
||||
return null;
|
||||
}
|
||||
if (usingCar != null && usingCar is not Car)
|
||||
{
|
||||
Diagnosis.Post($"CreateDeliveryFromSnapshot[{snap.Id}] skipped:usingCar[{snap.UsingCarId}] is not Car type");
|
||||
return null;
|
||||
}
|
||||
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
Id = snap.Id,
|
||||
TaskId = snap.TaskId ?? string.Empty,
|
||||
Src = snap.Src,
|
||||
Dst = snap.Dst,
|
||||
SkipFetch = snap.SkipFetch,
|
||||
SkipPut = snap.SkipPut,
|
||||
Putting = snap.Putting,
|
||||
CreateTime = snap.CreateTime,
|
||||
StartTime = snap.StartTime,
|
||||
FinishTime = snap.FinishTime,
|
||||
CarType = snap.CarType,
|
||||
UsingCar = (Car)usingCar
|
||||
};
|
||||
|
||||
if (usingCar != null && string.Equals(snap.Status, "putting", StringComparison.OrdinalIgnoreCase) && !CheckCarLoaded(usingCar))
|
||||
{
|
||||
d.Error = true;
|
||||
}
|
||||
|
||||
// 恢复回调配置与事件绑定
|
||||
d.ReportOnStarted = snap.ReportOnStarted;
|
||||
d.ReportOnFetched = snap.ReportOnFetched;
|
||||
d.ReportOnPut = snap.ReportOnPut;
|
||||
d.ReportOnFinished = snap.ReportOnFinished;
|
||||
d.ReportOnFailed = snap.ReportOnFailed;
|
||||
d.ReportOnTerminated = snap.ReportOnTerminated;
|
||||
|
||||
d.OnStartCallbackKeys = snap.OnStartCallbackKeys ?? new List<string>();
|
||||
d.DoneFetchCallbackKeys = snap.DoneFetchCallbackKeys ?? new List<string>();
|
||||
d.DonePutCallbackKeys = snap.DonePutCallbackKeys ?? new List<string>();
|
||||
d.DoneMissionCallbackKeys = snap.DoneMissionCallbackKeys ?? new List<string>();
|
||||
d.FailedCallbackKeys = snap.FailedCallbackKeys ?? new List<string>();
|
||||
d.OnTerminatedCallbackKeys = snap.OnTerminatedCallbackKeys ?? new List<string>();
|
||||
|
||||
// 统一通过 Attacher 挂载所有回调
|
||||
DeliveryCallbackAttacher.AttachAll(d);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
protected override bool CheckCarLoaded(AbstractCar car)
|
||||
{
|
||||
if(car is DummyCar)
|
||||
return true;
|
||||
var carLoaded = Commons.GetCarStatus((Car)car, "Loaded");
|
||||
if (!string.IsNullOrEmpty(carLoaded) && bool.TryParse(carLoaded, out var result))
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行方法(启动任务调度进程)
|
||||
/// 启动基类的任务调度循环,并启动状态显示线程
|
||||
/// </summary>
|
||||
public override void Execute()
|
||||
{
|
||||
base.Execute(); // 调用基类Execute方法,启动任务调度循环
|
||||
//HideSimpleConsole(); // 隐藏控制台窗口
|
||||
|
||||
// 启动状态显示线程,实时显示小车状态和任务执行情况
|
||||
new Thread(() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
Thread.Sleep(100); // 每100ms更新一次显示
|
||||
var painter = SimpleMonitor.getPainter("TransportMissionPainter");
|
||||
painter.clear();
|
||||
if (!_onDisplay) continue; // 如果未启用显示,跳过
|
||||
|
||||
// 检查并更新任务状态回调 URL(如果配置发生变化)
|
||||
var p = Param;
|
||||
var currentUrl = p?.MissionCallbackURL;
|
||||
if (!string.IsNullOrWhiteSpace(currentUrl) && currentUrl != _lastCallbackUrl)
|
||||
{
|
||||
// 使用 Commons 中的统一 URL 校验逻辑
|
||||
if (Commons.IsValidHttpUrl(currentUrl))
|
||||
{
|
||||
TransportDeliveryCallbacks.ConfigureCallbackUrl(currentUrl);
|
||||
_lastCallbackUrl = currentUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
Diagnosis.Log($"无效的 MissionCallbackURL 配置: {currentUrl}", "TransportMission");
|
||||
}
|
||||
}
|
||||
|
||||
var onMissionCnt = 0; // 正在执行任务的小车数量
|
||||
var carStr = $"{string.Join("\n", SimpleLib.GetAllCars().Select(cc =>
|
||||
{
|
||||
var status = "";
|
||||
if (cc.tags.TryGetValue("occupied", out var occupiedStr))
|
||||
{
|
||||
onMissionCnt++;
|
||||
status = occupiedStr;
|
||||
if (cc.tags.TryGetValue("idle", out var _))
|
||||
{
|
||||
Diagnosis.Post($"strange idle tag, {cc.name}({cc.id})");
|
||||
cc.tags.Remove("idle");
|
||||
|
||||
}
|
||||
}
|
||||
else if (cc.tags.TryGetValue("idle", out var idleStr)) status = DateTime.TryParse(idleStr, out var idleTime) ? $"idle:{idleTime}" : $"idle:{idleStr}";
|
||||
return $"{cc.name}({cc.id})\t{status}";
|
||||
}))}";
|
||||
//var waitingMissions = GetDeliveries()
|
||||
// .Where(dd => dd.GetStatus() == DeliveryStatus.Waiting).ToList();
|
||||
painter.drawTextFixed(
|
||||
$"小车:\t开动率:{onMissionCnt}/{SimpleLib.GetAllCars().Length}\n{carStr}\n\n",
|
||||
new SolidBrush(Color.Black),
|
||||
VirtualPainter.DrawPosition.LeftTop, Color.AliceBlue);
|
||||
painter = null;
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 变更任务优先级(重写基类方法)
|
||||
/// 根据配置决定是否执行就近任务策略
|
||||
/// </summary>
|
||||
public override void ChangePriority()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (NearestTask == "1") // NearestTask 等于1 执行就近原则
|
||||
{
|
||||
// 就近任务执行(当前被注释,未启用)
|
||||
// NearestTaskExecute();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果未启用就近原则,移除所有小车的就近选车标记
|
||||
foreach (var car in SimpleLib.GetAllCars().OfType<Car>())
|
||||
{
|
||||
Commons.DeleteTag(car.tags, "changePriority");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("同一工序就近执行就近任务执行:" + ex.ToString());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一键初始化所有小车
|
||||
/// 将状态为"正常"或"上线"且未初始化的小车进行重置
|
||||
/// </summary>
|
||||
[MethodMember(Name = "一键初始化")]
|
||||
public void ResetAll()
|
||||
{
|
||||
foreach (var car in SimpleLib.GetAllCars().OfType<Car>().Where(c => c.lstatus.Contains("正常") || c.lstatus.Contains("上线")))
|
||||
{
|
||||
// 如果小车未初始化(GetLastSite返回-1),执行重置
|
||||
if (car.GetLastSite() == -1)
|
||||
((Car)car).Reset();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 一键上线所有小车
|
||||
/// 将状态为"正常"或"上线"且已初始化的小车标记为在线状态
|
||||
/// </summary>
|
||||
[MethodMember(Name = "一键上线")]
|
||||
public void OnlineAll()
|
||||
{
|
||||
foreach (var car in SimpleLib.GetAllCars().OfType<Car>().Where(c => c.lstatus.Contains("正常") || c.lstatus.Contains("上线")))
|
||||
{
|
||||
// 如果小车已初始化,标记为在线
|
||||
if (car.GetLastSite() != -1)
|
||||
{
|
||||
Commons.AddOrUpdateTag(car.tags, "Online", "true");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查看任务列表界面
|
||||
/// 打开任务查看器窗口,显示所有任务的状态
|
||||
/// </summary>
|
||||
[MethodMember(Name = "查看任务", Description = "显示界面")]
|
||||
public void Print()
|
||||
{
|
||||
dv = new DeliveryViewer();
|
||||
dv.Show();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建单取货任务
|
||||
/// 通过UI交互选择小车和取货点,创建仅取货任务(跳过取货步骤,小车从当前位置移动到取货点)
|
||||
/// </summary>
|
||||
[MethodMember(Name = "单取货", Description = "增加并排队搬运任务链")]
|
||||
public async void ManualEnqueueFetch()
|
||||
{
|
||||
try
|
||||
{
|
||||
G.pushStatus("选择小车");
|
||||
var selected = SimpleMonitor.selected.ToArray();
|
||||
if (selected.Length == 0) { MessageBox.Show("请先选择需要控制的小车!"); return; }
|
||||
var obj = selected[0];
|
||||
if (obj is Car car)
|
||||
{
|
||||
G.pushStatus("选择取货位");
|
||||
// 等待用户在UI中选择取货点
|
||||
var pt1 = await Program.UI.getPoint(new UIOps.getPointOptions() { site = true });
|
||||
|
||||
// 创建运输任务:从小车当前位置到选择的取货点
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
CarType = "Car",
|
||||
Src = car.GetLastSite(), // 起始点为小车当前位置
|
||||
Dst = pt1.site, // 目标点为选择的取货点
|
||||
SkipFetch = true, // 跳过取货步骤(因为小车已经在起始点)
|
||||
UsingCar = car, // 指定使用的小车
|
||||
PutPlanInfo = new() { { "action", "fetch" } }, // 路径动作设置为fetch
|
||||
};
|
||||
|
||||
G.pushStatus($"排序了一个{car.name}搬运任务{d.Id}: {car.GetLastSite()} -> {d.Dst}");
|
||||
Enqueue(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("请选择需要控制的小车!");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
G.pushStatus($"结束任务链");
|
||||
}
|
||||
}
|
||||
|
||||
//写一个冒泡排序的算法,按照距离排序
|
||||
|
||||
[MethodMember(Name = "切换后台显示")]
|
||||
public void SwitchBackgroundDisplay()
|
||||
{
|
||||
ShowSimpleConsole();
|
||||
}
|
||||
/// <summary>
|
||||
/// 手动创建单放货任务
|
||||
/// 通过UI交互选择小车和放货点,创建仅放货任务(小车从当前位置移动到放货点并放货)
|
||||
/// </summary>
|
||||
[MethodMember(Name = "单放货", Description = "增加并排队搬运任务链")]
|
||||
public async void ManualEnqueuePut()
|
||||
{
|
||||
try
|
||||
{
|
||||
G.pushStatus("选择小车");
|
||||
var selected = SimpleMonitor.selected.ToArray();
|
||||
if (selected.Length == 0) { MessageBox.Show("请先选择需要控制的小车!"); return; }
|
||||
var obj = selected[0];
|
||||
if (obj is Car car)
|
||||
{
|
||||
G.pushStatus("选择取货位");
|
||||
// 等待用户在UI中选择放货点(注释写的是"取货位"但实际是放货点)
|
||||
var pt1 = await Program.UI.getPoint(new UIOps.getPointOptions() { site = true });
|
||||
var srcSite = SimpleLib.GetSite(pt1.site);
|
||||
|
||||
// 创建运输任务:从小车当前位置到选择的放货点
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
CarType = "Car",
|
||||
Src = car.GetLastSite(), // 起始点为小车当前位置
|
||||
Dst = pt1.site, // 目标点为选择的放货点
|
||||
UsingCar = car, // 指定使用的小车
|
||||
SkipFetch = true, // 跳过取货步骤
|
||||
PutPlanInfo = new() { { "action", "put" } }, // 路径动作设置为put
|
||||
|
||||
};
|
||||
G.pushStatus($"排序了一个{car.name}搬运任务{d.Id}: {srcSite.id} -> {d.Dst}");
|
||||
Enqueue(d);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("请选择需要控制的小车!");
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
G.pushStatus($"结束任务链");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建完整的取放货任务
|
||||
/// 通过UI交互选择取货点和放货点,创建完整的搬运任务(取货->放货)
|
||||
/// </summary>
|
||||
[MethodMember(Name = "取放货", Description = "增加并排队搬运任务链")]
|
||||
public async void ManualEnqueue()
|
||||
{
|
||||
try
|
||||
{
|
||||
G.pushStatus("选择取货位");
|
||||
// 等待用户在UI中选择取货点
|
||||
var pt1 = await Program.UI.getPoint(new UIOps.getPointOptions() { site = true });
|
||||
var srcSite = SimpleLib.GetSite(pt1.site);
|
||||
|
||||
G.pushStatus("选择放货位");
|
||||
// 等待用户在UI中选择放货点
|
||||
var pt2 = await Program.UI.getPoint(new UIOps.getPointOptions() { site = true });
|
||||
var dstSite = SimpleLib.GetSite(pt2.site);
|
||||
|
||||
// 创建完整的运输任务:从取货点到放货点
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
CarType = "Car",
|
||||
Src = srcSite.id, // 取货点
|
||||
Dst = dstSite.id, // 放货点
|
||||
TaskId = $"ManualTask-{DateTime.Now}" // 生成任务ID
|
||||
};
|
||||
|
||||
G.pushStatus($"排序了一个叉车搬运任务{d.Id}: {srcSite.id} -> {dstSite.id}");
|
||||
Enqueue(d);
|
||||
}
|
||||
catch
|
||||
{
|
||||
G.pushStatus($"结束任务链");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 手动创建移动任务(去某地)
|
||||
/// 通过UI交互选择目标站点,创建移动任务(起点和终点相同,只移动不放货)
|
||||
/// </summary>
|
||||
[MethodMember(Name = "去某地", Description = "去某地")]
|
||||
public async void ManualEnqueueGo()
|
||||
{
|
||||
try
|
||||
{
|
||||
G.pushStatus("选择前往的站点");
|
||||
// 等待用户在UI中选择目标站点
|
||||
var pt1 = await Program.UI.getPoint(new UIOps.getPointOptions() { site = true });
|
||||
var srcSite = SimpleLib.GetSite(pt1.site);
|
||||
|
||||
// 创建移动任务:起点和终点相同(只移动到目标点,不执行取放货操作)
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
CarType = "Car",
|
||||
Src = pt1.site, // 起点(实际不会取货)
|
||||
Dst = pt1.site, // 终点(实际不会放货)
|
||||
TaskId = $"ManualTask-{DateTime.Now}",
|
||||
SrcFindLoop = false, // 起点不查找回路
|
||||
DstFindLoop = false // 终点不查找回路
|
||||
};
|
||||
|
||||
G.pushStatus($"排序了一个叉车搬运任务{d.Id}: {srcSite.id} -> {srcSite.id}");
|
||||
Enqueue(d);
|
||||
}
|
||||
catch
|
||||
{
|
||||
G.pushStatus($"结束任务链");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 供按钮盒进程反射调用:ButtonMission.ExecuteButtonActionInternal 反射调用本方法后,
|
||||
/// 由 HandleMethodResult 解析返回值,驱动 OnActionExecuted 成功/失败反馈。
|
||||
/// 返回 true 表示已入队;false 表示站点无效。若 Enqueue 抛错,由按钮进程捕获后同样视为失败。
|
||||
/// 按钮配置示例:TriggerMission=TransportMission,TriggerMethod=EnqueueTransportByButton,TriggerMethodParams=取货站点ID,放货站点ID
|
||||
/// </summary>
|
||||
/// <param name="srcSiteId">取货站点 ID</param>
|
||||
/// <param name="dstSiteId">放货站点 ID</param>
|
||||
public bool EnqueueTransportByButton(int srcSiteId, int dstSiteId)
|
||||
{
|
||||
if (SimpleLib.GetSite(srcSiteId) == null || SimpleLib.GetSite(dstSiteId) == null)
|
||||
{
|
||||
Diagnosis.Log($"按钮排队搬运失败:站点不存在 src={srcSiteId}, dst={dstSiteId}", "TransportMission", true);
|
||||
return false;
|
||||
}
|
||||
|
||||
var d = new TransportDelivery
|
||||
{
|
||||
CarType = "Car",
|
||||
Src = srcSiteId,
|
||||
Dst = dstSiteId,
|
||||
TaskId = $"Button-{DateTime.Now:yyyyMMddHHmmssfff}"
|
||||
};
|
||||
Enqueue(d);
|
||||
Diagnosis.Post($"按钮排队搬运 {d.Id}: {srcSiteId} -> {dstSiteId}");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ========== 控制台窗口显示控制 ==========
|
||||
|
||||
/// <summary>Windows API:获取控制台窗口句柄</summary>
|
||||
[DllImport("kernel32.dll")]
|
||||
static extern IntPtr GetConsoleWindow();
|
||||
|
||||
/// <summary>Windows API:显示/隐藏窗口</summary>
|
||||
[DllImport("user32.dll")]
|
||||
static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
|
||||
|
||||
/// <summary>控制台显示状态标志</summary>
|
||||
private static bool ShowConsole = false;
|
||||
|
||||
/// <summary>
|
||||
/// 切换控制台窗口显示/隐藏
|
||||
/// </summary>
|
||||
public static void ShowSimpleConsole()
|
||||
{
|
||||
ShowConsole = !ShowConsole; // 切换显示状态
|
||||
var handle = GetConsoleWindow();
|
||||
int n = ShowConsole ? 0 : 5; // 0=显示,5=隐藏
|
||||
Console.WriteLine(n);
|
||||
ShowWindow(handle, n);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 隐藏控制台窗口
|
||||
/// </summary>
|
||||
public static void HideSimpleConsole()
|
||||
{
|
||||
var handle = GetConsoleWindow();
|
||||
ShowWindow(handle, 0); // 0表示隐藏窗口
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user