DynamicReport ve Seeder düzenlemesi

This commit is contained in:
Sedat Öztürk 2026-06-26 23:53:30 +03:00
parent 4f164f3289
commit 63951b8b7e
11 changed files with 388 additions and 71 deletions

View file

@ -5,6 +5,6 @@ public class MailQueueWorkerOptions
public string MailType { get; set; } // Template Tipi
public string MailSubject { get; set; } // Mail konusu
public string MailTemplate { get; set; } // Render edilecek html template
public string Tablo { get; set; } // Bu maildeki tablolar örn. {0:MT3_GECIKEN_SIPARIS:IN:Order Delay Notification:0:}
public string TableName { get; set; } // Bu maildeki tablolar örn. {0:MT3_GECIKEN_SIPARIS:IN:Order Delay Notification:0:}
}

View file

@ -296,10 +296,10 @@ public class ListFormWizardAppService(
KeyFieldDbSourceType = input.KeyFieldDbSourceType,
DefaultFilter = isDeleted ? WizardConsts.DefaultFilterJson : null,
SortMode = PlatformConsts.GridOptions.SortModeSingle,
FilterRowJson = WizardConsts.DefaultFilterRowJson,
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson,
SearchPanelJson = WizardConsts.DefaultSearchPanelJson,
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
FilterRowJson = WizardConsts.DefaultFilterRowJson(),
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? PlatformConsts.GridOptions.SelectionModeSingle : PlatformConsts.GridOptions.SelectionModeNone),
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
PermissionJson = WizardConsts.DefaultPermissionJson(code),

View file

@ -1146,7 +1146,7 @@
{
"name": "AI Save DbTableColumns",
"cron": "0 3 * * *",
"workerType": "BackupWorker",
"workerType": "SqlWorker",
"isActive": true,
"dataSourceCode": "Default",
"beforeSp": "Sas_H_ListFormFieldsDictionaryJson_SaveDbTableColumns"

View file

@ -1426,7 +1426,7 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),

View file

@ -1395,8 +1395,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -1509,7 +1509,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -1658,7 +1658,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -1748,7 +1748,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -1948,7 +1948,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -2084,7 +2084,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -2249,7 +2249,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -2556,8 +2556,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
SortMode = GridOptions.SortModeSingle,
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -2854,7 +2854,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -4577,7 +4577,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -5155,8 +5155,8 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
new() { Order=2,ColCount=2,ColSpan=1,ItemType="group",Items= [
new EditingFormItemDto { Order = 1, DataField = "Options:MailType", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 2, DataField = "Options:MailSubject", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 3, DataField = "Options:MailTemplate", ColSpan = 2, EditorType2=EditorTypes.dxTextArea, EditorOptions="{\"height\":200}" },
new EditingFormItemDto { Order = 4, DataField = "Options:Tablo", ColSpan = 2, EditorType2=EditorTypes.dxTextBox },
new EditingFormItemDto { Order = 3, DataField = "Options:MailTemplate", ColSpan = 2, EditorType2=EditorTypes.dxHtmlEditor, EditorOptions=EditorOptionValues.HtmlEditorOptions },
new EditingFormItemDto { Order = 4, DataField = "Options:TableName", ColSpan = 2, EditorType2=EditorTypes.dxTextBox },
]}
}),
InsertFieldsDefaultValueJson = DefaultInsertFieldsDefaultValueJson(),
@ -5521,7 +5521,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -5730,7 +5730,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -6370,7 +6370,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -6625,7 +6625,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -6760,7 +6760,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -6895,7 +6895,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),
@ -8151,7 +8151,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
FilterRowJson = DefaultFilterRowJson(),
HeaderFilterJson = DefaultHeaderFilterJson(),
SearchPanelJson = DefaultSearchPanelJson(),
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
GroupPanelJson = DefaultGroupPanelJson(),
SelectionJson = DefaultSelectionSingleJson,
ColumnOptionJson = DefaultColumnOptionJson(),
PermissionJson = DefaultPermissionJson(listFormName),

View file

