Files
qhmes/yy-admin-master/YY.Admin/ViewModels/RawMaterialEntry/RawMaterialEntryOperationViewModel.cs

289 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Prism.Commands;
using System.Collections.ObjectModel;
using System.IO;
using System.Text.Json;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Services;
using YY.Admin.Services.Service;
namespace YY.Admin.ViewModels.RawMaterialEntry;
/// <summary>
/// 「新增原料入场记录」独立页面:左侧表单逻辑继承编辑 VM右侧展示当日入场简要列表并支持选中回填模板。
/// </summary>
public class RawMaterialEntryOperationViewModel : RawMaterialEntryEditDialogViewModel
{
private const int TodayListFetchSize = 5000;
private readonly IRawMaterialCardService _rawMaterialCardService;
private static readonly JsonSerializerOptions LayoutJsonOpts = new()
{
PropertyNameCaseInsensitive = true,
WriteIndented = true
};
private static string LayoutFilePath => Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
"YY.Admin",
"raw-material-entry-add-layout.json");
private bool _suppressTodaySelectionReaction;
public ObservableCollection<MesXslRawMaterialEntry> TodayEntries { get; } = new();
private MesXslRawMaterialEntry? _selectedTodayEntry;
public MesXslRawMaterialEntry? SelectedTodayEntry
{
get => _selectedTodayEntry;
set
{
if (!SetProperty(ref _selectedTodayEntry, value)) return;
if (_suppressTodaySelectionReaction || value == null) return;
_ = ApplyTodayRowToFormAsync(value);
}
}
private bool _isRightPanelExpanded = true;
public bool IsRightPanelExpanded
{
get => _isRightPanelExpanded;
set
{
if (!SetProperty(ref _isRightPanelExpanded, value)) return;
SaveLayoutState();
}
}
private double _expandedRightPanelWidth = 280;
/// <summary>右侧面板展开时的目标宽度(像素),由 GridSplitter 拖拽结束时回写。</summary>
public double ExpandedRightPanelWidth
{
get => _expandedRightPanelWidth;
private set
{
var v = Math.Clamp(value, 200, 560);
if (SetProperty(ref _expandedRightPanelWidth, v))
SaveLayoutState();
}
}
/// <summary>仅当入场记录已保存(有 Id且存在拆码明细时允许生成原材料卡片。</summary>
public bool CanGenerateCards => !string.IsNullOrWhiteSpace(Entry?.Id) && SplitCodeDetails.Count > 0;
public DelegateCommand ToggleRightPanelCommand { get; }
public DelegateCommand RefreshTodayEntriesCommand { get; }
public DelegateCommand GenerateRawMaterialCardsCommand { get; }
public RawMaterialEntryOperationViewModel(
IRawMaterialEntryService entryService,
IJeecgDictSyncService dictSyncService,
IMixerMaterialService mixerMaterialService,
IRawMaterialCardService rawMaterialCardService,
IContainerExtension container,
IRegionManager regionManager)
: base(entryService, dictSyncService, mixerMaterialService, container, regionManager)
{
_rawMaterialCardService = rawMaterialCardService;
LoadLayoutState();
ToggleRightPanelCommand = new DelegateCommand(() => IsRightPanelExpanded = !IsRightPanelExpanded);
RefreshTodayEntriesCommand = new DelegateCommand(async () => await LoadTodayEntriesAsync());
GenerateRawMaterialCardsCommand = new DelegateCommand(async () => await GenerateRawMaterialCardsAsync());
SplitCodeDetails.CollectionChanged += (_, _) => RaisePropertyChanged(nameof(CanGenerateCards));
}
public override void InitializeForAdd()
{
_suppressTodaySelectionReaction = true;
_selectedTodayEntry = null;
RaisePropertyChanged(nameof(SelectedTodayEntry));
_suppressTodaySelectionReaction = false;
base.InitializeForAdd();
RaisePropertyChanged(nameof(CanGenerateCards));
}
/// <summary>页面首次加载时拉取「今日」列表(由 View Loaded 调用)。</summary>
public async Task LoadTodayEntriesOnFirstShowAsync() => await LoadTodayEntriesAsync();
/// <summary>用户在拖拽结束 GridSplitter 后提交实际列宽。</summary>
public void CommitRightPanelWidthFromView(double actualWidth)
{
if (!IsRightPanelExpanded || actualWidth < 1) return;
ExpandedRightPanelWidth = actualWidth;
}
private async Task LoadTodayEntriesAsync()
{
try
{
IsLoading = true;
var result = await EntryService.PageAsync(1, TodayListFetchSize);
var today = DateTime.Today;
var rows = result.Records
.Where(e => IsTodayEntry(e, today))
.OrderByDescending(e => e.EntryTime ?? e.CreateTime ?? DateTime.MinValue)
.ToList();
TodayEntries.Clear();
foreach (var r in rows)
TodayEntries.Add(r);
}
catch
{
// 列表失败不阻断左侧新增(与物料加载策略一致)
}
finally
{
IsLoading = false;
}
}
private static bool IsTodayEntry(MesXslRawMaterialEntry e, DateTime today)
{
var byEntry = e.EntryTime?.Date == today;
var byCreate = e.CreateTime?.Date == today;
return byEntry || byCreate;
}
/// <summary>
/// 点击右侧今日记录:直接以「编辑模式」加载源记录到左侧表单(保留 Id/条码/批次号),
/// 不再走「新增模板」逻辑,避免重新生成条码、覆盖原数据。
/// </summary>
private async Task ApplyTodayRowToFormAsync(MesXslRawMaterialEntry src)
{
// 复用基类 InitializeForEdit保留 Id/Barcode/BatchNo/状态等所有字段,标题自动切到「编辑原料入场记录」
base.InitializeForEdit(src);
RaisePropertyChanged(nameof(CanGenerateCards));
// 若物料列表此前未加载导致选中项未回填,则补一次拉取(与编辑弹窗逻辑一致)
if (_pendingMaterialId != null)
await LoadMaterialOptionsAsync();
}
/// <summary>编辑保存成功后:刷新右侧今日列表并切回新增态,避免连续误改同一条。</summary>
protected override async Task SaveAsync()
{
var wasEdit = !IsAddMode;
await base.SaveAsync();
RaisePropertyChanged(nameof(CanGenerateCards));
if (wasEdit && Result && CloseAction == null)
{
HandyControl.Controls.MessageBox.Success("编辑成功!");
await LoadTodayEntriesAsync();
InitializeForAdd();
}
}
private async Task GenerateRawMaterialCardsAsync()
{
if (Entry == null || string.IsNullOrWhiteSpace(Entry.Id))
{
HandyControl.Controls.MessageBox.Warning("请先保存入场记录再生成原材料卡片!");
return;
}
if (SplitCodeDetails.Count == 0)
{
HandyControl.Controls.MessageBox.Warning("当前入场记录无拆分明细,无法生成原材料卡片!");
return;
}
try
{
IsLoading = true;
var globalIndex = 1;
var baseBarcode = Entry.Barcode ?? "";
var failCount = 0;
foreach (var detail in SplitCodeDetails)
{
var portions = detail.Portions ?? 0;
for (var i = 0; i < portions; i++)
{
var card = new MesXslRawMaterialCard
{
Barcode = baseBarcode + globalIndex.ToString("D3"),
BatchNo = Entry.BatchNo,
EntryDate = Entry.EntryTime?.Date ?? DateTime.Today,
MaterialId = Entry.MaterialId,
MaterialName = Entry.MaterialName,
SupplierId = Entry.SupplierId,
SupplierName = Entry.SupplierName,
ManufacturerMaterialName = Entry.ManufacturerMaterialName,
ShelfLife = Entry.ShelfLife,
TotalWeight = detail.PortionWeight.HasValue ? (decimal?)detail.PortionWeight.Value : null,
RemainingWeight = detail.PortionWeight.HasValue ? (decimal?)detail.PortionWeight.Value : null,
RemainingQuantity = detail.PortionPackages,
WarehouseArea = detail.WarehouseLocation,
UnloadOperator = Entry.UnloadOperator,
Status = "1",
TestResult = "0",
PriorityPickup = "0",
TenantId = Entry.TenantId
};
var ok = await _rawMaterialCardService.AddAsync(card);
if (!ok) failCount++;
globalIndex++;
}
}
// 更新打印状态为「已打印」
Entry.PrintFlag = "1";
await EntryService.EditAsync(Entry);
RaisePropertyChanged(nameof(Entry));
var total = globalIndex - 1;
if (failCount == 0)
HandyControl.Controls.MessageBox.Success($"已生成 {total} 张原材料卡片,打印状态已更新为「已打印」!");
else
HandyControl.Controls.MessageBox.Warning($"共生成 {total} 张,其中 {failCount} 张失败,请检查网络后重试!");
}
catch (Exception ex)
{
HandyControl.Controls.MessageBox.Error($"生成原材料卡片失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private void LoadLayoutState()
{
try
{
if (!File.Exists(LayoutFilePath)) return;
var json = File.ReadAllText(LayoutFilePath);
var dto = JsonSerializer.Deserialize<AddPageLayoutDto>(json, LayoutJsonOpts);
if (dto == null) return;
if (dto.ExpandedWidth is > 0 and < 2000)
_expandedRightPanelWidth = Math.Clamp(dto.ExpandedWidth.Value, 200, 560);
if (dto.IsExpanded.HasValue)
_isRightPanelExpanded = dto.IsExpanded.Value;
RaisePropertyChanged(nameof(ExpandedRightPanelWidth));
RaisePropertyChanged(nameof(IsRightPanelExpanded));
}
catch { /* 布局文件损坏时忽略 */ }
}
private void SaveLayoutState()
{
try
{
var dir = Path.GetDirectoryName(LayoutFilePath);
if (!string.IsNullOrEmpty(dir))
Directory.CreateDirectory(dir);
var dto = new AddPageLayoutDto
{
ExpandedWidth = _expandedRightPanelWidth,
IsExpanded = _isRightPanelExpanded
};
File.WriteAllText(LayoutFilePath, JsonSerializer.Serialize(dto, LayoutJsonOpts));
}
catch { /* 写本地失败时不影响业务 */ }
}
private sealed class AddPageLayoutDto
{
public double? ExpandedWidth { get; set; }
public bool? IsExpanded { get; set; }
}
}