Forráskód Böngészése

Merge branch 'master' of https://git.xxb.lttc.cn/wangbc/UniformMaterialManagementSystem

宝臣 王 3 hónapja
szülő
commit
e4f8328b8c

+ 3 - 0
UniformMaterialManagementSystem/Entities/DeliveryReceiptDetail.cs

@@ -31,5 +31,8 @@ namespace UniformMaterialManagementSystem.Entities
 
         [NotMapped]
         public bool IsNewRow { get; set; } = true;
+
+        [NotMapped]
+        public bool IsSelected { get; set; }
     }
 }

BIN
UniformMaterialManagementSystem/Template/军需物资质量检验申请表模板_附表.docx


+ 10 - 0
UniformMaterialManagementSystem/Utils/CommonUtil.cs

@@ -13,6 +13,16 @@ namespace UniformMaterialManagementSystem.Utils
         ProductCompany,
         Supervision
     }
+
+    /// <summary>
+    /// 单据状态
+    /// </summary>
+    public enum BillStatus
+    {
+        Add,
+        Modify
+    }
+
     public static class CommonUtil
     {
         

+ 7 - 7
UniformMaterialManagementSystem/Utils/InspectApplyUtil.cs

@@ -170,31 +170,31 @@ namespace UniformMaterialManagementSystem.Utils
         /// <summary>
         /// 导出检验申请表附表
         /// </summary>
-        public static void ExportInspectApplyAttachedPdf(InspectApply inspectApply)
+        public static void ExportInspectApplyAttached(InspectApply inspectApply)
         {
             var templateFilePath = "Template\\军需物资质量检验申请表模板_附表.docx";
 
             SaveFileDialog saveFileDialog = new SaveFileDialog()
             {
                 FileName = "被装材料检验申请-附表-" + inspectApply.ApplyNo + "-" + WordUtil.GenerateFileSerialNumber(),
-                Filter = "PDF文件格式 (*.pdf)|*.pdf",
+                Filter = "word文件格式 (*.docx)|*.docx",
                 Title = "请选择检验申请表导出的位置"
             };
             if (saveFileDialog.ShowDialog() == false) return;
             var destinationFile = saveFileDialog.FileName;
 
-            var tempFile = $"Template\\temp_{WordUtil.GenerateFileSerialNumber()}.docx";
+            //var tempFile = $"Template\\temp_{WordUtil.GenerateFileSerialNumber()}.docx";
 
-            File.Copy(templateFilePath, tempFile);
+            File.Copy(templateFilePath, destinationFile);
             //将申请表明细行,包号、数量组成list
             var packetNoList = GetPacketNoList(inspectApply);
 
-            GenerateInspectApplyAttachedFile(tempFile, packetNoList, inspectApply);
+            GenerateInspectApplyAttachedFile(destinationFile, packetNoList, inspectApply);
 
             //将tempFile转换成pdf文件
-            WordUtil.SaveWordToPdf(tempFile, destinationFile);
+            //WordUtil.SaveWordToPdf(tempFile, destinationFile);
             //删除临时文件
-            File.Delete(tempFile);
+            //File.Delete(tempFile);
 
             MessageBox.Show("文档已生成!");
         }

+ 23 - 22
UniformMaterialManagementSystem/ViewModels/ContractPageViewModel.cs

@@ -78,7 +78,7 @@ namespace UniformMaterialManagementSystem.ViewModels
         [ObservableProperty]
         private ContractModel? _selectedUnExportContract;
 
-        private string _contactStatus = "Add";//Add:新增 Modify:修改
+        private BillStatus _contactStatus = BillStatus.Add;
 
         #endregion
 
@@ -199,7 +199,7 @@ namespace UniformMaterialManagementSystem.ViewModels
 
             ClearInput();
 
-            _contactStatus = "Add";
+            _contactStatus = BillStatus.Add;
         }
 
         /// <summary>
@@ -215,7 +215,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             //绑定数据源
             BindSelectedContractAndDetail();
 
-            _contactStatus = "Modify";
+            _contactStatus = BillStatus.Modify;
         }
 
         private void BindSelectedContractAndDetail()
@@ -231,8 +231,9 @@ namespace UniformMaterialManagementSystem.ViewModels
             Attachment = SelectedUnExportContract.Attachment;
             ApplyAttachment = SelectedUnExportContract.ApplyAttachment;
 
+            var existDetails = _contractDetailService.QueryNoTracking(x => x.ContractGuid == SelectedUnExportContract.Guid).Include(x=>x.Material).ToList();
             ContractDetails.Clear();
-            foreach (var detail in SelectedUnExportContract.ContractDetails)
+            foreach (var detail in existDetails)
             {
                 ContractDetails.Add(detail);
             }
@@ -274,7 +275,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            if ("Add".Equals(_contactStatus))  //新增
+            if (_contactStatus == BillStatus.Add)  //新增
             {
                 var success = SaveContractAndDetail();
                 if (success == null || !(bool)success) return;
@@ -286,7 +287,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                 /* 清空界面数据 */
                 ClearInput();
             }
