PredifinedReports için tasarım ve düzenleme

This commit is contained in:
Sedat ÖZTÜRK 2026-06-18 11:02:03 +03:00
parent d8763d6dee
commit 566a0ae0e5
11 changed files with 450 additions and 96 deletions

View file

@ -20,6 +20,7 @@ using Sozsoft.Platform.Enums;
using Sozsoft.Platform.ListForms;
using Sozsoft.Platform.Localization;
using Sozsoft.Platform.Queries;
using Volo.Abp.Users;
namespace Sozsoft.Reports.PredefinedReports;
@ -76,6 +77,7 @@ public class DynamicFormReport : XtraReport
var defaultValueHelper = scope.ServiceProvider.GetRequiredService<DefaultValueHelper>();
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<PlatformResource>>();
var configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
var currentUser = scope.ServiceProvider.GetRequiredService<ICurrentUser>();
if (!await authManager.CanAccess(listFormCode))
{
@ -117,7 +119,7 @@ public class DynamicFormReport : XtraReport
ConfigurePage();
ConfigureDataSource(selectQuery, connectionString, dataSourceType);
await BuildLayoutAsync(listForm, reportFields, row, localizer, DynamicReportImageHelper.GetImageBaseUrl(configuration));
await BuildLayoutAsync(listForm, reportFields, row, localizer, DynamicReportImageHelper.GetImageBaseUrl(configuration), currentUser.UserName);
RequestParameters = false;
}
@ -155,7 +157,8 @@ public class DynamicFormReport : XtraReport
IReadOnlyList<FormReportField> fields,
IDictionary<string, object> row,
IStringLocalizer<PlatformResource> localizer,
string imageBaseUrl)
string imageBaseUrl,
string currentUserName)
{
Bands.Clear();
var formGroups = GetFormGroups(listForm, fields).ToList();
@ -176,19 +179,15 @@ public class DynamicFormReport : XtraReport
Font = new DXFont("Arial", 14F, DXFontStyle.Bold),
TextAlignment = TextAlignment.MiddleLeft
});
DynamicReportImageHelper.AddGeneratedAtToHeader(reportHeader.Controls, pageWidth);
DynamicReportImageHelper.AddFooterTopLine(bottomMargin.Controls, pageWidth);
DynamicReportImageHelper.AddCurrentUserNameToFooter(bottomMargin.Controls, currentUserName, pageWidth);
bottomMargin.Controls.Add(new XRPageInfo
{
PageInfo = PageInfo.DateTime,
TextFormatString = "{0:dd.MM.yyyy HH:mm}",
BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth / 2, 18),
Font = new DXFont("Arial", 7.5F),
TextAlignment = TextAlignment.MiddleLeft
});
bottomMargin.Controls.Add(new XRPageInfo
{
TextFormatString = "Sayfa {0} / {1}",
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 0, pageWidth / 2, 18),
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 8, pageWidth / 2, 18),
Font = new DXFont("Arial", 8F),
TextAlignment = TextAlignment.MiddleRight
});

View file

