TaskExtension.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. using ServiceCenter.Extensions;
  2. using ServiceCenter.Logs;
  3. using ServiceCenter.Redis;
  4. using ServiceCenter.SqlSugars;
  5. using SqlSugar;
  6. using WCS.Core;
  7. using WCS.Entity;
  8. using WCS.WorkEngineering.Model.WMS;
  9. using WCS.WorkEngineering.Systems;
  10. using TaskStatus = WCS.Entity.TaskStatus;
  11. namespace WCS.WorkEngineering.Extensions
  12. {
  13. /// <summary>
  14. /// 任务扩展
  15. /// </summary>
  16. public static class TaskExtension
  17. {
  18. /// <summary>
  19. /// 更新任务执行记录
  20. /// 同步更新历史任务
  21. /// </summary>
  22. /// <param name="task">任务信息</param>
  23. /// <param name="db">数据库上下文</param>
  24. /// <param name="curPoint">当前地址</param>
  25. /// <param name="desc">描述</param>
  26. public static void AddWCS_TASK_DTL(this WCS_TaskInfo task, SqlSugarScopeProvider db, string curPoint, string desc) => task.AddWCS_TASK_DTL(db, curPoint, "", desc);
  27. /// <summary>
  28. /// 更新任务执行记录
  29. /// 同步更新历史任务
  30. /// </summary>
  31. /// <param name="task">任务信息</param>
  32. /// <param name="db">数据库上下文</param>
  33. /// <param name="curPoint">当前地址</param>
  34. /// <param name="nextPoint">下一个地址</param>
  35. /// <param name="desc">描述</param>
  36. public static void AddWCS_TASK_DTL(this WCS_TaskInfo task, SqlSugarScopeProvider db, string curPoint, string nextPoint, string desc)
  37. {
  38. db.InsertableRowLock(new WCS_TaskDtl
  39. {
  40. ID = Guid.NewGuid(),
  41. ParentTaskCode = task.ID,
  42. CurPoint = curPoint,
  43. NextPoint = nextPoint,
  44. Desc = desc,
  45. AddWho = "WCS"
  46. }).SplitTable().ExecuteCommand();
  47. task.UpdateableOldTask(db);
  48. }
  49. /// <summary>
  50. /// 更新任务执行记录
  51. /// 同步更新历史任务
  52. /// </summary>
  53. /// <param name="task">任务信息</param>
  54. /// <param name="db">数据库上下文</param>
  55. /// <param name="curPoint">当前地址</param>
  56. /// <param name="desc">描述</param>
  57. public static void AddWCS_TASK_DTL(this WCS_TaskOld task, SqlSugarScopeProvider db, string curPoint, string desc) => task.AddWCS_TASK_DTL(db, curPoint, "", desc);
  58. /// <summary>
  59. /// 更新任务执行记录
  60. /// 同步更新历史任务
  61. /// </summary>
  62. /// <param name="task">任务信息</param>
  63. /// <param name="db">数据库上下文</param>
  64. /// <param name="curPoint">当前地址</param>
  65. /// <param name="nextPoint">下一个地址</param>
  66. /// <param name="desc">描述</param>
  67. public static void AddWCS_TASK_DTL(this WCS_TaskOld task, SqlSugarScopeProvider db, string curPoint, string nextPoint, string desc)
  68. {
  69. db.InsertableRowLock(new WCS_TaskDtl
  70. {
  71. ID = Guid.NewGuid(),
  72. ParentTaskCode = task.Id,
  73. CurPoint = curPoint,
  74. NextPoint = nextPoint,
  75. Desc = desc,
  76. AddWho = "WCS"
  77. }).SplitTable().ExecuteCommand();
  78. }
  79. /// <summary>
  80. /// 更新历史表数据
  81. /// </summary>
  82. /// <param name="taskInfo"></param>
  83. /// <param name="db"></param>
  84. public static void UpdateableOldTask(this WCS_TaskInfo taskInfo, SqlSugarScopeProvider db)
  85. {
  86. if (taskInfo.Status == TaskStatus.NewBuild) return;
  87. // 同步任务信息
  88. var taskOld = db.Queryable<WCS_TaskOld>().RowLock().Where(v => v.Id == taskInfo.ID).SplitTable(tabs => tabs.Take(2)).ToList().OrderByDescending(v => v.AddTime).First();
  89. if (taskOld is not null)
  90. {
  91. if (taskInfo.Status >= TaskStatus.Finish) taskInfo.CompleteOrCancelTasks(db);
  92. else
  93. {
  94. taskOld = taskInfo.Mapper<WCS_TaskOld, WCS_TaskInfo>();
  95. taskOld.Id = taskInfo.ID;
  96. db.UpdateableRowLock(taskOld).Where(x => x.Id == taskOld.Id).SplitTable(tabs => tabs.Take(2)).ExecuteCommand();
  97. }
  98. }
  99. else
  100. {
  101. throw new KnownException($"WCS_TaskOld表中不存在任务:{taskInfo.ID},无法执行WCS_TaskInfo与WCS_TaskOld同步动作", LogLevelEnum.Mid);
  102. }
  103. }
  104. /// <summary>
  105. /// 完成或取消任务
  106. /// </summary>
  107. /// <param name="taskInfo"></param>
  108. /// <param name="db"></param>
  109. public static void CompleteOrCancelTasks(this WCS_TaskInfo taskInfo, SqlSugarScopeProvider db)
  110. {
  111. if (taskInfo.Status is not Entity.TaskStatus.Finish and not Entity.TaskStatus.Cancel) throw new KnownException("任务未完成或取消,无法执行WCS_TaskInfo与WCS_TaskOld同步动作", LogLevelEnum.Mid);
  112. // 任务完成或取消,进行相关同步动作
  113. var taskOld = db.Queryable<WCS_TaskOld>().RowLock().Where(v => v.Id == taskInfo.ID).SplitTable(tabs => tabs.Take(2)).ToList().OrderByDescending(v => v.AddTime).First();
  114. if (taskOld is not null)
  115. {
  116. taskOld = taskInfo.Mapper<WCS_TaskOld, WCS_TaskInfo>();
  117. taskOld.Id = taskInfo.ID;
  118. //更新任务历史表,删除任务当前表
  119. db.UpdateableRowLock(taskOld).Where(x => x.Id == taskOld.Id).SplitTable(tabs => tabs.Take(2)).ExecuteCommand();
  120. db.DeleteableRowLock(taskInfo).ExecuteCommand();
  121. }
  122. else
  123. {
  124. throw new KnownException($"WCS_TaskOld表中不存在任务:{taskInfo.ID},无法执行WCS_TaskInfo与WCS_TaskOld同步动作", LogLevelEnum.Mid);
  125. }
  126. }
  127. /// <summary>
  128. /// 更新表数据
  129. /// </summary>
  130. /// <param name="taskInfo"></param>
  131. /// <param name="db"></param>
  132. public static void Updateable(this WCS_TaskInfo taskInfo, SqlSugarScopeProvider db)
  133. {
  134. }
  135. /// <summary>
  136. /// 添加异常信息
  137. /// </summary>
  138. /// <param name="db">db</param>
  139. /// <param name="error"></param>
  140. /// <returns></returns>
  141. public static void AddBaseErrorInfo(this BaseErrorInfo error, SqlSugarScopeProvider db)
  142. {
  143. var errorinfoWcs = db.Queryable<BaseErrorInfo>().With(SqlWith.NoLock)
  144. .Where(v => v.BusName == error.BusName && v.Message == error.Message && v.BarCode == error.BarCode).First();
  145. if (errorinfoWcs != null && (error.AddTime - errorinfoWcs.AddTime).TotalMinutes < 60)
  146. {
  147. errorinfoWcs.Count += 1;
  148. db.Updateable(errorinfoWcs).ExecuteCommand();
  149. }
  150. else
  151. {
  152. db.Insertable(error).ExecuteCommand();
  153. }
  154. }
  155. /// <summary>
  156. /// 添加异常信息
  157. /// </summary>
  158. /// <param name="db">db</param>
  159. /// <param name="error"></param>
  160. /// <returns></returns>
  161. public static void AddBaseErrorInfo(this BaseErrorInfo error)
  162. {
  163. SqlSugarHelper.Do(_db =>
  164. {
  165. var db = _db.Default;
  166. var errorinfoWcs = db.Queryable<BaseErrorInfo>().With(SqlWith.NoLock)
  167. .Where(v => v.BusName == error.BusName && v.Message == error.Message && v.BarCode == error.BarCode).First();
  168. if (errorinfoWcs != null && (error.AddTime - errorinfoWcs.AddTime).TotalMinutes < 1)
  169. {
  170. errorinfoWcs.Count += 1;
  171. db.Updateable(errorinfoWcs).ExecuteCommand();
  172. }
  173. else
  174. {
  175. db.Insertable(error).ExecuteCommand();
  176. }
  177. });
  178. }
  179. ///// <summary>
  180. ///// 获取出库任务
  181. ///// </summary>
  182. ///// <param name="taskInfo">任务</param>
  183. ///// <param name="db">db</param>
  184. ///// <param name="allOutCode">可用出库站台</param>
  185. ///// <param name="floor">楼层</param>
  186. ///// <param name="obj">堆垛机</param>
  187. ///// <param name="index">递归次数</param>
  188. ///// <returns></returns>
  189. ///// <exception cref="KnownException"></exception>
  190. //public static WCS_TaskInfo GetOutTask(this WCS_TaskInfo taskInfo, SqlSugarHelper db, List<string> allOutCode, int floor, SRM obj, int index = 1)
  191. //{
  192. // return task;
  193. //}
  194. /// <summary>
  195. /// 获取AGV任务ID
  196. /// </summary>
  197. /// <param name="db">db</param>
  198. /// <returns></returns>
  199. public static int GetAgvTaskId(this SqlSugarHelper db)
  200. {
  201. //最多任务号不再连续
  202. var id = db.Default.Queryable<WCS_AgvTaskInfo>().NoLock().SplitTable(v => v.Take(2)).Max(v => v.ID);
  203. return id + 1;
  204. }
  205. /// <summary>
  206. /// 更新任务执行记录
  207. /// </summary>
  208. /// <param name="task">任务信息</param>
  209. public static void UpdateRedisHash(this WCS_TaskInfo task)
  210. {
  211. var key = $"Hash:{task.ID}";
  212. if (task.Status >= TaskStatus.Finish)
  213. {
  214. RedisHub.WMS.Del(key);
  215. }
  216. else
  217. {
  218. RedisHub.WMS.HMSet(key, task.ToDic());
  219. }
  220. }
  221. public static int GetOutTime(this List<BaseMatinfo> matInfoList, string matCode, string defaultOutTime)
  222. {
  223. var outTime = Convert.ToInt32(defaultOutTime);
  224. if (matInfoList.Any(m => matCode.Contains(m.Code)))
  225. {
  226. outTime = matInfoList.Where(m => matCode.Contains(m.Code)).Min(m => m.TimeOut);
  227. }
  228. return outTime;
  229. }
  230. #region 工字轮支线分流
  231. /// <summary>
  232. /// 初始化码垛信息
  233. /// </summary>
  234. /// <param name="task"></param>
  235. public static void InitStackStructure(this WCS_TaskInfo task, SqlSugarScopeProvider db, World world)
  236. {
  237. var billBomsetgrp = db.Queryable<BillBomsetgrp>().Single(x => x.IsStop == 0 && x.BomCode.Contains(task.MatCode));
  238. if (billBomsetgrp == null)
  239. {
  240. world.Log($"物料规格[{task.MatCode}]无可用码垛垛形");
  241. return;
  242. }
  243. ;
  244. var billBomsetinfos = db.Queryable<BillBomsetinfo>().Where(x => x.BomSetHdrId == billBomsetgrp.Id).ToList();
  245. var addTime = DateTime.Now;
  246. //开始构造垛形信息
  247. var palletizing = new WCS_Palletizing()
  248. {
  249. Code = billBomsetgrp.Code,
  250. ShortCode = billBomsetgrp.ShortCode,
  251. ProMaterCode = billBomsetgrp.ProMaterCode,
  252. TpTypeCode = billBomsetgrp.TpTypeCode,
  253. LayerCountQty = 2,
  254. StampType = billBomsetgrp.StampType,
  255. Finish = false,
  256. AddTime = addTime,
  257. EditTime = addTime,
  258. TaskId = task.ID,
  259. WarehouseCode = task.WarehouseCode,
  260. DeviceCode = task.Device
  261. };
  262. var matInfoList = db.Queryable<BaseMatinfo>().NoLock().Where(x => x.TimeOut != 0).ToList();
  263. var defaultOutTime = db.Queryable<fjSysConfig>().First(x => x.Code == "DefaultOutTime") ?? new fjSysConfig() { SContent = "12" };
  264. palletizing = db.InsertableRowLock(palletizing).ExecuteReturnEntity();
  265. foreach (var item in billBomsetinfos.Where(x => x.IsEmpty == 0).GroupBy(x => x.Row).OrderBy(x => x.Key))
  266. {
  267. var layerNo = item.Key <= 6 ? 1 : 2;
  268. //获取层信息
  269. var palletizingLayer = db.Queryable<WCS_PalletizingLayer>().Single(x => x.PalletizingId == palletizing.Id && x.LayerNo == layerNo);
  270. if (palletizingLayer == null)
  271. {
  272. palletizingLayer = new WCS_PalletizingLayer()
  273. {
  274. LayerNo = layerNo,
  275. PalletizingId = palletizing.Id,
  276. WarehouseCode = palletizing.WarehouseCode,
  277. };
  278. palletizingLayer = db.InsertableRowLock(palletizingLayer).ExecuteReturnEntity();
  279. }
  280. //获取行信息
  281. var palletizingRow = db.Queryable<WCS_PalletizingRow>().Single(x => x.PalletizingLayerId == palletizingLayer.Id && x.RowNo == item.Key);
  282. if (palletizingRow == null)
  283. {
  284. palletizingRow = new WCS_PalletizingRow()
  285. {
  286. RowNo = item.Key,
  287. PalletizingLayerId = palletizingLayer.Id,
  288. PalletizingId = palletizing.Id,
  289. WarehouseCode = palletizingLayer.WarehouseCode,
  290. AddTime = addTime,
  291. EditTime = addTime,
  292. };
  293. palletizingRow = db.InsertableRowLock(palletizingRow).ExecuteReturnEntity();
  294. }
  295. //重新查询最新的数据
  296. var layer = palletizingLayer;
  297. palletizingLayer = db.Queryable<WCS_PalletizingLayer>().Single(x => x.Id == layer.Id);
  298. var row = palletizingRow;
  299. palletizingRow = db.Queryable<WCS_PalletizingRow>().Single(x => x.Id == row.Id);
  300. //构造位信息
  301. foreach (var loc in item)
  302. {
  303. var palletizingLoc = db.Queryable<WCS_PalletizingLoc>().Single(x => x.PalletizingRowId == palletizingRow.Id && x.XYNo == loc.XYNo);
  304. if (palletizingLoc == null)
  305. {
  306. palletizingLoc = new WCS_PalletizingLoc()
  307. {
  308. IsEmpty = loc.IsEmpty != 0,
  309. XYNo = loc.XYNo,
  310. MatCode = loc.MatCode,
  311. SideNum = loc.SideNum,
  312. SpoolType = loc.SpoolType,
  313. TaskId = task.ID,
  314. PalletizingRowId = palletizingRow.Id,
  315. Finish = false,
  316. PalletizingId = palletizing.Id,
  317. WarehouseCode = palletizingRow.WarehouseCode,
  318. TimeOut = matInfoList.GetOutTime(loc.MatCode, defaultOutTime.SContent)
  319. };
  320. db.InsertableRowLock(palletizingLoc).ExecuteReturnEntity();
  321. }
  322. //同步是否混合料行
  323. palletizingRow.IsMixRow = loc.IsMixRow != 0;
  324. db.UpdateableRowLock(palletizingRow).UpdateColumns(x => new { x.IsMixRow }).ExecuteCommand();
  325. }
  326. //更新行信息
  327. palletizingRow = db.Queryable<WCS_PalletizingRow>().Includes(x => x.Locs).Single(x => x.Id == row.Id);
  328. palletizingRow.QtyMaxCount = palletizingRow.Locs.Count(x => !x.IsEmpty);
  329. palletizingRow.IsEmpty = palletizingRow.QtyMaxCount <= 0;
  330. palletizingRow.MatCodeList = palletizingRow.Locs.Select(x => x.MatCode).ToList().GetMatList();
  331. db.UpdateableRowLock(palletizingRow).UpdateColumns(x => new { x.QtyMaxCount, x.IsEmpty, x.MatCodeList }).ExecuteCommand();
  332. //更新层信息
  333. palletizingLayer = db.Queryable<WCS_PalletizingLayer>().Includes(x => x.Rows, l => l.Locs).Single(x => x.Id == layer.Id);
  334. var count = palletizingLayer.Rows.Count(x => !x.IsEmpty); //计算所有不空数量
  335. palletizingLayer.IsEmpty = count <= 0;
  336. palletizingLayer.RowCountQty = palletizingLayer.Rows.Count;
  337. palletizingLayer.Finish = false;
  338. palletizingLayer.MatCodeList = palletizingLayer.Rows.SelectMany(x => x.Locs).Select(x => x.MatCode).ToList().GetMatList();
  339. db.UpdateableRowLock(palletizingLayer).UpdateColumns(x => new { x.IsEmpty, x.RowCountQty, x.Finish, x.MatCodeList }).ExecuteCommand();
  340. }
  341. var palletizing1 = palletizing;
  342. palletizing = db.Queryable<WCS_Palletizing>().Includes(x => x.Layers, r => r.Rows, l => l.Locs).Single(x => x.Id == palletizing1.Id);
  343. //计算垛形信息
  344. var goods = palletizing.Layers.Select(x => x.Rows).SelectMany(x => x).Select(x => x.Locs).SelectMany(x => x).ToList();
  345. palletizing.CountQty = goods.Count(x => !x.IsEmpty);
  346. palletizing.MatCodeList = palletizing.Layers.SelectMany(x => x.Rows).SelectMany(x => x.Locs).Select(x => x.MatCode).ToList().GetMatList();
  347. db.UpdateableRowLock(palletizing).UpdateColumns(x => new { x.CountQty, x.MatCodeList }).ExecuteCommand();
  348. }
  349. public static string GetMatList(this List<string> matList)
  350. {
  351. return matList.Distinct().Aggregate("", (current, mat) => current + $"[{mat}]");
  352. }
  353. /// <summary>
  354. /// 去除转义字符
  355. /// </summary>
  356. /// <param name="value"></param>
  357. /// <returns></returns>
  358. public static string RemoveEscapeCharacters(this string? value)
  359. {
  360. return value.Trim('\0', '\a', '\b', '\f', '\n', '\r', '\t', '\v').Trim();
  361. }
  362. #endregion 工字轮支线分流
  363. }
  364. /// <summary>
  365. /// 垛形位信息
  366. /// </summary>
  367. public class StackPosInfo
  368. {
  369. /// <summary>
  370. /// 任务号
  371. /// </summary>
  372. public int TaskNumber { get; set; }
  373. /// <summary>
  374. /// 是否空置
  375. /// </summary>
  376. public bool IsEmpty { get; set; }
  377. /// <summary>
  378. /// 坐标号
  379. /// </summary>
  380. public string XYNo { get; set; }
  381. /// <summary>
  382. /// 物料编码
  383. /// </summary>
  384. public string MatCode { get; set; }
  385. /// <summary>
  386. /// 正反面
  387. /// </summary>
  388. public int SideNum { get; set; }
  389. /// <summary>
  390. /// 工字轮类型
  391. /// </summary>
  392. public string SpoolType { get; set; }
  393. /// <summary>
  394. /// 是否结束
  395. /// </summary>
  396. public bool Finish { get; set; }
  397. }
  398. }