From a9461977eed1f472ba6a0083f993d0f41a3843f5 Mon Sep 17 00:00:00 2001 From: zhoukeda <1315948824@qq.com> Date: Mon, 14 Aug 2023 10:48:05 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E6=8F=90=E6=8A=A5=E6=8A=A5=E5=BA=9F?= =?UTF-8?q?=E6=95=B0=E9=87=8F=E5=8F=8D=E5=86=99=E5=88=B0=E5=B7=A5=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Entity/PrdMo.cs | 5 ++ .../Tnb.ProductionMgr/PrdMoTaskService.cs | 87 ++++++++++++++++++- 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/ProductionMgr/Tnb.ProductionMgr.Entities/Entity/PrdMo.cs b/ProductionMgr/Tnb.ProductionMgr.Entities/Entity/PrdMo.cs index 6b12ce6d..97ec51d8 100644 --- a/ProductionMgr/Tnb.ProductionMgr.Entities/Entity/PrdMo.cs +++ b/ProductionMgr/Tnb.ProductionMgr.Entities/Entity/PrdMo.cs @@ -53,6 +53,11 @@ public partial class PrdMo : BaseEntity /// 已完工数量 /// public int? complete_qty { get; set; } + + /// + /// 已报工数量 + /// + public int? reported_work_qty { get; set; } /// /// 报废数量 diff --git a/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs b/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs index 326cb5fa..ab5ad11d 100644 --- a/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs +++ b/ProductionMgr/Tnb.ProductionMgr/PrdMoTaskService.cs @@ -1364,6 +1364,7 @@ namespace Tnb.ProductionMgr var row = -1; var report = await db.Queryable().FirstAsync(it => it.mo_task_id == input.mo_task_id); var prdMoTask = await db.Queryable().SingleAsync(x => x.id == input.mo_task_id); + var prdMo = await db.Queryable().SingleAsync(x => x.id == prdMoTask.mo_id); var mbomProcess = await db.Queryable().SingleAsync(x => x.id == prdMoTask.mbom_process_id); if (prdMoTask.mo_task_status == DictConst.MoStatusPauseCode) @@ -1444,6 +1445,35 @@ namespace Tnb.ProductionMgr .Where(x => x.id == input.mo_task_id).ExecuteCommandAsync(); } + if (prdMoTask.schedule_type==1) + { + if (prdMo.reported_work_qty == null) + { + await db.Updateable() + .SetColumns(x => x.reported_work_qty == input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.reported_work_qty == x.reported_work_qty + input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + + if (prdMo.complete_qty == null) + { + await db.Updateable() + .SetColumns(x => x.complete_qty == input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.complete_qty == x.complete_qty + input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + } + if (prdMoTask.schedule_type == 2 && !string.IsNullOrEmpty(prdMoTask.mbom_process_id)) { if (mbomProcess.is_last==1 && prdMoTask != null && !string.IsNullOrEmpty(prdMoTask.parent_id)) @@ -1462,6 +1492,32 @@ namespace Tnb.ProductionMgr // .SetColumnsIF(flag,x=>x.mo_task_status==DictConst.ComplatedEnCode) .Where(x => x.id == prdMoTask.parent_id).ExecuteCommandAsync(); } + + if (prdMo.reported_work_qty == null) + { + await db.Updateable() + .SetColumns(x => x.reported_work_qty == input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.reported_work_qty == x.reported_work_qty + input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + + if (prdMo.complete_qty == null) + { + await db.Updateable() + .SetColumns(x => x.complete_qty == input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.complete_qty == x.complete_qty + input.reported_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } } } @@ -1595,6 +1651,7 @@ namespace Tnb.ProductionMgr { List destDefects = new(); var batch = DateTime.Now.ToString("yyyyMMddHHmmss"); + var prdMoTask = await db.Queryable().SingleAsync(x => x.id == input.mo_task_id); foreach (var categoryItem in input.categoryItems) { @@ -1619,7 +1676,7 @@ namespace Tnb.ProductionMgr { #region 质检模块 //质检模块 - var prdMoTask = await db.Queryable().SingleAsync(x => x.id == input.mo_task_id); + TriggerPlanEntity entity = new TriggerPlanEntity(); entity.materialid = prdMoTask.material_id; entity.processid = prdMoTask.process_id; @@ -1640,6 +1697,34 @@ namespace Tnb.ProductionMgr await db.Updateable(defectRecord).ExecuteCommandAsync(); } var reportMaster = await db.Queryable().FirstAsync(it => it.mo_task_id == input.mo_task_id); + var prdMo = await db.Queryable().SingleAsync(x => x.id == prdMoTask.mo_id); + + if (prdMo.reported_work_qty == null) + { + await db.Updateable() + .SetColumns(x => x.scrap_qty == input.scrap_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.scrap_qty == x.scrap_qty + input.scrap_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + + if (prdMo.complete_qty == null) + { + await db.Updateable() + .SetColumns(x => x.complete_qty == input.scrap_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + else + { + await db.Updateable() + .SetColumns(x => x.complete_qty == x.complete_qty + input.scrap_qty) + .Where(x => x.id == prdMo.id).ExecuteCommandAsync(); + } + if (reportMaster != null) { reportMaster.completed_qty += input.scrap_qty; From 9055911b746312ba80d4c23fed796cbcf3339dee Mon Sep 17 00:00:00 2001 From: FanLian Date: Mon, 14 Aug 2023 12:07:14 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=96=B0=E4=B8=9A?= =?UTF-8?q?=E5=8A=A1=E8=BD=AC=E8=BF=90=E7=AD=BE=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../PDATransferSignService.cs | 137 ++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 WarehouseMgr/Tnb.WarehouseMgr/PDATransferSignService.cs diff --git a/WarehouseMgr/Tnb.WarehouseMgr/PDATransferSignService.cs b/WarehouseMgr/Tnb.WarehouseMgr/PDATransferSignService.cs new file mode 100644 index 00000000..6e6e2613 --- /dev/null +++ b/WarehouseMgr/Tnb.WarehouseMgr/PDATransferSignService.cs @@ -0,0 +1,137 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using JNPF.Common.Extension; +using JNPF.Systems.Interfaces.System; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.BasicData.Entities; +using Tnb.WarehouseMgr.Entities; +using Tnb.WarehouseMgr.Entities.Consts; +using Tnb.WarehouseMgr.Entities.Dto.Inputs; +using Tnb.WarehouseMgr.Entities.Dto; +using Tnb.WarehouseMgr.Entities.Enums; +using Mapster; +using JNPF.Common.Security; +using System.Collections.Immutable; +//using JNPF.Extras.CollectiveOAuth.Utils; + +namespace Tnb.WarehouseMgr +{ + public class PDATransferSignService : BaseWareHouseService + { + private readonly ISqlSugarClient _db; + private readonly IDictionaryDataService _dictionaryDataService; + private static Dictionary _dicBizType = new(); + public PDATransferSignService(ISqlSugarRepository repository, IDictionaryDataService dictionaryDataService) + { + _db = repository.AsSugarClient(); + _dictionaryDataService = dictionaryDataService; + } + + /// + /// 转运签收 + /// + /// + [HttpPost] + public async Task SignForDelivery(SignForDeliveryInput input) + { + if (_dicBizType.Count < 1) + { + _dicBizType = await _dictionaryDataService.GetDictionaryByTypeId(WmsWareHouseConst.WMS_BIZTYPE_ID); + } + try + { + await _db.Ado.BeginTranAsync(); + WmsCarryH? carry = null; + WmsCarryH? newCarry = null; + if (!input.carryId.IsNullOrWhiteSpace()) + { + carry = await _db.Queryable().SingleAsync(it => it.id == input.carryId); + } + else + { + carry = await _db.Queryable().SingleAsync(it => it.carry_code == input.carry_code); + } + if (!input.new_carry_code.IsNullOrWhiteSpace()) + newCarry = await _db.Queryable().SingleAsync(it => it.carry_code == input.new_carry_code); + if (carry != null && newCarry != null) + { + if (carry?.location_id?.IsNotEmptyOrNull() ?? false) + { + var loc = await _db.Queryable().SingleAsync(it => it.id == carry.location_id); + loc.is_use = ((int)EnumCarryStatus.空闲).ToString(); + await _db.Updateable(loc).UpdateColumns(it => it.is_use).ExecuteCommandAsync(); + } + WmsDistaskH? disTask = null; + if (!input.disTaskId.IsNullOrEmpty()) + { + disTask = await _db.Queryable().SingleAsync(it => it.id == input.disTaskId); + } + else if (!input.carryId.IsNullOrEmpty()) + { + disTask = await _db.Queryable().FirstAsync(it => it.carry_id == input.carryId && it.is_sign == 0); + } + else if (!input.carry_code.IsNullOrEmpty()) + { + disTask = await _db.Queryable().FirstAsync(it => it.carry_code == input.carry_code && it.is_sign == 0); + } + if (disTask != null) + { + var nCCode = await _db.Queryable().Where(it => it.carry_id == newCarry.id).ToListAsync(); + var dicMin = await _db.Queryable().Where(it => input.distaskCodes.Select(x => x.material_id).Contains(it.id)).ToDictionaryAsync(d => d.id, d => d.minpacking); + WmsCarryCode cCode = new WmsCarryCode(); + List iCodes = new List(); + List uCodes = new List(); + foreach (var dCode in input.distaskCodes) + { + decimal codeQty = 0; + var sMCode = nCCode.Find(x => x.material_id == dCode.material_id && x.codeqty <= dicMin[dCode.material_id].ParseToDecimal()); + cCode = dCode.Adapt(); + cCode.carry_id = newCarry.id; + cCode.code_batch = $"{DateTime.Today.Year}{DateTime.Today.Month}{DateTime.Today.Day}"; + if (sMCode != null) + { + codeQty = sMCode.codeqty; + cCode.codeqty += codeQty; + cCode.id = sMCode.id; + uCodes.Add(cCode); + } + else + { + cCode.id = SnowflakeIdHelper.NextId(); + iCodes.Add(cCode); + } + + + } + await _db.Insertable(iCodes).ExecuteCommandAsync(); + await _db.Updateable(uCodes).ExecuteCommandAsync(); + if (_dicBizType.ContainsKey(disTask.biz_type)) + { + WareHouseUpInput upInput = new() + { + loginType = "web", + bizTypeId = disTask.biz_type, + requireId = disTask!.require_id!, + carryIds = new List { carry!.id }, + distaskCodes = input.distaskCodes + }; + await DoUpdate(upInput); //回更业务 + } + disTask.is_sign = 1; + await _db.Updateable(disTask).UpdateColumns(it => it.is_sign).ExecuteCommandAsync(); + } + } + await _db.Ado.CommitTranAsync(); + } + catch (Exception) + { + await _db.Ado.RollbackTranAsync(); + throw; + } + } + } +} From 45e59b175fb84a658fe318e42714a5a60fa32b05 Mon Sep 17 00:00:00 2001 From: PhilPan Date: Tue, 15 Aug 2023 11:41:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Tnb.Vengine?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Tnb.Server.sln | 12 +- apihost/Tnb.API.Entry/Tnb.API.Entry.csproj | 1 - .../AppService}/BaseAppService.cs | 2 +- .../AppService}/IVmodelAppService.cs | 2 +- .../AppService}/IVmodelPageAppService.cs | 2 +- .../Tnb.Vengine/AppService/VmAppService.cs | 198 ++++++ .../Tnb.Vengine/AppService/VmAppServiceT.cs | 120 ++++ .../AppService/VmodelAppService.cs | 151 +++++ .../AppService/VmodelPageAppService.cs | 165 +++++ .../Constants/DbConsts.cs | 2 +- .../Constants/ModuleConst.cs | 2 +- .../Constants/VmodelEnum.cs | 2 +- .../Tnb.Vengine/DataAccess/DataAccess.cs | 422 +++++++++++++ .../Tnb.Vengine/DataAccess/IDataAccess.cs | 71 +++ .../Tnb.Vengine/DataAccess/SugarHelper.cs | 34 ++ .../Entities => Tnb.Vengine/Domain}/Entity.cs | 30 +- visualdev/Tnb.Vengine/Domain/VmBaseProp.cs | 36 ++ visualdev/Tnb.Vengine/Domain/VmCalcProp.cs | 12 + visualdev/Tnb.Vengine/Domain/VmDbProp.cs | 149 +++++ visualdev/Tnb.Vengine/Domain/VmDto.cs | 198 ++++++ visualdev/Tnb.Vengine/Domain/VmNavProp.cs | 54 ++ visualdev/Tnb.Vengine/Domain/Vmodel.cs | 443 ++++++++++++++ visualdev/Tnb.Vengine/Domain/VmodelDto.cs | 34 ++ visualdev/Tnb.Vengine/Domain/VmodelLink.cs | 49 ++ visualdev/Tnb.Vengine/Domain/VmodelPage.cs | 107 ++++ .../Tnb.Vengine/Extension/StringExtensions.cs | 577 ++++++++++++++++++ visualdev/Tnb.Vengine/Mapper/TypeAdapter.cs | 24 + visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs | 52 ++ .../Tnb.Vengine.csproj} | 0 visualdev/Tnb.Vengine/Util/ThrowIf.cs | 137 +++++ visualdev/Tnb.Vmodel/DataAccess/DataAccess.cs | 422 ------------- .../Tnb.Vmodel/DataAccess/IDataAccess.cs | 71 --- .../Tnb.Vmodel/DataAccess/SugarHelper.cs | 34 -- visualdev/Tnb.Vmodel/Dtos/VmDto.cs | 198 ------ visualdev/Tnb.Vmodel/Dtos/VmodelDto.cs | 34 -- visualdev/Tnb.Vmodel/Entities/Vmodel.cs | 444 -------------- visualdev/Tnb.Vmodel/Entities/VmodelLink.cs | 50 -- visualdev/Tnb.Vmodel/Entities/VmodelPage.cs | 107 ---- visualdev/Tnb.Vmodel/Entities/VmodelProp.cs | 231 ------- .../Tnb.Vmodel/Extension/StringExtensions.cs | 573 ----------------- visualdev/Tnb.Vmodel/Mapper/TypeAdapter.cs | 25 - visualdev/Tnb.Vmodel/Mapper/VmodelMapper.cs | 46 -- visualdev/Tnb.Vmodel/Util/ThrowIf.cs | 168 ----- visualdev/Tnb.Vmodel/VmAppService.cs | 200 ------ visualdev/Tnb.Vmodel/VmAppServiceT.cs | 119 ---- visualdev/Tnb.Vmodel/VmodelAppService.cs | 150 ----- visualdev/Tnb.Vmodel/VmodelPageAppService.cs | 166 ----- 47 files changed, 3060 insertions(+), 3066 deletions(-) rename visualdev/{Tnb.Vmodel => Tnb.Vengine/AppService}/BaseAppService.cs (93%) rename visualdev/{Tnb.Vmodel => Tnb.Vengine/AppService}/IVmodelAppService.cs (93%) rename visualdev/{Tnb.Vmodel => Tnb.Vengine/AppService}/IVmodelPageAppService.cs (93%) create mode 100644 visualdev/Tnb.Vengine/AppService/VmAppService.cs create mode 100644 visualdev/Tnb.Vengine/AppService/VmAppServiceT.cs create mode 100644 visualdev/Tnb.Vengine/AppService/VmodelAppService.cs create mode 100644 visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs rename visualdev/{Tnb.Vmodel => Tnb.Vengine}/Constants/DbConsts.cs (99%) rename visualdev/{Tnb.Vmodel => Tnb.Vengine}/Constants/ModuleConst.cs (77%) rename visualdev/{Tnb.Vmodel => Tnb.Vengine}/Constants/VmodelEnum.cs (98%) create mode 100644 visualdev/Tnb.Vengine/DataAccess/DataAccess.cs create mode 100644 visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs create mode 100644 visualdev/Tnb.Vengine/DataAccess/SugarHelper.cs rename visualdev/{Tnb.Vmodel/Entities => Tnb.Vengine/Domain}/Entity.cs (50%) create mode 100644 visualdev/Tnb.Vengine/Domain/VmBaseProp.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmCalcProp.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmDbProp.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmDto.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmNavProp.cs create mode 100644 visualdev/Tnb.Vengine/Domain/Vmodel.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmodelDto.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmodelLink.cs create mode 100644 visualdev/Tnb.Vengine/Domain/VmodelPage.cs create mode 100644 visualdev/Tnb.Vengine/Extension/StringExtensions.cs create mode 100644 visualdev/Tnb.Vengine/Mapper/TypeAdapter.cs create mode 100644 visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs rename visualdev/{Tnb.Vmodel/Tnb.VmodelEngine.csproj => Tnb.Vengine/Tnb.Vengine.csproj} (100%) create mode 100644 visualdev/Tnb.Vengine/Util/ThrowIf.cs delete mode 100644 visualdev/Tnb.Vmodel/DataAccess/DataAccess.cs delete mode 100644 visualdev/Tnb.Vmodel/DataAccess/IDataAccess.cs delete mode 100644 visualdev/Tnb.Vmodel/DataAccess/SugarHelper.cs delete mode 100644 visualdev/Tnb.Vmodel/Dtos/VmDto.cs delete mode 100644 visualdev/Tnb.Vmodel/Dtos/VmodelDto.cs delete mode 100644 visualdev/Tnb.Vmodel/Entities/Vmodel.cs delete mode 100644 visualdev/Tnb.Vmodel/Entities/VmodelLink.cs delete mode 100644 visualdev/Tnb.Vmodel/Entities/VmodelPage.cs delete mode 100644 visualdev/Tnb.Vmodel/Entities/VmodelProp.cs delete mode 100644 visualdev/Tnb.Vmodel/Extension/StringExtensions.cs delete mode 100644 visualdev/Tnb.Vmodel/Mapper/TypeAdapter.cs delete mode 100644 visualdev/Tnb.Vmodel/Mapper/VmodelMapper.cs delete mode 100644 visualdev/Tnb.Vmodel/Util/ThrowIf.cs delete mode 100644 visualdev/Tnb.Vmodel/VmAppService.cs delete mode 100644 visualdev/Tnb.Vmodel/VmAppServiceT.cs delete mode 100644 visualdev/Tnb.Vmodel/VmodelAppService.cs delete mode 100644 visualdev/Tnb.Vmodel/VmodelPageAppService.cs diff --git a/Tnb.Server.sln b/Tnb.Server.sln index 8b41da8c..f9236fb7 100644 --- a/Tnb.Server.sln +++ b/Tnb.Server.sln @@ -140,7 +140,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tnb.PerMgr.Entities", "PerM EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tnb.PerMgr.Interfaces", "PerMgr\Tnb.PerMgr.Interfaces\Tnb.PerMgr.Interfaces.csproj", "{F3656494-27D3-4BD7-B831-8D909DFBD7B9}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tnb.VmodelEngine", "visualdev\Tnb.Vmodel\Tnb.VmodelEngine.csproj", "{437AE0E4-66AE-4627-9ACD-29F5BB9E6642}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tnb.Vengine", "visualdev\Tnb.Vengine\Tnb.Vengine.csproj", "{644FEE7B-A58A-40F3-A011-3B73235B81D6}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -340,10 +340,10 @@ Global {F3656494-27D3-4BD7-B831-8D909DFBD7B9}.Debug|Any CPU.Build.0 = Debug|Any CPU {F3656494-27D3-4BD7-B831-8D909DFBD7B9}.Release|Any CPU.ActiveCfg = Release|Any CPU {F3656494-27D3-4BD7-B831-8D909DFBD7B9}.Release|Any CPU.Build.0 = Release|Any CPU - {437AE0E4-66AE-4627-9ACD-29F5BB9E6642}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {437AE0E4-66AE-4627-9ACD-29F5BB9E6642}.Debug|Any CPU.Build.0 = Debug|Any CPU - {437AE0E4-66AE-4627-9ACD-29F5BB9E6642}.Release|Any CPU.ActiveCfg = Release|Any CPU - {437AE0E4-66AE-4627-9ACD-29F5BB9E6642}.Release|Any CPU.Build.0 = Release|Any CPU + {644FEE7B-A58A-40F3-A011-3B73235B81D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {644FEE7B-A58A-40F3-A011-3B73235B81D6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {644FEE7B-A58A-40F3-A011-3B73235B81D6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {644FEE7B-A58A-40F3-A011-3B73235B81D6}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -396,7 +396,7 @@ Global {D41946CF-09C6-4CA4-A1F4-42E7E1538BF7} = {74AB6486-1090-4CC9-9D1A-F1245E3ECFC3} {42AD083D-D199-4B09-ADD8-89251011C959} = {74AB6486-1090-4CC9-9D1A-F1245E3ECFC3} {F3656494-27D3-4BD7-B831-8D909DFBD7B9} = {74AB6486-1090-4CC9-9D1A-F1245E3ECFC3} - {437AE0E4-66AE-4627-9ACD-29F5BB9E6642} = {161853F8-ADB9-4281-B706-E2E23D40D0F1} + {644FEE7B-A58A-40F3-A011-3B73235B81D6} = {161853F8-ADB9-4281-B706-E2E23D40D0F1} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {646DDD1C-F143-42C2-894F-F5C7B3A0CE74} diff --git a/apihost/Tnb.API.Entry/Tnb.API.Entry.csproj b/apihost/Tnb.API.Entry/Tnb.API.Entry.csproj index 7e3429bd..e3a54fc6 100644 --- a/apihost/Tnb.API.Entry/Tnb.API.Entry.csproj +++ b/apihost/Tnb.API.Entry/Tnb.API.Entry.csproj @@ -44,7 +44,6 @@ - diff --git a/visualdev/Tnb.Vmodel/BaseAppService.cs b/visualdev/Tnb.Vengine/AppService/BaseAppService.cs similarity index 93% rename from visualdev/Tnb.Vmodel/BaseAppService.cs rename to visualdev/Tnb.Vengine/AppService/BaseAppService.cs index e6fa3d23..f657fff2 100644 --- a/visualdev/Tnb.Vmodel/BaseAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/BaseAppService.cs @@ -6,7 +6,7 @@ using JNPF.DependencyInjection; using JNPF.DynamicApiController; -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine.AppService; /// /// 增删改查基类 diff --git a/visualdev/Tnb.Vmodel/IVmodelAppService.cs b/visualdev/Tnb.Vengine/AppService/IVmodelAppService.cs similarity index 93% rename from visualdev/Tnb.Vmodel/IVmodelAppService.cs rename to visualdev/Tnb.Vengine/AppService/IVmodelAppService.cs index 746bd7f2..f00093b5 100644 --- a/visualdev/Tnb.Vmodel/IVmodelAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/IVmodelAppService.cs @@ -5,7 +5,7 @@ using JNPF.DependencyInjection; -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine.AppService; /// /// 视图模型服务接口 diff --git a/visualdev/Tnb.Vmodel/IVmodelPageAppService.cs b/visualdev/Tnb.Vengine/AppService/IVmodelPageAppService.cs similarity index 93% rename from visualdev/Tnb.Vmodel/IVmodelPageAppService.cs rename to visualdev/Tnb.Vengine/AppService/IVmodelPageAppService.cs index 4b19ef28..33a0d1ce 100644 --- a/visualdev/Tnb.Vmodel/IVmodelPageAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/IVmodelPageAppService.cs @@ -5,7 +5,7 @@ using JNPF.DependencyInjection; -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine.AppService; /// /// 视图模型服务接口 diff --git a/visualdev/Tnb.Vengine/AppService/VmAppService.cs b/visualdev/Tnb.Vengine/AppService/VmAppService.cs new file mode 100644 index 00000000..1ef08ede --- /dev/null +++ b/visualdev/Tnb.Vengine/AppService/VmAppService.cs @@ -0,0 +1,198 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using JNPF.Common.Security; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.Vengine.DataAccess; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.AppService; + +/// +/// 增删改查基类 +/// +[ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 10, KeepVerb = true)] +[Route("api")] +public class VmAppService : BaseAppService +{ + private readonly IDataAccess _dataAccess; + private readonly ISqlSugarClient _db; + + /// + /// 构造函数 + /// + public VmAppService(IDataAccess da) + { + _dataAccess = da; + _db = _dataAccess.GetSqlSugar(); + } + + #region 根据vmodel id进行增删改查接口 + /// + /// 获取一条 数据信息 + /// + [HttpGet("[area]/[controller]/{vmid}/[action]")] + public async Task GetAsync(string vmid, [FromQuery] VmGetInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid, true); + VmQueryInput arg = input.Adapt(); + if (input.id != null) + { + if (arg.q == null) arg.q = new DObject(); + arg.q.Add(vm.GetPrimary().code, input.id); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls.items.FirstOrDefault(); + } + + /// + /// 获取多条 数据列表 + /// + [HttpGet("[area]/[controller]/{vmid}/[action]")] + public async Task GetListAsync(string vmid, [FromQuery] VmGetListInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid, true); + VmQueryInput arg = input.Adapt(); + if (!string.IsNullOrEmpty(input.q)) + { + arg.q = input.q.ToObject(); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls; + } + + /// + /// 获取多条 数据列表 + /// + [HttpPost("[area]/[controller]/{vmid}/[action]")] + public async Task QueryAsync(string vmid, [FromBody] VmQueryInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid, true); + var ls = await _dataAccess.QueryDataAsync(vm, input); + return ls; + } + + /// + /// 新增 数据 + /// + [HttpPost("[area]/[controller]/{vmid}/[action]")] + public async Task CreateAsync(string vmid, VmCreateInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid); + var ret = await _dataAccess.CreateDataAsync(vm, input); + return ret; + } + + /// + /// 更新 数据 + /// + [HttpPut("[area]/[controller]/{vmid}/[action]")] + public async Task UpdateAsync(string vmid, VmUpdateInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid); + var ret = await _dataAccess.UpdateDataAsync(vm, input); + return ret; + } + + /// + /// 删除 数据 + /// + [HttpDelete("[area]/[controller]/{vmid}/[action]")] + public async Task DeleteAsync(string vmid, [FromQuery] VmDeleteInput input) + { + var vm = await _dataAccess.GetVmodelAsync(vmid); + var ret = await _dataAccess.DeleteDataAsync(vm, input); + return ret; + } + + private async Task GetVmodelAsync(string area, string vmCode) + { + var vm = await _dataAccess.GetVmodelAsync(area.SnakeToPascalCase(), vmCode.SnakeToPascalCase(), true); + return vm; + } + #endregion + + #region 根据vmode的area和code进行增删改查接口 + /// + /// 获取一条 数据信息 + /// + [HttpGet("{areaCode}/{vmCode}/[action]")] + public async Task GetAsync(string areaCode, string vmCode, [FromQuery] VmGetInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + VmQueryInput arg = input.Adapt(); + if (input.id != null) + { + if (arg.q == null) arg.q = new DObject(); + arg.q.Add(vm.GetPrimary().code, input.id); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls.items.FirstOrDefault(); + } + + /// + /// 获取多条 数据列表 + /// + [HttpGet("{areaCode}/{vmCode}/[action]")] + public async Task GetListAsync(string areaCode, string vmCode, [FromQuery] VmGetListInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + VmQueryInput arg = input.Adapt(); + if (!string.IsNullOrEmpty(input.q)) + { + arg.q = input.q.ToObject(); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls; + } + + /// + /// 获取多条 数据列表 + /// + [HttpPost("{areaCode}/{vmCode}/[action]")] + public async Task QueryAsync(string areaCode, string vmCode, [FromBody] VmQueryInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + var ls = await _dataAccess.QueryDataAsync(vm, input); + return ls; + } + + /// + /// 新增 数据 + /// + [HttpPost("{areaCode}/{vmCode}/[action]")] + public async Task CreateAsync(string areaCode, string vmCode, VmCreateInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + var ret = await _dataAccess.CreateDataAsync(vm, input); + return ret; + } + + /// + /// 更新 数据 + /// + [HttpPut("{areaCode}/{vmCode}/[action]")] + public async Task UpdateAsync(string areaCode, string vmCode, VmUpdateInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + var ret = await _dataAccess.UpdateDataAsync(vm, input); + return ret; + } + + /// + /// 删除 数据 + /// + [HttpDelete("{areaCode}/{vmCode}/[action]")] + public async Task DeleteAsync(string areaCode, string vmCode, [FromQuery] VmDeleteInput input) + { + var vm = await GetVmodelAsync(areaCode, vmCode); + var ret = await _dataAccess.DeleteDataAsync(vm, input); + return ret; + } + #endregion + +} diff --git a/visualdev/Tnb.Vengine/AppService/VmAppServiceT.cs b/visualdev/Tnb.Vengine/AppService/VmAppServiceT.cs new file mode 100644 index 00000000..4919858d --- /dev/null +++ b/visualdev/Tnb.Vengine/AppService/VmAppServiceT.cs @@ -0,0 +1,120 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using JNPF.Common.Contracts; +using JNPF.Common.Security; +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.Vengine.DataAccess; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.AppService; + +/// +/// 增删改查基类 +/// +[ApiDescriptionSettings(Area = ModuleConst.Area, Order = 10, KeepVerb = true)] +[Route("api/[area]/[controller]/[action]")] +public class VmAppService : BaseAppService where TEntity : IEntity +{ + protected readonly IDataAccess _dataAccess; + protected readonly ISqlSugarClient _db; + + /// + /// 构造函数 + /// + public VmAppService(IDataAccess dataAccess) + { + _dataAccess = dataAccess; + _db = _dataAccess.GetSqlSugar(); + } + + protected async Task GetVmodelAsync() + { + var tp = typeof(TEntity); + if (string.IsNullOrEmpty(tp?.Namespace)) + { + throw new ArgumentNullException($"类型 {nameof(tp)} 的命名空间不可为空"); + } + var area = tp.Namespace.Split('.').Last().ToKebabCase(); + var vm = await _dataAccess.GetVmodelAsync(area, tp.Name, true); + + return vm; + } + + /// + /// 获取一条 数据信息 + /// + public virtual async Task GetAsync([FromQuery] VmGetInput input) + { + var vm = await GetVmodelAsync(); + VmQueryInput arg = input.Adapt(); + if (input.id != null) + { + if (arg.q == null) arg.q = new DObject(); + arg.q.Add(vm.GetPrimary().code, input.id); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls.items.FirstOrDefault()!; + } + + /// + /// 获取多条 数据列表 + /// + public virtual async Task GetListAsync([FromQuery] VmGetListInput input) + { + var vm = await GetVmodelAsync(); + VmQueryInput arg = input.Adapt(); + if (!string.IsNullOrEmpty(input.q)) + { + arg.q = input.q.ToObject(); + } + var ls = await _dataAccess.QueryDataAsync(vm, arg); + return ls; + } + + /// + /// 获取多条 数据列表 + /// + [HttpPost] + public virtual async Task QueryAsync([FromBody] VmQueryInput input) + { + var vm = await GetVmodelAsync(); + var ls = await _dataAccess.QueryDataAsync(vm, input); + return ls; + } + + /// + /// 新增 数据 + /// + public virtual async Task CreateAsync(VmCreateInput input) + { + var vm = await GetVmodelAsync(); + var ret = await _dataAccess.CreateDataAsync(vm, input); + return ret; + } + + /// + /// 更新 数据 + /// + public virtual async Task UpdateAsync(VmUpdateInput input) + { + var vm = await GetVmodelAsync(); + var ret = await _dataAccess.UpdateDataAsync(vm, input); + return ret; + } + + /// + /// 删除 数据 + /// + public virtual async Task DeleteAsync([FromQuery] VmDeleteInput input) + { + var vm = await GetVmodelAsync(); + var ret = await _dataAccess.DeleteDataAsync(vm, input); + return ret; + } + +} diff --git a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs new file mode 100644 index 00000000..d77245c3 --- /dev/null +++ b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs @@ -0,0 +1,151 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Mapster; +using Microsoft.AspNetCore.Mvc; +using SqlSugar; +using Tnb.Vengine.DataAccess; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.AppService; + +/// +/// 视图模型服务类 +/// +public class VmodelAppService : VmAppService, IVmodelAppService +{ + + /// + /// 构造函数 + /// + public VmodelAppService(IDataAccess da) : base(da) + { + } + + /// + /// 获取一条 数据信息 + /// + public override async Task GetAsync(VmGetInput input) + { + //return await _dataAccess.GetVmodelAsync(input.id); + var query = _db.Queryable().Where(a => a.deleted == 0); + Vmodel vm; + if (long.TryParse(input.id, out long id)) + { + vm = await query.FirstAsync(a => a.id == input.id); + } + else + { + vm = await query.FirstAsync(a => a.vmCode == input.id); + } + return vm; + } + + /// + /// 获取多条 数据列表 + /// + public override async Task GetListAsync(VmGetListInput input) + { + VmPagedOutput ret = new(); + var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.vmCode.Contains(input.k!) || a.vmName.Contains(input.k!)); + RefAsync total = 0; + var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); + ret.total = total; + ret.items = data.ConvertAll(a => a); + return ret; + } + + [NonAction] + public override Task QueryAsync(VmQueryInput input) + { + return base.QueryAsync(input); + } + + /// + /// 新增 模型 + /// + public override async Task CreateAsync(VmCreateInput input) + { + //ThrowIf.IsNull(input.data, nameof(input)); + ArgumentNullException.ThrowIfNull(input.data); + Vmodel vm = input.data.Adapt(); + await _db.Insertable(vm).ExecuteCommandAsync(); + return input; + } + + /// + /// 更新 数据 + /// + public override async Task UpdateAsync(VmUpdateInput input) + { + ArgumentNullException.ThrowIfNull(input.data); + Vmodel vm = input.data.Adapt(); + await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); + return input; + } + + /// + /// 删除 数据 + /// + public override async Task DeleteAsync(VmDeleteInput input) + { + var ret = await _db.Deleteable(input.id).ExecuteCommandAsync(); + return ret; + } + + /// + /// 从数据表创建模型 + /// + public async Task> CreateFromTable(VmodelCreateFromTableInput input) + { + ThrowIf.IsNull(input.tableName, nameof(input.tableName)); + var sugar = _dataAccess.GetSqlSugar(input.dbCode); + var lsTable = sugar.DbMaintenance.GetTableInfoList().WhereIF(input.tableName != "ALL", a => a.Name == input.tableName); + + List lsToAdd = new List(); + List lsToUpdate = new List(); + foreach (var tb in lsTable) + { + if (!string.IsNullOrEmpty(input.removePrefix) && !tb.Name.StartsWith(input.removePrefix)) continue; + var colInfo = sugar.DbMaintenance.GetColumnInfosByTableName(tb.Name); + Vmodel model = new() { dbCode = input.dbCode, vmName = tb.Description, tableName = tb.Name }; + model.area = input.area; + model.vmCode = (string.IsNullOrEmpty(input.removePrefix) ? tb.Name : tb.Name.RemovePreFix(input.removePrefix)).SnakeToPascalCase(); + //model.createId = CurrentUser.Id; + int n = 1; + foreach (var p in colInfo) + { + var prop = p.Adapt(); + prop.ordinal = n++; + prop.csType = sugar.Ado.DbBind.GetPropertyTypeName(p.DataType); + model.dbProps.Add(prop); + } + var exist = await _db.Queryable().FirstAsync(a => a.dbCode == input.dbCode && a.tableName == tb.Name); + if (exist == null) + { + lsToAdd.Add(model); + } + else + { + exist.area = model.area; + model.dbProps.Adapt(exist.dbProps); + //exist.dbProps.Clear(); + //exist.dbProps.AddRange(model.dbProps.OrderBy(a => a.ordinal)); + lsToUpdate.Add(exist); + } + } + if (lsToAdd.Count > 0) + { + await _db.Insertable(lsToAdd).ExecuteCommandAsync(); + } + if (lsToUpdate.Count > 0) + { + await _db.Updateable(lsToUpdate).ExecuteCommandAsync(); + } + return lsToAdd.Union(lsToUpdate).ToList(); + } + + +} diff --git a/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs new file mode 100644 index 00000000..553960f8 --- /dev/null +++ b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs @@ -0,0 +1,165 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using System.Text; +using JNPF.Common.Security; +using Mapster; +using Newtonsoft.Json.Linq; +using SqlSugar; +using Tnb.Vengine.DataAccess; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.AppService; + +/// +/// 视图模型服务类 +/// +public class VmodelPageAppService : VmAppService, IVmodelPageAppService +{ + /// + /// 构造函数 + /// + public VmodelPageAppService(IDataAccess da) : base(da) + { + } + + /// + /// 获取一条 数据信息 + /// + public override async Task GetAsync(VmGetInput input) + { + var query = _db.Queryable().Where(a => a.deleted == 0); + VmodelPage vm = await query.FirstAsync(a => a.id == input.id); + return vm; + } + + /// + /// 获取多条 数据列表 + /// + public override async Task GetListAsync(VmGetListInput input) + { + VmPagedOutput ret = new(); + var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.code.Contains(input.k!) || a.name.Contains(input.k!)); + RefAsync total = 0; + var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); + ret.total = total; + ret.items = data.ConvertAll(a => a); + return ret; + } + + /// + /// 新增 模型 + /// + public override async Task CreateAsync(VmCreateInput input) + { + ArgumentNullException.ThrowIfNull(input.data); + VmodelPage vpage = input.data.Adapt(); + await _db.Insertable(vpage).ExecuteCommandAsync(); + return vpage; + } + + /// + /// 更新 数据 + /// + public override async Task UpdateAsync(VmUpdateInput input) + { + ArgumentNullException.ThrowIfNull(input.data); + if (!input.data.ContainsKey(nameof(VmodelPage.id))) + { + throw new Exception($"更新数据时主键({nameof(VmodelPage.id)})不可为空"); + } + var id = input.data[nameof(VmodelPage.id)].ToString(); + var model = await _db.Queryable().FirstAsync(a => a.id == id); + ArgumentNullException.ThrowIfNull(model); + input.data.Adapt(model, TypeAdapter.IgnoreNull); + await _db.Updateable(model).WhereColumns(a => a.id).ExecuteCommandAsync(); + return model; + } + + /// + /// 删除 数据 + /// + public override async Task DeleteAsync(VmDeleteInput input) + { + var ret = await _db.Deleteable(input.id).ExecuteCommandAsync(); + return ret; + } + + /// + /// 从数据表创建模型 + /// + public async Task CreateByVmodel(CreatePageFromVmodelInput input) + { + ArgumentNullException.ThrowIfNull(input.vmid); + var vm = await _dataAccess.GetVmodelAsync(input.vmid); + ArgumentNullException.ThrowIfNull(vm); + + var page = await _db.Queryable().FirstAsync(a => a.vmid == vm.id); + if (page == null) + { + page = new VmodelPage { vmid = vm.id, code = vm.vmCode, name = vm.vmName }; + page.pageSchema = CreatePageSchema(vm, page.id); + await _db.Insertable(page).ExecuteCommandAsync(); + } + else + { + page.pageSchema = CreatePageSchema(vm, page.id); + await _db.Updateable(page).ExecuteCommandAsync(); + } + return page; + } + + private JObject CreatePageSchema(Vmodel vm, string pageid) + { + StringBuilder str = new StringBuilder(); + str.AppendLine("{"); + str.AppendLine($"\"page\": {{ \"loadList\": true, \"watchClient\": false }},"); + str.AppendLine($"\"queryData\": {{ }},"); + str.AppendLine($"\"queryForm\": {{"); + str.AppendLine($"\"show\": false,"); + str.AppendLine($"\"attr\": {{ \"labelWidth\": \"106px\", \"hasKeyword\":false }},"); + str.AppendLine($"\"cols\": {{"); + var pQuery = vm.dbProps.Skip(1).Take(1).FirstOrDefault(); + if (pQuery != null) + { + str.AppendLine($"\"{pQuery.code}\": {{ \"label\": \"{pQuery.name}\", \"span\": 8, \"qtype\": 2, \"isQuick\": true, \"comp\": {{ \"type\": \"el-input\", \"attr\": {{ \"placeholder\": \"{pQuery.name}\", \"clearable\": true, \"maxlength\": 20 }} }} }}"); + } + str.AppendLine($"}}"); + str.AppendLine($"}},"); + str.AppendLine($"\"list\": {{"); + str.AppendLine($"\"opt\": {{ \"isPage\": true, \"isCheck\": true, \"sortBy\": \"\", \"pkey\": \"{vm.GetPrimary().code}\" }},"); + str.AppendLine($"\"attr\": {{ \"border\": false }},"); + str.AppendLine($"\"cols\": {{"); + foreach (var p in vm.dbProps) + { + str.AppendLine($"\"{p.code}\":{{ \"label\": \"{p.name}\", \"show\": true, \"attr\": {{ {p.GetDefaultWidth()} }}, \"comp\": {{}} }},"); + } + str.AppendLine($"}}"); + str.AppendLine($"}},"); + str.AppendLine($"\"editData\": {vm.GetDefaultDObject().ToJsonString()},"); + str.AppendLine($"\"editDlg\": {{ \"isAdd\": true, \"tabHeight\": 300, \"name\": \"{vm.vmName}\" }},"); + str.AppendLine($"\"editForm\": {{"); + str.AppendLine($"\"attr\": {{ \"labelWidth\": \"106px\" }},"); + str.AppendLine($"\"rules\": {{"); + foreach (var p in vm.dbProps.Where(a => a.required && !a.pkey)) + { + str.AppendLine($"\"{p.code}\": [{{ \"required\": true, \"message\": \"必填项不能为空\", \"trigger\": \"blur\" }}],"); + } + str.AppendLine($"}},"); + str.AppendLine($"\"cols\": {{"); + foreach (var p in vm.dbProps) + { + str.AppendLine($"\"{p.code}\": {{ \"label\": \"{p.name}\", \"show\": true, \"comp\": {p.GetDefaultComp().ToJsonString()} }},"); + } + str.AppendLine($"}}"); + str.AppendLine($"}},"); + str.AppendLine($"\"tree\": {{ \"key\": \"id\", \"height\": 300, \"props\": {{ \"label\": \"enumName\" }}, \"data\": [] }}"); + str.AppendLine($"}}"); + var s = str.ToString(); + Console.WriteLine(s); + return JObject.Parse(s); + } + +} diff --git a/visualdev/Tnb.Vmodel/Constants/DbConsts.cs b/visualdev/Tnb.Vengine/Constants/DbConsts.cs similarity index 99% rename from visualdev/Tnb.Vmodel/Constants/DbConsts.cs rename to visualdev/Tnb.Vengine/Constants/DbConsts.cs index 162f3f70..bed8b683 100644 --- a/visualdev/Tnb.Vmodel/Constants/DbConsts.cs +++ b/visualdev/Tnb.Vengine/Constants/DbConsts.cs @@ -3,7 +3,7 @@ // https://git.tuotong-tech.com/tnb/tnb.server // ///////////////////////////////////////////////////////////////////////////////// -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine; public static class DbConsts { diff --git a/visualdev/Tnb.Vmodel/Constants/ModuleConst.cs b/visualdev/Tnb.Vengine/Constants/ModuleConst.cs similarity index 77% rename from visualdev/Tnb.Vmodel/Constants/ModuleConst.cs rename to visualdev/Tnb.Vengine/Constants/ModuleConst.cs index 1e99e591..52c2abbe 100644 --- a/visualdev/Tnb.Vmodel/Constants/ModuleConst.cs +++ b/visualdev/Tnb.Vengine/Constants/ModuleConst.cs @@ -1,4 +1,4 @@ -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine; public class ModuleConst { diff --git a/visualdev/Tnb.Vmodel/Constants/VmodelEnum.cs b/visualdev/Tnb.Vengine/Constants/VmodelEnum.cs similarity index 98% rename from visualdev/Tnb.Vmodel/Constants/VmodelEnum.cs rename to visualdev/Tnb.Vengine/Constants/VmodelEnum.cs index f4e4fe1b..c328ad33 100644 --- a/visualdev/Tnb.Vmodel/Constants/VmodelEnum.cs +++ b/visualdev/Tnb.Vengine/Constants/VmodelEnum.cs @@ -5,7 +5,7 @@ using System.ComponentModel; -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine; public enum eCsType { diff --git a/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs new file mode 100644 index 00000000..6d287556 --- /dev/null +++ b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs @@ -0,0 +1,422 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using System.Collections.Concurrent; +using JNPF; +using JNPF.DependencyInjection; +using Mapster; +using SqlSugar; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.DataAccess; + +/// +/// +/// +public class DataAccess : IDataAccess, ITransient, IDisposable +{ + const int MAX_PAGE_SIZE = 1000; + private ISqlSugarClient? sugar; + protected ISqlSugarClient Db + { + get + { + if (sugar == null) + { + ConnectionStringsOptions conn = App.GetConfig("ConnectionStrings", true); + //var DBType = (DbType)Enum.Parse(typeof(DbType), conn.DBType); + sugar = new SqlSugarScope(new ConnectionConfig + { + ConnectionString = conn.ConnectString, + DbType = conn.DBType.Adapt(), + IsAutoCloseConnection = true, + ConfigId = conn.ConfigId, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsAutoRemoveDataCache = true, // 自动清理缓存 + IsAutoToUpper = false, + PgSqlIsAutoToLower = false, + DisableNvarchar = true + }, + }, SugarHelper.ConfigSugar); + } + return sugar; + } + } + + /// + /// 全局缓存 + /// + static ConcurrentDictionary DbCache = new ConcurrentDictionary(); + + /// + /// 构造 + /// + public DataAccess() + { + } + + /// + /// 释放 + /// + public void Dispose() + { + foreach (var item in DbCache) + { + item.Value.Dispose(); + } + DbCache.Clear(); + } + + /// + /// 获取 ISqlSugarClient + /// + public ISqlSugarClient GetSqlSugar(string? dbCode = null) + { + if (string.IsNullOrEmpty(dbCode) || dbCode == DbConsts.DefaultDbCode) + { + return Db; + } + if (DbCache.ContainsKey(dbCode)) + { + return DbCache[dbCode]; + } + + var dblink = GetVmLink(dbCode); + if (dblink == null) + { + throw new Exception($"没有此数据库{dbCode}连接信息"); + } + var dbType = Enum.Parse(dblink.dbType.ToString(), true); + var sugar = new SqlSugarScope(new ConnectionConfig + { + ConnectionString = dblink.dbConnection, + DbType = dbType, + IsAutoCloseConnection = true, + ConfigId = dblink.dbCode, + InitKeyType = InitKeyType.Attribute, + MoreSettings = new ConnMoreSettings() + { + IsAutoRemoveDataCache = true, // 自动清理缓存 + IsAutoToUpper = false, + PgSqlIsAutoToLower = false, + DisableNvarchar = true + }, + }, SugarHelper.ConfigSugar); + if (sugar.Ado.IsValidConnection()) + { + DbCache[dbCode] = sugar; + } + else + { + sugar.Dispose(); + throw new Exception($"无法连接到数据库{dbCode}"); + } + return DbCache[dbCode]; + } + + /// + /// 获取 DbLink + /// + public VmodelLink GetVmLink(string dbCode) + { + var model = Db.Queryable().First(a => a.dbCode == dbCode); + return model; + } + + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + public async Task TryGetVmodelAsync(string id, bool loadNavigate = false) + { + Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); + if (vm != null && loadNavigate) + { + await LoadVmodelNavigateAsync(vm); + } + return vm; + } + + /// + /// 获取 Vmodel, 为空时抛异常 + /// + public async Task GetVmodelAsync(string id, bool loadNavigate = false) + { + Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); + ArgumentNullException.ThrowIfNull(vm, $"找不到vmid={id}的模型"); + if (loadNavigate) + { + await LoadVmodelNavigateAsync(vm); + } + return vm; + } + + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + public async Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false) + { + Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); + if (vm != null && loadNavigate) + { + await LoadVmodelNavigateAsync(vm); + } + + return vm; + } + + /// + /// 获取 Vmodel, 为空时抛异常 + /// + public async Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false) + { + Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); + ArgumentNullException.ThrowIfNull(vm, $"找不到area={area}, vmCode={vmCode}的模型"); + if (loadNavigate) + { + await LoadVmodelNavigateAsync(vm); + } + + return vm; + } + + ///// + ///// 获取 Vmodel + ///// + //public async Task GetVmodelAsync(string tableName, string? dbCode) + //{ + // Vmodel vm = await _db.Queryable().FirstAsync(a => a.tableName == tableName && a.dbCode == dbCode && a.deleted == 0); + // return vm; + //} + + /// + /// 加载模型的导航属性 + /// + /// + /// + private async Task LoadVmodelNavigateAsync(Vmodel vm) + { + Dictionary dictVm = new(); + foreach (var navProp in vm.navProps) + { + if (!dictVm.ContainsKey(navProp.vmid)) + { + var navModel = await GetVmodelAsync(navProp.vmid); + dictVm.Add(navProp.vmid, navModel); + } + navProp.naviModel = dictVm[navProp.vmid]; + } + } + + /// + /// 查询数据 默认方法 + /// + public async Task QueryDataAsync(Vmodel vm, VmQueryInput input) + { + ISqlSugarClient db = GetSqlSugar(vm.dbCode); + var query = db.Queryable().AS(vm.tableName, VmSelectProp.MAIN_ALIES); + var selProps = vm.GetVmSelectProps(input.o); + //处理导航属性联表 + List joins = vm.GetJoinInfos(selProps); + query.AddJoinInfo(joins); + List wheres = vm.GetConditionalModels(input.q); + if (!string.IsNullOrEmpty(input.k)) + { + var lsCondition = new List>(); + var wType = WhereType.And; + foreach (var prop in vm.dbProps.Where(a => a.fuzzy)) + { + lsCondition.Add(new(wType, new ConditionalModel() { FieldName = prop.field, ConditionalType = ConditionalType.Like, FieldValue = input.k })); + wType = WhereType.Or; + } + wheres.Add(new ConditionalCollections() { ConditionalList = lsCondition }); + } + //处理查询参数 + query.Where(wheres); + if (!string.IsNullOrEmpty(input.sort)) + { + query.OrderBy(input.sort); + } + //处理输出字段 + List selects = vm.GetSelectModels(selProps); + query.Select(selects); + //查询数据 + VmPagedOutput result = new(); + List> ls = new(); + int skip = input.pnum > 0 ? (input.pnum - 1) * input.psize : 0; + int take = input.psize == 0 ? MAX_PAGE_SIZE : input.psize; + if (input.pnum > 0) { result.total = await query.CountAsync(); } + ls = await query.Skip(skip).Take(take).ToDictionaryListAsync(); + //组装输出对象 + foreach (var data in ls) + { + DObject ret = await NestedOutputAsync(vm, data, selProps); + result.items.Add(ret); + } + + return result; + } + + /// + /// 组装子模型对象 + /// + /// + /// + /// + /// + private async Task NestedOutputAsync(Vmodel vm, Dictionary src, List selProps) + { + DObject ret = new(); + foreach (var prop in selProps) + { + if (prop.navType == eNavigateType.None || prop.navCode == VmSelectProp.MAIN_ALIES) + { + if (src.ContainsKey(prop.code)) + { + ret.Add(prop.code, src[prop.code]); + } + } + else + { + if (prop.navType == eNavigateType.OneToOne) + { + var key = prop.navCode + "_" + prop.code; + ret.Add(key, src[key]); + //if (!ret.ContainsKey(prop.navCode)) + //{ + // ret.Add(prop.navCode, new DObject()); + //} + //var key = prop.navCode + "_" + prop.code; + //if (src.ContainsKey(key)) + //{ + // ((DObject)ret[prop.navCode]).Add(prop.code, src[key]); + //} + } + else if (prop.navType == eNavigateType.OneToMany) + { + if (!ret.ContainsKey(prop.navCode)) + { + ret.Add(prop.navCode, new List()); + } + var navProp = vm.navProps.First(a => a.code == prop.navCode); + if (navProp != null && navProp.naviModel != null && src.ContainsKey(navProp.refField)) + { + VmQueryInput input = new VmQueryInput(); + input.q = new DObject(navProp.refField, src[navProp.refField]); + input.o = string.Join(',', selProps.Where(a => a.navCode == prop.navCode).Select(a => a.code)); + ret[prop.navCode] = (await QueryDataAsync(navProp.naviModel, input)).items; + } + } + else if (prop.navType == eNavigateType.ManyToMany) + { + if (!ret.ContainsKey(prop.navCode)) + { + ret.Add(prop.navCode, new List()); + } + + } + + } + } + return ret; + } + + /// + /// 新增数据 默认方法 + /// + public async Task CreateDataAsync(Vmodel vm, VmCreateInput input) + { + ISqlSugarClient db = GetSqlSugar(vm.dbCode); + int num = 0; + if (input.data != null) + { + var model = vm.PropToField(input.data); + num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); + return input.data; + } + else if (input.items != null) + { + List lst = new List(); + foreach (var item in input.items) + { + lst.Add(vm.PropToField(item)); + } + num = await db.Insertable(lst).AS(vm.tableName).ExecuteCommandAsync(); + return input.items; + } + else + { + input.data = vm.GetDefaultDObject(); + var model = vm.PropToField(input.data); + num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); + return input.data; + } + + } + + /// + /// 更新数据 默认方法 + /// + public async Task UpdateDataAsync(Vmodel vm, VmUpdateInput input) + { + ISqlSugarClient db = GetSqlSugar(vm.dbCode); + var pk = vm.GetPrimary(); + int num = 0; + if (input.data != null) + { + var model = vm.PropToField(input.data); + if (!model.ContainsKey(pk.field)) + { + throw new Exception($"更新数据时主键({pk.code})不可为空"); + } + //if (!model.ContainsKey(pk.field) && input.id != null) + //{ + // model.Add(pk.field, input.id); + //} + num = await db.Updateable(model).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); + } + else if (input.items != null) + { + List lst = new(); + foreach (var item in input.items) + { + var model = vm.PropToField(item); + if (model.ContainsKey(pk.field)) + { + lst.Add(model); + } + } + num = await db.Updateable(lst).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); + } + return num; + } + + /// + /// 删除数据 默认方法 + /// + public async Task DeleteDataAsync(Vmodel vm, VmDeleteInput input) + { + ISqlSugarClient db = GetSqlSugar(vm.dbCode); + var pk = vm.GetPrimary(); + int num = 0; + List> ids = new(); + if (input.id != null) + { + ids.Add(new DObject(pk.field, input.id)); + } + else if (input.ids != null) + { + ids.AddRange(input.ids.Select(a => new DObject(pk.field, a))); + } + if (ids.Count > 0) + { + num = await db.Deleteable().AS(vm.tableName).WhereColumns(ids).ExecuteCommandAsync(); + } + + return num; + } + +} diff --git a/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs new file mode 100644 index 00000000..f91e1593 --- /dev/null +++ b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs @@ -0,0 +1,71 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using JNPF.DependencyInjection; +using SqlSugar; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine.DataAccess; + +/// +/// +/// +public interface IDataAccess : ITransient +{ + /// + /// 获取 SqlSugar + /// + /// + /// + ISqlSugarClient GetSqlSugar(string? dbCode = null); + + /// + /// 获取DbLink + /// + /// + /// + VmodelLink GetVmLink(string dbCode); + + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + Task TryGetVmodelAsync(string id, bool loadNavigate = false); + /// + /// 获取 Vmodel, 为空时抛异常 + /// + Task GetVmodelAsync(string id, bool loadNavigate = false); + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false); + /// + /// 获取 Vmodel, 为空时抛异常 + /// + Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false); + //Task QueryDataAsync(VmBaseInput input); + + /// + /// 查询数据 默认方法 + /// + Task QueryDataAsync(Vmodel vm, VmQueryInput input); + + //Task CreateDataAsync(VmCreateInput input); + /// + /// 新增数据 默认方法 + /// + Task CreateDataAsync(Vmodel vm, VmCreateInput input); + + //Task UpdateDataAsync(VmUpdateInput input); + /// + /// 更新数据 默认方法 + /// + Task UpdateDataAsync(Vmodel vm, VmUpdateInput input); + + //Task DeleteDataAsync(VmDeleteInput input); + /// + /// 删除数据 默认方法 + /// + Task DeleteDataAsync(Vmodel vm, VmDeleteInput input); +} diff --git a/visualdev/Tnb.Vengine/DataAccess/SugarHelper.cs b/visualdev/Tnb.Vengine/DataAccess/SugarHelper.cs new file mode 100644 index 00000000..164a516e --- /dev/null +++ b/visualdev/Tnb.Vengine/DataAccess/SugarHelper.cs @@ -0,0 +1,34 @@ +using JNPF.Logging; +using SqlSugar; + +namespace Tnb.Vengine.DataAccess; + +public class SugarHelper +{ + public static void ConfigSugar(ISqlSugarClient db) + { + // 设置超时时间 + db.Ado.CommandTimeOut = 30; + db.Aop.OnLogExecuted = (sql, pars) => + { + var finalSql = UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, pars); + if (db.Ado.SqlExecutionTime.TotalMilliseconds > 3000) + { + Log.Warning($"慢查询: {db.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); + } + else + { + var oldColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Green; + Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{db.Ado.SqlExecutionTime.TotalMilliseconds} ms"); + Console.WriteLine(finalSql); + Console.ForegroundColor = oldColor; + Console.WriteLine(); + } + }; + db.Aop.OnError = (ex) => + { + Log.Error(UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); + }; + } +} diff --git a/visualdev/Tnb.Vmodel/Entities/Entity.cs b/visualdev/Tnb.Vengine/Domain/Entity.cs similarity index 50% rename from visualdev/Tnb.Vmodel/Entities/Entity.cs rename to visualdev/Tnb.Vengine/Domain/Entity.cs index c938c9f8..4424b5f3 100644 --- a/visualdev/Tnb.Vmodel/Entities/Entity.cs +++ b/visualdev/Tnb.Vengine/Domain/Entity.cs @@ -5,26 +5,26 @@ using JNPF.Common.Contracts; -namespace Tnb.VmodelEngine; +namespace Tnb.Vengine.Domain; [Serializable] public abstract class Entity : IEntity { - protected Entity() - { - //EntityHelper.TrySetTenantId(this); - } + protected Entity() + { + //EntityHelper.TrySetTenantId(this); + } - /// - public override string ToString() - { - return $"[ENTITY: {GetType().Name}] Keys = {string.Join(", ", GetKeys())}"; - } + /// + public override string ToString() + { + return $"[ENTITY: {GetType().Name}] Keys = {string.Join(", ", GetKeys())}"; + } - public abstract object[] GetKeys(); + public abstract object[] GetKeys(); - //public bool EntityEquals(IEntity other) - //{ - // return EntityHelper.EntityEquals(this, other); - //} + //public bool EntityEquals(IEntity other) + //{ + // return EntityHelper.EntityEquals(this, other); + //} } diff --git a/visualdev/Tnb.Vengine/Domain/VmBaseProp.cs b/visualdev/Tnb.Vengine/Domain/VmBaseProp.cs new file mode 100644 index 00000000..d2a1d135 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmBaseProp.cs @@ -0,0 +1,36 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Newtonsoft.Json.Linq; + +namespace Tnb.Vengine.Domain; + +/// +/// 视图模型属性 +/// +public class VmBaseProp +{ + /// + /// 属性代码 + /// + public string code { get; set; } = string.Empty; + + /// + /// 显示名称 + /// + public string name { get; set; } = string.Empty; +} + +public class DictOption +{ + public string dictTypeId { get; set; } = string.Empty; + public string refField { get; set; } = "id"; +} + +public class CompOption +{ + public string type { get; set; } = "el-input"; + public JObject attr { get; set; } = new JObject(); +} \ No newline at end of file diff --git a/visualdev/Tnb.Vengine/Domain/VmCalcProp.cs b/visualdev/Tnb.Vengine/Domain/VmCalcProp.cs new file mode 100644 index 00000000..ae00bbe1 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmCalcProp.cs @@ -0,0 +1,12 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +namespace Tnb.Vengine.Domain; + + +public class VmCalProp : VmBaseProp +{ + public string calculate { get; set; } = string.Empty; +} diff --git a/visualdev/Tnb.Vengine/Domain/VmDbProp.cs b/visualdev/Tnb.Vengine/Domain/VmDbProp.cs new file mode 100644 index 00000000..3b632786 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmDbProp.cs @@ -0,0 +1,149 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Yitter.IdGenerator; + +namespace Tnb.Vengine.Domain; + +/// +/// 字段属性 +/// +public class VmDbProp : VmBaseProp +{ + #region Properties + /// + /// 字段名称 + /// + public string field { get; set; } = string.Empty; + + /// + /// 数据类型 + /// + public string dataType { get; set; } = "varchar"; + + /// + /// 数据类型 + /// + public string? csType { get; set; } + + /// + /// 长度 + /// + public int length { get; set; } + + /// + /// 精度 + /// + public int digit { get; set; } + + /// + /// 排序 + /// + public int ordinal { get; set; } + + /// + /// 非空 + /// + public bool required { get; set; } + + /// + /// 是否主键 + /// + public bool pkey { get; set; } + + /// + /// 是否模糊搜索 + /// + public bool fuzzy { get; set; } + + /// + /// 默认值 + /// + public string? defValue { get; set; } + + /// + /// 描述 + /// + public string? descrip { get; set; } + #endregion + + /// + /// 获取默认值 + /// + /// + public object? GetDefaultValue() + { + object? val = null; + if (string.IsNullOrEmpty(defValue)) + { + val = defValue switch + { + "@@snowid" => YitIdHelper.NextId().ToString(), + "@@now" => DateTime.Now, + "@@userid" => YitIdHelper.NextId().ToString(), + "@@orgid" => YitIdHelper.NextId().ToString(), + _ => null + }; + } + else + { + val = csType switch + { + "string" => string.Empty, + "short" or "int" or "long" => 0, + "float" or "double" or "decimal" => 0f, + "DateTime" => DateTime.Now, + _ => null + }; + } + return val; + } + + /// + /// 获取默认宽度 + /// + /// + public string GetDefaultWidth() + { + return csType switch + { + "string" => "\"width\": \"auto\"", + "int" or "short" or "long" => "\"width\": 80", + "DateTime" => "\"width\": 150", + _ => "" + }; + } + + /// + /// 获取默认组件 + /// + /// + public CompOption GetDefaultComp() + { + CompOption comp = new CompOption(); + if (pkey) + { + comp.attr.Add("disabled", true); + return comp; + } + switch (csType) + { + case "string": + comp.attr.Add("clearable", true); + comp.attr.Add("maxlength", length); + comp.attr.Add("showWordLimit", true); + break; + case "int": + case "short": + case "long": + comp.type = "el-input-number"; + break; + case "DateTime": + comp.type = "el-date-picker"; + break; + }; + return comp; + } +} \ No newline at end of file diff --git a/visualdev/Tnb.Vengine/Domain/VmDto.cs b/visualdev/Tnb.Vengine/Domain/VmDto.cs new file mode 100644 index 00000000..0119c894 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmDto.cs @@ -0,0 +1,198 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +namespace Tnb.Vengine.Domain; + +/// +/// 字典对象 +/// +public class DObject : Dictionary +{ + public DObject() { } + public DObject(string key, object value) + { + Add(key, value); + } + public DObject(Dictionary dictionary) : base(dictionary) + { + } + public void AddCascade(string code, object value) + { + var keys = code.Split('.'); + if (keys.Length == 1) + { + Add(code, value); + return; + } + for (int i = 0; i < keys.Length; i++) + { + DObject temp = this; + if (i < keys.Length - 1) + { + if (!ContainsKey(keys[i])) + { + temp = new DObject(); + Add(keys[i], temp); + } + else + { + temp = (DObject)temp[keys[i]]; + } + } + else + { + temp.Add(keys[i], value); + } + } + } +} + +public class VmBaseInput +{ + ///// + ///// 视图模型id + ///// + //public string vmid { get; set; } = string.Empty; +} +public class VmGetInput : VmBaseInput +{ + /// + /// 要获取数据的id + /// + public string? id { get; set; } + + /// + /// 过滤条件 + /// + public string? q { get; set; } + + /// + /// 输出字段 + /// + public string o { get; set; } = "*"; +} + +public class VmGetListInput : VmBaseInput +{ + /// + /// 当前页数 + /// + public int pnum { get; set; } + + /// + /// 每页记录数 + /// + public int psize { get; set; } + + /// + /// 排序 + /// + public string? sort { get; set; } = null; + + /// + /// 模糊查询 + /// + public string? k { get; set; } + + /// + /// 过滤条件 + /// + public string? q { get; set; } + + /// + /// 输出字段 + /// + public string o { get; set; } = "*"; +} + +/// +/// 获取多条数据输入参数 +/// +public class VmQueryInput : VmGetListInput +{ + /// + /// 查询条件 + /// + public new DObject? q { get; set; } + + /// + /// 高级查询 + /// + public DObject? adv { get; set; } +} + +/// +/// 新增数据输入参数 +/// +public class VmCreateInput : VmBaseInput +{ + /// + /// 数据 + /// + public DObject? data { get; set; } + + /// + /// 批量添加 + /// + public List? items { get; set; } +} + +/// +/// 修改数据输入参数 +/// +public class VmUpdateInput : VmCreateInput +{ + ///// + ///// 要更新的数据id + ///// + //public string? id { get; set; } +} + +/// +/// 删除数据输入参数 +/// +public class VmDeleteInput : VmBaseInput +{ + /// + /// 要删除的数据id + /// + public string? id { get; set; } + + /// + /// 要删除的id列表 + /// + public List? ids { get; set; } +} + +/// +/// 分页列表输出对象 +/// +/// +public class PagedOutput +{ + public int total { get; set; } + public List items { get; set; } = new List(); +} + +/// +/// 动态分页列表输出对象 +/// +public class VmPagedOutput : PagedOutput +{ + +} + +/// +/// 查询属性信息 +/// +public class VmSelectProp +{ + public const string MAIN_ALIES = "m"; + public string code { get; set; } = string.Empty; + public string field { get; set; } = string.Empty; + public string navCode { get; set; } = MAIN_ALIES; + public ePropType propType { get; set; } + public eNavigateType navType { get; set; } +} diff --git a/visualdev/Tnb.Vengine/Domain/VmNavProp.cs b/visualdev/Tnb.Vengine/Domain/VmNavProp.cs new file mode 100644 index 00000000..41e9886c --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmNavProp.cs @@ -0,0 +1,54 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Newtonsoft.Json; + +namespace Tnb.Vengine.Domain; + +/// +/// 导航属性 +/// +public class VmNavProp : VmBaseProp +{ + /// + /// 导航属性模型id + /// + public string vmid { get; set; } = string.Empty; + + /// + /// 导航关联类型 + /// + public eNavigateType navType { get; set; } + + /// + /// 源表字段 + /// + public string refCode { get; set; } = VmSelectProp.MAIN_ALIES; + + /// + /// 被引用字段 + /// + public string refField { get; set; } = string.Empty; + + /// + /// 源表字段 + /// + public string fkField { get; set; } = string.Empty; + + ///// + ///// 关联表表名 + ///// + //[JsonIgnore] + //public string refTable { get; set; } = string.Empty; + + ///// + ///// 被引用表(中间表) + ///// + //[JsonIgnore] + //public string? midTable { get; set; } + + [JsonIgnore] + public Vmodel? naviModel { get; set; } +} diff --git a/visualdev/Tnb.Vengine/Domain/Vmodel.cs b/visualdev/Tnb.Vengine/Domain/Vmodel.cs new file mode 100644 index 00000000..189f7f27 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/Vmodel.cs @@ -0,0 +1,443 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Reflection; +using Mapster; +using Newtonsoft.Json.Linq; +using SqlSugar; +using Yitter.IdGenerator; + +namespace Tnb.Vengine.Domain; + +/// +/// 视图模型 +/// +[SugarTable("sys_vmodel")] +public partial class Vmodel : Entity +{ + #region Properties + /// + /// 主键标识 + /// + [SugarColumn(IsPrimaryKey = true)] + public string id { get; set; } = YitIdHelper.NextId().ToString(); + + /// + /// 模块代码 + /// + [SugarColumn(ColumnName = "area", Length = DbConsts.LengthS)] + public string area { get; set; } = "edp"; + + /// + /// 视图代码 + /// + [SugarColumn(ColumnName = "vm_code", IsNullable = false, Length = DbConsts.LengthM)] + public string vmCode { get; set; } = string.Empty; + + /// + /// 视图名称 + /// + [SugarColumn(ColumnName = "vm_name", IsNullable = false, Length = DbConsts.LengthM)] + public string vmName { get; set; } = string.Empty; + + /// + /// 数据库连接 + /// + [SugarColumn(ColumnName = "db_code", Length = DbConsts.LengthS)] + public string? dbCode { get; set; } + + /// + /// 主表名称 + /// + [SugarColumn(ColumnName = "table_name", IsNullable = false, Length = DbConsts.LengthS)] + public string tableName { get; set; } = string.Empty; + + /// + /// 表字段属性 + /// + [SugarColumn(ColumnName = "db_props", IsNullable = false, IsJson = true)] + public List dbProps { get; set; } = new List(); + + /// + /// 导航属性 + /// + [SugarColumn(ColumnName = "nav_props", IsNullable = true, IsJson = true)] + public List navProps { get; set; } = new List(); + + /// + /// 计算属性 + /// + [SugarColumn(ColumnName = "cal_props", IsNullable = true, IsJson = true)] + public List calProps { get; set; } = new List(); + + /// + /// 排序 + /// + [SugarColumn(ColumnName = "ordinal", IsNullable = false)] + public int ordinal { get; set; } + + /// + /// 软删除 + /// + [SugarColumn(ColumnName = "soft_delete", IsNullable = false)] + public short softDelete { get; set; } + + /// + /// 是否激活 + /// + [SugarColumn(ColumnName = "enabled", IsNullable = false)] + public short enabled { get; set; } = 1; + + /// + /// 是否删除 + /// + [SugarColumn(ColumnName = "deleted", IsNullable = false)] + public short deleted { get; set; } + + /// + /// 描述 + /// + [SugarColumn(ColumnName = "descrip", Length = DbConsts.LengthL)] + public string? descrip { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time", IsNullable = false)] + public DateTime createTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_id", Length = DbConsts.LengthS)] + public string? createId { get; set; } + + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", Length = DbConsts.LengthS)] + public DateTime? modifyTime { get; set; } + + /// + /// 修改人 + /// + [SugarColumn(ColumnName = "modify_id", Length = DbConsts.LengthS)] + public string? modifyId { get; set; } + + /// + /// 主键 + /// + public override object[] GetKeys() + { + return new object[] { id }; + } + #endregion + + /// + /// 通过实体创建模型 + /// + /// + /// + /// + public static Vmodel CreateByEntity(Type tpEntity, string? dbCode = null) + { + Vmodel model = new() { dbCode = dbCode, vmCode = tpEntity.Name }; + var sugarTableAttr = tpEntity.GetCustomAttribute(); + if (sugarTableAttr != null) + { + model.tableName = sugarTableAttr.TableName; + model.vmName = sugarTableAttr.TableDescription; + } + if (string.IsNullOrEmpty(model.tableName)) + { + model.tableName = tpEntity.GetCustomAttribute()?.Name ?? tpEntity.Name; + } + if (string.IsNullOrEmpty(model.vmName)) + { + model.vmName = tpEntity.GetCustomAttribute()?.Name ?? tpEntity.GetCustomAttribute()?.Description ?? model.vmCode; + } + var props = tpEntity.GetProperties(BindingFlags.Public); + int n = 1; + foreach (var p in props) + { + VmDbProp prop = new(); + var sugarColumn = p.GetCustomAttribute(); + if (sugarColumn != null) + { + prop = sugarColumn.Adapt(); + } + prop.code = p.Name; + prop.ordinal = n++; + model.dbProps.Add(prop); + } + return model; + } + + /// + /// 获取模型的主键字段属性 + /// + /// + public VmDbProp GetPrimary() + { + return dbProps.First(a => a.pkey); + } + + /// + /// 根据属性名获取字段名 + /// + /// + /// + public string? PropCodeToFieldCode(string propCode) + { + return dbProps.Where(a => a.code == propCode).Select(a => a.field).FirstOrDefault(); + } + + /// + /// 根据字段名获取属性名 + /// + /// + /// + public string? FieldCodeToPropCode(string fieldCode) + { + return dbProps.Where(a => a.field == fieldCode).Select(a => a.code).FirstOrDefault(); + } + + /// + /// 属性代码转换为字段代码 + /// + /// + /// + /// + public DObject PropToField(DObject input, bool ignoreNotMapped = true) + { + DObject ret = new(); + foreach (var item in input) + { + var fcode = PropCodeToFieldCode(item.Key); + if (!string.IsNullOrEmpty(fcode)) + { + ret.Add(fcode, item.Value); + } + else if (!ignoreNotMapped) + { + ret.Add(item.Key, item.Value); + } + } + return ret; + } + + /// + /// 字段代码转换为属性代码 + /// + /// + /// + /// + public DObject FieldToProp(DObject input, bool ignoreNotMapped = true) + { + DObject ret = new(); + foreach (var item in input) + { + var pcode = FieldCodeToPropCode(item.Key); + if (!string.IsNullOrEmpty(pcode)) + { + ret.Add(pcode, item.Value); + } + else if (!ignoreNotMapped) + { + ret.Add(item.Key, item.Value); + } + } + return ret; + } + + /// + /// 获取查询字段的属性信息 + /// + /// + /// + public List GetVmSelectProps(string? outputProps) + { + if (string.IsNullOrEmpty(outputProps) || outputProps == "*") + { + return dbProps.Select(a => new VmSelectProp { code = a.code, field = a.field }).ToList(); + } + List selProps = new(); + var outputs = outputProps.Split(',').Distinct().ToList(); + foreach (var propCode in outputs) + { + if (!propCode.Contains(".")) + { + var fieldCode = PropCodeToFieldCode(propCode); + if (!string.IsNullOrEmpty(fieldCode)) + { + selProps.Add(new VmSelectProp { code = propCode, field = fieldCode }); + } + continue; + } + var codes = propCode.Split('.'); + if (codes.Length != 2) continue; + if (codes[0] == VmSelectProp.MAIN_ALIES) + { + var fieldCode = PropCodeToFieldCode(propCode); + if (!string.IsNullOrEmpty(fieldCode)) + { + selProps.Add(new VmSelectProp { code = propCode, field = fieldCode }); + } + continue; + } + var navProp = navProps.FirstOrDefault(a => a.code == codes[0]); + if (navProp?.naviModel != null) + { + var fieldCode = navProp.naviModel.PropCodeToFieldCode(codes[1]); + if (!string.IsNullOrEmpty(fieldCode)) + { + selProps.Add(new VmSelectProp { code = codes[1], field = fieldCode, navCode = codes[0], propType = ePropType.Navigate, navType = navProp.navType }); + } + } + } + return selProps; + } + + /// + /// 获取联表配置信息 + /// + /// + /// + public List GetJoinInfos(List selProps) + { + var navigates = selProps.Where(a => a.propType == ePropType.Navigate).Select(a => a.navCode).Distinct().ToList(); + List joins = new(); + foreach (var navCode in navigates) + { + if (navCode == VmSelectProp.MAIN_ALIES) continue; + var navProp = navProps.First(a => a.code == navCode); + if (navProp.naviModel == null || navProp.navType != eNavigateType.OneToOne) continue; + JoinInfoParameter join = new JoinInfoParameter { TableName = navProp.naviModel.tableName, ShortName = navCode, Type = JoinType.Inner }; + var fkField = navProp.naviModel.PropCodeToFieldCode(navProp.fkField); + var refField = navProp.refField; + if (navProp.refCode != VmSelectProp.MAIN_ALIES) + { + var refProp = navProps.First(a => a.code == navProp.refCode); + refField = refProp.naviModel!.PropCodeToFieldCode(navProp.refField); + } + join.Models = ObjectFuncModel.Create("Equals", $"{navCode}.{fkField}", $"{navProp.refCode}.{refField}"); + joins.Add(join); + } + return joins; + } + + /// + /// 转换为查询过滤条件 + /// + /// + /// + public List GetConditionalModels(DObject? filter) + { + List wheres = new List(); + if (filter == null) return wheres; + foreach (var item in filter) + { + // TODO 按子表条件查询 + if (item.Key.Contains(".")) + { + + } + var prop = dbProps.FirstOrDefault(a => a.code == item.Key); + if (prop == null) continue; + if (item.Value is JArray val) + { + var op = val[0].ToString(); + switch (op) + { + case "><": + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan }); + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan }); + break; + case ">=<": + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual }); + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan }); + break; + case "><=": + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan }); + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual }); + break; + case ">=<=": + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual }); + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual }); + break; + case "in": + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val.Skip(1).ToString(), ConditionalType = ConditionalType.In }); + break; + default: op = string.Empty; break; + } + } + else + { + //if (item.Value == null) continue; + var conditionalType = ConditionalType.Equal; + string? value = item.Value?.ToString(); + if (string.IsNullOrEmpty(value)) continue; + if (value.Length >= 2) + { + var op = value.Substring(0, 2); + switch (op) + { + case "%%": conditionalType = ConditionalType.Like; break; + case ">>": conditionalType = ConditionalType.GreaterThan; break; + case "<<": conditionalType = ConditionalType.LessThan; break; + case ">=": conditionalType = ConditionalType.GreaterThanOrEqual; break; + case "<=": conditionalType = ConditionalType.LessThanOrEqual; break; + case "==": conditionalType = ConditionalType.Equal; break; + default: op = string.Empty; break; + } + if (!string.IsNullOrEmpty(op)) + { + value = value.RemovePreFix(op); + if (value.ToLower() == "null") + { + value = null; + } + } + } + wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = value, ConditionalType = conditionalType }); + } + } + return wheres; + } + + /// + /// 转换为查询字段列表 + /// + /// + /// + public List GetSelectModels(List selProps) + { + return selProps.Where(a => a.navType != eNavigateType.OneToMany && a.navType != eNavigateType.ManyToMany).Select(a => new SelectModel + { + FiledName = (a.navCode == VmSelectProp.MAIN_ALIES ? "" : a.navCode + ".") + a.field, + AsName = (a.navCode == VmSelectProp.MAIN_ALIES ? "" : a.navCode + "_") + a.code + }).ToList(); + } + + /// + /// 获取默认对象 + /// + /// + public DObject GetDefaultDObject() + { + DObject obj = new(); + foreach (var p in dbProps) + { + obj.Add(p.code, p.GetDefaultValue()!); + } + return obj; + } + + +} + diff --git a/visualdev/Tnb.Vengine/Domain/VmodelDto.cs b/visualdev/Tnb.Vengine/Domain/VmodelDto.cs new file mode 100644 index 00000000..6a73406f --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmodelDto.cs @@ -0,0 +1,34 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +namespace Tnb.Vengine.Domain; + +public class VmodelCreateFromTableInput +{ + public string? dbCode { get; set; } + + public string tableName { get; set; } = string.Empty; + + public string? removePrefix { get; set; } + public string area { get; set; } = "edp"; +} + +public class CreatePageFromVmodelInput +{ + public Guid? viewId { get; set; } + public string? vmid { get; set; } +} + +public class VmodelGetInput +{ + public long? id { get; set; } + public string? moduleCode { get; set; } + public string? vmCode { get; set; } + public string? dbCode { get; set; } + public string? tableName { get; set; } + public bool drill { get; set; } + +} + diff --git a/visualdev/Tnb.Vengine/Domain/VmodelLink.cs b/visualdev/Tnb.Vengine/Domain/VmodelLink.cs new file mode 100644 index 00000000..255cc211 --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmodelLink.cs @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using SqlSugar; +using Yitter.IdGenerator; + +namespace Tnb.Vengine.Domain; + +/// +/// 数据库连接 +/// +[SugarTable("sys_vmodel_link")] +public partial class VmodelLink : Entity +{ + /// + /// 主键标识 + /// + [SugarColumn(IsPrimaryKey = true)] + public string id { get; set; } = YitIdHelper.NextId().ToString(); + /// + /// 数据库连接 + /// + [SugarColumn(ColumnName = "db_code", Length = DbConsts.LengthS)] + public string? dbCode { get; set; } + + /// + /// 数据库类型 + /// + [SugarColumn(ColumnName = "db_type", IsNullable = false)] + public eDbType dbType { get; set; } + + /// + /// 连接串 + /// + [SugarColumn(ColumnName = "db_connection", IsNullable = false, Length = DbConsts.LengthXL)] + public string dbConnection { get; set; } = ""; + + /// + /// 主键 + /// + public override object[] GetKeys() + { + return new object[] { id }; + } + +} + diff --git a/visualdev/Tnb.Vengine/Domain/VmodelPage.cs b/visualdev/Tnb.Vengine/Domain/VmodelPage.cs new file mode 100644 index 00000000..995c0dbf --- /dev/null +++ b/visualdev/Tnb.Vengine/Domain/VmodelPage.cs @@ -0,0 +1,107 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Newtonsoft.Json.Linq; +using SqlSugar; +using Yitter.IdGenerator; + +namespace Tnb.Vengine.Domain; + +/// +/// 功能页面 +/// +[SugarTable("sys_vmodel_page")] +public partial class VmodelPage : Entity +{ + #region Properties + /// + /// 主键标识 + /// + [SugarColumn(IsPrimaryKey = true)] + public string id { get; set; } = YitIdHelper.NextId().ToString(); + + /// + /// 模型id + /// + [SugarColumn(ColumnName = "vmid", Length = DbConsts.LengthS)] + public string? vmid { get; set; } + + /// + /// 页面代码 + /// + [SugarColumn(ColumnName = "code", Length = DbConsts.LengthS)] + public string code { get; set; } = string.Empty; + + /// + /// 页面名称 + /// + [SugarColumn(ColumnName = "name", Length = DbConsts.LengthM)] + public string name { get; set; } = string.Empty; + + /// + /// 页面类型 + /// + [SugarColumn(ColumnName = "page_type", Length = DbConsts.LengthS)] + public string pageType { get; set; } = string.Empty; + + /// + /// 页面配置 + /// + [SugarColumn(ColumnName = "page_schema", Length = DbConsts.LengthS, IsJson = true)] + public JObject pageSchema { get; set; } = new JObject(); + + /// + /// 页面配置 + /// + [SugarColumn(ColumnName = "option", Length = DbConsts.LengthS)] + public string? option { get; set; } = string.Empty; + + /// + /// 是否启用 + /// + [SugarColumn(ColumnName = "enabled")] + public short enabled { get; set; } = 1; + + /// + /// 是否删除 + /// + [SugarColumn(ColumnName = "deleted")] + public short deleted { get; set; } + + /// + /// 创建时间 + /// + [SugarColumn(ColumnName = "create_time")] + public DateTime createTime { get; set; } = DateTime.Now; + + /// + /// 创建人 + /// + [SugarColumn(ColumnName = "create_id", Length = DbConsts.LengthS)] + public string? createId { get; set; } + + /// + /// 修改时间 + /// + [SugarColumn(ColumnName = "modify_time", Length = DbConsts.LengthS)] + public DateTime? modifyTime { get; set; } + + /// + /// 修改人 + /// + [SugarColumn(ColumnName = "modify_id", Length = DbConsts.LengthS)] + public string? modifyId { get; set; } + + /// + /// 主键 + /// + public override object[] GetKeys() + { + return new object[] { id }; + } + #endregion + +} + diff --git a/visualdev/Tnb.Vengine/Extension/StringExtensions.cs b/visualdev/Tnb.Vengine/Extension/StringExtensions.cs new file mode 100644 index 00000000..03983c3e --- /dev/null +++ b/visualdev/Tnb.Vengine/Extension/StringExtensions.cs @@ -0,0 +1,577 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using JNPF.Common.Extension; +using JNPF.DependencyInjection; + +namespace System; + +/// +/// 字符串扩展类,来自Abp +/// +[SuppressSniffer] +public static class StringExtensions +{ + /// + /// Adds a char to end of given string if it does not ends with the char. + /// + public static string EnsureEndsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) + { + ThrowIf.IsNull(str, nameof(str)); + + if (str.EndsWith(c.ToString(), comparisonType)) + { + return str; + } + + return str + c; + } + + /// + /// Adds a char to beginning of given string if it does not starts with the char. + /// + public static string EnsureStartsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) + { + ThrowIf.IsNull(str, nameof(str)); + + if (str.StartsWith(c.ToString(), comparisonType)) + { + return str; + } + + return c + str; + } + + /// + /// Indicates whether this string is null or an System.String.Empty string. + /// + public static bool IsNullOrEmpty(this string str) + { + return string.IsNullOrEmpty(str); + } + + /// + /// indicates whether this string is null, empty, or consists only of white-space characters. + /// + public static bool IsNullOrWhiteSpace(this string str) + { + return string.IsNullOrWhiteSpace(str); + } + + /// + /// Gets a substring of a string from beginning of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + public static string Left(this string str, int len) + { + ThrowIf.IsNull(str, nameof(str)); + + if (str.Length < len) + { + throw new ArgumentException("len argument can not be bigger than given string's length!"); + } + + return str.Substring(0, len); + } + + /// + /// Converts line endings in the string to . + /// + public static string NormalizeLineEndings(this string str) + { + return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); + } + + /// + /// Gets index of nth occurrence of a char in a string. + /// + /// source string to be searched + /// Char to search in + /// Count of the occurrence + public static int NthIndexOf(this string str, char c, int n) + { + ThrowIf.IsNull(str, nameof(str)); + + var count = 0; + for (var i = 0; i < str.Length; i++) + { + if (str[i] != c) + { + continue; + } + + if ((++count) == n) + { + return i; + } + } + + return -1; + } + + /// + /// Removes first occurrence of the given postfixes from end of the given string. + /// + /// The string. + /// one or more postfix. + /// Modified string or the same string if it has not any of given postfixes + public static string RemovePostFix(this string str, params string[] postFixes) + { + return str.RemovePostFix(StringComparison.Ordinal, postFixes); + } + + /// + /// Removes first occurrence of the given postfixes from end of the given string. + /// + /// The string. + /// String comparison type + /// one or more postfix. + /// Modified string or the same string if it has not any of given postfixes + public static string RemovePostFix(this string str, StringComparison comparisonType, params string[] postFixes) + { + if (str.IsNullOrEmpty()) + { + return str; + } + + if (postFixes.IsNullOrEmpty()) + { + return str; + } + + foreach (var postFix in postFixes) + { + if (str.EndsWith(postFix, comparisonType)) + { + return str.Left(str.Length - postFix.Length); + } + } + + return str; + } + + /// + /// Removes first occurrence of the given prefixes from beginning of the given string. + /// + /// The string. + /// one or more prefix. + /// Modified string or the same string if it has not any of given prefixes + public static string RemovePreFix(this string str, params string[] preFixes) + { + return str.RemovePreFix(StringComparison.Ordinal, preFixes); + } + + /// + /// Removes first occurrence of the given prefixes from beginning of the given string. + /// + /// The string. + /// String comparison type + /// one or more prefix. + /// Modified string or the same string if it has not any of given prefixes + public static string RemovePreFix(this string str, StringComparison comparisonType, params string[] preFixes) + { + if (str.IsNullOrEmpty()) + { + return str; + } + + if (preFixes.IsNullOrEmpty()) + { + return str; + } + + foreach (var preFix in preFixes) + { + if (str.StartsWith(preFix, comparisonType)) + { + return str.Right(str.Length - preFix.Length); + } + } + + return str; + } + + public static string ReplaceFirst(this string str, string search, string replace, StringComparison comparisonType = StringComparison.Ordinal) + { + + var pos = str.IndexOf(search, comparisonType); + if (pos < 0) + { + return str; + } + + return str.Substring(0, pos) + replace + str.Substring(pos + search.Length); + } + + /// + /// Gets a substring of a string from end of the string. + /// + /// Thrown if is null + /// Thrown if is bigger that string's length + public static string Right(this string str, int len) + { + + if (str.Length < len) + { + throw new ArgumentException("len argument can not be bigger than given string's length!"); + } + + return str.Substring(str.Length - len, len); + } + + /// + /// Uses string.Split method to split given string by given separator. + /// + public static string[] Split(this string str, string separator) + { + return str.Split(new[] { separator }, StringSplitOptions.None); + } + + /// + /// Uses string.Split method to split given string by given separator. + /// + public static string[] Split(this string str, string separator, StringSplitOptions options) + { + return str.Split(new[] { separator }, options); + } + + /// + /// Uses string.Split method to split given string by . + /// + public static string[] SplitToLines(this string str) + { + return str.Split(Environment.NewLine); + } + + /// + /// Uses string.Split method to split given string by . + /// + public static string[] SplitToLines(this string str, StringSplitOptions options) + { + return str.Split(Environment.NewLine, options); + } + + /// + /// Converts PascalCase string to camelCase string. + /// + /// String to convert + /// set true to use current culture. Otherwise, invariant culture will be used. + /// set true to if you want to convert 'XYZ' to 'xyz'. + /// camelCase of the string + public static string ToCamelCase(this string str, bool useCurrentCulture = false, bool handleAbbreviations = false) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + if (str.Length == 1) + { + return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); + } + + if (handleAbbreviations && IsAllUpperCase(str)) + { + return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); + } + + return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str.Substring(1); + } + + /// + /// Converts given PascalCase/camelCase string to sentence (by splitting words by space). + /// Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". + /// + /// String to convert. + /// set true to use current culture. Otherwise, invariant culture will be used. + public static string ToSentenceCase(this string str, bool useCurrentCulture = false) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + return useCurrentCulture + ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])) + : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLowerInvariant(m.Value[1])); + } + + /// + /// Converts given PascalCase/camelCase string to kebab-case. + /// + /// String to convert. + /// set true to use current culture. Otherwise, invariant culture will be used. + public static string ToKebabCase(this string str, bool useCurrentCulture = false) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + str = str.ToCamelCase(); + + return useCurrentCulture + ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLower(m.Value[1])) + : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLowerInvariant(m.Value[1])); + } + + /// + /// Converts given PascalCase/camelCase string to snake case. + /// Example: "ThisIsSampleSentence" is converted to "this_is_a_sample_sentence". + /// https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslator.cs#L51 + /// + /// String to convert. + /// + public static string ToSnakeCase(this string str) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + var builder = new StringBuilder(str.Length + Math.Min(2, str.Length / 5)); + var previousCategory = default(UnicodeCategory?); + + for (var currentIndex = 0; currentIndex < str.Length; currentIndex++) + { + var currentChar = str[currentIndex]; + if (currentChar == '_') + { + builder.Append('_'); + previousCategory = null; + continue; + } + + var currentCategory = char.GetUnicodeCategory(currentChar); + switch (currentCategory) + { + case UnicodeCategory.UppercaseLetter: + case UnicodeCategory.TitlecaseLetter: + if (previousCategory == UnicodeCategory.SpaceSeparator || + previousCategory == UnicodeCategory.LowercaseLetter || + previousCategory != UnicodeCategory.DecimalDigitNumber && + previousCategory != null && + currentIndex > 0 && + currentIndex + 1 < str.Length && + char.IsLower(str[currentIndex + 1])) + { + builder.Append('_'); + } + + currentChar = char.ToLower(currentChar); + break; + + case UnicodeCategory.LowercaseLetter: + case UnicodeCategory.DecimalDigitNumber: + if (previousCategory == UnicodeCategory.SpaceSeparator) + { + builder.Append('_'); + } + break; + + default: + if (previousCategory != null) + { + previousCategory = UnicodeCategory.SpaceSeparator; + } + continue; + } + + builder.Append(currentChar); + previousCategory = currentCategory; + } + + return builder.ToString(); + } + + /// + /// Converts string to enum value. + /// + /// Type of enum + /// String value to convert + /// Returns enum object + public static T ToEnum(this string value) + where T : struct + { + ThrowIf.IsNull(value, nameof(value)); + return (T)Enum.Parse(typeof(T), value); + } + + /// + /// Converts string to enum value. + /// + /// Type of enum + /// String value to convert + /// Ignore case + /// Returns enum object + public static T ToEnum(this string value, bool ignoreCase) + where T : struct + { + ThrowIf.IsNull(value, nameof(value)); + return (T)Enum.Parse(typeof(T), value, ignoreCase); + } + + public static string ToMd5(this string str) + { + using (var md5 = MD5.Create()) + { + var inputBytes = Encoding.UTF8.GetBytes(str); + var hashBytes = md5.ComputeHash(inputBytes); + + var sb = new StringBuilder(); + foreach (var hashByte in hashBytes) + { + sb.Append(hashByte.ToString("X2")); + } + + return sb.ToString(); + } + } + + /// + /// Converts camelCase string to PascalCase string. + /// + /// String to convert + /// set true to use current culture. Otherwise, invariant culture will be used. + /// PascalCase of the string + public static string ToPascalCase(this string str, bool useCurrentCulture = false) + { + if (string.IsNullOrWhiteSpace(str)) + { + return str; + } + + if (str.Length == 1) + { + return useCurrentCulture ? str.ToUpper() : str.ToUpperInvariant(); + } + + return (useCurrentCulture ? char.ToUpper(str[0]) : char.ToUpperInvariant(str[0])) + str.Substring(1); + } + + /// + /// Gets a substring of a string from beginning of the string if it exceeds maximum length. + /// + public static string Truncate(this string str, int maxLength) + { + if (str.Length <= maxLength) + { + return str; + } + + return str.Left(maxLength); + } + + /// + /// Gets a substring of a string from Ending of the string if it exceeds maximum length. + /// + public static string TruncateFromBeginning(this string str, int maxLength) + { + if (str.Length <= maxLength) + { + return str; + } + + return str.Right(maxLength); + } + + /// + /// Gets a substring of a string from beginning of the string if it exceeds maximum length. + /// It adds a "..." postfix to end of the string if it's truncated. + /// Returning string can not be longer than maxLength. + /// + /// Thrown if is null + public static string TruncateWithPostfix(this string str, int maxLength) + { + return TruncateWithPostfix(str, maxLength, "..."); + } + + /// + /// Gets a substring of a string from beginning of the string if it exceeds maximum length. + /// It adds given to end of the string if it's truncated. + /// Returning string can not be longer than maxLength. + /// + /// Thrown if is null + public static string TruncateWithPostfix(this string str, int maxLength, string postfix) + { + if (str == string.Empty || maxLength == 0) + { + return string.Empty; + } + + if (str.Length <= maxLength) + { + return str; + } + + if (maxLength <= postfix.Length) + { + return postfix.Left(maxLength); + } + + return str.Left(maxLength - postfix.Length) + postfix; + } + + /// + /// Converts given string to a byte array using encoding. + /// + public static byte[] GetBytes(this string str) + { + return str.GetBytes(Encoding.UTF8); + } + + /// + /// Converts given string to a byte array using the given + /// + public static byte[] GetBytes([NotNull] this string str, [NotNull] Encoding encoding) + { + ThrowIf.IsNull(str, nameof(str)); + ThrowIf.IsNull(encoding, nameof(encoding)); + + return encoding.GetBytes(str); + } + + private static bool IsAllUpperCase(string input) + { + for (int i = 0; i < input.Length; i++) + { + if (Char.IsLetter(input[i]) && !Char.IsUpper(input[i])) + { + return false; + } + } + + return true; + } + + /// + /// Converts snake_case string to PascalCase string. + /// + /// String to convert + /// set true to use current culture. Otherwise, invariant culture will be used. + /// PascalCase of the string + public static string SnakeToPascalCase(this string str, bool useCurrentCulture = false) + { + var sArr = str.Split(new char[] { '-', '_' }).Select(a => a.ToPascalCase(useCurrentCulture)); + return string.Join("", sArr); + } + /// + /// Converts snake_case string to PascalCase string. + /// + /// String to convert + /// set true to use current culture. Otherwise, invariant culture will be used. + /// PascalCase of the string + public static string SnakeToCamelCase(this string str, bool useCurrentCulture = false) + { + return SnakeToPascalCase(str, useCurrentCulture).ToCamelCase(); + } + +} \ No newline at end of file diff --git a/visualdev/Tnb.Vengine/Mapper/TypeAdapter.cs b/visualdev/Tnb.Vengine/Mapper/TypeAdapter.cs new file mode 100644 index 00000000..8ec37fc6 --- /dev/null +++ b/visualdev/Tnb.Vengine/Mapper/TypeAdapter.cs @@ -0,0 +1,24 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using Mapster; +using Newtonsoft.Json.Linq; + +namespace Tnb.Vengine; + +public class TypeAdapter +{ + public static TypeAdapterConfig IgnoreNull { get; } + static TypeAdapter() + { + TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true); + TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); + TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); + TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); + IgnoreNull = TypeAdapterConfig.GlobalSettings.Clone(); + IgnoreNull.Default.IgnoreNullValues(true); + } + +} diff --git a/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs b/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs new file mode 100644 index 00000000..a217474e --- /dev/null +++ b/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs @@ -0,0 +1,52 @@ +///////////////////////////////////////////////////////////////////////////////// +// 宁波拓通e智造平台 ToTong Next Builder // +// https://git.tuotong-tech.com/tnb/tnb.server // +///////////////////////////////////////////////////////////////////////////////// + +using JNPF.Common.Security; +using Mapster; +using SqlSugar; +using Tnb.Vengine.Domain; + +namespace Tnb.Vengine; + +public class VmodelMapper : IRegister +{ + public void Register(TypeAdapterConfig config) + { + config.ForType() + .Map(dest => dest.psize, src => 1) + .Map(dest => dest.pnum, src => 0) + .Map(dest => dest.q, src => string.IsNullOrEmpty(src.q) ? null : src.q.ToObject()); + config.ForType() + .Map(dest => dest.q, src => string.IsNullOrEmpty(src.q) ? null : src.q.ToObject()); + config.ForType() + .Map(dest => dest.code, src => src.DbColumnName.SnakeToCamelCase(false)) + .Map(dest => dest.name, src => src.ColumnDescription) + .Map(dest => dest.field, src => src.DbColumnName) + .Map(dest => dest.dataType, src => src.DataType) + //.Map(dest => dest.csType, src => src.DbColumnName) + //.Map(dest => dest.propType, src => ePropType.DbTable) + .Map(dest => dest.length, src => src.Length) + .Map(dest => dest.digit, src => src.DecimalDigits) + //.Map(dest => dest.ordinal, src => src.i) + .Map(dest => dest.required, src => !src.IsNullable) + .Map(dest => dest.pkey, src => src.IsPrimarykey) + //.Map(dest => dest.descrip, src => src.DbColumnName) + .Map(dest => dest.defValue, src => src.DefaultValue); + config.ForType() + //.Map(dest => dest.code, src => src.DbColumnName.SnakeToCamelCase(false)) + .Map(dest => dest.name, src => src.ColumnDescription) + .Map(dest => dest.field, src => src.ColumnName) + .Map(dest => dest.dataType, src => src.ColumnDataType) + //.Map(dest => dest.csType, src => src.DbColumnName) + //.Map(dest => dest.propType, src => ePropType.DbTable) + .Map(dest => dest.length, src => src.Length) + .Map(dest => dest.digit, src => src.DecimalDigits) + //.Map(dest => dest.ordinal, src => src.i) + .Map(dest => dest.required, src => !src.IsNullable) + .Map(dest => dest.pkey, src => src.IsPrimaryKey); + //.Map(dest => dest.descrip, src => src.DbColumnName) + //.Map(dest => dest.defValue, src => src.DefaultValue); + } +} diff --git a/visualdev/Tnb.Vmodel/Tnb.VmodelEngine.csproj b/visualdev/Tnb.Vengine/Tnb.Vengine.csproj similarity index 100% rename from visualdev/Tnb.Vmodel/Tnb.VmodelEngine.csproj rename to visualdev/Tnb.Vengine/Tnb.Vengine.csproj diff --git a/visualdev/Tnb.Vengine/Util/ThrowIf.cs b/visualdev/Tnb.Vengine/Util/ThrowIf.cs new file mode 100644 index 00000000..578062bd --- /dev/null +++ b/visualdev/Tnb.Vengine/Util/ThrowIf.cs @@ -0,0 +1,137 @@ +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace System; + +public static class ThrowIf +{ + public static void When(bool isMatch, string msg) + { + if (isMatch) + { + throw new ArgumentException(msg); + } + } + + public static T IsNull([NotNull] T? value, string? msg = null, [CallerArgumentExpression("value")] string? paraName = null) + { + if (value == null) + { + throw string.IsNullOrEmpty(msg) ? new ArgumentNullException(paraName) : new ArgumentException(msg); + } + + return value; + } + + public static T IsNullOrDefault([NotNull] T? value, string? msg = null, [CallerArgumentExpression("value")] string? paraName = null) where T : struct + { + if (!value.HasValue || value.Value.Equals(default(T))) + { + throw string.IsNullOrEmpty(msg) ? new ArgumentException("值不可为空或默认值", paraName) : new ArgumentException(msg); + } + + return value.Value; + } + + + public static string IsNullOrWhiteSpace([NotNull] string? value, string? msg = null, [CallerArgumentExpression("value")] string? paraName = null) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw string.IsNullOrEmpty(msg) ? new ArgumentException("值不可为空或空格", paraName) : new ArgumentException(msg); + } + return value; + } + + public static string IsNullOrEmpty([NotNull] string? value, string? msg = null, [CallerArgumentExpression("value")] string? paraName = null) + { + if (string.IsNullOrEmpty(value)) + { + throw string.IsNullOrEmpty(msg) ? new ArgumentException("值不可为空", paraName) : new ArgumentException(msg); + } + + return value; + } + + //public static ICollection NotNullOrEmpty(ICollection value, string paraName) + //{ + // if (value.IsNullOrEmpty()) + // { + // throw new ArgumentException(paraName + " can not be null or empty!", paraName); + // } + + // return value; + //} + + //public static Type AssignableTo(Type type, string paraName) + //{ + // NotNull(type, paraName); + // if (!type.IsAssignableTo()) + // { + // throw new ArgumentException(paraName + " (type of " + type.AssemblyQualifiedName + ") should be assignable to the " + typeof(TBaseType).GetFullNameWithAssemblyName() + "!"); + // } + + // return type; + //} + + public static short OutOfRange(short value, string paraName, short minimumValue, short maximumValue = short.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + + public static int OutOfRange(int value, string paraName, int minimumValue, int maximumValue = int.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + + public static long OutOfRange(long value, string paraName, long minimumValue, long maximumValue = long.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + + public static float OutOfRange(float value, string paraName, float minimumValue, float maximumValue = float.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + + public static double OutOfRange(double value, string paraName, double minimumValue, double maximumValue = double.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + + public static decimal OutOfRange(decimal value, string paraName, decimal minimumValue, decimal maximumValue = decimal.MaxValue) + { + if (value < minimumValue || value > maximumValue) + { + throw new ArgumentException($"{paraName} is out of range min: {minimumValue} - max: {maximumValue}"); + } + + return value; + } + +} diff --git a/visualdev/Tnb.Vmodel/DataAccess/DataAccess.cs b/visualdev/Tnb.Vmodel/DataAccess/DataAccess.cs deleted file mode 100644 index 367878d9..00000000 --- a/visualdev/Tnb.Vmodel/DataAccess/DataAccess.cs +++ /dev/null @@ -1,422 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using System.Collections.Concurrent; -using JNPF; -using JNPF.DependencyInjection; -using Mapster; -using SqlSugar; -using Tnb.VmodelEngine; - -namespace Tnb.DataAccess; - -/// -/// -/// -public class DataAccess : IDataAccess, ITransient, IDisposable -{ - const int MAX_PAGE_SIZE = 1000; - private ISqlSugarClient? sugar; - protected ISqlSugarClient Db - { - get - { - if (sugar == null) - { - ConnectionStringsOptions conn = App.GetConfig("ConnectionStrings", true); - //var DBType = (DbType)Enum.Parse(typeof(DbType), conn.DBType); - sugar = new SqlSugarScope(new ConnectionConfig - { - ConnectionString = conn.ConnectString, - DbType = conn.DBType.Adapt(), - IsAutoCloseConnection = true, - ConfigId = conn.ConfigId, - InitKeyType = InitKeyType.Attribute, - MoreSettings = new ConnMoreSettings() - { - IsAutoRemoveDataCache = true, // 自动清理缓存 - IsAutoToUpper = false, - PgSqlIsAutoToLower = false, - DisableNvarchar = true - }, - }, SugarHelper.ConfigSugar); - } - return sugar; - } - } - - /// - /// 全局缓存 - /// - static ConcurrentDictionary DbCache = new ConcurrentDictionary(); - - /// - /// 构造 - /// - public DataAccess() - { - } - - /// - /// 释放 - /// - public void Dispose() - { - foreach (var item in DbCache) - { - item.Value.Dispose(); - } - DbCache.Clear(); - } - - /// - /// 获取 ISqlSugarClient - /// - public ISqlSugarClient GetSqlSugar(string? dbCode = null) - { - if (string.IsNullOrEmpty(dbCode) || dbCode == DbConsts.DefaultDbCode) - { - return Db; - } - if (DbCache.ContainsKey(dbCode)) - { - return DbCache[dbCode]; - } - - var dblink = GetVmLink(dbCode); - if (dblink == null) - { - throw new Exception($"没有此数据库{dbCode}连接信息"); - } - var dbType = Enum.Parse(dblink.dbType.ToString(), true); - var sugar = new SqlSugarScope(new ConnectionConfig - { - ConnectionString = dblink.dbConnection, - DbType = dbType, - IsAutoCloseConnection = true, - ConfigId = dblink.dbCode, - InitKeyType = InitKeyType.Attribute, - MoreSettings = new ConnMoreSettings() - { - IsAutoRemoveDataCache = true, // 自动清理缓存 - IsAutoToUpper = false, - PgSqlIsAutoToLower = false, - DisableNvarchar = true - }, - }, SugarHelper.ConfigSugar); - if (sugar.Ado.IsValidConnection()) - { - DbCache[dbCode] = sugar; - } - else - { - sugar.Dispose(); - throw new Exception($"无法连接到数据库{dbCode}"); - } - return DbCache[dbCode]; - } - - /// - /// 获取 DbLink - /// - public VmodelLink GetVmLink(string dbCode) - { - var model = Db.Queryable().First(a => a.dbCode == dbCode); - return model; - } - - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - public async Task TryGetVmodelAsync(string id, bool loadNavigate = false) - { - Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); - if (vm != null && loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } - return vm; - } - - /// - /// 获取 Vmodel, 为空时抛异常 - /// - public async Task GetVmodelAsync(string id, bool loadNavigate = false) - { - Vmodel vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); - ArgumentNullException.ThrowIfNull(vm, $"找不到vmid={id}的模型"); - if (loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } - return vm; - } - - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - public async Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false) - { - Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); - if (vm != null && loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } - - return vm; - } - - /// - /// 获取 Vmodel, 为空时抛异常 - /// - public async Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false) - { - Vmodel vm = await Db.Queryable().FirstAsync(a => a.area == area && a.vmCode == vmCode && a.deleted == 0); - ArgumentNullException.ThrowIfNull(vm, $"找不到area={area}, vmCode={vmCode}的模型"); - if (loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } - - return vm; - } - - ///// - ///// 获取 Vmodel - ///// - //public async Task GetVmodelAsync(string tableName, string? dbCode) - //{ - // Vmodel vm = await _db.Queryable().FirstAsync(a => a.tableName == tableName && a.dbCode == dbCode && a.deleted == 0); - // return vm; - //} - - /// - /// 加载模型的导航属性 - /// - /// - /// - private async Task LoadVmodelNavigateAsync(Vmodel vm) - { - Dictionary dictVm = new(); - foreach (var navProp in vm.navProps) - { - if (!dictVm.ContainsKey(navProp.vmid)) - { - var navModel = await GetVmodelAsync(navProp.vmid); - dictVm.Add(navProp.vmid, navModel); - } - navProp.naviModel = dictVm[navProp.vmid]; - } - } - - /// - /// 查询数据 默认方法 - /// - public async Task QueryDataAsync(Vmodel vm, VmQueryInput input) - { - ISqlSugarClient db = GetSqlSugar(vm.dbCode); - var query = db.Queryable().AS(vm.tableName, VmSelectProp.MAIN_ALIES); - var selProps = vm.GetVmSelectProps(input.o); - //处理导航属性联表 - List joins = vm.GetJoinInfos(selProps); - query.AddJoinInfo(joins); - List wheres = vm.GetConditionalModels(input.q); - if (!string.IsNullOrEmpty(input.k)) - { - var lsCondition = new List>(); - var wType = WhereType.And; - foreach (var prop in vm.dbProps.Where(a => a.fuzzy)) - { - lsCondition.Add(new(wType, new ConditionalModel() { FieldName = prop.field, ConditionalType = ConditionalType.Like, FieldValue = input.k })); - wType = WhereType.Or; - } - wheres.Add(new ConditionalCollections() { ConditionalList = lsCondition }); - } - //处理查询参数 - query.Where(wheres); - if (!string.IsNullOrEmpty(input.sort)) - { - query.OrderBy(input.sort); - } - //处理输出字段 - List selects = vm.GetSelectModels(selProps); - query.Select(selects); - //查询数据 - VmPagedOutput result = new(); - List> ls = new(); - int skip = input.pnum > 0 ? (input.pnum - 1) * input.psize : 0; - int take = input.psize == 0 ? MAX_PAGE_SIZE : input.psize; - if (input.pnum > 0) { result.total = await query.CountAsync(); } - ls = await query.Skip(skip).Take(take).ToDictionaryListAsync(); - //组装输出对象 - foreach (var data in ls) - { - DObject ret = await NestedOutputAsync(vm, data, selProps); - result.items.Add(ret); - } - - return result; - } - - /// - /// 组装子模型对象 - /// - /// - /// - /// - /// - private async Task NestedOutputAsync(Vmodel vm, Dictionary src, List selProps) - { - DObject ret = new(); - foreach (var prop in selProps) - { - if (prop.navType == eNavigateType.None || prop.navCode == VmSelectProp.MAIN_ALIES) - { - if (src.ContainsKey(prop.code)) - { - ret.Add(prop.code, src[prop.code]); - } - } - else - { - if (prop.navType == eNavigateType.OneToOne) - { - var key = prop.navCode + "_" + prop.code; - ret.Add(key, src[key]); - //if (!ret.ContainsKey(prop.navCode)) - //{ - // ret.Add(prop.navCode, new DObject()); - //} - //var key = prop.navCode + "_" + prop.code; - //if (src.ContainsKey(key)) - //{ - // ((DObject)ret[prop.navCode]).Add(prop.code, src[key]); - //} - } - else if (prop.navType == eNavigateType.OneToMany) - { - if (!ret.ContainsKey(prop.navCode)) - { - ret.Add(prop.navCode, new List()); - } - var navProp = vm.navProps.First(a => a.code == prop.navCode); - if (navProp != null && navProp.naviModel != null && src.ContainsKey(navProp.refField)) - { - VmQueryInput input = new VmQueryInput(); - input.q = new DObject(navProp.refField, src[navProp.refField]); - input.o = string.Join(',', selProps.Where(a => a.navCode == prop.navCode).Select(a => a.code)); - ret[prop.navCode] = (await QueryDataAsync(navProp.naviModel, input)).items; - } - } - else if (prop.navType == eNavigateType.ManyToMany) - { - if (!ret.ContainsKey(prop.navCode)) - { - ret.Add(prop.navCode, new List()); - } - - } - - } - } - return ret; - } - - /// - /// 新增数据 默认方法 - /// - public async Task CreateDataAsync(Vmodel vm, VmCreateInput input) - { - ISqlSugarClient db = GetSqlSugar(vm.dbCode); - int num = 0; - if (input.data != null) - { - var model = vm.PropToField(input.data); - num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); - return input.data; - } - else if (input.items != null) - { - List lst = new List(); - foreach (var item in input.items) - { - lst.Add(vm.PropToField(item)); - } - num = await db.Insertable(lst).AS(vm.tableName).ExecuteCommandAsync(); - return input.items; - } - else - { - input.data = vm.GetDefaultDObject(); - var model = vm.PropToField(input.data); - num = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); - return input.data; - } - - } - - /// - /// 更新数据 默认方法 - /// - public async Task UpdateDataAsync(Vmodel vm, VmUpdateInput input) - { - ISqlSugarClient db = GetSqlSugar(vm.dbCode); - var pk = vm.GetPrimary(); - int num = 0; - if (input.data != null) - { - var model = vm.PropToField(input.data); - if (!model.ContainsKey(pk.field)) - { - throw new Exception($"更新数据时主键({pk.code})不可为空"); - } - //if (!model.ContainsKey(pk.field) && input.id != null) - //{ - // model.Add(pk.field, input.id); - //} - num = await db.Updateable(model).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); - } - else if (input.items != null) - { - List lst = new(); - foreach (var item in input.items) - { - var model = vm.PropToField(item); - if (model.ContainsKey(pk.field)) - { - lst.Add(model); - } - } - num = await db.Updateable(lst).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); - } - return num; - } - - /// - /// 删除数据 默认方法 - /// - public async Task DeleteDataAsync(Vmodel vm, VmDeleteInput input) - { - ISqlSugarClient db = GetSqlSugar(vm.dbCode); - var pk = vm.GetPrimary(); - int num = 0; - List> ids = new(); - if (input.id != null) - { - ids.Add(new DObject(pk.field, input.id)); - } - else if (input.ids != null) - { - ids.AddRange(input.ids.Select(a => new DObject(pk.field, a))); - } - if (ids.Count > 0) - { - num = await db.Deleteable().AS(vm.tableName).WhereColumns(ids).ExecuteCommandAsync(); - } - - return num; - } - -} diff --git a/visualdev/Tnb.Vmodel/DataAccess/IDataAccess.cs b/visualdev/Tnb.Vmodel/DataAccess/IDataAccess.cs deleted file mode 100644 index 549e8018..00000000 --- a/visualdev/Tnb.Vmodel/DataAccess/IDataAccess.cs +++ /dev/null @@ -1,71 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using JNPF.DependencyInjection; -using SqlSugar; -using Tnb.VmodelEngine; - -namespace Tnb.DataAccess; - -/// -/// -/// -public interface IDataAccess : ITransient -{ - /// - /// 获取 SqlSugar - /// - /// - /// - ISqlSugarClient GetSqlSugar(string? dbCode = null); - - /// - /// 获取DbLink - /// - /// - /// - VmodelLink GetVmLink(string dbCode); - - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - Task TryGetVmodelAsync(string id, bool loadNavigate = false); - /// - /// 获取 Vmodel, 为空时抛异常 - /// - Task GetVmodelAsync(string id, bool loadNavigate = false); - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false); - /// - /// 获取 Vmodel, 为空时抛异常 - /// - Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false); - //Task QueryDataAsync(VmBaseInput input); - - /// - /// 查询数据 默认方法 - /// - Task QueryDataAsync(Vmodel vm, VmQueryInput input); - - //Task CreateDataAsync(VmCreateInput input); - /// - /// 新增数据 默认方法 - /// - Task CreateDataAsync(Vmodel vm, VmCreateInput input); - - //Task UpdateDataAsync(VmUpdateInput input); - /// - /// 更新数据 默认方法 - /// - Task UpdateDataAsync(Vmodel vm, VmUpdateInput input); - - //Task DeleteDataAsync(VmDeleteInput input); - /// - /// 删除数据 默认方法 - /// - Task DeleteDataAsync(Vmodel vm, VmDeleteInput input); -} diff --git a/visualdev/Tnb.Vmodel/DataAccess/SugarHelper.cs b/visualdev/Tnb.Vmodel/DataAccess/SugarHelper.cs deleted file mode 100644 index 68364c26..00000000 --- a/visualdev/Tnb.Vmodel/DataAccess/SugarHelper.cs +++ /dev/null @@ -1,34 +0,0 @@ -using JNPF.Logging; -using SqlSugar; - -namespace Tnb.VmodelEngine; - -public class SugarHelper -{ - public static void ConfigSugar(ISqlSugarClient db) - { - // 设置超时时间 - db.Ado.CommandTimeOut = 30; - db.Aop.OnLogExecuted = (sql, pars) => - { - var finalSql = UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, sql, pars); - if (db.Ado.SqlExecutionTime.TotalMilliseconds > 3000) - { - Log.Warning($"慢查询: {db.Ado.SqlExecutionTime.TotalMilliseconds}ms, SQL: " + finalSql); - } - else - { - var oldColor = Console.ForegroundColor; - Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine($"【{DateTime.Now.ToString("HH:mm:ss.fff")}——SQL执行完成】{db.Ado.SqlExecutionTime.TotalMilliseconds} ms"); - Console.WriteLine(finalSql); - Console.ForegroundColor = oldColor; - Console.WriteLine(); - } - }; - db.Aop.OnError = (ex) => - { - Log.Error(UtilMethods.GetSqlString(db.CurrentConnectionConfig.DbType, ex.Sql, (SugarParameter[])ex.Parametres)); - }; - } -} diff --git a/visualdev/Tnb.Vmodel/Dtos/VmDto.cs b/visualdev/Tnb.Vmodel/Dtos/VmDto.cs deleted file mode 100644 index 97a6c736..00000000 --- a/visualdev/Tnb.Vmodel/Dtos/VmDto.cs +++ /dev/null @@ -1,198 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -namespace Tnb.VmodelEngine; - -/// -/// 字典对象 -/// -public class DObject : Dictionary -{ - public DObject() { } - public DObject(string key, object value) - { - Add(key, value); - } - public DObject(Dictionary dictionary) : base(dictionary) - { - } - public void AddCascade(string code, object value) - { - var keys = code.Split('.'); - if(keys.Length == 1 ) - { - Add(code, value); - return; - } - for (int i = 0; i < keys.Length; i++) - { - DObject temp = this; - if(i < keys.Length - 1) - { - if (!ContainsKey(keys[i])) - { - temp = new DObject(); - Add(keys[i], temp); - } - else - { - temp = (DObject)temp[keys[i]]; - } - } - else - { - temp.Add(keys[i], value); - } - } - } -} - -public class VmBaseInput -{ - ///// - ///// 视图模型id - ///// - //public string vmid { get; set; } = string.Empty; -} -public class VmGetInput : VmBaseInput -{ - /// - /// 要获取数据的id - /// - public string? id { get; set; } - - /// - /// 过滤条件 - /// - public string? q { get; set; } - - /// - /// 输出字段 - /// - public string o { get; set; } = "*"; -} - -public class VmGetListInput : VmBaseInput -{ - /// - /// 当前页数 - /// - public int pnum { get; set; } - - /// - /// 每页记录数 - /// - public int psize { get; set; } - - /// - /// 排序 - /// - public string? sort { get; set; } = null; - - /// - /// 模糊查询 - /// - public string? k { get; set; } - - /// - /// 过滤条件 - /// - public string? q { get; set; } - - /// - /// 输出字段 - /// - public string o { get; set; } = "*"; -} - -/// -/// 获取多条数据输入参数 -/// -public class VmQueryInput : VmGetListInput -{ - /// - /// 查询条件 - /// - public new DObject? q { get; set; } - - /// - /// 高级查询 - /// - public DObject? adv { get; set; } -} - -/// -/// 新增数据输入参数 -/// -public class VmCreateInput : VmBaseInput -{ - /// - /// 数据 - /// - public DObject? data { get; set; } - - /// - /// 批量添加 - /// - public List? items { get; set; } -} - -/// -/// 修改数据输入参数 -/// -public class VmUpdateInput : VmCreateInput -{ - ///// - ///// 要更新的数据id - ///// - //public string? id { get; set; } -} - -/// -/// 删除数据输入参数 -/// -public class VmDeleteInput : VmBaseInput -{ - /// - /// 要删除的数据id - /// - public string? id { get; set; } - - /// - /// 要删除的id列表 - /// - public List? ids { get; set; } -} - -/// -/// 分页列表输出对象 -/// -/// -public class PagedOutput -{ - public int total { get; set; } - public List items { get; set; } = new List(); -} - -/// -/// 动态分页列表输出对象 -/// -public class VmPagedOutput : PagedOutput -{ - -} - -/// -/// 查询属性信息 -/// -public class VmSelectProp -{ - public const string MAIN_ALIES = "m"; - public string code { get; set; } = string.Empty; - public string field { get; set; } = string.Empty; - public string navCode { get; set; } = MAIN_ALIES; - public ePropType propType { get; set; } - public eNavigateType navType { get; set; } -} diff --git a/visualdev/Tnb.Vmodel/Dtos/VmodelDto.cs b/visualdev/Tnb.Vmodel/Dtos/VmodelDto.cs deleted file mode 100644 index 78d43e09..00000000 --- a/visualdev/Tnb.Vmodel/Dtos/VmodelDto.cs +++ /dev/null @@ -1,34 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -namespace Tnb.VmodelEngine; - -public class VmodelCreateFromTableInput -{ - public string? dbCode { get; set; } - - public string tableName { get; set; } = string.Empty; - - public string? removePrefix { get; set; } - public string area { get; set; } = "edp"; -} - -public class CreatePageFromVmodelInput -{ - public Guid? viewId { get; set; } - public string? vmid { get; set; } -} - -public class VmodelGetInput -{ - public long? id { get; set; } - public string? moduleCode { get; set; } - public string? vmCode { get; set; } - public string? dbCode { get; set; } - public string? tableName { get; set; } - public bool drill { get; set; } - -} - diff --git a/visualdev/Tnb.Vmodel/Entities/Vmodel.cs b/visualdev/Tnb.Vmodel/Entities/Vmodel.cs deleted file mode 100644 index c4da2a12..00000000 --- a/visualdev/Tnb.Vmodel/Entities/Vmodel.cs +++ /dev/null @@ -1,444 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using System.ComponentModel; -using System.ComponentModel.DataAnnotations; -using System.ComponentModel.DataAnnotations.Schema; -using System.Reflection; -using Mapster; -using Newtonsoft.Json.Linq; -using SqlSugar; -using Tnb.DataAccess; -using Yitter.IdGenerator; - -namespace Tnb.VmodelEngine; - -/// -/// 视图模型 -/// -[SugarTable("sys_vmodel")] -public partial class Vmodel : Entity -{ - #region Properties - /// - /// 主键标识 - /// - [SugarColumn(IsPrimaryKey = true)] - public string id { get; set; } = YitIdHelper.NextId().ToString(); - - /// - /// 模块代码 - /// - [SugarColumn(ColumnName = "area", Length = DbConsts.LengthS)] - public string area { get; set; } = "edp"; - - /// - /// 视图代码 - /// - [SugarColumn(ColumnName = "vm_code", IsNullable = false, Length = DbConsts.LengthM)] - public string vmCode { get; set; } = string.Empty; - - /// - /// 视图名称 - /// - [SugarColumn(ColumnName = "vm_name", IsNullable = false, Length = DbConsts.LengthM)] - public string vmName { get; set; } = string.Empty; - - /// - /// 数据库连接 - /// - [SugarColumn(ColumnName = "db_code", Length = DbConsts.LengthS)] - public string? dbCode { get; set; } - - /// - /// 主表名称 - /// - [SugarColumn(ColumnName = "table_name", IsNullable = false, Length = DbConsts.LengthS)] - public string tableName { get; set; } = string.Empty; - - /// - /// 表字段属性 - /// - [SugarColumn(ColumnName = "db_props", IsNullable = false, IsJson = true)] - public List dbProps { get; set; } = new List(); - - /// - /// 导航属性 - /// - [SugarColumn(ColumnName = "nav_props", IsNullable = true, IsJson = true)] - public List navProps { get; set; } = new List(); - - /// - /// 计算属性 - /// - [SugarColumn(ColumnName = "cal_props", IsNullable = true, IsJson = true)] - public List calProps { get; set; } = new List(); - - /// - /// 排序 - /// - [SugarColumn(ColumnName = "ordinal", IsNullable = false)] - public int ordinal { get; set; } - - /// - /// 软删除 - /// - [SugarColumn(ColumnName = "soft_delete", IsNullable = false)] - public short softDelete { get; set; } - - /// - /// 是否激活 - /// - [SugarColumn(ColumnName = "enabled", IsNullable = false)] - public short enabled { get; set; } = 1; - - /// - /// 是否删除 - /// - [SugarColumn(ColumnName = "deleted", IsNullable = false)] - public short deleted { get; set; } - - /// - /// 描述 - /// - [SugarColumn(ColumnName = "descrip", Length = DbConsts.LengthL)] - public string? descrip { get; set; } - - /// - /// 创建时间 - /// - [SugarColumn(ColumnName = "create_time", IsNullable = false)] - public DateTime createTime { get; set; } = DateTime.Now; - - /// - /// 创建人 - /// - [SugarColumn(ColumnName = "create_id", Length = DbConsts.LengthS)] - public string? createId { get; set; } - - /// - /// 修改时间 - /// - [SugarColumn(ColumnName = "modify_time", Length = DbConsts.LengthS)] - public DateTime? modifyTime { get; set; } - - /// - /// 修改人 - /// - [SugarColumn(ColumnName = "modify_id", Length = DbConsts.LengthS)] - public string? modifyId { get; set; } - - /// - /// 主键 - /// - public override object[] GetKeys() - { - return new object[] { id }; - } - #endregion - - /// - /// 通过实体创建模型 - /// - /// - /// - /// - public static Vmodel CreateByEntity(Type tpEntity, string? dbCode = null) - { - Vmodel model = new() { dbCode = dbCode, vmCode = tpEntity.Name }; - var sugarTableAttr = tpEntity.GetCustomAttribute(); - if (sugarTableAttr != null) - { - model.tableName = sugarTableAttr.TableName; - model.vmName = sugarTableAttr.TableDescription; - } - if (string.IsNullOrEmpty(model.tableName)) - { - model.tableName = tpEntity.GetCustomAttribute()?.Name ?? tpEntity.Name; - } - if (string.IsNullOrEmpty(model.vmName)) - { - model.vmName = tpEntity.GetCustomAttribute()?.Name ?? tpEntity.GetCustomAttribute()?.Description ?? model.vmCode; - } - var props = tpEntity.GetProperties(BindingFlags.Public); - int n = 1; - foreach (var p in props) - { - VmDbProp prop = new(); - var sugarColumn = p.GetCustomAttribute(); - if (sugarColumn != null) - { - prop = sugarColumn.Adapt(); - } - prop.code = p.Name; - prop.ordinal = n++; - model.dbProps.Add(prop); - } - return model; - } - - /// - /// 获取模型的主键字段属性 - /// - /// - public VmDbProp GetPrimary() - { - return dbProps.First(a => a.pkey); - } - - /// - /// 根据属性名获取字段名 - /// - /// - /// - public string? PropCodeToFieldCode(string propCode) - { - return dbProps.Where(a => a.code == propCode).Select(a => a.field).FirstOrDefault(); - } - - /// - /// 根据字段名获取属性名 - /// - /// - /// - public string? FieldCodeToPropCode(string fieldCode) - { - return dbProps.Where(a => a.field == fieldCode).Select(a => a.code).FirstOrDefault(); - } - - /// - /// 属性代码转换为字段代码 - /// - /// - /// - /// - public DObject PropToField(DObject input, bool ignoreNotMapped = true) - { - DObject ret = new(); - foreach (var item in input) - { - var fcode = PropCodeToFieldCode(item.Key); - if (!string.IsNullOrEmpty(fcode)) - { - ret.Add(fcode, item.Value); - } - else if (!ignoreNotMapped) - { - ret.Add(item.Key, item.Value); - } - } - return ret; - } - - /// - /// 字段代码转换为属性代码 - /// - /// - /// - /// - public DObject FieldToProp(DObject input, bool ignoreNotMapped = true) - { - DObject ret = new(); - foreach (var item in input) - { - var pcode = FieldCodeToPropCode(item.Key); - if (!string.IsNullOrEmpty(pcode)) - { - ret.Add(pcode, item.Value); - } - else if (!ignoreNotMapped) - { - ret.Add(item.Key, item.Value); - } - } - return ret; - } - - /// - /// 获取查询字段的属性信息 - /// - /// - /// - public List GetVmSelectProps(string? outputProps) - { - if (string.IsNullOrEmpty(outputProps) || outputProps == "*") - { - return dbProps.Select(a => new VmSelectProp { code = a.code, field = a.field }).ToList(); - } - List selProps = new(); - var outputs = outputProps.Split(',').Distinct().ToList(); - foreach (var propCode in outputs) - { - if (!propCode.Contains(".")) - { - var fieldCode = PropCodeToFieldCode(propCode); - if (!string.IsNullOrEmpty(fieldCode)) - { - selProps.Add(new VmSelectProp { code = propCode, field = fieldCode }); - } - continue; - } - var codes = propCode.Split('.'); - if (codes.Length != 2) continue; - if (codes[0] == VmSelectProp.MAIN_ALIES) - { - var fieldCode = PropCodeToFieldCode(propCode); - if (!string.IsNullOrEmpty(fieldCode)) - { - selProps.Add(new VmSelectProp { code = propCode, field = fieldCode }); - } - continue; - } - var navProp = navProps.FirstOrDefault(a => a.code == codes[0]); - if (navProp?.naviModel != null) - { - var fieldCode = navProp.naviModel.PropCodeToFieldCode(codes[1]); - if (!string.IsNullOrEmpty(fieldCode)) - { - selProps.Add(new VmSelectProp { code = codes[1], field = fieldCode, navCode = codes[0], propType = ePropType.Navigate, navType = navProp.navType }); - } - } - } - return selProps; - } - - /// - /// 获取联表配置信息 - /// - /// - /// - public List GetJoinInfos(List selProps) - { - var navigates = selProps.Where(a => a.propType == ePropType.Navigate).Select(a => a.navCode).Distinct().ToList(); - List joins = new(); - foreach (var navCode in navigates) - { - if (navCode == VmSelectProp.MAIN_ALIES) continue; - var navProp = navProps.First(a => a.code == navCode); - if (navProp.naviModel == null || navProp.navType != eNavigateType.OneToOne) continue; - JoinInfoParameter join = new JoinInfoParameter { TableName = navProp.naviModel.tableName, ShortName = navCode, Type = JoinType.Inner }; - var fkField = navProp.naviModel.PropCodeToFieldCode(navProp.fkField); - var refField = navProp.refField; - if (navProp.refCode != VmSelectProp.MAIN_ALIES) - { - var refProp = navProps.First(a => a.code == navProp.refCode); - refField = refProp.naviModel!.PropCodeToFieldCode(navProp.refField); - } - join.Models = ObjectFuncModel.Create("Equals", $"{navCode}.{fkField}", $"{navProp.refCode}.{refField}"); - joins.Add(join); - } - return joins; - } - - /// - /// 转换为查询过滤条件 - /// - /// - /// - public List GetConditionalModels(DObject? filter) - { - List wheres = new List(); - if (filter == null) return wheres; - foreach (var item in filter) - { - // TODO 按子表条件查询 - if (item.Key.Contains(".")) - { - - } - var prop = dbProps.FirstOrDefault(a => a.code == item.Key); - if (prop == null) continue; - if (item.Value is JArray val) - { - var op = val[0].ToString(); - switch (op) - { - case "><": - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan }); - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan }); - break; - case ">=<": - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual }); - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThan }); - break; - case "><=": - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThan }); - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual }); - break; - case ">=<=": - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[1].ToString(), ConditionalType = ConditionalType.GreaterThanOrEqual }); - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val[2].ToString(), ConditionalType = ConditionalType.LessThanOrEqual }); - break; - case "in": - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = val.Skip(1).ToString(), ConditionalType = ConditionalType.In }); - break; - default: op = string.Empty; break; - } - } - else - { - //if (item.Value == null) continue; - var conditionalType = ConditionalType.Equal; - string? value = item.Value?.ToString(); - if (string.IsNullOrEmpty(value)) continue; - if (value.Length >= 2) - { - var op = value.Substring(0, 2); - switch (op) - { - case "%%": conditionalType = ConditionalType.Like; break; - case ">>": conditionalType = ConditionalType.GreaterThan; break; - case "<<": conditionalType = ConditionalType.LessThan; break; - case ">=": conditionalType = ConditionalType.GreaterThanOrEqual; break; - case "<=": conditionalType = ConditionalType.LessThanOrEqual; break; - case "==": conditionalType = ConditionalType.Equal; break; - default: op = string.Empty; break; - } - if (!string.IsNullOrEmpty(op)) - { - value = value.RemovePreFix(op); - if (value.ToLower() == "null") - { - value = null; - } - } - } - wheres.Add(new ConditionalModel { FieldName = prop.field, FieldValue = value, ConditionalType = conditionalType }); - } - } - return wheres; - } - - /// - /// 转换为查询字段列表 - /// - /// - /// - public List GetSelectModels(List selProps) - { - return selProps.Where(a => a.navType != eNavigateType.OneToMany && a.navType != eNavigateType.ManyToMany).Select(a => new SelectModel - { - FiledName = (a.navCode == VmSelectProp.MAIN_ALIES ? "" : a.navCode + ".") + a.field, - AsName = (a.navCode == VmSelectProp.MAIN_ALIES ? "" : a.navCode + "_") + a.code - }).ToList(); - } - - /// - /// 获取默认对象 - /// - /// - public DObject GetDefaultDObject() - { - DObject obj = new(); - foreach (var p in dbProps) - { - obj.Add(p.code, p.GetDefaultValue()!); - } - return obj; - } - - -} - diff --git a/visualdev/Tnb.Vmodel/Entities/VmodelLink.cs b/visualdev/Tnb.Vmodel/Entities/VmodelLink.cs deleted file mode 100644 index 5391c498..00000000 --- a/visualdev/Tnb.Vmodel/Entities/VmodelLink.cs +++ /dev/null @@ -1,50 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using JNPF.Common.Contracts; -using SqlSugar; -using Yitter.IdGenerator; - -namespace Tnb.VmodelEngine; - -/// -/// 数据库连接 -/// -[SugarTable("sys_vmodel_link")] -public partial class VmodelLink : Entity -{ - /// - /// 主键标识 - /// - [SugarColumn(IsPrimaryKey = true)] - public string id { get; set; } = YitIdHelper.NextId().ToString(); - /// - /// 数据库连接 - /// - [SugarColumn(ColumnName = "db_code", Length = DbConsts.LengthS)] - public string? dbCode { get; set; } - - /// - /// 数据库类型 - /// - [SugarColumn(ColumnName = "db_type", IsNullable = false)] - public eDbType dbType { get; set; } - - /// - /// 连接串 - /// - [SugarColumn(ColumnName = "db_connection", IsNullable = false, Length = DbConsts.LengthXL)] - public string dbConnection { get; set; } = ""; - - /// - /// 主键 - /// - public override object[] GetKeys() - { - return new object[] { id }; - } - -} - diff --git a/visualdev/Tnb.Vmodel/Entities/VmodelPage.cs b/visualdev/Tnb.Vmodel/Entities/VmodelPage.cs deleted file mode 100644 index 0c5576d3..00000000 --- a/visualdev/Tnb.Vmodel/Entities/VmodelPage.cs +++ /dev/null @@ -1,107 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using Newtonsoft.Json.Linq; -using SqlSugar; -using Yitter.IdGenerator; - -namespace Tnb.VmodelEngine; - -/// -/// 功能页面 -/// -[SugarTable("sys_vmodel_page")] -public partial class VmodelPage : Entity -{ - #region Properties - /// - /// 主键标识 - /// - [SugarColumn(IsPrimaryKey = true)] - public string id { get; set; } = YitIdHelper.NextId().ToString(); - - /// - /// 模型id - /// - [SugarColumn(ColumnName = "vmid", Length = DbConsts.LengthS)] - public string? vmid { get; set; } - - /// - /// 页面代码 - /// - [SugarColumn(ColumnName = "code", Length = DbConsts.LengthS)] - public string code { get; set; } = string.Empty; - - /// - /// 页面名称 - /// - [SugarColumn(ColumnName = "name", Length = DbConsts.LengthM)] - public string name { get; set; } = string.Empty; - - /// - /// 页面类型 - /// - [SugarColumn(ColumnName = "page_type", Length = DbConsts.LengthS)] - public string pageType { get; set; } = string.Empty; - - /// - /// 页面配置 - /// - [SugarColumn(ColumnName = "page_schema", Length = DbConsts.LengthS, IsJson = true)] - public JObject pageSchema { get; set; } = new JObject(); - - /// - /// 页面配置 - /// - [SugarColumn(ColumnName = "option", Length = DbConsts.LengthS)] - public string? option { get; set; } = string.Empty; - - /// - /// 是否启用 - /// - [SugarColumn(ColumnName = "enabled")] - public short enabled { get; set; } = 1; - - /// - /// 是否删除 - /// - [SugarColumn(ColumnName = "deleted")] - public short deleted { get; set; } - - /// - /// 创建时间 - /// - [SugarColumn(ColumnName = "create_time")] - public DateTime createTime { get; set; } = DateTime.Now; - - /// - /// 创建人 - /// - [SugarColumn(ColumnName = "create_id", Length = DbConsts.LengthS)] - public string? createId { get; set; } - - /// - /// 修改时间 - /// - [SugarColumn(ColumnName = "modify_time", Length = DbConsts.LengthS)] - public DateTime? modifyTime { get; set; } - - /// - /// 修改人 - /// - [SugarColumn(ColumnName = "modify_id", Length = DbConsts.LengthS)] - public string? modifyId { get; set; } - - /// - /// 主键 - /// - public override object[] GetKeys() - { - return new object[] { id }; - } - #endregion - -} - diff --git a/visualdev/Tnb.Vmodel/Entities/VmodelProp.cs b/visualdev/Tnb.Vmodel/Entities/VmodelProp.cs deleted file mode 100644 index ef001b24..00000000 --- a/visualdev/Tnb.Vmodel/Entities/VmodelProp.cs +++ /dev/null @@ -1,231 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Tnb.DataAccess; -using Yitter.IdGenerator; - -namespace Tnb.VmodelEngine; - -/// -/// 视图模型属性 -/// -public class VmProp -{ - /// - /// 属性代码 - /// - public string code { get; set; } = string.Empty; - - /// - /// 显示名称 - /// - public string name { get; set; } = string.Empty; -} - -/// -/// 字段属性 -/// -public class VmDbProp : VmProp -{ - #region Properties - /// - /// 字段名称 - /// - public string field { get; set; } = string.Empty; - - /// - /// 数据类型 - /// - public string dataType { get; set; } = "varchar"; - - /// - /// 数据类型 - /// - public string? csType { get; set; } - - /// - /// 长度 - /// - public int length { get; set; } - - /// - /// 精度 - /// - public int digit { get; set; } - - /// - /// 排序 - /// - public int ordinal { get; set; } - - /// - /// 非空 - /// - public bool required { get; set; } - - /// - /// 是否主键 - /// - public bool pkey { get; set; } - - /// - /// 是否模糊搜索 - /// - public bool fuzzy { get; set; } - - /// - /// 默认值 - /// - public string? defValue { get; set; } - - /// - /// 描述 - /// - public string? descrip { get; set; } - #endregion - - /// - /// 获取默认值 - /// - /// - public object? GetDefaultValue() - { - object? val = null; - if (string.IsNullOrEmpty(defValue)) - { - val = defValue switch - { - "@@snowid" => YitIdHelper.NextId().ToString(), - "@@now" => DateTime.Now, - "@@userid" => YitIdHelper.NextId().ToString(), - "@@orgid" => YitIdHelper.NextId().ToString(), - _ => null - }; - } - else - { - val = csType switch - { - "string" => string.Empty, - "short" or "int" or "long" => 0, - "float" or "double" or "decimal" => 0f, - "DateTime" => DateTime.Now, - _ => null - }; - } - return val; - } - - /// - /// 获取默认宽度 - /// - /// - public string GetDefaultWidth() - { - return csType switch - { - "string" => "\"width\": \"auto\"", - "int" or "short" or "long" => "\"width\": 80", - "DateTime" => "\"width\": 150", - _ => "" - }; - } - - /// - /// 获取默认组件 - /// - /// - public CompOption GetDefaultComp() - { - CompOption comp = new CompOption(); - if (pkey) - { - comp.attr.Add("disabled", true); - return comp; - } - switch (csType) - { - case "string": - comp.attr.Add("clearable", true); - comp.attr.Add("maxlength", length); - comp.attr.Add("showWordLimit", true); - break; - case "int": - case "short": - case "long": - comp.type = "el-input-number"; - break; - case "DateTime": - comp.type = "el-date-picker"; - break; - }; - return comp; - } -} - -/// -/// 导航属性 -/// -public class VmNavProp : VmProp -{ - /// - /// 导航属性模型id - /// - public string vmid { get; set; } = string.Empty; - - /// - /// 导航关联类型 - /// - public eNavigateType navType { get; set; } - - /// - /// 源表字段 - /// - public string refCode { get; set; } = VmSelectProp.MAIN_ALIES; - - /// - /// 被引用字段 - /// - public string refField { get; set; } = string.Empty; - - /// - /// 源表字段 - /// - public string fkField { get; set; } = string.Empty; - - ///// - ///// 关联表表名 - ///// - //[JsonIgnore] - //public string refTable { get; set; } = string.Empty; - - ///// - ///// 被引用表(中间表) - ///// - //[JsonIgnore] - //public string? midTable { get; set; } - - [JsonIgnore] - public Vmodel? naviModel { get; set; } -} - -public class VmCalProp : VmProp -{ - public string calculate { get; set; } = string.Empty; -} - -public class DictOption -{ - public string dictTypeId { get; set; } = string.Empty; - public string refField { get; set; } = "id"; -} - -public class CompOption -{ - public string type { get; set; } = "el-input"; - public JObject attr { get; set; } = new JObject(); -} \ No newline at end of file diff --git a/visualdev/Tnb.Vmodel/Extension/StringExtensions.cs b/visualdev/Tnb.Vmodel/Extension/StringExtensions.cs deleted file mode 100644 index 51a5990d..00000000 --- a/visualdev/Tnb.Vmodel/Extension/StringExtensions.cs +++ /dev/null @@ -1,573 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.Globalization; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using JNPF.Common.Extension; -using JNPF.DependencyInjection; -using Tnb.VmodelEngine; - -namespace System; - -/// -/// 字符串扩展类,来自Abp -/// -[SuppressSniffer] -public static class StringExtensions -{ - /// - /// Adds a char to end of given string if it does not ends with the char. - /// - public static string EnsureEndsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) - { - ThrowIf.IsNull(str, nameof(str)); - - if (str.EndsWith(c.ToString(), comparisonType)) - { - return str; - } - - return str + c; - } - - /// - /// Adds a char to beginning of given string if it does not starts with the char. - /// - public static string EnsureStartsWith(this string str, char c, StringComparison comparisonType = StringComparison.Ordinal) - { - ThrowIf.IsNull(str, nameof(str)); - - if (str.StartsWith(c.ToString(), comparisonType)) - { - return str; - } - - return c + str; - } - - /// - /// Indicates whether this string is null or an System.String.Empty string. - /// - public static bool IsNullOrEmpty(this string str) - { - return string.IsNullOrEmpty(str); - } - - /// - /// indicates whether this string is null, empty, or consists only of white-space characters. - /// - public static bool IsNullOrWhiteSpace(this string str) - { - return string.IsNullOrWhiteSpace(str); - } - - /// - /// Gets a substring of a string from beginning of the string. - /// - /// Thrown if is null - /// Thrown if is bigger that string's length - public static string Left(this string str, int len) - { - ThrowIf.IsNull(str, nameof(str)); - - if (str.Length < len) - { - throw new ArgumentException("len argument can not be bigger than given string's length!"); - } - - return str.Substring(0, len); - } - - /// - /// Converts line endings in the string to . - /// - public static string NormalizeLineEndings(this string str) - { - return str.Replace("\r\n", "\n").Replace("\r", "\n").Replace("\n", Environment.NewLine); - } - - /// - /// Gets index of nth occurrence of a char in a string. - /// - /// source string to be searched - /// Char to search in - /// Count of the occurrence - public static int NthIndexOf(this string str, char c, int n) - { - ThrowIf.IsNull(str, nameof(str)); - - var count = 0; - for (var i = 0; i < str.Length; i++) - { - if (str[i] != c) - { - continue; - } - - if ((++count) == n) - { - return i; - } - } - - return -1; - } - - /// - /// Removes first occurrence of the given postfixes from end of the given string. - /// - /// The string. - /// one or more postfix. - /// Modified string or the same string if it has not any of given postfixes - public static string RemovePostFix(this string str, params string[] postFixes) - { - return str.RemovePostFix(StringComparison.Ordinal, postFixes); - } - - /// - /// Removes first occurrence of the given postfixes from end of the given string. - /// - /// The string. - /// String comparison type - /// one or more postfix. - /// Modified string or the same string if it has not any of given postfixes - public static string RemovePostFix(this string str, StringComparison comparisonType, params string[] postFixes) - { - if (str.IsNullOrEmpty()) - { - return str; - } - - if (postFixes.IsNullOrEmpty()) - { - return str; - } - - foreach (var postFix in postFixes) - { - if (str.EndsWith(postFix, comparisonType)) - { - return str.Left(str.Length - postFix.Length); - } - } - - return str; - } - - /// - /// Removes first occurrence of the given prefixes from beginning of the given string. - /// - /// The string. - /// one or more prefix. - /// Modified string or the same string if it has not any of given prefixes - public static string RemovePreFix(this string str, params string[] preFixes) - { - return str.RemovePreFix(StringComparison.Ordinal, preFixes); - } - - /// - /// Removes first occurrence of the given prefixes from beginning of the given string. - /// - /// The string. - /// String comparison type - /// one or more prefix. - /// Modified string or the same string if it has not any of given prefixes - public static string RemovePreFix(this string str, StringComparison comparisonType, params string[] preFixes) - { - if (str.IsNullOrEmpty()) - { - return str; - } - - if (preFixes.IsNullOrEmpty()) - { - return str; - } - - foreach (var preFix in preFixes) - { - if (str.StartsWith(preFix, comparisonType)) - { - return str.Right(str.Length - preFix.Length); - } - } - - return str; - } - - public static string ReplaceFirst(this string str, string search, string replace, StringComparison comparisonType = StringComparison.Ordinal) - { - - var pos = str.IndexOf(search, comparisonType); - if (pos < 0) - { - return str; - } - - return str.Substring(0, pos) + replace + str.Substring(pos + search.Length); - } - - /// - /// Gets a substring of a string from end of the string. - /// - /// Thrown if is null - /// Thrown if is bigger that string's length - public static string Right(this string str, int len) - { - - if (str.Length < len) - { - throw new ArgumentException("len argument can not be bigger than given string's length!"); - } - - return str.Substring(str.Length - len, len); - } - - /// - /// Uses string.Split method to split given string by given separator. - /// - public static string[] Split(this string str, string separator) - { - return str.Split(new[] { separator }, StringSplitOptions.None); - } - - /// - /// Uses string.Split method to split given string by given separator. - /// - public static string[] Split(this string str, string separator, StringSplitOptions options) - { - return str.Split(new[] { separator }, options); - } - - /// - /// Uses string.Split method to split given string by . - /// - public static string[] SplitToLines(this string str) - { - return str.Split(Environment.NewLine); - } - - /// - /// Uses string.Split method to split given string by . - /// - public static string[] SplitToLines(this string str, StringSplitOptions options) - { - return str.Split(Environment.NewLine, options); - } - - /// - /// Converts PascalCase string to camelCase string. - /// - /// String to convert - /// set true to use current culture. Otherwise, invariant culture will be used. - /// set true to if you want to convert 'XYZ' to 'xyz'. - /// camelCase of the string - public static string ToCamelCase(this string str, bool useCurrentCulture = false, bool handleAbbreviations = false) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - if (str.Length == 1) - { - return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); - } - - if (handleAbbreviations && IsAllUpperCase(str)) - { - return useCurrentCulture ? str.ToLower() : str.ToLowerInvariant(); - } - - return (useCurrentCulture ? char.ToLower(str[0]) : char.ToLowerInvariant(str[0])) + str.Substring(1); - } - - /// - /// Converts given PascalCase/camelCase string to sentence (by splitting words by space). - /// Example: "ThisIsSampleSentence" is converted to "This is a sample sentence". - /// - /// String to convert. - /// set true to use current culture. Otherwise, invariant culture will be used. - public static string ToSentenceCase(this string str, bool useCurrentCulture = false) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - return useCurrentCulture - ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLower(m.Value[1])) - : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + " " + char.ToLowerInvariant(m.Value[1])); - } - - /// - /// Converts given PascalCase/camelCase string to kebab-case. - /// - /// String to convert. - /// set true to use current culture. Otherwise, invariant culture will be used. - public static string ToKebabCase(this string str, bool useCurrentCulture = false) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - str = str.ToCamelCase(); - - return useCurrentCulture - ? Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLower(m.Value[1])) - : Regex.Replace(str, "[a-z][A-Z]", m => m.Value[0] + "-" + char.ToLowerInvariant(m.Value[1])); - } - - /// - /// Converts given PascalCase/camelCase string to snake case. - /// Example: "ThisIsSampleSentence" is converted to "this_is_a_sample_sentence". - /// https://github.com/npgsql/npgsql/blob/dev/src/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslator.cs#L51 - /// - /// String to convert. - /// - public static string ToSnakeCase(this string str) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - var builder = new StringBuilder(str.Length + Math.Min(2, str.Length / 5)); - var previousCategory = default(UnicodeCategory?); - - for (var currentIndex = 0; currentIndex < str.Length; currentIndex++) - { - var currentChar = str[currentIndex]; - if (currentChar == '_') - { - builder.Append('_'); - previousCategory = null; - continue; - } - - var currentCategory = char.GetUnicodeCategory(currentChar); - switch (currentCategory) - { - case UnicodeCategory.UppercaseLetter: - case UnicodeCategory.TitlecaseLetter: - if (previousCategory == UnicodeCategory.SpaceSeparator || - previousCategory == UnicodeCategory.LowercaseLetter || - previousCategory != UnicodeCategory.DecimalDigitNumber && - previousCategory != null && - currentIndex > 0 && - currentIndex + 1 < str.Length && - char.IsLower(str[currentIndex + 1])) - { - builder.Append('_'); - } - - currentChar = char.ToLower(currentChar); - break; - - case UnicodeCategory.LowercaseLetter: - case UnicodeCategory.DecimalDigitNumber: - if (previousCategory == UnicodeCategory.SpaceSeparator) - { - builder.Append('_'); - } - break; - - default: - if (previousCategory != null) - { - previousCategory = UnicodeCategory.SpaceSeparator; - } - continue; - } - - builder.Append(currentChar); - previousCategory = currentCategory; - } - - return builder.ToString(); - } - - /// - /// Converts string to enum value. - /// - /// Type of enum - /// String value to convert - /// Returns enum object - public static T ToEnum(this string value) - where T : struct - { - ThrowIf.IsNull(value, nameof(value)); - return (T)Enum.Parse(typeof(T), value); - } - - /// - /// Converts string to enum value. - /// - /// Type of enum - /// String value to convert - /// Ignore case - /// Returns enum object - public static T ToEnum(this string value, bool ignoreCase) - where T : struct - { - ThrowIf.IsNull(value, nameof(value)); - return (T)Enum.Parse(typeof(T), value, ignoreCase); - } - - public static string ToMd5(this string str) - { - using (var md5 = MD5.Create()) - { - var inputBytes = Encoding.UTF8.GetBytes(str); - var hashBytes = md5.ComputeHash(inputBytes); - - var sb = new StringBuilder(); - foreach (var hashByte in hashBytes) - { - sb.Append(hashByte.ToString("X2")); - } - - return sb.ToString(); - } - } - - /// - /// Converts camelCase string to PascalCase string. - /// - /// String to convert - /// set true to use current culture. Otherwise, invariant culture will be used. - /// PascalCase of the string - public static string ToPascalCase(this string str, bool useCurrentCulture = false) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - if (str.Length == 1) - { - return useCurrentCulture ? str.ToUpper() : str.ToUpperInvariant(); - } - - return (useCurrentCulture ? char.ToUpper(str[0]) : char.ToUpperInvariant(str[0])) + str.Substring(1); - } - - /// - /// Gets a substring of a string from beginning of the string if it exceeds maximum length. - /// - public static string Truncate(this string str, int maxLength) - { - if (str.Length <= maxLength) - { - return str; - } - - return str.Left(maxLength); - } - - /// - /// Gets a substring of a string from Ending of the string if it exceeds maximum length. - /// - public static string TruncateFromBeginning(this string str, int maxLength) - { - if (str.Length <= maxLength) - { - return str; - } - - return str.Right(maxLength); - } - - /// - /// Gets a substring of a string from beginning of the string if it exceeds maximum length. - /// It adds a "..." postfix to end of the string if it's truncated. - /// Returning string can not be longer than maxLength. - /// - /// Thrown if is null - public static string TruncateWithPostfix(this string str, int maxLength) - { - return TruncateWithPostfix(str, maxLength, "..."); - } - - /// - /// Gets a substring of a string from beginning of the string if it exceeds maximum length. - /// It adds given to end of the string if it's truncated. - /// Returning string can not be longer than maxLength. - /// - /// Thrown if is null - public static string TruncateWithPostfix(this string str, int maxLength, string postfix) - { - if (str == string.Empty || maxLength == 0) - { - return string.Empty; - } - - if (str.Length <= maxLength) - { - return str; - } - - if (maxLength <= postfix.Length) - { - return postfix.Left(maxLength); - } - - return str.Left(maxLength - postfix.Length) + postfix; - } - - /// - /// Converts given string to a byte array using encoding. - /// - public static byte[] GetBytes(this string str) - { - return str.GetBytes(Encoding.UTF8); - } - - /// - /// Converts given string to a byte array using the given - /// - public static byte[] GetBytes([NotNull] this string str, [NotNull] Encoding encoding) - { - ThrowIf.IsNull(str, nameof(str)); - ThrowIf.IsNull(encoding, nameof(encoding)); - - return encoding.GetBytes(str); - } - - private static bool IsAllUpperCase(string input) - { - for (int i = 0; i < input.Length; i++) - { - if (Char.IsLetter(input[i]) && !Char.IsUpper(input[i])) - { - return false; - } - } - - return true; - } - - /// - /// Converts snake_case string to PascalCase string. - /// - /// String to convert - /// set true to use current culture. Otherwise, invariant culture will be used. - /// PascalCase of the string - public static string SnakeToPascalCase(this string str, bool useCurrentCulture = false) - { - var sArr = str.Split(new char[] { '-', '_' }).Select(a => a.ToPascalCase(useCurrentCulture)); - return string.Join("", sArr); - } - /// - /// Converts snake_case string to PascalCase string. - /// - /// String to convert - /// set true to use current culture. Otherwise, invariant culture will be used. - /// PascalCase of the string - public static string SnakeToCamelCase(this string str, bool useCurrentCulture = false) - { - return SnakeToPascalCase(str, useCurrentCulture).ToCamelCase(); - } - -} \ No newline at end of file diff --git a/visualdev/Tnb.Vmodel/Mapper/TypeAdapter.cs b/visualdev/Tnb.Vmodel/Mapper/TypeAdapter.cs deleted file mode 100644 index ea56e06d..00000000 --- a/visualdev/Tnb.Vmodel/Mapper/TypeAdapter.cs +++ /dev/null @@ -1,25 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.Json; -using System.Threading.Tasks; -using Mapster; -using Newtonsoft.Json.Linq; - -namespace Tnb.VmodelEngine; - -public class TypeAdapter -{ - public static TypeAdapterConfig IgnoreNull { get; } - static TypeAdapter() - { - TypeAdapterConfig.GlobalSettings.Default.PreserveReference(true); - TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); - TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); - TypeAdapterConfig.GlobalSettings.NewConfig().MapWith(json => json); - IgnoreNull = TypeAdapterConfig.GlobalSettings.Clone(); - IgnoreNull.Default.IgnoreNullValues(true); - } - -} diff --git a/visualdev/Tnb.Vmodel/Mapper/VmodelMapper.cs b/visualdev/Tnb.Vmodel/Mapper/VmodelMapper.cs deleted file mode 100644 index 0cfbc7d8..00000000 --- a/visualdev/Tnb.Vmodel/Mapper/VmodelMapper.cs +++ /dev/null @@ -1,46 +0,0 @@ -using JNPF.Common.Security; -using Mapster; -using SqlSugar; - -namespace Tnb.VmodelEngine; - -public class VmodelMapper : IRegister -{ - public void Register(TypeAdapterConfig config) - { - config.ForType() - .Map(dest => dest.psize, src => 1) - .Map(dest => dest.pnum, src => 0) - .Map(dest => dest.q, src => string.IsNullOrEmpty(src.q) ? null : src.q.ToObject()); - config.ForType() - .Map(dest => dest.q, src => string.IsNullOrEmpty(src.q) ? null : src.q.ToObject()); - config.ForType() - .Map(dest => dest.code, src => src.DbColumnName.SnakeToCamelCase(false)) - .Map(dest => dest.name, src => src.ColumnDescription) - .Map(dest => dest.field, src => src.DbColumnName) - .Map(dest => dest.dataType, src => src.DataType) - //.Map(dest => dest.csType, src => src.DbColumnName) - //.Map(dest => dest.propType, src => ePropType.DbTable) - .Map(dest => dest.length, src => src.Length) - .Map(dest => dest.digit, src => src.DecimalDigits) - //.Map(dest => dest.ordinal, src => src.i) - .Map(dest => dest.required, src => !src.IsNullable) - .Map(dest => dest.pkey, src => src.IsPrimarykey) - //.Map(dest => dest.descrip, src => src.DbColumnName) - .Map(dest => dest.defValue, src => src.DefaultValue); - config.ForType() - //.Map(dest => dest.code, src => src.DbColumnName.SnakeToCamelCase(false)) - .Map(dest => dest.name, src => src.ColumnDescription) - .Map(dest => dest.field, src => src.ColumnName) - .Map(dest => dest.dataType, src => src.ColumnDataType) - //.Map(dest => dest.csType, src => src.DbColumnName) - //.Map(dest => dest.propType, src => ePropType.DbTable) - .Map(dest => dest.length, src => src.Length) - .Map(dest => dest.digit, src => src.DecimalDigits) - //.Map(dest => dest.ordinal, src => src.i) - .Map(dest => dest.required, src => !src.IsNullable) - .Map(dest => dest.pkey, src => src.IsPrimaryKey); - //.Map(dest => dest.descrip, src => src.DbColumnName) - //.Map(dest => dest.defValue, src => src.DefaultValue); - } -} diff --git a/visualdev/Tnb.Vmodel/Util/ThrowIf.cs b/visualdev/Tnb.Vmodel/Util/ThrowIf.cs deleted file mode 100644 index a86da9ba..00000000 --- a/visualdev/Tnb.Vmodel/Util/ThrowIf.cs +++ /dev/null @@ -1,168 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Swashbuckle.AspNetCore.SwaggerGen; - -namespace Tnb.VmodelEngine; - -public static class ThrowIf -{ - public static void When(bool isMatch, string message) - { - if (isMatch) - { - throw new ArgumentException(message); - } - } - - public static T IsNull([NotNull] T? value, string parameterName, string? message = null) - { - if (value == null) - { - throw new ArgumentNullException(parameterName, message); - } - - return value; - } - - public static T IsNullOrDefault([NotNull] T? value, string parameterName) where T : struct - { - if (!value.HasValue) - { - throw new ArgumentException(parameterName + " is null!", parameterName); - } - - if (value.Value.Equals(default(T))) - { - throw new ArgumentException(parameterName + " has a default value!", parameterName); - } - - return value.Value; - } - - - public static string IsNullOrWhiteSpace(string value, string parameterName, int maxLength = int.MaxValue, int minLength = 0) - { - if (value.IsNullOrWhiteSpace()) - { - throw new ArgumentException(parameterName + " can not be null, empty or white space!", parameterName); - } - - if (value.Length > maxLength) - { - throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName); - } - - if (minLength > 0 && value.Length < minLength) - { - throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName); - } - - return value; - } - - public static string IsNullOrEmpty(string value, string parameterName, int maxLength = int.MaxValue, int minLength = 0) - { - if (value.IsNullOrEmpty()) - { - throw new ArgumentException(parameterName + " can not be null or empty!", parameterName); - } - - if (value.Length > maxLength) - { - throw new ArgumentException($"{parameterName} length must be equal to or lower than {maxLength}!", parameterName); - } - - if (minLength > 0 && value.Length < minLength) - { - throw new ArgumentException($"{parameterName} length must be equal to or bigger than {minLength}!", parameterName); - } - - return value; - } - - //public static ICollection NotNullOrEmpty(ICollection value, string parameterName) - //{ - // if (value.IsNullOrEmpty()) - // { - // throw new ArgumentException(parameterName + " can not be null or empty!", parameterName); - // } - - // return value; - //} - - //public static Type AssignableTo(Type type, string parameterName) - //{ - // NotNull(type, parameterName); - // if (!type.IsAssignableTo()) - // { - // throw new ArgumentException(parameterName + " (type of " + type.AssemblyQualifiedName + ") should be assignable to the " + typeof(TBaseType).GetFullNameWithAssemblyName() + "!"); - // } - - // return type; - //} - - public static short OutOfRange(short value, string parameterName, short minimumValue, short maximumValue = short.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - - public static int OutOfRange(int value, string parameterName, int minimumValue, int maximumValue = int.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - - public static long OutOfRange(long value, string parameterName, long minimumValue, long maximumValue = long.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - - public static float OutOfRange(float value, string parameterName, float minimumValue, float maximumValue = float.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - - public static double OutOfRange(double value, string parameterName, double minimumValue, double maximumValue = double.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - - public static decimal OutOfRange(decimal value, string parameterName, decimal minimumValue, decimal maximumValue = decimal.MaxValue) - { - if (value < minimumValue || value > maximumValue) - { - throw new ArgumentException($"{parameterName} is out of range min: {minimumValue} - max: {maximumValue}"); - } - - return value; - } - -} diff --git a/visualdev/Tnb.Vmodel/VmAppService.cs b/visualdev/Tnb.Vmodel/VmAppService.cs deleted file mode 100644 index 3dd7294a..00000000 --- a/visualdev/Tnb.Vmodel/VmAppService.cs +++ /dev/null @@ -1,200 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using JNPF.Common.Security; -using JNPF.DependencyInjection; -using JNPF.DynamicApiController; -using Mapster; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using SqlSugar; -using Tnb.DataAccess; - -namespace Tnb.VmodelEngine; - -/// -/// 增删改查基类 -/// -[ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 10, KeepVerb = true)] -[Route("api")] -public class VmAppService : BaseAppService -{ - private readonly IDataAccess _dataAccess; - private readonly ISqlSugarClient _db; - - /// - /// 构造函数 - /// - public VmAppService(IDataAccess da) - { - _dataAccess = da; - _db = _dataAccess.GetSqlSugar(); - } - - #region 根据vmodel id进行增删改查接口 - /// - /// 获取一条 数据信息 - /// - [HttpGet("[area]/[controller]/{vmid}/[action]")] - public async Task GetAsync(string vmid, [FromQuery] VmGetInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid, true); - VmQueryInput arg = input.Adapt(); - if (input.id != null) - { - if (arg.q == null) arg.q = new DObject(); - arg.q.Add(vm.GetPrimary().code, input.id); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls.items.FirstOrDefault(); - } - - /// - /// 获取多条 数据列表 - /// - [HttpGet("[area]/[controller]/{vmid}/[action]")] - public async Task GetListAsync(string vmid, [FromQuery] VmGetListInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid, true); - VmQueryInput arg = input.Adapt(); - if (!string.IsNullOrEmpty(input.q)) - { - arg.q = input.q.ToObject(); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls; - } - - /// - /// 获取多条 数据列表 - /// - [HttpPost("[area]/[controller]/{vmid}/[action]")] - public async Task QueryAsync(string vmid, [FromBody] VmQueryInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid, true); - var ls = await _dataAccess.QueryDataAsync(vm, input); - return ls; - } - - /// - /// 新增 数据 - /// - [HttpPost("[area]/[controller]/{vmid}/[action]")] - public async Task CreateAsync(string vmid, VmCreateInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid); - var ret = await _dataAccess.CreateDataAsync(vm, input); - return ret; - } - - /// - /// 更新 数据 - /// - [HttpPut("[area]/[controller]/{vmid}/[action]")] - public async Task UpdateAsync(string vmid, VmUpdateInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid); - var ret = await _dataAccess.UpdateDataAsync(vm, input); - return ret; - } - - /// - /// 删除 数据 - /// - [HttpDelete("[area]/[controller]/{vmid}/[action]")] - public async Task DeleteAsync(string vmid, [FromQuery] VmDeleteInput input) - { - var vm = await _dataAccess.GetVmodelAsync(vmid); - var ret = await _dataAccess.DeleteDataAsync(vm, input); - return ret; - } - - private async Task GetVmodelAsync(string area, string vmCode) - { - var vm = await _dataAccess.GetVmodelAsync(area.SnakeToPascalCase(), vmCode.SnakeToPascalCase(), true); - return vm; - } - #endregion - - #region 根据vmode的area和code进行增删改查接口 - /// - /// 获取一条 数据信息 - /// - [HttpGet("{areaCode}/{vmCode}/[action]")] - public async Task GetAsync(string areaCode, string vmCode, [FromQuery] VmGetInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - VmQueryInput arg = input.Adapt(); - if (input.id != null) - { - if (arg.q == null) arg.q = new DObject(); - arg.q.Add(vm.GetPrimary().code, input.id); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls.items.FirstOrDefault(); - } - - /// - /// 获取多条 数据列表 - /// - [HttpGet("{areaCode}/{vmCode}/[action]")] - public async Task GetListAsync(string areaCode, string vmCode, [FromQuery] VmGetListInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - VmQueryInput arg = input.Adapt(); - if (!string.IsNullOrEmpty(input.q)) - { - arg.q = input.q.ToObject(); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls; - } - - /// - /// 获取多条 数据列表 - /// - [HttpPost("{areaCode}/{vmCode}/[action]")] - public async Task QueryAsync(string areaCode, string vmCode, [FromBody] VmQueryInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - var ls = await _dataAccess.QueryDataAsync(vm, input); - return ls; - } - - /// - /// 新增 数据 - /// - [HttpPost("{areaCode}/{vmCode}/[action]")] - public async Task CreateAsync(string areaCode, string vmCode, VmCreateInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - var ret = await _dataAccess.CreateDataAsync(vm, input); - return ret; - } - - /// - /// 更新 数据 - /// - [HttpPut("{areaCode}/{vmCode}/[action]")] - public async Task UpdateAsync(string areaCode, string vmCode, VmUpdateInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - var ret = await _dataAccess.UpdateDataAsync(vm, input); - return ret; - } - - /// - /// 删除 数据 - /// - [HttpDelete("{areaCode}/{vmCode}/[action]")] - public async Task DeleteAsync(string areaCode, string vmCode, [FromQuery] VmDeleteInput input) - { - var vm = await GetVmodelAsync(areaCode, vmCode); - var ret = await _dataAccess.DeleteDataAsync(vm, input); - return ret; - } - #endregion - -} diff --git a/visualdev/Tnb.Vmodel/VmAppServiceT.cs b/visualdev/Tnb.Vmodel/VmAppServiceT.cs deleted file mode 100644 index 177eac81..00000000 --- a/visualdev/Tnb.Vmodel/VmAppServiceT.cs +++ /dev/null @@ -1,119 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using JNPF.Common.Contracts; -using JNPF.Common.Security; -using Mapster; -using Microsoft.AspNetCore.Mvc; -using SqlSugar; -using Tnb.DataAccess; - -namespace Tnb.VmodelEngine; - -/// -/// 增删改查基类 -/// -[ApiDescriptionSettings(Area = ModuleConst.Area, Order = 10, KeepVerb = true)] -[Route("api/[area]/[controller]/[action]")] -public class VmAppService : BaseAppService where TEntity : IEntity -{ - protected readonly IDataAccess _dataAccess; - protected readonly ISqlSugarClient _db; - - /// - /// 构造函数 - /// - public VmAppService(IDataAccess dataAccess) - { - _dataAccess = dataAccess; - _db = _dataAccess.GetSqlSugar(); - } - - protected async Task GetVmodelAsync() - { - var tp = typeof(TEntity); - if (string.IsNullOrEmpty(tp?.Namespace)) - { - throw new ArgumentNullException($"类型 {nameof(tp)} 的命名空间不可为空"); - } - var area = tp.Namespace.Split('.').Last().ToKebabCase(); - var vm = await _dataAccess.GetVmodelAsync(area, tp.Name, true); - - return vm; - } - - /// - /// 获取一条 数据信息 - /// - public virtual async Task GetAsync([FromQuery] VmGetInput input) - { - var vm = await GetVmodelAsync(); - VmQueryInput arg = input.Adapt(); - if (input.id != null) - { - if (arg.q == null) arg.q = new DObject(); - arg.q.Add(vm.GetPrimary().code, input.id); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls.items.FirstOrDefault()!; - } - - /// - /// 获取多条 数据列表 - /// - public virtual async Task GetListAsync([FromQuery] VmGetListInput input) - { - var vm = await GetVmodelAsync(); - VmQueryInput arg = input.Adapt(); - if (!string.IsNullOrEmpty(input.q)) - { - arg.q = input.q.ToObject(); - } - var ls = await _dataAccess.QueryDataAsync(vm, arg); - return ls; - } - - /// - /// 获取多条 数据列表 - /// - [HttpPost] - public virtual async Task QueryAsync([FromBody] VmQueryInput input) - { - var vm = await GetVmodelAsync(); - var ls = await _dataAccess.QueryDataAsync(vm, input); - return ls; - } - - /// - /// 新增 数据 - /// - public virtual async Task CreateAsync(VmCreateInput input) - { - var vm = await GetVmodelAsync(); - var ret = await _dataAccess.CreateDataAsync(vm, input); - return ret; - } - - /// - /// 更新 数据 - /// - public virtual async Task UpdateAsync(VmUpdateInput input) - { - var vm = await GetVmodelAsync(); - var ret = await _dataAccess.UpdateDataAsync(vm, input); - return ret; - } - - /// - /// 删除 数据 - /// - public virtual async Task DeleteAsync([FromQuery] VmDeleteInput input) - { - var vm = await GetVmodelAsync(); - var ret = await _dataAccess.DeleteDataAsync(vm, input); - return ret; - } - -} diff --git a/visualdev/Tnb.Vmodel/VmodelAppService.cs b/visualdev/Tnb.Vmodel/VmodelAppService.cs deleted file mode 100644 index e3ac361b..00000000 --- a/visualdev/Tnb.Vmodel/VmodelAppService.cs +++ /dev/null @@ -1,150 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using Mapster; -using Microsoft.AspNetCore.Mvc; -using SqlSugar; -using Tnb.DataAccess; - -namespace Tnb.VmodelEngine; - -/// -/// 视图模型服务类 -/// -public class VmodelAppService : VmAppService, IVmodelAppService -{ - - /// - /// 构造函数 - /// - public VmodelAppService(IDataAccess da) : base(da) - { - } - - /// - /// 获取一条 数据信息 - /// - public override async Task GetAsync(VmGetInput input) - { - //return await _dataAccess.GetVmodelAsync(input.id); - var query = _db.Queryable().Where(a => a.deleted == 0); - Vmodel vm; - if (long.TryParse(input.id, out long id)) - { - vm = await query.FirstAsync(a => a.id == input.id); - } - else - { - vm = await query.FirstAsync(a => a.vmCode == input.id); - } - return vm; - } - - /// - /// 获取多条 数据列表 - /// - public override async Task GetListAsync(VmGetListInput input) - { - VmPagedOutput ret = new(); - var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.vmCode.Contains(input.k!) || a.vmName.Contains(input.k!)); - RefAsync total = 0; - var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); - ret.total = total; - ret.items = data.ConvertAll(a => a); - return ret; - } - - [NonAction] - public override Task QueryAsync(VmQueryInput input) - { - return base.QueryAsync(input); - } - - /// - /// 新增 模型 - /// - public override async Task CreateAsync(VmCreateInput input) - { - //ThrowIf.IsNull(input.data, nameof(input)); - ArgumentNullException.ThrowIfNull(input.data); - Vmodel vm = input.data.Adapt(); - await _db.Insertable(vm).ExecuteCommandAsync(); - return input; - } - - /// - /// 更新 数据 - /// - public override async Task UpdateAsync(VmUpdateInput input) - { - ArgumentNullException.ThrowIfNull(input.data); - Vmodel vm = input.data.Adapt(); - await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); - return input; - } - - /// - /// 删除 数据 - /// - public override async Task DeleteAsync(VmDeleteInput input) - { - var ret = await _db.Deleteable(input.id).ExecuteCommandAsync(); - return ret; - } - - /// - /// 从数据表创建模型 - /// - public async Task> CreateFromTable(VmodelCreateFromTableInput input) - { - ThrowIf.IsNull(input.tableName, nameof(input.tableName)); - var sugar = _dataAccess.GetSqlSugar(input.dbCode); - var lsTable = sugar.DbMaintenance.GetTableInfoList().WhereIF(input.tableName != "ALL", a => a.Name == input.tableName); - - List lsToAdd = new List(); - List lsToUpdate = new List(); - foreach (var tb in lsTable) - { - if (!string.IsNullOrEmpty(input.removePrefix) && !tb.Name.StartsWith(input.removePrefix)) continue; - var colInfo = sugar.DbMaintenance.GetColumnInfosByTableName(tb.Name); - Vmodel model = new() { dbCode = input.dbCode, vmName = tb.Description, tableName = tb.Name }; - model.area = input.area; - model.vmCode = (string.IsNullOrEmpty(input.removePrefix) ? tb.Name : tb.Name.RemovePreFix(input.removePrefix)).SnakeToPascalCase(); - //model.createId = CurrentUser.Id; - int n = 1; - foreach (var p in colInfo) - { - var prop = p.Adapt(); - prop.ordinal = n++; - prop.csType = sugar.Ado.DbBind.GetPropertyTypeName(p.DataType); - model.dbProps.Add(prop); - } - var exist = await _db.Queryable().FirstAsync(a => a.dbCode == input.dbCode && a.tableName == tb.Name); - if (exist == null) - { - lsToAdd.Add(model); - } - else - { - exist.area = model.area; - model.dbProps.Adapt(exist.dbProps); - //exist.dbProps.Clear(); - //exist.dbProps.AddRange(model.dbProps.OrderBy(a => a.ordinal)); - lsToUpdate.Add(exist); - } - } - if (lsToAdd.Count > 0) - { - await _db.Insertable(lsToAdd).ExecuteCommandAsync(); - } - if (lsToUpdate.Count > 0) - { - await _db.Updateable(lsToUpdate).ExecuteCommandAsync(); - } - return lsToAdd.Union(lsToUpdate).ToList(); - } - - -} diff --git a/visualdev/Tnb.Vmodel/VmodelPageAppService.cs b/visualdev/Tnb.Vmodel/VmodelPageAppService.cs deleted file mode 100644 index 1b957326..00000000 --- a/visualdev/Tnb.Vmodel/VmodelPageAppService.cs +++ /dev/null @@ -1,166 +0,0 @@ -///////////////////////////////////////////////////////////////////////////////// -// 宁波拓通e智造平台 ToTong Next Builder // -// https://git.tuotong-tech.com/tnb/tnb.server // -///////////////////////////////////////////////////////////////////////////////// - -using System.Text; -using JNPF.Common.Security; -using Mapster; -using Microsoft.AspNetCore.Authorization; -using Microsoft.AspNetCore.Mvc; -using Newtonsoft.Json.Linq; -using SqlSugar; -using Tnb.DataAccess; - -namespace Tnb.VmodelEngine; - -/// -/// 视图模型服务类 -/// -public class VmodelPageAppService : VmAppService, IVmodelPageAppService -{ - /// - /// 构造函数 - /// - public VmodelPageAppService(IDataAccess da) : base(da) - { - } - - /// - /// 获取一条 数据信息 - /// - public override async Task GetAsync(VmGetInput input) - { - var query = _db.Queryable().Where(a => a.deleted == 0); - VmodelPage vm = await query.FirstAsync(a => a.id == input.id); - return vm; - } - - /// - /// 获取多条 数据列表 - /// - public override async Task GetListAsync(VmGetListInput input) - { - VmPagedOutput ret = new(); - var q = _db.Queryable().WhereIF(!string.IsNullOrEmpty(input.k), a => a.code.Contains(input.k!) || a.name.Contains(input.k!)); - RefAsync total = 0; - var data = await q.OrderBy(input.sort).ToPageListAsync((input.pnum - 1) * input.psize, input.psize, total); - ret.total = total; - ret.items = data.ConvertAll(a => a); - return ret; - } - - /// - /// 新增 模型 - /// - public override async Task CreateAsync(VmCreateInput input) - { - ArgumentNullException.ThrowIfNull(input.data); - VmodelPage vpage = input.data.Adapt(); - await _db.Insertable(vpage).ExecuteCommandAsync(); - return vpage; - } - - /// - /// 更新 数据 - /// - public override async Task UpdateAsync(VmUpdateInput input) - { - ArgumentNullException.ThrowIfNull(input.data); - if (!input.data.ContainsKey(nameof(VmodelPage.id))) - { - throw new Exception($"更新数据时主键({nameof(VmodelPage.id)})不可为空"); - } - var id = input.data[nameof(VmodelPage.id)].ToString(); - var model = await _db.Queryable().FirstAsync(a => a.id == id); - ArgumentNullException.ThrowIfNull(model); - input.data.Adapt(model, TypeAdapter.IgnoreNull); - await _db.Updateable(model).WhereColumns(a => a.id).ExecuteCommandAsync(); - return model; - } - - /// - /// 删除 数据 - /// - public override async Task DeleteAsync(VmDeleteInput input) - { - var ret = await _db.Deleteable(input.id).ExecuteCommandAsync(); - return ret; - } - - /// - /// 从数据表创建模型 - /// - public async Task CreateByVmodel(CreatePageFromVmodelInput input) - { - ArgumentNullException.ThrowIfNull(input.vmid); - var vm = await _dataAccess.GetVmodelAsync(input.vmid); - ArgumentNullException.ThrowIfNull(vm); - - var page = await _db.Queryable().FirstAsync(a => a.vmid == vm.id); - if (page == null) - { - page = new VmodelPage { vmid = vm.id, code = vm.vmCode, name = vm.vmName }; - page.pageSchema = CreatePageSchema(vm, page.id); - await _db.Insertable(page).ExecuteCommandAsync(); - } - else - { - page.pageSchema = CreatePageSchema(vm, page.id); - await _db.Updateable(page).ExecuteCommandAsync(); - } - return page; - } - - private JObject CreatePageSchema(Vmodel vm, string pageid) - { - StringBuilder str = new StringBuilder(); - str.AppendLine("{"); - str.AppendLine($"\"page\": {{ \"loadList\": true, \"watchClient\": false }},"); - str.AppendLine($"\"queryData\": {{ }},"); - str.AppendLine($"\"queryForm\": {{"); - str.AppendLine($"\"show\": false,"); - str.AppendLine($"\"attr\": {{ \"labelWidth\": \"106px\", \"hasKeyword\":false }},"); - str.AppendLine($"\"cols\": {{"); - var pQuery = vm.dbProps.Skip(1).Take(1).FirstOrDefault(); - if (pQuery != null) - { - str.AppendLine($"\"{pQuery.code}\": {{ \"label\": \"{pQuery.name}\", \"span\": 8, \"qtype\": 2, \"isQuick\": true, \"comp\": {{ \"type\": \"el-input\", \"attr\": {{ \"placeholder\": \"{pQuery.name}\", \"clearable\": true, \"maxlength\": 20 }} }} }}"); - } - str.AppendLine($"}}"); - str.AppendLine($"}},"); - str.AppendLine($"\"list\": {{"); - str.AppendLine($"\"opt\": {{ \"isPage\": true, \"isCheck\": true, \"sortBy\": \"\", \"pkey\": \"{vm.GetPrimary().code}\" }},"); - str.AppendLine($"\"attr\": {{ \"border\": false }},"); - str.AppendLine($"\"cols\": {{"); - foreach (var p in vm.dbProps) - { - str.AppendLine($"\"{p.code}\":{{ \"label\": \"{p.name}\", \"show\": true, \"attr\": {{ {p.GetDefaultWidth()} }}, \"comp\": {{}} }},"); - } - str.AppendLine($"}}"); - str.AppendLine($"}},"); - str.AppendLine($"\"editData\": {vm.GetDefaultDObject().ToJsonString()},"); - str.AppendLine($"\"editDlg\": {{ \"isAdd\": true, \"tabHeight\": 300, \"name\": \"{vm.vmName}\" }},"); - str.AppendLine($"\"editForm\": {{"); - str.AppendLine($"\"attr\": {{ \"labelWidth\": \"106px\" }},"); - str.AppendLine($"\"rules\": {{"); - foreach (var p in vm.dbProps.Where(a => a.required && !a.pkey)) - { - str.AppendLine($"\"{p.code}\": [{{ \"required\": true, \"message\": \"必填项不能为空\", \"trigger\": \"blur\" }}],"); - } - str.AppendLine($"}},"); - str.AppendLine($"\"cols\": {{"); - foreach (var p in vm.dbProps) - { - str.AppendLine($"\"{p.code}\": {{ \"label\": \"{p.name}\", \"show\": true, \"comp\": {p.GetDefaultComp().ToJsonString()} }},"); - } - str.AppendLine($"}}"); - str.AppendLine($"}},"); - str.AppendLine($"\"tree\": {{ \"key\": \"id\", \"height\": 300, \"props\": {{ \"label\": \"enumName\" }}, \"data\": [] }}"); - str.AppendLine($"}}"); - var s = str.ToString(); - Console.WriteLine(s); - return JObject.Parse(s); - } - -}