@ -18,6 +18,7 @@ using Sozsoft.Platform.Enums;
using Sozsoft.Platform.ListForms;
using Sozsoft.Platform.Localization;
using Sozsoft.Platform.Queries;
using Volo.Abp.Users;
namespace Sozsoft.Reports.PredefinedReports;
@ -69,6 +70,7 @@ public class DynamicGridReport : XtraReport
var defaultValueHelper = scope.ServiceProvider.GetRequiredService<DefaultValueHelper>();
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<PlatformResource>>();
var configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
var currentUser = scope.ServiceProvider.GetRequiredService<ICurrentUser>();
if (!await authManager.CanAccess(listFormCode))
{
@ -142,6 +144,11 @@ public class DynamicGridReport : XtraReport
defaultValueHelper,
dataSourceType);
var imageBaseUrl = DynamicReportImageHelper.GetImageBaseUrl(configuration);
var criteriaText = DynamicReportImageHelper.BuildReportCriteriaText(
queryParams.Filter,
queryParams.Sort,
fields,
localizer);
reportColumns = await ApplyImageCountsAsync(reportColumns, dynamicDataRepository, selectQuery, connectionString, imageBaseUrl);
ConfigurePage(reportColumns);
@ -149,7 +156,7 @@ public class DynamicGridReport : XtraReport
selectQuery,
connectionString,
dataSourceType);
BuildLayout(listForm, reportColumns, localizer, imageBaseUrl);
BuildLayout(listForm, reportColumns, localizer, imageBaseUrl, currentUser.UserName, criteriaText);
RequestParameters = false;
}
@ -236,13 +243,15 @@ public class DynamicGridReport : XtraReport
ListForm listForm,
IReadOnlyList<ReportColumn> fields,
IStringLocalizer<PlatformResource> localizer,
string imageBaseUrl)
string imageBaseUrl,
string currentUserName,
string criteriaText)
{
Bands.Clear();
var topMargin = new TopMarginBand { HeightF = Margins.Top };
var bottomMargin = new BottomMarginBand { HeightF = 32 };
var reportHeader = new ReportHeaderBand { HeightF = 32 };
var reportHeader = new ReportHeaderBand { HeightF = string.IsNullOrWhiteSpace(criteriaText) ? 32 : 50 };
var pageHeader = new PageHeaderBand { HeightF = 28 };
var detailHeight = fields.Any(x => x.IsImage)
? DynamicReportImageHelper.GetGridImageHeight()
@ -262,21 +271,16 @@ public class DynamicGridReport : XtraReport
Font = new DXFont("Arial", 14F, DXFontStyle.Bold),
TextAlignment = TextAlignment.MiddleLeft
});
DynamicReportImageHelper.AddGeneratedAtToHeader(reportHeader.Controls, pageWidth);
DynamicReportImageHelper.AddReportCriteriaToHeader(reportHeader.Controls, criteriaText, pageWidth);
var generatedAt = new XRPageInfo
{
PageInfo = PageInfo.DateTime,
TextFormatString = "{0:dd.MM.yyyy HH:mm}",
BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth / 2, 18),
Font = new DXFont("Arial", 7.5F),
TextAlignment = TextAlignment.MiddleLeft
};
bottomMargin.Controls.Add(generatedAt);
DynamicReportImageHelper.AddFooterTopLine(bottomMargin.Controls, pageWidth);
DynamicReportImageHelper.AddCurrentUserNameToFooter(bottomMargin.Controls, currentUserName, pageWidth);
var pageInfo = new XRPageInfo
{
TextFormatString = "Sayfa {0} / {1}",
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 0, pageWidth / 2, 18),
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 8, pageWidth / 2, 18),
Font = new DXFont("Arial", 8F),
TextAlignment = TextAlignment.MiddleRight
};

View file

