專案

一般

配置概況

Task #2511 » uc_OperationPerformance.xaml.cs

莊 施嶔, 11/05/2025 09:58

 
//*********************************************************************************
// 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<MyItem> myDataCollection = new ObservableCollection<MyItem>();
List<CassetteHis> cstLst = new List<CassetteHis>();
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<CassetteHis> cstList, List<CassetteHis> filteredList)> GetCSTDataAsync(DateTime startTime, DateTime endTime)
{
try
{
List<CassetteHis> 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<CassetteHis> cstList, List<CassetteHis> 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; }
}
}
}
(4-4/6)