This commit is contained in:
wxt
2026-01-27 17:27:59 +08:00
parent 35d19eb69e
commit 720d240817
7 changed files with 399 additions and 3 deletions

View File

@@ -15,4 +15,8 @@
</dependentAssembly>
</assemblyBinding>
</runtime>
<appSettings>
<add key="MaxExpirationPeriodInDays" value="30" />
<add key="ReminderPeriodInDays" value="7" />
</appSettings>
</configuration>

View File

@@ -0,0 +1,83 @@
namespace
{
partial class ChangPassword
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.label1 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(57, 59);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 8;
this.button1.Text = "确认";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(14, 15);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(37, 15);
this.label1.TabIndex = 7;
this.label1.Text = "密码";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(57, 12);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(186, 25);
this.textBox1.TabIndex = 6;
//
// ChangPassword
//
this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(303, 97);
this.Controls.Add(this.button1);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox1);
this.Name = "ChangPassword";
this.Text = "ChangPassword";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Label label1;
private System.Windows.Forms.TextBox textBox1;
}
}

View File

@@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace
{
public partial class ChangPassword : Form
{
public ChangPassword()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text == "07283622")
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// 更新或添加一个键值对到 AppSettings 配置节
config.AppSettings.Settings["MaxExpirationPeriodInDays"].Value = "40";
// 保存更改到配置文件
config.Save(ConfigurationSaveMode.Modified);
// 重新加载配置文件
ConfigurationManager.RefreshSection("appSettings");
MessageBox.Show("配置值已成功保存!", "保存成功");
}
if (textBox1.Text == "45983625")
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
// 更新或添加一个键值对到 AppSettings 配置节
config.AppSettings.Settings["MaxExpirationPeriodInDays"].Value = "36500";
// 保存更改到配置文件
config.Save(ConfigurationSaveMode.Modified);
// 重新加载配置文件
ConfigurationManager.RefreshSection("appSettings");
MessageBox.Show("配置值已成功保存!", "保存成功");
}
}
}
}

View File

@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
{
internal class PasswordExpirationService
{
private readonly TimeSpan _maxExpirationPeriod;
private readonly TimeSpan _reminderPeriod;
public PasswordExpirationService()
{
// 读取配置文件中的密码时效策略
var config = ConfigurationManager.AppSettings;
_maxExpirationPeriod = TimeSpan.FromDays(int.Parse(config["MaxExpirationPeriodInDays"]));
_reminderPeriod = TimeSpan.FromDays(int.Parse(config["ReminderPeriodInDays"]));
}
public bool IsPasswordExpired(DateTime passwordLastModified)
{
// 计算密码当前的有效期
TimeSpan passwordExpirationPeriod = passwordLastModified + _maxExpirationPeriod - DateTime.Now;
return passwordExpirationPeriod < TimeSpan.Zero;
}
public bool IsPasswordExpiringSoon(DateTime passwordLastModified)
{
// 判断密码是否接近过期提醒期
TimeSpan passwordExpirationPeriod = passwordLastModified + _maxExpirationPeriod - DateTime.Now;
return passwordExpirationPeriod < _reminderPeriod;
}
}
}

View File

@@ -1,10 +1,12 @@
using System;
using OfficeOpenXml.FormulaParsing.Excel.Functions.Math;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
using ;
using .DATA;
using ;
namespace
{
@@ -21,7 +23,92 @@ namespace 全自动水压检测仪
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
try
PasswordExpirationService expirationService = new PasswordExpirationService();
bool isExpired = expirationService.IsPasswordExpired(DateTime.Parse("2025-12-21"));
bool isExpiringSoon = expirationService.IsPasswordExpiringSoon(DateTime.Parse("2025-12-21"));
if (isExpired)
{
MessageBox.Show("授权已过期,请联系经销商处理");
Application.Run(new ChangPassword());
}
if (isExpiringSoon && !isExpired)
{
MessageBox.Show("授权即将过期,请联系经销商处理");
try
{
// 测试密码加密功能
System.Diagnostics.Debug.WriteLine("\n========================================");
System.Diagnostics.Debug.WriteLine("程序启动 - 密码加密测试");
System.Diagnostics.Debug.WriteLine("========================================");
PasswordHelper.TestPasswordEncryption();
// 检查是否有重置参数
bool forceReset = args.Length > 0 && args[0].ToLower() == "--reset-users";
if (forceReset)
{
var result = MessageBox.Show(
"确定要重置默认用户吗?\n\n这将删除并重新创建\n• admin / admin123 (管理员)\n• csi / 123456 (普通用户)\n\n其他用户不受影响。",
"重置默认用户",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (result == DialogResult.Yes)
{
DatabaseInitializer.Initialize();
DatabaseInitializer.ForceResetDefaultUsers();
MessageBox.Show("默认用户已重置!\n\n管理员: admin / admin123\n普通用户: csi / 123456",
"重置成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
return;
}
// 初始化数据库表和默认管理员账户
System.Diagnostics.Debug.WriteLine("\n========================================");
System.Diagnostics.Debug.WriteLine("初始化数据库");
System.Diagnostics.Debug.WriteLine("========================================");
DatabaseInitializer.Initialize();
// 检查并修复损坏的密码数据
System.Diagnostics.Debug.WriteLine("\n========================================");
System.Diagnostics.Debug.WriteLine("检查密码数据完整性");
System.Diagnostics.Debug.WriteLine("========================================");
CheckAndFixPasswordData();
}
catch (Exception ex)
{
MessageBox.Show($"数据库初始化失败:{ex.Message}\n\n请检查\n1. MySQL服务是否启动\n2. 数据库连接配置是否正确\n3. 数据库 fullautowaterpressure 是否存在\n\n应用程序将退出。",
"初始化错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// 显示登录窗体
using (var loginForm = new LoginForm())
{
if (loginForm.ShowDialog() == DialogResult.OK)
{
// 登录成功,根据用户权限显示对应窗体
if (LoginData.IsAdmin())
{
// 管理员登录,显示 ScanImport 页面
Application.Run(new ScanImport());
}
else
{
// 普通用户登录,显示 NormalTemperatureMode 页面
Application.Run(new NormalTemperatureMode());
}
}
// 登录失败或取消,直接退出
}
}
if (!isExpired && !isExpiringSoon)
{
try
{
// 测试密码加密功能
System.Diagnostics.Debug.WriteLine("\n========================================");
@@ -90,8 +177,10 @@ namespace 全自动水压检测仪
}
// 登录失败或取消,直接退出
}
}
}
/// <summary>
/// 检查并修复损坏的密码数据

View File

@@ -121,6 +121,12 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="ChangPassword.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="ChangPassword.Designer.cs">
<DependentUpon>ChangPassword.cs</DependentUpon>
</Compile>
<Compile Include="Coeffiicientsetting.cs">
<SubType>Form</SubType>
</Compile>
@@ -169,6 +175,7 @@
<Compile Include="Forms\UserManagerForm.Designer.cs">
<DependentUpon>UserManagerForm.cs</DependentUpon>
</Compile>
<Compile Include="PasswordExpirationService.cs" />
<Compile Include="ScanImport.cs">
<SubType>Form</SubType>
</Compile>
@@ -213,6 +220,9 @@
<Compile Include="Report.Designer.cs">
<DependentUpon>Report.cs</DependentUpon>
</Compile>
<EmbeddedResource Include="ChangPassword.resx">
<DependentUpon>ChangPassword.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Coeffiicientsetting.resx">
<DependentUpon>Coeffiicientsetting.cs</DependentUpon>
</EmbeddedResource>