@ -6,6 +6,7 @@ using DevExpress.XtraReports.UI;
using Sozsoft.Languages.Entities;
using Sozsoft.Platform.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Users;
namespace Sozsoft.Reports.PredefinedReports;
@ -35,11 +36,47 @@ public partial class DynamicReport : XtraReport
// Language verilerini yükle
LoadLanguageParameters();
AddHeaderGeneratedAt();
AddFooterCurrentUserName();
AddFooterLine();
pageInfo1.TextFormatString = "{0:d}";
pageInfo1.Visible = false;
xrRichText1.BeforePrint += XrRichText1_BeforePrint;
}
private void AddFooterLine()
{
var pageWidth = PageWidth - Margins.Left - Margins.Right;
DynamicReportImageHelper.AddFooterTopLine(BottomMargin.Controls, pageWidth);
pageInfo1.TopF = 8;
pageInfo2.TopF = 8;
}
private void AddHeaderGeneratedAt()
{
var pageWidth = PageWidth - Margins.Left - Margins.Right;
DynamicReportImageHelper.AddGeneratedAtToHeader(ReportHeader.Controls, pageWidth);
}
private void AddFooterCurrentUserName()
{
try
{
if (_serviceProvider == null)
{
return;
}
using var scope = _serviceProvider.CreateScope();
var currentUser = scope.ServiceProvider.GetRequiredService<ICurrentUser>();
var pageWidth = PageWidth - Margins.Left - Margins.Right;
DynamicReportImageHelper.AddCurrentUserNameToFooter(BottomMargin.Controls, currentUser.UserName, pageWidth);
}
catch
{
}
}
private void LoadLanguageParameters()
{
try

View file

@ -34,7 +34,7 @@ internal static class DynamicReportImageHelper
private const string ImageSourceFunctionName = "SozReportImageSource";
private const string FormatValueFunctionName = "SozReportFormatValue";
private static readonly Regex ReportPagingRegex = new(
@"\s+ORDER\s+BY[\s\S]*?(?:\s+OFFSET\s+\d+\s+ROWS(?:\s+FETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY)?)?\s*$",
@"\s+OFFSET\s+\d+\s+ROWS(?:\s+FETCH\s+NEXT\s+\d+\s+ROWS\s+ONLY)?\s*$",
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
private static readonly HttpClient HttpClient = new(new HttpClientHandler
{
@ -271,6 +271,94 @@ internal static class DynamicReportImageHelper
return Localize(localizer, caption, field.FieldName);
}
public static void AddGeneratedAtToHeader(XRControlCollection controls, float pageWidth)
{
var width = Math.Min(260F, pageWidth * 0.4F);
controls.Add(new XRPageInfo
{
PageInfo = PageInfo.DateTime,
TextFormatString = "{0:dd.MM.yyyy HH:mm}",
BoundsF = new System.Drawing.RectangleF(pageWidth - width, 0, width, 18),
Font = new DevExpress.Drawing.DXFont("Arial", 8F),
TextAlignment = TextAlignment.MiddleRight,
CanGrow = false
});
}
public static void AddCurrentUserNameToFooter(XRControlCollection controls, string userName, float pageWidth)
{
if (string.IsNullOrWhiteSpace(userName))
{
return;
}
controls.Add(new XRLabel
{
Text = userName,
BoundsF = new System.Drawing.RectangleF(0, 8, pageWidth / 2, 18),
Font = new DevExpress.Drawing.DXFont("Arial", 7.5F),
TextAlignment = TextAlignment.MiddleLeft,
CanGrow = false,
Multiline = false
});
}
public static void AddReportCriteriaToHeader(
XRControlCollection controls,
string criteriaText,
float pageWidth)
{
if (string.IsNullOrWhiteSpace(criteriaText))
{
return;
}
controls.Add(new XRLabel
{
Text = criteriaText,
BoundsF = new System.Drawing.RectangleF(0, 28, pageWidth, 18),
Font = new DevExpress.Drawing.DXFont("Arial", 7.5F),
ForeColor = System.Drawing.Color.FromArgb(100, 116, 139),
TextAlignment = TextAlignment.MiddleLeft,
CanGrow = true,
Multiline = true
});
}
public static void AddFooterTopLine(XRControlCollection controls, float pageWidth)
{
controls.Add(new XRLine
{
BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth, 2),
ForeColor = System.Drawing.Color.FromArgb(203, 213, 225),
LineWidth = 1
});
}
public static string BuildReportCriteriaText(
string filter,
string sort,
IEnumerable<ListFormField> fields,
IStringLocalizer<PlatformResource> localizer)
{
var parts = new List<string>();
var fieldCaptions = CreateFieldCaptionMap(fields, localizer);
var filterText = FormatFilterText(filter, fieldCaptions);
var sortText = FormatSortText(sort, fieldCaptions);
if (!string.IsNullOrWhiteSpace(filterText))
{
parts.Add("Filtre: " + filterText);
}
if (!string.IsNullOrWhiteSpace(sortText))
{
parts.Add("Sıralama: " + sortText);
}
return string.Join(" | ", parts);
}
public static string Localize(IStringLocalizer<PlatformResource> localizer, string key, string fallback)
{
if (string.IsNullOrWhiteSpace(key))
@ -485,7 +573,7 @@ internal static class DynamicReportImageHelper
string editorType,
out string text)
{
return TryFormatReportValue(value, field.SourceDbType, field.Format, editorType, out text);
return TryFormatReportValue(value, field.SourceDbType, GetEffectiveFormat(field), editorType, out text);
}
public static string CreateFormatValueExpression(
@ -493,7 +581,7 @@ internal static class DynamicReportImageHelper
ListFormField field,
string editorType)
{
return $"{FormatValueFunctionName}({valueExpression}, '{field.SourceDbType}', '{EscapeExpressionString(field.Format)}', '{EscapeExpressionString(editorType)}')";
return $"{FormatValueFunctionName}({valueExpression}, '{field.SourceDbType}', '{EscapeExpressionString(GetEffectiveFormat(field))}', '{EscapeExpressionString(editorType)}')";
}
public static string FormatReportDate(DateTime value)
@ -627,6 +715,190 @@ internal static class DynamicReportImageHelper
: value ? "Yes" : "No";
}
private static Dictionary<string, string> CreateFieldCaptionMap(
IEnumerable<ListFormField> fields,
IStringLocalizer<PlatformResource> localizer)
{
return (fields ?? [])
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName))
.GroupBy(x => x.FieldName, StringComparer.OrdinalIgnoreCase)
.ToDictionary(
x => x.Key,
x => GetLocalizedFieldCaption(x.First(), localizer),
StringComparer.OrdinalIgnoreCase);
}
private static string FormatSortText(string sort, IReadOnlyDictionary<string, string> fieldCaptions)
{
if (string.IsNullOrWhiteSpace(sort))
{
return null;
}
var items = sort
.Split(PlatformConsts.MultiValueDelimiter, StringSplitOptions.RemoveEmptyEntries)
.Select(item =>
{
var parts = item.Trim().Split(' ', StringSplitOptions.RemoveEmptyEntries);
if (parts.Length == 0)
{
return null;
}
var fieldName = parts[0].Trim('"');
var direction = parts.Length > 1 ? parts[1] : "asc";
var directionText = string.Equals(direction, "desc", StringComparison.OrdinalIgnoreCase)
? "azalan"
: "artan";
return $"{GetFieldCaption(fieldName, fieldCaptions)} {directionText}";
})
.Where(x => !string.IsNullOrWhiteSpace(x));
return string.Join(", ", items);
}
private static string FormatFilterText(string filter, IReadOnlyDictionary<string, string> fieldCaptions)
{
if (string.IsNullOrWhiteSpace(filter))
{
return null;
}
try
{
using var document = JsonDocument.Parse(filter);
return FormatFilterElement(document.RootElement, fieldCaptions);
}
catch (JsonException)
{
return null;
}
}
private static string FormatFilterElement(JsonElement element, IReadOnlyDictionary<string, string> fieldCaptions)
{
if (element.ValueKind != JsonValueKind.Array)
{
return FormatJsonValue(element);
}
var items = element.EnumerateArray().ToList();
if (items.Count == 0)
{
return null;
}
if (items.Count >= 3 &&
items[0].ValueKind == JsonValueKind.String &&
items[1].ValueKind == JsonValueKind.String)
{
return FormatFilterCondition(items[0].GetString(), items[1].GetString(), items[2], fieldCaptions);
}
if (items.Count == 2 &&
items[0].ValueKind == JsonValueKind.String &&
items[0].GetString() == "!")
{
var text = FormatFilterElement(items[1], fieldCaptions);
return string.IsNullOrWhiteSpace(text) ? null : "değil (" + text + ")";
}
var parts = new List<string>();
for (var i = 0; i < items.Count; i++)
{
if (items[i].ValueKind == JsonValueKind.String &&
IsFilterConnector(items[i].GetString()))
{
parts.Add(FormatFilterConnector(items[i].GetString()));
continue;
}
var text = FormatFilterElement(items[i], fieldCaptions);
if (!string.IsNullOrWhiteSpace(text))
{
parts.Add(text);
}
}
return string.Join(" ", parts);
}
private static string FormatFilterCondition(
string fieldName,
string operation,
JsonElement value,
IReadOnlyDictionary<string, string> fieldCaptions)
{
var caption = GetFieldCaption(fieldName, fieldCaptions);
var op = FormatFilterOperation(operation);
var formattedValue = FormatJsonValue(value);
return string.IsNullOrWhiteSpace(formattedValue)
? $"{caption} {op}"
: $"{caption} {op} {formattedValue}";
}
private static string FormatFilterOperation(string operation)
{
return operation?.ToLowerInvariant() switch
{
"=" => "=",
"<>" => "eşit değil",
">" => ">",
">=" => ">=",
"<" => "<",
"<=" => "<=",
"contains" => "içerir",
"notcontains" => "içermez",
"startswith" => "ile başlar",
"endswith" => "ile biter",
"between" => "arasında",
"anyof" => "şunlardan biri",
"noneof" => "şunlardan hiçbiri",
"isblank" => "boş",
"isnotblank" => "boş değil",
_ => operation
};
}
private static string FormatJsonValue(JsonElement value)
{
return value.ValueKind switch
{
JsonValueKind.String => value.GetString(),
JsonValueKind.Number => value.GetRawText(),
JsonValueKind.True => "Evet",
JsonValueKind.False => "Hayır",
JsonValueKind.Null => string.Empty,
JsonValueKind.Array => string.Join(", ", value.EnumerateArray().Select(FormatJsonValue)),
_ => value.ToString()
};
}
private static string GetFieldCaption(string fieldName, IReadOnlyDictionary<string, string> fieldCaptions)
{
if (string.IsNullOrWhiteSpace(fieldName))
{
return fieldName;
}
return fieldCaptions.TryGetValue(fieldName, out var caption)
? caption
: fieldName;
}
private static bool IsFilterConnector(string value)
{
return string.Equals(value, "and", StringComparison.OrdinalIgnoreCase) ||
string.Equals(value, "or", StringComparison.OrdinalIgnoreCase);
}
private static string FormatFilterConnector(string value)
{
return string.Equals(value, "or", StringComparison.OrdinalIgnoreCase) ? "veya" : "ve";
}
private static bool IsBooleanField(string editorType, DbType dbType)
{
return editorType is PlatformConsts.EditorTypes.dxCheckBox or PlatformConsts.EditorTypes.dxSwitch ||
@ -635,12 +907,70 @@ internal static class DynamicReportImageHelper
private static string GetCustomFormat(string format)
{
return string.IsNullOrWhiteSpace(format) ? null : format;
if (string.IsNullOrWhiteSpace(format))
{
return null;
}
var customFormat = TryGetFormatOption(format, "displayFormat") ??
TryGetFormatOption(format, "format") ??
format.Trim();
return NormalizeDateTimeFormat(customFormat);
}
private static string GetEffectiveFormat(ListFormField field)
{
return TryGetFormatOption(field?.EditorOptions, "displayFormat") ??
TryGetFormatOption(field?.EditorOptions, "format") ??
field?.Format;
}
private static string TryGetFormatOption(string json, string propertyName)
{
if (string.IsNullOrWhiteSpace(json))
{
return null;
}
try
{
using var document = JsonDocument.Parse(json);
if (document.RootElement.ValueKind != JsonValueKind.Object ||
!TryGetLookupProperty(document.RootElement, propertyName, out var value))
{
return null;
}
return value.ValueKind == JsonValueKind.String ? value.GetString() : null;
}
catch (JsonException)
{
return null;
}
}
private static string NormalizeDateTimeFormat(string format)
{
if (string.IsNullOrWhiteSpace(format))
{
return null;
}
return format.Trim() switch
{
PlatformConsts.GridColumnOptions.ColumnValueFormatShortDate => "d",
PlatformConsts.GridColumnOptions.ColumnValueFormatShortTime => "t",
PlatformConsts.GridColumnOptions.ColumnValueFormatLongTime => "T",
PlatformConsts.GridColumnOptions.ColumnValueFormatShortDateShortTime => "g",
PlatformConsts.GridColumnOptions.ColumnValueFormatLongDateLongTime => "G",
_ => format.Trim()
};
}
private static bool IsDateField(DbType dbType)
{
return dbType is DbType.Date or DbType.DateTime or DbType.DateTime2 or DbType.DateTimeOffset;
return dbType is DbType.Date or DbType.DateTime or DbType.DateTime2 or DbType.DateTimeOffset or DbType.Time;
}
private static bool TryConvertToDateTime(object value, out DateTime date)
@ -653,6 +983,9 @@ internal static class DynamicReportImageHelper
case DateTimeOffset dateTimeOffset:
date = dateTimeOffset.LocalDateTime;
return true;
case TimeSpan timeSpan:
date = DateTime.Today.Add(timeSpan);
return true;
}
var text = Convert.ToString(value, CultureInfo.InvariantCulture);

