完善 MCS 桌面代理与开炼机动作同步,修复原料相关菜单权限,桌面端新增上辅机 MES 菜单。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-27 15:56:05 +08:00
parent 7a9c19e4f3
commit 442a4c8ae2
113 changed files with 10169 additions and 91 deletions

View File

@@ -110,33 +110,69 @@ namespace YY.Admin.ViewModels
_tokenCheckTimer.Interval = TimeSpan.FromMinutes(minutes);
}
/// <summary>登录永不过期缓存,避免定时器在 UI 线程同步读库失败后回落到 30 分钟过期。</summary>
private static bool? _tokenNeverExpireCached;
/// <summary>
/// 是否开启登录永不过期
/// </summary>
private static bool IsTokenNeverExpireEnabled()
{
if (_tokenNeverExpireCached.HasValue)
return _tokenNeverExpireCached.Value;
try
{
var cfg = Prism.Ioc.ContainerLocator.Current.Resolve<ISysConfigService>();
return cfg.GetConfigValue<bool>(ConfigConst.SysTokenNeverExpire).GetAwaiter().GetResult();
// 用 string 读取再解析,避免 Convert.ChangeType(bool) 异常被吞掉后误判为未开启
var raw = cfg.GetConfigValue<string>(ConfigConst.SysTokenNeverExpire).GetAwaiter().GetResult();
var enabled = ParseNeverExpireFlag(raw);
_tokenNeverExpireCached = enabled;
return enabled;
}
catch
{
return false;
// 读配置失败时按「永不过期」处理,避免误踢回登录页
return true;
}
}
private static bool ParseNeverExpireFlag(string? raw)
{
if (string.IsNullOrWhiteSpace(raw))
return true;
if (bool.TryParse(raw, out var b))
return b;
return raw.Trim() is "1" or "Y" or "y" or "yes" or "YES" or "on" or "ON";
}
/// <summary>
/// 登录设置保存后刷新检查间隔(已启动定时器时立即生效)
/// 登录设置保存后刷新检查间隔 / 永不过期策略(已启动定时器时立即生效)
/// </summary>
public static void RefreshTokenCheckIntervalFromConfig()
{
_tokenNeverExpireCached = null;
if (IsTokenNeverExpireEnabled())
{
StopTokenCheckTimer();
return;
}
ApplyTokenCheckIntervalFromConfig();
if (_tokenCheckTimer != null && !_tokenCheckTimer.IsEnabled && UserContext?.Token != null)
_tokenCheckTimer.Start();
}
// 启动定时器的方法
public static void StartTokenCheckTimer()
{
_tokenNeverExpireCached = null;
if (IsTokenNeverExpireEnabled())
{
StopTokenCheckTimer();
return;
}
if (_tokenCheckTimer == null)
{
_tokenCheckTimer = new DispatcherTimer();

View File

@@ -170,6 +170,33 @@ namespace YY.Admin.ViewModels.Control
["/xslmes/mesXslMixingProductionPlan"] = "MixingProductionPlanListView",
["mesXslMixingProductionPlan"] = "MixingProductionPlanListView",
["McsActMillListView"] = "McsActMillListView",
["/xslmes/mcsActMill"] = "McsActMillListView",
["mcsActMill"] = "McsActMillListView",
// 上辅机mes功能占位
["ShiftHandoverListView"] = "ShiftHandoverListView",
["/xslmes/shiftHandover"] = "ShiftHandoverListView",
["shiftHandover"] = "ShiftHandoverListView",
["BomValidationListView"] = "BomValidationListView",
["/xslmes/bomValidation"] = "BomValidationListView",
["bomValidation"] = "BomValidationListView",
["FormulaMaintainListView"] = "FormulaMaintainListView",
["/xslmes/formulaMaintain"] = "FormulaMaintainListView",
["formulaMaintain"] = "FormulaMaintainListView",
["PlanManageListView"] = "PlanManageListView",
["/xslmes/planManage"] = "PlanManageListView",
["planManage"] = "PlanManageListView",
["ReportQueryListView"] = "ReportQueryListView",
["/xslmes/reportQuery"] = "ReportQueryListView",
["reportQuery"] = "ReportQueryListView",
["EquipmentDowntimeListView"] = "EquipmentDowntimeListView",
["/xslmes/equipmentDowntime"] = "EquipmentDowntimeListView",
["equipmentDowntime"] = "EquipmentDowntimeListView",
["ProductionLogListView"] = "ProductionLogListView",
["/xslmes/productionLog"] = "ProductionLogListView",
["productionLog"] = "ProductionLogListView",
// 已实现页面:打印设置
["PrintSettingsView"] = "PrintSettingsView",
["/system/printSettings"] = "PrintSettingsView",

View File

@@ -1,4 +1,5 @@
using YY.Admin.Helper;
using YY.Admin.Services.Service.EquipmentDb;
namespace YY.Admin.ViewModels.Dialogs
{
@@ -45,9 +46,6 @@ namespace YY.Admin.ViewModels.Dialogs
}
private bool _disconnectConnection;
/// <summary>
/// 是否断开连接true=断开false=连接)
/// </summary>
public bool DisconnectConnection
{
get => _disconnectConnection;
@@ -60,11 +58,50 @@ namespace YY.Admin.ViewModels.Dialogs
}
}
/// <summary>
/// 连接参数是否可编辑(勾选断开连接后禁用)。
/// </summary>
public bool IsConnectionFieldsEnabled => !DisconnectConnection;
private string _eqDeviceId = string.Empty;
public string EqDeviceId
{
get => _eqDeviceId;
set => SetProperty(ref _eqDeviceId, value);
}
private string _eqServerHost = "127.0.0.1";
public string EqServerHost
{
get => _eqServerHost;
set => SetProperty(ref _eqServerHost, value);
}
private int _eqServerPort = 1433;
public int EqServerPort
{
get => _eqServerPort;
set => SetProperty(ref _eqServerPort, value);
}
private string _eqDbName = "MES_ShareDB";
public string EqDbName
{
get => _eqDbName;
set => SetProperty(ref _eqDbName, value);
}
private string _eqUsername = "sa";
public string EqUsername
{
get => _eqUsername;
set => SetProperty(ref _eqUsername, value);
}
private string _eqPassword = string.Empty;
public string EqPassword
{
get => _eqPassword;
set => SetProperty(ref _eqPassword, value);
}
public DelegateCommand SaveCommand { get; }
public DelegateCommand CancelCommand { get; }
public DialogCloseListener RequestClose { get; private set; }
@@ -91,6 +128,14 @@ namespace YY.Admin.ViewModels.Dialogs
BasePath = string.IsNullOrWhiteSpace(settings.BasePath) ? "/jeecg-boot" : settings.BasePath;
DisconnectConnection = settings.DisconnectConnection;
ErrorMessage = string.Empty;
var eq = EquipmentDbSettingsStore.Load();
EqDeviceId = string.IsNullOrWhiteSpace(eq.DeviceId) ? Environment.MachineName : eq.DeviceId;
EqServerHost = eq.ServerHost;
EqServerPort = eq.ServerPort;
EqDbName = eq.DbName;
EqUsername = eq.Username;
EqPassword = eq.Password;
}
private void Save()
@@ -106,6 +151,11 @@ namespace YY.Admin.ViewModels.Dialogs
ErrorMessage = "端口号必须在 1-65535 之间";
return;
}
if (EqServerPort <= 0 || EqServerPort > 65535)
{
ErrorMessage = "设备库端口号必须在 1-65535 之间";
return;
}
try
{
@@ -127,6 +177,19 @@ namespace YY.Admin.ViewModels.Dialogs
WebSocketPath = DefaultWebSocketPath,
DisconnectConnection = DisconnectConnection
});
EquipmentDbSettingsStore.Save(new EquipmentDbSettingsStore.EquipmentDbSettings
{
Enabled = true,
DeviceId = string.IsNullOrWhiteSpace(EqDeviceId) ? Environment.MachineName : EqDeviceId.Trim(),
ServerHost = EqServerHost?.Trim() ?? "127.0.0.1",
ServerPort = EqServerPort,
DbName = EqDbName?.Trim() ?? "MES_ShareDB",
Username = EqUsername?.Trim() ?? "sa",
Password = EqPassword ?? string.Empty,
ConnectTimeoutSeconds = 15
});
RequestClose.Invoke(new DialogResult(ButtonResult.OK));
}
catch (Exception ex)

