Procházet zdrojové kódy

feat: 拆分材料接收管理

JaneDoe před 2 měsíci
rodič
revize
faaae21be5

+ 1 - 0
UniformMaterialManagementSystem/App.xaml.cs

@@ -116,6 +116,7 @@ namespace UniformMaterialManagementSystem
             services.AddTransient<FactoryLicenseManagePageViewModel>();
             services.AddTransient<SelectApplyContractDialogViewModel>();
             services.AddTransient<InspectionOrganizationPageViewModel>();
+            services.AddTransient<MaterialReceiptViewModel>();
 
             // Service 注册
             services.AddScoped(typeof(IDataBaseService<>), typeof(DataBaseService<>));

+ 5 - 3
UniformMaterialManagementSystem/ViewModels/DeliveryReceiptViewModel.cs

@@ -50,7 +50,7 @@ namespace UniformMaterialManagementSystem.ViewModels
         // 默认是发货单
         internal DeliveryPageCategroy? _deliveryPageCategroy;
 
-        // 删除屏蔽行切换事件
+        // 删除屏蔽行切换事件
         private bool _isExcute = true;
 
         // 发运数量误差
@@ -397,6 +397,8 @@ namespace UniformMaterialManagementSystem.ViewModels
                 // 界面删除
                 DeliveryReceipts.Remove(CurrDeliveryReceipt);
 
+                // todo 删除后反写到数据库
+
                 // 保存到数据库
                 _service.Delete(CurrDeliveryReceipt);
                 bool isSuccess = _service.SaveChanges();
@@ -537,8 +539,6 @@ namespace UniformMaterialManagementSystem.ViewModels
 
         }
 
-        #endregion
-
         [RelayCommand]
         public void ExportDB()
         {
@@ -610,6 +610,8 @@ namespace UniformMaterialManagementSystem.ViewModels
             MessageBox.Show("导入成功");
         }
 
+        #endregion
+
         #region 子表事件
 
         public void FdgDeliveryDetail_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)

+ 1 - 1
UniformMaterialManagementSystem/ViewModels/MaterialCompanyViewModel.cs

@@ -232,7 +232,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             var repeatNames = Companies.GroupBy(x => x.Name).Where(g => g.Count() > 1).Select(g => g.Key);
             var repeatShortNames = Companies.GroupBy(x => x.ShortName).Where(g => g.Count() > 1).Select(g => g.Key);
             var repeatCodes = Companies.GroupBy(x => x.Code).Where(g => g.Count() > 1).Select(g => g.Key);
-            var repeatSystemCodes = Companies.GroupBy(x => x.SystemCode).Where(g => g.Count() > 1).Select(g => g.Key);
+            var repeatSystemCodes = Companies.GroupBy(x => x.SystemCode).Where(g => g.Count() > 1 && !string.IsNullOrEmpty(g.Key)).Select(g => g.Key); // 军网企业代码不必录,去除空值
             StringBuilder repeatMsg = new StringBuilder();
             Dictionary<int, int> repeatIndexes = new Dictionary<int, int>();
             int firstRepeatRowIndex = Companies.Count;

+ 475 - 0
UniformMaterialManagementSystem/ViewModels/MaterialReceiptViewModel.cs

