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

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;
}
}
}