diff --git a/App.xaml b/App.xaml
new file mode 100644
index 0000000..b394797
--- /dev/null
+++ b/App.xaml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/App.xaml.cs b/App.xaml.cs
new file mode 100644
index 0000000..fe653b1
--- /dev/null
+++ b/App.xaml.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.DependencyInjection;
+using SunlightAggregationTerminal.Models;
+
+namespace SunlightAggregationTerminal
+{
+ public partial class App : Application
+ {
+ public static DataModel GlobalData { get; set;} = new DataModel();
+ public App()
+ {
+ InitializeComponent();
+ }
+
+ protected override Window CreateWindow(IActivationState? activationState)
+ {
+ return new Window(new AppShell());
+ }
+ }
+}
\ No newline at end of file
diff --git a/AppShell.xaml b/AppShell.xaml
new file mode 100644
index 0000000..051864f
--- /dev/null
+++ b/AppShell.xaml
@@ -0,0 +1,46 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AppShell.xaml.cs b/AppShell.xaml.cs
new file mode 100644
index 0000000..c8445dc
--- /dev/null
+++ b/AppShell.xaml.cs
@@ -0,0 +1,35 @@
+using SunlightAggregationTerminal.Class;
+using SunlightAggregationTerminal.Models;
+using SunlightAggregationTerminal.View;
+
+namespace SunlightAggregationTerminal
+{
+ public partial class AppShell : Shell
+ {
+ public AppShell()
+ {
+ InitializeComponent();
+ this.BindingContext = new AppModels();
+ }
+
+
+ private void Shell_Loaded(object sender, EventArgs e)
+ {
+ //打开登录
+ if (!App.GlobalData.LogNo)
+ {
+ var logpage = new View.LogPage();
+ Navigation.PushModalAsync(new NavigationPage(logpage));
+ }
+ else
+ {//发送登录请求
+ /* var dat = TcpServer.Query("");
+ if (dat != null)
+ {//拒绝登陆时打开登录页面
+ var logpage = new View.LogPage();
+ Navigation.PushModalAsync(logpage);
+ }*/
+ }
+ }
+ }
+}
diff --git a/Class/SQLiteConfig.cs b/Class/SQLiteConfig.cs
new file mode 100644
index 0000000..6b4b8b9
--- /dev/null
+++ b/Class/SQLiteConfig.cs
@@ -0,0 +1,312 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace SunlightAggregationTerminal.Class
+{
+
+ public class SQLiteConfig()
+ {
+
+ public static SqliteHelper SQLitedata = null!; //定义数据库
+
+ public static SqliteHelper? Config(string dat)
+ {
+ try
+ {
+ SQLitedata = new SqliteHelper(dat); //数据库连接路径(获取各平台的应用数据目录)
+ SQLitedata.Open(); //打开数据库
+ if (SQLitedata.TableExists("Users"))
+ {
+ CheckAndRepairTableSchema();
+ }
+ else
+ {
+ CreateFreshUserTable();
+ }
+
+ if (SQLitedata.TableExists("Notification"))
+ {
+ CheckAndRepairTableSchemaNotification();
+ }
+ else
+ {
+ CreateFreshUserTableNotification();
+ }
+
+ if (SQLitedata.TableExists("Server"))
+ {
+ CheckAndRepairTableSchemaSERVER();
+ }
+ else
+ {
+ CreateFreshUserTableSERVER();
+ }
+
+ SQLitedata.Close();
+
+ return SQLitedata;
+ }
+ catch (Exception)
+ {
+ return null;
+ }
+ }
+
+ // --- 逻辑分支 表存在,检查字段完整性 ---
+ private static void CheckAndRepairTableSchema()
+ {
+ // 获取现有字段列表
+ // 使用 PRAGMA table_info 获取结构
+ string pragmaSql = "PRAGMA table_info('Users');";
+
+ // 复用现有的 ExecuteReader 方法
+ // ExecuteReader 返回 null 代表出错,否则返回 DataReader
+ using (var reader = SQLitedata.ExecuteReader(pragmaSql, null))
+ {
+ if (reader == null) return;
+
+ var existingColumns = new List();
+ while (reader.Read())
+ {
+ // PRAGMA table_info 返回结果的第2列(Index=1)是列名
+ string colName = reader.GetString(1);
+ existingColumns.Add(colName);
+ }
+ reader.Close(); // 记得关闭 Reader
+
+ // 检查并添加缺失字段 (直接拼接 SQL)
+ // 检查 User
+ if (!existingColumns.Contains("User"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN User TEXT NOT NULL;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 UserId
+ if (!existingColumns.Contains("UserId"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN UserId TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 UserName
+ if (!existingColumns.Contains("UserName"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN UserName TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 UserPassword
+ if (!existingColumns.Contains("UserPassword"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN UserPassword TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Enterprise
+ if (!existingColumns.Contains("Enterprise"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN Enterprise TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Department
+ if (!existingColumns.Contains("Department"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN Department TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 ServerID
+ if (!existingColumns.Contains("ServerID"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN ServerID TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Group
+ if (!existingColumns.Contains("Groups"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN Groups TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 ProxyID
+ if (!existingColumns.Contains("ProxyID"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN ProxyID TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 LogNo
+ if (!existingColumns.Contains("LogNo"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN LogNo BOOL DEFAULT (0);";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 LocalAreaNetworkMode
+ if (!existingColumns.Contains("LocalAreaNetworkMode"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN LocalAreaNetworkMode BOOL DEFAULT (0);";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 LocalAreaNetworkMode
+ if (!existingColumns.Contains("DarkMode"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN DarkMode BOOL DEFAULT (0);";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 LocalAreaNetworkMode
+ if (!existingColumns.Contains("MessageNotificationMode"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN MessageNotificationMode BOOL DEFAULT (0);";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 GUID
+ if (!existingColumns.Contains("GUID"))
+ {
+ string sql = "ALTER TABLE Users ADD COLUMN GUID TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ string sqlupdata = "UPDATE Users SET GUID = '"+ Models.AppModels.GetAppUniqueId() + "';";
+ SQLitedata.ExecuteNonQuery(sqlupdata, null);
+ }
+ }
+ }
+ private static void CheckAndRepairTableSchemaNotification()
+ {
+ // 获取现有字段列表
+ // 使用 PRAGMA table_info 获取结构
+ string pragmaSql = "PRAGMA table_info('Notification');";
+
+ // 复用现有的 ExecuteReader 方法
+ // ExecuteReader 返回 null 代表出错,否则返回 DataReader
+ using (var reader = SQLitedata.ExecuteReader(pragmaSql, null))
+ {
+ if (reader == null) return;
+
+ var existingColumns = new List();
+ while (reader.Read())
+ {
+ // PRAGMA table_info 返回结果的第2列(Index=1)是列名
+ string colName = reader.GetString(1);
+ existingColumns.Add(colName);
+ }
+ reader.Close(); // 记得关闭 Reader
+
+ // 检查并添加缺失字段 (直接拼接 SQL)
+ // 检查 Title
+ if (!existingColumns.Contains("Title"))
+ {
+ string sql = "ALTER TABLE Notification ADD COLUMN Title TEXT NULL;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Content
+ if (!existingColumns.Contains("Content"))
+ {
+ string sql = "ALTER TABLE Notification ADD COLUMN Content TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Time
+ if (!existingColumns.Contains("Time"))
+ {
+ string sql = "ALTER TABLE Notification ADD COLUMN Time TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 Type
+ if (!existingColumns.Contains("Type"))
+ {
+ string sql = "ALTER TABLE Notification ADD COLUMN Type INT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ }
+ }
+ private static void CheckAndRepairTableSchemaSERVER()
+ {
+ // 获取现有字段列表
+ // 使用 PRAGMA table_info 获取结构
+ string pragmaSql = "PRAGMA table_info('Server');";
+
+ // 复用现有的 ExecuteReader 方法
+ // ExecuteReader 返回 null 代表出错,否则返回 DataReader
+ using (var reader = SQLitedata.ExecuteReader(pragmaSql, null))
+ {
+ if (reader == null) return;
+
+ var existingColumns = new List();
+ while (reader.Read())
+ {
+ // PRAGMA table_info 返回结果的第2列(Index=1)是列名
+ string colName = reader.GetString(1);
+ existingColumns.Add(colName);
+ }
+ reader.Close(); // 记得关闭 Reader
+
+ // 检查并添加缺失字段 (直接拼接 SQL)
+ // 检查 Enterprise
+ if (!existingColumns.Contains("Enterprise"))
+ {
+ string sql = "ALTER TABLE Server ADD COLUMN Enterprise TEXT NULL;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ // 检查 ServerID
+ if (!existingColumns.Contains("ServerID"))
+ {
+ string sql = "ALTER TABLE Server ADD COLUMN ServerID TEXT;";
+ SQLitedata.ExecuteNonQuery(sql, null);
+ }
+ }
+ }
+ // --- 逻辑分支 表不存在,直接创建 ---
+ private static void CreateFreshUserTable()
+ {
+ // 建表语句
+ string createSql = @"
+ CREATE TABLE Users (
+ User TEXT NOT NULL,
+ UserId TEXT,
+ UserName TEXT,
+ UserPassword TEXT,
+ Enterprise TEXT,
+ Department TEXT,
+ ServerID TEXT,
+ Groups TEXT,
+ ProxyID TEXT,
+ LogNo BOOL DEFAULT (0),
+ LocalAreaNetworkMode BOOL DEFAULT (0),
+ DarkMode BOOL DEFAULT (0),
+ MessageNotificationMode BOOL DEFAULT (0),
+ GUID TEXT
+ );";
+
+ // 复用现有的 ExecuteNonQuery 方法
+ SQLitedata.ExecuteNonQuery(createSql, null);
+
+ string Sql = @"
+ INSERT INTO Users (User,UserId ,UserName ,UserPassword ,Enterprise ,Department ,ServerID ,Groups ,ProxyID ,LogNo ,LocalAreaNetworkMode ,DarkMode ,MessageNotificationMode ,GUID
+ )VALUES('SUNLIGHT','SUNLIGHT','SUNLIGHT','SUNLIGHT','SUNLIGHT','ENGINEER','TEST','ENGINEER','',0,0,0,0,'"+ Models.AppModels.GetAppUniqueId() + "');";
+
+ // 复用现有的 ExecuteNonQuery 方法
+ SQLitedata.ExecuteNonQuery(Sql, null);
+ }
+ private static void CreateFreshUserTableNotification()
+ {
+ // 建表语句
+ string createSql = @"
+ CREATE TABLE Notification (
+ Id INTEGER PRIMARY KEY AUTOINCREMENT,
+ Title TEXT,
+ Content TEXT,
+ Time TEXT,
+ Type INT
+ );";
+
+ // 复用现有的 ExecuteNonQuery 方法
+ SQLitedata.ExecuteNonQuery(createSql, null);
+ }
+ private static void CreateFreshUserTableSERVER()
+ {
+ // 建表语句
+ string createSql = @"
+ CREATE TABLE Server (
+ Enterprise TEXT,
+ ServerID TEXT
+ );";
+
+ // 复用现有的 ExecuteNonQuery 方法
+ SQLitedata.ExecuteNonQuery(createSql, null);
+ }
+ }
+
+}
diff --git a/Class/SqliteHelper.cs b/Class/SqliteHelper.cs
new file mode 100644
index 0000000..8ccb658
--- /dev/null
+++ b/Class/SqliteHelper.cs
@@ -0,0 +1,504 @@
+using Microsoft.Data.Sqlite;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Data.Common;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+
+namespace SunlightAggregationTerminal.Class
+{
+ public class ClsLock : IDisposable
+ {
+ private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
+
+ public IDisposable Read()
+ {
+ _lock.EnterReadLock();
+ return new DisposableAction(() => _lock.ExitReadLock());
+ }
+
+ public void Dispose() => _lock?.Dispose();
+
+ private class DisposableAction : IDisposable
+ {
+ private readonly Action _action;
+ public DisposableAction(Action action) => _action = action;
+ public void Dispose() => _action?.Invoke();
+ }
+ }
+
+ public class SqliteHelper
+ {
+ #region 字段
+ private SqliteTransaction? dbTrans = null!;
+ private static readonly Dictionary RWL = new Dictionary();
+ private readonly string mDataFile;
+ private readonly string mPassWord = "";
+ private readonly string lockName = "";
+ private SqliteConnection mConn = null!;
+ #endregion
+
+ #region 构造函数
+ public SqliteHelper(string dataFile)
+ {
+ this.mDataFile = dataFile ?? throw new ArgumentNullException(nameof(dataFile));
+ this.mDataFile = dataFile; // 注意:原代码有两次赋值,保留逻辑
+ if (!RWL.ContainsKey(dataFile))
+ {
+ lockName = dataFile;
+ RWL.Add(dataFile, new ClsLock());
+ }
+ }
+
+ public SqliteHelper(string dataFile, string PassWord)
+ {
+ this.mDataFile = dataFile ?? throw new ArgumentNullException(nameof(dataFile));
+ this.mPassWord = PassWord ?? throw new ArgumentNullException(nameof(PassWord));
+ this.mDataFile = dataFile;
+ if (!RWL.ContainsKey(dataFile))
+ {
+ lockName = dataFile;
+ RWL.Add(dataFile, new ClsLock());
+ }
+ }
+ #endregion
+
+ #region 打开/关闭 数据库
+ // 注意:Microsoft.Data.Sqlite.Core 不支持连接字符串构建器,需手动拼接
+ // 加密支持通常需要 Microsoft.Data.Sqlite.Core + SQLitePCLRaw.bundle_green (且加密功能可能受限)
+
+ public void Open()
+ {
+ // 构建连接字符串
+ var connectionString = $"Data Source={mDataFile}";
+ if (!string.IsNullOrWhiteSpace(mPassWord))
+ {
+ connectionString += $";Password={mPassWord}"; // 注意:原生 Microsoft.Data.Sqlite 不支持加密
+ // 如果需要加密,通常需要使用 SQLitePCLRaw 的特定提供程序或第三方库
+ }
+
+ mConn = new SqliteConnection(connectionString);
+
+ // 如果文件不存在,Open() 会自动创建数据库文件
+ // 但表结构需要你自己执行 CREATE TABLE
+ mConn.Open();
+
+ Console.WriteLine("The database was opened successfully");
+ }
+
+ public void Close()
+ {
+ if (this.mConn != null)
+ {
+ try
+ {
+ this.mConn.Close();
+ // 注意:不要在这里移除 RWL,因为这是静态的,可能影响其他实例
+ // if (RWL.ContainsKey(LockName)) { RWL.Remove(LockName); }
+ }
+ catch
+ {
+ Console.WriteLine("Shutdown failed");
+ }
+ }
+ Console.WriteLine("The database was shut down successfully");
+ }
+ #endregion
+
+ #region 事务
+ public void BeginTrain()
+ {
+ EnsureConnection();
+ dbTrans = mConn.BeginTransaction();
+ }
+
+ public void DBCommit()
+ {
+ try
+ {
+ dbTrans?.Commit();
+ dbTrans?.Dispose();
+ dbTrans = null; // 提交后置空
+ }
+ catch (Exception)
+ {
+ dbTrans?.Rollback();
+ dbTrans?.Dispose();
+ dbTrans = null;
+ }
+ }
+ #endregion
+
+ #region 工具
+ // OpenConnection 逻辑已合并到 Open() 方法中,因为 SqliteConnection 构造函数只接受字符串
+
+ public SqliteConnection Connection
+ {
+ get { return mConn; }
+ private set { mConn = value ?? throw new ArgumentNullException(); }
+ }
+
+ protected void EnsureConnection()
+ {
+ if (this.mConn == null)
+ {
+ throw new Exception("SQLiteManager.Connection=null");
+ }
+ if (mConn.State != ConnectionState.Open)
+ {
+ mConn.Open();
+ }
+ }
+
+ public string GetDataFile() => this.mDataFile;
+
+ public bool TableExists(string table)
+ {
+ if (string.IsNullOrEmpty(table)) return false;
+ EnsureConnection();
+
+ // 注意:参数化查询在表名/列名上无效,这里使用字符串拼接(需确保table变量安全)
+ // 或者使用 PRAGMA table_info(table_name)
+ var sql = $"SELECT count(*) FROM sqlite_master WHERE type='table' AND name='{table}'";
+
+ using (var cmd = new SqliteCommand(sql, Connection))
+ {
+ var result = cmd.ExecuteScalar();
+ return Convert.ToInt32(result) > 0;
+ }
+ }
+
+ public bool Vacuum()
+ {
+ try
+ {
+ using (var Command = new SqliteCommand("VACUUM", Connection))
+ {
+ Command.ExecuteNonQuery();
+ }
+ return true;
+ }
+ catch (Exception) // SqliteException
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// 将 IDataReader 转换为 DataSet
+ ///
+ /// 已经执行了查询的 DataReader
+ /// 包含数据的 DataSet
+ public DataSet ReaderToDataSet(IDataReader reader)
+ {
+ DataSet ds = new DataSet();
+
+ do
+ {
+ DataTable schemaTable = reader.GetSchemaTable()!;
+ DataTable dataTable = new DataTable();
+
+ if (schemaTable != null)
+ {
+ // 创建列
+ foreach (DataRow schemaRow in schemaTable.Rows)
+ {
+ string colName = schemaRow["ColumnName"].ToString()!;
+ Type dataType = (Type)schemaRow["DataType"];
+
+ // 防止列名重复
+ string uniqueColName = colName;
+ int i = 1;
+ while (dataTable.Columns.Contains(uniqueColName))
+ {
+ uniqueColName = colName + i++;
+ }
+
+ DataColumn column = new DataColumn(uniqueColName, dataType);
+ dataTable.Columns.Add(column);
+ }
+
+ // 读取行
+ while (reader.Read())
+ {
+ object[] values = new object[dataTable.Columns.Count];
+ for (int i = 0; i < dataTable.Columns.Count; i++)
+ {
+ values[i] = reader.IsDBNull(i) ? DBNull.Value : reader.GetValue(i);
+ }
+ dataTable.Rows.Add(values);
+ }
+ }
+ else
+ {
+ // 如果没有 Schema (例如 "SELECT 1" 这种标量查询)
+ // 需要手动创建列
+ for (int i = 0; i < reader.FieldCount; i++)
+ {
+ dataTable.Columns.Add("Column" + i);
+ }
+ while (reader.Read())
+ {
+ object[] values = new object[reader.FieldCount];
+ reader.GetValues(values);
+ dataTable.Rows.Add(values);
+ }
+ }
+
+ ds.Tables.Add(dataTable);
+ } while (reader.NextResult()); // 处理多个结果集
+
+ return ds;
+ }
+
+ #endregion
+
+
+ #region 执行SQL (Reader & Scalar)
+
+ public SqliteDataReader? ExecuteReader(string sql, SqliteParameter[]? paramArr)
+ {
+ if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql));
+ EnsureConnection();
+
+ // 注意:using 语句会立即释放 Reader,导致无法读取
+ // 这里的 RWL 锁在 using 外部处理,或者调用方自己处理锁
+ // 这里简化逻辑,直接返回 Reader,调用方需自行管理连接状态
+ var cmd = new SqliteCommand(sql, Connection);
+
+ if (paramArr != null)
+ {
+ cmd.Parameters.AddRange(paramArr);
+ }
+
+ // CommandBehavior.CloseConnection 确保 Reader 关闭时连接也关闭
+ // 但这里我们管理连接,所以不加
+ try
+ {
+ // 注意:不要在这里 Dispose Command,否则 Reader 会失效
+ // 返回 Reader,由调用方在读取完毕后关闭
+ return cmd.ExecuteReader();
+ }
+ catch(Exception ex)
+ {
+ Console.WriteLine("[SQLITE_ExecuteReader:err]" + ex.ToString());
+ cmd?.Dispose();
+ return null;
+ }
+ }
+
+ public DataSet? ExecuteDataSet(string sql, SqliteParameter[]? paramArr)
+ {
+ var dat = ExecuteReader(sql, paramArr);
+ if (dat == null)
+ {
+ return null;
+ }
+ return ReaderToDataSet(dat);
+ }
+
+ // ExecuteScalar
+ public object? ExecuteScalar(string sql, SqliteParameter[]? paramArr)
+ {
+ if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql));
+ EnsureConnection();
+
+ using (RWL[lockName].Read())
+ {
+ using (var cmd = new SqliteCommand(sql, Connection))
+ {
+ if (paramArr != null)
+ {
+ cmd.Parameters.AddRange(paramArr);
+ }
+ try
+ {
+ return cmd.ExecuteScalar();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("[SQLITE_ExecuteScalar:err]" + ex.ToString());
+ return null;
+ }
+ }
+ }
+ }
+
+ // QueryOne (返回字典或对象)
+ public Dictionary? QueryOne(string table, string conditionCol, object conditionVal)
+ {
+ if (string.IsNullOrEmpty(table)) return null;
+ EnsureConnection();
+
+ string sql = $"SELECT * FROM [{table}]"; // 使用 [] 防止关键字冲突
+ var parameters = new List();
+
+ if (!string.IsNullOrEmpty(conditionCol))
+ {
+ sql += $" WHERE [{conditionCol}] = @{conditionCol}";
+ parameters.Add(new SqliteParameter($"@{conditionCol}", conditionVal));
+ }
+
+ using (var cmd = new SqliteCommand(sql, Connection))
+ {
+ cmd.Parameters.AddRange(parameters.ToArray());
+ using (var reader = cmd.ExecuteReader())
+ {
+ if (reader.Read())
+ {
+ var dict = new Dictionary();
+ for (int i = 0; i < reader.FieldCount; i++)
+ {
+ var value = reader.GetValue(i);
+ if (value == DBNull.Value) value = null;
+ dict[reader.GetName(i)] = value;
+ }
+ return dict;
+ }
+ }
+ }
+ return null;
+ }
+ #endregion
+
+ #region 增 删 改
+ // 注意:参数前缀统一为 @
+
+ public int InsertData(string table, Dictionary entity)
+ {
+ if (string.IsNullOrEmpty(table)) throw new ArgumentNullException(nameof(table));
+ EnsureConnection();
+
+ string sql = BuildInsert(table, entity);
+ var parameters = BuildParamArray(entity);
+ return ExecuteNonQuery(sql, parameters);
+ }
+
+ public int Update(string table, Dictionary entity, string where, SqliteParameter[]? whereParams)
+ {
+ if (string.IsNullOrEmpty(table)) throw new ArgumentNullException(nameof(table));
+ EnsureConnection();
+
+ string sql = BuildUpdate(table, entity);
+ var parameters = BuildParamArray(entity);
+
+ if (!string.IsNullOrEmpty(where))
+ {
+ sql += " WHERE " + where;
+ if (whereParams != null)
+ {
+ var combined = new SqliteParameter[parameters.Length + whereParams.Length];
+ parameters.CopyTo(combined, 0);
+ whereParams.CopyTo(combined, parameters.Length);
+ parameters = combined;
+ }
+ }
+
+ return ExecuteNonQuery(sql, parameters);
+ }
+
+ public int Delete(string table, string where, SqliteParameter[]? whereParams)
+ {
+ if (string.IsNullOrEmpty(table)) return 0;
+ EnsureConnection();
+
+ string sql = $"DELETE FROM [{table}]";
+ if (!string.IsNullOrEmpty(where))
+ {
+ sql += " WHERE " + where;
+ }
+
+ return ExecuteNonQuery(sql, whereParams);
+ }
+
+ public int ExecuteNonQuery(string sql, SqliteParameter[]? paramArr)
+ {
+ if (string.IsNullOrEmpty(sql)) throw new ArgumentNullException(nameof(sql));
+ EnsureConnection();
+
+ using (RWL[lockName].Read()) // 注意:写操作通常建议用 Write 锁
+ {
+ using (var cmd = new SqliteCommand(sql, Connection))
+ {
+ if (paramArr != null)
+ {
+ cmd.Parameters.AddRange(paramArr);
+ }
+ try
+ {
+ return cmd.ExecuteNonQuery();
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine("[SQLITE_ExecuteScalar:err]" + ex.ToString());
+ return 0;
+ }
+ }
+ }
+ }
+
+ // 构建 SQL 和 参数的方法保持不变,仅泛型类型变更
+ private SqliteParameter[] BuildParamArray(Dictionary entity)
+ {
+ var list = new List();
+ foreach (string key in entity.Keys)
+ {
+ // 注意:参数名必须包含 @ 前缀
+ list.Add(new SqliteParameter($"@{key}", entity[key]));
+ }
+ return list.ToArray();
+ }
+
+ private string BuildInsert(string table, Dictionary entity)
+ {
+ var buf = new StringBuilder();
+ buf.Append("INSERT INTO ").Append(table).Append(" (");
+ var cols = new List();
+ var vals = new List();
+ foreach (string key in entity.Keys)
+ {
+ cols.Add(key);
+ vals.Add($"@{key}");
+ }
+ buf.Append(string.Join(",", cols)).Append(") VALUES (");
+ buf.Append(string.Join(",", vals)).Append(")");
+ return buf.ToString();
+ }
+
+ private string BuildUpdate(string table, Dictionary entity)
+ {
+ var buf = new StringBuilder();
+ buf.Append("UPDATE ").Append(table).Append(" SET ");
+ var sets = new List();
+ foreach (string key in entity.Keys)
+ {
+ sets.Add($"{key} = @{key}");
+ }
+ buf.Append(string.Join(",", sets));
+ return buf.ToString();
+ }
+
+ // 辅助方法:DataRow 转 Dictionary (由于没有 DataTable,通常直接从 Reader 转)
+ // 这里保留原方法签名,但实际使用中可能需要调整
+ public Dictionary DataTableToDictionary(DataTable dataTable)
+ {
+ var result = new Dictionary();
+ if (dataTable.Rows.Count > 0)
+ {
+ var row = dataTable.Rows[0];
+ foreach (DataColumn column in dataTable.Columns)
+ {
+ var value = row[column];
+ if (value == DBNull.Value) value = null;
+ result[column.ColumnName] = value;
+ }
+ }
+ return result;
+ }
+ #endregion
+ }
+}
diff --git a/Class/TcpServer.cs b/Class/TcpServer.cs
new file mode 100644
index 0000000..4f4dd86
--- /dev/null
+++ b/Class/TcpServer.cs
@@ -0,0 +1,54 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using TouchSocket.Core;
+using TouchSocket.Sockets;
+
+namespace SunlightAggregationTerminal.Class
+{
+ public class TcpServer
+ {
+ public static string ServerIP = "";
+ public static string ServerName = "";
+ public static string ServerPassword = "";
+ public static string ServerTerminal = "";
+
+ public static TcpClient tcpClient = new TcpClient();
+
+ public static void Configuration(string ip, string Name, string Password, string Terminal)
+ {
+ ServerIP = ip;
+ ServerName = Name;
+ ServerPassword = Password;
+ ServerTerminal = Terminal;
+ }
+ public static async void Query(string Dat)
+ {
+
+ //发送字符串数据
+ await tcpClient.SendAsync("hello");
+ }
+
+
+ private static async Task CreateCustomService()
+ {
+ tcpClient.Config.SetRemoteIPHost(ServerIP);
+
+ tcpClient.Connecting = (client, e) => { return EasyTask.CompletedTask; };//即将连接到服务器,此时已经创建socket,但是还未建立tcp
+ tcpClient.Connected = (client, e) => { return EasyTask.CompletedTask; };//成功连接到服务器
+ tcpClient.Closing = (client, e) => { return EasyTask.CompletedTask; };//即将从服务器断开连接。此处仅主动断开才有效。
+ tcpClient.Closed = (client, e) => { return EasyTask.CompletedTask; };//从服务器断开连接,当连接不成功时不会触发。
+ #region Tcp客户端使用Received异步委托接收数据
+ tcpClient.Received = (client, e) =>
+ {
+ //从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。
+ var mes = e.Memory.Span.ToString(Encoding.UTF8);
+ tcpClient.Logger.Info($"客户端接收到信息:{mes}");
+ return EasyTask.CompletedTask;
+ };
+ #endregion
+
+ await tcpClient.ConnectAsync();//调用连接,当连接不成功时,会抛出异常。
+ }
+ }
+}
diff --git a/Images/adduserfilled.svg b/Images/adduserfilled.svg
new file mode 100644
index 0000000..7fdd12e
--- /dev/null
+++ b/Images/adduserfilled.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Images/infofeed.svg b/Images/infofeed.svg
new file mode 100644
index 0000000..18c65f8
--- /dev/null
+++ b/Images/infofeed.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/Images/ixnotifications.svg b/Images/ixnotifications.svg
new file mode 100644
index 0000000..ad74185
--- /dev/null
+++ b/Images/ixnotifications.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/Images/lucidescanline.png b/Images/lucidescanline.png
new file mode 100644
index 0000000..ebc6c05
Binary files /dev/null and b/Images/lucidescanline.png differ
diff --git a/Images/search.svg b/Images/search.svg
new file mode 100644
index 0000000..7f99d79
--- /dev/null
+++ b/Images/search.svg
@@ -0,0 +1,8 @@
+
+
diff --git a/InfoPage.xaml b/InfoPage.xaml
new file mode 100644
index 0000000..00e33b1
--- /dev/null
+++ b/InfoPage.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InfoPage.xaml.cs b/InfoPage.xaml.cs
new file mode 100644
index 0000000..c74c0ce
--- /dev/null
+++ b/InfoPage.xaml.cs
@@ -0,0 +1,9 @@
+namespace SunlightAggregationTerminal;
+
+public partial class InfoPage : ContentPage
+{
+ public InfoPage()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/MauiProgram.cs b/MauiProgram.cs
new file mode 100644
index 0000000..0d63c16
--- /dev/null
+++ b/MauiProgram.cs
@@ -0,0 +1,48 @@
+using Microsoft.Extensions.Logging;
+using Microsoft.Maui.Handlers;
+using SunlightAggregationTerminal.Models;
+using ZXing.Net.Maui.Controls;
+
+namespace SunlightAggregationTerminal
+{
+ public static class MauiProgram
+ {
+ public static MauiApp CreateMauiApp()
+ {
+ var builder = MauiApp.CreateBuilder();
+ builder
+ .UseMauiApp()
+ .UseBarcodeReader()
+ .ConfigureFonts(fonts =>
+ {
+ fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
+ fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
+ })
+ .ConfigureMauiHandlers(handlers =>
+ {
+ // 这里的 "NoUnderline" 是自定义映射名称,可以随意命名
+ EntryHandler.Mapper.AppendToMapping("NoUnderline", (handler, view) =>
+ {
+ #if ANDROID
+ // 将背景 tint 设为透明
+ // 这会移除 Android 默认的下划线颜色
+ handler.PlatformView.BackgroundTintList = Android.Content.Res.ColorStateList.ValueOf(Android.Graphics.Color.Transparent);
+
+ // 如果想彻底移除背景绘制(不仅仅是颜色透明)
+ // handler.PlatformView.Background = null;
+ #endif
+ });
+ });
+ // 将 HttpClient 注册为单例服务
+ builder.Services.AddSingleton();
+
+ builder.Services.AddSingleton();
+
+#if DEBUG
+ builder.Logging.AddDebug();
+#endif
+
+ return builder.Build();
+ }
+ }
+}
diff --git a/Models/AppModels.cs b/Models/AppModels.cs
new file mode 100644
index 0000000..c80c9a9
--- /dev/null
+++ b/Models/AppModels.cs
@@ -0,0 +1,89 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using SunlightAggregationTerminal.Class;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Text;
+
+namespace SunlightAggregationTerminal.Models
+{
+ public class AppModels : ObservableObject
+ {
+
+ public static SqliteHelper sqliteHelper = SQLiteConfig.Config(Path.Combine(FileSystem.AppDataDirectory, "MyAppData.db"))!; //数据库连接路径(获取各平台的应用数据目录)
+
+ public AppModels()
+ {
+ if(sqliteHelper != null)
+ {//获取配置信息
+ sqliteHelper.Open();
+ var userdata= sqliteHelper.ExecuteDataSet("select * from Users Where LogNo = 1", null);
+ sqliteHelper.Close();
+ if (userdata != null)
+ {
+ var dat = userdata.Tables[0].AsEnumerable().FirstOrDefault();
+ if (dat != null)
+ {
+ App.GlobalData.UserName = dat.Field("UserName") ?? "";
+ App.GlobalData.UserId = dat.Field("UserId") ?? "";
+ App.GlobalData.User = dat.Field("User") ?? "";
+ App.GlobalData.UserPassword = dat.Field("UserPassword") ?? "";
+ App.GlobalData.Enterprise = dat.Field("Enterprise") ?? "";
+ App.GlobalData.Department = dat.Field("Department") ?? "";
+ App.GlobalData.Groups = dat.Field("Groups") ?? "";
+ App.GlobalData.ServerID = dat.Field("ServerID") ?? "";
+ App.GlobalData.ProxyID = dat.Field("ProxyID") ?? "";
+ App.GlobalData.LogNo = Convert.ToBoolean(dat.Field