-            else if ("Modify".Equals(_contactStatus)) //修改
+            else if (_contactStatus == BillStatus.Modify) //修改
             {
                 if (SelectedUnExportContract == null)
                 {
@@ -702,20 +703,20 @@ namespace UniformMaterialManagementSystem.ViewModels
                 return;
             }
 
-            if ("Modify".Equals(_contactStatus))
-            {
-                //var detail = _contractDetailService?.Get(x => x.Guid == _selectedContractDetail.Guid);
-                //if (detail != null)
-                //{
-                //    _contractDetailService?.Delete(_selectedContractDetail);
-                //}
-
-                var detail = SelectedUnExportContract?.ContractDetails.FirstOrDefault(x => x.Guid == _selectedContractDetail.Guid);
-                if (detail != null)
-                {
-                    SelectedUnExportContract?.ContractDetails.Remove(detail);
-                }
-            }
+            //if ("Modify".Equals(_contactStatus))
+            //{
+            //    //var detail = _contractDetailService?.Get(x => x.Guid == _selectedContractDetail.Guid);
+            //    //if (detail != null)
+            //    //{
+            //    //    _contractDetailService?.Delete(_selectedContractDetail);
+            //    //}
+
+            //    var detail = SelectedUnExportContract?.ContractDetails.FirstOrDefault(x => x.Guid == _selectedContractDetail.Guid);
+            //    if (detail != null)
+            //    {
+            //        SelectedUnExportContract?.ContractDetails.Remove(detail);
+            //    }
+            //}
 
             ContractDetails.Remove(_selectedContractDetail);
         }
@@ -788,7 +789,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
 
             /* 校验材料合同号不重复 */
-            if ("Add".Equals(_contactStatus))
+            if (_contactStatus == BillStatus.Add)
             {
                 var contract = _contractService.Get(x => x.ContractNo == ContractNo);
                 if (contract != null)
@@ -796,7 +797,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                     errorMessage.Append($"材料合同号【{ContractNo}】已存在,不允许重复录入!\n");
                 }
             }
-            else if ("Modify".Equals(_contactStatus))
+            else if (_contactStatus == BillStatus.Modify)
             {
                 var count = _contractService.GetAll(x => x.ContractNo == ContractNo).ToList().Count;
                 if (count > 1)

+ 348 - 108
UniformMaterialManagementSystem/ViewModels/DeliveryReceiptViewModel.cs

@@ -13,6 +13,7 @@ using System.Windows.Controls;
 using System.Windows.Media.Media3D;
 using CommunityToolkit.Mvvm.ComponentModel;
 using CommunityToolkit.Mvvm.Input;
+using DocumentFormat.OpenXml.Office2016.Drawing.ChartDrawing;
 using DocumentFormat.OpenXml.Spreadsheet;
 using Microsoft.EntityFrameworkCore;
 using Microsoft.Extensions.DependencyInjection;
@@ -151,8 +152,11 @@ namespace UniformMaterialManagementSystem.ViewModels
                         continue;
                     }
 
-                    // 批次号和包号只能导入,只允许编辑发运数量和备注列
-                    col.IsReadOnly = header.Equals("发运数量*") || header.Equals("备注") ? false : true;
+                    // 发运数量列必录,所有列都可编辑
+                    if (header.Equals("发运数量"))
+                    {
+                        col.Header = "发运数量*";
+                    }
                 }
             }
             else if (_deliveryPageCategroy == DeliveryPageCategroy.Receipt)
@@ -192,10 +196,21 @@ namespace UniformMaterialManagementSystem.ViewModels
                         continue;
                     }
 
-                    // todo 其他列的 * 去掉
-
-                    // 只允许编辑接收数量和备注列
-                    col.IsReadOnly = header.Equals("接收数量*") || header.Equals("备注") ? false : true;
+                    // 接收数量列必录且可编辑
+                    if (header.Equals("接收数量"))
+                    {
+                        col.IsReadOnly = false;
+                        col.Header = "接收数量*";
+                        continue;
+                    }
+                    // 备注列可编辑
+                    if (header.Equals("备注"))
+                    {
+                        col.IsReadOnly = false;
+                        continue;
+                    }
+                    // 其他列只读
+                    col.IsReadOnly = true;
                 }
             }
             else if (_deliveryPageCategroy == DeliveryPageCategroy.Usage)
@@ -209,7 +224,10 @@ namespace UniformMaterialManagementSystem.ViewModels
                 // 发运字段不可编辑
                 page.tBlkShippedDate.Text = "发运时间:";
                 page.dpShippedDate.IsEnabled = page.fieldShippedMan.IsEnabled = page.fieldShippedTel.IsEnabled = false;
-                // todo 接收字段不可编辑 下拉列表的标题去掉 *
+
+                // 接收字段不可编辑
+                page.tBlkReceivedStatus.Text = "收货单状态:";
+                page.dpReceivedDate.IsEnabled = page.fieldReceivedMan.IsEnabled = page.fieldReceivedTel.IsEnabled = page.cbReceivedStatus.IsEnabled = false;
 
                 // 隐藏明细发货和接收按钮
                 page.btnAddDtl.Visibility = page.btnDeleteDtl.Visibility = page.sep2.Visibility = page.btnImportDtl.Visibility = page.btnExportDtl.Visibility = page.btnReceiveDtl.Visibility = Visibility.Collapsed;
@@ -233,14 +251,27 @@ namespace UniformMaterialManagementSystem.ViewModels
                         continue;
                     }
 
