Explorar el Código

统计查询模块支持多类记录分页与导出

新增生产、拍照、螺丝、披头、吸嘴等记录的分页查询与导出功能,完善相关ViewModel和界面,集成至统计主界面。优化锁付结果查询体验,项目文件同步更新。提升数据管理与追溯能力,界面风格统一。
孝锋 徐 hace 8 meses
padre
commit
2aa6d8a8df
Se han modificado 22 ficheros con 1741 adiciones y 14 borrados
  1. 158 2
      TeamAAS-VM/Data/SystemDatabaseService.cs
  2. 58 0
      TeamAAS-VM/Interfaces/ISystemDatabaseService.cs
  3. 4 0
      TeamAAS-VM/Services/ShiftWatcherService.cs
  4. 40 0
      TeamAAS-VM/TeamAAS-VP.csproj
  5. 119 0
      TeamAAS-VM/ViewModels/Statistics/HeadChangeRecordQueryViewModel.cs
  6. 11 3
      TeamAAS-VM/ViewModels/Statistics/LockResultRecoredQueryViewModel.cs
  7. 114 0
      TeamAAS-VM/ViewModels/Statistics/NozzleChangeRecordQueryViewModel.cs
  8. 166 0
      TeamAAS-VM/ViewModels/Statistics/PhotoCaptureQueryViewModel.cs
  9. 147 0
      TeamAAS-VM/ViewModels/Statistics/ProductionRecordQueryViewModel.cs
  10. 125 0
      TeamAAS-VM/ViewModels/Statistics/ScrewFeederBatchQueryViewModel.cs
  11. 117 0
      TeamAAS-VM/Views/Statistics/HeadChangeRecordQuery.xaml
  12. 28 0
      TeamAAS-VM/Views/Statistics/HeadChangeRecordQuery.xaml.cs
  13. 18 5
      TeamAAS-VM/Views/Statistics/LockResultRecoredQuery.xaml
  14. 115 0
      TeamAAS-VM/Views/Statistics/NozzleChangeRecordQuery.xaml
  15. 28 0
      TeamAAS-VM/Views/Statistics/NozzleChangeRecordQuery.xaml.cs
  16. 139 0
      TeamAAS-VM/Views/Statistics/PhotoCaptureQuery.xaml
  17. 28 0
      TeamAAS-VM/Views/Statistics/PhotoCaptureQuery.xaml.cs
  18. 133 0
      TeamAAS-VM/Views/Statistics/ProductionRecordQuery.xaml
  19. 28 0
      TeamAAS-VM/Views/Statistics/ProductionRecordQuery.xaml.cs
  20. 123 0
      TeamAAS-VM/Views/Statistics/ScrewFeederBatchQuery.xaml
  21. 28 0
      TeamAAS-VM/Views/Statistics/ScrewFeederBatchQuery.xaml.cs
  22. 14 4
      TeamAAS-VM/Views/StatisticsView.xaml

+ 158 - 2
TeamAAS-VM/Data/SystemDatabaseService.cs

@@ -1,3 +1,4 @@
+using NPOI.Util;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -24,10 +25,9 @@ namespace TeamAAS_VP.Data
         public SystemDatabaseService(ISqlSugarClient db)
         {
             _db = db;
+            //GenerateTestDataAsync();
         }
 
-        
-
         #region 用户
         // User CRUD
 
@@ -590,6 +590,20 @@ namespace TeamAAS_VP.Data
             return dict;
         }
 
+        /// <summary>
+        /// 分页查询生产记录
+        /// </summary>
+        public async Task<(IEnumerable<ProductionRecord> Items, int TotalCount)> QueryProductionRecordsPagedAsync(DateTime start, DateTime end, int pageIndex, int pageSize, string productName = null, string category = null)
+        {
+            if (pageIndex < 1) pageIndex = 1;
+            if (pageSize < 1) pageSize = 20;
+            var q = _db.Queryable<ProductionRecord>().Where(r => r.Timestamp >= start && r.Timestamp < end);
+            if (!string.IsNullOrEmpty(productName)) q = q.Where(r => r.ProductName == productName);
+            if (!string.IsNullOrEmpty(category)) q = q.Where(r => r.Category == category);
+            var total = await q.CountAsync();
+            var list = await q.OrderBy(r => r.Timestamp, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
+            return (list, total);
+        }
         #endregion
 
         #region 报警记录
@@ -719,6 +733,23 @@ namespace TeamAAS_VP.Data
             return list;
         }
 
+        /// <summary>
+        /// 分页查询螺丝供料器批次记录
+        /// </summary>
+        public async Task<(IEnumerable<ScrewFeederBatchRecord> Items, int TotalCount)> QueryScrewFeederBatchRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string batchNumber = null, int? feederNumber = null, int pageIndex = 1, int pageSize = 20)
+        {
+            if (pageIndex < 1) pageIndex = 1;
+            if (pageSize < 1) pageSize = 20;
+            var q = _db.Queryable<ScrewFeederBatchRecord>();
+            if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
+            if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
+            if (!string.IsNullOrEmpty(batchNumber)) q = q.Where(r => r.BatchNumber == batchNumber);
+            if (feederNumber.HasValue) q = q.Where(r => r.FeederNumber == feederNumber.Value);
+            var total = await q.CountAsync();
+            var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
+            return (list, total);
+        }
+
         /// <summary>
         /// 获取指定供料器编号的最新一条批次更换记录
         /// </summary>
@@ -770,6 +801,24 @@ namespace TeamAAS_VP.Data
             var list = await q.OrderBy(r => r.CaptureTime, OrderByType.Desc).ToListAsync();
             return list;
         }
+
+        /// <summary>
+        /// 分页查询拍照记录
+        /// </summary>
+        public async Task<(IEnumerable<PhotoCaptureRecord> Items, int TotalCount)> QueryPhotoCapturesPagedAsync(string recipeName = null, string cameraName = null, string productSN = null, DateTime? start = null, DateTime? end = null, int pageIndex = 1, int pageSize = 20)
+        {
+            if (pageIndex < 1) pageIndex = 1;
+            if (pageSize < 1) pageSize = 20;
+            var q = _db.Queryable<PhotoCaptureRecord>();
+            if (!string.IsNullOrEmpty(recipeName)) q = q.Where(r => r.RecipeName == recipeName);
+            if (!string.IsNullOrEmpty(cameraName)) q = q.Where(r => r.CameraName == cameraName);
+            if (!string.IsNullOrEmpty(productSN)) q = q.Where(r => r.ProductSN == productSN);
+            if (start.HasValue) q = q.Where(r => r.CaptureTime >= start.Value);
+            if (end.HasValue) q = q.Where(r => r.CaptureTime <= end.Value);
+            var total = await q.CountAsync();
+            var list = await q.OrderBy(r => r.CaptureTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
+            return (list, total);
+        }
         #endregion
 
         #region 披头更换记录
@@ -804,6 +853,22 @@ namespace TeamAAS_VP.Data
             return list;
         }
 
+        /// <summary>
+        /// 分页查询披头更换记录
+        /// </summary>
+        public async Task<(IEnumerable<HeadChangeRecord> Items, int TotalCount)> QueryHeadChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string headBatchNumber = null, int pageIndex = 1, int pageSize = 20)
+        {
+            if (pageIndex < 1) pageIndex = 1;
+            if (pageSize < 1) pageSize = 20;
+            var q = _db.Queryable<HeadChangeRecord>();
+            if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
+            if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
+            if (!string.IsNullOrEmpty(headBatchNumber)) q = q.Where(r => r.HeadBatchNumber == headBatchNumber);
+            var total = await q.CountAsync();
+            var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
+            return (list, total);
+        }
+
         /// <summary>
         /// 获取最新的一条披头更换记录
         /// </summary>
@@ -932,6 +997,97 @@ namespace TeamAAS_VP.Data
                 throw;
             }
         }
