InboundMaterialViewModel.cs
10.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using IndustrialControl.Services;
using System.Threading.Tasks;
namespace IndustrialControl.ViewModels
{
public partial class InboundMaterialViewModel : ObservableObject
{
[ObservableProperty] private string? scanCode;
private readonly IWarehouseDataService _warehouseSvc;
public ObservableCollection<string> AvailableBins { get; set; } = new ObservableCollection<string>
{
"CK1_A201",
"CK1_A202",
"CK1_A203",
"CK1_A204"
};
public ObservableCollection<OutScannedItem> ScannedList { get; }
public ObservableCollection<PendingItem> PendingList { get; set; }
[ObservableProperty]
private OutScannedItem? selectedScanItem;
public InboundMaterialViewModel(IWarehouseDataService warehouseSvc)
{
_warehouseSvc = warehouseSvc;
// 初始化命令
ShowPendingCommand = new RelayCommand(() => SwitchTab(true));
ShowScannedCommand = new RelayCommand(() => SwitchTab(false));
ConfirmCommand = new AsyncRelayCommand(ConfirmInboundAsync);
// 默认显示待入库明细
IsPendingVisible = true;
IsScannedVisible = false;
// 测试数据(上线可去掉)
PendingList = new ObservableCollection<PendingItem>
{
new PendingItem { Name="物料1", Spec="XXX", PendingQty=100, Bin="CK1_A201", ScannedQty=80 },
new PendingItem { Name="物料2", Spec="YYY", PendingQty=50, Bin="CK1_A202", ScannedQty=0 }
};
ScannedList = new ObservableCollection<OutScannedItem>
{
new OutScannedItem { IsSelected=false, Barcode="FSC2025060300001", Name="物料1", Spec="XXX", Bin="CK1_A201", Qty=1 },
new OutScannedItem { IsSelected=false, Barcode="FSC2025060300002", Name="物料1", Spec="XXX", Bin="请选择", Qty=1 }
};
}
// 基础信息
[ObservableProperty] private string orderNo;
[ObservableProperty] private string linkedDeliveryNo;
[ObservableProperty] private string linkedPurchaseNo;
[ObservableProperty] private string supplier;
// Tab 显示控制
[ObservableProperty] private bool isPendingVisible;
[ObservableProperty] private bool isScannedVisible;
// Tab 按钮颜色
[ObservableProperty] private string pendingTabColor = "#E6F2FF";
[ObservableProperty] private string scannedTabColor = "White";
[ObservableProperty] private string pendingTextColor = "#007BFF";
[ObservableProperty] private string scannedTextColor = "#333333";
// 列表数据
// 命令
public IRelayCommand ShowPendingCommand { get; }
public IRelayCommand ShowScannedCommand { get; }
public IAsyncRelayCommand ConfirmCommand { get; }
/// <summary>
/// 切换 Tab
/// </summary>
private void SwitchTab(bool showPending)
{
IsPendingVisible = showPending;
IsScannedVisible = !showPending;
if (showPending)
{
PendingTabColor = "#E6F2FF";
ScannedTabColor = "White";
PendingTextColor = "#007BFF";
ScannedTextColor = "#333333";
}
else
{
PendingTabColor = "White";
ScannedTabColor = "#E6F2FF";
PendingTextColor = "#333333";
ScannedTextColor = "#007BFF";
}
}
/// <summary>
/// 清空扫描记录
/// </summary>
public void ClearScan()
{
ScannedList.Clear();
}
/// <summary>
/// 清空所有数据
/// </summary>
public void ClearAll()
{
OrderNo = string.Empty;
LinkedDeliveryNo = string.Empty;
LinkedPurchaseNo = string.Empty;
Supplier = string.Empty;
PendingList.Clear();
ScannedList.Clear();
}
[RelayCommand]
private async Task PassScan() // 绑定到 XAML 的 PassScanCommand
{
var selected = ScannedList.Where(x => x.IsSelected).ToList();
if (selected.Count == 0)
{
await ShowTip("请先勾选一行记录。");
return;
}
if (selected.Count > 1)
{
await ShowTip("一次只能操作一行,请只勾选一行。");
return;
}
var row = selected[0];
row.Qty += 1;
row.Qty -= 1;
// 确保本行已变绿(如果你的行颜色基于 IsSelected)
if (!row.IsSelected) row.IsSelected = true;
SelectedScanItem = row;
}
[RelayCommand]
private async Task CancelScan() // 绑定到 XAML 的 CancelScanCommand
{
var selected = ScannedList.Where(x => x.IsSelected).ToList();
if (selected.Count == 0)
{
await ShowTip("请先勾选一行记录。");
return;
}
if (selected.Count > 1)
{
await ShowTip("一次只能操作一行,请只勾选一行。");
return;
}
var row = selected[0];
if (row.Qty <= 0)
{
await ShowTip("该行数量已为 0,无法再减少。");
return;
}
row.Qty -= 1;
// 如果希望数量减到 0 时取消高亮,可打开下一行
// if (row.Qty == 0) row.IsSelected = false;
}
public async Task HandleScannedAsync(string data, string symbology)
{
// TODO: 你的规则(判断是订单号/物料码/包装码等)
// 然后:查询接口 / 加入列表 / 自动提交
await Task.CompletedTask;
}
private Task ShowTip(string message) =>
Shell.Current?.DisplayAlert("提示", message, "确定") ?? Task.CompletedTask;
/// <summary>
/// 确认入库逻辑
/// </summary>
public async Task<bool> ConfirmInboundAsync()
{
if (string.IsNullOrWhiteSpace(OrderNo))
return false;
var result = await _warehouseSvc.ConfirmInboundAsync(OrderNo,
ScannedList.Select(x => new ScanItem(0, x.Barcode, x.Bin, x.Qty)));
return result.Succeeded;
}
public async Task LoadOrderAsync(string orderNo)
{
// 0) 清空旧数据
ClearAll();
// 1) 基础信息
var order = await _warehouseSvc.GetInboundOrderAsync(orderNo);
OrderNo = order.OrderNo;
Supplier = order.Supplier ?? string.Empty;
LinkedDeliveryNo = order.LinkedNo ?? string.Empty; // 到货/交货单
LinkedPurchaseNo = order is { } ? LinkedPurchaseNo : ""; // 你没有就留空
// 2) 预入库库位:从接口取(先 mock),用于行内 Picker
// (你已经在 IWarehouseDataService 里加了 ListInboundBinsAsync)
try
{
var bins = await _warehouseSvc.ListInboundBinsAsync(orderNo);
AvailableBins.Clear();
foreach (var b in bins) AvailableBins.Add(b);
}
catch
{
// 兜底:本地 mock,避免空集合导致 Picker 无选项
AvailableBins.Clear();
foreach (var b in new[] { "CK1_A201", "CK1_A202", "CK1_A203", "CK1_A204" })
AvailableBins.Add(b);
}
var defaultBin = AvailableBins.FirstOrDefault() ?? "CK1_A201";
// 3) 待入库明细:如果暂时没有后端接口,这里先 mock 多行,便于 UI 联调
PendingList.Clear();
// 你原来只加了 1 行,这里多给两行方便测试
PendingList.Add(new PendingItem { Name = "物料X", Spec = "型号X", PendingQty = order.ExpectedQty, Bin = defaultBin, ScannedQty = 0 });
PendingList.Add(new PendingItem { Name = "物料Y", Spec = "型号Y", PendingQty = Math.Max(10, order.ExpectedQty / 2), Bin = defaultBin, ScannedQty = 0 });
PendingList.Add(new PendingItem { Name = "物料Z", Spec = "型号Z", PendingQty = 8, Bin = defaultBin, ScannedQty = 0 });
// 4) 扫描明细初始化(为空即可;也可以放 1~2 条便于测试)
ScannedList.Clear();
// 可选:放两条测试数据,验证“库位下拉/数量可编辑”
ScannedList.Add(new OutScannedItem { IsSelected = false, Barcode = "FSC2025060300001", Name = "物料X", Spec = "型号X", Bin = defaultBin, Qty = 1 });
ScannedList.Add(new OutScannedItem { IsSelected = false, Barcode = "FSC2025060300002", Name = "物料Y", Spec = "型号Y", Bin = defaultBin, Qty = 2 });
// 5) 默认展示“待入库明细”页签
SwitchTab(true);
}
public void SetItemBin(object row, string bin)
{
if (row is OutScannedItem item) { item.Bin = bin; return; }
var barcode = row?.GetType().GetProperty("Barcode")?.GetValue(row)?.ToString();
if (!string.IsNullOrWhiteSpace(barcode))
{
var target = ScannedList.FirstOrDefault(x => x.Barcode == barcode);
if (target != null) target.Bin = bin;
}
}
}
// 待入库明细模型
public class PendingItem
{
public string Name { get; set; }
public string Spec { get; set; }
public int PendingQty { get; set; }
public string Bin { get; set; }
public int ScannedQty { get; set; }
}
// 扫描明细模型
public partial class OutScannedItem : ObservableObject
{
[ObservableProperty] private bool isSelected;
[ObservableProperty] private string barcode;
[ObservableProperty] private string name;
[ObservableProperty] private string spec;
[ObservableProperty] private string bin;
[ObservableProperty] private int qty;
}
}