-                    // 只允许编辑使用数量和备注列
-                    col.IsReadOnly = header.Equals("使用数量*") || header.Equals("备注") ? false : true;
+                    // 使用数量列必录且可编辑
+                    if (header.Equals("使用数量"))
+                    {
+                        col.IsReadOnly = false;
+                        col.Header = "使用数量*";
+                        continue;
+                    }
+                    // 备注列可编辑
+                    if (header.Equals("备注"))
+                    {
+                        col.IsReadOnly = false;
+                        continue;
+                    }
+                    // 其他列只读
+                    col.IsReadOnly = true;
                 }
             }
         }
 
         // CallMethodAction 不需要注册命令,可以传递事件参数。参数列表必须与事件自带的参数列表保持一致
-        public void DeliverySelectionChanged(object sender, SelectionChangedEventArgs args)
+        public void fdgDelivery_SelectionChanged(object sender, SelectionChangedEventArgs args)
         {
             // 手动屏蔽本事件
             if (!_isExcute) { return; }
@@ -350,7 +381,7 @@ namespace UniformMaterialManagementSystem.ViewModels
             // 发运数量:自动汇总子表
             // 联系电话:手动输入
 
-            OnPropertyChanged(CommunityToolkit.Mvvm.ComponentModel.__Internals.__KnownINotifyPropertyChangedArgs.CurrDeliveryReceipt);
+            OnPropertyChanged(new PropertyChangedEventArgs("CurrDeliveryReceipt"));
         }
 
         [RelayCommand]
@@ -414,67 +445,27 @@ namespace UniformMaterialManagementSystem.ViewModels
             if (CurrDeliveryReceipt == null) { return; }
             if (CurrDeliveryReceipt.IsExportDelivery || CurrDeliveryReceipt.IsExportReceive || CurrDeliveryReceipt.IsExportUsage) { return; }
 
-            // todo 主表和子表 带 * 的列必录
-            // 判断主表必录项:主表不允许编辑,判断编辑界面控件的值
+            // 删除子表空行
+            DeleteEmptyRows();
+
+            // 保存前校验
+            bool canSave = false;
             switch (_deliveryPageCategroy)
             {
                 case DeliveryPageCategroy.Delivery:
-                    // todo 清空日期选择框,但 发运日期 并不会清空
-                    if (string.IsNullOrWhiteSpace(page.dpShippedDate.Text)) // DateTime 类型永远不等于 null
-                    {
-                        MessageBox.Show("发运时间为空,不允许保存!");
-                        return;
-                    }
+                    canSave = VerifyDelivery(page.dpShippedDate);
                     break;
                 case DeliveryPageCategroy.Receipt:
-                    if (string.IsNullOrEmpty(CurrDeliveryReceipt.ReceivedStatus))
-                    {
-                        MessageBox.Show("收货单状态为空,不允许保存!");
-                        return;
-                    }
+                    canSave = VerifyReceipt();
                     break;
                 case DeliveryPageCategroy.Usage:
-                    if (CurrDeliveryReceipt.Licence == null)
-                    {
-                        MessageBox.Show("未上传许可证,不允许保存!");
-                        return;
-                    }
+                    canSave = VerifyUsage();
                     break;
             }
 
-            // 判断子表必录项:带 * 的列必录(不好实现,先固定检查每一列)
-            var nullBatchNoRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => string.IsNullOrEmpty(x.BatchNo));
-            var nullPackageNoRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => string.IsNullOrEmpty(x.PacketNo));
-            var nullShippedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.ShippedQuantity == 0);
-            var nullReceivedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.ReceiveQuantity == 0);
-            var nullUsageQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.UsageQuantity == 0);
-            // 根据页面类型校验子表必录项
-
-            // 删除子表空行
-            DeleteEmptyRows();
-
-            // todo 子表新增行和删除行和修改列时实时计算
-            // 计算发运包数和发运数量
-            int packNum = CurrDeliveryReceipt.DeliveryReceiptDetails.Count;
-            CurrDeliveryReceipt.ShippedPackets = packNum;
-            double shippedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Select(x => x.ShippedQuantity).Sum();
-            CurrDeliveryReceipt.ShippedQty = shippedQty;
-
-            // 检查发运数量不能超出可发运数量
-            if (CurrDeliveryReceipt.ShippedQty >= CurrDeliveryReceipt.RemainQty)
-            {
-                MessageBox.Show("发货数量超出可发运数量,请检查数据后重新保存!");
-                return;
-            }
-
-            // 检查子表的包号不允许重复
-            // 保存时检查材料名称是否存在重复项
-            var repeatPacketNos = CurrDeliveryReceipt.DeliveryReceiptDetails.GroupBy(x => x.PacketNo).Where(g => g.Count() > 1).Select(g => g.Key);
-            if (repeatPacketNos.Any())
+            // 校验不通过,直接返回
+            if (!canSave)
             {
-                // 若存在重复项则提示后返回
-                string repeatPacketNoText = string.Join("、", repeatPacketNos.ToArray());
-                MessageBox.Show("材料包号列存在以下重复值,请修改后保存:" + repeatPacketNoText, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                 return;
             }
 
@@ -493,7 +484,6 @@ namespace UniformMaterialManagementSystem.ViewModels
             {
                 // 已保存行更新到数据库
                 // todo 主表已保存,但子表明细 新增/删除/修改 怎么保存
-
                 _service.Update(CurrDeliveryReceipt);
             }
 
@@ -509,6 +499,41 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
         }
 