+
+        /// <summary>
+        /// 分页查询喷嘴更换记录
+        /// </summary>
+        public async Task<(IEnumerable<NozzleChangeRecord> Items, int TotalCount)> QueryNozzleChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string nozzleBatchNumber = null, int pageIndex = 1, int pageSize = 20)
+        {
+            if (pageIndex < 1) pageIndex = 1;
+            if (pageSize < 1) pageSize = 20;
+            var q = _db.Queryable<NozzleChangeRecord>();
+            if (start.HasValue) q = q.Where(r => r.ChangeTime >= start.Value);
+            if (end.HasValue) q = q.Where(r => r.ChangeTime <= end.Value);
+            if (!string.IsNullOrEmpty(nozzleBatchNumber)) q = q.Where(r => r.NozzleBatchNumber == nozzleBatchNumber);
+            var total = await q.CountAsync();
+            var list = await q.OrderBy(r => r.ChangeTime, OrderByType.Desc).ToPageListAsync(pageIndex, pageSize);
+            return (list, total);
+        }
+        #endregion
+
+
+        #region 生成测试数据
+
+        //定义一个方法来生成一些测试的数据,测试数据库写入和查询功能
+        public async Task GenerateTestDataAsync()
+        {
+            //生成一些喷嘴更换记录的测试数据
+            for (int i = 0; i < 10; i++)
+            {
+                var record = new NozzleChangeRecord
+                {
+                    ChangeTime = DateTime.UtcNow.AddMinutes(-i * 10),
+                    NozzleBatchNumber = $"Batch-{i}",
+                    CurrentLockCount = i,
+                    OperatorName = $"Operator-{i}"
+                };
+                await RecordNozzleChangeAsync(record);
+            }
+
+            //生成一些披头更换记录的测试数据
+            for (int i = 0; i < 10; i++)
+            {
+                var record = new HeadChangeRecord
+                {
+                    ChangeTime = DateTime.UtcNow.AddMinutes(-i * 15),
+                    HeadBatchNumber = $"HeadBatch-{i}",
+                    CurrentLockCount = i,
+                    OperatorName = $"HeadOperator-{i}"
+                };
+                await RecordHeadChangeAsync(record);
+            }
+
+            //生成一些螺丝供料器批次更换记录的测试数据
+            for (int i = 0; i < 10; i++)
+            {
+                var record = new ScrewFeederBatchRecord
+                {
+                    ChangeTime = DateTime.UtcNow.AddMinutes(-i * 20),
+                    BatchNumber = $"ScrewBatch-{i}",
+                    FeederNumber = i + 1
+                };
+                await RecordScrewFeederBatchAsync(record);
+            }
+
+            //生成一些生产记录的测试数据
+            for (int i = 0; i < 50; i++)
+            {
+                var record = new ProductionRecord
+                {
+                    Id = Guid.NewGuid(),
+                    ProductName = "产品1",
+                    Category = (i % 2 == 0) ? "OK" : "NG",
+                    Quantity = 1,
+                    Timestamp = DateTime.UtcNow.AddMinutes(-i * 5),
+                    UserName = "TestUser",
+                    Remark = $"TotalSeconds:1.10"
+                };
+                await RecordProductionAsync(record);
+            }
+
+            //生成一些锁付结果的测试数据
+            for (int i = 0; i < 200; i++)
+            {
+                var result = new LockResult(i % 4, $"PN-{i % 5}", 10.5f, 0.3f, (i % 3 != 0))
+                {
+                    ProductName = "产品1",
+                    Timestamp = DateTime.UtcNow.AddMinutes(-i * 3),
+                };
+                await RecordLockResultAsync(result);
+            }
+
+        }
+
         #endregion
     }
 }

+ 58 - 0
TeamAAS-VM/Interfaces/ISystemDatabaseService.cs

@@ -274,6 +274,17 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<Dictionary<int, Dictionary<string, int>>> GetDailyProductionByHourAndCategoryAsync(string productName);
 
+        /// <summary>
+        /// 分页查询生产记录。
+        /// </summary>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <param name="productName"></param>
+        /// <param name="category"></param>
+        /// <returns></returns>
+        Task<(IEnumerable<ProductionRecord> Items, int TotalCount)> QueryProductionRecordsPagedAsync(DateTime start, DateTime end, int pageIndex, int pageSize, string productName = null, string category = null);
 
         // Alarm records
 
@@ -345,6 +356,18 @@ namespace TeamAAS_VP.Interfaces
         /// <returns>满足条件的记录集合(按 ChangeTime 降序)。</returns>
         Task<IEnumerable<ScrewFeederBatchRecord>> QueryScrewFeederBatchRecordsAsync(DateTime? start = null, DateTime? end = null, string batchNumber = null, int? feederNumber = null);
 
+        /// <summary>
+        /// 分页查询螺丝供料器批次记录。
+        /// </summary>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <param name="batchNumber"></param>
+        /// <param name="feederNumber"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <returns></returns>
+        Task<(IEnumerable<ScrewFeederBatchRecord> Items, int TotalCount)> QueryScrewFeederBatchRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string batchNumber = null, int? feederNumber = null, int pageIndex = 1, int pageSize = 20);
+
         /// <summary>
         /// 获取指定供料器编号的最新一条批次更换记录
         /// </summary>
@@ -370,6 +393,19 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<IEnumerable<PhotoCaptureRecord>> QueryPhotoCapturesAsync(string recipeName = null, string cameraName = null, string productSN = null, DateTime? start = null, DateTime? end = null);
 
+        /// <summary>
+        /// 分页查询拍照记录,支持按配方名、产品序列号和时间段过滤(所有参数可选)。
+        /// </summary>
+        /// <param name="recipeName"></param>
+        /// <param name="cameraName"></param>
+        /// <param name="productSN"></param>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <returns></returns>
+        Task<(IEnumerable<PhotoCaptureRecord> Items, int TotalCount)> QueryPhotoCapturesPagedAsync(string recipeName = null, string cameraName = null, string productSN = null, DateTime? start = null, DateTime? end = null, int pageIndex = 1, int pageSize = 20);
+
         /// <summary>
         /// 记录披头更换记录。
         /// </summary>
@@ -386,6 +422,17 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<IEnumerable<HeadChangeRecord>> QueryHeadChangeRecordsAsync(DateTime? start = null, DateTime? end = null, string headBatchNumber = null);
 
+        /// <summary>
+        /// 分页查询披头更换记录,可按时间段或披头批号过滤(所有参数可选)。
+        /// </summary>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <param name="headBatchNumber"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <returns></returns>
+        Task<(IEnumerable<HeadChangeRecord> Items, int TotalCount)> QueryHeadChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string headBatchNumber = null, int pageIndex = 1, int pageSize = 20);
+
         /// <summary>
         /// 获取最新的一条披头更换记录(按 ChangeTime 降序)。
         /// </summary>
@@ -415,6 +462,17 @@ namespace TeamAAS_VP.Interfaces
         /// <returns></returns>
         Task<IEnumerable<NozzleChangeRecord>> QueryNozzleChangeRecordsAsync(DateTime? start = null, DateTime? end = null, string nozzleBatchNumber = null);
 
+        /// <summary>
+        /// 分页查询吸嘴更换记录,可按时间段或喷嘴批号过滤(所有参数可选)。
+        /// </summary>
+        /// <param name="start"></param>
+        /// <param name="end"></param>
+        /// <param name="nozzleBatchNumber"></param>
+        /// <param name="pageIndex"></param>
+        /// <param name="pageSize"></param>
+        /// <returns></returns>
+        Task<(IEnumerable<NozzleChangeRecord> Items, int TotalCount)> QueryNozzleChangeRecordsPagedAsync(DateTime? start = null, DateTime? end = null, string nozzleBatchNumber = null, int pageIndex = 1, int pageSize = 20);
+
         /// <summary>
         /// 获取最新的一条喷嘴更换记录(按 ChangeTime 降序)。
         /// </summary>

+ 4 - 0
TeamAAS-VM/Services/ShiftWatcherService.cs

