From 203b764bf299860c7ec6cc47d568d2c3d20c9510 Mon Sep 17 00:00:00 2001
From: liufei <296528480@qq.com>
Date: Sun, 10 Oct 2021 16:08:01 +0800
Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8D=B0=E6=9C=8D=E5=8A=A1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.gitignore | 116 +++++++++++
POSCorePrint.sln | 25 +++
POSCorePrint/Constant.cs | 19 ++
POSCorePrint/Content.cs | 55 +++++
POSCorePrint/Jobs/PrintJob.cs | 196 ++++++++++++++++++
POSCorePrint/POSCorePrint.csproj | 35 ++++
POSCorePrint/Program.cs | 73 +++++++
.../PublishProfiles/FolderProfile.pubxml | 15 ++
POSCorePrint/TaskStart.cs | 52 +++++
POSCorePrint/appsettings.json | 12 ++
readme.txt | 0
11 files changed, 598 insertions(+)
create mode 100644 .gitignore
create mode 100644 POSCorePrint.sln
create mode 100644 POSCorePrint/Constant.cs
create mode 100644 POSCorePrint/Content.cs
create mode 100644 POSCorePrint/Jobs/PrintJob.cs
create mode 100644 POSCorePrint/POSCorePrint.csproj
create mode 100644 POSCorePrint/Program.cs
create mode 100644 POSCorePrint/Properties/PublishProfiles/FolderProfile.pubxml
create mode 100644 POSCorePrint/TaskStart.cs
create mode 100644 POSCorePrint/appsettings.json
create mode 100644 readme.txt
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..695d2b0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,116 @@
+# ---> C Sharp
+# Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
+[Bb]in/
+[Oo]bj/
+
+# mstest test results
+TestResults
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Rr]elease/
+x64/
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.log
+*.vspscc
+*.vssscc
+*.cache
+*.dll
+*.pdb
+.builds
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish
+
+# Publish Web Output
+*.Publish.xml
+
+# NuGet Packages Directory
+packages
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+[Bb]in
+[Oo]bj
+sql
+TestResults
+[Tt]est[Rr]esult*
+*.Cache
+ClientBin
+[Ss]tyle[Cc]op.*
+~$*
+*.dbmdl
+Generated_Code #added for RIA/Silverlight projects
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+
+/lib
+.vs
+/.gitattributes
diff --git a/POSCorePrint.sln b/POSCorePrint.sln
new file mode 100644
index 0000000..5b291ed
--- /dev/null
+++ b/POSCorePrint.sln
@@ -0,0 +1,25 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29123.88
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "POSCorePrint", "POSCorePrint/POSCorePrint.csproj", "{C340E6AE-33B9-4C36-A84A-4B2E924C82AC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C340E6AE-33B9-4C36-A84A-4B2E924C82AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C340E6AE-33B9-4C36-A84A-4B2E924C82AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C340E6AE-33B9-4C36-A84A-4B2E924C82AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C340E6AE-33B9-4C36-A84A-4B2E924C82AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {444EB795-1EE2-4EDA-8747-1FF859AA80FF}
+ EndGlobalSection
+EndGlobal
diff --git a/POSCorePrint/Constant.cs b/POSCorePrint/Constant.cs
new file mode 100644
index 0000000..d6ec4e7
--- /dev/null
+++ b/POSCorePrint/Constant.cs
@@ -0,0 +1,19 @@
+using Microsoft.Extensions.Configuration;
+using MySql.Data.MySqlClient;
+using POSCorePrint.Jobs;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Text;
+
+namespace POSCorePrint
+{
+ internal class Constant
+ {
+ internal static int port = 9100;
+ internal static IConfigurationRoot Configuration;
+ internal static string ConnectionString;
+ internal static double PrintBackTime;//打印多久之前的数据:分钟
+ internal static double SaveHisDataDays;//只保留最近几天的打印数据:天
+ }
+}
\ No newline at end of file
diff --git a/POSCorePrint/Content.cs b/POSCorePrint/Content.cs
new file mode 100644
index 0000000..965cc0f
--- /dev/null
+++ b/POSCorePrint/Content.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace POSCorePrint
+{
+ ///
+ /// 打印机
+ ///
+ internal class Content
+ {
+ ///
+ /// ID
+ ///
+ public string ID { get; set; }
+ ///
+ /// 打印的内容
+ ///
+ public string ContentVal { get; set; }
+
+ ///
+ /// 通过Socket方式判断打印机是否正常连接
+ ///
+ ///
+ ///
+ ///
+ //internal static bool IsConnect(string ip, int port)
+ //{
+ // //Task.Delay(10);
+ // var isConnect = false;
+ // IPAddress iPAddress = IPAddress.Parse(ip);
+ // IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, port);
+ // Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ // try
+ // {
+ // IAsyncResult asyncResult = socket.BeginConnect(iPEndPoint, null, null);
+ // asyncResult.AsyncWaitHandle.WaitOne(2000, true);
+ // if (asyncResult.IsCompleted)
+ // isConnect = true;
+ // LogHelper.Log().Warn($"打印机 {ip}" + (isConnect ? "正常" : "离线!"));
+ // }
+ // catch (Exception ex)
+ // {
+ // ILog log = LogHelper.Log();
+ // Console.WriteLine($" {ip} 判断打印机是否正常连接失败:【{ex.Message}】",ex);
+ // }
+ // finally
+ // {
+ // socket.Close();
+ // }
+ // return isConnect;
+ //}
+
+ }
+}
\ No newline at end of file
diff --git a/POSCorePrint/Jobs/PrintJob.cs b/POSCorePrint/Jobs/PrintJob.cs
new file mode 100644
index 0000000..b8b00f7
--- /dev/null
+++ b/POSCorePrint/Jobs/PrintJob.cs
@@ -0,0 +1,196 @@
+
+using MySql.Data.MySqlClient;
+using Quartz;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Data;
+using System.Net;
+using System.Net.Sockets;
+using System.Text;
+using System.Threading.Tasks;
+using System.Linq;
+using System.Threading;
+
+namespace POSCorePrint.Jobs
+{
+ ///
+ /// edit by liuwz 2019-09-18 修改防止重复打印的方法
+ /// 打印任务
+ ///
+ [DisallowConcurrentExecution]
+ public class PrintJob : IJob
+ {
+ private readonly ManualResetEvent TimeoutObject = new ManualResetEvent(false);
+ private int Timeout = 1500;//连接打印机超时时间,毫秒。
+ private int TimeoutSend = 5000;//连接打印机超时时间,毫秒。
+
+ public Task Execute(IJobExecutionContext context)
+ {
+ //查询最近N分钟需要打印的数据,同时删除N天前的打印数据。
+ string sql = $@"select task.Id,task.content,print.PrintIP from pos_store_printtask task inner join pos_store_print print on task.code=print.Id
+ where task.status = 0 and print.isdelete=0 and task.CreateTime >'{DateTime.Now.AddMinutes(-Constant.PrintBackTime).ToString("yyyy-MM-dd HH:mm:ss")}';
+ delete from pos_store_printtask where CreateTime <'{DateTime.Now.AddDays(-Constant.SaveHisDataDays).ToString("yyyy-MM-dd HH:mm:ss")}';";
+ // TODO 查询数据库获取打印任务列表
+ DataTable dataTable;
+ try
+ {
+ dataTable = MySqlHelper.ExecuteDataset(Constant.ConnectionString, sql).Tables[0];
+ //无打印任务
+ if (dataTable.Rows.Count == 0)
+ return Task.CompletedTask;
+ //有打印任务,按打印机分组
+ var dicPrints = new Dictionary>();
+ foreach (DataRow row in dataTable.Rows)
+ {
+ var newContent = new Content() { ID = row["Id"].ToString(), ContentVal = row["Content"].ToString() };
+ if (!dicPrints.ContainsKey(row["PrintIP"].ToString()))
+ {
+ dicPrints.Add(
+ row["PrintIP"].ToString(),
+ new List { newContent }
+ );
+ }
+ else
+ dicPrints[row["PrintIP"].ToString()].Add(newContent);
+ }
+ //按打印机并行异步发送
+ Console.WriteLine($"{DateTime.Now.ToString()}:打印开始");
+ List taskList = new List();
+ foreach (KeyValuePair> p in dicPrints)
+ {
+ taskList.Add(Send(p));
+ }
+ //等所有异步打印完再返回
+ Task.WhenAll(taskList).Wait();
+ Console.WriteLine($"{DateTime.Now.ToString()}:打印结束");
+ return Task.CompletedTask;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}:获取打印任务失败", ex);
+ return Task.CompletedTask;
+ }
+ }
+
+ ///
+ /// 异步发送打印任务
+ ///
+ ///
+ private async Task Send(KeyValuePair> p)
+ {
+ string idSuccess = "";
+ string idFail = "";
+ await Task.Run(() =>
+ {
+ IPAddress iPAddress = IPAddress.Parse(p.Key);
+ IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, Constant.port);
+ Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+ try
+ {
+ TimeoutObject.Reset();
+ socket.BeginConnect(iPEndPoint, CallBackMethod,socket);
+ //阻塞当前线程
+ if (!TimeoutObject.WaitOne(Timeout, false))
+ {
+ //处理连接不成功的动作
+ socket.Close();
+ Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key}【连接超时】");
+ return;
+ }
+ if (!socket.Connected)
+ {
+ //处理连接不成功的动作
+ socket.Close();
+ Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key} socket【连接超时】");
+ return;
+ }
+{ foreach (Content content in p.Value)
+ {
+ ////判断打印机状态:是否在线,是否有纸
+ //byte[] dataSatus = new byte[3];
+ //for (int i = 0; i < dataSatus.Length; i++)
+ //{
+ // dataSatus[i] = byte.Parse(content.ContentVal.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
+ //}
+ //int iRes = socket.Send(dataSatus, 0);
+
+ //打印内容
+ byte[] data = new byte[content.ContentVal.Length / 2];
+ try
+ {
+ for (int i = 0; i < data.Length; i++)
+ {
+ data[i] = byte.Parse(content.ContentVal.Substring(i * 2, 2), System.Globalization.NumberStyles.HexNumber);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}:转换打印数据失败 {ex.Message}", ex);
+ }
+
+ try
+ {
+ //byte[] mData = new byte[data.Length];
+ //Array.Copy(data, 0, mData, 0, data.Length);
+ SocketError errorCode;
+ //edit by liuwz 2020-04-03 增加超时
+ socket.SendTimeout= TimeoutSend;
+
+ int iResult = socket.Send(data, 0, out errorCode);
+ //add by liuwz 2020-01-13增加打印发送长度判断。
+ if (SocketError.Success != errorCode || iResult !=data.Length)
+ {
+ //add by liuwz 2019-11-29失败时增加打印次数。
+ idFail += string.IsNullOrEmpty(idFail) ? $"'{content.ID}'" : $",'{content.ID}'";
+ Console.WriteLine($"{DateTime.Now.ToString()}: ip:{p.Key},id:{content.ID} 打印返回失败:【{errorCode.ToString()}】");
+ }
+ else
+ idSuccess += string.IsNullOrEmpty(idSuccess) ? $"'{content.ID}'" : $",'{content.ID}'";
+ }
+ catch (Exception ex)
+ {
+ //add by liuwz 2019-11-29失败时增加打印次数。
+ idFail += string.IsNullOrEmpty(idFail) ? $"'{content.ID}'" : $",'{content.ID}'";
+ Console.WriteLine($"{DateTime.Now.ToString()}: ip:{p.Key},id:{content.ID} 发送打印命令失败:【{ex.Message}】", ex);
+ }
+ }
+
+ // 操作数据库更新状态
+ if (!string.IsNullOrEmpty(idSuccess))
+ {
+ var sql = $"update pos_store_printtask set status=1,PrintTime=NOW(),PrintTimes=ifnull(PrintTimes,0)+1 where Id in({idSuccess});";
+ Console.WriteLine($"{DateTime.Now.ToString()}:打印成功更新记录:{iPAddress};{idSuccess}");
+
+ MySqlHelper.ExecuteNonQueryAsync(Constant.ConnectionString, sql);
+ }
+ if (!string.IsNullOrEmpty(idFail))
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}:打失败更新记录:{iPAddress};{idFail}");
+ var sql = $"update pos_store_printtask set PrintTimes=ifnull(PrintTimes,0)+1 where Id in({idFail});";
+ MySqlHelper.ExecuteNonQueryAsync(Constant.ConnectionString, sql);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}: 打印失败:{p.Key}【{ex.Message}】{string.Join('|',p.Value.Select(m=>new {m.ID}))}", ex);
+ }
+ finally
+ {
+ socket.Close();
+ }
+ });
+ }
+
+ ///
+ /// 异步回调方法
+ ///
+ ///
+ private void CallBackMethod(IAsyncResult asyncresult)
+ {
+ //使阻塞的线程继续
+ TimeoutObject.Set();
+ }
+
+ }
+}
diff --git a/POSCorePrint/POSCorePrint.csproj b/POSCorePrint/POSCorePrint.csproj
new file mode 100644
index 0000000..8737840
--- /dev/null
+++ b/POSCorePrint/POSCorePrint.csproj
@@ -0,0 +1,35 @@
+
+
+
+ Exe
+ netcoreapp2.2
+
+
+ win-x86;win-x64;linux-x64;osx-x64
+ 7.1
+
+
+
+ 3
+ false
+ AnyCPU
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+
diff --git a/POSCorePrint/Program.cs b/POSCorePrint/Program.cs
new file mode 100644
index 0000000..fb0fd30
--- /dev/null
+++ b/POSCorePrint/Program.cs
@@ -0,0 +1,73 @@
+
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace POSCorePrint
+{
+ class Program
+ {
+ //private static Dictionary printerList = new Dictionary();
+
+ static async Task Main(string[] args)
+ {
+ //add by liuwz 2019-12-26 解决linux下时间格式的问题
+ var culture = CultureInfo.CreateSpecificCulture("zh-CN");
+ var dateformat = new DateTimeFormatInfo()
+ {
+ ShortTimePattern = "HH:mm:ss",
+ LongTimePattern = "HH:mm:ss",
+ ShortDatePattern = "yyyy-MM-dd",
+ LongDatePattern = "yyyy-MM-dd",
+ FullDateTimePattern = "yyyy-MM-dd HH:mm:ss"
+ };
+ culture.DateTimeFormat = dateformat;
+ CultureInfo.DefaultThreadCurrentUICulture = culture;
+ CultureInfo.DefaultThreadCurrentCulture = culture;
+
+ var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory()).AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
+ Constant.Configuration = builder.Build();
+ Constant.ConnectionString = Constant.Configuration["Config:connectionString"];
+ Constant.PrintBackTime = double.Parse(Constant.Configuration["taskTimes:printBackTime"]);
+ Constant.SaveHisDataDays = double.Parse(Constant.Configuration["taskTimes:saveHisDataDays"]);
+
+
+
+ var hostBuilder = new HostBuilder()
+ .ConfigureServices(serviceCollection =>
+ {
+ //注册我们的服务接口
+ serviceCollection.AddSingleton();
+ });
+ await hostBuilder.RunConsoleAsync();
+ }
+ }
+
+ class MyService : IHostedService
+ {
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ return Task.Run(() =>
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}:开启打印任务:" + DateTime.Now.ToString());
+
+ TaskStart taskStart = new TaskStart();
+ taskStart.Start();
+ });
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.Run(() =>
+ {
+ Console.WriteLine($"{DateTime.Now.ToString()}:关闭打印任务:" + DateTime.Now.ToString());
+ });
+ }
+ }
+}
diff --git a/POSCorePrint/Properties/PublishProfiles/FolderProfile.pubxml b/POSCorePrint/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..9955b61
--- /dev/null
+++ b/POSCorePrint/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,15 @@
+
+
+
+
+ FileSystem
+ Release
+ Any CPU
+ netcoreapp2.2
+ D:\publish\core_posprint
+ false
+ <_IsPortable>true
+
+
\ No newline at end of file
diff --git a/POSCorePrint/TaskStart.cs b/POSCorePrint/TaskStart.cs
new file mode 100644
index 0000000..300cdbb
--- /dev/null
+++ b/POSCorePrint/TaskStart.cs
@@ -0,0 +1,52 @@
+using Quartz;
+using Quartz.Impl;
+using System;
+using System.Collections.Specialized;
+using System.Threading.Tasks;
+using POSCorePrint.Jobs;
+using System.Net;
+using System.Net.Sockets;
+
+namespace POSCorePrint
+{
+ public class TaskStart
+ {
+ public string PrintTaskTime { get; } = Constant.Configuration["taskTimes:printTaskTime"];
+ public async Task Start()
+ {
+ try
+ {
+ // 从工厂中获取调度程序实例
+ NameValueCollection props = new NameValueCollection
+ {
+ { "quartz.serializer.type", "binary" }
+ };
+ StdSchedulerFactory factory = new StdSchedulerFactory(props);
+ IScheduler scheduler = await factory.GetScheduler();
+
+ // 开启调度器
+ await scheduler.Start();
+
+ #region//打印任务
+ IJobDetail job = JobBuilder.Create()
+ .WithIdentity("PrintJob", "group")
+ .Build();
+
+ // 定时获取打印任务
+ ITrigger trigger = TriggerBuilder.Create()
+ .WithIdentity("PrintTrigger", "group")
+ .WithCronSchedule(PrintTaskTime)
+ .Build();
+
+ // 告诉Quartz使用我们的触发器来安排作业
+ await scheduler.ScheduleJob(job, trigger);
+ #endregion
+
+ }
+ catch (SchedulerException se)
+ {
+ await Console.Error.WriteLineAsync($"{DateTime.Now.ToString()}:{se.ToString()}");
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/POSCorePrint/appsettings.json b/POSCorePrint/appsettings.json
new file mode 100644
index 0000000..d887618
--- /dev/null
+++ b/POSCorePrint/appsettings.json
@@ -0,0 +1,12 @@
+{
+ "Config": {
+ "connectionString": "server=192.168.1.221;port=3306;uid=root;pwd=dlpos;database=posclient;charset=utf8;Allow User Variables=true;"
+ },
+ "taskTimes": {
+ "printTaskTime": "0/3 * * * * ? *",
+ //ӡ֮ǰݣ
+ "printBackTime": 30,
+ //ֻĴӡݣ
+ "saveHisDataDays": 3
+ }
+}
\ No newline at end of file
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..e69de29