+        [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 (var dtl in CurrDeliveryReceipt.DeliveryReceiptDetails)
+            {
+                var 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 = "已复核";
+            var sele11 = cbReceivedStatus.SelectedItem;
+        }
+
         [RelayCommand]
         public void DetailSelectionChanged(DataGrid fdgDeliveryDetail)
         {
@@ -524,21 +549,58 @@ namespace UniformMaterialManagementSystem.ViewModels
             //fdgDeliveryDetail.CancelEdit();
         }
 
-        [RelayCommand]
-        public void DetailCellChanged(DataGrid fdgDeliveryDetail)
+        public void fdgDeliveryDetail_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
         {
-            fdgDeliveryDetail.BeginEdit(); // 单击进入编辑状态
-                                           //fdgDeliveryDetail.CommitEdit();
-
+            DataGrid? fdgDeliveryDetail = sender as DataGrid;
+            if (fdgDeliveryDetail == null) { return; }
 
-            var items = fdgDeliveryDetail.Items;
-            DeliveryReceiptDetail? row = fdgDeliveryDetail.CurrentCell.Item as DeliveryReceiptDetail;
-            if (row != null)
+            if (e.RemovedCells.Count > 0)
             {
-                int rowIndex = DeliveryDetails.IndexOf(row);
-                int colIndex = fdgDeliveryDetail.CurrentCell.Column.DisplayIndex;
+                // 离开单元格时提交编辑
+                fdgDeliveryDetail.CommitEdit();
+
+                // 如果编辑的列是发运数量/接收数量/使用数量,自动汇总至主表 更新使用状态
+                foreach (var cellInfo in e.RemovedCells)
+                {
+                    if (cellInfo.Column.Header.Equals("发运数量*"))
+                    {
+                        SummaryDeliveryDetail();
+                    }
+                    else if (cellInfo.Column.Header.Equals("接收数量*"))
+                    {
+                        SummaryReceiveDetail();
+                    }
+                    else if (cellInfo.Column.Header.Equals("使用数量*"))
+                    {
+                        DeliveryReceiptDetail? detail = cellInfo.Item as DeliveryReceiptDetail;
+                        if (detail == null) { continue; }
+
+                        var usageQty = detail.UsageQuantity;
+                        if (usageQty < 0)
+                        {
+                            MessageBox.Show("使用数量非法,请重新输入!");
+                            return;
+                        }
+                        else if (usageQty > detail.ReceiveQuantity)
+                        {
+                            MessageBox.Show("使用数量不能超过接收数量,请重新输入!");
+                            return;
+                        }
+                        detail.UsageStatus = usageQty == null || usageQty == 0 ? "未使用" : usageQty < detail.ReceiveQuantity ? "部分使用" : "全部使用";
+
+                    }
+                }
+
+                // 手动触发值更新事件
+                OnPropertyChanged(new PropertyChangedEventArgs("CurrDeliveryReceipt"));
             }
 
+            // 单元格切换时,Added 里的是新单元格;Removed是旧单元格
+            if (e.AddedCells.Count > 0)
+            {
+                // 进入单元格时自动进入编辑状态
+                fdgDeliveryDetail.BeginEdit();
+            }
         }
 
         [RelayCommand]
@@ -547,27 +609,28 @@ namespace UniformMaterialManagementSystem.ViewModels
             // 若当前主表行为空,则直接返回
             if (CurrDeliveryReceipt == null) { return; }
 
+            // 已导出数据包的发货的不允许再新增明细
+            if (CurrDeliveryReceipt.IsExportDelivery)
+            {
+                MessageBox.Show("当前发货单已导出数据包,不允许新增明细!");
+                return;
+            }
+
             // 新增一行子表
             DeliveryReceiptDetail detail = new DeliveryReceiptDetail();
             //DeliveryDetails.Add(detail);
-            // 当前子表数据绑定到主表 todo 主表行切换子表展示数据清空(但保存在主表中)
+            // 当前子表数据绑定到主表
+            // todo 主表行切换子表展示数据清空(但保存在主表中)
             CurrDeliveryReceipt!.DeliveryReceiptDetails.Add(detail);
         }
 
         [RelayCommand]
-        public void DeleteDetail(DataGrid dataGridDeliveryDetail)
+        public void DeleteDetail(DataGrid fdgDeliveryDetail)
         {
             // todo 多选删除
             // 主表行为空直接返回
             if (CurrDeliveryReceipt == null) { return; }
 
-            // 已导出数据包的发货的不允许再新增明细
-            if (CurrDeliveryReceipt.IsExportDelivery)
-            {
-                MessageBox.Show("当前发货单已导出数据包,不允许新增明细!");
-                return;
-            }
-
             // 已导出数据包的发货的不允许再删除明细
             if (CurrDeliveryReceipt.IsExportDelivery)
             {
@@ -576,51 +639,69 @@ namespace UniformMaterialManagementSystem.ViewModels
             }
 
             // 若没有选择行,直接返回
-            DeliveryReceiptDetail? detail = dataGridDeliveryDetail.SelectedItem as DeliveryReceiptDetail;
-            if (detail == null) { return; }
-
-            // 未保存行直接删除
-            if (detail.IsNewRow)
+            var selectedRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.IsSelected);
+            if (!selectedRows.Any())
             {
-                CurrDeliveryReceipt.DeliveryReceiptDetails.Remove(detail);
-                dataGridDeliveryDetail.Items.Refresh(); // 刷新索引
+                MessageBox.Show("请选择行后删除!");
+                return;
             }