@@ -43,6 +43,10 @@ namespace TeamAAS_VP.Services
         {
             DateTime dateTimeDayShift = DateTime.Now;
             DateTime dateTimeNightShift = DateTime.Now;
+            if (workShift==null)
+            {
+                return;
+            }
             try
             {
                 dateTimeDayShift = DateTime.Parse(workShift.DayShift);

+ 40 - 0
TeamAAS-VM/TeamAAS-VP.csproj

@@ -553,6 +553,11 @@
     <Compile Include="Services\MesService.cs" />
     <Compile Include="Services\ShiftWatcherService.cs" />
     <Compile Include="ViewModels\Product\PlcPointOffserParamsViewModel.cs" />
+    <Compile Include="ViewModels\Statistics\HeadChangeRecordQueryViewModel.cs" />
+    <Compile Include="ViewModels\Statistics\NozzleChangeRecordQueryViewModel.cs" />
+    <Compile Include="ViewModels\Statistics\PhotoCaptureQueryViewModel.cs" />
+    <Compile Include="ViewModels\Statistics\ProductionRecordQueryViewModel.cs" />
+    <Compile Include="ViewModels\Statistics\ScrewFeederBatchQueryViewModel.cs" />
     <Compile Include="ViewModels\User\CardLoginWindowViewModel.cs" />
     <Compile Include="ViewModels\Home\ChangeNozzleViewModel.cs" />
     <Compile Include="ViewModels\Home\ChangeHeaderViewModel.cs" />
@@ -1083,12 +1088,27 @@
     <Compile Include="Views\Statistics\AlarmQuery.xaml.cs">
       <DependentUpon>AlarmQuery.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\Statistics\HeadChangeRecordQuery.xaml.cs">
+      <DependentUpon>HeadChangeRecordQuery.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\Statistics\LockResultRecoredQuery.xaml.cs">
       <DependentUpon>LockResultRecoredQuery.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\Statistics\NozzleChangeRecordQuery.xaml.cs">
+      <DependentUpon>NozzleChangeRecordQuery.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\Statistics\PhotoCaptureQuery.xaml.cs">
+      <DependentUpon>PhotoCaptureQuery.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\Statistics\ProductionRecordQuery.xaml.cs">
+      <DependentUpon>ProductionRecordQuery.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\Statistics\ProductionStatement.xaml.cs">
       <DependentUpon>ProductionStatement.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Views\Statistics\ScrewFeederBatchQuery.xaml.cs">
+      <DependentUpon>ScrewFeederBatchQuery.xaml</DependentUpon>
+    </Compile>
     <Compile Include="Views\Statistics\StatisticalQuery.xaml.cs">
       <DependentUpon>StatisticalQuery.xaml</DependentUpon>
     </Compile>
@@ -1481,14 +1501,34 @@
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\Statistics\HeadChangeRecordQuery.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\Statistics\LockResultRecoredQuery.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\Statistics\NozzleChangeRecordQuery.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Views\Statistics\PhotoCaptureQuery.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Views\Statistics\ProductionRecordQuery.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\Statistics\ProductionStatement.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
     </Page>
+    <Page Include="Views\Statistics\ScrewFeederBatchQuery.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
     <Page Include="Views\Statistics\StatisticalQuery.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>

+ 119 - 0
TeamAAS-VM/ViewModels/Statistics/HeadChangeRecordQueryViewModel.cs

@@ -0,0 +1,119 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+
+namespace TeamAAS_VP.ViewModels.Statistics
+{
+    public class HeadChangeRecordQueryViewModel : BindableBase
+    {
+        private readonly ISystemDatabaseService _systemDatabaseService;
+        public HeadChangeRecordQueryViewModel(ISystemDatabaseService systemDatabaseService)
+        {
+            _systemDatabaseService = systemDatabaseService;
+            PageSize = 20; PageIndex = 1;
+            StartDate = DateTime.Now.Date; EndDate = DateTime.Now.Date.AddDays(1);
+            SearchCommand = new DelegateCommand(async () => await ExecuteSearchCommand());
+            PrevPageCommand = new DelegateCommand(async () => { if (PageIndex > 1) { PageIndex--; await ExecuteSearchCommand(); } });
+            NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } });
+            ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand());
+        }
+
+        private DateTime? _StartDate;
+        public DateTime? StartDate
+        {
+            get { return _StartDate; }
+            set { SetProperty(ref _StartDate, value); }
+        }
+        private DateTime? _EndDate;
+        public DateTime? EndDate
+        {
+            get { return _EndDate; }
+            set { SetProperty(ref _EndDate, value); }
+        }
+        private string _HeadBatchNumber;
+        public string HeadBatchNumber
+        {
+            get { return _HeadBatchNumber; }
+            set { SetProperty(ref _HeadBatchNumber, value); }
+        }
+        private ObservableCollection<HeadChangeRecord> _Results;
+        public ObservableCollection<HeadChangeRecord> Results
+        {
+            get { return _Results; }
+            set { SetProperty(ref _Results, value); }
+        }
+        private int _PageIndex;
+        public int PageIndex
+        {
+            get { return _PageIndex; }
+            set { SetProperty(ref _PageIndex, value); }
+        }
+        private int _PageSize;
+        public int PageSize
+        {
+            get { return _PageSize; }
+            set { SetProperty(ref _PageSize, value); }
+        }
+        private int _TotalCount;
+        public int TotalCount
+        {
+            get { return _TotalCount; }
+            set { SetProperty(ref _TotalCount, value); }
+        }
+
+        public DelegateCommand SearchCommand { get; private set; }
+        public DelegateCommand PrevPageCommand { get; private set; }
+        public DelegateCommand NextPageCommand { get; private set; }
+        public DelegateCommand ExportCommand { get; private set; }
+
+        private async Task ExecuteSearchCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var res = await _systemDatabaseService.QueryHeadChangeRecordsPagedAsync(start, end, HeadBatchNumber, PageIndex, PageSize);
+                Results = new ObservableCollection<HeadChangeRecord>(res.Items);
+                TotalCount = res.TotalCount;
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async Task ExecuteExportCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var all = await _systemDatabaseService.QueryHeadChangeRecordsAsync(start, end, HeadBatchNumber);
+                if (all == null || !all.Any()) { MessageBox.Show("没有找到符合条件的记录", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; }
+                var dlg = new Microsoft.Win32.SaveFileDialog { FileName = $"HeadChange_{DateTime.Now:yyyyMMddHHmmss}.csv", DefaultExt = ".csv", Filter = "CSV Files (*.csv)|*.csv" };
+                if (dlg.ShowDialog() != true) return;
+                var path = dlg.FileName;
+                using (var sw = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    sw.WriteLine("ChangeTime,HeadBatchNumber,CurrentLockCount,OperatorName");
+                    foreach (var r in all)
+                    {
+                        sw.WriteLine($"{r.ChangeTime:yyyy-MM-dd HH:mm:ss},{r.HeadBatchNumber},{r.CurrentLockCount},{r.OperatorName}");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+    }
+}

+ 11 - 3
TeamAAS-VM/ViewModels/Statistics/LockResultRecoredQueryViewModel.cs

@@ -31,8 +31,6 @@ namespace TeamAAS_VP.ViewModels.Statistics
             PrevPageCommand = new DelegateCommand(async () => { if (PageIndex>1) { PageIndex--; await ExecuteSearchCommand(); } }).ObservesProperty(() => PageIndex);
             NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } }).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalCount);
             ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand(), CanExport).ObservesProperty(() => Results).ObservesProperty(() => IsSearching);
-
-            AllProduct = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
             StartDate = DateTime.Now.Date;
             EndDate = DateTime.Now.Date.AddDays(1);
         }
@@ -121,8 +119,18 @@ namespace TeamAAS_VP.ViewModels.Statistics
         public DelegateCommand PrevPageCommand { get; private set; }
         public DelegateCommand NextPageCommand { get; private set; }
         public DelegateCommand ExportCommand { get; private set; }
+
+        private DelegateCommand _LoadedCommand;
+        public DelegateCommand LoadedCommand =>
+            _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
+        void ExecuteLoadedCommand()
+        {
+            AllProduct = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
+        }
         #endregion
 
