From 08b83cc42dde45b16eb74e7927ff7f4bc9902486 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Tue, 16 Jun 2026 13:54:48 +0300 Subject: [PATCH] =?UTF-8?q?Devexpress=20Grid=20Raporundaki=20Selectbox=20k?= =?UTF-8?q?=C4=B1s=C4=B1mlar=C4=B1=20d=C3=BCzeltildi.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Value görünmüyor Text bilgileri görünüyor. --- .../Seeds/TenantData.json | 2 +- .../DynamicListFormReport.cs | 252 +++++++++++++++++- 2 files changed, 243 insertions(+), 11 deletions(-) diff --git a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json index fc10183..8ad2e37 100644 --- a/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json +++ b/api/src/Sozsoft.Platform.EntityFrameworkCore/Seeds/TenantData.json @@ -1390,7 +1390,7 @@ "name": "App.Definitions.AiBot", "description": "Liste Raporları", "categoryName": "Listeler", - "htmlContent": "

Liste Raporları.

", + "htmlContent": "

Liste Raporları.

http://localhost:3000/admin/reports/DynamicListFormReport/view?listFormCode=App.Languages.LanguageText&filter=[%22CultureName%22,%22=%22,%22en%22]

", "status": "active" } ], diff --git a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs index aa79ce9..bbf7f62 100644 --- a/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs +++ b/api/src/Sozsoft.Platform.HttpApi.Host/PredefinedReports/DynamicListFormReport.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Globalization; using System.Linq; +using System.Text.Json; using System.Text.RegularExpressions; using DevExpress.DataAccess.ConnectionParameters; using DevExpress.DataAccess.Sql; @@ -11,7 +12,6 @@ using DevExpress.XtraPrinting; using DevExpress.XtraReports.UI; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; -using Microsoft.Extensions.Primitives; using Sozsoft.Platform.DynamicData; using Sozsoft.Platform.Entities; using Sozsoft.Platform.Enums; @@ -65,6 +65,7 @@ public class DynamicListFormReport : XtraReport var customizationManager = scope.ServiceProvider.GetRequiredService(); var dynamicDataManager = scope.ServiceProvider.GetRequiredService(); var selectQueryManager = scope.ServiceProvider.GetRequiredService(); + var defaultValueHelper = scope.ServiceProvider.GetRequiredService(); var localizer = scope.ServiceProvider.GetRequiredService>(); if (!authManager.CanAccess(listFormCode).GetAwaiter().GetResult()) @@ -81,7 +82,6 @@ public class DynamicListFormReport : XtraReport var customizations = customizationManager.GetUsersServerCustomizations(listFormCode).GetAwaiter().GetResult(); var (_, connectionString, dataSourceType) = dynamicDataManager.GetAsync(listForm.IsTenant, listForm.DataSourceCode).GetAwaiter().GetResult(); - var queryParameters = ToStringValues(parameters); var queryParams = new QueryParameters { ListFormCode = listFormCode, @@ -116,14 +116,20 @@ public class DynamicListFormReport : XtraReport .Select(field => { var selectField = selectQueryManager.SelectFields.First(s => s.FieldName == field.FieldName); - return new ReportColumn(field, GetReportFieldName(selectField)); + return CreateReportColumn(field, selectField, defaultValueHelper); }) .Where(x => !string.IsNullOrWhiteSpace(x.BindingName) && x.BindingName != "undefined") .ToList(); + var selectQuery = ApplyLookupQueryColumns( + selectQueryManager.SelectQuery, + listForm, + reportColumns, + defaultValueHelper); + ConfigurePage(reportColumns); ConfigureDataSource( - ApplyQueryParameters(selectQueryManager.SelectQuery, selectQueryManager.SelectQueryParameters), + ApplyQueryParameters(selectQuery, selectQueryManager.SelectQueryParameters), connectionString, dataSourceType); BuildLayout(listForm, reportColumns, localizer); @@ -347,6 +353,18 @@ public class DynamicListFormReport : XtraReport CanGrow = false }; cell.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{column.BindingName}]")); + if (column.StaticLookupValues?.Count > 0) + { + cell.BeforePrint += (_, _) => + { + var value = Convert.ToString(cell.Text, CultureInfo.InvariantCulture); + if (value != null && column.StaticLookupValues.TryGetValue(value, out var displayText)) + { + cell.Text = displayText; + } + }; + } + return cell; } @@ -417,7 +435,226 @@ public class DynamicListFormReport : XtraReport return selectField?.FieldName; } - private sealed record ReportColumn(ListFormField Field, string BindingName); + private static ReportColumn CreateReportColumn( + ListFormField field, + SelectField selectField, + DefaultValueHelper defaultValueHelper) + { + var bindingName = GetReportFieldName(selectField); + var lookup = GetLookup(field); + + if (lookup == null || selectField?.JoinOptions != null) + { + return new ReportColumn(field, bindingName, null, null); + } + + if (IsReportQueryableLookup(lookup)) + { + return new ReportColumn(field, GetLookupBindingName(field), lookup, null); + } + + if (lookup.DataSourceType == UiLookupDataSourceTypeEnum.StaticData) + { + return new ReportColumn( + field, + bindingName, + lookup, + GetStaticLookupValues(lookup, defaultValueHelper)); + } + + return new ReportColumn(field, bindingName, null, null); + } + + private static bool IsReportQueryableLookup(LookupDto lookup) + { + return lookup.DataSourceType == UiLookupDataSourceTypeEnum.Query && + string.IsNullOrWhiteSpace(lookup.CascadeParentFields) && + !string.IsNullOrWhiteSpace(lookup.LookupQuery) && + !Regex.IsMatch(lookup.LookupQuery, @"@\s*param\d+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + private static LookupDto GetLookup(ListFormField field) + { + if (string.IsNullOrWhiteSpace(field.LookupJson)) + { + return null; + } + + try + { + return JsonSerializer.Deserialize(field.LookupJson); + } + catch (JsonException) + { + return null; + } + } + + private static Dictionary GetStaticLookupValues( + LookupDto lookup, + DefaultValueHelper defaultValueHelper) + { + if (string.IsNullOrWhiteSpace(lookup.LookupQuery)) + { + return null; + } + + try + { + var lookupJson = defaultValueHelper.GetDefaultValue(lookup.LookupQuery); + using var document = JsonDocument.Parse(lookupJson); + if (document.RootElement.ValueKind != JsonValueKind.Array) + { + return null; + } + + var valueExpr = lookup.ValueExpr ?? "Key"; + var displayExpr = lookup.DisplayExpr ?? "Name"; + var values = new Dictionary(StringComparer.OrdinalIgnoreCase); + foreach (var item in document.RootElement.EnumerateArray()) + { + if (!TryGetProperty(item, valueExpr, out var valueElement) || + !TryGetProperty(item, displayExpr, out var displayElement)) + { + continue; + } + + var value = GetJsonScalar(valueElement); + if (value == null) + { + continue; + } + + values[value] = GetJsonScalar(displayElement) ?? value; + } + + return values.Count == 0 ? null : values; + } + catch (JsonException) + { + return null; + } + } + + private static bool TryGetProperty(JsonElement element, string propertyName, out JsonElement value) + { + foreach (var property in element.EnumerateObject()) + { + if (string.Equals(property.Name, propertyName, StringComparison.OrdinalIgnoreCase)) + { + value = property.Value; + return true; + } + } + + value = default; + return false; + } + + private static string GetJsonScalar(JsonElement element) + { + return element.ValueKind switch + { + JsonValueKind.String => element.GetString(), + JsonValueKind.Number => element.GetRawText(), + JsonValueKind.True => bool.TrueString, + JsonValueKind.False => bool.FalseString, + JsonValueKind.Null => null, + _ => element.ToString() + }; + } + + private static string ApplyLookupQueryColumns( + string selectQuery, + ListForm listForm, + IReadOnlyList reportColumns, + DefaultValueHelper defaultValueHelper) + { + var lookupColumns = reportColumns + .Where(x => x.Lookup != null && IsReportQueryableLookup(x.Lookup)) + .ToList(); + + if (lookupColumns.Count == 0 || string.IsNullOrWhiteSpace(selectQuery)) + { + return selectQuery; + } + + var tableAlias = string.IsNullOrWhiteSpace(listForm.TableName) + ? listForm.SelectCommand + : listForm.TableName; + + var selectParts = new List(); + var joinParts = new List(); + foreach (var column in lookupColumns) + { + var lookup = column.Lookup; + var alias = GetLookupAlias(column.Field); + var valueExpr = QuoteSqlIdentifier(lookup.ValueExpr ?? "Key"); + var displayExpr = QuoteSqlIdentifier(lookup.DisplayExpr ?? "Name"); + var lookupQuery = NormalizeLookupQuery(defaultValueHelper.GetDefaultValue(lookup.LookupQuery)); + + selectParts.Add($"{alias}.{displayExpr} AS {QuoteSqlIdentifier(column.BindingName)}"); + joinParts.Add( + $"LEFT JOIN ({lookupQuery}) AS {alias} " + + $"ON {alias}.{valueExpr} = {QuoteSqlIdentifier(tableAlias)}.{QuoteSqlIdentifier(column.Field.FieldName)}"); + } + + var fromIndex = selectQuery.IndexOf(" FROM ", StringComparison.OrdinalIgnoreCase); + if (fromIndex < 0) + { + return selectQuery; + } + + selectQuery = selectQuery.Insert(fromIndex, "," + string.Join(',', selectParts)); + + var joinInsertIndex = FindClauseIndex(selectQuery, " WHERE "); + if (joinInsertIndex < 0) + { + joinInsertIndex = FindClauseIndex(selectQuery, " ORDER BY "); + } + if (joinInsertIndex < 0) + { + return selectQuery + " " + string.Join(' ', joinParts); + } + + return selectQuery.Insert(joinInsertIndex, " " + string.Join(' ', joinParts)); + } + + private static int FindClauseIndex(string sql, string clause) + { + return sql.IndexOf(clause, StringComparison.OrdinalIgnoreCase); + } + + private static string NormalizeLookupQuery(string lookupQuery) + { + var query = lookupQuery.Trim().TrimEnd(';'); + return Regex.Replace( + query, + @"\s+ORDER\s+BY\s+[\s\S]*$", + string.Empty, + RegexOptions.IgnoreCase | RegexOptions.CultureInvariant); + } + + private static string GetLookupBindingName(ListFormField field) + { + return $"{field.FieldName}__LookupText"; + } + + private static string GetLookupAlias(ListFormField field) + { + return QuoteSqlIdentifier($"Lookup_{Regex.Replace(field.FieldName, @"\W+", "_")}"); + } + + private static string QuoteSqlIdentifier(string identifier) + { + return $"\"{identifier.Replace("\"", "\"\"")}\""; + } + + private sealed record ReportColumn( + ListFormField Field, + string BindingName, + LookupDto Lookup, + Dictionary StaticLookupValues); private static SummaryFunc? GetSummaryType(string totalSummaryJson) { @@ -472,9 +709,4 @@ public class DynamicListFormReport : XtraReport { return parameters.TryGetValue(name, out var value) ? value : null; } - - private static Dictionary ToStringValues(IDictionary parameters) - { - return parameters.ToDictionary(x => x.Key, x => new StringValues(x.Value)); - } }