-            // 已保存行 则询问
-            else
+            int selectedCount = selectedRows.Count();
+
+            int newRowCount = 0;
+            StringBuilder hint = new StringBuilder();
+            foreach (var detail in selectedRows)
             {
-                // 判断当前行是否已修改
-                EntityState? state = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>()?.Entry(detail);
-                if (state == null)
+                // 未保存行直接删除
+                if (detail.IsNewRow)
                 {
-                    MessageBox.Show("判断当前行状态出错!");
-                    return;
+                    CurrDeliveryReceipt.DeliveryReceiptDetails.Remove(detail);
+                    newRowCount++;
+                    // fdgDeliveryDetail.Items.Refresh(); // 刷新索引:删除后单元格变化,不允许刷新索引
+                    continue;
                 }
+
+                // 已保存行判断是否修改
+                EntityState? state = App.Current.Services.GetService<IDataBaseService<DeliveryReceiptDetail>>()?.Entry(detail);
+                if (state == null) { continue; }
                 switch (state)
                 {
+                    // 未改变的行,直接询问,没有提示信息
+                    case EntityState.Added: // 不会是新增行(IsNewRow)
+                    case EntityState.Deleted: // 正常情况下不会出现 Deleted (删除后刷新界面)
+                    case EntityState.Detached: // 正常情况下不会出现 Detached
                     case EntityState.Unchanged:
-                        {
-                            // 已保存行询问,不删除则跳过
-                            MessageBoxResult result = MessageBox.Show("是否确定删除当前行?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
-                            if (result != MessageBoxResult.Yes) { return; }
-                            break;
-                        }
-                    //case EntityState.Added: // 不会是新增行(IsNewRow)
-                    //case EntityState.Deleted: // 正常情况下不会出现 Deleted (删除后刷新界面)
-                    //case EntityState.Detached: // 正常情况下不会出现 Detached
+                        break;
                     case EntityState.Modified: // 询问
                         {
-                            // 已修改行询问,不删除则跳过
-                            MessageBoxResult result = MessageBox.Show("当前行数据已修改,是否确定删除当前行?", "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
-                            if (result != MessageBoxResult.Yes) { return; }
+                            int index = CurrDeliveryReceipt.DeliveryReceiptDetails.IndexOf(detail);
+                            hint.AppendLine($"第 {index + 1} 行");
                             break;
                         }
-                    default: break;
+                }
+            }
+
+            // 已保存行 则询问后删除
+            if (newRowCount < selectedCount)
+            {
+                string msg = string.Empty;
+                if (hint.Length > 0)
+                {
+                    msg = "是否确定删除选中行?";
+                }
+                else
+                {
+                    msg = "以下数据已修改,是否确定删除选中行?\n" + hint;
                 }
 
+                // 已保存行询问,不删除则跳过
+                MessageBoxResult result = MessageBox.Show(msg, "询问", MessageBoxButton.YesNoCancel, MessageBoxImage.Question);
+                if (result != MessageBoxResult.Yes) { return; }
+
                 // ×界面删除当前行
                 // 数据库删除当前行
                 // 刷新界面
 
+
             }
         }
 
@@ -774,6 +855,36 @@ namespace UniformMaterialManagementSystem.ViewModels
             ExcelUtil.CreateExcelFromDataTable(dtDetail, saveFileDialog.FileName);
         }
 
+        [RelayCommand]
+        public void ReceiveAll()
+        {
+            if (CurrDeliveryReceipt == null) { return; }
+
+            var details = CurrDeliveryReceipt.DeliveryReceiptDetails;
+            if (details == null || details.Count == 0) { return; }
+
+            // 全部接收:将发货数量列赋值到接收数量列
+            foreach (var dtl in details)
+            {
+                dtl.ReceiveQuantity = dtl.ShippedQuantity;
+            }
+        }
+
+        [RelayCommand]
+        public void UseAll()
+        {
+            if (CurrDeliveryReceipt == null) { return; }
+
+            var details = CurrDeliveryReceipt.DeliveryReceiptDetails;
+            if (details == null || details.Count == 0) { return; }
+
+            // 全部接收:将发货数量列赋值到接收数量列
+            foreach (var dtl in details)
+            {
+                dtl.UsageQuantity = dtl.ReceiveQuantity;
+            }
+        }
+
         /// <summary>
         /// 加载发货单数据
         /// </summary>
@@ -931,6 +1042,135 @@ namespace UniformMaterialManagementSystem.ViewModels
 
             return false;
         }