View file

@ -60,7 +60,14 @@ internal static class DynamicReportSqlBuilder
}
var sourceAlias = QuoteSqlIdentifier(SourceAlias);
return $"SELECT {sourceAlias}.*, {string.Join(", ", lookupSelectParts)} FROM ({NormalizeSql(selectQuery)}) AS {sourceAlias}";
var normalizedSql = NormalizeSql(selectQuery);
var orderBy = ExtractOrderBy(normalizedSql);
if (!string.IsNullOrWhiteSpace(orderBy))
{
normalizedSql = OrderByRegex.Replace(normalizedSql, string.Empty).Trim();
}
return $"SELECT {sourceAlias}.*, {string.Join(", ", lookupSelectParts)} FROM ({normalizedSql}) AS {sourceAlias}{orderBy}";
}
private static string CreateLookupSelectPart(
@ -139,6 +146,12 @@ internal static class DynamicReportSqlBuilder
return sql.Trim().TrimEnd(';');
}
private static string ExtractOrderBy(string sql)
{
var match = OrderByRegex.Match(sql);
return match.Success ? " " + match.Value.Trim() : string.Empty;
}
private static string QuoteSqlIdentifier(string identifier)
{
return $"\"{identifier.Replace("\"", "\"\"")}\"";

View file

@ -19,6 +19,7 @@ using Sozsoft.Platform.Enums;
using Sozsoft.Platform.ListForms;
using Sozsoft.Platform.Localization;
using Sozsoft.Platform.Queries;
using Volo.Abp.Users;
namespace Sozsoft.Reports.PredefinedReports;
@ -73,6 +74,7 @@ public class DynamicTreeReport : XtraReport
var defaultValueHelper = scope.ServiceProvider.GetRequiredService<DefaultValueHelper>();
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<PlatformResource>>();
var configuration = scope.ServiceProvider.GetRequiredService<IConfiguration>();
var currentUser = scope.ServiceProvider.GetRequiredService<ICurrentUser>();
if (!await authManager.CanAccess(listFormCode))
{
@ -153,13 +155,18 @@ public class DynamicTreeReport : XtraReport
dataSourceType);
var imageBaseUrl = DynamicReportImageHelper.GetImageBaseUrl(configuration);
var criteriaText = DynamicReportImageHelper.BuildReportCriteriaText(
queryParams.Filter,
queryParams.Sort,
fields,
localizer);
var sourceRows = await ReadRowsAsync(dynamicDataRepository, selectQuery, connectionString);
var orderedRows = OrderTreeRows(sourceRows, treeOptions).ToList();
reportColumns = ApplyImageCounts(reportColumns, orderedRows, imageBaseUrl);
ConfigurePage(reportColumns);
ConfigureDataSource(orderedRows, reportColumns);
BuildLayout(listForm, reportColumns, localizer, imageBaseUrl);
BuildLayout(listForm, reportColumns, localizer, imageBaseUrl, currentUser.UserName, criteriaText);
RequestParameters = false;
}
@ -408,13 +415,15 @@ public class DynamicTreeReport : XtraReport
ListForm listForm,
IReadOnlyList<ReportColumn> fields,
IStringLocalizer<PlatformResource> localizer,
string imageBaseUrl)
string imageBaseUrl,
string currentUserName,
string criteriaText)
{
Bands.Clear();
var topMargin = new TopMarginBand { HeightF = Margins.Top };
var bottomMargin = new BottomMarginBand { HeightF = 32 };
var reportHeader = new ReportHeaderBand { HeightF = 32 };
var reportHeader = new ReportHeaderBand { HeightF = string.IsNullOrWhiteSpace(criteriaText) ? 32 : 50 };
var pageHeader = new PageHeaderBand { HeightF = 28 };
var detailHeight = fields.Any(x => x.IsImage)
? DynamicReportImageHelper.GetGridImageHeight()
@ -434,20 +443,16 @@ public class DynamicTreeReport : XtraReport
Font = new DXFont("Arial", 14F, DXFontStyle.Bold),
TextAlignment = TextAlignment.MiddleLeft
});
DynamicReportImageHelper.AddGeneratedAtToHeader(reportHeader.Controls, pageWidth);
DynamicReportImageHelper.AddReportCriteriaToHeader(reportHeader.Controls, criteriaText, pageWidth);
bottomMargin.Controls.Add(new XRPageInfo
{
PageInfo = PageInfo.DateTime,
TextFormatString = "{0:dd.MM.yyyy HH:mm}",
BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth / 2, 18),
Font = new DXFont("Arial", 7.5F),
TextAlignment = TextAlignment.MiddleLeft
});
DynamicReportImageHelper.AddFooterTopLine(bottomMargin.Controls, pageWidth);
DynamicReportImageHelper.AddCurrentUserNameToFooter(bottomMargin.Controls, currentUserName, pageWidth);
bottomMargin.Controls.Add(new XRPageInfo
{
TextFormatString = "Sayfa {0} / {1}",
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 0, pageWidth / 2, 18),
BoundsF = new System.Drawing.RectangleF(pageWidth / 2, 8, pageWidth / 2, 18),
Font = new DXFont("Arial", 8F),
TextAlignment = TextAlignment.MiddleRight
});