@@ -0,0 +1,475 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using UniformMaterialManagementSystem.Entities;
+using UniformMaterialManagementSystem.Models;
+using UniformMaterialManagementSystem.Services;
+using UniformMaterialManagementSystem.Utils;
+using UniformMaterialManagementSystem.Views;
+
+namespace UniformMaterialManagementSystem.ViewModels
+{
+    public partial class MaterialReceiptViewModel : ObservableObject
+    {
+        [ObservableProperty]
+        private List<string> _statusItems = ["未复核", "已复核"];
+
+        [ObservableProperty]
+        private ObservableCollection<DeliveryReceipt> _deliveryReceipts = [];
+
+        [ObservableProperty]
+        private ObservableCollection<DeliveryReceiptDetail> _deliveryDetails = [];
+
+        [ObservableProperty]
+        private DeliveryReceipt? _currDeliveryReceipt = null;
+
+        // 删除时屏蔽行切换事件
+        private bool _isExcute = true;
+
+        private string _exportFileName = "附件3成品生产企业报送接收数据模板";
+
+        private LoginUser? _currUser = App.CurrentUser;
+
+        private IDataBaseService<DeliveryReceipt> _service = null!;
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        public MaterialReceiptViewModel(IDataBaseService<DeliveryReceipt> service)
+        {
+            _service = service;
+
+            if (_currUser == null || _currUser.CompanyName == null)
+            {
+                MessageBox.Show("获取当前用户的数据失败,请联系系统管理员!");
+                return;
+            }
+
+            LoadReceiptData();
+        }
+
+        public void FdgDelivery_SelectionChanged(object sender, SelectionChangedEventArgs args)
+        {
+            // 手动屏蔽本事件
+            if (!_isExcute) { return; }
+            //args.Handled = true;
+
+            if (sender is not DataGrid fdgDelivery) { return; }
+
+            // 暂时屏蔽行切换事件
+            _isExcute = false;
+
+            // 离开行之前,判断当前行是否未保存
+            if (args.RemovedItems.Count > 0)
+            {
+                // 手动切换为切换前的行(为了主表编辑界面的值不切换)
+                if (args.RemovedItems[0] is not DeliveryReceipt leavingDelivery) { return; }
+                fdgDelivery.SelectedItem = leavingDelivery;
+
+                // 判断当前行是否新增行或已修改
+                bool isChanged = IsChanged(leavingDelivery);
+                if (isChanged)
+                {
+                    // 询问是否切换
+                    MessageBoxResult res = MessageBox.Show("当前行已修改,切换行会丢失已修改的数据,是否确认切换行?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+                    // 不切换:重新赋值为切换前的行
+                    if (res != MessageBoxResult.Yes)
+                    {
+                        // 取消切换行:当前行不变
+                        fdgDelivery.SelectedItem = leavingDelivery; // 重新赋值为旧行; CurrDeliveryReceipt 通过绑定自动更新
+                        fdgDelivery.Items.Refresh(); // 必须刷新界面
+                        // 直接赋值会循环调用本事件,CurrDeliveryReceipt 双向绑定也会循环调用
+
+                        // 取消屏蔽后返回
+                        _isExcute = true;
+                        return;
+                    }
+                    // 切换:则展示新行数据
+                }
+            }
+
+            // 进入新的行时,界面展示新行数据
+            if (args.AddedItems.Count > 0)
+            {
+                if (args.AddedItems[0] is not DeliveryReceipt newDelivery) { return; }
+                fdgDelivery.SelectedItem = newDelivery; // 刚刚为了界面数据赋值,所以这里需要设置为切换后的行
+                //fdgDelivery.Items.Refresh(); // 不必刷新前台界面
+            }
+
+            // 取消屏蔽行切换
+            _isExcute = true;
+        }
+
+        [RelayCommand]
+        public void Check(ComboBox cbReceivedStatus)
+        {
+            if (CurrDeliveryReceipt == null) { return; }
+
+            var sele00 = cbReceivedStatus.SelectedItem;
+            string status = CurrDeliveryReceipt.ReceivedStatus ?? string.Empty;
+            if (status.Equals("已复核"))
+            {
+                MessageBox.Show("当前接收单已复核,不用重复复核。");
+                return;
+            }
+
+            //  校验子表接收数量列
+            StringBuilder nullHint = new StringBuilder();
+            foreach (DeliveryReceiptDetail dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
+            {
+                decimal? receQty = dtl.ReceiveQuantity;
+                if (receQty == null || receQty == 0)
+                {
+                    int index = CurrDeliveryReceipt.DeliveryReceiptDetails.IndexOf(dtl);
+                    nullHint.AppendLine($"第 {index + 1} 行");
+                }
+            }
+            if (nullHint.Length > 0)
+            {
+                MessageBox.Show("子表中存在一下为空的接收数量,不允许复核!\n" + nullHint.ToString());
+                return;
+            }
+
+            // 更新为已复核
+            CurrDeliveryReceipt.ReceivedStatus = "已复核";
+            cbReceivedStatus.SelectedItem = "已复核";
+        }
+
+        // todo 
+        [RelayCommand]
+        public void Save(ComboBox cbReceivedStatus)
+        {
+            // 未选择行或者当前行已导出,直接返回
+            if (CurrDeliveryReceipt == null) { return; }
+            if (CurrDeliveryReceipt.IsExportDelivery || CurrDeliveryReceipt.IsExportReceive || CurrDeliveryReceipt.IsExportUsage) { return; }
+
+            // 若 收货单状态 为空,默认赋值为 未复核
+            var selectedStatus = cbReceivedStatus.SelectedItem;
+            if (selectedStatus == null)
+            {
+                cbReceivedStatus.SelectedItem = "未复核";
+            }
+
+            // 子表存在空值时
+            var nullReceivedQty = CurrDeliveryReceipt!.DeliveryReceiptDetails.Where(x => x.ReceiveQuantity == 0);
+            if (nullReceivedQty.Any())
+            {
+                MessageBoxResult res = MessageBox.Show("明细表的接收数量存在空值,是否确认保存?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+                if (res != MessageBoxResult.Yes) { return; }
+            }
+
+            // 保存到数据库
+            var serviceDtl = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>();
+            if (CurrDeliveryReceipt.IsNewRow)
+            {
+                // 新增行插入到数据库
+                CurrDeliveryReceipt.IsNewRow = false;
+                _service.Insert(CurrDeliveryReceipt);
+
+                foreach (DeliveryReceiptDetail dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
+                {
+                    dtl.IsNewRow = false;
+                    serviceDtl?.Insert(dtl);
+                }
+            }
+            else
+            {
+                // 已保存行更新到数据库
+                // todo 主表已保存,但子表明细 新增/删除/修改 怎么保存
+                _service.Update(CurrDeliveryReceipt);
+
+                foreach (DeliveryReceiptDetail dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
+                {
+                    if (dtl.IsNewRow)
+                    {
+                        dtl.IsNewRow = false;
+                        serviceDtl?.Insert(dtl);
+                    }
+                    else
+                    {
+                        serviceDtl?.Update(dtl);
+                    }
+                }
+            }
+
+            // 提示保存结果
+            bool isMainSuccess = _service.SaveChanges();
+            // todo 受影响行数为 0 ,但保存到数据库了
+            bool? isDtlSuccess = serviceDtl?.SaveChanges();
+            if (!isMainSuccess)
+            {
+                MessageBox.Show("数据库保存失败!", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+                return;
+            }
+        }
+
+        [RelayCommand]
+        public void ExportThree()
+        {
+
+        }
+
+        [RelayCommand]
+        public void ExportDB()
+        {
+            if (CurrDeliveryReceipt != null)
+            {
+                bool isChanged = IsChanged(CurrDeliveryReceipt);
+                if (isChanged)
+                {
+                    MessageBox.Show("当前发货单未保存,请保存后导出数据包!");
+                }
+            }
+
+            // 需要存在 bin\DataBase 目录,且目录下存在一份 .db 文件,需要存在表
+
+            // 导出主表到 bin\DataBase 目录下的 .db:根据主键判断,存在数据则更新,不存在则插入
+            var deliveries = DeliveryReceipts;
+            DataBaseUtil.ExportTable(deliveries, "DeliveryReceipts"); // 数据库表名输错会抛出异常,但在本方法里获取不到抛出异常
+
+            // 必须先导出主表,否则明细插入数据库时报错:Foreign Key constraint failed
+            List<DeliveryReceiptDetail> details = new List<DeliveryReceiptDetail>();
+            foreach (var delivery in DeliveryReceipts)
+            {
+                details.AddRange(delivery.DeliveryReceiptDetails);
+            }
+            DataBaseUtil.ExportTable(details, "DeliveryReceiptDetails");
+
+            // 将选择的数据导出为加密数据包
+            string exportPath = DataBaseUtil.ExportData();
+            if (!string.IsNullOrEmpty(exportPath))
+            {
+                MessageBox.Show("导出成功。");
+            }
+        }
+
+        [RelayCommand]
+        public async Task ImportDB()
+        {
+            if (CurrDeliveryReceipt != null)
+            {
+                bool isChanged = IsChanged(CurrDeliveryReceipt);
+                if (isChanged)
+                {
+                    MessageBox.Show("当前发货单未保存,请保存后导入数据包!");
+                }
+            }
+
+            // 从加密数据包中获取出 .db 放到 path 目录下(bin\DataBase 目录)
+            string path = DataBaseUtil.ImportData();
+            if (string.IsNullOrEmpty(path)) { return; }
+
+            // 新增发货单
+            var deliveries = DataBaseUtil.QueryAll<DeliveryReceipt>(path, x => x.Include(x => x.DeliveryReceiptDetails))
+                                         .Result;
+            await DataBaseUtil.ImportTable("DeliveryReceipts", deliveries);
+
+            // 新增发货单明细 - 方法一:
+            List<DeliveryReceiptDetail> details = new List<DeliveryReceiptDetail>();
+            foreach (var d in deliveries)
+            {
+                details.AddRange(d.DeliveryReceiptDetails);
+            }
+            await DataBaseUtil.ImportTable("DeliveryReceiptDetails", details);
+
+            // 新增发货单明细 - 方法二:
+            //var drDetails = DataBaseUtil.QueryAll<DeliveryReceiptDetail>(path)
+            //                             .Result;
+            //await DataBaseUtil.ImportTable("DeliveryReceiptDetails", drDetails);
+
+            MessageBox.Show("导入成功");
+        }
+
+        public void FdgDeliveryDetail_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
+        {
+            if (sender is not DataGrid fdgDeliveryDetail) { return; }
+
+            if (e.RemovedCells.Count > 0)
+            {
+                // 离开单元格时提交编辑
+                fdgDeliveryDetail.CommitEdit();
+
+                // 如果编辑的列是发运数量/接收数量/使用数量,自动汇总至主表 更新使用状态
+                foreach (DataGridCellInfo cellInfo in e.RemovedCells)
+                {
+                    // 删除行时为 null
+                    if (cellInfo.Column == null || cellInfo.Column.Header == null) { continue; } // DataGridCellInfo 类型的值永不等于 null
+
+                    if (!cellInfo.Column.Header.Equals("接收数量*")) { continue; }
+
+                    // 校验发运数量
+                    DeliveryReceiptDetail? dtl = cellInfo.Item as DeliveryReceiptDetail;
+                    if (dtl?.ReceiveQuantity < 0)
+                    {
+                        dtl.ReceiveQuantity = 0;
+                        fdgDeliveryDetail.Items.Refresh();
+                        MessageBox.Show("输入的数量异常,请重新输入!");
+                        return;
+                    }
+                    if (dtl?.ReceiveQuantity > dtl?.ShippedQuantity)
+                    {
+                        dtl.ReceiveQuantity = dtl?.ShippedQuantity;
+                        // todo 效率低,更高效的写法?
+                        fdgDeliveryDetail.Items.Refresh();
+                        //OnPropertyChanged(nameof(dtl)); // 无效
+                        //OnPropertyChanged(nameof(CurrDeliveryReceipt.DeliveryReceiptDetails));
+                        MessageBox.Show("接收数量不能超过发运数量,请重新输入");
+                        return;
+                    }
+
+                    // 汇总主表接收数量
+                    var validDtls = CurrDeliveryReceipt!.DeliveryReceiptDetails.Where(x => x.ReceiveQuantity != null && x.ReceiveQuantity > 0);
+                    CurrDeliveryReceipt.ReceivedPackets = validDtls.Count();
+                    CurrDeliveryReceipt.ReceivedQty = validDtls.Select(x => x.ReceiveQuantity).Sum() ?? 0;
+                }
+
+                // 手动触发值更新事件:此时没有切换焦点,不会自动触发更新
+                OnPropertyChanged(nameof(CurrDeliveryReceipt));
+                //OnPropertyChanged(nameof(CurrDeliveryReceipt.DeliveryReceiptDetails));
+                fdgDeliveryDetail.Items.Refresh();
+            }
+
+            // 单元格切换时,Added 里的是新单元格;Removed是旧单元格
+            if (e.AddedCells.Count > 0)
+            {
+                foreach (DataGridCellInfo cellInfo in e.AddedCells)
+                {
+                    // 进入单元格时自动进入编辑状态
+                    fdgDeliveryDetail.BeginEdit();
+
+                    // todo IsValid ?
+                    if (cellInfo.IsValid) { }
+                    if (cellInfo.Column == null)
+                    {
+                        continue;
+                    }
+
+                    // todo 点击两下才能勾选/取消勾选
+                    // 勾选/取消勾选行
+                    if (cellInfo.Column is DataGridCheckBoxColumn colCheck)
+                    {
+                        if (cellInfo.Item is not DeliveryReceiptDetail dtl) { continue; }
+                        dtl.IsSelected = !dtl.IsSelected;
+                    }
+                }
+            }
+        }
+
+        [RelayCommand]
+        public void ReceiveAll(MaterialReceiptPage page)
+        {
+            if (CurrDeliveryReceipt == null) { return; }
+
+            ObservableCollection<DeliveryReceiptDetail> details = CurrDeliveryReceipt.DeliveryReceiptDetails;
+            if (details == null || details.Count == 0) { return; }
+
+            // 全部接收:将发货数量列赋值到接收数量列
+            decimal qtyAll = 0;
+            foreach (DeliveryReceiptDetail dtl in details)
+            {
+                dtl.ReceiveQuantity = dtl.ShippedQuantity;
+                qtyAll += dtl.ShippedQuantity;
+            }
+
+            // 汇总到主表
+            CurrDeliveryReceipt.ReceivedPackets = details.Count();
+            CurrDeliveryReceipt.ReceivedQty = qtyAll;
+            OnPropertyChanged(nameof(CurrDeliveryReceipt));
+            OnPropertyChanged(nameof(CurrDeliveryReceipt.DeliveryReceiptDetails));
+
+            // 保存到数据库
+            Save(page.cbReceivedStatus);
+
+            // 刷新子表数据:值已更新,但没有显示
+            page.fdgDeliveryDetail.Items.Refresh();
+        }
+
+        /// <summary>
+        /// 加载接收单数据
+        /// </summary>
+        private void LoadReceiptData()
+        {
+            // 材料企业-发货单导出数据包赋值 IsExportDelivery 字段为 true:导出后不可再修改、删除
+            // 成品企业-接收单导出附件3的时候赋值 IsExportReceive 字段为 true:导出后不可编辑,不可重复导出
+            // 成品企业-使用单导出附件4的时候赋值 IsExportUsage 字段为 true:导出后不可编辑,不可重复导出
+            // 筛选当前工作年度、当前成品企业的所有发货单(数据包导入)
+            var deliveryReceipts = _service.Query(x => x.WorkYear.Equals(_currUser!.WorkYear) && x.ReceivedCompanyName.Equals(_currUser.CompanyName))
+                                           .Include(x => x.DeliveryReceiptDetails);
+            DeliveryReceipts = new ObservableCollection<DeliveryReceipt>(deliveryReceipts);
+
+            foreach (DeliveryReceipt delivery in DeliveryReceipts)
+            {
+                // 是否为新行:否
+                delivery.IsNewRow = false;
+
+                // 收货单状态
+                var status = delivery.ReceivedStatus;
+
+                // 子表明细行
+                var details = delivery.DeliveryReceiptDetails.OrderBy(x => x.PacketNo).ToArray();
+                foreach (DeliveryReceiptDetail dtl in details)
+                {
+                    dtl.IsNewRow = false;
+                }
+                delivery.DeliveryReceiptDetails = new ObservableCollection<DeliveryReceiptDetail>(details);
+            }
+        }
+
+        /// <summary>
+        /// 判断行是否已修改
+        /// </summary>
+        private bool IsChanged(DeliveryReceipt deliveryReceipt)
+        {
+            // 新增行直接返回 true
+            if (deliveryReceipt.IsNewRow)
+            {
+                return true;
+            }
+
+            // 已保存的行检查数据库状态
+            EntityState state = _service.Entry(deliveryReceipt);
+            if (state != EntityState.Unchanged)
+            {
+                return true;
+            }
+
+            // 检查子表行
+            foreach (DeliveryReceiptDetail detail in deliveryReceipt.DeliveryReceiptDetails)
+            {
+                if (detail.IsNewRow)
+                {
+                    return true;
+                }
+
+                EntityState? detailState = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>()?.Entry(detail);
+                if (detailState != EntityState.Unchanged)
+                {
+                    return true;
+                }
+
+                // todo 如果子表删除了几行是什么情况?
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        /// 汇总接收数据
+        /// </summary>
+        private void SummaryReceiveDetail()
+        {
+
+        }
+    }
+}

+ 26 - 56
UniformMaterialManagementSystem/Views/DeliveryReceiptControl.xaml

@@ -199,7 +199,6 @@
             </Setter>
         </Style>
 
-        <!-- TextBlock 一般用来展示文本,TextBox 一般用于输入文本 -->
         <!-- TextBlock 样式 -->
         <Style x:Key="CustomTextBlockStyle" TargetType="TextBlock">
             <Setter Property="Width" Value="100" />
@@ -209,24 +208,21 @@
             <Setter Property="TextAlignment" Value="Right" />
             <Setter Property="Margin" Value="5" />
         </Style>
-
-        <!-- Label 比 TextBlock 更复杂,但可以方便的设置边框 -->
-        <!-- Label 样式:有边框 -->
+        
+        <!-- Label 样式:自带边框 -->
         <Style x:Key="CustomLabelStyle" TargetType="Label">
-            <Setter Property="BorderBrush" Value="LightGray" />
-            <Setter Property="BorderThickness" Value="1" />
-            <!--<Setter Property="Background" Value="WhiteSmoke" />-->
-            <Setter Property="Foreground" Value="Gray" />
-            <Setter Property="Width" Value="250" />
-            <Setter Property="Height" Value="30" />
-            <Setter Property="FontSize" Value="14" />
+            <Setter Property="BorderBrush" Value="Gray" />
+            <Setter Property="BorderThickness" Value="1 0 1 0" />
+            <Setter Property="Width" Value="100" />
+            <Setter Property="FontWeight" Value="Bold" />
+            <Setter Property="VerticalAlignment" Value="Stretch" />
             <Setter Property="HorizontalContentAlignment" Value="Center" />
             <Setter Property="VerticalContentAlignment" Value="Center" />
-            <Setter Property="Margin" Value="0 5 0 5" />
+            <!--<Setter Property="FontSize" Value="14" />-->
         </Style>
 
         <!-- TextBox :输入框 -->
-        <Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
+        <!--<Style x:Key="CustomTextBoxStyle" TargetType="TextBox">
             <Setter Property="BorderBrush" Value="Gray" />
             <Setter Property="BorderThickness" Value="1" />
             <Setter Property="Width" Value="250" />
@@ -235,10 +231,10 @@
             <Setter Property="HorizontalContentAlignment" Value="Center" />
             <Setter Property="VerticalContentAlignment" Value="Center" />
             <Setter Property="Margin" Value="0 5 0 5" />
-        </Style>
+        </Style>-->
 
         <!-- 转换器 -->
-        <converters:MultiParamConverter x:Key="MultiParamConverter" />
+        <!--<converters:MultiParamConverter x:Key="MultiParamConverter" />-->
 
     </UserControl.Resources>
 
@@ -341,7 +337,7 @@
                             RowStyle="{StaticResource CustomRowStyle}"
                             CellStyle="{StaticResource CustomCellStyle}"
                             IsReadOnly="True"
-                            MinHeight="100"
+                            MinHeight="200"
                             SelectedItem="{Binding CurrDeliveryReceipt, Mode=TwoWay}"
                             ItemsSource="{Binding DeliveryReceipts, Mode=TwoWay}">
 
@@ -458,23 +454,16 @@
 
                 <!-- 表头信息 -->
                 <Border Grid.Row="1" 
-                    BorderBrush="Gray" 
-                    BorderThickness="1">
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
                     <Grid Background="White">
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
                             <ColumnDefinition Width="*" />
                         </Grid.ColumnDefinitions>
 
-                        <Label Grid.Column="0" 
-                               BorderBrush="Gray" BorderThickness="1 0 1 0" 
-                               Width="100"
-                               Content="表头信息" 
-                               FontWeight="Bold"
-                               VerticalAlignment="Stretch"
-                               HorizontalContentAlignment="Center"
-                               VerticalContentAlignment="Center"
-                               Padding="5" />
+                        <Label Grid.Column="0" Content="表头信息" 
+                               Style="{StaticResource CustomLabelStyle}" />
 
                         <WrapPanel Grid.Column="1" 
                                    Orientation="Horizontal">
@@ -507,23 +496,16 @@
 
                 <!-- 合同信息 -->
                 <Border Grid.Row="2" 
-                    BorderBrush="Gray" 
-                    BorderThickness="1">
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
                     <Grid Background="White">
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
                             <ColumnDefinition Width="*" />
                         </Grid.ColumnDefinitions>
 
-                        <Label Grid.Column="0" 
-                               BorderBrush="Gray" 
-                               BorderThickness="1 0 1 0" 
-                               Width="100"
-                               Content="合同信息"
-                               FontWeight="Bold"
-                               VerticalAlignment="Stretch"
-                               HorizontalContentAlignment="Center"
-                               VerticalContentAlignment="Center" />
+                        <Label Grid.Column="0" Content="合同信息" 
+                               Style="{StaticResource CustomLabelStyle}" />
 
                         <WrapPanel Grid.Column="1" 
                                Orientation="Horizontal">
@@ -564,22 +546,16 @@
 
                 <!-- 发运信息 -->
                 <Border Grid.Row="3" 
-                    BorderBrush="Gray" 
-                    BorderThickness="1">
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
                     <Grid Background="White">
                         <Grid.ColumnDefinitions>
                             <ColumnDefinition Width="auto" />
                             <ColumnDefinition Width="*" />
                         </Grid.ColumnDefinitions>
 
-                        <Label Grid.Column="0"
-                               BorderBrush="Gray" BorderThickness="1 0 1 0" 
-                               Width="100"
-                               Content="发运信息"
-                               FontWeight="Bold"
-                               VerticalAlignment="Stretch"
-                               HorizontalContentAlignment="Center"
-                               VerticalContentAlignment="Center" />
+                        <Label Grid.Column="0" Content="发运信息" 
+                               Style="{StaticResource CustomLabelStyle}" />
 
                         <WrapPanel Grid.Column="1"
                                    Orientation="Horizontal">
@@ -642,14 +618,8 @@
                             <ColumnDefinition Width="*" />
                         </Grid.ColumnDefinitions>
 
-                        <Label Grid.Column="0"
-                               BorderBrush="Gray" BorderThickness="1 0 1 0" 
-                               Width="100"
-                               Content="接收信息"
-                               FontWeight="Bold"
-                               VerticalAlignment="Stretch"
-                               HorizontalContentAlignment="Center"
-                               VerticalContentAlignment="Center" />
+                        <Label Grid.Column="0" Content="接收信息" 
+                               Style="{StaticResource CustomLabelStyle}" />
 
                         <WrapPanel Grid.Column="1"
                                    Orientation="Horizontal">

+ 645 - 4
UniformMaterialManagementSystem/Views/MaterialReceiptPage.xaml

@@ -4,14 +4,655 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:UniformMaterialManagementSystem.Views"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:behavoirs="clr-namespace:UniformMaterialManagementSystem.Behaviors"
+             xmlns:utils="clr-namespace:UniformMaterialManagementSystem.Utils"
+             xmlns:converters="clr-namespace:UniformMaterialManagementSystem.Converters"
+             xmlns:fdg="http://FilterDataGrid.Control.com/2024"
+             xmlns:custom="clr-namespace:UniformMaterialManagementSystem.Custom"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800">
+
+    <UserControl.Resources>
+        <!-- 工具栏按钮模板 -->
+        <ControlTemplate x:Key="CustomToolBarButtomTemplate" TargetType="Button">
+            <!-- 按钮文本超出2个字,设置 Width 宽度自适应。再设置 Padding ,增加按钮左右的空白 -->
+            <Border Width="auto"
+                Background="{TemplateBinding Background}" 
+                CornerRadius="5">
+                <StackPanel HorizontalAlignment="Center" Orientation="Vertical">
+                    <TextBlock HorizontalAlignment="Center"
+                           FontFamily="{StaticResource FluentSystemIconsRegular}"
+                           FontSize="20"
+                           Text="{TemplateBinding Tag}" />
+                    <TextBlock Text="{TemplateBinding Content}"
+                           Padding="5 0 5 0" />
+                </StackPanel>
+            </Border>
+            <ControlTemplate.Triggers>
+                <Trigger Property="IsMouseOver" Value="True">
+                    <Setter Property="Background" Value="LightGray" />
+                </Trigger>
+            </ControlTemplate.Triggers>
+        </ControlTemplate>
+
+        <!-- 列标题模板:必须在列标题样式引用之前定义 -->
+        <ControlTemplate x:Key="CustomColumnHeaderTemplate" TargetType="DataGridColumnHeader">
+            <!-- BorderThickness 分别设置左,上,右,下的边框宽度。 -->
+            <Border BorderThickness="0, 0, 1, 1" BorderBrush="Black">
+                <Grid>
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition />
+                        <ColumnDefinition Width="Auto" />
+                    </Grid.ColumnDefinitions>
+                    <!-- 重定义控件模板,在 Style 中设置的居中属性会被覆盖,所以在这里也需要设置居中 -->
+                    <ContentPresenter Grid.Column="0"
+                          HorizontalAlignment="Center" VerticalAlignment="Center" />
+                    <!-- 列排序图标 -->
+                    <Path x:Name="SortArrow"
+              Grid.Column="1"
+              Margin="0,0,5,0"
+              VerticalAlignment="Center"
+              Data="M 0 0 L 10 0 L 5 5 Z"
+              Fill="Gray"
+              Visibility="Collapsed" />
+                </Grid>
+            </Border>
+            <!-- 列排序按钮 -->
+            <ControlTemplate.Triggers>
+                <Trigger Property="SortDirection" Value="Ascending">
+                    <Setter TargetName="SortArrow" Property="Data" Value="M 0 5 L 10 5 L 5 0 Z" />
+                    <Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
+                </Trigger>
+                <Trigger Property="SortDirection" Value="Descending">
+                    <Setter TargetName="SortArrow" Property="Data" Value="M 0 0 L 10 0 L 5 5 Z" />
+                    <Setter TargetName="SortArrow" Property="Visibility" Value="Visible" />
+                </Trigger>
+            </ControlTemplate.Triggers>
+        </ControlTemplate>
+
+        <!-- 列标题样式 -->
+        <Style x:Key="CustomColumnHeaderStyle" TargetType="DataGridColumnHeader">
+            <Setter Property="Background" Value="White" />
+            <Setter Property="Foreground" Value="Black" />
+            <Setter Property="FontWeight" Value="Bold" />
+            <Setter Property="HorizontalContentAlignment" Value="Center" />
+            <Setter Property="VerticalContentAlignment" Value="Center" />
+            <Setter Property="Height" Value="40" />
+            <Setter Property="Template" Value="{StaticResource CustomColumnHeaderTemplate}" />
+        </Style>
+
+        <!-- 行标题样式 -->
+        <Style x:Key="CustomRowHeaderStyle" TargetType="DataGridRowHeader">
+            <!-- 通过 Template 设置行号、居中、边框 -->
+            <Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate TargetType="DataGridRowHeader">
+                        <!-- 在这里设置 Width 会受到 DataGrid.RowHeaderWidth 的限制,显示不全 -->
+                        <Label Width="30"
+                           Background="White"
+                           BorderBrush="Black"
+                           BorderThickness="0 0 1 1"
+                           Content="{Binding Path=Header, RelativeSource={RelativeSource AncestorType=DataGridRow}}"
+                           HorizontalContentAlignment="Center" />
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
+        </Style>
+
+        <!-- DataGrid 左上角样式 -->
+        <Style TargetType="Button" 
+           x:Key="{ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle, TypeInTargetAssembly={x:Type DataGrid}}">
+            <!-- 模板里面放 Border 添加边框 -->
+            <Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate TargetType="Button">
+                        <Border Background="White" 
+                            BorderBrush="Black"
+                            BorderThickness="0 0 1 1" />
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
+        </Style>
+
+        <!-- 行样式 -->
+        <Style x:Key="CustomRowStyle" TargetType="DataGridRow">
+            <Setter Property="Background" Value="White" />
+            <Setter Property="FontSize" Value="14" />
+            <Setter Property="Height" Value="30" />
+
+            <Style.Triggers>
+                <Trigger Property="AlternationIndex" Value="1">
+                    <Setter Property="Background" Value="WhiteSmoke" />
+                </Trigger>
+                <Trigger Property="IsSelected" Value="True">
+                    <Setter Property="Background" Value="LightBlue" />
+                </Trigger>
+            </Style.Triggers>
+        </Style>
+
+        <!-- todo 为什么必须设置文本列样式之后才能居中,单元格设置不起作用? -->
+        <!-- 单元格样式 -->
+        <Style x:Key="CustomCellStyle" TargetType="DataGridCell"
+           BasedOn="{StaticResource {x:Type DataGridCell}}">
+            <Setter Property="Background" Value="White" />
+            <Setter Property="HorizontalContentAlignment" Value="Center" />
+            <Setter Property="VerticalContentAlignment" Value="Center" />
+            <Setter Property="Padding" Value="10" />
+            <Setter Property="BorderThickness" Value="0" />
+            <Style.Triggers>
+                <Trigger Property="IsSelected" Value="True">
+                    <Setter Property="Background" Value="LightBlue" />
+                    <Setter Property="Foreground" Value="Black" />
+                </Trigger>
+            </Style.Triggers>
+        </Style>
+
+        <!--  文本列居中  -->
+        <Style x:Key="TextColumnElementStyle" TargetType="TextBlock">
+            <Setter Property="HorizontalAlignment" Value="Center" />
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="TextAlignment" Value="Center" />
+        </Style>
+
+        <!-- 文本列编辑状态居左 -->
+        <Style x:Key="TextColumnEditingStyle" TargetType="TextBox">
+            <Setter Property="HorizontalContentAlignment" Value="Left" />
+            <Setter Property="VerticalContentAlignment" Value="Center" />
+        </Style>
+
+        <!-- 复选框列居中 -->
+        <Style x:Key="CheckBoxColumnElementStyle" TargetType="CheckBox">
+            <Setter Property="HorizontalAlignment" Value="Center" />
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="Padding" Value="0, 5, 0, 5" />
+        </Style>
+
+        <!-- Label 样式:自带边框 -->
+        <Style x:Key="CustomLabelStyle" TargetType="Label">
+            <Setter Property="BorderBrush" Value="Gray" />
+            <Setter Property="BorderThickness" Value="1 0 1 0" />
+            <Setter Property="Width" Value="100" />
+            <Setter Property="FontWeight" Value="Bold" />
+            <Setter Property="VerticalAlignment" Value="Stretch" />
+            <Setter Property="HorizontalContentAlignment" Value="Center" />
+            <Setter Property="VerticalContentAlignment" Value="Center" />
+            <!--<Setter Property="FontSize" Value="14" />-->
+        </Style>
+
+        <!-- todo Template 里的使用样式;特殊的字段单独设置样式和模板 -->
+        <!-- 编辑界面字段 -->
+        <Style x:Key="CustomFieldTextBoxStyle" TargetType="TextBox">
+            <Setter Property="Template" >
+                <Setter.Value>
+                    <ControlTemplate>
+                        <StackPanel Orientation="Horizontal">
+                            <TextBlock Text="{Binding Tag, RelativeSource={RelativeSource TemplatedParent}}"
+                                   Width="100"
+                                   Height="20"
+                                   FontSize="14"
+                                   VerticalAlignment="Center"
+                                   TextAlignment="Right"
+                                   Margin="5" />
+                            <TextBox Text="{Binding Text, RelativeSource={RelativeSource TemplatedParent}}" 
+                                 IsEnabled="{Binding IsEnabled, RelativeSource={RelativeSource TemplatedParent}}"
+                                 BorderBrush="Gray"
+                                 BorderThickness="1"
+                                 Width="250"
+                                 Height="30"
+                                 FontSize="14"
+                                 HorizontalContentAlignment="Center"
+                                 VerticalContentAlignment="Center"
+                                 Margin="0 5 0 5" />
+                        </StackPanel>
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>
+        </Style>
+
+        <!-- TextBlock 样式 -->
+        <Style x:Key="CustomTextBlockStyle" TargetType="TextBlock">
+            <Setter Property="Width" Value="100" />
+            <Setter Property="Height" Value="20" />
+            <Setter Property="FontSize" Value="14" />
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="TextAlignment" Value="Right" />
+            <Setter Property="Margin" Value="5" />
+        </Style>
+
+        <!-- 转换器 -->
+        <converters:MultiParamConverter x:Key="MultiParamConverter" />
+
+    </UserControl.Resources>
+
     <Grid>
-        <Border BorderBrush="Gray"
-                BorderThickness="1"
-                Background="White">
-            <ContentControl x:Name="currContentControl" />
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="*" />
+            <ColumnDefinition Width="*" />
+        </Grid.ColumnDefinitions>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="auto" />
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>
+
+        <!-- 主表工具栏 -->
+        <Border x:Name="toolBarDelivery"
+                Grid.Row="0" 
+                Grid.Column="0"
+                Grid.ColumnSpan="2"
+                BorderBrush="Gray"
+                BorderThickness="1">
+            <ToolBar Background="White"
+                     ToolBarTray.IsLocked="True">
+                <Button Content="保存" 
+                        Tag="{x:Static utils:RegularFontUtil.Save_32}"
+                        Template="{StaticResource CustomToolBarButtomTemplate}"
+                        Command="{Binding SaveCommand}"
+                        CommandParameter="{Binding ElementName=cbReceivedStatus}" />
+                <Separator />
+                <Button x:Name="btnCheck"
+                        Content="复核" 
+                        Tag="{x:Static utils:RegularFontUtil.Clipboard_Checkmark_24}"
+                        Template="{StaticResource CustomToolBarButtomTemplate}"
+                        Command="{Binding CheckCommand}"
+                        CommandParameter="{Binding ElementName=cbReceivedStatus}" />
+                <Separator />
+                <Button x:Name="btnExportThree"
+                        Content="导出附件3" 
+                        Tag="{x:Static utils:RegularFontUtil.Open_32}"
+                        Template="{StaticResource CustomToolBarButtomTemplate}"
+                        Command="{Binding ExportThreeCommand}" />
+                <Separator />
+                <Button Content="导出数据包" 
+                    Tag="{x:Static utils:RegularFontUtil.Arrow_Export_Up_24}"
+                    Template="{StaticResource CustomToolBarButtomTemplate}"
+                    Command="{Binding ExportDBCommand}" />
+                <Button Content="导入数据包" 
+                    Tag="{x:Static utils:RegularFontUtil.Arrow_Download_24}"
+                    Template="{StaticResource CustomToolBarButtomTemplate}"
+                    Command="{Binding ImportDBCommand}" />
+
+            </ToolBar>
+        </Border>
+
+        <!-- 主表 -->
+        <fdg:FilterDataGrid x:Name="fdgDelivery"
+                            Grid.Row="1" 
+                            Grid.Column="0"
+                            Grid.ColumnSpan="2"
+                            FilterLanguage="SimplifiedChinese"
+                            Background="White"
+                            AutoGenerateColumns="False"
+                            CanUserAddRows="False"
+                            CanUserResizeRows="False"
+                            CanUserResizeColumns="True"
+                            SelectionMode="Single"
+                            SelectionUnit="FullRow"
+                            HeadersVisibility="All"
+                            ShowRowsCount="True"
+                            RowHeaderWidth="30"
+                            LoadingRow="DataGrid_LoadingRow"
+                            ColumnHeaderStyle="{StaticResource CustomColumnHeaderStyle}"
+                            RowHeaderStyle="{StaticResource CustomRowHeaderStyle}"
+                            RowStyle="{StaticResource CustomRowStyle}"
+                            CellStyle="{StaticResource CustomCellStyle}"
+                            IsReadOnly="True"
+                            MinHeight="200"
+                            SelectedItem="{Binding CurrDeliveryReceipt, Mode=TwoWay}"
+                            ItemsSource="{Binding DeliveryReceipts, Mode=TwoWay}">
+
+            <!-- DataGrid 事件 -->
+            <b:Interaction.Triggers>
+                <b:EventTrigger EventName="SelectionChanged">
+                    <b:CallMethodAction TargetObject="{Binding }" 
+                                        MethodName="FdgDelivery_SelectionChanged" />
+                </b:EventTrigger>
+            </b:Interaction.Triggers>
+
+            <!-- 数据结构 -->
+            <fdg:FilterDataGrid.Columns>
+                <fdg:FilterDataGridTextColumn Header="合同编号" Width="200"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ContractNo}" />
+                <fdg:FilterDataGridTextColumn Header="产品名称" Width="250"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ProductName}" />
+                <fdg:FilterDataGridTextColumn Header="生产企业" Width="250"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding CompanyName}" />
+                <fdg:FilterDataGridTextColumn Header="接收单位" Width="250"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedCompanyName}" />
+                <fdg:FilterDataGridTextColumn Header="发运包数" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ShippedPackets}" />
+                <fdg:FilterDataGridTextColumn Header="发运数量" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ShippedQty}" />
+                <fdg:FilterDataGridTextColumn Header="发运时间" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ShippedDate, StringFormat='yyyy/MM/dd'}" />
+                <fdg:FilterDataGridTextColumn Header="发运承办人" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ShippedMan}" />
+                <fdg:FilterDataGridTextColumn Header="发运联系电话" Width="200"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ShippedTel}" />
+                <fdg:FilterDataGridTextColumn Header="接收包数" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedPackets}" />
+                <fdg:FilterDataGridTextColumn Header="接收数量" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedQty}"  />
+                <fdg:FilterDataGridTextColumn Header="接收时间" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedDate, StringFormat='yyyy/MM/dd'}" />
+                <fdg:FilterDataGridTextColumn Header="接收承办人" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedMan}" />
+                <fdg:FilterDataGridTextColumn Header="接收联系电话" Width="200"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedTel}" />
+                <fdg:FilterDataGridTextColumn Header="接收状态" Width="100"
+                                          IsColumnFiltered="True"
+                                          ElementStyle="{StaticResource TextColumnElementStyle}"
+                                          Binding="{Binding ReceivedStatus}" />
+            </fdg:FilterDataGrid.Columns>
+        </fdg:FilterDataGrid>
+
+        <!-- 水平拖动分割线 -->
+        <GridSplitter Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Height="5"  HorizontalAlignment="Stretch" />
+
+        <!-- 发货单信息界面 -->
+        <Border Grid.Row="3" 
+                Grid.RowSpan="2"
+                Grid.Column="0"
+                BorderBrush="Gray"
+                BorderThickness="1">
+            <Grid Background="White">
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="*" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="auto" />
+                    <RowDefinition Height="*" />
+                </Grid.RowDefinitions>
 
