using WorkCameraExport.Models; using WorkCameraExport.Services; using WorkCameraExport.Services.Interfaces; namespace WorkCameraExport.Forms { /// /// 登录窗体 /// public partial class LoginForm : Form { private readonly ApiService _apiService; private readonly IConfigService? _configService; private readonly AppSettings _settings; // 验证码相关 private string _captchaUuid = ""; private bool _captchaRequired = true; /// /// 登录成功后的 Token /// public string? Token { get; private set; } /// /// 登录成功后的用户信息 /// public UserInfo? UserInfo { get; private set; } /// /// 是否为自动登录成功 /// public bool IsAutoLogin { get; private set; } public LoginForm(ApiService apiService, IConfigService? configService = null) { InitializeComponent(); _apiService = apiService; _configService = configService; _settings = AppSettings.Load(); LoadSettings(); } /// /// 加载保存的设置 /// private void LoadSettings() { txtServerUrl.Text = _settings.ServerUrl; txtUsername.Text = _settings.Username; chkRememberMe.Checked = _settings.RememberMe; // 如果记住登录且 Token 未过期,尝试自动登录 if (_settings.RememberMe && !string.IsNullOrEmpty(_settings.SavedToken) && _settings.TokenExpireTime.HasValue && _settings.TokenExpireTime.Value > DateTime.Now) { TryAutoLogin(); } } /// /// 尝试自动登录 /// private async void TryAutoLogin() { if (string.IsNullOrEmpty(_settings.ServerUrl) || string.IsNullOrEmpty(_settings.SavedToken)) { return; } SetControlsEnabled(false); lblStatus.Text = "正在自动登录..."; lblStatus.ForeColor = Color.Blue; try { _apiService.SetBaseUrl(_settings.ServerUrl); _apiService.SetToken(_settings.SavedToken); // 验证 Token 是否有效(通过获取当前用户信息) var (success, _, _) = await _apiService.GetCurrentUserAsync(); if (success) { Token = _settings.SavedToken; IsAutoLogin = true; DialogResult = DialogResult.OK; Close(); return; } // Token 无效,清除保存的登录信息并提示用户 _settings.ClearLoginInfo(); _configService?.ClearCredentials(); lblStatus.Text = "登录已失效,请重新登录"; lblStatus.ForeColor = Color.Orange; } catch { _settings.ClearLoginInfo(); _configService?.ClearCredentials(); lblStatus.Text = "自动登录失败,请重新登录"; lblStatus.ForeColor = Color.Red; } finally { SetControlsEnabled(true); // 加载验证码 await LoadCaptchaAsync(); } } /// /// 服务器地址输入框失去焦点时加载验证码 /// private async void txtServerUrl_Leave(object sender, EventArgs e) { if (!string.IsNullOrWhiteSpace(txtServerUrl.Text)) { await LoadCaptchaAsync(); } } /// /// 加载验证码 /// private async Task LoadCaptchaAsync() { if (string.IsNullOrWhiteSpace(txtServerUrl.Text)) { return; } try { _apiService.SetBaseUrl(txtServerUrl.Text.Trim()); var (success, message, data) = await _apiService.GetCaptchaAsync(); if (success && data != null) { _captchaUuid = data.Uuid; _captchaRequired = data.CaptchaOff?.ToLower() != "off"; // 显示或隐藏验证码控件 SetCaptchaVisible(_captchaRequired); if (_captchaRequired && !string.IsNullOrEmpty(data.Img)) { // 将 Base64 转换为图片 var imageBytes = Convert.FromBase64String(data.Img); using var ms = new MemoryStream(imageBytes); picCaptcha.Image?.Dispose(); picCaptcha.Image = Image.FromStream(ms); } lblStatus.Text = ""; } else { lblStatus.Text = "获取验证码失败,点击图片重试"; lblStatus.ForeColor = Color.Orange; } } catch (Exception ex) { lblStatus.Text = $"连接服务器失败: {ex.Message}"; lblStatus.ForeColor = Color.Red; } } /// /// 设置验证码控件可见性 /// private void SetCaptchaVisible(bool visible) { lblCaptcha.Visible = visible; txtCaptcha.Visible = visible; picCaptcha.Visible = visible; // 调整其他控件位置 if (visible) { chkRememberMe.Location = new Point(30, 265); btnLogin.Location = new Point(30, 300); btnCancel.Location = new Point(210, 300); lblStatus.Location = new Point(30, 355); this.ClientSize = new Size(400, 450); } else { chkRememberMe.Location = new Point(30, 200); btnLogin.Location = new Point(30, 240); btnCancel.Location = new Point(210, 240); lblStatus.Location = new Point(30, 295); this.ClientSize = new Size(400, 390); } } /// /// 点击验证码图片刷新 /// private async void picCaptcha_Click(object sender, EventArgs e) { txtCaptcha.Text = ""; await LoadCaptchaAsync(); } /// /// 登录按钮点击事件 /// private async void btnLogin_Click(object sender, EventArgs e) { // 验证输入 if (string.IsNullOrWhiteSpace(txtServerUrl.Text)) { ShowError("请输入服务器地址"); txtServerUrl.Focus(); return; } if (string.IsNullOrWhiteSpace(txtUsername.Text)) { ShowError("请输入用户名"); txtUsername.Focus(); return; } if (string.IsNullOrWhiteSpace(txtPassword.Text)) { ShowError("请输入密码"); txtPassword.Focus(); return; } if (_captchaRequired && string.IsNullOrWhiteSpace(txtCaptcha.Text)) { ShowError("请输入验证码"); txtCaptcha.Focus(); return; } await DoLoginAsync(); } /// /// 执行登录 /// private async Task DoLoginAsync() { SetControlsEnabled(false); lblStatus.Text = "正在登录..."; lblStatus.ForeColor = Color.Blue; try { var serverUrl = txtServerUrl.Text.Trim(); var username = txtUsername.Text.Trim(); var password = txtPassword.Text; var captchaCode = txtCaptcha.Text.Trim(); _apiService.SetBaseUrl(serverUrl); var (success, message, data) = await _apiService.LoginAsync( username, password, captchaCode, _captchaUuid); if (success && data != null) { Token = data.Token; UserInfo = data.User; // 保存设置 SaveSettings(serverUrl, username, data.Token); lblStatus.Text = "登录成功"; lblStatus.ForeColor = Color.Green; DialogResult = DialogResult.OK; Close(); } else { ShowError(message); SetControlsEnabled(true); // 登录失败后刷新验证码 if (_captchaRequired) { txtCaptcha.Text = ""; await LoadCaptchaAsync(); } } } catch (Exception ex) { ShowError($"登录异常: {ex.Message}"); SetControlsEnabled(true); } } /// /// 保存设置 /// private void SaveSettings(string serverUrl, string username, string token) { _settings.ServerUrl = serverUrl; _settings.Username = username; _settings.RememberMe = chkRememberMe.Checked; if (chkRememberMe.Checked) { _settings.SavedToken = token; // Token 有效期设为 7 天 _settings.TokenExpireTime = DateTime.Now.AddDays(7); // 同时保存到 ConfigService(加密存储) _configService?.SaveCredentials(serverUrl, token, username); } else { _settings.SavedToken = ""; _settings.TokenExpireTime = null; _configService?.ClearCredentials(); } _settings.Save(); } /// /// 显示错误信息 /// private void ShowError(string message) { lblStatus.Text = message; lblStatus.ForeColor = Color.Red; } /// /// 设置控件启用状态 /// private void SetControlsEnabled(bool enabled) { txtServerUrl.Enabled = enabled; txtUsername.Enabled = enabled; txtPassword.Enabled = enabled; txtCaptcha.Enabled = enabled; picCaptcha.Enabled = enabled; chkRememberMe.Enabled = enabled; btnLogin.Enabled = enabled; btnCancel.Enabled = enabled; } /// /// 取消按钮点击事件 /// private void btnCancel_Click(object sender, EventArgs e) { DialogResult = DialogResult.Cancel; Close(); } /// /// 验证码输入框按键事件 - 支持回车登录 /// private void txtCaptcha_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { e.SuppressKeyPress = true; btnLogin_Click(sender, e); } } /// /// 窗体加载事件 /// private async void LoginForm_Load(object sender, EventArgs e) { // 设置焦点 if (string.IsNullOrEmpty(txtServerUrl.Text)) { txtServerUrl.Focus(); } else if (string.IsNullOrEmpty(txtUsername.Text)) { txtUsername.Focus(); } else { txtPassword.Focus(); } // 如果已有服务器地址,加载验证码 if (!string.IsNullOrWhiteSpace(txtServerUrl.Text)) { await LoadCaptchaAsync(); } } } }