Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
47317ca033 | ||
|
|
83cd4915d8 | ||
|
|
25243c03e6 | ||
|
|
b97bfab44f | ||
|
|
40f380f95f | ||
|
|
f8da62df7d | ||
|
|
ff289a0221 | ||
|
|
a14f490032 | ||
|
|
af28d6eba3 | ||
|
|
f80d3f4950 | ||
|
|
40392fccb4 | ||
|
|
95b61a35ac | ||
|
|
ad9cd88b41 | ||
|
|
0122e98b4d | ||
|
|
7b0517c59c | ||
|
|
18cc18740c | ||
|
|
69f2a4e4ed | ||
|
|
ee07bb7eca | ||
|
|
5f3f2ab7bb | ||
|
|
2af3cccba8 | ||
|
|
6dbfa0610e | ||
|
|
395f066568 | ||
|
|
2e3f894a4d | ||
|
|
9e94b03bc4 | ||
|
|
9a3c8f0d80 | ||
|
|
c0e21f9752 | ||
|
|
7cd46d11de | ||
|
|
a72383e422 | ||
|
|
c3c4bfcd68 | ||
|
|
164c229cb2 | ||
|
|
ec1112f641 | ||
|
|
aea7c945ae | ||
|
|
cdacabee03 | ||
|
|
94d1fb6a5d | ||
|
|
130bfb9d7b | ||
|
|
c7afb21ddf | ||
|
|
822fb19d28 | ||
|
|
0b2d726287 | ||
|
|
3ad3523631 | ||
|
|
78aab33698 | ||
|
|
61ac666002 | ||
|
|
9f5afa0fbd | ||
|
|
809cecb54f | ||
|
|
cabba958f5 | ||
|
|
3852fc0142 | ||
|
|
e52dd61baa | ||
|
|
2d1d2bd6bc | ||
|
|
e4d0530cc3 | ||
|
|
5677817e55 | ||
|
|
06bbb5c8be | ||
|
|
6d6bcb623c | ||
|
|
f100d5398c | ||
|
|
0cc16df34c | ||
|
|
3a84a4bdcc | ||
|
|
2e44f1cfb7 | ||
|
|
70dabd0ca6 | ||
|
|
ce3381e776 | ||
|
|
3f4a5a7cd8 | ||
|
|
663410c31f | ||
|
|
e0c949bde9 | ||
|
|
cdbf09cd7f | ||
|
|
f11cb0f809 | ||
|
|
4af3fd5f46 | ||
|
|
2def1ca440 | ||
|
|
4fae724108 | ||
|
|
b1070143a0 | ||
|
|
5ac35c901d | ||
|
|
a5f08f1f8e | ||
|
|
27406f96e9 | ||
|
|
b1c89a3813 | ||
|
|
bfb85171f8 | ||
|
|
2334555c7b | ||
|
|
d4db376de0 | ||
|
|
a485d1cb58 | ||
|
|
b8ec091210 | ||
|
|
cd7a6df16c | ||
|
|
848a39bb44 | ||
|
|
5bdab974cc | ||
|
|
8f16acf5b3 | ||
|
|
7aad6f8d1a | ||
|
|
64dd8ce595 | ||
|
|
321e7d84c2 | ||
|
|
7675362ff5 | ||
|
|
dbb91fe0ee | ||
|
|
dc9da1925d | ||
|
|
c70e3430f9 | ||
|
|
051a36d885 | ||
|
|
c3aed2461a | ||
|
|
c01b362adc | ||
|
|
38be66b380 | ||
|
|
91d640821b | ||
|
|
386a22cef0 | ||
|
|
eb1803f835 | ||
|
|
d8c28f25e2 | ||
|
|
4b87e98b19 | ||
|
|
24a05a6373 | ||
|
|
742b013707 | ||
|
|
954d1458d3 | ||
|
|
f214801a17 | ||
|
|
035aa9b24a | ||
|
|
781cf15641 | ||
|
|
50a8d7f4b2 | ||
|
|
ea4420a42f | ||
|
|
9694a80c89 | ||
|
|
a19faea6cf | ||
|
|
155aff76c7 | ||
|
|
b380dad8f0 | ||
|
|
8e4af75d05 | ||
|
|
da4c744bb3 | ||
|
|
b3b42d129f | ||
|
|
ddaf80c1e2 | ||
|
|
7e8b05dfdf | ||
|
|
182e201f65 | ||
|
|
2c164c1aa0 | ||
|
|
268e7b5b22 | ||
|
|
9432d935c3 | ||
|
|
9787246c76 | ||
|
|
84b76c1eaf | ||
|
|
88e2960500 | ||
|
|
1b50793fb5 | ||
|
|
5a4393aafc | ||
|
|
0a1f94e644 |
No files matched your search
@@ -31,6 +31,12 @@
|
||||
Title="查询"
|
||||
Icon="search.png"
|
||||
ContentTemplate="{DataTemplate local:QueryPage}"/>
|
||||
<!-- 操作页面 -->
|
||||
<!--
|
||||
<ShellContent
|
||||
Title="操作"
|
||||
Icon="IcOutlinePsychologyAlt.png"
|
||||
ContentTemplate="{DataTemplate local:QueryPage}"/>-->
|
||||
<!-- 3 通知页面 -->
|
||||
<ShellContent
|
||||
Title="通知"
|
||||
|
||||
@@ -22,17 +22,22 @@ namespace SunlightAggregationTerminal
|
||||
await Navigation.PushModalAsync(new NavigationPage(logpage));
|
||||
}
|
||||
else
|
||||
{
|
||||
//发送登录请求
|
||||
TcpServer.Configuration(App.GlobalData.ServerID,
|
||||
App.GlobalData.User, App.GlobalData.UserPassword,
|
||||
Models.AppModels.GetAppUniqueId());
|
||||
{
|
||||
var loading = new View.Loading();
|
||||
await Navigation.PushModalAsync(loading);
|
||||
|
||||
if (await AppModels.LogIn())
|
||||
{//拒绝登陆时打开登录页面
|
||||
var logpage = new View.LogPage();
|
||||
await Navigation.PushModalAsync(logpage);
|
||||
{
|
||||
await loading.Navigation.PopModalAsync();
|
||||
}
|
||||
else
|
||||
{//拒绝登陆时打开登录页面
|
||||
await loading.Navigation.PopModalAsync();
|
||||
|
||||
var logpage = new View.LogPage();
|
||||
await Navigation.PushModalAsync(new NavigationPage(logpage));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.Intrinsics.X86;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
|
||||
namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
public class AES
|
||||
{
|
||||
public static string AesEncipher(string Key, string dat) //加密
|
||||
{
|
||||
//压缩
|
||||
byte[] plainBytes = Compress( Encoding.UTF8.GetBytes(dat));
|
||||
|
||||
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
using var aes = System.Security.Cryptography.Aes.Create();
|
||||
|
||||
aes.Key = sha256.ComputeHash(Encoding.UTF8.GetBytes(Key));
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.GenerateIV(); // 生成随机 IV
|
||||
|
||||
using var enc = aes.CreateEncryptor();
|
||||
byte[] cipherBytes = enc.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
|
||||
|
||||
//将 IV (16字节) 和 密文 拼接成一个完整的字节数组
|
||||
byte[] combinedBytes = new byte[aes.IV.Length + cipherBytes.Length];
|
||||
Buffer.BlockCopy(aes.IV, 0, combinedBytes, 0, aes.IV.Length);
|
||||
Buffer.BlockCopy(cipherBytes, 0, combinedBytes, aes.IV.Length, cipherBytes.Length);
|
||||
|
||||
return Convert.ToBase64String(combinedBytes);
|
||||
}
|
||||
|
||||
public static string AesDecrypt(string Key, string dat)//解密
|
||||
{
|
||||
// 解码Base64
|
||||
byte[] cipherBytes = Convert.FromBase64String(dat);
|
||||
|
||||
using var sha256 = System.Security.Cryptography.SHA256.Create();
|
||||
using var aes = System.Security.Cryptography.Aes.Create();
|
||||
|
||||
aes.Key = sha256.ComputeHash(Encoding.UTF8.GetBytes(Key));
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
// 从字节数组中提取前 16 字节作为 IV
|
||||
aes.IV = cipherBytes.AsSpan(0, 16).ToArray();
|
||||
using var dec = aes.CreateDecryptor();
|
||||
|
||||
// 解密
|
||||
byte[] bytes = dec.TransformFinalBlock(cipherBytes, 16, cipherBytes.Length - 16);
|
||||
//解压缩并返回
|
||||
return Encoding.UTF8.GetString(Decompress(bytes));
|
||||
}
|
||||
|
||||
// 3. Brotli 压缩辅助方法
|
||||
private static byte[] Compress(byte[] data)
|
||||
{
|
||||
using var output = new MemoryStream();
|
||||
using (var brotli = new BrotliStream(output, CompressionLevel.Optimal))
|
||||
{
|
||||
brotli.Write(data, 0, data.Length);
|
||||
}
|
||||
return output.ToArray();
|
||||
}
|
||||
|
||||
// 4. Brotli 解压辅助方法
|
||||
private static byte[] Decompress(byte[] data)
|
||||
{
|
||||
using var input = new MemoryStream(data);
|
||||
using var brotli = new BrotliStream(input, CompressionMode.Decompress);
|
||||
using var output = new MemoryStream();
|
||||
brotli.CopyTo(output);
|
||||
return output.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
public class DataReceived
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
public required string User { get; set; }
|
||||
public required string Password { get; set; }
|
||||
public required string IP { get; set; }
|
||||
public required string Terminal { get; set; }
|
||||
public required string Dat { get; set; }
|
||||
}
|
||||
|
||||
public static string GetLocalIpSimple()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 获取当前设备上所有的网络接口
|
||||
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
|
||||
|
||||
foreach (var networkInterface in networkInterfaces)
|
||||
{
|
||||
// 仅检查处于活动状态的网络接口
|
||||
if (networkInterface.OperationalStatus != OperationalStatus.Up)
|
||||
continue;
|
||||
|
||||
// 获取该接口下的所有单播 IP 地址
|
||||
var addresses = networkInterface.GetIPProperties().UnicastAddresses;
|
||||
|
||||
foreach (var address in addresses)
|
||||
{
|
||||
// 筛选条件:必须是 IPv4、非回环地址(127.x.x.x),且通常属于局域网网段
|
||||
if (address.Address.AddressFamily == AddressFamily.InterNetwork &&
|
||||
!IPAddress.IsLoopback(address.Address))
|
||||
{
|
||||
return address.Address.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("获取IP地址失败", ex.Message.ToString(), "是");
|
||||
});
|
||||
}
|
||||
|
||||
return ""; // 如果未找到有效IP则返回null
|
||||
}
|
||||
|
||||
public static string ServerIP = "";
|
||||
public static string ServerURL = "";
|
||||
public static string ServerName = "";
|
||||
public static string ServerPassword = "";
|
||||
public static string ServerTerminal = "";
|
||||
|
||||
public static void Received(string dat)
|
||||
{
|
||||
if (dat.Length < 6)
|
||||
{
|
||||
string inf;
|
||||
switch (dat)
|
||||
{
|
||||
case "999":
|
||||
inf = "不明错误";
|
||||
break;
|
||||
case "990":
|
||||
inf = "拒接访问账户远程访问许可证过期";
|
||||
break;
|
||||
case "980":
|
||||
inf = "目标对象服务器不存在或已离线";
|
||||
break;
|
||||
case "970":
|
||||
inf = "目标对象服务器不存在或已离线";
|
||||
break;
|
||||
default:
|
||||
inf = dat;
|
||||
break;
|
||||
}
|
||||
|
||||
// MainThread.BeginInvokeOnMainThread(() =>
|
||||
// {
|
||||
// Application.Current!.Windows[0].Page!.DisplayAlertAsync("", inf, "是");
|
||||
// });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
Person deserializedPerson = JsonSerializer.Deserialize<Person>(dat)!;
|
||||
var data = JsonSerializer.Deserialize<Dictionary<string, object>>
|
||||
(AES.AesDecrypt( deserializedPerson.Terminal,deserializedPerson.Dat));
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
//处理服务器发送信息
|
||||
if (data.TryGetValue("Enterprise", out var val) && val != null) App.GlobalData.Enterprise = val.ToString() ?? "";
|
||||
if (data.TryGetValue("Department", out val) && val != null) App.GlobalData.Department = val.ToString() ?? "";
|
||||
if (data.TryGetValue("Groups", out val) && val != null) App.GlobalData.Groups = val.ToString() ?? "";
|
||||
if (data.TryGetValue("UserName", out val) && val != null) App.GlobalData.UserName = val.ToString() ?? "";
|
||||
if (data.TryGetValue("UserId", out val) && val != null)
|
||||
{
|
||||
DataReceived.Transmit("{\"Command\":\"Info\"}");
|
||||
App.GlobalData.UserId = val.ToString() ?? "";
|
||||
App.GlobalData.LogNo = true;
|
||||
}
|
||||
|
||||
if (data.TryGetValue("UserData", out var value_UserData))
|
||||
{
|
||||
|
||||
}
|
||||
if (data.TryGetValue("SysData", out var value_SysData))
|
||||
{
|
||||
var tmp = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(value_SysData.ToString()!)!;
|
||||
}
|
||||
if (data.TryGetValue("Info", out val) && val != null)//机台信息接受
|
||||
{
|
||||
DataModel.Info_data = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(val.ToString()!)!;
|
||||
InfoPage.DyeMeasurementNumber = data.GetValue("DyeMeasurementNumber").ToString();
|
||||
InfoPage.ChemicalNumber = data.GetValue("ChemicalNumber").ToString();
|
||||
InfoPage.PowderNumber = data.GetValue("PowderNumber").ToString();
|
||||
InfoPage.DyeDissolveNumber = data.GetValue("DyeDissolveNumber").ToString();
|
||||
|
||||
//发送消息
|
||||
WeakReferenceMessenger.Default.Send(new object());
|
||||
}
|
||||
if (data.TryGetValue("ChemicalStatistics", out val) && val != null)//查询接受
|
||||
{
|
||||
InfoChemicalStatistics.Total_data(val.ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("Query", out val) && val != null)//查询接受
|
||||
{
|
||||
QueryPage.Query_data(val.ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("QueryDetail", out val) && val != null)//
|
||||
{
|
||||
QueryDetail.Query_data(val.ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("InfoMachine", out val) && val != null)//
|
||||
{
|
||||
InfoDetail.Info_data(val.ToString()!, data.GetValue("Type").ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("InfoMachineHistory", out val) && val != null)//
|
||||
{
|
||||
InfoDetail.Info_data(val.ToString()!, data.GetValue("Type").ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("InfoMachinePipes", out val) && val != null)//
|
||||
{
|
||||
InfoDetail.Info_data(val.ToString()!, "00");
|
||||
}
|
||||
if (data.TryGetValue("Notification", out val) && val != null)//信息通知接受
|
||||
{
|
||||
var dataNotification = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(val.ToString()!);
|
||||
|
||||
string _Title = "", _Content = "";
|
||||
int _Type = 0, _id = 0;
|
||||
|
||||
foreach (var dataNotificationrow in dataNotification!)
|
||||
{
|
||||
//解析信息
|
||||
if (dataNotificationrow!.TryGetValue("id", out var value_Notification_id)
|
||||
&& value_Notification_id != null)
|
||||
{
|
||||
_id = (int)value_Notification_id;
|
||||
App.GlobalData.NotificationID = _id.ToString();
|
||||
}
|
||||
if (dataNotificationrow!.TryGetValue("Title", out var value_Notification_Title)
|
||||
&& value_Notification_Title != null)
|
||||
{
|
||||
_Title = value_Notification_Title.ToString() ?? "";
|
||||
}
|
||||
if (dataNotificationrow!.TryGetValue("Content", out var value_Notification_Content)
|
||||
&& value_Notification_Content != null)
|
||||
{
|
||||
_Content = value_Notification_Content.ToString() ?? "";
|
||||
}
|
||||
if (dataNotificationrow!.TryGetValue("Type", out var value_Notification_Type)
|
||||
&& value_Notification_Type != null)
|
||||
{
|
||||
string temp = value_Notification_Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"System" => 2,
|
||||
"Message" => 1,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
if (_id != 0)
|
||||
{
|
||||
//记录信息到数据库
|
||||
DataSet? Notificationdata = AppModels.Select("select * from Notification where Id = " + _id);
|
||||
if (Notificationdata != null)
|
||||
{
|
||||
if (Notificationdata.Tables[0].Rows.Count == 0)
|
||||
{
|
||||
AppModels.INSERT("INSERT INTO Notification (Title,Content,Time,Type,Id)VALUES('" +
|
||||
_Title + "','" + _Content + "','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") +
|
||||
"','" + _Type + "'," + _id + ");");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string sql = "UPDATE Users SET NotificationID = '" + App.GlobalData.NotificationID +
|
||||
"'WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
}
|
||||
if (data.TryGetValue("SETUSER", out val) && val != null)//信息通知接受
|
||||
{
|
||||
ProfilePage._data(data.GetValue("VALUE").ToString()!,data.GetValue("KEY").ToString()!);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("", ex.Message.ToString(), "是");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Transmit(string Dat)
|
||||
{
|
||||
if (App.GlobalData.LocalAreaNetworkMode)
|
||||
{
|
||||
TcpServer.TcpTransmit(Dat);
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpServer.HttpTransmit(Dat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
using TouchSocket.Http;
|
||||
using TouchSocket.Http.WebSockets;
|
||||
using TouchSocket.Sockets;
|
||||
using static SunlightAggregationTerminal.Class.TcpServer;
|
||||
|
||||
namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
public class HttpServer
|
||||
{
|
||||
public static TouchSocket.Http.HttpClient httpclient = new TouchSocket.Http.HttpClient();
|
||||
|
||||
public static async void Configuration(string ip, string Name, string Password, string Terminal)
|
||||
{
|
||||
string[] parts = ip.Split('/');
|
||||
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
DataReceived.ServerIP = parts[0];
|
||||
DataReceived.ServerURL = parts[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
DataReceived.ServerIP = "";
|
||||
DataReceived.ServerURL = "";
|
||||
}
|
||||
DataReceived.ServerName = Name;
|
||||
DataReceived.ServerPassword = Password;
|
||||
DataReceived.ServerTerminal = Terminal;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ip))
|
||||
{
|
||||
App.GlobalData.LogNo = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
await HttpClient(DataReceived.ServerIP);
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task HttpClient(string url)
|
||||
{
|
||||
try
|
||||
{
|
||||
var config = new TouchSocketConfig();
|
||||
#region Http设置远程服务器地址
|
||||
config.SetRemoteIPHost("http://" + url);
|
||||
#endregion
|
||||
|
||||
#region Http客户端获取断线通知
|
||||
config.ConfigurePlugins(a =>
|
||||
{
|
||||
//处理连接断开
|
||||
a.AddTcpClosedPlugin(async (c, e) =>
|
||||
{
|
||||
//MainThread.BeginInvokeOnMainThread(() =>
|
||||
// {
|
||||
// Application.Current!.Windows[0].Page!.DisplayAlertAsync("", "客户端断开连接", "是");
|
||||
// });
|
||||
// await e.InvokeNext();
|
||||
});
|
||||
//自动重连
|
||||
a.UseReconnection<TouchSocket.Http.HttpClient>(options =>
|
||||
{
|
||||
options.PollingInterval = TimeSpan.FromSeconds(3);
|
||||
});
|
||||
//处理连接
|
||||
a.AddTcpConnectedPlugin(async (c, e) =>
|
||||
{
|
||||
await e.InvokeNext();
|
||||
});
|
||||
});
|
||||
#endregion
|
||||
|
||||
if (httpclient.Online)//是否重置客户端
|
||||
{
|
||||
await httpclient.CloseAsync();
|
||||
}
|
||||
|
||||
//配置config
|
||||
await httpclient.SetupAsync(config);
|
||||
//连接
|
||||
await httpclient.ConnectAsync();
|
||||
|
||||
HttpTransmit("{\"Command\":\"Log\"}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("网络错误", ex.Message.ToString(), "是");
|
||||
});
|
||||
await httpclient.CloseAsync();
|
||||
httpclient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/***发送信息处理***/
|
||||
private static int HttpOutN=0;
|
||||
public static async void HttpTransmit(string Dat)
|
||||
{
|
||||
if (!httpclient.Online) //检查连接
|
||||
{
|
||||
await httpclient.ConnectAsync();
|
||||
}
|
||||
|
||||
var dat = new DataReceived.Person()
|
||||
{
|
||||
User = DataReceived.ServerName,
|
||||
Password = AES.AesEncipher(DataReceived.ServerTerminal, DataReceived.ServerPassword),
|
||||
IP = DataReceived.GetLocalIpSimple(),
|
||||
Terminal = DataReceived.ServerTerminal,
|
||||
Dat = AES.AesEncipher(DataReceived.ServerTerminal, Dat),
|
||||
};
|
||||
|
||||
var request = new HttpRequest();
|
||||
request.SetContent(new StringHttpContent(JsonSerializer.Serialize(dat), Encoding.UTF8, "application/scjson"))
|
||||
.InitHeaders()
|
||||
.SetUrl(DataReceived.ServerURL)
|
||||
.SetHost(httpclient.RemoteIPHost.Host)
|
||||
.AsPost();
|
||||
|
||||
// 创建一个超时操作,15秒后取消
|
||||
using var cts = new CancellationTokenSource(1000 * 10);
|
||||
try
|
||||
{
|
||||
using (var responseResult = await httpclient.RequestAsync(request, cts.Token))
|
||||
{
|
||||
var response = responseResult.Response;
|
||||
// GetBodyAsync 同样需要响应取消信号,如果这里超过剩余时间也会抛出异常
|
||||
var result = await response.GetBodyAsync();
|
||||
DataReceived.Received(result);
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
if (HttpOutN >= 3)
|
||||
{
|
||||
HttpOutN = 0;
|
||||
// 专门处理超时或主动取消的情况
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("网络错误", "网络请求超时,请检查网络网络连接", "是");
|
||||
});
|
||||
await httpclient.CloseAsync();
|
||||
httpclient.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpTransmit(Dat);//回调
|
||||
HttpOutN++;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (HttpOutN >= 3)
|
||||
{
|
||||
HttpOutN = 0;
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("访问错误", ex.Message.ToString(), "是");
|
||||
});
|
||||
await httpclient.CloseAsync();
|
||||
httpclient.Dispose();
|
||||
}
|
||||
else
|
||||
{
|
||||
HttpTransmit(Dat);//回调
|
||||
HttpOutN++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -118,6 +118,12 @@ namespace SunlightAggregationTerminal.Class
|
||||
string sql = "ALTER TABLE Users ADD COLUMN ServerID TEXT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
// 检查 ServerID
|
||||
if (!existingColumns.Contains("ServerHTTP"))
|
||||
{
|
||||
string sql = "ALTER TABLE Users ADD COLUMN ServerHTTP TEXT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
// 检查 Group
|
||||
if (!existingColumns.Contains("Groups"))
|
||||
{
|
||||
@@ -154,6 +160,12 @@ namespace SunlightAggregationTerminal.Class
|
||||
string sql = "ALTER TABLE Users ADD COLUMN MessageNotificationMode BOOL DEFAULT (0);";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
// 检查 NotificationID
|
||||
if (!existingColumns.Contains("NotificationID"))
|
||||
{
|
||||
string sql = "ALTER TABLE Users ADD COLUMN NotificationID TEXT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
// 检查 GUID
|
||||
if (!existingColumns.Contains("GUID"))
|
||||
{
|
||||
@@ -209,7 +221,13 @@ namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
string sql = "ALTER TABLE Notification ADD COLUMN Type INT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
}
|
||||
// 检查 id
|
||||
if (!existingColumns.Contains("Id"))
|
||||
{
|
||||
string sql = "ALTER TABLE Notification ADD COLUMN Id INTEGER PRIMARY KEY;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void CheckAndRepairTableSchemaSERVER()
|
||||
@@ -250,7 +268,12 @@ namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
string sql = "ALTER TABLE Server ADD COLUMN ServerID TEXT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
}
|
||||
if (!existingColumns.Contains("ServerHTTP"))
|
||||
{
|
||||
string sql = "ALTER TABLE Server ADD COLUMN ServerHTTP TEXT;";
|
||||
SQLitedata.ExecuteNonQuery(sql, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
// --- 逻辑分支 表不存在,直接创建 ---
|
||||
@@ -266,12 +289,14 @@ namespace SunlightAggregationTerminal.Class
|
||||
Enterprise TEXT,
|
||||
Department TEXT,
|
||||
ServerID TEXT,
|
||||
ServerHTTP TEXT,
|
||||
Groups TEXT,
|
||||
ProxyID TEXT,
|
||||
LogNo BOOL DEFAULT (0),
|
||||
LocalAreaNetworkMode BOOL DEFAULT (0),
|
||||
DarkMode BOOL DEFAULT (0),
|
||||
MessageNotificationMode BOOL DEFAULT (0),
|
||||
NotificationID TEXT,
|
||||
GUID TEXT
|
||||
);";
|
||||
|
||||
@@ -290,7 +315,7 @@ namespace SunlightAggregationTerminal.Class
|
||||
// 建表语句
|
||||
string createSql = @"
|
||||
CREATE TABLE Notification (
|
||||
Id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
Id INTEGER PRIMARY KEY,
|
||||
Title TEXT,
|
||||
Content TEXT,
|
||||
Time TEXT,
|
||||
@@ -307,7 +332,8 @@ namespace SunlightAggregationTerminal.Class
|
||||
CREATE TABLE Server (
|
||||
START BOOL DEFAULT (0),
|
||||
Server TEXT,
|
||||
ServerID TEXT
|
||||
ServerID TEXT,
|
||||
ServerHTTP TEXT
|
||||
);";
|
||||
|
||||
// 复用现有的 ExecuteNonQuery 方法
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
public class SecureJsonService
|
||||
{
|
||||
private static readonly byte[] _aesKey = Encoding.UTF8.GetBytes("12345678901234567890123456789012");
|
||||
private static readonly byte[] _aesKey = Encoding.UTF8.GetBytes("1234567890");
|
||||
|
||||
/// <summary>
|
||||
/// 调用一:发送端处理
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.VisualBasic;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
@@ -10,57 +14,35 @@ using TouchSocket.Sockets;
|
||||
namespace SunlightAggregationTerminal.Class
|
||||
{
|
||||
public class TcpServer
|
||||
{
|
||||
public class Person
|
||||
{
|
||||
public required string User { get; set; }
|
||||
public required string Password { get; set; }
|
||||
public required string IP { get; set; }
|
||||
public required string Terminal { get; set; }
|
||||
public required string Dat { get; set; }
|
||||
}
|
||||
|
||||
public static string GetLocalIpSimple()
|
||||
{
|
||||
var host = Dns.GetHostEntry(Dns.GetHostName());
|
||||
foreach (var ip in host.AddressList)
|
||||
{
|
||||
if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
|
||||
{
|
||||
return ip.ToString();
|
||||
}
|
||||
}
|
||||
return "No network connection";
|
||||
}
|
||||
|
||||
public static string ServerIP = "";
|
||||
public static string ServerName = "";
|
||||
public static string ServerPassword = "";
|
||||
public static string ServerTerminal = "";
|
||||
|
||||
{
|
||||
public static TouchSocket.Sockets.TcpClient tcpClient = new TouchSocket.Sockets.TcpClient();
|
||||
|
||||
public static void Configuration(string ip, string Name, string Password, string Terminal)
|
||||
public static async void Configuration(string ip, string Name, string Password, string Terminal)
|
||||
{
|
||||
ServerIP = ip;
|
||||
ServerName = Name;
|
||||
ServerPassword = Password;
|
||||
ServerTerminal = Terminal;
|
||||
DataReceived.ServerIP = ip;
|
||||
DataReceived.ServerName = Name;
|
||||
DataReceived.ServerPassword = Password;
|
||||
DataReceived.ServerTerminal = Terminal;
|
||||
|
||||
_ = TcpClient(tcpClient, ServerIP);
|
||||
await TcpClient(tcpClient, DataReceived.ServerIP);
|
||||
}
|
||||
|
||||
// 引入发送锁,彻底解决连续发送导致的并发断连问题
|
||||
private static readonly SemaphoreSlim _sendLock = new SemaphoreSlim(1, 1);
|
||||
public static async void TcpTransmit(string Dat)
|
||||
{
|
||||
var dat = new Person()
|
||||
var dat = new DataReceived.Person()
|
||||
{
|
||||
User = ServerName,
|
||||
Password = ServerPassword,
|
||||
IP = GetLocalIpSimple(),
|
||||
Terminal = ServerTerminal,
|
||||
User = DataReceived.ServerName,
|
||||
Password = DataReceived.ServerPassword,
|
||||
IP = DataReceived.GetLocalIpSimple(),
|
||||
Terminal = DataReceived.ServerTerminal,
|
||||
Dat = Dat
|
||||
};
|
||||
|
||||
//SecureJsonService.CompressEncryptAndSend();
|
||||
// 使用锁确保同一时间只有一个任务在发送,防止并发写入导致 Socket 异常
|
||||
await _sendLock.WaitAsync();
|
||||
|
||||
//发送字符串数据
|
||||
try
|
||||
{
|
||||
@@ -68,91 +50,35 @@ namespace SunlightAggregationTerminal.Class
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Application.Current!.Windows[0].Page!.DisplayAlertAsync("错误", ex.ToString(), "是");
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("错误", ex.Message.ToString(), "是");
|
||||
});
|
||||
}
|
||||
finally
|
||||
{
|
||||
_sendLock.Release(); // 释放锁
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static async Task TcpClient(TouchSocket.Sockets.TcpClient tcpClient, string ip)
|
||||
{
|
||||
tcpClient.Connecting = (client, e) => { return EasyTask.CompletedTask; };//即将连接到服务器,此时已经创建socket,但是还未建立tcp
|
||||
tcpClient.Connected = (client, e) => {
|
||||
TcpServer.TcpTransmit("Log");
|
||||
return EasyTask.CompletedTask; };//成功连接到服务器
|
||||
tcpClient.Closing = (client, e) => { return EasyTask.CompletedTask; };//即将从服务器断开连接。此处仅主动断开才有效。
|
||||
tcpClient.Closed = (client, e) => { return EasyTask.CompletedTask; };//从服务器断开连接,当连接不成功时不会触发。
|
||||
tcpClient.Connected = (client, e) =>
|
||||
{
|
||||
TcpServer.TcpTransmit("{\"Command\":\"Log\"}");
|
||||
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);
|
||||
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<Dictionary<string, object>>(mes);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
//处理服务器发送信息
|
||||
if (data.TryGetValue("Enterprise", out var val) && val != null) App.GlobalData.Enterprise = val.ToString() ?? "";
|
||||
if (data.TryGetValue("Department", out val) && val != null) App.GlobalData.Department = val.ToString() ?? "";
|
||||
if (data.TryGetValue("Groups", out val) && val != null) App.GlobalData.Groups = val.ToString() ?? "";
|
||||
if (data.TryGetValue("UserName", out val) && val != null) App.GlobalData.UserName = val.ToString() ?? "";
|
||||
if (data.TryGetValue("UserId", out val) && val != null)
|
||||
{
|
||||
App.GlobalData.UserId = val.ToString() ?? "";
|
||||
App.GlobalData.LogNo = true;
|
||||
}
|
||||
|
||||
if (data.TryGetValue("UserData", out var value_UserData))
|
||||
{
|
||||
|
||||
}
|
||||
if (data.TryGetValue("SysData", out var value_SysData))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (data.TryGetValue("Query", out val) && val != null)//查询接受
|
||||
{
|
||||
QueryPage.Query_data(val.ToString()!);
|
||||
}
|
||||
if (data.TryGetValue("Notification", out val) && val != null)//信息通知接受
|
||||
{
|
||||
var dataNotification = JsonSerializer.Deserialize<Dictionary<string, object>>(val.ToString()!);
|
||||
|
||||
string _Title = "", _Content = "";
|
||||
int _Type = 0;
|
||||
|
||||
if (dataNotification!.TryGetValue("Title", out var value_Notification_Title))
|
||||
{
|
||||
_Title = value_Notification_Title.ToString() ?? "";
|
||||
}
|
||||
if (dataNotification!.TryGetValue("Content", out var value_Notification_Content))
|
||||
{
|
||||
_Content = value_Notification_Content.ToString() ?? "";
|
||||
}
|
||||
if (dataNotification!.TryGetValue("Type", out var value_Notification_Type))
|
||||
{
|
||||
string temp = value_Notification_Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"System" => 2,
|
||||
"Message" => 1,
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
Models.AppModels.INSERT("INSERT INTO Notification (Title,Content,Time,Type)VALUES('" +
|
||||
_Title + "','" + _Content + "','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "','" + _Type + "');");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception) { }
|
||||
|
||||
DataReceived.Received(mes);
|
||||
|
||||
return EasyTask.CompletedTask;
|
||||
};
|
||||
#endregion
|
||||
@@ -160,12 +86,24 @@ namespace SunlightAggregationTerminal.Class
|
||||
try
|
||||
{
|
||||
await tcpClient.SetupAsync(new TouchSocketConfig()
|
||||
.SetRemoteIPHost(ip));
|
||||
.SetSingleStreamDataHandlingAdapter(() => new PeriodPackageAdapter())//以超时周期和包
|
||||
.SetRemoteIPHost(ip)
|
||||
.ConfigurePlugins(a =>
|
||||
{
|
||||
a.UseReconnection<TouchSocket.Sockets.TcpClient>(options =>
|
||||
{
|
||||
options.PollingInterval = TimeSpan.FromSeconds(5);
|
||||
});
|
||||
}));
|
||||
|
||||
await tcpClient.ConnectAsync();//调用连接,当连接不成功时,会抛出异常。
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
await Application.Current!.Windows[0].Page!.DisplayAlertAsync("错误", ex.ToString(), "是");
|
||||
MainThread.BeginInvokeOnMainThread(() =>
|
||||
{
|
||||
Application.Current!.Windows[0].Page!.DisplayAlertAsync("网络错误", ex.Message.ToString(), "是");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
|
||||
namespace SunlightAggregationTerminal.Converters
|
||||
{
|
||||
public class StringToBoolConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value !=null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
// 单向绑定
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Globalization;
|
||||
using Microsoft.Maui.Controls;
|
||||
|
||||
namespace SunlightAggregationTerminal.Converters
|
||||
{
|
||||
public class StringToImageConverter: IValueConverter
|
||||
{
|
||||
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
if (value !=null)
|
||||
{
|
||||
// 根据字符串内容返回对应的图片路径
|
||||
// 确保你的 Resources/Raw 或 Resources/Images 目录下有这些图片
|
||||
if (value.ToString() == "252") return ImageSource.FromFile("sc252rb.png");
|
||||
else if (value.ToString() == "252-2T") return ImageSource.FromFile("sc2522t.png");
|
||||
else if (value.ToString() == "252RB") return ImageSource.FromFile("sc252rb.png");
|
||||
else if (value.ToString() == "252RDRM") return ImageSource.FromFile("sc252rmrd.png");
|
||||
else if (value.ToString() == "242W") return ImageSource.FromFile("sc242w.png");
|
||||
else if (value.ToString() == "302") return ImageSource.FromFile("sc302.png");
|
||||
else if (value.ToString() == "303") return ImageSource.FromFile("sc303.png");
|
||||
else if (value.ToString() == "303PDW") return ImageSource.FromFile("sc303pdw.png");
|
||||
else return ImageSource.FromFile("sunlightlogo.png");
|
||||
}
|
||||
|
||||
// 如果值为空或类型不对,返回默认值或 null
|
||||
return ImageSource.FromFile("sunlightlogo.png");
|
||||
}
|
||||
|
||||
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 24 24"><path fill="currentColor" d="M19.94 9.06C19.5 5.73 16.57 3 13 3C9.47 3 6.57 5.61 6.08 9l-1.93 3.48c-.41.66.07 1.52.85 1.52h1v2c0 1.1.9 2 2 2h1v3h7v-4.68a7.02 7.02 0 0 0 3.94-7.26m-5.05 5.57l-.89.42V19h-3v-3H8v-4H6.7l1.33-2.33C8.21 7.06 10.35 5 13 5c2.76 0 5 2.24 5 5c0 2.09-1.29 3.88-3.11 4.63"/><path fill="currentColor" d="M12.5 12.54c-.41 0-.74.31-.74.73c0 .41.33.74.74.74c.42 0 .73-.33.73-.74a.71.71 0 0 0-.73-.73m0-5.54c-1.03 0-1.74.67-2 1.45l.96.4c.13-.39.43-.86 1.05-.86c.95 0 1.13.89.8 1.36c-.32.45-.86.75-1.14 1.26c-.23.4-.18.87-.18 1.16h1.06c0-.55.04-.65.13-.82c.23-.42.65-.62 1.09-1.27c.4-.59.25-1.38-.01-1.8c-.31-.49-.9-.88-1.76-.88"/></svg>
|
||||
|
After Width: | Height: | Size: 738 B |
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.InfoChemicalStatistics"
|
||||
Title="耗用统计">
|
||||
<Grid>
|
||||
<Grid RowDefinitions="Auto, *" >
|
||||
<Grid ColumnDefinitions="*, Auto" Grid.Row="0" Grid.Column="0" Margin="5">
|
||||
<HorizontalStackLayout Grid.Row="0" Grid.Column="0" Margin="5,0,0,0" >
|
||||
<DatePicker x:Name="StartTime" Format="yyyy年MM月dd日" FontSize="16"
|
||||
MaximumWidthRequest="150" MinimumWidthRequest="130" WidthRequest="135"/>
|
||||
<Label Text="~" FontSize="28"/>
|
||||
<DatePicker x:Name="EndTime" Format="yyyy年MM月dd日" FontSize="16"
|
||||
MaximumWidthRequest="150" MinimumWidthRequest="130" WidthRequest="135"/>
|
||||
</HorizontalStackLayout>
|
||||
<Button Grid.Row="0" Grid.Column="1" Text="查询" Clicked="Button_Clicked"
|
||||
WidthRequest="60" Padding="5,0,5,0" Margin="20,0,0,5" />
|
||||
</Grid>
|
||||
<CollectionView Grid.Row="1" x:Name="CardCollectionView">
|
||||
<!-- 保持滚动条 -->
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<!-- 这里定义单个卡片的 UI 结构 -->
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10"
|
||||
StrokeShape="RoundRectangle 10">
|
||||
<VerticalStackLayout>
|
||||
<!-- 设备信息 -->
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="原料: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ProductName}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="代码: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ProductCode}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="用量: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding TotalDispenseGrams}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="Kg" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
<!-- 查询中动画页面 -->
|
||||
<Grid x:Name="LoadingIndicator" BackgroundColor="Gray"
|
||||
IsVisible="False" Opacity="0.9">
|
||||
<VerticalStackLayout Padding="30" Spacing="10"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator IsRunning="True"
|
||||
Color="#512BD4"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Label Text="查询中..." FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,89 @@
|
||||
using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
public partial class InfoChemicalStatistics : ContentPage
|
||||
{
|
||||
public class ChemicalTotal
|
||||
{
|
||||
public string? ProductName { get; set; }
|
||||
public string? ProductCode { get; set; }
|
||||
public float? TotalDispenseGrams { get; set; }
|
||||
}
|
||||
|
||||
public static ObservableCollection<ChemicalTotal> ChemicalTotals { get; set; } = new();
|
||||
public InfoChemicalStatistics()
|
||||
{
|
||||
InitializeComponent();
|
||||
Dictionary<string, object> Dictionary = new Dictionary<string, object>();
|
||||
Dictionary.Add("Command", "ChemicalStatistics");
|
||||
DateTime StartTimee_ = (DateTime)StartTime.Date!;
|
||||
Dictionary.Add("StartTime", StartTimee_.ToString("yyyy-MM-dd"));
|
||||
DateTime EndTime_ = (DateTime)EndTime.Date!;
|
||||
Dictionary.Add("EndTime", EndTime_.AddDays(1).ToString("yyyy-MM-dd"));
|
||||
Total_Command(Dictionary.ToJsonString());
|
||||
}
|
||||
|
||||
public async void Total_Command(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
ChemicalTotals.Clear();
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 15 秒的延时任务
|
||||
Task delayTask = Task.Delay(15000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (ChemicalTotals.Count == 0)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(100);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
await Task.WhenAny(delayTask, monitorTask);
|
||||
CardCollectionView.ItemsSource = ChemicalTotals;
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
|
||||
public static void Total_data(string dat)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<List<ChemicalTotal>>(dat);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
foreach (var item in data)
|
||||
{
|
||||
item.TotalDispenseGrams = MathF.Round((float)item.TotalDispenseGrams! / 1000, 5);
|
||||
|
||||
ChemicalTotals.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//搜索按钮
|
||||
private void Button_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
Dictionary<string, object> Dictionary = new Dictionary<string, object>();
|
||||
Dictionary.Add("Command", "ChemicalStatistics");
|
||||
DateTime StartTimee_ = (DateTime)StartTime.Date!;
|
||||
Dictionary.Add("StartTime", StartTimee_.ToString("yyyy-MM-dd"));
|
||||
DateTime EndTime_ = (DateTime)EndTime.Date!;
|
||||
Dictionary.Add("EndTime", EndTime_.AddDays(1).ToString("yyyy-MM-dd"));
|
||||
Total_Command(Dictionary.ToJsonString());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.InfoDetail"
|
||||
xmlns:converters="clr-namespace:SunlightAggregationTerminal.Converters"
|
||||
Title="细节信息"
|
||||
Loaded="ContentPage_Loaded">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:StringToImageConverter x:Key="StringToImageConverter" />
|
||||
<converters:StringToBoolConverter x:Key="StringToBoolConverter" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<Grid RowDefinitions="Auto, Auto, *" ColumnDefinitions="*, Auto" >
|
||||
<Grid BackgroundColor="#CCCCCC" Padding="10" Grid.Row="0" Grid.Column="0" >
|
||||
<HorizontalStackLayout>
|
||||
<!-- 图片 -->
|
||||
<Image WidthRequest="150" HeightRequest="150"
|
||||
Source="{Binding Path=Model, Converter={StaticResource StringToImageConverter}}"/>
|
||||
<!-- 设备状态 -->
|
||||
<VerticalStackLayout>
|
||||
<Label Text="{Binding Name}" FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black" Padding="5"/>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="状态: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding State}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="机台: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Machine}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</HorizontalStackLayout>
|
||||
</Grid>
|
||||
<!-- 选项 -->
|
||||
<Grid Grid.Row="1" Grid.Column="0" HeightRequest="50">
|
||||
<HorizontalStackLayout BackgroundColor="#F0F0F0">
|
||||
<Button Text="实时信息" Clicked="Button_real" BackgroundColor="Transparent" TextColor="Black"/>
|
||||
<Button Text="物料信息" Clicked="Button_machine" BackgroundColor="Transparent" TextColor="Black"/>
|
||||
<Button Text="执行历史" Clicked="Button_history" BackgroundColor="Transparent" TextColor="Black"/>
|
||||
<Button Text="远程控制" Clicked="Button_control" BackgroundColor="Transparent" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</Grid>
|
||||
<Grid x:Name="_real" Grid.Row="2" Grid.Column="0" BackgroundColor="#F0F0F0">
|
||||
<!-- 设备信息 -->
|
||||
<RefreshView x:Name="myCardCollectionView_" >
|
||||
<CollectionView x:Name="CardCollectionView_inf" RemainingItemsThreshold="5">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10" StrokeShape="RoundRectangle 10">
|
||||
<VerticalStackLayout VerticalOptions="Center">
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="{Binding inf}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</RefreshView>
|
||||
</Grid>
|
||||
|
||||
<!-- 设备内容 -->
|
||||
<Grid x:Name="_machine" IsVisible="False" Grid.Row="2" Grid.Column="0" BackgroundColor="#F0F0F0">
|
||||
<CollectionView x:Name="CardCollectionView_machine" RemainingItemsThreshold="5">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10" StrokeShape="RoundRectangle 10">
|
||||
<VerticalStackLayout VerticalOptions="Center">
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="名称: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ProductName}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="代码: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ProductCode}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="状态: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ProductState}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="{Binding ProductInf}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
|
||||
<!-- 历史 -->
|
||||
<Grid x:Name="_history" IsVisible="False" Grid.Row="2" Grid.Column="0" BackgroundColor="#F0F0F0">
|
||||
<CollectionView x:Name="CardCollectionView_history" RemainingItemsThreshold="5">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10"
|
||||
StrokeShape="RoundRectangle 10">
|
||||
<VerticalStackLayout VerticalOptions="Center">
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工单: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Dyelot}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="@" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ReDye}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="步骤: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding StepNumber}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<BoxView HeightRequest="3" Color="#CCCCCC" />
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="{Binding Notes}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="呼叫时间: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CallTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="开始时间: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding DispenseStartTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="完成时间: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding DispenseEndTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
|
||||
<!-- 远程 -->
|
||||
<Grid x:Name="_control" IsVisible="False" Grid.Row="2" Grid.Column="0" BackgroundColor="#F0F0F0">
|
||||
|
||||
</Grid>
|
||||
<Grid x:Name="LoadingIndicator" Grid.Row="2" Grid.Column="0"
|
||||
BackgroundColor="Gray" IsVisible="False" Opacity="0.9">
|
||||
<VerticalStackLayout Padding="30" Spacing="10"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator IsRunning="True"
|
||||
Color="#512BD4"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Label Text="查询中..." FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,606 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data;
|
||||
using System.Reflection.PortableExecutable;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
public class InfoMachineItem
|
||||
{
|
||||
public string? inf { get; set; }
|
||||
}public partial class InfoDetail : ContentPage
|
||||
{
|
||||
public static ObservableCollection<ProbuctItem> InfoProbuctItems { get; set; } = new();
|
||||
public static ObservableCollection<DyelotDetailsItem> InfoDyelotHistoryItems { get; set; } = new();
|
||||
public static ObservableCollection<InfoMachineItem> InfoMachineItems { get; set; } = new();
|
||||
public static InfoItem infoItem=new();
|
||||
private DateTime _lastRefreshTime = DateTime.MinValue;
|
||||
public InfoDetail(InfoItem item)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.BindingContext = item;
|
||||
infoItem = item;
|
||||
myCardCollectionView_.Refreshing += (sender, e) => {
|
||||
// 防抖判断:如果距离上次刷新不足5秒,直接取消本次操作
|
||||
if ((DateTime.Now - _lastRefreshTime).TotalSeconds < 1)
|
||||
{
|
||||
myCardCollectionView_.IsRefreshing = false;
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
// 更新刷新时间
|
||||
_lastRefreshTime = DateTime.Now;
|
||||
InfoMachine();
|
||||
myCardCollectionView_.IsRefreshing = false;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void ContentPage_Loaded(object sender, EventArgs e)
|
||||
{
|
||||
InfoMachine();
|
||||
|
||||
InfoMachineItems.Clear();
|
||||
InfoProbuctItems.Clear();
|
||||
InfoDyelotHistoryItems.Clear();
|
||||
|
||||
CardCollectionView_inf.ItemsSource = InfoMachineItems;
|
||||
CardCollectionView_machine.ItemsSource = InfoProbuctItems;
|
||||
CardCollectionView_history.ItemsSource = InfoDyelotHistoryItems;
|
||||
}
|
||||
|
||||
//查询
|
||||
private void InfoMachine() {
|
||||
Dictionary<string, object> data_ = new Dictionary<string, object>();
|
||||
data_.Add("Command", "InfoMachine");
|
||||
if (infoItem.Model == "252")
|
||||
{
|
||||
data_.Add("Type", "10");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252-2T")
|
||||
{
|
||||
data_.Add("Type", "10");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252RB")
|
||||
{
|
||||
data_.Add("Type", "10");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252RDRM")
|
||||
{
|
||||
data_.Add("Type", "12");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "242W")
|
||||
{
|
||||
data_.Add("Type", "10");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "302")
|
||||
{
|
||||
data_.Add("Type", "20");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "303")
|
||||
{
|
||||
data_.Add("Type", "20");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "303PDW")
|
||||
{
|
||||
data_.Add("Type", "20");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Command(data_.ToJsonString());
|
||||
}
|
||||
}
|
||||
|
||||
//设备信息
|
||||
private void Button_real(object sender, EventArgs e)
|
||||
{
|
||||
_real.IsVisible = true;
|
||||
_machine.IsVisible = false;
|
||||
_history.IsVisible = false;
|
||||
_control.IsVisible = false;
|
||||
}
|
||||
|
||||
//设备内容
|
||||
private async void Button_machine(object sender, EventArgs e)
|
||||
{
|
||||
_real.IsVisible = false;
|
||||
_machine.IsVisible = true;
|
||||
_history.IsVisible = false;
|
||||
_control.IsVisible = false;
|
||||
|
||||
if (infoItem.Model == "252" || infoItem.Model == "252-2T" ||
|
||||
infoItem.Model == "252RB" || infoItem.Model == "242W" ||
|
||||
infoItem.Model == "252RDRM")
|
||||
{
|
||||
await DisplayAlertAsync("限制", "当前功能暂不可用", "是");
|
||||
return;
|
||||
}
|
||||
|
||||
if (InfoProbuctItems.Count == 0)
|
||||
{
|
||||
Dictionary<string, object> data_ = new Dictionary<string, object>();
|
||||
data_.Add("Command", "InfoMachinePipes");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_Probuct(data_.ToJsonString());
|
||||
}
|
||||
}
|
||||
|
||||
//历史
|
||||
private void Button_history(object sender, EventArgs e)
|
||||
{
|
||||
_real.IsVisible = false;
|
||||
_machine.IsVisible = false;
|
||||
_history.IsVisible = true;
|
||||
_control.IsVisible = false;
|
||||
if (InfoDyelotHistoryItems.Count == 0)
|
||||
{
|
||||
Dictionary<string, object> data_ = new Dictionary<string, object>();
|
||||
data_.Add("Command", "InfoMachineHistory");
|
||||
if (infoItem.Model == "252")
|
||||
{
|
||||
data_.Add("Type", "80");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252-2T")
|
||||
{
|
||||
data_.Add("Type", "80");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252RB")
|
||||
{
|
||||
data_.Add("Type", "80");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "252RDRM")
|
||||
{
|
||||
data_.Add("Type", "82");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "242W")
|
||||
{
|
||||
data_.Add("Type", "80");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "302")
|
||||
{
|
||||
data_.Add("Type", "90");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "303")
|
||||
{
|
||||
data_.Add("Type", "90");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
else if (infoItem.Model == "303PDW")
|
||||
{
|
||||
data_.Add("Type", "90");
|
||||
data_.Add("Field", "*");
|
||||
data_.Add("MachinName", infoItem.Machine!);
|
||||
Query_History(data_.ToJsonString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//远程
|
||||
private async void Button_control(object sender, EventArgs e)
|
||||
{
|
||||
_real.IsVisible = false;
|
||||
_machine.IsVisible = false;
|
||||
_history.IsVisible = false;
|
||||
_control.IsVisible = true;
|
||||
await DisplayAlertAsync("限制", "当前功能暂不可用", "是");
|
||||
}
|
||||
|
||||
//发送请求
|
||||
public async void Query_Command(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
InfoMachineItems.Clear();
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 秒的延时任务
|
||||
Task delayTask = Task.Delay(10000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (InfoMachineItems.Count == 0)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
await Task.WhenAny(delayTask, monitorTask);
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
public async void Query_Probuct(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
InfoProbuctItems.Clear();
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 秒的延时任务
|
||||
Task delayTask = Task.Delay(10000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (InfoProbuctItems.Count == 0)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
await Task.WhenAny(delayTask, monitorTask);
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
public async void Query_History(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
InfoDyelotHistoryItems.Clear();
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 秒的延时任务
|
||||
Task delayTask = Task.Delay(10000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (InfoDyelotHistoryItems.Count == 0)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
await Task.WhenAny(delayTask, monitorTask);
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
public static void Info_data(string dat, string id)
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<List<Dictionary<string, object>>>(dat)!;
|
||||
//助剂原料查询
|
||||
if (id == "00")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
ProbuctItem probuctItem = new ProbuctItem();
|
||||
|
||||
probuctItem.ProductCode = SafeGet(item, "ProductCode");
|
||||
probuctItem.ProductName = SafeGet(item, "ProductName");
|
||||
if (item.GetValue("Enabled").ToString()! == "1")
|
||||
{
|
||||
probuctItem.ProductState = "启用";
|
||||
}
|
||||
else { probuctItem.ProductState = "停用"; }
|
||||
if (item!.TryGetValue("No", out var _No) && _No != null)
|
||||
{
|
||||
probuctItem.ProductInf = "管路: " + _No + "\n";
|
||||
}
|
||||
if (item!.TryGetValue("MinLimit", out var _MinLimit) && _MinLimit != null)
|
||||
{
|
||||
probuctItem.ProductInf = probuctItem.ProductInf+"最少量: " + _MinLimit + "g\n";
|
||||
}
|
||||
if (item!.TryGetValue("MaxLimit", out var _MaxLimit) && _MaxLimit != null)
|
||||
{
|
||||
probuctItem.ProductInf = probuctItem.ProductInf + "最大量: " + _MinLimit + "g\n";
|
||||
}
|
||||
if (item!.TryGetValue("Conc", out var _Conc) && _Conc != null)
|
||||
{
|
||||
probuctItem.ProductInf = probuctItem.ProductInf + "浓度: " + _Conc + "\n";
|
||||
}
|
||||
if (item!.TryGetValue("Enabled", out var _Gravity) && _Gravity != null)
|
||||
{
|
||||
probuctItem.ProductInf = probuctItem.ProductInf + "比重: " + _Gravity;
|
||||
}
|
||||
InfoProbuctItems.Add(probuctItem);
|
||||
}
|
||||
if (InfoProbuctItems.Count == 0) InfoProbuctItems.Add(new ProbuctItem());
|
||||
}
|
||||
//染料查询
|
||||
else if (id == "10")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
string inf_ = "染机: " + SafeGet(item, "Machine")+ "\n";
|
||||
inf_ = inf_ + "料单: " + SafeGet(item, "Dyelot");
|
||||
inf_ = inf_ + "@" + SafeGet(item, "ReDye") + "\n";
|
||||
inf_ = inf_ + "步骤: " + SafeGet(item, "StepNumber") + "\n";
|
||||
inf_ = inf_ + "流程: " + SafeGet(item, "Process") + "\n";
|
||||
inf_ = inf_ + "化料桶: " + SafeGet(item, "TankNO") + "\n";
|
||||
inf_ = inf_ + "染料桶数: " + SafeGet(item, "TotalNumber");
|
||||
if (item!.TryGetValue("BarrelState", out var _Type) && _Type != null)
|
||||
{
|
||||
string temp = _Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"301" => "就绪",
|
||||
"309" => "未准备",
|
||||
_ => "无信息"
|
||||
};
|
||||
inf_ = inf_ + _Type;
|
||||
}
|
||||
inf_ = inf_ + "状态: " + SafeGet(item, "State") + "\n";
|
||||
|
||||
InfoMachineItem infoMachineItem = new InfoMachineItem();
|
||||
infoMachineItem.inf = inf_;
|
||||
InfoMachineItems.Add(infoMachineItem);
|
||||
}
|
||||
if (InfoMachineItems.Count == 0) InfoMachineItems.Add(new InfoMachineItem());
|
||||
}
|
||||
//染料查询化料货架
|
||||
else if (id == "12")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
string inf_ = "位置: " + SafeGet(item, "Position") + "\n";
|
||||
inf_ = inf_ + "料单: " + SafeGet(item, "Dyelot");
|
||||
inf_ = inf_ + "@" + SafeGet(item, "ReDye") + "\n";
|
||||
inf_ = inf_ + "步骤: " + SafeGet(item, "StepNumber") + "\n";
|
||||
if (item!.TryGetValue("BarrelType", out var _Type) && _Type != null)
|
||||
{
|
||||
string temp = _Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"1" => "空桶",
|
||||
"2" => "染料桶",
|
||||
_ => "无桶"
|
||||
};
|
||||
inf_ = inf_ + "类型:" + _Type;
|
||||
}
|
||||
if (item!.TryGetValue("BarrelState", out var _BarrelState) && _BarrelState != null)
|
||||
{
|
||||
string temp = _BarrelState?.ToString() ?? "";
|
||||
_BarrelState = temp switch
|
||||
{
|
||||
"201" => "[分桶]",
|
||||
_ => ""
|
||||
};
|
||||
inf_ = inf_ + _BarrelState;
|
||||
}
|
||||
inf_ = inf_ + "[" + SafeGet(item, "Barrelserialnumber") + "]\n";
|
||||
inf_ = inf_ + "上架时间: " + DateTime.Parse(item.GetValue("Createtime").ToString() ?? "")
|
||||
.ToString("yyyy-MM-dd HH:mm:ss") + "\n";
|
||||
inf_ = inf_ + "状态 [" + SafeGet(item, "State") + "]";
|
||||
|
||||
InfoMachineItem infoMachineItem = new InfoMachineItem();
|
||||
infoMachineItem.inf = inf_;
|
||||
InfoMachineItems.Add(infoMachineItem);
|
||||
}
|
||||
if (InfoMachineItems.Count == 0) InfoMachineItems.Add(new InfoMachineItem());
|
||||
}
|
||||
//助剂查询
|
||||
else if (id == "20")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
string inf_ = "染机: " + SafeGet(item, "Machine") + "\n";
|
||||
inf_ = inf_ + "料单: " + SafeGet(item, "Dyelot");
|
||||
inf_ = inf_ + "@" + SafeGet(item, "ReDye") + "\n";
|
||||
inf_ = inf_ + "步骤: " + SafeGet(item, "StepNumber") + "\n";
|
||||
inf_ = inf_ + "总浴量: " + SafeGet(item, "Volume")+ "\n";
|
||||
inf_ = inf_ + "计量模组: " + SafeGet(item, "DispenseModule") + "\n";
|
||||
if (item!.TryGetValue("TankNo", out var _TankNo) && _TankNo != null)
|
||||
{
|
||||
inf_ = inf_ + "目标位置: " + item.GetValue("TankNo") + "\n";
|
||||
}
|
||||
else {
|
||||
inf_ = inf_ + "目标位置: 未指定\n" ;
|
||||
}
|
||||
inf_ = inf_ + "开始时间: " + DateTime.Parse(item.GetValue("DispenseStartTime").ToString() ?? "")
|
||||
.ToString("yyyy-MM-dd HH:mm:ss") + "\n";
|
||||
if (item!.TryGetValue("State", out var _Type) && _Type != null)
|
||||
{
|
||||
string temp = _Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"102" => "计量中",
|
||||
"301" => "完成",
|
||||
"309" => "异常",
|
||||
_ => "无信息"
|
||||
};
|
||||
inf_ = inf_ + "状态: " + _Type;
|
||||
}
|
||||
|
||||
InfoMachineItem infoMachineItem = new InfoMachineItem();
|
||||
infoMachineItem.inf = inf_;
|
||||
|
||||
if (!InfoMachineItems.Any(x => x.inf == inf_))
|
||||
{
|
||||
InfoMachineItems.Add(infoMachineItem);
|
||||
}
|
||||
}
|
||||
if (InfoMachineItems.Count==0) InfoMachineItems.Add(new InfoMachineItem());
|
||||
}
|
||||
//化料历史信息查询
|
||||
else if (id == "80")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
DyelotDetailsItem dyelotDetailsItem = new DyelotDetailsItem();
|
||||
dyelotDetailsItem.Dyelot = SafeGet(item,"Dyelot");
|
||||
dyelotDetailsItem.ReDye = int.Parse(SafeGet(item, "ReDye"));
|
||||
dyelotDetailsItem.StepNumber = int.Parse(SafeGet(item, "StepNumber"));
|
||||
dyelotDetailsItem.Notes = "染机: " + SafeGet(item, "Machine") + "\n";
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes +
|
||||
"流程: " + SafeGet(item, "Process") + "\n";
|
||||
if (item!.TryGetValue("State", out var _State) && _State != null)
|
||||
{
|
||||
string temp = _State?.ToString() ?? "";
|
||||
// 转换
|
||||
_State = temp switch
|
||||
{
|
||||
"301" => "完成",
|
||||
"309" => "异常",
|
||||
_ => "无信息"
|
||||
};
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + "状态: " + _State ;
|
||||
}
|
||||
if (item!.TryGetValue("TankNo", out var _TankNo) && _TankNo != null)
|
||||
{
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + " [化料桶T" + _TankNo + "]";
|
||||
}
|
||||
if (item!.TryGetValue("TotalNumber", out var _TotalNumber) && _TotalNumber != null)
|
||||
{
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + " [" + _TotalNumber+"桶]";
|
||||
}
|
||||
dyelotDetailsItem.DispenseStartTime = SafeGet(item, "DispenseStartTime", "T").Replace("T", " ");
|
||||
dyelotDetailsItem.DispenseEndTime = SafeGet(item, "DispenseEndTime", "T").Replace("T", " ");
|
||||
|
||||
if (item!.TryGetValue("CallTime", out var _CallTime) && _CallTime != null)
|
||||
{
|
||||
if (DateTime.TryParse(_CallTime.ToString(), out DateTime dtc))
|
||||
{
|
||||
dyelotDetailsItem.CallTime = dtc.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
InfoDyelotHistoryItems.Add(dyelotDetailsItem);
|
||||
}
|
||||
if (InfoDyelotHistoryItems.Count == 0) InfoDyelotHistoryItems.Add(new DyelotDetailsItem());
|
||||
}
|
||||
//化料货架历史信息查询
|
||||
else if (id == "82")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
DyelotDetailsItem dyelotDetailsItem = new DyelotDetailsItem();
|
||||
dyelotDetailsItem.Dyelot = SafeGet(item, "Dyelot");
|
||||
dyelotDetailsItem.ReDye = int.Parse(SafeGet(item, "ReDye"));
|
||||
dyelotDetailsItem.StepNumber = int.Parse(SafeGet(item, "StepNumber"));
|
||||
dyelotDetailsItem.Notes = "位置: " + SafeGet(item, "Position") + "\n";
|
||||
if (item!.TryGetValue("BarrelType", out var _Type) && _Type != null)
|
||||
{
|
||||
string temp = _Type?.ToString() ?? "";
|
||||
// 转换
|
||||
_Type = temp switch
|
||||
{
|
||||
"1" => "空桶",
|
||||
"2" => "染料桶",
|
||||
_ => "无桶"
|
||||
};
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + "类型: " + _Type;
|
||||
}
|
||||
if (item!.TryGetValue("BarrelState", out var _BarrelState) && _BarrelState != null)
|
||||
{
|
||||
string temp = _BarrelState?.ToString() ?? "";
|
||||
_BarrelState = temp switch
|
||||
{
|
||||
"201" => "[分桶]",
|
||||
_ => ""
|
||||
};
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + _BarrelState;
|
||||
}
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + "[" + SafeGet(item, "Barrelserialnumber") + "]\n";
|
||||
if (item!.TryGetValue("State", out var _State) && _State != null)
|
||||
{
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + "状态: " + _State;
|
||||
}
|
||||
dyelotDetailsItem.DispenseStartTime = SafeGet(item, "CreateTime", "T").Replace("T", " ");
|
||||
dyelotDetailsItem.DispenseEndTime = "";
|
||||
dyelotDetailsItem.UsageTime = SafeGet(item , "CreateTime","T").Replace("T", " ");
|
||||
dyelotDetailsItem.CallTime = SafeGet(item, "CreateTime", "T").Replace("T", " ");
|
||||
InfoDyelotHistoryItems.Add(dyelotDetailsItem);
|
||||
}
|
||||
if (InfoDyelotHistoryItems.Count == 0) InfoDyelotHistoryItems.Add(new DyelotDetailsItem());
|
||||
}
|
||||
//助剂历史信息查询
|
||||
else if (id == "90")
|
||||
{
|
||||
foreach (var item in data!)
|
||||
{
|
||||
DyelotDetailsItem dyelotDetailsItem = new DyelotDetailsItem();
|
||||
dyelotDetailsItem.Dyelot = SafeGet(item, "Dyelot");
|
||||
dyelotDetailsItem.ReDye = int.Parse(SafeGet(item, "ReDye"));
|
||||
dyelotDetailsItem.StepNumber = int.Parse(SafeGet(item, "StepNumber"));
|
||||
dyelotDetailsItem.Notes = "染机: " + SafeGet(item, "Machine") + "\n";
|
||||
if (item!.TryGetValue("State", out var _State) && _State != null)
|
||||
{
|
||||
string temp = _State?.ToString() ?? "";
|
||||
// 转换
|
||||
_State = temp switch
|
||||
{
|
||||
"301" => "完成",
|
||||
"309" => "异常",
|
||||
_ => "无信息"
|
||||
};
|
||||
dyelotDetailsItem.Notes = dyelotDetailsItem.Notes + "状态: " + _State;
|
||||
}
|
||||
dyelotDetailsItem.DispenseStartTime = SafeGet(item, "DispenseStartTime", "T").Replace("T", " ");
|
||||
dyelotDetailsItem.DispenseEndTime = SafeGet(item, "DispenseEndTime", "T").Replace("T", " ");
|
||||
if (item!.TryGetValue("CallTime", out var _CallTime) && _CallTime != null)
|
||||
{
|
||||
if (DateTime.TryParse(_CallTime.ToString(), out DateTime dtc))
|
||||
{
|
||||
dyelotDetailsItem.CallTime = dtc.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
}
|
||||
InfoDyelotHistoryItems.Add(dyelotDetailsItem);
|
||||
}
|
||||
if (InfoDyelotHistoryItems.Count == 0) InfoDyelotHistoryItems.Add(new DyelotDetailsItem());
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助查询方法
|
||||
private static string SafeGet(Dictionary<string, object> item, string key, string defaultValue = "0")
|
||||
{
|
||||
//获取值并检查
|
||||
if (item!.TryGetValue(key, out var _dat) && _dat != null)
|
||||
{
|
||||
return _dat.ToString()!;
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,145 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.InfoPage"
|
||||
Title="">
|
||||
<VerticalStackLayout>
|
||||
|
||||
</VerticalStackLayout>
|
||||
x:Class="SunlightAggregationTerminal.InfoPage"
|
||||
xmlns:converters="clr-namespace:SunlightAggregationTerminal.Converters"
|
||||
Title="设备信息">
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:StringToImageConverter x:Key="StringToImageConverter" />
|
||||
<converters:StringToBoolConverter x:Key="StringToBoolConverter" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<RefreshView x:Name="myRefreshView_" >
|
||||
<CollectionView x:Name="CardCollectionView">
|
||||
<CollectionView.Header>
|
||||
<Border BackgroundColor="White"
|
||||
Stroke="#CCCCCC"
|
||||
Margin="10,0,10,10"
|
||||
StrokeThickness="5"
|
||||
StrokeShape="RoundRectangle 10">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Label Text="今日输送信息" Grid.Row="0" BackgroundColor="#CCCCCC"
|
||||
FontAttributes="Bold" FontSize="24" TextColor="Black" Padding="5"/>
|
||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*,Auto" Padding="5" ColumnSpacing="5">
|
||||
<HorizontalStackLayout>
|
||||
<!-- 图片 -->
|
||||
<Image WidthRequest="100" HeightRequest="100" Source="sunlightlogo.png"/>
|
||||
<!-- 设备状态文字内容 -->
|
||||
<VerticalStackLayout Grid.Column="1" VerticalOptions="Center">
|
||||
<ContentView>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="染料称量(次): " FontAttributes="Bold"
|
||||
FontSize="20" TextColor="Black"/>
|
||||
<Label x:Name="_DyeMeasurementNumber" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</ContentView>
|
||||
<ContentView>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="染料输送(次): " FontAttributes="Bold"
|
||||
FontSize="20" TextColor="Black"/>
|
||||
<Label x:Name="_DyeDissolveNumber" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</ContentView>
|
||||
<ContentView>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="助剂输送(次): " FontAttributes="Bold"
|
||||
FontSize="20" TextColor="Black"/>
|
||||
<Label x:Name="_ChemicalNumber" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</ContentView>
|
||||
<ContentView>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="粉剂输送(次): " FontAttributes="Bold"
|
||||
FontSize="20" TextColor="Black"/>
|
||||
<Label x:Name="_PowderNumber" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</ContentView>
|
||||
</VerticalStackLayout>
|
||||
</HorizontalStackLayout>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<!-- 点击事件 -->
|
||||
<Border.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="TapGestureRecognizer_ChemicalStatistics"/>
|
||||
</Border.GestureRecognizers>
|
||||
</Border>
|
||||
</CollectionView.Header>
|
||||
<!-- 保持滚动条 -->
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<!-- 这里定义单个卡片的 UI 结构 -->
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10"
|
||||
StrokeShape="RoundRectangle 10">
|
||||
<Grid>
|
||||
<!-- 定义一行 -->
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid Grid.Row="0" BackgroundColor="#CCCCCC">
|
||||
<Label Text="{Binding Name}" FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black" Padding="5"/>
|
||||
</Grid>
|
||||
<Grid Grid.Row="1">
|
||||
<VerticalStackLayout>
|
||||
<Grid>
|
||||
<HorizontalStackLayout>
|
||||
<!-- 图片 -->
|
||||
<Image WidthRequest="100" HeightRequest="100"
|
||||
Source="{Binding Path=Model, Converter={StaticResource StringToImageConverter}}"/>
|
||||
<!-- 设备状态 -->
|
||||
<VerticalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="状态: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding State}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="机台: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Machine}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</HorizontalStackLayout>
|
||||
</Grid>
|
||||
<BoxView HeightRequest="3" Color="#CCCCCC" />
|
||||
<!-- 设备信息 -->
|
||||
<Label Text="{Binding ModelA}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelA, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding ModelB}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelB, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding ModelC}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelC, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding ModelD}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelD, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding ModelE}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelE, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding ModelF}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=ModelF, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding Information}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<!-- 点击事件 -->
|
||||
<Border.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
|
||||
</Border.GestureRecognizers>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</RefreshView>
|
||||
</ContentPage>
|
||||
@@ -1,9 +1,112 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.Maui.Controls;
|
||||
using Microsoft.Maui.Controls.PlatformConfiguration.WindowsSpecific;
|
||||
using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
public partial class InfoPage : ContentPage
|
||||
{
|
||||
public InfoPage()
|
||||
{
|
||||
public static ObservableCollection<InfoItem> InfoItems { get; set; } = new();
|
||||
private DateTime _lastRefreshTime = DateTime.MinValue;
|
||||
public static string? DyeMeasurementNumber, ChemicalNumber, PowderNumber, DyeDissolveNumber;
|
||||
|
||||
public InfoPage()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
CardCollectionView.ItemsSource = InfoItems;
|
||||
// 注册订阅一个不携带数据的消息(使用 object 作为泛型)
|
||||
WeakReferenceMessenger.Default.Register<object>(this, (r, m) =>
|
||||
{
|
||||
// 收到信号,直接触发函数
|
||||
HandleUITrigger();
|
||||
});
|
||||
//注册当前页面的下滑刷新
|
||||
myRefreshView_.Refreshing += (sender, e) => {
|
||||
// 防抖判断:如果距离上次刷新不足5秒,直接取消本次操作
|
||||
if ((DateTime.Now - _lastRefreshTime).TotalSeconds < 1)
|
||||
{
|
||||
myRefreshView_.IsRefreshing = false;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// 更新刷新时间
|
||||
_lastRefreshTime = DateTime.Now;
|
||||
|
||||
DataReceived.Transmit("{\"Command\":\"Info\"}");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private async void TapGestureRecognizer_ChemicalStatistics(object sender, TappedEventArgs e)
|
||||
{
|
||||
await Navigation.PushAsync(new InfoChemicalStatistics());
|
||||
}
|
||||
|
||||
private void HandleUITrigger()
|
||||
{
|
||||
_DyeMeasurementNumber.Text = DyeMeasurementNumber;
|
||||
_ChemicalNumber.Text = ChemicalNumber;
|
||||
_PowderNumber.Text = PowderNumber;
|
||||
_DyeDissolveNumber.Text = DyeDissolveNumber;
|
||||
InfoItems.Clear();
|
||||
foreach (Dictionary<string, object> List in DataModel.Info_data)
|
||||
{
|
||||
var mapping = new Dictionary<string, Action<InfoItem, string>>
|
||||
{
|
||||
{ "Name", (obj, val) => obj.Name = val },
|
||||
{ "State", (obj, val) => obj.State = val },
|
||||
{ "MachineName", (obj, val) => obj.MachineName = val },
|
||||
{ "Machine", (obj, val) => obj.Machine = val },
|
||||
{ "Information", (obj, val) => obj.Information = val },
|
||||
{ "Type", (obj, val) => obj.Type = val },
|
||||
{ "Model", (obj, val) => obj.Model = val },
|
||||
{ "ModelA", (obj, val) => obj.ModelA = val },
|
||||
{ "ModelB", (obj, val) => obj.ModelB = val },
|
||||
{ "ModelC", (obj, val) => obj.ModelC = val },
|
||||
{ "ModelD", (obj, val) => obj.ModelD = val },
|
||||
{ "ModelE", (obj, val) => obj.ModelE = val },
|
||||
{ "ModelF", (obj, val) => obj.ModelF = val }
|
||||
};
|
||||
|
||||
var info = new InfoItem();
|
||||
foreach (var (key, action) in mapping)
|
||||
{
|
||||
if (List.TryGetValue(key, out var val) && val != null)
|
||||
{
|
||||
action(info, val.ToString()!);
|
||||
}
|
||||
}
|
||||
InfoItems.Add(info);
|
||||
}
|
||||
CardCollectionView.ItemsSource = InfoItems;
|
||||
myRefreshView_.IsRefreshing = false;
|
||||
}
|
||||
|
||||
~InfoPage()//关闭时注销消息
|
||||
{
|
||||
WeakReferenceMessenger.Default.UnregisterAll(this);
|
||||
}
|
||||
|
||||
private async void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
// 将 sender 强制转换为 BindingContext 定义在 BindableObject
|
||||
if (sender is Microsoft.Maui.Controls.BindableObject bindable)
|
||||
{
|
||||
var context = bindable.BindingContext;
|
||||
|
||||
if (context is InfoItem item)
|
||||
{
|
||||
await Navigation.PushAsync(new InfoDetail(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal.Models
|
||||
{
|
||||
@@ -11,7 +12,7 @@ namespace SunlightAggregationTerminal.Models
|
||||
{
|
||||
|
||||
public static SqliteHelper sqliteHelper = SQLiteConfig.Config(Path.Combine(FileSystem.AppDataDirectory, "MyAppData.db"))!; //数据库连接路径(获取各平台的应用数据目录)
|
||||
|
||||
private Timer timer;
|
||||
public AppModels()
|
||||
{
|
||||
if(sqliteHelper != null)
|
||||
@@ -34,19 +35,33 @@ namespace SunlightAggregationTerminal.Models
|
||||
App.GlobalData.Department = dat.Field<string>("Department") ?? "";
|
||||
App.GlobalData.Groups = dat.Field<string>("Groups") ?? "";
|
||||
App.GlobalData.ServerID = dat.Field<string>("ServerID") ?? "";
|
||||
App.GlobalData.ServerHTTP = dat.Field<string>("ServerHTTP") ?? "";
|
||||
App.GlobalData.ProxyID = dat.Field<string>("ProxyID") ?? "";
|
||||
App.GlobalData.LogNo = Convert.ToBoolean(dat.Field<object>("LogNo"));
|
||||
App.GlobalData.LocalAreaNetworkMode = Convert.ToBoolean(dat.Field<object>("LocalAreaNetworkMode"));
|
||||
App.GlobalData.DarkMode = Convert.ToBoolean(dat.Field<object>("DarkMode"));
|
||||
App.GlobalData.MessageNotificationMode = Convert.ToBoolean(dat.Field<object>("MessageNotificationMode"));
|
||||
|
||||
TcpServer.Configuration(App.GlobalData.ServerID, App.GlobalData.User, App.GlobalData.UserPassword, dat.Field<string>("GUID") ?? "Not");
|
||||
App.GlobalData.NotificationID = dat.Field<string>("NotificationID")?? "0";
|
||||
}
|
||||
//启动tcp
|
||||
// TcpServer.CreateCustomService();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//启动通知轮询延迟120s启动周期600s
|
||||
timer = new Timer(TimerNotification, null, TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(120));
|
||||
}
|
||||
|
||||
//轮询通知的定时任务
|
||||
static void TimerNotification(object? state)
|
||||
{
|
||||
if (App.GlobalData.LogNo)//已经登录
|
||||
{
|
||||
Dictionary<string, object> NotificationDictionary = new Dictionary<string, object>();
|
||||
NotificationDictionary.Add("Command", "Notification");
|
||||
NotificationDictionary.Add("StartTime", App.GlobalData.NotificationID);
|
||||
NotificationDictionary.Add("EndTime", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
|
||||
DataReceived.Transmit(NotificationDictionary.ToJsonString());
|
||||
}
|
||||
}
|
||||
|
||||
public static void Updata(string sql)
|
||||
@@ -76,7 +91,23 @@ namespace SunlightAggregationTerminal.Models
|
||||
{
|
||||
App.GlobalData.LogNo = false;
|
||||
|
||||
//发生登录请求
|
||||
// await WebSocketServer.WebSocketClient();
|
||||
|
||||
//发送登录请求
|
||||
if (App.GlobalData.LocalAreaNetworkMode)
|
||||
{
|
||||
//tcp
|
||||
TcpServer.Configuration(App.GlobalData.ServerID,
|
||||
App.GlobalData.User, App.GlobalData.UserPassword,
|
||||
GetAppUniqueId());
|
||||
}
|
||||
else
|
||||
{
|
||||
//http
|
||||
HttpServer.Configuration(App.GlobalData.ServerHTTP,
|
||||
App.GlobalData.User, App.GlobalData.UserPassword,
|
||||
GetAppUniqueId());
|
||||
}
|
||||
|
||||
// 创建一个 15 秒的延时任务
|
||||
Task delayTask = Task.Delay(15000);
|
||||
@@ -86,7 +117,7 @@ namespace SunlightAggregationTerminal.Models
|
||||
while (!App.GlobalData.LogNo)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(100);
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
|
||||
@@ -23,6 +23,8 @@ namespace SunlightAggregationTerminal.Models
|
||||
[ObservableProperty]
|
||||
public partial string ServerID { get; set; }
|
||||
[ObservableProperty]
|
||||
public partial string ServerHTTP { get; set; }
|
||||
[ObservableProperty]
|
||||
public partial string Groups { get; set; }
|
||||
[ObservableProperty]
|
||||
public partial string ProxyID { get; set; }
|
||||
@@ -35,6 +37,11 @@ namespace SunlightAggregationTerminal.Models
|
||||
public partial bool DarkMode { get; set; }
|
||||
[ObservableProperty]
|
||||
public partial bool MessageNotificationMode { get; set; }
|
||||
[ObservableProperty]
|
||||
public partial string NotificationID { get; set; }
|
||||
|
||||
|
||||
public class RefreshUISignal { }
|
||||
public static List<Dictionary<string, object>> Info_data = new List<Dictionary<string, object>>();
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace SunlightAggregationTerminal.Models
|
||||
{
|
||||
@@ -23,14 +25,65 @@ namespace SunlightAggregationTerminal.Models
|
||||
public DateTime Time { get; set; }
|
||||
public MsgType Type { get; set; }
|
||||
}
|
||||
public partial class InfoItem
|
||||
{
|
||||
public string? Name { get; set; }
|
||||
public string? State { get; set; }
|
||||
public string? MachineName { get; set; }
|
||||
public string? Machine { get; set; }
|
||||
public string? Information { get; set; }
|
||||
public string? Model { get; set; }
|
||||
public string? Type { get; set; }
|
||||
public string? ModelA { get; set; }
|
||||
public string? ModelB { get; set; }
|
||||
public string? ModelC { get; set; }
|
||||
public string? ModelD { get; set; }
|
||||
public string? ModelE { get; set; }
|
||||
public string? ModelF { get; set; }
|
||||
}
|
||||
public partial class ProbuctItem
|
||||
{
|
||||
public string? ProductName { get; set; }
|
||||
public string? ProductCode { get; set; }
|
||||
public string? ProductState { get; set; }
|
||||
public string? ProductInf { get; set; }
|
||||
}
|
||||
public class DyelotItem
|
||||
{
|
||||
public string? Dyelot { get; set; }
|
||||
public int? ReDye { get; set; }
|
||||
public int? Color { get; set; }
|
||||
public string? Machine { get; set; }
|
||||
public string? Program { get; set; }
|
||||
public string? CreationTime { get; set; }
|
||||
public string? FabricName { get; set; }
|
||||
public string? ColorName { get; set; }
|
||||
public string? CustomerName { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
public class DyelotDetailsItem
|
||||
{
|
||||
public string? Dyelot { get; set; }
|
||||
public int? ReDye { get; set; }
|
||||
public int? StepNumber { get; set; }
|
||||
public string? ProductName { get; set; }
|
||||
public string? ProductCode { get; set; }
|
||||
public int? ProductType { get; set; }
|
||||
public string? Process { get; set; }
|
||||
public double? Grams { get; set; }
|
||||
public string GramsDisplay => Grams?.ToString("F2") ?? "";
|
||||
public string? Created { get; set; }
|
||||
public string? DispenseStartTime { get; set; }
|
||||
public string? DispenseEndTime { get; set; }
|
||||
public string? DispenseTime { get; set; }
|
||||
public string? CallTime { get; set; }
|
||||
public string? UsageTime { get; set; }
|
||||
public string? Tank { get; set; }
|
||||
public object? PowderTargetTank { get; set; }
|
||||
public double? DispenseGrams { get; set; }
|
||||
public string DispenseGramsDisplay => DispenseGrams?.ToString("F2") ?? "";
|
||||
public int? DispenseResult { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public static class DataService
|
||||
@@ -40,7 +93,7 @@ namespace SunlightAggregationTerminal.Models
|
||||
public static List<NotificationItem> GetAllItems()
|
||||
{
|
||||
DataSet? data = AppModels.Select("select * from Notification Where Time > '" +
|
||||
DateTime.Now.AddDays(-30).ToString("yyyy-MM-dd HH:mm:ss.fff") + "'");
|
||||
DateTime.Now.AddDays(-60).ToString("yyyy-MM-dd HH:mm:ss.fff") + "'");
|
||||
|
||||
_NotificationData.Clear();
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@
|
||||
Title="信息">
|
||||
<CollectionView x:Name="CardCollectionView"
|
||||
ItemsSource="{Binding MessageItems}"
|
||||
RemainingItemsThreshold="5"
|
||||
RemainingItemsThresholdReached="CardCollectionView_RemainingItemsThresholdReached">
|
||||
RemainingItemsThreshold="5">
|
||||
<!-- 保持滚动条 -->
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
|
||||
@@ -24,7 +24,7 @@ public partial class MessagePage : ContentPage
|
||||
MessageItems.Clear();
|
||||
|
||||
// 按时间倒序,并只取最新的 50 条
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(50).Where(x => x.Type == MsgType.Message);
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(100).Where(x => x.Type == MsgType.Message);
|
||||
|
||||
// 将数据添加到集合中,UI 会自动更新
|
||||
foreach (var item in itemsToShow)
|
||||
@@ -34,8 +34,5 @@ public partial class MessagePage : ContentPage
|
||||
}
|
||||
}
|
||||
|
||||
private void CardCollectionView_RemainingItemsThresholdReached(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ public partial class NoticePage : ContentPage
|
||||
NoticeItems.Clear();
|
||||
|
||||
// 按时间倒序,并只取最新的 N 条(例如 50 条)
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(50).Where(x => x.Type == MsgType.Notice);
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(100).Where(x => x.Type == MsgType.Notice);
|
||||
|
||||
// 将数据添加到集合中,UI 会自动更新
|
||||
foreach (var item in itemsToShow)
|
||||
|
||||
@@ -24,7 +24,7 @@ public partial class SystemPage : ContentPage
|
||||
SystemItems.Clear();
|
||||
|
||||
// 按时间倒序,并只取最新的 N 条(例如 50 条)
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(50).Where(x => x.Type == MsgType.System);
|
||||
var itemsToShow = allData.OrderByDescending(x => x.Time).Take(100).Where(x => x.Type == MsgType.System);
|
||||
|
||||
// 将数据添加到集合中,UI 会自动更新
|
||||
foreach (var item in itemsToShow)
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
using AndroidX.Core.App;
|
||||
using SunlightAggregationTerminal;
|
||||
// 使用 global:: 强制指定原生安卓的命名空间
|
||||
using AndroidApp = global::Android.App;
|
||||
|
||||
namespace SunlightAggregationTerminal.Platforms.Android
|
||||
{
|
||||
public class NotificationService : INotificationService
|
||||
{
|
||||
const string channelId = "default_channel";
|
||||
const string channelName = "Default Notifications";
|
||||
const string channelDescription = "Default notification channel";
|
||||
|
||||
public void SendNotification(string title, string message, int notificationId = 0)
|
||||
{
|
||||
// 1. 创建通知渠道(仅 Android 8.0 / API 26 及以上需要)
|
||||
#pragma warning disable CA1416 // 暂时关闭平台兼容性警告
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||
{
|
||||
var channel = new AndroidApp.NotificationChannel(channelId, channelName, NotificationImportance.Default)
|
||||
{
|
||||
Description = channelDescription
|
||||
};
|
||||
|
||||
// 修复点:获取系统服务并处理可能的 null 值
|
||||
// 如果 GetSystemService 返回 null,则直接 return 终止方法,防止后续崩溃
|
||||
var notificationManager = AndroidApp.Application.Context.GetSystemService(Context.NotificationService) as AndroidApp.NotificationManager;
|
||||
if (notificationManager == null) return;
|
||||
|
||||
notificationManager.CreateNotificationChannel(channel);
|
||||
}
|
||||
#pragma warning restore CA1416 // 恢复平台兼容性警告
|
||||
|
||||
// 2. 构建通知内容
|
||||
var intent = new Intent(AndroidApp.Application.Context, typeof(MainActivity));
|
||||
intent.AddFlags(ActivityFlags.ClearTop);
|
||||
|
||||
#pragma warning disable CA1416
|
||||
// PendingIntent 同样建议做安全获取
|
||||
var pendingIntent = PendingIntent.GetActivity(AndroidApp.Application.Context, 0, intent, PendingIntentFlags.Immutable | PendingIntentFlags.UpdateCurrent);
|
||||
#pragma warning restore CA1416 // 恢复平台兼容性警告
|
||||
|
||||
NotificationCompat.Builder notificationBuilder;
|
||||
|
||||
// 核心兼容处理:根据系统版本选择不同的 Builder 构造方法
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.O)
|
||||
{
|
||||
// Android 8.0+:必须传入 channelId
|
||||
notificationBuilder = new NotificationCompat.Builder(AndroidApp.Application.Context, channelId);
|
||||
}
|
||||
else
|
||||
{
|
||||
#pragma warning disable CS0618
|
||||
// Android 5.0 ~ 7.x:不支持 channelId,使用旧版单参数构造方法
|
||||
notificationBuilder = new NotificationCompat.Builder(AndroidApp.Application.Context);
|
||||
#pragma warning restore CS0618
|
||||
}
|
||||
|
||||
var notification = notificationBuilder!
|
||||
.SetContentTitle(title)!
|
||||
.SetContentText(message)!
|
||||
// 请确保你的 Resources/drawable 文件夹下有这个图标
|
||||
//.SetSmallIcon(Resource.Drawable.abc_vector_test)!
|
||||
.SetAutoCancel(true)!
|
||||
.SetContentIntent(pendingIntent);
|
||||
|
||||
// 如果是 Android 5.0 (API 21) 及以上,还可以设置锁屏可见等特性
|
||||
if (Build.VERSION.SdkInt >= BuildVersionCodes.Lollipop)
|
||||
{
|
||||
notification!.SetVisibility(NotificationCompat.VisibilityPublic);
|
||||
}
|
||||
|
||||
// 3. 发送通知
|
||||
var compatManager = NotificationManagerCompat.From(AndroidApp.Application.Context);
|
||||
compatManager!.Notify(notificationId, notification!.Build());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.ProfilePage"
|
||||
xmlns:vm="clr-namespace:SunlightAggregationTerminal.Models"
|
||||
x:DataType="vm:DataModel"
|
||||
Title="">
|
||||
<Grid RowDefinitions="Auto, *"
|
||||
ColumnDefinitions="*, Auto"
|
||||
@@ -21,8 +23,8 @@
|
||||
FontAttributes="Bold"
|
||||
TextColor="Black" />
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="ID:" FontSize="12" TextColor="Gray" Margin="0,0,0,0"/>
|
||||
<Label Text="{Binding UserId}" FontSize="12" TextColor="Gray" Margin="0,0,0,0"/>
|
||||
<Label Text="ID:" FontSize="12" TextColor="Gray" Margin="0,0,0,0"/>
|
||||
<Label Text="{Binding UserId}" FontSize="12" TextColor="Gray" Margin="0,0,0,0"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</HorizontalStackLayout>
|
||||
@@ -170,7 +172,7 @@
|
||||
<ContentView HeightRequest="50" Padding="15,0">
|
||||
<Grid>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="服务器:" VerticalOptions="Center" />
|
||||
<Label Text="服务器(TCP):" VerticalOptions="Center" />
|
||||
<Label Text="{Binding ServerID}" TextColor="Gray" VerticalOptions="Center" Margin="0,0,10,0"/>
|
||||
</HorizontalStackLayout>
|
||||
<Label Text=">" TextColor="Gray" VerticalOptions="Center" HorizontalOptions="End"
|
||||
@@ -181,6 +183,20 @@
|
||||
</ContentView.GestureRecognizers>
|
||||
</ContentView>
|
||||
<BoxView HeightRequest="1" Color="#E0E0E0" Margin="15,0" />
|
||||
<ContentView HeightRequest="50" Padding="15,0">
|
||||
<Grid>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
<Label Text="服务器(HTTP):" VerticalOptions="Center" />
|
||||
<Label Text="{Binding ServerHTTP}" TextColor="Gray" VerticalOptions="Center" Margin="0,0,10,0"/>
|
||||
</HorizontalStackLayout>
|
||||
<Label Text=">" TextColor="Gray" VerticalOptions="Center" HorizontalOptions="End"
|
||||
Margin="0,0,10,0" FontSize="24"/>
|
||||
</Grid>
|
||||
<ContentView.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="ProxyID_Tapped"/>
|
||||
</ContentView.GestureRecognizers>
|
||||
</ContentView>
|
||||
<BoxView HeightRequest="1" Color="#E0E0E0" Margin="15,0" />
|
||||
<ContentView HeightRequest="50" Padding="15,0">
|
||||
<Grid>
|
||||
<HorizontalStackLayout VerticalOptions="Center">
|
||||
|
||||
@@ -3,17 +3,63 @@ using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using SunlightAggregationTerminal.View;
|
||||
using System.Collections.ObjectModel;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
public partial class ProfilePage : ContentPage
|
||||
{
|
||||
private static bool SET = false;
|
||||
public ProfilePage()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.BindingContext = App.GlobalData;
|
||||
}
|
||||
|
||||
|
||||
public static void _data(string v,string k)
|
||||
{
|
||||
if (k == "Password")
|
||||
{
|
||||
App.GlobalData.UserPassword = v;
|
||||
string sql = @"UPDATE Users SET UserPassword = '" + App.GlobalData.UserPassword
|
||||
+ "' WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
SET = false;
|
||||
}
|
||||
if (k == "Name")
|
||||
{
|
||||
App.GlobalData.UserName = v;
|
||||
string sql = @"UPDATE Users SET UserName = '" + App.GlobalData.UserName
|
||||
+ "' WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
SET = false;
|
||||
}
|
||||
}
|
||||
public async void _Command(string dat)
|
||||
{
|
||||
DataReceived.Transmit(dat);
|
||||
SET = true;
|
||||
// 创建一个 秒的延时任务
|
||||
Task delayTask = Task.Delay(10000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (SET)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
Task task = await Task.WhenAny(delayTask, monitorTask);
|
||||
|
||||
if (task==delayTask)
|
||||
{ //超时
|
||||
await DisplayAlertAsync("", "修改失败", "是");
|
||||
}
|
||||
SET = false;
|
||||
}
|
||||
|
||||
private async void Out_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
//退出
|
||||
@@ -38,10 +84,12 @@ public partial class ProfilePage : ContentPage
|
||||
// 处理结果
|
||||
if (!string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
App.GlobalData.UserName=result;
|
||||
string sql = @"UPDATE Users SET UserName = '" + App.GlobalData.UserName
|
||||
+ "' WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
Dictionary<string, object> data_ = new Dictionary<string, object>();
|
||||
data_.Add("Command", "SETUSER");
|
||||
data_.Add("USER", App.GlobalData.User);
|
||||
data_.Add("KEY", "Name");
|
||||
data_.Add("VALUE", result);
|
||||
_Command(data_.ToJsonString());
|
||||
}
|
||||
}
|
||||
private async void UserPassword_Tapped(object sender, TappedEventArgs e)
|
||||
@@ -51,10 +99,12 @@ public partial class ProfilePage : ContentPage
|
||||
// 处理结果
|
||||
if (!string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
App.GlobalData.UserPassword = result;
|
||||
string sql = @"UPDATE Users SET UserPassword = '" + App.GlobalData.UserPassword
|
||||
+ "' WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
Dictionary<string, object> data_ = new Dictionary<string, object>();
|
||||
data_.Add("Command", "SETUSER");
|
||||
data_.Add("USER", App.GlobalData.User);
|
||||
data_.Add("KEY", "Password");
|
||||
data_.Add("VALUE", result);
|
||||
_Command(data_.ToJsonString());
|
||||
}
|
||||
}
|
||||
private async void ServerID_Tapped(object sender, TappedEventArgs e)
|
||||
@@ -70,6 +120,19 @@ public partial class ProfilePage : ContentPage
|
||||
AppModels.Updata(sql);
|
||||
}
|
||||
}
|
||||
private async void ServerHTTP_Tapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
string result = await DisplayPromptAsync("", "服务器地址");
|
||||
|
||||
// 处理结果
|
||||
if (!string.IsNullOrWhiteSpace(result))
|
||||
{
|
||||
App.GlobalData.ServerID = result;
|
||||
string sql = @"UPDATE Users SET ServerHTTP = '" + App.GlobalData.ServerID
|
||||
+ "' WHERE User='" + App.GlobalData.User + "';";
|
||||
AppModels.Updata(sql);
|
||||
}
|
||||
}
|
||||
private async void ProxyID_Tapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
string result = await DisplayPromptAsync("", "代理");
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.QueryDetail"
|
||||
xmlns:converters="clr-namespace:SunlightAggregationTerminal.Converters"
|
||||
Title="细节" >
|
||||
<ContentPage.Resources>
|
||||
<ResourceDictionary>
|
||||
<converters:StringToBoolConverter x:Key="StringToBoolConverter" />
|
||||
</ResourceDictionary>
|
||||
</ContentPage.Resources>
|
||||
<Grid RowDefinitions="Auto, *" >
|
||||
<Grid BackgroundColor="#CCCCCC" Padding="10" Grid.Row="0" Grid.Column="0">
|
||||
<VerticalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工单: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_Dyelot" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
<Label Text="@" FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_ReDye" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="机台: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_Machine" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="下单时间: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_CreationTime" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工艺: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_FabricName1" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="面料: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_FabricName" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="客户: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label x:Name="_CustomerName" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="颜色: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label FontSize="22" BackgroundColor="Black"/>
|
||||
<Label x:Name="_ColorName" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<BoxView x:Name="_Color" HeightRequest="25" />
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
|
||||
<Grid x:Name="_data" Grid.Row="1" Grid.Column="0" BackgroundColor="#F0F0F0">
|
||||
<CollectionView x:Name="CardCollectionView_data" RemainingItemsThreshold="5">
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Border BackgroundColor="White" Stroke="#CCCCCC"
|
||||
StrokeThickness="2" Margin="10,0,10,10"
|
||||
StrokeShape="RoundRectangle 10">
|
||||
<VerticalStackLayout VerticalOptions="Center">
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="步骤: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding StepNumber}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="呼叫时间: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CallTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="完成时间: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding DispenseEndTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="用时: " FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding UsageTime}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="目标地址: " FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=Tank, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding Tank}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=Tank, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="溶解流程: " FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=Process, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
<Label Text="{Binding Process}" FontAttributes="Bold" FontSize="22" TextColor="Black"
|
||||
IsVisible="{Binding Path=Process, Converter={StaticResource StringToBoolConverter}}"/>
|
||||
</HorizontalStackLayout>
|
||||
<BoxView HeightRequest="3" Color="#CCCCCC" />
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="{Binding ProductName}" FontAttributes="Bold"
|
||||
FontSize="22" TextColor="Black"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
<Grid x:Name="LoadingIndicator" Grid.Row="1" Grid.Column="0"
|
||||
BackgroundColor="Gray" IsVisible="False" Opacity="0.9">
|
||||
<VerticalStackLayout Padding="30" Spacing="10"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator IsRunning="True"
|
||||
Color="#512BD4"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Label Text="查询中..." FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,138 @@
|
||||
using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
public partial class QueryDetail : ContentPage
|
||||
{
|
||||
public static ObservableCollection<DyelotDetailsItem> QueryDetailDyelotDetailsItems { get; set; } = new();
|
||||
public QueryDetail(DyelotItem item)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
_Dyelot.Text = item.Dyelot;
|
||||
_ReDye.Text = item.ReDye?.ToString()??"";
|
||||
_Machine.Text = item.Machine;
|
||||
_CreationTime.Text = item.CreationTime;
|
||||
_FabricName.Text = item.FabricName;
|
||||
_CustomerName.Text = item.CustomerName;
|
||||
_ColorName.Text = item.ColorName;
|
||||
// 如果 item.Color 为 null,则默认为透明色
|
||||
_Color.Color = item.Color.HasValue ? Color.FromInt(item.Color.Value) : Colors.Gray;
|
||||
|
||||
Dictionary<string, object> QueryDictionary = new Dictionary<string, object>();
|
||||
QueryDictionary.Add("Command", "QueryDetail");
|
||||
/* QueryDictionary.Add("Field", "[Dyelot],[ReDye],[StepNumber],[ProductCode],[ProductName]," +
|
||||
"[ProductType],[Grams],[Created],[DispenseStartTime],[DispenseEndTime],[DispenseTime]," +
|
||||
"[DispenseGrams],[DispenseResult],[Process]");*/
|
||||
QueryDictionary.Add("Field", "*");
|
||||
QueryDictionary.Add("Dyelot", item.Dyelot?.ToString() ?? "");
|
||||
QueryDictionary.Add("ReDye", item.ReDye?.ToString()??"");
|
||||
Query_Command(QueryDictionary.ToJsonString());
|
||||
}
|
||||
|
||||
private void Data_()
|
||||
{
|
||||
var processedList = QueryDetailDyelotDetailsItems
|
||||
.GroupBy(item => new
|
||||
{
|
||||
// ?.Trim() 防止空格和 null 导致的分组偏差
|
||||
Dyelot = item.Dyelot?.Trim(),
|
||||
Step = item.StepNumber
|
||||
})
|
||||
.Select(g =>
|
||||
{
|
||||
var list = g.ToList();
|
||||
var firstItem = list.First();
|
||||
// 直接使用 Select 的重载,获取当前元素的索引 i,然后通过 list[i] 访问对应的其他字段
|
||||
var combinedInfo = string.Join("\n",
|
||||
list.Select((x, i) => $"原料: {list[i].ProductName} ({list[i].ProductCode})\n" +
|
||||
$"目标/实际: {list[i].GramsDisplay}g / {list[i].DispenseGramsDisplay}g")
|
||||
);
|
||||
// 赋值给最终展示的 ProductName
|
||||
firstItem.ProductName = combinedInfo;
|
||||
return firstItem;
|
||||
})
|
||||
.ToList(); // 强制立刻执行查询
|
||||
|
||||
// 更新 UI 绑定的 ObservableCollection
|
||||
QueryDetailDyelotDetailsItems.Clear();
|
||||
foreach (var item in processedList)
|
||||
{
|
||||
QueryDetailDyelotDetailsItems.Add(item);
|
||||
}
|
||||
CardCollectionView_data.ItemsSource = QueryDetailDyelotDetailsItems;
|
||||
}
|
||||
|
||||
public async void Query_Command(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
QueryDetailDyelotDetailsItems.Clear();
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 秒的延时任务
|
||||
Task delayTask = Task.Delay(10000);
|
||||
// 创建一个监测任务,不断检查变量
|
||||
Task monitorTask = Task.Run(async () =>
|
||||
{
|
||||
while (QueryDetailDyelotDetailsItems.Count == 0)
|
||||
{
|
||||
// 每隔 100 毫秒检查一次,避免 CPU 占用过高
|
||||
await Task.Delay(1000);
|
||||
}
|
||||
});
|
||||
// 使用 Task.WhenAny 等待任意一个任务完成
|
||||
await Task.WhenAny(delayTask, monitorTask);
|
||||
|
||||
Data_();
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
|
||||
public static void Query_data(string dat)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<List<DyelotDetailsItem>>(dat);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
//添加入显示信息
|
||||
foreach (var item in data)
|
||||
{
|
||||
//时间处理
|
||||
if (DateTime.TryParse(item.DispenseEndTime, out DateTime dte))
|
||||
{
|
||||
item.DispenseEndTime = dte.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
if (DateTime.TryParse(item.DispenseStartTime, out DateTime dtr))
|
||||
{
|
||||
//计算用时
|
||||
item.UsageTime = $"{(int)(dte - dtr).TotalMinutes}:{(dte - dtr).Seconds:D2}";
|
||||
}
|
||||
}
|
||||
if (DateTime.TryParse(item.CallTime, out DateTime dtc))
|
||||
{
|
||||
item.CallTime = dtc.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
}
|
||||
if (item.ProductType == 1 && item.Process == null) item.Process = "未知";
|
||||
if (item.ProductType == 3) item.Tank = item.PowderTargetTank.ToString();
|
||||
|
||||
//行信息
|
||||
QueryDetailDyelotDetailsItems.Add(item);
|
||||
}
|
||||
|
||||
if (data.Count == 0)
|
||||
{//如果无信息添加空白行
|
||||
QueryDetailDyelotDetailsItems.Add(new DyelotDetailsItem { });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,56 +4,40 @@
|
||||
x:Class="SunlightAggregationTerminal.QueryPage"
|
||||
Title="">
|
||||
<Grid>
|
||||
<VerticalStackLayout>
|
||||
<Grid RowDefinitions="Auto, *" ColumnDefinitions="*, Auto">
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Stroke="#CCCCCC"
|
||||
StrokeThickness="1"
|
||||
StrokeShape="RoundRectangle 10"
|
||||
BackgroundColor="White"
|
||||
Padding="0,0"
|
||||
VerticalOptions="Center"
|
||||
Margin="10,10,0,10">
|
||||
<Entry x:Name="ResultEntry"
|
||||
Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
FontSize="Medium"
|
||||
Placeholder="等待扫码..."
|
||||
VerticalOptions="Center"
|
||||
BackgroundColor="Transparent"
|
||||
Margin="0,0,0,0" >
|
||||
</Entry>
|
||||
<Grid RowDefinitions="Auto, *" >
|
||||
<Grid RowDefinitions="Auto, *" ColumnDefinitions="*, Auto"
|
||||
Grid.Row="0" Grid.Column="0">
|
||||
<Border Grid.Row="0" Grid.Column="0" Stroke="#CCCCCC"
|
||||
StrokeThickness="1" StrokeShape="RoundRectangle 10"
|
||||
BackgroundColor="White" Padding="0,0"
|
||||
VerticalOptions="Center" Margin="10,10,0,10">
|
||||
<Entry x:Name="ResultEntry" Grid.Row="0"
|
||||
Grid.Column="0" FontSize="Medium"
|
||||
Placeholder="等待扫码..." VerticalOptions="Center"
|
||||
BackgroundColor="Transparent" Margin="0,0,0,0" />
|
||||
</Border>
|
||||
<!--扫码按钮-->
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="1"
|
||||
Clicked="OnScanButtonClicked"
|
||||
BackgroundColor="Transparent"
|
||||
WidthRequest="60"
|
||||
HeightRequest="60"
|
||||
Margin="10">
|
||||
<Button Grid.Row="0" Grid.Column="1" Clicked="OnScanButtonClicked"
|
||||
BackgroundColor="Transparent" WidthRequest="80"
|
||||
HeightRequest="60" Margin="10">
|
||||
<Button.ImageSource>
|
||||
<!-- 设置图标 -->
|
||||
<FileImageSource File="lucidescanline.png" />
|
||||
</Button.ImageSource>
|
||||
</Button>
|
||||
</Grid>
|
||||
<StackLayout >
|
||||
|
||||
<HorizontalStackLayout>
|
||||
<DatePicker Format="yyyy年MM月dd日" FontSize="18"/>
|
||||
<Label Text="~" FontSize="32"/>
|
||||
<DatePicker Format="yyyy年MM月dd日" FontSize="18"/>
|
||||
<Button Text="搜索" Margin="5"/>
|
||||
<HorizontalStackLayout Grid.Row="1" Grid.Column="0" Margin="5,0,0,0" >
|
||||
<DatePicker x:Name="StartTime" Format="yyyy年MM月dd日" FontSize="16"
|
||||
MaximumWidthRequest="150" MinimumWidthRequest="130" WidthRequest="135"/>
|
||||
<Label Text="~" FontSize="28"/>
|
||||
<DatePicker x:Name="EndTime" Format="yyyy年MM月dd日" FontSize="16"
|
||||
MaximumWidthRequest="150" MinimumWidthRequest="130" WidthRequest="135"/>
|
||||
</HorizontalStackLayout>
|
||||
<Button Grid.Row="1" Grid.Column="1" Text="搜索" Clicked="Button_Clicked"
|
||||
WidthRequest="60" Padding="5,0,5,0" Margin="20,0,0,5" />
|
||||
</Grid>
|
||||
|
||||
</StackLayout>
|
||||
|
||||
<Grid>
|
||||
<CollectionView x:Name="CardCollectionView"
|
||||
ItemsSource="{Binding DyelotItems}"
|
||||
RemainingItemsThreshold="5">
|
||||
<Grid Grid.Row="1" Grid.Column="0">
|
||||
<CollectionView x:Name="CardCollectionView">
|
||||
<!-- 保持滚动条 -->
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
@@ -61,78 +45,48 @@
|
||||
<Border BackgroundColor="White"
|
||||
Stroke="#CCCCCC" StrokeThickness="1"
|
||||
Margin="10,0,10,10" StrokeShape="RoundRectangle 10">
|
||||
<Grid Padding="15">
|
||||
<VerticalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工单: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Dyelot}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="机台: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Machine}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="下单时间: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CreationTime}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="面料: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding FabricName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="颜色: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ColorName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="客户: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CustomerName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
<VerticalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工单: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Dyelot}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
<Label Text="@" FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ReDye}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="机台: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Machine}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="下单时间: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CreationTime}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="工艺: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding Program}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="面料: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding FabricName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="客户: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding CustomerName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
<HorizontalStackLayout>
|
||||
<Label Text="颜色: " FontAttributes="Bold" FontSize="22" TextColor="Black"/>
|
||||
<Label Text="{Binding ColorName}" FontAttributes="Bold" FontSize="22" TextColor="Gray"/>
|
||||
</HorizontalStackLayout>
|
||||
</VerticalStackLayout>
|
||||
<Border.GestureRecognizers>
|
||||
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
|
||||
</Border.GestureRecognizers>
|
||||
</Border>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
|
||||
|
||||
|
||||
<CollectionView ItemsSource="{Binding Items}" IsVisible="False">
|
||||
<CollectionView.Header>
|
||||
<!-- 表头 -->
|
||||
<Grid BackgroundColor="Gray" Padding="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="2*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Label Text="步骤" TextColor="White" FontAttributes="Bold" Grid.Column="0"/>
|
||||
<Label Text="物料" TextColor="White" FontAttributes="Bold" Grid.Column="1"/>
|
||||
<Label Text="状态" TextColor="White" FontAttributes="Bold" Grid.Column="2"/>
|
||||
<Label Text="实际" TextColor="White" FontAttributes="Bold" Grid.Column="3"/>
|
||||
<Label Text="时间" TextColor="White" FontAttributes="Bold" Grid.Column="4"/>
|
||||
</Grid>
|
||||
</CollectionView.Header>
|
||||
|
||||
<CollectionView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<!-- 数据行 -->
|
||||
<Grid Padding="10" ColumnDefinitions="*,2*,*,*,*">
|
||||
<Label Text="{Binding Id}" Grid.Column="0"/>
|
||||
<Label Text="{Binding Name}" Grid.Column="1"/>
|
||||
<Label Text="{Binding Start}" Grid.Column="2"/>
|
||||
<Label Text="{Binding Value}" Grid.Column="3"/>
|
||||
<Label Text="{Binding date}" Grid.Column="4"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</CollectionView.ItemTemplate>
|
||||
</CollectionView>
|
||||
</CollectionView>
|
||||
</Grid>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
|
||||
<!-- 查询中动画页面 -->
|
||||
<Grid x:Name="LoadingIndicator" BackgroundColor="Gray"
|
||||
IsVisible="False" Opacity="0.9">
|
||||
@@ -143,10 +97,8 @@
|
||||
Color="#512BD4"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Label Text="查询中..."
|
||||
FontAttributes="Bold"
|
||||
FontSize="24"
|
||||
TextColor="Black"/>
|
||||
<Label Text="查询中..." FontAttributes="Bold"
|
||||
FontSize="24" TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -3,7 +3,7 @@ using SunlightAggregationTerminal.Class;
|
||||
using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using static SunlightAggregationTerminal.QueryPage;
|
||||
using TouchSocket.Core;
|
||||
|
||||
namespace SunlightAggregationTerminal;
|
||||
|
||||
@@ -17,18 +17,46 @@ public partial class QueryPage : ContentPage
|
||||
|
||||
WeakReferenceMessenger.Default.Register<string>(this, (r, scannedValue) =>
|
||||
{
|
||||
ResultEntry.Text = scannedValue;
|
||||
ResultEntry.Text = scannedValue;
|
||||
//扫码返回信息
|
||||
if (!string.IsNullOrWhiteSpace(scannedValue))
|
||||
{
|
||||
Dictionary<string, object> QueryDictionary = new Dictionary<string, object>();
|
||||
QueryDictionary.Add("Command", "QueryDyelot");
|
||||
QueryDictionary.Add("Field", "[Dyelot],[ReDye],[Program],[Color],[CreationTime]," +
|
||||
"[Batch],[OrderNo],[TotalWeight],[LiquidRatio],[TotalVolume],[Final],[UserAccount]," +
|
||||
"[FabricName],[ColorName],[CustomerName]");
|
||||
QueryDictionary.Add("DyelotName", scannedValue);
|
||||
Query_Command(QueryDictionary.ToJsonString());
|
||||
}
|
||||
});
|
||||
|
||||
Query_data();
|
||||
|
||||
CardCollectionView.ItemsSource = DyelotItems;
|
||||
}
|
||||
|
||||
//扫码按钮
|
||||
private async void OnScanButtonClicked(object sender, EventArgs e)
|
||||
{
|
||||
ResultEntry.Text = "";
|
||||
// 跳转到扫码页面
|
||||
await Navigation.PushAsync(new ScanPage(0));
|
||||
}
|
||||
|
||||
private void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
|
||||
//打开单个选项卡
|
||||
private async void TapGestureRecognizer_Tapped(object sender, TappedEventArgs e)
|
||||
{
|
||||
if (sender is Microsoft.Maui.Controls.BindableObject bindable)
|
||||
{
|
||||
var context = bindable.BindingContext;
|
||||
|
||||
if (context is DyelotItem item)
|
||||
{
|
||||
await Navigation.PushAsync(new QueryDetail(item));
|
||||
}
|
||||
}
|
||||
ResultEntry.Text = "";
|
||||
}
|
||||
|
||||
//信息回复
|
||||
@@ -42,19 +70,26 @@ public partial class QueryPage : ContentPage
|
||||
{
|
||||
foreach (var item in data)
|
||||
{
|
||||
if(item.CreationTime != null) item.CreationTime = item.CreationTime.Replace("T", " ");
|
||||
DyelotItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.Count == 0)
|
||||
{//如果无信息添加空白行
|
||||
DyelotItems.Add(new DyelotItem { });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception) {
|
||||
}
|
||||
catch (Exception) { }
|
||||
}
|
||||
|
||||
public async void Query_Command(string dat)
|
||||
{
|
||||
LoadingIndicator.IsVisible = true;
|
||||
DyelotItems.Clear();
|
||||
|
||||
TcpServer.TcpTransmit(dat);
|
||||
|
||||
DataReceived.Transmit(dat);
|
||||
|
||||
// 创建一个 15 秒的延时任务
|
||||
Task delayTask = Task.Delay(15000);
|
||||
@@ -72,6 +107,39 @@ public partial class QueryPage : ContentPage
|
||||
|
||||
LoadingIndicator.IsVisible = false;
|
||||
}
|
||||
|
||||
private void Button_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
if (ResultEntry.Text.Length >0)
|
||||
{
|
||||
Dictionary<string, object> QueryDictionary = new Dictionary<string, object>();
|
||||
QueryDictionary.Add("Command", "QueryDyelot");
|
||||
QueryDictionary.Add("Field", "[Dyelot],[ReDye],[Program],[Color],[CreationTime]," +
|
||||
"[Batch],[OrderNo],[TotalWeight],[LiquidRatio],[TotalVolume],[Final],[UserAccount]," +
|
||||
"[FabricName],[ColorName],[CustomerName]");
|
||||
QueryDictionary.Add("DyelotName", ResultEntry.Text);
|
||||
Query_Command(QueryDictionary.ToJsonString());
|
||||
}
|
||||
else
|
||||
{
|
||||
Query_data();
|
||||
}
|
||||
}
|
||||
|
||||
private void Query_data()
|
||||
{
|
||||
Dictionary<string, object> QueryDictionary = new Dictionary<string, object>();
|
||||
QueryDictionary.Add("Command", "Query");
|
||||
QueryDictionary.Add("Field", "[Dyelot],[ReDye],[Program],[Color],[CreationTime]," +
|
||||
"[Batch],[OrderNo],[TotalWeight],[LiquidRatio],[TotalVolume],[Final],[UserAccount]," +
|
||||
"[FabricName],[ColorName],[CustomerName]");
|
||||
DateTime StartTimee_ = (DateTime)StartTime.Date!;
|
||||
QueryDictionary.Add("StartTime", StartTimee_.ToString("yyyy-MM-dd"));
|
||||
DateTime EndTime_ = (DateTime)EndTime.Date!;
|
||||
QueryDictionary.Add("EndTime", EndTime_.AddDays(1).ToString("yyyy-MM-dd"));
|
||||
Query_Command(QueryDictionary.ToJsonString());
|
||||
}
|
||||
|
||||
// 处理“回车/完成”按钮点击
|
||||
/* private void OnEntryCompleted()
|
||||
{
|
||||
@@ -79,10 +147,14 @@ public partial class QueryPage : ContentPage
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(inputText))
|
||||
{
|
||||
// 在这里处理用户手动输入的内容
|
||||
// 例如:验证格式、跳转页面、或者搜索商品
|
||||
//DisplayAlert("提示", $"你输入了: {inputText}", "确定");
|
||||
}
|
||||
Dictionary<string, object> QueryDictionary = new Dictionary<string, object>();
|
||||
QueryDictionary.Add("Command", "QueryDyelot");
|
||||
QueryDictionary.Add("Field", "[Dyelot],[ReDye],[Program],[Color],[CreationTime]," +
|
||||
"[Batch],[OrderNo],[TotalWeight],[LiquidRatio],[TotalVolume],[Final],[UserAccount]," +
|
||||
"[FabricName],[ColorName],[CustomerName],[Notes]");
|
||||
QueryDictionary.Add("DyelotName", inputText);
|
||||
Query_Command(QueryDictionary.ToJsonString());
|
||||
}
|
||||
}*/
|
||||
|
||||
}
|
||||
|
After Width: | Height: | Size: 110 KiB |
|
After Width: | Height: | Size: 128 KiB |
|
After Width: | Height: | Size: 101 KiB |
|
After Width: | Height: | Size: 132 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 231 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 38 KiB |
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace SunlightAggregationTerminal
|
||||
{
|
||||
public interface INotificationService
|
||||
{
|
||||
void SendNotification(string title, string message, int notificationId = 0);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,15 @@
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">21.0</SupportedOSPlatformVersion>
|
||||
<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</SupportedOSPlatformVersion>
|
||||
<TargetPlatformMinVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'windows'">10.0.17763.0</TargetPlatformMinVersion>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Debug|net10.0-android|AnyCPU'">
|
||||
<EmbedAssembliesIntoApk>True</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(TargetFramework)|$(Platform)'=='Release|net10.0-android|AnyCPU'">
|
||||
<AndroidPackageFormat>apk</AndroidPackageFormat>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@@ -83,15 +92,28 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.2" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.7" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.51" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.7" />
|
||||
<PackageReference Include="TouchSocket" Version="4.2.7" />
|
||||
<PackageReference Include="ZXing.Net.Maui.Controls" Version="0.7.4" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Maui.Controls" Version="10.0.80" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="10.0.10" />
|
||||
<PackageReference Include="TouchSocket" Version="4.2.10" />
|
||||
<PackageReference Include="TouchSocket.Http" Version="4.2.10" />
|
||||
<PackageReference Include="ZXing.Net.Maui.Controls" Version="0.10.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Update="View\LogLoading.xaml.cs">
|
||||
<DependentUpon>LogLoading.xaml</DependentUpon>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<MauiXaml Update="InfoChemicalStatistics.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="InfoDetail.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="InfoPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
@@ -110,22 +132,24 @@
|
||||
<MauiXaml Update="ProfilePage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="QueryDetail.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="QueryPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="ScanPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="View\LogLoading.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="View\Loading.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="View\LogPage.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
<MauiXaml Update="View\LogWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</MauiXaml>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Services\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.View.Loading"
|
||||
Title="Loading">
|
||||
<Grid x:Name="LoadingIndicator" BackgroundColor="Gray"
|
||||
IsVisible="True" Opacity="0.9">
|
||||
<VerticalStackLayout Padding="30" Spacing="10"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<ActivityIndicator IsRunning="True"
|
||||
Color="#512BD4"
|
||||
HorizontalOptions="Center"
|
||||
VerticalOptions="Center" />
|
||||
<Label Text="等待中..."
|
||||
FontAttributes="Bold"
|
||||
FontSize="24"
|
||||
TextColor="Black"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace SunlightAggregationTerminal.View;
|
||||
|
||||
public partial class Loading : ContentPage
|
||||
{
|
||||
public Loading()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.View.LogLoading"
|
||||
Title="LogLoading">
|
||||
<Grid x:Name="LoadingIndicator" BackgroundColor="Gray"
|
||||
IsVisible="True" Opacity="0.9">
|
||||
<VerticalStackLayout Padding="30" Spacing="10"
|
||||
VerticalOptions="Center"
|
||||
HorizontalOptions="Center">
|
||||
<Button Text="登 录"
|
||||
BackgroundColor="#512BD4"
|
||||
TextColor="White"
|
||||
HeightRequest="50"
|
||||
WidthRequest="100"
|
||||
CornerRadius="10"
|
||||
Margin="0,10,0,0"
|
||||
Clicked="Button_Clicked"/>
|
||||
</VerticalStackLayout>
|
||||
</Grid>
|
||||
</ContentPage>
|
||||
@@ -0,0 +1,17 @@
|
||||
namespace SunlightAggregationTerminal.View;
|
||||
|
||||
public partial class LogLoading : ContentPage
|
||||
{
|
||||
public LogLoading()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void Button_Clicked(object sender, EventArgs e)
|
||||
{
|
||||
await Navigation.PopModalAsync();
|
||||
var logpage = new View.LogPage();
|
||||
await Navigation.PushModalAsync(logpage);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using SunlightAggregationTerminal.Models;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using static System.Net.Mime.MediaTypeNames;
|
||||
|
||||
namespace SunlightAggregationTerminal.View;
|
||||
|
||||
@@ -28,7 +29,7 @@ public partial class LogPage : ContentPage
|
||||
|
||||
//可用服务器列表
|
||||
AppModels.sqliteHelper.Open();
|
||||
var userdata = AppModels.sqliteHelper.ExecuteDataSet("select * from Server", null);
|
||||
var userdata = AppModels.sqliteHelper.ExecuteDataSet("SELECT * FROM Server", null);
|
||||
AppModels.sqliteHelper.Close();
|
||||
|
||||
Items = new ObservableCollection<ItemOption>();
|
||||
@@ -39,10 +40,13 @@ public partial class LogPage : ContentPage
|
||||
{
|
||||
if (dataRow != null)
|
||||
{
|
||||
string _SERVER = dataRow.Field<string>("Server")!;
|
||||
string _SERVERIP = dataRow.Field<string>("ServerID")! + "," + dataRow.Field<string>("ServerHTTP")!;
|
||||
|
||||
var dat = new ItemOption
|
||||
{
|
||||
SERVER = dataRow.Field<string>("Server") ?? "",
|
||||
SERVERIP = dataRow.Field<string>("ServerID") ?? ""
|
||||
SERVER = _SERVER,
|
||||
SERVERIP = _SERVERIP
|
||||
};
|
||||
Items.Add(dat);
|
||||
}
|
||||
@@ -69,47 +73,62 @@ public partial class LogPage : ContentPage
|
||||
{
|
||||
// 跳转到扫码页面
|
||||
var scanPage = new ScanPage(3);
|
||||
Navigation.PushAsync(scanPage);
|
||||
Navigation.PushModalAsync(scanPage);
|
||||
}
|
||||
|
||||
private async void Log_Clicked(object sender, EventArgs e)//登录
|
||||
{
|
||||
TcpServer.Configuration(SERVERIP.Text, UsernameEntry.Text, PasswordEntry.Text,
|
||||
Models.AppModels.GetAppUniqueId());
|
||||
|
||||
LoadingIndicator.IsVisible = true;
|
||||
|
||||
string[] result = SERVERIP.Text.Split(',', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
|
||||
App.GlobalData.ServerID = result[0]?? "";
|
||||
//判断是否有http连接信息
|
||||
if (result.Length ==2)
|
||||
{
|
||||
App.GlobalData.ServerHTTP = result[1] ?? "";
|
||||
App.GlobalData.LocalAreaNetworkMode = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
App.GlobalData.LocalAreaNetworkMode = true;
|
||||
}
|
||||
App.GlobalData.User = UsernameEntry.Text;
|
||||
App.GlobalData.UserPassword = PasswordEntry.Text;
|
||||
|
||||
if (await AppModels.LogIn())
|
||||
{
|
||||
App.GlobalData.ServerID = SERVERIP.Text;
|
||||
|
||||
int temp_name = AppModels.Select("SELECT * FROM Users WHERE User='" + UsernameEntry.Text + "' LIMIT 1;")!.Tables[0].Rows.Count;
|
||||
if (temp_name >0)
|
||||
{
|
||||
//存在更新账号状态
|
||||
string sql = "UPDATE Users SET ServerID = '" + SERVERIP.Text
|
||||
+ "', UserPassword = '" + PasswordEntry.Text +
|
||||
"', LogNo = 1 WHERE User='" + UsernameEntry.Text + "';";
|
||||
string sql = "UPDATE Users SET ServerID = '" + App.GlobalData.ServerID
|
||||
+ "', ServerHTTP = '" + App.GlobalData.ServerHTTP
|
||||
+ "', UserPassword = '" + PasswordEntry.Text
|
||||
+"', LogNo = 1 WHERE User='" + UsernameEntry.Text + "';";
|
||||
AppModels.Updata(sql);
|
||||
}
|
||||
else
|
||||
{
|
||||
//插入账号
|
||||
string sql = @"INSERT INTO Users (User,UserId ,UserName ,UserPassword ,
|
||||
Enterprise ,Department ,ServerID ,Groups ,
|
||||
Enterprise ,Department ,ServerID ,ServerHTTP ,Groups ,
|
||||
ProxyID ,LogNo ,LocalAreaNetworkMode ,DarkMode ,
|
||||
MessageNotificationMode ,GUID
|
||||
)VALUES('" + UsernameEntry.Text + "','SUNLIGHT','SUNLIGHT','" + PasswordEntry.Text +
|
||||
"','SUNLIGHT','ENGINEER','" + SERVERIP.Text + "','ENGINEER'," +
|
||||
" '',1,0,0,0,'" + Models.AppModels.GetAppUniqueId() + "');";
|
||||
MessageNotificationMode ,GUID ,NotificationID
|
||||
)VALUES('" + UsernameEntry.Text + "','"+ App.GlobalData.UserId +
|
||||
"','" + App.GlobalData.UserName + "','" + PasswordEntry.Text +
|
||||
"','"+ App.GlobalData.Enterprise + "','"+ App.GlobalData.Department +
|
||||
"','" + App.GlobalData.ServerID + "','" +App.GlobalData.ServerHTTP+
|
||||
"','"+ App.GlobalData.Groups + "'," + " '',1,0,0,0,'" +
|
||||
Models.AppModels.GetAppUniqueId() + "','0');";
|
||||
AppModels.INSERT(sql);
|
||||
}
|
||||
|
||||
int temp_server = AppModels.Select("SELECT * FROM Server WHERE ServerID='" + SERVERIP.Text + "' LIMIT 1;")!.Tables[0].Rows.Count;
|
||||
int temp_server = AppModels.Select("SELECT * FROM Server WHERE Server='"+ App.GlobalData.Enterprise + "' LIMIT 1;")!.Tables[0].Rows.Count;
|
||||
if (temp_server == 0)
|
||||
{
|
||||
string sql = @"INSERT INTO Server ( Server, ServerID)VALUES('" + App.GlobalData.Enterprise + "','" +
|
||||
App.GlobalData.ServerID + "');";
|
||||
string sql = @"INSERT INTO Server ( Server, ServerID,ServerHTTP)VALUES('" + App.GlobalData.Enterprise + "','" +
|
||||
App.GlobalData.ServerID+"','"+ App.GlobalData.ServerHTTP + "');";
|
||||
AppModels.INSERT(sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<Window xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
|
||||
x:Class="SunlightAggregationTerminal.View.LogWindow"
|
||||
Title="LogWindow">
|
||||
<ContentPage>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<Button Text="登 录"
|
||||
BackgroundColor="#512BD4"
|
||||
TextColor="White"
|
||||
HeightRequest="50"
|
||||
WidthRequest="100"
|
||||
CornerRadius="10"
|
||||
Margin="0,10,0,0"/>
|
||||
</ContentPage>
|
||||
</Window>
|
||||
@@ -1,19 +0,0 @@
|
||||
namespace SunlightAggregationTerminal.View;
|
||||
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
public LogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Page = new ContentPage()
|
||||
{
|
||||
Content = new VerticalStackLayout
|
||||
{
|
||||
Children = {
|
||||
new Label { HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center, Text = "Welcome to .NET MAUI!"
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC 清单选项
|
||||
如果想要更改 Windows 用户帐户控制级别,请使用
|
||||
以下节点之一替换 requestedExecutionLevel 节点。
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
|
||||
如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
|
||||
元素。
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
|
||||
Windows 版本的列表。取消评论适当的元素,
|
||||
Windows 将自动选择最兼容的环境。 -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
|
||||
自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
|
||||
选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
|
||||
在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
|
||||
|
||||
将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
|
||||
<!--
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
-->
|
||||
|
||||
<!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
||||