2026-06-29 14:44:30 +00:00
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using System.Text.Json;
|
2026-06-30 19:20:01 +00:00
|
|
|
using Sozsoft.Platform;
|
2026-06-29 14:44:30 +00:00
|
|
|
using Sozsoft.Platform.Entities;
|
2026-06-30 19:20:01 +00:00
|
|
|
using Sozsoft.Platform.ListForms;
|
2026-06-29 14:44:30 +00:00
|
|
|
|
|
|
|
|
namespace Sozsoft.Reports.PredefinedReports;
|
|
|
|
|
|
|
|
|
|
internal static class DynamicReportGridStateHelper
|
|
|
|
|
{
|
|
|
|
|
public static string GetFilterName(ListForm listForm, string prefix) =>
|
|
|
|
|
$"{prefix}-{GetStateStorageKey(listForm)}";
|
|
|
|
|
|
|
|
|
|
public static List<ListFormField> GetVisibleFields(
|
|
|
|
|
IReadOnlyList<ListFormField> availableFields,
|
|
|
|
|
string gridStateJson)
|
|
|
|
|
{
|
|
|
|
|
if (!TryGetColumnStates(gridStateJson, out var statesByField))
|
|
|
|
|
{
|
|
|
|
|
return availableFields
|
|
|
|
|
.Where(x => x.Visible == true)
|
|
|
|
|
.ToList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return availableFields
|
|
|
|
|
.Where(field => statesByField.TryGetValue(field.FieldName, out var state)
|
|
|
|
|
? state.Visible
|
|
|
|
|
: field.Visible == true)
|
|
|
|
|
.OrderBy(field => statesByField.TryGetValue(field.FieldName, out var state)
|
|
|
|
|
? state.VisibleIndex
|
|
|
|
|
: int.MaxValue)
|
|
|
|
|
.ToList();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-30 19:20:01 +00:00
|
|
|
public static List<ListFormField> GetGroupedFields(
|
|
|
|
|
IReadOnlyList<ListFormField> availableFields,
|
|
|
|
|
string gridStateJson,
|
|
|
|
|
string groupParameter)
|
|
|
|
|
{
|
|
|
|
|
var groupedFields = new List<ListFormField>();
|
|
|
|
|
var groupedFieldNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
foreach (var field in GetGroupFieldsFromParameter(availableFields, groupParameter))
|
|
|
|
|
{
|
|
|
|
|
AddGroupedField(field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TryGetColumnStates(gridStateJson, out var statesByField))
|
|
|
|
|
{
|
|
|
|
|
foreach (var field in availableFields.Where(field =>
|
|
|
|
|
statesByField.TryGetValue(field.FieldName, out var state) &&
|
|
|
|
|
state.GroupIndex.HasValue)
|
|
|
|
|
.OrderBy(field => statesByField[field.FieldName].GroupIndex)
|
|
|
|
|
.ThenBy(field => statesByField[field.FieldName].VisibleIndex))
|
|
|
|
|
{
|
|
|
|
|
AddGroupedField(field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var field in availableFields
|
|
|
|
|
.Select(field => new { Field = field, GroupIndex = GetConfiguredGroupIndex(field) })
|
|
|
|
|
.Where(x => x.GroupIndex.HasValue)
|
|
|
|
|
.OrderBy(x => x.GroupIndex)
|
|
|
|
|
.Select(x => x.Field))
|
|
|
|
|
{
|
|
|
|
|
AddGroupedField(field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return groupedFields;
|
|
|
|
|
|
|
|
|
|
void AddGroupedField(ListFormField field)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(field?.FieldName) && groupedFieldNames.Add(field.FieldName))
|
|
|
|
|
{
|
|
|
|
|
groupedFields.Add(field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-29 14:44:30 +00:00
|
|
|
private static string GetStateStorageKey(ListForm listForm)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(listForm.StateStoringJson))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var document = JsonDocument.Parse(listForm.StateStoringJson);
|
|
|
|
|
if (TryGetProperty(document.RootElement, "storageKey", out var storageKey) &&
|
|
|
|
|
storageKey.ValueKind == JsonValueKind.String &&
|
|
|
|
|
!string.IsNullOrWhiteSpace(storageKey.GetString()))
|
|
|
|
|
{
|
|
|
|
|
return storageKey.GetString();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (JsonException)
|
|
|
|
|
{
|
|
|
|
|
// Fall back to the same default value used by GridOptionsDto.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $"listFormGridStorage-{listForm.ListFormCode}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool TryGetColumnStates(
|
|
|
|
|
string gridStateJson,
|
|
|
|
|
out Dictionary<string, GridColumnState> statesByField)
|
|
|
|
|
{
|
|
|
|
|
statesByField = null;
|
|
|
|
|
if (string.IsNullOrWhiteSpace(gridStateJson))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using var document = JsonDocument.Parse(gridStateJson);
|
|
|
|
|
if (!TryGetProperty(document.RootElement, "columns", out var columns) ||
|
|
|
|
|
columns.ValueKind != JsonValueKind.Array)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var states = new List<GridColumnState>();
|
|
|
|
|
AddColumnStates(columns, true, states);
|
|
|
|
|
statesByField = states
|
|
|
|
|
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName))
|
|
|
|
|
.GroupBy(x => x.FieldName, StringComparer.OrdinalIgnoreCase)
|
|
|
|
|
.ToDictionary(x => x.Key, x => x.First(), StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
return statesByField.Count > 0;
|
|
|
|
|
}
|
|
|
|
|
catch (JsonException)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void AddColumnStates(JsonElement columns, bool parentVisible, ICollection<GridColumnState> states)
|
|
|
|
|
{
|
|
|
|
|
foreach (var column in columns.EnumerateArray())
|
|
|
|
|
{
|
|
|
|
|
var visible = parentVisible &&
|
|
|
|
|
(!TryGetProperty(column, "visible", out var visibleProperty) ||
|
|
|
|
|
visibleProperty.ValueKind != JsonValueKind.False);
|
|
|
|
|
var fieldName = GetColumnFieldName(column);
|
|
|
|
|
var visibleIndex = TryGetProperty(column, "visibleIndex", out var visibleIndexProperty) &&
|
|
|
|
|
visibleIndexProperty.TryGetInt32(out var value)
|
|
|
|
|
? value
|
|
|
|
|
: states.Count;
|
2026-06-30 19:20:01 +00:00
|
|
|
var groupIndex = TryGetProperty(column, "groupIndex", out var groupIndexProperty) &&
|
|
|
|
|
groupIndexProperty.TryGetInt32(out var groupValue)
|
|
|
|
|
? groupValue
|
|
|
|
|
: (int?)null;
|
2026-06-29 14:44:30 +00:00
|
|
|
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(fieldName))
|
|
|
|
|
{
|
2026-06-30 19:20:01 +00:00
|
|
|
states.Add(new GridColumnState(fieldName, visible, visibleIndex, groupIndex));
|
2026-06-29 14:44:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TryGetProperty(column, "columns", out var childColumns) &&
|
|
|
|
|
childColumns.ValueKind == JsonValueKind.Array)
|
|
|
|
|
{
|
|
|
|
|
AddColumnStates(childColumns, visible, states);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetColumnFieldName(JsonElement column)
|
|
|
|
|
{
|
|
|
|
|
if (TryGetProperty(column, "dataField", out var dataField) &&
|
|
|
|
|
dataField.ValueKind == JsonValueKind.String)
|
|
|
|
|
{
|
|
|
|
|
return dataField.GetString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (TryGetProperty(column, "name", out var name) &&
|
|
|
|
|
name.ValueKind == JsonValueKind.String)
|
|
|
|
|
{
|
|
|
|
|
return name.GetString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-30 19:20:01 +00:00
|
|
|
private static List<ListFormField> GetGroupFieldsFromParameter(
|
|
|
|
|
IReadOnlyList<ListFormField> availableFields,
|
|
|
|
|
string groupParameter)
|
|
|
|
|
{
|
|
|
|
|
var result = new List<ListFormField>();
|
|
|
|
|
if (string.IsNullOrWhiteSpace(groupParameter))
|
|
|
|
|
{
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var fieldsByName = availableFields
|
|
|
|
|
.Where(x => !string.IsNullOrWhiteSpace(x.FieldName))
|
|
|
|
|
.ToDictionary(x => x.FieldName, StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
|
|
|
|
|
foreach (var group in groupParameter.Split(
|
|
|
|
|
PlatformConsts.MultiValueDelimiter,
|
|
|
|
|
StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries))
|
|
|
|
|
{
|
|
|
|
|
var parts = group.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
|
|
|
|
if (parts.Length > 0 && fieldsByName.TryGetValue(parts[0], out var field))
|
|
|
|
|
{
|
|
|
|
|
result.Add(field);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int? GetConfiguredGroupIndex(ListFormField field)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(field.GroupingJson))
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var grouping = JsonSerializer.Deserialize<ColumnGroupingDto>(field.GroupingJson, new JsonSerializerOptions
|
|
|
|
|
{
|
|
|
|
|
PropertyNameCaseInsensitive = true
|
|
|
|
|
});
|
|
|
|
|
return grouping?.GroupIndex;
|
|
|
|
|
}
|
|
|
|
|
catch (JsonException)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-29 14:44:30 +00:00
|
|
|
private static bool TryGetProperty(JsonElement element, string name, out JsonElement value)
|
|
|
|
|
{
|
|
|
|
|
if (element.ValueKind == JsonValueKind.Object)
|
|
|
|
|
{
|
|
|
|
|
foreach (var property in element.EnumerateObject())
|
|
|
|
|
{
|
|
|
|
|
if (string.Equals(property.Name, name, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
value = property.Value;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
value = default;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-30 19:20:01 +00:00
|
|
|
private sealed record GridColumnState(string FieldName, bool Visible, int VisibleIndex, int? GroupIndex);
|
2026-06-29 14:44:30 +00:00
|
|
|
}
|