View file

@ -282,7 +282,7 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
var keyValue = pair.Split('=', 2);
if (keyValue.Length == 2 && !string.IsNullOrWhiteSpace(keyValue[0]))
{
parameters[keyValue[0]] = keyValue[1];
parameters[DecodeQueryComponent(keyValue[0])] = DecodeQueryComponent(keyValue[1]);
}
}
}
@ -375,6 +375,11 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
return decoded;
}
private static string DecodeQueryComponent(string value)
{
return DecodeRepeatedly(value ?? string.Empty);
}
public override Dictionary<string, string> GetUrls()
{
// Returns a dictionary that contains the report names (URLs) and display names.

View file

@ -22,6 +22,7 @@ import { ROUTES_ENUM } from '@/routes/route.constant'
import { GanttRef } from 'devextreme-react/cjs/gantt'
import { useStoreState } from '@/store'
import { MULTIVALUE_DELIMITER } from '@/constants/app.constant'
import { createReportQueryString } from '../report/reportRouteParams'
export interface ISelectBoxData {
value?: string
@ -208,7 +209,7 @@ const createDynamicListReportUrl = (
searchParams.set('sort', sort)
}
const queryString = searchParams.toString()
const queryString = createReportQueryString(searchParams)
return queryString ? `${reportUrl}?${queryString}` : reportUrl
}

View file

@ -58,30 +58,6 @@ const loadViewerCss = (isDarkMode: boolean) => {
if (themeLink.href !== themeHref) {
themeLink.href = themeHref
}
if (!document.getElementById(VIEWER_DARK_OVERRIDES_ID)) {
const style = document.createElement('style')
style.id = VIEWER_DARK_OVERRIDES_ID
style.textContent = `
.report-viewer-shell {
min-height: calc(100vh - 4rem);
}
.report-viewer-shell-dark {
background: #111827;
color: #e5e7eb;
}
.report-viewer-shell-dark .dxrd-preview,
.report-viewer-shell-dark .dxrd-preview-wrapper,
.report-viewer-shell-dark .dxrd-toolbar-wrapper,
.report-viewer-shell-dark .dxrd-right-panel,
.report-viewer-shell-dark .dxrd-search-wrapper {
background-color: #111827;
}
`
document.head.appendChild(style)
}
}
const DevexpressReportDesigner: React.FC = () => {

View file

@ -12,7 +12,7 @@ import { ZoomAutoBy } from 'devexpress-reporting/viewer/constants'
import { APP_NAME } from '@/constants/app.constant'
import { MODE_DARK } from '@/constants/theme.constant'
import { useStoreState } from '@/store'
import { createReportUrl } from './reportRouteParams'
import { createReportQueryString, createReportUrl } from './reportRouteParams'
const VIEWER_THEME_LINK_ID = 'devexpress-report-viewer-theme'
const VIEWER_DARK_OVERRIDES_ID = 'devexpress-report-viewer-dark-overrides'
@ -60,30 +60,6 @@ const loadViewerCss = (isDarkMode: boolean) => {
if (themeLink.href !== themeHref) {
themeLink.href = themeHref
}
if (!document.getElementById(VIEWER_DARK_OVERRIDES_ID)) {
const style = document.createElement('style')
style.id = VIEWER_DARK_OVERRIDES_ID
style.textContent = `
.report-viewer-shell {
min-height: calc(100vh - 4rem);
}
.report-viewer-shell-dark {
background: #111827;
color: #e5e7eb;
}
.report-viewer-shell-dark .dxrd-preview,
.report-viewer-shell-dark .dxrd-preview-wrapper,
.report-viewer-shell-dark .dxrd-toolbar-wrapper,
.report-viewer-shell-dark .dxrd-right-panel,
.report-viewer-shell-dark .dxrd-search-wrapper {
background-color: #111827;
}
`
document.head.appendChild(style)
}
}
const DevexpressReportViewer: React.FC = () => {
@ -177,7 +153,7 @@ const DevexpressReportViewer: React.FC = () => {
searchParams.set('cultureName', reportCultureName)
}
const search = searchParams.toString()
const search = createReportQueryString(searchParams)
return createReportUrl({ report, id, listFormCode }, search ? `?${search}` : '')
}, [report, id, listFormCode, location.search, reportCultureName])

View file

@ -30,6 +30,11 @@ export const normalizeReportRouteParams = ({
}
}
export const createReportQueryString = (searchParams: URLSearchParams) =>
Array.from(searchParams.entries())
.map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`)
.join('&')
export const createReportUrl = (
params: ReportRouteParams,
search: string,
@ -47,6 +52,6 @@ export const createReportUrl = (
if (listFormCode) pathSegments.push(listFormCode)
const path = pathSegments.map((segment) => encodeURIComponent(segment)).join('/')
const queryString = searchParams.toString()
const queryString = createReportQueryString(searchParams)
return queryString ? `${path}?${queryString}` : path
}