|
//*********************************************************************************
|
|
// 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; }
|
|
}
|
|
}
|
|
}
|