@ -408,10 +408,10 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
KeyFieldDbSourceType = input.KeyFieldDbSourceType,
DefaultFilter = isDeleted ? WizardConsts.DefaultFilterJson : null,
SortMode = GridOptions.SortModeSingle,
FilterRowJson = WizardConsts.DefaultFilterRowJson,
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson,
SearchPanelJson = WizardConsts.DefaultSearchPanelJson,
GroupPanelJson = JsonSerializer.Serialize(new { Visible = false }),
FilterRowJson = WizardConsts.DefaultFilterRowJson(),
HeaderFilterJson = WizardConsts.DefaultHeaderFilterJson(),
SearchPanelJson = WizardConsts.DefaultSearchPanelJson(),
GroupPanelJson = WizardConsts.DefaultGroupPanelJson(),
SelectionJson = WizardConsts.DefaultSelectionSingleJson(input.WorkflowCriteria.Count > 0 ? GridOptions.SelectionModeSingle : GridOptions.SelectionModeNone),
ColumnOptionJson = WizardConsts.DefaultColumnOptionJson(),
PermissionJson = WizardConsts.DefaultPermissionJson(code),

View file

@ -96,10 +96,10 @@ public static class WizardConsts
});
public static readonly string DefaultFilterJson = "\"IsDeleted\" = 'false'";
public static readonly string DefaultFilterRowJson = JsonSerializer.Serialize(new { Visible = true });
public static readonly string DefaultHeaderFilterJson = JsonSerializer.Serialize(new { Visible = true });
public static readonly string DefaultSearchPanelJson = JsonSerializer.Serialize(new { Visible = true });
public static readonly string DefaultGroupPanelJson = JsonSerializer.Serialize(new { Visible = true });
public static string DefaultFilterRowJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible });
public static string DefaultHeaderFilterJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible });
public static string DefaultSearchPanelJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible });
public static string DefaultGroupPanelJson(bool visible = true) => JsonSerializer.Serialize(new { Visible = visible });
public static string DefaultSelectionSingleJson(string Mode = "none") => JsonSerializer.Serialize(new
{
@ -212,7 +212,7 @@ public static class WizardConsts
new { FieldName = "Id", FieldDbType = dbType, Value = "@NEWID", CustomValueType = FieldCustomValueTypeEnum.CustomKey }
});
}
public static readonly string DefaultPagerOptionJson = JsonSerializer.Serialize(new
{
Visible = true,

View file

@ -301,7 +301,8 @@ public class DynamicGridReport : XtraReport
var headerTable = CreateTable(pageWidth, 28);
var headerRow = new XRTableRow { HeightF = 28 };
var detailTable = CreateTable(pageWidth, detailHeight);
var detailRow = new XRTableRow { HeightF = detailHeight };
detailTable.CanGrow = true;
var detailRow = new XRTableRow { HeightF = detailHeight, CanGrow = true };
var footerTable = CreateTable(pageWidth, 24);
var footerRow = new XRTableRow { HeightF = 24 };
@ -355,7 +356,11 @@ public class DynamicGridReport : XtraReport
};
}
private static XRTableCell CreateDetailCell(ReportColumn column, float width, string imageBaseUrl, float height)
private static XRTableCell CreateDetailCell(
ReportColumn column,
float width,
string imageBaseUrl,
float height)
{
var field = column.Field;
if (column.IsImage)
@ -380,8 +385,8 @@ public class DynamicGridReport : XtraReport
Font = new DXFont("Segoe UI Emoji", 8F),
Padding = new PaddingInfo(4, 4, 2, 2),
TextAlignment = DynamicReportImageHelper.ToTextAlignment(field.Alignment, field.SourceDbType),
Multiline = false,
CanGrow = false
Multiline = true,
CanGrow = true
};
cell.ExpressionBindings.Add(new ExpressionBinding(
"BeforePrint",
@ -391,14 +396,17 @@ public class DynamicGridReport : XtraReport
return cell;
}
private static XRTableCell CreateHtmlDetailCell(ReportColumn column, float width, float height)
private static XRTableCell CreateHtmlDetailCell(
ReportColumn column,
float width,
float height)
{
var cell = new XRTableCell
{
WidthF = width,
Weight = width,
Padding = new PaddingInfo(0, 0, 0, 0),
CanGrow = false
CanGrow = true
};
var richText = new XRRichText
@ -406,7 +414,7 @@ public class DynamicGridReport : XtraReport
BoundsF = new System.Drawing.RectangleF(0, 0, width, height),
Font = new DXFont("Arial", 8F),
Padding = new PaddingInfo(4, 4, 2, 2),
CanGrow = false
CanGrow = true
};
richText.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Html", $"[{column.BindingName}]"));
cell.Controls.Add(richText);

View file

@ -618,7 +618,9 @@ internal static class DynamicReportImageHelper
return true;
}
return TryFormatDateValue(dbType, format, value, out text) ||
var formatOptions = ReportFormatOptions.Parse(format);
return TryFormatNamedTextValue(formatOptions, value, out text) ||
TryFormatDateValue(dbType, formatOptions, value, out text) ||
TryFormatNumericValue(dbType, format, value, out text);
}
@ -638,7 +640,11 @@ internal static class DynamicReportImageHelper
return false;
}
private static bool TryFormatDateValue(DbType dbType, string format, object value, out string text)
private static bool TryFormatDateValue(
DbType dbType,
ReportFormatOptions formatOptions,
object value,
out string text)
{
text = null;
if (!IsDateField(dbType) || !TryConvertToDateTime(value, out var date))
@ -647,7 +653,12 @@ internal static class DynamicReportImageHelper
}
var culture = CultureInfo.CurrentCulture;
var customFormat = GetCustomFormat(format);
if (TryFormatDevExtremeDateValue(date, formatOptions.Type, culture, out text))
{
return true;
}
var customFormat = NormalizeDateTimeFormat(formatOptions.CustomFormat);
if (!string.IsNullOrWhiteSpace(customFormat))
{
try
@ -675,7 +686,13 @@ internal static class DynamicReportImageHelper
}
var culture = CultureInfo.CurrentCulture;
var customFormat = GetCustomFormat(format);
var formatOptions = ReportFormatOptions.Parse(format);
if (TryFormatDevExtremeNumericValue(number, formatOptions, culture, out text))
{
return true;
}
var customFormat = formatOptions.CustomFormat;
if (!string.IsNullOrWhiteSpace(customFormat))
{
try
@ -692,6 +709,185 @@ internal static class DynamicReportImageHelper
return true;
}
private static bool TryFormatNamedTextValue(
ReportFormatOptions formatOptions,
object value,
out string text)
{
text = null;
if (!string.Equals(formatOptions.Type, "phoneGlobal", StringComparison.OrdinalIgnoreCase))
{
return false;
}
var digits = Regex.Replace(
Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty,
@"\D",
string.Empty);
if (digits.StartsWith("90", StringComparison.Ordinal) && digits.Length > 10)
{
digits = digits[^10..];
}
if (digits.StartsWith("0", StringComparison.Ordinal) && digits.Length > 10)
{
digits = digits[^10..];
}
if (digits.Length > 10)
{
digits = digits[^10..];
}
text = digits.Length == 10
? $"({digits[..3]}) {digits.Substring(3, 3)}-{digits[6..]}"
: Convert.ToString(value, CultureInfo.CurrentCulture) ?? string.Empty;
return true;
}
private static bool TryFormatDevExtremeDateValue(
DateTime date,
string formatType,
CultureInfo culture,
out string text)
{
text = null;
switch (formatType)
{
case PlatformConsts.GridColumnOptions.ColumnValueFormatShortDate:
text = date.ToString(culture.DateTimeFormat.ShortDatePattern, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatLongDate:
text = date.ToString(culture.DateTimeFormat.LongDatePattern, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatShortTime:
text = date.ToString(culture.DateTimeFormat.ShortTimePattern, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatLongTime:
text = date.ToString(culture.DateTimeFormat.LongTimePattern, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatShortDateShortTime:
text = date.ToString("g", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatLongDateLongTime:
text = date.ToString("G", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndDay:
text = date.ToString("M", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndYear:
text = date.ToString("Y", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatYear:
text = date.ToString("yyyy", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMonth:
text = date.ToString("MMMM", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatDay:
text = date.ToString("dd", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatDayOfWeek:
text = date.ToString("dddd", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatQuarter:
text = GetQuarter(date).ToString(culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatQuarterAndYear:
text = $"Q{GetQuarter(date)} {date:yyyy}";
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatHour:
text = date.ToString("%H", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMinute:
text = date.ToString("%m", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatSecond:
text = date.ToString("%s", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMillisecond:
text = date.Millisecond.ToString(culture);
return true;
default:
return false;
}
}
private static bool TryFormatDevExtremeNumericValue(
decimal number,
ReportFormatOptions formatOptions,
CultureInfo culture,
out string text)
{
text = null;
var precision = formatOptions.Precision;
switch (formatOptions.Type)
{
case PlatformConsts.GridColumnOptions.ColumnValueFormatFixedPoint:
case PlatformConsts.GridColumnOptions.ColumnValueFormatDecimal:
text = number.ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatCurrency:
text = number.ToString(precision.HasValue ? $"C{precision.Value}" : "C", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatPercent:
text = number.ToString(precision.HasValue ? $"P{precision.Value}" : "P", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatExponential:
text = number.ToString(precision.HasValue ? $"E{precision.Value}" : "E", culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatThousands:
text = FormatScaledNumber(number, 1_000M, "K", precision, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatMillions:
text = FormatScaledNumber(number, 1_000_000M, "M", precision, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatBillions:
text = FormatScaledNumber(number, 1_000_000_000M, "B", precision, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatTrillions:
text = FormatScaledNumber(number, 1_000_000_000_000M, "T", precision, culture);
return true;
case PlatformConsts.GridColumnOptions.ColumnValueFormatLargeNumber:
text = FormatLargeNumber(number, precision, culture);
return true;
default:
return false;
}
}
private static string FormatLargeNumber(decimal number, int? precision, CultureInfo culture)
{
var absolute = Math.Abs(number);
if (absolute >= 1_000_000_000_000M)
{
return FormatScaledNumber(number, 1_000_000_000_000M, "T", precision, culture);
}
if (absolute >= 1_000_000_000M)
{
return FormatScaledNumber(number, 1_000_000_000M, "B", precision, culture);
}
if (absolute >= 1_000_000M)
{
return FormatScaledNumber(number, 1_000_000M, "M", precision, culture);
}
if (absolute >= 1_000M)
{
return FormatScaledNumber(number, 1_000M, "K", precision, culture);
}
return number.ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture);
}
private static string FormatScaledNumber(
decimal number,
decimal scale,
string suffix,
int? precision,
CultureInfo culture)
{
return (number / scale).ToString(precision.HasValue ? $"N{precision.Value}" : "N", culture) + suffix;
}
private static bool TryFormatBoolean(string value, out string text)
{
if (bool.TryParse(value, out var boolean))
@ -716,6 +912,8 @@ internal static class DynamicReportImageHelper
return false;
}
private static int GetQuarter(DateTime date) => ((date.Month - 1) / 3) + 1;
private static string FormatBoolean(bool value)
{
return CultureInfo.CurrentCulture.TwoLetterISOLanguageName.Equals("tr", StringComparison.OrdinalIgnoreCase)
@ -950,7 +1148,12 @@ internal static class DynamicReportImageHelper
return null;
}
return value.ValueKind == JsonValueKind.String ? value.GetString() : null;
return value.ValueKind switch
{
JsonValueKind.String => value.GetString(),
JsonValueKind.Object => value.GetRawText(),
_ => null
};
}
catch (JsonException)
{
@ -976,6 +1179,110 @@ internal static class DynamicReportImageHelper
};
}
private sealed class ReportFormatOptions
{
public string Type { get; private init; }
public string CustomFormat { get; private init; }
public int? Precision { get; private init; }
public static ReportFormatOptions Parse(string format)
{
if (string.IsNullOrWhiteSpace(format))
{
return new ReportFormatOptions();
}
var trimmed = format.Trim();
if (!trimmed.StartsWith("{", StringComparison.Ordinal))
{
var normalized = NormalizeDateTimeFormat(trimmed);
return new ReportFormatOptions
{
Type = trimmed,
CustomFormat = normalized == trimmed && IsKnownDevExtremeFormat(trimmed) ? null : normalized
};
}
try
{
using var document = JsonDocument.Parse(trimmed);
if (document.RootElement.ValueKind != JsonValueKind.Object)
{
return new ReportFormatOptions();
}
var type = GetJsonString(document.RootElement, "type");
var formatter = GetJsonString(document.RootElement, "formatter");
var customFormat =
GetJsonString(document.RootElement, "displayFormat") ??
GetJsonString(document.RootElement, "format") ??
GetJsonString(document.RootElement, "formatString");
return new ReportFormatOptions
{
Type = type ?? customFormat,
CustomFormat = NormalizeDateTimeFormat(formatter ?? customFormat),
Precision = GetJsonInt(document.RootElement, "precision")
};
}
catch (JsonException)
{
return new ReportFormatOptions();
}
}
private static string GetJsonString(JsonElement element, string propertyName)
{
return TryGetLookupProperty(element, propertyName, out var value) &&
value.ValueKind == JsonValueKind.String
? value.GetString()
: null;
}
private static int? GetJsonInt(JsonElement element, string propertyName)
{
return TryGetLookupProperty(element, propertyName, out var value) &&
value.ValueKind == JsonValueKind.Number &&
value.TryGetInt32(out var number)
? Math.Clamp(number, 0, 15)
: null;
}
}
private static bool IsKnownDevExtremeFormat(string format)
{
return format is
PlatformConsts.GridColumnOptions.ColumnValueFormatBillions or
PlatformConsts.GridColumnOptions.ColumnValueFormatCurrency or
PlatformConsts.GridColumnOptions.ColumnValueFormatDay or
PlatformConsts.GridColumnOptions.ColumnValueFormatDecimal or
PlatformConsts.GridColumnOptions.ColumnValueFormatExponential or
PlatformConsts.GridColumnOptions.ColumnValueFormatFixedPoint or
PlatformConsts.GridColumnOptions.ColumnValueFormatLargeNumber or
PlatformConsts.GridColumnOptions.ColumnValueFormatLongDate or
PlatformConsts.GridColumnOptions.ColumnValueFormatLongTime or
PlatformConsts.GridColumnOptions.ColumnValueFormatMillions or
PlatformConsts.GridColumnOptions.ColumnValueFormatMillisecond or
PlatformConsts.GridColumnOptions.ColumnValueFormatMonth or
PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndDay or
PlatformConsts.GridColumnOptions.ColumnValueFormatMonthAndYear or
PlatformConsts.GridColumnOptions.ColumnValueFormatPercent or
PlatformConsts.GridColumnOptions.ColumnValueFormatQuarter or
PlatformConsts.GridColumnOptions.ColumnValueFormatQuarterAndYear or
PlatformConsts.GridColumnOptions.ColumnValueFormatShortDate or
PlatformConsts.GridColumnOptions.ColumnValueFormatShortTime or
PlatformConsts.GridColumnOptions.ColumnValueFormatThousands or
PlatformConsts.GridColumnOptions.ColumnValueFormatTrillions or
PlatformConsts.GridColumnOptions.ColumnValueFormatYear or
PlatformConsts.GridColumnOptions.ColumnValueFormatDayOfWeek or
PlatformConsts.GridColumnOptions.ColumnValueFormatHour or
PlatformConsts.GridColumnOptions.ColumnValueFormatLongDateLongTime or
PlatformConsts.GridColumnOptions.ColumnValueFormatMinute or
PlatformConsts.GridColumnOptions.ColumnValueFormatSecond or
PlatformConsts.GridColumnOptions.ColumnValueFormatShortDateShortTime or
"phoneGlobal";
}
private static bool IsDateField(DbType dbType)
{
return dbType is DbType.Date or DbType.DateTime or DbType.DateTime2 or DbType.DateTimeOffset or DbType.Time;

View file

@ -466,7 +466,8 @@ public class DynamicTreeReport : XtraReport
var headerTable = CreateTable(pageWidth, 28);
var headerRow = new XRTableRow { HeightF = 28 };
var detailTable = CreateTable(pageWidth, detailHeight);
var detailRow = new XRTableRow { HeightF = detailHeight };
detailTable.CanGrow = true;
var detailRow = new XRTableRow { HeightF = detailHeight, CanGrow = true };
var footerTable = CreateTable(pageWidth, 24);
var footerRow = new XRTableRow { HeightF = 24 };
@ -550,8 +551,8 @@ public class DynamicTreeReport : XtraReport
TextAlignment = isTreeColumn
? TextAlignment.MiddleLeft
: DynamicReportImageHelper.ToTextAlignment(column.Field.Alignment, column.Field.SourceDbType),
Multiline = false,
CanGrow = false
Multiline = true,
CanGrow = true
};
var valueExpression = DynamicReportImageHelper.CreateFormatValueExpression($"[{column.BindingName}]", column.Field, column.EditorType);
@ -573,14 +574,17 @@ public class DynamicTreeReport : XtraReport
return cell;
}
private static XRTableCell CreateHtmlDetailCell(ReportColumn column, float width, float height)
private static XRTableCell CreateHtmlDetailCell(
ReportColumn column,
float width,
float height)
{
var cell = new XRTableCell
{
WidthF = width,
Weight = width,
Padding = new PaddingInfo(0, 0, 0, 0),
CanGrow = false
CanGrow = true
};
var richText = new XRRichText
@ -588,7 +592,7 @@ public class DynamicTreeReport : XtraReport
BoundsF = new System.Drawing.RectangleF(0, 0, width, height),
Font = new DXFont("Arial", 8F),
Padding = new PaddingInfo(4, 4, 2, 2),
CanGrow = false
CanGrow = true
};
richText.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Html", $"[{column.BindingName}]"));
cell.Controls.Add(richText);

View file

@ -99,21 +99,22 @@ const DevexpressReportViewer: React.FC = () => {
return candidates.find(
(candidate) =>
candidate &&
('zoom' in candidate ||
'originalZoom' in candidate ||
'autoFitBy' in candidate),
('zoom' in candidate || 'originalZoom' in candidate || 'autoFitBy' in candidate),
)
}, [])
const setDefaultZoom = useCallback((eventOrModel?: any) => {
const preview = getReportPreview(eventOrModel)
if (!preview) return
const setDefaultZoom = useCallback(
(eventOrModel?: any) => {
const preview = getReportPreview(eventOrModel)
if (!preview) return
previewModelRef.current = preview
preview.autoFitBy = ZoomAutoBy.None
preview.originalZoom = DEFAULT_REPORT_ZOOM
preview.zoom = DEFAULT_REPORT_ZOOM
}, [getReportPreview])
previewModelRef.current = preview
preview.autoFitBy = ZoomAutoBy.None
preview.originalZoom = DEFAULT_REPORT_ZOOM
preview.zoom = DEFAULT_REPORT_ZOOM
},
[getReportPreview],
)
useEffect(() => {
loadViewerCss(isDarkMode)
@ -168,15 +169,12 @@ const DevexpressReportViewer: React.FC = () => {
/>
{isRequestAuthReady && (
<ReportViewer reportUrl={reportUrlWithParams}>
<ReportViewer key={reportUrlWithParams} reportUrl={reportUrlWithParams}>
<Callbacks
BeforeRender={setDefaultZoom}
DocumentReady={setDefaultZoom}
/>
<RequestOptions
host={import.meta.env.VITE_API_URL}
invokeAction="/DXXRDV"
/>
<RequestOptions host={import.meta.env.VITE_API_URL} invokeAction="/DXXRDV" />
</ReportViewer>
)}
</Container>