打印服务
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
9.1 KiB

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
{
/// <summary>
/// edit by liuwz 2019-09-18 修改防止重复打印的方法
/// 打印任务
/// </summary>
[DisallowConcurrentExecution]
public class PrintJob : IJob
{
private readonly ManualResetEvent TimeoutObject = new ManualResetEvent(false);
private int Timeout = 2500;//连接打印机超时时间,毫秒。
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<string, List<Content>>();
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<Content> { newContent }
);
}
else
dicPrints[row["PrintIP"].ToString()].Add(newContent);
}
//按打印机并行异步发送
Console.WriteLine($"{DateTime.Now.ToString()}:打印开始");
List<Task> taskList = new List<Task>();
foreach (KeyValuePair<string, List<Content>> 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;
}
}
/// <summary>
/// 异步发送打印任务
/// </summary>
/// <param name="p"></param>
private async Task Send(KeyValuePair<string, List<Content>> 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();
}
});
}
/// <summary>
/// 异步回调方法 
/// </summary>
/// <param name="asyncresult"></param>
private void CallBackMethod(IAsyncResult asyncresult)
{
//使阻塞的线程继续          
TimeoutObject.Set();
}
}
}