//********************************************************************************* // uc_UserOperationRecords.cs //********************************************************************************* // File Name: uc_UserOperationRecords.cs // Description: User Operation查詢介面 // //(c) Copyright 2014, MIRLE Automation Corporation // // Date Author Request No. Tag Description // --------------- --------------- --------------- --------------- ------------------------------ // 2020/08/24 Boan Chen N/A N/A Initial。 //********************************************************************************* using BlockControl_3._0_WPF.frm_Help; using com.mirle.ibg3k0.bc.winform.App; using com.mirle.ibg3k0.sc.App; using com.mirle.ibg3k0.sc.Data.VO; using NLog; using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Collections.ObjectModel; using System.Threading.Tasks; namespace BCWPF.frm_Query { public partial class uc_OperationPerformance : UserControl { #region 全域變數 BCApplication bcApp = null; SCApplication scApp = null; public event EventHandler btn_Close_Click; private static Logger logger = LogManager.GetCurrentClassLogger(); protected static Logger logger_SystemError = LogManager.GetLogger("SystemErrorLogger"); private ObservableCollection myDataCollection = new ObservableCollection(); List cstLst = new List(); int cstCount = 0; int panelCount = 0; int normalEndCount = 0; // Add counter for normal end int abnormalEndCount = 0; // Add counter for abnormal end int normalEndPanelCount = 0; // Add counter for normal end panel count int abnormalEndPanelCount = 0; // Add counter for abnormal end panel count frm_TipMessage_OK tipmsg_ok = new frm_TipMessage_OK(""); DateTime dt_start; DateTime dt_end; #endregion 全域變數 #region 建構子 public uc_OperationPerformance() { try { InitializeComponent(); bcApp = BCApplication.getInstance(); scApp = SCApplication.getInstance(); // Set default start date to yesterday dt_StartTime.SelectedDate = DateTime.Now.AddDays(-1); } catch (Exception ex) { logger_SystemError.Error(ex, "Exception"); } } #endregion 建構子 #region 介面顯示 private void UC_VisibleChanged(object sender, DependencyPropertyChangedEventArgs e) { try { // Remove automatic query when window opens // if ((bool)e.NewValue) // { // Search_Click(null, null); // } } catch (Exception ex) { logger_SystemError.Error(ex, "Exception"); } } #endregion 介面顯示 #region 按鈕事件_查詢 private void Search_Click(object sender, RoutedEventArgs e) { try { Task.Run(() => QueryDataAsync()); } catch (Exception ex) { logger_SystemError.Error(ex, "Exception in Search_Click"); ShowError("執行查詢時發生錯誤\nAn error occurred while executing the query.", ex); } } #endregion 按鈕事件_查詢 #region 按鈕事件_關閉 private void Close_Click(object sender, RoutedEventArgs e) { try { if (btn_Close_Click != null) { this.Visibility = Visibility.Hidden; btn_Close_Click(sender, e); } } catch (Exception ex) { logger_SystemError.Error(ex, "Exception"); } } #endregion 按鈕事件_關閉 #region 查詢資料 private async Task QueryDataAsync() { try { // 檢查日期並取得時間範圍 var (isValid, startTime, endTime) = await ValidateDateRangeAsync(); if (!isValid) return; // 清空資料集合 await ClearCollectionsAsync(); // 在背景執行資料查詢 var queryResult = await Task.Run(() => GetCSTDataAsync(startTime, endTime)); if (queryResult.cstList == null) { await ShowErrorAsync("查詢資料失敗,請聯絡系統管理員。\nFailed to query data. Please contact system administrator."); return; } // 更新UI顯示 await UpdateUIWithDataAsync(queryResult.cstList, queryResult.filteredList); } catch (Exception ex) { logger_SystemError.Error(ex, "Exception in QueryDataAsync"); await ShowErrorAsync("查詢作業發生未預期的錯誤,請聯絡系統管理員。\nAn unexpected error occurred during query. Please contact system administrator."); } } private async Task<(bool isValid, DateTime startTime, DateTime endTime)> ValidateDateRangeAsync() { return await Dispatcher.InvokeAsync(() => { DateTime? startTime = null; DateTime? endTime = null; var today = DateTime.Today.AddHours(23.9999); // Start date is optional if (dt_StartTime.SelectedDate != null) { startTime = dt_StartTime.SelectedDate.Value; if (startTime > today) { ShowError("開始日期不可以大於今天。\nStart date cannot be later than today."); return (false, DateTime.MinValue, DateTime.MinValue); } } // End date is optional if (dt_EndTime.SelectedDate != null) { endTime = dt_EndTime.SelectedDate.Value.AddHours(23.9999); if (endTime > today) { ShowError("結束日期不可以大於今天。\nEnd date cannot be later than today."); return (false, DateTime.MinValue, DateTime.MinValue); } } // If both dates are set, check if start date is before end date if (startTime.HasValue && endTime.HasValue && startTime > endTime) { ShowError("開始時間必須在結束時間之前。\nStart date must be before end date."); return (false, DateTime.MinValue, DateTime.MinValue); } // If no dates are set, return MinValue and MaxValue if (!startTime.HasValue && !endTime.HasValue) { return (true, DateTime.MinValue, DateTime.MaxValue); } // If only start date is set, use MaxValue for end date if (startTime.HasValue && !endTime.HasValue) { return (true, startTime.Value, DateTime.MaxValue); } // If only end date is set, use MinValue for start date if (!startTime.HasValue && endTime.HasValue) { return (true, DateTime.MinValue, endTime.Value); } // Both dates are set return (true, startTime.Value, endTime.Value); }); } private async Task ClearCollectionsAsync() { await Dispatcher.InvokeAsync(() => { myDataCollection.Clear(); cstLst.Clear(); cstCount = 0; panelCount = 0; }); } private async Task<(List cstList, List filteredList)> GetCSTDataAsync(DateTime startTime, DateTime endTime) { try { List cstList; // Handle different date scenarios if (startTime == DateTime.MinValue && endTime == DateTime.MaxValue) { // No date filter - get all records cstList = scApp.SheetBLL.getAllCSTHis(); } else if (startTime == DateTime.MinValue) { // Only end date filter - get all records up to end time cstList = scApp.SheetBLL.getAllCSTHis(); if (cstList != null) { string endTimeStr = endTime.ToString("yyyyMMddHHmmssfffff"); cstList = cstList.Where(c => string.Compare(c.T_STAMP, endTimeStr) <= 0).ToList(); } } else if (endTime == DateTime.MaxValue) { // Only start date filter cstList = scApp.SheetBLL.getAllCSTHis(); if (cstList != null) { string startTimeStr = startTime.ToString("yyyyMMddHHmmssfffff"); cstList = cstList.Where(c => string.Compare(c.T_STAMP, startTimeStr) >= 0).ToList(); } } else { // Both dates specified cstList = scApp.SheetBLL.getAllCSTHis(); if (cstList != null) { string startTimeStr = startTime.ToString("yyyyMMddHHmmssfffff"); string endTimeStr = endTime.ToString("yyyyMMddHHmmssfffff"); cstList = cstList.Where(c => string.Compare(c.T_STAMP, startTimeStr) >= 0 && string.Compare(c.T_STAMP, endTimeStr) <= 0).ToList(); } } if (cstList == null) { logger_SystemError.Error("Failed to get CST list from database"); return (null, null); } var filteredList = await Dispatcher.InvokeAsync(() => { var resultList = cstList; // 篩選 Carrier ID (CST_ID) if (!string.IsNullOrWhiteSpace(tbx_CarrierID.Text.Trim())) { string carrierIDFilter = tbx_CarrierID.Text.Trim(); // 實現模糊搜尋:包含部分匹配、大小寫不敏感,並處理null值 resultList = resultList.Where(c => c.CST_ID == null || // 包含null值 c.CST_ID.Trim().ToUpper().Contains(carrierIDFilter.ToUpper()) || // 部分匹配 c.CST_ID.Trim().ToUpper().StartsWith(carrierIDFilter.ToUpper()) || // 開頭匹配 c.CST_ID.Trim().ToUpper().EndsWith(carrierIDFilter.ToUpper()) // 結尾匹配 ).ToList(); } // 篩選 End State if (cbx_EndState.SelectedItem != null) { string selectedEndState = ((ComboBoxItem)cbx_EndState.SelectedItem).Content.ToString(); if (selectedEndState != "All") { string endStateFilter = selectedEndState == "Normal End" ? SCAppConstants.CSTEndStatus.Normal_End : SCAppConstants.CSTEndStatus.Abort_End; resultList = resultList.Where(c => c.End_Stat == endStateFilter).ToList(); } } return resultList; }); return (cstList, filteredList); } catch (Exception ex) { logger_SystemError.Error(ex, "Exception in GetCSTDataAsync"); throw; } } private async Task UpdateUIWithDataAsync(List cstList, List filteredList) { await Dispatcher.InvokeAsync(() => { try { dgv_DataGrid.ItemsSource = null; if (filteredList != null && filteredList.Count > 0) { var orderedList = filteredList.OrderByDescending(t => t.CstLogOn_Time).ToList(); cstCount = orderedList.Count(); panelCount = orderedList.Select(a => a.Sht_Cnt).Sum(); // Calculate normal and abnormal end counts normalEndCount = orderedList.Count(c => c.End_Stat == SCAppConstants.CSTEndStatus.Normal_End); abnormalEndCount = orderedList.Count(c => c.End_Stat == SCAppConstants.CSTEndStatus.Abort_End); // Calculate normal and abnormal end panel counts normalEndPanelCount = orderedList .Where(c => c.End_Stat == SCAppConstants.CSTEndStatus.Normal_End) .Sum(c => c.Sht_Cnt); abnormalEndPanelCount = orderedList .Where(c => c.End_Stat == SCAppConstants.CSTEndStatus.Abort_End) .Sum(c => c.Sht_Cnt); // Calculate ratios double carrierNormalEndRatio = cstCount > 0 ? (double)normalEndCount / cstCount * 100 : 0; double carrierAbortEndRatio = cstCount > 0 ? (double)abnormalEndCount / cstCount * 100 : 0; double panelNormalEndRatio = panelCount > 0 ? (double)normalEndPanelCount / panelCount * 100 : 0; double panelAbortEndRatio = panelCount > 0 ? (double)abnormalEndPanelCount / panelCount * 100 : 0; foreach (var cst in orderedList) { myDataCollection.Add(new MyItem() { CST_ID = cst.CST_ID?.Trim() ?? "", // 處理null值 Sht_Cnt = cst.Sht_Cnt, End_Stat = cst.End_Stat == null ? "" : (cst.End_Stat == SCAppConstants.CSTEndStatus.Normal_End ? "Normal End" : "Abort End"), CstLogOn_Time = cst.CstLogOn_Time, CstLogOff_Time = cst.CstLogOff_Time, CstProcStart_Time = cst.CstProcStart_Time, CstProcEnd_Time = cst.CstProcEnd_Time }); } CurrPanelCount.Text = panelCount.ToString(); CurrCount.Text = orderedList.Count.ToString(); NormalEndCount.Text = normalEndCount.ToString(); AbnormalEndCount.Text = abnormalEndCount.ToString(); NormalEndPanelCount.Text = normalEndPanelCount.ToString(); AbnormalEndPanelCount.Text = abnormalEndPanelCount.ToString(); // Update ratio displays CarrierNormalEndRatio.Text = $"{carrierNormalEndRatio:F1}%"; CarrierAbortEndRatio.Text = $"{carrierAbortEndRatio:F1}%"; PanelNormalEndRatio.Text = $"{panelNormalEndRatio:F1}%"; PanelAbortEndRatio.Text = $"{panelAbortEndRatio:F1}%"; dgv_DataGrid.ItemsSource = myDataCollection; } else { CurrCount.Text = "0"; CurrPanelCount.Text = "0"; NormalEndCount.Text = "0"; AbnormalEndCount.Text = "0"; NormalEndPanelCount.Text = "0"; AbnormalEndPanelCount.Text = "0"; CarrierNormalEndRatio.Text = "0%"; CarrierAbortEndRatio.Text = "0%"; PanelNormalEndRatio.Text = "0%"; PanelAbortEndRatio.Text = "0%"; // 提示沒有找到符合條件的資料 string bilingualMessage = "沒有查詢到符合條件的資料。\nNo matching data found."; tipmsg_ok = new frm_TipMessage_OK(bilingualMessage); tipmsg_ok.ShowDialog(); } } catch (Exception ex) { logger_SystemError.Error(ex, "Exception in UpdateUIWithDataAsync"); throw; } }); } private void ShowError(string bilingualMessage, Exception ex = null) { try { // 記錄日誌 if (ex != null) { logger_SystemError.Error(ex, bilingualMessage); } // 當有例外錯誤時,添加查看日誌的提示 if (ex != null) { string logHint = "請查看SystemError日誌以獲取詳細錯誤資訊。\nPlease check the SystemError log for detailed error information."; bilingualMessage = $"{bilingualMessage}\n\n{logHint}"; } // UI更新 Dispatcher.InvokeAsync(() => { try { tipmsg_ok = new frm_TipMessage_OK(bilingualMessage); tipmsg_ok.ShowDialog(); } catch (Exception uiEx) { // UI更新失敗時,使用基本的MessageBox MessageBox.Show(bilingualMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }); } catch (Exception outerEx) { // 不顯示例外訊息,只顯示一般性錯誤提示 string errorMsg = "系統發生未預期的錯誤,請聯絡系統管理員。\nAn unexpected system error occurred. Please contact system administrator."; MessageBox.Show(errorMsg, "Error", MessageBoxButton.OK, MessageBoxImage.Error); // 記錄未預期的例外 try { logger_SystemError.Error(outerEx, "ShowError方法發生未預期的例外"); } catch { // 如果連日誌記錄都失敗,就不再嘗試任何處理 } } } private async Task ShowErrorAsync(string bilingualMessage) { try { await Dispatcher.InvokeAsync(() => { try { tipmsg_ok = new frm_TipMessage_OK(bilingualMessage); tipmsg_ok.ShowDialog(); } catch (Exception uiEx) { // UI更新失敗時,使用基本的MessageBox MessageBox.Show(bilingualMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error); } }); } catch (Exception ex) { // 不顯示例外訊息,只顯示一般性錯誤提示 string errorMsg = "系統發生未預期的錯誤,請聯絡系統管理員。\nAn unexpected system error occurred. Please contact system administrator."; MessageBox.Show(errorMsg, "Error", MessageBoxButton.OK, MessageBoxImage.Error); // 記錄未預期的例外 try { logger_SystemError.Error(ex, "ShowErrorAsync方法發生未預期的例外"); } catch { // 如果連日誌記錄都失敗,就不再嘗試任何處理 } } } #endregion 查詢資料 #region 文字輸入框事件 private void keydown(object sender, KeyEventArgs e) { try { if (e.Key == Key.Enter) { Search_Click(null, null); } } catch (Exception ex) { logger_SystemError.Error(ex, "Exception"); } } #endregion 文字輸入框事件 public class MyItem { public string CST_ID { get; set; } public int Sht_Cnt { get; set; } public string End_Stat { get; set; } public DateTime? CstLogOn_Time { get; set; } public DateTime? CstLogOff_Time { get; set; } public DateTime? CstProcStart_Time { get; set; } public DateTime? CstProcEnd_Time { get; set; } } } }