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();
}
}
}
}