1090 lines
35 KiB
C#
1090 lines
35 KiB
C#
|
|
using System;
|
|||
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
using TMPro;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// BFI历史记录和数据导出UI面板
|
|||
|
|
/// 提供历史记录查看、搜索、选择和导出功能
|
|||
|
|
/// </summary>
|
|||
|
|
public class BFIHistoryExportPanel : BasePanel
|
|||
|
|
{
|
|||
|
|
[Header("UI引用")]
|
|||
|
|
[SerializeField] private Transform historyListParent;
|
|||
|
|
[SerializeField] private GameObject historyItemPrefab;
|
|||
|
|
[SerializeField] private ScrollRect historyScrollRect;
|
|||
|
|
[SerializeField] private TMP_InputField searchInputField;
|
|||
|
|
[SerializeField] private KeyboardLayout searchKeyboardLayout = KeyboardLayout.Pinyin;
|
|||
|
|
[SerializeField] private Button searchButton;
|
|||
|
|
[SerializeField] private Button clearRecordButton;
|
|||
|
|
|
|||
|
|
[Header("过滤器")]
|
|||
|
|
[SerializeField] private TMP_Dropdown dateFilterDropdown;
|
|||
|
|
[SerializeField] private TMP_InputField startDateInput;
|
|||
|
|
[SerializeField] private TMP_InputField endDateInput;
|
|||
|
|
[SerializeField] private Button applyDateFilterButton;
|
|||
|
|
|
|||
|
|
[Header("选择控制")]
|
|||
|
|
[SerializeField] private Toggle selectAllToggle;
|
|||
|
|
// [SerializeField] private Button selectTodayButton;
|
|||
|
|
// [SerializeField] private Button selectWeekButton;
|
|||
|
|
// [SerializeField] private Button clearSelectionButton;
|
|||
|
|
[SerializeField] private TextMeshProUGUI selectionCountText;
|
|||
|
|
|
|||
|
|
[Header("导出控制")]
|
|||
|
|
[SerializeField] private TMP_Dropdown exportFormatDropdown;
|
|||
|
|
[SerializeField] private Button exportSelectedButton;
|
|||
|
|
[SerializeField] private Button exportAllButton;
|
|||
|
|
[SerializeField] private Button previewButton;
|
|||
|
|
|
|||
|
|
[Header("通用按钮")]
|
|||
|
|
public Button HomeButton;
|
|||
|
|
public Button BackButton;
|
|||
|
|
|
|||
|
|
[Header("统计信息")]
|
|||
|
|
[SerializeField] private TextMeshProUGUI totalRecordsText;
|
|||
|
|
[SerializeField] private TextMeshProUGUI totalTestTimeText;
|
|||
|
|
[SerializeField] private TextMeshProUGUI todayRecordsText;
|
|||
|
|
[SerializeField] private TextMeshProUGUI weekRecordsText;
|
|||
|
|
[SerializeField] private TextMeshProUGUI monthRecordsText;
|
|||
|
|
|
|||
|
|
[Header("状态显示")]
|
|||
|
|
[SerializeField] private TextMeshProUGUI statusText;
|
|||
|
|
// [SerializeField] private Slider progressSlider;
|
|||
|
|
// [SerializeField] private GameObject loadingPanel;
|
|||
|
|
|
|||
|
|
private List<BFITestRecord> allRecords;
|
|||
|
|
private List<BFITestRecord> filteredRecords;
|
|||
|
|
private List<BFIHistoryItem> historyItems;
|
|||
|
|
private Dictionary<string, BFIHistoryItem> historyItemsByRecordId;
|
|||
|
|
private HashSet<string> selectedRecordIds;
|
|||
|
|
private string lastExportedFilePath;
|
|||
|
|
private string lastExportFailureMessage;
|
|||
|
|
private Coroutine historyListBuildCoroutine;
|
|||
|
|
private const int HISTORY_ITEMS_PER_FRAME = 20;
|
|||
|
|
|
|||
|
|
public override void Init()
|
|||
|
|
{
|
|||
|
|
allRecords = new List<BFITestRecord>();
|
|||
|
|
filteredRecords = new List<BFITestRecord>();
|
|||
|
|
historyItems = new List<BFIHistoryItem>();
|
|||
|
|
historyItemsByRecordId = new Dictionary<string, BFIHistoryItem>();
|
|||
|
|
selectedRecordIds = new HashSet<string>();
|
|||
|
|
|
|||
|
|
InitializeUI();
|
|||
|
|
LoadHistoryRecords();
|
|||
|
|
UpdateStatistics();
|
|||
|
|
|
|||
|
|
// 订阅历史管理器事件
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
BFIHistoryManager.Instance.OnRecordAdded += OnRecordAdded;
|
|||
|
|
BFIHistoryManager.Instance.OnRecordUpdated += OnRecordUpdated;
|
|||
|
|
BFIHistoryManager.Instance.OnRecordRemoved += OnRecordRemoved;
|
|||
|
|
BFIHistoryManager.Instance.OnHistoryLoaded += OnHistoryLoaded;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnDestroy()
|
|||
|
|
{
|
|||
|
|
StopHistoryListBuildCoroutine();
|
|||
|
|
HideCustomKeyboardIfNeeded();
|
|||
|
|
|
|||
|
|
// 取消订阅事件
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
BFIHistoryManager.Instance.OnRecordAdded -= OnRecordAdded;
|
|||
|
|
BFIHistoryManager.Instance.OnRecordUpdated -= OnRecordUpdated;
|
|||
|
|
BFIHistoryManager.Instance.OnRecordRemoved -= OnRecordRemoved;
|
|||
|
|
BFIHistoryManager.Instance.OnHistoryLoaded -= OnHistoryLoaded;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void InitializeUI()
|
|||
|
|
{
|
|||
|
|
// 搜索功能
|
|||
|
|
if (searchButton != null)
|
|||
|
|
searchButton.onClick.AddListener(OnSearchClicked);
|
|||
|
|
|
|||
|
|
if (searchInputField != null)
|
|||
|
|
{
|
|||
|
|
searchInputField.onEndEdit.AddListener(OnSearchInputChanged);
|
|||
|
|
SetupSearchCustomKeyboard();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 日期过滤
|
|||
|
|
if (applyDateFilterButton != null)
|
|||
|
|
applyDateFilterButton.onClick.AddListener(OnApplyDateFilter);
|
|||
|
|
|
|||
|
|
// 选择控制
|
|||
|
|
if (selectAllToggle != null){
|
|||
|
|
selectAllToggle.onValueChanged.AddListener(OnSelectAllToggled);
|
|||
|
|
selectAllToggle.isOn = false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清空记录
|
|||
|
|
if (clearRecordButton != null)
|
|||
|
|
clearRecordButton.onClick.AddListener(OnClearClicked);
|
|||
|
|
|
|||
|
|
// 导出控制
|
|||
|
|
if (exportSelectedButton != null)
|
|||
|
|
exportSelectedButton.onClick.AddListener(OnExportSelectedClicked);
|
|||
|
|
if (exportAllButton != null)
|
|||
|
|
exportAllButton.onClick.AddListener(OnExportAllClicked);
|
|||
|
|
if (previewButton != null)
|
|||
|
|
previewButton.onClick.AddListener(OnPreviewClicked);
|
|||
|
|
|
|||
|
|
// 通用按钮
|
|||
|
|
if (HomeButton != null)
|
|||
|
|
HomeButton.onClick.AddListener(() =>
|
|||
|
|
{
|
|||
|
|
HideCustomKeyboardIfNeeded();
|
|||
|
|
ReturnToHome();
|
|||
|
|
});
|
|||
|
|
if (BackButton != null)
|
|||
|
|
BackButton.onClick.AddListener(() =>
|
|||
|
|
{
|
|||
|
|
HideCustomKeyboardIfNeeded();
|
|||
|
|
ClosePanel();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 初始化下拉菜单
|
|||
|
|
InitializeDropdowns();
|
|||
|
|
|
|||
|
|
// 设置默认日期
|
|||
|
|
if (startDateInput != null)
|
|||
|
|
startDateInput.text = DateTime.Today.AddDays(-7).ToString("yyyy-MM-dd");
|
|||
|
|
if (endDateInput != null)
|
|||
|
|
endDateInput.text = DateTime.Today.ToString("yyyy-MM-dd");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void InitializeDropdowns()
|
|||
|
|
{
|
|||
|
|
// 日期过滤下拉菜单
|
|||
|
|
if (dateFilterDropdown != null)
|
|||
|
|
{
|
|||
|
|
dateFilterDropdown.ClearOptions();
|
|||
|
|
dateFilterDropdown.AddOptions(new List<string>
|
|||
|
|
{
|
|||
|
|
"全部时间",
|
|||
|
|
"今天",
|
|||
|
|
"本周",
|
|||
|
|
"本月",
|
|||
|
|
// "自定义日期范围"
|
|||
|
|
});
|
|||
|
|
dateFilterDropdown.SetValueWithoutNotify(0);
|
|||
|
|
dateFilterDropdown.RefreshShownValue();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 导出格式下拉菜单
|
|||
|
|
if (exportFormatDropdown != null)
|
|||
|
|
{
|
|||
|
|
exportFormatDropdown.ClearOptions();
|
|||
|
|
exportFormatDropdown.AddOptions(new List<string>
|
|||
|
|
{
|
|||
|
|
"文本报告",
|
|||
|
|
"CSV数据",
|
|||
|
|
"PDF报告",
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void SetupSearchCustomKeyboard()
|
|||
|
|
{
|
|||
|
|
if (searchInputField == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (CustomKeyboardManager.Instance == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("BFI导出搜索框未找到CustomKeyboardManager,保留默认输入方式");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
CustomKeyboardManager.SetupInputField(searchInputField, searchKeyboardLayout,
|
|||
|
|
(newValue) =>
|
|||
|
|
{
|
|||
|
|
searchInputField.text = newValue;
|
|||
|
|
ApplySearch();
|
|||
|
|
},
|
|||
|
|
clearOnFirstInput: false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void HideCustomKeyboardIfNeeded()
|
|||
|
|
{
|
|||
|
|
if (CustomKeyboardManager.Instance != null && CustomKeyboardManager.Instance.IsKeyboardShowing())
|
|||
|
|
{
|
|||
|
|
CustomKeyboardManager.Instance.HideKeyboard();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<BFITestRecord> SortRecordsByRecentFirst(IEnumerable<BFITestRecord> records)
|
|||
|
|
{
|
|||
|
|
return (records ?? Enumerable.Empty<BFITestRecord>())
|
|||
|
|
.Where(record => record != null)
|
|||
|
|
.OrderByDescending(record => record.StartTime)
|
|||
|
|
.ThenByDescending(record => record.EndTime)
|
|||
|
|
.ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void LoadHistoryRecords()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
UpdateStatus("正在加载历史记录...");
|
|||
|
|
|
|||
|
|
RecoverPendingRecordingJournal();
|
|||
|
|
FlushCurrentRecordingSnapshot();
|
|||
|
|
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
allRecords = BFIHistoryManager.Instance.LoadHistoryRecordSummaries(false);
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(allRecords);
|
|||
|
|
|
|||
|
|
RefreshHistoryList();
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
|
|||
|
|
string historyPath = BFIHistoryManager.Instance.GetHistoryFilePath();
|
|||
|
|
UpdateStatus(allRecords.Count > 0
|
|||
|
|
? $"已加载 {allRecords.Count} 条历史记录"
|
|||
|
|
: $"未找到已保存的BFI历史记录");
|
|||
|
|
Debug.Log($"BFI历史索引路径: {historyPath}");
|
|||
|
|
UpdateStatistics();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
UpdateStatus("历史管理器未初始化");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"加载历史记录失败: {ex.Message}");
|
|||
|
|
UpdateStatus($"加载失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void FlushCurrentRecordingSnapshot()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var dataService = ServiceLocator.IsRegistered<IDataService>() ? ServiceLocator.Get<IDataService>() as DataService : null;
|
|||
|
|
if (dataService != null)
|
|||
|
|
{
|
|||
|
|
dataService.FlushCurrentBFIRecordingSnapshot("打开BFI数据导出界面");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DataService.Instance?.FlushCurrentBFIRecordingSnapshot("打开BFI数据导出界面");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"刷新当前BFI记录快照失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void RecoverPendingRecordingJournal()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var dataService = ServiceLocator.IsRegistered<IDataService>() ? ServiceLocator.Get<IDataService>() as DataService : null;
|
|||
|
|
if (dataService != null)
|
|||
|
|
{
|
|||
|
|
dataService.RecoverPendingBFIRecordingJournal("打开BFI数据导出界面");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DataService.Instance?.RecoverPendingBFIRecordingJournal("打开BFI数据导出界面");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"恢复待保存BFI实时日志失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void RefreshHistoryList()
|
|||
|
|
{
|
|||
|
|
StopHistoryListBuildCoroutine();
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(filteredRecords);
|
|||
|
|
if (historyItemsByRecordId == null)
|
|||
|
|
{
|
|||
|
|
historyItemsByRecordId = new Dictionary<string, BFIHistoryItem>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (historyScrollRect == null && historyListParent != null)
|
|||
|
|
{
|
|||
|
|
historyScrollRect = historyListParent.GetComponentInParent<ScrollRect>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清空现有项目
|
|||
|
|
foreach (var item in historyItems)
|
|||
|
|
{
|
|||
|
|
if (item != null && item.gameObject != null)
|
|||
|
|
Destroy(item.gameObject);
|
|||
|
|
}
|
|||
|
|
historyItems.Clear();
|
|||
|
|
historyItemsByRecordId.Clear();
|
|||
|
|
|
|||
|
|
MoveHistoryScrollToNewest();
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
historyListBuildCoroutine = StartCoroutine(BuildHistoryListGradually(filteredRecords));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private IEnumerator BuildHistoryListGradually(List<BFITestRecord> records)
|
|||
|
|
{
|
|||
|
|
var recordsToBuild = records != null ? new List<BFITestRecord>(records) : new List<BFITestRecord>();
|
|||
|
|
for (int i = 0; i < recordsToBuild.Count; i++)
|
|||
|
|
{
|
|||
|
|
CreateHistoryItem(recordsToBuild[i]);
|
|||
|
|
|
|||
|
|
if ((i + 1) % HISTORY_ITEMS_PER_FRAME == 0)
|
|||
|
|
{
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
yield return null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
historyListBuildCoroutine = null;
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
UpdateSelectAllToggle();
|
|||
|
|
MoveHistoryScrollToNewest();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void StopHistoryListBuildCoroutine()
|
|||
|
|
{
|
|||
|
|
if (historyListBuildCoroutine != null)
|
|||
|
|
{
|
|||
|
|
StopCoroutine(historyListBuildCoroutine);
|
|||
|
|
historyListBuildCoroutine = null;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void MoveHistoryScrollToNewest()
|
|||
|
|
{
|
|||
|
|
if (historyScrollRect == null)
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Canvas.ForceUpdateCanvases();
|
|||
|
|
historyScrollRect.verticalNormalizedPosition = 1f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void CreateHistoryItem(BFITestRecord record)
|
|||
|
|
{
|
|||
|
|
if (historyItemPrefab == null || historyListParent == null)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
GameObject itemObj = Instantiate(historyItemPrefab, historyListParent);
|
|||
|
|
BFIHistoryItem historyItem = itemObj.GetComponent<BFIHistoryItem>();
|
|||
|
|
|
|||
|
|
if (historyItem == null)
|
|||
|
|
historyItem = itemObj.AddComponent<BFIHistoryItem>();
|
|||
|
|
|
|||
|
|
historyItem.Initialize(record);
|
|||
|
|
historyItem.OnSelectionChanged += OnItemSelectionChanged;
|
|||
|
|
historyItem.SetSelected(selectedRecordIds.Contains(record.TestId));
|
|||
|
|
|
|||
|
|
historyItems.Add(historyItem);
|
|||
|
|
if (historyItemsByRecordId == null)
|
|||
|
|
{
|
|||
|
|
historyItemsByRecordId = new Dictionary<string, BFIHistoryItem>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!string.IsNullOrEmpty(record.TestId))
|
|||
|
|
{
|
|||
|
|
historyItemsByRecordId[record.TestId] = historyItem;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool TryUpdateVisibleHistoryItem(BFITestRecord record)
|
|||
|
|
{
|
|||
|
|
if (record == null || string.IsNullOrEmpty(record.TestId))
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int filteredIndex = filteredRecords.FindIndex(r => r != null && r.TestId == record.TestId);
|
|||
|
|
if (filteredIndex < 0)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
filteredRecords[filteredIndex] = record;
|
|||
|
|
if (historyItemsByRecordId == null)
|
|||
|
|
{
|
|||
|
|
historyItemsByRecordId = new Dictionary<string, BFIHistoryItem>();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!historyItemsByRecordId.TryGetValue(record.TestId, out var historyItem) || historyItem == null)
|
|||
|
|
{
|
|||
|
|
historyItem = historyItems.FirstOrDefault(item => item != null && item.GetRecord()?.TestId == record.TestId);
|
|||
|
|
if (historyItem == null)
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
historyItemsByRecordId[record.TestId] = historyItem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
historyItem.Initialize(record);
|
|||
|
|
historyItem.SetSelected(selectedRecordIds.Contains(record.TestId));
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
UpdateSelectAllToggle();
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnItemSelectionChanged(string recordId, bool isSelected)
|
|||
|
|
{
|
|||
|
|
if (isSelected)
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Add(recordId);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Remove(recordId);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
UpdateSelectAllToggle();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateSelectionCount()
|
|||
|
|
{
|
|||
|
|
if (selectionCountText != null)
|
|||
|
|
{
|
|||
|
|
int totalCount = filteredRecords?.Count ?? 0;
|
|||
|
|
int visibleCount = historyItems?.Count ?? 0;
|
|||
|
|
selectionCountText.text = visibleCount < totalCount
|
|||
|
|
? $"已选择: {selectedRecordIds.Count} / {totalCount}(已显示 {visibleCount})"
|
|||
|
|
: $"已选择: {selectedRecordIds.Count} / {totalCount}";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新导出按钮状态
|
|||
|
|
if (exportSelectedButton != null)
|
|||
|
|
exportSelectedButton.interactable = selectedRecordIds.Count > 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateSelectAllToggle()
|
|||
|
|
{
|
|||
|
|
if (selectAllToggle != null)
|
|||
|
|
{
|
|||
|
|
int filteredCount = filteredRecords?.Count ?? 0;
|
|||
|
|
bool allSelected = filteredCount > 0 &&
|
|||
|
|
filteredRecords.All(record => record != null && selectedRecordIds.Contains(record.TestId));
|
|||
|
|
selectAllToggle.SetIsOnWithoutNotify(allSelected);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateStatistics()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
var stats = BFIHistoryManager.Instance.GetHistoryStatistics();
|
|||
|
|
|
|||
|
|
if (totalRecordsText != null)
|
|||
|
|
totalRecordsText.text = $"总记录数: {stats.TotalRecords}";
|
|||
|
|
if (totalTestTimeText != null)
|
|||
|
|
totalTestTimeText.text = $"总测试时间: {stats.TotalTestTime:F1} 分钟";
|
|||
|
|
if (todayRecordsText != null)
|
|||
|
|
todayRecordsText.text = $"今日: {stats.TodayRecords}";
|
|||
|
|
if (weekRecordsText != null)
|
|||
|
|
weekRecordsText.text = $"本周: {stats.WeekRecords}";
|
|||
|
|
if (monthRecordsText != null)
|
|||
|
|
monthRecordsText.text = $"本月: {stats.MonthRecords}";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"更新统计信息失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#region 事件处理
|
|||
|
|
|
|||
|
|
private void OnSearchClicked()
|
|||
|
|
{
|
|||
|
|
ApplySearch();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnClearSearchClicked()
|
|||
|
|
{
|
|||
|
|
if (searchInputField != null)
|
|||
|
|
searchInputField.text = "";
|
|||
|
|
ApplySearch();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清空所有测试数据
|
|||
|
|
private void OnClearClicked()
|
|||
|
|
{
|
|||
|
|
// 显示确认对话框
|
|||
|
|
ConfirmDialog.ShowDeleteConfirm(
|
|||
|
|
"所有BFI历史记录",
|
|||
|
|
() => ClearBFIRecordData(),
|
|||
|
|
() => Debug.Log("取消清空记录")
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public void ClearBFIRecordData()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
ResetCurrentRecordingAfterClear();
|
|||
|
|
BFIHistoryManager.Instance.ClearHistory();
|
|||
|
|
Debug.Log("BFIHistoryTestHelper: 测试数据已清空");
|
|||
|
|
LoadHistoryRecords();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("BFIHistoryTestHelper: BFIHistoryManager.Instance 为空");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"BFIHistoryTestHelper: 清空测试数据失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ResetCurrentRecordingAfterClear()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
var dataService = ServiceLocator.IsRegistered<IDataService>() ? ServiceLocator.Get<IDataService>() as DataService : null;
|
|||
|
|
if (dataService != null)
|
|||
|
|
{
|
|||
|
|
dataService.ResetCurrentBFIRecordingAfterHistoryClear("清空BFI历史记录");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
DataService.Instance?.ResetCurrentBFIRecordingAfterHistoryClear("清空BFI历史记录");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"清空后重置当前BFI记录失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnSearchInputChanged(string searchText)
|
|||
|
|
{
|
|||
|
|
ApplySearch();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplySearch()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string searchText = searchInputField?.text ?? "";
|
|||
|
|
|
|||
|
|
if (string.IsNullOrEmpty(searchText))
|
|||
|
|
{
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(allRecords);
|
|||
|
|
}
|
|||
|
|
else if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(BFIHistoryManager.Instance.SearchRecords(searchText));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
RefreshHistoryList();
|
|||
|
|
UpdateStatus($"搜索结果: {filteredRecords.Count} 条记录");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"搜索失败: {ex.Message}");
|
|||
|
|
UpdateStatus($"搜索失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnApplyDateFilter()
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
int filterIndex = dateFilterDropdown?.value ?? 0;
|
|||
|
|
DateTime startDate, endDate;
|
|||
|
|
|
|||
|
|
switch (filterIndex)
|
|||
|
|
{
|
|||
|
|
case 0: // 全部时间
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(allRecords);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 1: // 今天
|
|||
|
|
startDate = DateTime.Today;
|
|||
|
|
endDate = DateTime.Today.AddDays(1);
|
|||
|
|
ApplyDateRangeFilter(startDate, endDate);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 2: // 本周
|
|||
|
|
startDate = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
|
|||
|
|
endDate = startDate.AddDays(7);
|
|||
|
|
ApplyDateRangeFilter(startDate, endDate);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 3: // 本月
|
|||
|
|
startDate = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
|
|||
|
|
endDate = startDate.AddMonths(1);
|
|||
|
|
ApplyDateRangeFilter(startDate, endDate);
|
|||
|
|
break;
|
|||
|
|
|
|||
|
|
case 4: // 自定义日期范围
|
|||
|
|
if (DateTime.TryParse(startDateInput?.text, out startDate) &&
|
|||
|
|
DateTime.TryParse(endDateInput?.text, out endDate))
|
|||
|
|
{
|
|||
|
|
ApplyDateRangeFilter(startDate, endDate.AddDays(1));
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
UpdateStatus("日期格式错误");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
RefreshHistoryList();
|
|||
|
|
UpdateStatus($"过滤结果: {filteredRecords.Count} 条记录");
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"日期过滤失败: {ex.Message}");
|
|||
|
|
UpdateStatus($"过滤失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyDateRangeFilter(DateTime startDate, DateTime endDate)
|
|||
|
|
{
|
|||
|
|
if (BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
filteredRecords = SortRecordsByRecentFirst(BFIHistoryManager.Instance.GetRecordsByDateRange(startDate, endDate));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnSelectAllToggled(bool isOn)
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Clear();
|
|||
|
|
|
|||
|
|
if (isOn)
|
|||
|
|
{
|
|||
|
|
foreach (var record in filteredRecords)
|
|||
|
|
{
|
|||
|
|
if (record != null && !string.IsNullOrEmpty(record.TestId))
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Add(record.TestId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 更新所有项目的选择状态
|
|||
|
|
foreach (var item in historyItems)
|
|||
|
|
{
|
|||
|
|
if (item != null)
|
|||
|
|
{
|
|||
|
|
item.SetSelected(isOn);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnSelectTodayClicked()
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Clear();
|
|||
|
|
|
|||
|
|
var today = DateTime.Today;
|
|||
|
|
foreach (var record in filteredRecords)
|
|||
|
|
{
|
|||
|
|
if (record.StartTime.Date == today)
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Add(record.TestId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateItemSelections();
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnSelectWeekClicked()
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Clear();
|
|||
|
|
|
|||
|
|
var weekStart = DateTime.Today.AddDays(-(int)DateTime.Today.DayOfWeek);
|
|||
|
|
foreach (var record in filteredRecords)
|
|||
|
|
{
|
|||
|
|
if (record.StartTime >= weekStart)
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Add(record.TestId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateItemSelections();
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnClearSelectionClicked()
|
|||
|
|
{
|
|||
|
|
selectedRecordIds.Clear();
|
|||
|
|
|
|||
|
|
foreach (var item in historyItems)
|
|||
|
|
{
|
|||
|
|
item.SetSelected(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
if (selectAllToggle != null)
|
|||
|
|
selectAllToggle.SetIsOnWithoutNotify(false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateItemSelections()
|
|||
|
|
{
|
|||
|
|
foreach (var item in historyItems)
|
|||
|
|
{
|
|||
|
|
if (item == null || item.GetRecord() == null)
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool isSelected = selectedRecordIds.Contains(item.GetRecord().TestId);
|
|||
|
|
item.SetSelected(isSelected);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateSelectAllToggle();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnExportSelectedClicked()
|
|||
|
|
{
|
|||
|
|
if (selectedRecordIds.Count == 0)
|
|||
|
|
{
|
|||
|
|
UpdateStatus("请先选择要导出的记录");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ExportRecords(selectedRecordIds.ToList());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnExportAllClicked()
|
|||
|
|
{
|
|||
|
|
var allIds = filteredRecords.Select(r => r.TestId).ToList();
|
|||
|
|
ExportRecords(allIds);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnPreviewClicked()
|
|||
|
|
{
|
|||
|
|
// 显示导出预览
|
|||
|
|
if (selectedRecordIds.Count > 0)
|
|||
|
|
{
|
|||
|
|
ShowExportPreview(selectedRecordIds.ToList());
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
UpdateStatus("请先选择要预览的记录");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 导出功能
|
|||
|
|
|
|||
|
|
private async void ExportRecords(List<string> recordIds)
|
|||
|
|
{
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
UpdateStatus("正在准备导出...");
|
|||
|
|
lastExportedFilePath = null;
|
|||
|
|
lastExportFailureMessage = null;
|
|||
|
|
|
|||
|
|
var selectedRecords = new List<BFITestRecord>();
|
|||
|
|
foreach (var id in recordIds)
|
|||
|
|
{
|
|||
|
|
var record = BFIHistoryManager.Instance != null
|
|||
|
|
? BFIHistoryManager.Instance.GetFullRecord(id)
|
|||
|
|
: allRecords.FirstOrDefault(r => r.TestId == id);
|
|||
|
|
if (record != null)
|
|||
|
|
{
|
|||
|
|
selectedRecords.Add(record);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (selectedRecords.Count == 0)
|
|||
|
|
{
|
|||
|
|
UpdateStatus("没有找到可导出的记录");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取导出格式
|
|||
|
|
ExportFormat format = GetSelectedExportFormat();
|
|||
|
|
|
|||
|
|
UpdateStatus($"正在导出 {selectedRecords.Count} 条记录...");
|
|||
|
|
|
|||
|
|
// 执行导出
|
|||
|
|
bool success = await ExportRecordsAsync(selectedRecords, format);
|
|||
|
|
|
|||
|
|
if (success)
|
|||
|
|
{
|
|||
|
|
UpdateStatus($"导出成功!已导出 {selectedRecords.Count} 条记录");
|
|||
|
|
ShowExportSuccessDialog(selectedRecords.Count, format, lastExportedFilePath);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
string failureMessage = string.IsNullOrEmpty(lastExportFailureMessage)
|
|||
|
|
? "导出失败,请检查U盘、存储空间和权限"
|
|||
|
|
: lastExportFailureMessage;
|
|||
|
|
UpdateStatus(failureMessage);
|
|||
|
|
ShowExportFailureDialog(failureMessage);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"导出失败: {ex.Message}");
|
|||
|
|
UpdateStatus("导出失败");
|
|||
|
|
ShowExportFailureDialog($"导出失败: {ex.Message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private ExportFormat GetSelectedExportFormat()
|
|||
|
|
{
|
|||
|
|
int formatIndex = exportFormatDropdown?.value ?? 0;
|
|||
|
|
return (ExportFormat)formatIndex;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private async System.Threading.Tasks.Task<bool> ExportRecordsAsync(List<BFITestRecord> records, ExportFormat format)
|
|||
|
|
{
|
|||
|
|
await System.Threading.Tasks.Task.Yield();
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
records = EnsureFullRecordsForExport(records);
|
|||
|
|
if (records == null || records.Count == 0)
|
|||
|
|
{
|
|||
|
|
if (string.IsNullOrEmpty(lastExportFailureMessage))
|
|||
|
|
{
|
|||
|
|
lastExportFailureMessage = "没有找到可导出的完整BFI记录";
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var exportService = new DataExportService();
|
|||
|
|
int totalPointCount = records.Sum(record => record?.DataPoints?.Count ?? 0);
|
|||
|
|
Debug.Log($"BFI导出完整记录准备完成: 记录数={records.Count}, 数据点={totalPointCount}, 格式={format}");
|
|||
|
|
Debug.Log("BFI导出开始检查U盘目录授权");
|
|||
|
|
|
|||
|
|
// 先做权限和目录可用性检查,避免仅返回通用失败文案
|
|||
|
|
if (!exportService.CheckExportPermissions())
|
|||
|
|
{
|
|||
|
|
string errorMessage = exportService.GetLastErrorMessage();
|
|||
|
|
Debug.LogWarning($"导出权限检查未通过,原因: {errorMessage}");
|
|||
|
|
if (!string.IsNullOrEmpty(errorMessage))
|
|||
|
|
{
|
|||
|
|
lastExportFailureMessage = errorMessage;
|
|||
|
|
UpdateStatus(errorMessage);
|
|||
|
|
}
|
|||
|
|
lastExportedFilePath = null;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool success = exportService.ExportHistoryRecords(records, format);
|
|||
|
|
lastExportedFilePath = success ? exportService.GetLastExportedFilePath() : null;
|
|||
|
|
|
|||
|
|
if (!success)
|
|||
|
|
{
|
|||
|
|
string errorMessage = exportService.GetLastErrorMessage();
|
|||
|
|
Debug.LogWarning($"导出服务返回失败,格式: {format},原因: {errorMessage}");
|
|||
|
|
if (!string.IsNullOrEmpty(errorMessage))
|
|||
|
|
{
|
|||
|
|
lastExportFailureMessage = errorMessage;
|
|||
|
|
UpdateStatus(errorMessage);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 记录导出操作日志
|
|||
|
|
if (success)
|
|||
|
|
{
|
|||
|
|
var authService = ServiceLocator.Get<IAuthenticationService>();
|
|||
|
|
var logService = ServiceLocator.Get<UserLogService>();
|
|||
|
|
|
|||
|
|
// 统计导出信息
|
|||
|
|
string patientNames = string.Join(", ", records.Select(r => r.PatientName).Distinct().Take(3));
|
|||
|
|
if (records.Select(r => r.PatientName).Distinct().Count() > 3)
|
|||
|
|
patientNames += "等";
|
|||
|
|
|
|||
|
|
logService?.LogUserOperation(
|
|||
|
|
authService?.CurrentUsername ?? "system",
|
|||
|
|
"导出BFI历史记录",
|
|||
|
|
$"导出{records.Count}条记录, 格式: {format}, 患者: {patientNames}",
|
|||
|
|
true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return success;
|
|||
|
|
}
|
|||
|
|
catch (Exception ex)
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"异步导出失败: {ex.Message}");
|
|||
|
|
lastExportFailureMessage = $"导出失败: {ex.Message}";
|
|||
|
|
|
|||
|
|
// 记录导出失败日志
|
|||
|
|
var authService = ServiceLocator.Get<IAuthenticationService>();
|
|||
|
|
var logService = ServiceLocator.Get<UserLogService>();
|
|||
|
|
logService?.LogUserOperation(
|
|||
|
|
authService?.CurrentUsername ?? "system",
|
|||
|
|
"导出BFI历史记录",
|
|||
|
|
$"失败: {ex.Message}",
|
|||
|
|
false);
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private List<BFITestRecord> EnsureFullRecordsForExport(List<BFITestRecord> records)
|
|||
|
|
{
|
|||
|
|
var fullRecords = new List<BFITestRecord>();
|
|||
|
|
var missingDetailRecords = new List<string>();
|
|||
|
|
if (records == null)
|
|||
|
|
{
|
|||
|
|
return fullRecords;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (var record in records)
|
|||
|
|
{
|
|||
|
|
if (record == null)
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
BFITestRecord fullRecord = record;
|
|||
|
|
bool needsFullRecord = record.DataPoints == null || record.DataPoints.Count == 0;
|
|||
|
|
if (needsFullRecord && BFIHistoryManager.Instance != null)
|
|||
|
|
{
|
|||
|
|
fullRecord = BFIHistoryManager.Instance.GetFullRecord(record.TestId) ?? record;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fullRecord.DataPoints == null || fullRecord.DataPoints.Count == 0)
|
|||
|
|
{
|
|||
|
|
string displayName = string.IsNullOrEmpty(fullRecord.TestName) ? fullRecord.TestId : fullRecord.TestName;
|
|||
|
|
missingDetailRecords.Add(displayName);
|
|||
|
|
Debug.LogWarning($"BFI导出记录缺少明细数据: {fullRecord.TestName}, ID: {fullRecord.TestId}, 文件: {fullRecord.FilePath}");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
fullRecords.Add(fullRecord);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (missingDetailRecords.Count > 0)
|
|||
|
|
{
|
|||
|
|
string names = string.Join("、", missingDetailRecords.Take(3));
|
|||
|
|
if (missingDetailRecords.Count > 3)
|
|||
|
|
{
|
|||
|
|
names += "等";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lastExportFailureMessage = $"所选记录中有 {missingDetailRecords.Count} 条缺少BFI明细数据,无法导出:{names}";
|
|||
|
|
fullRecords.Clear();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return fullRecords;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ShowExportPreview(List<string> recordIds)
|
|||
|
|
{
|
|||
|
|
// 实现导出预览功能
|
|||
|
|
// 这里可以显示一个预览窗口,显示将要导出的数据
|
|||
|
|
UpdateStatus($"预览 {recordIds.Count} 条记录的导出内容");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ShowExportSuccessDialog(int recordCount, ExportFormat format, string filePath)
|
|||
|
|
{
|
|||
|
|
string message = $"已成功导出 {recordCount} 条BFI历史记录\n导出格式: {GetExportFormatDisplayName(format)}";
|
|||
|
|
if (!string.IsNullOrEmpty(filePath))
|
|||
|
|
{
|
|||
|
|
message += $"\n文件路径: {filePath}";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
ConfirmDialog.Show("导出成功", message, () => { }, null, "确认", "取消", false, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ShowExportFailureDialog(string message)
|
|||
|
|
{
|
|||
|
|
ConfirmDialog.Show("导出失败", message, () => { }, null, "确认", "取消", true, false);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private string GetExportFormatDisplayName(ExportFormat format)
|
|||
|
|
{
|
|||
|
|
switch (format)
|
|||
|
|
{
|
|||
|
|
case ExportFormat.CSV:
|
|||
|
|
return "CSV数据";
|
|||
|
|
case ExportFormat.PDF:
|
|||
|
|
return "PDF报告";
|
|||
|
|
case ExportFormat.TXT:
|
|||
|
|
default:
|
|||
|
|
return "文本报告";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region 历史管理器事件
|
|||
|
|
|
|||
|
|
private void OnRecordAdded(BFITestRecord record)
|
|||
|
|
{
|
|||
|
|
allRecords.Add(record);
|
|||
|
|
ApplyCurrentFilter();
|
|||
|
|
UpdateStatistics();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnRecordUpdated(BFITestRecord record)
|
|||
|
|
{
|
|||
|
|
var existingRecord = allRecords.FirstOrDefault(r => r.TestId == record.TestId);
|
|||
|
|
if (existingRecord != null)
|
|||
|
|
{
|
|||
|
|
int index = allRecords.IndexOf(existingRecord);
|
|||
|
|
allRecords[index] = record;
|
|||
|
|
if (!TryUpdateVisibleHistoryItem(record))
|
|||
|
|
{
|
|||
|
|
// 记录当前不可见时不重建列表;搜索/筛选操作会重新计算可见集合。
|
|||
|
|
UpdateSelectionCount();
|
|||
|
|
UpdateSelectAllToggle();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnRecordRemoved(string recordId)
|
|||
|
|
{
|
|||
|
|
allRecords.RemoveAll(r => r.TestId == recordId);
|
|||
|
|
selectedRecordIds.Remove(recordId);
|
|||
|
|
ApplyCurrentFilter();
|
|||
|
|
UpdateStatistics();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnHistoryLoaded()
|
|||
|
|
{
|
|||
|
|
LoadHistoryRecords();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ApplyCurrentFilter()
|
|||
|
|
{
|
|||
|
|
// 重新应用当前的搜索和过滤条件
|
|||
|
|
ApplySearch();
|
|||
|
|
OnApplyDateFilter();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
|
|||
|
|
#region UI辅助方法
|
|||
|
|
|
|||
|
|
private void UpdateStatus(string message)
|
|||
|
|
{
|
|||
|
|
if (statusText != null)
|
|||
|
|
{
|
|||
|
|
statusText.text = message;
|
|||
|
|
Debug.Log($"状态更新: {message}");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#endregion
|
|||
|
|
}
|