更新MybatisPlusSaasConfig中的租户ID默认值为1002;在ShiroConfig中添加MES密炼物料管理和系统分类字典的免密接口;在MesMixerMaterialController中实现密炼物料信息的免密增删改查接口,并添加相应的事件广播功能;在SysCategoryController中新增分类字典的免密查询接口;更新前端导航和菜单数据以支持密炼物料信息模块。

This commit is contained in:
geht
2026-05-07 09:47:39 +08:00
parent 25629f2df1
commit ce9dc8efd8
31 changed files with 1967 additions and 2 deletions

View File

@@ -54,6 +54,13 @@ namespace YY.Admin.ViewModels.Control
["/platform/dict"] = "DataDictionaryManagementView",
["sysDict"] = "DataDictionaryManagementView",
// 已实现页面:分类字典
["CategoryDictionaryManagementView"] = "CategoryDictionaryManagementView",
["/system/category"] = "CategoryDictionaryManagementView",
["/system/category/index"] = "CategoryDictionaryManagementView",
["/platform/category"] = "CategoryDictionaryManagementView",
["sysCategory"] = "CategoryDictionaryManagementView",
// 已实现页面:角色管理
["RoleManagementView"] = "RoleManagementView",
["/system/role"] = "RoleManagementView",
@@ -108,7 +115,12 @@ namespace YY.Admin.ViewModels.Control
// 已实现页面:地磅称重操作
["WeightRecordOperationView"] = "WeightRecordOperationView",
["/xslmes/weightRecordOperation"] = "WeightRecordOperationView",
["weightRecordOperation"] = "WeightRecordOperationView"
["weightRecordOperation"] = "WeightRecordOperationView",
// 已实现页面:密炼物料信息
["MixerMaterialListView"] = "MixerMaterialListView",
["/xslmes/mesMixerMaterial"] = "MixerMaterialListView",
["mesMixerMaterial"] = "MixerMaterialListView"
};
private MenuItem? _selectedMenuItem;

View File

