diff --git a/Tnb.Server.sln b/Tnb.Server.sln index 6bf614ee..8b5c0688 100644 --- a/Tnb.Server.sln +++ b/Tnb.Server.sln @@ -24,6 +24,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "解决方案项", "解决 dotnet.ruleset = dotnet.ruleset global.json = global.json nuget.config = nuget.config + request.http = request.http EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tnb.Message", "message\Tnb.Message\Tnb.Message.csproj", "{134DB335-444D-47CE-94EE-3AF062F26883}" diff --git a/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDto.cshtml b/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDto.cshtml index cbdd7046..ef7ef708 100644 --- a/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDto.cshtml +++ b/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDto.cshtml @@ -17,10 +17,15 @@ namespace @(context.NsPrefix + "." + vm.areaCode + ".AppService"); /// /// @(vm.vmCode)Dto对象 /// -public partial class @(vm.vmCode)Dto -{ - @foreach (var col in vm.dbProps.OrderBy(a => a.ordinal)){ - @://public @(col.required ? col.csType : (col.csType + "?")) @col.code { get; set; }@(col.GetDefaultValueString()) - } -} +public record @(vm.vmCode)Dto(@vm.GetPropStr(true, true)); +public class @(vm.vmCode)CreateInput : VmEditInput +{ + public new @(vm.vmCode)CreateData? data { get; set; } + public override VmEditInput ToEditInput() + { + VmEditInput input = this; + input.data = DObject.FromObject(data); + return input; + } +} \ No newline at end of file diff --git a/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDtoAcmen.cshtml b/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDtoAcmen.cshtml index 83083e09..a1fd3788 100644 --- a/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDtoAcmen.cshtml +++ b/apihost/Tnb.API.Entry/wwwroot/Template/VengineSqlSugar/EntityDtoAcmen.cshtml @@ -12,20 +12,15 @@ @using Tnb.Vengine; @using Tnb.Vengine.Domain; @{ - AcmenVmodelContext context = Model; - Vmodel vm = context.Vm; + AcmenVmodelContext context = Model; + Vmodel vm = context.Vm; } using Tnb.Core; namespace @(context.NsPrefix + "." + vm.areaCode + ".AppService"); -/// -/// @(vm.vmCode)Dto对象 -/// -public partial class @(vm.vmCode)Dto -{ - @foreach (var col in vm.dbProps.OrderBy(a => a.ordinal)){ - @://public @(col.required ? col.csType : (col.csType + "?")) @col.code { get; set; }@(col.GetDefaultValueString()) - } -} +public record @(vm.vmCode)CreateData(@vm.GetPropStr(false, false)); + +public record @(vm.vmCode)UpdateData(@vm.GetPropStr(true, false)); + diff --git a/request.http b/request.http index 5234e8af..32cf24b5 100644 --- a/request.http +++ b/request.http @@ -12,20 +12,54 @@ origin=password&code=&account=admin&login_type=&jnpf_ticket=&socialsOptions.IsCu @token=Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJVc2VySWQiOiIyNDc1NTMxNzY0OTQyOSIsIkFjY291bnQiOiJhZG1pbiIsIlVzZXJOYW1lIjoi6LaF57qn566h55CG5ZGYIiwiT3JnSWQiOiIyNDc1NTQ2OTg5ODAwNSIsIkFkbWluaXN0cmF0b3IiOjEsIlRlbmFudElkIjoiZGVmYXVsdCIsIkNvbm5lY3Rpb25Db25maWciOnsiQ29uZmlnSWQiOiJkZWZhdWx0IiwiSXNDdXN0b20iOmZhbHNlLCJJc01hc3RlclNsYXZlU2VwYXJhdGlvbiI6ZmFsc2UsIkNvbmZpZ0xpc3QiOlt7IklzTWFzdGVyIjp0cnVlLCJTZXJ2aWNlTmFtZSI6InRpYW55aV9iYXMiLCJkYlR5cGUiOjQsImNvbm5lY3Rpb25TdHIiOiJCQUYyMzBERkVGNzhEQjJEMEY2REY1Njg1REU1NjZGRUE5RjQ4NUU1OEFCQjE2RjIwMDIyMDk0QTExMTU4QjdDMDg2NzU0ODM0MjU1NzI4M0Q2RjE0NTRGRjVDM0NDRkI2QjYzMjYyM0E4QTYyMUI2QUY4ODkzNUMwOTcwNzAxOEYxQkNBOENBMTE5RkY0NUY2N0Q0MzdGMEQyMERFRTlEOTFEQzQ1ODk0OTg0NDQyNUVFQUY3QUZENTZGQUM1OTkifV19LCJTaW5nbGVMb2dpbiI6MiwiT25saW5lVGlja2V0IjpudWxsLCJMb2dpblR5cGUiOm51bGwsImlhdCI6MTcwMDAxOTA1NiwibmJmIjoxNzAwMDE5MDU2LCJleHAiOjE3MDc3OTUwNTYsImlzcyI6InR1b3RvbmciLCJhdWQiOiJ0dW90b25nIn0.8BgT-K1uWoADsmIvqGXp_6e3Fb31-X1euodhn3uqXg0 ///////////////////////////////////////////////////////////////////////// -// 动态模型接口 +// 动态模型接口 通过vmid访问 ///////////////////////////////////////////////////////////////////////// -@vmid=29974114038805 +@vmid=30060151588373 ### 获取一条数据 -GET {{host}}/api/vengine/{{vmid}}/get?id=3 +GET {{host}}/api/tnb/vengine/{{vmid}}/get?whcode=007 Authorization: {{token}} ### 获取多条数据 -GET {{host}}/api/vengine/{{vmid}}/get-list?pnum=1&psize=10 +GET {{host}}/api/tnb/vengine/{{vmid}}/get-list?pnum=1&psize=10&whcode=>>002&sort=whcode +Authorization: {{token}} + +### 新增 +POST {{host}}/api/tnb/vengine/{{vmid}}/create +Content-Type: application/json +Authorization: {{token}} + +{ + +} + +### 修改 +PUT {{host}}/api/tnb/vengine/{{vmid}}/update +Content-Type: application/json +Authorization: {{token}} + +{ + +} + +### 删除 +DELETE {{host}}/api/tnb/vengine/{{vmid}}/delete?id= +Authorization: {{token}} + +///////////////////////////////////////////////////////////////////////// +// 动态模型接口 通过areaCode/vmCode访问 +///////////////////////////////////////////////////////////////////////// + +### 获取一条数据 +GET {{host}}/api/wms/distask-h/get?id=30068699288343 Authorization: {{token}} ### 获取多条数据 -POST {{host}}/api/wms/distask/list +GET {{host}}/api/wms/distask-h/get-list?pnum=1&psize=10&billCode=%%WTR20231114 +Authorization: {{token}} + +### 获取多条数据 +POST {{host}}/api/wms/distask-h/list Content-Type: application/json Authorization: {{token}} @@ -35,36 +69,16 @@ Authorization: {{token}} "sort": "", "k": "", "q": { - "equip.code": "Elevator4", + "bindDevice.code": "Elevator4", //"equip.equipType.code": "004", //"isSign": ["in", 0, 1] }, - "o": "billCode,taskType,equip.name,equip.code" - //"o": "billCode,taskType,equip.name,equip.code,equip.equipType.code,equip.equipType.name" + "o": "billCode,taskType,bindDevice.name,bindDevice.code" + //"o": "billCode,taskType,equip.name,bindDevice.code,bindDevice.equipType.code,equip.equipType.name" //"o": "*, equip.*, equip.equipType.*" } -### 新增 -POST {{host}}/api/vengine/{{vmid}}/create -Content-Type: application/json -Authorization: {{token}} -{ - -} - -### 修改 -PUT {{host}}/api/vengine/{{vmid}}/update -Content-Type: application/json -Authorization: {{token}} - -{ - -} - -### 删除 -DELETE {{host}}/api/vengine/{{vmid}}/delete?id= -Authorization: {{token}} ### 获取模型信息 GET {{host}}/api/tnb/vmodel/get?id=27075467238421 diff --git a/visualdev/Tnb.Vengine/AppService/BaseAppService.cs b/visualdev/Tnb.Vengine/AppService/BaseAppService.cs index 891cb27c..1f1ddfab 100644 --- a/visualdev/Tnb.Vengine/AppService/BaseAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/BaseAppService.cs @@ -3,8 +3,10 @@ // https://git.tuotong-tech.com/tnb/tnb.server // ///////////////////////////////////////////////////////////////////////////////// +using JNPF; using JNPF.DependencyInjection; using JNPF.DynamicApiController; +using Microsoft.AspNetCore.Http; using Tnb.Vengine.DataAccess; using Tnb.Vengine.Domain; @@ -30,7 +32,7 @@ public class BaseAppService : IDynamicApiController, ITransient { if (!_models.ContainsKey(id)) { - _models[id] = await _dataAccess.GetVmodelAsync(id, false); + _models[id] = await _dataAccess.GetVmodelAsync(id); } return _models[id]; } @@ -42,7 +44,7 @@ public class BaseAppService : IDynamicApiController, ITransient var key = areaCode + "/" + vmCode; if (!_models.ContainsKey(key)) { - _models[key] = await _dataAccess.GetVmodelAsync(areaCode, vmCode, false); + _models[key] = await _dataAccess.GetVmodelAsync(areaCode, vmCode); } return _models[key]; } diff --git a/visualdev/Tnb.Vengine/AppService/VengineAppService.cs b/visualdev/Tnb.Vengine/AppService/VengineAppService.cs index 49ee50fb..56003c72 100644 --- a/visualdev/Tnb.Vengine/AppService/VengineAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VengineAppService.cs @@ -3,6 +3,7 @@ // https://git.tuotong-tech.com/tnb/tnb-server // ///////////////////////////////////////////////////////////////////////////////// +using JNPF; using JNPF.Common.Security; using Mapster; using Microsoft.AspNetCore.Authorization; @@ -40,10 +41,10 @@ public class VengineAppService : BaseAppService, IVengineAppService public async Task GetAsync(string vmid, [FromQuery] VmGetInput input) { var vm = await GetVmodelAsync(vmid); - var arg = input.Adapt(); - arg.AddQueryParaIf(!string.IsNullOrEmpty(input.id), vm.GetPrimary().code, input.id!); + if (!string.IsNullOrEmpty(input.id)) input.q.Add(vm.GetPrimary().code, input.id); + input.LoadFromHttpContext(App.HttpContext); - var ls = await ListAsync(vmid, arg); + var ls = await ListAsync(vmid, input.Adapt()); return ls.items.FirstOrDefault(); } @@ -51,9 +52,10 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 获取多条 数据列表 /// [HttpGet("api/[area]/[controller]/{vmid}/get-list")] - public async Task GetListAsync(string vmid, [FromQuery] VmGetListInput input) + public async Task GetListAsync(string vmid, [FromQuery] VmQueryInput input) { - return await ListAsync(vmid, input.Adapt()); + input.LoadFromHttpContext(App.HttpContext); + return await ListAsync(vmid, input); } /// @@ -110,10 +112,10 @@ public class VengineAppService : BaseAppService, IVengineAppService public async Task GetAsync(string areaCode, string vmCode, [FromQuery] VmGetInput input) { var vm = await GetVmodelAsync(areaCode, vmCode); - var arg = input.Adapt(); - arg.AddQueryParaIf(!string.IsNullOrEmpty(input.id), vm.GetPrimary().code, input.id!); + if (!string.IsNullOrEmpty(input.id)) input.q.Add(vm.GetPrimary().code, input.id); + input.LoadFromHttpContext(App.HttpContext); - var ls = await ListAsync(areaCode, vmCode, arg); + var ls = await ListAsync(areaCode, vmCode, input.Adapt()); return ls.items.FirstOrDefault(); } @@ -121,9 +123,10 @@ public class VengineAppService : BaseAppService, IVengineAppService /// 获取多条 数据列表 /// [HttpGet("api/{areaCode}/{vmCode}/get-list")] - public async Task GetListAsync(string areaCode, string vmCode, [FromQuery] VmGetListInput input) + public async Task GetListAsync(string areaCode, string vmCode, [FromQuery] VmQueryInput input) { - return await ListAsync(areaCode, vmCode, input.Adapt()); + input.LoadFromHttpContext(App.HttpContext); + return await ListAsync(areaCode, vmCode, input); } /// diff --git a/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs b/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs index f5975d96..ddcbb15d 100644 --- a/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs +++ b/visualdev/Tnb.Vengine/AppService/VengineAppServiceT.cs @@ -27,11 +27,10 @@ namespace Tnb.Vengine.AppService; [Authorize] //[ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 1102)] [Route("api/[area]/[controller]/[action]")] -public class VengineAppService : BaseAppService +public class VengineAppService : BaseAppService where TEntity : Entity where TGetInput : VmGetInput where TQueryInput : VmQueryInput - where TGetListInput : VmGetListInput where TCreateInput : VmEditInput where TUpdateInput : VmEditInput { @@ -93,10 +92,10 @@ public class VengineAppService GetAsync([FromQuery] TGetInput input) { var vm = await GetVmodelAsync(); - TQueryInput arg = input.Adapt(); - arg.AddQueryParaIf(!string.IsNullOrEmpty(input.id), vm.GetPrimary().code, input.id!); + if (!string.IsNullOrEmpty(input.id)) input.q.Add(vm.GetPrimary().code, input.id); + input.LoadFromHttpContext(App.HttpContext); - var data = (await ListAsync(arg)).items.FirstOrDefault(); + var data = (await ListAsync(input.Adapt())).items.FirstOrDefault(); return data == null ? default! : data.Adapt(); } @@ -104,20 +103,21 @@ public class VengineAppService [HttpGet] - public virtual async Task> GetListAsync([FromQuery] TGetListInput input) + public virtual async Task> GetListAsync([FromQuery] TQueryInput input) { - return await ListAsync(input.Adapt()); + input.LoadFromHttpContext(App.HttpContext); + return await ListAsync(input); } /// /// 获取多条 数据列表 /// [HttpPost] - public virtual async Task> ListAsync([FromBody] TQueryInput input) + public virtual async Task> ListAsync([FromBody] TQueryInput input) { var vm = await GetVmodelAsync(); var ls = await _dataAccess.QueryDataAsync(vm, input); - return ls.ToPagedOutput(); + return ls.ToPagedOutput(); } /// @@ -155,22 +155,31 @@ public class VengineAppService : - VengineAppService +public class VengineAppService : + VengineAppService + where TEntity : Entity + where TGetInput : VmGetInput + where TQueryInput : VmQueryInput + where TCreateInput : VmEditInput +{ + public VengineAppService(IDataAccess da) : base(da) + { + } +} +public class VengineAppService : + VengineAppService where TEntity : Entity where TGetInput : VmGetInput - where TGetListInput : VmGetListInput where TQueryInput : VmQueryInput { public VengineAppService(IDataAccess da) : base(da) { } } -public class VengineAppService : - VengineAppService +public class VengineAppService : + VengineAppService where TEntity : Entity where TGetInput : VmGetInput - where TGetListInput : VmGetListInput where TQueryInput : VmQueryInput { public VengineAppService(IDataAccess da) : base(da) @@ -178,7 +187,7 @@ public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity where TGetInput : VmGetInput { @@ -186,8 +195,18 @@ public class VengineAppService : { } } +public class VengineAppService : + VengineAppService + where TEntity : Entity + where TGetInput : VmGetInput +{ + public VengineAppService(IDataAccess da) : base(da) + { + } +} + public class VengineAppService : - VengineAppService + VengineAppService where TEntity : Entity { public VengineAppService(IDataAccess da) : base(da) diff --git a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs index b03f2231..605dfa94 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelAppService.cs @@ -5,11 +5,15 @@ using JNPF; using JNPF.Common.Core.Manager; +using JNPF.Common.Extension; using JNPF.Common.Manager; using JNPF.Common.Security; using JNPF.ViewEngine; using Mapster; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Newtonsoft.Json; +using Org.BouncyCastle.Crypto; using SqlSugar; using Tnb.Core; using Tnb.Vengine.DataAccess; @@ -23,7 +27,7 @@ namespace Tnb.Vengine.AppService; /// [ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, KeepVerb = true, Order = 1102)] //[Route("api/[area]/[controller]/[action]")] -public class VmodelAppService : VengineAppService, IVmodelAppService +public class VmodelAppService : VengineAppService, IVmodelAppService { private readonly IViewEngine _viewEngine; private readonly ICacheManager _cache; @@ -39,41 +43,113 @@ public class VmodelAppService : VengineAppService GetVmodelAsync() + { + var vm = new Vmodel + { + + //id = "30285088677397", + areaCode = "tnb", + vmCode = "vmodel", + vmName = "视图模型", + dbCode = "", + tableName = "sys_vmodel", + dbProps = new List { + new VmDbProp{field="id",csType="string",length=50,digit=0,ordinal=1,required=true,pkey=true,fuzzy=false,defValue=null,descrip=null,code="id",name="主键标识"}, + new VmDbProp{field="area_code",csType="string",length=50,digit=0,ordinal=2,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="areaCode",name="模块代码"}, + new VmDbProp{field="vm_code",csType="string",length=100,digit=0,ordinal=3,required=true,pkey=false,fuzzy=true,defValue=null,descrip=null,code="vmCode",name="视图代码"}, + new VmDbProp{field="vm_name",csType="string",length=100,digit=0,ordinal=4,required=true,pkey=false,fuzzy=true,defValue=null,descrip=null,code="vmName",name="视图名称"}, + new VmDbProp{field="db_code",csType="string",length=50,digit=0,ordinal=5,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="dbCode",name="数据库连接"}, + new VmDbProp{field="table_name",csType="string",length=50,digit=0,ordinal=6,required=true,pkey=false,fuzzy=true,defValue=null,descrip=null,code="tableName",name="主表名称"}, + new VmDbProp{field="db_props",csType="string",length=0,digit=0,ordinal=7,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="dbProps",name="表字段属性"}, + new VmDbProp{field="nav_props",csType="string",length=0,digit=0,ordinal=8,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="navProps",name="导航属性"}, + new VmDbProp{field="cal_props",csType="string",length=0,digit=0,ordinal=9,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="calProps",name="计算配置"}, + new VmDbProp{field="ordinal",csType="int",length=0,digit=0,ordinal=10,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="ordinal",name="排序"}, + new VmDbProp{field="soft_delete",csType="short",length=0,digit=0,ordinal=11,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="softDelete",name="软删除"}, + new VmDbProp{field="enabled",csType="short",length=0,digit=0,ordinal=12,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="enabled",name="是否激活"}, + new VmDbProp{field="deleted",csType="short",length=0,digit=0,ordinal=13,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="deleted",name="是否删除"}, + new VmDbProp{field="descrip",csType="string",length=250,digit=0,ordinal=14,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="descrip",name="描述"}, + new VmDbProp{field="create_time",csType="DateTime",length=0,digit=0,ordinal=15,required=true,pkey=false,fuzzy=false,defValue=null,descrip=null,code="createTime",name="创建时间"}, + new VmDbProp{field="create_id",csType="string",length=50,digit=0,ordinal=16,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="createId",name="创建人"}, + new VmDbProp{field="modify_time",csType="DateTime",length=0,digit=0,ordinal=17,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="modifyTime",name="修改时间"}, + new VmDbProp{field="modify_id",csType="string",length=50,digit=0,ordinal=18,required=false,pkey=false,fuzzy=false,defValue=null,descrip=null,code="modifyId",name="修改人"} + }, + navProps = [], + calProps = [], + ordinal = 0, + softDelete = 0, + enabled = 1, + deleted = 0, + descrip = null + }; + return Task.FromResult(vm); + } + /// /// 获取一条 数据信息, q参数无效 /// public override async Task GetAsync(VmodelGetInput input) { + input.LoadFromHttpContext(App.HttpContext); var query = _db.Queryable().Where(a => a.deleted == 0); Vmodel? vm = null; if (!string.IsNullOrEmpty(input.id)) { - vm = await _dataAccess.GetVmodelAsync(input.id, input.drill); + vm = await _dataAccess.GetVmodelAsync(input.id); } - else if (!string.IsNullOrEmpty(input.areaCode) && !string.IsNullOrEmpty(input.vmCode)) + else if (input.q.ContainsKey("areaCode") && input.q.ContainsKey("vmCode")) { - vm = await _dataAccess.GetVmodelAsync(input.areaCode, input.vmCode, input.drill); + vm = await _dataAccess.GetVmodelAsync(input.q["areaCode"].ToString()!, input.q["vmCode"].ToString()!); } ThrowIf.IsNull(vm, "输入参数有误, id 和 areaCode,vmCode 不可同时为空"); + if (input.drill) + { + List vmids = vm.navProps.Select(a => a.vmid).Distinct().ToList(); + if (vmids.Count > 0) + { + List ls = await _db.Queryable().Where(a => vmids.Contains(a.id)).ToListAsync(); + Dictionary navs = ls.ToDictionary(a => a.id); + foreach (VmNavProp navProp in vm.navProps) + { + navProp.naviModel = navs.GetOrDefault(navProp.vmid); + } + } + } + //var serializer = new Newtonsoft.Json.JsonSerializer(); + //var stringWriter = new StringWriter(); + //using (var writer = new Newtonsoft.Json.JsonTextWriter(stringWriter)) + //{ + // writer.QuoteName = false; + // serializer.Serialize(writer, vm); + //} + //var json = stringWriter.ToString(); + return vm; } /// /// 获取多条 数据列表 /// - public override async Task> GetListAsync(VmGetListInput input) + public override async Task> GetListAsync(VmQueryInput input) { - return await ListAsync(input.Adapt()); + input.LoadFromHttpContext(App.HttpContext); + return await ListAsync(input); } [NonAction] public override async Task> ListAsync(VmQueryInput input) { - var q = _db.Queryable().Where(a => a.deleted == 0) - .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); - return PagedOutput.Create(total, data); + PagedOutput result = new PagedOutput(); + var vm = await GetVmodelAsync(); + var ls = await _dataAccess.QueryDataAsync(vm, input); + foreach (var item in ls.items) + { + item["dbProps"] = JsonConvert.DeserializeObject>(item["dbProps"].ToString()!)!; + item["navProps"] = JsonConvert.DeserializeObject>(item["navProps"].ToString()!)!; + item["calProps"] = JsonConvert.DeserializeObject>(item["calProps"].ToString()!)!; + } + + return ls.ToPagedOutput(); } /// @@ -95,20 +171,30 @@ public class VmodelAppService : VengineAppService /// 更新 数据 /// - public override async Task UpdateAsync(VmodelUpdateInput input) + public override async Task UpdateAsync(VmEditInput input) { - ThrowIf.IsNull(input.data); - ThrowIf.IsNullOrEmpty(input.data.id, $"更新数据时主键(id)不可为空"); - - Vmodel vm = input.data.Adapt(); - vm.areaCode = vm.areaCode.ToKebab(); - vm.vmCode = vm.vmCode.ToKebab(); - vm.navProps.ForEach(a => a.naviModel = null); - vm.modifyTime = DateTime.Now; - vm.modifyId = _user.UserId; - await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); - await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(vm.id)); - return vm; + var ret = await base.UpdateAsync(input); + if (input.data != null) + { + var id = ret as string; + await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(id!)); + } + else if (input.items != null) + { + var ids = ret as List; + foreach (var item in ids!) + { + await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(item)); + } + } + return ret; + //vm.areaCode = vm.areaCode.ToKebab(); + //vm.vmCode = vm.vmCode.ToKebab(); + //vm.navProps.ForEach(a => a.naviModel = null); + //vm.modifyTime = DateTime.Now; + //vm.modifyId = _user.UserId; + //await _db.Updateable(vm).WhereColumns(a => a.id).ExecuteCommandAsync(); + //return vm; } /// @@ -116,8 +202,21 @@ public class VmodelAppService : VengineAppService public override async Task DeleteAsync(VmDeleteInput input) { - var ret = await _db.Updateable().SetColumns(a => a.deleted, 1).Where(a => a.id == input.id).ExecuteCommandAsync(); - await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(input.id!)); + List ids = new(); + if (input.id != null) + { + ids.Add(input.id); + } + else if (input.ids != null) + { + ids.AddRange(input.ids); + } + + var ret = await _db.Updateable().SetColumns(a => a.deleted, 1).Where(a => ids.Contains(a.id)).ExecuteCommandAsync(); + foreach (var item in ids) + { + await _cache.DelAsync(_dataAccess.GetVmodelCacheKey(item)); + } return ret; } @@ -242,4 +341,5 @@ public class VmodelAppService : VengineAppService dbProps, List navProps, List calProps, int ordinal, short softDelete, short enabled, string? descrip); public record VmNavPropCreateData(string code, string name, string vmid, eNavigateType navType, string refCode, string refProp, string fkProp); -public record VmodelUpdateData(string id, string areaCode, string vmCode, string vmName, string? dbCode, string tableName, List dbProps, List navProps, List calProps, int ordinal, short softDelete, short enabled, string? descrip); public class VmodelGetInput : VmGetInput { - /// - /// 模块code, areaCode和vmCode为一组 - /// - public string? areaCode { get; set; } - /// - /// 模型code, areaCode和vmCode为一组 - /// - public string? vmCode { get; set; } /// /// 是否钻取子模型 /// @@ -40,10 +31,6 @@ public class VmodelCreateInput : VmEditInput return input; } } -public class VmodelUpdateInput : VmEditInput -{ - public new VmodelUpdateData? data { get; set; } -} public class VmodelCreateFromTableInput { public string? dbCode { get; set; } @@ -65,17 +52,6 @@ public class VmodelPageCreateInput : VmEditInput } } -public class VmodelPageUpdateInput : VmEditInput -{ - public new VmodelPage? data { get; set; } - public override VmEditInput ToEditInput() - { - VmEditInput input = this; - input.data = DObject.FromObject(data); - return input; - } -} - public class VmodelPageCreateFromVmodelInput { public Guid? viewId { get; set; } diff --git a/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs index 75b29763..d0d2234f 100644 --- a/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs +++ b/visualdev/Tnb.Vengine/AppService/VmodelPageAppService.cs @@ -19,7 +19,7 @@ namespace Tnb.Vengine.AppService; /// 视图模型服务类 /// [ApiDescriptionSettings(Tag = ModuleConst.Tag, Area = ModuleConst.Area, Order = 1104, KeepVerb = true)] -public class VmodelPageAppService : VengineAppService, IVmodelPageAppService +public class VmodelPageAppService : VengineAppService, IVmodelPageAppService { /// /// 构造函数 diff --git a/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs index d399017e..e625de38 100644 --- a/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs +++ b/visualdev/Tnb.Vengine/DataAccess/DataAccess.cs @@ -112,62 +112,47 @@ public class DataAccess : IDataAccess, ITransient, IDisposable /// /// 获取 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) + public async Task TryGetVmodelAsync(string id) { var key = GetVmodelCacheKey(id); var vm = await _cache.GetAsync(key); if (vm == null) { vm = await Db.Queryable().FirstAsync(a => a.id == id && a.deleted == 0); - ThrowIf.IsNull(vm, $"找不到id={id}的模型"); - if (loadNavigate) + if (vm != null) { - await LoadVmodelNavigateAsync(vm); + await _cache.SetAsync(key, vm, TimeSpan.FromMinutes(10)); } - await _cache.SetAsync(key, vm, TimeSpan.FromMinutes(10)); } return vm; } - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - public async Task TryGetVmodelAsync(string areaCode, string vmCode, bool loadNavigate = false) - { - Vmodel vm = await Db.Queryable().FirstAsync(a => a.areaCode == areaCode && a.vmCode == vmCode && a.deleted == 0); - if (vm != null && loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } - - return vm; - } - /// /// 获取 Vmodel, 为空时抛异常 /// - public async Task GetVmodelAsync(string areaCode, string vmCode, bool loadNavigate = false) + public async Task GetVmodelAsync(string id) + { + var vm = await TryGetVmodelAsync(id); + ThrowIf.IsNull(vm, $"找不到id={id}的模型"); + return vm; + } + + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + public async Task TryGetVmodelAsync(string areaCode, string vmCode) { Vmodel vm = await Db.Queryable().FirstAsync(a => a.areaCode == areaCode && a.vmCode == vmCode && a.deleted == 0); - ThrowIf.IsNull(vm, $"找不到areaCode={areaCode}, vmCode={vmCode}的模型"); - if (loadNavigate) - { - await LoadVmodelNavigateAsync(vm); - } + return vm; + } + /// + /// 获取 Vmodel, 为空时抛异常 + /// + public async Task GetVmodelAsync(string areaCode, string vmCode) + { + var vm = await TryGetVmodelAsync(areaCode, vmCode); + ThrowIf.IsNull(vm, $"找不到areaCode={areaCode}, vmCode={vmCode}的模型"); return vm; } @@ -321,8 +306,8 @@ public class DataAccess : IDataAccess, ITransient, IDisposable /// public async Task CreateDataAsync(Vmodel vm, VmEditInput input) { - ISqlSugarClient db = GetSqlSugar(vm.dbCode); ThrowIf.When(input.data == null && input.items == null, "新增数据时,data和items不可同时为空"); + ISqlSugarClient db = GetSqlSugar(vm.dbCode); //新增一条数据 if (input.data != null) { @@ -331,7 +316,7 @@ public class DataAccess : IDataAccess, ITransient, IDisposable if (pkey.csType is "int" or "long") { long id = await db.Insertable(model).AS(vm.tableName).ExecuteReturnBigIdentityAsync(); - if ((long)input.data[pkey.code] != id) + if (input.data[pkey.code].ParseToLong() != id) { input.data[pkey.code] = id; } @@ -339,6 +324,10 @@ public class DataAccess : IDataAccess, ITransient, IDisposable else { _ = await db.Insertable(model).AS(vm.tableName).ExecuteCommandAsync(); + if (input.data[pkey.code].ToString() != model[pkey.field].ToString()) + { + input.data[pkey.code] = model[pkey.field]; + } } return input.data; } @@ -370,6 +359,11 @@ public class DataAccess : IDataAccess, ITransient, IDisposable else { _ = await db.Insertable(lst).AS(vm.tableName).ExecuteCommandAsync(); + for (int i = 0; i < input.items.Count; i++) + { + input.items[i][pkey.code] = lst[i][pkey.field]; + } + } return input.items; } @@ -387,31 +381,35 @@ public class DataAccess : IDataAccess, ITransient, IDisposable /// public async Task UpdateDataAsync(Vmodel vm, VmEditInput input) { + ThrowIf.When(input.data == null && input.items == null, "新增数据时,data和items不可同时为空"); ISqlSugarClient db = GetSqlSugar(vm.dbCode); VmDbProp pk = vm.GetPrimary(); int num = 0; //修改一条数据 if (input.data != null) { + ThrowIf.When(!input.data.ContainsKey(pk.code) || string.IsNullOrWhiteSpace(input.data[pk.code].ToString()), $"更新数据时主键({pk.code})不可为空"); DObject model = vm.ToUpdateEntity(input.data, _user); - ThrowIf.When(!model.ContainsKey(pk.field), $"更新数据时主键({pk.code})不可为空"); num = await db.Updateable(model).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); + return num > 0 ? input.data[pk.code].ToString()! : 0; } //批量修改数据 - else if (input.items != null) + else { List lst = new(); - foreach (DObject item in input.items) + List ids = new(); + foreach (DObject item in input.items!) { - DObject model = vm.ToUpdateEntity(item, _user); - if (model.ContainsKey(pk.field)) + if (item.ContainsKey(pk.code) && !string.IsNullOrWhiteSpace(item[pk.code].ToString())) { + DObject model = vm.ToUpdateEntity(item, _user); lst.Add(model); + ids.Add(item[pk.code].ToString()!); } } num = await db.Updateable(lst).AS(vm.tableName).WhereColumns(pk.field).ExecuteCommandAsync(); + return num > 0 ? ids : 0; } - return num; } /// diff --git a/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs index afc4562d..2420d2e8 100644 --- a/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs +++ b/visualdev/Tnb.Vengine/DataAccess/IDataAccess.cs @@ -23,30 +23,30 @@ public interface IDataAccess : ITransient /// VmodelLink GetVmodelLink(string dbCode); - /// - /// 获取 Vmodel, 为空时不抛异常 - /// - Task TryGetVmodelAsync(string id, bool loadNavigate = false); - /// /// 获取 Vmodel 的缓存键 /// string GetVmodelCacheKey(string id); + /// + /// 获取 Vmodel, 为空时不抛异常 + /// + Task TryGetVmodelAsync(string id); + /// /// 获取 Vmodel, 为空时抛异常 /// - Task GetVmodelAsync(string id, bool loadNavigate = false); + Task GetVmodelAsync(string id); /// /// 获取 Vmodel, 为空时不抛异常 /// - Task TryGetVmodelAsync(string area, string vmCode, bool loadNavigate = false); + Task TryGetVmodelAsync(string area, string vmCode); /// /// 获取 Vmodel, 为空时抛异常 /// - Task GetVmodelAsync(string area, string vmCode, bool loadNavigate = false); + Task GetVmodelAsync(string area, string vmCode); //Task QueryDataAsync(VmBaseInput input); diff --git a/visualdev/Tnb.Vengine/Domain/VengineDto.cs b/visualdev/Tnb.Vengine/Domain/VengineDto.cs index f71b4923..15807e7d 100644 --- a/visualdev/Tnb.Vengine/Domain/VengineDto.cs +++ b/visualdev/Tnb.Vengine/Domain/VengineDto.cs @@ -5,6 +5,7 @@ using JNPF.Common.Security; using Mapster; +using Microsoft.AspNetCore.Http; using Tnb.Core; namespace Tnb.Vengine.Domain; @@ -17,6 +18,9 @@ public class VmBaseInput public object? extra { get; set; } } +/// +/// 查询单条数据的输入参数 +/// public class VmGetInput : VmBaseInput { /// @@ -27,16 +31,38 @@ public class VmGetInput : VmBaseInput /// /// 过滤条件 /// - public string? q { get; set; } + public DObject q { get; set; } = new DObject(); /// /// 输出字段 /// public string o { get; set; } = "*"; - + /// + /// 从HttpContext中加载查询参数 + /// + /// + public void LoadFromHttpContext(HttpContext? context) + { + if (context == null) return; + string[] filter = new string[] { "id", "q", "o" }; + foreach (var item in context.Request.Query.Where(a => !filter.Contains(a.Key))) + { + if (item.Value.Count > 1) + { + q.Add(item.Key, item.Value.ToArray()); + } + else + { + q.Add(item.Key, item.Value.ToString()); + } + } + } } -public class VmGetListInput : VmBaseInput +/// +/// 查询列表数据的输入参数 +/// +public class VmQueryInput : VmBaseInput { /// /// 当前页数 @@ -61,48 +87,37 @@ public class VmGetListInput : VmBaseInput /// /// 过滤条件 /// - public string? q { get; set; } + public DObject q { get; set; } = new DObject(); /// /// 输出字段 /// public string o { get; set; } = "*"; -} - -/// -/// 获取多条数据输入参数 -/// -public class VmQueryInput : VmGetListInput -{ - /// - /// 查询条件 - /// - public new DObject? q { get; set; } /// - /// 添加一个查询条件 + /// 从HttpContext中加载查询参数 /// - /// - /// - public void AddQueryPara(string key, object value) + /// + public void LoadFromHttpContext(HttpContext? context) { - if (q == null) q = new DObject(); - q.Add(key, value); - } - - /// - /// 添加一个查询条件 - /// - /// - /// - public void AddQueryParaIf(bool condition, string key, object value) - { - if(condition) AddQueryPara(key, value); + if (context == null) return; + string[] filter = new string[] { "pnum", "psize", "sort", "k", "q", "o" }; + foreach (var item in context.Request.Query.Where(a => !filter.Contains(a.Key))) + { + if (item.Value.Count > 1) + { + q.Add(item.Key, item.Value.ToArray()); + } + else + { + q.Add(item.Key, item.Value.ToString()); + } + } } } /// -/// 新增数据输入参数 +/// 新增或修改数据输入参数 /// public class VmEditInput : VmBaseInput { diff --git a/visualdev/Tnb.Vengine/Domain/VmDbProp.cs b/visualdev/Tnb.Vengine/Domain/VmDbProp.cs index f45062b0..cb89b77c 100644 --- a/visualdev/Tnb.Vengine/Domain/VmDbProp.cs +++ b/visualdev/Tnb.Vengine/Domain/VmDbProp.cs @@ -5,6 +5,7 @@ using JNPF.Common.Extension; using Newtonsoft.Json; +using NPOI.SS.Formula.Functions; using Yitter.IdGenerator; namespace Tnb.Vengine.Domain; @@ -74,6 +75,15 @@ public class VmDbProp : VmBaseProp #endregion Properties + /// + /// 获取可空类型的字符串名称 + /// + /// + public string GetCsType() + { + return required ? csType : csType + "?"; + } + /// /// 获取默认值 /// diff --git a/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs b/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs index 3cd197a1..d21c9d55 100644 --- a/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs +++ b/visualdev/Tnb.Vengine/Domain/VmQueryParser.cs @@ -88,13 +88,8 @@ internal class VmQueryParser /// /// 解析查询参数 /// - private void ParseQueryPara(DObject? query) + private void ParseQueryPara(DObject query) { - if (query == null) - { - return; - } - foreach (KeyValuePair item in query) { string[] codes = item.Key.Split(NAVI_SEPERATE); diff --git a/visualdev/Tnb.Vengine/Domain/Vmodel.cs b/visualdev/Tnb.Vengine/Domain/Vmodel.cs index 2a7bcb78..05c05155 100644 --- a/visualdev/Tnb.Vengine/Domain/Vmodel.cs +++ b/visualdev/Tnb.Vengine/Domain/Vmodel.cs @@ -24,6 +24,7 @@ namespace Tnb.Vengine.Domain; public partial class Vmodel : Entity { private static string[] SOFT_DELETED = new string[] { "deleted", "isDeleted", "softDeleted" }; + private static string[] AUTO_FILL_PROP = new string[] { "createTime", "createId", "updateTime", "modifyTime", "updateId", "modifyId" }; #region Properties @@ -195,7 +196,7 @@ public partial class Vmodel : Entity /// public VmDbProp GetPrimary() { - var key = dbProps.FirstOrDefault(a => a.pkey); + var key = dbProps.FirstOrDefault(a => a.pkey); ThrowIf.IsNull(key, $"模型({fullCode})没有定义主键属性"); return key; } @@ -238,7 +239,7 @@ public partial class Vmodel : Entity /// public DObject GetDefaultDObject() { - DObject obj = new (); + DObject obj = new(); foreach (VmDbProp p in dbProps) { obj.Add(p.code, p.GetDefaultValue()!); @@ -246,13 +247,30 @@ public partial class Vmodel : Entity return obj; } + /// + /// 获取属性字符串 + /// + /// + /// + public string GetPropStr(bool includePkey, bool includeAutoProp) + { + var strs = new List(); + foreach (var col in dbProps.OrderBy(a => a.ordinal)) + { + if (!includeAutoProp && AUTO_FILL_PROP.Contains(col.code)) continue; + if (!includePkey && col.pkey) continue; + strs.Add(col.GetCsType() + " " + col.code); + } + return string.Join(", ", strs); + } + /// /// 转换为待新增的实体对象 /// /// public DObject ToCreateEntity(DObject input, IUserManager user) { - DObject obj = new (); + DObject obj = new(); foreach (VmDbProp p in dbProps) { if (input.ContainsKey(p.code)) @@ -286,7 +304,7 @@ public partial class Vmodel : Entity /// public DObject ToUpdateEntity(DObject input, IUserManager user) { - DObject obj = new (); + DObject obj = new(); foreach (VmDbProp p in dbProps) { if (input.ContainsKey(p.code)) diff --git a/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs b/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs index e2442008..fe8cd4df 100644 --- a/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs +++ b/visualdev/Tnb.Vengine/Mapper/VmodelMapper.cs @@ -17,10 +17,8 @@ public class VmodelMapper : IRegister { 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()); + .Map(dest => dest.pnum, src => 0); + //.Map(dest => dest.q, src => string.IsNullOrEmpty(src.q) ? null : src.q.ToObject()); config.ForType() .Map(dest => dest.code, src => src.DbColumnName.ToCamel()) .Map(dest => dest.name, src => src.ColumnDescription)