Files
Fishing2/Assets/Scripts/Editor/Excel/ExcelToJsonWindow.cs
2025-06-05 15:39:47 +08:00

487 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}
}