@@ -0,0 +1,186 @@
using HandyControl.Controls;
using HandyControl.Tools.Extension;
using System.Collections.ObjectModel;
using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Services;
namespace YY.Admin.ViewModels.MixerMaterial;
public class MixerMaterialEditDialogViewModel : BaseViewModel, IDialogResultable<bool>
{
private readonly IMixerMaterialService _mixerMaterialService;
private MesMixerMaterial? _material;
public MesMixerMaterial? Material
{
get => _material;
set => SetProperty(ref _material, value);
}
public bool IsAddMode => string.IsNullOrWhiteSpace(Material?.Id);
public string DialogTitle => IsAddMode ? "新增密炼物料" : "编辑密炼物料";
public ObservableCollection<KeyValuePair<string, string>> MajorCategoryOptions { get; } = new();
public ObservableCollection<KeyValuePair<string, string>> MinorCategoryOptions { get; } = new();
public ObservableCollection<KeyValuePair<string, int>> FeedManageStatusOptions { get; } =
[
new("在投管", 1),
new("未投管", 0)
];
public ObservableCollection<KeyValuePair<string, int>> UseStatusOptions { get; } =
[
new("使用中", 1),
new("停用", 0)
];
private bool _result;
public bool Result { get => _result; set => SetProperty(ref _result, value); }
public Action? CloseAction { get; set; }
public DelegateCommand SaveCommand { get; }
public DelegateCommand CancelCommand { get; }
public DelegateCommand MajorCategoryChangedCommand { get; }
public MixerMaterialEditDialogViewModel(
IMixerMaterialService mixerMaterialService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_mixerMaterialService = mixerMaterialService;
SaveCommand = new DelegateCommand(async () => await SaveAsync());
CancelCommand = new DelegateCommand(() => CloseAction?.Invoke());
MajorCategoryChangedCommand = new DelegateCommand(async () => await OnMajorCategoryChangedAsync());
_ = LoadMajorCategoryOptionsAsync();
}
public void InitializeForAdd()
{
Material = new MesMixerMaterial
{
FeedManageStatus = 1,
UseStatus = 1
};
MinorCategoryOptions.Clear();
RaisePropertyChanged(nameof(IsAddMode));
RaisePropertyChanged(nameof(DialogTitle));
}
public void InitializeForEdit(MesMixerMaterial material)
{
Material = new MesMixerMaterial
{
Id = material.Id,
MaterialCode = material.MaterialCode,
MaterialName = material.MaterialName,
ErpCode = material.ErpCode,
MajorCategoryId = material.MajorCategoryId,
MinorCategoryId = material.MinorCategoryId,
MaterialDesc = material.MaterialDesc,
AliasName = material.AliasName,
FeedManageStatus = material.FeedManageStatus,
UseStatus = material.UseStatus,
SpecificGravity = material.SpecificGravity,
ShelfLifeDays = material.ShelfLifeDays,
MinBakeMinutes = material.MinBakeMinutes,
TotalSafetyStockKg = material.TotalSafetyStockKg,
QualifiedSafetyStockKg = material.QualifiedSafetyStockKg,
Remark = material.Remark,
TenantId = material.TenantId,
};
_ = LoadMinorCategoryOptionsAsync(Material.MajorCategoryId);
RaisePropertyChanged(nameof(IsAddMode));
RaisePropertyChanged(nameof(DialogTitle));
}
private async Task LoadMajorCategoryOptionsAsync()
{
try
{
MajorCategoryOptions.Clear();
var options = await _mixerMaterialService.GetMajorCategoryOptionsAsync();
foreach (var item in options)
{
MajorCategoryOptions.Add(item);
}
}
catch
{
// ignore
}
}
private async Task LoadMinorCategoryOptionsAsync(string? majorCategoryId)
{
MinorCategoryOptions.Clear();
if (string.IsNullOrWhiteSpace(majorCategoryId))
{
return;
}
try
{
var options = await _mixerMaterialService.GetMinorCategoryOptionsAsync(majorCategoryId);
foreach (var item in options)
{
MinorCategoryOptions.Add(item);
}
}
catch
{
// ignore
}
}
private async Task OnMajorCategoryChangedAsync()
{
if (Material == null) return;
Material.MinorCategoryId = null;
RaisePropertyChanged(nameof(Material));
await LoadMinorCategoryOptionsAsync(Material.MajorCategoryId);
}
private async Task SaveAsync()
{
if (Material == null) return;
if (string.IsNullOrWhiteSpace(Material.MaterialCode))
{
HandyControl.Controls.MessageBox.Warning("物料编码不能为空!");
return;
}
if (string.IsNullOrWhiteSpace(Material.MaterialName))
{
HandyControl.Controls.MessageBox.Warning("物料名称不能为空!");
return;
}
if (string.IsNullOrWhiteSpace(Material.MajorCategoryId))
{
HandyControl.Controls.MessageBox.Warning("物料大类不能为空!");
return;
}
if (string.IsNullOrWhiteSpace(Material.MinorCategoryId))
{
HandyControl.Controls.MessageBox.Warning("物料小类不能为空!");
return;
}
try
{
bool ok = IsAddMode
? await _mixerMaterialService.AddAsync(Material)
: await _mixerMaterialService.EditAsync(Material);
if (!ok)
{
HandyControl.Controls.MessageBox.Error($"{(IsAddMode ? "" : "")}密炼物料失败!");
return;
}
Result = true;
CloseAction?.Invoke();
}
catch (Exception ex)
{
HandyControl.Controls.MessageBox.Error($"操作失败:{ex.Message}");
}
}
}

View File