+
+
         private bool CanSearch()
         {
             if (IsSearching) return false;
@@ -143,7 +151,7 @@ namespace TeamAAS_VP.ViewModels.Statistics
             try
             {
                 IsSearching = true;
-
+                PageIndex = 1;
                 // determine time range (use full days)
                 var start = StartDate.HasValue ? StartDate.Value.Date : DateTime.MinValue;
                 var end = EndDate.HasValue ? EndDate.Value.Date.AddDays(1) : DateTime.MaxValue;

+ 114 - 0
TeamAAS-VM/ViewModels/Statistics/NozzleChangeRecordQueryViewModel.cs

@@ -0,0 +1,114 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+
+namespace TeamAAS_VP.ViewModels.Statistics
+{
+    public class NozzleChangeRecordQueryViewModel : BindableBase
+    {
+        private readonly ISystemDatabaseService _systemDatabaseService;
+        public NozzleChangeRecordQueryViewModel(ISystemDatabaseService systemDatabaseService)
+        {
+            _systemDatabaseService = systemDatabaseService;
+            PageSize = 20; PageIndex = 1;
+            StartDate = DateTime.Now.Date; EndDate = DateTime.Now.Date.AddDays(1);
+            SearchCommand = new DelegateCommand(async () => await ExecuteSearchCommand());
+            PrevPageCommand = new DelegateCommand(async () => { if (PageIndex > 1) { PageIndex--; await ExecuteSearchCommand(); } });
+            NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } });
+            ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand());
+        }
+
+        private DateTime? _StartDate;
+        public DateTime? StartDate
+        {
+            get { return _StartDate; }
+            set { SetProperty(ref _StartDate, value); }
+        }
+        private DateTime? _EndDate;
+        public DateTime? EndDate
+        {
+            get { return _EndDate; }
+            set { SetProperty(ref _EndDate, value); }
+        }
+        private string _NozzleBatchNumber;
+        public string NozzleBatchNumber
+        {
+            get { return _NozzleBatchNumber; }
+            set { SetProperty(ref _NozzleBatchNumber, value); }
+        }
+        public ObservableCollection<NozzleChangeRecord> Results { get; set; } = new ObservableCollection<NozzleChangeRecord>();
+        private int _PageIndex;
+        public int PageIndex
+        {
+            get { return _PageIndex; }
+            set { SetProperty(ref _PageIndex, value); }
+        }
+        private int _PageSize;
+        public int PageSize
+        {
+            get { return _PageSize; }
+            set { SetProperty(ref _PageSize, value); }
+        }
+        private int _TotalCount;
+        public int TotalCount
+        {
+            get { return _TotalCount; }
+            set { SetProperty(ref _TotalCount, value); }
+        }
+
+        public DelegateCommand SearchCommand { get; private set; }
+        public DelegateCommand PrevPageCommand { get; private set; }
+        public DelegateCommand NextPageCommand { get; private set; }
+        public DelegateCommand ExportCommand { get; private set; }
+
+        private async Task ExecuteSearchCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var res = await _systemDatabaseService.QueryNozzleChangeRecordsPagedAsync(start, end, NozzleBatchNumber, PageIndex, PageSize);
+                Results = new ObservableCollection<NozzleChangeRecord>(res.Items);
+                TotalCount = res.TotalCount;
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async Task ExecuteExportCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var all = await _systemDatabaseService.QueryNozzleChangeRecordsAsync(start, end, NozzleBatchNumber);
+                if (all == null || !all.Any()) { MessageBox.Show("没有找到符合条件的记录", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; }
+                var dlg = new Microsoft.Win32.SaveFileDialog { FileName = $"NozzleChange_{DateTime.Now:yyyyMMddHHmmss}.csv", DefaultExt = ".csv", Filter = "CSV Files (*.csv)|*.csv" };
+                if (dlg.ShowDialog() != true) return;
+                var path = dlg.FileName;
+                using (var sw = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    sw.WriteLine("ChangeTime,NozzleBatchNumber,CurrentLockCount,OperatorName");
+                    foreach (var r in all)
+                    {
+                        sw.WriteLine($"{r.ChangeTime:yyyy-MM-dd HH:mm:ss},{r.NozzleBatchNumber},{r.CurrentLockCount},{r.OperatorName}");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+    }
+}

+ 166 - 0
TeamAAS-VM/ViewModels/Statistics/PhotoCaptureQueryViewModel.cs

@@ -0,0 +1,166 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Controls;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+using TeamAAS_VP.Services;
+
+namespace TeamAAS_VP.ViewModels.Statistics
+{
+    public class PhotoCaptureQueryViewModel : BindableBase
+    {
+        private readonly ISystemDatabaseService _systemDatabaseService;
+        private readonly IProductService _productService;
+        private readonly IConfigService _configService;
+
+        public PhotoCaptureQueryViewModel(ISystemDatabaseService systemDatabaseService, ProductService productService, IConfigService configService)
+        {
+            _systemDatabaseService = systemDatabaseService;
+            _productService = productService;
+            _configService = configService;
+            PageSize = 20; PageIndex = 1;
+            StartDate = DateTime.Now.Date; EndDate = DateTime.Now.Date.AddDays(1);
+            SearchCommand = new DelegateCommand(async () => await ExecuteSearchCommand());
+            PrevPageCommand = new DelegateCommand(async () => { if (PageIndex > 1) { PageIndex--; await ExecuteSearchCommand(); } });
+            NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } });
+            ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand());
+        }
+
+        private ObservableCollection<ProductModel> _AllProduct;
+        public ObservableCollection<ProductModel> AllProduct
+        {
+            get { return _AllProduct; }
+            set { SetProperty(ref _AllProduct, value); }
+        }
+
+        private ProductModel _SelectedProduct;
+        public ProductModel SelectedProduct
+        {
+            get { return _SelectedProduct; }
+            set { SetProperty(ref _SelectedProduct, value); }
+        }
+
+        private ObservableCollection<CameraInfo> _AllCamera;
+        public ObservableCollection<CameraInfo> AllCamera
+        {
+            get { return _AllCamera; }
+            set { SetProperty(ref _AllCamera, value); }
+        }
+
+        private CameraInfo _SelectedCamera;
+        public CameraInfo SelectedCamera
+        {
+            get { return _SelectedCamera; }
+            set { SetProperty(ref _SelectedCamera, value); }
+        }
+        private string _ProductSN;
+        public string ProductSN
+        {
+            get { return _ProductSN; }
+            set { SetProperty(ref _ProductSN, value); }
+        }
+
+        private DateTime? _StartDate;
+        public DateTime? StartDate
+        {
+            get { return _StartDate; }
+            set { SetProperty(ref _StartDate, value); }
+        }
+
+        private DateTime? _EndDate;
+        public DateTime? EndDate
+        {
+            get { return _EndDate; }
+            set { SetProperty(ref _EndDate, value); }
+        }
+
+        private ObservableCollection<PhotoCaptureRecord> _Results;
+        public ObservableCollection<PhotoCaptureRecord> Results
+        {
+            get { return _Results; }
+            set { SetProperty(ref _Results, value); }
+        }
+
+        private int _PageIndex;
+        public int PageIndex
+        {
+            get { return _PageIndex; }
+            set { SetProperty(ref _PageIndex, value); }
+        }
+        private int _PageSize;
+        public int PageSize
+        {
+            get { return _PageSize; }
+            set { SetProperty(ref _PageSize, value); }
+        }
+        private int _TotalCount;
+        public int TotalCount
+        {
+            get { return _TotalCount; }
+            set { SetProperty(ref _TotalCount, value); }
+        }
+
+        public DelegateCommand SearchCommand { get; private set; }
+        public DelegateCommand PrevPageCommand { get; private set; }
+        public DelegateCommand NextPageCommand { get; private set; }
+        public DelegateCommand ExportCommand { get; private set; }
+
+        private DelegateCommand _LoadedCommand;
+        public DelegateCommand LoadedCommand =>
+            _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
+        void ExecuteLoadedCommand()
+        {
+            AllProduct = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
+            _AllCamera = new ObservableCollection<CameraInfo>(_configService.GetAllCameras());
+        }
+
+        private async Task ExecuteSearchCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var res = await _systemDatabaseService.QueryPhotoCapturesAsync(SelectedProduct?.Name, SelectedCamera?.CameraName, ProductSN, start, end);
+                Results = new ObservableCollection<PhotoCaptureRecord>(res);
+                TotalCount = Results.Count;
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async Task ExecuteExportCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var all = await _systemDatabaseService.QueryPhotoCapturesAsync(SelectedProduct?.Name, SelectedCamera?.CameraName, ProductSN, start, end);
+                if (all == null || !all.Any()) { MessageBox.Show("没有找到符合条件的记录", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; }
+                var dlg = new Microsoft.Win32.SaveFileDialog { FileName = $"PhotoCapture_{DateTime.Now:yyyyMMddHHmmss}.csv", DefaultExt = ".csv", Filter = "CSV Files (*.csv)|*.csv" };
+                if (dlg.ShowDialog() != true) return;
+                var path = dlg.FileName;
+                using (var sw = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    sw.WriteLine("CaptureTime,RecipeName,CameraName,ProductSN,Result,ImagePath");
+                    foreach (var r in all)
+                    {
+                        sw.WriteLine($"{r.CaptureTime:yyyy-MM-dd HH:mm:ss},{r.RecipeName},{r.CameraName},{r.ProductSN},{r.IsSuccess},{r.ImagePath}");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+    }
+}

+ 147 - 0
TeamAAS-VM/ViewModels/Statistics/ProductionRecordQueryViewModel.cs

@@ -0,0 +1,147 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models.Product;
+using TeamAAS_VP.Models;
+
+namespace TeamAAS_VP.ViewModels.Statistics
+{
+    public class ProductionRecordQueryViewModel : BindableBase
+    {
+        private readonly IProductService _productService;
+        private readonly ISystemDatabaseService _systemDatabaseService;
+
+        public ProductionRecordQueryViewModel(IProductService productService, ISystemDatabaseService systemDatabaseService)
+        {
+            _productService = productService;
+            _systemDatabaseService = systemDatabaseService;
+
+            PageSize = 20;
+            PageIndex = 1;
+            AllProduct = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
+            Categories = new ObservableCollection<string>();
+
+            StartDate = DateTime.Now.Date;
+            EndDate = DateTime.Now.Date.AddDays(1);
+
+            SearchCommand = new DelegateCommand(async () => await ExecuteSearchCommand()).ObservesProperty(() => SelectedProduct).ObservesProperty(() => StartDate).ObservesProperty(() => EndDate);
+            PrevPageCommand = new DelegateCommand(async () => { if (PageIndex > 1) { PageIndex--; await ExecuteSearchCommand(); } }).ObservesProperty(() => PageIndex);
+            NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } }).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalCount);
+            ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand()).ObservesProperty(() => Results);
+        }
+
+        public ObservableCollection<ProductModel> AllProduct { get; set; }
+        public ObservableCollection<string> Categories { get; set; }
+
+        private ProductModel _SelectedProduct;
+        public ProductModel SelectedProduct { get => _SelectedProduct; set { SetProperty(ref _SelectedProduct, value); if (value != null) LoadCategoriesForProduct(value.Name); } }
+
+        private string _SelectedCategory;
+        public string SelectedCategory { get => _SelectedCategory; set { SetProperty(ref _SelectedCategory, value); } }
+
+        private DateTime? _StartDate;
+        public DateTime? StartDate { get => _StartDate; set { SetProperty(ref _StartDate, value); } }
+
+        private DateTime? _EndDate;
+        public DateTime? EndDate { get => _EndDate; set { SetProperty(ref _EndDate, value); } }
+
+        private ObservableCollection<ProductionRecord> _Results = new ObservableCollection<ProductionRecord>();
+        public ObservableCollection<ProductionRecord> Results { get => _Results; set { SetProperty(ref _Results, value); } }
+
+        private int _PageIndex;
+        public int PageIndex
+        {
+            get { return _PageIndex; }
+            set { SetProperty(ref _PageIndex, value); }
+        }
+        private int _PageSize;
+        public int PageSize
+        {
+            get { return _PageSize; }
+            set { SetProperty(ref _PageSize, value); }
+        }
+        private int _TotalCount;
+        public int TotalCount
+        {
+            get { return _TotalCount; }
+            set { SetProperty(ref _TotalCount, value); }
+        }
+
+        public DelegateCommand SearchCommand { get; private set; }
+        public DelegateCommand PrevPageCommand { get; private set; }
+        public DelegateCommand NextPageCommand { get; private set; }
+        public DelegateCommand ExportCommand { get; private set; }
+
+        private DelegateCommand _LoadedCommand;
+        public DelegateCommand LoadedCommand =>
+            _LoadedCommand ?? (_LoadedCommand = new DelegateCommand(ExecuteLoadedCommand));
+        void ExecuteLoadedCommand()
+        {
+            AllProduct = new ObservableCollection<ProductModel>(_productService.GetAllProducts());
+        }
+
+        private async Task ExecuteSearchCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value.Date : DateTime.MinValue;
+                var end = EndDate.HasValue ? EndDate.Value.Date.AddDays(1) : DateTime.MaxValue;
+                string productName = SelectedProduct?.Name;
+                var res = await _systemDatabaseService.QueryProductionRecordsPagedAsync(start, end, PageIndex, PageSize, productName, SelectedCategory);
+                Results = new ObservableCollection<ProductionRecord>(res.Items);
+                TotalCount = res.TotalCount;
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "´íÎó", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async Task ExecuteExportCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value.Date : DateTime.MinValue;
+                var end = EndDate.HasValue ? EndDate.Value.Date.AddDays(1) : DateTime.MaxValue;
+                string productName = SelectedProduct?.Name;
+                var resAll = await _systemDatabaseService.GetProductionStatsAsync(new ProductionStatQuery { ProductName = productName, Start = start, End = end, GroupBy = "total" });
+                var saveFileDialog = new Microsoft.Win32.SaveFileDialog { FileName = $"Production_{DateTime.Now:yyyyMMddHHmmss}.csv", DefaultExt = ".csv", Filter = "CSV Files (*.csv)|*.csv" };
+                if (saveFileDialog.ShowDialog() != true) return;
+                var path = saveFileDialog.FileName;
+                using (var sw = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    sw.WriteLine("PeriodStart,PeriodEnd,Quantity,ProductName");
+                    foreach (var r in resAll)
+                    {
+                        sw.WriteLine($"{r.PeriodStart:yyyy-MM-dd HH:mm:ss},{r.PeriodEnd:yyyy-MM-dd HH:mm:ss},{r.Quantity},{r.ProductName}");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "´íÎó", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async void LoadCategoriesForProduct(string productName)
+        {
+            try
+            {
+                Categories.Clear();
+                var cats = await _systemDatabaseService.GetProductCategoriesAsync(productName);
+                if (cats != null)
+                {
+                    foreach (var c in cats) Categories.Add(c);
+                }
+            }
+            catch { }
+        }
+    }
+}

