DynamicForm, DynamicList ve DynamicReport güncellemesi
This commit is contained in:
parent
ec438afab5
commit
fdf48c04ee
14 changed files with 947 additions and 436 deletions
|
|
@ -1584,28 +1584,37 @@ public class ListFormSeeder_Administration : IDataSeedContributor, ITransientDep
|
||||||
Text ="App.Platform.View",
|
Text ="App.Platform.View",
|
||||||
UrlTarget="_blank",
|
UrlTarget="_blank",
|
||||||
AuthName = listFormName,
|
AuthName = listFormName,
|
||||||
Url=$"/admin/reports/TemplateReport/view?id=@Id",
|
Url=$"/admin/reports/DynamicReport/view?id=@Id",
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
|
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Raporlar')"
|
||||||
},
|
},
|
||||||
new() {
|
new() {
|
||||||
Hint = "App.Platform.Design",
|
Hint = "App.Platform.Design",
|
||||||
Text ="App.Platform.Design",
|
Text ="App.Platform.Design",
|
||||||
UrlTarget="_blank",
|
UrlTarget="_blank",
|
||||||
AuthName = listFormName + ".Update",
|
AuthName = listFormName + ".Update",
|
||||||
Url=$"/admin/reports/TemplateReport/design?id=@Id",
|
Url=$"/admin/reports/DynamicReport/design?id=@Id",
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
VisibleExpression = "((e)=> e.row.data.CategoryId !== 'Listeler')"
|
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Raporlar')"
|
||||||
},
|
},
|
||||||
new() {
|
new() {
|
||||||
Hint = "App.Platform.View",
|
Hint = "App.Platform.View",
|
||||||
Text ="App.Platform.View",
|
Text ="App.Platform.View",
|
||||||
UrlTarget="_blank",
|
UrlTarget="_blank",
|
||||||
AuthName = listFormName,
|
AuthName = listFormName,
|
||||||
Url=$"/admin/reports/DynamicListFormReport/view?listFormCode=@Name",
|
Url=$"/admin/reports/DynamicGrid/view?listFormCode=@Name",
|
||||||
IsVisible = true,
|
IsVisible = true,
|
||||||
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Listeler')"
|
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Listeler')"
|
||||||
},
|
},
|
||||||
|
new() {
|
||||||
|
Hint = "App.Platform.View",
|
||||||
|
Text ="App.Platform.View",
|
||||||
|
UrlTarget="_blank",
|
||||||
|
AuthName = listFormName,
|
||||||
|
Url=$"/admin/reports/DynamicGrid/view?listFormCode=@Name&id=@Id",
|
||||||
|
IsVisible = true,
|
||||||
|
VisibleExpression = "((e)=> e.row.data.CategoryId === 'Formlar')"
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -3599,7 +3599,7 @@ public class ListFormSeeder_Saas : IDataSeedContributor, ITransientDependency
|
||||||
EditingOptionJson = DefaultEditingOptionJson(listFormName, 600, 450, true, true, true, true, false, true),
|
EditingOptionJson = DefaultEditingOptionJson(listFormName, 600, 450, true, true, true, true, false, true),
|
||||||
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
|
EditingFormJson = JsonSerializer.Serialize(new List<EditingFormDto>() {
|
||||||
new() {
|
new() {
|
||||||
Order=1, ColCount=1, ColSpan=1, ItemType="group", Items= [
|
Order=1, ColCount=2, ColSpan=1, ItemType="group", Items= [
|
||||||
new EditingFormItemDto { Order = 1, DataField = "CultureName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order = 1, DataField = "CultureName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
||||||
new EditingFormItemDto { Order = 2, DataField = "UiCultureName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order = 2, DataField = "UiCultureName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
||||||
new EditingFormItemDto { Order = 3, DataField = "DisplayName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
new EditingFormItemDto { Order = 3, DataField = "DisplayName", ColSpan = 1, EditorType2=EditorTypes.dxTextBox },
|
||||||
|
|
|
||||||
|
|
@ -417,7 +417,7 @@
|
||||||
"authority": ["App.Files"]
|
"authority": ["App.Files"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "admin.devexpressReportView",
|
"key": "admin.devexpressDynamicReportView",
|
||||||
"path": "/admin/reports/:id/view",
|
"path": "/admin/reports/:id/view",
|
||||||
"componentType": "normal",
|
"componentType": "normal",
|
||||||
"componentPath": "@/views/report/DevexpressReportViewer",
|
"componentPath": "@/views/report/DevexpressReportViewer",
|
||||||
|
|
@ -425,7 +425,7 @@
|
||||||
"authority": []
|
"authority": []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"key": "admin.devexpressReportDesigner",
|
"key": "admin.devexpressDynamicReportDesigner",
|
||||||
"path": "/admin/reports/:id/design",
|
"path": "/admin/reports/:id/design",
|
||||||
"componentType": "normal",
|
"componentType": "normal",
|
||||||
"componentPath": "@/views/report/DevexpressReportDesigner",
|
"componentPath": "@/views/report/DevexpressReportDesigner",
|
||||||
|
|
|
||||||
|
|
@ -1362,11 +1362,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"ReportCategories": [
|
"ReportCategories": [
|
||||||
{
|
|
||||||
"name": "Taahhütnameler",
|
|
||||||
"description": "Kursiyeler ile ilgili taahhütname raporları",
|
|
||||||
"icon": "✍️"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "Raporlar",
|
"name": "Raporlar",
|
||||||
"description": "Şirket içi genel tüm raporlar",
|
"description": "Şirket içi genel tüm raporlar",
|
||||||
|
|
@ -1387,15 +1382,22 @@
|
||||||
{
|
{
|
||||||
"name": "Standard Taahhütname",
|
"name": "Standard Taahhütname",
|
||||||
"description": "Standard Taahhütname",
|
"description": "Standard Taahhütname",
|
||||||
"categoryName": "Taahhütnameler",
|
"categoryName": "Raporlar",
|
||||||
"htmlContent": "<h1>Taahhütname</h1><p>Bu belge, tarafların belirli yükümlülüklerini ve taahhütlerini belirtir.</p>",
|
"htmlContent": "<h1>Taahhütname</h1><p>http://localhost:3000/admin/reports/DynamicReport/view?id=ede12de7-0e94-4b84-a953-6c359606478b</p>",
|
||||||
"status": "active"
|
"status": "active"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "App.Definitions.AiBot",
|
"name": "App.Languages.LanguageText",
|
||||||
"description": "Liste Raporları",
|
"description": "Liste Raporları",
|
||||||
"categoryName": "Listeler",
|
"categoryName": "Listeler",
|
||||||
"htmlContent": "<h1>Liste Raporları.</h1><p>http://localhost:3000/admin/reports/DynamicListFormReport/view?listFormCode=App.Languages.LanguageText&filter=[%22CultureName%22,%22=%22,%22en%22]</p>",
|
"htmlContent": "<h1>Liste Raporları.</h1><p>http://localhost:3000/admin/reports/DynamicGridReport/view?listFormCode=App.Languages.LanguageText&filter=[%22CultureName%22,%22=%22,%22en%22]</p>",
|
||||||
|
"status": "active"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "App.Languages.Language",
|
||||||
|
"description": "Form Raporları",
|
||||||
|
"categoryName": "Formlar",
|
||||||
|
"htmlContent": "<h1>Liste Raporları.</h1><p>http://localhost:3000/admin/reports/DynamicFormReport/view?listFormCode=App.Languages.Language&id=e2c8a2e0-af22-f7bb-5d88-3a21e3079997</p>",
|
||||||
"status": "active"
|
"status": "active"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,849 @@
|
||||||
|
using System;
|
||||||
|
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;
|
||||||
|
using DevExpress.Drawing;
|
||||||
|
using DevExpress.XtraPrinting;
|
||||||
|
using DevExpress.XtraReports.UI;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.Localization;
|
||||||
|
using Sozsoft.Platform;
|
||||||
|
using Sozsoft.Platform.DynamicData;
|
||||||
|
using Sozsoft.Platform.Entities;
|
||||||
|
using Sozsoft.Platform.Enums;
|
||||||
|
using Sozsoft.Platform.ListForms;
|
||||||
|
using Sozsoft.Platform.Localization;
|
||||||
|
using Sozsoft.Platform.Queries;
|
||||||
|
|
||||||
|
namespace Sozsoft.Reports.PredefinedReports;
|
||||||
|
|
||||||
|
public class DynamicFormReport : XtraReport
|
||||||
|
{
|
||||||
|
public const string ReportName = nameof(DynamicFormReport);
|
||||||
|
private const string QueryName = "DynamicForm";
|
||||||
|
private const int HorizontalMargin = 35;
|
||||||
|
private const float RowHeight = 24;
|
||||||
|
private static IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
|
public static void SetServiceProvider(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
_serviceProvider = serviceProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DynamicFormReport Create(IDictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
var report = new DynamicFormReport();
|
||||||
|
report.Build(parameters);
|
||||||
|
return report;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DynamicFormReport()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Build(IDictionary<string, string> parameters)
|
||||||
|
{
|
||||||
|
if (_serviceProvider == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("DynamicFormReport service provider is not configured.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parameters.TryGetValue("listFormCode", out var listFormCode) || string.IsNullOrWhiteSpace(listFormCode))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("listFormCode parameter is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!parameters.TryGetValue("id", out var id) || string.IsNullOrWhiteSpace(id))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("id parameter is required.");
|
||||||
|
}
|
||||||
|
|
||||||
|
using var scope = _serviceProvider.CreateScope();
|
||||||
|
var authManager = scope.ServiceProvider.GetRequiredService<IListFormAuthorizationManager>();
|
||||||
|
var listFormManager = scope.ServiceProvider.GetRequiredService<IListFormManager>();
|
||||||
|
var listFormFieldManager = scope.ServiceProvider.GetRequiredService<IListFormFieldManager>();
|
||||||
|
var customizationManager = scope.ServiceProvider.GetRequiredService<IListFormCustomizationManager>();
|
||||||
|
var dynamicDataManager = scope.ServiceProvider.GetRequiredService<IDynamicDataManager>();
|
||||||
|
var selectQueryManager = scope.ServiceProvider.GetRequiredService<ISelectQueryManager>();
|
||||||
|
var defaultValueHelper = scope.ServiceProvider.GetRequiredService<DefaultValueHelper>();
|
||||||
|
var localizer = scope.ServiceProvider.GetRequiredService<IStringLocalizer<PlatformResource>>();
|
||||||
|
|
||||||
|
if (!authManager.CanAccess(listFormCode).GetAwaiter().GetResult())
|
||||||
|
{
|
||||||
|
throw new UnauthorizedAccessException($"No read permission for list form '{listFormCode}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
var listForm = listFormManager.GetUserListForm(listFormCode).GetAwaiter().GetResult();
|
||||||
|
var fields = listFormFieldManager.GetUserListFormFields(listFormCode).GetAwaiter().GetResult()
|
||||||
|
.Where(x => x.CanRead)
|
||||||
|
.OrderBy(x => x.ListOrderNo ?? int.MaxValue)
|
||||||
|
.ThenBy(x => x.CaptionName)
|
||||||
|
.ToList();
|
||||||
|
var customizations = customizationManager.GetUsersServerCustomizations(listFormCode).GetAwaiter().GetResult();
|
||||||
|
var (dynamicDataRepository, connectionString, dataSourceType) = dynamicDataManager
|
||||||
|
.GetAsync(listForm.IsTenant, listForm.DataSourceCode)
|
||||||
|
.GetAwaiter()
|
||||||
|
.GetResult();
|
||||||
|
|
||||||
|
var queryParams = new QueryParameters
|
||||||
|
{
|
||||||
|
ListFormCode = listFormCode,
|
||||||
|
Filter = GetParameter(parameters, "filter") ?? CreateKeyFilter(listForm.KeyFieldName, id),
|
||||||
|
Take = 1,
|
||||||
|
Skip = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
selectQueryManager.PrepareQueries(listForm, fields, dataSourceType, customizations, queryParams);
|
||||||
|
|
||||||
|
var reportFields = GetReportFields(listForm, fields, selectQueryManager, defaultValueHelper);
|
||||||
|
var selectQuery = ApplyLookupQueryColumns(
|
||||||
|
selectQueryManager.SelectQuery,
|
||||||
|
listForm,
|
||||||
|
reportFields,
|
||||||
|
defaultValueHelper);
|
||||||
|
selectQuery = ApplyQueryParameters(selectQuery, selectQueryManager.SelectQueryParameters);
|
||||||
|
|
||||||
|
var row = GetFirstRow(dynamicDataRepository.QueryAsync(selectQuery, connectionString).GetAwaiter().GetResult());
|
||||||
|
|
||||||
|
ConfigurePage();
|
||||||
|
ConfigureDataSource(selectQuery, connectionString, dataSourceType);
|
||||||
|
BuildLayout(listForm, reportFields, row, localizer);
|
||||||
|
RequestParameters = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigurePage()
|
||||||
|
{
|
||||||
|
Margins = new System.Drawing.Printing.Margins(HorizontalMargin, HorizontalMargin, 35, 35);
|
||||||
|
PaperKind = DevExpress.Drawing.Printing.DXPaperKind.A4;
|
||||||
|
Landscape = false;
|
||||||
|
Font = new DXFont("Arial", 8.25F);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConfigureDataSource(string selectQuery, string connectionString, DataSourceTypeEnum dataSourceType)
|
||||||
|
{
|
||||||
|
var dataSource = new SqlDataSource(new CustomStringConnectionParameters(ToDevExpressConnectionString(connectionString, dataSourceType)));
|
||||||
|
dataSource.Queries.Add(new CustomSqlQuery(QueryName, selectQuery));
|
||||||
|
ComponentStorage.Add(dataSource);
|
||||||
|
DataSource = dataSource;
|
||||||
|
DataMember = QueryName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BuildLayout(
|
||||||
|
ListForm listForm,
|
||||||
|
IReadOnlyList<FormReportField> fields,
|
||||||
|
IDictionary<string, object> row,
|
||||||
|
IStringLocalizer<PlatformResource> localizer)
|
||||||
|
{
|
||||||
|
Bands.Clear();
|
||||||
|
|
||||||
|
var topMargin = new TopMarginBand { HeightF = Margins.Top };
|
||||||
|
var bottomMargin = new BottomMarginBand { HeightF = 32 };
|
||||||
|
var reportHeader = new ReportHeaderBand { HeightF = 38 };
|
||||||
|
var detail = new DetailBand { HeightF = CalculateDetailHeight(fields, listForm, row) };
|
||||||
|
|
||||||
|
Bands.AddRange([topMargin, reportHeader, detail, bottomMargin]);
|
||||||
|
|
||||||
|
var pageWidth = PageWidth - Margins.Left - Margins.Right;
|
||||||
|
reportHeader.Controls.Add(new XRLabel
|
||||||
|
{
|
||||||
|
Text = GetLocalizedReportTitle(listForm, localizer),
|
||||||
|
BoundsF = new System.Drawing.RectangleF(0, 0, pageWidth, 30),
|
||||||
|
Font = new DXFont("Arial", 14F, DXFontStyle.Bold),
|
||||||
|
TextAlignment = TextAlignment.MiddleLeft
|
||||||
|
});
|
||||||
|
|
||||||
|
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),
|
||||||
|
Font = new DXFont("Arial", 8F),
|
||||||
|
TextAlignment = TextAlignment.MiddleRight
|
||||||
|
});
|
||||||
|
|
||||||
|
var y = 0F;
|
||||||
|
foreach (var group in GetFormGroups(listForm, fields))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(group.Caption))
|
||||||
|
{
|
||||||
|
detail.Controls.Add(new XRLabel
|
||||||
|
{
|
||||||
|
Text = Localize(localizer, group.Caption, group.Caption),
|
||||||
|
BoundsF = new System.Drawing.RectangleF(0, y, pageWidth, 22),
|
||||||
|
Font = new DXFont("Arial", 9F, DXFontStyle.Bold),
|
||||||
|
BackColor = System.Drawing.Color.FromArgb(238, 242, 247),
|
||||||
|
Padding = new PaddingInfo(5, 5, 2, 2),
|
||||||
|
TextAlignment = TextAlignment.MiddleLeft
|
||||||
|
});
|
||||||
|
y += 26;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var field in group.Fields)
|
||||||
|
{
|
||||||
|
var rowHeight = GetFieldRowHeight(field);
|
||||||
|
var labelWidth = pageWidth * 0.28F;
|
||||||
|
detail.Controls.Add(CreateCaptionLabel(field, localizer, 0, y, labelWidth, rowHeight));
|
||||||
|
detail.Controls.Add(CreateValueLabel(field, labelWidth, y, pageWidth - labelWidth, rowHeight));
|
||||||
|
y += rowHeight + 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
y += 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var subForm in GetListSubForms(listForm, row))
|
||||||
|
{
|
||||||
|
detail.Controls.Add(new XRSubreport
|
||||||
|
{
|
||||||
|
BoundsF = new System.Drawing.RectangleF(0, y, pageWidth, 24),
|
||||||
|
ReportSource = DynamicGridReport.Create(CreateSubReportParameters(subForm.Form, subForm.Filter))
|
||||||
|
});
|
||||||
|
y += 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
detail.HeightF = Math.Max(y, RowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XRLabel CreateCaptionLabel(
|
||||||
|
FormReportField field,
|
||||||
|
IStringLocalizer<PlatformResource> localizer,
|
||||||
|
float x,
|
||||||
|
float y,
|
||||||
|
float width,
|
||||||
|
float height)
|
||||||
|
{
|
||||||
|
return new XRLabel
|
||||||
|
{
|
||||||
|
Text = GetLocalizedFieldCaption(field.Field, localizer),
|
||||||
|
BoundsF = new System.Drawing.RectangleF(x, y, width, height),
|
||||||
|
Font = new DXFont("Arial", 8F, DXFontStyle.Bold),
|
||||||
|
BackColor = System.Drawing.Color.FromArgb(248, 250, 252),
|
||||||
|
Borders = BorderSide.All,
|
||||||
|
BorderWidth = 0.5F,
|
||||||
|
Padding = new PaddingInfo(5, 5, 2, 2),
|
||||||
|
TextAlignment = TextAlignment.MiddleLeft,
|
||||||
|
Multiline = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static XRLabel CreateValueLabel(FormReportField field, float x, float y, float width, float height)
|
||||||
|
{
|
||||||
|
var label = new XRLabel
|
||||||
|
{
|
||||||
|
BoundsF = new System.Drawing.RectangleF(x, y, width, height),
|
||||||
|
Font = new DXFont("Arial", 8F),
|
||||||
|
Borders = BorderSide.All,
|
||||||
|
BorderWidth = 0.5F,
|
||||||
|
Padding = new PaddingInfo(5, 5, 2, 2),
|
||||||
|
TextAlignment = ToTextAlignment(field.Field.Alignment, field.Field.SourceDbType),
|
||||||
|
Multiline = true,
|
||||||
|
CanGrow = true
|
||||||
|
};
|
||||||
|
|
||||||
|
label.ExpressionBindings.Add(new ExpressionBinding("BeforePrint", "Text", $"[{field.BindingName}]"));
|
||||||
|
|
||||||
|
if (IsBooleanEditor(field) || field.StaticLookupValues?.Count > 0)
|
||||||
|
{
|
||||||
|
label.BeforePrint += (_, _) =>
|
||||||
|
{
|
||||||
|
var value = Convert.ToString(label.Text, CultureInfo.InvariantCulture);
|
||||||
|
if (IsBooleanEditor(field) && TryFormatBoolean(value, out var booleanText))
|
||||||
|
{
|
||||||
|
label.Text = booleanText;
|
||||||
|
}
|
||||||
|
else if (value != null && field.StaticLookupValues?.TryGetValue(value, out var displayText) == true)
|
||||||
|
{
|
||||||
|
label.Text = displayText;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float CalculateDetailHeight(
|
||||||
|
IReadOnlyList<FormReportField> fields,
|
||||||
|
ListForm listForm,
|
||||||
|
IDictionary<string, object> row)
|
||||||
|
{
|
||||||
|
var groupHeight = GetFormGroups(listForm, fields)
|
||||||
|
.Sum(group => (string.IsNullOrWhiteSpace(group.Caption) ? 0 : 26) +
|
||||||
|
group.Fields.Sum(field => GetFieldRowHeight(field) + 3) + 8);
|
||||||
|
|
||||||
|
var subFormHeight = GetListSubForms(listForm, row).Count() * 32;
|
||||||
|
return Math.Max(groupHeight + subFormHeight, RowHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static float GetFieldRowHeight(FormReportField field)
|
||||||
|
{
|
||||||
|
return field.EditorType is PlatformConsts.EditorTypes.dxTextArea or PlatformConsts.EditorTypes.dxHtmlEditor
|
||||||
|
? 48
|
||||||
|
: RowHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FormReportField> GetReportFields(
|
||||||
|
ListForm listForm,
|
||||||
|
List<ListFormField> fields,
|
||||||
|
ISelectQueryManager selectQueryManager,
|
||||||
|
DefaultValueHelper defaultValueHelper)
|
||||||
|
{
|
||||||
|
var fieldsByName = fields
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName) && x.FieldName != "undefined")
|
||||||
|
.Where(x => x.IsActive != false)
|
||||||
|
.ToDictionary(x => x.FieldName, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var formItems = GetEditingFormItems(listForm)
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.DataField))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var orderedFields = formItems.Count > 0
|
||||||
|
? formItems
|
||||||
|
.Where(x => fieldsByName.ContainsKey(x.DataField))
|
||||||
|
.Select(x => new FieldWithEditor(fieldsByName[x.DataField], x.EditorType2))
|
||||||
|
.ToList()
|
||||||
|
: fields
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName) && x.FieldName != "undefined")
|
||||||
|
.Where(x => x.IsActive != false && x.Visible == true)
|
||||||
|
.Select(x => new FieldWithEditor(x, null))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
return orderedFields
|
||||||
|
.Where(x => selectQueryManager.SelectFields.Any(s => s.FieldName == x.Field.FieldName))
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var selectField = selectQueryManager.SelectFields.First(s => s.FieldName == x.Field.FieldName);
|
||||||
|
return CreateFormReportField(x.Field, selectField, x.EditorType, defaultValueHelper);
|
||||||
|
})
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.BindingName) && x.BindingName != "undefined")
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<FormGroup> GetFormGroups(ListForm listForm, IReadOnlyList<FormReportField> fields)
|
||||||
|
{
|
||||||
|
var fieldsByName = fields.ToDictionary(x => x.Field.FieldName, StringComparer.OrdinalIgnoreCase);
|
||||||
|
var groups = GetEditingFormGroups(listForm).ToList();
|
||||||
|
if (groups.Count == 0)
|
||||||
|
{
|
||||||
|
yield return new FormGroup(null, fields);
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
var usedFields = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
foreach (var group in groups)
|
||||||
|
{
|
||||||
|
var groupFields = (group.Items ?? [])
|
||||||
|
.OrderBy(x => x.Order)
|
||||||
|
.Where(x => !string.IsNullOrWhiteSpace(x.DataField) && fieldsByName.ContainsKey(x.DataField))
|
||||||
|
.Select(x => fieldsByName[x.DataField])
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
foreach (var field in groupFields)
|
||||||
|
{
|
||||||
|
usedFields.Add(field.Field.FieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groupFields.Count > 0)
|
||||||
|
{
|
||||||
|
yield return new FormGroup(group.Caption, groupFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var remainingFields = fields
|
||||||
|
.Where(x => !usedFields.Contains(x.Field.FieldName))
|
||||||
|
.ToList();
|
||||||
|
if (remainingFields.Count > 0)
|
||||||
|
{
|
||||||
|
yield return new FormGroup(null, remainingFields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<EditingFormDto> GetEditingFormGroups(ListForm listForm)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(listForm.EditingFormJson))
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson) ?? [];
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<EditingFormItemDto> GetEditingFormItems(ListForm listForm)
|
||||||
|
{
|
||||||
|
return GetEditingFormGroups(listForm)
|
||||||
|
.OrderBy(x => x.Order)
|
||||||
|
.SelectMany(x => (x.Items ?? []).OrderBy(i => i.Order));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<(SubFormDto Form, string Filter)> GetListSubForms(
|
||||||
|
ListForm listForm,
|
||||||
|
IDictionary<string, object> row)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(listForm.SubFormsJson) || row == null)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<SubFormDto> subForms;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
subForms = JsonSerializer.Deserialize<List<SubFormDto>>(listForm.SubFormsJson) ?? [];
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
yield break;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var subForm in subForms.Where(x => string.Equals(x.TabType, ListFormTypeEnum.List, StringComparison.OrdinalIgnoreCase)))
|
||||||
|
{
|
||||||
|
var relation = subForm.Relation?
|
||||||
|
.FirstOrDefault(x => !string.IsNullOrWhiteSpace(x.ParentFieldName) &&
|
||||||
|
!string.IsNullOrWhiteSpace(x.ChildFieldName) &&
|
||||||
|
TryGetRowValue(row, x.ParentFieldName, out var value) &&
|
||||||
|
value != null &&
|
||||||
|
value != DBNull.Value);
|
||||||
|
|
||||||
|
if (relation == null || !TryGetRowValue(row, relation.ParentFieldName, out var parentValue))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield return (subForm, CreateFilter(relation.ChildFieldName, "=", parentValue));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> CreateSubReportParameters(SubFormDto subForm, string filter)
|
||||||
|
{
|
||||||
|
return new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["listFormCode"] = subForm.Code,
|
||||||
|
["filter"] = filter
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FormReportField CreateFormReportField(
|
||||||
|
ListFormField field,
|
||||||
|
SelectField selectField,
|
||||||
|
string editorType,
|
||||||
|
DefaultValueHelper defaultValueHelper)
|
||||||
|
{
|
||||||
|
var bindingName = GetReportFieldName(selectField);
|
||||||
|
var lookup = GetLookup(field);
|
||||||
|
|
||||||
|
if (lookup == null || selectField?.JoinOptions != null)
|
||||||
|
{
|
||||||
|
return new FormReportField(field, bindingName, editorType, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsReportQueryableLookup(lookup))
|
||||||
|
{
|
||||||
|
return new FormReportField(field, GetLookupBindingName(field), editorType, lookup, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lookup.DataSourceType == UiLookupDataSourceTypeEnum.StaticData)
|
||||||
|
{
|
||||||
|
return new FormReportField(
|
||||||
|
field,
|
||||||
|
bindingName,
|
||||||
|
editorType,
|
||||||
|
lookup,
|
||||||
|
GetStaticLookupValues(lookup, defaultValueHelper));
|
||||||
|
}
|
||||||
|
|
||||||
|
return new FormReportField(field, bindingName, editorType, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CreateKeyFilter(string keyFieldName, string id)
|
||||||
|
{
|
||||||
|
return CreateFilter(keyFieldName, "=", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string CreateFilter(string fieldName, string op, object value)
|
||||||
|
{
|
||||||
|
return JsonSerializer.Serialize(new object[] { fieldName, op, value });
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IDictionary<string, object> GetFirstRow(IEnumerable<dynamic> rows)
|
||||||
|
{
|
||||||
|
var row = rows?.FirstOrDefault();
|
||||||
|
if (row is IDictionary<string, object> dictionary)
|
||||||
|
{
|
||||||
|
return dictionary;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryGetRowValue(IDictionary<string, object> row, string name, out object value)
|
||||||
|
{
|
||||||
|
foreach (var item in row)
|
||||||
|
{
|
||||||
|
if (string.Equals(item.Key, name, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
value = item.Value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToDevExpressConnectionString(string connectionString, DataSourceTypeEnum dataSourceType)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(connectionString) ||
|
||||||
|
connectionString.Contains("XpoProvider=", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return connectionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
var provider = dataSourceType switch
|
||||||
|
{
|
||||||
|
DataSourceTypeEnum.Mssql => "MSSqlServer",
|
||||||
|
DataSourceTypeEnum.Postgresql => "Postgres",
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
|
||||||
|
return string.IsNullOrWhiteSpace(provider)
|
||||||
|
? connectionString
|
||||||
|
: $"XpoProvider={provider};{connectionString}";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ApplyQueryParameters(string sql, Dictionary<string, object> parameters)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(sql) || parameters == null || parameters.Count == 0)
|
||||||
|
{
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var parameter in parameters.OrderByDescending(x => x.Key.Length))
|
||||||
|
{
|
||||||
|
var key = parameter.Key.StartsWith("@") ? parameter.Key : "@" + parameter.Key;
|
||||||
|
sql = Regex.Replace(
|
||||||
|
sql,
|
||||||
|
Regex.Escape(key) + @"\b",
|
||||||
|
ToSqlLiteral(parameter.Value),
|
||||||
|
RegexOptions.CultureInvariant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ToSqlLiteral(object value)
|
||||||
|
{
|
||||||
|
if (value == null || value == DBNull.Value)
|
||||||
|
{
|
||||||
|
return "NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
return value switch
|
||||||
|
{
|
||||||
|
string text => $"'{text.Replace("'", "''")}'",
|
||||||
|
Guid guid => $"'{guid}'",
|
||||||
|
DateTime date => $"'{date:yyyy-MM-dd HH:mm:ss.fff}'",
|
||||||
|
DateTimeOffset date => $"'{date:yyyy-MM-dd HH:mm:ss.fff zzz}'",
|
||||||
|
bool boolean => boolean ? "1" : "0",
|
||||||
|
byte or sbyte or short or ushort or int or uint or long or ulong or float or double or decimal
|
||||||
|
=> Convert.ToString(value, CultureInfo.InvariantCulture),
|
||||||
|
_ => $"'{value.ToString()?.Replace("'", "''")}'"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetReportFieldName(SelectField selectField)
|
||||||
|
{
|
||||||
|
if (selectField?.JoinOptions != null && !string.IsNullOrWhiteSpace(selectField.JoinOptions.FieldNameAlias))
|
||||||
|
{
|
||||||
|
return selectField.JoinOptions.FieldNameAlias;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectField?.FieldName;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LookupDto GetLookup(ListFormField field)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(field.LookupJson))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return JsonSerializer.Deserialize<LookupDto>(field.LookupJson);
|
||||||
|
}
|
||||||
|
catch (JsonException)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> 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<string, string>(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<FormReportField> reportFields,
|
||||||
|
DefaultValueHelper defaultValueHelper)
|
||||||
|
{
|
||||||
|
var lookupFields = reportFields
|
||||||
|
.Where(x => x.Lookup != null && IsReportQueryableLookup(x.Lookup))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
if (lookupFields.Count == 0 || string.IsNullOrWhiteSpace(selectQuery))
|
||||||
|
{
|
||||||
|
return selectQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tableAlias = string.IsNullOrWhiteSpace(listForm.TableName)
|
||||||
|
? listForm.SelectCommand
|
||||||
|
: listForm.TableName;
|
||||||
|
|
||||||
|
var selectParts = new List<string>();
|
||||||
|
var joinParts = new List<string>();
|
||||||
|
foreach (var field in lookupFields)
|
||||||
|
{
|
||||||
|
var lookup = field.Lookup;
|
||||||
|
var alias = GetLookupAlias(field.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(field.BindingName)}");
|
||||||
|
joinParts.Add(
|
||||||
|
$"LEFT JOIN ({lookupQuery}) AS {alias} " +
|
||||||
|
$"ON {alias}.{valueExpr} = {QuoteSqlIdentifier(tableAlias)}.{QuoteSqlIdentifier(field.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 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 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 static string GetLocalizedReportTitle(ListForm listForm, IStringLocalizer<PlatformResource> localizer)
|
||||||
|
{
|
||||||
|
var title = string.IsNullOrWhiteSpace(listForm.Title) ? listForm.Name : listForm.Title;
|
||||||
|
return Localize(localizer, title, listForm.ListFormCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetLocalizedFieldCaption(ListFormField field, IStringLocalizer<PlatformResource> localizer)
|
||||||
|
{
|
||||||
|
var caption = string.IsNullOrWhiteSpace(field.CaptionName) ? field.FieldName : field.CaptionName;
|
||||||
|
return Localize(localizer, caption, field.FieldName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string Localize(IStringLocalizer<PlatformResource> localizer, string key, string fallback)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(key))
|
||||||
|
{
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
var localized = localizer[key];
|
||||||
|
return localized.ResourceNotFound || string.IsNullOrWhiteSpace(localized.Value)
|
||||||
|
? key
|
||||||
|
: localized.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TextAlignment ToTextAlignment(string alignment, DbType dbType)
|
||||||
|
{
|
||||||
|
return alignment?.ToLowerInvariant() switch
|
||||||
|
{
|
||||||
|
"center" => TextAlignment.MiddleCenter,
|
||||||
|
"right" => TextAlignment.MiddleRight,
|
||||||
|
"left" => TextAlignment.MiddleLeft,
|
||||||
|
_ => IsNumeric(dbType) ? TextAlignment.MiddleRight : TextAlignment.MiddleLeft
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsNumeric(DbType dbType)
|
||||||
|
{
|
||||||
|
return dbType is DbType.Currency or DbType.Decimal or DbType.Double or DbType.Int16 or DbType.Int32
|
||||||
|
or DbType.Int64 or DbType.Single or DbType.UInt16 or DbType.UInt32 or DbType.UInt64;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsBooleanEditor(FormReportField field)
|
||||||
|
{
|
||||||
|
return field.EditorType is PlatformConsts.EditorTypes.dxCheckBox or PlatformConsts.EditorTypes.dxSwitch ||
|
||||||
|
field.Field.SourceDbType == DbType.Boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryFormatBoolean(string value, out string text)
|
||||||
|
{
|
||||||
|
if (bool.TryParse(value, out var boolean))
|
||||||
|
{
|
||||||
|
text = boolean ? "Evet" : "Hayır";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == "1" || string.Equals(value, "true", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
text = "Evet";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value == "0" || string.Equals(value, "false", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
text = "Hayır";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
text = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetParameter(IDictionary<string, string> parameters, string name)
|
||||||
|
{
|
||||||
|
return parameters.TryGetValue(name, out var value) ? value : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed record FieldWithEditor(ListFormField Field, string EditorType);
|
||||||
|
private sealed record FormGroup(string Caption, IReadOnlyList<FormReportField> Fields);
|
||||||
|
private sealed record FormReportField(
|
||||||
|
ListFormField Field,
|
||||||
|
string BindingName,
|
||||||
|
string EditorType,
|
||||||
|
LookupDto Lookup,
|
||||||
|
Dictionary<string, string> StaticLookupValues);
|
||||||
|
}
|
||||||
|
|
@ -21,10 +21,10 @@ using Sozsoft.Platform.Queries;
|
||||||
|
|
||||||
namespace Sozsoft.Reports.PredefinedReports;
|
namespace Sozsoft.Reports.PredefinedReports;
|
||||||
|
|
||||||
public class DynamicListFormReport : XtraReport
|
public class DynamicGridReport : XtraReport
|
||||||
{
|
{
|
||||||
public const string ReportName = nameof(DynamicListFormReport);
|
public const string ReportName = nameof(DynamicGridReport);
|
||||||
private const string QueryName = "DynamicList";
|
private const string QueryName = "DynamicGrid";
|
||||||
private const int A4PortraitWidth = 827;
|
private const int A4PortraitWidth = 827;
|
||||||
private const int HorizontalMargin = 35;
|
private const int HorizontalMargin = 35;
|
||||||
private const int LandscapeColumnThreshold = 5;
|
private const int LandscapeColumnThreshold = 5;
|
||||||
|
|
@ -35,14 +35,14 @@ public class DynamicListFormReport : XtraReport
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DynamicListFormReport Create(IDictionary<string, string> parameters)
|
public static DynamicGridReport Create(IDictionary<string, string> parameters)
|
||||||
{
|
{
|
||||||
var report = new DynamicListFormReport();
|
var report = new DynamicGridReport();
|
||||||
report.Build(parameters);
|
report.Build(parameters);
|
||||||
return report;
|
return report;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DynamicListFormReport()
|
public DynamicGridReport()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3,7 +3,7 @@ using Sozsoft.Platform.Enums;
|
||||||
|
|
||||||
namespace Sozsoft.Reports.PredefinedReports
|
namespace Sozsoft.Reports.PredefinedReports
|
||||||
{
|
{
|
||||||
partial class TemplateReport
|
partial class DynamicReport
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Required designer variable.
|
/// Required designer variable.
|
||||||
|
|
@ -36,7 +36,7 @@ namespace Sozsoft.Reports.PredefinedReports
|
||||||
DevExpress.DataAccess.Sql.Column column1 = new DevExpress.DataAccess.Sql.Column();
|
DevExpress.DataAccess.Sql.Column column1 = new DevExpress.DataAccess.Sql.Column();
|
||||||
DevExpress.DataAccess.Sql.ColumnExpression columnExpression1 = new DevExpress.DataAccess.Sql.ColumnExpression();
|
DevExpress.DataAccess.Sql.ColumnExpression columnExpression1 = new DevExpress.DataAccess.Sql.ColumnExpression();
|
||||||
DevExpress.DataAccess.Sql.Table table1 = new DevExpress.DataAccess.Sql.Table();
|
DevExpress.DataAccess.Sql.Table table1 = new DevExpress.DataAccess.Sql.Table();
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TemplateReport));
|
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(DynamicReport));
|
||||||
this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand();
|
this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand();
|
||||||
this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand();
|
this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand();
|
||||||
this.pageInfo1 = new DevExpress.XtraReports.UI.XRPageInfo();
|
this.pageInfo1 = new DevExpress.XtraReports.UI.XRPageInfo();
|
||||||
|
|
@ -9,7 +9,7 @@ using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
namespace Sozsoft.Reports.PredefinedReports;
|
namespace Sozsoft.Reports.PredefinedReports;
|
||||||
|
|
||||||
public partial class TemplateReport : XtraReport
|
public partial class DynamicReport : XtraReport
|
||||||
{
|
{
|
||||||
private Dictionary<string, string> _parameters;
|
private Dictionary<string, string> _parameters;
|
||||||
private static IServiceProvider _serviceProvider;
|
private static IServiceProvider _serviceProvider;
|
||||||
|
|
@ -22,7 +22,7 @@ public partial class TemplateReport : XtraReport
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TemplateReport()
|
public DynamicReport()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
|
@ -1,264 +0,0 @@
|
||||||
using Sozsoft.Platform.Enums;
|
|
||||||
|
|
||||||
namespace Sozsoft.Reports.PredefinedReports
|
|
||||||
{
|
|
||||||
partial class TestReport
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Required designer variable.
|
|
||||||
/// </summary>
|
|
||||||
private System.ComponentModel.IContainer components = null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Clean up any resources being used.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing && (components != null))
|
|
||||||
{
|
|
||||||
components.Dispose();
|
|
||||||
}
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Designer generated code
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Required method for Designer support - do not modify
|
|
||||||
/// the contents of this method with the code editor.
|
|
||||||
/// </summary>
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
this.components = new System.ComponentModel.Container();
|
|
||||||
DevExpress.DataAccess.Sql.SelectQuery selectQuery1 = new DevExpress.DataAccess.Sql.SelectQuery();
|
|
||||||
DevExpress.DataAccess.Sql.Column column1 = new DevExpress.DataAccess.Sql.Column();
|
|
||||||
DevExpress.DataAccess.Sql.ColumnExpression columnExpression1 = new DevExpress.DataAccess.Sql.ColumnExpression();
|
|
||||||
DevExpress.DataAccess.Sql.Table table1 = new DevExpress.DataAccess.Sql.Table();
|
|
||||||
DevExpress.DataAccess.Sql.Column column2 = new DevExpress.DataAccess.Sql.Column();
|
|
||||||
DevExpress.DataAccess.Sql.ColumnExpression columnExpression2 = new DevExpress.DataAccess.Sql.ColumnExpression();
|
|
||||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TemplateReport));
|
|
||||||
this.TopMargin = new DevExpress.XtraReports.UI.TopMarginBand();
|
|
||||||
this.BottomMargin = new DevExpress.XtraReports.UI.BottomMarginBand();
|
|
||||||
this.pageInfo1 = new DevExpress.XtraReports.UI.XRPageInfo();
|
|
||||||
this.pageInfo2 = new DevExpress.XtraReports.UI.XRPageInfo();
|
|
||||||
this.ReportHeader = new DevExpress.XtraReports.UI.ReportHeaderBand();
|
|
||||||
this.label1 = new DevExpress.XtraReports.UI.XRLabel();
|
|
||||||
this.Detail = new DevExpress.XtraReports.UI.DetailBand();
|
|
||||||
this.table2 = new DevExpress.XtraReports.UI.XRTable();
|
|
||||||
this.tableRow1 = new DevExpress.XtraReports.UI.XRTableRow();
|
|
||||||
this.tableCell1 = new DevExpress.XtraReports.UI.XRTableCell();
|
|
||||||
this.tableCell2 = new DevExpress.XtraReports.UI.XRTableCell();
|
|
||||||
this.sqlDataSource1 = new DevExpress.DataAccess.Sql.SqlDataSource(this.components);
|
|
||||||
this.Title = new DevExpress.XtraReports.UI.XRControlStyle();
|
|
||||||
this.DetailCaption1 = new DevExpress.XtraReports.UI.XRControlStyle();
|
|
||||||
this.DetailData1 = new DevExpress.XtraReports.UI.XRControlStyle();
|
|
||||||
this.DetailData3_Odd = new DevExpress.XtraReports.UI.XRControlStyle();
|
|
||||||
this.PageInfo = new DevExpress.XtraReports.UI.XRControlStyle();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.table2)).BeginInit();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this)).BeginInit();
|
|
||||||
//
|
|
||||||
// TopMargin
|
|
||||||
//
|
|
||||||
this.TopMargin.Name = "TopMargin";
|
|
||||||
//
|
|
||||||
// BottomMargin
|
|
||||||
//
|
|
||||||
this.BottomMargin.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
|
|
||||||
this.pageInfo1,
|
|
||||||
this.pageInfo2});
|
|
||||||
this.BottomMargin.Name = "BottomMargin";
|
|
||||||
//
|
|
||||||
// pageInfo1
|
|
||||||
//
|
|
||||||
this.pageInfo1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
|
||||||
this.pageInfo1.Name = "pageInfo1";
|
|
||||||
this.pageInfo1.PageInfo = DevExpress.XtraPrinting.PageInfo.DateTime;
|
|
||||||
this.pageInfo1.SizeF = new System.Drawing.SizeF(325F, 23F);
|
|
||||||
this.pageInfo1.StyleName = "PageInfo";
|
|
||||||
//
|
|
||||||
// pageInfo2
|
|
||||||
//
|
|
||||||
this.pageInfo2.LocationFloat = new DevExpress.Utils.PointFloat(325F, 0F);
|
|
||||||
this.pageInfo2.Name = "pageInfo2";
|
|
||||||
this.pageInfo2.SizeF = new System.Drawing.SizeF(325F, 23F);
|
|
||||||
this.pageInfo2.StyleName = "PageInfo";
|
|
||||||
this.pageInfo2.TextAlignment = DevExpress.XtraPrinting.TextAlignment.TopRight;
|
|
||||||
this.pageInfo2.TextFormatString = "Page {0} of {1}";
|
|
||||||
//
|
|
||||||
// ReportHeader
|
|
||||||
//
|
|
||||||
this.ReportHeader.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
|
|
||||||
this.label1});
|
|
||||||
this.ReportHeader.HeightF = 60F;
|
|
||||||
this.ReportHeader.Name = "ReportHeader";
|
|
||||||
//
|
|
||||||
// label1
|
|
||||||
//
|
|
||||||
this.label1.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
|
||||||
this.label1.Name = "label1";
|
|
||||||
this.label1.SizeF = new System.Drawing.SizeF(650F, 24.19433F);
|
|
||||||
this.label1.StyleName = "Title";
|
|
||||||
this.label1.Text = "Sector Report";
|
|
||||||
//
|
|
||||||
// Detail
|
|
||||||
//
|
|
||||||
this.Detail.Controls.AddRange(new DevExpress.XtraReports.UI.XRControl[] {
|
|
||||||
this.table2});
|
|
||||||
this.Detail.HeightF = 25F;
|
|
||||||
this.Detail.Name = "Detail";
|
|
||||||
//
|
|
||||||
// table2
|
|
||||||
//
|
|
||||||
this.table2.LocationFloat = new DevExpress.Utils.PointFloat(0F, 0F);
|
|
||||||
this.table2.Name = "table2";
|
|
||||||
this.table2.OddStyleName = "DetailData3_Odd";
|
|
||||||
this.table2.Rows.AddRange(new DevExpress.XtraReports.UI.XRTableRow[] {
|
|
||||||
this.tableRow1});
|
|
||||||
this.table2.SizeF = new System.Drawing.SizeF(650F, 25F);
|
|
||||||
//
|
|
||||||
// tableRow1
|
|
||||||
//
|
|
||||||
this.tableRow1.Cells.AddRange(new DevExpress.XtraReports.UI.XRTableCell[] {
|
|
||||||
this.tableCell1,
|
|
||||||
this.tableCell2});
|
|
||||||
this.tableRow1.Name = "tableRow1";
|
|
||||||
this.tableRow1.Weight = 1D;
|
|
||||||
//
|
|
||||||
// tableCell1
|
|
||||||
//
|
|
||||||
this.tableCell1.Borders = DevExpress.XtraPrinting.BorderSide.None;
|
|
||||||
this.tableCell1.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
|
|
||||||
new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "Text", "[Id]")});
|
|
||||||
this.tableCell1.Name = "tableCell1";
|
|
||||||
this.tableCell1.StyleName = "DetailData1";
|
|
||||||
this.tableCell1.StylePriority.UseBorders = false;
|
|
||||||
this.tableCell1.Text = "Id";
|
|
||||||
this.tableCell1.Weight = 0.3D;
|
|
||||||
//
|
|
||||||
// tableCell2
|
|
||||||
//
|
|
||||||
this.tableCell2.ExpressionBindings.AddRange(new DevExpress.XtraReports.UI.ExpressionBinding[] {
|
|
||||||
new DevExpress.XtraReports.UI.ExpressionBinding("BeforePrint", "Text", "[Name]")});
|
|
||||||
this.tableCell2.Name = "tableCell2";
|
|
||||||
this.tableCell2.StyleName = "DetailData1";
|
|
||||||
this.tableCell2.Text = "Name";
|
|
||||||
this.tableCell2.Weight = 0.7D;
|
|
||||||
//
|
|
||||||
// sqlDataSource1
|
|
||||||
//
|
|
||||||
this.sqlDataSource1.ConnectionName = "SqlServer";
|
|
||||||
this.sqlDataSource1.Name = "sqlDataSource1";
|
|
||||||
columnExpression1.ColumnName = "Id";
|
|
||||||
table1.Name = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Sector));
|
|
||||||
columnExpression1.Table = table1;
|
|
||||||
column1.Expression = columnExpression1;
|
|
||||||
columnExpression2.ColumnName = "Name";
|
|
||||||
columnExpression2.Table = table1;
|
|
||||||
column2.Expression = columnExpression2;
|
|
||||||
selectQuery1.Columns.Add(column1);
|
|
||||||
selectQuery1.Columns.Add(column2);
|
|
||||||
selectQuery1.Name = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Sector));
|
|
||||||
selectQuery1.Tables.Add(table1);
|
|
||||||
this.sqlDataSource1.Queries.AddRange(new DevExpress.DataAccess.Sql.SqlQuery[] {
|
|
||||||
selectQuery1});
|
|
||||||
this.sqlDataSource1.ResultSchemaSerializable = resources.GetString("sqlDataSource1.ResultSchemaSerializable");
|
|
||||||
//
|
|
||||||
// Title
|
|
||||||
//
|
|
||||||
this.Title.BackColor = System.Drawing.Color.Transparent;
|
|
||||||
this.Title.BorderColor = System.Drawing.Color.Black;
|
|
||||||
this.Title.Borders = DevExpress.XtraPrinting.BorderSide.None;
|
|
||||||
this.Title.BorderWidth = 1F;
|
|
||||||
this.Title.Font = new DevExpress.Drawing.DXFont("Arial", 14.25F);
|
|
||||||
this.Title.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
|
|
||||||
this.Title.Name = "Title";
|
|
||||||
this.Title.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
|
|
||||||
//
|
|
||||||
// DetailCaption1
|
|
||||||
//
|
|
||||||
this.DetailCaption1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(181)))), ((int)(((byte)(211)))), ((int)(((byte)(142)))));
|
|
||||||
this.DetailCaption1.BorderColor = System.Drawing.Color.White;
|
|
||||||
this.DetailCaption1.Borders = DevExpress.XtraPrinting.BorderSide.Left;
|
|
||||||
this.DetailCaption1.BorderWidth = 2F;
|
|
||||||
this.DetailCaption1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
|
|
||||||
this.DetailCaption1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
|
|
||||||
this.DetailCaption1.Name = "DetailCaption1";
|
|
||||||
this.DetailCaption1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
|
|
||||||
this.DetailCaption1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
|
|
||||||
//
|
|
||||||
// DetailData1
|
|
||||||
//
|
|
||||||
this.DetailData1.BorderColor = System.Drawing.Color.Transparent;
|
|
||||||
this.DetailData1.Borders = DevExpress.XtraPrinting.BorderSide.Left;
|
|
||||||
this.DetailData1.BorderWidth = 2F;
|
|
||||||
this.DetailData1.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F);
|
|
||||||
this.DetailData1.ForeColor = System.Drawing.Color.Black;
|
|
||||||
this.DetailData1.Name = "DetailData1";
|
|
||||||
this.DetailData1.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
|
|
||||||
this.DetailData1.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
|
|
||||||
//
|
|
||||||
// DetailData3_Odd
|
|
||||||
//
|
|
||||||
this.DetailData3_Odd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(243)))), ((int)(((byte)(245)))), ((int)(((byte)(248)))));
|
|
||||||
this.DetailData3_Odd.BorderColor = System.Drawing.Color.Transparent;
|
|
||||||
this.DetailData3_Odd.Borders = DevExpress.XtraPrinting.BorderSide.None;
|
|
||||||
this.DetailData3_Odd.BorderWidth = 1F;
|
|
||||||
this.DetailData3_Odd.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F);
|
|
||||||
this.DetailData3_Odd.ForeColor = System.Drawing.Color.Black;
|
|
||||||
this.DetailData3_Odd.Name = "DetailData3_Odd";
|
|
||||||
this.DetailData3_Odd.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
|
|
||||||
this.DetailData3_Odd.TextAlignment = DevExpress.XtraPrinting.TextAlignment.MiddleLeft;
|
|
||||||
//
|
|
||||||
// PageInfo
|
|
||||||
//
|
|
||||||
this.PageInfo.Font = new DevExpress.Drawing.DXFont("Arial", 8.25F, DevExpress.Drawing.DXFontStyle.Bold);
|
|
||||||
this.PageInfo.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(64)))), ((int)(((byte)(70)))), ((int)(((byte)(80)))));
|
|
||||||
this.PageInfo.Name = "PageInfo";
|
|
||||||
this.PageInfo.Padding = new DevExpress.XtraPrinting.PaddingInfo(6, 6, 0, 0, 100F);
|
|
||||||
//
|
|
||||||
// TestReport
|
|
||||||
//
|
|
||||||
this.Bands.AddRange(new DevExpress.XtraReports.UI.Band[] {
|
|
||||||
this.TopMargin,
|
|
||||||
this.BottomMargin,
|
|
||||||
this.ReportHeader,
|
|
||||||
this.Detail});
|
|
||||||
this.ComponentStorage.AddRange(new System.ComponentModel.IComponent[] {
|
|
||||||
this.sqlDataSource1});
|
|
||||||
this.DataMember = TableNameResolver.GetFullTableName(nameof(TableNameEnum.Sector));
|
|
||||||
this.DataSource = this.sqlDataSource1;
|
|
||||||
this.Font = new DevExpress.Drawing.DXFont("Arial", 9.75F);
|
|
||||||
this.StyleSheet.AddRange(new DevExpress.XtraReports.UI.XRControlStyle[] {
|
|
||||||
this.Title,
|
|
||||||
this.DetailCaption1,
|
|
||||||
this.DetailData1,
|
|
||||||
this.DetailData3_Odd,
|
|
||||||
this.PageInfo});
|
|
||||||
this.Version = "22.2";
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this.table2)).EndInit();
|
|
||||||
((System.ComponentModel.ISupportInitialize)(this)).EndInit();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
private DevExpress.XtraReports.UI.TopMarginBand TopMargin;
|
|
||||||
private DevExpress.XtraReports.UI.BottomMarginBand BottomMargin;
|
|
||||||
private DevExpress.XtraReports.UI.XRPageInfo pageInfo1;
|
|
||||||
private DevExpress.XtraReports.UI.XRPageInfo pageInfo2;
|
|
||||||
private DevExpress.XtraReports.UI.ReportHeaderBand ReportHeader;
|
|
||||||
private DevExpress.XtraReports.UI.XRLabel label1;
|
|
||||||
private DevExpress.XtraReports.UI.DetailBand Detail;
|
|
||||||
private DevExpress.XtraReports.UI.XRTable table2;
|
|
||||||
private DevExpress.XtraReports.UI.XRTableRow tableRow1;
|
|
||||||
private DevExpress.XtraReports.UI.XRTableCell tableCell1;
|
|
||||||
private DevExpress.XtraReports.UI.XRTableCell tableCell2;
|
|
||||||
private DevExpress.DataAccess.Sql.SqlDataSource sqlDataSource1;
|
|
||||||
private DevExpress.XtraReports.UI.XRControlStyle Title;
|
|
||||||
private DevExpress.XtraReports.UI.XRControlStyle DetailCaption1;
|
|
||||||
private DevExpress.XtraReports.UI.XRControlStyle DetailData1;
|
|
||||||
private DevExpress.XtraReports.UI.XRControlStyle DetailData3_Odd;
|
|
||||||
private DevExpress.XtraReports.UI.XRControlStyle PageInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
namespace Sozsoft.Reports.PredefinedReports;
|
|
||||||
|
|
||||||
public partial class TestReport : DevExpress.XtraReports.UI.XtraReport
|
|
||||||
{
|
|
||||||
public TestReport()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,123 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<data name="sqlDataSource1.ResultSchemaSerializable" xml:space="preserve">
|
|
||||||
<value>PERhdGFTZXQgTmFtZT0ic3FsRGF0YVNvdXJjZTEiPjxWaWV3IE5hbWU9IkNhdGVnb3JpZXMiPjxGaWVsZCBOYW1lPSJDYXRlZ29yeUlEIiBUeXBlPSJJbnQ2NCIgLz48RmllbGQgTmFtZT0iQ2F0ZWdvcnlOYW1lIiBUeXBlPSJTdHJpbmciIC8+PEZpZWxkIE5hbWU9IkRlc2NyaXB0aW9uIiBUeXBlPSJTdHJpbmciIC8+PEZpZWxkIE5hbWU9IlBpY3R1cmUiIFR5cGU9IkJ5dGVBcnJheSIgLz48RmllbGQgTmFtZT0iSWNvbjE3IiBUeXBlPSJCeXRlQXJyYXkiIC8+PEZpZWxkIE5hbWU9Ikljb24yNSIgVHlwZT0iQnl0ZUFycmF5IiAvPjwvVmlldz48L0RhdGFTZXQ+</value>
|
|
||||||
</data>
|
|
||||||
</root>
|
|
||||||
|
|
@ -19,9 +19,10 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
|
|
||||||
// TemplateReport için ServiceProvider'ı set et
|
// DynamicReport için ServiceProvider'ı set et
|
||||||
Sozsoft.Reports.PredefinedReports.TemplateReport.SetServiceProvider(serviceProvider);
|
Sozsoft.Reports.PredefinedReports.DynamicReport.SetServiceProvider(serviceProvider);
|
||||||
Sozsoft.Reports.PredefinedReports.DynamicListFormReport.SetServiceProvider(serviceProvider);
|
Sozsoft.Reports.PredefinedReports.DynamicGridReport.SetServiceProvider(serviceProvider);
|
||||||
|
Sozsoft.Reports.PredefinedReports.DynamicFormReport.SetServiceProvider(serviceProvider);
|
||||||
|
|
||||||
if (!Directory.Exists(reportDirectory))
|
if (!Directory.Exists(reportDirectory))
|
||||||
{
|
{
|
||||||
|
|
@ -33,9 +34,10 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
|
||||||
{
|
{
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
|
|
||||||
// TemplateReport için ServiceProvider'ı set et
|
// DynamicReport için ServiceProvider'ı set et
|
||||||
Sozsoft.Reports.PredefinedReports.TemplateReport.SetServiceProvider(serviceProvider);
|
Sozsoft.Reports.PredefinedReports.DynamicReport.SetServiceProvider(serviceProvider);
|
||||||
Sozsoft.Reports.PredefinedReports.DynamicListFormReport.SetServiceProvider(serviceProvider);
|
Sozsoft.Reports.PredefinedReports.DynamicGridReport.SetServiceProvider(serviceProvider);
|
||||||
|
Sozsoft.Reports.PredefinedReports.DynamicFormReport.SetServiceProvider(serviceProvider);
|
||||||
|
|
||||||
if (!Directory.Exists(reportDirectory))
|
if (!Directory.Exists(reportDirectory))
|
||||||
{
|
{
|
||||||
|
|
@ -81,10 +83,20 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var (reportName, parameters) = ParseReportUrl(url);
|
var (reportName, parameters) = ParseReportUrl(url);
|
||||||
|
|
||||||
if (reportName == Sozsoft.Reports.PredefinedReports.DynamicListFormReport.ReportName)
|
if (IsDynamicGridReport(reportName))
|
||||||
{
|
{
|
||||||
var report = Sozsoft.Reports.PredefinedReports.DynamicListFormReport.Create(parameters);
|
XtraReport report = HasParameter(parameters, "id")
|
||||||
|
? Sozsoft.Reports.PredefinedReports.DynamicFormReport.Create(parameters)
|
||||||
|
: Sozsoft.Reports.PredefinedReports.DynamicGridReport.Create(parameters);
|
||||||
|
using MemoryStream ms = new MemoryStream();
|
||||||
|
report.SaveLayoutToXml(ms);
|
||||||
|
return ms.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IsDynamicFormReport(reportName))
|
||||||
|
{
|
||||||
|
var report = Sozsoft.Reports.PredefinedReports.DynamicFormReport.Create(parameters);
|
||||||
using MemoryStream ms = new MemoryStream();
|
using MemoryStream ms = new MemoryStream();
|
||||||
report.SaveLayoutToXml(ms);
|
report.SaveLayoutToXml(ms);
|
||||||
return ms.ToArray();
|
return ms.ToArray();
|
||||||
|
|
@ -171,7 +183,7 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
|
||||||
{
|
{
|
||||||
var decodedUrl = DecodeRepeatedly(url);
|
var decodedUrl = DecodeRepeatedly(url);
|
||||||
var reportName = decodedUrl;
|
var reportName = decodedUrl;
|
||||||
var parameters = new Dictionary<string, string>();
|
var parameters = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
var queryIndex = decodedUrl.IndexOf('?');
|
var queryIndex = decodedUrl.IndexOf('?');
|
||||||
if (queryIndex < 0)
|
if (queryIndex < 0)
|
||||||
|
|
@ -195,6 +207,23 @@ public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extens
|
||||||
return (reportName, parameters);
|
return (reportName, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsDynamicGridReport(string reportName)
|
||||||
|
{
|
||||||
|
return string.Equals(reportName, "DynamicGrid", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(reportName, Sozsoft.Reports.PredefinedReports.DynamicGridReport.ReportName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsDynamicFormReport(string reportName)
|
||||||
|
{
|
||||||
|
return string.Equals(reportName, "DynamicForm", StringComparison.OrdinalIgnoreCase) ||
|
||||||
|
string.Equals(reportName, Sozsoft.Reports.PredefinedReports.DynamicFormReport.ReportName, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool HasParameter(Dictionary<string, string> parameters, string name)
|
||||||
|
{
|
||||||
|
return parameters.TryGetValue(name, out var value) && !string.IsNullOrWhiteSpace(value);
|
||||||
|
}
|
||||||
|
|
||||||
private static string DecodeRepeatedly(string value)
|
private static string DecodeRepeatedly(string value)
|
||||||
{
|
{
|
||||||
var decoded = value;
|
var decoded = value;
|
||||||
|
|
|
||||||
|
|
@ -84,12 +84,17 @@ const loadViewerCss = (isDarkMode: boolean) => {
|
||||||
|
|
||||||
const DevexpressReportViewer: React.FC = () => {
|
const DevexpressReportViewer: React.FC = () => {
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
const { id } = useParams<{ id: string }>()
|
const { id, listFormCode, recordId } = useParams<{
|
||||||
|
id: string
|
||||||
|
listFormCode: string
|
||||||
|
recordId: string
|
||||||
|
}>()
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const token = useStoreState((state) => state.auth.session.token)
|
const token = useStoreState((state) => state.auth.session.token)
|
||||||
const themeMode = useStoreState((state) => state.theme.mode)
|
const themeMode = useStoreState((state) => state.theme.mode)
|
||||||
const [isRequestAuthReady, setIsRequestAuthReady] = useState(false)
|
const [isRequestAuthReady, setIsRequestAuthReady] = useState(false)
|
||||||
const isDarkMode = themeMode === MODE_DARK
|
const isDarkMode = themeMode === MODE_DARK
|
||||||
|
const formRecordId = recordId ?? (listFormCode ? id : undefined)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadViewerCss(isDarkMode)
|
loadViewerCss(isDarkMode)
|
||||||
|
|
@ -116,11 +121,24 @@ const DevexpressReportViewer: React.FC = () => {
|
||||||
}, [token])
|
}, [token])
|
||||||
|
|
||||||
const reportUrlWithParams = useMemo(() => {
|
const reportUrlWithParams = useMemo(() => {
|
||||||
|
const searchParams = new URLSearchParams(location.search)
|
||||||
|
|
||||||
|
if (listFormCode) {
|
||||||
|
searchParams.set('listFormCode', listFormCode)
|
||||||
|
|
||||||
|
if (formRecordId) {
|
||||||
|
searchParams.set('id', formRecordId)
|
||||||
|
return `DynamicFormReport?${searchParams.toString()}`
|
||||||
|
}
|
||||||
|
|
||||||
|
return `DynamicListFormReport?${searchParams.toString()}`
|
||||||
|
}
|
||||||
|
|
||||||
if (!id) return ''
|
if (!id) return ''
|
||||||
return location.search ? `${id}${location.search}` : id
|
return location.search ? `${id}${location.search}` : id
|
||||||
}, [id, location.search])
|
}, [id, listFormCode, formRecordId, location.search])
|
||||||
|
|
||||||
if (!id) return null
|
if (!reportUrlWithParams) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={getViewerClassName(isDarkMode)}>
|
<Container className={getViewerClassName(isDarkMode)}>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue