433 lines
13 KiB
C#
433 lines
13 KiB
C#
|
|
using System.Collections;
|
|||
|
|
using System.Collections.Generic;
|
|||
|
|
using System.Linq;
|
|||
|
|
using TMPro;
|
|||
|
|
using UnityEngine;
|
|||
|
|
using UnityEngine.UI;
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 用户使用日志面板
|
|||
|
|
/// 显示和管理用户操作日志记录
|
|||
|
|
/// </summary>
|
|||
|
|
public class UseLogPanel : BasePanel
|
|||
|
|
{
|
|||
|
|
[Header("滚动列表")]
|
|||
|
|
public ScrollableListView UseLogListView;
|
|||
|
|
|
|||
|
|
[Header("操作按钮")]
|
|||
|
|
public Button HomeButton;
|
|||
|
|
public Button BackButton;
|
|||
|
|
public Button RefreshButton; // 刷新按钮
|
|||
|
|
public Button ClearButton; // 清空记录按钮
|
|||
|
|
public Button ExportButton; // 导出按钮
|
|||
|
|
|
|||
|
|
[Header("状态显示")]
|
|||
|
|
public TextMeshProUGUI StatusText; // 状态文本
|
|||
|
|
public TextMeshProUGUI RecordCountText; // 记录数量文本
|
|||
|
|
|
|||
|
|
[Header("筛选选项")]
|
|||
|
|
public TMP_Dropdown LogTypeDropdown; // 日志类型筛选
|
|||
|
|
public TMP_InputField UserFilterInput; // 用户筛选
|
|||
|
|
public Button FilterButton; // 筛选按钮
|
|||
|
|
|
|||
|
|
private UserLogService _userLogService;
|
|||
|
|
private IAuthenticationService _authService;
|
|||
|
|
private List<UseLogEvent> _currentLogs = new List<UseLogEvent>();
|
|||
|
|
|
|||
|
|
// 自动刷新相关
|
|||
|
|
private const int MAX_DISPLAY_RECORDS = 500; // 最多显示500条记录
|
|||
|
|
private const float AUTO_REFRESH_INTERVAL = 15f; // 自动刷新间隔(秒)
|
|||
|
|
private Coroutine _autoRefreshCoroutine;
|
|||
|
|
|
|||
|
|
public override void Init()
|
|||
|
|
{
|
|||
|
|
_userLogService = ServiceLocator.Get<UserLogService>();
|
|||
|
|
_authService = ServiceLocator.Get<IAuthenticationService>();
|
|||
|
|
if (_userLogService == null)
|
|||
|
|
{
|
|||
|
|
_userLogService = new UserLogService();
|
|||
|
|
ServiceLocator.Register(_userLogService);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
InitializeUI();
|
|||
|
|
Populate();
|
|||
|
|
|
|||
|
|
// 启动自动刷新
|
|||
|
|
_autoRefreshCoroutine = StartCoroutine(AutoRefreshCoroutine());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void InitializeUI()
|
|||
|
|
{
|
|||
|
|
if (HomeButton != null)
|
|||
|
|
HomeButton.onClick.AddListener(() =>
|
|||
|
|
{
|
|||
|
|
ConfirmDialog.Show("确认", "是否返回主界面?", () =>
|
|||
|
|
{
|
|||
|
|
ReturnToHome();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (BackButton != null)
|
|||
|
|
BackButton.onClick.AddListener(() =>
|
|||
|
|
ConfirmDialog.Show("确认", "是否返回设置界面?", () =>
|
|||
|
|
{
|
|||
|
|
ClosePanel();
|
|||
|
|
ClosePanel();
|
|||
|
|
})
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
// 刷新按钮已取消,改为自动刷新
|
|||
|
|
if (RefreshButton != null)
|
|||
|
|
RefreshButton.gameObject.SetActive(false);
|
|||
|
|
|
|||
|
|
if (ClearButton != null)
|
|||
|
|
ClearButton.onClick.AddListener(OnClearClicked);
|
|||
|
|
|
|||
|
|
if (ExportButton != null)
|
|||
|
|
ExportButton.onClick.AddListener(OnExportClicked);
|
|||
|
|
|
|||
|
|
if (FilterButton != null)
|
|||
|
|
FilterButton.onClick.AddListener(OnFilterClicked);
|
|||
|
|
|
|||
|
|
// 设置用户筛选输入框的自定义键盘
|
|||
|
|
if (UserFilterInput != null)
|
|||
|
|
{
|
|||
|
|
CustomKeyboardManager.SetupInputField(UserFilterInput, KeyboardLayout.Default,
|
|||
|
|
(newValue) =>
|
|||
|
|
{
|
|||
|
|
UserFilterInput.text = newValue;
|
|||
|
|
},
|
|||
|
|
clearOnFirstInput: false); // 筛选输入不需要清空
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化筛选下拉框
|
|||
|
|
if (LogTypeDropdown != null)
|
|||
|
|
{
|
|||
|
|
LogTypeDropdown.ClearOptions();
|
|||
|
|
LogTypeDropdown.AddOptions(new List<string>
|
|||
|
|
{
|
|||
|
|
"全部日志", "用户日志", "系统日志", "登录日志", "操作日志"
|
|||
|
|
});
|
|||
|
|
LogTypeDropdown.value = 0;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
SetStatus("正在加载用户操作日志...", true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
private void SetStatus(string message, bool isSuccess)
|
|||
|
|
{
|
|||
|
|
if (StatusText != null)
|
|||
|
|
{
|
|||
|
|
StatusText.text = message;
|
|||
|
|
StatusText.color = isSuccess ? Color.green : Color.red;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void UpdateRecordCount(int count)
|
|||
|
|
{
|
|||
|
|
if (RecordCountText != null)
|
|||
|
|
{
|
|||
|
|
RecordCountText.text = $"共 {count} 条记录";
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 自动刷新协程
|
|||
|
|
/// </summary>
|
|||
|
|
private IEnumerator AutoRefreshCoroutine()
|
|||
|
|
{
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
yield return new WaitForSeconds(AUTO_REFRESH_INTERVAL);
|
|||
|
|
|
|||
|
|
// 只有在面板激活时才刷新
|
|||
|
|
if (gameObject.activeInHierarchy)
|
|||
|
|
{
|
|||
|
|
Populate();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnClearClicked()
|
|||
|
|
{
|
|||
|
|
// 显示确认对话框
|
|||
|
|
ConfirmDialog.ShowDeleteConfirm(
|
|||
|
|
"所有用户操作日志",
|
|||
|
|
() => ClearAllRecords(),
|
|||
|
|
() => Debug.Log("取消清空记录")
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void ClearAllRecords()
|
|||
|
|
{
|
|||
|
|
if (_userLogService != null)
|
|||
|
|
{
|
|||
|
|
// 根据当前筛选类型清空不同的日志
|
|||
|
|
if (LogTypeDropdown != null)
|
|||
|
|
{
|
|||
|
|
switch (LogTypeDropdown.value)
|
|||
|
|
{
|
|||
|
|
case 1: // 用户日志
|
|||
|
|
_userLogService.ClearUserLogs();
|
|||
|
|
break;
|
|||
|
|
case 2: // 系统日志
|
|||
|
|
_userLogService.ClearSystemLogs();
|
|||
|
|
break;
|
|||
|
|
default: // 全部日志
|
|||
|
|
_userLogService.ClearAllLogs();
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
_userLogService.ClearAllLogs();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 清空UI显示
|
|||
|
|
if (UseLogListView != null)
|
|||
|
|
{
|
|||
|
|
UseLogListView.ClearItems();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_currentLogs.Clear();
|
|||
|
|
UpdateRecordCount(0);
|
|||
|
|
SetStatus("记录已清空", true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void Populate()
|
|||
|
|
{
|
|||
|
|
if (_userLogService == null)
|
|||
|
|
{
|
|||
|
|
SetStatus("日志服务不可用", false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 获取系统日志(保持向后兼容)
|
|||
|
|
var systemLogs = _userLogService.GetAllSystemLogs();
|
|||
|
|
|
|||
|
|
// 也可以将用户日志转换为系统日志格式显示
|
|||
|
|
var userLogs = _userLogService.GetAllUserLogs();
|
|||
|
|
foreach (var userLog in userLogs)
|
|||
|
|
{
|
|||
|
|
var systemLog = new UseLogEvent
|
|||
|
|
{
|
|||
|
|
Id = userLog.Id,
|
|||
|
|
Account = userLog.Username,
|
|||
|
|
OperationContentText = $"{userLog.Operation}: {userLog.OperationDetails ?? ""}",
|
|||
|
|
Time = userLog.Timestamp
|
|||
|
|
};
|
|||
|
|
systemLogs.Add(systemLog);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按时间排序,最新的在后面
|
|||
|
|
systemLogs.Sort((a, b) => a.Time.CompareTo(b.Time));
|
|||
|
|
|
|||
|
|
// 限制最多显示500条记录
|
|||
|
|
if (systemLogs.Count > MAX_DISPLAY_RECORDS)
|
|||
|
|
{
|
|||
|
|
systemLogs = systemLogs.Take(MAX_DISPLAY_RECORDS).ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_currentLogs = systemLogs;
|
|||
|
|
|
|||
|
|
// 优先使用新的ScrollableListView
|
|||
|
|
if (UseLogListView != null)
|
|||
|
|
{
|
|||
|
|
PopulateWithScrollableList(_currentLogs);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateRecordCount(_currentLogs.Count);
|
|||
|
|
SetStatus($"成功加载 {_currentLogs.Count} 条记录", true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void PopulateWithScrollableList(IReadOnlyList<UseLogEvent> records)
|
|||
|
|
{
|
|||
|
|
UseLogListView.ClearItems();
|
|||
|
|
|
|||
|
|
for (int i = 0; i < records.Count; i++)
|
|||
|
|
{
|
|||
|
|
var evt = records[i];
|
|||
|
|
var listItem = UseLogListView.AddItem(evt);
|
|||
|
|
if (listItem != null)
|
|||
|
|
{
|
|||
|
|
var uselogItem = listItem.gameObject.GetComponent<UseLogItem>();
|
|||
|
|
if (uselogItem != null)
|
|||
|
|
{
|
|||
|
|
uselogItem.Initialize(evt, i + 1);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 滚动到底部显示最新记录
|
|||
|
|
UseLogListView.ScrollToBottom();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 导出日志按钮点击事件
|
|||
|
|
/// </summary>
|
|||
|
|
private void OnExportClicked(){
|
|||
|
|
InputDialog.Show("验证身份",
|
|||
|
|
$"请输入管理者密码:",
|
|||
|
|
"",
|
|||
|
|
(password) => {
|
|||
|
|
if (_authService.ValidCurrentPassword(password)){
|
|||
|
|
ExportUseLogs();
|
|||
|
|
}else{
|
|||
|
|
SetStatus("密码错误", false);
|
|||
|
|
// ClosePanel();
|
|||
|
|
}
|
|||
|
|
},
|
|||
|
|
ClosePanel, true); // 密码模式
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 导出日志
|
|||
|
|
/// </summary>
|
|||
|
|
private void ExportUseLogs()
|
|||
|
|
{
|
|||
|
|
if (_userLogService == null)
|
|||
|
|
{
|
|||
|
|
SetStatus("日志服务不可用", false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
try
|
|||
|
|
{
|
|||
|
|
string exportPath = _userLogService.GetLogFilePath();
|
|||
|
|
SetStatus($"日志文件路径: {exportPath}", true);
|
|||
|
|
|
|||
|
|
// 可以在这里添加更多导出功能,比如复制到剪贴板或生成CSV等
|
|||
|
|
Debug.Log($"日志文件导出路径: {exportPath}");
|
|||
|
|
}
|
|||
|
|
catch (System.Exception ex)
|
|||
|
|
{
|
|||
|
|
SetStatus($"导出失败: {ex.Message}", false);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 筛选按钮点击事件
|
|||
|
|
/// </summary>
|
|||
|
|
private void OnFilterClicked()
|
|||
|
|
{
|
|||
|
|
ApplyFilter();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// <summary>
|
|||
|
|
/// 应用筛选条件
|
|||
|
|
/// </summary>
|
|||
|
|
private void ApplyFilter()
|
|||
|
|
{
|
|||
|
|
if (_userLogService == null)
|
|||
|
|
{
|
|||
|
|
SetStatus("日志服务不可用", false);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var filteredLogs = new List<UseLogEvent>();
|
|||
|
|
|
|||
|
|
// 根据日志类型筛选
|
|||
|
|
if (LogTypeDropdown != null)
|
|||
|
|
{
|
|||
|
|
switch (LogTypeDropdown.value)
|
|||
|
|
{
|
|||
|
|
case 1: // 用户日志
|
|||
|
|
var userLogs = _userLogService.GetAllUserLogs();
|
|||
|
|
foreach (var userLog in userLogs)
|
|||
|
|
{
|
|||
|
|
filteredLogs.Add(new UseLogEvent
|
|||
|
|
{
|
|||
|
|
Id = userLog.Id,
|
|||
|
|
Account = userLog.Username,
|
|||
|
|
OperationContentText = $"{userLog.Operation}: {userLog.OperationDetails ?? ""}",
|
|||
|
|
Time = userLog.Timestamp
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 2: // 系统日志
|
|||
|
|
filteredLogs.AddRange(_userLogService.GetAllSystemLogs());
|
|||
|
|
break;
|
|||
|
|
case 3: // 登录日志
|
|||
|
|
var loginLogs = _userLogService.GetLogsByOperation("登录");
|
|||
|
|
foreach (var loginLog in loginLogs)
|
|||
|
|
{
|
|||
|
|
filteredLogs.Add(new UseLogEvent
|
|||
|
|
{
|
|||
|
|
Id = loginLog.Id,
|
|||
|
|
Account = loginLog.Username,
|
|||
|
|
OperationContentText = $"{loginLog.Operation}: {loginLog.OperationDetails ?? ""}",
|
|||
|
|
Time = loginLog.Timestamp
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
case 4: // 操作日志(排除登录登出)
|
|||
|
|
var operationLogs = _userLogService.GetAllUserLogs()
|
|||
|
|
.Where(log => !log.Operation.Contains("登录") && !log.Operation.Contains("登出"))
|
|||
|
|
.ToList();
|
|||
|
|
foreach (var opLog in operationLogs)
|
|||
|
|
{
|
|||
|
|
filteredLogs.Add(new UseLogEvent
|
|||
|
|
{
|
|||
|
|
Id = opLog.Id,
|
|||
|
|
Account = opLog.Username,
|
|||
|
|
OperationContentText = $"{opLog.Operation}: {opLog.OperationDetails ?? ""}",
|
|||
|
|
Time = opLog.Timestamp
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
break;
|
|||
|
|
default: // 全部日志
|
|||
|
|
Populate();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 根据用户名筛选
|
|||
|
|
if (UserFilterInput != null && !string.IsNullOrEmpty(UserFilterInput.text))
|
|||
|
|
{
|
|||
|
|
string userFilter = UserFilterInput.text.ToLower();
|
|||
|
|
filteredLogs = filteredLogs.Where(log =>
|
|||
|
|
log.Account.ToLower().Contains(userFilter)).ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 按时间排序,最新的在后面
|
|||
|
|
filteredLogs.Sort((a, b) => a.Time.CompareTo(b.Time));
|
|||
|
|
|
|||
|
|
// 限制最多显示500条记录
|
|||
|
|
if (filteredLogs.Count > MAX_DISPLAY_RECORDS)
|
|||
|
|
{
|
|||
|
|
filteredLogs = filteredLogs.Take(MAX_DISPLAY_RECORDS).ToList();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_currentLogs = filteredLogs;
|
|||
|
|
|
|||
|
|
// 更新UI显示
|
|||
|
|
if (UseLogListView != null)
|
|||
|
|
{
|
|||
|
|
PopulateWithScrollableList(_currentLogs);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
UpdateRecordCount(_currentLogs.Count);
|
|||
|
|
SetStatus($"筛选完成,显示 {_currentLogs.Count} 条记录", true);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void OnDestroy()
|
|||
|
|
{
|
|||
|
|
// 停止自动刷新协程
|
|||
|
|
if (_autoRefreshCoroutine != null)
|
|||
|
|
{
|
|||
|
|
StopCoroutine(_autoRefreshCoroutine);
|
|||
|
|
}
|
|||
|
|
// 关闭自定义键盘(如果正在显示)
|
|||
|
|
if (CustomKeyboardManager.Instance != null && CustomKeyboardManager.Instance.IsKeyboardShowing())
|
|||
|
|
{
|
|||
|
|
CustomKeyboardManager.Instance.HideKeyboard();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|