+ 125 - 0
TeamAAS-VM/ViewModels/Statistics/ScrewFeederBatchQueryViewModel.cs

@@ -0,0 +1,125 @@
+using Prism.Commands;
+using Prism.Mvvm;
+using System;
+using System.Collections.ObjectModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using TeamAAS_VP.Interfaces;
+using TeamAAS_VP.Models;
+
+namespace TeamAAS_VP.ViewModels.Statistics
+{
+    public class ScrewFeederBatchQueryViewModel : BindableBase
+    {
+        private readonly ISystemDatabaseService _systemDatabaseService;
+        public ScrewFeederBatchQueryViewModel(ISystemDatabaseService systemDatabaseService)
+        {
+            _systemDatabaseService = systemDatabaseService;
+            PageSize = 20; PageIndex = 1;
+            StartDate = DateTime.Now.Date; EndDate = DateTime.Now.Date.AddDays(1);
+            SearchCommand = new DelegateCommand(async () => await ExecuteSearchCommand());
+            PrevPageCommand = new DelegateCommand(async () => { if (PageIndex > 1) { PageIndex--; await ExecuteSearchCommand(); } });
+            NextPageCommand = new DelegateCommand(async () => { if (PageIndex * PageSize < TotalCount) { PageIndex++; await ExecuteSearchCommand(); } });
+            ExportCommand = new DelegateCommand(async () => await ExecuteExportCommand());
+        }
+
+        private DateTime? _StartDate;
+        public DateTime? StartDate
+        {
+            get { return _StartDate; }
+            set { SetProperty(ref _StartDate, value); }
+        }
+        private DateTime? _EndDate;
+        public DateTime? EndDate
+        {
+            get { return _EndDate; }
+            set { SetProperty(ref _EndDate, value); }
+        }
+        private string _BatchNumber;
+        public string BatchNumber
+        {
+            get { return _BatchNumber; }
+            set { SetProperty(ref _BatchNumber, value); }
+        }
+        private int? _FeederNumber;
+        public int? FeederNumber
+        {
+            get { return _FeederNumber; }
+            set { SetProperty(ref _FeederNumber, value); }
+        }
+        private ObservableCollection<ScrewFeederBatchRecord> _Results;
+        public ObservableCollection<ScrewFeederBatchRecord> Results
+        {
+            get { return _Results; }
+            set { SetProperty(ref _Results, value); }
+        }
+        private int _PageIndex;
+        public int PageIndex
+        {
+            get { return _PageIndex; }
+            set { SetProperty(ref _PageIndex, value); }
+        }
+        private int _PageSize;
+        public int PageSize
+        {
+            get { return _PageSize; }
+            set { SetProperty(ref _PageSize, value); }
+        }
+        private int _TotalCount;
+        public int TotalCount
+        {
+            get { return _TotalCount; }
+            set { SetProperty(ref _TotalCount, value); }
+        }
+
+        public DelegateCommand SearchCommand { get; private set; }
+        public DelegateCommand PrevPageCommand { get; private set; }
+        public DelegateCommand NextPageCommand { get; private set; }
+        public DelegateCommand ExportCommand { get; private set; }
+
+        private async Task ExecuteSearchCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var res = await _systemDatabaseService.QueryScrewFeederBatchRecordsPagedAsync(start, end, BatchNumber, FeederNumber, PageIndex, PageSize);
+                Results = new ObservableCollection<ScrewFeederBatchRecord>(res.Items);
+                TotalCount = res.TotalCount;
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+
+        private async Task ExecuteExportCommand()
+        {
+            try
+            {
+                var start = StartDate.HasValue ? StartDate.Value : (DateTime?)null;
+                var end = EndDate.HasValue ? EndDate.Value : (DateTime?)null;
+                var all = await _systemDatabaseService.QueryScrewFeederBatchRecordsAsync(start, end, BatchNumber, FeederNumber);
+                if (all == null || !all.Any()) { MessageBox.Show("没有找到符合条件的记录", "提示", MessageBoxButton.OK, MessageBoxImage.Information); return; }
+                var dlg = new Microsoft.Win32.SaveFileDialog { FileName = $"ScrewFeederBatch_{DateTime.Now:yyyyMMddHHmmss}.csv", DefaultExt = ".csv", Filter = "CSV Files (*.csv)|*.csv" };
+                if (dlg.ShowDialog() != true) return;
+                var path = dlg.FileName;
+                using (var sw = new StreamWriter(path, false, Encoding.UTF8))
+                {
+                    sw.WriteLine("ChangeTime,BatchNumber,FeederNumber,OperatorName");
+                    foreach (var r in all)
+                    {
+                        sw.WriteLine($"{r.ChangeTime:yyyy-MM-dd HH:mm:ss},{r.BatchNumber},{r.FeederNumber},{r.OperatorName}");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
+            }
+        }
+    }
+}

+ 117 - 0
TeamAAS-VM/Views/Statistics/HeadChangeRecordQuery.xaml

@@ -0,0 +1,117 @@
+<UserControl x:Class="TeamAAS_VP.Views.Statistics.HeadChangeRecordQuery"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Statistics"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:HeadChangeRecordQueryViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White">
+    <Grid Margin="8">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+
+        <!--标题-->
+        <TextBlock Text="披头更换记录查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
+
+        <StackPanel Grid.Row="1"
+                    Orientation="Horizontal"
+                    Margin="0,0,0,8">
+            <TextBlock Text="开始"
+                       VerticalAlignment="Center"
+                       Margin="0,0,8,0" />
+            <DatePicker SelectedDate="{Binding StartDate}"
+                        MinWidth="100" />
+            <TextBlock Text="结束"
+                       VerticalAlignment="Center"
+                       Margin="8,0,8,0" />
+            <DatePicker SelectedDate="{Binding EndDate}"
+                        MinWidth="100" />
+            <TextBlock Text="披头批次"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <TextBox Width="150"
+                     Text="{Binding HeadBatchNumber}" />
+            <Button Content="查询"
+                    Command="{Binding SearchCommand}"
+                    Margin="12,0,0,0" />
+            <Button Content="导出当前页"
+                    Command="{Binding ExportCommand}"
+                    Margin="6,0,0,0" />
+        </StackPanel>
+        <DataGrid Grid.Row="2"
+                  ItemsSource="{Binding Results}"
+                  AutoGenerateColumns="False"
+                  CanUserAddRows="False"
+                  IsReadOnly="True">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="ChangeTime"
+                                    Binding="{Binding ChangeTime, StringFormat=yyyy-MM-dd HH:mm:ss}" />
+                <DataGridTextColumn Header="HeadBatchNumber"
+                                    Binding="{Binding HeadBatchNumber}" />
+                <DataGridTextColumn Header="CurrentLockCount"
+                                    Binding="{Binding CurrentLockCount}" />
+                <DataGridTextColumn Header="OperatorName"
+                                    Binding="{Binding OperatorName}" />
+            </DataGrid.Columns>
+        </DataGrid>
+        <StackPanel Grid.Row="3"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    Margin="0,8,0,0">
+            <Button Content="上一页"
+                    Command="{Binding PrevPageCommand}"
+                    Margin="4" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">第</TextBlock>
+            <TextBox Width="50"
+                     Text="{Binding PageIndex, UpdateSourceTrigger=PropertyChanged}"
+                     HorizontalContentAlignment="Center" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">页 / 共</TextBlock>
+            <TextBlock VerticalAlignment="Center"
+                       Text="{Binding TotalCount}"
+                       Margin="4" />
+            <Button Content="下一页"
+                    Command="{Binding NextPageCommand}"
+                    Margin="4" />
+        </StackPanel>
+
+        <Button Margin="16"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
+            <materialDesign:PackIcon Kind="StepBackward" />
+        </Button>
+        <Button Margin="16"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
+            <materialDesign:PackIcon Kind="StepForward" />
+        </Button>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Statistics/HeadChangeRecordQuery.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Statistics
+{
+    /// <summary>
+    /// HeadChangeRecordQuery.xaml 的交互逻辑
+    /// </summary>
+    public partial class HeadChangeRecordQuery : UserControl
+    {
+        public HeadChangeRecordQuery()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 18 - 5
TeamAAS-VM/Views/Statistics/LockResultRecoredQuery.xaml

@@ -20,14 +20,27 @@
              d:Height="600"
              d:Width="1024"
              d:Background="White">
+    <b:Interaction.Triggers>
+        <b:EventTrigger EventName="Loaded">
+            <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
+        </b:EventTrigger>
+    </b:Interaction.Triggers>
     <Grid Margin="8">
         <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
             <RowDefinition Height="Auto" />
             <RowDefinition Height="*" />
             <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
+        
+        <!--标题-->
+        <TextBlock Grid.Row="0"
+                   Text="锁付结果记录查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
 
-        <StackPanel Orientation="Horizontal"
+        <StackPanel Grid.Row="1" Orientation="Horizontal"
                     VerticalAlignment="Center"
                     Margin="0,0,0,8">
             <TextBlock Text="{lex:Loc 产品}"
@@ -67,7 +80,7 @@
                     Margin="6,0,0,0" />
         </StackPanel>
 
-        <DataGrid Grid.Row="1"
+        <DataGrid Grid.Row="2"
                   ItemsSource="{Binding Results}"
                   AutoGenerateColumns="False"
                   CanUserAddRows="False"
@@ -190,7 +203,7 @@
         <Button Margin="16"
                 HorizontalAlignment="Left"
                 VerticalAlignment="Center"
-                Grid.RowSpan="2"
+                Grid.RowSpan="3"
                 Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
                 Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
             <materialDesign:PackIcon Kind="StepBackward" />
@@ -198,12 +211,12 @@
         <Button Margin="16"
                 HorizontalAlignment="Right"
                 VerticalAlignment="Center"
-                Grid.RowSpan="2"
+                Grid.RowSpan="3"
                 Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
                 Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
             <materialDesign:PackIcon Kind="StepForward" />
         </Button>
-        <StackPanel Grid.Row="2"
+        <StackPanel Grid.Row="3"
                     Orientation="Horizontal"
                     HorizontalAlignment="Center"
                     Margin="0,8,0,0">

+ 115 - 0
TeamAAS-VM/Views/Statistics/NozzleChangeRecordQuery.xaml

@@ -0,0 +1,115 @@
+<UserControl x:Class="TeamAAS_VP.Views.Statistics.NozzleChangeRecordQuery"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Statistics"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:NozzleChangeRecordQueryViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White">
+    <Grid Margin="8">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <!--标题-->
+        <TextBlock Text="吸嘴更换记录查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
+        <StackPanel Grid.Row="1"
+                    Orientation="Horizontal"
+                    Margin="0,0,0,8">
+            <TextBlock Text="开始"
+                       VerticalAlignment="Center"
+                       Margin="0,0,8,0" />
+            <DatePicker SelectedDate="{Binding StartDate}"
+                        MinWidth="100" />
+            <TextBlock Text="结束"
+                       VerticalAlignment="Center"
+                       Margin="8,0,8,0" />
+            <DatePicker SelectedDate="{Binding EndDate}"
+                        MinWidth="100" />
+            <TextBlock Text="喷嘴批号"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <TextBox Width="150"
+                     Text="{Binding NozzleBatchNumber}" />
+            <Button Content="查询"
+                    Command="{Binding SearchCommand}"
+                    Margin="12,0,0,0" />
+            <Button Content="导出当前页"
+                    Command="{Binding ExportCommand}"
+                    Margin="6,0,0,0" />
+        </StackPanel>
+        <DataGrid Grid.Row="2"
+                  ItemsSource="{Binding Results}"
+                  AutoGenerateColumns="False"
+                  CanUserAddRows="False"
+                  IsReadOnly="True">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="ChangeTime"
+                                    Binding="{Binding ChangeTime, StringFormat=yyyy-MM-dd HH:mm:ss}" />
+                <DataGridTextColumn Header="NozzleBatchNumber"
+                                    Binding="{Binding NozzleBatchNumber}" />
+                <DataGridTextColumn Header="CurrentLockCount"
+                                    Binding="{Binding CurrentLockCount}" />
+                <DataGridTextColumn Header="OperatorName"
+                                    Binding="{Binding OperatorName}" />
+            </DataGrid.Columns>
+        </DataGrid>
+        <StackPanel Grid.Row="3"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    Margin="0,8,0,0">
+            <Button Content="上一页"
+                    Command="{Binding PrevPageCommand}"
+                    Margin="4" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">第</TextBlock>
+            <TextBox Width="50"
+                     Text="{Binding PageIndex, UpdateSourceTrigger=PropertyChanged}"
+                     HorizontalContentAlignment="Center" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">页 / 共</TextBlock>
+            <TextBlock VerticalAlignment="Center"
+                       Text="{Binding TotalCount}"
+                       Margin="4" />
+            <Button Content="下一页"
+                    Command="{Binding NextPageCommand}"
+                    Margin="4" />
+        </StackPanel>
+
+        <Button Margin="16"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
+            <materialDesign:PackIcon Kind="StepBackward" />
+        </Button>
+        <Button Margin="16"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
+            <materialDesign:PackIcon Kind="StepForward" />
+        </Button>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Statistics/NozzleChangeRecordQuery.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Statistics
+{
+    /// <summary>
+    /// NozzleChangeRecordQuery.xaml 的交互逻辑
+    /// </summary>
+    public partial class NozzleChangeRecordQuery : UserControl
+    {
+        public NozzleChangeRecordQuery()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 139 - 0
TeamAAS-VM/Views/Statistics/PhotoCaptureQuery.xaml

@@ -0,0 +1,139 @@
+<UserControl x:Class="TeamAAS_VP.Views.Statistics.PhotoCaptureQuery"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Statistics"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:PhotoCaptureQueryViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White">
+    <b:Interaction.Triggers>
+        <b:EventTrigger EventName="Loaded">
+            <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
+        </b:EventTrigger>
+    </b:Interaction.Triggers>
+    <Grid Margin="8">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <!--标题-->
+        <TextBlock Text="拍照记录查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
+
+        <StackPanel Grid.Row="1"
+                    Orientation="Horizontal"
+                    Margin="0,0,0,8">
+            <TextBlock Text="产品"
+                       VerticalAlignment="Center"
+                       Margin="0,0,8,0" />
+            <ComboBox MinWidth="100"
+                      ItemsSource="{Binding AllProduct}"
+                      DisplayMemberPath="Name"
+                      SelectedItem="{Binding SelectedProduct}" />
+            <TextBlock Text="相机"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <ComboBox MinWidth="100"
+                      ItemsSource="{Binding AllCamera}"
+                      DisplayMemberPath="CameraName"
+                      SelectedItem="{Binding SelectedCamera}" />
+            <TextBlock Text="产品SN"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <TextBox Width="150"
+                     Text="{Binding ProductSN}" />
+            <TextBlock Text="开始"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <DatePicker SelectedDate="{Binding StartDate}"
+                        MinWidth="100" />
+            <TextBlock Text="结束"
+                       VerticalAlignment="Center"
+                       Margin="8,0,8,0" />
+            <DatePicker SelectedDate="{Binding EndDate}"
+                        MinWidth="100" />
+            <Button Content="查询"
+                    Command="{Binding SearchCommand}"
+                    Margin="12,0,0,0" />
+            <Button Content="导出当前页"
+                    Command="{Binding ExportCommand}"
+                    Margin="6,0,0,0" />
+        </StackPanel>
+        <DataGrid Grid.Row="2"
+                  ItemsSource="{Binding Results}"
+                  AutoGenerateColumns="False"
+                  CanUserAddRows="False"
+                  IsReadOnly="True">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="CaptureTime"
+                                    Binding="{Binding CaptureTime, StringFormat=yyyy-MM-dd HH:mm:ss}" />
+                <DataGridTextColumn Header="RecipeName"
+                                    Binding="{Binding RecipeName}" />
+                <DataGridTextColumn Header="CameraName"
+                                    Binding="{Binding CameraName}" />
+                <DataGridTextColumn Header="ProductSN"
+                                    Binding="{Binding ProductSN}" />
+                <DataGridTextColumn Header="Result"
+                                    Binding="{Binding Result}" />
+                <DataGridTextColumn Header="ImagePath"
+                                    Binding="{Binding ImagePath}" />
+            </DataGrid.Columns>
+        </DataGrid>
+        <StackPanel Grid.Row="3"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    Margin="0,8,0,0">
+            <Button Content="上一页"
+                    Command="{Binding PrevPageCommand}"
+                    Margin="4" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">第</TextBlock>
+            <TextBox Width="50"
+                     Text="{Binding PageIndex, UpdateSourceTrigger=PropertyChanged}"
+                     HorizontalContentAlignment="Center" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">页 / 共</TextBlock>
+            <TextBlock VerticalAlignment="Center"
+                       Text="{Binding TotalCount}"
+                       Margin="4" />
+            <Button Content="下一页"
+                    Command="{Binding NextPageCommand}"
+                    Margin="4" />
+        </StackPanel>
+
+        <Button Margin="16"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
+            <materialDesign:PackIcon Kind="StepBackward" />
+        </Button>
+        <Button Margin="16"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
+            <materialDesign:PackIcon Kind="StepForward" />
+        </Button>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Statistics/PhotoCaptureQuery.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Statistics
+{
+    /// <summary>
+    /// PhotoCaptureQuery.xaml 的交互逻辑
+    /// </summary>
+    public partial class PhotoCaptureQuery : UserControl
+    {
+        public PhotoCaptureQuery()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 133 - 0
TeamAAS-VM/Views/Statistics/ProductionRecordQuery.xaml

@@ -0,0 +1,133 @@
+<UserControl x:Class="TeamAAS_VP.Views.Statistics.ProductionRecordQuery"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Statistics"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:ProductionRecordQueryViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White">
+    <b:Interaction.Triggers>
+        <b:EventTrigger EventName="Loaded">
+            <b:InvokeCommandAction Command="{Binding LoadedCommand}" />
+        </b:EventTrigger>
+    </b:Interaction.Triggers>
+    <Grid Margin="8">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <!--标题-->
+        <TextBlock Text="生产记录查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
+
+        <StackPanel Grid.Row="1"
+                    Orientation="Horizontal"
+                    Margin="0,0,0,8">
+            <TextBlock Text="产品"
+                       VerticalAlignment="Center"
+                       Margin="0,0,8,0" />
+            <ComboBox Width="200"
+                      ItemsSource="{Binding AllProduct}"
+                      DisplayMemberPath="Name"
+                      SelectedItem="{Binding SelectedProduct}" />
+            <TextBlock Text="类别"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <ComboBox Width="150"
+                      ItemsSource="{Binding Categories}"
+                      SelectedItem="{Binding SelectedCategory}" />
+            <TextBlock Text="开始"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <DatePicker SelectedDate="{Binding StartDate}"
+                        MinWidth="100" />
+            <TextBlock Text="结束"
+                       VerticalAlignment="Center"
+                       Margin="8,0,8,0" />
+            <DatePicker SelectedDate="{Binding EndDate}"
+                        MinWidth="100" />
+            <Button Content="查询"
+                    Command="{Binding SearchCommand}"
+                    Margin="12,0,0,0" />
+            <Button Content="导出当前页"
+                    Command="{Binding ExportCommand}"
+                    Margin="6,0,0,0" />
+        </StackPanel>
+        <DataGrid Grid.Row="2"
+                  ItemsSource="{Binding Results}"
+                  AutoGenerateColumns="False"
+                  CanUserAddRows="False"
+                  IsReadOnly="True">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="时间"
+                                    Binding="{Binding Timestamp, StringFormat=yyyy-MM-dd HH:mm:ss}" />
+                <DataGridTextColumn Header="产品"
+                                    Binding="{Binding ProductName}" />
+                <DataGridTextColumn Header="类别"
+                                    Binding="{Binding Category}" />
+                <DataGridTextColumn Header="数量"
+                                    Binding="{Binding Quantity}" />
+                <DataGridTextColumn Header="操作员"
+                                    Binding="{Binding UserName}" />
+                <DataGridTextColumn Header="备注"
+                                    Binding="{Binding Remark}" />
+            </DataGrid.Columns>
+        </DataGrid>
+        <StackPanel Grid.Row="3"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    Margin="0,8,0,0">
+            <Button Content="上一页"
+                    Command="{Binding PrevPageCommand}"
+                    Margin="4" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">第</TextBlock>
+            <TextBox Width="50"
+                     Text="{Binding PageIndex, UpdateSourceTrigger=PropertyChanged}"
+                     HorizontalContentAlignment="Center" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">页 / 共</TextBlock>
+            <TextBlock VerticalAlignment="Center"
+                       Text="{Binding TotalCount}"
+                       Margin="4" />
+            <Button Content="下一页"
+                    Command="{Binding NextPageCommand}"
+                    Margin="4" />
+        </StackPanel>
+
+        <Button Margin="16"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
+            <materialDesign:PackIcon Kind="StepBackward" />
+        </Button>
+        <Button Margin="16"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
+            <materialDesign:PackIcon Kind="StepForward" />
+        </Button>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Statistics/ProductionRecordQuery.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Statistics
+{
+    /// <summary>
+    /// ProductionRecordQuery.xaml 的交互逻辑
+    /// </summary>
+    public partial class ProductionRecordQuery : UserControl
+    {
+        public ProductionRecordQuery()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 123 - 0
TeamAAS-VM/Views/Statistics/ScrewFeederBatchQuery.xaml

@@ -0,0 +1,123 @@
+<UserControl x:Class="TeamAAS_VP.Views.Statistics.ScrewFeederBatchQuery"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:prism="http://prismlibrary.com/"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+             xmlns:vm="clr-namespace:TeamAAS_VP.ViewModels.Statistics"
+             xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
+             xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
+             xmlns:lex="http://wpflocalizeextension.codeplex.com"
+             lex:LocalizeDictionary.DesignCulture="zh-CN"
+             lex:ResxLocalizationProvider.DefaultAssembly="TeamAAS-VP"
+             lex:ResxLocalizationProvider.DefaultDictionary="Lang"
+             prism:ViewModelLocator.AutoWireViewModel="True"
+             HorizontalAlignment="Stretch"
+             VerticalAlignment="Stretch"
+             FontFamily="{DynamicResource DefaultFont}"
+             mc:Ignorable="d"
+             d:DataContext="{d:DesignInstance Type=vm:ScrewFeederBatchQueryViewModel}"
+             d:Height="600"
+             d:Width="1024"
+             d:Background="White">
+    <Grid Margin="8">
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+            <RowDefinition Height="Auto" />
+        </Grid.RowDefinitions>
+        <!--标题-->
+        <TextBlock Text="螺丝更换批次查询"
+                   FontSize="20"
+                   FontWeight="Bold"
+                   Margin="0,0,0,12" />
+
+        <StackPanel Grid.Row="1"
+                    Orientation="Horizontal"
+                    Margin="0,0,0,8">
+            <TextBlock Text="开始"
+                       VerticalAlignment="Center"
+                       Margin="0,0,8,0" />
+            <DatePicker SelectedDate="{Binding StartDate}"
+                        MinWidth="100" />
+            <TextBlock Text="结束"
+                       VerticalAlignment="Center"
+                       Margin="8,0,8,0" />
+            <DatePicker SelectedDate="{Binding EndDate}"
+                        MinWidth="100" />
+            <TextBlock Text="批次号"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <TextBox Width="150"
+                     Text="{Binding BatchNumber}" />
+            <TextBlock Text="供料器"
+                       VerticalAlignment="Center"
+                       Margin="16,0,8,0" />
+            <TextBox Width="80"
+                     Text="{Binding FeederNumber}" />
+            <Button Content="查询"
+                    Command="{Binding SearchCommand}"
+                    Margin="12,0,0,0" />
+            <Button Content="导出当前页"
+                    Command="{Binding ExportCommand}"
+                    Margin="6,0,0,0" />
+        </StackPanel>
+        <DataGrid Grid.Row="2"
+                  ItemsSource="{Binding Results}"
+                  AutoGenerateColumns="False"
+                  CanUserAddRows="False"
+                  IsReadOnly="True">
+            <DataGrid.Columns>
+                <DataGridTextColumn Header="ChangeTime"
+                                    Binding="{Binding ChangeTime, StringFormat=yyyy-MM-dd HH:mm:ss}" />
+                <DataGridTextColumn Header="BatchNumber"
+                                    Binding="{Binding BatchNumber}" />
+                <DataGridTextColumn Header="FeederNumber"
+                                    Binding="{Binding FeederNumber}" />
+                <DataGridTextColumn Header="Operator"
+                                    Binding="{Binding OperatorName}" />
+                <DataGridTextColumn Header="Remark"
+                                    Binding="{Binding Remark}" />
+            </DataGrid.Columns>
+        </DataGrid>
+        <StackPanel Grid.Row="3"
+                    Orientation="Horizontal"
+                    HorizontalAlignment="Center"
+                    Margin="0,8,0,0">
+            <Button Content="上一页"
+                    Command="{Binding PrevPageCommand}"
+                    Margin="4" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">第</TextBlock>
+            <TextBox Width="50"
+                     Text="{Binding PageIndex, UpdateSourceTrigger=PropertyChanged}"
+                     HorizontalContentAlignment="Center" />
+            <TextBlock VerticalAlignment="Center"
+                       Margin="4">页 / 共</TextBlock>
+            <TextBlock VerticalAlignment="Center"
+                       Text="{Binding TotalCount}"
+                       Margin="4" />
+            <Button Content="下一页"
+                    Command="{Binding NextPageCommand}"
+                    Margin="4" />
+        </StackPanel>
+
+        <Button Margin="16"
+                HorizontalAlignment="Left"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MovePreviousCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionMiniButton}">
+            <materialDesign:PackIcon Kind="StepBackward" />
+        </Button>
+        <Button Margin="16"
+                HorizontalAlignment="Right"
+                VerticalAlignment="Center"
+                Grid.RowSpan="3"
+                Command="{x:Static materialDesign:Transitioner.MoveNextCommand}"
+                Style="{StaticResource MaterialDesignFloatingActionSecondaryButton}">
+            <materialDesign:PackIcon Kind="StepForward" />
+        </Button>
+    </Grid>
+</UserControl>

+ 28 - 0
TeamAAS-VM/Views/Statistics/ScrewFeederBatchQuery.xaml.cs

@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace TeamAAS_VP.Views.Statistics
+{
+    /// <summary>
+    /// ScrewFeederBatchQuery.xaml 的交互逻辑
+    /// </summary>
+    public partial class ScrewFeederBatchQuery : UserControl
+    {
+        public ScrewFeederBatchQuery()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 14 - 4
TeamAAS-VM/Views/StatisticsView.xaml

@@ -25,13 +25,23 @@
             <materialDesign:TransitionerSlide OpeningEffect="{materialDesign:TransitionEffect FadeIn}">
                 <local:ProductionStatement />
             </materialDesign:TransitionerSlide>
-
+            <!--锁付记录查询-->
             <local:LockResultRecoredQuery />
-            
+            <!--拍照记录查询-->
+            <local:PhotoCaptureQuery />
+            <!--生产记录查询-->
+            <local:ProductionRecordQuery />
+            <!--螺丝批次更换记录-->
+            <local:ScrewFeederBatchQuery />
+            <!--披头更换记录查询-->
+            <local:HeadChangeRecordQuery />
+            <!--吸嘴更换记录查询-->
+            <local:NozzleChangeRecordQuery />
+            <!--统计记录查询-->
             <local:StatisticalQuery />
-
+            <!--报警记录查询-->
             <local:AlarmQuery />
-            
+
         </materialDesign:Transitioner>
     </Grid>
 </UserControl>