// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。 // // 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。 // // 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任! using Admin.NET.Core.Service; using Microsoft.AspNetCore.Http; using System.Linq.Expressions; using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; @{ string joinTableName = "u"; Dictionary definedObjects = new Dictionary(); bool haveLikeCdt = false; string RemoteField=""; string PKName=""; foreach (var column in Model.TableField){ if (column.QueryWhether == "Y" && column.QueryType == "like"){ haveLikeCdt = true; } if(column.RemoteVerify){ RemoteField=@column.PropertyName; } if(column.ColumnKey == "True"){ PKName=column.PropertyName; } } } using @(@Model.NameSpace).Entity; namespace @Model.NameSpace; /// /// @(@Model.BusName)服务 /// [ApiDescriptionSettings(@(@Model.ProjectLastName)Const.GroupName, Name = "@(@Model.LowerClassName)", Order = 100)] public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransient { private readonly SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep; @foreach (var column in Model.TableField){ if(@column.EffectType == "ForeignKey"||@column.EffectType == "ApiTreeSelector"){ @:private readonly SqlSugarRepository<@(@column.FkEntityName)> _@(@column.LowerFkEntityName)Rep; } } private TypeAdapterConfig _typeAdapterConfig = TypeAdapterConfig.GlobalSettings; public @(@Model.ClassName)Service(SqlSugarRepository<@(@Model.ClassName)> @(@Model.LowerClassName)Rep @foreach (var column in Model.TableField){ if(@column.EffectType == "ForeignKey"||@column.EffectType == "ApiTreeSelector"){ @:,SqlSugarRepository<@(@column.FkEntityName)> @(@column.LowerFkEntityName)Rep } } ) { _@(@Model.LowerClassName)Rep = @(@Model.LowerClassName)Rep; @foreach (var column in Model.TableField){ if(@column.EffectType == "ForeignKey"||@column.EffectType == "ApiTreeSelector"){ @:_@(@column.LowerFkEntityName)Rep = @(@column.LowerFkEntityName)Rep; } } _typeAdapterConfig.ForType().IgnoreNullValues(true); } /// /// 分页查询@(@Model.BusName) /// /// /// [ApiDescriptionSettings(Name = "page", Description = "分页查询", Order = 1000), HttpPost] [DisplayName("分页查询@(@Model.BusName)")] public async Task> Page(Page@(@Model.ClassName)Input input) { //var query= @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input); //var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).MergeTable().ToPagedListAsync(input.Page, input.PageSize); var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize); return list; } /// /// 增加@(@Model.BusName) /// /// /// [ApiDescriptionSettings(Name = "add", Description = "增加@(@Model.BusName)", Order = 990), HttpPost] [DisplayName("增加@(@Model.BusName)")] public async Task Add(Add@(@Model.ClassName)Input input) { var entity = input.Adapt<@(@Model.ClassName)>(_typeAdapterConfig); @if(Model.RemoteVerify){ @://验证重复值 @:if (await _@(@Model.LowerClassName)Rep.IsAnyAsync(t => t.@(RemoteField) == entity.@(RemoteField))) @:{ @://已存在 @:throw Oops.Oh(ErrorCodeEnum.D1006); @:} } await _@(@Model.LowerClassName)Rep.InsertAsync(entity); return entity.@(@PKName); } /// /// 删除@(@Model.BusName) /// /// /// [ApiDescriptionSettings(Name = "delete", Description = "删除(@Model.BusName)", Order = 980), HttpPost] [DisplayName("删除@(@Model.BusName)")] public async Task Delete(Delete@(@Model.ClassName)Input input) { @foreach (var column in Model.TableField){ if (@column.ColumnKey == "True"){ @:var entity = await _@(@Model.LowerClassName)Rep.GetFirstAsync(u => u.@(@column.PropertyName) == input.@(@column.PropertyName)) ?? throw Oops.Oh(ErrorCodeEnum.D1002); } } //await _@(@Model.LowerClassName)Rep.FakeDeleteAsync(entity); // 假删除 await _@(@Model.LowerClassName)Rep.DeleteAsync(entity); // 真删除 } /// /// 更新@(@Model.BusName) /// /// /// [ApiDescriptionSettings(Name = "update", Description = "更新@(@Model.BusName)", Order = 970), HttpPost] [DisplayName("更新@(@Model.BusName)")] public async Task Update(Update@(@Model.ClassName)Input input) { var entity = input.Adapt<@(@Model.ClassName)>(_typeAdapterConfig); entity.Id = input.Id; @if(Model.RemoteVerify){ @://验证重复值 @:if (await _@(@Model.LowerClassName)Rep.IsAnyAsync(t => t.@(RemoteField) == entity.@(RemoteField) && t.@(@PKName) != entity.@(@PKName))) @:{ @://已存在 @:throw Oops.Oh(ErrorCodeEnum.D1006); @:} } await _@(@Model.LowerClassName)Rep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); } /// /// 获取@(@Model.BusName) /// /// /// [ApiDescriptionSettings(Name = "detail", Description = "获取@(@Model.BusName)", Order = 960), HttpGet] [DisplayName("获取@(@Model.BusName)")] public async Task<@(@Model.ClassName)> Detail([FromQuery] QueryById@(@Model.ClassName)Input input) { @foreach (var column in Model.TableField){ if (@column.ColumnKey == "True"){ @:return await _@(@Model.LowerClassName)Rep.GetFirstAsync(u => u.@(@column.PropertyName) == input.@(@column.PropertyName)); } } } /// /// 获取@(@Model.BusName)列表 /// /// /// [ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpPost] [DisplayName("获取@(@Model.BusName)列表")] public async Task> List(Page@(@Model.ClassName)Input input) { return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync(); } @if(@Model.TableField.Any(x=>x.Statistical == "Y")){ @:/// @:/// 获取@(@Model.BusName) @:/// @:/// @:/// @:[ApiDescriptionSettings(Name = "GetTotalSum", Description = "获取@(@Model.BusName)统计", Order = 960), HttpPost] @:[DisplayName("获取@(@Model.BusName)统计")] @:public async Task> GetTotalSum(Page@(@Model.ClassName)Input input) @:{ @:// 单次查询同时获取统计值 @:var querystats = @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input) @foreach (var column in Model.TableField){ if (@column.IsGroupBy == "Y"){ @: .GroupByIF(input.GroupBy.Contains("@column.PropertyName"), u => u.@column.PropertyName) } } @: //.Having(it => SqlFunc.AggregateCount(it.Id) > 0)//聚合函数过滤 @: .Select(it => new @(@Model.ClassName)Output @: { @: count = SqlFunc.AggregateCount(it.Id), @foreach (var column in Model.TableField){ if (@column.IsGroupBy == "Y"){ @: @(@column.PropertyName) = it.@(@column.PropertyName), } if (@column.Statistical == "Y"){ @: @(@column.PropertyName) = SqlFunc.AggregateSum(it.@(@column.PropertyName)) ?? 0, } } @: }); @:return await querystats.ToListAsync(); @:} } /// /// 根据输入参数获取@(@Model.BusName)统计 /// 支持双模式聚合配置: /// 常规模式:Field + Function /// 高级模式:CustomExpression(支持任意合法SQL表达式) /// 智能条件组合: /// 多个HAVING条件自动用AND连接 /// 条件表达式自动包裹聚合函数(如SUM(cost) > 10000) /// 可扩展支持OR条件 /// /// /// [ApiDescriptionSettings(Name = "GetAggregTotalSum", Order = 970), HttpPost] [DisplayName("根据输入参数获取@(@Model.BusName)统计")] public async Task> GetAggregTotalSum(Page@(@Model.ClassName)Input input) { @:var query = @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input) // 输入参数示例 //input = new Page@(@Model.ClassName)Input //{ // GroupBy = ["department", "project"], // GroupBy = input.GroupBy, // Aggregations = // [ // new AggregationConfig //{ // Field = "cost", // Function = AggregateFunction.Sum, // Alias = "totalCost", // HavingCondition = "> 10000" //}, //new AggregationConfig //{ // CustomExpression = "AVG(CAST(response_time AS FLOAT))", // Alias = "avgResponse", // HavingCondition = "< 500" //} // ] //}; // 生成SQL示例 // SELECT // department, project, // SUM(cost) AS totalCost, // AVG(CAST(response_time AS FLOAT)) AS avgResponse // FROM... // GROUP BY department, project // HAVING(SUM(cost) > 10000) AND(AVG(CAST(response_time AS FLOAT)) < 500) // 处理分组字段 var groupFields = AggregationBuilder.ValidateFields(input.GroupBy, typeof(@(@Model.ClassName)Output)); if (groupFields.Count > 0) { query = query.GroupBy(string.Join(",", groupFields)); } // 构建聚合配置 var aggregator = new AggregationBuilder( configs: input.Aggregations, entityType: typeof(@(@Model.ClassName)), outputType: typeof(@(@Model.ClassName)Output) ); // 组合SELECT语句 var selectParts = groupFields.Select(f => $"{f} AS {f}") .Concat(aggregator.SelectParts) .ToList(); // 应用HAVING条件 if (aggregator.HavingConditions.Count > 0) { query = query.Having(string.Join(" AND ", aggregator.HavingConditions)); } // 执行查询 return await query.Select<@(@Model.ClassName)Output>(string.Join(", ", selectParts)) .ToListAsync(); } @foreach (var column in Model.TableField){ if(@column.EffectType == "ForeignKey" && (@column.WhetherAddUpdate == "Y" || column.QueryWhether == "Y")){ @:/// @:/// 获取@(@column.ColumnComment)列表 @:/// @:/// @:[ApiDescriptionSettings(Name = "@(LowerFirstLetter(@column.FkEntityName))@(@column.PropertyName)Dropdown", Description = "获取@(@column.ColumnComment)列表", Order = 940), HttpGet] @:[DisplayName("获取@(@column.ColumnComment)列表")] @:public async Task> @(@column.FkEntityName)@(@column.PropertyName)Dropdown() @:{ @:return (await _@(@column.LowerFkEntityName)Rep.GetListAsync(t => t.Id > 0)) @:.Select(u => new LabelValueOutput @:{ @:Label = u.@(@column.FkColumnName), @:Value = u.@(@column.FkLinkColumnName).ToString() @:} @:).ToList(); @:} } } @foreach (var column in Model.TableField){ if(@column.EffectType == "Upload"){ @:/// @:/// 上传@(@column.ColumnComment) @:/// @:/// @:/// @:[ApiDescriptionSettings(Name = "upload@(@column.PropertyName)", Description = "上传@(@column.ColumnComment)", Order = 930), HttpPost] @:[DisplayName("上传@(@column.ColumnComment)")] @:public async Task Upload@(@column.PropertyName)([Required] IFormFile file) @:{ @:var service = App.GetRequiredService(); @:return await service.UploadFile(new UploadFileInput { File = file, Path = "upload/@(@column.PropertyName)" }); @:} } } @foreach (var column in Model.TableField){ if(@column.EffectType == "ApiTreeSelector" && !definedObjects.ContainsKey("@(@column.FkEntityName)Tree")){ @{definedObjects.Add("@(@column.FkEntityName)Tree", 1);} @:[ApiDescriptionSettings(Name = "@(LowerFirstLetter(@column.FkEntityName))Tree", Description = "获取@(@column.ColumnComment)列表", Order = 920), HttpGet] @:[DisplayName("获取@(@column.FkEntityName)Tree")] @:public async Task @(@column.FkEntityName)Tree() @:{ @:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>().Select<@(@column.FkEntityName)Output>().ToTreeAsync(u => u.Children, u => u.@(@column.PidColumn), 0); @:} } } @if(Model.RemoteVerify){ @:/// @:/// 检查@(RemoteField)字段是否可用 @:/// @:/// 检查字段参数 @:/// @:[ApiDescriptionSettings(Name = "exists@(RemoteField)",Description = "检查@(RemoteField)字段是否可用", Order = 910), HttpPost] @:[DisplayName("检查@(RemoteField)字段是否可用")] @:public async Task Exists@(RemoteField)Async(Exists@(RemoteField)Input param) @:{ @:if (string.IsNullOrWhiteSpace(param.FieldValue)) @:{ @:return false; @:} @:if (!string.IsNullOrWhiteSpace(param.OldFieldValue)) @:{ @:if (param.FieldValue.Trim() == param.OldFieldValue.Trim()) @:{ @://编辑状态下触发的 @:return true; @:} @:} @:return !(await _@(@Model.LowerClassName)Rep.IsAnyAsync(t => t.@(RemoteField).Equals(param.FieldValue.Trim()))); @:} } } @{ string LowerFirstLetter(string text) { return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写 } }