Files
RBMESAPICore/Controllers/Cloud/HostService/PushMesInterface.cs

526 lines
26 KiB
C#
Raw Normal View History

2025-09-09 22:41:29 +08:00
using Microsoft.EntityFrameworkCore;
using Nancy.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RB_MES_API.Context;
using RB_MES_API.Controllers;
using RB_MES_API.Controllers.Cloud;
using RB_MES_API.Models;
using RB_MES_API.Models.Cloud;
using RB_MES_API.Models.Pangu;
using RB_MES_APICore.Models.Pangu;
using RB_MES_APICore.Models;
using System.Data;
using System.Net;
using System.Reflection;
using System.Text;
namespace RB_MES_API.HostService
{
/// <summary>
/// 定时推送服务
/// </summary>
public class PushMesInterface : IPushMesInterface,IDisposable
{
private List<Timer> _timer = new List<Timer>();
private readonly RBContext _context;
private readonly IConfiguration _config;
private readonly IShareController _shareController;
private readonly IKDCloudHttpClient _KdhttpClient;
private readonly IKDSqlHelper _kdsqlhelper;
/// <summary>
///
/// </summary>
/// <param name="context">注入的数据库连接</param>
/// <param name="shareController">共享方法</param>
/// <param name="httpClient">金蝶API</param>
/// <param name="configuration"></param>
/// <param name="kdsqlhelper"></param>
public PushMesInterface(RBContext context, IConfiguration configuration, IShareController shareController
, IKDCloudHttpClient httpClient, IKDSqlHelper kdsqlhelper)
{
_context = context;
_config = configuration;
_shareController = shareController;
_KdhttpClient = httpClient;
_kdsqlhelper = kdsqlhelper;
}
/// <inheritdoc/>
public void Dispose()
{
foreach (Timer timer in _timer)
{
timer?.Dispose();
}
}
private void DoWork(object state)
{
// 定时任务逻辑
try
{
List<CloudBillQuery> queryJsons = _shareController.GetAPIList<CloudBillQuery>().Result;
var clouds = queryJsons.Where(s => s.GetFormID.FDocType == state.ToString()).ToList();
if (clouds.Count > 0)
{
new TaskFactory().StartNew(async () =>
{
CloudBillQuery query = clouds.FirstOrDefault();
//启动新线程执行推送业务
Type type = this.GetType();
MethodInfo? methodInfo = type.GetMethod(query.GetFormID.FActionName);
if (methodInfo != null)
{
object[] para = new object[] { query.GetFormID.FID, query.GetFormID.functions.FUrl };
methodInfo.Invoke(this, para);
}
});
}
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork发生错误{0}", ex.Message));
}
}
public async void DoTimerWorkAsyn()
{
await Task.Run(() => LoadLocalStaticRequest());
try
{
string v = LocalStaticRequest.GetSystemProfile(1, "AutoPushTask");
int at = 0;
int.TryParse(v, out at);
if (at > 0)
{
//只要FTimer > 0的接口都有一个属于自己的定时器
List<ApiHostService> systimeds = _shareController.GetAPIList<ApiHostService>().Result;
if (systimeds.Count == 0) { return; }
var sys = from a in systimeds
select new
{
worktime = a.FTimer,
name = a.FDocType
};
foreach (var item in sys)
{
_timer.Add(new Timer(DoWork, item.name, TimeSpan.Zero, TimeSpan.FromMinutes(item.worktime)));
}
}
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService的StartAsync发生错误{0}", ex.Message));
}
return;
}
/// <summary>
/// 优先加载系统必须的静态数据
/// </summary>
private void LoadLocalStaticRequest()
{
try
{
//如果缓存中不存在,就从数据库里取出来再放进缓存
List<SystemProfile> sys = CacheHelper.GetCache<List<SystemProfile>>("sys");
if (sys == null)
{
//先初始化全局变量
sys = _context.r_SystemProfiles!.AsNoTracking().ToList();
if (sys.Any())
{
CacheHelper.Set_AbsluteExpire("sys", sys);
}
}
LocalStaticRequest.sysprofile = sys; //定时刷新
}
catch (Exception ex)
{
//如果金蝶Cloud登录失败就会发生异常可能导致程序崩溃...
string msg = ex.Message;
LogHelper.WriteLog(string.Format("TimedHostedService的LoadHostFunctionAsync发生错误{0}", msg));
}
//将计量单位加入缓存
Thread uthread = new Thread(AddUnitCache);
uthread.Start();
//无论是否推送,静态全局设置应该首先加载
string orgid = LocalStaticRequest.GetSystemProfile(2, "DefaultORGID");
string orgno = LocalStaticRequest.GetSystemProfile(2, "DefaultORG");
LocalStaticRequest.DefaultOrgID = string.IsNullOrEmpty(orgid) ? 1 : int.Parse(orgid);
LocalStaticRequest.DefaultOrg = string.IsNullOrEmpty(orgno) ? "100" : orgno;
}
private void AddUnitCache()
{
try
{
List<BD_UNIT> units = new List<BD_UNIT>();
string messstr = string.Empty;
string fileds = "FUNITID,FNumber,FName,FIsBaseUnit,FPrecision,FDocumentStatus,FForbidStatus,FConvertDenominator,FConvertNumerator,FRoundType";
//从云星空中把所有计量单位获取过来
BillQuery queryJson = new BillQuery()
{
FieldKeys = fileds,
FormId = "BD_UNIT",
FilterString = "FDOCUMENTSTATUS='C' AND FFORBIDSTATUS='A'"
};
if (!LocalStaticRequest.Islogin)
{
if (!_KdhttpClient.LoginErp().Result)
{
return;
}
}
//从云星空查询
string jsonstr = JsonConvert.SerializeObject(queryJson);
List<object> Parameters = new List<object>();
Parameters.Add(jsonstr);
string content = JsonConvert.SerializeObject(Parameters);
string url = LocalStaticRequest.GetSystemProfile(4, "TokenUrl");
string myurl = url + "Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc";
//string result = _KdhttpClient.AsyncRequest();
string result = _KdhttpClient.AsyncRequest(myurl, content);
//如果访问正常
if (_KdhttpClient.CloudExecuteQueryStatus(result, ref messstr))
{
//将获取到的结果转为List<BD_UNIT>
units = _shareController.GetNewObjForChild<BD_UNIT>(fileds, result, ref messstr);
CacheHelper.Set_AbsluteExpire("BD_UNIT", units);
}
}
catch (Exception e)
{
LogHelper.WriteLog(string.Format("TimedHostedService的AddUnitCache发生错误{0}", e.Message));
}
}
/// <summary>
/// 将自定义SQL查询结果推送给MES
/// </summary>
/// <param name="formtypeid"></param>
/// <param name="url"></param>
public void GetSelfDBbaseAsync(int formtypeid, string url)
{
string result = GetCustomRequestTBAsync(formtypeid);
List<CloudBillQuery> query = _shareController.GetAPIList<CloudBillQuery>().Result;
if (query.Count == 0) return;
string doctype = query.Find(s => s.FFormIDTypeID == formtypeid).GetFormID.FDocType;
if (string.IsNullOrEmpty(result)) { return; }
try
{
//可以将datatable直接转为JSON但这里约定的格式用不上
//new JsonSerializer().Deserialize(new JsonTextReader(new StringReader(result)));
JArray array = (JArray)JsonConvert.DeserializeObject(result);
if (array == null || array.Count == 0) { return; }
PanguPostBill mes = new PanguPostBill()
{
DocType = doctype,
DataSet = _shareController.GetClassList(array)
};
string json = JsonConvert.SerializeObject(mes);
////推送给MES
//PanguBreakJson mesjson = PushMesData(json).Result;
//if (mesjson.Status)
//{
// LogHelper.WriteLog(string.Format("推送【{0}】成功:{1}", doctype, json), doctype);
//}
//else
//{
// LogHelper.WriteLog(string.Format("TimedHostedService的GetSelfDBbaseAsync方法推送【{0}】失败:{1}\n原始数据{2}", doctype, mesjson.Message, json), doctype);
//}
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService推送【{0}】动态GetSelfDBbaseAsync方法出错{1}", doctype, ex.Message), doctype);
}
}
/// <summary>
/// 查询Cloud表单。注意基础资料表单查询有多用途FFieldKeys中必须有Key。同理...
/// </summary>
/// <param name="formtypeid"></param>
/// <param name="url"></param>
public async void GetBDbase(int formtypeid, string url) //动态引用
{
string reason = string.Empty;
List<CloudBillQuery> queryJsons = await _shareController.GetAPIList<CloudBillQuery>();
if (queryJsons.Count == 0)
{
LogHelper.WriteLog("TimedHostedService的GetBDbase方法_shareController.GetAPIList<CloudBillQuery>()缓存过期");
return;
}
else
{
var formtype = queryJsons.Where(s => s.GetFormID.FID == formtypeid).FirstOrDefault()!.GetFormID;
int fid = formtype.FFunctionID;
string doctype = formtype.FDocType;
var queryJson = from a in queryJsons.Where(s => s.GetFormID.FID == formtypeid)
select new BillQuery
{
FieldKeys = a.FFieldKeys.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg),
FormId = a.GetFormID.FDBName,
FilterString = a.FFiledString.Replace("GETDATE", DateTime.Now.ToShortDateString()).Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg),
Limit = a.FLimit,
OrderString = a.FOrderString,
StartRow = a.FStartRow,
SubSystemId = a.FSubSystemID,
TopRowCount = a.FTopRowCount
};
if (queryJson.Any())
{
try
{
if (!LocalStaticRequest.Islogin)
{
await _KdhttpClient.LoginErp();
}
if (!LocalStaticRequest.Islogin)
{
reason = "KdhttpClient登录失败";
goto EBread;
}
string jsonstr = JsonConvert.SerializeObject(queryJson.FirstOrDefault());
List<object> Parameters = new List<object>() { jsonstr };
string content = JsonConvert.SerializeObject(Parameters);
//string result = _KdhttpClient.AsyncRequest();
string result = _KdhttpClient.AsyncRequest(url, content);
if (_KdhttpClient.CloudExecuteQueryStatus(result, ref reason)) //查询表单数据接口使用
{
if (!string.IsNullOrEmpty(reason)) { goto EBread; }
JArray jArray = (JArray)JsonConvert.DeserializeObject(result.ToString()!)!; //特别注意!!!
//为dt添加数据
if (jArray != null && jArray.Count > 0)
{
string fileds = queryJson.FirstOrDefault()!.FieldKeys!;
//根据字段对应关系分配字段
DataTable dt = _shareController.JsonConvertDatatable(fileds, result, ref reason);
if (!string.IsNullOrEmpty(reason)) { goto EBread; }
//DataTable dt = CreateFFieldKeys(fileds);
//由于jArray没有字段名只能先装填DataTable
//LoadDatatable(jArray, ref dt);
if (dt.Rows.Count > 0)
{
List<Dictionary<string, object>> dic = GetClassList(fid, doctype, dt);
if (dic.Any())
{
//json = JsonConvert.SerializeObject(dic);
PanguPostBill mes = new PanguPostBill()
{
DocType = doctype,
DataSet = dic
};
string json = JsonConvert.SerializeObject(mes);
////推送给MES
//PanguBreakJson mesjson = await PushMesData(json);
//if (mesjson.Status)
//{
// reason = string.Format("推送【{0}】成功:{1}", doctype, json);
//}
//else
//{
// reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】失败:{1}\r原始数据{2}", doctype, mesjson.Message, json);
//}
}
else
{
reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】失败:!GetClassList(fid, doctype, dt)Any(){1}}", doctype, result);
}
}
}
}
else
{
//将message写入错误日志
reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】返回结果:{1}", doctype, result.ToString());
}
}
catch (Exception ex)
{
reason = string.Format("TimedHostedService的GetBDbase方法推送【{0}】过程中发生错误:{1}", doctype, ex.Message);
}
}
EBread:
if (!string.IsNullOrEmpty(reason)) { LogHelper.WriteLog(reason, doctype); }
}
}
/// <summary>
/// 向第三方系统推送数据
/// </summary>
/// <param name="inputdata">推送的JSON文本</param>
/// <returns></returns>
private async Task<PanguBreakJson> PushMesData(string inputdata)
{
PanguBreakJson breadJson = new PanguBreakJson() { Status = false };
string mesurl = _config.GetConnectionString("MesUrl");
mesurl += mesurl.Substring(mesurl.Length - 1, 1) == "/" ? "" : "/"; //如果最后一个字符不是"/"就添加上去
mesurl += "updateimsdata";
HttpWebRequest reqest = (HttpWebRequest)WebRequest.Create(mesurl);
reqest.Timeout = 20 * 60 * 1000;
reqest.Method = "POST";
reqest.ContentType = "application/json";
try
{
byte[] bytes = Encoding.UTF8.GetBytes(inputdata);
reqest.ContentLength = bytes.Length;
string result = string.Empty;
reqest.GetRequestStream().Write(bytes, 0, bytes.Length);
HttpWebResponse webResponse = (HttpWebResponse)await reqest.GetResponseAsync();
//读取返回数据
StreamReader streamReader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8);
result = streamReader.ReadToEnd();
streamReader.Dispose();
webResponse.Dispose();
breadJson = JsonConvert.DeserializeObject<PanguBreakJson>(result);
}
catch (Exception ex)
{
breadJson.Message = ex.Message;
}
return breadJson;
}
/// <summary>
/// 根据字段转换的目标名称从table获取数据生成新的键值对集合。
/// 适用于定时推送任务或其他不需要存储的动态对象。与接口_shareController中同名方法有异曲同工之处
/// </summary>
/// <param name="fid">FFunctionID</param>
/// <param name="decname">目标表名</param>
/// <param name="table">需要转换的表,没有字段名</param>
/// <returns></returns>
private List<Dictionary<string, object>> GetClassList(int fid, string decname, DataTable table)
{
List<Dictionary<string, object>> list = new List<Dictionary<string, object>>();
//先检查是否需要作字段转换
List<SelectClumnConvert> scc = _shareController.GetAPIList<SelectClumnConvert>().Result;
scc = scc.Where(s => s.FFunctionID == fid && s.FDesTableName.Equals(decname)).ToList();
if (scc.Any())
{
foreach (DataRow row in table.Rows)
{
Dictionary<string, object> keyValuePairs = new Dictionary<string, object>();
foreach (SelectClumnConvert clumnConvert in scc)
{
string oldname = clumnConvert.FSourceName;
if (table.Columns.Contains(oldname))
{
string newname = clumnConvert.FDesName;
keyValuePairs.Add(newname, row[oldname].ToString()!);
}
}
list.Add(keyValuePairs);
}
}
return list;
}
/// <summary>
/// 来源于接口_ChiledSelect但由于本地服务启动与依赖性注入底层冲突而不能直接调用接口
/// </summary>
/// <param name="formtypeid"></param>
/// <returns></returns>
private string GetCustomRequestTBAsync(int formtypeid)
{
//throw new NotImplementedException();
string tbjson = string.Empty;
try
{
List<CloudBillQuery> queryJsons = _shareController.GetAPIList<CloudBillQuery>().Result;
var query = queryJsons.Where(s => s.FFormIDTypeID == formtypeid).FirstOrDefault();
//查询脚本
string sql = query.FFieldKeys.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString());
if (string.IsNullOrEmpty(sql)) { return tbjson; }
//这个方法无法携带参数,只能先写在查询语句里,然后替换之...
string param = query.FFiledString.Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString()).Replace("@defaultorgno", LocalStaticRequest.DefaultOrg);
if (!string.IsNullOrEmpty(param))
{
string[] strings = param.Split(',');
foreach (string s in strings)
{
string[] cs = s.Split('=');
string key = cs[0];
string value = cs[1].Replace("GETDATE", DateTime.Now.ToShortDateString()).Replace("@defaultorgid", LocalStaticRequest.DefaultOrgID.ToString());
sql = sql.Replace(key, value);
}
}
string doctype = query.GetFormID.FDocType;
string costomsql = _config.GetValue<string>("CustomRequestRemoteSql");
if (costomsql.ToUpper() == "Y")
{
string result = GetCustomReaderAsync(sql, "ExecuteDataSet");
//string errmess = string.Empty;
try
{
if (string.IsNullOrWhiteSpace(result)) { return tbjson; }
//先将返回数据格式化
JObject jobj = (JObject)JsonConvert.DeserializeObject(result);
tbjson = JsonConvert.SerializeObject(jobj["Table"]);
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})本地查询{1}发生错误:{2}", formtypeid, doctype, ex.Message));
}
}
else
{
string mess = string.Empty;
//实施本地化查询
DataSet dataSet = _kdsqlhelper.GetDataSet(CommandType.Text, sql, null, ref mess, true);
if (mess != null || dataSet == null)
{
LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})网络查询{1}发生错误:{2}", formtypeid, doctype, mess));
}
else if (dataSet.Tables.Count != 0)
{
DataTable dataTable = dataSet.Tables[0];
tbjson = JsonConvert.SerializeObject(dataTable);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0})发生错误:{1}", formtypeid, ex.Message));
}
return tbjson;
}
/// <summary>
/// 来源于接口_ChiledSelect但由于本地服务启动与依赖性注入底层冲突而不能直接调用接口
/// </summary>
/// <param name="sql"></param>
/// <param name="servicesstubname"></param>
/// <returns></returns>
private string GetCustomReaderAsync(string sql, string servicesstubname)
{
string tbjson = string.Empty;
try
{
//获取自定义查询的服务器端插件地址...
string apiid = LocalStaticRequest.GetSystemProfile(1, "APIGrouID");
var sv = _context.r_CustomServices.Where(s => s.FApiGroupID == int.Parse(apiid) && s.FActionName == servicesstubname);
if (!sv.Any()) { return tbjson; }
CustomService customservice = sv.FirstOrDefault();
if (customservice == null) { return tbjson; }
//查询前必须先登录...
if (!LocalStaticRequest.Islogin) { _KdhttpClient.LoginErp(); }
if (!LocalStaticRequest.Islogin) { return tbjson; }
string url = LocalStaticRequest.GetSystemProfile(4, "TokenUrl");
url += url.Substring(url.Length - 1, 1) == "/" ? "" : "/"; //如果最后一个字符不是"/"就添加上去
url += customservice.FNamespace + "." + customservice.FClassName + "." + customservice.FActionName + "," + customservice.FAppComponents;
List<object> Parameters = new List<object>
{
sql//服务中可添加参数SqlParam[],但要引用金蝶组件!
};
string content = JsonConvert.SerializeObject(Parameters);
tbjson = _KdhttpClient.AsyncRequest(url, content);
}
catch (Exception ex)
{
LogHelper.WriteLog(string.Format("TimedHostedService的BackgroundServiceWork({0},{1})发生错误:{1}", sql, servicesstubname, ex.Message));
}
return tbjson;
//throw new NotImplementedException();
}
}
}