View File

@@ -0,0 +1,100 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using HandyControl.Controls;
using YY.Admin.Core;
using YY.Admin.Core.Helper;
using YY.Admin.Services.Service.EquipmentDb;
namespace YY.Admin.ViewModels.McsActMill;
public class McsActMillListViewModel : BaseViewModel
{
private readonly IMcsActMillService _service;
private ObservableCollection<McsActMillRow> _items = new();
public ObservableCollection<McsActMillRow> Items
{
get => _items;
set => SetProperty(ref _items, 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? _filterActName;
public string? FilterActName { get => _filterActName; set => SetProperty(ref _filterActName, value); }
private string? _filterActAddrText;
public string? FilterActAddrText { get => _filterActAddrText; set => SetProperty(ref _filterActAddrText, value); }
public DelegateCommand SearchCommand { get; }
public DelegateCommand ResetCommand { get; }
public DelegateCommand PrevPageCommand { get; }
public DelegateCommand NextPageCommand { get; }
public McsActMillListViewModel(
IMcsActMillService service,
IContainerExtension container,
IRegionManager regionManager) : base(container, regionManager)
{
_service = service;
SearchCommand = new DelegateCommand(async () => { PageNo = 1; await LoadAsync(); });
ResetCommand = new DelegateCommand(async () =>
{
FilterActName = null;
FilterActAddrText = null;
PageNo = 1;
await LoadAsync();
});
PrevPageCommand = new DelegateCommand(async () => { if (PageNo > 1) { PageNo--; await LoadAsync(); } });
NextPageCommand = new DelegateCommand(async () => { if ((long)PageNo * PageSize < Total) { PageNo++; await LoadAsync(); } });
_ = InitializeAsync();
}
private async Task InitializeAsync()
{
try
{
await UIHelper.WaitForRenderAsync();
await LoadAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"开炼机动作中间表初始化失败: {ex.Message}");
}
}
public async Task LoadAsync()
{
try
{
IsLoading = true;
int? actAddr = null;
if (!string.IsNullOrWhiteSpace(FilterActAddrText)
&& int.TryParse(FilterActAddrText.Trim(), out var parsed))
{
actAddr = parsed;
}
var result = await _service.PageAsync(PageNo, PageSize, FilterActName, actAddr);
Items = new ObservableCollection<McsActMillRow>(result.Records);
Total = result.Total;
}
catch (Exception ex)
{
Growl.Error($"加载开炼机动作中间表失败:{ex.Message}");
}
finally
{
IsLoading = false;
}
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class BomValidationListViewModel : BaseViewModel
{
public BomValidationListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "bom验证";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class EquipmentDowntimeListViewModel : BaseViewModel
{
public EquipmentDowntimeListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "设备停机记录";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class FormulaMaintainListViewModel : BaseViewModel
{
public FormulaMaintainListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "配方维护";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class PlanManageListViewModel : BaseViewModel
{
public PlanManageListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "计划管理";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class ProductionLogListViewModel : BaseViewModel
{
public ProductionLogListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "生产日志";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class ReportQueryListViewModel : BaseViewModel
{
public ReportQueryListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "报表查询";
}
}

View File

@@ -0,0 +1,13 @@
using Prism.Ioc;
using Prism.Navigation.Regions;
namespace YY.Admin.ViewModels.UpperMes;
public class ShiftHandoverListViewModel : BaseViewModel
{
public ShiftHandoverListViewModel(IContainerExtension container, IRegionManager regionManager)
: base(container, regionManager)
{
Title = "交接班";
}
}