DataServices 现场调试OK
This commit is contained in:
62
FATrace.App/frmMain.Designer.cs
generated
62
FATrace.App/frmMain.Designer.cs
generated
@@ -85,7 +85,7 @@ namespace FATrace.App
|
|||||||
tabPage3 = new TabPage();
|
tabPage3 = new TabPage();
|
||||||
btnLogin = new Button();
|
btnLogin = new Button();
|
||||||
txtPassword = new TextBox();
|
txtPassword = new TextBox();
|
||||||
txtUserName = new TextBox();
|
txtCheckUserName = new TextBox();
|
||||||
label17 = new Label();
|
label17 = new Label();
|
||||||
label16 = new Label();
|
label16 = new Label();
|
||||||
label15 = new Label();
|
label15 = new Label();
|
||||||
@@ -103,6 +103,8 @@ namespace FATrace.App
|
|||||||
dtpSearchStartTime = new DateTimePicker();
|
dtpSearchStartTime = new DateTimePicker();
|
||||||
dataGridView1 = new DataGridView();
|
dataGridView1 = new DataGridView();
|
||||||
label22 = new Label();
|
label22 = new Label();
|
||||||
|
txtOpName = new TextBox();
|
||||||
|
label28 = new Label();
|
||||||
statusStrip1.SuspendLayout();
|
statusStrip1.SuspendLayout();
|
||||||
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
|
((System.ComponentModel.ISupportInitialize)splitContainer1).BeginInit();
|
||||||
splitContainer1.Panel1.SuspendLayout();
|
splitContainer1.Panel1.SuspendLayout();
|
||||||
@@ -369,11 +371,11 @@ namespace FATrace.App
|
|||||||
//
|
//
|
||||||
// btnWeightPrint
|
// btnWeightPrint
|
||||||
//
|
//
|
||||||
btnWeightPrint.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
|
btnWeightPrint.Font = new Font("Microsoft YaHei UI", 20F, FontStyle.Bold);
|
||||||
btnWeightPrint.ForeColor = SystemColors.ControlDarkDark;
|
btnWeightPrint.ForeColor = SystemColors.ControlDarkDark;
|
||||||
btnWeightPrint.Location = new Point(741, 119);
|
btnWeightPrint.Location = new Point(670, 95);
|
||||||
btnWeightPrint.Name = "btnWeightPrint";
|
btnWeightPrint.Name = "btnWeightPrint";
|
||||||
btnWeightPrint.Size = new Size(119, 47);
|
btnWeightPrint.Size = new Size(190, 71);
|
||||||
btnWeightPrint.TabIndex = 9;
|
btnWeightPrint.TabIndex = 9;
|
||||||
btnWeightPrint.Text = "称重打印";
|
btnWeightPrint.Text = "称重打印";
|
||||||
btnWeightPrint.UseVisualStyleBackColor = true;
|
btnWeightPrint.UseVisualStyleBackColor = true;
|
||||||
@@ -735,9 +737,11 @@ namespace FATrace.App
|
|||||||
//
|
//
|
||||||
// tabPage3
|
// tabPage3
|
||||||
//
|
//
|
||||||
|
tabPage3.Controls.Add(txtOpName);
|
||||||
|
tabPage3.Controls.Add(label28);
|
||||||
tabPage3.Controls.Add(btnLogin);
|
tabPage3.Controls.Add(btnLogin);
|
||||||
tabPage3.Controls.Add(txtPassword);
|
tabPage3.Controls.Add(txtPassword);
|
||||||
tabPage3.Controls.Add(txtUserName);
|
tabPage3.Controls.Add(txtCheckUserName);
|
||||||
tabPage3.Controls.Add(label17);
|
tabPage3.Controls.Add(label17);
|
||||||
tabPage3.Controls.Add(label16);
|
tabPage3.Controls.Add(label16);
|
||||||
tabPage3.Controls.Add(label15);
|
tabPage3.Controls.Add(label15);
|
||||||
@@ -753,7 +757,7 @@ namespace FATrace.App
|
|||||||
btnLogin.BackColor = Color.SandyBrown;
|
btnLogin.BackColor = Color.SandyBrown;
|
||||||
btnLogin.Font = new Font("微软雅黑", 22F);
|
btnLogin.Font = new Font("微软雅黑", 22F);
|
||||||
btnLogin.ForeColor = SystemColors.ButtonHighlight;
|
btnLogin.ForeColor = SystemColors.ButtonHighlight;
|
||||||
btnLogin.Location = new Point(329, 387);
|
btnLogin.Location = new Point(355, 372);
|
||||||
btnLogin.Name = "btnLogin";
|
btnLogin.Name = "btnLogin";
|
||||||
btnLogin.Size = new Size(224, 79);
|
btnLogin.Size = new Size(224, 79);
|
||||||
btnLogin.TabIndex = 7;
|
btnLogin.TabIndex = 7;
|
||||||
@@ -764,24 +768,24 @@ namespace FATrace.App
|
|||||||
// txtPassword
|
// txtPassword
|
||||||
//
|
//
|
||||||
txtPassword.Font = new Font("微软雅黑", 16F);
|
txtPassword.Font = new Font("微软雅黑", 16F);
|
||||||
txtPassword.Location = new Point(365, 296);
|
txtPassword.Location = new Point(335, 296);
|
||||||
txtPassword.Name = "txtPassword";
|
txtPassword.Name = "txtPassword";
|
||||||
txtPassword.Size = new Size(224, 36);
|
txtPassword.Size = new Size(289, 36);
|
||||||
txtPassword.TabIndex = 6;
|
txtPassword.TabIndex = 6;
|
||||||
//
|
//
|
||||||
// txtUserName
|
// txtCheckUserName
|
||||||
//
|
//
|
||||||
txtUserName.Font = new Font("微软雅黑", 16F);
|
txtCheckUserName.Font = new Font("微软雅黑", 16F);
|
||||||
txtUserName.Location = new Point(365, 218);
|
txtCheckUserName.Location = new Point(335, 218);
|
||||||
txtUserName.Name = "txtUserName";
|
txtCheckUserName.Name = "txtCheckUserName";
|
||||||
txtUserName.Size = new Size(224, 36);
|
txtCheckUserName.Size = new Size(97, 36);
|
||||||
txtUserName.TabIndex = 5;
|
txtCheckUserName.TabIndex = 5;
|
||||||
//
|
//
|
||||||
// label17
|
// label17
|
||||||
//
|
//
|
||||||
label17.AutoSize = true;
|
label17.AutoSize = true;
|
||||||
label17.Font = new Font("微软雅黑", 16F);
|
label17.Font = new Font("微软雅黑", 16F);
|
||||||
label17.Location = new Point(277, 296);
|
label17.Location = new Point(247, 296);
|
||||||
label17.Name = "label17";
|
label17.Name = "label17";
|
||||||
label17.Size = new Size(62, 30);
|
label17.Size = new Size(62, 30);
|
||||||
label17.TabIndex = 4;
|
label17.TabIndex = 4;
|
||||||
@@ -791,17 +795,17 @@ namespace FATrace.App
|
|||||||
//
|
//
|
||||||
label16.AutoSize = true;
|
label16.AutoSize = true;
|
||||||
label16.Font = new Font("微软雅黑", 16F);
|
label16.Font = new Font("微软雅黑", 16F);
|
||||||
label16.Location = new Point(277, 219);
|
label16.Location = new Point(247, 219);
|
||||||
label16.Name = "label16";
|
label16.Name = "label16";
|
||||||
label16.Size = new Size(84, 30);
|
label16.Size = new Size(84, 30);
|
||||||
label16.TabIndex = 3;
|
label16.TabIndex = 3;
|
||||||
label16.Text = "用户名:";
|
label16.Text = "确认者:";
|
||||||
//
|
//
|
||||||
// label15
|
// label15
|
||||||
//
|
//
|
||||||
label15.AutoSize = true;
|
label15.AutoSize = true;
|
||||||
label15.Font = new Font("微软雅黑", 26.75F);
|
label15.Font = new Font("微软雅黑", 26.75F);
|
||||||
label15.Location = new Point(365, 128);
|
label15.Location = new Point(361, 128);
|
||||||
label15.Name = "label15";
|
label15.Name = "label15";
|
||||||
label15.Size = new Size(164, 46);
|
label15.Size = new Size(164, 46);
|
||||||
label15.TabIndex = 2;
|
label15.TabIndex = 2;
|
||||||
@@ -957,6 +961,24 @@ namespace FATrace.App
|
|||||||
label22.Text = "历史数据";
|
label22.Text = "历史数据";
|
||||||
label22.TextAlign = ContentAlignment.MiddleCenter;
|
label22.TextAlign = ContentAlignment.MiddleCenter;
|
||||||
//
|
//
|
||||||
|
// txtOpName
|
||||||
|
//
|
||||||
|
txtOpName.Font = new Font("微软雅黑", 16F);
|
||||||
|
txtOpName.Location = new Point(527, 218);
|
||||||
|
txtOpName.Name = "txtOpName";
|
||||||
|
txtOpName.Size = new Size(97, 36);
|
||||||
|
txtOpName.TabIndex = 9;
|
||||||
|
//
|
||||||
|
// label28
|
||||||
|
//
|
||||||
|
label28.AutoSize = true;
|
||||||
|
label28.Font = new Font("微软雅黑", 16F);
|
||||||
|
label28.Location = new Point(439, 219);
|
||||||
|
label28.Name = "label28";
|
||||||
|
label28.Size = new Size(84, 30);
|
||||||
|
label28.TabIndex = 8;
|
||||||
|
label28.Text = "操作者:";
|
||||||
|
//
|
||||||
// frmMain
|
// frmMain
|
||||||
//
|
//
|
||||||
AutoScaleDimensions = new SizeF(7F, 17F);
|
AutoScaleDimensions = new SizeF(7F, 17F);
|
||||||
@@ -1039,7 +1061,7 @@ namespace FATrace.App
|
|||||||
private Label label14;
|
private Label label14;
|
||||||
private Button btnLogin;
|
private Button btnLogin;
|
||||||
private TextBox txtPassword;
|
private TextBox txtPassword;
|
||||||
private TextBox txtUserName;
|
private TextBox txtCheckUserName;
|
||||||
private Label label17;
|
private Label label17;
|
||||||
private Label label16;
|
private Label label16;
|
||||||
private Label label15;
|
private Label label15;
|
||||||
@@ -1077,5 +1099,7 @@ namespace FATrace.App
|
|||||||
private PictureBox pictureBox2;
|
private PictureBox pictureBox2;
|
||||||
private PictureBox pictureBox3;
|
private PictureBox pictureBox3;
|
||||||
private PictureBox pictureBox4;
|
private PictureBox pictureBox4;
|
||||||
|
private TextBox txtOpName;
|
||||||
|
private Label label28;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,9 +182,14 @@ namespace FATrace.App
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前用户名
|
/// 当前确认者用户名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CurrentOperationNo { get; set; } = string.Empty;
|
public string CurrentCheckUserNo { get; set; } = string.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前操作者用户名
|
||||||
|
/// </summary>
|
||||||
|
public string CurrentOpUserNo { get; set; } = string.Empty;
|
||||||
|
|
||||||
public string CurrentOperationNoUserLevel { get; set; } = string.Empty;
|
public string CurrentOperationNoUserLevel { get; set; } = string.Empty;
|
||||||
|
|
||||||
@@ -696,13 +701,14 @@ namespace FATrace.App
|
|||||||
Batch = CurSelectedRawProInput.Batch,
|
Batch = CurSelectedRawProInput.Batch,
|
||||||
InBagCode = Code,
|
InBagCode = Code,
|
||||||
BoxCode = Code + ",A",
|
BoxCode = Code + ",A",
|
||||||
OpUser = CurrentOperationNo,
|
OpUser = CurrentOpUserNo,
|
||||||
CheckUser = CurrentOperationNo,
|
CheckUser = CurrentCheckUserNo,
|
||||||
RawCode = CurSelectedRawProInput.RawCode,
|
RawCode = CurSelectedRawProInput.RawCode,
|
||||||
ShelfLife = CurSelectedRawProInput.ShelfLife,
|
ShelfLife = CurSelectedRawProInput.ShelfLife,
|
||||||
RawName = CurSelectedRawProInput.RawName,
|
RawName = CurSelectedRawProInput.RawName,
|
||||||
RemainWeight = NewRemainWeight,
|
RemainWeight = NewRemainWeight,
|
||||||
Weight = CurWeight,
|
Weight = CurWeight,
|
||||||
|
DeliveryDate= DateTime.Now.ToString("yyyy-MM-dd"),
|
||||||
WeightTime = DateTime.Now,
|
WeightTime = DateTime.Now,
|
||||||
StockWeight = CurSelectedRawProInput.Weight,
|
StockWeight = CurSelectedRawProInput.Weight,
|
||||||
}).ExecuteAffrows();
|
}).ExecuteAffrows();
|
||||||
@@ -714,7 +720,7 @@ namespace FATrace.App
|
|||||||
txtRemainWeight.Text = CurSelectedRawProInput.RemainWeight.ToString();
|
txtRemainWeight.Text = CurSelectedRawProInput.RemainWeight.ToString();
|
||||||
|
|
||||||
//称重检查,如果剩余重量为0,进行提示,当剩余的重量小于称重的重量,进行提示
|
//称重检查,如果剩余重量为0,进行提示,当剩余的重量小于称重的重量,进行提示
|
||||||
if (CurSelectedRawProInput.RemainWeight < CurWeight / 1000)
|
if (CurSelectedRawProInput.RemainWeight < CurWeight / 1000.0)
|
||||||
{
|
{
|
||||||
//剩余的重量小于称重的重量,进行提示,强制进行清零
|
//剩余的重量小于称重的重量,进行提示,强制进行清零
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
@@ -928,9 +934,14 @@ namespace FATrace.App
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(txtUserName.Text))
|
if (string.IsNullOrEmpty(txtCheckUserName.Text))
|
||||||
{
|
{
|
||||||
MessageBox.Show("请输入用户名称", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show("请输入确认者用户名称", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (string.IsNullOrEmpty(txtOpName.Text))
|
||||||
|
{
|
||||||
|
MessageBox.Show("请输入操作者用户名称", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (string.IsNullOrEmpty(txtPassword.Text))
|
if (string.IsNullOrEmpty(txtPassword.Text))
|
||||||
@@ -939,17 +950,17 @@ namespace FATrace.App
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ListUser = FSqlContext.FDb.Select<TbUser>().Where(a => a.UserName == txtUserName.Text.Trim()).ToList();
|
var ListUser = FSqlContext.FDb.Select<TbUser>().Where(a => a.UserName == txtCheckUserName.Text.Trim()).ToList();
|
||||||
if (ListUser != null && ListUser.Count() > 0)
|
if (ListUser != null && ListUser.Count() > 0)
|
||||||
{
|
{
|
||||||
if (ListUser.FirstOrDefault().Password == txtPassword.Text.Trim())
|
if (ListUser.FirstOrDefault().Password == txtPassword.Text.Trim())
|
||||||
{
|
{
|
||||||
MessageBox.Show("登录成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
MessageBox.Show("登录成功!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
||||||
Main_PopUserNameEvent(txtPassword.Text.Trim(), ListUser.FirstOrDefault().AccessLevel);
|
Main_PopUserNameEvent(txtCheckUserName.Text.Trim(), txtOpName.Text.Trim(), ListUser.FirstOrDefault().AccessLevel);
|
||||||
|
|
||||||
this.TabControlMain.SelectedIndex = 0;
|
this.TabControlMain.SelectedIndex = 0;
|
||||||
|
|
||||||
txtUserName.Text = "";
|
txtCheckUserName.Text = "";
|
||||||
txtPassword.Text = "";
|
txtPassword.Text = "";
|
||||||
//PopUserNameEvent(txtUserName.Text.Trim());
|
//PopUserNameEvent(txtUserName.Text.Trim());
|
||||||
//this.Close();
|
//this.Close();
|
||||||
@@ -977,15 +988,17 @@ namespace FATrace.App
|
|||||||
/// 用户登录的事件发布方法
|
/// 用户登录的事件发布方法
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="UserName"></param>
|
/// <param name="UserName"></param>
|
||||||
private void Main_PopUserNameEvent(string UserName, string UserLevel)
|
private void Main_PopUserNameEvent(string CheckUserName, string OpUserName, string UserLevel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
CurrentOperationNo = UserName;
|
CurrentCheckUserNo = CheckUserName;
|
||||||
|
CurrentOpUserNo = OpUserName;
|
||||||
|
|
||||||
CurrentOperationNoUserLevel = UserLevel;
|
CurrentOperationNoUserLevel = UserLevel;
|
||||||
Invoke(new Action(() =>
|
Invoke(new Action(() =>
|
||||||
{
|
{
|
||||||
tslCurrentUser.Text = "当前用户:" + CurrentOperationNo;
|
tslCurrentUser.Text = "确认者用户:" + CurrentCheckUserNo;
|
||||||
tslCurrentUser.BackColor = Color.Green;
|
tslCurrentUser.BackColor = Color.Green;
|
||||||
tslCurrentUser.ForeColor = Color.White;
|
tslCurrentUser.ForeColor = Color.White;
|
||||||
}));
|
}));
|
||||||
@@ -1006,7 +1019,7 @@ namespace FATrace.App
|
|||||||
|
|
||||||
private void btnSysConfig_Click(object sender, EventArgs e)
|
private void btnSysConfig_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(CurrentOperationNo))
|
if (!string.IsNullOrEmpty(CurrentCheckUserNo))
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1048,7 +1061,7 @@ namespace FATrace.App
|
|||||||
|
|
||||||
private void btnMain_Click(object sender, EventArgs e)
|
private void btnMain_Click(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(CurrentOperationNo))
|
if (!string.IsNullOrEmpty(CurrentCheckUserNo))
|
||||||
{
|
{
|
||||||
TabControlMain.SelectedIndex = 0;
|
TabControlMain.SelectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
51
FATrace.Model/HistoryAlarm.cs
Normal file
51
FATrace.Model/HistoryAlarm.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using FreeSql.DataAnnotations;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FATrace.Model
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 报警 HistoryAlarm
|
||||||
|
/// </summary>
|
||||||
|
[Table(Name = "HistoryAlarm")]
|
||||||
|
public class HistoryAlarm
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 主键
|
||||||
|
/// </summary>
|
||||||
|
[Column(IsPrimary = true, IsIdentity = true)]
|
||||||
|
public long Id { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警消息分类
|
||||||
|
/// </summary>
|
||||||
|
[Column(Name = "Category", IsNullable = false, StringLength = 20)]
|
||||||
|
public string? Category { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 报警消息
|
||||||
|
/// </summary>
|
||||||
|
[Column(Name = "Message", IsNullable = false, StringLength = 150)]
|
||||||
|
public string? Message { get; set; }
|
||||||
|
|
||||||
|
///// <summary>
|
||||||
|
///// 报警时长
|
||||||
|
///// 秒
|
||||||
|
///// </summary>
|
||||||
|
//[Column(Name = "Duration")]
|
||||||
|
//public long Duration { get; set; }
|
||||||
|
|
||||||
|
[Column(Name = "CreateTime")]
|
||||||
|
public DateTime CreateTime { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ///////////////////////////////////////////导航属性///////////////////////////////////////////////////////
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
//public Guid? AlarmAddressId { get; set; }
|
||||||
|
//public AlarmAddress AlarmAddress { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,13 @@ namespace FATrace.Model
|
|||||||
[Column(Name = "Batch", IsNullable = false, StringLength = 50)]
|
[Column(Name = "Batch", IsNullable = false, StringLength = 50)]
|
||||||
public string? Batch { get; set; }
|
public string? Batch { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配料日期 当天日期
|
||||||
|
/// 年,月,日
|
||||||
|
/// </summary>
|
||||||
|
[Column(Name = "DeliveryDate", IsNullable = false, StringLength = 30)]
|
||||||
|
public string? DeliveryDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保质期 年
|
/// 保质期 年
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
<add key="PLCIP" value="127.0.1.1" />
|
<add key="PLCIP" value="127.0.1.1" />
|
||||||
<add key="PLCPort" value="5000" />
|
<add key="PLCPort" value="5000" />
|
||||||
<add key="PLCScan" value="600" />
|
<add key="PLCScan" value="600" />
|
||||||
|
<add key="RawProUseCsvPath" value="D:\TestData" />
|
||||||
<!-- Keyence 布尔量地址:用于 WeightPhotoEnable 信号(默认 M100) -->
|
<!-- Keyence 布尔量地址:用于 WeightPhotoEnable 信号(默认 M100) -->
|
||||||
<add key="Addr_WeightPhotoEnable" value="M100" />
|
<add key="Addr_WeightPhotoEnable" value="M100" />
|
||||||
</appSettings>
|
</appSettings>
|
||||||
|
|||||||
@@ -1,20 +1,21 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using DryIoc;
|
||||||
|
using FATrace.Com;
|
||||||
|
using FATrace.WPLApp.MapperProfile;
|
||||||
|
using FATrace.WPLApp.RegionAdapter;
|
||||||
using FATrace.WPLApp.Services;
|
using FATrace.WPLApp.Services;
|
||||||
|
using FATrace.WPLApp.ViewModels;
|
||||||
|
using FATrace.WPLApp.Views;
|
||||||
|
using FreeSql;
|
||||||
using Prism.DryIoc;
|
using Prism.DryIoc;
|
||||||
using Prism.Ioc;
|
using Prism.Ioc;
|
||||||
using Prism.Regions;
|
using Prism.Regions;
|
||||||
using System.Windows;
|
|
||||||
using DryIoc;
|
|
||||||
using AutoMapper;
|
|
||||||
using FreeSql;
|
|
||||||
using FATrace.WPLApp.Views;
|
|
||||||
using FATrace.WPLApp.ViewModels;
|
|
||||||
using FATrace.WPLApp.RegionAdapter;
|
|
||||||
using Syncfusion.UI.Xaml.NavigationDrawer;
|
using Syncfusion.UI.Xaml.NavigationDrawer;
|
||||||
using System.Windows.Threading;
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Diagnostics;
|
using System.Windows;
|
||||||
using FATrace.Com;
|
using System.Windows.Threading;
|
||||||
|
|
||||||
namespace FATrace.WPLApp
|
namespace FATrace.WPLApp
|
||||||
{
|
{
|
||||||
@@ -189,7 +190,7 @@ namespace FATrace.WPLApp
|
|||||||
|
|
||||||
// 基础服务注册
|
// 基础服务注册
|
||||||
containerRegistry.RegisterSingleton<ILogService, LogService>();
|
containerRegistry.RegisterSingleton<ILogService, LogService>();
|
||||||
containerRegistry.RegisterSingleton<IMapperProvider, MapperProvidere>();
|
containerRegistry.RegisterSingleton<IMapperProvider, MapperConfig>();
|
||||||
containerRegistry.Register(typeof(IMapper), GetMapper);
|
containerRegistry.Register(typeof(IMapper), GetMapper);
|
||||||
|
|
||||||
//containerRegistry.RegisterSingleton<AlarmService>();
|
//containerRegistry.RegisterSingleton<AlarmService>();
|
||||||
@@ -255,11 +256,16 @@ namespace FATrace.WPLApp
|
|||||||
//containerRegistry.RegisterForNavigation<ProFlowView, ProFlowViewModel>();
|
//containerRegistry.RegisterForNavigation<ProFlowView, ProFlowViewModel>();
|
||||||
//containerRegistry.RegisterForNavigation<ReportView, ReportViewModel>();
|
//containerRegistry.RegisterForNavigation<ReportView, ReportViewModel>();
|
||||||
//containerRegistry.RegisterForNavigation<HelpManualView, HelpManualViewModel>();
|
//containerRegistry.RegisterForNavigation<HelpManualView, HelpManualViewModel>();
|
||||||
//containerRegistry.RegisterForNavigation<HistoryAlarmView, HistoryAlarmViewModel>();
|
containerRegistry.RegisterForNavigation<HistoryAlarmView, HistoryAlarmViewModel>();
|
||||||
// 原料使用查询页
|
// 原料使用查询页
|
||||||
containerRegistry.RegisterForNavigation<RawProUseView, RawProUseViewModel>();
|
containerRegistry.RegisterForNavigation<RawProUseView, RawProUseViewModel>();
|
||||||
// 原料入库查询页
|
// 原料入库查询页
|
||||||
containerRegistry.RegisterForNavigation<RawProInputView, RawProInputViewModel>();
|
containerRegistry.RegisterForNavigation<RawProInputView, RawProInputViewModel>();
|
||||||
|
// 用户登录
|
||||||
|
containerRegistry.RegisterForNavigation<LoginView, LoginViewModel>("LoginView");
|
||||||
|
containerRegistry.RegisterForNavigation<HistoryAlarmView, HistoryAlarmViewModel>();
|
||||||
|
// 日志查看
|
||||||
|
containerRegistry.RegisterForNavigation<LogView, LogViewModel>("LogView");
|
||||||
|
|
||||||
//containerRegistry.RegisterForNavigation<RealTimeChartView, RealTimeChartViewModel>();
|
//containerRegistry.RegisterForNavigation<RealTimeChartView, RealTimeChartViewModel>();
|
||||||
//containerRegistry.RegisterForNavigation<UserManageView, UserManageViewModel>();
|
//containerRegistry.RegisterForNavigation<UserManageView, UserManageViewModel>();
|
||||||
|
|||||||
45
FATrace.WPLApp/CsvModel/RawProUserCsvDtoMap.cs
Normal file
45
FATrace.WPLApp/CsvModel/RawProUserCsvDtoMap.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using CsvHelper.Configuration;
|
||||||
|
using FATrace.WPLApp.ModelDto;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.CsvModel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// RawProUserCsvDto 的 CSV 列映射,固定输出顺序并设置日期格式。
|
||||||
|
/// </summary>
|
||||||
|
public class RawProUserCsvDtoMap : ClassMap<RawProUserCsvDto>
|
||||||
|
{
|
||||||
|
public RawProUserCsvDtoMap()
|
||||||
|
{
|
||||||
|
//Map(x => x.RawCode).Index(0).Name(nameof(RawProUserCsvDto.RawCode));
|
||||||
|
//Map(x => x.RawName).Index(1).Name(nameof(RawProUserCsvDto.RawName));
|
||||||
|
//Map(x => x.InBagCode).Index(2).Name(nameof(RawProUserCsvDto.InBagCode));
|
||||||
|
//Map(x => x.BoxCode).Index(3).Name(nameof(RawProUserCsvDto.BoxCode));
|
||||||
|
//Map(x => x.Batch).Index(4).Name(nameof(RawProUserCsvDto.Batch));
|
||||||
|
//Map(x => x.ShelfLife).Index(5).Name(nameof(RawProUserCsvDto.ShelfLife));
|
||||||
|
//Map(x => x.Weight).Index(6).Name(nameof(RawProUserCsvDto.Weight));
|
||||||
|
//Map(x => x.DeliveryDate).Index(7).Name(nameof(RawProUserCsvDto.DeliveryDate));
|
||||||
|
//Map(x => x.RemainWeight).Index(8).Name(nameof(RawProUserCsvDto.RemainWeight));
|
||||||
|
//Map(x => x.StockWeight).Index(9).Name(nameof(RawProUserCsvDto.StockWeight));
|
||||||
|
//Map(x => x.WeightTime).Index(10).Name(nameof(RawProUserCsvDto.WeightTime)).TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
||||||
|
//Map(x => x.OpUser).Index(11).Name(nameof(RawProUserCsvDto.OpUser));
|
||||||
|
//Map(x => x.CheckUser).Index(12).Name(nameof(RawProUserCsvDto.CheckUser));
|
||||||
|
//Map(x => x.OutTime).Index(13).Name(nameof(RawProUserCsvDto.OutTime)).TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
Map(x => x.RawCode).Index(0).Name("原料编号");
|
||||||
|
Map(x => x.RawName).Index(1).Name("原料名称");
|
||||||
|
Map(x => x.InBagCode).Index(2).Name("内袋二维码");
|
||||||
|
Map(x => x.BoxCode).Index(3).Name("外箱二维码");
|
||||||
|
Map(x => x.Batch).Index(4).Name("批号");
|
||||||
|
Map(x => x.ShelfLife).Index(5).Name("保质期");
|
||||||
|
Map(x => x.Weight).Index(6).Name("称重重量(g)");
|
||||||
|
Map(x => x.DeliveryDate).Index(7).Name("配料日期");
|
||||||
|
Map(x => x.RemainWeight).Index(8).Name("剩余重量(Kg)");
|
||||||
|
Map(x => x.StockWeight).Index(9).Name("入库总重量(Kg)");
|
||||||
|
Map(x => x.WeightTime).Index(10).Name("称重时间").TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
||||||
|
Map(x => x.OpUser).Index(11).Name("操作者");
|
||||||
|
Map(x => x.CheckUser).Index(12).Name("确认者");
|
||||||
|
Map(x => x.OutTime).Index(13).Name("外箱扫码时间").TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
@@ -58,7 +58,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="PrismEvent\" />
|
<Folder Include="PrismEvent\" />
|
||||||
<Folder Include="MapperProfile\" />
|
|
||||||
<Folder Include="EnvSupport\" />
|
<Folder Include="EnvSupport\" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
@@ -68,4 +67,10 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Report\UserManual.md">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
35
FATrace.WPLApp/MapperProfile/MapperConfig.cs
Normal file
35
FATrace.WPLApp/MapperProfile/MapperConfig.cs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using FATrace.WPLApp.Services;
|
||||||
|
using Prism.Ioc;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.MapperProfile
|
||||||
|
{
|
||||||
|
public class MapperConfig : IMapperProvider
|
||||||
|
{
|
||||||
|
private readonly MapperConfiguration _Configuration;
|
||||||
|
|
||||||
|
public MapperConfig(IContainerProvider container)
|
||||||
|
{
|
||||||
|
_Configuration = new MapperConfiguration(configure =>
|
||||||
|
{
|
||||||
|
//var assemblys = AppDomain.CurrentDomain.GetAssemblies();
|
||||||
|
//configure.AddMaps(assemblys);
|
||||||
|
|
||||||
|
configure.ConstructServicesUsing(container.Resolve);
|
||||||
|
|
||||||
|
//扫描profile文件
|
||||||
|
configure.AddMaps(AppDomain.CurrentDomain.GetAssemblies());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMapper GetMapper()
|
||||||
|
{
|
||||||
|
return _Configuration.CreateMapper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
20
FATrace.WPLApp/MapperProfile/RawProUseProfile.cs
Normal file
20
FATrace.WPLApp/MapperProfile/RawProUseProfile.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using FATrace.Model;
|
||||||
|
using FATrace.WPLApp.ModelDto;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.MapperProfile
|
||||||
|
{
|
||||||
|
public class RawProUseProfile : Profile
|
||||||
|
{
|
||||||
|
public RawProUseProfile()
|
||||||
|
{
|
||||||
|
CreateMap<RawProUse, RawProUserCsvDto>().ReverseMap();
|
||||||
|
CreateMap<RawProUse, RawProUseDto>().ReverseMap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -39,6 +39,11 @@ namespace FATrace.WPLApp.ModelDto
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Batch { get; set; }
|
public string? Batch { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 配料日期
|
||||||
|
/// </summary>
|
||||||
|
public string? DeliveryDate { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 保质期 年
|
/// 保质期 年
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
144
FATrace.WPLApp/Report/UserManual.md
Normal file
144
FATrace.WPLApp/Report/UserManual.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
# FATrace 用户说明书(WPLApp)
|
||||||
|
|
||||||
|
版本:v1.0 适用模块:FATrace.WPLApp(桌面应用)
|
||||||
|
|
||||||
|
## 1. 简介
|
||||||
|
|
||||||
|
FATrace 是一套用于食品添加剂生产过程追溯与运行监控的桌面应用。WPLApp 负责生产端的日常使用,包括:
|
||||||
|
|
||||||
|
- 实时运行信息查看与统计总览(Dashboard)
|
||||||
|
- 历史报警查询(History Alarm)
|
||||||
|
- 用户登录与状态显示
|
||||||
|
- PLC 通信状态指示与当前终端信息(底部状态栏)
|
||||||
|
|
||||||
|
本说明书面向一线操作员、现场工程、以及系统管理员,帮助快速上手并定位常见问题。
|
||||||
|
|
||||||
|
## 2. 安装与启动
|
||||||
|
|
||||||
|
- 安装:由管理员完成程序分发与安装(通常包含可执行文件与依赖项)。
|
||||||
|
- 运行:双击启动桌面应用,进入主界面。
|
||||||
|
- 字体资源:应用内置图标字体,界面会自动加载,无需额外配置。
|
||||||
|
- 数据库:应用使用 FreeSql 进行数据访问。数据库连接等参数由管理员预配置。
|
||||||
|
|
||||||
|
如启动失败、页面空白或频繁报错,请联系系统管理员检查运行环境与数据库连接配置。
|
||||||
|
|
||||||
|
## 3. 登录与账号
|
||||||
|
|
||||||
|
- 打开左侧菜单“用户登录”进入登录页。
|
||||||
|
- 输入“用户名”和“密码”,点击“登录”或直接按回车键。
|
||||||
|
- 登录成功后自动导航到 Dashboard;底部状态栏将显示“当前用户:已登录”。
|
||||||
|
|
||||||
|
注意:当前版本按用户表中明文密码进行校验,请妥善保管账号信息。若忘记密码,请联系管理员重置。
|
||||||
|
|
||||||
|
## 4. 主界面与导航
|
||||||
|
|
||||||
|
应用主界面由顶部、内容区域、底部状态栏组成。常用页面:
|
||||||
|
|
||||||
|
- Dashboard(统计与实时信息)
|
||||||
|
- 历史报警(History Alarm)
|
||||||
|
- 原料相关查询(如原料使用、原料入库等,若已在系统中启用)
|
||||||
|
|
||||||
|
通过左侧菜单切换页面。页面内容区支持自动刷新与数据联动,无需手动刷新按钮。
|
||||||
|
|
||||||
|
## 5. Dashboard(统计与实时信息)
|
||||||
|
|
||||||
|
Dashboard 提供生产运行的概览信息,包括:
|
||||||
|
|
||||||
|
- 统计卡片:按“日、月、年、累计”汇总原料使用重量(RawProUse)。
|
||||||
|
- 实时运行信息:系统拦截并呈现关键运行日志与事件(如扫码、喷码、过程提示等)。
|
||||||
|
- PLC 连接状态:以指示灯颜色直观显示当前 PLC 通信状态。
|
||||||
|
- 预留区域:用于后续扩展显示(如更多曲线、指标或提示)。
|
||||||
|
|
||||||
|
刷新机制:当产生关键业务事件(例如扫码处理)时,系统自动发布事件触发 Dashboard 刷新,无需手动点击。
|
||||||
|
|
||||||
|
使用建议:
|
||||||
|
|
||||||
|
- 关注统计卡片的趋势变化,快速判断当日与周期产量情况。
|
||||||
|
- 实时信息区域用于排查当班异常,如出现错误或报警文字,可结合“历史报警”页进一步定位。
|
||||||
|
|
||||||
|
## 6. 历史报警(History Alarm)
|
||||||
|
|
||||||
|
用于查询系统运行过程中记录的历史报警。功能特性:
|
||||||
|
|
||||||
|
- 支持按关键字、类别、时间范围进行过滤查询。
|
||||||
|
- 结果列表分页显示,便于快速定位。
|
||||||
|
- 报警内容来自系统在关键点输出的报警信息,出现后会自动写入数据库。
|
||||||
|
|
||||||
|
使用步骤:
|
||||||
|
|
||||||
|
1. 打开“历史报警”页。
|
||||||
|
2. 选择查询条件(时间范围、类别、关键字等)。
|
||||||
|
3. 点击查询,查看结果列表。
|
||||||
|
|
||||||
|
排查建议:
|
||||||
|
|
||||||
|
- 若报警持续出现,先检查 PLC 连接与设备状态,再根据报警文本采取现场处理措施。
|
||||||
|
- 如怀疑数据库未记录,关注是否出现数据库连接问题或权限异常。
|
||||||
|
|
||||||
|
## 7. 底部状态栏(FootView)
|
||||||
|
|
||||||
|
底部状态栏持续显示系统运行关键信息:
|
||||||
|
|
||||||
|
- PLC 通信指示灯:绿色表示连接正常;红色表示断开或异常。
|
||||||
|
- PLC 终端信息:显示配置的 IP:Port,便于对照设备。
|
||||||
|
- 当前用户与登录状态:显示当前登录用户及是否已登录。
|
||||||
|
|
||||||
|
当 PLC 状态改变时,这里会同步更新,便于第一时间发现通信问题。
|
||||||
|
|
||||||
|
## 8. 常见操作流程
|
||||||
|
|
||||||
|
- 开机与登录:启动应用 → 进入“用户登录” → 登录成功 → 自动跳转至 Dashboard。
|
||||||
|
- 查看产线运行:在 Dashboard 观察统计卡片与实时信息,注意异常提示。
|
||||||
|
- 报警定位与复盘:在“历史报警”中按时间段和关键字查询,结合现场记录进行处理与复盘。
|
||||||
|
|
||||||
|
## 9. 常见问题与排查
|
||||||
|
|
||||||
|
- 无法登录:
|
||||||
|
- 确认用户名、密码输入正确;
|
||||||
|
- 若提示“用户不存在”,请联系管理员检查用户表;
|
||||||
|
- 若提示数据库错误,联系管理员检查数据库连接与网络。
|
||||||
|
|
||||||
|
- Dashboard 统计为空:
|
||||||
|
- 确认数据库中是否存在有效的原料使用数据;
|
||||||
|
- 等待系统产生新数据或触发刷新事件;
|
||||||
|
- 检查时间范围与系统时间是否正确。
|
||||||
|
|
||||||
|
- 实时信息无更新:
|
||||||
|
- 确认产线是否有新的扫码或业务事件;
|
||||||
|
- 若日志区长时间无输出,可能产线空闲或通信异常。
|
||||||
|
|
||||||
|
- PLC 指示红色:
|
||||||
|
- 检查 PLC 电源、网线、IP 配置;
|
||||||
|
- 确认与应用配置一致(IP、端口);
|
||||||
|
- 联系电气与系统工程师排查网络或驱动问题。
|
||||||
|
|
||||||
|
- 历史报警无记录:
|
||||||
|
- 近期是否确有报警触发;
|
||||||
|
- 检查数据库是否可写;
|
||||||
|
- 关注应用日志,必要时联系管理员。
|
||||||
|
|
||||||
|
## 10. 使用技巧
|
||||||
|
|
||||||
|
- 登录页支持“回车键”快捷登录。
|
||||||
|
- 关注底部状态栏的用户与 PLC 状态,能快速判断系统是否处于可用状态。
|
||||||
|
- 建议按班次定期查看“历史报警”,形成闭环处理与优化记录。
|
||||||
|
|
||||||
|
## 11. 安全与权限
|
||||||
|
|
||||||
|
- 账号仅限本人使用,请勿外借与分享。
|
||||||
|
- 退出离岗前可在“用户登录”页切换用户(如需要可联系管理员提供退出功能)。
|
||||||
|
- 如需更细粒度权限(基于岗位/等级),请与管理员沟通后续版本规划。
|
||||||
|
|
||||||
|
## 12. 版本与更新
|
||||||
|
|
||||||
|
- 本说明书适配当前应用版本的已上线功能。新增功能或 UI 调整将另行更新说明。
|
||||||
|
- 如需升级或安装补丁,请联系系统管理员统一安排。
|
||||||
|
|
||||||
|
## 13. 反馈与支持
|
||||||
|
|
||||||
|
- 使用中如遇到界面异常、统计不准、报警缺失等问题:
|
||||||
|
- 记录问题发生时间、操作步骤、界面提示;
|
||||||
|
- 截图或拍照(含底部状态栏与异常信息);
|
||||||
|
- 联系系统管理员或运维支持。
|
||||||
|
|
||||||
|
— 结束 —
|
||||||
@@ -10,12 +10,15 @@ using CsvHelper;
|
|||||||
using CsvHelper.Configuration;
|
using CsvHelper.Configuration;
|
||||||
using FATrace.WPLApp.ModelDto;
|
using FATrace.WPLApp.ModelDto;
|
||||||
using Prism.Mvvm;
|
using Prism.Mvvm;
|
||||||
|
using FATrace.WPLApp.CsvModel;
|
||||||
|
using FATrace.Com;
|
||||||
|
|
||||||
namespace FATrace.WPLApp.Services
|
namespace FATrace.WPLApp.Services
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CSV服务
|
/// CSV服务
|
||||||
///导出CSV文件
|
///导出CSV文件
|
||||||
|
///读取CSV 文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CsvServices:BindableBase
|
public class CsvServices:BindableBase
|
||||||
{
|
{
|
||||||
@@ -26,74 +29,121 @@ namespace FATrace.WPLApp.Services
|
|||||||
{
|
{
|
||||||
LogService = logService;
|
LogService = logService;
|
||||||
FreeSql = freeSql;
|
FreeSql = freeSql;
|
||||||
|
|
||||||
|
RawProUseCsvPath = GetConfiguredOutputDirectory();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 导出单条记录为 CSV 文件,文件名即记录的 InBagCode(自动追加 .csv 扩展名)。
|
/// 导出Csv目录
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="item">要导出的数据项,类型为 RawProUserCsvDto</param>
|
private string RawProUseCsvPath { get; set; }
|
||||||
/// <param name="outputDirectory">导出目录,不存在将自动创建</param>
|
|
||||||
/// <param name="overwrite">若目标文件已存在,是否允许覆盖</param>
|
/// <summary>
|
||||||
/// <returns>导出后的完整文件路径</returns>
|
/// 从 App.config 读取导出目录(key: RawProUseCsvPath)。
|
||||||
/// <exception cref="ArgumentNullException">item 或 outputDirectory 为 null</exception>
|
/// </summary>
|
||||||
/// <exception cref="ArgumentException">InBagCode 为空或仅空白</exception>
|
private string GetConfiguredOutputDirectory()
|
||||||
/// <exception cref="IOException">文件已存在且不允许覆盖</exception>
|
|
||||||
public string ExportSingle(RawProUserCsvDto item, string outputDirectory, bool overwrite = false)
|
|
||||||
{
|
{
|
||||||
if (item is null) throw new ArgumentNullException(nameof(item));
|
var dir = ConfigHelper.GetValue("RawProUseCsvPath");
|
||||||
if (outputDirectory is null) throw new ArgumentNullException(nameof(outputDirectory));
|
// 支持环境变量(如 %USERPROFILE%)
|
||||||
|
dir = Environment.ExpandEnvironmentVariables(dir ?? string.Empty).Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(dir))
|
||||||
|
throw new InvalidOperationException("配置项 RawProUseCsvPath 为空");
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
var inBagCode = (item.InBagCode ?? string.Empty).Trim();
|
/// <summary>
|
||||||
if (string.IsNullOrWhiteSpace(inBagCode))
|
/// 导出单条记录为 CSV 文件,文件名为记录的 InBagCode(自动追加 .csv 扩展名)。
|
||||||
throw new ArgumentException("InBagCode 不能为空", nameof(item.InBagCode));
|
/// 使用 App.config 中的 RawProUseCsvPath 作为导出目录,目录不存在会自动创建。
|
||||||
|
/// 失败时记录错误日志并返回空字符串。
|
||||||
// 目录确保存在
|
/// </summary>
|
||||||
Directory.CreateDirectory(outputDirectory);
|
/// <param name="item">要导出的数据项,类型为 RawProUserCsvDto(InBagCode 不能为空)</param>
|
||||||
|
/// <param name="overwrite">若目标文件已存在,是否允许覆盖</param>
|
||||||
var safeName = SanitizeFileName(inBagCode);
|
/// <returns>成功:返回导出后的完整文件路径;失败:返回空字符串</returns>
|
||||||
var filePath = Path.Combine(outputDirectory, safeName + ".csv");
|
public string ExportSingle(RawProUserCsvDto item, bool overwrite = false)
|
||||||
|
{
|
||||||
if (File.Exists(filePath) && !overwrite)
|
try
|
||||||
{
|
{
|
||||||
throw new IOException($"文件已存在且不允许覆盖: {filePath}");
|
if (item is null) throw new ArgumentNullException(nameof(item));
|
||||||
|
// 线程安全:使用局部缓存目录变量,必要时从配置读取一次并回写字段。
|
||||||
|
var outputDir = RawProUseCsvPath;
|
||||||
|
if (string.IsNullOrWhiteSpace(outputDir))
|
||||||
|
{
|
||||||
|
outputDir = GetConfiguredOutputDirectory();
|
||||||
|
RawProUseCsvPath = outputDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inBagCode = (item.InBagCode ?? string.Empty).Trim();
|
||||||
|
if (string.IsNullOrWhiteSpace(inBagCode))
|
||||||
|
throw new ArgumentException("InBagCode 不能为空", nameof(item.InBagCode));
|
||||||
|
|
||||||
|
// 目录确保存在
|
||||||
|
Directory.CreateDirectory(outputDir);
|
||||||
|
|
||||||
|
var safeName = SanitizeFileName(inBagCode);
|
||||||
|
var filePath = Path.Combine(outputDir, safeName + ".csv");
|
||||||
|
|
||||||
|
if (File.Exists(filePath) && !overwrite)
|
||||||
|
{
|
||||||
|
throw new IOException($"文件已存在且不允许覆盖: {filePath}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 UTF8 BOM,便于 Excel 正确识别中文
|
||||||
|
using var writer = new StreamWriter(filePath, false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
|
||||||
|
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
// 固定列顺序映射,并设置日期格式
|
||||||
|
csv.Context.RegisterClassMap<RawProUserCsvDtoMap>();
|
||||||
|
|
||||||
|
csv.WriteHeader<RawProUserCsvDto>();
|
||||||
|
csv.NextRecord();
|
||||||
|
csv.WriteRecord(item);
|
||||||
|
csv.NextRecord();
|
||||||
|
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
var code = item?.InBagCode ?? string.Empty;
|
||||||
|
var outputDir = RawProUseCsvPath;
|
||||||
|
LogService.Error($"导出CSV失败,目录={outputDir}, InBagCode={code}", ex);
|
||||||
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用 UTF8 BOM,便于 Excel 正确识别中文
|
|
||||||
using var writer = new StreamWriter(filePath, false, new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
|
|
||||||
using var csv = new CsvWriter(writer, CultureInfo.InvariantCulture);
|
|
||||||
|
|
||||||
// 固定列顺序映射,并设置日期格式
|
|
||||||
csv.Context.RegisterClassMap<RawProUserCsvDtoMap>();
|
|
||||||
|
|
||||||
csv.WriteHeader<RawProUserCsvDto>();
|
|
||||||
csv.NextRecord();
|
|
||||||
csv.WriteRecord(item);
|
|
||||||
csv.NextRecord();
|
|
||||||
|
|
||||||
return filePath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 批量导出:把每一条记录分别导出为以各自 InBagCode 命名的 CSV 文件。
|
/// 异步导出单条记录(包装线程池执行)。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="items">数据集合</param>
|
public Task<string> ExportSingleAsync(RawProUserCsvDto item, bool overwrite = false)
|
||||||
/// <param name="outputDirectory">导出目录,不存在将自动创建</param>
|
=> Task.Run(() => ExportSingle(item, overwrite));
|
||||||
/// <param name="overwrite">若目标文件已存在,是否允许覆盖</param>
|
|
||||||
/// <returns>成功导出的文件完整路径集合</returns>
|
/// <summary>
|
||||||
public IEnumerable<string> ExportMany(IEnumerable<RawProUserCsvDto> items, string outputDirectory, bool overwrite = false)
|
/// 批量导出:将集合中的每一条记录分别导出为以 InBagCode 命名的 CSV 文件。
|
||||||
|
/// 成功项返回其路径,失败项返回空字符串(并已记录日志)。
|
||||||
|
/// </summary>
|
||||||
|
public IEnumerable<string> ExportMany(IEnumerable<RawProUserCsvDto> items, bool overwrite = false)
|
||||||
{
|
{
|
||||||
if (items is null) throw new ArgumentNullException(nameof(items));
|
if (items is null) throw new ArgumentNullException(nameof(items));
|
||||||
|
|
||||||
var results = new List<string>();
|
var results = new List<string>();
|
||||||
foreach (var item in items)
|
foreach (var it in items)
|
||||||
{
|
{
|
||||||
// 逐条导出,沿用相同规则
|
results.Add(ExportSingle(it, overwrite));
|
||||||
var path = ExportSingle(item, outputDirectory, overwrite);
|
|
||||||
results.Add(path);
|
|
||||||
}
|
}
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 异步批量导出(并行度受限于线程池;如需更精细控制,可改为并行批处理)。
|
||||||
|
/// </summary>
|
||||||
|
public async Task<List<string>> ExportManyAsync(IEnumerable<RawProUserCsvDto> items, bool overwrite = false)
|
||||||
|
{
|
||||||
|
if (items is null) throw new ArgumentNullException(nameof(items));
|
||||||
|
var list = items.ToList();
|
||||||
|
var tasks = list.Select(it => Task.Run(() => ExportSingle(it, overwrite)));
|
||||||
|
var paths = await Task.WhenAll(tasks);
|
||||||
|
return paths.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清理文件名中的非法字符。
|
/// 清理文件名中的非法字符。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -108,44 +158,6 @@ namespace FATrace.WPLApp.Services
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// RawProUserCsvDto 的 CSV 列映射,固定输出顺序并设置日期格式。
|
|
||||||
/// </summary>
|
|
||||||
private sealed class RawProUserCsvDtoMap : ClassMap<RawProUserCsvDto>
|
|
||||||
{
|
|
||||||
public RawProUserCsvDtoMap()
|
|
||||||
{
|
|
||||||
//Map(x => x.RawCode).Index(0).Name(nameof(RawProUserCsvDto.RawCode));
|
|
||||||
//Map(x => x.RawName).Index(1).Name(nameof(RawProUserCsvDto.RawName));
|
|
||||||
//Map(x => x.InBagCode).Index(2).Name(nameof(RawProUserCsvDto.InBagCode));
|
|
||||||
//Map(x => x.BoxCode).Index(3).Name(nameof(RawProUserCsvDto.BoxCode));
|
|
||||||
//Map(x => x.Batch).Index(4).Name(nameof(RawProUserCsvDto.Batch));
|
|
||||||
//Map(x => x.ShelfLife).Index(5).Name(nameof(RawProUserCsvDto.ShelfLife));
|
|
||||||
//Map(x => x.Weight).Index(6).Name(nameof(RawProUserCsvDto.Weight));
|
|
||||||
//Map(x => x.DeliveryDate).Index(7).Name(nameof(RawProUserCsvDto.DeliveryDate));
|
|
||||||
//Map(x => x.RemainWeight).Index(8).Name(nameof(RawProUserCsvDto.RemainWeight));
|
|
||||||
//Map(x => x.StockWeight).Index(9).Name(nameof(RawProUserCsvDto.StockWeight));
|
|
||||||
//Map(x => x.WeightTime).Index(10).Name(nameof(RawProUserCsvDto.WeightTime)).TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
|
||||||
//Map(x => x.OpUser).Index(11).Name(nameof(RawProUserCsvDto.OpUser));
|
|
||||||
//Map(x => x.CheckUser).Index(12).Name(nameof(RawProUserCsvDto.CheckUser));
|
|
||||||
//Map(x => x.OutTime).Index(13).Name(nameof(RawProUserCsvDto.OutTime)).TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
Map(x => x.RawCode).Index(0).Name("原料编号");
|
|
||||||
Map(x => x.RawName).Index(1).Name("原料名称");
|
|
||||||
Map(x => x.InBagCode).Index(2).Name("内袋二维码");
|
|
||||||
Map(x => x.BoxCode).Index(3).Name("外箱二维码");
|
|
||||||
Map(x => x.Batch).Index(4).Name("批号");
|
|
||||||
Map(x => x.ShelfLife).Index(5).Name("保质期");
|
|
||||||
Map(x => x.Weight).Index(6).Name("称重重量(g)");
|
|
||||||
Map(x => x.DeliveryDate).Index(7).Name("配料日期");
|
|
||||||
Map(x => x.RemainWeight).Index(8).Name("剩余重量(Kg)");
|
|
||||||
Map(x => x.StockWeight).Index(9).Name("入库总重量(Kg)");
|
|
||||||
Map(x => x.WeightTime).Index(10).Name("称重时间").TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
|
||||||
Map(x => x.OpUser).Index(11).Name("操作者");
|
|
||||||
Map(x => x.CheckUser).Index(12).Name("确认者");
|
|
||||||
Map(x => x.OutTime).Index(13).Name("出库时间").TypeConverterOption.Format("yyyy-MM-dd HH:mm:ss");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
using AutoMapper;
|
||||||
using FATrace.Model;
|
using FATrace.Model;
|
||||||
|
using FATrace.WPLApp.Events;
|
||||||
|
using FATrace.WPLApp.ModelDto;
|
||||||
using FATrace.WPLApp.Models;
|
using FATrace.WPLApp.Models;
|
||||||
using HslCommunication;
|
using HslCommunication;
|
||||||
using HslCommunication.Profinet.Keyence;
|
using HslCommunication.Profinet.Keyence;
|
||||||
|
using Prism.Events;
|
||||||
using Prism.Mvvm;
|
using Prism.Mvvm;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using ComConfigHelper = FATrace.Com.ConfigHelper;
|
using ComConfigHelper = FATrace.Com.ConfigHelper;
|
||||||
using Prism.Events;
|
|
||||||
using FATrace.WPLApp.Events;
|
|
||||||
|
|
||||||
namespace FATrace.WPLApp.Services
|
namespace FATrace.WPLApp.Services
|
||||||
{
|
{
|
||||||
@@ -17,13 +19,14 @@ namespace FATrace.WPLApp.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class DataServices : BindableBase, IDisposable
|
public class DataServices : BindableBase, IDisposable
|
||||||
{
|
{
|
||||||
public DataServices(ILogService logService, IFreeSql freeSql, IEventAggregator eventAggregator, SysRunService sysRunService)
|
public DataServices(ILogService logService, IFreeSql freeSql, IEventAggregator eventAggregator, IMapper mapper, SysRunService sysRunService, CsvServices csvServices)
|
||||||
{
|
{
|
||||||
LogService = logService;
|
LogService = logService;
|
||||||
FreeSql = freeSql;
|
FreeSql = freeSql;
|
||||||
EventAggregator = eventAggregator;
|
EventAggregator = eventAggregator;
|
||||||
|
Mapper = mapper;
|
||||||
SysRunService = sysRunService;
|
SysRunService = sysRunService;
|
||||||
|
CsvServices = csvServices;
|
||||||
LineSglModel = new LineSglModel();
|
LineSglModel = new LineSglModel();
|
||||||
LineSglModel.WeightScanCodeHandle += LineSglModel_WeightScanCodeHandle;
|
LineSglModel.WeightScanCodeHandle += LineSglModel_WeightScanCodeHandle;
|
||||||
LineSglModel.BoxSprayCodeReqHandle += LineSglModel_BoxSprayCodeReqHandle;
|
LineSglModel.BoxSprayCodeReqHandle += LineSglModel_BoxSprayCodeReqHandle;
|
||||||
@@ -32,6 +35,10 @@ namespace FATrace.WPLApp.Services
|
|||||||
PLCLinkInitial();
|
PLCLinkInitial();
|
||||||
StartPlcScan();
|
StartPlcScan();
|
||||||
//var DD= RevData("DYG05030013,20250923,802,3,01,0001,");
|
//var DD= RevData("DYG05030013,20250923,802,3,01,0001,");
|
||||||
|
|
||||||
|
//var dd1= RevData("DYG05030013,251111,10193,6,01,3");
|
||||||
|
//var dd2 = RevData("DYG05030013,251111,2116,6,01,3");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -53,9 +60,13 @@ namespace FATrace.WPLApp.Services
|
|||||||
if (ReqData.Count > 0)
|
if (ReqData.Count > 0)
|
||||||
{
|
{
|
||||||
var CodeItem = ReqData.FirstOrDefault();
|
var CodeItem = ReqData.FirstOrDefault();
|
||||||
KeyencePlcMcNet.Write("D1150", RevData(CodeItem!.Code + ",A"));
|
|
||||||
|
|
||||||
Console.WriteLine($"外箱喷码:{CodeItem.Code}-发送OK");
|
var BoxSprayCodeSource = CodeItem!.Code + ",A";
|
||||||
|
var BoxSprayCodeRev = RevData(BoxSprayCodeSource);
|
||||||
|
|
||||||
|
KeyencePlcMcNet.Write("D1150", BoxSprayCodeRev);
|
||||||
|
|
||||||
|
Console.WriteLine($"外箱喷码:{BoxSprayCodeSource}-发送OK");
|
||||||
|
|
||||||
//这里需要删除数据吗?还是等扫码后删除,会不会过来新的箱子
|
//这里需要删除数据吗?还是等扫码后删除,会不会过来新的箱子
|
||||||
|
|
||||||
@@ -65,6 +76,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
//不存在请求的数据,报错
|
//不存在请求的数据,报错
|
||||||
KeyencePlcMcNet.Write("D1102", (Int16)1);
|
KeyencePlcMcNet.Write("D1102", (Int16)1);
|
||||||
Console.WriteLine($"外箱喷码:不存在请求的数据");
|
Console.WriteLine($"外箱喷码:不存在请求的数据");
|
||||||
|
AddAlarm("外箱喷码", "不存在请求的数据");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -72,10 +84,9 @@ namespace FATrace.WPLApp.Services
|
|||||||
{
|
{
|
||||||
await Task.Delay(1000).ConfigureAwait(false);
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
KeyencePlcMcNet!.Write("D1102", (Int16)0);
|
KeyencePlcMcNet!.Write("D1102", (Int16)0);
|
||||||
|
//KeyencePlcMcNet.Write("D1150", new Int16[30]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -89,17 +100,20 @@ namespace FATrace.WPLApp.Services
|
|||||||
//首先复位PLC信号
|
//首先复位PLC信号
|
||||||
KeyencePlcMcNet!.Write("D1200", (Int16)0);
|
KeyencePlcMcNet!.Write("D1200", (Int16)0);
|
||||||
|
|
||||||
|
string BoxScanCode = string.Empty;
|
||||||
|
BoxScanCode = this.BoxScanCode;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(BoxScanCode))
|
if (!string.IsNullOrEmpty(BoxScanCode))
|
||||||
{
|
{
|
||||||
//var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode == BoxScanCode);
|
var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode == BoxScanCode);
|
||||||
var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode!.Contains(BoxScanCode));// 内包和外包一样的条码测试用 ???????????????
|
//var IsExist = FreeSql.Select<RawProUse>().Where(a => a.BoxCode!.Contains(BoxScanCode));// 内包和外包一样的条码测试用 ???????????????
|
||||||
if (IsExist.Count() > 0)
|
if (IsExist.Count() > 0)
|
||||||
{
|
{
|
||||||
//存在条码数据 OK,返回PLC结果
|
//存在条码数据 OK,返回PLC结果
|
||||||
KeyencePlcMcNet!.Write("D1210", (Int16)1);
|
KeyencePlcMcNet!.Write("D1210", (Int16)1);
|
||||||
|
|
||||||
Console.WriteLine($"外箱扫描码:{BoxScanCode}-存在找到");
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}-存在找到");
|
||||||
//// 加入队列
|
// 加入队列
|
||||||
//EnqueueMessage(WeightScanCode);
|
//EnqueueMessage(WeightScanCode);
|
||||||
LogService.Info($"外箱扫描码:{BoxScanCode}");
|
LogService.Info($"外箱扫描码:{BoxScanCode}");
|
||||||
|
|
||||||
@@ -109,28 +123,40 @@ namespace FATrace.WPLApp.Services
|
|||||||
.ExecuteAffrows();
|
.ExecuteAffrows();
|
||||||
if (DeleteResult > 0)
|
if (DeleteResult > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"外箱扫描码:{WeightScanCode}-删除临时队列数据成功");
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}-删除临时队列数据成功");
|
||||||
LogService.Info($"外箱扫描码:{WeightScanCode}-删除临时队列数据成功");
|
LogService.Info($"外箱扫描码:{BoxScanCode}-删除临时队列数据成功");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"外箱扫描码:{WeightScanCode}-删除临时队列数据失败");
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}-删除临时队列数据失败");
|
||||||
LogService.Info($"外箱扫描码:{WeightScanCode}-删除临时队列数据失败");
|
LogService.Info($"外箱扫描码:{BoxScanCode}-删除临时队列数据失败");
|
||||||
|
AddAlarm("外箱扫描", $"{BoxScanCode}-删除临时队列数据失败");
|
||||||
}
|
}
|
||||||
|
|
||||||
var Result = FreeSql.Update<RawProUse>()
|
var UpdatedResult = FreeSql.Update<RawProUse>()
|
||||||
.Set(p => p.OutTime, DateTime.Now)
|
.Set(p => p.OutTime, DateTime.Now)
|
||||||
.Where(p => p.BoxCode == BoxScanCode + ",A")//外箱二维码就是外箱扫描码
|
.Where(p => p.BoxCode == BoxScanCode)//外箱二维码就是外箱扫描码
|
||||||
.ExecuteAffrows();
|
.ExecuteUpdated();
|
||||||
if (Result > 0)
|
if (UpdatedResult.Count() > 0)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"外箱扫描码:{WeightScanCode}更新时间成功");
|
var Data = CsvServices.ExportSingle(Mapper.Map<RawProUserCsvDto>(UpdatedResult.First()), true);
|
||||||
LogService.Info($"外箱扫描码:{WeightScanCode}更新时间成功");
|
if (Data != null && !string.IsNullOrEmpty(Data))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"外箱扫描码:{BoxScanCode} CSV文件生成");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine($"外箱扫描码:{BoxScanCode} CSV文件失败!");
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}更新时间成功");
|
||||||
|
LogService.Info($"外箱扫描码:{BoxScanCode}更新时间成功");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"外箱扫描码:{WeightScanCode}更新时间失败");
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}更新时间失败");
|
||||||
LogService.Warn($"外箱扫描码:{WeightScanCode}更新时间失败");
|
LogService.Warn($"外箱扫描码:{BoxScanCode}更新时间失败");
|
||||||
|
AddAlarm("外箱扫描", $"{BoxScanCode}更新时间失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -138,14 +164,16 @@ namespace FATrace.WPLApp.Services
|
|||||||
//不存在条码数据 NG,返回PLC结果报警
|
//不存在条码数据 NG,返回PLC结果报警
|
||||||
KeyencePlcMcNet!.Write("D1210", (Int16)2);
|
KeyencePlcMcNet!.Write("D1210", (Int16)2);
|
||||||
|
|
||||||
Console.WriteLine($"外箱扫描码:{WeightScanCode}-未发现外箱扫码数据在数据库中");
|
Console.WriteLine($"外箱扫描码:{BoxScanCode}-未发现外箱扫码数据在数据库中");
|
||||||
LogService.Warn($"外箱扫描码:{WeightScanCode}-未发现外箱扫码数据在数据库中");
|
LogService.Warn($"外箱扫描码:{BoxScanCode}-未发现外箱扫码数据在数据库中");
|
||||||
|
AddAlarm("外箱扫描", $"{BoxScanCode}-未发现外箱扫码数据在数据库中");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"外箱扫描码为空");
|
Console.WriteLine($"外箱扫描码为空");
|
||||||
LogService.Warn("外箱扫描码为空");
|
LogService.Warn("外箱扫描码为空");
|
||||||
|
AddAlarm("外箱扫描", "外箱扫描码为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
@@ -155,7 +183,10 @@ namespace FATrace.WPLApp.Services
|
|||||||
|
|
||||||
KeyencePlcMcNet.Write("D1250", new Int16[30]);
|
KeyencePlcMcNet.Write("D1250", new Int16[30]);
|
||||||
});
|
});
|
||||||
try { EventAggregator?.GetEvent<DashboardRefreshEvent>()?.Publish(true); } catch { }
|
|
||||||
|
//try { EventAggregator?.GetEvent<DashboardRefreshEvent>()?.Publish(true); } catch { }
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -200,6 +231,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"称重扫描码:{WeightScanCode}更新时间失败");
|
Console.WriteLine($"称重扫描码:{WeightScanCode}更新时间失败");
|
||||||
LogService.Warn($"称重扫描码:{WeightScanCode}更新时间失败");
|
LogService.Warn($"称重扫描码:{WeightScanCode}更新时间失败");
|
||||||
|
AddAlarm("称重扫描", $"{WeightScanCode}更新时间失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -209,6 +241,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
|
|
||||||
Console.WriteLine($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
|
Console.WriteLine($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
|
||||||
LogService.Warn($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
|
LogService.Warn($"称重扫描码:{WeightScanCode}-未发现内包扫码数据在数据库中");
|
||||||
|
AddAlarm("称重扫描", $"{WeightScanCode}-未发现内包扫码数据在数据库中");
|
||||||
}
|
}
|
||||||
|
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
@@ -225,6 +258,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"称重扫描码为空");
|
Console.WriteLine($"称重扫描码为空");
|
||||||
LogService.Warn("称重扫描码为空");
|
LogService.Warn("称重扫描码为空");
|
||||||
|
AddAlarm("称重扫描", "称重扫描码为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -232,7 +266,9 @@ namespace FATrace.WPLApp.Services
|
|||||||
public ILogService LogService { get; }
|
public ILogService LogService { get; }
|
||||||
public IFreeSql FreeSql { get; }
|
public IFreeSql FreeSql { get; }
|
||||||
public IEventAggregator EventAggregator { get; }
|
public IEventAggregator EventAggregator { get; }
|
||||||
|
public IMapper Mapper { get; }
|
||||||
public SysRunService SysRunService { get; }
|
public SysRunService SysRunService { get; }
|
||||||
|
public CsvServices CsvServices { get; }
|
||||||
|
|
||||||
private bool _plcConnected;
|
private bool _plcConnected;
|
||||||
public bool PlcConnected
|
public bool PlcConnected
|
||||||
@@ -281,27 +317,6 @@ namespace FATrace.WPLApp.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private readonly ConcurrentQueue<string> _messageQueue = new();
|
private readonly ConcurrentQueue<string> _messageQueue = new();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 入队:将字符串加入 FIFO 队列(先进先出)。允许空字符串,不允许 null。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">要加入队列的字符串</param>
|
|
||||||
/// <exception cref="ArgumentNullException">当 message 为 null 时抛出</exception>
|
|
||||||
public void EnqueueMessage(string message)
|
|
||||||
{
|
|
||||||
if (message is null) throw new ArgumentNullException(nameof(message));
|
|
||||||
_messageQueue.Enqueue(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 出队:尝试从 FIFO 队列取出一个字符串。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">输出参数:若成功则为取出的字符串;若失败(队列为空)则为 default</param>
|
|
||||||
/// <returns>是否成功取出</returns>
|
|
||||||
public bool TryDequeueMessage(out string message)
|
|
||||||
{
|
|
||||||
return _messageQueue.TryDequeue(out message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 产线信号模型
|
/// 产线信号模型
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -327,7 +342,6 @@ namespace FATrace.WPLApp.Services
|
|||||||
KeyencePlcMcNet.Port = Port;
|
KeyencePlcMcNet.Port = Port;
|
||||||
KeyencePlcMcNet.ConnectClose();
|
KeyencePlcMcNet.ConnectClose();
|
||||||
|
|
||||||
|
|
||||||
KeyencePlcMcNet.ConnectTimeOut = 3000; // 连接3秒超时
|
KeyencePlcMcNet.ConnectTimeOut = 3000; // 连接3秒超时
|
||||||
OperateResult connect = KeyencePlcMcNet.ConnectServer();
|
OperateResult connect = KeyencePlcMcNet.ConnectServer();
|
||||||
if (connect.IsSuccess)//初始连接状态的显示判断
|
if (connect.IsSuccess)//初始连接状态的显示判断
|
||||||
@@ -443,7 +457,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
OperateResultWeightScanCode = KeyencePlcMcNet!.ReadString("D1050", 20);
|
OperateResultWeightScanCode = KeyencePlcMcNet!.ReadString("D1050", 20);
|
||||||
if (OperateResultWeightScanCode.IsSuccess)
|
if (OperateResultWeightScanCode.IsSuccess)
|
||||||
{
|
{
|
||||||
WeightScanCode = RevData(OperateResultWeightScanCode.Content).Replace("\r", "").Replace("\n", "");
|
WeightScanCode = RevData(OperateResultWeightScanCode.Content).Replace("\r", "").Replace("\n", "").Trim();
|
||||||
}
|
}
|
||||||
OperateResultWeightScanSgl = KeyencePlcMcNet!.ReadInt16("D1000");
|
OperateResultWeightScanSgl = KeyencePlcMcNet!.ReadInt16("D1000");
|
||||||
if (OperateResultWeightScanSgl.IsSuccess)
|
if (OperateResultWeightScanSgl.IsSuccess)
|
||||||
@@ -462,7 +476,8 @@ namespace FATrace.WPLApp.Services
|
|||||||
OperateResultBoxScanCode = KeyencePlcMcNet!.ReadString("D1250", 20);
|
OperateResultBoxScanCode = KeyencePlcMcNet!.ReadString("D1250", 20);
|
||||||
if (OperateResultBoxScanCode.IsSuccess)
|
if (OperateResultBoxScanCode.IsSuccess)
|
||||||
{
|
{
|
||||||
BoxScanCode = RevData(OperateResultBoxScanCode.Content).Replace("\r", "").Replace("\n", "");
|
BoxScanCode = RevData(OperateResultBoxScanCode.Content).Replace("\r", "").Replace("\n", "").Trim();
|
||||||
|
//BoxScanCode = OperateResultBoxScanCode.Content.Replace("\r", "").Replace("\n", "");
|
||||||
}
|
}
|
||||||
OperateResultBoxScanSgl = KeyencePlcMcNet!.ReadInt16("D1200");
|
OperateResultBoxScanSgl = KeyencePlcMcNet!.ReadInt16("D1200");
|
||||||
if (OperateResultBoxScanSgl.IsSuccess)
|
if (OperateResultBoxScanSgl.IsSuccess)
|
||||||
@@ -558,7 +573,7 @@ namespace FATrace.WPLApp.Services
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 把字符串对调
|
/// 把字符串对调
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string RevData(string Code)
|
public string RevData(string Code)
|
||||||
{
|
{
|
||||||
// 需求:PLC 字符串按“字”(2字节)进行高低字节对调,导致 ABCDEF -> BADCFE
|
// 需求:PLC 字符串按“字”(2字节)进行高低字节对调,导致 ABCDEF -> BADCFE
|
||||||
// 纠正方式:按两个字符一组交换顺序,奇数长度保留最后一个字符
|
// 纠正方式:按两个字符一组交换顺序,奇数长度保留最后一个字符
|
||||||
@@ -578,6 +593,8 @@ namespace FATrace.WPLApp.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 奇数长度,最后一个字符原样保留
|
// 奇数长度,最后一个字符原样保留
|
||||||
|
//sb.Append((char)0x0);
|
||||||
|
sb.Append('\0');
|
||||||
sb.Append(src[i]);
|
sb.Append(src[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -585,5 +602,25 @@ namespace FATrace.WPLApp.Services
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 写入历史报警
|
||||||
|
/// </summary>
|
||||||
|
private void AddAlarm(string category, string message)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FreeSql.Insert(new HistoryAlarm
|
||||||
|
{
|
||||||
|
Category = category,
|
||||||
|
Message = message,
|
||||||
|
CreateTime = DateTime.Now
|
||||||
|
}).ExecuteAffrows();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
LogService.Error($"写入历史报警失败: {ex.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,5 @@
|
|||||||
using FATrace.WPLApp.ModelDto;
|
using FATrace.WPLApp.ModelDto;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FATrace.WPLApp.Services
|
namespace FATrace.WPLApp.Services
|
||||||
{
|
{
|
||||||
|
|||||||
73
FATrace.WPLApp/Utils/PasswordBoxAssistant.cs
Normal file
73
FATrace.WPLApp/Utils/PasswordBoxAssistant.cs
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.Utils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 允许将 PasswordBox 的 Password 与 ViewModel 绑定
|
||||||
|
/// 用法:
|
||||||
|
/// <PasswordBox utils:PasswordBoxAssistant.BindPassword="True"
|
||||||
|
/// utils:PasswordBoxAssistant.BoundPassword="{Binding Password, Mode=TwoWay}" />
|
||||||
|
/// </summary>
|
||||||
|
public static class PasswordBoxAssistant
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty BoundPasswordProperty =
|
||||||
|
DependencyProperty.RegisterAttached("BoundPassword", typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty BindPasswordProperty =
|
||||||
|
DependencyProperty.RegisterAttached("BindPassword", typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnBindPasswordChanged));
|
||||||
|
|
||||||
|
private static readonly DependencyProperty IsUpdatingProperty =
|
||||||
|
DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxAssistant));
|
||||||
|
|
||||||
|
public static string GetBoundPassword(DependencyObject dp) => (string)dp.GetValue(BoundPasswordProperty);
|
||||||
|
public static void SetBoundPassword(DependencyObject dp, string value) => dp.SetValue(BoundPasswordProperty, value);
|
||||||
|
|
||||||
|
public static bool GetBindPassword(DependencyObject dp) => (bool)dp.GetValue(BindPasswordProperty);
|
||||||
|
public static void SetBindPassword(DependencyObject dp, bool value) => dp.SetValue(BindPasswordProperty, value);
|
||||||
|
|
||||||
|
private static bool GetIsUpdating(DependencyObject dp) => (bool)dp.GetValue(IsUpdatingProperty);
|
||||||
|
private static void SetIsUpdating(DependencyObject dp, bool value) => dp.SetValue(IsUpdatingProperty, value);
|
||||||
|
|
||||||
|
private static void OnBoundPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (dp is PasswordBox passwordBox)
|
||||||
|
{
|
||||||
|
passwordBox.PasswordChanged -= HandlePasswordChanged;
|
||||||
|
if (!(bool)GetIsUpdating(passwordBox))
|
||||||
|
{
|
||||||
|
passwordBox.Password = e.NewValue?.ToString() ?? string.Empty;
|
||||||
|
}
|
||||||
|
passwordBox.PasswordChanged += HandlePasswordChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void OnBindPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (dp is PasswordBox passwordBox)
|
||||||
|
{
|
||||||
|
bool wasBound = (bool)(e.OldValue ?? false);
|
||||||
|
bool needBind = (bool)(e.NewValue ?? false);
|
||||||
|
|
||||||
|
if (wasBound)
|
||||||
|
{
|
||||||
|
passwordBox.PasswordChanged -= HandlePasswordChanged;
|
||||||
|
}
|
||||||
|
if (needBind)
|
||||||
|
{
|
||||||
|
passwordBox.PasswordChanged += HandlePasswordChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (sender is PasswordBox passwordBox)
|
||||||
|
{
|
||||||
|
SetIsUpdating(passwordBox, true);
|
||||||
|
SetBoundPassword(passwordBox, passwordBox.Password);
|
||||||
|
SetIsUpdating(passwordBox, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -119,30 +119,6 @@ namespace FATrace.WPLApp.ViewModels
|
|||||||
public DelegateCommand ClearLogsCommand { get; }
|
public DelegateCommand ClearLogsCommand { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void StartLogTimer()
|
|
||||||
{
|
|
||||||
if (_logTimer != null) return;
|
|
||||||
_logTimer = new DispatcherTimer
|
|
||||||
{
|
|
||||||
Interval = TimeSpan.FromMilliseconds(500)
|
|
||||||
};
|
|
||||||
_logTimer.Tick += (s, e) =>
|
|
||||||
{
|
|
||||||
// 从 DataServices 的队列中取出消息并展示
|
|
||||||
int drain = 0;
|
|
||||||
while (_data.TryDequeueMessage(out var msg))
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
AppendLiveMessage(msg);
|
|
||||||
drain++;
|
|
||||||
if (drain >= 50) break; // 防止一次处理过多
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
_logTimer.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AppendLiveMessage(string message)
|
private void AppendLiveMessage(string message)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(message)) return;
|
if (string.IsNullOrWhiteSpace(message)) return;
|
||||||
|
|||||||
32
FATrace.WPLApp/ViewModels/DialogHelpManualViewModel.cs
Normal file
32
FATrace.WPLApp/ViewModels/DialogHelpManualViewModel.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using FATrace.WPLApp.Core;
|
||||||
|
using Prism.Services.Dialogs;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.ViewModels
|
||||||
|
{
|
||||||
|
public class DialogHelpManualViewModel : DialogViewModel
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 窗口打开时的传递的参数
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="parameters"></param>
|
||||||
|
public override void OnDialogOpened(IDialogParameters parameters)
|
||||||
|
{
|
||||||
|
//CurMeterName = parameters.GetValue<string>("Name");
|
||||||
|
////RefreshChartSelectedData();
|
||||||
|
|
||||||
|
//var Data = FreeSql.Select<ConfigLimit>().Where(a => a.MeterName == CurMeterName).ToList();
|
||||||
|
|
||||||
|
//ConfigLimitDtoItems = new ObservableCollection<ConfigLimitDto>(Mapper.Map<List<ConfigLimitDto>>(Data));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
229
FATrace.WPLApp/ViewModels/HistoryAlarmViewModel.cs
Normal file
229
FATrace.WPLApp/ViewModels/HistoryAlarmViewModel.cs
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
using FATrace.WPLApp.Core;
|
||||||
|
using Prism.Commands;
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using FreeSql;
|
||||||
|
using FATrace.Model;
|
||||||
|
using FATrace.WPLApp.Services;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.ViewModels
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 历史报警查询 VM
|
||||||
|
/// 支持按时间范围/类别/消息模糊查询,分页展示。
|
||||||
|
/// </summary>
|
||||||
|
public class HistoryAlarmViewModel : NavigationViewModel
|
||||||
|
{
|
||||||
|
private readonly IFreeSql _fsql;
|
||||||
|
private readonly ILogService _log;
|
||||||
|
|
||||||
|
public HistoryAlarmViewModel(IFreeSql fsql, ILogService log)
|
||||||
|
{
|
||||||
|
_fsql = fsql;
|
||||||
|
_log = log;
|
||||||
|
|
||||||
|
Items = new ObservableCollection<HistoryAlarm>();
|
||||||
|
CategoryList = new ObservableCollection<string>();
|
||||||
|
|
||||||
|
// 默认时间范围为今日
|
||||||
|
StartTime = DateTime.Today;
|
||||||
|
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||||
|
|
||||||
|
SearchCommand = new DelegateCommand(async () => await SearchAsync(), () => !IsBusy)
|
||||||
|
.ObservesProperty(() => IsBusy);
|
||||||
|
ClearCommand = new DelegateCommand(ClearFilters, () => !IsBusy)
|
||||||
|
.ObservesProperty(() => IsBusy);
|
||||||
|
|
||||||
|
FirstPageCommand = new DelegateCommand(async () => { if (PageIndex == 1) return; PageIndex = 1; await SearchAsync(); }, () => !IsBusy && PageIndex > 1)
|
||||||
|
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex);
|
||||||
|
PrevPageCommand = new DelegateCommand(async () => { if (PageIndex <= 1) return; PageIndex -= 1; await SearchAsync(); }, () => !IsBusy && PageIndex > 1)
|
||||||
|
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex);
|
||||||
|
NextPageCommand = new DelegateCommand(async () => { if (PageIndex >= TotalPages) return; PageIndex += 1; await SearchAsync(); }, () => !IsBusy && PageIndex < TotalPages)
|
||||||
|
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalPages);
|
||||||
|
LastPageCommand = new DelegateCommand(async () => { if (TotalPages <= 0 || PageIndex == TotalPages) return; PageIndex = TotalPages; await SearchAsync(); }, () => !IsBusy && PageIndex < TotalPages)
|
||||||
|
.ObservesProperty(() => IsBusy).ObservesProperty(() => PageIndex).ObservesProperty(() => TotalPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region 查询条件
|
||||||
|
public string? Category { get => _category; set { _category = value; RaisePropertyChanged(); } }
|
||||||
|
private string? _category;
|
||||||
|
|
||||||
|
public ObservableCollection<string> CategoryList { get; }
|
||||||
|
|
||||||
|
public string? Keyword { get => _keyword; set { _keyword = value; RaisePropertyChanged(); } }
|
||||||
|
private string? _keyword;
|
||||||
|
|
||||||
|
public DateTime? StartTime { get => _startTime; set { _startTime = value; RaisePropertyChanged(); } }
|
||||||
|
private DateTime? _startTime;
|
||||||
|
|
||||||
|
public DateTime? EndTime { get => _endTime; set { _endTime = value; RaisePropertyChanged(); } }
|
||||||
|
private DateTime? _endTime;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 列表/状态/分页
|
||||||
|
public ObservableCollection<HistoryAlarm> Items { get; }
|
||||||
|
|
||||||
|
private bool _isBusy;
|
||||||
|
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private int _totalCount;
|
||||||
|
public int TotalCount { get => _totalCount; set { _totalCount = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private int _pageIndex = 1;
|
||||||
|
public int PageIndex { get => _pageIndex; set { _pageIndex = value < 1 ? 1 : value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private int _pageSize = 20;
|
||||||
|
public int PageSize
|
||||||
|
{
|
||||||
|
get => _pageSize;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var newSize = value <= 0 ? 20 : value;
|
||||||
|
if (_pageSize != newSize)
|
||||||
|
{
|
||||||
|
_pageSize = newSize;
|
||||||
|
RaisePropertyChanged();
|
||||||
|
PageIndex = 1;
|
||||||
|
if (!IsBusy) _ = SearchAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _totalPages;
|
||||||
|
public int TotalPages { get => _totalPages; set { _totalPages = value; RaisePropertyChanged(); } }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region 命令
|
||||||
|
public DelegateCommand SearchCommand { get; }
|
||||||
|
public DelegateCommand ClearCommand { get; }
|
||||||
|
public DelegateCommand FirstPageCommand { get; }
|
||||||
|
public DelegateCommand PrevPageCommand { get; }
|
||||||
|
public DelegateCommand NextPageCommand { get; }
|
||||||
|
public DelegateCommand LastPageCommand { get; }
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void ClearFilters()
|
||||||
|
{
|
||||||
|
Category = "全部";
|
||||||
|
Keyword = string.Empty;
|
||||||
|
StartTime = DateTime.Today;
|
||||||
|
EndTime = DateTime.Today.AddDays(1).AddSeconds(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task SearchAsync()
|
||||||
|
{
|
||||||
|
if (IsBusy) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (StartTime.HasValue && EndTime.HasValue && StartTime > EndTime)
|
||||||
|
{
|
||||||
|
MessageBox.Show("开始时间不能大于结束时间", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsBusy = true;
|
||||||
|
_log.Info("HistoryAlarm 查询开始");
|
||||||
|
|
||||||
|
var data = await Task.Run(() =>
|
||||||
|
{
|
||||||
|
var q = _fsql.Select<HistoryAlarm>();
|
||||||
|
|
||||||
|
DateTime? start = StartTime;
|
||||||
|
DateTime? end = EndTime;
|
||||||
|
if (start.HasValue) q = q.Where(a => a.CreateTime >= start.Value);
|
||||||
|
if (end.HasValue)
|
||||||
|
{
|
||||||
|
var endInclusive = end.Value;
|
||||||
|
if (endInclusive.TimeOfDay == TimeSpan.Zero) endInclusive = endInclusive.Date.AddDays(1).AddTicks(-1);
|
||||||
|
q = q.Where(a => a.CreateTime <= endInclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Category) && Category != "全部") q = q.Where(a => a.Category == Category);
|
||||||
|
if (!string.IsNullOrWhiteSpace(Keyword)) q = q.Where(a => a.Message!.Contains(Keyword));
|
||||||
|
|
||||||
|
q = q.OrderByDescending(a => a.CreateTime);
|
||||||
|
|
||||||
|
var size = PageSize <= 0 ? 20 : PageSize;
|
||||||
|
var page = PageIndex < 1 ? 1 : PageIndex;
|
||||||
|
var list = q.Count(out var total)
|
||||||
|
.Page(page, size)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var pages = total <= 0 || size <= 0 ? 0 : (int)Math.Ceiling(total * 1.0 / size);
|
||||||
|
if (pages > 0 && page > pages)
|
||||||
|
{
|
||||||
|
page = pages;
|
||||||
|
list = q.Page(page, size).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (items: list, total: (int)total, normalizedPage: page, totalPages: pages);
|
||||||
|
});
|
||||||
|
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
Items.Clear();
|
||||||
|
foreach (var it in data.items) Items.Add(it);
|
||||||
|
TotalCount = data.total;
|
||||||
|
TotalPages = data.totalPages;
|
||||||
|
PageIndex = data.normalizedPage == 0 ? 1 : data.normalizedPage;
|
||||||
|
});
|
||||||
|
|
||||||
|
_log.Info($"HistoryAlarm 查询完成,记录数: {TotalCount}");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error($"HistoryAlarm 查询失败: {ex}");
|
||||||
|
MessageBox.Show($"查询失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async void OnNavigatedTo(Prism.Regions.NavigationContext navigationContext)
|
||||||
|
{
|
||||||
|
await LoadCategoriesAsync();
|
||||||
|
await SearchAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadCategoriesAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var list = await Task.Run(() =>
|
||||||
|
{
|
||||||
|
// 直接在数据库端去重,避免将大量重复数据拉回内存
|
||||||
|
var cateList = _fsql.Select<HistoryAlarm>()
|
||||||
|
.Where(a => a.Category != null && a.Category != "")
|
||||||
|
.Distinct()
|
||||||
|
.ToList(a => a.Category);
|
||||||
|
return (cateList ?? new System.Collections.Generic.List<string>())
|
||||||
|
.Where(s => !string.IsNullOrWhiteSpace(s))
|
||||||
|
.OrderBy(s => s)
|
||||||
|
.ToList();
|
||||||
|
});
|
||||||
|
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
CategoryList.Clear();
|
||||||
|
CategoryList.Add("全部");
|
||||||
|
foreach (var s in list) CategoryList.Add(s);
|
||||||
|
if (string.IsNullOrWhiteSpace(Category)) Category = "全部";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn($"加载报警类别失败: {ex.Message}");
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (CategoryList.Count == 0) CategoryList.Add("全部");
|
||||||
|
if (string.IsNullOrWhiteSpace(Category)) Category = "全部";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
FATrace.WPLApp/ViewModels/LogViewModel.cs
Normal file
178
FATrace.WPLApp/ViewModels/LogViewModel.cs
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
using FATrace.WPLApp.Core;
|
||||||
|
using Prism.Commands;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.ViewModels
|
||||||
|
{
|
||||||
|
public class LogViewModel : NavigationViewModel
|
||||||
|
{
|
||||||
|
private readonly DispatcherTimer _timer;
|
||||||
|
|
||||||
|
public LogViewModel()
|
||||||
|
{
|
||||||
|
Levels = new ObservableCollection<string>(new[] { "ALL", "DEBUG", "INFO", "WARN", "ERROR", "FATAL" });
|
||||||
|
_selectedDate = DateTime.Today;
|
||||||
|
_levelFilter = Levels.First();
|
||||||
|
_maxLines = 2000;
|
||||||
|
|
||||||
|
RefreshCommand = new DelegateCommand(async () => await LoadAsync(), () => !IsBusy).ObservesProperty(() => IsBusy);
|
||||||
|
OpenFolderCommand = new DelegateCommand(OpenFolder);
|
||||||
|
|
||||||
|
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(2) };
|
||||||
|
_timer.Tick += async (_, __) =>
|
||||||
|
{
|
||||||
|
if (AutoRefresh && !IsBusy)
|
||||||
|
await LoadAsync();
|
||||||
|
};
|
||||||
|
_timer.Start();
|
||||||
|
|
||||||
|
// 初始加载当日日志
|
||||||
|
_ = LoadAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<string> Levels { get; }
|
||||||
|
|
||||||
|
private ObservableCollection<LogEntry> _items = new();
|
||||||
|
public ObservableCollection<LogEntry> Items { get => _items; set { _items = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private DateTime? _selectedDate;
|
||||||
|
public DateTime? SelectedDate { get => _selectedDate; set { _selectedDate = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
||||||
|
|
||||||
|
private string _levelFilter;
|
||||||
|
public string LevelFilter { get => _levelFilter; set { _levelFilter = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
||||||
|
|
||||||
|
private string _keyword;
|
||||||
|
public string Keyword { get => _keyword; set { _keyword = value; RaisePropertyChanged(); _ = LoadAsync(); } }
|
||||||
|
|
||||||
|
private bool _autoRefresh;
|
||||||
|
public bool AutoRefresh { get => _autoRefresh; set { _autoRefresh = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private int _maxLines;
|
||||||
|
public int MaxLines { get => _maxLines; set { _maxLines = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private bool _isBusy;
|
||||||
|
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
public DelegateCommand RefreshCommand { get; }
|
||||||
|
public DelegateCommand OpenFolderCommand { get; }
|
||||||
|
|
||||||
|
private string GetLogDirectory()
|
||||||
|
{
|
||||||
|
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GetLogFilePath(DateTime? date)
|
||||||
|
{
|
||||||
|
var dir = GetLogDirectory();
|
||||||
|
var dt = date ?? DateTime.Today;
|
||||||
|
var file = dt.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log";
|
||||||
|
return Path.Combine(dir, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool PassLevel(string levelFilter, string level)
|
||||||
|
{
|
||||||
|
if (string.Equals(levelFilter, "ALL", StringComparison.OrdinalIgnoreCase)) return true;
|
||||||
|
return string.Equals(level, levelFilter, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadAsync()
|
||||||
|
{
|
||||||
|
if (IsBusy) return;
|
||||||
|
IsBusy = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var path = GetLogFilePath(SelectedDate);
|
||||||
|
var list = await Task.Run(() => ReadLogFile(path, MaxLines));
|
||||||
|
|
||||||
|
var filtered = list.Where(x => PassLevel(LevelFilter, x.Level)
|
||||||
|
&& (string.IsNullOrWhiteSpace(Keyword) || (x.Message?.IndexOf(Keyword, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||||
|
|| (x.Logger?.IndexOf(Keyword, StringComparison.OrdinalIgnoreCase) >= 0)));
|
||||||
|
|
||||||
|
Items = new ObservableCollection<LogEntry>(filtered);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
Items = new ObservableCollection<LogEntry>();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<LogEntry> ReadLogFile(string path, int maxLines)
|
||||||
|
{
|
||||||
|
var result = new LinkedList<LogEntry>();
|
||||||
|
if (!File.Exists(path)) return result.ToList();
|
||||||
|
|
||||||
|
using var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||||
|
using var sr = new StreamReader(fs, Encoding.UTF8);
|
||||||
|
|
||||||
|
string? line;
|
||||||
|
while ((line = sr.ReadLine()) != null)
|
||||||
|
{
|
||||||
|
var entry = ParseLine(line);
|
||||||
|
result.AddLast(entry);
|
||||||
|
if (result.Count > maxLines) result.RemoveFirst();
|
||||||
|
}
|
||||||
|
return result.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LogEntry ParseLine(string line)
|
||||||
|
{
|
||||||
|
// layout: longdate|LEVEL|logger|threadid|message[|exception]
|
||||||
|
var parts = line.Split('|');
|
||||||
|
var entry = new LogEntry();
|
||||||
|
if (parts.Length >= 4)
|
||||||
|
{
|
||||||
|
entry.Time = parts[0];
|
||||||
|
entry.Level = parts[1];
|
||||||
|
entry.Logger = parts[2];
|
||||||
|
entry.ThreadId = parts[3];
|
||||||
|
if (parts.Length >= 5)
|
||||||
|
{
|
||||||
|
entry.Message = string.Join("|", parts.Skip(4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry.Message = line;
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenFolder()
|
||||||
|
{
|
||||||
|
var dir = GetLogDirectory();
|
||||||
|
Directory.CreateDirectory(dir);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Process.Start(new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = dir,
|
||||||
|
UseShellExecute = true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LogEntry
|
||||||
|
{
|
||||||
|
public string Time { get; set; }
|
||||||
|
public string Level { get; set; }
|
||||||
|
public string Logger { get; set; }
|
||||||
|
public string ThreadId { get; set; }
|
||||||
|
public string Message { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
96
FATrace.WPLApp/ViewModels/LoginViewModel.cs
Normal file
96
FATrace.WPLApp/ViewModels/LoginViewModel.cs
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
using FATrace.Model;
|
||||||
|
using FATrace.WPLApp.Core;
|
||||||
|
using FATrace.WPLApp.Services;
|
||||||
|
using FreeSql;
|
||||||
|
using Prism.Commands;
|
||||||
|
using Prism.Regions;
|
||||||
|
using System;
|
||||||
|
using System.Security;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.ViewModels
|
||||||
|
{
|
||||||
|
public class LoginViewModel : NavigationViewModel
|
||||||
|
{
|
||||||
|
private readonly IFreeSql _fsql;
|
||||||
|
private readonly ILogService _log;
|
||||||
|
private readonly SysRunService _sys;
|
||||||
|
private readonly IRegionManager _regionManager;
|
||||||
|
|
||||||
|
public LoginViewModel(IFreeSql fsql, ILogService log, SysRunService sysRunService, IRegionManager regionManager)
|
||||||
|
{
|
||||||
|
_fsql = fsql;
|
||||||
|
_log = log;
|
||||||
|
_sys = sysRunService;
|
||||||
|
_regionManager = regionManager;
|
||||||
|
|
||||||
|
LoginCommand = new DelegateCommand(async () => await DoLoginAsync(), () => !IsBusy)
|
||||||
|
.ObservesProperty(() => IsBusy);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string _userName;
|
||||||
|
public string UserName { get => _userName; set { _userName = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private string _password;
|
||||||
|
public string Password { get => _password; set { _password = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
private bool _isBusy;
|
||||||
|
public bool IsBusy { get => _isBusy; set { _isBusy = value; RaisePropertyChanged(); } }
|
||||||
|
|
||||||
|
public DelegateCommand LoginCommand { get; }
|
||||||
|
|
||||||
|
private async Task DoLoginAsync()
|
||||||
|
{
|
||||||
|
if (IsBusy) return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(UserName) || string.IsNullOrWhiteSpace(Password))
|
||||||
|
{
|
||||||
|
MessageBox.Show("请输入用户名和密码", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsBusy = true;
|
||||||
|
var user = await Task.Run(() =>
|
||||||
|
{
|
||||||
|
return _fsql.Select<TbUser>()
|
||||||
|
.Where(a => a.UserName == UserName)
|
||||||
|
.First();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (user == null)
|
||||||
|
{
|
||||||
|
MessageBox.Show("用户不存在", "登录失败", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 明文密码对比(与现有模型字段一致)。如后续改为哈希,可在此替换校验逻辑。
|
||||||
|
if (!string.Equals(user.Password, Password))
|
||||||
|
{
|
||||||
|
MessageBox.Show("密码错误", "登录失败", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sys.CurUser = user.UserName;
|
||||||
|
_log.Info($"用户登录成功: {user.UserName}");
|
||||||
|
UserName="";
|
||||||
|
Password="";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_regionManager.Regions["ContentRegion"].RequestNavigate("DashBoardView");
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error($"登录异常: {ex}");
|
||||||
|
MessageBox.Show($"登录异常: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,12 +90,12 @@ namespace FATrace.WPLApp.ViewModels
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "报表数据":
|
//case "报表数据":
|
||||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("ReportView");
|
// this.regionManager.Regions["ContentRegion"].RequestNavigate("ReportView");
|
||||||
|
|
||||||
|
|
||||||
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
||||||
break;
|
//break;
|
||||||
case "原料使用查询":
|
case "原料使用查询":
|
||||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("RawProUseView");
|
this.regionManager.Regions["ContentRegion"].RequestNavigate("RawProUseView");
|
||||||
break;
|
break;
|
||||||
@@ -105,15 +105,17 @@ namespace FATrace.WPLApp.ViewModels
|
|||||||
case "历史报警":
|
case "历史报警":
|
||||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("HistoryAlarmView");
|
this.regionManager.Regions["ContentRegion"].RequestNavigate("HistoryAlarmView");
|
||||||
|
|
||||||
|
|
||||||
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
//this.regionManager.Regions["ContentRegion"].Activate(viewB);
|
||||||
break;
|
break;
|
||||||
|
case "日志信息":
|
||||||
|
this.regionManager.Regions["ContentRegion"].RequestNavigate("LogView");
|
||||||
|
break;
|
||||||
case "用户登录":
|
case "用户登录":
|
||||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("UserView");
|
this.regionManager.Regions["ContentRegion"].RequestNavigate("LoginView");
|
||||||
//this.regionManager.Regions["ContentRegion"].Activate(Shift);
|
//this.regionManager.Regions["ContentRegion"].Activate(Shift);
|
||||||
break;
|
break;
|
||||||
case "使用手册":
|
case "使用手册":
|
||||||
this.regionManager.Regions["ContentRegion"].RequestNavigate("HelpManualView");
|
//this.regionManager.Regions["ContentRegion"].RequestNavigate("HelpManualView");
|
||||||
//弹窗
|
//弹窗
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -365,56 +365,56 @@ namespace FATrace.WPLApp.ViewModels
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private void ExportToCsv()
|
private void ExportToCsv()
|
||||||
{
|
{
|
||||||
if (IsBusy) return;
|
//if (IsBusy) return;
|
||||||
if (Items.Count == 0)
|
//if (Items.Count == 0)
|
||||||
{
|
//{
|
||||||
System.Windows.MessageBox.Show("无可导出的数据", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
// System.Windows.MessageBox.Show("无可导出的数据", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
return;
|
// return;
|
||||||
}
|
//}
|
||||||
|
|
||||||
try
|
//try
|
||||||
{
|
//{
|
||||||
IsBusy = true;
|
// IsBusy = true;
|
||||||
|
|
||||||
var dr = "D:\\迅雷下载";
|
// var dr = "D:\\迅雷下载";
|
||||||
// 转换为 RawProUserCsvDto
|
// // 转换为 RawProUserCsvDto
|
||||||
var all = Items.Select(it => new RawProUserCsvDto
|
// var all = Items.Select(it => new RawProUserCsvDto
|
||||||
{
|
// {
|
||||||
RawCode = it.RawCode,
|
// RawCode = it.RawCode,
|
||||||
RawName = it.RawName,
|
// RawName = it.RawName,
|
||||||
InBagCode = it.InBagCode,
|
// InBagCode = it.InBagCode,
|
||||||
BoxCode = it.BoxCode,
|
// BoxCode = it.BoxCode,
|
||||||
Batch = it.Batch,
|
// Batch = it.Batch,
|
||||||
ShelfLife = it.ShelfLife,
|
// ShelfLife = it.ShelfLife,
|
||||||
Weight = it.Weight,
|
// Weight = it.Weight,
|
||||||
DeliveryDate = it.WeightTime.ToString("yyyyMMdd"),
|
// DeliveryDate = it.WeightTime.ToString("yyyyMMdd"),
|
||||||
RemainWeight = it.RemainWeight,
|
// RemainWeight = it.RemainWeight,
|
||||||
StockWeight = it.StockWeight,
|
// StockWeight = it.StockWeight,
|
||||||
WeightTime = it.WeightTime,
|
// WeightTime = it.WeightTime,
|
||||||
OpUser = it.OpUser,
|
// OpUser = it.OpUser,
|
||||||
CheckUser = it.CheckUser,
|
// CheckUser = it.CheckUser,
|
||||||
OutTime = it.OutTime
|
// OutTime = it.OutTime
|
||||||
}).ToList();
|
// }).ToList();
|
||||||
|
|
||||||
// 过滤 InBagCode 为空的记录,避免导出失败
|
// // 过滤 InBagCode 为空的记录,避免导出失败
|
||||||
var valid = all.Where(x => !string.IsNullOrWhiteSpace(x.InBagCode)).ToList();
|
// var valid = all.Where(x => !string.IsNullOrWhiteSpace(x.InBagCode)).ToList();
|
||||||
int skipped = all.Count - valid.Count;
|
// int skipped = all.Count - valid.Count;
|
||||||
|
|
||||||
var svc = csvServices;
|
// var svc = csvServices;
|
||||||
var paths = svc.ExportMany(valid, dr, overwrite: true);
|
// var paths = svc.ExportMany(valid, dr, overwrite: true);
|
||||||
|
|
||||||
_log.Info($"RawProUse CSV 导出完成: 目录={dr}, 成功={valid.Count}, 跳过={skipped}");
|
// _log.Info($"RawProUse CSV 导出完成: 目录={dr}, 成功={valid.Count}, 跳过={skipped}");
|
||||||
System.Windows.MessageBox.Show($"导出完成:成功 {valid.Count} 条,跳过 {skipped} 条。\n目录:{dr}", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
// System.Windows.MessageBox.Show($"导出完成:成功 {valid.Count} 条,跳过 {skipped} 条。\n目录:{dr}", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||||
}
|
//}
|
||||||
catch (Exception ex)
|
//catch (Exception ex)
|
||||||
{
|
//{
|
||||||
_log.Error($"RawProUse CSV 导出失败: {ex}");
|
// _log.Error($"RawProUse CSV 导出失败: {ex}");
|
||||||
System.Windows.MessageBox.Show($"导出失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
// System.Windows.MessageBox.Show($"导出失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
}
|
//}
|
||||||
finally
|
//finally
|
||||||
{
|
//{
|
||||||
IsBusy = false;
|
// IsBusy = false;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
12
FATrace.WPLApp/Views/HelpManualView.xaml
Normal file
12
FATrace.WPLApp/Views/HelpManualView.xaml
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<UserControl x:Class="FATrace.WPLApp.Views.HelpManualView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:FATrace.WPLApp.Views"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
<Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
28
FATrace.WPLApp/Views/HelpManualView.xaml.cs
Normal file
28
FATrace.WPLApp/Views/HelpManualView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HelpManualView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class HelpManualView : UserControl
|
||||||
|
{
|
||||||
|
public HelpManualView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
225
FATrace.WPLApp/Views/HistoryAlarmView.xaml
Normal file
225
FATrace.WPLApp/Views/HistoryAlarmView.xaml
Normal file
@@ -0,0 +1,225 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="FATrace.WPLApp.Views.HistoryAlarmView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
d:DesignHeight="720"
|
||||||
|
d:DesignWidth="1280"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid Margin="10">
|
||||||
|
<Grid.Resources>
|
||||||
|
<FontFamily x:Key="IconSegoe">Segoe MDL2 Assets</FontFamily>
|
||||||
|
<Style x:Key="PrimaryButton" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="#4A90E2" />
|
||||||
|
<Setter Property="Foreground" Value="White" />
|
||||||
|
<Setter Property="BorderBrush" Value="#4A90E2" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Padding" Value="12,6" />
|
||||||
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="Height" Value="32" />
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="SecondaryButton" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="#F0F4F8" />
|
||||||
|
<Setter Property="Foreground" Value="#334E68" />
|
||||||
|
<Setter Property="BorderBrush" Value="#CBD5E0" />
|
||||||
|
<Setter Property="BorderThickness" Value="1" />
|
||||||
|
<Setter Property="Padding" Value="12,6" />
|
||||||
|
<Setter Property="Cursor" Value="Hand" />
|
||||||
|
<Setter Property="Height" Value="32" />
|
||||||
|
</Style>
|
||||||
|
</Grid.Resources>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- 查询条件 -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="0"
|
||||||
|
Padding="10"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E6ECF2"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="4">
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect
|
||||||
|
BlurRadius="8"
|
||||||
|
Opacity="0.15"
|
||||||
|
ShadowDepth="1" />
|
||||||
|
</Border.Effect>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="2*" />
|
||||||
|
<ColumnDefinition Width="2*" />
|
||||||
|
<ColumnDefinition Width="2*" />
|
||||||
|
<ColumnDefinition Width="2*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="类别:" />
|
||||||
|
<ComboBox
|
||||||
|
Width="180"
|
||||||
|
ItemsSource="{Binding CategoryList}"
|
||||||
|
SelectedItem="{Binding Category, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="关键字:" />
|
||||||
|
<TextBox Width="220" Text="{Binding Keyword, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="2"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="开始:" />
|
||||||
|
<DatePicker Width="160" SelectedDate="{Binding StartTime, Mode=TwoWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="3"
|
||||||
|
Margin="0,0,10,0"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="结束:" />
|
||||||
|
<DatePicker Width="160" SelectedDate="{Binding EndTime, Mode=TwoWay}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="4"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
Width="100"
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Command="{Binding SearchCommand}"
|
||||||
|
Style="{StaticResource PrimaryButton}">
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,6,0"
|
||||||
|
FontFamily="{StaticResource IconSegoe}"
|
||||||
|
Text="" />
|
||||||
|
<TextBlock Text="查询" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
Width="100"
|
||||||
|
Command="{Binding ClearCommand}"
|
||||||
|
Style="{StaticResource SecondaryButton}">
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
Margin="0,0,6,0"
|
||||||
|
FontFamily="{StaticResource IconSegoe}"
|
||||||
|
Text="" />
|
||||||
|
<TextBlock Text="清空" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 列表 -->
|
||||||
|
<DataGrid
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="0,10,0,10"
|
||||||
|
AlternatingRowBackground="#F7FAFC"
|
||||||
|
AlternationCount="2"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E6ECF2"
|
||||||
|
BorderThickness="1"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
FontSize="16"
|
||||||
|
GridLinesVisibility="Horizontal"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding Items}">
|
||||||
|
<DataGrid.ColumnHeaderStyle>
|
||||||
|
<Style TargetType="DataGridColumnHeader">
|
||||||
|
<Setter Property="FontSize" Value="18" />
|
||||||
|
<Setter Property="FontWeight" Value="Bold" />
|
||||||
|
<Setter Property="HorizontalContentAlignment" Value="Center" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.ColumnHeaderStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="160"
|
||||||
|
Binding="{Binding Category}"
|
||||||
|
Header="类别" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="*"
|
||||||
|
Binding="{Binding Message}"
|
||||||
|
Header="消息" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="180"
|
||||||
|
Binding="{Binding CreateTime, StringFormat=yyyy-MM-dd HH:mm:ss}"
|
||||||
|
Header="时间" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
|
||||||
|
<!-- 底部状态/分页 -->
|
||||||
|
<StatusBar Grid.Row="2">
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="总数:" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="{Binding TotalCount}" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<Separator Width="20" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="页码:" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="{Binding PageIndex}" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="/" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<TextBlock Text="{Binding TotalPages}" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
Margin="5,0"
|
||||||
|
Command="{Binding FirstPageCommand}"
|
||||||
|
Content="|<" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
Margin="5,0"
|
||||||
|
Command="{Binding PrevPageCommand}"
|
||||||
|
Content="<" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
Margin="5,0"
|
||||||
|
Command="{Binding NextPageCommand}"
|
||||||
|
Content=">" />
|
||||||
|
</StatusBarItem>
|
||||||
|
<StatusBarItem>
|
||||||
|
<Button
|
||||||
|
Width="40"
|
||||||
|
Margin="5,0"
|
||||||
|
Command="{Binding LastPageCommand}"
|
||||||
|
Content=">|" />
|
||||||
|
</StatusBarItem>
|
||||||
|
</StatusBar>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
28
FATrace.WPLApp/Views/HistoryAlarmView.xaml.cs
Normal file
28
FATrace.WPLApp/Views/HistoryAlarmView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// HistoryAlarmView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class HistoryAlarmView : UserControl
|
||||||
|
{
|
||||||
|
public HistoryAlarmView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
130
FATrace.WPLApp/Views/LogView.xaml
Normal file
130
FATrace.WPLApp/Views/LogView.xaml
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="FATrace.WPLApp.Views.LogView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
d:DesignHeight="720"
|
||||||
|
d:DesignWidth="1280"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid Background="#F5F7FA">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!-- Toolbar -->
|
||||||
|
<Border
|
||||||
|
Padding="10"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E6ECF2"
|
||||||
|
BorderThickness="0,0,0,1">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="200" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="日期:" />
|
||||||
|
<DatePicker SelectedDate="{Binding SelectedDate}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="1"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="级别:" />
|
||||||
|
<ComboBox
|
||||||
|
Width="110"
|
||||||
|
ItemsSource="{Binding Levels}"
|
||||||
|
SelectedItem="{Binding LevelFilter}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="2"
|
||||||
|
Height="28"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Text="{Binding Keyword, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<CheckBox
|
||||||
|
Grid.Column="3"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Content="自动刷新"
|
||||||
|
IsChecked="{Binding AutoRefresh}" />
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="4"
|
||||||
|
Margin="0,0,16,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock VerticalAlignment="Center" Text="最大行数:" />
|
||||||
|
<TextBox Width="80" Text="{Binding MaxLines, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel
|
||||||
|
Grid.Column="5"
|
||||||
|
HorizontalAlignment="Left"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<Button
|
||||||
|
Margin="0,0,8,0"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
Content="刷新" />
|
||||||
|
<Button Command="{Binding OpenFolderCommand}" Content="打开日志文件夹" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- Log list -->
|
||||||
|
<Border
|
||||||
|
Grid.Row="1"
|
||||||
|
Margin="10"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E6ECF2"
|
||||||
|
BorderThickness="1">
|
||||||
|
<DataGrid
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
GridLinesVisibility="None"
|
||||||
|
HeadersVisibility="Column"
|
||||||
|
IsReadOnly="True"
|
||||||
|
ItemsSource="{Binding Items}">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="180"
|
||||||
|
Binding="{Binding Time}"
|
||||||
|
Header="时间" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="100"
|
||||||
|
Binding="{Binding Level}"
|
||||||
|
Header="级别" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="200"
|
||||||
|
Binding="{Binding Logger}"
|
||||||
|
Header="记录器" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="80"
|
||||||
|
Binding="{Binding ThreadId}"
|
||||||
|
Header="线程" />
|
||||||
|
<DataGridTextColumn
|
||||||
|
Width="*"
|
||||||
|
Binding="{Binding Message}"
|
||||||
|
Header="内容" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
28
FATrace.WPLApp/Views/LogView.xaml.cs
Normal file
28
FATrace.WPLApp/Views/LogView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// LogView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class LogView : UserControl
|
||||||
|
{
|
||||||
|
public LogView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
134
FATrace.WPLApp/Views/LoginView.xaml
Normal file
134
FATrace.WPLApp/Views/LoginView.xaml
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="FATrace.WPLApp.Views.LoginView"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:prism="http://prismlibrary.com/"
|
||||||
|
xmlns:utils="clr-namespace:FATrace.WPLApp.Utils"
|
||||||
|
d:DesignHeight="720"
|
||||||
|
d:DesignWidth="1280"
|
||||||
|
prism:ViewModelLocator.AutoWireViewModel="True"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid Background="#F5F7FA">
|
||||||
|
<Grid.Resources>
|
||||||
|
<BooleanToVisibilityConverter x:Key="Bool2Vis" />
|
||||||
|
</Grid.Resources>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Border
|
||||||
|
Width="420"
|
||||||
|
Padding="28"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Background="White"
|
||||||
|
BorderBrush="#E6ECF2"
|
||||||
|
BorderThickness="1"
|
||||||
|
CornerRadius="12">
|
||||||
|
<Border.Effect>
|
||||||
|
<DropShadowEffect
|
||||||
|
BlurRadius="12"
|
||||||
|
Opacity="0.2"
|
||||||
|
ShadowDepth="2" />
|
||||||
|
</Border.Effect>
|
||||||
|
<StackPanel>
|
||||||
|
<!-- 标题 -->
|
||||||
|
<StackPanel
|
||||||
|
Margin="0,6,0,18"
|
||||||
|
HorizontalAlignment="Center"
|
||||||
|
Orientation="Horizontal">
|
||||||
|
<TextBlock
|
||||||
|
FontFamily="/Assets/Fonts/#iconfont"
|
||||||
|
FontSize="26"
|
||||||
|
Foreground="#4A90E2"
|
||||||
|
Text="" />
|
||||||
|
<TextBlock
|
||||||
|
FontSize="24"
|
||||||
|
FontWeight="Bold"
|
||||||
|
Text=" 用户登录" />
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 用户名 -->
|
||||||
|
<StackPanel Margin="0,6">
|
||||||
|
<TextBlock Foreground="#6B7C93" Text="用户名" />
|
||||||
|
<Border
|
||||||
|
Height="40"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Background="#F7F9FC"
|
||||||
|
CornerRadius="6">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="36" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontFamily="/Assets/Fonts/#iconfont"
|
||||||
|
Foreground="#A0AEC0"
|
||||||
|
Text="" />
|
||||||
|
<TextBox
|
||||||
|
Grid.Column="1"
|
||||||
|
Padding="8,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 密码 -->
|
||||||
|
<StackPanel Margin="0,6,0,12">
|
||||||
|
<TextBlock Foreground="#6B7C93" Text="密码" />
|
||||||
|
<Border
|
||||||
|
Height="40"
|
||||||
|
Margin="0,6,0,0"
|
||||||
|
Background="#F7F9FC"
|
||||||
|
CornerRadius="6">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="36" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock
|
||||||
|
Grid.Column="0"
|
||||||
|
Margin="8,0,0,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
FontFamily="/Assets/Fonts/#iconfont"
|
||||||
|
Foreground="#A0AEC0"
|
||||||
|
Text="" />
|
||||||
|
<PasswordBox
|
||||||
|
Grid.Column="1"
|
||||||
|
Padding="8,0"
|
||||||
|
VerticalContentAlignment="Center"
|
||||||
|
Background="Transparent"
|
||||||
|
BorderThickness="0"
|
||||||
|
utils:PasswordBoxAssistant.BindPassword="True"
|
||||||
|
utils:PasswordBoxAssistant.BoundPassword="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<!-- 登录按钮 -->
|
||||||
|
<Button
|
||||||
|
Height="42"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
Background="#4A90E2"
|
||||||
|
BorderBrush="#4A90E2"
|
||||||
|
Command="{Binding LoginCommand}"
|
||||||
|
Content="登录"
|
||||||
|
Cursor="Hand"
|
||||||
|
FontSize="16"
|
||||||
|
Foreground="White" />
|
||||||
|
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<!-- 忙碌遮罩 -->
|
||||||
|
<!--<Grid Background="#80FFFFFF" Visibility="{Binding IsBusy, Converter={StaticResource Bool2Vis}}" />-->
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
28
FATrace.WPLApp/Views/LoginView.xaml.cs
Normal file
28
FATrace.WPLApp/Views/LoginView.xaml.cs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace FATrace.WPLApp.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// LoginView.xaml 的交互逻辑
|
||||||
|
/// </summary>
|
||||||
|
public partial class LoginView : UserControl
|
||||||
|
{
|
||||||
|
public LoginView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user