+
+        private void SummaryDeliveryDetail()
+        {
+            var details = CurrDeliveryReceipt!.DeliveryReceiptDetails;
+            int deliCount = details.Where(x => x.ShippedQuantity > 0).Count();
+            CurrDeliveryReceipt.ShippedPackets = deliCount;
+            double deliQty = details.Where(x => x.ShippedQuantity > 0).Select(x => x.ShippedQuantity).Sum();
+            CurrDeliveryReceipt.ShippedQty = deliQty;
+        }
+
+        private void SummaryReceiveDetail()
+        {
+            var details = CurrDeliveryReceipt!.DeliveryReceiptDetails;
+            int receCount = details.Where(x => x.ReceiveQuantity != null && x.ReceiveQuantity > 0).Count();
+            CurrDeliveryReceipt.ReceivedPackets = receCount;
+            double? receQty = details.Where(x => x.ReceiveQuantity != null && x.ReceiveQuantity > 0).Select(x => x.ReceiveQuantity).Sum();
+            CurrDeliveryReceipt.ReceivedQty = receQty ?? 0;
+        }
+
+        private void SummaryUsageDetail()
+        {
+            var details = CurrDeliveryReceipt!.DeliveryReceiptDetails;
+            foreach (var dtl in details)
+            {
+                if (dtl.UsageQuantity < dtl.ReceiveQuantity)
+                {
+                    dtl.UsageStatus = "";
+                }
+            }
+        }
+
+        private bool VerifyDelivery(DatePicker datePicker)
+        {
+            // 检查主表必录项
+            // todo 清空日期选择框,但 发运日期 并不会清空
+            if (string.IsNullOrWhiteSpace(datePicker.Text)) // DateTime 类型永远不等于 null
+            {
+                MessageBox.Show("发运时间为空,不允许保存!");
+                return false;
+            }
+
+            // 检查子表必录项
+            var nullBatchNoRows = CurrDeliveryReceipt!.DeliveryReceiptDetails.Where(x => string.IsNullOrEmpty(x.BatchNo));
+            var nullPackageNoRows = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => string.IsNullOrEmpty(x.PacketNo));
+            var nullShippedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Where(x => x.ShippedQuantity == 0);
+            StringBuilder nullFields = new StringBuilder();
+            if (nullBatchNoRows.Any())
+            {
+                nullFields.Append("批次号、");
+            }
+            if (nullPackageNoRows.Any())
+            {
+                nullFields.Append("材料包号、");
+            }
+            if (nullPackageNoRows.Any())
+            {
+                nullFields.Append("发运数量、");
+            }
+            if (nullFields.Length > 0)
+            {
+                nullFields = nullFields.Remove(nullFields.Length - 1, 1);
+                MessageBox.Show($"明细表的{nullFields}存在空值,不允许保存!");
+                return false;
+            }
+
+            // todo 子表新增行和删除行和修改列时实时计算
+            // 计算发运包数和发运数量
+            int packNum = CurrDeliveryReceipt.DeliveryReceiptDetails.Count;
+            CurrDeliveryReceipt.ShippedPackets = packNum;
+            double shippedQty = CurrDeliveryReceipt.DeliveryReceiptDetails.Select(x => x.ShippedQuantity).Sum();
+            CurrDeliveryReceipt.ShippedQty = shippedQty;
+
+            // 检查发运数量不能超出可发运数量
+            if (CurrDeliveryReceipt.ShippedQty >= CurrDeliveryReceipt.RemainQty)
+            {
+                MessageBox.Show("发货数量超出可发运数量,请检查数据后重新保存!");
+                return false;
+            }
+
+            // 检查子表的包号不允许重复
+            // 保存时检查材料名称是否存在重复项
+            var repeatPacketNos = CurrDeliveryReceipt.DeliveryReceiptDetails.GroupBy(x => x.PacketNo).Where(g => g.Count() > 1).Select(g => g.Key);
+            if (repeatPacketNos.Any())
+            {
+                // 若存在重复项则提示后返回
+                string repeatPacketNoText = string.Join("、", repeatPacketNos.ToArray());
+                MessageBox.Show("材料包号列存在以下重复值,请修改后保存:" + repeatPacketNoText, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool VerifyReceipt()
+        {
+            var nullReceivedQty = CurrDeliveryReceipt!.DeliveryReceiptDetails.Where(x => x.ReceiveQuantity == 0);
+            if (string.IsNullOrEmpty(CurrDeliveryReceipt.ReceivedStatus))
+            {
+                MessageBox.Show("收货单状态为空,不允许保存!");
+                return false;
+            }
+
+            if (nullReceivedQty.Any())
+            {
+                MessageBox.Show("明细表的接收数量存在空值,不允许保存!");
+                return false;
+            }
+
+            return true;
+        }
+
+        private bool VerifyUsage()
+        {
+            var nullUsageQty = CurrDeliveryReceipt!.DeliveryReceiptDetails.Where(x => x.UsageQuantity == 0);
+            if (CurrDeliveryReceipt.Licence == null)
+            {
+                MessageBox.Show("未上传许可证,不允许保存!");
+                return false;
+            }
+
+            if (nullUsageQty.Any())
+            {
+                MessageBox.Show("明细表的使用数量存在空值,不允许保存!");
+                return false;
+            }
+
+            return true;
+        }
+
     }
 
     /// <summary>

+ 2 - 1
UniformMaterialManagementSystem/ViewModels/InspectApplyPageViewModel.cs

@@ -689,6 +689,7 @@ namespace UniformMaterialManagementSystem.ViewModels
                     //扣减全部可报检数量
                     detail.ShareInspectQty = detail.UnInspectQty;
                     remainQty -= detail.UnInspectQty;
+                    remainQty = Math.Round(remainQty, 1);
                 }
                 else
                 {
@@ -761,7 +762,7 @@ namespace UniformMaterialManagementSystem.ViewModels
 
             TotalPackage = InspectApplyDetails.Count;
 
-            string result = InspectApplyUtil.ReplaceApplyDescription(ApplyDescription, "InspQuantity", $"[{sum}{SelectedMaterial?.MeasureUnit}]");
+            string result = InspectApplyUtil.ReplaceApplyDescription(ApplyDescription, "InspQuantity", $"[{InspQuantity}{SelectedMaterial?.MeasureUnit}]");
             ApplyDescription = InspectApplyUtil.ReplaceApplyDescription(result, "PackageQty", $"[{TotalPackage}]");
         }
 

