diff --git a/BasicData/Tnb.BasicData.Entities/Consts/DictConst.cs b/BasicData/Tnb.BasicData.Entities/Consts/DictConst.cs index c413b9b4..25e27e82 100644 --- a/BasicData/Tnb.BasicData.Entities/Consts/DictConst.cs +++ b/BasicData/Tnb.BasicData.Entities/Consts/DictConst.cs @@ -72,8 +72,11 @@ public static class DictConst /// 工单状态-强制接单 /// public const string MoCloseId = "25501969636645"; - - + /// + /// 工单状态-code + /// + public const string MoTaskStatusCode = "OrderStatus"; + /// /// 工单状态 已下发字典Id /// diff --git a/EquipMgr/Tnb.EquipMgr.Entities/Dto/ToolInput.cs b/EquipMgr/Tnb.EquipMgr.Entities/Dto/ToolInput.cs new file mode 100644 index 00000000..cae96d36 --- /dev/null +++ b/EquipMgr/Tnb.EquipMgr.Entities/Dto/ToolInput.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.EquipMgr.Entities +{ + public class ToolInput + { + public string? sort { get; set; } + public string? keyword { get; set; } + public string? status { get; set; } + } +} diff --git a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs index 2fe6f947..6fb1fa6c 100644 --- a/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs +++ b/EquipMgr/Tnb.EquipMgr/ToolMoldMaintainRunService.cs @@ -99,7 +99,6 @@ namespace Tnb.EquipMgr } [HttpGet] - [AllowAnonymous] public async Task GetMaintainInfo([FromQuery] MaintainInfoQueryinput input) { Dictionary dicstatus = new Dictionary(); diff --git a/EquipMgr/Tnb.EquipMgr/ToolMoldRequisitionService.cs b/EquipMgr/Tnb.EquipMgr/ToolMoldRequisitionService.cs index 7f4aa7e7..e7cbfec5 100644 --- a/EquipMgr/Tnb.EquipMgr/ToolMoldRequisitionService.cs +++ b/EquipMgr/Tnb.EquipMgr/ToolMoldRequisitionService.cs @@ -1,3 +1,4 @@ +using System.Dynamic; using JNPF.Common.Dtos.VisualDev; using JNPF.Common.Enums; using JNPF.Common.Extension; @@ -14,6 +15,7 @@ using JNPF.VisualDev.Interfaces; using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using SqlSugar; +using Tnb.BasicData.Entities; using Tnb.EquipMgr.Entities; using Tnb.EquipMgr.Entities.Dto; using Tnb.EquipMgr.Interfaces; @@ -112,5 +114,39 @@ namespace Tnb.EquipMgr if (!result.IsSuccess) throw Oops.Oh(ErrorCode.COM1008); return result.IsSuccess ? "保存成功" : result.ErrorMessage; } + [HttpPost] + public async Task GetTools(ToolInput toolinput) + { + Dictionary dic = new Dictionary(); + dic.Add("26149307089941", "在库"); + dic.Add("26149309121045", "生产"); + dic.Add("26149311082005", "保养"); + dic.Add("26149314425877", "报废"); + dic.Add("26149312750101", "外协"); + dic.Add("26149320818965", "维修"); + List result = new(); + var BasLocations = await _db.Queryable().ToListAsync(); + var ToolMolds = await _db.Queryable() + .WhereIF(!string.IsNullOrEmpty(toolinput.keyword),p=>p.mold_code!.Contains(toolinput.keyword!)|| p.mold_name!.Contains(toolinput.keyword!)) + .WhereIF(!string.IsNullOrEmpty(toolinput.status), p => p.mold_status== dic.Where(p=>p.Value== toolinput.status).First().Key) + .ToListAsync(); + if (string.IsNullOrEmpty(toolinput.sort)) + { + if (toolinput.sort == "mold_code") + ToolMolds = ToolMolds.OrderByDescending(p => p.mold_code).ToList(); + } + foreach (var tool in ToolMolds) + { + dynamic info = new ExpandoObject(); + info.id=tool.id; + info.mold_code=tool.mold_code; + info.mold_name = tool.mold_name; + info.mold_status= dic.Where(p=>p.Key==tool.mold_status).Any()? dic.Where(p => p.Key == tool.mold_status).First().Value:""; + info.warehosue_id=tool.warehosue_id; + info.location_id= BasLocations.Where(p => p.id == tool.location_id).Any() ? BasLocations.Where(p => p.id == tool.location_id).First().location_code : ""; + result.Add(info); + } + return result; + } } } \ No newline at end of file diff --git a/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PADPackageTaskPageOutput.cs b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PADPackageTaskPageOutput.cs index 93b18d85..622015f1 100644 --- a/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PADPackageTaskPageOutput.cs +++ b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PADPackageTaskPageOutput.cs @@ -91,5 +91,6 @@ namespace Tnb.ProductionMgr.Entities.Dto.PrdManage public string mold_id { get; set; } public string mold_code { get; set; } public string mold_name { get; set; } + public DateTime? create_time { get; set; } } } \ No newline at end of file diff --git a/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsInput.cs b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsInput.cs new file mode 100644 index 00000000..45254ca1 --- /dev/null +++ b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsInput.cs @@ -0,0 +1,16 @@ +namespace Tnb.ProductionMgr.Entities.Dto.PrdManage +{ + public class PrdMoStatisticsInput + { + public string mo_status { get; set; } + /// + /// 页码. + /// + public int currentPage { get; set; } + + /// + /// 页容量. + /// + public int pageSize { get; set; } + } +} \ No newline at end of file diff --git a/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsOutput.cs b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsOutput.cs new file mode 100644 index 00000000..e867dd4c --- /dev/null +++ b/ProductionMgr/Tnb.ProductionMgr.Entities/Dto/PrdManage/PrdMoStatisticsOutput.cs @@ -0,0 +1,29 @@ +namespace Tnb.ProductionMgr.Entities.Dto.PrdManage +{ + public class PrdMoStatisticsOutput + { + public string id { get; set; } + public string mo_code { get; set; } + public string mo_status { get; set; } + public string material_name { get; set; } + public string material_code { get; set; } + public decimal? plan_qty { get; set; } + public decimal? scheduled_qty { get; set; } + public decimal? tobe_scheduled_qty { get; set; } + public decimal? reported_work_qty { get; set; } + public decimal? complete_rate { get; set; } + public List children { get; set; } = new List(); + } + + public class PrdMoStatisticsDetailOutput + { + public string id { get; set; } + public string mo_task_code { get; set; } + public string mo_task_status { get; set; } + public string estimated_start_date { get; set; } + public string estimated_end_date { get; set; } + public decimal? scheduled_qty { get; set; } + public decimal? reported_work_qty { get; set; } + public decimal? scrap_qty { get; set; } + } +} \ No newline at end of file diff --git a/ProductionMgr/Tnb.ProductionMgr/PrdMoService.cs b/ProductionMgr/Tnb.ProductionMgr/PrdMoService.cs index 9c7ca149..4b418519 100644 --- a/ProductionMgr/Tnb.ProductionMgr/PrdMoService.cs +++ b/ProductionMgr/Tnb.ProductionMgr/PrdMoService.cs @@ -362,7 +362,52 @@ namespace Tnb.ProductionMgr .ExecuteCommandHasChangeAsync(); } - + /// + /// 工单统计 + /// + /// + /// + [HttpPost] + public async Task GetPrdMoStatistics(PrdMoStatisticsInput input) + { + var result = await _db.Queryable() + .LeftJoin((a, b) => a.mo_status == b.Id) + .LeftJoin((a, b, c) => a.material_id == c.id) + .WhereIF(!string.IsNullOrEmpty(input.mo_status), (a, b) => b.EnCode == input.mo_status) + // .OrderByDescending((a,b,c)=>a.reported_work_qty==null?0:a.reported_work_qty*100/a.plan_qty) + .Select((a, b, c) => new PrdMoStatisticsOutput + { + id = a.id, + mo_code = a.mo_code, + mo_status = b.FullName, + material_code = c.code, + material_name = c.name, + plan_qty = a.plan_qty, + scheduled_qty = a.scheduled_qty, + tobe_scheduled_qty = a.plan_qty - a.scheduled_qty, + reported_work_qty = a.reported_work_qty, + complete_rate = a.reported_work_qty==null?0:SqlFunc.ToDecimal(a.reported_work_qty*100)/SqlFunc.ToDecimal(a.plan_qty), + children = SqlFunc.Subqueryable() + .LeftJoin((x,y)=>x.mo_task_status==y.EnCode && y.DictionaryTypeId==DictConst.PrdTaskStatusTypeId) + .Where(x=>x.mo_id==a.id && !SqlFunc.IsNullOrEmpty(x.parent_id)) + .OrderByDesc((x,y)=>x.create_time) + .ToList((x,y)=>new PrdMoStatisticsDetailOutput() + { + id = x.id, + mo_task_code = x.mo_task_code, + mo_task_status = y.FullName, + estimated_start_date = x.estimated_start_date==null ? "" : x.estimated_start_date.Value.ToString("yyyy-MM-dd HH:mm:ss"), + estimated_end_date = x.estimated_end_date==null ? "" : x.estimated_end_date.Value.ToString("yyyy-MM-dd HH:mm:ss"), + scheduled_qty = x.scheduled_qty, + reported_work_qty = x.reported_work_qty, + scrap_qty = x.scrap_qty, + }), + }) + .MergeTable().OrderByDescending(a=>a.complete_rate) + .ToPagedListAsync(input.currentPage, input.pageSize); + + return PageResult.SqlSugarPageResult(result); + } #endregion diff --git a/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs b/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs index 87d405c5..ece210a1 100644 --- a/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs +++ b/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs @@ -670,6 +670,9 @@ namespace Tnb.ProductionMgr if (input.schedule_type.Value == 1) //注塑、基础排产 { var mo = await db.Queryable().FirstAsync(it => it.id == input.mo_id); + BasMbomProcess basMbomProcess = null; + if(!string.IsNullOrEmpty(input.bom_id)) + basMbomProcess = await db.Queryable().FirstAsync(x => x.mbom_id == input.bom_id); var moTask = input.Adapt(); moTask.id = SnowflakeIdHelper.NextId(); moTask.create_id = _userManager.UserId; @@ -677,6 +680,7 @@ namespace Tnb.ProductionMgr moTask.mo_task_status = DictConst.ToBeScheduledEncode; moTask.scheduled_qty = input.scheduled_qty; moTask.unit_id = mo.unit_id; + moTask.mbom_process_id = basMbomProcess?.id ?? ""; if (!string.IsNullOrEmpty(input.eqp_id)) { @@ -2335,6 +2339,26 @@ namespace Tnb.ProductionMgr return result.IsSuccess ? "排产成功" : result.ErrorMessage; } + /// + /// 获取工单各个状态数量 + /// + /// + [HttpPost] + public async Task GetMoTaskStatusNum() + { + return await _db.Queryable(). + LeftJoin((a,b)=>a.Id==b.DictionaryTypeId) + .LeftJoin((a,b,c)=>b.Id==c.mo_status) + .Where((a,b,c)=>a.EnCode==DictConst.MoTaskStatusCode) + .GroupBy((a,b,c)=>new { mo_status_code = b.EnCode,mo_status_name = b.FullName}) + .Select((a,b,c) => new + { + mo_status_code = b.EnCode, + mo_status_name = b.FullName, + count = SqlFunc.AggregateCount(c.mo_status) + }).ToListAsync(); + } + } diff --git a/ProductionMgr/Tnb.ProductionMgr/PrdPackReportService.cs b/ProductionMgr/Tnb.ProductionMgr/PrdPackReportService.cs index 6ed5f27f..664a4b4d 100644 --- a/ProductionMgr/Tnb.ProductionMgr/PrdPackReportService.cs +++ b/ProductionMgr/Tnb.ProductionMgr/PrdPackReportService.cs @@ -341,9 +341,72 @@ namespace Tnb.ProductionMgr return PageResult.SqlSugarPageResult(result); } + + /// + /// pda端根据工位获取任务单列表 + /// + /// + [HttpPost] + public async Task GetPadPrdMoTaskList(PrdPackReportQueryInput input) + { + if (string.IsNullOrEmpty(input.stationId)) + { + return new + { + pagination = new PageResult(), + list = Array.Empty() + }; + } + + var result = await _db.Queryable() + .LeftJoin((a, b) => a.material_id == b.id) + .LeftJoin((a, b, c) => a.process_id == c.id) + .LeftJoin((a, b, c, d) => a.workline_id == d.Id) + .LeftJoin((a, b, c, d, e) => e.DictionaryTypeId == DictConst.PrdTaskStatusTypeId && a.mo_task_status == e.EnCode) + .LeftJoin((a,b,c,d,e,f)=>a.eqp_id==f.id) + .LeftJoin((a,b,c,d,e,f,g)=>a.mold_id==g.id) + .Where((a, b) => a.workstation_id == input.stationId && (a.mo_task_status == DictConst.ToBeStartedEnCode || a.mo_task_status == DictConst.MoStatusPauseCode || a.mo_task_status == DictConst.ComplatedEnCode || a.mo_task_status == DictConst.InProgressEnCode) ) + .Select((a, b, c, d, e,f,g) => new PADPackageTaskPageOutput + { + id = a.id, + mo_task_code = a.mo_task_code, + mo_id = a.mo_id, + material_id = a.material_id, + material_code = b.code, + material_name = b.name, + workline_id = a.workline_id, + workline_name = d.FullName, + bom_id = a.bom_id, + mo_task_status = e.FullName, + complete_qty = SqlFunc.IsNull(a.reported_work_qty,0) + SqlFunc.IsNull(a.scrap_qty,0), + scrap_qty = a.scrap_qty, + scheduled_qty = a.scheduled_qty, + reported_work_qty = a.reported_work_qty, + estimated_start_date = a.estimated_start_date==null ? "" : a.estimated_start_date.Value.ToString("yyyy-MM-dd HH:mm:ss"), + estimated_end_date = a.estimated_end_date==null ? "" : a.estimated_end_date.Value.ToString("yyyy-MM-dd HH:mm:ss"), + parent_id = a.parent_id, + process_id = a.process_id, + process_name = c.process_name, + mbom_process_id = a.mbom_process_id, + create_time = a.create_time, + equip_id = a.eqp_id, + equip_code = f.code, + equip_name = f.name, + mold_id = a.mold_id, + mold_code = g.mold_code, + mold_name = g.mold_name, + schedule_type = a.schedule_type, + }) + .MergeTable() + .OrderByDescending((a) => a.create_time) + .ToPagedListAsync(input.currentPage, int.MaxValue); + + return PageResult.SqlSugarPageResult(result); + + } /// - /// pda端根据工位获取组装包装列表 + /// 上模校验 /// /// [HttpPost] diff --git a/QcMgr/Tnb.QcMgr.Entities/Dto/CheckTaskData.cs b/QcMgr/Tnb.QcMgr.Entities/Dto/CheckTaskData.cs new file mode 100644 index 00000000..0683b82b --- /dev/null +++ b/QcMgr/Tnb.QcMgr.Entities/Dto/CheckTaskData.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tnb.QcMgr.Entities +{ + public class CheckTaskData + { + public string? checktype { get; set; } + + public string? materialid { get; set; } + public string? processid { get; set; } + public string? workid { get; set; } + public string? wareid { get; set; } + public List? checktypes { get; set; } + } + + public class CheckTaskDataInput + { + public string? id { get; set; } + public List? items { get; set; } + } + public class TaskItemInput + { + public string? itemid { get; set; } + public string? extype { get; set; } + public string? excontent { get; set; } + public string? check { get; set; } + public string? errorcause { get; set; } + public string? errorlevel { get; set; } + public string? remark { get; set; } + public string? attachment { get; set; } + public string? isexec { get; set; } + public string? customer { get; set; } + } +} diff --git a/QcMgr/Tnb.QcMgr/QcCheckPlanService.cs b/QcMgr/Tnb.QcMgr/QcCheckPlanService.cs index 8c6c0a34..0793142c 100644 --- a/QcMgr/Tnb.QcMgr/QcCheckPlanService.cs +++ b/QcMgr/Tnb.QcMgr/QcCheckPlanService.cs @@ -94,7 +94,7 @@ namespace Tnb.QcMgr CheckPlansOut.addid = QcCheckPlanAdd.id; CheckPlansOut.triggertype = QcCheckPlanAdd.triggertype!; CheckPlansOut.content = QcCheckPlanAdd.content!; - CheckPlansOut.number= QcCheckPlanAdd.number; + CheckPlansOut.number = QcCheckPlanAdd.number; } if (QcCheckPlanDs != null && QcCheckPlanDs.Count > 0) { @@ -137,7 +137,18 @@ namespace Tnb.QcMgr Item.setShow.remark = !string.IsNullOrEmpty(Item.setData.remark); Item.setShow.attachment = !string.IsNullOrEmpty(Item.setData.attachment); Item.setShow.customer = !string.IsNullOrEmpty(Item.setData.customer); - Item.setShow.isexec = Item.setData.isexec == null ? false : true; + if (Item.setData.isexec == null) + { + Item.setShow.isexec = false; + } + else + { + if(!Item.setData.isexec.attachment&& !Item.setData.isexec.remark) + Item.setShow.isexec = false; + else + Item.setShow.isexec = true; + } + CheckPlansOut.checktypes.Where(p => p.checktypeid == QcCheckPlanD.typeid).First()?.items?.Add(Item); } } @@ -187,6 +198,7 @@ namespace Tnb.QcMgr { if (string.IsNullOrEmpty(CheckPlanInput.mainid)) return; + await _timeTaskService.DeleteByName("生成质检任务" + CheckPlanInput.mainid); await db.Deleteable(p => p.mainid == CheckPlanInput.mainid).ExecuteCommandAsync(); await db.Deleteable(p => p.mainid == CheckPlanInput.mainid).ExecuteCommandAsync(); QcCheckPlanAdd QcCheckPlanAdd = new QcCheckPlanAdd(); @@ -280,10 +292,47 @@ namespace Tnb.QcMgr JoinType.Left,a.id == e.planid, }); GetQuery(Query, entity); - var list = await Query - .WhereIF(!string.IsNullOrEmpty(entity.materialid), (a, b, c, d, e) => c.materialid == entity.materialid) - .WhereIF(!string.IsNullOrEmpty(entity.processid), (a, b, c, d, e) => d.processid == entity.processid) - .WhereIF(!string.IsNullOrEmpty(entity.workid), (a, b, c, d, e) => e.workid == entity.workid).ToListAsync(); + var list = await Query.ToListAsync(); + List removes = new List(); + foreach (var data in list) + { + if (!string.IsNullOrEmpty(entity.materialid)) + { + if (_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id).Any()) + { + if (!_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id && p.materialid == entity.materialid).Any()) + { + removes.Add(data.id); + } + } + } + if (!string.IsNullOrEmpty(entity.processid)) + { + if (_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id).Any()) + { + if (!_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id && p.processid == entity.processid).Any()) + { + removes.Add(data.id); + } + + } + } + if (!string.IsNullOrEmpty(entity.workid)) + { + if (_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id).Any()) + { + if (!_repository.AsSugarClient().Queryable().Where(p => p.planid == data.id && p.workid == entity.workid).Any()) + { + removes.Add(data.id); + } + } + } + } + + list = list.Where(p => !removes.Contains(p.id)).ToList(); + // .WhereIF(!string.IsNullOrEmpty(entity.materialid), (a, b, c, d, e) => c.materialid == entity.materialid) + // .WhereIF(!string.IsNullOrEmpty(entity.processid), (a, b, c, d, e) => d.processid == entity.processid) + // .WhereIF(!string.IsNullOrEmpty(entity.workid), (a, b, c, d, e) => e.workid == entity.workid).ToListAsync(); Filter(list, entity); if (list.Count > 0) await SaveTask(list, entity); @@ -410,5 +459,6 @@ namespace Tnb.QcMgr await _repository.AsSugarClient().Insertable(ExecDs).ExecuteCommandAsync(); } } + } } diff --git a/QcMgr/Tnb.QcMgr/QcCheckTaskResultService.cs b/QcMgr/Tnb.QcMgr/QcCheckTaskResultService.cs index f33ee000..ee0fd197 100644 --- a/QcMgr/Tnb.QcMgr/QcCheckTaskResultService.cs +++ b/QcMgr/Tnb.QcMgr/QcCheckTaskResultService.cs @@ -40,6 +40,12 @@ namespace Tnb.QcMgr private async Task GetListAsync(VisualDevModelListQueryInput input) { var db = _repository.AsSugarClient(); + Dictionary dic= new Dictionary(); + dic.Add("ok", "合格"); + dic.Add("no", "不合格"); + dic.Add("barelyok", "让步合格"); + dic.Add("await", "待检"); + dic.Add("temporarily", "暂控"); Dictionary queryJson = !string.IsNullOrEmpty(input.queryJson) ? JsonConvert.DeserializeObject>(input.queryJson) : new Dictionary(); string materialid = queryJson.ContainsKey("materialid") ? queryJson["materialid"].ToString() : ""; string checktype = queryJson.ContainsKey("checktype") ? queryJson["checktype"].ToString() : ""; @@ -47,6 +53,7 @@ namespace Tnb.QcMgr var list = await db.Queryable() .LeftJoin((a, b) => a.DictionaryTypeId == b.Id) .Where((a, b) => b.FullName == "质检状态" || b.FullName == "质检类型选择").ToListAsync(); + var BasLocations= await db.Queryable().ToListAsync(); var result = await db.Queryable() .LeftJoin((a, b) => a.materialid == b.id) .LeftJoin((a, b, c) => a.processid == c.id) @@ -70,11 +77,13 @@ namespace Tnb.QcMgr tasktime = a.tasktime == null ? "" : a.tasktime, exectime = a.exectime == null ? "" : a.exectime, execuser = e.RealName == null ? "" : e.RealName, - }).OrderByDescending(a => a.tasktime).ToPagedListAsync(input.currentPage, input.pageSize); + }).OrderByDescending(a =>DateTime.Parse( a.exectime)).ToPagedListAsync(input.currentPage, input.pageSize); foreach (var item in result.list) { item.checktype = list.Select(p => p.Id).Contains(item.checktype) ? list.Where(p => p.Id == item.checktype).First().FullName : ""; item.status = list.Select(p => p.Id).Contains(item.status) ? list.Where(p => p.Id == item.status).First().FullName : ""; + item.result = dic.Where(p => p.Key == item.result).Any() ? dic.Where(p => p.Key == item.result).First().Value : ""; + item.wareid = BasLocations.Where(p => p.id == item.wareid).Any() ? BasLocations.Where(p => p.id == item.wareid).First().location_code: ""; } return PageResult.SqlSugarPageResult(result); } diff --git a/QcMgr/Tnb.QcMgr/QcCheckTaskService.cs b/QcMgr/Tnb.QcMgr/QcCheckTaskService.cs index 431fd37d..5634bf81 100644 --- a/QcMgr/Tnb.QcMgr/QcCheckTaskService.cs +++ b/QcMgr/Tnb.QcMgr/QcCheckTaskService.cs @@ -31,6 +31,7 @@ using Tnb.QcMgr.Entities; using Tnb.QcMgr.Entities.Entity; using Tnb.QcMgr.Interfaces; using JNPF.Common.Extension; +using Microsoft.AspNetCore.Authorization; namespace Tnb.QcMgr { @@ -56,6 +57,12 @@ namespace Tnb.QcMgr private async Task GetListAsync(VisualDevModelListQueryInput input) { var db = _repository.AsSugarClient(); + Dictionary dic = new Dictionary(); + dic.Add("ok", "合格"); + dic.Add("no", "不合格"); + dic.Add("barelyok", "让步合格"); + dic.Add("await", "待检"); + dic.Add("temporarily", "暂控"); Dictionary queryJson = !string.IsNullOrEmpty(input.queryJson) ? JsonConvert.DeserializeObject>(input.queryJson) : new Dictionary(); string materialid = queryJson.ContainsKey("materialid") ? queryJson["materialid"].ToString() : ""; string checktype = queryJson.ContainsKey("checktype") ? queryJson["checktype"].ToString() : ""; @@ -63,6 +70,7 @@ namespace Tnb.QcMgr var list = await db.Queryable() .LeftJoin((a, b) => a.DictionaryTypeId == b.Id) .Where((a, b) => b.FullName == "质检状态" || b.FullName == "质检类型选择").ToListAsync(); + var BasLocations = await db.Queryable().ToListAsync(); var result = await db.Queryable() .LeftJoin((a, b) => a.materialid == b.id) .LeftJoin((a, b, c) => a.processid == c.id) @@ -86,11 +94,13 @@ namespace Tnb.QcMgr tasktime = a.tasktime == null ? "" : a.tasktime, exectime = a.exectime == null ? "" : a.exectime, execuser = e.RealName == null ? "" : e.RealName, - }).OrderByDescending(a => a.tasktime).ToPagedListAsync(input.currentPage, input.pageSize); + }).OrderByDescending(a => DateTime.Parse(a.tasktime)).ToPagedListAsync(input.currentPage, input.pageSize); foreach (var item in result.list) { item.checktype = list.Select(p => p.Id).Contains(item.checktype) ? list.Where(p => p.Id == item.checktype).First().FullName : ""; item.status = list.Select(p => p.Id).Contains(item.status) ? list.Where(p => p.Id == item.status).First().FullName : ""; + item.result = dic.Where(p => p.Key == item.result).Any() ? dic.Where(p => p.Key == item.result).First().Value : ""; + item.wareid = BasLocations.Where(p => p.id == item.wareid).Any() ? BasLocations.Where(p => p.id == item.wareid).First().location_code : ""; } return PageResult.SqlSugarPageResult(result); } @@ -164,8 +174,8 @@ namespace Tnb.QcMgr Item.setShow.extype = !string.IsNullOrEmpty(Item.setData.extype); Item.setShow.excontent = !string.IsNullOrEmpty(QcCheckExecD.excontent); Item.setShow.check = !string.IsNullOrEmpty(Item.setData.check); - Item.setShow.errorcause = Item.setData.errorcause?.Count == 0 ? false : true; - Item.setShow.errorlevel = Item.setData.errorlevel?.Count == 0 ? false : true; + Item.setShow.errorcause = Item.setData.errorcause==null|| Item.setData.errorcause?.Count == 0 ? false : true; + Item.setShow.errorlevel = Item.setData.errorlevel == null || Item.setData.errorlevel?.Count == 0 ? false : true; Item.setShow.remark = !string.IsNullOrEmpty(Item.setData.remark); Item.setShow.attachment = !string.IsNullOrEmpty(Item.setData.attachment); Item.setShow.customer = !string.IsNullOrEmpty(Item.setData.customer); @@ -209,6 +219,8 @@ namespace Tnb.QcMgr { foreach (var item in exextype.items) { + if (item.postItemForm == null) + throw Oops.Oh("执行失败"); var QcCheckExecD = QcCheckExecDs.Where(p => p.id == item.itemdid).FirstOrDefault(); if (QcCheckExecD == null) continue; @@ -247,8 +259,7 @@ namespace Tnb.QcMgr } catch (Exception) { - - throw Oops.Oh(ErrorCode.COM1000); + throw Oops.Oh("执行失败"); } } @@ -339,6 +350,59 @@ namespace Tnb.QcMgr return Result; } + + [HttpPost] + public async Task CreateTaskData(CheckTaskData checkTaskData) + { + var db = _repository.AsSugarClient(); + var DictionaryType = await db.Queryable().Where(p => p.FullName == "质检状态").FirstAsync(); + var DictionaryData = await db.Queryable().Where(p => p.DictionaryTypeId == DictionaryType.Id && p.FullName == "待执行").FirstAsync(); + QcCheckExecH QcCheckExecH = new QcCheckExecH(); + QcCheckExecH.checktype = checkTaskData.checktype; + QcCheckExecH.materialid = checkTaskData.materialid; + QcCheckExecH.processid = checkTaskData.processid; + QcCheckExecH.workid = checkTaskData.workid; + QcCheckExecH.wareid = checkTaskData.wareid; + QcCheckExecH.status = DictionaryData.Id; + QcCheckExecH.tasktime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); + QcCheckExecH.create_id = _userManager.UserId; + QcCheckExecH.create_time = DateTime.Now; + List QcCheckExecDs = new List(); + if (checkTaskData.checktypes != null) + { + foreach (var checktype in checkTaskData.checktypes) + { + if (checktype.items != null) + { + foreach (var item in checktype.items) + { + QcCheckExecD QcCheckExecD = new QcCheckExecD(); + QcCheckExecD.mainid = QcCheckExecH.id; + QcCheckExecD.typeid = checktype.id; + QcCheckExecD.itemid = item.itemid; + QcCheckExecD.extype = item.extype; + QcCheckExecD.excontent = item.excontent; + QcCheckExecD.check = item.check; + QcCheckExecD.errorcause = item.errorcause?.Replace("\"", "").Trim(); + QcCheckExecD.errorlevel = item.errorlevel?.Replace("\"", "").Trim(); + QcCheckExecD.remark = item.remark; + QcCheckExecD.attachment = item.attachment; + QcCheckExecD.isexec = item.isexec; + QcCheckExecD.custom = item.customer; + QcCheckExecD.create_id = _userManager.UserId; + QcCheckExecD.create_time = DateTime.Now; + QcCheckExecDs.Add(QcCheckExecD); + } + } + } + } + await db.Ado.BeginTranAsync(); + await db.Insertable(QcCheckExecH).ExecuteCommandAsync(); + await db.Insertable(QcCheckExecDs).ExecuteCommandAsync(); + await db.Ado.CommitTranAsync(); + + } + } } diff --git a/taskschedule/Tnb.TaskScheduler.Interfaces/ITimeTaskService.cs b/taskschedule/Tnb.TaskScheduler.Interfaces/ITimeTaskService.cs index 88626728..e8559489 100644 --- a/taskschedule/Tnb.TaskScheduler.Interfaces/ITimeTaskService.cs +++ b/taskschedule/Tnb.TaskScheduler.Interfaces/ITimeTaskService.cs @@ -16,5 +16,5 @@ public interface ITimeTaskService /// void StartTimerJob(); - List GetTasks(); + Task> GetTasks(); } diff --git a/taskschedule/Tnb.TaskScheduler/Listener/MoldMaintainTask.cs b/taskschedule/Tnb.TaskScheduler/Listener/MoldMaintainTask.cs index 64648af6..8c0418e3 100644 --- a/taskschedule/Tnb.TaskScheduler/Listener/MoldMaintainTask.cs +++ b/taskschedule/Tnb.TaskScheduler/Listener/MoldMaintainTask.cs @@ -26,15 +26,16 @@ namespace Tnb.TaskScheduler.Listener { try { - var TimeTasks = timeTaskService.GetTasks(); - var timeTaskEntity = TimeTasks.Where(p => p.Id == timer.WorkerName && p.EnabledMark == 1).First(); + var TimeTasks =await timeTaskService.GetTasks(); + var timeTaskEntity = TimeTasks.Where(p => p.Id == timer.WorkerName && p.EnabledMark == 1).FirstOrDefault(); if (timeTaskEntity == null) return; ContentModel? comtentModel = timeTaskEntity.ExecuteContent.ToObject(); - var ToolMoldMaintainRule = await repository.AsSugarClient().Queryable().Where(p => p.id == comtentModel.parameter.Where(p => p.field == "id").First().value).FirstAsync(); + var client = repository.CopyNew(); + var ToolMoldMaintainRule = await client.Queryable().Where(p => p.id == comtentModel.parameter.Where(p => p.field == "id").First().value).FirstAsync(); if (ToolMoldMaintainRule == null) return; - var ToolMoldMaintainRuleRelations= await repository.AsSugarClient().Queryable().Where(p => p.rule_id == ToolMoldMaintainRule.id).ToListAsync(); + var ToolMoldMaintainRuleRelations= await client.Queryable().Where(p => p.rule_id == ToolMoldMaintainRule.id).ToListAsync(); if (ToolMoldMaintainRuleRelations.Count() > 0) { var now = DateTime.Now; @@ -58,8 +59,8 @@ namespace Tnb.TaskScheduler.Listener toolMoldMaintainPlanRelation.group_id = ToolMoldMaintainRuleRelation.item_group_id; toolMoldMaintainPlanRelations.Add(toolMoldMaintainPlanRelation); } - await repository.AsSugarClient().Insertable(toolMoldMaintainPlanRelations).ExecuteCommandAsync(); - await repository.AsSugarClient().Insertable(toolMoldMaintainPlan).ExecuteCommandAsync(); + await client.Insertable(toolMoldMaintainPlanRelations).ExecuteCommandAsync(); + await client.Insertable(toolMoldMaintainPlan).ExecuteCommandAsync(); } } catch (Exception) diff --git a/taskschedule/Tnb.TaskScheduler/Listener/QcTaskTimeWorker.cs b/taskschedule/Tnb.TaskScheduler/Listener/QcTaskTimeWorker.cs index dae48ea4..851c3382 100644 --- a/taskschedule/Tnb.TaskScheduler/Listener/QcTaskTimeWorker.cs +++ b/taskschedule/Tnb.TaskScheduler/Listener/QcTaskTimeWorker.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Aop.Api.Domain; using JNPF; using JNPF.Common.Security; using JNPF.Systems.Entitys.System; @@ -32,71 +33,120 @@ namespace Tnb.TaskScheduler.Listener { try { - var TimeTasks = timeTaskService.GetTasks(); - var timeTaskEntity = TimeTasks.Where(p => p.Id == timer.WorkerName && p.EnabledMark == 1).First(); + var TimeTasks =await timeTaskService.GetTasks(); + var timeTaskEntity = TimeTasks.Where(p => p.Id == timer.WorkerName && p.EnabledMark == 1).FirstOrDefault(); if (timeTaskEntity == null) return; ContentModel? comtentModel = timeTaskEntity.ExecuteContent.ToObject(); - var PlanH = await repository.AsSugarClient().Queryable().Where(p => p.id == comtentModel.parameter.Where(p => p.field == "id").First().value).FirstAsync(); - var PlanDs = await repository.AsSugarClient().Queryable().Where(p => p.mainid == PlanH.id).ToListAsync(); + var client= repository.CopyNew(); + var PlanH = await client.Queryable().Where(p => p.id == comtentModel.parameter.Where(p => p.field == "id").First().value).FirstAsync(); + var PlanDs = await client.Queryable().Where(p => p.mainid == PlanH.id).ToListAsync(); if (PlanH == null || PlanDs.Count == 0) return; - var PlanMaterials = repository.AsSugarClient().Queryable().Where(p => p.planid == PlanH.id).Select(p => p.materialid).ToList(); - var PlanProcesss = repository.AsSugarClient().Queryable().Where(p => p.planid == PlanH.id).Select(p => p.processid).ToList(); - var PlanWork = repository.AsSugarClient().Queryable().Where(p => p.planid == PlanH.id).Select(p => p.workid).ToList(); - //物料工序工位不能同时为空 - if (PlanMaterials.Count == 0 && PlanProcesss.Count == 0 && PlanWork.Count == 0) - return; - var PrdMoTasks = await repository.AsSugarClient().Queryable() - .WhereIF(PlanMaterials.Count > 0, p => PlanMaterials.Contains(p.material_id)) - .WhereIF(PlanProcesss.Count > 0, p => PlanProcesss.Contains(p.process_id)) - .WhereIF(PlanWork.Count > 0, p => PlanWork.Contains(p.workstation_id)) - .Where(p => p.mo_task_status == "InProgress")//进行中 - .ToListAsync(); - - var DictionaryType = await repository.AsSugarClient().Queryable().Where(p => p.FullName == "质检状态").FirstAsync(); - var DictionaryData = await repository.AsSugarClient().Queryable().Where(p => p.DictionaryTypeId == DictionaryType.Id && p.FullName == "待执行").FirstAsync(); - var time = DateTime.Now; - foreach (var PrdMoTask in PrdMoTasks) + List strs = new List(); + strs.Add("26589795199765");//首检 + strs.Add("26589835919125");//生产检 + strs.Add("26590141686549");//巡检 + if (strs.Contains(PlanH.checktype)) { + var PlanMaterials = await client.Queryable().Where(p => p.planid == PlanH.id).Select(p => p.materialid).ToListAsync(); + var PlanProcesss = await client.Queryable().Where(p => p.planid == PlanH.id).Select(p => p.processid).ToListAsync(); + var PlanWork = await client.Queryable().Where(p => p.planid == PlanH.id).Select(p => p.workid).ToListAsync(); + //物料工序工位不能同时为空 + if (PlanMaterials.Count == 0 && PlanProcesss.Count == 0 && PlanWork.Count == 0) + return; + var PrdMoTasks = await client.Queryable() + .WhereIF(PlanMaterials.Count > 0, p => PlanMaterials.Contains(p.material_id)) + .WhereIF(PlanProcesss.Count > 0, p => PlanProcesss.Contains(p.process_id)) + .WhereIF(PlanWork.Count > 0, p => PlanWork.Contains(p.workstation_id)) + .Where(p => p.mo_task_status == "InProgress")//进行中 + .ToListAsync(); - QcCheckExecH qcCheckExecH = new QcCheckExecH(); - qcCheckExecH.id = SnowflakeIdHelper.NextId(); - qcCheckExecH.checktype = PlanH.checktype; - qcCheckExecH.status = DictionaryData.Id; - qcCheckExecH.tasktime = time.ToString("yyyy-MM-dd HH:mm:ss"); - qcCheckExecH.materialid = PrdMoTask.material_id; - qcCheckExecH.processid = PrdMoTask.process_id; - qcCheckExecH.workid = PrdMoTask.workstation_id; - qcCheckExecH.create_time = time; - var ExecDs = new List(); - foreach (var PlanD in PlanDs) + var DictionaryType = await client.Queryable().Where(p => p.FullName == "质检状态").FirstAsync(); + var DictionaryData = await client.Queryable().Where(p => p.DictionaryTypeId == DictionaryType.Id && p.FullName == "待执行").FirstAsync(); + var time = DateTime.Now; + foreach (var PrdMoTask in PrdMoTasks) { - QcCheckExecD QcCheckExecD = new QcCheckExecD(); - QcCheckExecD.mainid = qcCheckExecH.id; - QcCheckExecD.extype = PlanD.extype; - QcCheckExecD.excontent = PlanD.excontent; - QcCheckExecD.check = PlanD.check; - QcCheckExecD.errorcause = PlanD.errorcause; - QcCheckExecD.errorlevel = PlanD.errorlevel; - QcCheckExecD.remark = PlanD.remark; - QcCheckExecD.attachment = PlanD.attachment; - QcCheckExecD.isexec = PlanD.isexec; - QcCheckExecD.custom = PlanD.custom; - QcCheckExecD.typeid = PlanD.typeid; - QcCheckExecD.itemid = PlanD.itemid; - QcCheckExecD.create_time = time; - ExecDs.Add(QcCheckExecD); + + QcCheckExecH qcCheckExecH = new QcCheckExecH(); + qcCheckExecH.id = SnowflakeIdHelper.NextId(); + qcCheckExecH.checktype = PlanH.checktype; + qcCheckExecH.status = DictionaryData.Id; + qcCheckExecH.tasktime = time.ToString("yyyy-MM-dd HH:mm:ss"); + qcCheckExecH.materialid = PrdMoTask.material_id; + qcCheckExecH.processid = PrdMoTask.process_id; + qcCheckExecH.workid = PrdMoTask.workstation_id; + qcCheckExecH.create_time = time; + var ExecDs = new List(); + foreach (var PlanD in PlanDs) + { + QcCheckExecD QcCheckExecD = new QcCheckExecD(); + QcCheckExecD.mainid = qcCheckExecH.id; + QcCheckExecD.extype = PlanD.extype; + QcCheckExecD.excontent = PlanD.excontent; + QcCheckExecD.check = PlanD.check; + QcCheckExecD.errorcause = PlanD.errorcause; + QcCheckExecD.errorlevel = PlanD.errorlevel; + QcCheckExecD.remark = PlanD.remark; + QcCheckExecD.attachment = PlanD.attachment; + QcCheckExecD.isexec = PlanD.isexec; + QcCheckExecD.custom = PlanD.custom; + QcCheckExecD.typeid = PlanD.typeid; + QcCheckExecD.itemid = PlanD.itemid; + QcCheckExecD.create_time = time; + ExecDs.Add(QcCheckExecD); + } + await client.Insertable(qcCheckExecH).ExecuteCommandAsync(); + await client.Insertable(ExecDs).ExecuteCommandAsync(); } - await repository.AsSugarClient().Insertable(qcCheckExecH).ExecuteCommandAsync(); - await repository.AsSugarClient().Insertable(ExecDs).ExecuteCommandAsync(); + } + else + { + var PlanMaterials = await client.Queryable().Where(p => p.planid == PlanH.id).Select(p => p.materialid).ToListAsync(); + var DictionaryType = await client.Queryable().Where(p => p.FullName == "质检状态").FirstAsync(); + var DictionaryData = await client.Queryable().Where(p => p.DictionaryTypeId == DictionaryType.Id && p.FullName == "待执行").FirstAsync(); + var time = DateTime.Now; + foreach (var Material in PlanMaterials) + { + QcCheckExecH qcCheckExecH = new QcCheckExecH(); + qcCheckExecH.id = SnowflakeIdHelper.NextId(); + qcCheckExecH.checktype = PlanH.checktype; + qcCheckExecH.status = DictionaryData.Id; + qcCheckExecH.tasktime = time.ToString("yyyy-MM-dd HH:mm:ss"); + qcCheckExecH.materialid = Material; + qcCheckExecH.processid = ""; + qcCheckExecH.workid = ""; + qcCheckExecH.create_time = time; + var ExecDs = new List(); + foreach (var PlanD in PlanDs) + { + QcCheckExecD QcCheckExecD = new QcCheckExecD(); + QcCheckExecD.mainid = qcCheckExecH.id; + QcCheckExecD.extype = PlanD.extype; + QcCheckExecD.excontent = PlanD.excontent; + QcCheckExecD.check = PlanD.check; + QcCheckExecD.errorcause = PlanD.errorcause; + QcCheckExecD.errorlevel = PlanD.errorlevel; + QcCheckExecD.remark = PlanD.remark; + QcCheckExecD.attachment = PlanD.attachment; + QcCheckExecD.isexec = PlanD.isexec; + QcCheckExecD.custom = PlanD.custom; + QcCheckExecD.typeid = PlanD.typeid; + QcCheckExecD.itemid = PlanD.itemid; + QcCheckExecD.create_time = time; + ExecDs.Add(QcCheckExecD); + } + await client.Insertable(qcCheckExecH).ExecuteCommandAsync(); + await client.Insertable(ExecDs).ExecuteCommandAsync(); + } + } //只执行一次的 修改EnabledMark字段 var InterfaceParameter = comtentModel.parameter.Where(p => p.field == "doonce").FirstOrDefault(); if (InterfaceParameter != null && bool.Parse(InterfaceParameter.value)) { timeTaskEntity.EnabledMark = 0; - await repository.AsSugarClient().Updateable(timeTaskEntity).ExecuteCommandAsync(); + await client.Updateable(timeTaskEntity).ExecuteCommandAsync(); SpareTime.Cancel(timeTaskEntity.Id); } } diff --git a/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs b/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs index 3390256d..32d30c37 100644 --- a/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs +++ b/taskschedule/Tnb.TaskScheduler/TimeTaskService.cs @@ -136,9 +136,9 @@ public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransie #endregion #region Post - public List GetTasks() + public async Task> GetTasks() { - var list= _repository.AsQueryable().ToList(); + var list = await _repository.CopyNew().Queryable().ToListAsync(); return list; } diff --git a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs index 9b55a234..2ecf9373 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs @@ -4,6 +4,8 @@ ///////////////////////////////////////////////////////////////////////////////// using JNPF; +using JNPF.Common.Extension; +using JNPF.Common.Security; using JNPF.ViewEngine; using Mapster; using Microsoft.AspNetCore.Mvc; @@ -35,17 +37,22 @@ public class VmodelAppService : VengineAppService, IVmodelAppService /// public override async Task GetAsync(VmGetInput input) { + VmodelGetInput para = new VmodelGetInput(); + if (!string.IsNullOrEmpty(input.q)) + { + para = input.q.ToObject(); + } var query = _db.Queryable().Where(a => a.deleted == 0); - Vmodel vm; - if (long.TryParse(input.id, out long id)) + Vmodel? vm = null; + if (!string.IsNullOrEmpty(input.id)) { - query.Where(a => a.id == input.id); - vm = await query.FirstAsync(); + vm = await _dataAccess.GetVmodelAsync(input.id, para.drill); } - else + else if(!string.IsNullOrEmpty(para.areaCode) && !string.IsNullOrEmpty(para.vmCode)) { - vm = await query.FirstAsync(a => a.vmCode == input.id); + vm = await _dataAccess.GetVmodelAsync(para.areaCode, para.vmCode, para.drill); } + ThrowIf.IsNull(vm, "输入参数有误, id 和 areaCode,vmCode 不可同时为空"); return vm; } @@ -93,6 +100,7 @@ public class VmodelAppService : VengineAppService, IVmodelAppService Vmodel vm = input.data.Adapt(); vm.areaCode = vm.areaCode.ToKebab(); vm.vmCode = vm.vmCode.ToKebab(); + vm.navProps.ForEach(a => a.naviModel = null); await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); return input; } diff --git a/visualdev/Tnb.Vengine/AppService/VmodelDto.cs b/visualdev/Tnb.Vengine/AppService/VmodelDto.cs index ab280788..9c69cd3a 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelDto.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelDto.cs @@ -23,10 +23,9 @@ public class CreatePageFromVmodelInput public class VmodelGetInput { - public long? id { get; set; } - public string? moduleCode { get; set; } + public string? areaCode { get; set; } public string? vmCode { get; set; } public string? dbCode { get; set; } public string? tableName { get; set; } - public bool drill { get; set; } + public bool drill { get; set; } = false; } \ No newline at end of file diff --git a/visualdev/Tnb.Vengine/Domain/VmNavProp.cs b/visualdev/Tnb.Vengine/Domain/VmNavProp.cs index 203f251b..ae6d0957 100644 --- a/visualdev/Tnb.Vengine/Domain/VmNavProp.cs +++ b/visualdev/Tnb.Vengine/Domain/VmNavProp.cs @@ -51,7 +51,7 @@ public class VmNavProp : VmBaseProp //[JsonIgnore] //public string? midTable { get; set; } - [JsonIgnore] + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] public Vmodel? naviModel { get; set; } #endregion Properties