487 lines
16 KiB
C#
487 lines
16 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data;
|
||
using System.Diagnostics;
|
||
using System.Globalization;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Text;
|
||
using ExcelDataReader;
|
||
using NBC;
|
||
using Newtonsoft.Json;
|
||
using Newtonsoft.Json.Linq;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using Debug = UnityEngine.Debug;
|
||
|
||
namespace NBF
|
||
{
|
||
public static class ExcelToJsonWindow
|
||
{
|
||
#region 生成配置表
|
||
|
||
public static void GenConfig(bool showMessageBox = true)
|
||
{
|
||
CfgEditorUtil.GenConfigScripts();
|
||
GenConfig(Application.dataPath + "/../Config", showMessageBox);
|
||
}
|
||
|
||
|
||
public static void GenConfig(string path, bool showMessageBox = false)
|
||
{
|
||
List<string> list = new List<string>();
|
||
|
||
GetFiles(path, fileList: ref list);
|
||
|
||
AllJsonData.Clear();
|
||
Stopwatch s = Stopwatch.StartNew();
|
||
|
||
ReadExcel(list.ToArray());
|
||
|
||
BuildAsset();
|
||
|
||
s.Stop();
|
||
if (showMessageBox)
|
||
{
|
||
EditorUtility.DisplayDialog("成功", $"导表完成,耗时{(s.ElapsedMilliseconds / 1000f):.00}秒", "知道了");
|
||
EditorUtility.ClearProgressBar();
|
||
}
|
||
else
|
||
{
|
||
Debug.Log($"导表完成,耗时{(s.ElapsedMilliseconds / 1000f):.00}秒");
|
||
}
|
||
|
||
AssetDatabase.Refresh();
|
||
}
|
||
|
||
|
||
private static void BuildAsset()
|
||
{
|
||
var json = JsonConvert.SerializeObject(AllJsonData, Formatting.Indented, new JsonSerializerSettings
|
||
{
|
||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||
});
|
||
var jsonObj = JObject.Parse(json);
|
||
|
||
Dictionary<string, JToken> tokens = new Dictionary<string, JToken>(StringComparer.OrdinalIgnoreCase);
|
||
|
||
foreach (var item in jsonObj)
|
||
{
|
||
try
|
||
{
|
||
var name = item.Key;
|
||
var value = item.Value;
|
||
if (value != null)
|
||
{
|
||
tokens[name] = value;
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log.Error($"读表异常,请检查,name={item.Key} ex={e}");
|
||
}
|
||
}
|
||
|
||
var relativePath = ConfigAssets.SavePath;
|
||
|
||
var asset = EditorUtils.GetOrCreateAsset<ConfigAssets>(relativePath);
|
||
|
||
var types = Reflection.GetAllNonAbstractDerivedTypes<ConfigBase>();
|
||
foreach (var type in types)
|
||
{
|
||
var tableNameAttribute = type.GetCustomAttribute<TableNameAttribute>();
|
||
if (tableNameAttribute == null) continue;
|
||
if (!tokens.TryGetValue(tableNameAttribute.Name, out var token))
|
||
{
|
||
Log.Warning($"{tableNameAttribute.Name} 解析失败,tableName不一致");
|
||
continue;
|
||
}
|
||
|
||
if (token is not JArray jArray) return;
|
||
asset.Parse(jArray.ToArray(), type);
|
||
}
|
||
|
||
EditorUtility.SetDirty(asset);
|
||
AssetDatabase.SaveAssets();
|
||
AssetDatabase.Refresh();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 生成多语言
|
||
|
||
public static void GenLanguage()
|
||
{
|
||
var path = Application.dataPath + "/../Config/language";
|
||
|
||
List<string> list = new List<string>();
|
||
|
||
GetFiles(path, fileList: ref list);
|
||
|
||
AllJsonData.Clear();
|
||
Stopwatch s = Stopwatch.StartNew();
|
||
|
||
ReadExcel(list.ToArray());
|
||
|
||
var savePath = Path.Combine(Application.dataPath, "Resources/config/language.json");
|
||
|
||
BuildJson(savePath);
|
||
|
||
s.Stop();
|
||
|
||
Debug.Log($"导多语言完成,耗时{(s.ElapsedMilliseconds / 1000f):.00}秒");
|
||
|
||
AssetDatabase.Refresh();
|
||
}
|
||
|
||
private static void BuildJson(string savaPath)
|
||
{
|
||
var json = JsonConvert.SerializeObject(AllJsonData, Formatting.Indented, new JsonSerializerSettings
|
||
{
|
||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
|
||
});
|
||
SaveJson(savaPath, json);
|
||
|
||
AssetDatabase.SaveAssets();
|
||
AssetDatabase.Refresh();
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region 文件读写
|
||
|
||
private static void GetFiles(string path, ref List<string> fileList)
|
||
{
|
||
var files = Directory.GetFiles(path);
|
||
if (files.Length > 0)
|
||
{
|
||
foreach (var file in files)
|
||
{
|
||
var fileName = Path.GetFileName(file);
|
||
|
||
if ((fileName.EndsWith(".xls", true, CultureInfo.CurrentCulture) ||
|
||
fileName.EndsWith(".xlsx", true, CultureInfo.CurrentCulture)) && !fileName.StartsWith(".") &&
|
||
!fileName.StartsWith("~"))
|
||
{
|
||
fileList.Add(file.Replace('\\', '/'));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
private static void SaveJson(string jsonPath, string json)
|
||
{
|
||
try
|
||
{
|
||
if (File.Exists(jsonPath))
|
||
{
|
||
File.Delete(jsonPath);
|
||
}
|
||
|
||
File.WriteAllBytes(jsonPath, Encoding.UTF8.GetBytes(json));
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
// Console.WriteLine(e);
|
||
// throw;
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Excel读取
|
||
|
||
private static readonly Dictionary<string, object> AllJsonData = new Dictionary<string, object>();
|
||
private static bool _buildIng = false;
|
||
private static int _buildTotal = 0;
|
||
|
||
private static int _buildDoneCount = 0;
|
||
|
||
private static void ReadExcel(IReadOnlyCollection<string> paths)
|
||
{
|
||
_buildTotal = paths.Count;
|
||
_buildDoneCount = 0;
|
||
_buildIng = true;
|
||
|
||
foreach (var t in paths)
|
||
{
|
||
ReadSingleExcel(t);
|
||
}
|
||
|
||
_buildIng = false;
|
||
}
|
||
|
||
private static void ReadSingleExcelFunc(string xlsxPath, bool isThrow = false)
|
||
{
|
||
try
|
||
{
|
||
using FileStream stream = File.Open(xlsxPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||
IExcelDataReader excelReader = ExcelReaderFactory.CreateOpenXmlReader(stream);
|
||
DataSet result = excelReader.AsDataSet();
|
||
// 读取第一张工资表
|
||
DataTableCollection tc = result.Tables;
|
||
|
||
if (tc.Count >= 1)
|
||
{
|
||
foreach (DataTable table in tc)
|
||
{
|
||
if (!table.TableName.StartsWith("!") && !table.TableName.StartsWith("Sheet"))
|
||
{
|
||
ReadSingleSheet(table, isThrow);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
Debug.LogError("表名为空,请检查表");
|
||
}
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Log.Error(e);
|
||
}
|
||
}
|
||
|
||
|
||
public static void ReadSingleExcel(string xlsxPath, bool isThrow = false)
|
||
{
|
||
Stopwatch s = Stopwatch.StartNew();
|
||
string xlsxName = Path.GetFileName(xlsxPath);
|
||
|
||
if (!File.Exists(xlsxPath))
|
||
{
|
||
Debug.LogError("不存在该Excel!");
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
ReadSingleExcelFunc(xlsxPath, isThrow);
|
||
|
||
Debug.Log(xlsxName + ".xlsx" + "转换Json成功!");
|
||
|
||
s.Stop();
|
||
Debug.Log($"导表{xlsxName},花费时间={s.ElapsedMilliseconds}毫秒");
|
||
_buildDoneCount++;
|
||
}
|
||
catch (Exception e)
|
||
{
|
||
Debug.LogError(e);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 读取一个工作表的数据
|
||
/// </summary>
|
||
/// <param name="dataTable">读取的工作表数据</param>
|
||
/// <param name="isThrow">是否抛出异常</param>
|
||
private static void ReadSingleSheet(DataTable dataTable, bool isThrow = false)
|
||
{
|
||
int rows = dataTable.Rows.Count;
|
||
int columns = dataTable.Columns.Count;
|
||
if (rows < 1 || columns < 1)
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 工作表的行数据
|
||
DataRowCollection collect = dataTable.Rows;
|
||
// xlsx对应的数据字段,规定是第二行
|
||
string[] jsonFields = new string[columns];
|
||
string[] jsonFieldsType = new string[columns];
|
||
// 要保存成Json的obj
|
||
List<object> objsToSave = new List<object>();
|
||
for (int i = 0; i < columns; i++)
|
||
{
|
||
//字段
|
||
jsonFields[i] = collect[1][i].ToString();
|
||
//字段类型
|
||
jsonFieldsType[i] = collect[2][i].ToString();
|
||
}
|
||
|
||
// _lastTableName = dataTable.TableName;
|
||
// 从第三行开始
|
||
for (int i = 3; i < rows; i++)
|
||
{
|
||
Dictionary<string, object> jObject = new Dictionary<string, object>();
|
||
|
||
// _lastX = i;
|
||
for (int j = 0; j < columns; j++)
|
||
{
|
||
var objectValue = collect[i][j].ToString();
|
||
// _lastY = j;
|
||
var lastValue = $"{collect[1][j]}---{objectValue}";
|
||
try
|
||
{
|
||
if (isThrow)
|
||
{
|
||
Debug.Log($"{i}/{j}/{objectValue}");
|
||
}
|
||
|
||
Type type = GetTypeByString(jsonFieldsType[j]);
|
||
// 获取字段
|
||
string field = jsonFields[j];
|
||
//过滤掉字段为空的值
|
||
if (!string.IsNullOrEmpty(field))
|
||
{
|
||
object value = null;
|
||
if (!string.IsNullOrEmpty(objectValue))
|
||
{
|
||
//需要先判断下是否为数组
|
||
if (type != typeof(Array))
|
||
{
|
||
//需要判断一下是否为bool值 bool 直接返回int 0 或者 1
|
||
if (type == typeof(bool))
|
||
{
|
||
value = int.Parse(objectValue);
|
||
}
|
||
else if (type == typeof(Vector2))
|
||
{
|
||
value = objectValue.ToVector2();
|
||
}
|
||
else if (type == typeof(Vector3))
|
||
{
|
||
value = objectValue.ToVector3();
|
||
}
|
||
else
|
||
{
|
||
value = Convert.ChangeType(objectValue, type);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//这里在做二维数组的处理
|
||
//一般到这都是Int数组,当然还可以更细致的处理不同类型的数组
|
||
string[] strs = objectValue.Split(',');
|
||
string arrayType = jsonFieldsType[j];
|
||
|
||
object[] ints = new object[strs.Length];
|
||
|
||
for (int k = 0; k < strs.Length; k++)
|
||
{
|
||
switch (arrayType)
|
||
{
|
||
case "[int]":
|
||
{
|
||
int.TryParse(strs[k], out var v);
|
||
ints[k] = v;
|
||
break;
|
||
}
|
||
case "[float]":
|
||
{
|
||
float.TryParse(strs[k], out var v);
|
||
ints[k] = v;
|
||
break;
|
||
}
|
||
case "[string]":
|
||
ints[k] = strs[k];
|
||
break;
|
||
default:
|
||
ints[k] = strs[k];
|
||
break;
|
||
}
|
||
}
|
||
|
||
value = ints;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Log.I($"{dataTable.TableName} 字段{field}有空值存在 第{j + 1}列数据 请检查表格!!!");
|
||
//如果值为空会出现导表失败 这里需要做一下处理
|
||
value = GetDataType(type);
|
||
}
|
||
|
||
jObject[field] = value;
|
||
}
|
||
}
|
||
catch (Exception)
|
||
{
|
||
Debug.LogError($"解析表错误,table={dataTable.TableName} y={i} x={j} value={lastValue}");
|
||
}
|
||
}
|
||
|
||
objsToSave.Add(jObject);
|
||
}
|
||
|
||
AllJsonData[dataTable.TableName] = objsToSave;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// 判断一下数据类型
|
||
/// </summary>
|
||
/// <param name="type"></param>
|
||
/// <returns></returns>
|
||
public static object GetDataType(Type type)
|
||
{
|
||
object value = null;
|
||
if (type == typeof(int) || type == typeof(float))
|
||
{
|
||
value = 0;
|
||
}
|
||
else if (type == typeof(string))
|
||
{
|
||
value = "";
|
||
}
|
||
else if (type == typeof(bool))
|
||
{
|
||
//如果boo值类型为空 默认显示
|
||
value = 0;
|
||
}
|
||
else if (type == typeof(Array))
|
||
{
|
||
value = new List<object>().ToArray();
|
||
}
|
||
else
|
||
{
|
||
value = "";
|
||
}
|
||
|
||
return value;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取字段类型
|
||
/// </summary>
|
||
/// <param name="type"></param>
|
||
/// <returns></returns>
|
||
public static Type GetTypeByString(string type)
|
||
{
|
||
switch (type.ToLower())
|
||
{
|
||
case "bool":
|
||
return typeof(bool);
|
||
case "array":
|
||
return typeof(Array);
|
||
case "double":
|
||
return typeof(double);
|
||
case "float":
|
||
return typeof(float);
|
||
case "int":
|
||
return typeof(int);
|
||
case "long":
|
||
return typeof(long);
|
||
case "object":
|
||
return typeof(object);
|
||
case "string":
|
||
return typeof(string);
|
||
case "[float]":
|
||
return typeof(Array);
|
||
case "[int]":
|
||
return typeof(Array);
|
||
case "[string]":
|
||
return typeof(Array);
|
||
case "v2":
|
||
return typeof(Vector2);
|
||
case "v3":
|
||
return typeof(Vector3);
|
||
default:
|
||
return typeof(string);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
}
|
||
} |