diff --git a/FATrace.Com/Class1.cs b/FATrace.Com/Class1.cs
deleted file mode 100644
index dc6b742..0000000
--- a/FATrace.Com/Class1.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-namespace FATrace.Com
-{
- public class Class1
- {
-
- }
-}
diff --git a/FATrace.Com/ConfigHelper.cs b/FATrace.Com/ConfigHelper.cs
index 6372b2d..fb1c0d7 100644
--- a/FATrace.Com/ConfigHelper.cs
+++ b/FATrace.Com/ConfigHelper.cs
@@ -45,6 +45,15 @@ namespace FATrace.Com
}
}
+ ///
+ /// 根据Key取Value值
+ ///
+ ///
+ public static string GetValue(string key)
+ {
+ return ConfigurationManager.AppSettings[key].ToString().Trim();
+ }
+
///
/// 根据 key 读取字符串配置,不存在时返回默认值。
///
diff --git a/FATrace.Com/NVRCom.cs b/FATrace.Com/NVRCom.cs
new file mode 100644
index 0000000..325aacd
--- /dev/null
+++ b/FATrace.Com/NVRCom.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FATrace.Com
+{
+ ///
+ /// NVR 公共的类
+ ///
+ public class NVRCom
+ {
+ ///
+ /// 获取视频名称
+ ///
+ ///
+ ///
+ public static string GetVideoName(string Path,string Code)
+ {
+ return $"{Path}\\{DateTime.Now.ToString("yyyy-MM-dd HHmmss")} {Code}.mp4";
+ }
+ }
+}
diff --git a/FATrace.HKNetLib/Common/NVRCamera.cs b/FATrace.HKNetLib/Common/NVRCamera.cs
new file mode 100644
index 0000000..e775f5b
--- /dev/null
+++ b/FATrace.HKNetLib/Common/NVRCamera.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FATrace.HKNetLib.Common
+{
+ ///
+ /// NVR Camera 模型
+ ///
+ public class NVRCamera
+ {
+ ///
+ /// 通道号
+ ///
+ public int ChNo { get; set; }
+
+ ///
+ /// 是否在线
+ ///
+ public byte IsOnline { get; set; }
+
+ ///
+ /// IP设备ID
+ ///
+ public ushort IPID { get; set; }
+
+ }
+}
diff --git a/FATrace.HKNetLib/FATrace.HKNetLib.csproj b/FATrace.HKNetLib/FATrace.HKNetLib.csproj
index 8826f6b..7acbb83 100644
--- a/FATrace.HKNetLib/FATrace.HKNetLib.csproj
+++ b/FATrace.HKNetLib/FATrace.HKNetLib.csproj
@@ -192,4 +192,8 @@
+
+
+
+
diff --git a/FATrace.HKNetLib/Wrapper/HkCamera.cs b/FATrace.HKNetLib/Wrapper/HkCamera.cs
index 76b3c57..a3c9215 100644
--- a/FATrace.HKNetLib/Wrapper/HkCamera.cs
+++ b/FATrace.HKNetLib/Wrapper/HkCamera.cs
@@ -1,13 +1,11 @@
-using FATrace.HKNetLib.Common;
+using FATrace.HKNetLib.Common;
using FATrace.HKNetLib.Hardware;
-using System;
-using System.Collections.Generic;
-using System.Linq;
+using FATrace.Model;
using System.Reflection;
using System.Runtime.InteropServices;
-using System.Text;
-using System.Threading.Tasks;
using static FATrace.HKNetLib.Hardware.CHCNetSDK;
+using System.Threading;
+using System.Threading.Tasks;
namespace FATrace.HKNetLib.Wrapper
{
@@ -93,8 +91,73 @@ namespace FATrace.HKNetLib.Wrapper
}
}
+ #region NVR信息
+
+ ///
+ /// NVR IP
+ ///
+ public string NVR_IP { get; set; }
+
+ ///
+ /// NVR Port
+ ///
+ public ushort NVR_Port { get; set; }
+
+ ///
+ /// NVR UserName
+ ///
+ public string NVR_UserName { get; set; }
+
+ ///
+ /// NVR Pw
+ ///
+ public string NVR_Pw { get; set; }
+
+ ///
+ /// NVR VideoSavePath 保存的地址信息
+ ///
+ public string NVRVideoSavePath { get; set; }
+
+ #endregion
+
+
+ #region 公共信息
+
+ ///
+ /// 事件发布的消息
+ ///
+ public event EventHandler VideoActionEventHandler;
+
+ ///
+ /// 下发视频进度过程的Handler
+ ///
+ public event EventHandler NVRLoadVideoProcessEventHandler;
+
+ ///
+ /// 下发视频完成的Handler
+ ///
+ public event EventHandler NVRLoadVideoCompleteEventHandler;
+
+ ///
+ /// 当前NVR登录信息
+ ///
+ public CameraLoginInfo NVRLoginInfo { get; set; } = new CameraLoginInfo();
+
+ ///
+ /// NVR登录状态
+ ///
+ public bool NVRLoginState { get; set; }
+
+ #endregion
+
+
#region NVR开发
+ ///
+ /// NVRCamera 集合数据
+ ///
+ public List ListNVRCamera { get; set; } = new List();
+
///
/// NVR设备信息 DVR_DEVICEINFO_V30
///
@@ -105,7 +168,14 @@ namespace FATrace.HKNetLib.Wrapper
///
public CHCNetSDK.NET_DVR_IPPARACFG_V40 DVR_IPPARACFG_V40 { get; set; }
+ ///
+ /// 模拟通道个数
+ ///
private uint dwAChanTotalNum { get; set; } = 0;
+
+ ///
+ /// 数字通道个数
+ ///
private uint dwDChanTotalNum { get; set; } = 0;
public NET_DVR_GET_STREAM_UNION DVR_GET_STREAM_UNION { get; set; }
@@ -153,6 +223,7 @@ namespace FATrace.HKNetLib.Wrapper
{
LastMsgErr = GetLastError();
//MessageBox.Show(str1);
+ NVRLoginState = false;
return false;
}
else
@@ -161,6 +232,12 @@ namespace FATrace.HKNetLib.Wrapper
//MessageBox.Show("Login Success!");
//btnLogin.Text = "Logout";
+ NVRLoginInfo.IP = DVRIPAddress;
+ NVRLoginInfo.Port = (ushort)DVRPortNumber;
+ NVRLoginInfo.Password = DVRPassword;
+ NVRLoginInfo.UserName = DVRUserName;
+ NVRLoginState = true;
+
dwAChanTotalNum = (uint)DVRDeviceInfoV30.byChanNum;
dwDChanTotalNum = (uint)DVRDeviceInfoV30.byIPChanNum + 256 * (uint)DVRDeviceInfoV30.byHighDChanNum;
@@ -236,6 +313,14 @@ namespace FATrace.HKNetLib.Wrapper
Marshal.StructureToPtr(DVR_GET_STREAM_UNION, ptrChanInfo, false);
DVR_IPCHANINFO = (CHCNetSDK.NET_DVR_IPCHANINFO)Marshal.PtrToStructure(ptrChanInfo, typeof(CHCNetSDK.NET_DVR_IPCHANINFO));
+ ListNVRCamera.Add(new NVRCamera()
+ {
+ //ChNo = DVR_IPCHANINFO.byChannel,
+ ChNo = (i + 1),
+ IPID = DVR_IPCHANINFO.byIPID,
+ IsOnline = DVR_IPCHANINFO.byEnable
+ });
+
//列出IP通道
//ListIPChannel(i + 1, DVR_IPCHANINFO.byEnable, DVR_IPCHANINFO.byIPID);
Marshal.FreeHGlobal(ptrChanInfo);
@@ -250,20 +335,19 @@ namespace FATrace.HKNetLib.Wrapper
}
///
- /// 根据时间获取DVR统计信息
+ /// 根据时间获取DVR 视频数据信息
///
public (bool Result, string Msg) Sdk_NET_DVR_GetFileByTime_V40(DateTime startTime, DateTime endTime, string SaveVideFilePath)
{
if (m_lDownHandle >= 0)
{
- //MessageBox.Show("Downloading, please stop firstly!");//正在下载,请先停止下载
return (Result: false, Msg: "正在下载,请先停止下载");
}
NET_DVR_PLAYCOND struDownPara = new NET_DVR_PLAYCOND();
- struDownPara.dwChannel = (uint)iChannelNum[(int)iSelIndex]; //通道号 Channel number
+ struDownPara.dwChannel = (uint)iChannelNum[(int)iSelIndex];
- //设置下载的开始时间 Set the starting time
+ // 设置下载的开始时间
struDownPara.struStartTime.dwYear = startTime.Year;
struDownPara.struStartTime.dwMonth = startTime.Month;
struDownPara.struStartTime.dwDay = startTime.Day;
@@ -271,7 +355,7 @@ namespace FATrace.HKNetLib.Wrapper
struDownPara.struStartTime.dwMinute = startTime.Minute;
struDownPara.struStartTime.dwSecond = startTime.Second;
- //设置下载的结束时间 Set the stopping time
+ // 设置下载的结束时间
struDownPara.struStopTime.dwYear = endTime.Year;
struDownPara.struStopTime.dwMonth = endTime.Month;
struDownPara.struStopTime.dwDay = endTime.Day;
@@ -279,10 +363,7 @@ namespace FATrace.HKNetLib.Wrapper
struDownPara.struStopTime.dwMinute = endTime.Minute;
struDownPara.struStopTime.dwSecond = endTime.Second;
- //string sVideoFileName; //录像文件保存路径和文件名 the path and file name to save
- //sVideoFileName = "D:\\Downtest_Channel" + struDownPara.dwChannel + ".mp4";
-
- //按时间下载 Download by time
+ // 按时间下载
m_lDownHandle = CHCNetSDK.NET_DVR_GetFileByTime_V40(m_lUserID, SaveVideFilePath, ref struDownPara);
if (m_lDownHandle < 0)
{
@@ -291,30 +372,153 @@ namespace FATrace.HKNetLib.Wrapper
}
uint iOutValue = 0;
- //该接口指定了当前要下载的录像文件,调用成功后,还需要调用NET_DVR_PlayBackControl_V40接口的开始播放控制命令(NET_DVR_PLAYSTART)才能实现下载。
- //V5.0.3.2或以后版本,通过该接口保存录像,保存的录像文件数据超过文件最大限制字节数(默认为1024MB),SDK会自动切片,即新建文件进行保存,文件名命名规则为“在接口传入的文件名基础上增加数字标识(例如:*_1.mp4、*_2.mp4)”。
- //可以调用NET_DVR_GetSDKLocalCfg、NET_DVR_SetSDKLocalCfg(配置类型:NET_DVR_LOCAL_CFG_TYPE_GENERAL)获取和设置切片模式和文件最大限制字节数。
+ // 该接口指定了当前要下载的录像文件,调用成功后,还需要调用 NET_DVR_PlayBackControl_V40 接口的开始播放控制命令(NET_DVR_PLAYSTART)才能实现下载。
if (!CHCNetSDK.NET_DVR_PlayBackControl_V40(m_lDownHandle, CHCNetSDK.NET_DVR_PLAYSTART, IntPtr.Zero, 0, IntPtr.Zero, ref iOutValue))
{
LastMsgErr = GetLastError();
+ try { CHCNetSDK.NET_DVR_StopGetFile(m_lDownHandle); } catch { }
+ m_lDownHandle = -1;
return (Result: false, Msg: $"[NET_DVR_PlayBackControl_V40] 执行下载控制失败:{LastMsgErr}");
}
- return (Result: true, Msg: "下载成功!");
- }
-
- ///
- /// 获取下载的进度
- ///
- ///
- ///
- public int Sdk_NET_DVR_GetDownloadPos(Int32 downHandle)
- {
- return CHCNetSDK.NET_DVR_GetDownloadPos(downHandle);
+ StartDownloadProgressMonitor();
+ return (Result: true, Msg: "下载OK!");
}
#endregion
+
+ #region 跟踪下载
+
+ private CancellationTokenSource _downloadCts;
+ private const int _downloadPollIntervalMs = 500;
+
+ ///
+ /// 启动下载进度轮询,定期发布 NVRLoadVideoProcessEventHandler 事件
+ ///
+ public void StartDownloadProgressMonitor()
+ {
+ // 先确保没有旧的轮询任务
+ StopDownloadProgressMonitor();
+
+ _downloadCts = new CancellationTokenSource();
+ var token = _downloadCts.Token;
+
+ Task.Run(async () =>
+ {
+ try
+ {
+ while (!token.IsCancellationRequested && m_lDownHandle >= 0)
+ {
+ int progress = -1;
+ try
+ {
+ progress = CHCNetSDK.NET_DVR_GetDownloadPos(m_lDownHandle);
+ }
+ catch
+ {
+ progress = -1;
+ }
+
+ if (progress >= 0)
+ {
+ short percent = (short)Math.Min(100, progress);
+ try
+ {
+ NVRLoadVideoProcessEventHandler?.Invoke(this, percent);
+ }
+ catch
+ {
+ // 事件订阅者异常不应中断轮询
+ }
+
+ if (progress >= 100)
+ {
+ // 完成:停止下载,退出轮询
+ Sdk_NET_DVR_StopGetFile();
+
+ NVRLoadVideoCompleteEventHandler?.Invoke(this, "下载完成");
+ break;
+ }
+ }
+ else
+ {
+ // 发生错误,尝试停止下载并退出
+ Sdk_NET_DVR_StopGetFile();
+ break;
+ }
+
+ try { await Task.Delay(_downloadPollIntervalMs, token); } catch { /* ignore */ }
+ }
+ }
+ catch
+ {
+ // 轮询线程异常吞掉,避免影响上层逻辑
+ }
+ }, token);
+ }
+
+
+ ///
+ /// 停止下载进度轮询
+ ///
+ private void StopDownloadProgressMonitor()
+ {
+ try
+ {
+ if (_downloadCts != null)
+ {
+ if (!_downloadCts.IsCancellationRequested)
+ {
+ _downloadCts.Cancel();
+ }
+ _downloadCts.Dispose();
+ _downloadCts = null;
+ }
+ }
+ catch
+ {
+ // 忽略取消中的异常
+ }
+ }
+
+
+ ///
+ /// 停止当前下载并清理资源
+ ///
+ ///
+ public (bool Result, string Msg) Sdk_NET_DVR_StopGetFile()
+ {
+ try
+ {
+ // 停止轮询
+ StopDownloadProgressMonitor();
+
+ if (m_lDownHandle >= 0)
+ {
+ bool stopOk = CHCNetSDK.NET_DVR_StopGetFile(m_lDownHandle);
+ m_lDownHandle = -1;
+ if (!stopOk)
+ {
+ LastMsgErr = GetLastError();
+ return (false, $"[NET_DVR_StopGetFile] 停止下载失败:{LastMsgErr}");
+ }
+ }
+ return (true, "停止下载成功");
+ }
+ catch (Exception)
+ {
+ return (false, "停止下载异常");
+ }
+ }
+
+
+
+ #endregion
+
+
+
+
public bool IsOnline()
{
try
diff --git a/FATrace.Model/OEMRawUse.cs b/FATrace.Model/OEMRawUse.cs
new file mode 100644
index 0000000..3fa0e92
--- /dev/null
+++ b/FATrace.Model/OEMRawUse.cs
@@ -0,0 +1,69 @@
+using FreeSql.DataAnnotations;
+
+namespace FATrace.Model
+{
+ ///
+ /// OEM原料使用信息
+ ///
+ [Table(Name = "OEMRawUse")]
+ public class OEMRawUse
+ {
+ ///
+ /// 主键
+ ///
+ [Column(IsPrimary = true, IsIdentity = true)]
+ public long Id { get; set; }
+
+ ///
+ /// 内袋二维码
+ ///
+ [Column(Name = "InBagCode", IsNullable = false, StringLength = 100)]
+ public string? InBagCode { get; set; }
+
+ ///
+ /// 原料名称
+ ///
+ [Column(Name = "InBagCode", IsNullable = false, StringLength = 100)]
+ public string? RawName{ get; set; }
+
+ ///
+ /// 视频链接
+ ///
+ [Column(Name = "VideoUrl", IsNullable = false, StringLength = 100)]
+ public string? VideoUrl{ get; set; }
+
+ ///
+ /// 用户信息
+ ///
+ [Column(Name = "User", IsNullable = false, StringLength = 100)]
+ public string? User { get; set; }
+
+ ///
+ /// URl状态
+ ///
+ [Column(Name = "UrlState", IsNullable = false)]
+ public bool UrlState { get; set; }
+
+ /////
+ ///// 视频信息
+ /////
+ //[Column(Name = "User", IsNullable = false, StringLength = 100)]
+ //public VideoAction? VideoAction { get; set; }
+
+ ///
+ /// 创建时间
+ ///
+ [Column(ServerTime = DateTimeKind.Local, CanUpdate = true)]
+ public DateTime CreateTime { get; set; }
+
+ ///
+ /// ///////////////////////////////////////////导航属性 LIN 一对一///////////////////////////////////////////////////////
+ ///
+ public long VideoActionId { get; set; } // 外键字段,必要
+ ///
+ /// 视频信息
+ ///
+ public VideoAction? VideoAction { get; set; }
+
+ }
+}
diff --git a/FATrace.Model/VideoAction.cs b/FATrace.Model/VideoAction.cs
index 4ec2560..115514a 100644
--- a/FATrace.Model/VideoAction.cs
+++ b/FATrace.Model/VideoAction.cs
@@ -26,12 +26,6 @@ namespace FATrace.Model
[Column(Name = "User", IsNullable = false, StringLength = 100)]
public string? User { get; set; }
- /////
- ///// 分类信息-CAN/LIN
- /////
- //[Column(Name = "CANLINInfo", IsNullable = false, MapType = typeof(string))]
- //public CANLIN CANLINInfo { get; set; }
-
///
/// 视频文件路径
///
diff --git a/FATrace.OEMApp/App.config b/FATrace.OEMApp/App.config
index 63e7c72..794f590 100644
--- a/FATrace.OEMApp/App.config
+++ b/FATrace.OEMApp/App.config
@@ -3,11 +3,16 @@
-
+
+
+
+
+
+
diff --git a/FATrace.OEMApp/FATrace.OEMApp.csproj b/FATrace.OEMApp/FATrace.OEMApp.csproj
index cf6fb4b..c4912f5 100644
--- a/FATrace.OEMApp/FATrace.OEMApp.csproj
+++ b/FATrace.OEMApp/FATrace.OEMApp.csproj
@@ -415,9 +415,13 @@
+
+
+
+
diff --git a/FATrace.OEMApp/FSqlContext.cs b/FATrace.OEMApp/FSqlContext.cs
index d4fd078..14e556a 100644
--- a/FATrace.OEMApp/FSqlContext.cs
+++ b/FATrace.OEMApp/FSqlContext.cs
@@ -1,9 +1,4 @@
using FATrace.Com;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
namespace FATrace.OEMApp
{
@@ -16,7 +11,7 @@ namespace FATrace.OEMApp
{
return new FreeSql.FreeSqlBuilder()
.UseConnectionString(FreeSql.DataType.SqlServer, connectionString)
- .UseAutoSyncStructure(false)
+ .UseAutoSyncStructure(true)
.Build();
}
catch (Exception ex)
diff --git a/FATrace.OEMApp/MainApp.Designer.cs b/FATrace.OEMApp/MainApp.Designer.cs
index 1d55d72..78f59df 100644
--- a/FATrace.OEMApp/MainApp.Designer.cs
+++ b/FATrace.OEMApp/MainApp.Designer.cs
@@ -30,20 +30,79 @@
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainApp));
+ statusStrip1 = new StatusStrip();
imageList1 = new ImageList(components);
materialTabControl1 = new ReaLTaiizor.Controls.MaterialTabControl();
tabPage1 = new TabPage();
+ materialCard4 = new ReaLTaiizor.Controls.MaterialCard();
+ label18 = new Label();
+ txtIOOutputTime = new TextBox();
+ label17 = new Label();
+ txtIOInputTime = new TextBox();
+ label16 = new Label();
+ txtIOInBagCode = new TextBox();
+ txtRemainBoxCount = new TextBox();
+ label15 = new Label();
+ txtOutBoxCount = new TextBox();
+ label14 = new Label();
+ txtInBoxCount = new TextBox();
+ label13 = new Label();
+ label12 = new Label();
+ label9 = new Label();
+ txtIORawName = new TextBox();
+ label10 = new Label();
+ txtIOOutBagCode = new TextBox();
+ label11 = new Label();
+ materialCard3 = new ReaLTaiizor.Controls.MaterialCard();
+ label8 = new Label();
+ materialCard2 = new ReaLTaiizor.Controls.MaterialCard();
+ btnTestAction = new Button();
+ label7 = new Label();
+ txtRURawName = new TextBox();
+ label6 = new Label();
+ txtRUInBagCode = new TextBox();
+ label5 = new Label();
tabPage2 = new TabPage();
+ btnStopHistoryPlay = new Button();
+ dataGridView1 = new DataGridView();
+ materialCard1 = new ReaLTaiizor.Controls.MaterialCard();
+ label4 = new Label();
+ txtSearchCode = new TextBox();
+ btnHistoryVideoSearch = new Button();
+ label3 = new Label();
+ PdtHistorySearchEnd = new ReaLTaiizor.Controls.PoisonDateTime();
+ label2 = new Label();
+ label1 = new Label();
+ PdtHistorySearchStart = new ReaLTaiizor.Controls.PoisonDateTime();
+ btnPlayHistoryVideo = new Button();
+ videoView1 = new LibVLCSharp.WinForms.VideoView();
tabPage3 = new TabPage();
+ metroProgressBar1 = new ReaLTaiizor.Controls.MetroProgressBar();
+ DownloadProgressBar = new ProgressBar();
btnStopLoadVideo = new Button();
btnLoadVideo = new Button();
btnNVRLogin = new Button();
- DownTimer = new System.Windows.Forms.Timer(components);
- DownloadProgressBar = new ProgressBar();
+ DownloadProgressBarMain = new ProgressBar();
materialTabControl1.SuspendLayout();
+ tabPage1.SuspendLayout();
+ materialCard4.SuspendLayout();
+ materialCard3.SuspendLayout();
+ materialCard2.SuspendLayout();
+ tabPage2.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)dataGridView1).BeginInit();
+ materialCard1.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)videoView1).BeginInit();
tabPage3.SuspendLayout();
SuspendLayout();
//
+ // statusStrip1
+ //
+ statusStrip1.Location = new Point(3, 1005);
+ statusStrip1.Name = "statusStrip1";
+ statusStrip1.Size = new Size(1914, 22);
+ statusStrip1.TabIndex = 1;
+ statusStrip1.Text = "statusStrip1";
+ //
// imageList1
//
imageList1.ColorDepth = ColorDepth.Depth32Bit;
@@ -76,6 +135,9 @@
//
// tabPage1
//
+ tabPage1.Controls.Add(materialCard4);
+ tabPage1.Controls.Add(materialCard3);
+ tabPage1.Controls.Add(materialCard2);
tabPage1.Font = new Font("Microsoft YaHei UI", 14.25F, FontStyle.Bold, GraphicsUnit.Point, 134);
tabPage1.ImageKey = "set2.png";
tabPage1.Location = new Point(4, 26);
@@ -86,8 +148,323 @@
tabPage1.Text = "主界面";
tabPage1.UseVisualStyleBackColor = true;
//
+ // materialCard4
+ //
+ materialCard4.BackColor = Color.FromArgb(255, 255, 255);
+ materialCard4.Controls.Add(label18);
+ materialCard4.Controls.Add(txtIOOutputTime);
+ materialCard4.Controls.Add(label17);
+ materialCard4.Controls.Add(txtIOInputTime);
+ materialCard4.Controls.Add(label16);
+ materialCard4.Controls.Add(txtIOInBagCode);
+ materialCard4.Controls.Add(txtRemainBoxCount);
+ materialCard4.Controls.Add(label15);
+ materialCard4.Controls.Add(txtOutBoxCount);
+ materialCard4.Controls.Add(label14);
+ materialCard4.Controls.Add(txtInBoxCount);
+ materialCard4.Controls.Add(label13);
+ materialCard4.Controls.Add(label12);
+ materialCard4.Controls.Add(label9);
+ materialCard4.Controls.Add(txtIORawName);
+ materialCard4.Controls.Add(label10);
+ materialCard4.Controls.Add(txtIOOutBagCode);
+ materialCard4.Controls.Add(label11);
+ materialCard4.Depth = 0;
+ materialCard4.ForeColor = Color.FromArgb(222, 0, 0, 0);
+ materialCard4.Location = new Point(14, 373);
+ materialCard4.Margin = new Padding(14);
+ materialCard4.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.HOVER;
+ materialCard4.Name = "materialCard4";
+ materialCard4.Padding = new Padding(14);
+ materialCard4.Size = new Size(864, 535);
+ materialCard4.TabIndex = 5;
+ //
+ // label18
+ //
+ label18.AutoSize = true;
+ label18.ForeColor = Color.DimGray;
+ label18.Location = new Point(41, 260);
+ label18.Name = "label18";
+ label18.Size = new Size(88, 26);
+ label18.TabIndex = 17;
+ label18.Text = "出库时间";
+ //
+ // txtIOOutputTime
+ //
+ txtIOOutputTime.Location = new Point(154, 257);
+ txtIOOutputTime.Name = "txtIOOutputTime";
+ txtIOOutputTime.Size = new Size(446, 32);
+ txtIOOutputTime.TabIndex = 16;
+ //
+ // label17
+ //
+ label17.AutoSize = true;
+ label17.ForeColor = Color.DimGray;
+ label17.Location = new Point(41, 211);
+ label17.Name = "label17";
+ label17.Size = new Size(88, 26);
+ label17.TabIndex = 15;
+ label17.Text = "入库时间";
+ //
+ // txtIOInputTime
+ //
+ txtIOInputTime.Location = new Point(154, 208);
+ txtIOInputTime.Name = "txtIOInputTime";
+ txtIOInputTime.Size = new Size(446, 32);
+ txtIOInputTime.TabIndex = 14;
+ //
+ // label16
+ //
+ label16.AutoSize = true;
+ label16.ForeColor = Color.DimGray;
+ label16.Location = new Point(41, 109);
+ label16.Name = "label16";
+ label16.Size = new Size(107, 26);
+ label16.TabIndex = 13;
+ label16.Text = "内袋二维码";
+ //
+ // txtIOInBagCode
+ //
+ txtIOInBagCode.Location = new Point(154, 106);
+ txtIOInBagCode.Name = "txtIOInBagCode";
+ txtIOInBagCode.Size = new Size(446, 32);
+ txtIOInBagCode.TabIndex = 12;
+ //
+ // txtRemainBoxCount
+ //
+ txtRemainBoxCount.BackColor = SystemColors.ButtonHighlight;
+ txtRemainBoxCount.BorderStyle = BorderStyle.None;
+ txtRemainBoxCount.Font = new Font("Microsoft YaHei UI", 21.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ txtRemainBoxCount.Location = new Point(507, 417);
+ txtRemainBoxCount.Name = "txtRemainBoxCount";
+ txtRemainBoxCount.ReadOnly = true;
+ txtRemainBoxCount.Size = new Size(100, 37);
+ txtRemainBoxCount.TabIndex = 11;
+ txtRemainBoxCount.Text = "100";
+ txtRemainBoxCount.TextAlign = HorizontalAlignment.Center;
+ //
+ // label15
+ //
+ label15.AutoSize = true;
+ label15.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label15.ForeColor = Color.DimGray;
+ label15.Location = new Point(496, 475);
+ label15.Name = "label15";
+ label15.Size = new Size(117, 28);
+ label15.TabIndex = 10;
+ label15.Text = "剩余总箱数";
+ //
+ // txtOutBoxCount
+ //
+ txtOutBoxCount.BackColor = SystemColors.ButtonHighlight;
+ txtOutBoxCount.BorderStyle = BorderStyle.None;
+ txtOutBoxCount.Font = new Font("Microsoft YaHei UI", 21.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ txtOutBoxCount.Location = new Point(317, 417);
+ txtOutBoxCount.Name = "txtOutBoxCount";
+ txtOutBoxCount.ReadOnly = true;
+ txtOutBoxCount.Size = new Size(100, 37);
+ txtOutBoxCount.TabIndex = 9;
+ txtOutBoxCount.Text = "100";
+ txtOutBoxCount.TextAlign = HorizontalAlignment.Center;
+ //
+ // label14
+ //
+ label14.AutoSize = true;
+ label14.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label14.ForeColor = Color.DimGray;
+ label14.Location = new Point(306, 475);
+ label14.Name = "label14";
+ label14.Size = new Size(117, 28);
+ label14.TabIndex = 8;
+ label14.Text = "出库总箱数";
+ //
+ // txtInBoxCount
+ //
+ txtInBoxCount.BackColor = SystemColors.ButtonHighlight;
+ txtInBoxCount.BorderStyle = BorderStyle.None;
+ txtInBoxCount.Font = new Font("Microsoft YaHei UI", 21.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ txtInBoxCount.Location = new Point(103, 417);
+ txtInBoxCount.Name = "txtInBoxCount";
+ txtInBoxCount.ReadOnly = true;
+ txtInBoxCount.Size = new Size(100, 37);
+ txtInBoxCount.TabIndex = 7;
+ txtInBoxCount.Text = "100";
+ txtInBoxCount.TextAlign = HorizontalAlignment.Center;
+ //
+ // label13
+ //
+ label13.AutoSize = true;
+ label13.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label13.ForeColor = Color.DimGray;
+ label13.Location = new Point(92, 475);
+ label13.Name = "label13";
+ label13.Size = new Size(117, 28);
+ label13.TabIndex = 6;
+ label13.Text = "入库总箱数";
+ //
+ // label12
+ //
+ label12.AutoSize = true;
+ label12.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label12.ForeColor = Color.FromArgb(64, 64, 64);
+ label12.Location = new Point(10, 319);
+ label12.Name = "label12";
+ label12.Size = new Size(159, 28);
+ label12.TabIndex = 5;
+ label12.Text = "成品出入库统计";
+ //
+ // label9
+ //
+ label9.AutoSize = true;
+ label9.ForeColor = Color.DimGray;
+ label9.Location = new Point(41, 160);
+ label9.Name = "label9";
+ label9.Size = new Size(88, 26);
+ label9.TabIndex = 4;
+ label9.Text = "原料名称";
+ //
+ // txtIORawName
+ //
+ txtIORawName.Location = new Point(154, 157);
+ txtIORawName.Name = "txtIORawName";
+ txtIORawName.Size = new Size(446, 32);
+ txtIORawName.TabIndex = 3;
+ //
+ // label10
+ //
+ label10.AutoSize = true;
+ label10.ForeColor = Color.DimGray;
+ label10.Location = new Point(41, 61);
+ label10.Name = "label10";
+ label10.Size = new Size(107, 26);
+ label10.TabIndex = 2;
+ label10.Text = "外箱二维码";
+ //
+ // txtIOOutBagCode
+ //
+ txtIOOutBagCode.Location = new Point(154, 58);
+ txtIOOutBagCode.Name = "txtIOOutBagCode";
+ txtIOOutBagCode.Size = new Size(446, 32);
+ txtIOOutBagCode.TabIndex = 1;
+ //
+ // label11
+ //
+ label11.AutoSize = true;
+ label11.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label11.ForeColor = Color.FromArgb(64, 64, 64);
+ label11.Location = new Point(10, 9);
+ label11.Name = "label11";
+ label11.Size = new Size(159, 28);
+ label11.TabIndex = 0;
+ label11.Text = "成品出入库信息";
+ //
+ // materialCard3
+ //
+ materialCard3.BackColor = Color.FromArgb(255, 255, 255);
+ materialCard3.Controls.Add(label8);
+ materialCard3.Depth = 0;
+ materialCard3.ForeColor = Color.FromArgb(222, 0, 0, 0);
+ materialCard3.Location = new Point(897, 8);
+ materialCard3.Margin = new Padding(14);
+ materialCard3.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.HOVER;
+ materialCard3.Name = "materialCard3";
+ materialCard3.Padding = new Padding(14);
+ materialCard3.Size = new Size(1000, 900);
+ materialCard3.TabIndex = 1;
+ //
+ // label8
+ //
+ label8.AutoSize = true;
+ label8.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label8.ForeColor = Color.FromArgb(64, 64, 64);
+ label8.Location = new Point(12, 9);
+ label8.Name = "label8";
+ label8.Size = new Size(180, 28);
+ label8.TabIndex = 5;
+ label8.Text = "原料使用历史信息";
+ //
+ // materialCard2
+ //
+ materialCard2.BackColor = Color.FromArgb(255, 255, 255);
+ materialCard2.Controls.Add(DownloadProgressBarMain);
+ materialCard2.Controls.Add(btnTestAction);
+ materialCard2.Controls.Add(label7);
+ materialCard2.Controls.Add(txtRURawName);
+ materialCard2.Controls.Add(label6);
+ materialCard2.Controls.Add(txtRUInBagCode);
+ materialCard2.Controls.Add(label5);
+ materialCard2.Depth = 0;
+ materialCard2.ForeColor = Color.FromArgb(222, 0, 0, 0);
+ materialCard2.Location = new Point(14, 9);
+ materialCard2.Margin = new Padding(14);
+ materialCard2.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.HOVER;
+ materialCard2.Name = "materialCard2";
+ materialCard2.Padding = new Padding(14);
+ materialCard2.Size = new Size(864, 348);
+ materialCard2.TabIndex = 0;
+ //
+ // btnTestAction
+ //
+ btnTestAction.Location = new Point(41, 223);
+ btnTestAction.Name = "btnTestAction";
+ btnTestAction.Size = new Size(142, 44);
+ btnTestAction.TabIndex = 5;
+ btnTestAction.Text = "结束操作";
+ btnTestAction.UseVisualStyleBackColor = true;
+ btnTestAction.Click += btnTestAction_Click;
+ //
+ // label7
+ //
+ label7.AutoSize = true;
+ label7.ForeColor = Color.DimGray;
+ label7.Location = new Point(41, 126);
+ label7.Name = "label7";
+ label7.Size = new Size(88, 26);
+ label7.TabIndex = 4;
+ label7.Text = "原料名称";
+ //
+ // txtRURawName
+ //
+ txtRURawName.Location = new Point(154, 123);
+ txtRURawName.Name = "txtRURawName";
+ txtRURawName.Size = new Size(446, 32);
+ txtRURawName.TabIndex = 3;
+ //
+ // label6
+ //
+ label6.AutoSize = true;
+ label6.ForeColor = Color.DimGray;
+ label6.Location = new Point(41, 68);
+ label6.Name = "label6";
+ label6.Size = new Size(107, 26);
+ label6.TabIndex = 2;
+ label6.Text = "内袋二维码";
+ //
+ // txtRUInBagCode
+ //
+ txtRUInBagCode.Location = new Point(154, 65);
+ txtRUInBagCode.Name = "txtRUInBagCode";
+ txtRUInBagCode.Size = new Size(446, 32);
+ txtRUInBagCode.TabIndex = 1;
+ //
+ // label5
+ //
+ label5.AutoSize = true;
+ label5.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label5.ForeColor = Color.FromArgb(64, 64, 64);
+ label5.Location = new Point(10, 9);
+ label5.Name = "label5";
+ label5.Size = new Size(138, 28);
+ label5.TabIndex = 0;
+ label5.Text = "原料使用信息";
+ //
// tabPage2
//
+ tabPage2.Controls.Add(btnStopHistoryPlay);
+ tabPage2.Controls.Add(dataGridView1);
+ tabPage2.Controls.Add(materialCard1);
+ tabPage2.Controls.Add(btnPlayHistoryVideo);
+ tabPage2.Controls.Add(videoView1);
tabPage2.Font = new Font("Microsoft YaHei UI", 14.25F, FontStyle.Bold, GraphicsUnit.Point, 134);
tabPage2.ImageKey = "Load.png";
tabPage2.Location = new Point(4, 26);
@@ -98,8 +475,145 @@
tabPage2.Text = "录像历史数据";
tabPage2.UseVisualStyleBackColor = true;
//
+ // btnStopHistoryPlay
+ //
+ btnStopHistoryPlay.Location = new Point(628, 14);
+ btnStopHistoryPlay.Name = "btnStopHistoryPlay";
+ btnStopHistoryPlay.Size = new Size(116, 45);
+ btnStopHistoryPlay.TabIndex = 12;
+ btnStopHistoryPlay.Text = "停止播放";
+ btnStopHistoryPlay.UseVisualStyleBackColor = true;
+ btnStopHistoryPlay.Click += btnStopHistoryPlay_Click;
+ //
+ // dataGridView1
+ //
+ dataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
+ dataGridView1.Location = new Point(17, 328);
+ dataGridView1.Name = "dataGridView1";
+ dataGridView1.Size = new Size(483, 584);
+ dataGridView1.TabIndex = 11;
+ //
+ // materialCard1
+ //
+ materialCard1.BackColor = Color.FromArgb(255, 255, 255);
+ materialCard1.Controls.Add(label4);
+ materialCard1.Controls.Add(txtSearchCode);
+ materialCard1.Controls.Add(btnHistoryVideoSearch);
+ materialCard1.Controls.Add(label3);
+ materialCard1.Controls.Add(PdtHistorySearchEnd);
+ materialCard1.Controls.Add(label2);
+ materialCard1.Controls.Add(label1);
+ materialCard1.Controls.Add(PdtHistorySearchStart);
+ materialCard1.Depth = 0;
+ materialCard1.ForeColor = Color.FromArgb(222, 0, 0, 0);
+ materialCard1.Location = new Point(17, 24);
+ materialCard1.Margin = new Padding(14);
+ materialCard1.MouseState = ReaLTaiizor.Helper.MaterialDrawHelper.MaterialMouseState.HOVER;
+ materialCard1.Name = "materialCard1";
+ materialCard1.Padding = new Padding(14);
+ materialCard1.Size = new Size(483, 287);
+ materialCard1.TabIndex = 10;
+ //
+ // label4
+ //
+ label4.AutoSize = true;
+ label4.ForeColor = Color.Gray;
+ label4.Location = new Point(196, 34);
+ label4.Name = "label4";
+ label4.Size = new Size(88, 26);
+ label4.TabIndex = 7;
+ label4.Text = "条码信息";
+ //
+ // txtSearchCode
+ //
+ txtSearchCode.Location = new Point(17, 63);
+ txtSearchCode.Name = "txtSearchCode";
+ txtSearchCode.Size = new Size(449, 32);
+ txtSearchCode.TabIndex = 6;
+ //
+ // btnHistoryVideoSearch
+ //
+ btnHistoryVideoSearch.ForeColor = Color.DimGray;
+ btnHistoryVideoSearch.Location = new Point(125, 214);
+ btnHistoryVideoSearch.Name = "btnHistoryVideoSearch";
+ btnHistoryVideoSearch.Size = new Size(210, 56);
+ btnHistoryVideoSearch.TabIndex = 5;
+ btnHistoryVideoSearch.Text = "历史记录视频搜索";
+ btnHistoryVideoSearch.UseVisualStyleBackColor = true;
+ btnHistoryVideoSearch.Click += btnHistoryVideoSearch_Click;
+ //
+ // label3
+ //
+ label3.AutoSize = true;
+ label3.ForeColor = Color.Gray;
+ label3.Location = new Point(288, 117);
+ label3.Name = "label3";
+ label3.Size = new Size(88, 26);
+ label3.TabIndex = 4;
+ label3.Text = "结束时间";
+ //
+ // PdtHistorySearchEnd
+ //
+ PdtHistorySearchEnd.FontSize = ReaLTaiizor.Extension.Poison.PoisonDateTimeSize.Medium;
+ PdtHistorySearchEnd.Location = new Point(268, 155);
+ PdtHistorySearchEnd.MinimumSize = new Size(0, 29);
+ PdtHistorySearchEnd.Name = "PdtHistorySearchEnd";
+ PdtHistorySearchEnd.Size = new Size(131, 32);
+ PdtHistorySearchEnd.TabIndex = 3;
+ //
+ // label2
+ //
+ label2.AutoSize = true;
+ label2.ForeColor = Color.Gray;
+ label2.Location = new Point(75, 116);
+ label2.Name = "label2";
+ label2.Size = new Size(88, 26);
+ label2.TabIndex = 2;
+ label2.Text = "开始时间";
+ //
+ // label1
+ //
+ label1.AutoSize = true;
+ label1.Font = new Font("Microsoft YaHei UI", 15.75F, FontStyle.Bold, GraphicsUnit.Point, 134);
+ label1.ForeColor = Color.Gray;
+ label1.Location = new Point(6, 7);
+ label1.Name = "label1";
+ label1.Size = new Size(96, 28);
+ label1.TabIndex = 1;
+ label1.Text = "搜索条件";
+ //
+ // PdtHistorySearchStart
+ //
+ PdtHistorySearchStart.FontSize = ReaLTaiizor.Extension.Poison.PoisonDateTimeSize.Medium;
+ PdtHistorySearchStart.Location = new Point(55, 154);
+ PdtHistorySearchStart.MinimumSize = new Size(0, 29);
+ PdtHistorySearchStart.Name = "PdtHistorySearchStart";
+ PdtHistorySearchStart.Size = new Size(131, 32);
+ PdtHistorySearchStart.TabIndex = 0;
+ //
+ // btnPlayHistoryVideo
+ //
+ btnPlayHistoryVideo.Location = new Point(506, 14);
+ btnPlayHistoryVideo.Name = "btnPlayHistoryVideo";
+ btnPlayHistoryVideo.Size = new Size(116, 45);
+ btnPlayHistoryVideo.TabIndex = 8;
+ btnPlayHistoryVideo.Text = "button1";
+ btnPlayHistoryVideo.UseVisualStyleBackColor = true;
+ btnPlayHistoryVideo.Click += btnPlayHistoryVideo_Click;
+ //
+ // videoView1
+ //
+ videoView1.BackColor = Color.Black;
+ videoView1.Location = new Point(506, 65);
+ videoView1.MediaPlayer = null;
+ videoView1.Name = "videoView1";
+ videoView1.Size = new Size(1394, 847);
+ videoView1.TabIndex = 7;
+ videoView1.Text = "videoView1";
+ //
// tabPage3
//
+ tabPage3.Controls.Add(metroProgressBar1);
tabPage3.Controls.Add(DownloadProgressBar);
tabPage3.Controls.Add(btnStopLoadVideo);
tabPage3.Controls.Add(btnLoadVideo);
@@ -112,6 +626,36 @@
tabPage3.Text = "相机设置";
tabPage3.UseVisualStyleBackColor = true;
//
+ // metroProgressBar1
+ //
+ metroProgressBar1.BackgroundColor = Color.FromArgb(238, 238, 238);
+ metroProgressBar1.BorderColor = Color.FromArgb(238, 238, 238);
+ metroProgressBar1.DisabledBackColor = Color.FromArgb(238, 238, 238);
+ metroProgressBar1.DisabledBorderColor = Color.FromArgb(238, 238, 238);
+ metroProgressBar1.DisabledProgressColor = Color.FromArgb(120, 65, 177, 225);
+ metroProgressBar1.IsDerivedStyle = true;
+ metroProgressBar1.Location = new Point(252, 181);
+ metroProgressBar1.Maximum = 100;
+ metroProgressBar1.Minimum = 0;
+ metroProgressBar1.Name = "metroProgressBar1";
+ metroProgressBar1.Orientation = ReaLTaiizor.Enum.Metro.ProgressOrientation.Horizontal;
+ metroProgressBar1.ProgressColor = Color.FromArgb(65, 177, 225);
+ metroProgressBar1.Size = new Size(125, 23);
+ metroProgressBar1.Style = ReaLTaiizor.Enum.Metro.Style.Light;
+ metroProgressBar1.StyleManager = null;
+ metroProgressBar1.TabIndex = 4;
+ metroProgressBar1.Text = "metroProgressBar1";
+ metroProgressBar1.ThemeAuthor = "Taiizor";
+ metroProgressBar1.ThemeName = "MetroLight";
+ metroProgressBar1.Value = 0;
+ //
+ // DownloadProgressBar
+ //
+ DownloadProgressBar.Location = new Point(247, 124);
+ DownloadProgressBar.Name = "DownloadProgressBar";
+ DownloadProgressBar.Size = new Size(130, 23);
+ DownloadProgressBar.TabIndex = 3;
+ //
// btnStopLoadVideo
//
btnStopLoadVideo.Location = new Point(409, 54);
@@ -142,22 +686,19 @@
btnNVRLogin.UseVisualStyleBackColor = true;
btnNVRLogin.Click += btnNVRLogin_Click;
//
- // DownTimer
+ // DownloadProgressBarMain
//
- DownTimer.Tick += DownTimer_Tick;
- //
- // DownloadProgressBar
- //
- DownloadProgressBar.Location = new Point(247, 124);
- DownloadProgressBar.Name = "DownloadProgressBar";
- DownloadProgressBar.Size = new Size(130, 23);
- DownloadProgressBar.TabIndex = 3;
+ DownloadProgressBarMain.Location = new Point(1, 324);
+ DownloadProgressBarMain.Name = "DownloadProgressBarMain";
+ DownloadProgressBarMain.Size = new Size(862, 23);
+ DownloadProgressBarMain.TabIndex = 6;
//
// MainApp
//
AutoScaleDimensions = new SizeF(8F, 17F);
AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(1920, 1030);
+ Controls.Add(statusStrip1);
Controls.Add(materialTabControl1);
DrawerTabControl = materialTabControl1;
Font = new Font("Microsoft YaHei UI", 9F, FontStyle.Bold, GraphicsUnit.Point, 134);
@@ -168,12 +709,30 @@
WindowState = FormWindowState.Maximized;
Load += MainApp_Load;
materialTabControl1.ResumeLayout(false);
+ tabPage1.ResumeLayout(false);
+ materialCard4.ResumeLayout(false);
+ materialCard4.PerformLayout();
+ materialCard3.ResumeLayout(false);
+ materialCard3.PerformLayout();
+ materialCard2.ResumeLayout(false);
+ materialCard2.PerformLayout();
+ tabPage2.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)dataGridView1).EndInit();
+ materialCard1.ResumeLayout(false);
+ materialCard1.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)videoView1).EndInit();
tabPage3.ResumeLayout(false);
ResumeLayout(false);
+ PerformLayout();
}
#endregion
+
+ private StatusStrip statusStrip1;
+
private ImageList imageList1;
+
+
private ReaLTaiizor.Controls.MaterialTabControl materialTabControl1;
private TabPage tabPage1;
private TabPage tabPage2;
@@ -181,7 +740,49 @@
private Button btnNVRLogin;
private Button btnLoadVideo;
private Button btnStopLoadVideo;
- private System.Windows.Forms.Timer DownTimer;
private ProgressBar DownloadProgressBar;
+ private ReaLTaiizor.Controls.MetroProgressBar metroProgressBar1;
+ private LibVLCSharp.WinForms.VideoView videoView1;
+ private Button btnPlayHistoryVideo;
+ private ReaLTaiizor.Controls.MaterialCard materialCard1;
+ private ReaLTaiizor.Controls.PoisonDateTime PdtHistorySearchStart;
+ private Label label1;
+ private Button btnHistoryVideoSearch;
+ private Label label3;
+ private ReaLTaiizor.Controls.PoisonDateTime PdtHistorySearchEnd;
+ private Label label2;
+ private Label label4;
+ private TextBox txtSearchCode;
+ private DataGridView dataGridView1;
+ private Button btnStopHistoryPlay;
+ private ReaLTaiizor.Controls.MaterialCard materialCard2;
+ private Label label5;
+ private Label label6;
+ private TextBox txtRUInBagCode;
+ private Label label7;
+ private TextBox txtRURawName;
+ private ReaLTaiizor.Controls.MaterialCard materialCard3;
+ private Label label8;
+ private ReaLTaiizor.Controls.MaterialCard materialCard4;
+ private Label label9;
+ private TextBox txtIORawName;
+ private Label label10;
+ private TextBox txtIOOutBagCode;
+ private Label label11;
+ private Label label12;
+ private Label label13;
+ private TextBox txtInBoxCount;
+ private TextBox txtOutBoxCount;
+ private Label label14;
+ private TextBox txtRemainBoxCount;
+ private Label label15;
+ private Label label16;
+ private TextBox txtIOInBagCode;
+ private Label label18;
+ private TextBox txtIOOutputTime;
+ private Label label17;
+ private TextBox txtIOInputTime;
+ private Button btnTestAction;
+ private ProgressBar DownloadProgressBarMain;
}
}
\ No newline at end of file
diff --git a/FATrace.OEMApp/MainApp.cs b/FATrace.OEMApp/MainApp.cs
index 40e3d6f..df5aa45 100644
--- a/FATrace.OEMApp/MainApp.cs
+++ b/FATrace.OEMApp/MainApp.cs
@@ -1,24 +1,32 @@
+using FATrace.Com;
using FATrace.HKNetLib.Hardware;
using FATrace.HKNetLib.Wrapper;
+using FATrace.Model;
+using LibVLCSharp.Shared;
using ReaLTaiizor.Forms;
-using System;
-using System.Runtime.InteropServices;
+using System.ComponentModel;
namespace FATrace.OEMApp
{
public partial class MainApp : MaterialForm
{
-
///
/// 海康Camera 客户端
///
public HkCamera HkCameraClient { get; set; }
- ///
- /// 通道集合
- ///
- [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 96, ArraySubType = UnmanagedType.U4)]
- private int[] iChannelNum;
+ // 历史表列头中文映射
+ private readonly Dictionary _historyHeaderMap = new Dictionary
+ {
+ { nameof(VideoAction.Id), "编号" },
+ { nameof(VideoAction.Code), "条码" },
+ { nameof(VideoAction.User), "用户" },
+ { nameof(VideoAction.VideoFilePath), "视频路径" },
+ { nameof(VideoAction.VideoName), "视频名称" },
+ { nameof(VideoAction.StartTime), "开始时间" },
+ { nameof(VideoAction.EndTime), "结束时间" },
+ { nameof(VideoAction.CreateTime), "创建时间" }
+ };
public MainApp()
{
@@ -31,8 +39,20 @@ namespace FATrace.OEMApp
HkCameraClient = new HkCamera();
//保存SDK日志
CHCNetSDK.NET_DVR_SetLogToFile(3, "C:\\SdkLog\\", true);
- iChannelNum = new int[96];
+ //读取配置
+ //HkCameraClient.NVR_IP = ConfigHelper.GetValue("NVRIP");
+ //HkCameraClient.NVR_Port = ConfigHelper.GetValue("NVRPort");
+ //HkCameraClient.NVR_UserName = ConfigHelper.GetValue("NVRUserName");
+
+ HkCameraClient.NVRVideoSavePath = ConfigHelper.GetValue("NVRVideoSavePath");
+
+
+
+ InitMediaPlayer();
+ InitHistoryGridBinding();
+
+ //materialListView1.DataBindings
try
{
var systemName = Program.SystemName;
@@ -56,24 +76,43 @@ namespace FATrace.OEMApp
}
}
+ ///
+ /// 当前登录用户
+ ///
+ public string CurUserName { get; set; }
+
+ #region 视频处理变量
+
+ ///
+ /// 当前播放的视频
+ ///
+ public string CurrentVideoPath { get; set; }
+
+ #endregion
+
+
+ #region 内包信息
+
+ ///
+ /// 内包条码
+ ///
+ public string CurInBagCode { get; set; }
+
+ ///
+ /// 内包条码 原料名称
+ ///
+ public string CurInBagRawName { get; set; }
+
+ #endregion
+
private void btnNVRLogin_Click(object sender, EventArgs e)
{
- //var Result = HkCameraClient.Login(new CameraLoginInfo()
- //{
- // IP = "192.168.1.168",
- // Port = 8000,
- // UserName = "admin",
- // Password = "glico@2025",
- //});
+ HkCameraClient.NVR_IP = ConfigHelper.GetValue("NVRIP");
+ HkCameraClient.NVR_Port = ushort.Parse(ConfigHelper.GetValue("NVRPort"));
+ HkCameraClient.NVR_UserName = ConfigHelper.GetValue("NVRUserName");
+ HkCameraClient.NVR_Pw = ConfigHelper.GetValue("NVRPw");
- //if (Result)
- //{
- // MessageBox.Show("登录成功");
- // return;
- //}
- //MessageBox.Show("登录失败");
-
- var result = HkCameraClient.Sdk_NET_DVR_Login_V30("192.168.1.168", 8000, "admin", "glico@2025");
+ var result = HkCameraClient.Sdk_NET_DVR_Login_V30(HkCameraClient.NVR_IP, HkCameraClient.NVR_Port, HkCameraClient.NVR_UserName, HkCameraClient.NVR_Pw);
if (result)
{
MessageBox.Show("登录成功");
@@ -83,24 +122,35 @@ namespace FATrace.OEMApp
return;
}
+
private void btnLoadVideo_Click(object sender, EventArgs e)
{
+ CurrentVideoPath = NVRCom.GetVideoName(HkCameraClient.NVRVideoSavePath, "CODE");
- var Result = HkCameraClient.Sdk_NET_DVR_GetFileByTime_V40(DateTime.Now.AddMinutes(-5), DateTime.Now, $"D:\\Downtest_Channel{DateTime.Now.ToString("yyyy-MM-dd HHmmss")}.mp4");
+ var Result = HkCameraClient.Sdk_NET_DVR_GetFileByTime_V40(DateTime.Now.AddMinutes(-5), DateTime.Now, CurrentVideoPath);
if (Result.Result)
{
- DownTimer.Interval = 2000;
- DownTimer.Enabled = true;
+ HkCameraClient.NVRLoadVideoProcessEventHandler -= HkCameraClient_NVRLoadVideoProcessEventHandler;
+ HkCameraClient.NVRLoadVideoProcessEventHandler += HkCameraClient_NVRLoadVideoProcessEventHandler;
+ // 进度轮询已在库方法内部自动启动,这里无需再次调用
+ HkCameraClient.StartDownloadProgressMonitor();
}
else
{
MessageBox.Show($"[Sdk_NET_DVR_GetFileByTime_V40] 执行失败:{Result.Msg}");
}
-
//btnStopDownload.Enabled = true;
}
+ private void HkCameraClient_NVRLoadVideoProcessEventHandler(object? sender, short value)
+ {
+ this.BeginInvoke(new Action(() =>
+ {
+ DownloadProgressBarMain.Value = value;
+ }));
+ }
+
private void btnDownloadName_Click(object sender, EventArgs e)
{
//if (m_lDownHandle >= 0)
@@ -151,59 +201,266 @@ namespace FATrace.OEMApp
private void btnStopLoadVideo_Click(object sender, EventArgs e)
{
- //if (m_lDownHandle < 0)
- //{
- // return;
- //}
-
- //if (!CHCNetSDK.NET_DVR_StopGetFile(m_lDownHandle))
- //{
- // iLastErr = CHCNetSDK.NET_DVR_GetLastError();
- // str = "NET_DVR_StopGetFile failed, error code= " + iLastErr; //下载控制失败,输出错误号
- // MessageBox.Show(str);
- // return;
- //}
-
- //timerDownload.Stop();
-
- //MessageBox.Show("The downloading has been stopped succesfully!");
- //m_lDownHandle = -1;
- //DownloadProgressBar.Value = 0;
- //btnStopDownload.Enabled = true;
+ var Result = HkCameraClient.Sdk_NET_DVR_StopGetFile();
+ if (Result.Result)
+ {
+ MessageBox.Show($"[暂停成功] :{Result.Msg}");
+ }
+ else
+ {
+ MessageBox.Show($"[暂停失败] :{Result.Msg}");
+ }
}
- private void DownTimer_Tick(object sender, EventArgs e)
+ #region 视频播放
+
+ private LibVLC _libVLC;
+ private MediaPlayer _mediaPlayer;
+
+ ///
+ /// 初始化MediaPlay
+ ///
+ private void InitMediaPlayer()
{
- DownloadProgressBar.Maximum = 100;
- DownloadProgressBar.Minimum = 0;
+ _libVLC = new LibVLC();
+ _mediaPlayer = new MediaPlayer(_libVLC);
+ videoView1.MediaPlayer = _mediaPlayer;
- int iPos = 0;
+ }
- //获取下载进度
- iPos = HkCameraClient.Sdk_NET_DVR_GetDownloadPos(HkCameraClient.m_lDownHandle);
- if ((iPos > DownloadProgressBar.Minimum) && (iPos < DownloadProgressBar.Maximum))
+ #endregion
+
+ ///
+ /// 测试手动播放
+ ///
+ ///
+ ///
+ private void btnPlayHistoryVideo_Click(object sender, EventArgs e)
+ {
+ string path = "D:\\Downtest_Channel2025-09-12 102454.mp4";
+ _mediaPlayer.Play(new Media(_libVLC, path));
+ }
+
+ ///
+ /// 停止播放当前的视频文件
+ ///
+ ///
+ ///
+ private void btnStopHistoryPlay_Click(object sender, EventArgs e)
+ {
+ _mediaPlayer.Stop();
+ }
+
+ ///
+ /// 清理播放资源
+ ///
+ private void CleanMediaPlay()
+ {
+ _mediaPlayer.Stop();
+ _mediaPlayer.Dispose();
+ _libVLC.Dispose();
+ }
+
+
+ #region 历史数据查询
+
+
+
+ ///
+ /// 采用 BindingList + BindingSource,使数据变化自动触发 UI 刷新
+ ///
+ private BindingSource historyBindingSource { get; set; }
+ private BindingList historyVideoBindingList { get; set; }
+
+
+ ///
+ /// 初始化历史记录表格的数据绑定
+ ///
+ private void InitHistoryGridBinding()
+ {
+ historyBindingSource = new BindingSource();
+ historyVideoBindingList = new BindingList();
+ historyBindingSource.DataSource = historyVideoBindingList;
+ // 绑定到 WinForms 原生 DataGridView
+ dataGridView1.AutoGenerateColumns = true;
+ dataGridView1.DataSource = historyBindingSource;
+ // 绑定完成后统一调整列头与可见性
+ dataGridView1.DataBindingComplete -= DataGridView1_DataBindingComplete;
+ dataGridView1.DataBindingComplete += DataGridView1_DataBindingComplete;
+ // 双击行播放对应视频
+ dataGridView1.CellDoubleClick -= DataGridView1_CellDoubleClick;
+ dataGridView1.CellDoubleClick += DataGridView1_CellDoubleClick;
+ // 若此时已存在列,立即调整一次
+ ConfigureHistoryGridColumns();
+ }
+
+
+ private void btnHistoryVideoSearch_Click(object sender, EventArgs e)
+ {
+ var query = FSqlContext.FDb.Select();
+ if (!string.IsNullOrEmpty(txtSearchCode.Text.Trim()))
{
- DownloadProgressBar.Value = iPos;
+ query = query.Where(a => a.Code!.Contains(txtSearchCode.Text.Trim()));
}
+ query.Where(a => a.CreateTime >= PdtHistorySearchStart.Value && a.CreateTime <= PdtHistorySearchEnd.Value);
- if (iPos == 100) //下载完成
+ // 拉取结果并刷新绑定列表
+ var resultList = query.ToList();
+ // 暂停变更通知,批量更新提高效率
+ historyVideoBindingList.RaiseListChangedEvents = false;
+ historyVideoBindingList.Clear();
+ foreach (var item in resultList)
{
- DownloadProgressBar.Value = iPos;
- if (!CHCNetSDK.NET_DVR_StopGetFile(HkCameraClient.m_lDownHandle))
+ historyVideoBindingList.Add(item);
+ }
+ historyVideoBindingList.RaiseListChangedEvents = true;
+ // 通知 UI 刷新
+ historyVideoBindingList.ResetBindings();
+ }
+
+ // 与历史记录表格列配置相关的成员(WinForms DataGridView)
+ private void DataGridView1_DataBindingComplete(object? sender, DataGridViewBindingCompleteEventArgs e)
+ {
+ try
+ {
+ ConfigureHistoryGridColumns();
+ }
+ catch (Exception ex)
+ {
+ // 仅记录,不中断界面
+ System.Diagnostics.Debug.WriteLine($"[DataBindingComplete] 列配置失败: {ex.Message}");
+ }
+ }
+
+ ///
+ /// 双击行,播放该行对应的视频文件
+ ///
+ private void DataGridView1_CellDoubleClick(object? sender, DataGridViewCellEventArgs e)
+ {
+ if (e.RowIndex < 0) return; // 双击列头等
+ try
+ {
+ var row = dataGridView1.Rows[e.RowIndex];
+ if (row?.DataBoundItem is VideoAction va)
{
- MessageBox.Show($"[NET_DVR_StopGetFile] 执行失败:{HkCameraClient.GetLastError()}");
- return;
+ var path = va.VideoFilePath;
+ if (string.IsNullOrWhiteSpace(path))
+ {
+ MessageBox.Show("该记录没有可播放的视频路径。", "播放提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
+ return;
+ }
+ if (!File.Exists(path))
+ {
+ MessageBox.Show($"未找到视频文件:\n{path}", "播放失败", MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ return;
+ }
+
+ _mediaPlayer?.Stop();
+ _mediaPlayer?.Play(new LibVLCSharp.Shared.Media(_libVLC, path));
+ }
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show($"播放失败: {ex.Message}", "播放失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ }
+
+ ///
+ /// 按照 _historyHeaderMap 配置列头、隐藏不需要的列,并做常用格式化
+ ///
+ private void ConfigureHistoryGridColumns()
+ {
+ if (dataGridView1 == null || dataGridView1.Columns.Count == 0) return;
+
+ foreach (DataGridViewColumn col in dataGridView1.Columns)
+ {
+ var propName = col.DataPropertyName;
+
+ // 设置列头中文
+ if (!string.IsNullOrWhiteSpace(propName) && _historyHeaderMap.TryGetValue(propName, out var headerText))
+ {
+ col.HeaderText = headerText;
+ }
+
+ // 隐藏 Id 列
+ if (propName == nameof(VideoAction.Id))
+ {
+ col.Visible = false;
+ continue;
+ }
+
+ //// 常用列宽与格式
+ //if (propName is nameof(VideoAction.Code))
+ //{
+ // col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
+ //}
+ //else if (propName is nameof(VideoAction.VideoFilePath))
+ //{
+ // col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
+ //}
+
+ // 时间列格式化
+ if (propName is nameof(VideoAction.StartTime) or nameof(VideoAction.EndTime) or nameof(VideoAction.CreateTime))
+ {
+ col.DefaultCellStyle.Format = "yyyy-MM-dd HH:mm:ss";
+ col.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
}
- HkCameraClient.m_lDownHandle = -1;
- DownTimer.Stop();
}
- if (iPos == 200) //网络异常,下载失败
+ // 选中整行,易于操作
+ dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
+ dataGridView1.MultiSelect = false;
+ dataGridView1.ReadOnly = true;
+ dataGridView1.AllowUserToAddRows = false;
+ }
+
+
+ #endregion
+
+
+ ///
+ /// 操作结束
+ ///
+ ///
+ ///
+ private void btnTestAction_Click(object sender, EventArgs e)
+ {
+ var Result = HkCameraClient.Sdk_NET_DVR_GetFileByTime_V40(DateTime.Now.AddMinutes(-5), DateTime.Now, NVRCom.GetVideoName(HkCameraClient.NVRVideoSavePath, "cODE"));
+ if (Result.Result)
{
- MessageBox.Show("The downloading is abnormal for the abnormal network!");
- DownTimer.Stop();
+ HkCameraClient.NVRLoadVideoProcessEventHandler -= HkCameraClient_NVRLoadVideoProcessEventHandler;
+ HkCameraClient.NVRLoadVideoProcessEventHandler += HkCameraClient_NVRLoadVideoProcessEventHandler;
+
+ HkCameraClient.NVRLoadVideoCompleteEventHandler -= HkCameraClient_NVRLoadVideoCompleteEventHandler;
+ HkCameraClient.NVRLoadVideoCompleteEventHandler += HkCameraClient_NVRLoadVideoCompleteEventHandler;
+
+ // 进度轮询已在库方法内部自动启动,这里无需再次调用
}
+ else
+ {
+ MessageBox.Show($"[Sdk_NET_DVR_GetFileByTime_V40] 执行失败:{Result.Msg}");
+ }
+ }
+
+ ///
+ /// Handles the event triggered when the NVR (Network Video Recorder) completes loading a video.
+ /// Video下载完成
+ ///
+ /// The source of the event. This can be if the event is not raised by a specific object.
+ /// A string containing information about the completed video load operation.
+ private void HkCameraClient_NVRLoadVideoCompleteEventHandler(object? sender, string e)
+ {
+ //先保存当前的信息
+ var returnValues = FSqlContext.FDb.Insert(new OEMRawUse()
+ {
+ InBagCode=CurInBagCode,
+ RawName=CurInBagRawName,
+ User= CurUserName,
+ UrlState=false,
+ VideoUrl="",//暂时无法获取URL,因为服务器还没有扫描到文件信息
+ }).ExecuteInserted();
+
}
}
}
diff --git a/FATrace.OEMApp/MainApp.resx b/FATrace.OEMApp/MainApp.resx
index 57a94aa..f3c7b73 100644
--- a/FATrace.OEMApp/MainApp.resx
+++ b/FATrace.OEMApp/MainApp.resx
@@ -117,6 +117,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ 134, 17
+
17, 17
@@ -124,8 +127,8 @@
AAEAAAD/////AQAAAAAAAAAMAgAAAEZTeXN0ZW0uV2luZG93cy5Gb3JtcywgQ3VsdHVyZT1uZXV0cmFs
LCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5BQEAAAAmU3lzdGVtLldpbmRvd3MuRm9ybXMu
- SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAfCEAAAJNU0Z0AUkBTAIBAQgB
- AAF4AQABeAEAARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAATADAAEBAQABIAYAATD/
+ SW1hZ2VMaXN0U3RyZWFtZXIBAAAABERhdGEHAgIAAAAJAwAAAA8DAAAAaiEAAAJNU0Z0AUkBTAIBAQgB
+ AAEwAQEBMAEBARABAAEQAQAE/wEhAQAI/wFCAU0BNgcAATYDAAEoAwABQAMAATADAAEBAQABIAYAATD/
AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AP8A/wD/AFIAAdsBlgESAf8B2wGWARIB/wQAAxIBGANJAYgB
2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsB
lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8UAAHbAZYB
@@ -159,120 +162,117 @@
+QH/AgAC/wP1Af8CAAL/AgAC/wIAAv8CAAL/AgAC/wIAAv8CxwH2Af8D9QH/AgAC/wIAAfwB/wJoAe4B
/wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AlEBUAGfBAABkgF2AUQB8wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8B2wGWARIB/ywAAdsBlgESAf8B2wGWARIB
- /wNGAX8CAgFMAf8CAgHoAf8CAAHwAf8CiQH0Af8D9QH/AgAB9QH/AgAB9QH/A/UB/wIAAfUB/wIAAfUB
- /wP1Af8CAAH1Af8CAAHwAf8CBgHrAf8CYgHqAf8DKgFAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8DSQGIBAADBgEIAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/1AAAdsB
- lgESAf8B2wGWARIB/ywAAdsBlgESAf8B2wGWARIB/wNGAX8CAgFAAf8CIAHdAf8CCgHgAf8CAwHhAf8D
- 9QH/AgMB4QH/AgMB4QH/A/UB/wIDAeEB/wP1Af8D9QH/AgMB4QH/AiAB5AH/AiAB3QH/AlsB5AH/BAAD
- CQEMAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/DAADDAEQAdsBlgESAf8B2wGWARIB/wFpAWMBWgHfFAAB
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8DKAE8BAADUgGgAdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/wHbAZYB
- EgH/KAADHQEoAdsBlgESAf8B2wGWARIB/wNGAX8CAgE0Af8COAHUAf8COAHYAf8COAHbAf8CAwHRAf8D
- 9QH/AgMB0QH/A/UB/wIDAdEB/wP1Af8CDQHSAf8COAHbAf8COAHYAf8COAHUAf8CVAHeAf8IAAHbAZYB
- EgH/AdsBlgESAf8UAAHbAZYBEgH/AdsBlgESAf8UAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/CAAB2wGWARIB/wHbAZYBEgH/DAAB2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8MAAHbAZYBEgH/AdsBlgESAf8EAANGAX8CAgEpAf8CUQHNAf8CTwHUAf8C
- TwHVAf8CTwHVAf8D9QH/Ao0B4QH/Ak8B1QH/A/UB/wP1Af8CTwHVAf8CTwHVAf8CTwHUAf8CUQHNAf8C
- TAHXAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/DAAB2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8CXwFcAcgIAAHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAADRgF/AgEBHgH/AmgBzAH/AmgB0QH/AmgB
- 0gH/AmgB0gH/AmgB0gH/A/UB/wJoAdIB/wP1Af8CaAHSAf8CaAHSAf8CaAHSAf8CaAHRAf8CaAHMAf8C
- QwHKAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8DUgGgDAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wwAAdsBlgESAf8MAAHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wwAAdsBlgESAf8IAANGAX8CAQEUAf8CgAHOAf8CgAHRAf8CgAHSAf8CgAHSAf8C
- gAHSAf8D9QH/A/UB/wKAAdIB/wKAAdIB/wKAAdIB/wKAAdIB/wKAAdEB/wKAAc4B/wI5AboB/wQAAdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ lgESAf8B2wGWARIB/wHbAZYBEgH/AlEBUAGfBAACbwFgAfMB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8sAAHbAZYBEgH/AdsBlgESAf8D
+ RgF/AgIBTAH/AgIB6AH/AgAB8AH/AokB9AH/A/UB/wIAAfUB/wIAAfUB/wP1Af8CAAH1Af8CAAH1Af8D
+ 9QH/AgAB9QH/AgAB8AH/AgYB6wH/AmIB6gH/AyoBQAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/A0kBiAQAAwYBCAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf9QAAHbAZYB
+ EgH/AdsBlgESAf8sAAHbAZYBEgH/AdsBlgESAf8DRgF/AgIBQAH/AiAB3QH/AgoB4AH/AgMB4QH/A/UB
+ /wIDAeEB/wIDAeEB/wP1Af8CAwHhAf8D9QH/A/UB/wIDAeEB/wIgAeQB/wIgAd0B/wJbAeQB/wQAAwkB
+ DAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wwAAwwBEAHbAZYBEgH/AdsBlgESAf8CYwFdAd8UAAHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wMoATwEAANSAaAB2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8o
+ AAMdASgB2wGWARIB/wHbAZYBEgH/A0YBfwICATQB/wI4AdQB/wI4AdgB/wI4AdsB/wIDAdEB/wP1Af8C
+ AwHRAf8D9QH/AgMB0QH/A/UB/wINAdIB/wI4AdsB/wI4AdgB/wI4AdQB/wJUAd4B/wgAAdsBlgESAf8B
+ 2wGWARIB/xQAAdsBlgESAf8B2wGWARIB/xQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8cAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xgAAyoB
- PwIEAU8B/wKWAb8B/wKXAdYB/wKXAdYB/wKXAdYB/wKXAdYB/wKXAdYB/wP1Af8ClwHWAf8ClwHWAf8C
- lwHWAf8ClwHWAf8ClwHWAf8ClwHTAf8CCgF3Af8IAAMyAU8EAANaAb8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8DWgG/HAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8MAAHbAZYBEgH/AdsB
+ lgESAf8B2wGWARIB/wwAAdsBlgESAf8B2wGWARIB/wQAA0YBfwICASkB/wJRAc0B/wJPAdQB/wJPAdUB
+ /wJPAdUB/wP1Af8CjQHhAf8CTwHVAf8D9QH/A/UB/wJPAdUB/wJPAdUB/wJPAdQB/wJRAc0B/wJMAdcB
+ /wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8MAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/EAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/HAACCAFoAf8CVwFpAf8CrgHGAf8C
- rwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8CrwHeAf8C
- CAF1Af8CCgFuAf8UAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/yAAA1gBuAHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/HAADIQEvAggBZgH/AggBawH/AggBbgH/AggBbgH/AggBbgH/AggBbgH/AggBbgH/AggBbgH/AggB
- bgH/AggBbgH/AggBbgH/AggBagH/AhABfgH/GAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8kAAJaAVgB
- twHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8MAAHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8DSQGHHAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8kAAMqAT8D
- RgF/A0YBfwNGAX8DRgF/A0YBfwNGAX8DRgF/A0YBfwNGAX9oAAJiAV0B3AHbAZYBEgH/AdsBlgESAf8D
- PQFoJAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8MAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xgAAwwB
- EAJHAUYBgAMtAUQUAAM6AWADOgFgbAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/HAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/GAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/CAACWwFZAcAB
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/EAACWwFZAcAB2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8D
- KgFAGAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8YAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf8BqQF9ATUB+BAAAaUBhQE3AfcB2wGWARIB/wwAAzMBUAHbAZYBEgH/BAAB
- 2wGWARIB/xAAAdsBlgESAf8QAAJbAVkBwCAAAkcBRgGAAyoBQBQAAdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8MAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsB
- lgESAf8UAAHbAZYBEgH/BAAB2wGWARIB/xAAAdsBlgESAf8QAAJbAVkBwCAAAkcBRgGAAyoBQBAAAdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8QAAMSARgB
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/xQAAdsBlgESAf8E
- AAHbAZYBEgH/EAAB2wGWARIB/xAAAlsBWQHACAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/BAACRwFGAYADKgFAEAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xQAAz0B
- aAHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AzoBYAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/GAADGAEgAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/EAAB2wGWARIB
- /wQAAdsBlgESAf8QAAHbAZYBEgH/EAACWwFZAcAgAAJHAUYBgAMqAUAQAAHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/ygAAdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB
- /wHbAZYBEgH/DAABdAFsAVcB5wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8E
- AAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8UAAJbAVkBwAgAAdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AkcBRgGAAyoBQBAAAdsBlgESAf8B
- kwGAAUEB9ygAAdsBlgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/HAAB2wGWARIB
- /wHbAZYBEgH/AdsBlgESAf9QAAJbAVkBwCAAAkcBRgGAAyoBQBAAAdsBlgESAf8oAAHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/HAAB2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8MAAJBAUABcAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8UAAJbAVkBwAgAAlsBWQHAAlsBWQHAAlsB
- WQHADAACRwFGAYADKgFAGAAB2wGWARIB/wHbAZYBEgH/GAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8cAAHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/CAAB2wGWARIB/xAAAdsBlgESAf8EAAHbAZYBEgH/DAADKgFAAdsBlgESAf8Q
- AAJbAVkBwAgAAzoBYAM6AWADOgFgDAACRwFGAYADKgFAFAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8DDAEQAwYBCAHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8UAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8EAAHbAZYBEgH/FAAB2wGWARIB/wQAAdsBlgESAf8QAAHbAZYBEgH/EAACWwFZAcAg
- AAJHAUYBgAMqAUAUAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ lgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wJfAVwByAgAAdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/CAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAANGAX8CAQEeAf8CaAHMAf8CaAHRAf8CaAHSAf8C
+ aAHSAf8CaAHSAf8D9QH/AmgB0gH/A/UB/wJoAdIB/wJoAdIB/wJoAdIB/wJoAdEB/wJoAcwB/wJDAcoB
+ /wQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wNSAaAMAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/DAAB2wGWARIB/wwAAdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/DAAB2wGWARIB/wgAA0YBfwIBARQB/wKAAc4B/wKAAdEB/wKAAdIB/wKAAdIB/wKAAdIB
+ /wP1Af8D9QH/AoAB0gH/AoAB0gH/AoAB0gH/AoAB0gH/AoAB0QH/AoABzgH/AjkBugH/BAAB2wGWARIB
/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8UAAHbAZYBEgH/BAAB
- 2wGWARIB/xAAAdsBlgESAf8QAAJbAVkBwAJpAV0B6AMYASADGAEgAxgBIAMYASADGAEgAxgBIAMYASAB
- 2wGWARIB/wMqAUAYAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/A1YBsAgAAdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/GAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8QAAHbAZYBEgH/AdsBlgESAf8QAAHbAZYBEgH/BAAB
- 2wGWARIB/xAAAdsBlgESAf8UAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
- 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/yAAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
- lgESAf8B2wGWARIB/ygAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/xgAAdsBlgESAf8B2wGWARIB/wMqAUAB2wGWARIB/wHbAZYBEgH/CAAB
- 2wGWARIB/wHbAZYBEgH/AWQBYQFbAdgCWwFZAcAB2wGWARIB/wHbAZYBEgH/YAAB2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8B2wGWARIB/yQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/DAAB2wGWARIB/wHbAZYB
- EgH/AdsBlgESAf8YAAJHAUYBgAFpAWMBWgHfAlgBVgGzFAABaQFjAVoB3wFpAWMBWgHfAwYBCKAAAxgB
- IAwAAlEBUAGfVAABQgFNAT4HAAE+AwABKAMAAUADAAEwAwABAQEAAQEFAAGAAQEWAAP/gQAB/wHyAQAB
- gAH4AQ8BwAEBAf8BwAEAAYAB4AEDAYABAAH/AewBAAGAAcMB4wGAAQAB+AHMAQABgAHPAfkCAAH4AcAB
- AAGAAY8B+QIAAdABQwEAAYABnwH8AgABgAEPAoABnwH8AgABAgEHAv8BnwH8AgABhwEPAoABnwH4AgAB
- zwGfAQABgAHOATkCAAGHAQ8BAAGAAcYBMQIAAYIBBwEAAYAB7gE7AgABgAEPAQABgAH+AT8CAAHQAX8B
- AAGAAf4BPwGAAQAB+AH/AQABgAH+AT8BgAEBAfgB/wGBAcAB/gE/AeABBwL/Af4BHwHxAccB4wHnA/8B
- BwHwAQ8BwQGBAeABAwHxAYMB8AEHAZwBvQHvAfMB4QHBAYABAAG+Ab0B7wHzAcEB4QGDAcABvgG9AewB
- EwHDAeIBBwHgAd4BvQHvAfMBxwH+AccB8QHAAYMB7AEDAc8B/AHHAfEC/wHvAfMB3wH4AccB8QHAAYMB
- 7AFzAfMB8AGHAfAB3gG5AewBcwHhAeABAwHgAb4BvQHvAfMB4AHBAYABAAG+Ab0B4AEDAfABYwHwAQcB
- ngG9AfABBwH4AT8B8AEPAcEBgQL/Af4BHwHxAccC4wT/Af0B3wL/Cw==
+ lgESAf8B2wGWARIB/wHbAZYBEgH/EAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/GAADKgE/AgQB
+ TwH/ApYBvwH/ApcB1gH/ApcB1gH/ApcB1gH/ApcB1gH/ApcB1gH/A/UB/wKXAdYB/wKXAdYB/wKXAdYB
+ /wKXAdYB/wKXAdYB/wKXAdMB/wIKAXcB/wgAAzIBTwQAA1oBvwHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wNaAb8cAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/HAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8cAAIIAWgB/wJXAWkB/wKuAcYB/wKvAd4B
+ /wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wKvAd4B/wIIAXUB
+ /wIKAW4B/xQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/IAADWAG4AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8EAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/HAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8c
+ AAMhAS8CCAFmAf8CCAFrAf8CCAFuAf8CCAFuAf8CCAFuAf8CCAFuAf8CCAFuAf8CCAFuAf8CCAFuAf8C
+ CAFuAf8CCAFuAf8CCAFqAf8CEAF+Af8YAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/yQAAloBWAG3AdsB
+ lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wwAAdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wNJAYccAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/yQAAyoBPwNGAX8D
+ RgF/A0YBfwNGAX8DRgF/A0YBfwNGAX8DRgF/A0YBf2gAAmIBXQHcAdsBlgESAf8B2wGWARIB/wM9AWgk
+ AAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wwAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/GAADDAEQAkcB
+ RgGAAy0BRBQAAzoBYAM6AWBsAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8c
+ AAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8YAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAJbAVkBwAHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8QAAJbAVkBwAHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wMqAUAY
+ AAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/xgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8B2wGWARIB/wJ8AVMB+BAAAXkBbwFRAfcB2wGWARIB/wwAAzMBUAHbAZYBEgH/BAAB2wGWARIB
+ /xAAAdsBlgESAf8QAAJbAVkBwCAAAkcBRgGAAyoBQBQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8MAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsB
+ lgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8U
+ AAHbAZYBEgH/BAAB2wGWARIB/xAAAdsBlgESAf8QAAJbAVkBwCAAAkcBRgGAAyoBQBAAAdsBlgESAf8B
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8QAAMSARgB2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/xQAAdsBlgESAf8EAAHbAZYB
+ EgH/EAAB2wGWARIB/xAAAlsBWQHACAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/BAACRwFGAYADKgFAEAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xQAAz0BaAHbAZYB
+ EgH/AdsBlgESAf8EAAHbAZYBEgH/AzoBYAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/GAAD
+ GAEgAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/EAAB2wGWARIB/wQAAdsB
+ lgESAf8QAAHbAZYBEgH/EAACWwFZAcAgAAJHAUYBgAMqAUAQAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /ygAAdsBlgESAf8IAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/DAACZQFcAecB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/FAACWwFZAcAIAAHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wJHAUYBgAMqAUAQAAHbAZYBEgH/Am8BUQH3KAAB
+ 2wGWARIB/wHbAZYBEgH/CAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8cAAHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/1AAAlsBWQHAIAACRwFGAYADKgFAEAAB2wGWARIB/ygAAdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/CAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8cAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wwAAkEB
+ QAFwAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wQAAdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xQAAlsBWQHACAACWwFZAcACWwFZAcACWwFZAcAMAAJHAUYB
+ gAMqAUAYAAHbAZYBEgH/AdsBlgESAf8YAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/xwAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8IAAHbAZYBEgH/EAAB2wGWARIB/wQAAdsBlgESAf8MAAMqAUAB2wGWARIB/xAAAlsBWQHACAAD
+ OgFgAzoBYAM6AWAMAAJHAUYBgAMqAUAUAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/EAAB
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wMMARADBgEIAdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/xQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wQAAdsBlgESAf8UAAHbAZYBEgH/BAAB2wGWARIB/xAAAdsBlgESAf8QAAJbAVkBwCAAAkcBRgGAAyoB
+ QBQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/BAAB2wGWARIB/xQAAdsBlgESAf8EAAHbAZYBEgH/EAAB
+ 2wGWARIB/xAAAlsBWQHAAmkBYAHoAxgBIAMYASADGAEgAxgBIAMYASADGAEgAxgBIAHbAZYBEgH/AyoB
+ QBgAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8DVgGwCAAB2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8YAAHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/AdsBlgESAf8B2wGWARIB/xAAAdsBlgESAf8B2wGWARIB/xAAAdsBlgESAf8EAAHbAZYBEgH/EAAB
+ 2wGWARIB/xQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsB
+ lgESAf8B2wGWARIB/wHbAZYBEgH/IAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYB
+ EgH/KAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B2wGWARIB
+ /wHbAZYBEgH/GAAB2wGWARIB/wHbAZYBEgH/AyoBQAHbAZYBEgH/AdsBlgESAf8IAAHbAZYBEgH/AdsB
+ lgESAf8CXwFbAdgCWwFZAcAB2wGWARIB/wHbAZYBEgH/YAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8B
+ 2wGWARIB/yQAAdsBlgESAf8B2wGWARIB/wHbAZYBEgH/DAAB2wGWARIB/wHbAZYBEgH/AdsBlgESAf8Y
+ AAJHAUYBgAJjAV0B3wJYAVYBsxQAAmMBXQHfAmMBXQHfAwYBCKAAAxgBIAwAAlEBUAGfVAABQgFNAT4H
+ AAE+AwABKAMAAUADAAEwAwABAQEAAQEFAAGAAQEWAAP/gQAB/wHyAQABgAH4AQ8BwAEBAf8BwAEAAYAB
+ 4AEDAYABAAH/AewBAAGAAcMB4wGAAQAB+AHMAQABgAHPAfkCAAH4AcABAAGAAY8B+QIAAdABQwEAAYAB
+ nwH8AgABgAEPAoABnwH8AgABAgEHAv8BnwH8AgABhwEPAoABnwH4AgABzwGfAQABgAHOATkCAAGHAQ8B
+ AAGAAcYBMQIAAYIBBwEAAYAB7gE7AgABgAEPAQABgAH+AT8CAAHQAX8BAAGAAf4BPwGAAQAB+AH/AQAB
+ gAH+AT8BgAEBAfgB/wGBAcAB/gE/AeABBwL/Af4BHwHxAccB4wHnA/8BBwHwAQ8BwQGBAeABAwHxAYMB
+ 8AEHAZwBvQHvAfMB4QHBAYABAAG+Ab0B7wHzAcEB4QGDAcABvgG9AewBEwHDAeIBBwHgAd4BvQHvAfMB
+ xwH+AccB8QHAAYMB7AEDAc8B/AHHAfEC/wHvAfMB3wH4AccB8QHAAYMB7AFzAfMB8AGHAfAB3gG5AewB
+ cwHhAeABAwHgAb4BvQHvAfMB4AHBAYABAAG+Ab0B4AEDAfABYwHwAQcBngG9AfABBwH4AT8B8AEPAcEB
+ gQL/Af4BHwHxAccC4wT/Af0B3wL/Cw==
-
- 134, 17
-
diff --git a/FATrace.OEMApp/Model/Jellyfin/JellyfinModels.cs b/FATrace.OEMApp/Model/Jellyfin/JellyfinModels.cs
new file mode 100644
index 0000000..72d6a19
--- /dev/null
+++ b/FATrace.OEMApp/Model/Jellyfin/JellyfinModels.cs
@@ -0,0 +1,65 @@
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+
+namespace FATrace.OEMApp.Model.Jellyfin
+{
+ ///
+ /// Jellyfin /Items 接口响应模型
+ ///
+ public sealed class JellyfinItemsResponse
+ {
+ ///
+ /// 返回的项目集合
+ ///
+ [JsonPropertyName("Items")]
+ public List Items { get; set; } = new();
+
+ ///
+ /// 记录总数
+ ///
+ [JsonPropertyName("TotalRecordCount")]
+ public int TotalRecordCount { get; set; }
+
+ ///
+ /// 起始索引
+ ///
+ [JsonPropertyName("StartIndex")]
+ public int StartIndex { get; set; }
+ }
+
+ ///
+ /// Jellyfin 媒体条目最小字段模型
+ ///
+ public sealed class JellyfinItem
+ {
+ ///
+ /// 名称
+ ///
+ [JsonPropertyName("Name")]
+ public string? Name { get; set; }
+
+ ///
+ /// 服务器 ID
+ ///
+ [JsonPropertyName("ServerId")]
+ public string? ServerId { get; set; }
+
+ ///
+ /// 项目 ID
+ ///
+ [JsonPropertyName("Id")]
+ public string? Id { get; set; }
+
+ ///
+ /// 频道 ID(可能为 null)
+ ///
+ [JsonPropertyName("ChannelId")]
+ public string? ChannelId { get; set; }
+
+ ///
+ /// 类型,如 Movie、Series
+ ///
+ [JsonPropertyName("Type")]
+ public string? Type { get; set; }
+ }
+}
diff --git a/FATrace.OEMApp/Services/JellyfinClient.cs b/FATrace.OEMApp/Services/JellyfinClient.cs
new file mode 100644
index 0000000..880a882
--- /dev/null
+++ b/FATrace.OEMApp/Services/JellyfinClient.cs
@@ -0,0 +1,245 @@
+using System;
+using System.Diagnostics;
+using System.Net;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using FATrace.OEMApp.Model.Jellyfin;
+using NLog;
+using RestSharp;
+
+namespace FATrace.OEMApp.Services
+{
+ ///
+ /// Jellyfin 客户端配置选项
+ ///
+ public sealed class JellyfinClientOptions
+ {
+ ///
+ /// Jellyfin 基础地址,例如:http://192.168.0.30:8096
+ ///
+ public required string BaseUrl { get; init; }
+
+ ///
+ /// API 密钥(建议使用 Jellyfin 后台创建的密钥)。
+ ///
+ public required string ApiKey { get; init; }
+
+ ///
+ /// 超时时间,毫秒。默认 10000 毫秒。
+ ///
+ public int TimeoutMs { get; init; } = 10000;
+
+ ///
+ /// 是否将 api_key 作为查询参数传递。默认 true。
+ /// 若为 false,则通过请求头 X-Emby-Token 传递。
+ ///
+ public bool UseQueryApiKey { get; init; } = true;
+
+ ///
+ /// 自定义 User-Agent。若为空将使用默认。
+ ///
+ public string? UserAgent { get; init; }
+ }
+
+ ///
+ /// Jellyfin HTTP 异常
+ ///
+ public sealed class JellyfinHttpException : Exception
+ {
+ public HttpStatusCode StatusCode { get; }
+ public string? ResponseContent { get; }
+
+ public JellyfinHttpException(string message, HttpStatusCode statusCode, string? content, Exception? inner = null)
+ : base(message, inner)
+ {
+ StatusCode = statusCode;
+ ResponseContent = content;
+ }
+ }
+
+ ///
+ /// Jellyfin API 客户端封装(基于 RestSharp)
+ ///
+ public sealed class JellyfinClient : IJellyfinClient, IDisposable
+ {
+ private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
+
+ private readonly RestClient _client;
+ private readonly JellyfinClientOptions _options;
+ private readonly JsonSerializerOptions _jsonOptions = new()
+ {
+ PropertyNameCaseInsensitive = true
+ };
+
+ public JellyfinClient(JellyfinClientOptions options)
+ {
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ if (string.IsNullOrWhiteSpace(_options.BaseUrl))
+ throw new ArgumentException("BaseUrl 不能为空", nameof(options));
+ if (string.IsNullOrWhiteSpace(_options.ApiKey))
+ throw new ArgumentException("ApiKey 不能为空", nameof(options));
+
+ if (!Uri.TryCreate(_options.BaseUrl, UriKind.Absolute, out var baseUri))
+ {
+ throw new ArgumentException($"无效的 BaseUrl: {_options.BaseUrl}", nameof(options));
+ }
+
+ var restOptions = new RestClientOptions(baseUri)
+ {
+ MaxTimeout = _options.TimeoutMs,
+ ThrowOnAnyError = false,
+ // UseUnsafeSerializer = false // 保持默认 System.Text.Json
+ };
+
+ _client = new RestClient(restOptions);
+
+ // 默认头
+ _client.AddDefaultHeader("Accept", "application/json");
+ _client.AddDefaultHeader("Accept-Charset", "utf-8");
+ if (!string.IsNullOrWhiteSpace(_options.UserAgent))
+ {
+ _client.AddDefaultHeader("User-Agent", _options.UserAgent);
+ }
+
+ // 通过 Header 传递 Token(若未使用 Query)
+ if (!_options.UseQueryApiKey)
+ {
+ _client.AddDefaultHeader("X-Emby-Token", _options.ApiKey);
+ }
+ }
+
+ ///
+ /// 获取 Jellyfin Items 列表。
+ ///
+ /// 父级目录/库 ID
+ /// 排序字段(默认 DateCreated)
+ /// 排序方向(Ascending/Descending,默认 Descending)
+ /// 限制返回数量,默认 10
+ /// 包含的类型(例如 Movie, Series),默认 Movie
+ /// 取消令牌
+ public async Task GetItemsAsync(
+ string parentId,
+ string sortBy = "DateCreated",
+ string sortOrder = "Descending",
+ int? limit = 10,
+ string includeItemTypes = "Movie",
+ CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(parentId))
+ throw new ArgumentException("parentId 不能为空", nameof(parentId));
+
+ var request = new RestRequest("Items", Method.Get);
+ request.AddQueryParameter("ParentId", parentId);
+ if (!string.IsNullOrWhiteSpace(sortBy)) request.AddQueryParameter("SortBy", sortBy);
+ if (!string.IsNullOrWhiteSpace(sortOrder)) request.AddQueryParameter("SortOrder", sortOrder);
+ if (limit.HasValue && limit.Value > 0) request.AddQueryParameter("Limit", limit.Value.ToString());
+ if (!string.IsNullOrWhiteSpace(includeItemTypes)) request.AddQueryParameter("IncludeItemTypes", includeItemTypes);
+
+ if (_options.UseQueryApiKey)
+ {
+ request.AddQueryParameter("api_key", _options.ApiKey);
+ }
+
+ return await ExecuteAndDeserializeAsync(request, cancellationToken).ConfigureAwait(false);
+ }
+
+ ///
+ /// 仅返回 Items 列表的便捷方法。
+ ///
+ public async Task> GetItemsOnlyAsync(
+ string parentId,
+ string sortBy = "DateCreated",
+ string sortOrder = "Descending",
+ int? limit = 10,
+ string includeItemTypes = "Movie",
+ CancellationToken cancellationToken = default)
+ {
+ var resp = await GetItemsAsync(parentId, sortBy, sortOrder, limit, includeItemTypes, cancellationToken).ConfigureAwait(false);
+ return resp.Items ?? new System.Collections.Generic.List();
+ }
+
+ private async Task ExecuteAndDeserializeAsync(RestRequest request, CancellationToken ct)
+ {
+ var sw = Stopwatch.StartNew();
+ try
+ {
+ Logger.Info("Jellyfin 请求: {Method} {Resource}", request.Method, request.Resource);
+
+ var response = await _client.ExecuteAsync(request, ct).ConfigureAwait(false);
+ sw.Stop();
+
+ if (!response.IsSuccessful)
+ {
+ Logger.Warn("Jellyfin 响应失败: Status={StatusCode}, Elapsed={Elapsed}ms, ContentLength={Length}",
+ (int)response.StatusCode, sw.ElapsedMilliseconds, response.Content?.Length ?? 0);
+
+ throw new JellyfinHttpException(
+ $"请求失败,HTTP {(int)response.StatusCode} {response.StatusDescription}",
+ response.StatusCode,
+ response.Content,
+ response.ErrorException);
+ }
+
+ if (string.IsNullOrWhiteSpace(response.Content))
+ {
+ throw new JellyfinHttpException("响应内容为空", response.StatusCode, null);
+ }
+
+ var result = JsonSerializer.Deserialize(response.Content, _jsonOptions);
+ if (result == null)
+ {
+ throw new JellyfinHttpException("响应反序列化失败,返回结果为 null", response.StatusCode, response.Content);
+ }
+
+ Logger.Debug("Jellyfin 调用成功: {Method} {Resource}, Elapsed={Elapsed}ms", request.Method, request.Resource, sw.ElapsedMilliseconds);
+ return result;
+ }
+ catch (OperationCanceledException)
+ {
+ sw.Stop();
+ Logger.Warn("Jellyfin 请求被取消: {Resource}, Elapsed={Elapsed}ms", request.Resource, sw.ElapsedMilliseconds);
+ throw;
+ }
+ catch (JellyfinHttpException)
+ {
+ // 已包含上下文,直接抛出
+ throw;
+ }
+ catch (Exception ex)
+ {
+ sw.Stop();
+ Logger.Error(ex, "Jellyfin 请求异常: {Resource}, Elapsed={Elapsed}ms", request.Resource, sw.ElapsedMilliseconds);
+ throw new JellyfinHttpException("请求执行异常", HttpStatusCode.InternalServerError, null, ex);
+ }
+ }
+
+ public void Dispose()
+ {
+ // RestClient 在新版本基于 HttpClient,通常无需显式释放。
+ // 如需自定义 HttpMessageHandler,可在此释放。
+ }
+ }
+
+ ///
+ /// Jellyfin 客户端接口,便于后续依赖注入与单元测试。
+ ///
+ public interface IJellyfinClient
+ {
+ Task GetItemsAsync(
+ string parentId,
+ string sortBy = "DateCreated",
+ string sortOrder = "Descending",
+ int? limit = 10,
+ string includeItemTypes = "Movie",
+ CancellationToken cancellationToken = default);
+
+ Task> GetItemsOnlyAsync(
+ string parentId,
+ string sortBy = "DateCreated",
+ string sortOrder = "Descending",
+ int? limit = 10,
+ string includeItemTypes = "Movie",
+ CancellationToken cancellationToken = default);
+ }
+}