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();
/// 选中行的背景色
private static readonly Color SelectedRowBackColor = Color.FromArgb(220, 230, 250);
/// 缓存选中行索引,避免在 RetrieveVirtualItem 中访问 SelectedIndices 引发递归
private readonly HashSet _selectedIndicesCache = new HashSet();
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 _listDeliveries = new List();
/// 将任务标记为已取消(Canceled)。
private static void MarkDeliveryCanceled(Delivery d)
{
if (d == null) return;
lock (d.SyncStatus)
{
d.Canceled = true;
d.Active = false;
}
}
///
/// 将任务状态重置为 Waiting。
/// 当 clearCarForChange=true 时,仅当状态为 Suspended 或 Waiting 且未处于放货阶段时,
/// 才会清空 UsingCar 并返回 true;否则返回 false。
///
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())
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().FirstOrDefault();
if (cdm == null) return;
var d = cdm.GetDeliveries(true, true, true, true)
.OfType()
.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().FirstOrDefault();
if (cdm == null) return;
var d = cdm.GetDeliveries(true, true, true, true)
.OfType()
.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().FirstOrDefault();
if (cdm == null) return;
var d = cdm.GetDeliveries(true, true, true, true)
.OfType()
.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());
}
}
}