代码生成优化
This commit is contained in:
parent
8fe140346e
commit
8677435176
@ -136,6 +136,12 @@ public partial class SysCodeGenConfig : EntityBase
|
||||
[SugarColumn(ColumnDescription = "是否是统计字段", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? Statistical { get; set; }
|
||||
/// <summary>
|
||||
/// 是否是GroupBy字段
|
||||
/// </summary>
|
||||
[SugarColumn(ColumnDescription = "是否是GroupBy字段", Length = 8)]
|
||||
[MaxLength(8)]
|
||||
public string? IsGroupBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是查询条件
|
||||
|
||||
@ -222,6 +222,23 @@ public class SysCodeGenTemplateSeedData : ISqlSugarEntitySeedData<SysCodeGenTemp
|
||||
""UpdateUserName"": null,
|
||||
""IsDelete"": false,
|
||||
""Id"": 1300000000211
|
||||
},
|
||||
{
|
||||
""Name"": ""service_Mid.cs.vm"",
|
||||
""Type"": 2,
|
||||
""SysFlag"": 1,
|
||||
""IsDefault"": true,
|
||||
""OutputFile"": ""Service/{TableName}/Dto/{TableName}Mid.cs"",
|
||||
""Describe"": ""(服务端)中间件"",
|
||||
""OrderNo"": 100,
|
||||
""CreateTime"": ""1900-01-01 00:00:00"",
|
||||
""UpdateTime"": ""2025-01-13 21:25:43"",
|
||||
""CreateUserId"": null,
|
||||
""CreateUserName"": null,
|
||||
""UpdateUserId"": null,
|
||||
""UpdateUserName"": null,
|
||||
""IsDelete"": false,
|
||||
""Id"": 1300000000215
|
||||
}
|
||||
]
|
||||
";
|
||||
|
||||
@ -122,6 +122,10 @@ public class CodeGenConfig
|
||||
/// 是否是统计字段
|
||||
/// </summary>
|
||||
public string Statistical { get; set; }
|
||||
/// <summary>
|
||||
/// 是否是GroupBy字段
|
||||
/// </summary>
|
||||
public string? IsGroupBy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否是查询条件
|
||||
|
||||
144
Admin.NET/Admin.NET.Core/Utils/AggregationBuilder.cs
Normal file
144
Admin.NET/Admin.NET.Core/Utils/AggregationBuilder.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Admin.NET.Core.Utils;
|
||||
// 聚合配置增强版(独立类)
|
||||
public class AggregationBuilder
|
||||
{
|
||||
private readonly List<AggregationConfig> _configs;
|
||||
private readonly Type _entityType;
|
||||
private readonly Type _outputType;
|
||||
|
||||
public List<string> SelectParts { get; } = new();
|
||||
public List<string> HavingConditions { get; } = new();
|
||||
|
||||
public AggregationBuilder(
|
||||
IEnumerable<AggregationConfig> configs,
|
||||
Type entityType,
|
||||
Type outputType)
|
||||
{
|
||||
_configs = configs.ToList();
|
||||
_entityType = entityType;
|
||||
_outputType = outputType;
|
||||
Build();
|
||||
}
|
||||
|
||||
private void Build()
|
||||
{
|
||||
foreach (var config in _configs.Where(IsValidConfig))
|
||||
{
|
||||
// 处理SELECT部分
|
||||
var expression = string.IsNullOrEmpty(config.CustomExpression)
|
||||
? $"{config.Function.ToString().ToUpper()}({config.Field})"
|
||||
: config.CustomExpression;
|
||||
|
||||
SelectParts.Add($"{expression} AS {config.Alias}");
|
||||
|
||||
// 处理HAVING条件
|
||||
if (!string.IsNullOrEmpty(config.HavingCondition))
|
||||
{
|
||||
HavingConditions.Add($"{expression} {config.HavingCondition}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsValidConfig(AggregationConfig config)
|
||||
{
|
||||
// 字段基础验证
|
||||
if (!string.IsNullOrEmpty(config.Field) &&
|
||||
_entityType.GetProperty(config.Field) == null)
|
||||
return false;
|
||||
|
||||
// 输出属性验证
|
||||
return _outputType.GetProperty(config.Alias) != null;
|
||||
}
|
||||
/// <summary>
|
||||
/// 验证聚合配置有效性
|
||||
/// </summary>
|
||||
private bool ValidateAggregation(AggregationConfig config, Type entityType, Type outputType)
|
||||
{
|
||||
// 验证实体字段存在性
|
||||
var entityProp = entityType.GetProperty(config.Field);
|
||||
if (entityProp == null) return false;
|
||||
|
||||
// 验证输出字段存在性
|
||||
var outputProp = outputType.GetProperty(config.Alias);
|
||||
if (outputProp == null) return false;
|
||||
|
||||
// 验证类型兼容性
|
||||
return config.Function switch
|
||||
{
|
||||
AggregateFunction.Count => outputProp.PropertyType == typeof(int),
|
||||
_ => outputProp.PropertyType == entityProp.PropertyType ||
|
||||
IsNumericType(outputProp.PropertyType)
|
||||
};
|
||||
}
|
||||
|
||||
private static bool IsNumericType(Type type)
|
||||
{
|
||||
return Type.GetTypeCode(type) switch
|
||||
{
|
||||
TypeCode.Byte or TypeCode.SByte or TypeCode.UInt16
|
||||
or TypeCode.UInt32 or TypeCode.UInt64 or TypeCode.Int16
|
||||
or TypeCode.Int32 or TypeCode.Int64 or TypeCode.Decimal
|
||||
or TypeCode.Double or TypeCode.Single => true,
|
||||
_ => false
|
||||
};
|
||||
}
|
||||
/// <summary>
|
||||
/// 验证字段有效性
|
||||
/// </summary>
|
||||
public static List<string> ValidateFields(string[] fields, Type targetType)
|
||||
{
|
||||
if (fields == null || fields.Length == 0) return new List<string>();
|
||||
|
||||
return fields
|
||||
.Where(f => !string.IsNullOrWhiteSpace(f))
|
||||
.Select(f => f.Trim())
|
||||
.Where(f => targetType.GetProperty(
|
||||
targetType == typeof(UsagetokenOutput) ?
|
||||
$"{f}Sum" : f) != null)
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
// 增强版聚合配置类
|
||||
public class AggregationConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 数据库字段名(与CustomExpression二选一)
|
||||
/// </summary>
|
||||
public string Field { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义聚合表达式(优先级高于Field+Function)
|
||||
/// </summary>
|
||||
public string CustomExpression { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 聚合函数类型(使用CustomExpression时可不填)
|
||||
/// </summary>
|
||||
public AggregateFunction Function { get; set; } = AggregateFunction.Sum;
|
||||
|
||||
/// <summary>
|
||||
/// 输出字段别名(必须与DTO属性名一致)
|
||||
/// </summary>
|
||||
public required string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// HAVING条件表达式(如"> 100")
|
||||
/// </summary>
|
||||
public string HavingCondition { get; set; }
|
||||
}
|
||||
public enum AggregateFunction
|
||||
{
|
||||
Sum,
|
||||
Avg,
|
||||
Count,
|
||||
Max,
|
||||
Min,
|
||||
// 可扩展其他函数
|
||||
}
|
||||
@ -17,7 +17,7 @@ namespace @Model.NameSpace;
|
||||
@if(@Model.ConfigId!="1300000000001"){
|
||||
@:[Tenant("@(@Model.ConfigId)")]
|
||||
}
|
||||
public partial class @(@Model.EntityName) @Model.BaseClassName
|
||||
public class @(@Model.EntityName) @Model.BaseClassName
|
||||
{
|
||||
@foreach (var column in Model.TableField){
|
||||
if(@Model.BaseClassName=="" && @column.IsPrimarykey){
|
||||
|
||||
@ -1,28 +1,60 @@
|
||||
|
||||
namespace @(@Model.NameSpace).Entity;
|
||||
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||
@:using Admin.NET.Core;
|
||||
}
|
||||
namespace @(@Model.NameSpace);
|
||||
/// <summary>
|
||||
/// 扩展@(@Model.BusName)实体
|
||||
/// 扩展@(@Model.BusName)输出实体
|
||||
/// </summary>
|
||||
public partial class @(@Model.ClassName)
|
||||
public partial class @(@Model.ClassName)Output
|
||||
{
|
||||
|
||||
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
||||
@:/// <summary>
|
||||
@:/// 合约商品树形Name
|
||||
@:/// </summary>
|
||||
@:[SugarColumn(IsIgnore = true)]
|
||||
@:public string Name { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// @(@Model.BusName)子项
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public List<@(@Model.ClassName)> Children { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 是否禁止选中
|
||||
/// count
|
||||
/// </summary>
|
||||
[SugarColumn(IsIgnore = true)]
|
||||
public bool Disabled { get; set; }
|
||||
public int count { get; set; }
|
||||
@foreach (var par in Model.TableInoutpar.Where(m => m.inouttype == "Input").ToList()){
|
||||
@:/// <summary>
|
||||
@:/// @(@par.Name)
|
||||
@:/// </summary>
|
||||
@:public @(@par.DataType) @(@par.parameter) { get; set; }
|
||||
}
|
||||
|
||||
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
||||
@:/// <summary>
|
||||
@:/// Name
|
||||
@:/// </summary>
|
||||
@:public string Name { get; set; }
|
||||
}
|
||||
@if(Model.TabType=="Tree"){
|
||||
@:/// <summary>
|
||||
@:/// @(@Model.BusName)子项
|
||||
@:/// </summary>
|
||||
@:[SugarColumn(IsIgnore = true)]
|
||||
@:public List<@(@Model.ClassName)Output> Children { get; set; }
|
||||
|
||||
@:/// <summary>
|
||||
@:/// 是否禁止选中
|
||||
@:/// </summary>
|
||||
@:[SugarColumn(IsIgnore = true)]
|
||||
@:public bool Disabled { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扩展@(@Model.BusName)分页查询输入参数
|
||||
/// </summary>
|
||||
public partial class Page@(@Model.ClassName)Input
|
||||
{
|
||||
public string[] GroupBy { get; set; }
|
||||
public string[] Sum { get; set; }
|
||||
public IEnumerable<AggregationConfig> Aggregations { get; set; }
|
||||
@foreach (var par in Model.TableInoutpar.Where(m => m.inouttype == "Output").ToList()){
|
||||
@:/// <summary>
|
||||
@:/// @(@par.Name)
|
||||
@:/// </summary>
|
||||
@:public @(@par.DataType) @(@par.parameter) { get; set; }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
using Admin.NET.Core.Service;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||
@{
|
||||
@ -19,7 +18,9 @@ using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
||||
}
|
||||
}
|
||||
}
|
||||
using @(@Model.NameSpace).Entity;
|
||||
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||
@:using Admin.NET.Core;
|
||||
}
|
||||
|
||||
namespace @Model.NameSpace;
|
||||
/// <summary>
|
||||
@ -35,26 +36,35 @@ public partial class @(@Model.ClassName)Service
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "GetTreeList", Description = "获取列表", Order = 1100), HttpPost]
|
||||
[DisplayName("获取列表")]
|
||||
public async Task<List<@(@Model.ClassName)>> GetTreeList([FromQuery] Tree input)
|
||||
public async Task<List<@(@Model.ClassName)Output>> GetTreeList(Page@(@Model.ClassName)Input input)
|
||||
{
|
||||
// 带条件筛选时返回列表数据
|
||||
var list = await _@(@Model.LowerClassName)Rep.AsQueryable()
|
||||
.WhereIF(input.Id > 0, t => t.Id == input.Id)
|
||||
//名称
|
||||
//.WhereIF(!string.IsNullOrWhiteSpace(input.tacticsNme), u => u.tacticsNme.Contains(input.tacticsNme.Trim()))
|
||||
.OrderBy(t => new { t.Id })
|
||||
//.Select((u) => new Tree
|
||||
//{
|
||||
// Id = u.Id.ToString(),
|
||||
// Name = u.@(@Model.TreeName)
|
||||
//})
|
||||
.ToListAsync();
|
||||
@if(!string.IsNullOrEmpty(Model.TreeName)){
|
||||
@if(Model.TableField.FirstOrDefault(u => u.ColumnName.ToLower() == "name") == null){
|
||||
@:list.ForEach(t => t.Name = t.@(@Model.TreeName) );
|
||||
}
|
||||
}
|
||||
return list;
|
||||
@if(Model.TabType=="Tree"){
|
||||
@:var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToTreeAsync(u => u.Children, u => u.@(@Model.TreeKey), input.Id);
|
||||
@://var list = await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();//非树形结构表
|
||||
|
||||
@:var md = await _@(@Model.LowerClassName)Rep.AsQueryable().Where(u => u.Id == input.Id).Select<@(@Model.ClassName)Output>().FirstAsync();
|
||||
@:if (md == null) return list;
|
||||
@:
|
||||
@:md.Children = list;
|
||||
@:list = [md];
|
||||
@:return list;
|
||||
}else{
|
||||
@://return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToTreeAsync(u => u.Children, u => u.@(@Model.TreeKey), input.Id));//树形结构表
|
||||
@:return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/// <summary>
|
||||
/// 扩展@(@Model.BusName)中间件
|
||||
/// </summary>
|
||||
public partial class @(@Model.ClassName)Mid
|
||||
{
|
||||
|
||||
}
|
||||
@{
|
||||
string LowerFirstLetter(string text)
|
||||
{
|
||||
return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,7 @@ if (@column.ColumnKey != "True"){
|
||||
/// <summary>
|
||||
/// @(@Model.BusName)分页查询输入参数
|
||||
/// </summary>
|
||||
public class Page@(@Model.ClassName)Input : BasePageInput
|
||||
public partial class Page@(@Model.ClassName)Input : BasePageInput
|
||||
{
|
||||
/// <summary>
|
||||
/// 关键字查询
|
||||
|
||||
116
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Mid.cs.vm
Normal file
116
Admin.NET/Admin.NET.Web.Entry/wwwroot/template/service_Mid.cs.vm
Normal file
@ -0,0 +1,116 @@
|
||||
@{
|
||||
string joinTableName = "u";
|
||||
Dictionary<string, int> definedObjects = new Dictionary<string, int>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@if(@Model.NameSpace != "Admin.NET.Core"){
|
||||
@:using Admin.NET.Core;
|
||||
}
|
||||
|
||||
namespace @(@Model.NameSpace);
|
||||
public partial class @(@Model.ClassName)Mid
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取查询
|
||||
/// </summary>
|
||||
/// <param name="_@(@Model.LowerClassName)Rep"></param>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
public static ISugarQueryable<@(@Model.ClassName)Output> GetQuery(SqlSugarRepository<@(@Model.ClassName)> _@(@Model.LowerClassName)Rep,Page@(@Model.ClassName)Input input)
|
||||
{
|
||||
var sysCacheService = App.GetRequiredService<SysCacheService>();
|
||||
var db = App.GetRequiredService<ISqlSugarClient>();
|
||||
@if (haveLikeCdt) {
|
||||
@:input.SearchKey = input.SearchKey?.Trim();
|
||||
}
|
||||
var query = _@(@Model.LowerClassName)Rep.AsQueryable()
|
||||
@{string conditionFlag = "";}
|
||||
@if (haveLikeCdt) {
|
||||
@:.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
|
||||
@foreach (var column in Model.TableField){
|
||||
if (@column.QueryWhether == "Y" && column.QueryType == "like"){
|
||||
@:@(conditionFlag)u.@(@column.PropertyName).Contains(input.SearchKey)
|
||||
conditionFlag="|| ";
|
||||
}
|
||||
}
|
||||
@:)
|
||||
}
|
||||
@foreach (var column in Model.TableField){
|
||||
if (@column.QueryWhether == "Y"){
|
||||
if (@column.NetType?.TrimEnd('?') == "string"){
|
||||
if(@column.QueryType == "like"){
|
||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName).Contains(input.@(@column.PropertyName).Trim()))
|
||||
}else{
|
||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}
|
||||
}else if(@column.NetType?.TrimEnd('?') == "int" || @column.NetType?.TrimEnd('?') == "long"){
|
||||
@:.WhereIF(input.@column.PropertyName>0, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}else if(@column.NetType?.TrimEnd('?') == "DateTime" && @column.QueryType == "~"){
|
||||
@:.WhereIF(input.@(@column.PropertyName)Range != null && input.@(@column.PropertyName)Range.Length == 2, u => u.@(@column.PropertyName) >= input.@(@column.PropertyName)Range[0] && u.@(@column.PropertyName) <= input.@(@column.PropertyName)Range[1])
|
||||
}else if(@column.NetType?.TrimEnd('?').EndsWith("Enum") == true) {
|
||||
@:.WhereIF(input.@(@column.PropertyName).HasValue, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.Select<@(@Model.ClassName)Output>()
|
||||
@if(!string.IsNullOrEmpty(Model.TreeName)){
|
||||
@:.Mapper(c => c.Name= c.@(@Model.TreeName).ToString())
|
||||
}
|
||||
@foreach (var column in Model.TableField){
|
||||
if(@column.EffectType == "Upload"){
|
||||
@://.Mapper(c => c.@(@column.PropertyName)Attachment, c => c.@(@column.PropertyName))
|
||||
}
|
||||
else if(@column.EffectType == "ForeignKey"){
|
||||
@:.Mapper(t =>
|
||||
@:{
|
||||
@: //使用缓存
|
||||
@: var key = $"@(@column.FkEntityName)_{t.@(@column.PropertyName)}";
|
||||
@: if (!sysCacheService.ExistKey(key))
|
||||
@: {
|
||||
@: var m = db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName));
|
||||
@: if (m != null) sysCacheService.Set(key, m);
|
||||
@: }
|
||||
@: t.@(@column.PropertyName)@(@column.FkColumnName) = sysCacheService.Get<@(@column.FkEntityName)>(key)?.@(@column.FkColumnName);
|
||||
@: //t.@(@column.PropertyName)@(@column.FkColumnName)=db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName))).@(@column.FkColumnName);//
|
||||
@:})
|
||||
}
|
||||
else if(@column.EffectType == "ApiTreeSelector"){
|
||||
@:.Mapper(t =>
|
||||
@:{
|
||||
@: //使用缓存
|
||||
@: var key = $"@(@column.FkEntityName)_{t.@(@column.PropertyName)}";
|
||||
@: if (!sysCacheService.ExistKey(key))
|
||||
@: {
|
||||
@: var m = db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.ValueColumn) == t.@(@column.PropertyName));
|
||||
@: if (m != null) sysCacheService.Set(key, m);
|
||||
@: }
|
||||
@: t.@(@column.PropertyName)@(@column.DisplayColumn) = sysCacheService.Get<@(@column.FkEntityName)>(key)?.@(@column.DisplayColumn);
|
||||
@: //t.@(@column.PropertyName)@(@column.FkColumnName)=db.CopyNew().GetSimpleClient<@(@column.FkEntityName)>().GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName))).@(@column.FkColumnName);//
|
||||
@:})
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
return query;
|
||||
}
|
||||
}
|
||||
@{
|
||||
string LowerFirstLetter(string text)
|
||||
{
|
||||
return text.ToString()[..1].ToLower() + text[1..]; // 首字母小写
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@ namespace @Model.NameSpace;
|
||||
/// <summary>
|
||||
/// @(@Model.BusName)输出参数
|
||||
/// </summary>
|
||||
public class @(@Model.ClassName)Output
|
||||
public partial class @(@Model.ClassName)Output
|
||||
{
|
||||
@foreach (var column in Model.TableField){
|
||||
@:/// <summary>
|
||||
|
||||
@ -71,65 +71,9 @@ public partial class @(@Model.ClassName)Service : IDynamicApiController, ITransi
|
||||
[DisplayName("分页查询@(@Model.BusName)")]
|
||||
public async Task<SqlSugarPagedList<@(@Model.ClassName)Output>> Page(Page@(@Model.ClassName)Input input)
|
||||
{
|
||||
@if (haveLikeCdt) {
|
||||
@:input.SearchKey = input.SearchKey?.Trim();
|
||||
}
|
||||
var query = _@(@Model.LowerClassName)Rep.AsQueryable()
|
||||
@{string conditionFlag = "";}
|
||||
@if (haveLikeCdt) {
|
||||
@:.WhereIF(!string.IsNullOrEmpty(input.SearchKey), u =>
|
||||
@foreach (var column in Model.TableField){
|
||||
if (@column.QueryWhether == "Y" && column.QueryType == "like"){
|
||||
@:@(conditionFlag)u.@(@column.PropertyName).Contains(input.SearchKey)
|
||||
conditionFlag="|| ";
|
||||
}
|
||||
}
|
||||
@:)
|
||||
}
|
||||
@foreach (var column in Model.TableField){
|
||||
if (@column.QueryWhether == "Y"){
|
||||
if (@column.NetType?.TrimEnd('?') == "string"){
|
||||
if(@column.QueryType == "like"){
|
||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName).Contains(input.@(@column.PropertyName).Trim()))
|
||||
}else{
|
||||
@:.WhereIF(!string.IsNullOrWhiteSpace(input.@column.PropertyName), u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}
|
||||
}else if(@column.NetType?.TrimEnd('?') == "int" || @column.NetType?.TrimEnd('?') == "long"){
|
||||
@:.WhereIF(input.@column.PropertyName>0, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}else if(@column.NetType?.TrimEnd('?') == "DateTime" && @column.QueryType == "~"){
|
||||
@:.WhereIF(input.@(@column.PropertyName)Range != null && input.@(@column.PropertyName)Range.Length == 2, u => u.@(@column.PropertyName) >= input.@(@column.PropertyName)Range[0] && u.@(@column.PropertyName) <= input.@(@column.PropertyName)Range[1])
|
||||
}else if(@column.NetType?.TrimEnd('?').EndsWith("Enum") == true) {
|
||||
@:.WhereIF(input.@(@column.PropertyName).HasValue, u => u.@(@column.PropertyName) @column.QueryType input.@(@column.PropertyName))
|
||||
}
|
||||
}
|
||||
}
|
||||
@foreach (var column in Model.TableField){
|
||||
if(@column.EffectType == "Upload"){
|
||||
@://.Mapper(c => c.@(@column.PropertyName)Attachment, c => c.@(@column.PropertyName))
|
||||
}
|
||||
}
|
||||
.Select<@(@Model.ClassName)Output>();
|
||||
|
||||
|
||||
|
||||
@if(@Model.TableField.Any(x=>x.EffectType == "ForeignKey"||x.EffectType == "ApiTreeSelector")){
|
||||
@:var list = await query.MergeTable().OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
||||
} else {
|
||||
@:var list = await query.OrderBuilder(input).ToPagedListAsync(input.Page, input.PageSize);
|
||||
}
|
||||
@if(@Model.TableField.Any(x=>x.EffectType == "ForeignKey"||x.EffectType == "ApiTreeSelector")){
|
||||
@:list.Items.ForEach(t =>{
|
||||
|
||||
@foreach (var column in Model.TableField){
|
||||
if(@column.EffectType == "ForeignKey"){
|
||||
@:t.@(@column.PropertyName)@(@column.FkColumnName) =_@(@column.LowerFkEntityName)Rep.GetFirst(f => f.@(@column.FkLinkColumnName) == t.@(@column.PropertyName)).@(@column.FkColumnName);
|
||||
}
|
||||
else if(@column.EffectType == "ApiTreeSelector"){
|
||||
@:t.@(@column.PropertyName)@(@column.FkColumnName) =_@(@column.LowerFkEntityName)Rep.GetFirst(f => f.@(@column.DisplayColumn) == t.@(@column.PropertyName)).@(@column.FkColumnName);
|
||||
}
|
||||
}
|
||||
@:});
|
||||
}
|
||||
//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;
|
||||
|
||||
}
|
||||
@ -217,14 +161,125 @@ if (@column.ColumnKey == "True"){
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpGet]
|
||||
[ApiDescriptionSettings(Name = "list", Description = "获取@(@Model.BusName)列表", Order = 950), HttpPost]
|
||||
[DisplayName("获取@(@Model.BusName)列表")]
|
||||
public async Task<List<@(@Model.ClassName)Output>> List([FromQuery] Page@(@Model.ClassName)Input input)
|
||||
public async Task<List<@(@Model.ClassName)Output>> List(Page@(@Model.ClassName)Input input)
|
||||
{
|
||||
return await _@(@Model.LowerClassName)Rep.AsQueryable().Select<@(@Model.ClassName)Output>().ToListAsync();
|
||||
return await @(@Model.ClassName)Mid.GetQuery(_@(@Model.LowerClassName)Rep, input).OrderBuilder(input).ToListAsync();
|
||||
}
|
||||
|
||||
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||
@:/// <summary>
|
||||
@:/// 获取@(@Model.BusName)
|
||||
@:/// </summary>
|
||||
@:/// <param name="input"></param>
|
||||
@:/// <returns></returns>
|
||||
@:[ApiDescriptionSettings(Name = "GetTotalSum", Description = "获取@(@Model.BusName)统计", Order = 960), HttpPost]
|
||||
@:[DisplayName("获取@(@Model.BusName)统计")]
|
||||
@:public async Task<List<@(@Model.ClassName)Output>> 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();
|
||||
@:}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据输入参数获取@(@Model.BusName)统计
|
||||
/// 支持双模式聚合配置:
|
||||
/// 常规模式:Field + Function
|
||||
/// 高级模式:CustomExpression(支持任意合法SQL表达式)
|
||||
/// 智能条件组合:
|
||||
/// 多个HAVING条件自动用AND连接
|
||||
/// 条件表达式自动包裹聚合函数(如SUM(cost) > 10000)
|
||||
/// 可扩展支持OR条件
|
||||
/// </summary>
|
||||
/// <param name="input"></param>
|
||||
/// <returns></returns>
|
||||
[ApiDescriptionSettings(Name = "GetAggregTotalSum", Order = 970), HttpPost]
|
||||
[DisplayName("根据输入参数获取@(@Model.BusName)统计")]
|
||||
public async Task<List<@(@Model.ClassName)Output>> 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")){
|
||||
@:/// <summary>
|
||||
@ -270,7 +325,7 @@ if(@column.EffectType == "ApiTreeSelector" && !definedObjects.ContainsKey("@(@co
|
||||
@:[DisplayName("获取@(@column.FkEntityName)Tree")]
|
||||
@:public async Task<dynamic> @(@column.FkEntityName)Tree()
|
||||
@:{
|
||||
@:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>().ToTreeAsync(u => u.Children, u => u.@(@column.PidColumn), 0);
|
||||
@:return await _@(@Model.LowerClassName)Rep.Context.Queryable<@(@column.FkEntityName)>().Select<@(@column.FkEntityName)Output>().ToTreeAsync(u => u.Children, u => u.@(@column.PidColumn), 0);
|
||||
@:}
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,6 +18,8 @@ enum Api {
|
||||
Update@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/update',
|
||||
Page@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/page',
|
||||
Tree@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/GetTreeList',
|
||||
Get@(@Model.ClassName)TotalSum = '/api/@(@Model.LowerClassName)/GetTotalSum',
|
||||
Get@(@Model.ClassName)AggregTotalSum = '/api/@(@Model.LowerClassName)/GetAggregTotalSum',
|
||||
Detail@(@Model.ClassName) = '/api/@(@Model.LowerClassName)/detail',
|
||||
@if(Model.RemoteVerify){
|
||||
@:Exists@(RemoteField) = '/api/@(@Model.LowerClassName)/exists@(RemoteField)',
|
||||
@ -72,6 +74,20 @@ export const treelist@(@Model.ClassName) = (params?: any) =>
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
// 获取统计,支持全表和分组
|
||||
export const get@(@Model.ClassName)TotalSum = (params?: any) =>
|
||||
request({
|
||||
url: Api.Get@(@Model.ClassName)TotalSum,
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
// 输入参数获取统计
|
||||
export const get@(@Model.ClassName)AggregTotalSum = (params?: any) =>
|
||||
request({
|
||||
url: Api.Get@(@Model.ClassName)AggregTotalSum,
|
||||
method: 'post',
|
||||
data: params,
|
||||
});
|
||||
// 详情@(@Model.BusName)
|
||||
export const detail@(@Model.ClassName) = (id: any) =>
|
||||
request({
|
||||
|
||||
@ -235,7 +235,7 @@ import ModifyRecord from '/@@/components/table/modifyRecord.vue';
|
||||
@:import { @(@Model.ClassName), @(@Model.ClassName)Input, @(@Model.ClassName)Output } from '/@@/api-services/models';
|
||||
|
||||
} else {
|
||||
@:import { page@(@Model.ClassName), delete@(@Model.ClassName) } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
||||
@:import { page@(@Model.ClassName), delete@(@Model.ClassName), get@(@Model.ClassName)TotalSum } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
||||
foreach (var column in Model.QueryWhetherList){
|
||||
if(@column.EffectType == "ForeignKey"){
|
||||
@:import { get@(@column.FkEntityName)@(@column.PropertyName)Dropdown } from '/@@/api/@(@Model.PagePath)/@(@Model.LowerClassName)';
|
||||
@ -278,6 +278,7 @@ const state = reactive({
|
||||
pageSize: 50 as number,
|
||||
defaultSort: { field: 'Id', order: 'asc', descStr: 'desc' },
|
||||
},
|
||||
totalSum:[] as any,
|
||||
visible: false,
|
||||
title: '',
|
||||
});
|
||||
@ -337,6 +338,26 @@ const checkTableColumnVisible = (tableColumnName: any) => {
|
||||
}
|
||||
{ title: '操作', fixed: 'right', width: 180, showOverflow: true, slots: { default: 'row_buttons' } },
|
||||
],
|
||||
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||
@:footerMethod: ({ columns, data }) => {
|
||||
@: const totalSum=state.totalSum[0];
|
||||
@: return [
|
||||
@: columns.map((column, colIndex) => {
|
||||
@: if (colIndex === 0) {
|
||||
@: return `合计:`
|
||||
@: }
|
||||
@foreach (var column in Model.TableField){
|
||||
if (@column.Statistical == "Y"){
|
||||
@: if (column.field === '@(@column.LowerPropertyName)') {
|
||||
@: // 计算表格内总和
|
||||
@: return `${data.reduce((sum, row) => sum + (row.@(@column.LowerPropertyName) || 0), 0)}/总数:${totalSum.@(@column.LowerPropertyName)}`
|
||||
@: }
|
||||
}
|
||||
}
|
||||
@: })
|
||||
@: ]
|
||||
@:},
|
||||
}
|
||||
},
|
||||
// vxeGrid配置参数(此处可覆写任何参数),参考vxe-table官方文档
|
||||
{
|
||||
@ -377,6 +398,14 @@ const handleQueryApi = async (page: VxeGridPropTypes.ProxyAjaxQueryPageParams, s
|
||||
// 查询操作
|
||||
const handleQuery = async (reset = false) => {
|
||||
options.loading = true;
|
||||
@if(@Model.TableField.Any(x=>x.Statistical == "Y")){
|
||||
@if (@Model.IsApiService) {
|
||||
@:state.totalSum =getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)GetTotalSumPost(params).data.result;
|
||||
}
|
||||
} else {
|
||||
@:state.totalSum =(await get@(@Model.ClassName)TotalSum(state.queryParams)).data.result;
|
||||
}
|
||||
}
|
||||
reset ? await xGrid.value?.commitProxy('reload') : await xGrid.value?.commitProxy('query');
|
||||
options.loading = false;
|
||||
};
|
||||
|
||||
@ -109,7 +109,11 @@ watch(filterText, (val) => {
|
||||
// 获取树数据
|
||||
const fetchTreeData = async (showLoading: boolean = true) => {
|
||||
if (showLoading) state.loading = true;
|
||||
var res = await treelist@(@Model.ClassName)({Id:0});
|
||||
@if (@Model.IsApiService) {
|
||||
@:var res = await getAPI(@(@Model.ClassName)Api).api@(@Model.ClassName)GetTreeListPost({Id:0});
|
||||
} else {
|
||||
@:var res = await treelist@(@Model.ClassName)({Id:0});
|
||||
}
|
||||
state.@(@Model.LowerClassName)Data = res.data.result ?? [];
|
||||
if (showLoading) state.loading = false;
|
||||
return res.data.result ?? [];
|
||||
|
||||
@ -38,6 +38,9 @@
|
||||
<template #statistical="{ row }">
|
||||
<vxe-switch v-model="row.statistical" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||
</template>
|
||||
<template #isGroupBy="{ row }">
|
||||
<vxe-switch v-model="row.isGroupBy" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||
</template>
|
||||
<template #queryWhether="{ row }">
|
||||
<vxe-switch v-model="row.queryWhether" open-label="是" close-label="否" :openValue="true" :closeValue="false"></vxe-switch>
|
||||
</template>
|
||||
@ -205,6 +208,15 @@ const options = reactive<VxeGridProps>({
|
||||
default: 'statistical',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'isGroupBy',
|
||||
title: 'GroupBy',
|
||||
minWidth: 70,
|
||||
slots: {
|
||||
edit: 'isGroupBy',
|
||||
default: 'isGroupBy',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'queryWhether',
|
||||
title: '是否是查询',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user