完善 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

@@ -9,10 +9,11 @@ using YY.Admin.Core.Services;
using YY.Admin.Core.Session;
using YY.Admin.Helper;
using YY.Admin.Infrastructure.Storage;
using YY.Admin.Services.Service.EquipmentDb;
namespace YY.Admin.Infrastructure.Hubs;
public class StompWebSocketService : ISignalRService
public class StompWebSocketService : ISignalRService, IEquipmentDbStompSender
{
// STOMP heart-beat: send \n every 10 s, declare we want to receive every 10 s
private const int HeartbeatMs = 10_000;
@@ -188,6 +189,11 @@ public class StompWebSocketService : ISignalRService
BuildSubscribeFrame("sub-device-pong", $"/topic/device/{_deviceId}/pong"),
cancellationToken).ConfigureAwait(false);
// 设备库命令通道(匿名/登录均订阅)
await SendFrameAsync(
BuildSubscribeFrame("sub-device-eq-cmd", $"/topic/device/{_deviceId}/cmd"),
cancellationToken).ConfigureAwait(false);
if (!anonymous && !string.IsNullOrWhiteSpace(_token))
{
await SendFrameAsync(
@@ -207,6 +213,25 @@ public class StompWebSocketService : ISignalRService
_networkMonitor.SetStompTransportOnline(true);
_ = Task.Run(() => ReceiveLoopAsync(cts.Token), cts.Token);
// 连接成功后上报设备代理状态
_ = Task.Run(async () =>
{
try
{
await SendAgentStatusAsync(new
{
deviceId = _deviceId,
hostName = Environment.MachineName,
dbConnected = false,
dbMessage = "pending",
ts = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
}, CancellationToken.None).ConfigureAwait(false);
}
catch
{
// ignore
}
});
return;
}
catch
@@ -232,6 +257,38 @@ public class StompWebSocketService : ISignalRService
await SendFrameAsync(frame, cancellationToken).ConfigureAwait(false);
}
public string CurrentDeviceId => _deviceId;
public async Task SendAgentStatusAsync(object status, CancellationToken cancellationToken = default)
{
if (IsDisconnectedByUser() || _socket == null || _socket.State != WebSocketState.Open)
{
return;
}
var json = System.Text.Json.JsonSerializer.Serialize(status);
var frame = "SEND\n" +
"destination:/app/device/agent/status\n" +
"content-type:application/json\n" +
$"content-length:{Encoding.UTF8.GetByteCount(json)}\n\n" +
$"{json}\0";
await SendFrameAsync(frame, cancellationToken).ConfigureAwait(false);
}
public async Task SendAgentResultAsync(object result, CancellationToken cancellationToken = default)
{
if (IsDisconnectedByUser() || _socket == null || _socket.State != WebSocketState.Open)
{
return;
}
var json = System.Text.Json.JsonSerializer.Serialize(result);
var frame = "SEND\n" +
"destination:/app/device/agent/result\n" +
"content-type:application/json\n" +
$"content-length:{Encoding.UTF8.GetByteCount(json)}\n\n" +
$"{json}\0";
await SendFrameAsync(frame, cancellationToken).ConfigureAwait(false);
}
public async Task DisconnectAsync(CancellationToken cancellationToken = default)
{
var cts = Interlocked.Exchange(ref _connectionCts, null);
@@ -437,8 +494,29 @@ public class StompWebSocketService : ISignalRService
return "ws://" + baseUrl["http://".Length..] + "/ws/device";
}
private static string ResolveDeviceId(string token)
private string ResolveDeviceId(string token)
{
try
{
var fromConfig = EquipmentDbSettingsStore.Load().DeviceId;
if (!string.IsNullOrWhiteSpace(fromConfig))
{
return fromConfig.Trim();
}
}
catch
{
// ignore
}
var configured = _configuration.GetValue<string>("EquipmentDb:DeviceId");
if (!string.IsNullOrWhiteSpace(configured))
{
return configured.Trim();
}
if (!string.IsNullOrWhiteSpace(Environment.MachineName))
{
return Environment.MachineName;
}
try
{
var parts = token.Split('.');

View File

@@ -21,6 +21,8 @@ using YY.Admin.Views.MixerMaterialTareStrategy;
using YY.Admin.Views.RubberQuickTest;
using YY.Admin.Views.RubberQuickTestStd;
using YY.Admin.Views.MixingProductionPlan;
using YY.Admin.Views.McsActMill;
using YY.Admin.Views.UpperMes;
namespace YY.Admin
{
@@ -105,6 +107,15 @@ namespace YY.Admin
containerRegistry.RegisterForNavigation<RubberQuickTestStdListView>();
// 密炼计划(只读)
containerRegistry.RegisterForNavigation<MixingProductionPlanListView>();
containerRegistry.RegisterForNavigation<McsActMillListView>();
// 上辅机mes功能占位
containerRegistry.RegisterForNavigation<ShiftHandoverListView>();
containerRegistry.RegisterForNavigation<BomValidationListView>();
containerRegistry.RegisterForNavigation<FormulaMaintainListView>();
containerRegistry.RegisterForNavigation<PlanManageListView>();
containerRegistry.RegisterForNavigation<ReportQueryListView>();
containerRegistry.RegisterForNavigation<EquipmentDowntimeListView>();
containerRegistry.RegisterForNavigation<ProductionLogListView>();
// 打印设置
containerRegistry.RegisterForNavigation<PrintSettingsView>();
// 打印模板列表

View File

@@ -30,6 +30,7 @@ using YY.Admin.Services.Service.Print;
using YY.Admin.Services.Service.RubberQuickTest;
using YY.Admin.Services.Service.RubberQuickTestStd;
using YY.Admin.Services.Service.MixingProductionPlan;
using YY.Admin.Services.Service.EquipmentDb;
namespace YY.Admin.Module;
@@ -103,6 +104,11 @@ public class SyncModule : IModule
containerRegistry.RegisterSingleton<IMixingProductionPlanService, MixingProductionPlanService>();
containerRegistry.RegisterSingleton<MixingProductionPlanSyncCoordinator>();
// 设备库代理(厂区 SQL Server 直连 + EQ_* 命令执行)
containerRegistry.RegisterSingleton<IEquipmentDbConnectionFactory, EquipmentDbConnectionFactory>();
containerRegistry.RegisterSingleton<EquipmentDbCommandHandler>();
containerRegistry.RegisterSingleton<IMcsActMillService, McsActMillService>();
var serviceCollection = new ServiceCollection();
serviceCollection.AddTransient<DisconnectGuardHandler>();
serviceCollection.AddHttpClient("JeecgApi", (sp, client) =>
@@ -179,6 +185,21 @@ public class SyncModule : IModule
_ = containerProvider.Resolve<RubberQuickTestStdSyncCoordinator>();
// 密炼计划只读同步协调器
_ = containerProvider.Resolve<MixingProductionPlanSyncCoordinator>();
// 设备库命令处理器(订阅 EQ_*
var eqHandler = containerProvider.Resolve<EquipmentDbCommandHandler>();
_ = Task.Run(async () =>
{
try
{
var factory = containerProvider.Resolve<IEquipmentDbConnectionFactory>();
var (ok, msg) = await factory.TestAsync(CancellationToken.None).ConfigureAwait(false);
await eqHandler.ReportStatusAsync(ok, msg, CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
await eqHandler.ReportStatusAsync(false, ex.Message, CancellationToken.None).ConfigureAwait(false);
}
});
}
private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()

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 = "交接班";
}
}

View File

@@ -38,6 +38,20 @@
Style="{StaticResource ToggleButtonSwitch}"/>
</DockPanel>
<TextBlock Text="设备库(厂区 SQL Server" FontWeight="SemiBold" Margin="0,18,0,8"/>
<TextBlock Text="设备 ID" Margin="0,0,0,6"/>
<TextBox Text="{Binding EqDeviceId, UpdateSourceTrigger=PropertyChanged}" Height="32"/>
<TextBlock Text="服务器" Margin="0,12,0,6"/>
<TextBox Text="{Binding EqServerHost, UpdateSourceTrigger=PropertyChanged}" Height="32"/>
<TextBlock Text="端口" Margin="0,12,0,6"/>
<TextBox Text="{Binding EqServerPort, UpdateSourceTrigger=PropertyChanged}" Height="32"/>
<TextBlock Text="数据库" Margin="0,12,0,6"/>
<TextBox Text="{Binding EqDbName, UpdateSourceTrigger=PropertyChanged}" Height="32"/>
<TextBlock Text="用户名" Margin="0,12,0,6"/>
<TextBox Text="{Binding EqUsername, UpdateSourceTrigger=PropertyChanged}" Height="32"/>
<TextBlock Text="密码" Margin="0,12,0,6"/>
<PasswordBox x:Name="EqPasswordBox" Height="32" PasswordChanged="EqPasswordBox_OnPasswordChanged"/>
<TextBlock Text="{Binding ErrorMessage}" Foreground="Red" Margin="0,12,0,0"/>
</StackPanel>

View File

@@ -1,4 +1,6 @@
using System.Windows;
using System.Windows.Controls;
using YY.Admin.ViewModels.Dialogs;
namespace YY.Admin.Views.Dialogs
{
@@ -10,6 +12,23 @@ namespace YY.Admin.Views.Dialogs
public ServerSettingsDialogView()
{
InitializeComponent();
DataContextChanged += OnDataContextChanged;
}
private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (DataContext is ServerSettingsDialogViewModel vm && !string.IsNullOrEmpty(vm.EqPassword))
{
EqPasswordBox.Password = vm.EqPassword;
}
}
private void EqPasswordBox_OnPasswordChanged(object sender, RoutedEventArgs e)
{
if (DataContext is ServerSettingsDialogViewModel vm)
{
vm.EqPassword = EqPasswordBox.Password;
}
}
}
}

