From 23e797a3f38bf14561bf707551f567be5c9cd192 Mon Sep 17 00:00:00 2001 From: tdx Date: Fri, 27 Jun 2025 10:25:34 +0000 Subject: [PATCH] SVN r808 SVN-Revision: r808 --- 插件库/Lskj.Control/GridControlEx.cs | 175 ++++++++++++++------------- 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/插件库/Lskj.Control/GridControlEx.cs b/插件库/Lskj.Control/GridControlEx.cs index 50eeba5..9566086 100644 --- a/插件库/Lskj.Control/GridControlEx.cs +++ b/插件库/Lskj.Control/GridControlEx.cs @@ -7021,7 +7021,7 @@ namespace Lskj.Control GridColumnModel GroupPrimary = ColumnList.FirstOrDefault(o => o.IsCustomGroupPrimary); GridColumnModel GroupFieldprimary = ColumnList.FirstOrDefault(o => o.IsCustomGroupField == 1); List GroupField = ColumnList.Where(o => o.IsCustomGroupField == 2).ToList(); - + List sumField = ColumnList.Where(o => o.IsCustomGroupField == 3).ToList(); if (GroupPrimary == null || GroupFieldprimary == null || !GroupField.Any()) return; // 数据不足直接退出 @@ -7072,7 +7072,7 @@ namespace Lskj.Control var dynamicHeaders = originalDataSource.AsEnumerable() .Select(r => r.Field(GroupFieldprimary.FieldName)) .Distinct().Where(x => !string.IsNullOrEmpty(x)).ToList(); - + // 为每个动态表头生成GridBand,并添加子列 foreach (string headerName in dynamicHeaders) { @@ -7111,7 +7111,7 @@ namespace Lskj.Control } bandedGridControlEx.BandedView.EndUpdate(); // 构建最终动态数据源 - DataTable dynamicDataTable = BuildDynamicDataSource(originalDataSource, GroupPrimary, GroupFieldprimary, GroupField, normalColumns, dynamicHeaders); + DataTable dynamicDataTable = BuildDynamicDataSource(originalDataSource, GroupPrimary, GroupFieldprimary, GroupField, normalColumns, sumField, dynamicHeaders); bandedGridControlEx.gridControl.DataSource = dynamicDataTable; } @@ -7125,98 +7125,75 @@ namespace Lskj.Control /// /// /// - private DataTable BuildDynamicDataSource(DataTable originalDataSource, - GridColumnModel GroupPrimary, - GridColumnModel GroupFieldprimary, - List GroupField, - List normalColumns, - List dynamicHeaders) + /// + /// 把行转列、动态列拼接,并对指定列做求和 + /// + private DataTable BuildDynamicDataSource( + DataTable original, // 原始数据 + GridColumnModel keyCol, // 分组主键 + GridColumnModel headerCol, // 动态列的“Header”列 + List subCols, // Header 后要展开的子列 + List normalCols, // 普通列(取首行值) + List sumColumns, // 需要求和的列 + List headers) // Header 值集合 { - try + var dt = new DataTable(); + + /* ============ 1. 建列 ============ */ + dt.Columns.Add(keyCol.FieldName, original.Columns[keyCol.FieldName].DataType); + + // 普通列 + var exist = new HashSet(original.Columns.Cast() + .Select(c => c.ColumnName)); + foreach (var col in normalCols.Where(c => exist.Contains(c.FieldName) + && c.FieldName != keyCol.FieldName)) + dt.Columns.Add(col.FieldName, original.Columns[col.FieldName].DataType); + + // 求和列 + foreach (var col in sumColumns.Where(c => exist.Contains(c.FieldName))) + if (!dt.Columns.Contains(col.FieldName)) + dt.Columns.Add(col.FieldName, original.Columns[col.FieldName].DataType); + + // 动态列:统一 string + foreach (string h in headers) + foreach (var s in subCols) + dt.Columns.Add($"{h}_{s.FieldName}", typeof(string)); + + /* ============ 2. 分组聚合 ============ */ + foreach (var grp in original.AsEnumerable().GroupBy(r => r[keyCol.FieldName])) { - DataTable dtResult = new DataTable(); + var newRow = dt.NewRow(); + var first = grp.First(); - // 添加主键列 - if (!dtResult.Columns.Contains(GroupPrimary.FieldName)) + newRow[keyCol.FieldName] = first[keyCol.FieldName]; + + // 普通列:取首行 + foreach (var col in normalCols.Where(c => exist.Contains(c.FieldName))) + newRow[col.FieldName] = first[col.FieldName]; + + // 求和列 + foreach (var col in sumColumns.Where(c => exist.Contains(c.FieldName))) { - Type dataType = originalDataSource.Columns[GroupPrimary.FieldName].DataType; - dtResult.Columns.Add(GroupPrimary.FieldName, dataType); + var sum = grp + .Where(r => r[col.FieldName] != DBNull.Value) + .Sum(r => Convert.ToDecimal(r[col.FieldName])); + newRow[col.FieldName] = sum; } - - // 添加普通列,仅当原数据源存在时才添加 - foreach (var col in normalColumns) - { - if (originalDataSource.Columns.Contains(col.FieldName) && col.FieldName != GroupPrimary.FieldName) + // 动态列 + var lookup = grp.ToLookup(r => r[headerCol.FieldName]?.ToString()); + foreach (string h in headers) + foreach (var s in subCols) { - Type dataType = originalDataSource.Columns[col.FieldName].DataType; - dtResult.Columns.Add(col.FieldName, dataType); - } - } - - // 添加动态列 (改为string类型避免异常) - foreach (string header in dynamicHeaders) - { - foreach (var subField in GroupField) - { - string dynamicFieldName = $"{header}_{subField.FieldName}"; - if (!dtResult.Columns.Contains(dynamicFieldName)) - { - Type dataType = originalDataSource.Columns[subField.FieldName].DataType; - dtResult.Columns.Add(dynamicFieldName, dataType); // <-- 此处已修改为string - } - } - } - - // 根据主键聚合数据 - var groupedData = originalDataSource.AsEnumerable() - .GroupBy(row => row.Field(GroupPrimary.FieldName)); - - foreach (var group in groupedData) - { - DataRow newRow = dtResult.NewRow(); - - // 主键列赋值 - DataRow firstRow = group.First(); - newRow[GroupPrimary.FieldName] = firstRow[GroupPrimary.FieldName]; - - // 普通列赋值(需判断原数据源中存在) - foreach (var col in normalColumns) - { - if (originalDataSource.Columns.Contains(col.FieldName)) - newRow[col.FieldName] = firstRow[col.FieldName]; + string dyn = $"{h}_{s.FieldName}"; + var hit = lookup[h].FirstOrDefault(); + newRow[dyn] = hit?[s.FieldName]?.ToString(); } - // 动态聚合列赋值 - foreach (var header in dynamicHeaders) - { - var matchedRow = group.FirstOrDefault(r => r.Field(GroupFieldprimary.FieldName) == header); - foreach (var subField in GroupField) - { - string dynamicFieldName = $"{header}_{subField.FieldName}"; - - object value = DBNull.Value; - - if (matchedRow != null && originalDataSource.Columns.Contains(subField.FieldName)) - { - value = matchedRow[subField.FieldName]; - } - - newRow[dynamicFieldName] = value; - } - } - - dtResult.Rows.Add(newRow); - } - - return dtResult; - } - catch (Exception ex) - { - // 最好将异常记录下来 - Console.WriteLine(ex.Message); - return null; + dt.Rows.Add(newRow); } + + return dt; } @@ -8739,4 +8716,30 @@ namespace Lskj.Control { // 只处理列名可解析成日期的列 if (!DateTime.TryParse(col.FieldName, out _)) - \ No newline at end of file + continue; + + // 取 “Sum” 合计 + var sumItem = col.Summary + .OfType() + .FirstOrDefault(s => s.SummaryType == SummaryItemType.Sum); + + bool needRed = false; + + if (sumItem?.SummaryValue != null && + decimal.TryParse(sumItem.SummaryValue.ToString(), out var colSum) && + jhrowitem.Table.Columns.Contains(col.FieldName) && + decimal.TryParse(jhrowitem[col.FieldName].ToString(), out var planVal)) + { + needRed = (colSum != planVal); + } + + // 只改表头文字颜色 + col.AppearanceHeader.ForeColor = needRed ? Color.Red : Color.Black; + col.AppearanceHeader.Options.UseForeColor = true; + } + // 立刻刷新表头 + gridView.Invalidate(); + } + + } +} \ No newline at end of file