+                <!-- 表头信息 -->
+                <Border Grid.Row="1" 
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
+                    <Grid Background="White">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+
+                        <Label Grid.Column="0" Content="表头信息" 
+                               Style="{StaticResource CustomLabelStyle}" />
+
+                        <WrapPanel Grid.Column="1" 
+                                   Orientation="Horizontal">
+                            <TextBox Tag="产品名称:"
+                                     Text="{Binding CurrDeliveryReceipt.ProductName}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="生产企业:"
+                                     Text="{Binding CurrDeliveryReceipt.CompanyName}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+
+                        </WrapPanel>
+                    </Grid>
+
+                </Border>
+
+                <!-- 合同信息 -->
+                <Border Grid.Row="2" 
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
+                    <Grid Background="White">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+
+                        <Label Grid.Column="0" Content="合同信息"
+                               Style="{StaticResource CustomLabelStyle}" />
+
+                        <WrapPanel Grid.Column="1" 
+                                   Orientation="Horizontal">
+                            <TextBox Tag="合同编号:"
+                                     Text="{Binding CurrDeliveryReceipt.ContractNo}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="采购机构:"
+                                     Text="{Binding CurrDeliveryReceipt.PurchaseCompanyName}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="合同数量:"
+                                     Text="{Binding CurrDeliveryReceipt.ContractQty}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="合同时间:"
+                                     Text="{Binding CurrDeliveryReceipt.ContractSigningDate, StringFormat='yyyy/MM/dd'}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+
+                        </WrapPanel>
+                    </Grid>
+
+                </Border>
+
+                <!-- 发运信息 -->
+                <Border Grid.Row="3" 
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
+                    <Grid Background="White">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+
+                        <Label Grid.Column="0" Content="发运信息"
+                               Style="{StaticResource CustomLabelStyle}" />
+
+                        <WrapPanel Grid.Column="1"
+                                   Orientation="Horizontal">
+                            <TextBox Tag="接收单位:"
+                                     Text="{Binding CurrDeliveryReceipt.ReceivedCompanyName}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="发运包数:"
+                                     Text="{Binding CurrDeliveryReceipt.ShippedPackets}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="发运数量:"
+                                     Text="{Binding CurrDeliveryReceipt.ShippedQty}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="发运时间:"
+                                     Text="{Binding CurrDeliveryReceipt.ShippedDate, StringFormat= 'yyyy/MM/dd'}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox x:Name="fieldShippedMan"
+                                     Tag="发运承办人:"
+                                     Text="{Binding CurrDeliveryReceipt.ShippedMan}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox x:Name="fieldShippedTel"
+                                     Tag="联系电话:"
+                                     Text="{Binding CurrDeliveryReceipt.ShippedTel}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                        </WrapPanel>
+                    </Grid>
+
+                </Border>
+
+                <!-- 接收信息 -->
+                <Border x:Name="borderReceipt"
+                        Grid.Row="4" 
+                        BorderBrush="Gray" 
+                        BorderThickness="1">
+                    <Grid Background="White">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="auto" />
+                            <ColumnDefinition Width="*" />
+                        </Grid.ColumnDefinitions>
+
+                        <Label Grid.Column="0" Content="接收信息"
+                               Style="{StaticResource CustomLabelStyle}" />
+
+                        <WrapPanel Grid.Column="1"
+                                   Orientation="Horizontal">
+                            <TextBox Tag="接收包数:"
+                                     Text="{Binding CurrDeliveryReceipt.ReceivedPackets}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox Tag="接收数量:"
+                                     Text="{Binding CurrDeliveryReceipt.ReceivedQty}"
+                                     IsEnabled="False"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+
+                            <!-- 接收时间 -->
+                            <StackPanel Orientation="Horizontal">
+                                <TextBlock Text="接收时间:"
+                                           Foreground="Black"
+                                           Style="{StaticResource CustomTextBlockStyle}" />
+                                <DatePicker x:Name="dpReceivedDate"
+                                            Width="250" 
+                                            Text="{Binding CurrDeliveryReceipt.ReceivedDate, Mode=TwoWay}"
+                                            SelectedDateFormat="Short"
+                                            HorizontalContentAlignment="Center"
+                                            VerticalContentAlignment="Center"
+                                            Height="30"
+                                            FontSize="14" />
+                            </StackPanel>
+
+                            <TextBox x:Name="fieldReceivedMan"
+                                     Tag="接收承办人:"
+                                     Text="{Binding CurrDeliveryReceipt.ReceivedMan}"
+                                     IsEnabled="True"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+                            <TextBox x:Name="fieldReceivedTel"
+                                     Tag="联系电话:"
+                                     Text="{Binding CurrDeliveryReceipt.ReceivedTel}"
+                                     IsEnabled="True"
+                                     Style="{StaticResource CustomFieldTextBoxStyle}" />
+
+                            <!-- 收货单状态 -->
+                            <StackPanel Orientation="Horizontal">
+                                <TextBlock x:Name="tBlkReceivedStatus"
+                                           Text="收货单状态*:"
+                                           Foreground="Black"
+                                           Style="{StaticResource CustomTextBlockStyle}" />
+                                <ComboBox x:Name="cbReceivedStatus"
+                                          Width="250"
+                                          Height="30"
+                                          FontSize="14"
+                                          HorizontalContentAlignment="Center"
+                                          VerticalContentAlignment="Center"
+                                          ItemsSource="{Binding StatusItems}"
+                                          SelectedItem="{Binding CurrDeliveryReceipt.ReceivedStatus}" />
+                            </StackPanel>
+                        </WrapPanel>
+                    </Grid>
+                </Border>
+
+            </Grid>
         </Border>