@@ -0,0 +1,232 @@
using HandyControl.Controls;
using HandyControl.Tools.Extension;
using Prism.Events;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Windows;
using YY.Admin.Core;
using YY.Admin.Core.Entity;
using YY.Admin.Core.Events;
using YY.Admin.Core.Helper;
using YY.Admin.Core.Services;
using YY.Admin.Views.MixerMaterial;
namespace YY.Admin.ViewModels.MixerMaterial;
public class MixerMaterialListViewModel : BaseViewModel
{
private readonly IMixerMaterialService _mixerMaterialService;
private SubscriptionToken? _materialChangedToken;
private ObservableCollection<MesMixerMaterial> _materials = new();
public ObservableCollection<MesMixerMaterial> Materials
{
get => _materials;
set => SetProperty(ref _materials, value);
}
private long _total;
public long Total { get => _total; set => SetProperty(ref _total, value); }
private int _pageNo = 1;
public int PageNo { get => _pageNo; set => SetProperty(ref _pageNo, value); }
private int _pageSize = 20;
public int PageSize { get => _pageSize; set => SetProperty(ref _pageSize, value); }
private string? _filterMaterialCode;
public string? FilterMaterialCode { get => _filterMaterialCode; set => SetProperty(ref _filterMaterialCode, value); }
private string? _filterMaterialName;
public string? FilterMaterialName { get => _filterMaterialName; set => SetProperty(ref _filterMaterialName, value); }
private string? _filterErpCode;
public string? FilterErpCode { get => _filterErpCode; set => SetProperty(ref _filterErpCode, value); }
private string? _filterMajorCategoryId;
public string? FilterMajorCategoryId
{
get => _filterMajorCategoryId;
set
{
if (SetProperty(ref _filterMajorCategoryId, value))
{
_ = OnMajorCategoryChangedAsync();
}
}
}
private string? _filterMinorCategoryId;
public string? FilterMinorCategoryId { get => _filterMinorCategoryId; set => SetProperty(ref _filterMinorCategoryId, value); }
public ObservableCollection<KeyValuePair<string, string>> MajorCategoryOptions { get; } = new();
public ObservableCollection<KeyValuePair<string, string>> MinorCategoryOptions { get; } = new();
public DelegateCommand SearchCommand { get; }
public DelegateCommand ResetCommand { get; }
public DelegateCommand AddCommand { get; }
public DelegateCommand<MesMixerMaterial> EditCommand { get; }
public DelegateCommand<MesMixerMaterial> DeleteCommand { get; }
public DelegateCommand PrevPageCommand { get; }
public DelegateCommand NextPageCommand { get; }
public MixerMaterialListViewModel(
IMixerMaterialService mixerMaterialService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_mixerMaterialService = mixerMaterialService;
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
ResetCommand = new DelegateCommand(async () =>
{
FilterMaterialCode = null;
FilterMaterialName = null;
FilterErpCode = null;
FilterMajorCategoryId = null;
FilterMinorCategoryId = null;
PageNo = 1;
await LoadMinorCategoryOptionsAsync();
await LoadAsync();
});
AddCommand = new DelegateCommand(async () => await ShowAddDialogAsync());
EditCommand = new DelegateCommand<MesMixerMaterial>(async m => await ShowEditDialogAsync(m));
DeleteCommand = new DelegateCommand<MesMixerMaterial>(async m => await DeleteAsync(m));
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
_materialChangedToken = _eventAggregator
.GetEvent<MixerMaterialChangedEvent>()
.Subscribe(async _ => await LoadAsync(), ThreadOption.UIThread);
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
await LoadMajorCategoryOptionsAsync();
await LoadMinorCategoryOptionsAsync();
await UIHelper.WaitForRenderAsync();
await LoadAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"密炼物料列表初始化失败: {ex.Message}");
}
}
private async Task LoadMajorCategoryOptionsAsync()
{
MajorCategoryOptions.Clear();
var options = await _mixerMaterialService.GetMajorCategoryOptionsAsync();
MajorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
foreach (var item in options)
{
MajorCategoryOptions.Add(item);
}
}
private async Task LoadMinorCategoryOptionsAsync()
{
MinorCategoryOptions.Clear();
MinorCategoryOptions.Add(new KeyValuePair<string, string>("全部", ""));
if (string.IsNullOrWhiteSpace(FilterMajorCategoryId))
{
return;
}
var options = await _mixerMaterialService.GetMinorCategoryOptionsAsync(FilterMajorCategoryId!);
foreach (var item in options)
{
MinorCategoryOptions.Add(item);
}
}
private async Task OnMajorCategoryChangedAsync()
{
FilterMinorCategoryId = null;
await LoadMinorCategoryOptionsAsync();
}
public async Task LoadAsync()
{
try
{
IsLoading = true;
var result = await _mixerMaterialService.PageAsync(
PageNo, PageSize, FilterMaterialCode, FilterMaterialName, FilterErpCode, FilterMajorCategoryId, FilterMinorCategoryId);
Materials = new ObservableCollection<MesMixerMaterial>(result.Records);
Total = result.Total;
}
catch (Exception ex)
{
Growl.Error($"加载密炼物料列表失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
private async Task ShowAddDialogAsync()
{
try
{
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForAdd())
.GetResultAsync<bool>();
if (result) await LoadAsync();
}
catch (Exception ex)
{
Growl.Error($"打开新增对话框失败:{ex.Message}");
}
}
private async Task ShowEditDialogAsync(MesMixerMaterial material)
{
if (material == null) return;
try
{
var result = await HandyControl.Controls.Dialog.Show<MixerMaterialEditDialogView>()
.Initialize<MixerMaterialEditDialogViewModel>(vm => vm.InitializeForEdit(material))
.GetResultAsync<bool>();
if (result) await LoadAsync();
}
catch (Exception ex)
{
Growl.Error($"打开编辑对话框失败:{ex.Message}");
}
}
private async Task DeleteAsync(MesMixerMaterial material)
{
if (material?.Id == null) return;
var confirm = System.Windows.MessageBox.Show($"确定删除物料 {material.MaterialName}?此操作不可恢复!", "确认删除",
MessageBoxButton.OKCancel, MessageBoxImage.Question);
if (confirm != System.Windows.MessageBoxResult.OK) return;
var ok = await _mixerMaterialService.DeleteAsync(material.Id);
if (ok)
{
Growl.Success("删除成功!");
await LoadAsync();
}
else
{
Growl.Error("删除失败!");
}
}
protected override void CleanUp()
{
base.CleanUp();
if (_materialChangedToken != null)
{
_eventAggregator.GetEvent<MixerMaterialChangedEvent>().Unsubscribe(_materialChangedToken);
_materialChangedToken = null;
}
}
}

View File

@@ -0,0 +1,143 @@
using HandyControl.Controls;
using System.Collections.ObjectModel;
using YY.Admin.Core;
using YY.Admin.Core.Helper;
using YY.Admin.Services.Service.Category;
using YY.Admin.Services.Service.Category.Dto;
using YY.Admin.ViewModels.Control;
namespace YY.Admin.ViewModels.SysManage;
public class CategoryDictionaryManagementViewModel : BaseViewModel
{
private readonly IJeecgCategorySyncService _categorySyncService;
private PaginationDataGridViewModel<JeecgCategoryItemOutput> _paginationDataGridViewModel;
public PaginationDataGridViewModel<JeecgCategoryItemOutput> PaginationDataGridViewModel
{
get => _paginationDataGridViewModel;
set => SetProperty(ref _paginationDataGridViewModel, value);
}
private PageJeecgCategoryItemInput _input;
public PageJeecgCategoryItemInput Input
{
get => _input;
set => SetProperty(ref _input, value);
}
public DelegateCommand SearchCommand { get; }
public DelegateCommand ResetCommand { get; }
public DelegateCommand SyncCommand { get; }
public ObservableCollection<CategoryTreeNode> TreeNodes { get; } = [];
private CategoryTreeNode? _selectedTreeNode;
public CategoryTreeNode? SelectedTreeNode
{
get => _selectedTreeNode;
set => SetProperty(ref _selectedTreeNode, value);
}
public CategoryDictionaryManagementViewModel(
IJeecgCategorySyncService categorySyncService,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_categorySyncService = categorySyncService;
_paginationDataGridViewModel = new PaginationDataGridViewModel<JeecgCategoryItemOutput>(FetchAsync);
_input = new PageJeecgCategoryItemInput();
SearchCommand = new DelegateCommand(async () => await SearchAsync());
ResetCommand = new DelegateCommand(async () => await ResetAsync());
SyncCommand = new DelegateCommand(async () => await SyncAsync());
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
await LoadTreeAsync();
await UIHelper.WaitForRenderAsync();
await PaginationDataGridViewModel.LoadDataAsync();
}
private async Task<(IEnumerable<JeecgCategoryItemOutput> data, int totalCount)> FetchAsync()
{
Input.Page = PaginationDataGridViewModel.PageIndex;
Input.PageSize = PaginationDataGridViewModel.DataCountPerPage;
var result = await _categorySyncService.PageAsync(Input);
return (result.Items, result.Total);
}
private async Task SearchAsync()
{
PaginationDataGridViewModel.PageIndex = 1;
await PaginationDataGridViewModel.LoadDataAsync();
}
private async Task ResetAsync()
{
Input = new PageJeecgCategoryItemInput();
SelectedTreeNode = null;
await UIHelper.WaitForRenderAsync();
await LoadTreeAsync();
await SearchAsync();
}
private async Task SyncAsync()
{
var count = await _categorySyncService.SyncFromJeecgAsync();
if (count > 0)
{
Growl.Success($"同步完成,共处理 {count} 条分类字典数据");
}
else
{
Growl.Warning("未同步到分类字典,请确认后端可访问");
}
await LoadTreeAsync();
await SearchAsync();
}
public async Task OnTreeSelectedAsync(CategoryTreeNode? node)
{
SelectedTreeNode = node;
Input.Pid = node?.Id;
await SearchAsync();
}
private async Task LoadTreeAsync()
{
TreeNodes.Clear();
var tree = await _categorySyncService.LoadTreeAsync();
foreach (var item in tree)
{
TreeNodes.Add(MapTreeNode(item));
}
}
private static CategoryTreeNode MapTreeNode(JeecgCategoryTreeNodeDto dto)
{
var node = new CategoryTreeNode
{
Id = dto.Id,
Name = dto.Name ?? dto.Code ?? dto.Id,
Code = dto.Code
};
foreach (var child in dto.Children)
{
node.Children.Add(MapTreeNode(child));
}
return node;
}
public class CategoryTreeNode
{
public string Id { get; set; } = string.Empty;
public string? Name { get; set; }
public string? Code { get; set; }
public ObservableCollection<CategoryTreeNode> Children { get; set; } = [];
public string DisplayName => string.IsNullOrWhiteSpace(Code) ? (Name ?? Id) : $"{Name} ({Code})";
}
}