View File

@@ -0,0 +1,100 @@
<UserControl x:Class="YY.Admin.Views.McsActMill.McsActMillListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" CornerRadius="4" Margin="0 0 -10 0">
<hc:Row>
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
<hc:TextBox Text="{Binding FilterActName, UpdateSourceTrigger=PropertyChanged}"
Margin="0 0 10 10"
hc:InfoElement.Title="动作名称"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.TitleWidth="80"
hc:InfoElement.Placeholder="动作名称"
hc:InfoElement.ShowClearButton="True"/>
</hc:Col>
<hc:Col Layout="{hc:ColLayout Xs=12, Sm=8, Md=6, Lg=6, Xl=4}">
<hc:TextBox Text="{Binding FilterActAddrText, UpdateSourceTrigger=PropertyChanged}"
Margin="0 0 10 10"
hc:InfoElement.Title="动作地址"
hc:InfoElement.TitlePlacement="Left"
hc:InfoElement.TitleWidth="80"
hc:InfoElement.Placeholder="动作地址"
hc:InfoElement.ShowClearButton="True"/>
</hc:Col>
</hc:Row>
</Border>
<Border Grid.Row="1" Margin="0,10">
<hc:UniformSpacingPanel Spacing="10">
<Button Style="{StaticResource ButtonPrimary}" Command="{Binding SearchCommand}">
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="Search"/>
<TextBlock Text="搜索" Style="{StaticResource IconButtonStyle}"/>
</StackPanel>
</Button>
<Button Style="{StaticResource ButtonDefault}" Command="{Binding ResetCommand}">
<StackPanel Orientation="Horizontal">
<md:PackIcon Kind="Refresh"/>
<TextBlock Text="重置" Style="{StaticResource IconButtonStyle}"/>
</StackPanel>
</Button>
<TextBlock Text="数据直连设备库中间表 MCSToMES_Act_Mill只读"
VerticalAlignment="Center"
Foreground="{DynamicResource SecondaryTextBrush}"
FontSize="12"/>
</hc:UniformSpacingPanel>
</Border>
<DataGrid Grid.Row="2"
ItemsSource="{Binding Items}"
AutoGenerateColumns="False"
IsReadOnly="True"
CanUserAddRows="False"
SelectionMode="Single"
GridLinesVisibility="Horizontal"
HorizontalGridLinesBrush="#FFEDEDED"
VerticalGridLinesBrush="Transparent"
HeadersVisibility="All"
ColumnHeaderStyle="{StaticResource CusDataGridColumnHeaderStyle}"
Style="{StaticResource CusDataGridStyle}"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="GUID" Binding="{Binding Guid}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="280"/>
<DataGridTextColumn Header="动作地址" Binding="{Binding ActAddr}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
<DataGridTextColumn Header="动作名称" Binding="{Binding ActName}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
<DataGridTextColumn Header="动作名称(英)" Binding="{Binding ActNameEn}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="140"/>
<DataGridTextColumn Header="动作备注" Binding="{Binding ActMemo}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="120"/>
<DataGridTextColumn Header="关联地址" Binding="{Binding ActRepaddr}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="90"/>
<DataGridTextColumn Header="写入时间" Binding="{Binding WriteTime, StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="160"/>
<DataGridTextColumn Header="读取时间" Binding="{Binding ReadTime, StringFormat={}{0:yyyy-MM-dd HH:mm:ss}}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="160"/>
<DataGridTextColumn Header="读写标识" Binding="{Binding RwFlag}" CellStyle="{StaticResource CusDataGridCellStyle}" Width="80"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,10,0,0">
<TextBlock Text="{Binding Total, StringFormat=共 {0} 条}" VerticalAlignment="Center" Margin="0,0,16,0"
Foreground="{DynamicResource SecondaryTextBrush}"/>
<Button Content="上一页" Command="{Binding PrevPageCommand}" Style="{StaticResource ButtonDefault}" Margin="0,0,4,0" Width="80"/>
<TextBlock Text="{Binding PageNo, StringFormat=第 {0} 页}" VerticalAlignment="Center" Margin="8,0"
Foreground="{DynamicResource PrimaryTextBrush}"/>
<Button Content="下一页" Command="{Binding NextPageCommand}" Style="{StaticResource ButtonDefault}" Width="80"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.McsActMill;
public partial class McsActMillListView : UserControl
{
public McsActMillListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.BomValidationListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class BomValidationListView : UserControl
{
public BomValidationListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.EquipmentDowntimeListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class EquipmentDowntimeListView : UserControl
{
public EquipmentDowntimeListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.FormulaMaintainListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class FormulaMaintainListView : UserControl
{
public FormulaMaintainListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.PlanManageListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class PlanManageListView : UserControl
{
public PlanManageListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.ProductionLogListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class ProductionLogListView : UserControl
{
public ProductionLogListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.ReportQueryListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class ReportQueryListView : UserControl
{
public ReportQueryListView()
{
InitializeComponent();
}
}

View File

@@ -0,0 +1,15 @@
<UserControl x:Class="YY.Admin.Views.UpperMes.ShiftHandoverListView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d">
<Grid Style="{StaticResource BaseViewStyle}">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBlock Text="{Binding Title}" FontSize="22" FontWeight="SemiBold" HorizontalAlignment="Center"/>
<TextBlock Text="功能开发中" Margin="0 16 0 0" FontSize="14" Opacity="0.65" HorizontalAlignment="Center"/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,11 @@
using System.Windows.Controls;
namespace YY.Admin.Views.UpperMes;
public partial class ShiftHandoverListView : UserControl
{
public ShiftHandoverListView()
{
InitializeComponent();
}
}

View File

@@ -135,8 +135,9 @@ var ensureNeverExpireConfig = conn.CreateCommand();
ensureNeverExpireConfig.Transaction = tx;
ensureNeverExpireConfig.CommandText = @"
INSERT INTO sys_config (id, name, code, value, sys_flag, remark, order_no, group_code, create_time)
SELECT 1300000000194, '登录永不过期', 'sys_token_never_expire', 'False', 'Y', '桌面端:开启后不触发登录过期提示与自动踢回登录页', 119, 'Default', datetime('now')
SELECT 1300000000194, '登录永不过期', 'sys_token_never_expire', 'True', 'Y', '桌面端:开启后不触发登录过期提示与自动踢回登录页', 119, 'Default', datetime('now')
WHERE NOT EXISTS (SELECT 1 FROM sys_config WHERE code = 'sys_token_never_expire');
UPDATE sys_config SET value = 'True' WHERE code = 'sys_token_never_expire' AND IFNULL(value,'') <> 'True';
";
ensureNeverExpireConfig.ExecuteNonQuery();