BinPickerViewModel.cs 4.2 KB
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using IndustrialControl.Services;
using IndustrialControl.Pages;
using System.Collections.ObjectModel;

namespace IndustrialControl.ViewModels;

public partial class BinPickerViewModel : ObservableObject
{
    public ObservableCollection<BinTreeNode> Tree { get; } = new();
    public ObservableCollection<BinInfo> AllBins { get; } = new();
    public ObservableCollection<BinTreeNode> VisibleTree { get; } = new();

    private Func<BinInfo, Task>? _onPicked;
    private Func<Task>? _onCanceled;

    public void SetCloseHandlers(Func<BinInfo, Task> onPicked, Func<Task> onCanceled)
    {
        _onPicked = onPicked;
        _onCanceled = onCanceled;
    }

    public void Initialize(string? preselectBinCode)
    {
        BuildMockTree();
        BuildMockBins();
        // 根/区域默认展开,这样有下级
        foreach (var root in Tree) root.IsExpanded = true;
        RebuildVisible(); // ★ 初始化可见列表
    }

    // 展开/收起
    [RelayCommand]
    private void Toggle(BinTreeNode node)
    {
        node.IsExpanded = !node.IsExpanded;
        RebuildVisible(); // ★ 每次切换都重建
    }

    // 选中树节点:Level==2 表示“货架” → 弹出库位列表;否则仅展开
    [RelayCommand]
    private async Task SelectNode(BinTreeNode node)
    {
        if (node.Level != 2)
        {
            node.IsExpanded = !node.IsExpanded;
            RebuildVisible();
            return;
        }

        var list = AllBins.Where(b => b.ShelfPath.Equals(node.Path, StringComparison.OrdinalIgnoreCase)).ToList();

        // ★ 让 BinListPage 在选择后连关自己和父页
        var picked = await BinListPage.ShowAsync(list, closeParent: true);
        if (picked == null) return;

        // 仍把结果回传,完成 BinPickerPage.ShowAsync 的 Task
        if (_onPicked != null)
            await _onPicked.Invoke(picked);
    }



    // ★ 递归把“当前应可见”的节点平铺出来
    private void RebuildVisible()
    {
        VisibleTree.Clear();
        foreach (var root in Tree)
            AddVisible(root);
    }

    private void AddVisible(BinTreeNode n)
    {
        VisibleTree.Add(n);
        if (!n.IsExpanded) return;
        foreach (var c in n.Children)
            AddVisible(c);
    }

    public Task CancelAsync() => _onCanceled?.Invoke() ?? Task.CompletedTask;

    // ====== Mock(保持不变,只展示必要部分)======
    private void BuildMockTree()
    {
        Tree.Clear();
        var semi = new BinTreeNode("半成品库", 0, "半成品库") { IsExpanded = true };
        var semiAreaA = new BinTreeNode("区域A", 1, "半成品库/区域A") { IsExpanded = true };
        semiAreaA.Children.Add(new BinTreeNode("货架A1", 2, "半成品库/区域A/货架A1"));
        semi.Children.Add(semiAreaA);
        Tree.Add(semi);
    }

    private void BuildMockBins()
    {
        AllBins.Clear();
        AllBins.Add(new BinInfo
        {
            BinCode = "A1-101",
            WarehouseName = "半成品库",
            WarehouseCode = "FBCPK",
            Layer = "货架层A1-1",
            Shelf = "货架A1",
            Zone = "区域A",
            Status = "-",
            ShelfPath = "半成品库/区域A/货架A1"
        });
        AllBins.Add(new BinInfo
        {
            BinCode = "A1-102",
            WarehouseName = "半成品库",
            WarehouseCode = "FBCPK",
            Layer = "货架层A1-1",
            Shelf = "货架A1",
            Zone = "区域A",
            Status = "-",
            ShelfPath = "半成品库/区域A/货架A1"
        });
    }
}

// 树节点
public partial class BinTreeNode : ObservableObject
{
    public BinTreeNode(string name, int level, string path)
    { Name = name; Level = level; Path = path; Indent = new Thickness(level * 16, 0, 0, 0); }

    [ObservableProperty] private string name;
    [ObservableProperty] private bool isExpanded;
    public int Level { get; }
    public string Path { get; }
    public Thickness Indent { get; }
    public ObservableCollection<BinTreeNode> Children { get; } = new();
    public string ToggleIcon => Children.Count == 0 ? "" : (IsExpanded ? "▾" : "▸");
}