【特性】支持从excel中读入Table列表定义。这样大多数情况下,只通过修改excel文件就能完成添加新表。
parent
0e872b5610
commit
0628dd1e6f
|
|
@ -13,9 +13,13 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
{
|
||||
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private bool OrientRow { get; set; } = true; // 以行为数据读取方向
|
||||
private const int TITLE_MIN_ROW_NUM = 2;
|
||||
private const int TITLE_MAX_ROW_NUM = 10;
|
||||
private const int TITLE_DEFAULT_ROW_NUM = 3;
|
||||
|
||||
private int TitleRows { get; set; } = 3; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释
|
||||
private bool IsOrientRow { get; set; } = true; // 以行为数据读取方向
|
||||
|
||||
public int TitleRows { get; private set; } = TITLE_DEFAULT_ROW_NUM; // 默认有三行是标题行. 第一行是字段名,第二行是中文描述,第三行是注释
|
||||
|
||||
public string RawUrl { get; }
|
||||
|
||||
|
|
@ -266,11 +270,11 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
case "r":
|
||||
case "row":
|
||||
case "l":
|
||||
case "landscape": OrientRow = true; break;
|
||||
case "landscape": IsOrientRow = true; break;
|
||||
case "c":
|
||||
case "column":
|
||||
case "p":
|
||||
case "portrait": OrientRow = false; break;
|
||||
case "portrait": IsOrientRow = false; break;
|
||||
default:
|
||||
{
|
||||
throw new Exception($"单元薄 meta 定义 row:{value} 属性值只能为landscape(l,row,r)或portrait(p,row,r)");
|
||||
|
|
@ -282,11 +286,11 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
{
|
||||
if (!int.TryParse(value, out var v))
|
||||
{
|
||||
throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[1,10]");
|
||||
throw new Exception($"单元薄 meta 定义 title_rows:{value} 属性值只能为整数[{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}]");
|
||||
}
|
||||
if (v < 2 || v > 10)
|
||||
if (v < TITLE_MIN_ROW_NUM || v > TITLE_MAX_ROW_NUM)
|
||||
{
|
||||
throw new Exception($"单元薄 title_rows 应该在 [1,10] 范围内,默认是3");
|
||||
throw new Exception($"单元薄 title_rows 应该在 [{TITLE_MIN_ROW_NUM},{TITLE_MAX_ROW_NUM}] 范围内,默认是{TITLE_DEFAULT_ROW_NUM}");
|
||||
}
|
||||
TitleRows = v;
|
||||
break;
|
||||
|
|
@ -388,7 +392,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
{
|
||||
++rowIndex; // 第1行是 meta ,标题及数据行从第2行开始
|
||||
// 重点优化横表的headerOnly模式, 此模式下只读前几行标题行,不读数据行
|
||||
if (headerOnly && this.OrientRow && rowIndex >= 10)
|
||||
if (headerOnly && this.IsOrientRow && rowIndex >= 10)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
|
@ -400,7 +404,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
rows.Add(row);
|
||||
}
|
||||
|
||||
if (OrientRow)
|
||||
if (IsOrientRow)
|
||||
{
|
||||
this._rowColumns = rows;
|
||||
}
|
||||
|
|
@ -430,7 +434,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
int titleRowNum = 1;
|
||||
if (reader.MergeCells != null)
|
||||
{
|
||||
if (OrientRow)
|
||||
if (IsOrientRow)
|
||||
{
|
||||
foreach (var mergeCell in reader.MergeCells)
|
||||
{
|
||||
|
|
@ -444,7 +448,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
|||
|
||||
foreach (var mergeCell in reader.MergeCells)
|
||||
{
|
||||
if (OrientRow)
|
||||
if (IsOrientRow)
|
||||
{
|
||||
//if (mergeCell.FromRow <= 1 && mergeCell.ToRow >= 1)
|
||||
if (mergeCell.FromRow == 1)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using Luban.Common.Utils;
|
||||
using Luban.Job.Cfg.Datas;
|
||||
using Luban.Job.Cfg.DataSources.Excel;
|
||||
using Luban.Job.Cfg.RawDefs;
|
||||
using Luban.Job.Cfg.Utils;
|
||||
using Luban.Job.Common.Defs;
|
||||
using Luban.Job.Common.RawDefs;
|
||||
using Luban.Job.Common.Types;
|
||||
using Luban.Server.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -18,6 +20,8 @@ namespace Luban.Job.Cfg.Defs
|
|||
{
|
||||
private static readonly NLog.Logger s_logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
private readonly List<string> _importExcels = new List<string>();
|
||||
|
||||
private readonly List<Branch> _branches = new();
|
||||
|
||||
private readonly List<Table> _cfgTables = new List<Table>();
|
||||
|
|
@ -30,6 +34,7 @@ namespace Luban.Job.Cfg.Defs
|
|||
|
||||
public CfgDefLoader(RemoteAgent agent) : base(agent)
|
||||
{
|
||||
RegisterRootDefineHandler("importexcel", AddImportExcel);
|
||||
RegisterRootDefineHandler("branch", AddBranch);
|
||||
RegisterRootDefineHandler("service", AddService);
|
||||
RegisterRootDefineHandler("group", AddGroup);
|
||||
|
|
@ -55,10 +60,22 @@ namespace Luban.Job.Cfg.Defs
|
|||
};
|
||||
}
|
||||
|
||||
private static readonly List<string> _excelImportRequireAttrs = new List<string> { "name" };
|
||||
private void AddImportExcel(XElement e)
|
||||
{
|
||||
ValidAttrKeys(e, null, _excelImportRequireAttrs);
|
||||
var importName = e.Attribute("name").Value;
|
||||
if (string.IsNullOrWhiteSpace(importName))
|
||||
{
|
||||
throw new Exception("importexcel 属性name不能为空");
|
||||
}
|
||||
this._importExcels.Add(importName);
|
||||
}
|
||||
|
||||
private static readonly List<string> _branchRequireAttrs = new List<string> { "name" };
|
||||
private void AddBranch(XElement e)
|
||||
{
|
||||
ValidAttrKeys(e, null, _branchRequireAttrs);
|
||||
var branchName = e.Attribute("name").Value;
|
||||
if (string.IsNullOrWhiteSpace(branchName))
|
||||
{
|
||||
|
|
@ -194,10 +211,10 @@ namespace Luban.Job.Cfg.Defs
|
|||
}
|
||||
case "map":
|
||||
{
|
||||
if ((string.IsNullOrWhiteSpace(indexStr) || indexStr.Split(',').Length != 1))
|
||||
{
|
||||
throw new Exception($"定义文件:{CurImportFile} table:{tableName} 是单键表,必须在index属性里指定1个key");
|
||||
}
|
||||
//if ((string.IsNullOrWhiteSpace(indexStr) || indexStr.Split(',').Length != 1))
|
||||
//{
|
||||
// throw new Exception($"定义文件:{CurImportFile} table:{tableName} 是单键表,必须在index属性里指定1个key");
|
||||
//}
|
||||
mode = ETableMode.MAP;
|
||||
break;
|
||||
}
|
||||
|
|
@ -220,18 +237,33 @@ namespace Luban.Job.Cfg.Defs
|
|||
private void AddTable(XElement e)
|
||||
{
|
||||
ValidAttrKeys(e, _tableOptionalAttrs, _tableRequireAttrs);
|
||||
string name = XmlUtil.GetRequiredAttribute(e, "name");
|
||||
string module = CurNamespace;
|
||||
string valueType = XmlUtil.GetRequiredAttribute(e, "value");
|
||||
bool defineFromFile = XmlUtil.GetOptionBoolAttribute(e, "define_from_file");
|
||||
string index = XmlUtil.GetOptionalAttribute(e, "index");
|
||||
string group = XmlUtil.GetOptionalAttribute(e, "group");
|
||||
string comment = XmlUtil.GetOptionalAttribute(e, "comment");
|
||||
string input = XmlUtil.GetRequiredAttribute(e, "input");
|
||||
string branchInput = XmlUtil.GetOptionalAttribute(e, "branch_input");
|
||||
string mode = XmlUtil.GetOptionalAttribute(e, "mode");
|
||||
AddTable(name, module, valueType, index, mode, group, comment, defineFromFile, input, branchInput);
|
||||
}
|
||||
|
||||
private void AddTable(string name, string module, string valueType, string index, string mode, string group,
|
||||
string comment, bool defineFromExcel, string input, string branchInput)
|
||||
{
|
||||
var p = new Table()
|
||||
{
|
||||
Name = XmlUtil.GetRequiredAttribute(e, "name"),
|
||||
Namespace = CurNamespace,
|
||||
ValueType = XmlUtil.GetRequiredAttribute(e, "value"),
|
||||
LoadDefineFromFile = XmlUtil.GetOptionBoolAttribute(e, "define_from_file"),
|
||||
Index = XmlUtil.GetOptionalAttribute(e, "index"),
|
||||
Groups = CreateGroups(XmlUtil.GetOptionalAttribute(e, "group")),
|
||||
Comment = XmlUtil.GetOptionalAttribute(e, "comment"),
|
||||
Name = name,
|
||||
Namespace = module,
|
||||
ValueType = valueType,
|
||||
LoadDefineFromFile = defineFromExcel,
|
||||
Index = index,
|
||||
Groups = CreateGroups(group),
|
||||
Comment = comment,
|
||||
Mode = ConvertMode(name, mode, index),
|
||||
};
|
||||
p.Mode = ConvertMode(p.Name, XmlUtil.GetOptionalAttribute(e, "mode"), p.Index);
|
||||
|
||||
if (p.Groups.Count == 0)
|
||||
{
|
||||
|
|
@ -241,12 +273,11 @@ namespace Luban.Job.Cfg.Defs
|
|||
{
|
||||
throw new Exception($"定义文件:{CurImportFile} table:{p.Name} group:{invalidGroup} 不存在");
|
||||
}
|
||||
p.InputFiles.AddRange(XmlUtil.GetRequiredAttribute(e, "input").Split(','));
|
||||
p.InputFiles.AddRange(input.Split(','));
|
||||
|
||||
var branchInputAttr = e.Attribute("branch_input");
|
||||
if (branchInputAttr != null)
|
||||
if (!string.IsNullOrWhiteSpace(branchInput))
|
||||
{
|
||||
foreach (var subBranchStr in branchInputAttr.Value.Split('|').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)))
|
||||
foreach (var subBranchStr in branchInput.Split('|').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)))
|
||||
{
|
||||
var nameAndDirs = subBranchStr.Split(':');
|
||||
if (nameAndDirs.Length != 2)
|
||||
|
|
@ -261,6 +292,11 @@ namespace Luban.Job.Cfg.Defs
|
|||
}
|
||||
}
|
||||
|
||||
AddTableList(p);
|
||||
}
|
||||
|
||||
private void AddTableList(Table p)
|
||||
{
|
||||
if (!_name2CfgTable.TryAdd(p.Name, p))
|
||||
{
|
||||
var exist = _name2CfgTable[p.Name];
|
||||
|
|
@ -269,9 +305,7 @@ namespace Luban.Job.Cfg.Defs
|
|||
_cfgTables.Add(p);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private async Task<CfgBean> LoadDefineFromFileAsync(Table table, string dataDir)
|
||||
private async Task<CfgBean> LoadTableRecordDefineFromFileAsync(Table table, string dataDir)
|
||||
{
|
||||
var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, table.InputFiles, dataDir);
|
||||
var file = inputFileInfos[0];
|
||||
|
|
@ -285,7 +319,8 @@ namespace Luban.Job.Cfg.Defs
|
|||
var rc = sheet.RowColumns;
|
||||
var attrRow = sheet.RowColumns[0];
|
||||
var titleRow = sheet.RowColumns[1];
|
||||
var descRow = sheet.RowColumns[2];
|
||||
// 有可能没有注释行,此时使用标题行,这个是必须有的
|
||||
var descRow = sheet.TitleRows >= 3 ? sheet.RowColumns[2] : titleRow;
|
||||
foreach (var f in sheet.RootFields)
|
||||
{
|
||||
var cf = new CfgField() { Name = f.Name, Id = 0 };
|
||||
|
|
@ -374,12 +409,12 @@ namespace Luban.Job.Cfg.Defs
|
|||
return cb;
|
||||
}
|
||||
|
||||
public async Task LoadDefinesFromFileAsync(string dataDir)
|
||||
private async Task LoadTableRecordDefinesFromFileAsync(string dataDir)
|
||||
{
|
||||
var loadTasks = new List<Task<CfgBean>>();
|
||||
foreach (var table in this._cfgTables.Where(t => t.LoadDefineFromFile))
|
||||
{
|
||||
loadTasks.Add(Task.Run(async () => await this.LoadDefineFromFileAsync(table, dataDir)));
|
||||
loadTasks.Add(Task.Run(async () => await this.LoadTableRecordDefineFromFileAsync(table, dataDir)));
|
||||
}
|
||||
|
||||
foreach (var task in loadTasks)
|
||||
|
|
@ -388,6 +423,75 @@ namespace Luban.Job.Cfg.Defs
|
|||
}
|
||||
}
|
||||
|
||||
private async Task LoadTableListFromFileAsync(string dataDir)
|
||||
{
|
||||
if (this._importExcels.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, this._importExcels, dataDir);
|
||||
|
||||
var defTableRecordType = new DefBean(new CfgBean()
|
||||
{
|
||||
Namespace = "__intern__",
|
||||
Name = "__TextInfo__",
|
||||
Parent = "",
|
||||
Alias = "",
|
||||
IsValueType = false,
|
||||
Sep = "",
|
||||
TypeId = 0,
|
||||
IsSerializeCompatible = false,
|
||||
Fields = new List<Common.RawDefs.Field>
|
||||
{
|
||||
new CfgField() { Name = "name", Type = "string" },
|
||||
new CfgField() { Name = "module", Type = "string" },
|
||||
new CfgField() { Name = "value_type", Type = "string" },
|
||||
new CfgField() { Name = "index", Type = "string" },
|
||||
new CfgField() { Name = "mode", Type = "string" },
|
||||
new CfgField() { Name = "group", Type = "string" },
|
||||
new CfgField() { Name = "comment", Type = "string" },
|
||||
new CfgField() { Name = "define_from_excel", Type = "bool" },
|
||||
new CfgField() { Name = "input", Type = "string" },
|
||||
new CfgField() { Name = "branch_input", Type = "string" },
|
||||
}
|
||||
})
|
||||
{
|
||||
AssemblyBase = new DefAssembly("", null, true, Agent),
|
||||
};
|
||||
defTableRecordType.PreCompile();
|
||||
defTableRecordType.Compile();
|
||||
defTableRecordType.PostCompile();
|
||||
var tableRecordType = new TBean(defTableRecordType, false);
|
||||
|
||||
foreach (var file in inputFileInfos)
|
||||
{
|
||||
var source = new ExcelDataSource();
|
||||
var bytes = await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5);
|
||||
var records = DataLoaderUtil.LoadCfgRecords(tableRecordType, file.OriginFile, null, bytes, true, false);
|
||||
foreach (var r in records)
|
||||
{
|
||||
DBean data = r.Data;
|
||||
//s_logger.Info("== read text:{}", r.Data);
|
||||
string name = (data.GetField("name") as DString).Value;
|
||||
string module = (data.GetField("module") as DString).Value;
|
||||
string valueType = (data.GetField("value_type") as DString).Value;
|
||||
string index = (data.GetField("index") as DString).Value;
|
||||
string mode = (data.GetField("mode") as DString).Value;
|
||||
string group = (data.GetField("group") as DString).Value;
|
||||
string comment = (data.GetField("commnet") as DString).Value;
|
||||
bool isDefineFromExcel = (data.GetField("define_from_excel") as DBool).Value;
|
||||
string inputFile = (data.GetField("input") as DString).Value;
|
||||
string branchInput = (data.GetField("branch_input") as DString).Value;
|
||||
AddTable(name, module, valueType, index, mode, group, comment, isDefineFromExcel, inputFile, branchInput);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public async Task LoadDefinesFromFileAsync(string dataDir)
|
||||
{
|
||||
await LoadTableListFromFileAsync(dataDir);
|
||||
await LoadTableRecordDefinesFromFileAsync(dataDir);
|
||||
}
|
||||
|
||||
private static readonly List<string> _fieldOptionalAttrs = new List<string> {
|
||||
"index", "sep", "validator", "key_validator", "value_validator",
|
||||
|
|
|
|||
Loading…
Reference in New Issue