+
+        <!-- 明细表工具栏 -->
+        <Border Grid.Row="3" 
+                Grid.Column="1" 
+                BorderBrush="Gray"
+                BorderThickness="1"
+                Height="{Binding Path=ActualHeight,ElementName=toolBarDelivery}">
+            <ToolBar Background="White"
+                     ToolBarTray.IsLocked="True">
+                <Button Content="全部接收"
+                        Tag="{x:Static utils:RegularFontUtil.Clipboard_Checkmark_24}"
+                        Template="{StaticResource CustomToolBarButtomTemplate}"
+                        Command="{Binding ReceiveAllCommand}"
+                        CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor,  AncestorType={x:Type UserControl}}}" />
+            </ToolBar>
+        </Border>
+
+        <!-- 明细表 -->
+        <fdg:FilterDataGrid x:Name="fdgDeliveryDetail"
+                            Grid.Row="4" 
+                            Grid.Column="1" 
+                            Background="White"
+                            AutoGenerateColumns="False"
+                            CanUserAddRows="False"
+                            CanUserResizeRows="False"
+                            SelectionMode="Extended"
+                            SelectionUnit="CellOrRowHeader"
+                            HeadersVisibility="All"
+                            GridLinesVisibility="All"
+                            ShowRowsCount="True"
+                            RowHeaderWidth="30"
+                            LoadingRow="DataGrid_LoadingRow"
+                            ColumnHeaderStyle="{StaticResource CustomColumnHeaderStyle}"
+                            RowHeaderStyle="{StaticResource CustomRowHeaderStyle}"
+                            RowStyle="{StaticResource CustomRowStyle}"
+                            CellStyle="{StaticResource CustomCellStyle}"
+                            ItemsSource="{Binding CurrDeliveryReceipt.DeliveryReceiptDetails, Mode=TwoWay}">
+
+            <!-- DataGrid 事件 -->
+            <b:Interaction.Triggers>
+                <b:EventTrigger EventName="SelectedCellsChanged">
+                    <b:CallMethodAction TargetObject="{Binding }"
+                                    MethodName="FdgDeliveryDetail_SelectedCellsChanged" />
+                </b:EventTrigger>
+            </b:Interaction.Triggers>
+
+            <!-- 数据结构 -->
+            <fdg:FilterDataGrid.Columns>
+                <fdg:FilterDataGridTextColumn Header="材料批号" Width="200"
+                                              ElementStyle="{StaticResource TextColumnElementStyle}"
+                                              EditingElementStyle="{StaticResource TextColumnEditingStyle}"
+                                              Binding="{Binding BatchNo}"
+                                              IsReadOnly="True" />
+                <fdg:FilterDataGridTextColumn Header="包号" Width="100"
+                                              ElementStyle="{StaticResource TextColumnElementStyle}"
+                                              EditingElementStyle="{StaticResource TextColumnEditingStyle}"
+                                              Binding="{Binding PacketNo}"
+                                              IsReadOnly="True" />
+                <fdg:FilterDataGridTextColumn Header="发运数量" Width="100"
+                                              ElementStyle="{StaticResource TextColumnElementStyle}"
+                                              EditingElementStyle="{StaticResource TextColumnEditingStyle}"
+                                              Binding="{Binding ShippedQuantity}" 
+                                              IsReadOnly="True" />
+                <fdg:FilterDataGridTextColumn Header="接收数量*" Width="100"
+                                              ElementStyle="{StaticResource TextColumnElementStyle}"
+                                              EditingElementStyle="{StaticResource TextColumnEditingStyle}"
+                                              Binding="{Binding ReceiveQuantity, UpdateSourceTrigger=PropertyChanged, StringFormat='#0.0'}" />
+                <fdg:FilterDataGridTextColumn Header="备注" Width="200"
+                                              ElementStyle="{StaticResource TextColumnElementStyle}"
+                                              EditingElementStyle="{StaticResource TextColumnEditingStyle}"
+                                              Binding="{Binding ShipNote, UpdateSourceTrigger=PropertyChanged}" />
+            </fdg:FilterDataGrid.Columns>
+        </fdg:FilterDataGrid>
     </Grid>
+    
 </UserControl>

+ 9 - 2
UniformMaterialManagementSystem/Views/MaterialReceiptPage.xaml.cs

@@ -12,6 +12,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
+using Microsoft.Extensions.DependencyInjection;
 using UniformMaterialManagementSystem.ViewModels;
 
 namespace UniformMaterialManagementSystem.Views
@@ -25,8 +26,14 @@ namespace UniformMaterialManagementSystem.Views
         {
             InitializeComponent();
 
-            // 展示材料接收单
-            this.currContentControl.Content = new DeliveryReceiptControl(DeliveryPageCategroy.Receipt);
+            // 绑定 ViewModel
+            this.DataContext = App.Current.Services.GetService<MaterialReceiptViewModel>();
+        }
+
+        private void DataGrid_LoadingRow(object? sender, DataGridRowEventArgs e)
+        {
+            // 设置行标题:行索引+1
+            e.Row.Header = e.Row.GetIndex() + 1;
         }
     }
 }