using Prism.Events; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using TeamAAS_VP.Core; using TeamAAS_VP.Events; using TeamAAS_VP.Models; namespace TeamAAS_VP.Services { public class ShiftWatcherService { private readonly IEventAggregator _eventAggregator; private Timer _timer; private string _lastShift; private WorkShift workShift; public ShiftWatcherService(IEventAggregator eventAggregator) { this._eventAggregator = eventAggregator; } public void Start() { // 中文注释:每秒检测一次 _timer = new Timer(_ => CheckShift(), null, 0, 1000); try { this.workShift = FileHelper.ReadJsonFile(FilePath.WorkShiftParamPath); } catch (Exception) { } _eventAggregator.GetEvent().Subscribe((p) => { this.workShift = p; }); } private void CheckShift() { DateTime dateTimeDayShift = DateTime.Now; DateTime dateTimeNightShift = DateTime.Now; if (workShift==null) { return; } try { dateTimeDayShift = DateTime.Parse(workShift.DayShift); dateTimeNightShift = DateTime.Parse(workShift.NightShift); } catch { } string currentShift = (DateTime.Now.Hour >= 8 && DateTime.Now.Hour < 20) ? "Day" : "Night"; if (_lastShift == null) { _lastShift = currentShift; return; } if (_lastShift != currentShift) { _lastShift = currentShift; // 只负责“通知”,不要弹窗 _ = App.Current.Dispatcher.BeginInvoke(new Action(() => { _eventAggregator.GetEvent().Publish(); })); } } } } /* ```csharp // =========================== // 文件1:ShiftChangedEvent.cs // =========================== using Prism.Events; using System; namespace YourApp.Shift { // 中文注释:班次切换事件(发布/订阅用) public class ShiftChangedEvent : PubSubEvent { } // 中文注释:班次切换携带的数据 public class ShiftChangedPayload { public string NewShiftName { get; set; } // 中文注释:新班次名称 public DateTime SwitchTime { get; set; } // 中文注释:切换时间 } } ``` ```csharp // =========================== // 文件2:IShiftWatcher.cs / ShiftWatcher.cs // =========================== using Prism.Events; using System; using System.Threading; namespace YourApp.Shift { public interface IShiftWatcher { void Start(); void Stop(); } public class ShiftWatcher : IShiftWatcher { private readonly IEventAggregator _ea; private Timer _timer; private string _lastShiftKey; public ShiftWatcher(IEventAggregator ea) { _ea = ea; } public void Start() { // 中文注释:每秒检查一次(你可以改成 5s/10s) _timer = new Timer(_ => CheckShift(), null, TimeSpan.Zero, TimeSpan.FromSeconds(1)); } public void Stop() { _timer?.Dispose(); _timer = null; } private void CheckShift() { // 中文注释:示例班次规则:白班 08:00-20:00,夜班 20:00-08:00 var now = DateTime.Now; string currentShift = (now.Hour >= 8 && now.Hour < 20) ? "Day" : "Night"; if (_lastShiftKey == null) { _lastShiftKey = currentShift; return; } if (_lastShiftKey != currentShift) { _lastShiftKey = currentShift; // 中文注释:只发布事件,不在定时器线程里弹窗 _ea.GetEvent().Publish(new ShiftChangedPayload { NewShiftName = currentShift, SwitchTime = now }); } } } } ``` ```csharp // =========================== // 文件3:IMainProcess.cs / MainProcess.cs // =========================== using System.Threading; using System.Threading.Tasks; namespace YourApp.Process { public interface IMainProcess { Task RunAsync(CancellationToken token); } public class MainProcess : IMainProcess { public async Task RunAsync(CancellationToken token) { // 中文注释:示例主流程循环(把你的采图/检测/运动控制逻辑放这里) while (!token.IsCancellationRequested) { // TODO: 在这里写你的主流程逻辑(注意尊重 token) await Task.Delay(100, token); // 中文注释:模拟工作 } } } } ``` ```csharp // =========================== // 文件4:MainWindowViewModel.cs(整合:切班→停流程→隐藏主窗口→ShowDialog登录→恢复) // =========================== using Prism.Events; using Prism.Mvvm; using System; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using YourApp.Process; using YourApp.Shift; namespace YourApp.ViewModels { public class MainWindowViewModel : BindableBase { private readonly IEventAggregator _ea; private readonly IMainProcess _mainProcess; private CancellationTokenSource _mainFlowCts; private bool _loginShowing; public MainWindowViewModel(IEventAggregator ea, IMainProcess mainProcess) { _ea = ea; _mainProcess = mainProcess; // 中文注释:订阅班次切换事件,强制在UI线程执行(这样可以安全Hide/Show主窗口和弹窗) _ea.GetEvent() .Subscribe(OnShiftChanged, ThreadOption.UIThread); } // 中文注释:你可以在程序启动后调用一次,启动主流程 public void StartMainFlow() { _mainFlowCts?.Cancel(); _mainFlowCts = new CancellationTokenSource(); // 中文注释:后台线程运行主流程,不阻塞UI Task.Run(async () => { try { await _mainProcess.RunAsync(_mainFlowCts.Token); } catch (OperationCanceledException) { // 中文注释:正常取消 } catch (Exception ex) { // 中文注释:实际项目里这里写日志 Application.Current.Dispatcher.Invoke(() => { MessageBox.Show(ex.Message, "主流程异常"); }); } }); } // 中文注释:班次切换时触发:停流程→隐藏主窗口→弹登录→登录成功恢复 private void OnShiftChanged(ShiftChangedPayload payload) { if (_loginShowing) return; _loginShowing = true; // 1️⃣ 中断主流程(取消后台任务,不动UI线程) _mainFlowCts?.Cancel(); // 2️⃣ 隐藏主窗口 var mainWindow = Application.Current.MainWindow; mainWindow?.Hide(); // 3️⃣ 弹出重新登录窗口(你当前是 Window.ShowDialog) var loginWindow = new LoginWindow { Owner = mainWindow // 中文注释:设置Owner,防止窗口跑到后面 }; // 中文注释:可选,把提示原因传给登录窗口(你需要在LoginWindow里定义这个属性) loginWindow.LoginReason = $"班次切换到 {payload.NewShiftName},请重新登录"; bool? result = loginWindow.ShowDialog(); // 4️⃣ 根据登录结果处理 if (result == true) { // 中文注释:登录成功 → 显示主窗口 → 重新启动主流程 mainWindow?.Show(); StartMainFlow(); } else { // 中文注释:登录失败/取消:按需求决定(示例:仍显示主窗口但不启动流程) mainWindow?.Show(); // 如果你想强制退出可以用: // Application.Current.Shutdown(); } _loginShowing = false; } } } ``` ```csharp // =========================== // 文件5:App.xaml.cs(Prism启动:注册服务 + 启动初始化 + 启动班次监控) // =========================== using Prism.Ioc; using Prism.Unity; // 如果你用 DryIoc/Autofac,这里换对应的PrismApplication基类命名空间 using System.Text; using System.Windows; using YourApp.Process; using YourApp.Shift; namespace YourApp { public partial class App : PrismApplication { protected override Window CreateShell() { // 中文注释:支持GBK等编码(如果你有CSV/老设备编码需求) Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); // 中文注释:创建主窗口(MainWindowView) return Container.Resolve(); } protected override void RegisterTypes(IContainerRegistry containerRegistry) { // 中文注释:注册主流程服务 containerRegistry.RegisterSingleton(); // 中文注释:注册班次监控(定时器) containerRegistry.RegisterSingleton(); // 你原来这些也可以在这里注册或在别处注册 // containerRegistry.RegisterSingleton(); // containerRegistry.RegisterSingleton(); } protected override void OnInitialized() { base.OnInitialized(); // 中文注释:启动时初始化(你原来Resolve的配置、数据库初始化可以放这里) var configService = Container.Resolve(); var dbInit = Container.Resolve(); dbInit.Initialize(); // 中文注释:启动班次监控 var watcher = Container.Resolve(); watcher.Start(); // 中文注释:启动主流程(通过主窗口VM调用) // 注意:主窗口已经显示后再启动更合理 if (Current.MainWindow?.DataContext is YourApp.ViewModels.MainWindowViewModel vm) { vm.StartMainFlow(); } } } } ``` ```csharp // =========================== // 文件6:LoginWindow.xaml.cs(示例:让 MainWindowViewModel 能设置 LoginReason) // 说明:你已有LoginWindow就按需合并,不需要照搬UI // =========================== using System.Windows; namespace YourApp { public partial class LoginWindow : Window { // 中文注释:给外部传入提示原因(可选) public string LoginReason { get { return (string)GetValue(LoginReasonProperty); } set { SetValue(LoginReasonProperty, value); } } public static readonly DependencyProperty LoginReasonProperty = DependencyProperty.Register(nameof(LoginReason), typeof(string), typeof(LoginWindow), new PropertyMetadata("")); public LoginWindow() { InitializeComponent(); } // 中文注释:登录成功按钮 private void BtnOk_Click(object sender, RoutedEventArgs e) { // TODO:这里做你的账号密码校验 // 校验成功: this.DialogResult = true; this.Close(); } // 中文注释:取消/关闭按钮 private void BtnCancel_Click(object sender, RoutedEventArgs e) { this.DialogResult = false; this.Close(); } } } ``` */ /* ///// ///// 判断在班次时间内是否是登录过点控 ///// ///// ///// ///// //public bool JudgeIsSpotCheck(string DayShhift, string NightShift) //{ // DateTime dateTimeDayShift = DateTime.Now; // DateTime dateTimeNightShift = DateTime.Now; // try // { // dateTimeDayShift = DateTime.Parse(DayShhift); // dateTimeNightShift = DateTime.Parse(NightShift); // } // catch (Exception) // { // AddLog(2, "Check Time格式输入错误,请参照 7:50 该格式进行填写"); // MessageBox.Show("Check Time格式输入错误,请参照 7:50 该格式进行填写"); // return false; // } // DateTime LoginTime = DateTime.Parse(IniConfigHelper.ReadIniData("CheckTime", "LoginTime", "")); // //在原有的基础上增加一天 // DateTime endOfDateTimeDayShift = dateTimeDayShift.AddDays(1); // DateTime NowDataTime = DateTime.Now; // if (NowDataTime >= dateTimeDayShift && NowDataTime <= dateTimeNightShift) // { // if (!GlobalVariable.CheckTime.DayShiftSpotCheck && LoginTime >= dateTimeDayShift) // { // frmSpotCheck = new FrmSpotCheck(IniConfigHelper.ReadIniData("CheckTime", "LoginTime", ""), dateTimeDayShift, dateTimeNightShift); // if (frmSpotCheck.ShowDialog() == DialogResult.OK) // { // return true; // } // else // { // return false; // } // } // } // if (NowDataTime >= dateTimeNightShift && NowDataTime <= endOfDateTimeDayShift) // { // if (!GlobalVariable.CheckTime.NightShiftSpotCheck && LoginTime >= dateTimeNightShift) // { // frmSpotCheck = new FrmSpotCheck(IniConfigHelper.ReadIniData("CheckTime", "LoginTime", ""), dateTimeDayShift, dateTimeNightShift); // if (frmSpotCheck.ShowDialog() == DialogResult.OK) // { // return true; // } // else // { // return false; // } // } // } // return true; //} //[CheckTime] //DayShift=7:50 //NightShift=19:50 //NtcTempSelectStore=NTC.xlsx //LoginTime = 2025年8月14日 13:28 //DayShiftSpotCheck=1 //NightShiftSpotCheck=0 #endregion */