From 066486c48f959c659b9ce74acc8a979fa87c0bcd Mon Sep 17 00:00:00 2001 From: cloud301530 <2690004082@qq.com> Date: Thu, 19 Dec 2024 09:57:45 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=E7=99=BB=E5=BD=95=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/PBAnaly/LoginCommon/LastLogin.cs | 32 ++ src/PBAnaly/LoginCommon/LoginForm.Designer.cs | 175 +++++++++++ src/PBAnaly/LoginCommon/LoginForm.cs | 191 ++++++++++++ src/PBAnaly/LoginCommon/LoginForm.resx | 120 ++++++++ src/PBAnaly/LoginCommon/User.cs | 85 ++++++ src/PBAnaly/LoginCommon/UserManage.cs | 275 ++++++++++++++++++ src/PBAnaly/LoginCommon/UserRole.cs | 25 ++ src/PBAnaly/MainForm.Designer.cs | 11 +- src/PBAnaly/MainForm.cs | 24 ++ src/PBAnaly/PBAnaly.csproj | 18 ++ src/PBAnaly/Program.cs | 9 +- src/PBAnaly/Properties/Resources.Designer.cs | 10 + src/PBAnaly/Properties/Resources.resx | 89 +++--- src/PBAnaly/Resources/关闭White.png | Bin 0 -> 2869 bytes 14 files changed, 1015 insertions(+), 49 deletions(-) create mode 100644 src/PBAnaly/LoginCommon/LastLogin.cs create mode 100644 src/PBAnaly/LoginCommon/LoginForm.Designer.cs create mode 100644 src/PBAnaly/LoginCommon/LoginForm.cs create mode 100644 src/PBAnaly/LoginCommon/LoginForm.resx create mode 100644 src/PBAnaly/LoginCommon/User.cs create mode 100644 src/PBAnaly/LoginCommon/UserManage.cs create mode 100644 src/PBAnaly/LoginCommon/UserRole.cs create mode 100644 src/PBAnaly/Resources/关闭White.png diff --git a/src/PBAnaly/LoginCommon/LastLogin.cs b/src/PBAnaly/LoginCommon/LastLogin.cs new file mode 100644 index 0000000..f2e453d --- /dev/null +++ b/src/PBAnaly/LoginCommon/LastLogin.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PBAnaly.LoginCommon +{ + public class LastLogin + { + #region Name 上一次登录的名称 + /// + /// 上一次登录的名称 + /// + public string UserName { get; set; } + #endregion + + #region Password 上一次登录的密码 + /// + /// 上一次登录的密码 + /// + public string Password { get; set; } + #endregion + + #region Remember 是否记住本次登录信息 1:记住 0:不记住 + /// + /// 是否记住本次登录信息 1:记住 0:不记住 + /// + public int Remember { get; set; } + #endregion + } +} diff --git a/src/PBAnaly/LoginCommon/LoginForm.Designer.cs b/src/PBAnaly/LoginCommon/LoginForm.Designer.cs new file mode 100644 index 0000000..8903cb6 --- /dev/null +++ b/src/PBAnaly/LoginCommon/LoginForm.Designer.cs @@ -0,0 +1,175 @@ +namespace PBAnaly.LoginCommon +{ + partial class LoginForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.txt_Password = new System.Windows.Forms.TextBox(); + this.cb_Remember = new System.Windows.Forms.CheckBox(); + this.txt_UserName = new System.Windows.Forms.TextBox(); + this.SIGNIN_materialButton = new MaterialSkin.Controls.MaterialButton(); + this.btn_Login = new MaterialSkin.Controls.MaterialButton(); + this.btn_Close = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50))))); + this.panel1.Controls.Add(this.txt_Password); + this.panel1.Controls.Add(this.cb_Remember); + this.panel1.Controls.Add(this.txt_UserName); + this.panel1.Controls.Add(this.SIGNIN_materialButton); + this.panel1.Controls.Add(this.btn_Login); + this.panel1.Location = new System.Drawing.Point(-1, 33); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(588, 332); + this.panel1.TabIndex = 14; + // + // txt_Password + // + this.txt_Password.Font = new System.Drawing.Font("宋体", 18F); + this.txt_Password.Location = new System.Drawing.Point(106, 120); + this.txt_Password.Multiline = true; + this.txt_Password.Name = "txt_Password"; + this.txt_Password.PasswordChar = '*'; + this.txt_Password.Size = new System.Drawing.Size(389, 33); + this.txt_Password.TabIndex = 18; + this.txt_Password.Text = "User Name"; + this.txt_Password.Click += new System.EventHandler(this.txt_Password_Click); + // + // cb_Remember + // + this.cb_Remember.AutoSize = true; + this.cb_Remember.Font = new System.Drawing.Font("微软雅黑", 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134))); + this.cb_Remember.ForeColor = System.Drawing.Color.White; + this.cb_Remember.Location = new System.Drawing.Point(106, 175); + this.cb_Remember.Name = "cb_Remember"; + this.cb_Remember.Size = new System.Drawing.Size(142, 25); + this.cb_Remember.TabIndex = 17; + this.cb_Remember.Text = "Remember Me"; + this.cb_Remember.UseVisualStyleBackColor = true; + // + // txt_UserName + // + this.txt_UserName.Font = new System.Drawing.Font("宋体", 18F); + this.txt_UserName.Location = new System.Drawing.Point(106, 54); + this.txt_UserName.Multiline = true; + this.txt_UserName.Name = "txt_UserName"; + this.txt_UserName.Size = new System.Drawing.Size(389, 33); + this.txt_UserName.TabIndex = 16; + this.txt_UserName.Text = "User Name"; + this.txt_UserName.Click += new System.EventHandler(this.txt_UserName_Click); + // + // SIGNIN_materialButton + // + this.SIGNIN_materialButton.AutoSize = false; + this.SIGNIN_materialButton.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.SIGNIN_materialButton.Density = MaterialSkin.Controls.MaterialButton.MaterialButtonDensity.Default; + this.SIGNIN_materialButton.Depth = 0; + this.SIGNIN_materialButton.HighEmphasis = true; + this.SIGNIN_materialButton.Icon = null; + this.SIGNIN_materialButton.Location = new System.Drawing.Point(321, 220); + this.SIGNIN_materialButton.Margin = new System.Windows.Forms.Padding(4, 6, 4, 6); + this.SIGNIN_materialButton.MouseState = MaterialSkin.MouseState.HOVER; + this.SIGNIN_materialButton.Name = "SIGNIN_materialButton"; + this.SIGNIN_materialButton.NoAccentTextColor = System.Drawing.Color.Empty; + this.SIGNIN_materialButton.Size = new System.Drawing.Size(147, 36); + this.SIGNIN_materialButton.TabIndex = 15; + this.SIGNIN_materialButton.Text = "Sign In"; + this.SIGNIN_materialButton.Type = MaterialSkin.Controls.MaterialButton.MaterialButtonType.Contained; + this.SIGNIN_materialButton.UseAccentColor = false; + this.SIGNIN_materialButton.UseVisualStyleBackColor = true; + // + // btn_Login + // + this.btn_Login.AutoSize = false; + this.btn_Login.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink; + this.btn_Login.Density = MaterialSkin.Controls.MaterialButton.MaterialButtonDensity.Default; + this.btn_Login.Depth = 0; + this.btn_Login.HighEmphasis = true; + this.btn_Login.Icon = null; + this.btn_Login.Location = new System.Drawing.Point(126, 220); + this.btn_Login.Margin = new System.Windows.Forms.Padding(4, 6, 4, 6); + this.btn_Login.MouseState = MaterialSkin.MouseState.HOVER; + this.btn_Login.Name = "btn_Login"; + this.btn_Login.NoAccentTextColor = System.Drawing.Color.Empty; + this.btn_Login.Size = new System.Drawing.Size(147, 36); + this.btn_Login.TabIndex = 14; + this.btn_Login.Text = "Login"; + this.btn_Login.Type = MaterialSkin.Controls.MaterialButton.MaterialButtonType.Contained; + this.btn_Login.UseAccentColor = false; + this.btn_Login.UseVisualStyleBackColor = true; + this.btn_Login.Click += new System.EventHandler(this.btn_Login_Click); + // + // btn_Close + // + this.btn_Close.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); + this.btn_Close.BackColor = System.Drawing.Color.Transparent; + this.btn_Close.FlatAppearance.BorderSize = 0; + this.btn_Close.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.btn_Close.ForeColor = System.Drawing.Color.Transparent; + this.btn_Close.Image = global::PBAnaly.Properties.Resources.关闭White; + this.btn_Close.Location = new System.Drawing.Point(543, -1); + this.btn_Close.Name = "btn_Close"; + this.btn_Close.Size = new System.Drawing.Size(44, 35); + this.btn_Close.TabIndex = 447; + this.btn_Close.UseVisualStyleBackColor = false; + this.btn_Close.Click += new System.EventHandler(this.btn_Close_Click); + // + // LoginForm + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(55)))), ((int)(((byte)(71)))), ((int)(((byte)(79))))); + this.ClientSize = new System.Drawing.Size(587, 365); + this.Controls.Add(this.btn_Close); + this.Controls.Add(this.panel1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; + this.Name = "LoginForm"; + this.Text = "LoginForm"; + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private System.Windows.Forms.Panel panel1; + private System.Windows.Forms.TextBox txt_Password; + private System.Windows.Forms.CheckBox cb_Remember; + private System.Windows.Forms.TextBox txt_UserName; + private MaterialSkin.Controls.MaterialButton SIGNIN_materialButton; + private MaterialSkin.Controls.MaterialButton btn_Login; + private System.Windows.Forms.Button btn_Close; + } +} \ No newline at end of file diff --git a/src/PBAnaly/LoginCommon/LoginForm.cs b/src/PBAnaly/LoginCommon/LoginForm.cs new file mode 100644 index 0000000..b1de47e --- /dev/null +++ b/src/PBAnaly/LoginCommon/LoginForm.cs @@ -0,0 +1,191 @@ +using MaterialSkin; +using MaterialSkin.Controls; +using ReaLTaiizor.Manager; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace PBAnaly.LoginCommon +{ + public partial class LoginForm : Form + { + private MaterialSkin.MaterialSkinManager materialSkinManager; + public bool isOK = false; + + public LoginForm() + { + InitializeComponent(); + + // 设置窗体的启动位置为屏幕的中心 + this.StartPosition = FormStartPosition.CenterScreen; + this.Location = new System.Drawing.Point((Screen.PrimaryScreen.WorkingArea.Width - this.Width) / 2, + (Screen.PrimaryScreen.WorkingArea.Height - this.Height) / 2); + + + //如果上一次登录的时候是勾选了记住本次登录,那么就像用户名和密码填充到本文控件 + if (UserManage.LastLoginUser.Count > 0) + { + foreach (var item in UserManage.LastLoginUser.Values) + { + if (item.Remember == 1) + { + txt_UserName.Text= item.UserName; + txt_Password.Text = item.Password; + cb_Remember.Checked = true; + } + } + } + } + + + #region =====重写WndPoc方法 无边框窗体更改大小及拖动========= + const int HTLEFT = 10; + const int HTRIGHT = 11; + const int HTTOP = 12; + const int HTTOPLEFT = 13; + const int HTTOPRIGHT = 14; + const int HTBOTTOM = 15; + const int HTBOTTOMLEFT = 0x10; + const int HTBOTTOMRIGHT = 17; + protected override void WndProc(ref System.Windows.Forms.Message m) + { + try + { + switch (m.Msg) + { + case 0x0084: + base.WndProc(ref m); + System.Drawing.Point vPoint = new System.Drawing.Point((int)m.LParam & 0xFFFF, (int)m.LParam >> 16 & 0xFFFF); + vPoint = PointToClient(vPoint); + if (vPoint.X <= 5) + { + if (vPoint.Y <= 5) + { + m.Result = (IntPtr)HTTOPLEFT; + } + else if (vPoint.Y >= ClientSize.Height - 5) + { + m.Result = (IntPtr)HTBOTTOMLEFT; + } + else + { + m.Result = (IntPtr)HTLEFT; + } + } + else if (vPoint.X >= ClientSize.Width - 5) + { + if (vPoint.Y <= 5) + { + m.Result = (IntPtr)HTTOPRIGHT; + } + else if (vPoint.Y >= ClientSize.Height - 5) + { + m.Result = (IntPtr)HTBOTTOMRIGHT; + } + else + { + m.Result = (IntPtr)HTRIGHT; + } + } + else if (vPoint.Y <= 5) + { + m.Result = (IntPtr)HTTOP; + } + else if (vPoint.Y >= ClientSize.Height - 5) + { + m.Result = (IntPtr)HTBOTTOM; + } + break; + + case 0x0201://鼠标左键按下的消息 用于实现拖动窗口功能 + m.Msg = 0x00A1;//更改消息为非客户区按下鼠标 + m.LParam = IntPtr.Zero;//默认值 + m.WParam = new IntPtr(2);//鼠标放在标题栏内 + base.WndProc(ref m); + break; + + default: + base.WndProc(ref m); + break; + } + } + catch (Exception ex) + { + //showERRORMsg($"重写WndPoc方法 无边框窗体更改大小及拖动方法发生异常,原因:{ex.Message}"); + } + + } + #endregion + + #region ProcessCmdKey 是一个用于处理按键命令的方法,在自定义控件中可以重写它来捕获键盘输入(包括 Enter 键) + protected override bool ProcessCmdKey(ref Message msg, Keys keyData) + { + // 检查是否按下了 Enter 键 + if (keyData == Keys.Enter) + { + btn_Login_Click(null, null); + return true; // 表示该按键已处理 + } + return base.ProcessCmdKey(ref msg, keyData); + } + #endregion + + private void txt_UserName_Click(object sender, EventArgs e) + { + txt_UserName.Text = ""; + } + + private void txt_Password_Click(object sender, EventArgs e) + { + txt_Password.Text = ""; + } + + #region btn_Login_Click 登录按钮 + private void btn_Login_Click(object sender, EventArgs e) + { + string UserName = txt_UserName.Text; + string Password = txt_Password.Text; + int Remember = cb_Remember.Checked ? 1 : 0; + if (string.IsNullOrEmpty(UserName) || string.IsNullOrEmpty(Password)) + { + MessageBox.Show("User ID or Password is empty ,Please Check!!", "Login Error"); + return; + } + + + if (UserManage.UsersKeyValuePairs.ContainsKey(UserName)) + { + User user = UserManage.UsersKeyValuePairs[UserName]; + if (Password == UserManage.UsersKeyValuePairs[UserName].Password) + { + UserManage.IsLogined = true;//系统已登录 + UserManage.SetLogionUser(user);//当前登录的用户 + //将本次登录更新为上一次登录的用户插入数据库,方便下次登录的时候查看 + UserManage.UpDateLastUser(UserName, Password, Remember); + isOK = true; + Close(); + } + else { MessageBox.Show("Password is incorrect, please re-enter"); return; } + } + else { MessageBox.Show("User name is incorrect, please re-enter"); } + + } + #endregion + + #region btn_Close_Click 关闭按钮 + private void btn_Close_Click(object sender, EventArgs e) + { + isOK = false; + + Close(); + } + #endregion + + } +} diff --git a/src/PBAnaly/LoginCommon/LoginForm.resx b/src/PBAnaly/LoginCommon/LoginForm.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/src/PBAnaly/LoginCommon/LoginForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/src/PBAnaly/LoginCommon/User.cs b/src/PBAnaly/LoginCommon/User.cs new file mode 100644 index 0000000..3d9ceef --- /dev/null +++ b/src/PBAnaly/LoginCommon/User.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PBAnaly.LoginCommon +{ + #region User 用户详情类,保存用户名称、密码、创建者、描述、用户权限 + /// + /// 用户详情类,保存用户名称、密码、创建者、描述、用户权限 + /// + public struct User + { + #region publice propertys + + #region Name 设置或获取用户名 + /// + /// 设置或获取用户名 + /// + public string Name { get; set; } + #endregion + + #region Password 设置或获取密码 + /// + /// 设置或获取密码 + /// + public string Password { get; set; } + #endregion + + #region CreatedBy 设置或获取创建者 + /// + /// 设置或获取创建者 + /// + public string CreatedBy { get; set; } + #endregion + + #region PasswordQuestion 设置或获取密保问题 + /// + /// 设置或获取密保问题 + /// + public string PasswordQuestion { get; set; } + #endregion + + #region QuestionAnswer 设置或获取密保答案 + /// + /// 设置或获取密保答案 + /// + public string QuestionAnswer { get; set; } + #endregion + + #region CreatedDate 设置或获取创时间 + /// + /// 设置或获取创时间 + /// + public DateTime CreatedDate { get; set; } + #endregion + + + #region Role 设置或获取用户权限 + /// + /// 设置或获取用户权限 + /// + public UserRole Role { get; set; } + #endregion + + #endregion + + + #region Init 初始化用户 + /// + /// 初始化用户 + /// + public void Init() + { + Name = "未登录"; + Password = "Op"; + CreatedBy = "System"; + CreatedDate = DateTime.Now; + Role = UserRole.Operator; + } + #endregion + } + #endregion +} diff --git a/src/PBAnaly/LoginCommon/UserManage.cs b/src/PBAnaly/LoginCommon/UserManage.cs new file mode 100644 index 0000000..4b8f893 --- /dev/null +++ b/src/PBAnaly/LoginCommon/UserManage.cs @@ -0,0 +1,275 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SQLite; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PBAnaly.LoginCommon +{ + public static class UserManage + { + public static string dbPath = "UserManage.db"; + public static string connectionString = $"Data Source={dbPath};Version=3;"; + + /// + /// 记录上一次登录的用户名和密码 + /// + public static Dictionary LastLoginUser; + /// + /// 登录用户更改事件 + /// + public static EventHandler LogionUserChanged; + /// + /// 数据库所有的用户 + /// + public static Dictionary UsersKeyValuePairs; + /// + /// 系统当前登录的用户 + /// + public static User LogionUser { get; private set; } + /// + /// 系统是否已经登录 + /// + public static bool IsLogined { get; set; } + + /// + /// 设置当前登录的用户 + /// + /// 当前登录的用户信息 + public static void SetLogionUser(User user) + { + if (LogionUser.Name != user.Name) + { + LogionUser = user; + LogionUserChanged?.Invoke(null, EventArgs.Empty); + } + } + + #region ConnectDb 连接数据库,如果数据库不存在的话,就创建一个,数据库名:UserManage + /// + /// 连接数据库,如果数据库不存在的话,就创建一个,数据库名:UserManage + /// + /// + public static bool ConnectDb() + { + bool isOK = false; + + try + { + // 检查数据库文件是否存在 + if (!File.Exists(dbPath)) + { + SQLiteConnection.CreateFile(dbPath); // 创建数据库文件 + Console.WriteLine("数据库文件已创建。"); + + // 在新数据库上创建表 + using (var connection = new SQLiteConnection(connectionString)) + { + connection.Open(); + + string sql = @" + CREATE TABLE IF NOT EXISTS User ( + UserName VARCHAR(200) NOT NULL, + Password VARCHAR(2000) NOT NULL, + CreatedBy CHAR(50) NOT NULL, + CreatedDate DATETIME NOT NULL, + Role CHAR(200), + PasswordQuestion VARCHAR(1000) DEFAULT NULL, + QuestionAnswer VARCHAR(1000) DEFAULT NULL, + PRIMARY KEY (UserName) + );"; + + using (var command = new SQLiteCommand(sql, connection)) + { + command.ExecuteNonQuery(); // 执行SQL命令创建表 + Console.WriteLine("表 'User' 已创建。"); + } + + // 插入数据 + InsertDefaultUserData(connectionString); + } + } + //加载用户 + LoadUsersFromDatabase(connectionString); + //加载上一次登录的用户 + LoadLastLoginUser(); + } + catch (Exception ex) + { + isOK = false; + } + + return isOK; + + } + #endregion + + #region InsertDefaultUserData 创建完数据库之后需要插入一个管理员用户 root + /// + /// 创建完数据库之后需要插入一个管理员用户root + /// + /// + private static void InsertDefaultUserData(string connectionString) + { + using (var connection = new SQLiteConnection(connectionString)) + { + connection.Open(); + + string insertSQL = @" + INSERT OR IGNORE INTO User (UserName, Password, CreatedBy, CreatedDate, Role, PasswordQuestion, QuestionAnswer) + VALUES (@UserName, @Password, @CreatedBy, @CreatedDate, @Role, @PasswordQuestion, @QuestionAnswer);"; + + using (var command = new SQLiteCommand(insertSQL, connection)) + { + // 参数化查询,防止SQL注入 + command.Parameters.AddWithValue("@UserName", "root"); + command.Parameters.AddWithValue("@Password", "root"); // 示例密码 + command.Parameters.AddWithValue("@CreatedBy", "System"); + command.Parameters.AddWithValue("@CreatedDate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); + command.Parameters.AddWithValue("@Role", "Administrator"); + command.Parameters.AddWithValue("@PasswordQuestion", "我的名字"); + command.Parameters.AddWithValue("@QuestionAnswer", "root"); + + command.ExecuteNonQuery(); + } + + connection.Close(); + } + } + + #endregion + + #region LoadUsersFromDatabase 从数据库加载 User 表数据到 UsersKeyValuePairs 字典中 + /// + /// 从数据库加载 User 表数据到 UsersKeyValuePairs 字典中 + /// + /// SQLite 数据库连接字符串 + private static void LoadUsersFromDatabase(string connectionString) + { + UsersKeyValuePairs = new Dictionary(); + using (var connection = new SQLiteConnection(connectionString)) + { + connection.Open(); + + string query = "SELECT UserName, Password, CreatedBy, CreatedDate, Role, PasswordQuestion, QuestionAnswer FROM User"; + using (var command = new SQLiteCommand(query, connection)) + { + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + User user = new User + { + Name = reader["UserName"].ToString(), + Password = reader["Password"].ToString(), + CreatedBy = reader["CreatedBy"].ToString(), + CreatedDate = Convert.ToDateTime(reader["CreatedDate"]), + Role = Enum.TryParse(reader["Role"].ToString(), out var role) ? role : UserRole.Operator, + PasswordQuestion = reader["PasswordQuestion"].ToString(), + QuestionAnswer = reader["QuestionAnswer"].ToString() + }; + + // 添加到字典中,使用 UserName 作为 Key + UsersKeyValuePairs[user.Name] = user; + } + } + } + + connection.Close(); + } + } + + #endregion + + #region LoadLastLoginUser 加载上一次登录的用户 + /// + /// 加载上一次登录的用户 + /// + public static void LoadLastLoginUser() + { + LastLoginUser = new Dictionary(); + using (SQLiteConnection connection = new SQLiteConnection(connectionString)) + { + try + { + connection.Open(); + string query = "SELECT * FROM last"; // 更改为您的表名和查询 + + SQLiteCommand command = new SQLiteCommand(query, connection); + SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter(command); + + DataTable dataTable = new DataTable(); + dataAdapter.Fill(dataTable); + + if (dataTable.Rows.Count > 0) + { + foreach (DataRow row in dataTable.Rows) + { + LastLogin last = new LastLogin(); + last.UserName = row["UserName"].ToString(); + last.Password = row["Password"].ToString(); + last.Remember = int.Parse(row["Remember"].ToString()); + LastLoginUser.Add(last.UserName, last); + } + } + + } + catch (Exception e) + { + Console.WriteLine("数据库操作出错:"); + Console.WriteLine(e.Message); + } + } + } + + + + #endregion + + #region UpDateLastUser 更新上一次登录的用户 + /// + /// 更新上一次登录的用户 + /// + /// + /// + /// + public static void UpDateLastUser(string UserName,string Password,int Remember) + { + try + { + string updateQuery = "UPDATE last SET UserName = @UserName," + + " Password = @Password, Remember = @Remember WHERE ID = @ID"; + + using (SQLiteConnection conn = new SQLiteConnection(connectionString)) + { + conn.Open(); + + using (SQLiteCommand cmd = new SQLiteCommand(updateQuery, conn)) + { + // 参数化查询,防止SQL注入 + cmd.Parameters.AddWithValue("@UserName", UserName); + cmd.Parameters.AddWithValue("@Password", Password); + cmd.Parameters.AddWithValue("@Remember", Remember); + cmd.Parameters.AddWithValue("@ID", 1); + + // 执行更新命令 + int rowsAffected = cmd.ExecuteNonQuery(); + + Console.WriteLine($"更新成功,受影响的行数:{rowsAffected}"); + } + + conn.Close(); + } + } + catch (Exception) + { + + } + } + + #endregion + } +} diff --git a/src/PBAnaly/LoginCommon/UserRole.cs b/src/PBAnaly/LoginCommon/UserRole.cs new file mode 100644 index 0000000..617110d --- /dev/null +++ b/src/PBAnaly/LoginCommon/UserRole.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PBAnaly.LoginCommon +{ + #region UserRole 用户权限枚举 + /// + /// 用户权限枚举 + /// + public enum UserRole + { + /// + /// 操作员权限 + /// + Operator, + /// + /// 管理员权限 + /// + Administrator + } + #endregion +} diff --git a/src/PBAnaly/MainForm.Designer.cs b/src/PBAnaly/MainForm.Designer.cs index 8c5f79e..ad734a4 100644 --- a/src/PBAnaly/MainForm.Designer.cs +++ b/src/PBAnaly/MainForm.Designer.cs @@ -237,7 +237,7 @@ this.tableLayoutPanel1.Controls.Add(this.pl_right, 2, 1); this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.tableLayoutPanel1.Location = new System.Drawing.Point(3, 24); - this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.tableLayoutPanel1.Margin = new System.Windows.Forms.Padding(2); this.tableLayoutPanel1.Name = "tableLayoutPanel1"; this.tableLayoutPanel1.RowCount = 3; this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 55F)); @@ -270,7 +270,7 @@ this.DataProcess_panel.EdgeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(41)))), ((int)(((byte)(50))))); this.DataProcess_panel.Location = new System.Drawing.Point(3, 3); this.DataProcess_panel.Name = "DataProcess_panel"; - this.DataProcess_panel.Padding = new System.Windows.Forms.Padding(5, 5, 5, 5); + this.DataProcess_panel.Padding = new System.Windows.Forms.Padding(5); this.tl_right_main_view.SetRowSpan(this.DataProcess_panel, 2); this.DataProcess_panel.Size = new System.Drawing.Size(553, 489); this.DataProcess_panel.SmoothingType = System.Drawing.Drawing2D.SmoothingMode.HighQuality; @@ -302,7 +302,7 @@ this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; this.flowLayoutPanel1.FlowDirection = System.Windows.Forms.FlowDirection.TopDown; this.flowLayoutPanel1.Location = new System.Drawing.Point(2, 88); - this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(2); this.flowLayoutPanel1.Name = "flowLayoutPanel1"; this.flowLayoutPanel1.Size = new System.Drawing.Size(206, 491); this.flowLayoutPanel1.TabIndex = 18; @@ -642,9 +642,9 @@ this.pl_right.Dock = System.Windows.Forms.DockStyle.Fill; this.pl_right.EdgeColor = System.Drawing.Color.FromArgb(((int)(((byte)(32)))), ((int)(((byte)(41)))), ((int)(((byte)(50))))); this.pl_right.Location = new System.Drawing.Point(771, 57); - this.pl_right.Margin = new System.Windows.Forms.Padding(2, 2, 2, 2); + this.pl_right.Margin = new System.Windows.Forms.Padding(2); this.pl_right.Name = "pl_right"; - this.pl_right.Padding = new System.Windows.Forms.Padding(4, 4, 4, 4); + this.pl_right.Padding = new System.Windows.Forms.Padding(4); this.tableLayoutPanel1.SetRowSpan(this.pl_right, 2); this.pl_right.Size = new System.Drawing.Size(324, 522); this.pl_right.SmoothingType = System.Drawing.Drawing2D.SmoothingMode.HighQuality; @@ -678,6 +678,7 @@ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "MainForm"; this.WindowState = System.Windows.Forms.FormWindowState.Maximized; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.MainForm_FormClosed); this.SizeChanged += new System.EventHandler(this.MainForm_SizeChanged); this.metroPanel_RightTop.ResumeLayout(false); diff --git a/src/PBAnaly/MainForm.cs b/src/PBAnaly/MainForm.cs index b1071a5..e278cee 100644 --- a/src/PBAnaly/MainForm.cs +++ b/src/PBAnaly/MainForm.cs @@ -59,7 +59,26 @@ namespace PBAnaly FormGenerate_Y = 0; // initPanel(); } + public MainForm() + { + InitializeComponent(); + LoginCommon.LoginForm loginForm = new LoginCommon.LoginForm(); + loginForm.ShowDialog(); + if (!loginForm.isOK) + { + this.FormClosing -= new FormClosingEventHandler(MainForm_FormClosing); + Close(); + } + + loginForm.Hide(); + + UIInit(); + + FormGenerate_X = 0; + FormGenerate_Y = 0; + // initPanel(); + } @@ -602,5 +621,10 @@ namespace PBAnaly } } + + private void MainForm_FormClosing(object sender, FormClosingEventArgs e) + { + + } } } diff --git a/src/PBAnaly/PBAnaly.csproj b/src/PBAnaly/PBAnaly.csproj index fe0c8af..9cc7667 100644 --- a/src/PBAnaly/PBAnaly.csproj +++ b/src/PBAnaly/PBAnaly.csproj @@ -75,6 +75,16 @@ LogForm.cs + + + Form + + + LoginForm.cs + + + + Form @@ -158,6 +168,9 @@ LogForm.cs + + LoginForm.cs + LoginForm.cs @@ -273,6 +286,9 @@ 3.7.0 + + 1.0.119 + 8.0.1 @@ -387,6 +403,7 @@ + @@ -413,5 +430,6 @@ + \ No newline at end of file diff --git a/src/PBAnaly/Program.cs b/src/PBAnaly/Program.cs index 32d644a..e33b75d 100644 --- a/src/PBAnaly/Program.cs +++ b/src/PBAnaly/Program.cs @@ -4,6 +4,7 @@ using System.IO; using System.Windows.Forms; using PBAnaly.Module; using PBAnaly.UI; +using PBAnaly.LoginCommon; namespace PBAnaly { public static class Global @@ -67,9 +68,15 @@ namespace PBAnaly { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); + + //数据库操作 + string dbPath = "UserManage.db"; + string connectionString = $"Data Source={dbPath};Version=3;"; + UserManage.ConnectDb(); + var login = new LoginForm(); login.StartPosition = FormStartPosition.CenterScreen; - Application.Run(login); + Application.Run(new MainForm()); } else diff --git a/src/PBAnaly/Properties/Resources.Designer.cs b/src/PBAnaly/Properties/Resources.Designer.cs index 8faa62e..166c7a0 100644 --- a/src/PBAnaly/Properties/Resources.Designer.cs +++ b/src/PBAnaly/Properties/Resources.Designer.cs @@ -350,6 +350,16 @@ namespace PBAnaly.Properties { } } + /// + /// 查找 System.Drawing.Bitmap 类型的本地化资源。 + /// + internal static System.Drawing.Bitmap 关闭White { + get { + object obj = ResourceManager.GetObject("关闭White", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// 查找 System.Drawing.Bitmap 类型的本地化资源。 /// diff --git a/src/PBAnaly/Properties/Resources.resx b/src/PBAnaly/Properties/Resources.resx index b92b6ec..f4db092 100644 --- a/src/PBAnaly/Properties/Resources.resx +++ b/src/PBAnaly/Properties/Resources.resx @@ -130,17 +130,23 @@ ..\Resources\yto-icon-X-transit_time.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\数据报告.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\EtBr_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\壁纸.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\保存图片.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\饼干.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\线段.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\YellowHot_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\Black_Green_0.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\Black_Green_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -148,9 +154,15 @@ ..\Resources\Black_Red_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\前台.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\保存.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\文本.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\重组蛋白-CAR-T靶点蛋白.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -163,30 +175,33 @@ ..\Resources\波形设置-未选中.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Gray.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\Black_Blue_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\zoom-in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\数据报告 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\導出.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\保存.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\圖片_20240731174523.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\重置.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\Black_Red_0.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\京仪科技定稿_画板 1 副本2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\分析.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\zoom-out.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -196,11 +211,8 @@ ..\Resources\风控.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Black_SDS_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\分析.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\饼干.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\控制窗口.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -235,12 +247,6 @@ ..\Resources\圆形.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\執行日誌紀錄.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\圆形.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - ..\Resources\主页面-图像编辑-正反片.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -250,49 +256,46 @@ ..\Resources\Black_Yley_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\线段 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\導出.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\Pseudo_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\线段.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Gray.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\10矩形.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\放大.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\线段 (1).png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\Black_Green_0.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - - ..\Resources\YellowHot_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\執行日誌紀錄.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\蛋白质-01.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\数据报告.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\壁纸.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\zoom-in.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\圆形.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\黑白平衡.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\重置.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\Black_SDS_1.bmp;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\前台.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\放大.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a ..\Resources\波形图.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - - ..\Resources\文本.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\关闭White.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a \ No newline at end of file diff --git a/src/PBAnaly/Resources/关闭White.png b/src/PBAnaly/Resources/关闭White.png new file mode 100644 index 0000000000000000000000000000000000000000..2a84598032170ecc470b3ccba6a1648f91b4a48d GIT binary patch literal 2869 zcmV-53(E9~P)KLZ*U+5Lu!Sk^o_Z5E4Meg@_7P6crJiNL9pw)e1;Xm069{HJUZAPk55R%$-RIA z6-eL&AQ0xu!e<4=008gy@A0LT~suv4>S3ILP<0Bm`DLLvaF4FK%)Nj?Pt*r}7;7Xa9z9H|HZjR63e zC`Tj$K)V27Re@400>HumpsYY5E(E}?0f1SyGDiY{y#)Yvj#!WnKwtoXnL;eg03bL5 z07D)V%>y7z1E4U{zu>7~aD})?0RX_umCct+(lZpemCzb@^6=o|A>zVpu|i=NDG+7} zl4`aK{0#b-!z=TL9Wt0BGO&T{GJWpjryhdijfaIQ&2!o}p04JRKYg3k&Tf zVxhe-O!X z{f;To;xw^bEES6JSc$k$B2CA6xl)ltA<32E66t?3@gJ7`36pmX0IY^jz)rRYwaaY4 ze(nJRiw;=Qb^t(r^DT@T3y}a2XEZW-_W%Hszxj_qD**t_m!#tW0KDiJT&R>6OvVTR z07RgHDzHHZ48atvzz&?j9lXF70$~P3Knx_nJP<+#`N z#-MZ2bTkiLfR>_b(HgWKJ%F~Nr_oF3b#wrIijHG|(J>BYjM-sajE6;FiC7vY#};Gd zST$CUHDeuEH+B^pz@B062qXfFfD`NpUW5?BY=V%GM_5c)L#QR}BeW8_2v-S%gfYS= zB9o|3v?Y2H`NVi)In3rTB8+ej^> zQ=~r95NVuDChL%G$=>7$vVg20myx%S50Foi`^m%Pw-h?Xh~i8Mq9jtJloCocWk2Nv zrJpiFnV_ms&8eQ$2&#xWpIS+6pmtC%Q-`S&GF4Q#^mhymh7E(qNMa}%YZ-ePrx>>xFPTiH1=E+A$W$=bG8>s^ zm=Bn5Rah$aDtr}@$`X}2l~$F0mFKEdRdZE8)p@E5RI61Ft6o-prbbn>P~)iy)E2AN zsU20jsWz_8Qg>31P|s0cqrPALg8E|(vWA65poU1JRAaZs8I2(p#xiB`SVGovRs-uS zYnV-9TeA7=Om+qP8+I>yOjAR1s%ETak!GFdam@h^# z)@rS0t$wXH+Irf)+G6c;?H29p+V6F6oj{!|o%K3xI`?%6x;DB|x`n#ibhIR?(H}Q3Gzd138Ei2)WAMz7W9Vy`X}HnwgyEn!VS)>mv$8&{hQn>w4zwy3R}t;BYlZQm5)6pty=DfLrs+A-|>>;~;Q z_F?uV_HFjh9n2gO9o9Q^JA86v({H5aB!kjoO6 zc9$1ZZKsN-Zl8L~mE{`ly3)1N^`o1+o7}D0ZPeY&J;i;i`%NyJ8_8Y6J?}yE@b_5a zam?eLr<8@mESk|3$_SkmS{wQ>%qC18))9_|&j{ZT zes8AvOzF(F2#DZEY>2oYX&IRp`F#{ADl)1r>QS^)ba8a|EY_^#S^HO&t^Rgqwv=MZThqqEWH8 zxJo>d=ABlR_Bh=;eM9Tw|Ih34~oTE|= zX_mAr*D$vzw@+p(E0Yc6dFE}(8oqt`+R{gE3x4zjX+Sb3_cYE^= zgB=w+-tUy`ytONMS8KgRef4hA?t0j zufM;t32jm~jUGrkaOInTZ`zyfns>EuS}G30LFK_G-==(f<51|K&cocp&EJ`SxAh3? zNO>#LI=^+SEu(FqJ)ynt=!~PC9bO$rzPJB=?=j6w@a-(u02P7 zaQ)#(uUl{HW%tYNS3ItC^iAtK(eKlL`f9+{bJzISE?u8_z3;~C8@FyI-5j_jy7l;W z_U#vU3hqqYU3!mrul&B+{ptt$59)uk{;_4iZQ%G|z+lhASr6|H35TBkl>gI*;nGLU zN7W-nBaM%pA0HbH8olyl&XeJ%vZoWz%6?Y=dFykl=imL}`%BMQ{Mhgd`HRoLu6e2R za__6DuR6yg#~-}Tc|Gx_{H@O0eebyMy5GmWADJlpK>kqk(fVV@r_fLLKIeS?{4e)} z^ZO;zpECde03c&XQcVB=dL;k=fP(-4`Tqa_faw4Lbua(`>RI+y?e7jKeZ#YO-C z0Afi*K~#9!%#*F