@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
@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 async Task OpenImportDialog() { var dialog = await DialogService.ShowAsync( "Import Order JSON", new DialogOptions { FullWidth = true, MaxWidth = MaxWidth.Large }); var result = await dialog.Result; if (!result.Canceled && result.Data is OrderMessage imported) { Order = imported; RebuildOrderJson(); StateHasChanged(); } } 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.MarkExpanded(); // ✅ 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() }); node.Actions = list.ToArray(); } void RemoveAction(Node node, VDA5050.InstantAction.Action action) { node.Actions = node.Actions?.Where(a => a != action).ToArray() ?? Array.Empty(); } void AddActionParameter(VDA5050.InstantAction.Action act) { var list = (act.ActionParameters ?? Array.Empty()).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(); } // ================= 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(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 { { x => x.Node, node } }; var options = new DialogOptions { CloseButton = true, FullWidth = true, MaxWidth = MaxWidth.Large }; var dialog = await DialogService.ShowAsync( $"Edit Node: {node.NodeId}", parameters, options); await dialog.Result; OnOrderChanged(); // 🔥 cập nhật JSON sau dialog } }