作者 李壮

Order Search

正在显示 41 个修改的文件 包含 749 行增加51 行删除
... ... @@ -18,6 +18,8 @@ public partial class AppShell : Shell
Routing.RegisterRoute(nameof(Pages.OutboundMaterialPage), typeof(Pages.OutboundMaterialPage));
Routing.RegisterRoute(nameof(Pages.OutboundFinishedPage), typeof(Pages.OutboundFinishedPage));
Routing.RegisterRoute(nameof(Pages.OutboundFinishedSearchPage), typeof(Pages.OutboundFinishedSearchPage));
Routing.RegisterRoute(nameof(Pages.WorkOrderSearchPage), typeof(Pages.WorkOrderSearchPage));
Routing.RegisterRoute(nameof(Pages.MoldOutboundExecutePage), typeof(Pages.MoldOutboundExecutePage));
BuildTabs(authed);
}
... ...
... ... @@ -79,22 +79,24 @@
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</MauiAsset>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Maui" Version="8.0.1" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
<PackageReference Include="Microsoft.Maui.Controls" Version="8.0.0" />
<PackageReference Include="Microsoft.Maui.Controls.Compatibility" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="8.0.1" />
</ItemGroup>
<ItemGroup>
<Compile Update="Pages\OutboundMaterialSearchPage.xaml.cs">
<Compile Update="Pages\WarehouseOperations\OutboundMaterialSearchPage.xaml.cs">
<DependentUpon>OutboundMaterialSearchPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\OutboundFinishedSearchPage.xaml.cs">
<Compile Update="Pages\WarehouseOperations\OutboundFinishedSearchPage.xaml.cs">
<DependentUpon>OutboundFinishedSearchPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\InboundProductionSearchPage.xaml.cs">
<Compile Update="Pages\WarehouseOperations\InboundProductionSearchPage.xaml.cs">
<DependentUpon>InboundProductionSearchPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
... ... @@ -106,31 +108,37 @@
<MauiXaml Update="Pages\AdminPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\BinListPage.xaml">
<MauiXaml Update="Pages\ProductionOperations\MoldOutboundExecutePage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\ProductionOperations\WorkOrderSearchPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\WarehouseOperations\BinListPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\BinPickerPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\BinPickerPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\HomePage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\InboundMaterialPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\InboundMaterialPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\OutboundMaterialSearchPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\OutboundMaterialSearchPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\OutboundFinishedSearchPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\OutboundFinishedSearchPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\InboundProductionSearchPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\InboundProductionSearchPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\InboundMaterialSearchPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\InboundMaterialSearchPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\InboundProductionPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\InboundProductionPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\LoginPage.xaml">
... ... @@ -139,10 +147,10 @@
<MauiXaml Update="Pages\LogsPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\OutboundFinishedPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\OutboundFinishedPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
<MauiXaml Update="Pages\OutboundMaterialPage.xaml">
<MauiXaml Update="Pages\WarehouseOperations\OutboundMaterialPage.xaml">
<Generator>MSBuild:Compile</Generator>
</MauiXaml>
</ItemGroup>
... ...
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using IndustrialControl.Services;
using CommunityToolkit.Maui;
namespace IndustrialControl
{
... ... @@ -11,6 +12,7 @@ namespace IndustrialControl
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
... ... @@ -44,6 +46,8 @@ namespace IndustrialControl
builder.Services.AddTransient<ViewModels.OutboundMaterialSearchViewModel>();
builder.Services.AddTransient<ViewModels.OutboundFinishedViewModel>();
builder.Services.AddTransient<ViewModels.OutboundFinishedSearchViewModel>();
builder.Services.AddTransient<ViewModels.WorkOrderSearchViewModel>();
builder.Services.AddTransient<ViewModels.MoldOutboundExecuteViewModel>();
// ===== 注册 Pages(DI 创建)=====
builder.Services.AddTransient<Pages.LoginPage>();
... ... @@ -60,6 +64,10 @@ namespace IndustrialControl
builder.Services.AddTransient<Pages.OutboundMaterialSearchPage>();
builder.Services.AddTransient<Pages.OutboundFinishedPage>();
builder.Services.AddTransient<Pages.OutboundFinishedSearchPage>();
builder.Services.AddTransient<Pages.WorkOrderSearchPage>();
builder.Services.AddTransient<Pages.MoldOutboundExecutePage>();
var app = builder.Build();
App.Services = app.Services;
return app;
... ...
namespace IndustrialControl.ViewModels;
public class WorkOrderDto
{
public string OrderNo { get; set; } = "";
public string OrderName { get; set; } = "";
public string Status { get; set; } = "";
public string ProductName { get; set; } = "";
public int Quantity { get; set; }
public DateTime CreateDate { get; set; }
}
public class WorkOrderSummary
{
public string OrderNo { get; set; } = "";
public string OrderName { get; set; } = "";
public string Status { get; set; } = "";
public string ProductName { get; set; } = "";
public int Quantity { get; set; }
public DateTime CreateDate { get; set; }
}
... ...
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="IndustrialControl.Pages.HomePage"
Title="仓储作业">
Title="作业">
<ContentPage.ToolbarItems>
<ToolbarItem Text="退出" Clicked="OnLogoutClicked" />
</ContentPage.ToolbarItems>
<VerticalStackLayout Padding="24" Spacing="16">
<Frame Style="{StaticResource BlueCardStyle}">
<Label Text="物料入库" FontSize="18" TextColor="White" VerticalTextAlignment="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnInMat" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
<Frame Style="{StaticResource BlueCardStyle}">
<Label Text="生产入库" FontSize="18" TextColor="White" VerticalTextAlignment="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnInProd" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
<Frame Style="{StaticResource BlueCardStyle}">
<Label Text="物料出库" FontSize="18" TextColor="White" VerticalTextAlignment="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnOutMat" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
<Frame Style="{StaticResource BlueCardStyle}">
<Label Text="成品出库/装货" FontSize="18" TextColor="White" VerticalTextAlignment="Center"/>
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnOutFinished" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
<ContentPage.Resources>
<!-- 子项一行样式 -->
<Style TargetType="Grid" x:Key="ItemRow">
<Setter Property="Padding" Value="0,4"/>
<Setter Property="ColumnDefinitions" Value="Auto,*"/>
</Style>
</ContentPage.Resources>
<ScrollView>
<VerticalStackLayout Padding="20" Spacing="12">
<!-- 一级:仓储作业 -->
<toolkit:Expander>
<toolkit:Expander.Header>
<Grid Padding="12,10" BackgroundColor="#F5F7FA">
<Label Text="📦 仓储作业" FontSize="18" FontAttributes="Bold"/>
</Grid>
</toolkit:Expander.Header>
<VerticalStackLayout Spacing="6" Padding="16,6,0,12">
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbInMat" CheckedChanged="OnInMat"/>
<Label Grid.Column="1" Text="物料入库">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbInMat}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbInProd" CheckedChanged="OnInProd"/>
<Label Grid.Column="1" Text="生产入库">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbInProd}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbOutMat" CheckedChanged="OnOutMat"/>
<Label Grid.Column="1" Text="物料出库">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbOutMat}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbOutFinished" CheckedChanged="OnOutFinished"/>
<Label Grid.Column="1" Text="产成品出库接货">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbOutFinished}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbMoldOut"/>
<Label Grid.Column="1" Text="模具出库管理">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbMoldOut}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbMoldIn"/>
<Label Grid.Column="1" Text="模具入库管理">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbMoldIn}" />
</Label.GestureRecognizers>
</Label>
</Grid>
</VerticalStackLayout>
</toolkit:Expander>
<!-- 一级:生产作业 -->
<toolkit:Expander>
<toolkit:Expander.Header>
<Grid Padding="12,10" BackgroundColor="#F5F7FA">
<Label Text="🏭 生产作业" FontSize="18" FontAttributes="Bold"/>
</Grid>
</toolkit:Expander.Header>
<VerticalStackLayout Spacing="6" Padding="16,6,0,12">
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbOrderQry" CheckedChanged="OnOrderQry" />
<Label Grid.Column="1" Text="工单查询">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbOrderQry}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbOpExec"/>
<Label Grid.Column="1" Text="工序任务执行">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbOpExec}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbParamLog"/>
<Label Grid.Column="1" Text="参数登记">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbParamLog}" />
</Label.GestureRecognizers>
</Label>
</Grid>
<Grid Style="{StaticResource ItemRow}">
<CheckBox x:Name="cbBindDevice"/>
<Label Grid.Column="1" Text="设备扫描绑定">
<Label.GestureRecognizers>
<TapGestureRecognizer Tapped="OnTapToggle" CommandParameter="{x:Reference cbBindDevice}" />
</Label.GestureRecognizers>
</Label>
</Grid>
</VerticalStackLayout>
</toolkit:Expander>
</VerticalStackLayout>
</ContentPage>
</ScrollView>
</ContentPage>
\ No newline at end of file
... ...
... ... @@ -7,24 +7,46 @@
InitializeComponent();
}
private async void OnInMat(object sender, EventArgs e)
// 点“文字”也能切换复选框
void OnTapToggle(object? sender, TappedEventArgs e)
{
if (e.Parameter is CheckBox cb)
cb.IsChecked = !cb.IsChecked;
}
// 勾选即跳转,返回后复位(保持你原有页面名)
private async void OnInMat(object sender, CheckedChangedEventArgs e)
{
if (!e.Value) return;
await Shell.Current.GoToAsync(nameof(InboundMaterialSearchPage));
((CheckBox)sender).IsChecked = false;
}
private async void OnInProd(object sender, EventArgs e)
private async void OnInProd(object sender, CheckedChangedEventArgs e)
{
if (!e.Value) return;
await Shell.Current.GoToAsync(nameof(InboundProductionSearchPage));
((CheckBox)sender).IsChecked = false;
}
private async void OnOutMat(object sender, EventArgs e)
private async void OnOutMat(object sender, CheckedChangedEventArgs e)
{
if (!e.Value) return;
await Shell.Current.GoToAsync(nameof(OutboundMaterialSearchPage));
((CheckBox)sender).IsChecked = false;
}
private async void OnOutFinished(object sender, EventArgs e)
private async void OnOutFinished(object sender, CheckedChangedEventArgs e)
{
if (!e.Value) return;
await Shell.Current.GoToAsync(nameof(OutboundFinishedSearchPage));
((CheckBox)sender).IsChecked = false;
}
private async void OnOrderQry(object sender, CheckedChangedEventArgs e)
{
if (!e.Value) return;
await Shell.Current.GoToAsync(nameof(WorkOrderSearchPage));
((CheckBox)sender).IsChecked = false;
}
// 新增:退出登录
... ...
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="IndustrialControl.Pages.MoldOutboundExecutePage"
Title="出库执行">
<ContentPage.Resources>
<!-- 表头与行样式 -->
<Style TargetType="Grid" x:Key="TableHeader">
<Setter Property="BackgroundColor" Value="#F5F7FA"/>
<Setter Property="Padding" Value="8,6"/>
<Setter Property="ColumnSpacing" Value="8"/>
</Style>
<Style TargetType="Grid" x:Key="TableRow">
<Setter Property="Padding" Value="8,6"/>
<Setter Property="ColumnSpacing" Value="8"/>
</Style>
</ContentPage.Resources>
<Grid RowDefinitions="Auto,*,Auto">
<!-- 顶部蓝条 -->
<Grid Grid.Row="0" BackgroundColor="#007BFF" HeightRequest="56" Padding="16,0">
<Label Text="仓储管理系统"
VerticalOptions="Center"
TextColor="White" FontSize="18" FontAttributes="Bold"/>
</Grid>
<!-- 主体 -->
<ScrollView Grid.Row="1">
<VerticalStackLayout Padding="12" Spacing="12">
<!-- 模具编码 -->
<Grid ColumnDefinitions="Auto,*" ColumnSpacing="12">
<Label Text="模具编码" VerticalTextAlignment="Center" />
<Entry x:Name="MoldEntry"
Grid.Column="1"
Placeholder="请扫描模具或输入具编码"
Completed="OnMoldCompleted" />
</Grid>
<!-- 需求基础信息 -->
<Label Text="需求基础信息" FontAttributes="Bold" />
<Frame Padding="0" HasShadow="False" BorderColor="#E0E6EF">
<VerticalStackLayout Spacing="0">
<!-- 顶部两列 -->
<Grid ColumnDefinitions="*,*" Style="{StaticResource TableHeader}">
<Grid ColumnDefinitions="Auto,*">
<Label Text="工单号:" />
<Label Grid.Column="1" Text="{Binding OrderNo}" />
</Grid>
<Grid Grid.Column="1" ColumnDefinitions="Auto,*">
<Label Text="产品名称:" />
<Label Grid.Column="1" Text="XXXXX" />
<!-- 需要时可绑定到 VM 的 ProductName -->
</Grid>
</Grid>
<!-- 模具型号表(示例样式;后续可替换为绑定集合) -->
<Grid Padding="8,6" ColumnDefinitions="Auto,*" BackgroundColor="#FFFFFF">
<Label Text="序号" FontAttributes="Bold"/>
<Label Grid.Column="1" Text="模具型号" FontAttributes="Bold"/>
</Grid>
<Grid Padding="8,6" ColumnDefinitions="Auto,*">
<Label Text="1"/>
<Label Grid.Column="1" Text="MU_DHJD_01"/>
</Grid>
<Grid Padding="8,6" ColumnDefinitions="Auto,*">
<Label Text="2"/>
<Label Grid.Column="1" Text="MU_DHJD_02"/>
</Grid>
</VerticalStackLayout>
</Frame>
<!-- 扫描明细 -->
<Label Text="扫描明细" TextColor="#17A673" FontAttributes="Bold" />
<!-- 表头 -->
<Grid ColumnDefinitions="40,Auto,*,*,Auto,*"
Style="{StaticResource TableHeader}">
<Label Text="#" />
<Label Grid.Column="1" Text="选择" />
<Label Grid.Column="2" Text="模具编码" />
<Label Grid.Column="3" Text="模具型号" />
<Label Grid.Column="4" Text="出库数量" />
<Label Grid.Column="5" Text="出库库位" />
</Grid>
<!-- 明细列表 -->
<CollectionView ItemsSource="{Binding ScanDetails}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid ColumnDefinitions="40,Auto,*,*,Auto,*"
Style="{StaticResource TableRow}">
<!-- 背景根据 Selected 高亮为绿色 -->
<Grid.Triggers>
<DataTrigger TargetType="Grid" Binding="{Binding Selected}" Value="True">
<Setter Property="BackgroundColor" Value="#6EF593"/>
</DataTrigger>
</Grid.Triggers>
<Label Text="{Binding Index}" />
<CheckBox Grid.Column="1" IsChecked="{Binding Selected, Mode=TwoWay}" />
<Label Grid.Column="2" Text="{Binding MoldCode}" />
<Label Grid.Column="3" Text="{Binding MoldModel}" />
<Label Grid.Column="4" Text="{Binding Qty}" HorizontalTextAlignment="Center" />
<Label Grid.Column="5" Text="{Binding Bin}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</VerticalStackLayout>
</ScrollView>
<!-- 底部操作条 -->
<Grid Grid.Row="2" BackgroundColor="White" Padding="16,8" ColumnDefinitions="*,Auto,*">
<!-- 取消扫描 -->
<Button Grid.Column="0"
Text="取消扫描"
TextColor="#C62828"
BorderColor="#C62828"
BorderWidth="1"
CornerRadius="8"
Command="{Binding CancelScanCommand}" />
<!-- 占位间距 -->
<BoxView Grid.Column="1" WidthRequest="16" />
<!-- 确认出库 -->
<Button Grid.Column="2"
Text="确认出库"
BackgroundColor="#0EA5E9"
TextColor="White"
CornerRadius="8"
Command="{Binding ConfirmCommand}" />
</Grid>
</Grid>
</ContentPage>
... ...
using IndustrialControl.ViewModels;
using IndustrialControl.Services; // ✅ 引入扫描服务
namespace IndustrialControl.Pages;
[QueryProperty(nameof(OrderNo), "orderNo")]
public partial class MoldOutboundExecutePage : ContentPage
{
public string? OrderNo { get; set; } // Shell QueryProperty 接收
private readonly MoldOutboundExecuteViewModel _vm;
private readonly ScanService _scanSvc; // ✅ 扫描服务
public MoldOutboundExecutePage(MoldOutboundExecuteViewModel vm, ScanService scanSvc)
{
InitializeComponent();
BindingContext = _vm = vm;
_scanSvc = scanSvc;
// 与项目里其它页保持一致的扫码配置
_scanSvc.Prefix = null;
_scanSvc.Suffix = null;
_scanSvc.DebounceMs = 0;
}
protected override async void OnNavigatedTo(NavigatedToEventArgs args)
{
base.OnNavigatedTo(args);
if (!string.IsNullOrWhiteSpace(OrderNo))
{
await _vm.LoadAsync(OrderNo); // 维持你现有逻辑
}
}
protected override void OnAppearing()
{
base.OnAppearing();
// ✅ 注册扫描回调并开始监听
_scanSvc.Scanned += OnScanned;
_scanSvc.StartListening();
// ✅ 让“模具编码”输入框也能接收键盘/扫描枪字符
_scanSvc.Attach(MoldEntry);
MoldEntry.Focus();
}
protected override void OnDisappearing()
{
// ✅ 页面离开时及时注销,避免多个页面抢占扫码
_scanSvc.Scanned -= OnScanned;
_scanSvc.StopListening();
base.OnDisappearing();
}
// ✅ 硬件/广播 扫到码
private void OnScanned(string data, string type)
{
MainThread.BeginInvokeOnMainThread(async () =>
{
// 1) 回填到输入框(UI 可见)
MoldEntry.Text = data;
// 2) 如需联动业务:在此调用 VM 方法(按需实现)
// 例如:await _vm.HandleMoldScannedAsync(data, type);
// 3) 如果只是想用扫描即“勾选相应行”,可在这里根据编码查找并置 Selected=true
// ⚠ 你的行模型 MoldOutboundDetailRow 目前不是可通知对象,直接赋值 UI 不一定刷新;
// 建议后续把它改成 ObservableObject 再做切换高亮。
});
}
// ✅ 手动输入并按回车,也走同一套逻辑
private async void OnMoldCompleted(object? sender, EventArgs e)
{
var code = MoldEntry.Text?.Trim();
if (string.IsNullOrEmpty(code)) return;
// 可选:与 OnScanned 同步的处理
// await _vm.HandleMoldScannedAsync(code, "manual");
// 光标回到输入框,便于连续扫描
MoldEntry.CursorPosition = MoldEntry.Text?.Length ?? 0;
MoldEntry.Focus();
}
}
... ...
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="IndustrialControl.Pages.WorkOrderSearchPage"
Title="工单查询">
<!-- 根布局:顶部(蓝条) / 条件区 / 列表 -->
<Grid RowDefinitions="Auto,Auto,*">
<!-- 顶部蓝条 -->
<Grid Grid.Row="0" BackgroundColor="#007BFF" HeightRequest="56" Padding="16,0">
<Label Text="仓储管理系统"
VerticalOptions="Center"
TextColor="White"
FontSize="18"
FontAttributes="Bold" />
</Grid>
<!-- 条件区 -->
<VerticalStackLayout Grid.Row="1" Padding="12" Spacing="10">
<!-- 第一行:工单号 + 查询 + 扫码图标按钮 -->
<Grid ColumnDefinitions="*,Auto,44">
<Entry x:Name="OrderEntry"
Placeholder="请输入/扫描工单号"
Text="{Binding Keyword}"
HeightRequest="40" />
<Button Grid.Column="1"
Text="查询"
HeightRequest="40"
Command="{Binding SearchCommand}" />
<!-- 图标按钮:避免 Button 内嵌 <Image> 的限制 -->
<ImageButton Grid.Column="2"
HeightRequest="40"
WidthRequest="44"
BackgroundColor="Transparent"
Source="scan.png"
Clicked="OnScanHintClicked" />
</Grid>
<!-- 第二行:时间 + 状态 -->
<Grid ColumnDefinitions="*,*,Auto" ColumnSpacing="8">
<DatePicker Date="{Binding StartDate}" />
<DatePicker Grid.Column="1" Date="{Binding EndDate}" />
<Picker Grid.Column="2"
Title="状态"
WidthRequest="120"
ItemsSource="{Binding StatusList}"
SelectedItem="{Binding SelectedStatus}" />
</Grid>
</VerticalStackLayout>
<!-- 列表(自身可滚动,外面不要再套 ScrollView) -->
<CollectionView Grid.Row="2"
x:Name="OrderList"
ItemsSource="{Binding Orders}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame Margin="0,6,0,0"
Padding="10"
HasShadow="False"
BorderColor="#E0E6EF">
<!-- 点整卡片就跳转 -->
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnOrderTapped"
CommandParameter="{Binding .}" />
</Frame.GestureRecognizers>
<!-- 列表项内容 -->
<Grid RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto">
<Grid Grid.Row="0" ColumnDefinitions="Auto,*">
<Label Text="工单编号:" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding OrderNo}" />
</Grid>
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
<Label Text="工单名称:" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding OrderName}" />
</Grid>
<Grid Grid.Row="2" ColumnDefinitions="Auto,*">
<Label Text="状态:" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Status}" />
</Grid>
<Grid Grid.Row="3" ColumnDefinitions="Auto,*">
<Label Text="产品名称:" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding ProductName}" />
</Grid>
<Grid Grid.Row="4" ColumnDefinitions="Auto,*">
<Label Text="生产量:" FontAttributes="Bold" />
<Label Grid.Column="1" Text="{Binding Quantity}" />
</Grid>
<Grid Grid.Row="5" ColumnDefinitions="Auto,*">
<Label Text="创建时间:" FontAttributes="Bold" />
<Label Grid.Column="1"
Text="{Binding CreateDate, StringFormat='{0:yyyy-M-d}'}" />
</Grid>
</Grid>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Grid>
</ContentPage>
... ...
using IndustrialControl.Services;
using IndustrialControl.ViewModels;
namespace IndustrialControl.Pages;
public partial class WorkOrderSearchPage : ContentPage
{
private readonly ScanService _scanSvc;
private readonly WorkOrderSearchViewModel _vm;
public WorkOrderSearchPage(WorkOrderSearchViewModel vm, ScanService scanSvc)
{
InitializeComponent();
BindingContext = vm;
_vm = vm;
_scanSvc = scanSvc;
// 与现有页面一致的扫码策略
_scanSvc.Prefix = null;
_scanSvc.Suffix = null;
_scanSvc.DebounceMs = 0;
}
protected override void OnAppearing()
{
base.OnAppearing();
_scanSvc.Scanned += OnScanned;
_scanSvc.StartListening();
_scanSvc.Attach(OrderEntry); // 支持键盘/手持枪统一输入
OrderEntry.Focus();
}
protected override void OnDisappearing()
{
_scanSvc.Scanned -= OnScanned;
_scanSvc.StopListening();
base.OnDisappearing();
}
private void OnScanned(string data, string type)
{
MainThread.BeginInvokeOnMainThread(async () =>
{
_vm.Keyword = data; // 回填查询条件
await _vm.SearchAsync(); // 触发查询
});
}
// 点整张卡片跳转(推荐)
private async void OnOrderTapped(object sender, TappedEventArgs e)
{
try
{
// 如果你的 ItemsSource 元素类型是 WorkOrderDto,请把 WorkOrderSummary 换成 WorkOrderDto
if (e.Parameter is not WorkOrderDto item) return;
// 跳到目标页并传参(示例为 MoldOutboundExecutePage;按需改成你的页名)
await Shell.Current.GoToAsync(
$"{nameof(MoldOutboundExecutePage)}?orderNo={Uri.EscapeDataString(item.OrderNo)}");
}
catch (Exception ex)
{
await DisplayAlert("导航失败", ex.Message, "确定");
}
}
private async void OnScanHintClicked(object sender, EventArgs e)
=> await DisplayAlert("提示", "此按钮预留摄像头扫码;硬件扫描直接扣扳机。", "确定");
}
... ...
... ... @@ -2,7 +2,6 @@
<ContentPage x:Name="Page"
xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:zxing="clr-namespace:ZXing.Net.Maui.Controls;assembly=ZXing.Net.MAUI"
x:Class="IndustrialControl.Pages.InboundMaterialSearchPage"
xmlns:conv="clr-namespace:IndustrialControl.Converters"
Title="仓储管理系统">
... ...
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
namespace IndustrialControl.ViewModels;
public partial class MoldOutboundExecuteViewModel : ObservableObject
{
[ObservableProperty] private string? orderNo;
public ObservableCollection<MoldOutboundDetailRow> ScanDetails { get; } = new();
[RelayCommand]
public async Task LoadAsync(string orderNo)
{
OrderNo = orderNo;
// TODO: 调接口获取:需求基础信息 + 扫描明细
await Task.Delay(80);
// mock 数据
ScanDetails.Clear();
ScanDetails.Add(new MoldOutboundDetailRow { Index = 1, MoldCode = "XXX", MoldModel = "MU_DHJD_01", Qty = 1, Bin = "A202", Selected = true });
ScanDetails.Add(new MoldOutboundDetailRow { Index = 2, MoldCode = "XXX", MoldModel = "MU_DHJD_01", Qty = 1, Bin = "A202" });
ScanDetails.Add(new MoldOutboundDetailRow { Index = 3, MoldCode = "XXX", MoldModel = "MU_DHJD_02", Qty = 1, Bin = "A202" });
}
[RelayCommand] public Task ConfirmAsync() => Task.CompletedTask; // TODO
[RelayCommand] public Task CancelScanAsync() => Task.CompletedTask; // TODO
}
public class MoldOutboundDetailRow
{
public int Index { get; set; }
public bool Selected { get; set; }
public string MoldCode { get; set; } = "";
public string MoldModel { get; set; } = "";
public int Qty { get; set; }
public string Bin { get; set; } = "";
}
... ...
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Collections.ObjectModel;
using System.Windows.Input;
namespace IndustrialControl.ViewModels;
public class WorkOrderSearchViewModel : ObservableObject
{
public ObservableCollection<WorkOrderDto> Orders { get; } = new();
private string? _keyword;
public string? Keyword
{
get => _keyword;
set => SetProperty(ref _keyword, value);
}
public DateTime StartDate { get; set; } = DateTime.Today.AddDays(-7);
public DateTime EndDate { get; set; } = DateTime.Today;
public List<string> StatusList { get; } = new() { "待执行", "执行中", "已完成", "已取消" };
private string? _selectedStatus = "待执行";
public string? SelectedStatus
{
get => _selectedStatus;
set => SetProperty(ref _selectedStatus, value);
}
private WorkOrderDto? _selectedOrder;
public WorkOrderDto? SelectedOrder
{
get => _selectedOrder;
set => SetProperty(ref _selectedOrder, value);
}
public ICommand SearchCommand { get; }
public ICommand ClearCommand { get; }
public WorkOrderSearchViewModel()
{
SearchCommand = new AsyncRelayCommand(SearchAsync);
ClearCommand = new RelayCommand(Clear);
}
public async Task SearchAsync()
{
// TODO: 调后端 API;这里先用 Mock
await Task.Delay(120);
Orders.Clear();
// 伪数据(根据条件简单过滤)
var all = MockOrders();
var filtered = all.Where(o =>
(string.IsNullOrWhiteSpace(Keyword) || o.OrderNo.Contains(Keyword!, StringComparison.OrdinalIgnoreCase)) &&
o.CreateDate.Date >= StartDate.Date && o.CreateDate.Date <= EndDate.Date &&
(string.IsNullOrWhiteSpace(SelectedStatus) || o.Status == SelectedStatus)
);
foreach (var m in filtered) Orders.Add(m);
}
public void Clear()
{
Keyword = string.Empty;
StartDate = DateTime.Today.AddDays(-7);
EndDate = DateTime.Today;
SelectedStatus = "待执行";
Orders.Clear();
}
private IEnumerable<WorkOrderDto> MockOrders()
{
yield return new WorkOrderDto
{
OrderNo = "SCGD20250601002",
OrderName = "XXXXXXXXXX",
Status = "待执行",
ProductName = "梅林午餐肉罐头198g",
Quantity = 10000,
CreateDate = DateTime.Today.AddDays(-3)
};
yield return new WorkOrderDto
{
OrderNo = "SCGD20250601003",
OrderName = "XXXXXXXXXX",
Status = "待执行",
ProductName = "梅林午餐肉罐头198g",
Quantity = 5000,
CreateDate = DateTime.Today.AddDays(-2)
};
yield return new WorkOrderDto
{
OrderNo = "SCGD20250601004",
OrderName = "XXXXXXXXXX",
Status = "执行中",
ProductName = "梅林午餐肉罐头198g",
Quantity = 8000,
CreateDate = DateTime.Today.AddDays(-1)
};
}
}
... ...