268 lines
8.0 KiB
Plaintext
268 lines
8.0 KiB
Plaintext
@page "/robot-order"
|
|
|
|
@attribute [Authorize]
|
|
@rendermode InteractiveWebAssemblyNoPrerender
|
|
|
|
@using System.Text.Json
|
|
@using System.Text.Json.Serialization
|
|
|
|
@inject IJSRuntime JS
|
|
@inject IDialogService DialogService
|
|
@inject HttpClient Http
|
|
|
|
<MudMainContent Class="pa-0 ma-0">
|
|
<div style="height:100vh; overflow:hidden;">
|
|
<MudContainer MaxWidth="MaxWidth.False"
|
|
Class="pa-4"
|
|
Style="max-width:100%; height:100%; display:flex; flex-direction:column;">
|
|
<MudGrid Spacing="4" Class="flex-grow-1" Style="overflow:hidden;">
|
|
|
|
<!-- ================= LEFT ================= -->
|
|
<MudItem xs="12" md="7" Class="d-flex flex-column h-100" Style="gap:16px;">
|
|
<MudGrid Spacing="4" Class="flex-grow-1" Style="overflow:hidden;">
|
|
|
|
<MudItem xs="12" md="6" Class="h-100">
|
|
<NodesPanel Order="Order"
|
|
OnAddNode="AddNode"
|
|
OnRemoveNode="RemoveNode"
|
|
OnEditNode="OpenEditNodeDialog"
|
|
OnAddAction="AddAction"
|
|
OnRemoveAction="@(w => RemoveAction(w.Node, w.Action))"
|
|
OnAddActionParameter="AddActionParameter"
|
|
OnRemoveActionParameter="@(w => RemoveActionParameter(w.Action, w.Parameter))"
|
|
OnOrderChanged="OnOrderChanged" />
|
|
</MudItem>
|
|
|
|
<MudItem xs="12" md="6" Class="h-100">
|
|
<EdgesPanel Order="Order"
|
|
OnAddEdge="AddEdge"
|
|
OnRemoveEdge="RemoveEdge"
|
|
OnApplyCurve="ApplyCurve"
|
|
OnOrderChanged="OnOrderChanged" />
|
|
</MudItem>
|
|
|
|
</MudGrid>
|
|
</MudItem>
|
|
|
|
<!-- ================= RIGHT ================= -->
|
|
<MudItem xs="12" md="5" Class="h-100">
|
|
<JsonOutputPanel OrderJson="@OrderJson"
|
|
Copied="@copied"
|
|
SendSuccess="@sendSuccess"
|
|
OnCopy="CopyJsonToClipboard"
|
|
OnSend="SendOrderToServer" />
|
|
|
|
</MudItem>
|
|
|
|
</MudGrid>
|
|
</MudContainer>
|
|
</div>
|
|
</MudMainContent>
|
|
|
|
@code {
|
|
// ================= STATE =================
|
|
private OrderMessage Order { get; set; } = new();
|
|
private string OrderJson = ""; // 🔥 CACHE JSON (QUAN TRỌNG)
|
|
private bool copied;
|
|
private bool? sendSuccess;
|
|
private bool sending;
|
|
private CancellationTokenSource? _copyCts;
|
|
|
|
// ================= INIT =================
|
|
protected override void OnInitialized()
|
|
{
|
|
RebuildOrderJson();
|
|
}
|
|
|
|
// ================= CORE FIX =================
|
|
private void RebuildOrderJson()
|
|
{
|
|
OrderJson = JsonSerializer.Serialize(
|
|
Order.ToSchemaObject(),
|
|
new JsonSerializerOptions
|
|
{
|
|
WriteIndented = true,
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
});
|
|
}
|
|
|
|
private void OnOrderChanged()
|
|
{
|
|
RebuildOrderJson(); // 🔥 JSON luôn rebuild
|
|
StateHasChanged(); // 🔥 ép render
|
|
}
|
|
|
|
// ================= NODE =================
|
|
void AddNode()
|
|
{
|
|
Order.Nodes.Add(new Node
|
|
{
|
|
NodeId = $"NODE_{Order.Nodes.Count + 1}",
|
|
SequenceId = Order.Nodes.Count,
|
|
Released = true,
|
|
NodePosition = new VDA5050.Order.NodePosition { MapId = "MAP_01" }
|
|
});
|
|
}
|
|
|
|
void RemoveNode(Node node)
|
|
{
|
|
Order.Nodes.Remove(node);
|
|
Order.Edges.RemoveAll(e => e.StartNodeId == node.NodeId || e.EndNodeId == node.NodeId);
|
|
ResequenceNodes();
|
|
}
|
|
|
|
void ResequenceNodes()
|
|
{
|
|
for (int i = 0; i < Order.Nodes.Count; i++)
|
|
Order.Nodes[i].SequenceId = i;
|
|
}
|
|
|
|
// ================= EDGE =================
|
|
void AddEdge()
|
|
{
|
|
if (Order.Nodes.Count == 0)
|
|
return;
|
|
|
|
var start = Order.Nodes[0].NodeId;
|
|
var end = Order.Nodes.Count > 1
|
|
? Order.Nodes[1].NodeId
|
|
: start; // 👈 1 node thì start = end
|
|
|
|
Order.Edges.Add(new UiEdge
|
|
{
|
|
EdgeId = $"EDGE_{Order.Edges.Count + 1}",
|
|
StartNodeId = start,
|
|
EndNodeId = end
|
|
});
|
|
}
|
|
|
|
|
|
void RemoveEdge(UiEdge edge)
|
|
{
|
|
Order.Edges.Remove(edge);
|
|
}
|
|
|
|
void ApplyCurve(UiEdge edge)
|
|
{
|
|
if (edge.Radius <= 0 || edge.Expanded) return;
|
|
|
|
var startNode = Order.Nodes.First(n => n.NodeId == edge.StartNodeId);
|
|
var newNode = OrderMessage.CreateCurveNode(startNode, edge);
|
|
|
|
Order.Nodes.Add(newNode);
|
|
edge.EndNodeId = newNode.NodeId;
|
|
edge.Expanded = true;
|
|
|
|
ResequenceNodes();
|
|
}
|
|
|
|
// ================= ACTION =================
|
|
void AddAction(Node node)
|
|
{
|
|
var list = node.Actions?.ToList() ?? new();
|
|
list.Add(new VDA5050.InstantAction.Action
|
|
{
|
|
ActionId = Guid.NewGuid().ToString(),
|
|
ActionType = ActionType.startPause.ToString(),
|
|
BlockingType = "NONE",
|
|
ActionParameters = Array.Empty<ActionParameter>()
|
|
});
|
|
node.Actions = list.ToArray();
|
|
}
|
|
|
|
void RemoveAction(Node node, VDA5050.InstantAction.Action action)
|
|
{
|
|
node.Actions = node.Actions?.Where(a => a != action).ToArray()
|
|
?? Array.Empty<VDA5050.InstantAction.Action>();
|
|
}
|
|
|
|
void AddActionParameter(VDA5050.InstantAction.Action act)
|
|
{
|
|
var list = (act.ActionParameters ?? Array.Empty<ActionParameter>()).ToList();
|
|
list.Add(new UiActionParameter());
|
|
act.ActionParameters = list.ToArray();
|
|
}
|
|
|
|
void RemoveActionParameter(VDA5050.InstantAction.Action act, ActionParameter param)
|
|
{
|
|
act.ActionParameters =
|
|
act.ActionParameters?.Where(p => p != param).ToArray()
|
|
?? Array.Empty<ActionParameter>();
|
|
}
|
|
|
|
// ================= SEND / COPY =================
|
|
async Task SendOrderToServer()
|
|
{
|
|
// reset trạng thái trước khi gửi
|
|
sendSuccess = null;
|
|
StateHasChanged();
|
|
|
|
try
|
|
{
|
|
var response = await Http.PostAsJsonAsync(
|
|
"/api/order",
|
|
JsonSerializer.Deserialize<JsonElement>(OrderJson)
|
|
);
|
|
|
|
sendSuccess = response.IsSuccessStatusCode;
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
sendSuccess = false;
|
|
}
|
|
|
|
StateHasChanged();
|
|
|
|
// 🔥 AUTO RESET SAU 2 GIÂY
|
|
_ = Task.Run(async () =>
|
|
{
|
|
await Task.Delay(2000);
|
|
|
|
// quay về trạng thái Send
|
|
sendSuccess = null;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
});
|
|
}
|
|
|
|
|
|
|
|
async Task CopyJsonToClipboard()
|
|
{
|
|
_copyCts?.Cancel();
|
|
_copyCts = new();
|
|
|
|
await JS.InvokeVoidAsync("navigator.clipboard.writeText", OrderJson);
|
|
|
|
copied = true;
|
|
StateHasChanged();
|
|
|
|
try { await Task.Delay(1500, _copyCts.Token); } catch { }
|
|
copied = false;
|
|
StateHasChanged();
|
|
}
|
|
|
|
// ================= DIALOG =================
|
|
async Task OpenEditNodeDialog(Node node)
|
|
{
|
|
var parameters = new DialogParameters<EditNodeDialog>
|
|
{
|
|
{ x => x.Node, node }
|
|
};
|
|
|
|
var options = new DialogOptions
|
|
{
|
|
CloseButton = true,
|
|
FullWidth = true,
|
|
MaxWidth = MaxWidth.Large
|
|
};
|
|
|
|
var dialog = await DialogService.ShowAsync<EditNodeDialog>(
|
|
$"Edit Node: {node.NodeId}", parameters, options);
|
|
|
|
await dialog.Result;
|
|
OnOrderChanged(); // 🔥 cập nhật JSON sau dialog
|
|
}
|
|
}
|