251029
This commit is contained in:
20
FATrace.WPLApp/ViewModels/FootViewModel.cs
Normal file
20
FATrace.WPLApp/ViewModels/FootViewModel.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using FATrace.WPLApp.Core;
|
||||
using FATrace.WPLApp.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FATrace.WPLApp.ViewModels
|
||||
{
|
||||
public class FootViewModel : NavigationViewModel
|
||||
{
|
||||
public FootViewModel(SysRunService sysRunService)
|
||||
{
|
||||
SysRunService = sysRunService;
|
||||
}
|
||||
|
||||
public SysRunService SysRunService { get; }
|
||||
}
|
||||
}
|
||||
20
FATrace.WPLApp/ViewModels/HeadViewModel.cs
Normal file
20
FATrace.WPLApp/ViewModels/HeadViewModel.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using FATrace.WPLApp.Core;
|
||||
using FATrace.WPLApp.Services;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FATrace.WPLApp.ViewModels
|
||||
{
|
||||
public class HeadViewModel : NavigationViewModel
|
||||
{
|
||||
public HeadViewModel(SysRunService sysRunService)
|
||||
{
|
||||
SysRunService = sysRunService;
|
||||
}
|
||||
|
||||
public SysRunService SysRunService { get; }
|
||||
}
|
||||
}
|
||||
136
FATrace.WPLApp/ViewModels/MainViewModel.cs
Normal file
136
FATrace.WPLApp/ViewModels/MainViewModel.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using FATrace.WPLApp.Core;
|
||||
using FATrace.WPLApp.ModelDto;
|
||||
using FATrace.WPLApp.Services;
|
||||
using FATrace.WPLApp.Views;
|
||||
using Prism.Commands;
|
||||
using Prism.Events;
|
||||
using Prism.Regions;
|
||||
using Prism.Services.Dialogs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace FATrace.WPLApp.ViewModels
|
||||
{
|
||||
public class MainViewModel : NavigationViewModel
|
||||
{
|
||||
public MainViewModel(IRegionManager regionManager, IDialogService dialogService, IEventAggregator eventAggregator, NavigationServices navigationServices)
|
||||
{
|
||||
this.regionManager = regionManager;
|
||||
DialogService = dialogService;
|
||||
NavigationServices = navigationServices;
|
||||
NavigationItems = NavigationServices.NavItemDtos;
|
||||
|
||||
this.regionManager.RegisterViewWithRegion("FootRegion", typeof(FootView));
|
||||
this.regionManager.RegisterViewWithRegion("HeadRegion", typeof(HeadView));
|
||||
|
||||
//this.regionManager.RegisterViewWithRegion("ContentRegion", typeof(ProFlowView));
|
||||
|
||||
}
|
||||
|
||||
private IRegionManager regionManager { get; set; }
|
||||
public IDialogService DialogService { get; }
|
||||
public NavigationServices NavigationServices { get; }
|
||||
|
||||
public ObservableCollection<NavItemDto> NavigationItems { get; set; }
|
||||
|
||||
private string titel = string.Empty;
|
||||
/// <summary>
|
||||
/// 标题
|
||||
/// </summary>
|
||||
public string Title
|
||||
{
|
||||
get { return titel; }
|
||||
set { titel = value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private DelegateCommand<object> _OpenCommand;
|
||||
/// <summary>
|
||||
/// 命令
|
||||
/// </summary>
|
||||
public DelegateCommand<object> OpenCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_OpenCommand == null)
|
||||
{
|
||||
_OpenCommand = new DelegateCommand<object>((p) => OpenCommandMethod(p));
|
||||
}
|
||||
return _OpenCommand;
|
||||
}
|
||||
}
|
||||
|
||||
private void OpenCommandMethod(object obj)
|
||||
{
|
||||
switch (obj.ToString())
|
||||
{
|
||||
case "Dashboard":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("DashBoardView");
|
||||
//this.regionManager.Regions["ContentRegion"].Activate(viewA);
|
||||
break;
|
||||
case "3D工艺流程":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("ProFlowView");
|
||||
//this.regionManager.Regions["DriveTree"].RequestNavigate("DeviceProtocolTreeView");
|
||||
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
||||
break;
|
||||
case "管道线路":
|
||||
DialogService.ShowDialog("DialogLineSelectView", new DialogParameters() { { "TabIndex", "SeletedGroupTabIndex" } }, (par) =>
|
||||
{
|
||||
if (par.Result == ButtonResult.OK)
|
||||
{
|
||||
//程序名称
|
||||
var ReturnValue = par.Parameters.GetValue<string>("Name");
|
||||
//返回数据,刷新Chart
|
||||
|
||||
}
|
||||
else if (par.Result == ButtonResult.Cancel)
|
||||
{
|
||||
//取消
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
break;
|
||||
|
||||
case "报表数据":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("ReportView");
|
||||
|
||||
|
||||
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
||||
break;
|
||||
case "原料使用查询":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("RawProUseView");
|
||||
break;
|
||||
case "原料入库查询":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("RawProInputView");
|
||||
break;
|
||||
case "历史报警":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("HistoryAlarmView");
|
||||
|
||||
|
||||
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
||||
break;
|
||||
case "用户登录":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("UserView");
|
||||
//this.regionManager.Regions["ContentRegion"].Activate(Shift);
|
||||
break;
|
||||
case "使用手册":
|
||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("HelpManualView");
|
||||
//弹窗
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
//this.regionManager.RegisterViewWithRegion("ContentRegion", typeof(CoreShift.Views.Shift.Index));
|
||||
|
||||
//MessageBox.Show(obj.ToString());
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
358
FATrace.WPLApp/ViewModels/RawProInputViewModel.cs
Normal file
358
FATrace.WPLApp/ViewModels/RawProInputViewModel.cs
Normal file
@@ -0,0 +1,358 @@
|
||||
using FATrace.WPLApp.Core;
|
||||
using Prism.Commands;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using FreeSql;
|
||||
using FATrace.Model;
|
||||
using FATrace.WPLApp.Services;
|
||||
using FATrace.WPLApp.ModelDto;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
// 为避免与 System.Windows.HorizontalAlignment/VerticalAlignment 冲突,添加别名
|
||||
using HAlign = NPOI.SS.UserModel.HorizontalAlignment;
|
||||
using VAlign = NPOI.SS.UserModel.VerticalAlignment;
|
||||
|
||||
namespace FATrace.WPLApp.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// 原料入库信息查询 VM
|
||||
/// - 枚举过滤:RawSource、RawSplitState
|
||||
/// - 条件:原料编号/名称、批号、时间范围(CreateTime)
|
||||
/// - 支持分页、Excel 导出
|
||||
/// </summary>
|
||||
public class RawProInputViewModel : NavigationViewModel
|
||||
{
|
||||
private readonly IFreeSql _fsql;
|
||||
private readonly ILogService _log;
|
||||
|
||||
public RawProInputViewModel(IFreeSql fsql, ILogService log)
|
||||
{
|
||||
_fsql = fsql;
|
||||
_log = log;
|
||||
|
||||
Items = new ObservableCollection<RawProInputDto>();
|
||||
Items.CollectionChanged += (s, e) => { try { ExportCommand?.RaiseCanExecuteChanged(); } catch { } };
|
||||
|
||||
// 默认时间范围为今日
|
||||
StartTime = DateTime.Today;
|
||||
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||
|
||||
SearchCommand = new DelegateCommand(async () => await SearchAsync(), () => !IsBusy)
|
||||
.ObservesProperty(() => IsBusy);
|
||||
ExportCommand = new DelegateCommand(ExportToExcel, () => !IsBusy && Items.Count > 0)
|
||||
.ObservesProperty(() => IsBusy);
|
||||
ClearCommand = new DelegateCommand(ClearFilters, () => !IsBusy)
|
||||
.ObservesProperty(() => IsBusy);
|
||||
|
||||
// 分页命令
|
||||
FirstPageCommand = new DelegateCommand(async () => { if (PageIndex == 1) return; PageIndex = 1; await SearchAsync(); }, () => !IsBusy && PageIndex > 1)
|
||||
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex);
|
||||
PrevPageCommand = new DelegateCommand(async () => { if (PageIndex <= 1) return; PageIndex -= 1; await SearchAsync(); }, () => !IsBusy && PageIndex > 1)
|
||||
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex);
|
||||
NextPageCommand = new DelegateCommand(async () => { if (PageIndex >= TotalPages) return; PageIndex += 1; await SearchAsync(); }, () => !IsBusy && PageIndex < TotalPages)
|
||||
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalPages);
|
||||
LastPageCommand = new DelegateCommand(async () => { if (TotalPages <= 0 || PageIndex == TotalPages) return; PageIndex = TotalPages; await SearchAsync(); }, () => !IsBusy && PageIndex < TotalPages)
|
||||
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalPages);
|
||||
}
|
||||
|
||||
#region 查询条件属性
|
||||
public string? RawCode { get => _rawCode; set { _rawCode = value; RaisePropertyChanged(); } }
|
||||
private string? _rawCode;
|
||||
|
||||
public string? RawName { get => _rawName; set { _rawName = value; RaisePropertyChanged(); } }
|
||||
private string? _rawName;
|
||||
|
||||
public string? Batch { get => _batch; set { _batch = value; RaisePropertyChanged(); } }
|
||||
private string? _batch;
|
||||
|
||||
/// <summary>
|
||||
/// 原料来源(可空)
|
||||
/// </summary>
|
||||
public RawSource? SelectedRawSource { get => _selectedRawSource; set { _selectedRawSource = value; RaisePropertyChanged(); } }
|
||||
private RawSource? _selectedRawSource;
|
||||
|
||||
/// <summary>
|
||||
/// 分拆状态(可空)
|
||||
/// </summary>
|
||||
public RawSplitState? SelectedRawState { get => _selectedRawState; set { _selectedRawState = value; RaisePropertyChanged(); } }
|
||||
private RawSplitState? _selectedRawState;
|
||||
|
||||
/// <summary>
|
||||
/// 可绑定到下拉的枚举值列表
|
||||
/// </summary>
|
||||
public Array RawSourceValues => Enum.GetValues(typeof(RawSource));
|
||||
public Array RawSplitStateValues => Enum.GetValues(typeof(RawSplitState));
|
||||
|
||||
public DateTime? StartTime { get => _startTime; set { _startTime = value; RaisePropertyChanged(); } }
|
||||
private DateTime? _startTime;
|
||||
|
||||
public DateTime? EndTime { get => _endTime; set { _endTime = value; RaisePropertyChanged(); } }
|
||||
private DateTime? _endTime;
|
||||
#endregion
|
||||
|
||||
#region 列表与状态
|
||||
/// <summary>
|
||||
/// 查询结果数据集合(DTO)
|
||||
/// </summary>
|
||||
public ObservableCollection<RawProInputDto> Items { get; }
|
||||
|
||||
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
||||
private bool _isBusy;
|
||||
|
||||
public int TotalCount { get => _totalCount; set { _totalCount = value; RaisePropertyChanged(); } }
|
||||
private int _totalCount;
|
||||
|
||||
public int PageIndex { get => _pageIndex; set { _pageIndex = value < 1 ? 1 : value; RaisePropertyChanged(); } }
|
||||
private int _pageIndex = 1;
|
||||
|
||||
public int PageSize
|
||||
{
|
||||
get => _pageSize;
|
||||
set
|
||||
{
|
||||
var v = value <= 0 ? 20 : value;
|
||||
if (_pageSize != v)
|
||||
{
|
||||
_pageSize = v;
|
||||
RaisePropertyChanged();
|
||||
PageIndex = 1;
|
||||
if (!IsBusy) _ = SearchAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
private int _pageSize = 20;
|
||||
|
||||
public int TotalPages { get => _totalPages; set { _totalPages = value; RaisePropertyChanged(); } }
|
||||
private int _totalPages;
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
public DelegateCommand SearchCommand { get; }
|
||||
public DelegateCommand ExportCommand { get; }
|
||||
public DelegateCommand ClearCommand { get; }
|
||||
public DelegateCommand FirstPageCommand { get; }
|
||||
public DelegateCommand PrevPageCommand { get; }
|
||||
public DelegateCommand NextPageCommand { get; }
|
||||
public DelegateCommand LastPageCommand { get; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 清空条件
|
||||
/// </summary>
|
||||
private void ClearFilters()
|
||||
{
|
||||
RawCode = RawName = Batch = string.Empty;
|
||||
SelectedRawSource = null;
|
||||
SelectedRawState = null;
|
||||
StartTime = DateTime.Today;
|
||||
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询逻辑:支持枚举过滤、时间范围(CreateTime)、分页、按 CreateTime 倒序
|
||||
/// </summary>
|
||||
private async Task SearchAsync()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
try
|
||||
{
|
||||
if (StartTime.HasValue && EndTime.HasValue && StartTime > EndTime)
|
||||
{
|
||||
MessageBox.Show("开始时间不能大于结束时间", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
IsBusy = true;
|
||||
_log.Info("RawProInput 查询开始");
|
||||
|
||||
var data = await Task.Run(() =>
|
||||
{
|
||||
var q = _fsql.Select<RawProInput>();
|
||||
|
||||
// 时间范围:CreateTime
|
||||
DateTime? start = StartTime;
|
||||
DateTime? end = EndTime;
|
||||
if (start.HasValue)
|
||||
q = q.Where(a => a.CreateTime >= start.Value);
|
||||
if (end.HasValue)
|
||||
{
|
||||
var endInclusive = end.Value;
|
||||
if (endInclusive.TimeOfDay == TimeSpan.Zero)
|
||||
endInclusive = endInclusive.Date.AddDays(1).AddTicks(-1);
|
||||
q = q.Where(a => a.CreateTime <= endInclusive);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(RawCode)) q = q.Where(a => a.RawCode.Contains(RawCode));
|
||||
if (!string.IsNullOrWhiteSpace(RawName)) q = q.Where(a => a.RawName.Contains(RawName));
|
||||
if (!string.IsNullOrWhiteSpace(Batch)) q = q.Where(a => a.Batch.Contains(Batch));
|
||||
if (SelectedRawSource.HasValue) q = q.Where(a => a.RawSource == SelectedRawSource.Value);
|
||||
if (SelectedRawState.HasValue) q = q.Where(a => a.RawState == SelectedRawState.Value);
|
||||
|
||||
// 倒序
|
||||
q = q.OrderByDescending(a => a.CreateTime);
|
||||
|
||||
// 分页
|
||||
var page = PageIndex < 1 ? 1 : PageIndex;
|
||||
var size = PageSize <= 0 ? 20 : PageSize;
|
||||
var list = q.Count(out var total)
|
||||
.Page(page, size)
|
||||
.ToList(a => new RawProInputDto
|
||||
{
|
||||
Id = a.Id,
|
||||
RawCode = a.RawCode,
|
||||
RawName = a.RawName,
|
||||
Weight = a.Weight,
|
||||
Batch = a.Batch,
|
||||
ShelfLife = a.ShelfLife,
|
||||
RawSource = a.RawSource.ToString(),
|
||||
RemainWeight = a.RemainWeight,
|
||||
RawState = a.RawState.ToString(),
|
||||
CreateTime = a.CreateTime
|
||||
});
|
||||
|
||||
var pages = total <= 0 || size <= 0 ? 0 : (int)Math.Ceiling(total * 1.0 / size);
|
||||
if (pages > 0 && page > pages)
|
||||
{
|
||||
page = pages;
|
||||
list = q.Page(page, size).ToList(a => new RawProInputDto
|
||||
{
|
||||
Id = a.Id,
|
||||
RawCode = a.RawCode,
|
||||
RawName = a.RawName,
|
||||
Weight = a.Weight,
|
||||
Batch = a.Batch,
|
||||
ShelfLife = a.ShelfLife,
|
||||
RawSource = a.RawSource.ToString(),
|
||||
RemainWeight = a.RemainWeight,
|
||||
RawState = a.RawState.ToString(),
|
||||
CreateTime = a.CreateTime
|
||||
});
|
||||
}
|
||||
|
||||
return (items: list, total: (int)total, normalizedPage: page, totalPages: pages);
|
||||
});
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Items.Clear();
|
||||
foreach (var it in data.items) Items.Add(it);
|
||||
TotalCount = data.total;
|
||||
TotalPages = data.totalPages;
|
||||
PageIndex = data.normalizedPage == 0 ? 1 : data.normalizedPage;
|
||||
});
|
||||
|
||||
_log.Info($"RawProInput 查询完成,记录数: {TotalCount}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"RawProInput 查询失败: {ex}");
|
||||
MessageBox.Show($"查询失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出当前页结果为 Excel(.xlsx)
|
||||
/// </summary>
|
||||
private void ExportToExcel()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
if (Items.Count == 0)
|
||||
{
|
||||
MessageBox.Show("无可导出的数据", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsBusy = true;
|
||||
var sfd = new SaveFileDialog
|
||||
{
|
||||
Title = "导出为 Excel",
|
||||
Filter = "Excel 工作簿 (*.xlsx)|*.xlsx",
|
||||
FileName = $"RawProInput_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
|
||||
};
|
||||
if (sfd.ShowDialog() != true) return;
|
||||
|
||||
using IWorkbook workbook = new XSSFWorkbook();
|
||||
var sheet = workbook.CreateSheet("原料入库");
|
||||
|
||||
// 表头
|
||||
var header = sheet.CreateRow(0);
|
||||
string[] headers = new[]
|
||||
{
|
||||
"Id","原料编号","原料名称","入库重量(kg)","批号","保质期(年)","原料来源","剩余重量(kg)","分拆状态","创建时间"
|
||||
};
|
||||
var headerFont = workbook.CreateFont();
|
||||
headerFont.IsBold = true;
|
||||
headerFont.FontHeightInPoints = 12;
|
||||
var headerStyle = workbook.CreateCellStyle();
|
||||
headerStyle.SetFont(headerFont);
|
||||
headerStyle.Alignment = HAlign.Center;
|
||||
headerStyle.VerticalAlignment = VAlign.Center;
|
||||
header.HeightInPoints = 20f;
|
||||
|
||||
for (int i = 0; i < headers.Length; i++)
|
||||
{
|
||||
var hc = header.CreateCell(i);
|
||||
hc.SetCellValue(headers[i]);
|
||||
hc.CellStyle = headerStyle;
|
||||
}
|
||||
|
||||
// 日期格式
|
||||
var dateStyle = workbook.CreateCellStyle();
|
||||
var dataFormat = workbook.CreateDataFormat();
|
||||
dateStyle.DataFormat = dataFormat.GetFormat("yyyy-mm-dd hh:mm:ss");
|
||||
|
||||
// 数据
|
||||
for (int r = 0; r < Items.Count; r++)
|
||||
{
|
||||
var it = Items[r];
|
||||
var row = sheet.CreateRow(r + 1);
|
||||
int c = 0;
|
||||
row.CreateCell(c++).SetCellValue((double)it.Id);
|
||||
row.CreateCell(c++).SetCellValue(it.RawCode ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.RawName ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.Weight);
|
||||
row.CreateCell(c++).SetCellValue(it.Batch ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.ShelfLife);
|
||||
row.CreateCell(c++).SetCellValue(it.RawSource);
|
||||
row.CreateCell(c++).SetCellValue(it.RemainWeight);
|
||||
row.CreateCell(c++).SetCellValue(it.RawState);
|
||||
|
||||
var cellCreateTime = row.CreateCell(c++);
|
||||
cellCreateTime.SetCellValue(it.CreateTime);
|
||||
cellCreateTime.CellStyle = dateStyle;
|
||||
}
|
||||
|
||||
for (int i = 0; i < headers.Length; i++) sheet.AutoSizeColumn(i);
|
||||
|
||||
using var fs = System.IO.File.OpenWrite(sfd.FileName);
|
||||
workbook.Write(fs);
|
||||
|
||||
_log.Info($"RawProInput 导出完成: {sfd.FileName}");
|
||||
MessageBox.Show("导出成功", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"RawProInput 导出失败: {ex}");
|
||||
MessageBox.Show($"导出失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
public override async void OnNavigatedTo(Prism.Regions.NavigationContext navigationContext)
|
||||
{
|
||||
await SearchAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
479
FATrace.WPLApp/ViewModels/RawProUseViewModel.cs
Normal file
479
FATrace.WPLApp/ViewModels/RawProUseViewModel.cs
Normal file
@@ -0,0 +1,479 @@
|
||||
using FATrace.WPLApp.Core;
|
||||
using Prism.Commands;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using FreeSql;
|
||||
using FATrace.Model;
|
||||
using FATrace.WPLApp.Services;
|
||||
using FATrace.WPLApp.ModelDto;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.XSSF.UserModel;
|
||||
// 为避免与 System.Windows.HorizontalAlignment/VerticalAlignment 冲突,添加别名
|
||||
using HAlign = NPOI.SS.UserModel.HorizontalAlignment;
|
||||
using VAlign = NPOI.SS.UserModel.VerticalAlignment;
|
||||
|
||||
namespace FATrace.WPLApp.ViewModels
|
||||
{
|
||||
/// <summary>
|
||||
/// 原料生产使用信息查询 VM
|
||||
/// - 提供条件查询(时间范围、编码/名称/批次/扫码/操作人)
|
||||
/// - 支持使用 NPOI 导出为 Excel(.xlsx)
|
||||
/// 依赖注入:IFreeSql(数据库)、ILogService(日志)
|
||||
/// </summary>
|
||||
public class RawProUseViewModel : NavigationViewModel
|
||||
{
|
||||
private readonly IFreeSql _fsql;
|
||||
private readonly ILogService _log;
|
||||
|
||||
public RawProUseViewModel(IFreeSql fsql, ILogService log)
|
||||
{
|
||||
_fsql = fsql;
|
||||
_log = log;
|
||||
|
||||
Items = new ObservableCollection<RawProUseDto>();
|
||||
// 集合变化时动态刷新导出命令可用性
|
||||
Items.CollectionChanged += (s, e) =>
|
||||
{
|
||||
try { ExportCommand?.RaiseCanExecuteChanged(); } catch { }
|
||||
};
|
||||
|
||||
// 默认查询时间为今日
|
||||
StartTime = DateTime.Today;
|
||||
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||
|
||||
SearchCommand = new DelegateCommand(async () => await SearchAsync(), () => !IsBusy)
|
||||
.ObservesProperty(() => IsBusy);
|
||||
ExportCommand = new DelegateCommand(ExportToExcel, () => !IsBusy && Items.Count > 0)
|
||||
.ObservesProperty(() => IsBusy)
|
||||
// Items 是集合引用,通常不会替换引用,这里通过 CollectionChanged 手动触发
|
||||
;
|
||||
ClearCommand = new DelegateCommand(ClearFilters, () => !IsBusy)
|
||||
.ObservesProperty(() => IsBusy);
|
||||
|
||||
// 分页命令
|
||||
FirstPageCommand = new DelegateCommand(async () =>
|
||||
{
|
||||
if (PageIndex == 1) return;
|
||||
PageIndex = 1;
|
||||
await SearchAsync();
|
||||
}, () => !IsBusy && PageIndex > 1)
|
||||
.ObservesProperty(() => IsBusy)
|
||||
.ObservesProperty(() => PageIndex);
|
||||
|
||||
PrevPageCommand = new DelegateCommand(async () =>
|
||||
{
|
||||
if (PageIndex <= 1) return;
|
||||
PageIndex -= 1;
|
||||
await SearchAsync();
|
||||
}, () => !IsBusy && PageIndex > 1)
|
||||
.ObservesProperty(() => IsBusy)
|
||||
.ObservesProperty(() => PageIndex);
|
||||
|
||||
NextPageCommand = new DelegateCommand(async () =>
|
||||
{
|
||||
if (PageIndex >= TotalPages) return;
|
||||
PageIndex += 1;
|
||||
await SearchAsync();
|
||||
}, () => !IsBusy && PageIndex < TotalPages)
|
||||
.ObservesProperty(() => IsBusy)
|
||||
.ObservesProperty(() => PageIndex)
|
||||
.ObservesProperty(() => TotalPages);
|
||||
|
||||
LastPageCommand = new DelegateCommand(async () =>
|
||||
{
|
||||
if (TotalPages <= 0) return;
|
||||
if (PageIndex == TotalPages) return;
|
||||
PageIndex = TotalPages;
|
||||
await SearchAsync();
|
||||
}, () => !IsBusy && PageIndex < TotalPages)
|
||||
.ObservesProperty(() => IsBusy)
|
||||
.ObservesProperty(() => PageIndex)
|
||||
.ObservesProperty(() => TotalPages);
|
||||
}
|
||||
|
||||
#region 查询条件属性
|
||||
private string? _rawCode;
|
||||
/// <summary>
|
||||
/// 原料编号模糊匹配
|
||||
/// </summary>
|
||||
public string? RawCode { get => _rawCode; set { _rawCode = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _rawName;
|
||||
/// <summary>
|
||||
/// 原料名称模糊匹配
|
||||
/// </summary>
|
||||
public string? RawName { get => _rawName; set { _rawName = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _inBagCode;
|
||||
/// <summary>
|
||||
/// 内袋二维码模糊匹配
|
||||
/// </summary>
|
||||
public string? InBagCode { get => _inBagCode; set { _inBagCode = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _boxCode;
|
||||
/// <summary>
|
||||
/// 外箱二维码模糊匹配
|
||||
/// </summary>
|
||||
public string? BoxCode { get => _boxCode; set { _boxCode = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _batch;
|
||||
/// <summary>
|
||||
/// 批号模糊匹配
|
||||
/// </summary>
|
||||
public string? Batch { get => _batch; set { _batch = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _opUser;
|
||||
/// <summary>
|
||||
/// 操作者模糊匹配
|
||||
/// </summary>
|
||||
public string? OpUser { get => _opUser; set { _opUser = value; RaisePropertyChanged(); } }
|
||||
|
||||
private string? _checkUser;
|
||||
/// <summary>
|
||||
/// 确认者模糊匹配
|
||||
/// </summary>
|
||||
public string? CheckUser { get => _checkUser; set { _checkUser = value; RaisePropertyChanged(); } }
|
||||
|
||||
private DateTime? _startTime;
|
||||
/// <summary>
|
||||
/// 查询起始时间(包含)
|
||||
/// </summary>
|
||||
public DateTime? StartTime { get => _startTime; set { _startTime = value; RaisePropertyChanged(); } }
|
||||
|
||||
private DateTime? _endTime;
|
||||
/// <summary>
|
||||
/// 查询结束时间(包含)
|
||||
/// </summary>
|
||||
public DateTime? EndTime { get => _endTime; set { _endTime = value; RaisePropertyChanged(); } }
|
||||
#endregion
|
||||
|
||||
#region 列表与状态
|
||||
/// <summary>
|
||||
/// 查询结果数据集合(DTO)
|
||||
/// </summary>
|
||||
public ObservableCollection<RawProUseDto> Items { get; }
|
||||
|
||||
private bool _isBusy;
|
||||
/// <summary>
|
||||
/// 是否忙碌(查询/导出中)
|
||||
/// </summary>
|
||||
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
||||
|
||||
private int _totalCount;
|
||||
/// <summary>
|
||||
/// 结果总数
|
||||
/// </summary>
|
||||
public int TotalCount { get => _totalCount; set { _totalCount = value; RaisePropertyChanged(); } }
|
||||
|
||||
// 分页属性
|
||||
private int _pageIndex = 1;
|
||||
/// <summary>
|
||||
/// 当前页(从1开始)
|
||||
/// </summary>
|
||||
public int PageIndex
|
||||
{
|
||||
get => _pageIndex;
|
||||
set { _pageIndex = value < 1 ? 1 : value; RaisePropertyChanged(); }
|
||||
}
|
||||
|
||||
private int _pageSize = 20;
|
||||
/// <summary>
|
||||
/// 每页数量
|
||||
/// </summary>
|
||||
public int PageSize
|
||||
{
|
||||
get => _pageSize;
|
||||
set
|
||||
{
|
||||
var newSize = value <= 0 ? 20 : value;
|
||||
if (_pageSize != newSize)
|
||||
{
|
||||
_pageSize = newSize;
|
||||
RaisePropertyChanged();
|
||||
// 页大小改变,重置到第1页并刷新
|
||||
PageIndex = 1;
|
||||
if (!IsBusy)
|
||||
_ = SearchAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int _totalPages;
|
||||
/// <summary>
|
||||
/// 总页数
|
||||
/// </summary>
|
||||
public int TotalPages { get => _totalPages; set { _totalPages = value; RaisePropertyChanged(); } }
|
||||
#endregion
|
||||
|
||||
#region 命令
|
||||
public DelegateCommand SearchCommand { get; }
|
||||
public DelegateCommand ExportCommand { get; }
|
||||
public DelegateCommand ClearCommand { get; }
|
||||
public DelegateCommand FirstPageCommand { get; }
|
||||
public DelegateCommand PrevPageCommand { get; }
|
||||
public DelegateCommand NextPageCommand { get; }
|
||||
public DelegateCommand LastPageCommand { get; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 清空查询条件
|
||||
/// </summary>
|
||||
private void ClearFilters()
|
||||
{
|
||||
RawCode = RawName = InBagCode = BoxCode = Batch = OpUser = CheckUser = string.Empty;
|
||||
StartTime = DateTime.Today;
|
||||
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行查询(使用 FreeSql 构建查询语句,最终 ToList 获取数据)
|
||||
/// </summary>
|
||||
private async Task SearchAsync()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
try
|
||||
{
|
||||
if (StartTime.HasValue && EndTime.HasValue && StartTime > EndTime)
|
||||
{
|
||||
MessageBox.Show("开始时间不能大于结束时间", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return;
|
||||
}
|
||||
|
||||
IsBusy = true;
|
||||
_log.Info("RawProUse 查询开始");
|
||||
|
||||
var data = await Task.Run(() =>
|
||||
{
|
||||
var q = _fsql.Select<RawProUse>();
|
||||
|
||||
// 计算安全的时间区间(EndTime 若无时分秒,则自动包含至该日23:59:59.9999999)
|
||||
DateTime? start = StartTime;
|
||||
DateTime? end = EndTime;
|
||||
if (start.HasValue)
|
||||
q = q.Where(a => a.WeightTime >= start.Value);
|
||||
if (end.HasValue)
|
||||
{
|
||||
var endInclusive = end.Value;
|
||||
if (endInclusive.TimeOfDay == TimeSpan.Zero)
|
||||
endInclusive = endInclusive.Date.AddDays(1).AddTicks(-1);
|
||||
q = q.Where(a => a.WeightTime <= endInclusive);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(RawCode))
|
||||
q = q.Where(a => a.RawCode.Contains(RawCode));
|
||||
if (!string.IsNullOrWhiteSpace(RawName))
|
||||
q = q.Where(a => a.RawName.Contains(RawName));
|
||||
if (!string.IsNullOrWhiteSpace(InBagCode))
|
||||
q = q.Where(a => a.InBagCode.Contains(InBagCode));
|
||||
if (!string.IsNullOrWhiteSpace(BoxCode))
|
||||
q = q.Where(a => a.BoxCode.Contains(BoxCode));
|
||||
if (!string.IsNullOrWhiteSpace(Batch))
|
||||
q = q.Where(a => a.Batch.Contains(Batch));
|
||||
if (!string.IsNullOrWhiteSpace(OpUser))
|
||||
q = q.Where(a => a.OpUser.Contains(OpUser));
|
||||
if (!string.IsNullOrWhiteSpace(CheckUser))
|
||||
q = q.Where(a => a.CheckUser.Contains(CheckUser));
|
||||
|
||||
// 按时间倒序
|
||||
q = q.OrderByDescending(a => a.WeightTime);
|
||||
|
||||
// 计算总数并分页(Page 从1开始)
|
||||
var size = PageSize <= 0 ? 20 : PageSize;
|
||||
var page = PageIndex < 1 ? 1 : PageIndex;
|
||||
var list = q.Count(out var total)
|
||||
.Page(page, size)
|
||||
.ToList(a => new RawProUseDto
|
||||
{
|
||||
Id = a.Id,
|
||||
RawCode = a.RawCode,
|
||||
RawName = a.RawName,
|
||||
InBagCode = a.InBagCode,
|
||||
BoxCode = a.BoxCode,
|
||||
Batch = a.Batch,
|
||||
ShelfLife = a.ShelfLife,
|
||||
Weight = a.Weight,
|
||||
RemainWeight = a.RemainWeight,
|
||||
StockWeight = a.StockWeight,
|
||||
WeightTime = a.WeightTime,
|
||||
OpUser = a.OpUser,
|
||||
CheckUser = a.CheckUser,
|
||||
OutTime = a.OutTime,
|
||||
CreateTime = a.CreateTime
|
||||
});
|
||||
|
||||
// 若当前页超出总页数,则自动回退到最后一页
|
||||
var pages = total <= 0 || size <= 0 ? 0 : (int)Math.Ceiling(total * 1.0 / size);
|
||||
if (pages > 0 && page > pages)
|
||||
{
|
||||
page = pages;
|
||||
list = q.Page(page, size).ToList(a => new RawProUseDto
|
||||
{
|
||||
Id = a.Id,
|
||||
RawCode = a.RawCode,
|
||||
RawName = a.RawName,
|
||||
InBagCode = a.InBagCode,
|
||||
BoxCode = a.BoxCode,
|
||||
Batch = a.Batch,
|
||||
ShelfLife = a.ShelfLife,
|
||||
Weight = a.Weight,
|
||||
RemainWeight = a.RemainWeight,
|
||||
StockWeight = a.StockWeight,
|
||||
WeightTime = a.WeightTime,
|
||||
OpUser = a.OpUser,
|
||||
CheckUser = a.CheckUser,
|
||||
OutTime = a.OutTime,
|
||||
CreateTime = a.CreateTime
|
||||
});
|
||||
}
|
||||
|
||||
return (items: list, total: (int)total, normalizedPage: page, totalPages: pages);
|
||||
});
|
||||
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
Items.Clear();
|
||||
foreach (var it in data.items)
|
||||
Items.Add(it);
|
||||
TotalCount = data.total;
|
||||
TotalPages = data.totalPages;
|
||||
PageIndex = data.normalizedPage == 0 ? 1 : data.normalizedPage;
|
||||
});
|
||||
|
||||
_log.Info($"RawProUse 查询完成,记录数: {TotalCount}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"RawProUse 查询失败: {ex}");
|
||||
MessageBox.Show($"查询失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出当前查询结果为 Excel(.xlsx)
|
||||
/// </summary>
|
||||
private void ExportToExcel()
|
||||
{
|
||||
if (IsBusy) return;
|
||||
if (Items.Count == 0)
|
||||
{
|
||||
MessageBox.Show("无可导出的数据", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IsBusy = true;
|
||||
var sfd = new SaveFileDialog
|
||||
{
|
||||
Title = "导出为 Excel",
|
||||
Filter = "Excel 工作簿 (*.xlsx)|*.xlsx",
|
||||
FileName = $"RawProUse_{DateTime.Now:yyyyMMdd_HHmmss}.xlsx"
|
||||
};
|
||||
if (sfd.ShowDialog() != true) return;
|
||||
|
||||
using IWorkbook workbook = new XSSFWorkbook();
|
||||
var sheet = workbook.CreateSheet("原料使用");
|
||||
|
||||
// 表头
|
||||
var header = sheet.CreateRow(0);
|
||||
string[] headers = new[]
|
||||
{
|
||||
"Id","原料编号","原料名称","内袋二维码","外箱二维码","批号","保质期(年)",
|
||||
"称重重量(g)","剩余重量(g)","入库总重量(g)","称重时间","操作者","确认者","出库时间","创建时间"
|
||||
};
|
||||
// 表头样式:加粗与更大字号
|
||||
var headerFont = workbook.CreateFont();
|
||||
headerFont.IsBold = true;
|
||||
headerFont.FontHeightInPoints = 12;
|
||||
var headerStyle = workbook.CreateCellStyle();
|
||||
headerStyle.SetFont(headerFont);
|
||||
headerStyle.Alignment = HAlign.Center;
|
||||
headerStyle.VerticalAlignment = VAlign.Center;
|
||||
header.HeightInPoints = 20f;
|
||||
|
||||
for (int i = 0; i < headers.Length; i++)
|
||||
{
|
||||
var hc = header.CreateCell(i);
|
||||
hc.SetCellValue(headers[i]);
|
||||
hc.CellStyle = headerStyle;
|
||||
}
|
||||
|
||||
// 日期格式
|
||||
var dateStyle = workbook.CreateCellStyle();
|
||||
var dataFormat = workbook.CreateDataFormat();
|
||||
dateStyle.DataFormat = dataFormat.GetFormat("yyyy-mm-dd hh:mm:ss");
|
||||
|
||||
// 数据
|
||||
for (int r = 0; r < Items.Count; r++)
|
||||
{
|
||||
var it = Items[r];
|
||||
var row = sheet.CreateRow(r + 1);
|
||||
int c = 0;
|
||||
row.CreateCell(c++).SetCellValue((double)it.Id);
|
||||
row.CreateCell(c++).SetCellValue(it.RawCode ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.RawName ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.InBagCode ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.BoxCode ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.Batch ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.ShelfLife);
|
||||
row.CreateCell(c++).SetCellValue(it.Weight);
|
||||
row.CreateCell(c++).SetCellValue(it.RemainWeight);
|
||||
row.CreateCell(c++).SetCellValue(it.StockWeight);
|
||||
|
||||
var cellWeightTime = row.CreateCell(c++);
|
||||
cellWeightTime.SetCellValue(it.WeightTime);
|
||||
cellWeightTime.CellStyle = dateStyle;
|
||||
|
||||
row.CreateCell(c++).SetCellValue(it.OpUser ?? string.Empty);
|
||||
row.CreateCell(c++).SetCellValue(it.CheckUser ?? string.Empty);
|
||||
|
||||
var cellOutTime = row.CreateCell(c++);
|
||||
cellOutTime.SetCellValue(it.OutTime);
|
||||
cellOutTime.CellStyle = dateStyle;
|
||||
|
||||
var cellCreateTime = row.CreateCell(c++);
|
||||
cellCreateTime.SetCellValue(it.CreateTime);
|
||||
cellCreateTime.CellStyle = dateStyle;
|
||||
}
|
||||
|
||||
// 自适应列宽(注意:大量数据时可能较慢)
|
||||
for (int i = 0; i < headers.Length; i++)
|
||||
{
|
||||
sheet.AutoSizeColumn(i);
|
||||
}
|
||||
|
||||
using var fs = System.IO.File.OpenWrite(sfd.FileName);
|
||||
workbook.Write(fs);
|
||||
|
||||
_log.Info($"RawProUse 导出完成: {sfd.FileName}");
|
||||
MessageBox.Show("导出成功", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error($"RawProUse 导出失败: {ex}");
|
||||
MessageBox.Show($"导出失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导航进入时,可触发一次默认查询(可按需开启)
|
||||
/// </summary>
|
||||
/// <param name="navigationContext"></param>
|
||||
public override async void OnNavigatedTo(Prism.Regions.NavigationContext navigationContext)
|
||||
{
|
||||
await SearchAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user