+ 2 - 2
UniformMaterialManagementSystem/ViewModels/InspectionRecordPageViewModel.cs

@@ -306,14 +306,14 @@ namespace UniformMaterialManagementSystem.ViewModels
         /// 测试导出检验申请表附表
         /// </summary>
         [RelayCommand]
-        private void ExportInspectApplyAttachedPdf()
+        private void ExportInspectApplyAttached()
         {
             if (InspectApply == null)
             {
                 MessageBox.Show("请先选中一条数据,再执行删除操作!");
                 return;
             }
-            InspectApplyUtil.ExportInspectApplyAttachedPdf(InspectApply);
+            InspectApplyUtil.ExportInspectApplyAttached(InspectApply);
 
         }
 

+ 29 - 22
UniformMaterialManagementSystem/Views/DeliveryReceiptControl.xaml

@@ -293,17 +293,18 @@
                         Content="导出附件3" 
                         Tag="{x:Static utils:RegularFontUtil.Open_32}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding SaveCommand}" />
+                        Command="{Binding ExportThreeCommand}" />
                 <Button x:Name="btnCheck"
                         Content="复核" 
                         Tag="{x:Static utils:RegularFontUtil.Clipboard_Checkmark_24}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding SaveCommand}" />
+                        Command="{Binding CheckCommand}"
+                        CommandParameter="{Binding ElementName=cbReceivedStatus}"/>
                 <Button x:Name="btnExportFour"
                         Content="导出附件4" 
                         Tag="{x:Static utils:RegularFontUtil.Arrow_Turn_Right_48}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding SaveCommand}" />
+                        Command="{Binding ExportFourCommand}" />
 
                 <!--<WrapPanel Orientation="Horizontal">
                     <StackPanel Orientation="Horizontal">
@@ -374,7 +375,7 @@
                     <!-- 调用方法:传递事件参数 -->
                     <!-- TargetObject="{Binding }" 表示目标对象是当前的数据上下文 -->
                     <b:CallMethodAction TargetObject="{Binding }" 
-                                        MethodName="DeliverySelectionChanged" />
+                                        MethodName="fdgDelivery_SelectionChanged" />
 
                 </b:EventTrigger>
             </b:Interaction.Triggers>
@@ -689,7 +690,8 @@
                                 <TextBlock Text="接收时间:"
                                            Foreground="Black"
                                            Style="{StaticResource CustomTextBlockStyle}" />
-                                <DatePicker Width="250" 
+                                <DatePicker x:Name="dpReceivedDate"
+                                            Width="250" 
                                             Text="{Binding CurrDeliveryReceipt.ReceivedDate, Mode=TwoWay}"
                                             SelectedDateFormat="Short"
                                             HorizontalContentAlignment="Center"
@@ -698,21 +700,25 @@
                                             FontSize="14" />
                             </StackPanel>
 
-                            <TextBox Tag="接收承办人:"
+                            <TextBox x:Name="fieldReceivedMan"
+                                     Tag="接收承办人:"
                                      Text="{Binding CurrDeliveryReceipt.ReceivedMan}"
                                      IsEnabled="True"
                                      Style="{StaticResource CustomFieldTextBoxStyle}" />
-                            <TextBox Tag="联系电话:"
+                            <TextBox x:Name="fieldReceivedTel"
+                                     Tag="联系电话:"
                                      Text="{Binding CurrDeliveryReceipt.ReceivedTel}"
                                      IsEnabled="True"
                                      Style="{StaticResource CustomFieldTextBoxStyle}" />
 
                             <!-- 收货单状态 -->
                             <StackPanel Orientation="Horizontal">
-                                <TextBlock Text="收货单状态*:"
+                                <TextBlock x:Name="tBlkReceivedStatus"
+                                           Text="收货单状态*:"
                                            Foreground="Black"
                                            Style="{StaticResource CustomTextBlockStyle}" />
-                                <ComboBox Width="250"
+                                <ComboBox x:Name="cbReceivedStatus"
+                                          Width="250"
                                           Height="30"
                                           FontSize="14"
                                           HorizontalContentAlignment="Center"
@@ -764,12 +770,12 @@
                         Content="全部接收"
                         Tag="{x:Static utils:RegularFontUtil.Clipboard_Checkmark_24}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding ReceiveCommand}" />
+                        Command="{Binding ReceiveAllCommand}" />
                 <Button x:Name="btnUseDtl"
                         Content="全部使用"
                         Tag="{x:Static utils:RegularFontUtil.Box_Checkmark_24}"
                         Template="{StaticResource CustomToolBarButtomTemplate}"
-                        Command="{Binding UsageCommand}" />
+                        Command="{Binding UseAllCommand}" />
             </ToolBar>
         </Border>
 
