You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
273 lines
13 KiB
273 lines
13 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.IO; |
|
using System.Linq; |
|
using System.Security.Cryptography; |
|
using OfficeOpenXml; |
|
using Tools.Editor; |
|
using UnityEditor; |
|
using UnityEditor.Compilation; |
|
using UnityEngine; |
|
using UnityEngine.Assertions; |
|
using FileUtil = UnityEditor.FileUtil; |
|
|
|
namespace Tools.ExcelResolver.Editor |
|
{ |
|
public sealed partial class ExcelResolverEditorWindow |
|
{ |
|
private void ReadExcel(bool needWriteCode = true) |
|
{ |
|
classCodeDataDict = new Dictionary<ExcelWorksheet, ClassCodeData>(); |
|
|
|
// 获取Excel文件 |
|
excelResolverConfig.MakeSureDirectory(); |
|
var removeFiles = new DirectoryInfo(excelResolverConfig.SOPathRoot).GetDirectories(); |
|
var excelFiles = new DirectoryInfo(excelResolverConfig.ExcelPathRoot).GetFiles("*.xlsx").Where(f => !f.Name.StartsWith("~$") && !f.Name.StartsWith("##")); |
|
|
|
removeFiles = removeFiles.Where(f => excelFiles.All(ef => ef.Name[..^5] != f.Name)).ToArray(); |
|
foreach (var removeFile in removeFiles) |
|
{ |
|
DirectoryUtil.DeleteDirectory(removeFile.FullName); |
|
Debug.Log($"删除文件夹:'{removeFile.Name}'"); |
|
FileUtil.DeleteFileOrDirectory($"{excelResolverConfig.CodePathRoot}/{removeFile.Name}.cs"); |
|
FileUtil.DeleteFileOrDirectory($"{excelResolverConfig.CodePathRoot}/{removeFile.Name}Util.cs"); |
|
} |
|
if (excelFiles.Count() == 0) |
|
{ |
|
Debug.LogError("未检测到Excel文件,请检查路径"); |
|
return; |
|
} |
|
|
|
foreach (var excelFile in excelFiles) |
|
{ |
|
using FileStream stream = File.Open(excelFile.FullName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); |
|
using MD5 md5 = MD5.Create(); |
|
byte[] hash = md5.ComputeHash(stream);// 转换为十六进制字符串 |
|
var m = BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); |
|
if (excelResolverConfig.md5Dict.GetValueOrDefault(excelFile.FullName) == m && excelResolverConfig.useMD5) |
|
{ |
|
Debug.Log($"'{excelFile.Name}' 文件未发生变化,跳过"); |
|
continue; |
|
} |
|
excelResolverConfig.md5Dict[excelFile.FullName] = m; |
|
|
|
using ExcelPackage package = new ExcelPackage(stream); |
|
ExcelWorksheet worksheet = package.Workbook.Worksheets["Sheet1"]; |
|
Assert.IsTrue(worksheet != null, $"Excel:{excelFile.Name} don't have Sheet1 !!"); |
|
|
|
var classCodeData = new ClassCodeData(excelFile.Name[..^5]); |
|
|
|
classCodeData.fields = GetFieldData(worksheet, classCodeData); |
|
classCodeData.tableType = CheckTableTypeAndSetKeyField(worksheet, classCodeData); |
|
|
|
if (needWriteCode) |
|
{ |
|
WriteDataCode(classCodeData); |
|
WriteUtilCode(classCodeData); |
|
} |
|
classCodeDataDict.Add(worksheet, classCodeData); |
|
Debug.Log($"读取Excel文件:'{excelFile.Name}',并生成代码"); |
|
} |
|
|
|
if (classCodeDataDict.Count == 0) |
|
{ |
|
Debug.LogError("未检测到Excel文件改动,如需重新生成,请清空md5Dict"); |
|
return; |
|
} |
|
|
|
AssetDatabase.Refresh(); |
|
if (EditorApplication.isCompiling) |
|
{ |
|
Debug.Log("代码成功生成,请等待编译..."); |
|
CompilationPipeline.compilationFinished += CompilationFinished; |
|
} |
|
else |
|
{ |
|
Debug.Log("未更改过字段,开始写入SO数据"); |
|
WriteDataSO(); |
|
} |
|
} |
|
|
|
private bool isCompilationFinished; |
|
private void CompilationFinished(object obj) |
|
{ |
|
CompilationPipeline.compilationFinished -= CompilationFinished; |
|
Debug.Log("编译完成"); |
|
isCompilationFinished = true; |
|
} |
|
|
|
private void Update() |
|
{ |
|
if (isCompilationFinished) |
|
{ |
|
var assemblies = AppDomain.CurrentDomain.GetAssemblies(); |
|
if (assemblies.Any(a => a.GetName().Name == "Assembly-CSharp")) |
|
{ |
|
isCompilationFinished = false; |
|
Debug.Log("Assembly-CSharp加载完成,开始写入SO数据"); |
|
if (classCodeDataDict == null) |
|
{ |
|
ReadExcel(false); |
|
} |
|
} |
|
} |
|
} |
|
|
|
private static TableType CheckTableTypeAndSetKeyField(ExcelWorksheet worksheet, ClassCodeData classCodeData) |
|
{ |
|
var tableType = TableType.SingleKeyTable; |
|
|
|
string config = worksheet.Cells[1, 1].Text; |
|
|
|
if (config.Contains("SingleKeyTable")) |
|
{ |
|
tableType = TableType.SingleKeyTable; |
|
var configs = config.Split("|"); |
|
Assert.IsTrue(configs.Length >= 2, $"'{classCodeData.className}'配置错误,SingleKeyTable只能有一个主键"); |
|
var key = configs[1]; |
|
classCodeData.keyField = new FieldData[] { classCodeData.fields.FirstOrDefault(f => f.Value.varName == key).Value }; |
|
Assert.IsTrue(classCodeData.keyField[0] != null, $"'{classCodeData.className}'配置错误,主键字段不存在或重复"); |
|
// 判断主键是否有重复值或空值 |
|
var keyDict = ExcelResolverUtil.ReadColumn(worksheet, classCodeData.keyField[0].colIndex); |
|
|
|
// 检查是否有空值 |
|
var emptyKey = keyDict.Where(p => string.IsNullOrEmpty(p.Value)); |
|
Assert.IsTrue(emptyKey.Count() <= 0, $"'{classCodeData.className}'主键字段在第<color=cyan>'{string.Join(",", emptyKey.Select(p => p.Key))}'</color>行存在空值"); |
|
|
|
var duplicateValues = keyDict.GroupBy(x => x.Value).Where(g => g.Count() > 1); |
|
foreach (var duplicateValue in duplicateValues) |
|
{ |
|
Debug.LogError($"'{classCodeData.className}'主键字段存在重复值:'<color=cyan>{duplicateValue.Key}</color>' " + |
|
$"行号:<color=cyan>{string.Join(",", duplicateValue.Select(g => g.Key))}</color>"); |
|
} |
|
Assert.IsTrue(duplicateValues.Count() <= 0); |
|
} |
|
else if (config.Contains("UnionMultiKeyTable") || config.Contains("MultiKeyTable")) |
|
{ |
|
tableType = config.Contains("UnionMultiKeyTable") ? TableType.UnionMultiKeyTable : TableType.MultiKeyTable; |
|
var configs = config.Split("|"); |
|
Assert.IsTrue(configs.Length >= 3, $"'<color=cyan>{classCodeData.className}</color>'配置错误,UnionMultiKeyTable至少有两个主键"); |
|
var keys = configs[1..]; |
|
classCodeData.keyField = keys.Select(key => |
|
{ |
|
var field = classCodeData.fields.FirstOrDefault(f => f.Value.varName == key); |
|
Assert.IsTrue(field.Value != null, $"'<color=cyan>{classCodeData.className}</color>'配置错误,主键字段不存在"); |
|
return field.Value; |
|
}).ToArray(); |
|
|
|
// 判断主键是否有重复值或空值 |
|
var keyDictList = new List<Dictionary<int, string>>(); |
|
foreach (var keyField in classCodeData.keyField) |
|
{ |
|
keyDictList.Add(ExcelResolverUtil.ReadColumn(worksheet, keyField.colIndex)); |
|
} |
|
for (int i = 0; i < keyDictList.Count; i++) |
|
{ |
|
Dictionary<int, string> keyDict = keyDictList[i]; |
|
var keyField = classCodeData.keyField[i]; |
|
|
|
// 检查是否有空值 |
|
var emptyKey = keyDict.Where(p => string.IsNullOrEmpty(p.Value)); |
|
Assert.IsTrue(emptyKey.Count() <= 0, $"'{classCodeData.className}'主键字段 '<color=cyan>{keyField.varName}</color>' 在 '<color=cyan>{string.Join(",", emptyKey.Select(p => p.Key))}</color>' 存在空值"); |
|
|
|
/* |
|
// 检查是否有重复值 |
|
var duplicates = keyDict.GroupBy(v => v.Value).Where(g => g.Count() > 1); |
|
foreach (var duplicate in duplicates) |
|
{ |
|
Debug.LogError($"'{classCodeData.className}'主键字段 '<color=cyan>{keyField.varName}</color>' 存在重复值: '<color=cyan>{duplicate.Key}</color>' " + |
|
$"行号:{string.Join(",", duplicate.Select(g => g.Key))}"); |
|
} |
|
Assert.IsTrue(duplicates.Count() <= 0);*/ |
|
} |
|
|
|
// 检查组合是否唯一 |
|
var combinedKeys = new HashSet<string>(); |
|
foreach (var pair in keyDictList[0]) |
|
{ |
|
var combinedKey = string.Join("_", keyDictList.Select(dict => dict[pair.Key])); |
|
if (combinedKeys.Contains(combinedKey)) |
|
{ |
|
Debug.LogError($"'{classCodeData.className}'主键在行 '<color=cyan>{pair.Key}</color>' 存在重复组合: '<color=cyan>{combinedKey}</color>'"); |
|
} |
|
else |
|
{ |
|
combinedKeys.Add(combinedKey); |
|
} |
|
} |
|
Assert.IsTrue(combinedKeys.Count == keyDictList[0].Count); |
|
} |
|
else if (config.Contains("NotKetTable")) |
|
{ |
|
tableType = TableType.NotKetTable; |
|
} |
|
else if (config.Contains("ColumnTable")) |
|
{ |
|
tableType = TableType.ColumnTable; |
|
} |
|
else |
|
{ |
|
Debug.LogError("配置错误"); |
|
} |
|
|
|
return tableType; |
|
} |
|
|
|
private Dictionary<int, FieldData> GetFieldData(ExcelWorksheet worksheet, ClassCodeData classCodeData) |
|
{ |
|
var fieldDatas = new Dictionary<int, FieldData>(); |
|
|
|
// 横表 |
|
if (!worksheet.Cells[1, 1].Text.Contains("ColumnTable", StringComparison.OrdinalIgnoreCase)) |
|
{ |
|
for (int col = 2; col <= worksheet.Dimension.End.Column; col++) |
|
{ |
|
var varText = worksheet.Cells[2, col].Text; |
|
if (string.IsNullOrEmpty(varText) || worksheet.Cells[1, col].Text == "##") continue; |
|
|
|
FieldData fieldData = new FieldData |
|
{ |
|
colIndex = col, |
|
varName = varText, |
|
// typeString = worksheet.Cells[3, col].Text, |
|
type = ExcelResolverUtil.GetTTypeByString(worksheet.Cells[3, col].Text, worksheet.Cells[3, col], classCodeData.className), |
|
info = worksheet.Cells[4, col].Text, |
|
description = worksheet.Cells[5, col].Text, |
|
}; |
|
fieldDatas.Add(col, fieldData); |
|
} |
|
} |
|
// 纵表 |
|
else |
|
{ |
|
for (int row = 2; row <= worksheet.Dimension.End.Row; row++) |
|
{ |
|
var varText = worksheet.Cells[row, 1].Text; |
|
if (string.IsNullOrEmpty(varText) || varText.StartsWith("##")) continue; |
|
|
|
FieldData fieldData = new FieldData |
|
{ |
|
colIndex = row, |
|
varName = varText, |
|
// typeString = worksheet.Cells[row, 2].Text, |
|
type = ExcelResolverUtil.GetTTypeByString(worksheet.Cells[row, 2].Text, worksheet.Cells[row, 2], classCodeData.className), |
|
info = worksheet.Cells[row, 4].Text, |
|
description = worksheet.Cells[row, 5].Text, |
|
}; |
|
fieldDatas.Add(row, fieldData); |
|
} |
|
} |
|
|
|
// 判断是否有重复的varName |
|
foreach (var fieldData in fieldDatas.Values) |
|
{ |
|
if (fieldDatas.Values.Count(f => f.varName == fieldData.varName) > 1) |
|
{ |
|
throw new Exception($"'{classCodeData.className}'拥有相同的字段: {fieldData.varName}"); |
|
} |
|
} |
|
|
|
return fieldDatas; |
|
} |
|
} |
|
} |