正在显示
19 个修改的文件
包含
794 行增加
和
32 行删除
| @@ -12,9 +12,12 @@ public partial class AppShell : Shell | @@ -12,9 +12,12 @@ public partial class AppShell : Shell | ||
| 12 | _sp = App.Services ?? throw new InvalidOperationException("Services not ready"); | 12 | _sp = App.Services ?? throw new InvalidOperationException("Services not ready"); |
| 13 | Routing.RegisterRoute(nameof(Pages.InboundMaterialSearchPage), typeof(Pages.InboundMaterialSearchPage)); | 13 | Routing.RegisterRoute(nameof(Pages.InboundMaterialSearchPage), typeof(Pages.InboundMaterialSearchPage)); |
| 14 | Routing.RegisterRoute(nameof(Pages.InboundMaterialPage), typeof(Pages.InboundMaterialPage)); | 14 | Routing.RegisterRoute(nameof(Pages.InboundMaterialPage), typeof(Pages.InboundMaterialPage)); |
| 15 | + Routing.RegisterRoute(nameof(Pages.InboundProductionSearchPage), typeof(Pages.InboundProductionSearchPage)); | ||
| 15 | Routing.RegisterRoute(nameof(Pages.InboundProductionPage), typeof(Pages.InboundProductionPage)); | 16 | Routing.RegisterRoute(nameof(Pages.InboundProductionPage), typeof(Pages.InboundProductionPage)); |
| 17 | + Routing.RegisterRoute(nameof(Pages.OutboundMaterialSearchPage), typeof(Pages.OutboundMaterialSearchPage)); | ||
| 16 | Routing.RegisterRoute(nameof(Pages.OutboundMaterialPage), typeof(Pages.OutboundMaterialPage)); | 18 | Routing.RegisterRoute(nameof(Pages.OutboundMaterialPage), typeof(Pages.OutboundMaterialPage)); |
| 17 | Routing.RegisterRoute(nameof(Pages.OutboundFinishedPage), typeof(Pages.OutboundFinishedPage)); | 19 | Routing.RegisterRoute(nameof(Pages.OutboundFinishedPage), typeof(Pages.OutboundFinishedPage)); |
| 20 | + Routing.RegisterRoute(nameof(Pages.OutboundFinishedSearchPage), typeof(Pages.OutboundFinishedSearchPage)); | ||
| 18 | BuildTabs(authed); | 21 | BuildTabs(authed); |
| 19 | } | 22 | } |
| 20 | 23 |
| @@ -44,7 +44,7 @@ | @@ -44,7 +44,7 @@ | ||
| 44 | <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> | 44 | <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> |
| 45 | <AndroidLinkMode>None</AndroidLinkMode> | 45 | <AndroidLinkMode>None</AndroidLinkMode> |
| 46 | <!-- 旧设备是32位ARM,强制只打 v7a,避免64位/不匹配ABI引起崩溃 --> | 46 | <!-- 旧设备是32位ARM,强制只打 v7a,避免64位/不匹配ABI引起崩溃 --> |
| 47 | - <AndroidSupportedAbis>armeabi-v7a</AndroidSupportedAbis> | 47 | + <AndroidSupportedAbis>armeabi-v7a;arm64-v8a;x86_64;x86</AndroidSupportedAbis> |
| 48 | </PropertyGroup> | 48 | </PropertyGroup> |
| 49 | 49 | ||
| 50 | <!-- Release 也先保守一点(便于现场调试稳定),确认稳定再逐步打开 --> | 50 | <!-- Release 也先保守一点(便于现场调试稳定),确认稳定再逐步打开 --> |
| @@ -53,7 +53,7 @@ | @@ -53,7 +53,7 @@ | ||
| 53 | <RunAOTCompilation>false</RunAOTCompilation> | 53 | <RunAOTCompilation>false</RunAOTCompilation> |
| 54 | <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> | 54 | <AndroidEnableProfiledAot>false</AndroidEnableProfiledAot> |
| 55 | <AndroidLinkMode>SdkOnly</AndroidLinkMode> | 55 | <AndroidLinkMode>SdkOnly</AndroidLinkMode> |
| 56 | - <AndroidSupportedAbis>armeabi-v7a</AndroidSupportedAbis> | 56 | + <AndroidSupportedAbis>armeabi-v7a;arm64-v8a</AndroidSupportedAbis> |
| 57 | </PropertyGroup> | 57 | </PropertyGroup> |
| 58 | 58 | ||
| 59 | <ItemGroup> | 59 | <ItemGroup> |
| @@ -88,6 +88,18 @@ | @@ -88,6 +88,18 @@ | ||
| 88 | </ItemGroup> | 88 | </ItemGroup> |
| 89 | 89 | ||
| 90 | <ItemGroup> | 90 | <ItemGroup> |
| 91 | + <Compile Update="Pages\OutboundMaterialSearchPage.xaml.cs"> | ||
| 92 | + <DependentUpon>OutboundMaterialSearchPage.xaml</DependentUpon> | ||
| 93 | + </Compile> | ||
| 94 | + <Compile Update="Pages\OutboundFinishedSearchPage.xaml.cs"> | ||
| 95 | + <DependentUpon>OutboundFinishedSearchPage.xaml</DependentUpon> | ||
| 96 | + </Compile> | ||
| 97 | + <Compile Update="Pages\InboundProductionSearchPage.xaml.cs"> | ||
| 98 | + <DependentUpon>InboundProductionSearchPage.xaml</DependentUpon> | ||
| 99 | + </Compile> | ||
| 100 | + </ItemGroup> | ||
| 101 | + | ||
| 102 | + <ItemGroup> | ||
| 91 | <MauiXaml Update="App.xaml"> | 103 | <MauiXaml Update="App.xaml"> |
| 92 | <Generator>MSBuild:Compile</Generator> | 104 | <Generator>MSBuild:Compile</Generator> |
| 93 | </MauiXaml> | 105 | </MauiXaml> |
| @@ -100,6 +112,15 @@ | @@ -100,6 +112,15 @@ | ||
| 100 | <MauiXaml Update="Pages\InboundMaterialPage.xaml"> | 112 | <MauiXaml Update="Pages\InboundMaterialPage.xaml"> |
| 101 | <Generator>MSBuild:Compile</Generator> | 113 | <Generator>MSBuild:Compile</Generator> |
| 102 | </MauiXaml> | 114 | </MauiXaml> |
| 115 | + <MauiXaml Update="Pages\OutboundMaterialSearchPage.xaml"> | ||
| 116 | + <Generator>MSBuild:Compile</Generator> | ||
| 117 | + </MauiXaml> | ||
| 118 | + <MauiXaml Update="Pages\OutboundFinishedSearchPage.xaml"> | ||
| 119 | + <Generator>MSBuild:Compile</Generator> | ||
| 120 | + </MauiXaml> | ||
| 121 | + <MauiXaml Update="Pages\InboundProductionSearchPage.xaml"> | ||
| 122 | + <Generator>MSBuild:Compile</Generator> | ||
| 123 | + </MauiXaml> | ||
| 103 | <MauiXaml Update="Pages\InboundMaterialSearchPage.xaml"> | 124 | <MauiXaml Update="Pages\InboundMaterialSearchPage.xaml"> |
| 104 | <Generator>MSBuild:Compile</Generator> | 125 | <Generator>MSBuild:Compile</Generator> |
| 105 | </MauiXaml> | 126 | </MauiXaml> |
| @@ -37,8 +37,11 @@ namespace IndustrialControl | @@ -37,8 +37,11 @@ namespace IndustrialControl | ||
| 37 | builder.Services.AddTransient<ViewModels.InboundMaterialSearchViewModel>(); | 37 | builder.Services.AddTransient<ViewModels.InboundMaterialSearchViewModel>(); |
| 38 | builder.Services.AddTransient<ViewModels.InboundMaterialViewModel>(); | 38 | builder.Services.AddTransient<ViewModels.InboundMaterialViewModel>(); |
| 39 | builder.Services.AddTransient<ViewModels.InboundProductionViewModel>(); | 39 | builder.Services.AddTransient<ViewModels.InboundProductionViewModel>(); |
| 40 | + builder.Services.AddTransient<ViewModels.InboundProductionSearchViewModel>(); | ||
| 40 | builder.Services.AddTransient<ViewModels.OutboundMaterialViewModel>(); | 41 | builder.Services.AddTransient<ViewModels.OutboundMaterialViewModel>(); |
| 42 | + builder.Services.AddTransient<ViewModels.OutboundMaterialSearchViewModel>(); | ||
| 41 | builder.Services.AddTransient<ViewModels.OutboundFinishedViewModel>(); | 43 | builder.Services.AddTransient<ViewModels.OutboundFinishedViewModel>(); |
| 44 | + builder.Services.AddTransient<ViewModels.OutboundFinishedSearchViewModel>(); | ||
| 42 | 45 | ||
| 43 | // ===== 注册 Pages(DI 创建)===== | 46 | // ===== 注册 Pages(DI 创建)===== |
| 44 | builder.Services.AddTransient<Pages.LoginPage>(); | 47 | builder.Services.AddTransient<Pages.LoginPage>(); |
| @@ -50,8 +53,11 @@ namespace IndustrialControl | @@ -50,8 +53,11 @@ namespace IndustrialControl | ||
| 50 | builder.Services.AddTransient<Pages.InboundMaterialSearchPage>(); | 53 | builder.Services.AddTransient<Pages.InboundMaterialSearchPage>(); |
| 51 | builder.Services.AddTransient<Pages.InboundMaterialPage>(); | 54 | builder.Services.AddTransient<Pages.InboundMaterialPage>(); |
| 52 | builder.Services.AddTransient<Pages.InboundProductionPage>(); | 55 | builder.Services.AddTransient<Pages.InboundProductionPage>(); |
| 56 | + builder.Services.AddTransient<Pages.InboundProductionSearchPage>(); | ||
| 53 | builder.Services.AddTransient<Pages.OutboundMaterialPage>(); | 57 | builder.Services.AddTransient<Pages.OutboundMaterialPage>(); |
| 58 | + builder.Services.AddTransient<Pages.OutboundMaterialSearchPage>(); | ||
| 54 | builder.Services.AddTransient<Pages.OutboundFinishedPage>(); | 59 | builder.Services.AddTransient<Pages.OutboundFinishedPage>(); |
| 60 | + builder.Services.AddTransient<Pages.OutboundFinishedSearchPage>(); | ||
| 55 | var app = builder.Build(); | 61 | var app = builder.Build(); |
| 56 | App.Services = app.Services; | 62 | App.Services = app.Services; |
| 57 | return app; | 63 | return app; |
| @@ -14,17 +14,17 @@ | @@ -14,17 +14,17 @@ | ||
| 14 | 14 | ||
| 15 | private async void OnInProd(object sender, EventArgs e) | 15 | private async void OnInProd(object sender, EventArgs e) |
| 16 | { | 16 | { |
| 17 | - await Shell.Current.GoToAsync(nameof(InboundProductionPage)); | 17 | + await Shell.Current.GoToAsync(nameof(InboundProductionSearchPage)); |
| 18 | } | 18 | } |
| 19 | 19 | ||
| 20 | private async void OnOutMat(object sender, EventArgs e) | 20 | private async void OnOutMat(object sender, EventArgs e) |
| 21 | { | 21 | { |
| 22 | - await Shell.Current.GoToAsync(nameof(OutboundMaterialPage)); | 22 | + await Shell.Current.GoToAsync(nameof(OutboundMaterialSearchPage)); |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | private async void OnOutFinished(object sender, EventArgs e) | 25 | private async void OnOutFinished(object sender, EventArgs e) |
| 26 | { | 26 | { |
| 27 | - await Shell.Current.GoToAsync(nameof(OutboundFinishedPage)); | 27 | + await Shell.Current.GoToAsync(nameof(OutboundFinishedSearchPage)); |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | // 新增:退出登录 | 30 | // 新增:退出登录 |
| @@ -193,8 +193,9 @@ | @@ -193,8 +193,9 @@ | ||
| 193 | 193 | ||
| 194 | <!-- 扫描通过 --> | 194 | <!-- 扫描通过 --> |
| 195 | <Grid BackgroundColor="#4CAF50" | 195 | <Grid BackgroundColor="#4CAF50" |
| 196 | - HorizontalOptions="Fill" | ||
| 197 | - VerticalOptions="Fill"> | 196 | + HorizontalOptions="Fill" |
| 197 | + VerticalOptions="Fill" | ||
| 198 | + HeightRequest="50"> | ||
| 198 | <Grid.GestureRecognizers> | 199 | <Grid.GestureRecognizers> |
| 199 | <TapGestureRecognizer Command="{Binding PassScanCommand}" /> | 200 | <TapGestureRecognizer Command="{Binding PassScanCommand}" /> |
| 200 | </Grid.GestureRecognizers> | 201 | </Grid.GestureRecognizers> |
| @@ -211,9 +212,10 @@ | @@ -211,9 +212,10 @@ | ||
| 211 | 212 | ||
| 212 | <!-- 取消扫描 --> | 213 | <!-- 取消扫描 --> |
| 213 | <Grid Grid.Column="1" | 214 | <Grid Grid.Column="1" |
| 214 | - BackgroundColor="#F44336" | ||
| 215 | - HorizontalOptions="Fill" | ||
| 216 | - VerticalOptions="Fill"> | 215 | + BackgroundColor="#F44336" |
| 216 | + HorizontalOptions="Fill" | ||
| 217 | + VerticalOptions="Fill" | ||
| 218 | + HeightRequest="50"> | ||
| 217 | <Grid.GestureRecognizers> | 219 | <Grid.GestureRecognizers> |
| 218 | <TapGestureRecognizer Command="{Binding CancelScanCommand}" /> | 220 | <TapGestureRecognizer Command="{Binding CancelScanCommand}" /> |
| 219 | </Grid.GestureRecognizers> | 221 | </Grid.GestureRecognizers> |
| @@ -230,9 +232,10 @@ | @@ -230,9 +232,10 @@ | ||
| 230 | 232 | ||
| 231 | <!-- 确认入库 --> | 233 | <!-- 确认入库 --> |
| 232 | <Grid Grid.Column="2" | 234 | <Grid Grid.Column="2" |
| 233 | - BackgroundColor="#2196F3" | ||
| 234 | - HorizontalOptions="Fill" | ||
| 235 | - VerticalOptions="Fill"> | 235 | + BackgroundColor="#2196F3" |
| 236 | + HorizontalOptions="Fill" | ||
| 237 | + VerticalOptions="Fill" | ||
| 238 | + HeightRequest="50"> | ||
| 236 | <Grid.GestureRecognizers> | 239 | <Grid.GestureRecognizers> |
| 237 | <TapGestureRecognizer Command="{Binding ConfirmCommand}" /> | 240 | <TapGestureRecognizer Command="{Binding ConfirmCommand}" /> |
| 238 | </Grid.GestureRecognizers> | 241 | </Grid.GestureRecognizers> |
| @@ -71,10 +71,6 @@ | @@ -71,10 +71,6 @@ | ||
| 71 | <Grid Grid.Row="2" ColumnDefinitions="*,Auto" Padding="0,8,0,0"> | 71 | <Grid Grid.Row="2" ColumnDefinitions="*,Auto" Padding="0,8,0,0"> |
| 72 | <Label Text="{Binding Orders.Count, StringFormat='共 {0} 条'}" | 72 | <Label Text="{Binding Orders.Count, StringFormat='共 {0} 条'}" |
| 73 | VerticalTextAlignment="Center" /> | 73 | VerticalTextAlignment="Center" /> |
| 74 | - <Button Grid.Column="1" | ||
| 75 | - Text="进入入库" | ||
| 76 | - Command="{Binding GoInboundCommand}" | ||
| 77 | - IsEnabled="{Binding SelectedOrder, Converter={StaticResource NullToBoolConverter}}"/> | ||
| 78 | </Grid> | 74 | </Grid> |
| 79 | </Grid> | 75 | </Grid> |
| 80 | </ContentPage> | 76 | </ContentPage> |
| @@ -17,7 +17,7 @@ | @@ -17,7 +17,7 @@ | ||
| 17 | <!-- 入库单/条码扫描 --> | 17 | <!-- 入库单/条码扫描 --> |
| 18 | <Grid Grid.Row="1" ColumnDefinitions="*,60" Padding="16,8"> | 18 | <Grid Grid.Row="1" ColumnDefinitions="*,60" Padding="16,8"> |
| 19 | <Entry x:Name="ScanEntry" | 19 | <Entry x:Name="ScanEntry" |
| 20 | - Placeholder="请扫描入库单/产品/包装条码" | 20 | + Placeholder="请扫描产品/包装条码" |
| 21 | FontSize="14" | 21 | FontSize="14" |
| 22 | VerticalOptions="Center" | 22 | VerticalOptions="Center" |
| 23 | BackgroundColor="White" | 23 | BackgroundColor="White" |
Pages/InboundProductionSearchPage.xaml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8" ?> | ||
| 2 | +<ContentPage x:Name="Page" | ||
| 3 | + xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| 4 | + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| 5 | + x:Class="IndustrialControl.Pages.InboundProductionSearchPage" | ||
| 6 | + xmlns:conv="clr-namespace:IndustrialControl.Converters" | ||
| 7 | + Title="仓储管理系统"> | ||
| 8 | + <ContentPage.Resources> | ||
| 9 | + <ResourceDictionary> | ||
| 10 | + <!-- 空/非空转布尔:非空 => true(按钮可用) --> | ||
| 11 | + <conv:NullToBoolConverter x:Key="NullToBoolConverter" /> | ||
| 12 | + </ResourceDictionary> | ||
| 13 | + </ContentPage.Resources> | ||
| 14 | + | ||
| 15 | + <Grid RowDefinitions="Auto,*,Auto" Padding="16" BackgroundColor="#F6F7FB"> | ||
| 16 | + | ||
| 17 | + <!-- 顶部:输入条件(第0行) --> | ||
| 18 | + <VerticalStackLayout Grid.Row="0" Spacing="10"> | ||
| 19 | + <Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto" ColumnSpacing="8" RowSpacing="8"> | ||
| 20 | + <Entry x:Name="OrderEntry" | ||
| 21 | + Grid.Row="0" Grid.Column="0" | ||
| 22 | + Placeholder="请输入入库单号/包裹条码" | ||
| 23 | + VerticalOptions="Center" | ||
| 24 | + BackgroundColor="White" | ||
| 25 | + Text="{Binding SearchOrderNo}" /> | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + <DatePicker Grid.Row="1" Grid.Column="0" | ||
| 29 | + Date="{Binding CreatedDate}" | ||
| 30 | + MinimumDate="2000-01-01" /> | ||
| 31 | + <Button Grid.Row="1" Grid.Column="1" | ||
| 32 | + Text="查询" | ||
| 33 | + Command="{Binding SearchCommand}" /> | ||
| 34 | + </Grid> | ||
| 35 | + </VerticalStackLayout> | ||
| 36 | + | ||
| 37 | + <!-- 中部:结果列表(第1行) --> | ||
| 38 | + <CollectionView Grid.Row="1" | ||
| 39 | + ItemsSource="{Binding Orders}" | ||
| 40 | + SelectionMode="Single" | ||
| 41 | + SelectionChanged="OnOrderSelected"> | ||
| 42 | + <CollectionView.ItemTemplate> | ||
| 43 | + <DataTemplate> | ||
| 44 | + <Frame Margin="0,8,0,0" Padding="12" HasShadow="True" CornerRadius="10"> | ||
| 45 | + <!-- ⭐ 点击整卡片触发命令 --> | ||
| 46 | + <Frame.GestureRecognizers> | ||
| 47 | + <TapGestureRecognizer | ||
| 48 | + Command="{Binding BindingContext.OpenItemCommand, Source={x:Reference Page}}" | ||
| 49 | + CommandParameter="{Binding .}" /> | ||
| 50 | + </Frame.GestureRecognizers> | ||
| 51 | + <Grid RowDefinitions="Auto,Auto,Auto,Auto" | ||
| 52 | + ColumnDefinitions="Auto,*" ColumnSpacing="8"> | ||
| 53 | + <Label Grid.Row="0" Grid.Column="0" Text="入库单号:" FontAttributes="Bold"/> | ||
| 54 | + <Label Grid.Row="0" Grid.Column="1" Text="{Binding OrderNo}"/> | ||
| 55 | + | ||
| 56 | + <Label Grid.Row="1" Grid.Column="0" Text="入库类型:" FontAttributes="Bold"/> | ||
| 57 | + <Label Grid.Row="1" Grid.Column="1" Text="{Binding InboundType}" /> | ||
| 58 | + | ||
| 59 | + <Label Grid.Row="2" Grid.Column="0" Text="供应商:" FontAttributes="Bold"/> | ||
| 60 | + <Label Grid.Row="2" Grid.Column="1" Text="{Binding Supplier}" /> | ||
| 61 | + | ||
| 62 | + <Label Grid.Row="3" Grid.Column="0" Text="创建日期:" FontAttributes="Bold"/> | ||
| 63 | + <Label Grid.Row="3" Grid.Column="1" Text="{Binding CreatedAt, StringFormat='{0:yyyy-M-d}'}"/> | ||
| 64 | + </Grid> | ||
| 65 | + </Frame> | ||
| 66 | + </DataTemplate> | ||
| 67 | + </CollectionView.ItemTemplate> | ||
| 68 | + </CollectionView> | ||
| 69 | + | ||
| 70 | + <!-- 底部:操作(第2行) --> | ||
| 71 | + <Grid Grid.Row="2" ColumnDefinitions="*,Auto" Padding="0,8,0,0"> | ||
| 72 | + <Label Text="{Binding Orders.Count, StringFormat='共 {0} 条'}" | ||
| 73 | + VerticalTextAlignment="Center" /> | ||
| 74 | + </Grid> | ||
| 75 | + </Grid> | ||
| 76 | +</ContentPage> |
Pages/InboundProductionSearchPage.xaml.cs
0 → 100644
| 1 | +using System.Threading; | ||
| 2 | +using IndustrialControl.Services; | ||
| 3 | +using IndustrialControl.ViewModels; | ||
| 4 | +namespace IndustrialControl.Pages; | ||
| 5 | +public partial class InboundProductionSearchPage : ContentPage | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | + private readonly ScanService _scanSvc; | ||
| 9 | + private readonly InboundProductionSearchViewModel _vm; | ||
| 10 | + public InboundProductionSearchPage(InboundProductionSearchViewModel vm, ScanService scanSvc) | ||
| 11 | + { | ||
| 12 | + _vm = vm; | ||
| 13 | + | ||
| 14 | + BindingContext = vm; | ||
| 15 | + _scanSvc = scanSvc; | ||
| 16 | + InitializeComponent(); | ||
| 17 | + // 可选:配置前后缀与防抖 | ||
| 18 | + _scanSvc.Prefix = null; // 例如 "}q" 之类的前缀;没有就留 null | ||
| 19 | + // _scanSvc.Suffix = "\n"; // 如果设备会附带换行,可去掉;没有就设 null | ||
| 20 | + //_scanSvc.DebounceMs = 250; | ||
| 21 | + _scanSvc.Suffix = null; // 先关掉 | ||
| 22 | + _scanSvc.DebounceMs = 0; // 先关掉 | ||
| 23 | + } | ||
| 24 | + protected override async void OnAppearing() | ||
| 25 | + { | ||
| 26 | + base.OnAppearing(); | ||
| 27 | + // 动态注册广播接收器(只在当前页面前台时生效) | ||
| 28 | + _scanSvc.Scanned += OnScanned; | ||
| 29 | + _scanSvc.StartListening(); | ||
| 30 | + //键盘输入 | ||
| 31 | + _scanSvc.Attach(OrderEntry); | ||
| 32 | + OrderEntry.Focus(); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /// <summary> | ||
| 36 | + /// 清空扫描记录 | ||
| 37 | + /// </summary> | ||
| 38 | + void OnClearClicked(object sender, EventArgs e) | ||
| 39 | + { | ||
| 40 | + OrderEntry.Text = string.Empty; | ||
| 41 | + OrderEntry.Focus(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + protected override void OnDisappearing() | ||
| 45 | + { | ||
| 46 | + // 退出页面即注销(防止多个程序/页面抢处理) | ||
| 47 | + _scanSvc.Scanned -= OnScanned; | ||
| 48 | + _scanSvc.StopListening(); | ||
| 49 | + | ||
| 50 | + base.OnDisappearing(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + private void OnScanned(string data, string type) | ||
| 54 | + { | ||
| 55 | + MainThread.BeginInvokeOnMainThread(async () => | ||
| 56 | + { | ||
| 57 | + // 常见处理:自动填入单号/条码并触发查询或加入明细 | ||
| 58 | + _vm.SearchOrderNo = data; | ||
| 59 | + }); | ||
| 60 | + } | ||
| 61 | + private async void OnOrderSelected(object sender, SelectionChangedEventArgs e) | ||
| 62 | + { | ||
| 63 | + var item = e.CurrentSelection?.FirstOrDefault() as InboundOrderSummary; | ||
| 64 | + if (item is null) return; | ||
| 65 | + | ||
| 66 | + // 二选一:A) 点选跳转到入库页 | ||
| 67 | + await Shell.Current.GoToAsync( | ||
| 68 | + $"{nameof(InboundMaterialPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 69 | + | ||
| 70 | + // 或 B) 只把单号写到输入框/VM(不跳转) | ||
| 71 | + // if (BindingContext is InboundMaterialSearchViewModel vm) vm.SearchOrderNo = item.OrderNo; | ||
| 72 | + | ||
| 73 | + ((CollectionView)sender).SelectedItem = null; // 清除选中高亮 | ||
| 74 | + } | ||
| 75 | +} |
Pages/OutboundFinishedSearchPage.xaml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8" ?> | ||
| 2 | +<ContentPage x:Name="Page" | ||
| 3 | + xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| 4 | + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| 5 | + x:Class="IndustrialControl.Pages.OutboundFinishedSearchPage" | ||
| 6 | + xmlns:conv="clr-namespace:IndustrialControl.Converters" | ||
| 7 | + Title="仓储管理系统"> | ||
| 8 | + <ContentPage.Resources> | ||
| 9 | + <ResourceDictionary> | ||
| 10 | + <!-- 空/非空转布尔:非空 => true(按钮可用) --> | ||
| 11 | + <conv:NullToBoolConverter x:Key="NullToBoolConverter" /> | ||
| 12 | + </ResourceDictionary> | ||
| 13 | + </ContentPage.Resources> | ||
| 14 | + | ||
| 15 | + <Grid RowDefinitions="Auto,*,Auto" Padding="16" BackgroundColor="#F6F7FB"> | ||
| 16 | + | ||
| 17 | + <!-- 顶部:输入条件(第0行) --> | ||
| 18 | + <VerticalStackLayout Grid.Row="0" Spacing="10"> | ||
| 19 | + <Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto" ColumnSpacing="8" RowSpacing="8"> | ||
| 20 | + <Entry x:Name="OrderEntry" | ||
| 21 | + Grid.Row="0" Grid.Column="0" | ||
| 22 | + Placeholder="请输入出库单条码" | ||
| 23 | + VerticalOptions="Center" | ||
| 24 | + BackgroundColor="White" | ||
| 25 | + Text="{Binding SearchOrderNo}" /> | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + <DatePicker Grid.Row="1" Grid.Column="0" | ||
| 29 | + Date="{Binding CreatedDate}" | ||
| 30 | + MinimumDate="2000-01-01" /> | ||
| 31 | + <Button Grid.Row="1" Grid.Column="1" | ||
| 32 | + Text="查询" | ||
| 33 | + Command="{Binding SearchCommand}" /> | ||
| 34 | + </Grid> | ||
| 35 | + </VerticalStackLayout> | ||
| 36 | + | ||
| 37 | + <!-- 中部:结果列表(第1行) --> | ||
| 38 | + <CollectionView Grid.Row="1" | ||
| 39 | + ItemsSource="{Binding Orders}" | ||
| 40 | + SelectionMode="Single" | ||
| 41 | + SelectionChanged="OnOrderSelected"> | ||
| 42 | + <CollectionView.ItemTemplate> | ||
| 43 | + <DataTemplate> | ||
| 44 | + <Frame Margin="0,8,0,0" Padding="12" HasShadow="True" CornerRadius="10"> | ||
| 45 | + <!-- ⭐ 点击整卡片触发命令 --> | ||
| 46 | + <Frame.GestureRecognizers> | ||
| 47 | + <TapGestureRecognizer | ||
| 48 | + Command="{Binding BindingContext.OpenItemCommand, Source={x:Reference Page}}" | ||
| 49 | + CommandParameter="{Binding .}" /> | ||
| 50 | + </Frame.GestureRecognizers> | ||
| 51 | + <Grid RowDefinitions="Auto,Auto,Auto,Auto" | ||
| 52 | + ColumnDefinitions="Auto,*" ColumnSpacing="8"> | ||
| 53 | + <Label Grid.Row="0" Grid.Column="0" Text="入库单号:" FontAttributes="Bold"/> | ||
| 54 | + <Label Grid.Row="0" Grid.Column="1" Text="{Binding OrderNo}"/> | ||
| 55 | + | ||
| 56 | + <Label Grid.Row="1" Grid.Column="0" Text="入库类型:" FontAttributes="Bold"/> | ||
| 57 | + <Label Grid.Row="1" Grid.Column="1" Text="{Binding InboundType}" /> | ||
| 58 | + | ||
| 59 | + <Label Grid.Row="2" Grid.Column="0" Text="供应商:" FontAttributes="Bold"/> | ||
| 60 | + <Label Grid.Row="2" Grid.Column="1" Text="{Binding Supplier}" /> | ||
| 61 | + | ||
| 62 | + <Label Grid.Row="3" Grid.Column="0" Text="创建日期:" FontAttributes="Bold"/> | ||
| 63 | + <Label Grid.Row="3" Grid.Column="1" Text="{Binding CreatedAt, StringFormat='{0:yyyy-M-d}'}"/> | ||
| 64 | + </Grid> | ||
| 65 | + </Frame> | ||
| 66 | + </DataTemplate> | ||
| 67 | + </CollectionView.ItemTemplate> | ||
| 68 | + </CollectionView> | ||
| 69 | + | ||
| 70 | + <!-- 底部:操作(第2行) --> | ||
| 71 | + <Grid Grid.Row="2" ColumnDefinitions="*,Auto" Padding="0,8,0,0"> | ||
| 72 | + <Label Text="{Binding Orders.Count, StringFormat='共 {0} 条'}" | ||
| 73 | + VerticalTextAlignment="Center" /> | ||
| 74 | + </Grid> | ||
| 75 | + </Grid> | ||
| 76 | +</ContentPage> |
Pages/OutboundFinishedSearchPage.xaml.cs
0 → 100644
| 1 | +using System.Threading; | ||
| 2 | +using IndustrialControl.Services; | ||
| 3 | +using IndustrialControl.ViewModels; | ||
| 4 | +namespace IndustrialControl.Pages; | ||
| 5 | +public partial class OutboundFinishedSearchPage : ContentPage | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | + private readonly ScanService _scanSvc; | ||
| 9 | + private readonly OutboundFinishedSearchViewModel _vm; | ||
| 10 | + public OutboundFinishedSearchPage(OutboundFinishedSearchViewModel vm, ScanService scanSvc) | ||
| 11 | + { | ||
| 12 | + _vm = vm; | ||
| 13 | + | ||
| 14 | + BindingContext = vm; | ||
| 15 | + _scanSvc = scanSvc; | ||
| 16 | + InitializeComponent(); | ||
| 17 | + // 可选:配置前后缀与防抖 | ||
| 18 | + _scanSvc.Prefix = null; // 例如 "}q" 之类的前缀;没有就留 null | ||
| 19 | + // _scanSvc.Suffix = "\n"; // 如果设备会附带换行,可去掉;没有就设 null | ||
| 20 | + //_scanSvc.DebounceMs = 250; | ||
| 21 | + _scanSvc.Suffix = null; // 先关掉 | ||
| 22 | + _scanSvc.DebounceMs = 0; // 先关掉 | ||
| 23 | + } | ||
| 24 | + protected override async void OnAppearing() | ||
| 25 | + { | ||
| 26 | + base.OnAppearing(); | ||
| 27 | + // 动态注册广播接收器(只在当前页面前台时生效) | ||
| 28 | + _scanSvc.Scanned += OnScanned; | ||
| 29 | + _scanSvc.StartListening(); | ||
| 30 | + //键盘输入 | ||
| 31 | + _scanSvc.Attach(OrderEntry); | ||
| 32 | + OrderEntry.Focus(); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /// <summary> | ||
| 36 | + /// 清空扫描记录 | ||
| 37 | + /// </summary> | ||
| 38 | + void OnClearClicked(object sender, EventArgs e) | ||
| 39 | + { | ||
| 40 | + OrderEntry.Text = string.Empty; | ||
| 41 | + OrderEntry.Focus(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + protected override void OnDisappearing() | ||
| 45 | + { | ||
| 46 | + // 退出页面即注销(防止多个程序/页面抢处理) | ||
| 47 | + _scanSvc.Scanned -= OnScanned; | ||
| 48 | + _scanSvc.StopListening(); | ||
| 49 | + | ||
| 50 | + base.OnDisappearing(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + private void OnScanned(string data, string type) | ||
| 54 | + { | ||
| 55 | + MainThread.BeginInvokeOnMainThread(async () => | ||
| 56 | + { | ||
| 57 | + // 常见处理:自动填入单号/条码并触发查询或加入明细 | ||
| 58 | + _vm.SearchOrderNo = data; | ||
| 59 | + }); | ||
| 60 | + } | ||
| 61 | + private async void OnOrderSelected(object sender, SelectionChangedEventArgs e) | ||
| 62 | + { | ||
| 63 | + var item = e.CurrentSelection?.FirstOrDefault() as InboundOrderSummary; | ||
| 64 | + if (item is null) return; | ||
| 65 | + | ||
| 66 | + // 二选一:A) 点选跳转到入库页 | ||
| 67 | + await Shell.Current.GoToAsync( | ||
| 68 | + $"{nameof(OutboundFinishedPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 69 | + | ||
| 70 | + // 或 B) 只把单号写到输入框/VM(不跳转) | ||
| 71 | + // if (BindingContext is InboundMaterialSearchViewModel vm) vm.SearchOrderNo = item.OrderNo; | ||
| 72 | + | ||
| 73 | + ((CollectionView)sender).SelectedItem = null; // 清除选中高亮 | ||
| 74 | + } | ||
| 75 | +} |
Pages/OutboundMaterialSearchPage.xaml
0 → 100644
| 1 | +<?xml version="1.0" encoding="utf-8" ?> | ||
| 2 | +<ContentPage x:Name="Page" | ||
| 3 | + xmlns="http://schemas.microsoft.com/dotnet/2021/maui" | ||
| 4 | + xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" | ||
| 5 | + x:Class="IndustrialControl.Pages.OutboundMaterialSearchPage" | ||
| 6 | + xmlns:conv="clr-namespace:IndustrialControl.Converters" | ||
| 7 | + Title="仓储管理系统"> | ||
| 8 | + <ContentPage.Resources> | ||
| 9 | + <ResourceDictionary> | ||
| 10 | + <!-- 空/非空转布尔:非空 => true(按钮可用) --> | ||
| 11 | + <conv:NullToBoolConverter x:Key="NullToBoolConverter" /> | ||
| 12 | + </ResourceDictionary> | ||
| 13 | + </ContentPage.Resources> | ||
| 14 | + | ||
| 15 | + <Grid RowDefinitions="Auto,*,Auto" Padding="16" BackgroundColor="#F6F7FB"> | ||
| 16 | + | ||
| 17 | + <!-- 顶部:输入条件(第0行) --> | ||
| 18 | + <VerticalStackLayout Grid.Row="0" Spacing="10"> | ||
| 19 | + <Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto" ColumnSpacing="8" RowSpacing="8"> | ||
| 20 | + <Entry x:Name="OrderEntry" | ||
| 21 | + Grid.Row="0" Grid.Column="0" | ||
| 22 | + Placeholder="请输入出库单条码" | ||
| 23 | + VerticalOptions="Center" | ||
| 24 | + BackgroundColor="White" | ||
| 25 | + Text="{Binding SearchOrderNo}" /> | ||
| 26 | + | ||
| 27 | + | ||
| 28 | + <DatePicker Grid.Row="1" Grid.Column="0" | ||
| 29 | + Date="{Binding CreatedDate}" | ||
| 30 | + MinimumDate="2000-01-01" /> | ||
| 31 | + <Button Grid.Row="1" Grid.Column="1" | ||
| 32 | + Text="查询" | ||
| 33 | + Command="{Binding SearchCommand}" /> | ||
| 34 | + </Grid> | ||
| 35 | + </VerticalStackLayout> | ||
| 36 | + | ||
| 37 | + <!-- 中部:结果列表(第1行) --> | ||
| 38 | + <CollectionView Grid.Row="1" | ||
| 39 | + ItemsSource="{Binding Orders}" | ||
| 40 | + SelectionMode="Single" | ||
| 41 | + SelectionChanged="OnOrderSelected"> | ||
| 42 | + <CollectionView.ItemTemplate> | ||
| 43 | + <DataTemplate> | ||
| 44 | + <Frame Margin="0,8,0,0" Padding="12" HasShadow="True" CornerRadius="10"> | ||
| 45 | + <!-- ⭐ 点击整卡片触发命令 --> | ||
| 46 | + <Frame.GestureRecognizers> | ||
| 47 | + <TapGestureRecognizer | ||
| 48 | + Command="{Binding BindingContext.OpenItemCommand, Source={x:Reference Page}}" | ||
| 49 | + CommandParameter="{Binding .}" /> | ||
| 50 | + </Frame.GestureRecognizers> | ||
| 51 | + <Grid RowDefinitions="Auto,Auto,Auto,Auto" | ||
| 52 | + ColumnDefinitions="Auto,*" ColumnSpacing="8"> | ||
| 53 | + <Label Grid.Row="0" Grid.Column="0" Text="入库单号:" FontAttributes="Bold"/> | ||
| 54 | + <Label Grid.Row="0" Grid.Column="1" Text="{Binding OrderNo}"/> | ||
| 55 | + | ||
| 56 | + <Label Grid.Row="1" Grid.Column="0" Text="入库类型:" FontAttributes="Bold"/> | ||
| 57 | + <Label Grid.Row="1" Grid.Column="1" Text="{Binding InboundType}" /> | ||
| 58 | + | ||
| 59 | + <Label Grid.Row="2" Grid.Column="0" Text="供应商:" FontAttributes="Bold"/> | ||
| 60 | + <Label Grid.Row="2" Grid.Column="1" Text="{Binding Supplier}" /> | ||
| 61 | + | ||
| 62 | + <Label Grid.Row="3" Grid.Column="0" Text="创建日期:" FontAttributes="Bold"/> | ||
| 63 | + <Label Grid.Row="3" Grid.Column="1" Text="{Binding CreatedAt, StringFormat='{0:yyyy-M-d}'}"/> | ||
| 64 | + </Grid> | ||
| 65 | + </Frame> | ||
| 66 | + </DataTemplate> | ||
| 67 | + </CollectionView.ItemTemplate> | ||
| 68 | + </CollectionView> | ||
| 69 | + | ||
| 70 | + <!-- 底部:操作(第2行) --> | ||
| 71 | + <Grid Grid.Row="2" ColumnDefinitions="*,Auto" Padding="0,8,0,0"> | ||
| 72 | + <Label Text="{Binding Orders.Count, StringFormat='共 {0} 条'}" | ||
| 73 | + VerticalTextAlignment="Center" /> | ||
| 74 | + </Grid> | ||
| 75 | + </Grid> | ||
| 76 | +</ContentPage> |
Pages/OutboundMaterialSearchPage.xaml.cs
0 → 100644
| 1 | +using System.Threading; | ||
| 2 | +using IndustrialControl.Services; | ||
| 3 | +using IndustrialControl.ViewModels; | ||
| 4 | +namespace IndustrialControl.Pages; | ||
| 5 | +public partial class OutboundMaterialSearchPage : ContentPage | ||
| 6 | +{ | ||
| 7 | + | ||
| 8 | + private readonly ScanService _scanSvc; | ||
| 9 | + private readonly OutboundMaterialSearchViewModel _vm; | ||
| 10 | + public OutboundMaterialSearchPage(OutboundMaterialSearchViewModel vm, ScanService scanSvc) | ||
| 11 | + { | ||
| 12 | + _vm = vm; | ||
| 13 | + | ||
| 14 | + BindingContext = vm; | ||
| 15 | + _scanSvc = scanSvc; | ||
| 16 | + InitializeComponent(); | ||
| 17 | + // 可选:配置前后缀与防抖 | ||
| 18 | + _scanSvc.Prefix = null; // 例如 "}q" 之类的前缀;没有就留 null | ||
| 19 | + // _scanSvc.Suffix = "\n"; // 如果设备会附带换行,可去掉;没有就设 null | ||
| 20 | + //_scanSvc.DebounceMs = 250; | ||
| 21 | + _scanSvc.Suffix = null; // 先关掉 | ||
| 22 | + _scanSvc.DebounceMs = 0; // 先关掉 | ||
| 23 | + } | ||
| 24 | + protected override async void OnAppearing() | ||
| 25 | + { | ||
| 26 | + base.OnAppearing(); | ||
| 27 | + // 动态注册广播接收器(只在当前页面前台时生效) | ||
| 28 | + _scanSvc.Scanned += OnScanned; | ||
| 29 | + _scanSvc.StartListening(); | ||
| 30 | + //键盘输入 | ||
| 31 | + _scanSvc.Attach(OrderEntry); | ||
| 32 | + OrderEntry.Focus(); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + /// <summary> | ||
| 36 | + /// 清空扫描记录 | ||
| 37 | + /// </summary> | ||
| 38 | + void OnClearClicked(object sender, EventArgs e) | ||
| 39 | + { | ||
| 40 | + OrderEntry.Text = string.Empty; | ||
| 41 | + OrderEntry.Focus(); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + protected override void OnDisappearing() | ||
| 45 | + { | ||
| 46 | + // 退出页面即注销(防止多个程序/页面抢处理) | ||
| 47 | + _scanSvc.Scanned -= OnScanned; | ||
| 48 | + _scanSvc.StopListening(); | ||
| 49 | + | ||
| 50 | + base.OnDisappearing(); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + private void OnScanned(string data, string type) | ||
| 54 | + { | ||
| 55 | + MainThread.BeginInvokeOnMainThread(async () => | ||
| 56 | + { | ||
| 57 | + // 常见处理:自动填入单号/条码并触发查询或加入明细 | ||
| 58 | + _vm.SearchOrderNo = data; | ||
| 59 | + }); | ||
| 60 | + } | ||
| 61 | + private async void OnOrderSelected(object sender, SelectionChangedEventArgs e) | ||
| 62 | + { | ||
| 63 | + var item = e.CurrentSelection?.FirstOrDefault() as InboundOrderSummary; | ||
| 64 | + if (item is null) return; | ||
| 65 | + | ||
| 66 | + // 二选一:A) 点选跳转到入库页 | ||
| 67 | + await Shell.Current.GoToAsync( | ||
| 68 | + $"{nameof(OutboundMaterialPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 69 | + | ||
| 70 | + // 或 B) 只把单号写到输入框/VM(不跳转) | ||
| 71 | + // if (BindingContext is InboundMaterialSearchViewModel vm) vm.SearchOrderNo = item.OrderNo; | ||
| 72 | + | ||
| 73 | + ((CollectionView)sender).SelectedItem = null; // 清除选中高亮 | ||
| 74 | + } | ||
| 75 | +} |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| 2 | -<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg"> | ||
| 3 | - <rect x="0" y="0" width="456" height="456" fill="#512BD4" /> | ||
| 4 | -</svg> | ||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"> | ||
| 3 | + <!-- 背景随便一个形状,前景会由 appiconfg.svg 提供 --> | ||
| 4 | + <rect x="0" y="0" width="512" height="512" rx="96" ry="96" fill="#FFFFFF"/> | ||
| 5 | +</svg> |
| 1 | -<?xml version="1.0" encoding="UTF-8" standalone="no"?> | ||
| 2 | -<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | ||
| 3 | -<svg width="456" height="456" viewBox="0 0 456 456" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"> | ||
| 4 | - <path d="m 105.50037,281.60863 c -2.70293,0 -5.00091,-0.90042 -6.893127,-2.70209 -1.892214,-1.84778 -2.837901,-4.04181 -2.837901,-6.58209 0,-2.58722 0.945687,-4.80389 2.837901,-6.65167 1.892217,-1.84778 4.190197,-2.77167 6.893127,-2.77167 2.74819,0 5.06798,0.92389 6.96019,2.77167 1.93749,1.84778 2.90581,4.06445 2.90581,6.65167 0,2.54028 -0.96832,4.73431 -2.90581,6.58209 -1.89221,1.80167 -4.212,2.70209 -6.96019,2.70209 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" /> | ||
| 5 | - <path d="M 213.56111,280.08446 H 195.99044 L 149.69953,207.0544 c -1.17121,-1.84778 -2.14037,-3.76515 -2.90581,-5.75126 h -0.40578 c 0.36051,2.12528 0.54076,6.67515 0.54076,13.6496 v 65.13172 h -15.54349 v -99.36009 h 18.71925 l 44.7374,71.29798 c 1.89222,2.95695 3.1087,4.98917 3.64945,6.09751 h 0.26996 c -0.45021,-2.6325 -0.67573,-7.09015 -0.67573,-13.37293 v -64.02256 h 15.47557 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" /> | ||
| 6 | - <path d="m 289.25134,280.08446 h -54.40052 v -99.36009 h 52.23835 v 13.99669 h -36.15411 v 28.13085 h 33.31621 v 13.9271 h -33.31621 v 29.37835 h 38.31628 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" /> | ||
| 7 | - <path d="M 366.56466,194.72106 H 338.7222 v 85.3634 h -16.08423 v -85.3634 h -27.77455 v -13.99669 h 71.70124 z" style="fill:#ffffff;fill-rule:nonzero;stroke-width:0.838376" /> | ||
| 8 | -</svg> | ||
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | +<svg width="512" height="512" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"> | ||
| 3 | + <!-- 简单一个“IC”字母标识,你可替换成自己的LOGO路径 --> | ||
| 4 | + <g transform="translate(256,256)" font-family="Segoe UI, Arial" font-size="200" text-anchor="middle" dominant-baseline="central" fill="#FFFFFF"> | ||
| 5 | + <text>IC</text> | ||
| 6 | + </g> | ||
| 7 | +</svg> |
| @@ -5,18 +5,25 @@ namespace IndustrialControl.Services; | @@ -5,18 +5,25 @@ namespace IndustrialControl.Services; | ||
| 5 | public interface IWarehouseDataService | 5 | public interface IWarehouseDataService |
| 6 | { | 6 | { |
| 7 | Task<InboundOrder> GetInboundOrderAsync(string orderNo); | 7 | Task<InboundOrder> GetInboundOrderAsync(string orderNo); |
| 8 | + Task<OutboundOrder> GetOutboundOrderAsync(string orderNo); | ||
| 8 | Task<SimpleOk> ConfirmInboundAsync(string orderNo, IEnumerable<ScanItem> items); | 9 | Task<SimpleOk> ConfirmInboundAsync(string orderNo, IEnumerable<ScanItem> items); |
| 9 | 10 | ||
| 10 | Task<SimpleOk> ConfirmInboundProductionAsync(string orderNo, IEnumerable<ScanItem> items); | 11 | Task<SimpleOk> ConfirmInboundProductionAsync(string orderNo, IEnumerable<ScanItem> items); |
| 12 | + Task<SimpleOk> ConfirmOutboundProductionAsync(string orderNo, IEnumerable<ScanItem> items); | ||
| 11 | Task<SimpleOk> ConfirmOutboundMaterialAsync(string orderNo, IEnumerable<ScanItem> items); | 13 | Task<SimpleOk> ConfirmOutboundMaterialAsync(string orderNo, IEnumerable<ScanItem> items); |
| 12 | Task<SimpleOk> ConfirmOutboundFinishedAsync(string orderNo, IEnumerable<ScanItem> items); | 14 | Task<SimpleOk> ConfirmOutboundFinishedAsync(string orderNo, IEnumerable<ScanItem> items); |
| 13 | Task<IEnumerable<string>> ListInboundBinsAsync(string orderNo); | 15 | Task<IEnumerable<string>> ListInboundBinsAsync(string orderNo); |
| 16 | + Task<IEnumerable<string>> ListOutboundBinsAsync(string orderNo); | ||
| 14 | 17 | ||
| 15 | // NEW: 查询列表(图1) | 18 | // NEW: 查询列表(图1) |
| 16 | Task<IEnumerable<InboundOrderSummary>> ListInboundOrdersAsync(string? orderNoOrBarcode, DateTime createdDate); | 19 | Task<IEnumerable<InboundOrderSummary>> ListInboundOrdersAsync(string? orderNoOrBarcode, DateTime createdDate); |
| 20 | + // NEW: 查询列表(图1) | ||
| 21 | + Task<IEnumerable<OutboundOrderSummary>> ListOutboundOrdersAsync(string? orderNoOrBarcode, DateTime createdDate); | ||
| 17 | } | 22 | } |
| 18 | 23 | ||
| 19 | public record InboundOrder(string OrderNo, string Supplier, string LinkedNo, int ExpectedQty); | 24 | public record InboundOrder(string OrderNo, string Supplier, string LinkedNo, int ExpectedQty); |
| 25 | + | ||
| 26 | +public record OutboundOrder(string OrderNo, string Supplier, string LinkedNo, int ExpectedQty); | ||
| 20 | public record ScanItem(int Index, string Barcode, string? Bin, int Qty); | 27 | public record ScanItem(int Index, string Barcode, string? Bin, int Qty); |
| 21 | public record SimpleOk(bool Succeeded, string? Message = null); | 28 | public record SimpleOk(bool Succeeded, string? Message = null); |
| 22 | 29 | ||
| @@ -27,12 +34,19 @@ public class MockWarehouseDataService : IWarehouseDataService | @@ -27,12 +34,19 @@ public class MockWarehouseDataService : IWarehouseDataService | ||
| 27 | public Task<InboundOrder> GetInboundOrderAsync(string orderNo) | 34 | public Task<InboundOrder> GetInboundOrderAsync(string orderNo) |
| 28 | => Task.FromResult(new InboundOrder(orderNo, "XXXX", "DHD_23326", _rand.Next(10, 80))); | 35 | => Task.FromResult(new InboundOrder(orderNo, "XXXX", "DHD_23326", _rand.Next(10, 80))); |
| 29 | 36 | ||
| 37 | + public Task<OutboundOrder> GetOutboundOrderAsync(string orderNo) | ||
| 38 | + => Task.FromResult(new OutboundOrder(orderNo, "XXXX", "DHD_23326", _rand.Next(10, 80))); | ||
| 39 | + | ||
| 30 | public Task<SimpleOk> ConfirmInboundAsync(string orderNo, IEnumerable<ScanItem> items) | 40 | public Task<SimpleOk> ConfirmInboundAsync(string orderNo, IEnumerable<ScanItem> items) |
| 31 | => Task.FromResult(new SimpleOk(true, $"入库成功:{items.Count()} 条")); | 41 | => Task.FromResult(new SimpleOk(true, $"入库成功:{items.Count()} 条")); |
| 32 | 42 | ||
| 43 | + public Task<SimpleOk> ConfirmOutboundAsync(string orderNo, IEnumerable<ScanItem> items) | ||
| 44 | + => Task.FromResult(new SimpleOk(true, $"出库库成功:{items.Count()} 条")); | ||
| 45 | + | ||
| 33 | public Task<SimpleOk> ConfirmInboundProductionAsync(string orderNo, IEnumerable<ScanItem> items) | 46 | public Task<SimpleOk> ConfirmInboundProductionAsync(string orderNo, IEnumerable<ScanItem> items) |
| 34 | => Task.FromResult(new SimpleOk(true, $"生产入库成功:{items.Count()} 条")); | 47 | => Task.FromResult(new SimpleOk(true, $"生产入库成功:{items.Count()} 条")); |
| 35 | - | 48 | + public Task<SimpleOk> ConfirmOutboundProductionAsync(string orderNo, IEnumerable<ScanItem> items) |
| 49 | + => Task.FromResult(new SimpleOk(true, $"生产出库成功:{items.Count()} 条")); | ||
| 36 | public Task<SimpleOk> ConfirmOutboundMaterialAsync(string orderNo, IEnumerable<ScanItem> items) | 50 | public Task<SimpleOk> ConfirmOutboundMaterialAsync(string orderNo, IEnumerable<ScanItem> items) |
| 37 | => Task.FromResult(new SimpleOk(true, $"物料出库成功:{items.Count()} 条")); | 51 | => Task.FromResult(new SimpleOk(true, $"物料出库成功:{items.Count()} 条")); |
| 38 | 52 | ||
| @@ -60,6 +74,28 @@ public class MockWarehouseDataService : IWarehouseDataService | @@ -60,6 +74,28 @@ public class MockWarehouseDataService : IWarehouseDataService | ||
| 60 | 74 | ||
| 61 | return Task.FromResult(filtered); | 75 | return Task.FromResult(filtered); |
| 62 | } | 76 | } |
| 77 | + public Task<IEnumerable<OutboundOrderSummary>> ListOutboundOrdersAsync(string? orderNoOrBarcode, DateTime createdDate) | ||
| 78 | + { | ||
| 79 | + // 简单过滤逻辑(按需改造) | ||
| 80 | + var today = DateTime.Today; | ||
| 81 | + var all = Enumerable.Range(1, 8).Select(i => | ||
| 82 | + new OutboundOrderSummary( | ||
| 83 | + OrderNo: $"CGD{today:yyyyMMdd}-{i:000}", | ||
| 84 | + InboundType: (i % 2 == 0) ? "采购入库" : "生产入库", | ||
| 85 | + Supplier: $"供应商{i}", | ||
| 86 | + CreatedAt: today.AddDays(-i) | ||
| 87 | + )); | ||
| 88 | + | ||
| 89 | + IEnumerable<OutboundOrderSummary> filtered = all; | ||
| 90 | + | ||
| 91 | + //if (!string.IsNullOrWhiteSpace(orderNoOrBarcode)) | ||
| 92 | + // filtered = filtered.Where(x => x.OrderNo.Contains(orderNoOrBarcode, StringComparison.OrdinalIgnoreCase)); | ||
| 93 | + | ||
| 94 | + //// 示例:按创建日期“同一天”过滤(你可以换成 >= 起始 && < 次日) | ||
| 95 | + //filtered = filtered.Where(x => x.CreatedAt.Date == createdDate.Date); | ||
| 96 | + | ||
| 97 | + return Task.FromResult(filtered); | ||
| 98 | + } | ||
| 63 | 99 | ||
| 64 | public Task<IEnumerable<string>> ListInboundBinsAsync(string orderNo) | 100 | public Task<IEnumerable<string>> ListInboundBinsAsync(string orderNo) |
| 65 | { | 101 | { |
| @@ -67,5 +103,9 @@ public class MockWarehouseDataService : IWarehouseDataService | @@ -67,5 +103,9 @@ public class MockWarehouseDataService : IWarehouseDataService | ||
| 67 | return Task.FromResult<IEnumerable<string>>(bins); | 103 | return Task.FromResult<IEnumerable<string>>(bins); |
| 68 | } | 104 | } |
| 69 | 105 | ||
| 70 | - | 106 | + public Task<IEnumerable<string>> ListOutboundBinsAsync(string orderNo) |
| 107 | + { | ||
| 108 | + var bins = new[] { "CK1_A201", "CK1_A202", "CK1_A203", "CK1_A204", "CK1_B101" }; | ||
| 109 | + return Task.FromResult<IEnumerable<string>>(bins); | ||
| 110 | + } | ||
| 71 | } | 111 | } |
| 1 | +using CommunityToolkit.Mvvm.ComponentModel; | ||
| 2 | +using CommunityToolkit.Mvvm.Input; | ||
| 3 | +using IndustrialControl.Services; | ||
| 4 | +using System.Collections.ObjectModel; | ||
| 5 | +using System; | ||
| 6 | +using IndustrialControl.Pages; | ||
| 7 | + | ||
| 8 | +namespace IndustrialControl.ViewModels; | ||
| 9 | + | ||
| 10 | +public partial class InboundProductionSearchViewModel : ObservableObject | ||
| 11 | +{ | ||
| 12 | + private readonly IWarehouseDataService _dataSvc; | ||
| 13 | + [ObservableProperty] private string? searchOrderNo; | ||
| 14 | + [ObservableProperty] private DateTime _createdDate = DateTime.Today; | ||
| 15 | + [ObservableProperty] private InboundOrderSummary? selectedOrder; | ||
| 16 | + | ||
| 17 | + public InboundProductionSearchViewModel(IWarehouseDataService dataSvc) | ||
| 18 | + { | ||
| 19 | + _dataSvc = dataSvc; | ||
| 20 | + Orders = new ObservableCollection<InboundOrderSummary>(); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + public ObservableCollection<InboundOrderSummary> Orders { get; } | ||
| 26 | + | ||
| 27 | + [RelayCommand] | ||
| 28 | + private async Task SearchAsync() | ||
| 29 | + { | ||
| 30 | + try | ||
| 31 | + { | ||
| 32 | + var list = await _dataSvc.ListInboundOrdersAsync(SearchOrderNo, CreatedDate); | ||
| 33 | + | ||
| 34 | + // ★ 在主线程更新 ObservableCollection,避免看起来“没刷新” | ||
| 35 | + await MainThread.InvokeOnMainThreadAsync(() => | ||
| 36 | + { | ||
| 37 | + Orders.Clear(); | ||
| 38 | + if (list != null) | ||
| 39 | + { | ||
| 40 | + foreach (var o in list) | ||
| 41 | + Orders.Add(o); | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + // (排查辅助)无数据时提示一下,确认命令确实执行了 | ||
| 46 | + if (list == null || !list.Any()) | ||
| 47 | + await Shell.Current.DisplayAlert("提示", "未查询到任何入库单", "确定"); | ||
| 48 | + } | ||
| 49 | + catch (Exception ex) | ||
| 50 | + { | ||
| 51 | + await Shell.Current.DisplayAlert("查询失败", ex.Message, "确定"); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + // 打开明细(携带 orderNo 导航) | ||
| 56 | + [RelayCommand] | ||
| 57 | + private async Task OpenItemAsync(InboundOrderSummary item) | ||
| 58 | + { | ||
| 59 | + if (item is null) return; | ||
| 60 | + await Shell.Current.GoToAsync( | ||
| 61 | + $"{nameof(InboundProductionPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + [RelayCommand(CanExecute = nameof(CanGoInbound))] | ||
| 65 | + private async Task GoInboundAsync() | ||
| 66 | + { | ||
| 67 | + if (SelectedOrder == null) return; | ||
| 68 | + // 导航到原“入库明细/扫描”页面,并传入 orderNo | ||
| 69 | + await Shell.Current.GoToAsync($"//InboundProduction?orderNo={Uri.EscapeDataString(SelectedOrder.OrderNo)}"); | ||
| 70 | + } | ||
| 71 | + public async Task LoadOrderAsync(string orderNo) | ||
| 72 | + { | ||
| 73 | + var order = await _dataSvc.GetInboundOrderAsync(orderNo); | ||
| 74 | + // TODO: 将 order 映射到页面“基础信息”“待入库明细”等绑定源,保持你现有绑定字段/集合不变 | ||
| 75 | + } | ||
| 76 | + private bool CanGoInbound() => SelectedOrder != null; | ||
| 77 | +} | ||
| 78 | + |
| 1 | +using CommunityToolkit.Mvvm.ComponentModel; | ||
| 2 | +using CommunityToolkit.Mvvm.Input; | ||
| 3 | +using IndustrialControl.Services; | ||
| 4 | +using System.Collections.ObjectModel; | ||
| 5 | +using System; | ||
| 6 | +using IndustrialControl.Pages; | ||
| 7 | + | ||
| 8 | +namespace IndustrialControl.ViewModels; | ||
| 9 | + | ||
| 10 | +public partial class OutboundFinishedSearchViewModel : ObservableObject | ||
| 11 | +{ | ||
| 12 | + private readonly IWarehouseDataService _dataSvc; | ||
| 13 | + [ObservableProperty] private string? searchOrderNo; | ||
| 14 | + [ObservableProperty] private DateTime _createdDate = DateTime.Today; | ||
| 15 | + [ObservableProperty] private OutboundOrderSummary? selectedOrder; | ||
| 16 | + | ||
| 17 | + public OutboundFinishedSearchViewModel(IWarehouseDataService dataSvc) | ||
| 18 | + { | ||
| 19 | + _dataSvc = dataSvc; | ||
| 20 | + Orders = new ObservableCollection<OutboundOrderSummary>(); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + public ObservableCollection<OutboundOrderSummary> Orders { get; } | ||
| 26 | + | ||
| 27 | + [RelayCommand] | ||
| 28 | + private async Task SearchAsync() | ||
| 29 | + { | ||
| 30 | + try | ||
| 31 | + { | ||
| 32 | + var list = await _dataSvc.ListOutboundOrdersAsync(SearchOrderNo, CreatedDate); | ||
| 33 | + | ||
| 34 | + // ★ 在主线程更新 ObservableCollection,避免看起来“没刷新” | ||
| 35 | + await MainThread.InvokeOnMainThreadAsync(() => | ||
| 36 | + { | ||
| 37 | + Orders.Clear(); | ||
| 38 | + if (list != null) | ||
| 39 | + { | ||
| 40 | + foreach (var o in list) | ||
| 41 | + Orders.Add(o); | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + // (排查辅助)无数据时提示一下,确认命令确实执行了 | ||
| 46 | + if (list == null || !list.Any()) | ||
| 47 | + await Shell.Current.DisplayAlert("提示", "未查询到任何入库单", "确定"); | ||
| 48 | + } | ||
| 49 | + catch (Exception ex) | ||
| 50 | + { | ||
| 51 | + await Shell.Current.DisplayAlert("查询失败", ex.Message, "确定"); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + // 打开明细(携带 orderNo 导航) | ||
| 56 | + [RelayCommand] | ||
| 57 | + private async Task OpenItemAsync(OutboundOrderSummary item) | ||
| 58 | + { | ||
| 59 | + if (item is null) return; | ||
| 60 | + await Shell.Current.GoToAsync( | ||
| 61 | + $"{nameof(OutboundMaterialPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + [RelayCommand(CanExecute = nameof(CanGoOutbound))] | ||
| 65 | + private async Task GoOutboundAsync() | ||
| 66 | + { | ||
| 67 | + if (SelectedOrder == null) return; | ||
| 68 | + // 导航到原“入库明细/扫描”页面,并传入 orderNo | ||
| 69 | + await Shell.Current.GoToAsync($"//OutboundFinished?orderNo={Uri.EscapeDataString(SelectedOrder.OrderNo)}"); | ||
| 70 | + } | ||
| 71 | + public async Task LoadOrderAsync(string orderNo) | ||
| 72 | + { | ||
| 73 | + var order = await _dataSvc.GetOutboundOrderAsync(orderNo); | ||
| 74 | + // TODO: 将 order 映射到页面“基础信息”“待入库明细”等绑定源,保持你现有绑定字段/集合不变 | ||
| 75 | + } | ||
| 76 | + private bool CanGoOutbound() => SelectedOrder != null; | ||
| 77 | +} | ||
| 78 | + |
| 1 | +using CommunityToolkit.Mvvm.ComponentModel; | ||
| 2 | +using CommunityToolkit.Mvvm.Input; | ||
| 3 | +using IndustrialControl.Services; | ||
| 4 | +using System.Collections.ObjectModel; | ||
| 5 | +using System; | ||
| 6 | +using IndustrialControl.Pages; | ||
| 7 | + | ||
| 8 | +namespace IndustrialControl.ViewModels; | ||
| 9 | + | ||
| 10 | +public partial class OutboundMaterialSearchViewModel : ObservableObject | ||
| 11 | +{ | ||
| 12 | + private readonly IWarehouseDataService _dataSvc; | ||
| 13 | + [ObservableProperty] private string? searchOrderNo; | ||
| 14 | + [ObservableProperty] private DateTime _createdDate = DateTime.Today; | ||
| 15 | + [ObservableProperty] private OutboundOrderSummary? selectedOrder; | ||
| 16 | + | ||
| 17 | + public OutboundMaterialSearchViewModel(IWarehouseDataService dataSvc) | ||
| 18 | + { | ||
| 19 | + _dataSvc = dataSvc; | ||
| 20 | + Orders = new ObservableCollection<OutboundOrderSummary>(); | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + | ||
| 24 | + | ||
| 25 | + public ObservableCollection<OutboundOrderSummary> Orders { get; } | ||
| 26 | + | ||
| 27 | + [RelayCommand] | ||
| 28 | + private async Task SearchAsync() | ||
| 29 | + { | ||
| 30 | + try | ||
| 31 | + { | ||
| 32 | + var list = await _dataSvc.ListOutboundOrdersAsync(SearchOrderNo, CreatedDate); | ||
| 33 | + | ||
| 34 | + // ★ 在主线程更新 ObservableCollection,避免看起来“没刷新” | ||
| 35 | + await MainThread.InvokeOnMainThreadAsync(() => | ||
| 36 | + { | ||
| 37 | + Orders.Clear(); | ||
| 38 | + if (list != null) | ||
| 39 | + { | ||
| 40 | + foreach (var o in list) | ||
| 41 | + Orders.Add(o); | ||
| 42 | + } | ||
| 43 | + }); | ||
| 44 | + | ||
| 45 | + // (排查辅助)无数据时提示一下,确认命令确实执行了 | ||
| 46 | + if (list == null || !list.Any()) | ||
| 47 | + await Shell.Current.DisplayAlert("提示", "未查询到任何入库单", "确定"); | ||
| 48 | + } | ||
| 49 | + catch (Exception ex) | ||
| 50 | + { | ||
| 51 | + await Shell.Current.DisplayAlert("查询失败", ex.Message, "确定"); | ||
| 52 | + } | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + // 打开明细(携带 orderNo 导航) | ||
| 56 | + [RelayCommand] | ||
| 57 | + private async Task OpenItemAsync(OutboundOrderSummary item) | ||
| 58 | + { | ||
| 59 | + if (item is null) return; | ||
| 60 | + await Shell.Current.GoToAsync( | ||
| 61 | + $"{nameof(OutboundMaterialPage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}"); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + [RelayCommand(CanExecute = nameof(CanGoOutbound))] | ||
| 65 | + private async Task GoOutboundAsync() | ||
| 66 | + { | ||
| 67 | + if (SelectedOrder == null) return; | ||
| 68 | + // 导航到原“入库明细/扫描”页面,并传入 orderNo | ||
| 69 | + await Shell.Current.GoToAsync($"//OutboundMaterial?orderNo={Uri.EscapeDataString(SelectedOrder.OrderNo)}"); | ||
| 70 | + } | ||
| 71 | + public async Task LoadOrderAsync(string orderNo) | ||
| 72 | + { | ||
| 73 | + var order = await _dataSvc.GetOutboundOrderAsync(orderNo); | ||
| 74 | + // TODO: 将 order 映射到页面“基础信息”“待入库明细”等绑定源,保持你现有绑定字段/集合不变 | ||
| 75 | + } | ||
| 76 | + private bool CanGoOutbound() => SelectedOrder != null; | ||
| 77 | +} | ||
| 78 | +public record OutboundOrderSummary( | ||
| 79 | + string OrderNo, | ||
| 80 | + string InboundType, | ||
| 81 | + string Supplier, | ||
| 82 | + DateTime CreatedAt | ||
| 83 | +); | ||
| 84 | + |
-
请 注册 或 登录 后发表评论