init commit
This commit is contained in:
@@ -0,0 +1,316 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using StandardScene.Model;
|
||||
using SimpleLite;
|
||||
using SimpleCore;
|
||||
using SimpleCore.Library;
|
||||
using StandardScene.Utils;
|
||||
using static StandardScene.Chained.ChainedDeliveryMission;
|
||||
|
||||
namespace StandardScene.Chained
|
||||
{
|
||||
public partial class DeliveryViewer : Form
|
||||
{
|
||||
private const int OverdueMinutesThreshold = 10000; // 约7天视为超时
|
||||
private const int DisplayColumnIndexOverdueFlag = 9;
|
||||
private static readonly HttpClient SharedHttpClient = new HttpClient();
|
||||
/// <summary>选中行的背景色</summary>
|
||||
private static readonly Color SelectedRowBackColor = Color.FromArgb(220, 230, 250);
|
||||
/// <summary>缓存选中行索引,避免在 RetrieveVirtualItem 中访问 SelectedIndices 引发递归</summary>
|
||||
private readonly HashSet<int> _selectedIndicesCache = new HashSet<int>();
|
||||
|
||||
private ListViewItem _item = null;
|
||||
|
||||
public DeliveryViewer()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private readonly ContextMenuStrip strip = new ContextMenuStrip();
|
||||
|
||||
private void DeliveryViewer_Load(object sender, EventArgs e)
|
||||
{
|
||||
strip.Items.Clear();
|
||||
strip.Items.Add("取消任务", null, CancelClick);
|
||||
strip.Items.Add("重发任务", null, ResendClick);
|
||||
strip.Items.Add("换车重发任务", null, ChangeCarResendClick);
|
||||
currentTaskList.ContextMenuStrip = strip;
|
||||
}
|
||||
|
||||
private List<string[]> _listDeliveries = new List<string[]>();
|
||||
|
||||
/// <summary>将任务标记为已取消(Canceled)。</summary>
|
||||
private static void MarkDeliveryCanceled(Delivery d)
|
||||
{
|
||||
if (d == null) return;
|
||||
lock (d.SyncStatus)
|
||||
{
|
||||
d.Canceled = true;
|
||||
d.Active = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将任务状态重置为 Waiting。
|
||||
/// 当 clearCarForChange=true 时,仅当状态为 Suspended 或 Waiting 且未处于放货阶段时,
|
||||
/// 才会清空 UsingCar 并返回 true;否则返回 false。
|
||||
/// </summary>
|
||||
private static bool MarkDeliveryWaiting(Delivery d, bool clearCarForChange)
|
||||
{
|
||||
if (d == null) return false;
|
||||
lock (d.SyncStatus)
|
||||
{
|
||||
var status = d.GetStatus();
|
||||
if (clearCarForChange)
|
||||
{
|
||||
if ((status is not DeliveryStatus.Suspended and not DeliveryStatus.Waiting) || d.Putting)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
d.UsingCar = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
d.SkipFetch = d.Putting;
|
||||
}
|
||||
|
||||
d.Active = false;
|
||||
d.Finished = false;
|
||||
d.Error = false;
|
||||
d.Canceled = false;
|
||||
d.Terminated = false;
|
||||
d.Suspended = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string[] GetDisplayContent(Delivery dd)
|
||||
{
|
||||
var srcName =SimpleLib.GetSite(dd.Src).name;
|
||||
var dstName =SimpleLib.GetSite(dd.Dst).name;
|
||||
var now = DateTime.Now;
|
||||
var usingCar = dd.UsingCar == null ? string.Empty : dd.UsingCar.name;
|
||||
return
|
||||
[
|
||||
$"{dd.Id}",
|
||||
$"{usingCar}",
|
||||
$"{dd.Src}-{srcName}",
|
||||
$"{dd.Dst}-{dstName}",
|
||||
$"{dd.GetStatus()}",
|
||||
$"{dd.CreateTime:yyyy-mm-dd HH:mm:ss:fff}",
|
||||
$"{dd.StartTime:yyyy-mm-dd HH:mm:ss:fff}",
|
||||
$"{dd.FinishTime:yyyy-mm-dd HH:mm:ss:fff}",
|
||||
|
||||
$"{dd.Priority}",
|
||||
$"{((now - dd.CreateTime).TotalMinutes > OverdueMinutesThreshold ? 1 : 0)}",
|
||||
$"{dd.Id}"
|
||||
];
|
||||
}
|
||||
|
||||
private void TaskFlush()
|
||||
{
|
||||
_listDeliveries.Clear();
|
||||
try
|
||||
{
|
||||
foreach (var cdm in SimpleProject.proj.Missions.OfType<ChainedDeliveryMission>())
|
||||
foreach (var dd in cdm.GetDeliveries(checkBox1.Checked, checkBox2.Checked,checkBox2.Checked,checkBox2.Checked))
|
||||
_listDeliveries.Add(GetDisplayContent(dd));
|
||||
|
||||
if (_listDeliveries.Count > 0)
|
||||
{
|
||||
var len = _listDeliveries[0].Length;
|
||||
if (len > 0) _listDeliveries = _listDeliveries.OrderByDescending(p => int.Parse(p[len - 2])).ToList();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Post($"TaskFlush 异常: {ExceptionFormatter.FormatEx(ex)}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void timer1_Tick(object sender, EventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
TaskFlush();
|
||||
currentTaskList.VirtualListSize = _listDeliveries.Count;
|
||||
currentTaskList.Invalidate();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Post($"timer1_Tick 异常: {ExceptionFormatter.FormatEx(ex)}");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void currentTaskList_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
var n = e.ItemIndex;
|
||||
e.Item = new ListViewItem(_listDeliveries[n]);
|
||||
if (_listDeliveries[n].Length > DisplayColumnIndexOverdueFlag && _listDeliveries[n][DisplayColumnIndexOverdueFlag] == "1")
|
||||
e.Item.ForeColor = Color.Red;
|
||||
if (_selectedIndicesCache.Contains(n))
|
||||
e.Item.BackColor = SelectedRowBackColor;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
e.Item = new ListViewItem(["", "", "", "", "", "", "", "", ""]);
|
||||
}
|
||||
}
|
||||
|
||||
private void currentTaskList_MouseClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.Button != MouseButtons.Right) return;
|
||||
_item = currentTaskList.GetItemAt(e.X, e.Y);
|
||||
}
|
||||
|
||||
private void ResendClick(object sender, EventArgs e)
|
||||
{
|
||||
if (_item == null) return;
|
||||
string taskCode = _item.Text;
|
||||
try
|
||||
{
|
||||
var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().FirstOrDefault();
|
||||
if (cdm == null) return;
|
||||
var d = cdm.GetDeliveries(true, true, true, true)
|
||||
.OfType<TransportDelivery>()
|
||||
.FirstOrDefault(s => s.Id == taskCode);
|
||||
if (d == null)
|
||||
{
|
||||
MessageBox.Show("列表中不存在目标任务", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
var ms = MessageBox.Show($"是否重发任务--{taskCode}", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
|
||||
if (ms != System.Windows.Forms.DialogResult.OK) return;
|
||||
if (!MarkDeliveryWaiting(d, clearCarForChange: false))
|
||||
{
|
||||
MessageBox.Show("重发任务失败:当前状态不允许重发", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 状态已改为 Waiting,持久化
|
||||
cdm.PersistDelivery(d);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
MessageBox.Show("列表中不存在目标任务", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void CancelClick(object sender, EventArgs e)
|
||||
{
|
||||
if (_item == null) return;
|
||||
string str = _item.Text;
|
||||
try
|
||||
{
|
||||
var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().FirstOrDefault();
|
||||
if (cdm == null) return;
|
||||
var d = cdm.GetDeliveries(true, true, true, true)
|
||||
.OfType<TransportDelivery>()
|
||||
.FirstOrDefault(s => s.Id == str);
|
||||
if (d == null)
|
||||
{
|
||||
MessageBox.Show("列表中不存在目标任务", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
var ms = MessageBox.Show($"是否结束任务--{str}", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
|
||||
if (ms != System.Windows.Forms.DialogResult.OK || d.IsFinished()) return;
|
||||
|
||||
// 1) 状态上将任务标记为已取消
|
||||
MarkDeliveryCanceled(d);
|
||||
|
||||
// 2) 若小车当前正在执行该任务,则下发 reset 指令
|
||||
bool excutingTask = d.UsingCar != null && d.UsingCar.tags.IsEqual("taskCode", d.TaskId);
|
||||
if (excutingTask && d.UsingCar != null
|
||||
&& (d.UsingCar.tags?.Contains("occupied") == true || (d.UsingCar.status?.pendingLocks?.Length ?? 0) != 0))
|
||||
{
|
||||
_ = SharedHttpClient.GetStringAsync($"http://{d.UsingCar.address}:8008/reset");
|
||||
Diagnosis.Log($"手动结束任务;{d.TaskId}", "task", true);
|
||||
}
|
||||
|
||||
// 3) 持久化已取消状态
|
||||
cdm.PersistDelivery(d);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Post($"结束任务 {str} 异常: {ExceptionFormatter.FormatEx(ex)}");
|
||||
}
|
||||
}
|
||||
|
||||
private void ChangeCarResendClick(object sender, EventArgs e)
|
||||
{
|
||||
if (_item == null) return;
|
||||
string taskCode = _item.Text;
|
||||
try
|
||||
{
|
||||
var cdm = SimpleProject.proj.Missions.OfType<TransportMission>().FirstOrDefault();
|
||||
if (cdm == null) return;
|
||||
var d = cdm.GetDeliveries(true, true, true, true)
|
||||
.OfType<TransportDelivery>()
|
||||
.FirstOrDefault(s => s.Id == taskCode);
|
||||
if (d == null)
|
||||
{
|
||||
MessageBox.Show("列表中不存在目标任务", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
var ms = MessageBox.Show($"是否换车重发任务--{taskCode}", "提示", MessageBoxButtons.OKCancel, MessageBoxIcon.Question);
|
||||
if (ms != System.Windows.Forms.DialogResult.OK) return;
|
||||
|
||||
if (!MarkDeliveryWaiting(d, clearCarForChange: true))
|
||||
{
|
||||
MessageBox.Show("换车重发失败:仅当任务状态为 Suspended 或 Waiting 且未处于放货阶段时才允许换车重发", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// 状态已改为 Waiting 且 UsingCar 已清空,持久化
|
||||
cdm.PersistDelivery(d);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Diagnosis.Post($"换车重发任务 {taskCode} 异常: {ExceptionFormatter.FormatEx(ex)}");
|
||||
MessageBox.Show("换车重发任务异常,请查看日志", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
||||
}
|
||||
}
|
||||
|
||||
private void DeliveryViewer_FormClosing(object sender, FormClosingEventArgs e)
|
||||
{
|
||||
if (e.CloseReason == CloseReason.UserClosing)
|
||||
{
|
||||
e.Cancel = true;
|
||||
this.Visible = false;
|
||||
timer1.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void SetVisibleCore(bool value)
|
||||
{
|
||||
if (!IsHandleCreated && value)
|
||||
CreateHandle();
|
||||
bool wasVisible = Visible;
|
||||
base.SetVisibleCore(value);
|
||||
if (value && !wasVisible)
|
||||
timer1.Start();
|
||||
}
|
||||
|
||||
private void currentTaskList_SelectedIndexChanged(object sender, EventArgs e)
|
||||
{
|
||||
_selectedIndicesCache.Clear();
|
||||
foreach (int i in currentTaskList.SelectedIndices)
|
||||
_selectedIndicesCache.Add(i);
|
||||
this.BeginInvoke(() => currentTaskList.Invalidate());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user