DatabaseHelper.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. using System.Data.SQLite;
  2. using System;
  3. // 并且可能需要处理 SQLite 的原生库(x86/x64)。
  4. public class DatabaseHelper
  5. {
  6. // C# 7.3 完全支持字符串字面量
  7. public static string ConnectionString = "Data Source=app.db;Version=3; Pooling=True;";
  8. public static void InitializeDatabase()
  9. {
  10. //Batteries_V2.Init();
  11. //SQLitePCL.Batteries.Init();
  12. using (var connection = new SQLiteConnection(ConnectionString))
  13. {
  14. connection.Open();
  15. using (var cmd = connection.CreateCommand())
  16. {
  17. // 启用 WAL 模式(只需一次)
  18. cmd.CommandText = "PRAGMA journal_mode=WAL;";
  19. cmd.ExecuteNonQuery();
  20. // 降低同步级别(安全可接受)
  21. cmd.CommandText = "PRAGMA synchronous=NORMAL;";
  22. cmd.ExecuteNonQuery();
  23. }
  24. CreateTablesIfNotExists(connection);
  25. InsertDefaultAdminIfNotExists(connection);
  26. EnsureUserTableColumns(connection);
  27. } // connection 在这里被自动关闭和释放
  28. }
  29. private static void CreateTablesIfNotExists(SQLiteConnection connection)
  30. {
  31. string createUsersTable = @"
  32. CREATE TABLE IF NOT EXISTS Users (
  33. Id INTEGER PRIMARY KEY AUTOINCREMENT,
  34. Username TEXT NOT NULL UNIQUE,
  35. PasswordHash TEXT NOT NULL,
  36. PermissionLevel INTEGER NOT NULL,
  37. CanCloseSoftware INTEGER NOT NULL
  38. );";
  39. string createLogsTable = @"
  40. CREATE TABLE IF NOT EXISTS OperationLogs (
  41. Id INTEGER PRIMARY KEY AUTOINCREMENT,
  42. Timestamp DATETIME NOT NULL DEFAULT (datetime('now','localtime')),
  43. UserId INTEGER NOT NULL,
  44. Username TEXT NOT NULL,
  45. ActionType INTEGER NOT NULL,
  46. ControlName TEXT NOT NULL,
  47. OldValue TEXT,
  48. NewValue TEXT,
  49. Details TEXT,
  50. FOREIGN KEY (UserId) REFERENCES Users(Id)
  51. );";
  52. string createAlarmsTable = @"
  53. CREATE TABLE IF NOT EXISTS AlarmLogs (
  54. Id INTEGER PRIMARY KEY AUTOINCREMENT,
  55. Timestamp DATETIME NOT NULL DEFAULT (datetime('now','localtime')),
  56. UserId INTEGER NOT NULL,
  57. Username TEXT NOT NULL,
  58. AlarmMessage TEXT,
  59. AlarmType INTEGER NOT NULL,
  60. FOREIGN KEY (UserId) REFERENCES Users(Id)
  61. );";
  62. string createTipsTable = @"
  63. CREATE TABLE IF NOT EXISTS TipsLogs (
  64. Id INTEGER PRIMARY KEY AUTOINCREMENT,
  65. Timestamp DATETIME NOT NULL DEFAULT (datetime('now','localtime')),
  66. UserId INTEGER NOT NULL,
  67. Username TEXT NOT NULL,
  68. Message TEXT,
  69. Type INTEGER NOT NULL,
  70. FOREIGN KEY (UserId) REFERENCES Users(Id)
  71. );";
  72. string createBathcesTable = @"
  73. CREATE TABLE IF NOT EXISTS BatchLogs (
  74. Id INTEGER PRIMARY KEY AUTOINCREMENT,
  75. BatchID TEXT NOT NULL UNIQUE, --加 UNIQUE 约束
  76. StartTimestamp DATETIME NOT NULL DEFAULT (datetime('now','localtime')),
  77. StartUserId INTEGER NOT NULL,
  78. StartUsername TEXT NOT NULL,
  79. EndTimestamp DATETIME,
  80. EndUserId INTEGER,
  81. EndUsername TEXT,
  82. RecipeName TEXT,
  83. Details TEXT,
  84. FOREIGN KEY (StartUserId) REFERENCES Users(Id),
  85. FOREIGN KEY (EndUserId) REFERENCES Users(Id)
  86. );";
  87. using (var cmd = connection.CreateCommand())
  88. {
  89. cmd.CommandText = createUsersTable;
  90. cmd.ExecuteNonQuery();
  91. cmd.CommandText = createLogsTable;
  92. cmd.ExecuteNonQuery();
  93. cmd.CommandText = createAlarmsTable;
  94. cmd.ExecuteNonQuery();
  95. cmd.CommandText = createTipsTable;
  96. cmd.ExecuteNonQuery();
  97. cmd.CommandText = createBathcesTable;
  98. cmd.ExecuteNonQuery();
  99. }
  100. }
  101. private static void InsertDefaultAdminIfNotExists(SQLiteConnection connection)
  102. {
  103. // 假设最高权限为 4(你可以根据自己的定义调整)
  104. const string defaultUsername = "developer";
  105. const int developerPermissionLevel = 4; // 最高权限
  106. const string defaultPassword = "developer123"; // 初始密码建议首次登录后强制修改
  107. // 先检查是否有任何用户存在(或更严格地检查 developer 是否存在)
  108. var checkCmd = new SQLiteCommand("SELECT 1 FROM Users LIMIT 1", connection);
  109. var exists = checkCmd.ExecuteScalar() != null;
  110. if (!exists)
  111. {
  112. // 插入默认开发者账户
  113. string passwordHash = BCrypt.Net.BCrypt.HashPassword(defaultPassword);
  114. using (var insertCmd = new SQLiteCommand(@"
  115. INSERT INTO Users (Username, PasswordHash, PermissionLevel,CanCloseSoftware)
  116. VALUES (@username, @hash, @level,@canClose)", connection))
  117. {
  118. insertCmd.Parameters.AddWithValue("@username", defaultUsername);
  119. insertCmd.Parameters.AddWithValue("@hash", passwordHash);
  120. insertCmd.Parameters.AddWithValue("@level", developerPermissionLevel);
  121. insertCmd.Parameters.AddWithValue("@canClose", 1);
  122. insertCmd.ExecuteNonQuery();
  123. // 可选:记录日志(此时可能还不能写日志表)
  124. }
  125. }
  126. }
  127. private static void EnsureUserTableColumns(SQLiteConnection connection)
  128. {
  129. return;
  130. // 检查 RegistrationDate 是否已存在
  131. if (!ColumnExists(connection, "Users", "RegistrationDate"))
  132. {
  133. string addColumnSql = @"
  134. ALTER TABLE Users
  135. ADD COLUMN RegistrationDate DATETIME NOT NULL DEFAULT (datetime('now'));";
  136. using (var cmd = new SQLiteCommand(addColumnSql, connection))
  137. {
  138. cmd.ExecuteNonQuery();
  139. }
  140. }
  141. }
  142. // 辅助方法:检查某表是否包含某列
  143. private static bool ColumnExists(SQLiteConnection connection, string tableName, string columnName)
  144. {
  145. using (var cmd = new SQLiteCommand(@"
  146. SELECT COUNT(*)
  147. FROM pragma_table_info(@tableName)
  148. WHERE name = @columnName", connection))
  149. {
  150. cmd.Parameters.AddWithValue("@tableName", tableName);
  151. cmd.Parameters.AddWithValue("@columnName", columnName);
  152. long count = (long)cmd.ExecuteScalar();
  153. return count > 0;
  154. }
  155. }
  156. }