From e75289d82fdf7dbe47969aa7ea5e233062a6689f Mon Sep 17 00:00:00 2001 From: walon Date: Thu, 9 Sep 2021 11:19:07 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E9=87=8D=E6=9E=84=E3=80=91cfg=20?= =?UTF-8?q?=E4=BB=8Eexcel=E4=B8=AD=E8=AF=BB=E5=8F=96table=E7=9A=84value=20?= =?UTF-8?q?type=E5=AE=9A=E4=B9=89=E7=9A=84=E4=BB=A3=E7=A0=81=E7=9A=84?= =?UTF-8?q?=E4=B8=80=E4=BA=9B=E5=BE=AE=E5=B0=8F=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Source/DataSources/Excel/Sheet.cs | 35 +++++++++++++------ src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs | 16 +++++---- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs index 5a103d6..3120854 100644 --- a/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs +++ b/src/Luban.Job.Cfg/Source/DataSources/Excel/Sheet.cs @@ -21,7 +21,9 @@ namespace Luban.Job.Cfg.DataSources.Excel private bool IsOrientRow { get; set; } = true; // 以行为数据读取方向 - public int TitleRows { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释 + public int HeaderRowCount { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释 + + public int AttrRowCount { get; private set; } public string RawUrl { get; } @@ -358,7 +360,7 @@ namespace Luban.Job.Cfg.DataSources.Excel { throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}"); } - TitleRows = v; + HeaderRowCount = v; break; } default: @@ -397,7 +399,7 @@ namespace Luban.Job.Cfg.DataSources.Excel { if (mergeCell.FromRow == depth + 1 && mergeCell.FromColumn >= fromColumn && mergeCell.ToColumn <= toColumn) { - string subTitleName = row[mergeCell.FromColumn].Value?.ToString().Trim(); + string subTitleName = row[mergeCell.FromColumn].Value?.ToString()?.Trim(); if (!string.IsNullOrWhiteSpace(subTitleName)) { var newTitle = new Title() { Name = subTitleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn }; @@ -459,7 +461,7 @@ namespace Luban.Job.Cfg.DataSources.Excel { ++rowIndex; // 第1行是 meta ,标题及数据行从第2行开始 // 重点优化横表的headerOnly模式, 此模式下只读前几行标题行,不读数据行 - if (headerOnly && this.IsOrientRow && rowIndex >= 10) + if (headerOnly && this.IsOrientRow && rowIndex > this.HeaderRowCount) { break; } @@ -498,7 +500,8 @@ namespace Luban.Job.Cfg.DataSources.Excel _rootTitle = new Title() { Root = true, Name = ROOT_TITLE_NAME, FromIndex = 1, ToIndex = rows.Select(r => r.Count).Max() - 1 }; - int titleRowNum = 1; + int fieldRowCount = 1; + int attrRowCount = 1; if (reader.MergeCells != null) { if (IsOrientRow) @@ -507,7 +510,16 @@ namespace Luban.Job.Cfg.DataSources.Excel { if (mergeCell.FromRow == 1 && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0) { - titleRowNum = mergeCell.ToRow - mergeCell.FromRow + 1; + fieldRowCount = mergeCell.ToRow - mergeCell.FromRow + 1; + break; + } + } + foreach (var mergeCell in reader.MergeCells) + { + if (mergeCell.FromRow == 1 + fieldRowCount && mergeCell.FromColumn == 0 && mergeCell.ToColumn == 0) + { + attrRowCount = mergeCell.ToRow - mergeCell.FromRow + 1; + break; } } } @@ -521,7 +533,7 @@ namespace Luban.Job.Cfg.DataSources.Excel if (mergeCell.FromRow == 1) { // 标题 行 - titleRowNum = Math.Max(titleRowNum, mergeCell.ToRow - mergeCell.FromRow + 1); + fieldRowCount = Math.Max(fieldRowCount, mergeCell.ToRow - mergeCell.FromRow + 1); var titleName = _rowColumns[0][mergeCell.FromColumn].Value?.ToString()?.Trim(); if (string.IsNullOrWhiteSpace(titleName)) { @@ -529,9 +541,9 @@ namespace Luban.Job.Cfg.DataSources.Excel } var newTitle = new Title() { Name = titleName, FromIndex = mergeCell.FromColumn, ToIndex = mergeCell.ToColumn }; - if (titleRowNum > 1) + if (fieldRowCount > 1) { - InitSubTitles(newTitle, rows, reader.MergeCells, titleRowNum, 1, mergeCell.FromColumn, mergeCell.ToColumn); + InitSubTitles(newTitle, rows, reader.MergeCells, fieldRowCount, 1, mergeCell.FromColumn, mergeCell.ToColumn); } _rootTitle.AddSubTitle(newTitle); //s_logger.Info("=== sheet:{sheet} title:{title}", Name, newTitle); @@ -554,6 +566,7 @@ namespace Luban.Job.Cfg.DataSources.Excel } } + this.AttrRowCount = attrRowCount; //TODO 其实有bug. 未处理只占一列的 多级标题头 @@ -589,12 +602,12 @@ namespace Luban.Job.Cfg.DataSources.Excel if (headerOnly) { // 删除字段名行,保留属性行开始的行 - this._rowColumns.RemoveRange(0, Math.Min(titleRowNum, this._rowColumns.Count)); + this._rowColumns.RemoveRange(0, Math.Min(fieldRowCount, this._rowColumns.Count)); } else { // 删除所有标题行,包含字段名行、属性行、标题、描述等等非有效数据行 - this._rowColumns.RemoveRange(0, Math.Min(TitleRows, this._rowColumns.Count)); + this._rowColumns.RemoveRange(0, Math.Min(HeaderRowCount, this._rowColumns.Count)); // 删除忽略的记录行 this._rowColumns.RemoveAll(row => DataUtil.IsIgnoreTag(GetRowTag(row))); } diff --git a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs index 345726c..6e86638 100644 --- a/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs +++ b/src/Luban.Job.Cfg/Source/Defs/CfgDefLoader.cs @@ -311,7 +311,7 @@ namespace Luban.Job.Cfg.Defs _cfgTables.Add(p); } - private async Task LoadTableRecordDefineFromFileAsync(Table table, string dataDir) + private async Task LoadTableValueTypeDefineFromFileAsync(Table table, string dataDir) { var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, table.InputFiles, dataDir); var file = inputFileInfos[0]; @@ -323,9 +323,13 @@ namespace Luban.Job.Cfg.Defs var rc = sheet.RowColumns; var attrRow = sheet.RowColumns[0]; - var titleRow = sheet.RowColumns[1]; + if (rc.Count < sheet.AttrRowCount + 1) + { + throw new Exception($"table:'{table.Name}' file:{file.OriginFile} 至少包含 属性行和标题行"); + } + var titleRow = sheet.RowColumns[sheet.AttrRowCount]; // 有可能没有注释行,此时使用标题行,这个是必须有的 - var descRow = sheet.TitleRows >= 3 ? sheet.RowColumns[2] : titleRow; + var descRow = sheet.HeaderRowCount >= sheet.AttrRowCount + 2 ? sheet.RowColumns[sheet.AttrRowCount + 1] : titleRow; foreach (var f in sheet.RootFields) { var cf = new CfgField() { Name = f.Name, Id = 0 }; @@ -428,12 +432,12 @@ namespace Luban.Job.Cfg.Defs return cb; } - private async Task LoadTableRecordDefinesFromFileAsync(string dataDir) + private async Task LoadTableValueTypeDefinesFromFileAsync(string dataDir) { var loadTasks = new List>(); foreach (var table in this._cfgTables.Where(t => t.LoadDefineFromFile)) { - loadTasks.Add(Task.Run(async () => await this.LoadTableRecordDefineFromFileAsync(table, dataDir))); + loadTasks.Add(Task.Run(async () => await this.LoadTableValueTypeDefineFromFileAsync(table, dataDir))); } foreach (var task in loadTasks) @@ -723,7 +727,7 @@ namespace Luban.Job.Cfg.Defs public async Task LoadDefinesFromFileAsync(string dataDir) { await Task.WhenAll(LoadTableListFromFileAsync(dataDir), LoadEnumListFromFileAsync(dataDir), LoadBeanListFromFileAsync(dataDir)); - await LoadTableRecordDefinesFromFileAsync(dataDir); + await LoadTableValueTypeDefinesFromFileAsync(dataDir); } private static readonly List _fieldOptionalAttrs = new()