471 lines
15 KiB
C#
471 lines
15 KiB
C#
|
|
using System.Collections;
|
||
|
|
using System.Collections.Generic;
|
||
|
|
using TMPro;
|
||
|
|
using UnityEngine;
|
||
|
|
using UnityEngine.UI;
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 用户管理面板
|
||
|
|
/// 提供用户的增删改查功能,仅管理员可访问
|
||
|
|
/// </summary>
|
||
|
|
public class UserManagementPanel : BasePanel
|
||
|
|
{
|
||
|
|
[Header("用户列表")]
|
||
|
|
public Transform UserListParent; // 用户列表的父对象
|
||
|
|
public GameObject UserItemPrefab; // 用户项预制体
|
||
|
|
public ScrollRect UserScrollRect; // 滚动区域
|
||
|
|
|
||
|
|
[Header("添加用户")]
|
||
|
|
public TMP_InputField NewUsernameInput; // 新用户名输入
|
||
|
|
public TMP_InputField NewPasswordInput; // 新密码输入
|
||
|
|
public TMP_Dropdown NewRoleDropdown; // 角色选择下拉框
|
||
|
|
public Button AddUserButton; // 添加用户按钮
|
||
|
|
|
||
|
|
[Header("操作按钮")]
|
||
|
|
public Button RefreshButton; // 刷新按钮
|
||
|
|
public Button HomeButton; // 主页按钮
|
||
|
|
public Button BackButton; // 返回按钮
|
||
|
|
|
||
|
|
[Header("状态显示")]
|
||
|
|
public TextMeshProUGUI StatusText; // 状态文本
|
||
|
|
public TextMeshProUGUI TotalCountText; // 总用户数显示
|
||
|
|
|
||
|
|
private IAuthenticationService _authService;
|
||
|
|
private List<UserInfo> _currentUsers = new List<UserInfo>();
|
||
|
|
private List<GameObject> _userItemObjects = new List<GameObject>();
|
||
|
|
|
||
|
|
public override void Init()
|
||
|
|
{
|
||
|
|
_authService = ServiceLocator.Get<IAuthenticationService>();
|
||
|
|
|
||
|
|
// 检查权限
|
||
|
|
if (_authService.CurrentRole != UserRole.Admin)
|
||
|
|
{
|
||
|
|
SetStatus("权限不足:只有管理员可以访问用户管理", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
InitializeUI();
|
||
|
|
LoadUserList();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void InitializeUI()
|
||
|
|
{
|
||
|
|
// 初始化角色下拉框
|
||
|
|
if (NewRoleDropdown != null)
|
||
|
|
{
|
||
|
|
NewRoleDropdown.ClearOptions();
|
||
|
|
NewRoleDropdown.AddOptions(new List<string> { "普通用户", "管理员" });
|
||
|
|
NewRoleDropdown.value = 0; // 默认选择普通用户
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置密码输入框为密码模式
|
||
|
|
if (NewPasswordInput != null)
|
||
|
|
{
|
||
|
|
NewPasswordInput.contentType = TMP_InputField.ContentType.Password;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置按钮事件
|
||
|
|
if (AddUserButton != null)
|
||
|
|
{
|
||
|
|
AddUserButton.onClick.AddListener(OnAddUserClicked);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (RefreshButton != null)
|
||
|
|
{
|
||
|
|
RefreshButton.onClick.AddListener(LoadUserList);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (HomeButton != null)
|
||
|
|
{
|
||
|
|
HomeButton.onClick.AddListener(() =>
|
||
|
|
{
|
||
|
|
ReturnToHome();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
if (BackButton != null)
|
||
|
|
{
|
||
|
|
BackButton.onClick.AddListener(() =>
|
||
|
|
{
|
||
|
|
ClosePanel();
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置输入验证
|
||
|
|
SetupInputValidation();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetupInputValidation()
|
||
|
|
{
|
||
|
|
if (NewUsernameInput != null)
|
||
|
|
{
|
||
|
|
NewUsernameInput.onValueChanged.AddListener(OnInputChanged);
|
||
|
|
// 设置自定义键盘
|
||
|
|
CustomKeyboardManager.SetupInputField(NewUsernameInput, KeyboardLayout.Default,
|
||
|
|
(newValue) =>
|
||
|
|
{
|
||
|
|
NewUsernameInput.text = newValue;
|
||
|
|
OnInputChanged(newValue);
|
||
|
|
},
|
||
|
|
clearOnFirstInput: true);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (NewPasswordInput != null)
|
||
|
|
{
|
||
|
|
NewPasswordInput.onValueChanged.AddListener(OnInputChanged);
|
||
|
|
// 设置自定义键盘(密码模式)
|
||
|
|
CustomKeyboardManager.SetupInputField(NewPasswordInput, KeyboardLayout.Default,
|
||
|
|
(newValue) =>
|
||
|
|
{
|
||
|
|
NewPasswordInput.text = newValue;
|
||
|
|
OnInputChanged(newValue);
|
||
|
|
},
|
||
|
|
clearOnFirstInput: true);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnInputChanged(string value)
|
||
|
|
{
|
||
|
|
ValidateAddUserInput();
|
||
|
|
}
|
||
|
|
|
||
|
|
private bool ValidateAddUserInput()
|
||
|
|
{
|
||
|
|
string username = NewUsernameInput?.text ?? "";
|
||
|
|
string password = NewPasswordInput?.text ?? "";
|
||
|
|
|
||
|
|
bool isValid = !string.IsNullOrEmpty(username) &&
|
||
|
|
!string.IsNullOrEmpty(password) &&
|
||
|
|
password.Length >= 6;
|
||
|
|
|
||
|
|
if (AddUserButton != null)
|
||
|
|
{
|
||
|
|
AddUserButton.interactable = isValid;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!isValid)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(username))
|
||
|
|
{
|
||
|
|
SetStatus("请输入用户名", false);
|
||
|
|
}
|
||
|
|
else if (string.IsNullOrEmpty(password))
|
||
|
|
{
|
||
|
|
SetStatus("请输入密码", false);
|
||
|
|
}
|
||
|
|
else if (password.Length < 6)
|
||
|
|
{
|
||
|
|
SetStatus("密码至少需要6个字符", false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetStatus("输入验证通过", true);
|
||
|
|
}
|
||
|
|
|
||
|
|
return isValid;
|
||
|
|
}
|
||
|
|
|
||
|
|
private void LoadUserList()
|
||
|
|
{
|
||
|
|
if (_authService == null)
|
||
|
|
{
|
||
|
|
SetStatus("认证服务不可用", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 清空现有列表
|
||
|
|
ClearUserList();
|
||
|
|
|
||
|
|
// 获取所有用户
|
||
|
|
_currentUsers = _authService.GetAllUsers();
|
||
|
|
if (_currentUsers == null)
|
||
|
|
{
|
||
|
|
SetStatus("获取用户列表失败", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 更新总数显示
|
||
|
|
if (TotalCountText != null)
|
||
|
|
{
|
||
|
|
TotalCountText.text = $"总用户数: {_currentUsers.Count}";
|
||
|
|
}
|
||
|
|
|
||
|
|
// 创建用户项
|
||
|
|
foreach (var user in _currentUsers)
|
||
|
|
{
|
||
|
|
CreateUserItem(user);
|
||
|
|
}
|
||
|
|
|
||
|
|
SetStatus($"成功加载 {_currentUsers.Count} 个用户", true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void CreateUserItem(UserInfo user)
|
||
|
|
{
|
||
|
|
if (UserItemPrefab == null || UserListParent == null) return;
|
||
|
|
|
||
|
|
GameObject userItem = Instantiate(UserItemPrefab, UserListParent);
|
||
|
|
_userItemObjects.Add(userItem);
|
||
|
|
|
||
|
|
// 查找用户项组件
|
||
|
|
var userItemComponent = userItem.GetComponent<UserItem>();
|
||
|
|
if (userItemComponent != null)
|
||
|
|
{
|
||
|
|
userItemComponent.Initialize(user, OnDeleteUser, OnResetPassword);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
// 如果没有 UserItem 组件,直接设置文本
|
||
|
|
var nameText = userItem.transform.Find("UsernameText")?.GetComponent<TextMeshProUGUI>();
|
||
|
|
var roleText = userItem.transform.Find("RoleText")?.GetComponent<TextMeshProUGUI>();
|
||
|
|
var timeText = userItem.transform.Find("TimeText")?.GetComponent<TextMeshProUGUI>();
|
||
|
|
|
||
|
|
if (nameText != null) nameText.text = user.Username;
|
||
|
|
if (roleText != null) roleText.text = user.Role == UserRole.Admin ? "管理员" : "普通用户";
|
||
|
|
if (timeText != null) timeText.text = user.CreatedTime.ToString("yyyy-MM-dd HH:mm");
|
||
|
|
|
||
|
|
// 设置删除按钮
|
||
|
|
var deleteButton = userItem.transform.Find("DeleteButton")?.GetComponent<Button>();
|
||
|
|
if (deleteButton != null)
|
||
|
|
{
|
||
|
|
deleteButton.onClick.AddListener(() => OnDeleteUser(user.Username));
|
||
|
|
// 不能删除admin用户和当前用户
|
||
|
|
deleteButton.interactable = !user.Username.Equals("admin", System.StringComparison.OrdinalIgnoreCase) &&
|
||
|
|
!user.Username.Equals(_authService.CurrentUsername, System.StringComparison.OrdinalIgnoreCase);
|
||
|
|
}
|
||
|
|
|
||
|
|
// 设置重置密码按钮
|
||
|
|
var resetButton = userItem.transform.Find("ResetButton")?.GetComponent<Button>();
|
||
|
|
if (resetButton != null)
|
||
|
|
{
|
||
|
|
resetButton.onClick.AddListener(() => OnResetPassword(user.Username));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void ClearUserList()
|
||
|
|
{
|
||
|
|
foreach (var item in _userItemObjects)
|
||
|
|
{
|
||
|
|
if (item != null)
|
||
|
|
{
|
||
|
|
DestroyImmediate(item);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
_userItemObjects.Clear();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnAddUserClicked()
|
||
|
|
{
|
||
|
|
if (!ValidateAddUserInput()) return;
|
||
|
|
|
||
|
|
string username = NewUsernameInput.text.Trim();
|
||
|
|
string password = NewPasswordInput.text;
|
||
|
|
UserRole role = NewRoleDropdown.value == 0 ? UserRole.User : UserRole.Admin;
|
||
|
|
|
||
|
|
ConfirmDialog.Show("添加用户",
|
||
|
|
$"确定要添加用户 '{username}' 吗?\n角色: {(role == UserRole.Admin ? "管理员" : "普通用户")}",
|
||
|
|
() => AddUser(username, password, role),
|
||
|
|
null, "确认添加", "取消", true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void AddUser(string username, string password, UserRole role)
|
||
|
|
{
|
||
|
|
bool success = _authService.AddUser(username, password, role);
|
||
|
|
|
||
|
|
if (success)
|
||
|
|
{
|
||
|
|
SetStatus($"成功添加用户 '{username}'", true);
|
||
|
|
|
||
|
|
// 清空输入框
|
||
|
|
if (NewUsernameInput != null) NewUsernameInput.text = "";
|
||
|
|
if (NewPasswordInput != null) NewPasswordInput.text = "";
|
||
|
|
NewRoleDropdown.value = 0;
|
||
|
|
|
||
|
|
// 刷新用户列表
|
||
|
|
LoadUserList();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetStatus($"添加用户 '{username}' 失败:用户已存在或其他错误", false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnDeleteUser(string username)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(username)) return;
|
||
|
|
|
||
|
|
// 不能删除admin用户和当前用户
|
||
|
|
if (username.Equals("admin", System.StringComparison.OrdinalIgnoreCase))
|
||
|
|
{
|
||
|
|
SetStatus("不能删除管理员账户", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (username.Equals(_authService.CurrentUsername, System.StringComparison.OrdinalIgnoreCase))
|
||
|
|
{
|
||
|
|
SetStatus("不能删除当前登录用户", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
ConfirmDialog.Show("删除用户",
|
||
|
|
$"确定要删除用户 '{username}' 吗?\n此操作不可撤销。",
|
||
|
|
() => DeleteUser(username),
|
||
|
|
null, "确认删除", "取消", true);
|
||
|
|
}
|
||
|
|
|
||
|
|
private void DeleteUser(string username)
|
||
|
|
{
|
||
|
|
bool success = _authService.RemoveUser(username);
|
||
|
|
|
||
|
|
if (success)
|
||
|
|
{
|
||
|
|
SetStatus($"成功删除用户 '{username}'", true);
|
||
|
|
LoadUserList(); // 刷新列表
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetStatus($"删除用户 '{username}' 失败", false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void OnResetPassword(string username)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(username)) return;
|
||
|
|
|
||
|
|
// 弹出输入新密码的对话框
|
||
|
|
InputDialog.Show("重置密码",
|
||
|
|
$"请为用户 '{username}' 输入新密码:",
|
||
|
|
"",
|
||
|
|
(newPassword) => ResetPassword(username, newPassword),
|
||
|
|
null, true); // 密码模式
|
||
|
|
}
|
||
|
|
|
||
|
|
private void ResetPassword(string username, string newPassword)
|
||
|
|
{
|
||
|
|
if (string.IsNullOrEmpty(newPassword) || newPassword.Length < 6)
|
||
|
|
{
|
||
|
|
SetStatus("新密码至少需要6个字符", false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 管理员重置密码不需要旧密码
|
||
|
|
bool success = _authService.ChangePassword(username, null, newPassword);
|
||
|
|
|
||
|
|
if (success)
|
||
|
|
{
|
||
|
|
SetStatus($"成功重置用户 '{username}' 的密码", true);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SetStatus($"重置用户 '{username}' 密码失败", false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetStatus(string message, bool isSuccess)
|
||
|
|
{
|
||
|
|
if (StatusText != null)
|
||
|
|
{
|
||
|
|
StatusText.text = message;
|
||
|
|
StatusText.color = isSuccess ? Color.green : Color.red;
|
||
|
|
}
|
||
|
|
|
||
|
|
Debug.Log($"[UserManagement] {message}");
|
||
|
|
}
|
||
|
|
|
||
|
|
void OnDestroy()
|
||
|
|
{
|
||
|
|
// 清理事件监听器
|
||
|
|
if (NewUsernameInput != null)
|
||
|
|
NewUsernameInput.onValueChanged.RemoveListener(OnInputChanged);
|
||
|
|
if (NewPasswordInput != null)
|
||
|
|
NewPasswordInput.onValueChanged.RemoveListener(OnInputChanged);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 用户项组件
|
||
|
|
/// 用于显示单个用户的信息和操作按钮
|
||
|
|
/// </summary>
|
||
|
|
public class UserItem : MonoBehaviour
|
||
|
|
{
|
||
|
|
[Header("显示组件")]
|
||
|
|
public TextMeshProUGUI UsernameText;
|
||
|
|
public TextMeshProUGUI RoleText;
|
||
|
|
public TextMeshProUGUI CreatedTimeText;
|
||
|
|
public TextMeshProUGUI LastLoginText;
|
||
|
|
|
||
|
|
[Header("操作按钮")]
|
||
|
|
public Button DeleteButton;
|
||
|
|
public Button ResetPasswordButton;
|
||
|
|
|
||
|
|
private UserInfo _userInfo;
|
||
|
|
private System.Action<string> _onDelete;
|
||
|
|
private System.Action<string> _onResetPassword;
|
||
|
|
|
||
|
|
public void Initialize(UserInfo userInfo, System.Action<string> onDelete, System.Action<string> onResetPassword)
|
||
|
|
{
|
||
|
|
_userInfo = userInfo;
|
||
|
|
_onDelete = onDelete;
|
||
|
|
_onResetPassword = onResetPassword;
|
||
|
|
|
||
|
|
UpdateUI();
|
||
|
|
SetupButtons();
|
||
|
|
}
|
||
|
|
|
||
|
|
private void UpdateUI()
|
||
|
|
{
|
||
|
|
if (_userInfo == null) return;
|
||
|
|
|
||
|
|
if (UsernameText != null)
|
||
|
|
{
|
||
|
|
UsernameText.text = _userInfo.Username;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (RoleText != null)
|
||
|
|
{
|
||
|
|
RoleText.text = _userInfo.Role == UserRole.Admin ? "管理员" : "普通用户";
|
||
|
|
RoleText.color = _userInfo.Role == UserRole.Admin ? Color.yellow : Color.white;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (CreatedTimeText != null)
|
||
|
|
{
|
||
|
|
CreatedTimeText.text = $"创建: {_userInfo.CreatedTime:yyyy-MM-dd HH:mm}";
|
||
|
|
}
|
||
|
|
|
||
|
|
if (LastLoginText != null)
|
||
|
|
{
|
||
|
|
if (_userInfo.LastLoginTime != default(System.DateTime))
|
||
|
|
{
|
||
|
|
LastLoginText.text = $"最后登录: {_userInfo.LastLoginTime:yyyy-MM-dd HH:mm}";
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
LastLoginText.text = "最后登录: 从未登录";
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void SetupButtons()
|
||
|
|
{
|
||
|
|
var authService = ServiceLocator.Get<IAuthenticationService>();
|
||
|
|
|
||
|
|
if (DeleteButton != null)
|
||
|
|
{
|
||
|
|
DeleteButton.onClick.RemoveAllListeners();
|
||
|
|
DeleteButton.onClick.AddListener(() => _onDelete?.Invoke(_userInfo.Username));
|
||
|
|
|
||
|
|
// 不能删除admin用户和当前用户
|
||
|
|
bool canDelete = !_userInfo.Username.Equals("admin", System.StringComparison.OrdinalIgnoreCase) &&
|
||
|
|
!_userInfo.Username.Equals(authService?.CurrentUsername, System.StringComparison.OrdinalIgnoreCase);
|
||
|
|
DeleteButton.interactable = canDelete;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ResetPasswordButton != null)
|
||
|
|
{
|
||
|
|
ResetPasswordButton.onClick.RemoveAllListeners();
|
||
|
|
ResetPasswordButton.onClick.AddListener(() => _onResetPassword?.Invoke(_userInfo.Username));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|