@@ -797,16 +803,16 @@
 
             <!-- DataGrid 事件 -->
             <b:Interaction.Triggers>
-                <!-- 选择行切换事件 -->
-                <b:EventTrigger EventName="SelectionChanged">
+                <!-- 选择行切换事件:不用 -->
+                <!--<b:EventTrigger EventName="SelectionChanged">
                     <b:InvokeCommandAction Command="{Binding DetailSelectionChangedCommand}"
                                            CommandParameter="{Binding ElementName=fdgDeliveryDetail}" />
-                </b:EventTrigger>
+                </b:EventTrigger>-->
 
                 <!-- 选择单元格切换事件 -->
                 <b:EventTrigger EventName="SelectedCellsChanged">
-                    <b:InvokeCommandAction Command="{Binding DetailCellChangedCommand}"
-                                           CommandParameter="{Binding ElementName=fdgDeliveryDetail}" />
+                    <b:CallMethodAction TargetObject="{Binding }"
+                                        MethodName="fdgDeliveryDetail_SelectedCellsChanged" />
                 </b:EventTrigger>
 
             </b:Interaction.Triggers>
@@ -816,24 +822,25 @@
                 <!--<DataGridTextColumn Header="序号" Width="*" />-->
                 <fdg:FilterDataGridCheckBoxColumn Header="  " Width="30"
                                                   ElementStyle="{StaticResource CheckBoxColumnElementStyle}"
-                                                  EditingElementStyle="{StaticResource CheckBoxColumnElementStyle}" />
-                <fdg:FilterDataGridTextColumn Header="批次号*" Width="100"
+                                                  EditingElementStyle="{StaticResource CheckBoxColumnElementStyle}"
+                                                  Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged}"/>
+                <fdg:FilterDataGridTextColumn Header="批次号" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding BatchNo, UpdateSourceTrigger=PropertyChanged}" />
-                <fdg:FilterDataGridTextColumn Header="材料包号*" Width="100"
+                <fdg:FilterDataGridTextColumn Header="材料包号" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding PacketNo, UpdateSourceTrigger=PropertyChanged}" />
-                <fdg:FilterDataGridTextColumn Header="发运数量*" Width="100"
+                <fdg:FilterDataGridTextColumn Header="发运数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding ShippedQuantity, UpdateSourceTrigger=PropertyChanged}" />
-                <fdg:FilterDataGridTextColumn Header="接收数量*" Width="100"
+                <fdg:FilterDataGridTextColumn Header="接收数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding ReceiveQuantity, UpdateSourceTrigger=PropertyChanged}" />
-                <fdg:FilterDataGridTextColumn Header="使用数量*" Width="100"
+                <fdg:FilterDataGridTextColumn Header="使用数量" Width="100"
                                               ElementStyle="{StaticResource TextColumnElementStyle}"
                                               EditingElementStyle="{StaticResource TextColumnEditingStyle}"
                                               Binding="{Binding UsageQuantity, UpdateSourceTrigger=PropertyChanged}" />

+ 1 - 1
UniformMaterialManagementSystem/Views/InspectApplyPage.xaml

@@ -166,7 +166,7 @@
             BorderThickness="1">
             <ToolBarPanel>
                 <ToolBar Background="White" ToolBarTray.IsLocked="True">
-                    <Button Command="{Binding SaveInspectApplyCommand}">
+                    <Button Command="{Binding SaveInspectApplyCommand}" Click="Button_Click">
                         <Button.Template>
                             <ControlTemplate>
                                 <Border

+ 7 - 2
UniformMaterialManagementSystem/Views/InspectApplyPage.xaml.cs

@@ -98,7 +98,7 @@ namespace UniformMaterialManagementSystem.Views
                 sum += qty;
             }
 
-            InspQuantityText.Text = sum.ToString();
+            InspQuantityText.Text = Math.Round(sum,1).ToString();
             TotalPackageText.Text = DataGridDetail.Items.Count.ToString();
 
             string result = InspectApplyUtil.ReplaceApplyDescription(ApplyDescriptionTextBox.Text, "InspQuantity", "[" + InspQuantityText.Text + (MaterialComboBox.SelectedItem as Material)?.MeasureUnit + "]");
@@ -176,7 +176,7 @@ namespace UniformMaterialManagementSystem.Views
 
         private void AddButton_Click(object sender, RoutedEventArgs e)
         {
-            DataGridDetail.CommitEdit(DataGridEditingUnit.Cell, true);
+            DataGridDetail.CommitEdit(DataGridEditingUnit.Row, true);
         }
 
         /// <summary>
@@ -198,5 +198,10 @@ namespace UniformMaterialManagementSystem.Views
             }
 
         }
+
+        private void Button_Click(object sender, RoutedEventArgs e)
+        {
+            DataGridDetail.CommitEdit();
+        }
     }
 }

+ 1 - 1
UniformMaterialManagementSystem/Views/InspectionRecordPage.xaml

@@ -292,7 +292,7 @@
                                         </ControlTemplate>
                                     </Button.Template>
                                 </Button>
-                                <Button Command="{Binding ExportInspectApplyAttachedPdfCommand}">
+                                <Button Command="{Binding ExportInspectApplyAttachedCommand}">
                                     <Button.Template>
                                         <ControlTemplate>
                                             <Border