【特性】支持从excel文件的标题头里直接读取定义,定义和数据一体了。简化写记录定义的麻烦
parent
94197d9968
commit
2ca0cebe99
|
|
@ -52,10 +52,46 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Sheet LoadFirstSheet(string rawUrl, string sheetName, Stream stream)
|
||||||
|
{
|
||||||
|
s_logger.Trace("{filename} {sheet}", rawUrl, sheetName);
|
||||||
|
RawUrl = rawUrl;
|
||||||
|
string ext = Path.GetExtension(rawUrl);
|
||||||
|
using (var reader = ext != ".csv" ? ExcelReaderFactory.CreateReader(stream) : ExcelReaderFactory.CreateCsvReader(stream))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (sheetName == null || reader.Name == sheetName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var sheet = ReadSheetHeader(rawUrl, reader);
|
||||||
|
if (sheet != null)
|
||||||
|
{
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new Exception($"excel:{rawUrl} sheet:{reader.Name} 读取失败. ==> {e.Message}", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} while (reader.NextResult());
|
||||||
|
}
|
||||||
|
throw new Exception($"excel:{rawUrl} 不包含有效的单元薄(有效单元薄的A0单元格必须是##).");
|
||||||
|
}
|
||||||
|
|
||||||
private Sheet ReadSheet(string url, IExcelDataReader reader)
|
private Sheet ReadSheet(string url, IExcelDataReader reader)
|
||||||
{
|
{
|
||||||
var sheet = new Sheet(url, reader.Name ?? "");
|
var sheet = new Sheet(url, reader.Name ?? "");
|
||||||
return sheet.Load(reader) ? sheet : null;
|
return sheet.Load(reader, false) ? sheet : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Sheet ReadSheetHeader(string url, IExcelDataReader reader)
|
||||||
|
{
|
||||||
|
var sheet = new Sheet(url, reader.Name ?? "");
|
||||||
|
return sheet.Load(reader, true) ? sheet : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override List<Record> ReadMulti(TBean type)
|
public override List<Record> ReadMulti(TBean type)
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,10 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
|
|
||||||
private Title _rootTitle;
|
private Title _rootTitle;
|
||||||
|
|
||||||
|
public List<Title> RootFields => _rootTitle.SubTitleList;
|
||||||
|
|
||||||
|
public List<List<Cell>> RowColumns => _rowColumns;
|
||||||
|
|
||||||
public class Title
|
public class Title
|
||||||
{
|
{
|
||||||
public int FromIndex { get; set; }
|
public int FromIndex { get; set; }
|
||||||
|
|
@ -213,7 +217,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
this.Name = name;
|
this.Name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Load(IExcelDataReader reader)
|
public bool Load(IExcelDataReader reader, bool headerOnly)
|
||||||
{
|
{
|
||||||
//s_logger.Info("read sheet:{sheet}", reader.Name);
|
//s_logger.Info("read sheet:{sheet}", reader.Name);
|
||||||
if (!ParseMeta(reader))
|
if (!ParseMeta(reader))
|
||||||
|
|
@ -221,7 +225,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadRemainRows(reader);
|
LoadRemainRows(reader, headerOnly);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -368,7 +372,7 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void LoadRemainRows(IExcelDataReader reader)
|
private void LoadRemainRows(IExcelDataReader reader, bool headerOnly)
|
||||||
{
|
{
|
||||||
// TODO 优化性能
|
// TODO 优化性能
|
||||||
// 几个思路
|
// 几个思路
|
||||||
|
|
@ -508,7 +512,14 @@ namespace Luban.Job.Cfg.DataSources.Excel
|
||||||
//}
|
//}
|
||||||
|
|
||||||
// 删除标题行
|
// 删除标题行
|
||||||
this._rowColumns.RemoveRange(0, Math.Min(TitleRows + titleRowNum - 1, this._rowColumns.Count));
|
if (headerOnly)
|
||||||
|
{
|
||||||
|
this._rowColumns.RemoveRange(0, Math.Min(titleRowNum, this._rowColumns.Count));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._rowColumns.RemoveRange(0, Math.Min(TitleRows + titleRowNum - 1, this._rowColumns.Count));
|
||||||
|
}
|
||||||
|
|
||||||
// 删除忽略的记录行
|
// 删除忽略的记录行
|
||||||
this._rowColumns.RemoveAll(row => AbstractDataSource.IsIgnoreTag(GetRowTag(row)));
|
this._rowColumns.RemoveAll(row => AbstractDataSource.IsIgnoreTag(GetRowTag(row)));
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
using Luban.Common.Utils;
|
using Luban.Common.Utils;
|
||||||
|
using Luban.Job.Cfg.DataSources.Excel;
|
||||||
using Luban.Job.Cfg.RawDefs;
|
using Luban.Job.Cfg.RawDefs;
|
||||||
|
using Luban.Job.Cfg.Utils;
|
||||||
using Luban.Job.Common.Defs;
|
using Luban.Job.Common.Defs;
|
||||||
using Luban.Job.Common.RawDefs;
|
using Luban.Job.Common.RawDefs;
|
||||||
using Luban.Server.Common;
|
using Luban.Server.Common;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Luban.Job.Cfg.Defs
|
namespace Luban.Job.Cfg.Defs
|
||||||
|
|
@ -152,9 +156,6 @@ namespace Luban.Job.Cfg.Defs
|
||||||
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
|
_cfgServices.Add(new Service() { Name = name, Manager = manager, Groups = groups, Refs = refs });
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<string> _tableOptionalAttrs = new List<string> { "index", "mode", "group", "branch_input", "comment" };
|
|
||||||
private readonly List<string> _tableRequireAttrs = new List<string> { "name", "value", "input" };
|
|
||||||
|
|
||||||
|
|
||||||
private readonly Dictionary<string, Table> _name2CfgTable = new Dictionary<string, Table>();
|
private readonly Dictionary<string, Table> _name2CfgTable = new Dictionary<string, Table>();
|
||||||
|
|
||||||
|
|
@ -213,6 +214,9 @@ namespace Luban.Job.Cfg.Defs
|
||||||
return mode;
|
return mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private readonly List<string> _tableOptionalAttrs = new List<string> { "index", "mode", "group", "branch_input", "comment", "define_from_file" };
|
||||||
|
private readonly List<string> _tableRequireAttrs = new List<string> { "name", "value", "input" };
|
||||||
|
|
||||||
private void AddTable(XElement e)
|
private void AddTable(XElement e)
|
||||||
{
|
{
|
||||||
ValidAttrKeys(e, _tableOptionalAttrs, _tableRequireAttrs);
|
ValidAttrKeys(e, _tableOptionalAttrs, _tableRequireAttrs);
|
||||||
|
|
@ -222,6 +226,7 @@ namespace Luban.Job.Cfg.Defs
|
||||||
Name = XmlUtil.GetRequiredAttribute(e, "name"),
|
Name = XmlUtil.GetRequiredAttribute(e, "name"),
|
||||||
Namespace = CurNamespace,
|
Namespace = CurNamespace,
|
||||||
ValueType = XmlUtil.GetRequiredAttribute(e, "value"),
|
ValueType = XmlUtil.GetRequiredAttribute(e, "value"),
|
||||||
|
LoadDefineFromFile = XmlUtil.GetOptionBoolAttribute(e, "define_from_file"),
|
||||||
Index = XmlUtil.GetOptionalAttribute(e, "index"),
|
Index = XmlUtil.GetOptionalAttribute(e, "index"),
|
||||||
Groups = CreateGroups(XmlUtil.GetOptionalAttribute(e, "group")),
|
Groups = CreateGroups(XmlUtil.GetOptionalAttribute(e, "group")),
|
||||||
Comment = XmlUtil.GetOptionalAttribute(e, "comment"),
|
Comment = XmlUtil.GetOptionalAttribute(e, "comment"),
|
||||||
|
|
@ -266,6 +271,124 @@ namespace Luban.Job.Cfg.Defs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<CfgBean> LoadDefineFromFileAsync(Table table, string dataDir)
|
||||||
|
{
|
||||||
|
var inputFileInfos = await DataLoaderUtil.CollectInputFilesAsync(this.Agent, table.InputFiles, dataDir);
|
||||||
|
var file = inputFileInfos[0];
|
||||||
|
|
||||||
|
var source = new ExcelDataSource();
|
||||||
|
var stream = new MemoryStream(await this.Agent.GetFromCacheOrReadAllBytesAsync(file.ActualFile, file.MD5));
|
||||||
|
var sheet = source.LoadFirstSheet(file.OriginFile, file.SheetName, stream);
|
||||||
|
|
||||||
|
var cb = new CfgBean() { Namespace = table.Namespace, Name = table.ValueType, };
|
||||||
|
|
||||||
|
var rc = sheet.RowColumns;
|
||||||
|
var attrRow = sheet.RowColumns[0];
|
||||||
|
var titleRow = sheet.RowColumns[1];
|
||||||
|
var descRow = sheet.RowColumns[2];
|
||||||
|
foreach (var f in sheet.RootFields)
|
||||||
|
{
|
||||||
|
var cf = new CfgField() { Name = f.Name, Id = 0 };
|
||||||
|
|
||||||
|
|
||||||
|
string[] attrs = attrRow[f.FromIndex].Value?.ToString().Split('&');
|
||||||
|
|
||||||
|
if (attrs.Length == 0 || string.IsNullOrWhiteSpace(attrs[0]))
|
||||||
|
{
|
||||||
|
throw new Exception($"table:{table.Name} file:{file.OriginFile} title:{f.Name} type missing!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 优先取desc行,如果为空,则取title行
|
||||||
|
|
||||||
|
cf.Comment = descRow[f.FromIndex].Value?.ToString();
|
||||||
|
if (string.IsNullOrWhiteSpace(cf.Comment))
|
||||||
|
{
|
||||||
|
cf.Comment = titleRow[f.FromIndex].Value?.ToString();
|
||||||
|
}
|
||||||
|
if (string.IsNullOrWhiteSpace(cf.Comment))
|
||||||
|
{
|
||||||
|
cf.Comment = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
cf.Type = attrs[0];
|
||||||
|
|
||||||
|
for (int i = 1; i < attrs.Length; i++)
|
||||||
|
{
|
||||||
|
var pair = attrs[i].Split('=');
|
||||||
|
if (pair.Length != 2)
|
||||||
|
{
|
||||||
|
throw new Exception($"table:{table.Name} file:{file.OriginFile} title:{f.Name} attr: '{attrs[i]}' is invalid!");
|
||||||
|
}
|
||||||
|
var attrName = pair[0];
|
||||||
|
var attrValue = pair[1];
|
||||||
|
switch (attrName)
|
||||||
|
{
|
||||||
|
case "index":
|
||||||
|
{
|
||||||
|
cf.Index = attrValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "sep":
|
||||||
|
{
|
||||||
|
cf.Sep = attrValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "ref":
|
||||||
|
case "path":
|
||||||
|
case "range":
|
||||||
|
{
|
||||||
|
var validator = new Validator() { Type = attrName, Rule = attrValue };
|
||||||
|
cf.Validators.Add(validator);
|
||||||
|
cf.ValueValidators.Add(validator);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "multi_lines":
|
||||||
|
{
|
||||||
|
cf.IsMultiRow = attrValue == "1" || attrValue.Equals("true", StringComparison.OrdinalIgnoreCase);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "group":
|
||||||
|
{
|
||||||
|
cf.Groups = attrValue.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)).ToList();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "comment":
|
||||||
|
{
|
||||||
|
cf.Comment = attrValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "convert":
|
||||||
|
{
|
||||||
|
cf.Converter = attrValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
throw new Exception($"table:{table.Name} file:{file.OriginFile} title:{f.Name} attr: '{attrs[i]}' is invalid!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb.Fields.Add(cf);
|
||||||
|
}
|
||||||
|
return cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task LoadDefinesFromFileAsync(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)));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var task in loadTasks)
|
||||||
|
{
|
||||||
|
this._beans.Add(await task);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static readonly List<string> _fieldOptionalAttrs = new List<string> {
|
private static readonly List<string> _fieldOptionalAttrs = new List<string> {
|
||||||
"index", "sep", "validator", "key_validator", "value_validator",
|
"index", "sep", "validator", "key_validator", "value_validator",
|
||||||
"ref", "path", "range", "multi_rows", "group", "res", "convert", "comment" };
|
"ref", "path", "range", "multi_rows", "group", "res", "convert", "comment" };
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ namespace Luban.Job.Cfg
|
||||||
timer.StartPhase("build defines");
|
timer.StartPhase("build defines");
|
||||||
var loader = new CfgDefLoader(agent);
|
var loader = new CfgDefLoader(agent);
|
||||||
await loader.LoadAsync(args.DefineFile);
|
await loader.LoadAsync(args.DefineFile);
|
||||||
|
await loader.LoadDefinesFromFileAsync(inputDataDir);
|
||||||
timer.EndPhaseAndLog();
|
timer.EndPhaseAndLog();
|
||||||
|
|
||||||
var rawDefines = loader.BuildDefines();
|
var rawDefines = loader.BuildDefines();
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ namespace Luban.Job.Cfg.RawDefs
|
||||||
|
|
||||||
public string ValueType { get; set; }
|
public string ValueType { get; set; }
|
||||||
|
|
||||||
|
public bool LoadDefineFromFile { get; set; }
|
||||||
|
|
||||||
public ETableMode Mode { get; set; }
|
public ETableMode Mode { get; set; }
|
||||||
|
|
||||||
public string Comment { get; set; }
|
public string Comment { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import ByteBuf = Bright.Serialization.ByteBuf";
|
||||||
}
|
}
|
||||||
|
|
||||||
public const string BrightByteBufPathImportsFormat = "import ByteBuf from '{0}/serialization/ByteBuf'";
|
public const string BrightByteBufPathImportsFormat = "import ByteBuf from '{0}/serialization/ByteBuf'";
|
||||||
public const string BrightByteBufPackageImportsFormat = "import ByteBuf from '{0}'";
|
public const string BrightByteBufPackageImportsFormat = "import {{ByteBuf}} from '{0}'";
|
||||||
|
|
||||||
public static string GetVectorImports(string path, string package)
|
public static string GetVectorImports(string path, string package)
|
||||||
{
|
{
|
||||||
|
|
@ -31,9 +31,9 @@ import Vector3 from '{0}/math/Vector3'
|
||||||
import Vector4 from '{0}/math/Vector4'
|
import Vector4 from '{0}/math/Vector4'
|
||||||
";
|
";
|
||||||
public const string VectorPackageImportsFormat = @"
|
public const string VectorPackageImportsFormat = @"
|
||||||
import Vector2 from '{0}'
|
import {{Vector2}} from '{0}'
|
||||||
import Vector3 from '{0}'
|
import {{Vector3}} from '{0}'
|
||||||
import Vector4 from '{0}'
|
import {{Vector4}} from '{0}'
|
||||||
";
|
";
|
||||||
public static string GetSerializeImports(string path, string package)
|
public static string GetSerializeImports(string path, string package)
|
||||||
{
|
{
|
||||||
|
|
@ -41,14 +41,14 @@ import Vector4 from '{0}'
|
||||||
}
|
}
|
||||||
|
|
||||||
public const string SerializePathImportsFormat = @"import BeanBase from '{0}/serialization/BeanBase'";
|
public const string SerializePathImportsFormat = @"import BeanBase from '{0}/serialization/BeanBase'";
|
||||||
public const string SerializePackageImportsFormat = @"import BeanBase from '{0}'";
|
public const string SerializePackageImportsFormat = @"import {{BeanBase}} from '{0}'";
|
||||||
|
|
||||||
public static string GetProtocolImports(string path, string package)
|
public static string GetProtocolImports(string path, string package)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(package) ? string.Format(ProtocolPathImportsFormat, path) : string.Format(ProtocolPackageImportsFormat, package);
|
return string.IsNullOrEmpty(package) ? string.Format(ProtocolPathImportsFormat, path) : string.Format(ProtocolPackageImportsFormat, package);
|
||||||
}
|
}
|
||||||
public const string ProtocolPathImportsFormat = "import Protocol from '{0}/net/Protocol'";
|
public const string ProtocolPathImportsFormat = "import Protocol from '{0}/net/Protocol'";
|
||||||
public const string ProtocolPackageImportsFormat = "import Protocol from '{0}'";
|
public const string ProtocolPackageImportsFormat = "import {{Protocol}} from '{0}'";
|
||||||
|
|
||||||
public const string SerializeTypes = @"
|
public const string SerializeTypes = @"
|
||||||
export interface ISerializable {
|
export interface ISerializable {
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ export {{x.ts_class_modifier}} class {{name}} extends {{if parent_def_type}} {{x
|
||||||
if (value == null) throw new Error()
|
if (value == null) throw new Error()
|
||||||
{{~end~}}
|
{{~end~}}
|
||||||
if (this.isManaged) {
|
if (this.isManaged) {
|
||||||
let txn = TransactionContext.current
|
let txn = TransactionContext.current!
|
||||||
txn.putFieldLong(this.getObjectId() + {{field.id}}, new {{name}}.{{field.log_type}}(this, value))
|
txn.putFieldLong(this.getObjectId() + {{field.id}}, new {{name}}.{{field.log_type}}(this, value))
|
||||||
{{~if ctype.need_set_children_root~}}
|
{{~if ctype.need_set_children_root~}}
|
||||||
value?.initRoot(this.getRoot())
|
value?.initRoot(this.getRoot())
|
||||||
|
|
|
||||||
|
|
@ -162,19 +162,19 @@ namespace Luban.Job.Db
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fileContent.Add($"import {{FieldLogger, FieldLoggerGeneric1, FieldLoggerGeneric2}} from '{brightPackageName}'");
|
fileContent.Add($"import {{FieldLogger, FieldLoggerGeneric1, FieldLoggerGeneric2}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import TxnBeanBase from '{brightPackageName}'");
|
fileContent.Add($"import {{TxnBeanBase}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import {{TxnTable, TxnTableGeneric}} from '{brightPackageName}'");
|
fileContent.Add($"import {{TxnTable, TxnTableGeneric}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import TransactionContext from '{brightPackageName}'");
|
fileContent.Add($"import {{TransactionContext}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import {{FieldTag}} from '{brightPackageName}'");
|
fileContent.Add($"import {{FieldTag}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import TKey from '{brightPackageName}'");
|
fileContent.Add($"import {{TKey}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PList from '{brightPackageName}'");
|
fileContent.Add($"import {{PList}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PList1 from '{brightPackageName}'");
|
fileContent.Add($"import {{PList1}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PList2 from '{brightPackageName}'");
|
fileContent.Add($"import {{PList2}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PSet from '{brightPackageName}'");
|
fileContent.Add($"import {{PSet}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PMap from '{brightPackageName}'");
|
fileContent.Add($"import {{PMap}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PMap1 from '{brightPackageName}'");
|
fileContent.Add($"import {{PMap1}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import PMap2 from '{brightPackageName}'");
|
fileContent.Add($"import {{PMap2}} from '{brightPackageName}'");
|
||||||
fileContent.Add($"import SerializeFactory from '{brightPackageName}'");
|
fileContent.Add($"import {{SerializeFactory}} from '{brightPackageName}'");
|
||||||
}
|
}
|
||||||
|
|
||||||
fileContent.Add($"export namespace {ass.TopModule} {{");
|
fileContent.Add($"export namespace {ass.TopModule} {{");
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue