422 lines
16 KiB
C#
422 lines
16 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using UnityEditor;
|
||
using UnityEngine;
|
||
using OfficeOpenXml;
|
||
|
||
namespace ThriftPipelineTools
|
||
{
|
||
/// <summary>
|
||
/// Excel 查看器 - 用于学习和测试 EPPlus 的 Excel 读取功能
|
||
///
|
||
/// 功能:
|
||
/// 1. 选择 Excel 文件 (.xlsx)
|
||
/// 2. 加载并显示所有工作表 (Sheet)
|
||
/// 3. 点击工作表查看数据内容
|
||
/// 4. 实时预览 Excel 数据结构
|
||
///
|
||
/// 学习目的:
|
||
/// - 理解 EPPlus 的基本用法
|
||
/// - 了解 Excel 文件的结构(Workbook、Worksheet、Cells)
|
||
/// - 掌握单元格数据的读取方法
|
||
/// </summary>
|
||
public class EPPlusTestEditor : EditorWindow
|
||
{
|
||
// ========== 文件路径 ==========
|
||
private string excelFilePath = ""; // 选中的Excel文件路径
|
||
|
||
// ========== Excel 数据 ==========
|
||
private List<string> sheetNames = new List<string>(); // 所有工作表名称
|
||
private int selectedSheetIndex = 0; // 当前选中的工作表索引
|
||
private string[,] sheetData = null; // 当前工作表的数据(二维数组)
|
||
private int maxRows = 0; // 当前工作表的最大行数
|
||
private int maxCols = 0; // 当前工作表的最大列数
|
||
|
||
// ========== UI 状态 ==========
|
||
private Vector2 sheetListScrollPosition; // 工作表列表滚动位置
|
||
private Vector2 dataScrollPosition; // 数据表格滚动位置
|
||
private bool isFileLoaded = false; // 是否已加载文件
|
||
private string statusMessage = "请选择一个 Excel 文件"; // 状态消息
|
||
|
||
// ========== UI 配置 ==========
|
||
private const float CELL_WIDTH = 120f; // 单元格显示宽度
|
||
private const float CELL_HEIGHT = 20f; // 单元格显示高度
|
||
private const int MAX_DISPLAY_ROWS = 100; // 最多显示行数(避免性能问题)
|
||
private const int MAX_DISPLAY_COLS = 50; // 最多显示列数
|
||
|
||
/// <summary>
|
||
/// Unity 菜单项:打开 Excel 查看器窗口
|
||
/// </summary>
|
||
[MenuItem("蹊径/Thrift/Excel 查看器")]
|
||
public static void ShowWindow()
|
||
{
|
||
var window = GetWindow<EPPlusTestEditor>("Excel 查看器");
|
||
window.minSize = new Vector2(800, 600);
|
||
window.Show();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绘制 Editor 窗口 UI
|
||
/// </summary>
|
||
private void OnGUI()
|
||
{
|
||
EditorGUILayout.Space(10);
|
||
|
||
// ===== 标题区域 =====
|
||
EditorGUILayout.LabelField("EPPlus Excel 读取测试工具", EditorStyles.boldLabel);
|
||
EditorGUILayout.HelpBox(
|
||
"此工具用于测试 EPPlus 读取 Excel 文件的功能\n" +
|
||
"1. 选择 .xlsx 文件\n" +
|
||
"2. 点击「加载文件」查看所有工作表\n" +
|
||
"3. 选择工作表查看数据内容",
|
||
MessageType.Info
|
||
);
|
||
|
||
EditorGUILayout.Space(10);
|
||
|
||
// ===== 文件选择区域 =====
|
||
DrawFileSelection();
|
||
|
||
EditorGUILayout.Space(10);
|
||
|
||
// ===== 状态信息 =====
|
||
EditorGUILayout.BeginVertical("box");
|
||
EditorGUILayout.LabelField("状态:", statusMessage, EditorStyles.miniLabel);
|
||
if (isFileLoaded)
|
||
{
|
||
EditorGUILayout.LabelField($"工作表数量: {sheetNames.Count}", EditorStyles.miniLabel);
|
||
if (sheetData != null)
|
||
{
|
||
EditorGUILayout.LabelField($"当前表格: {maxRows} 行 × {maxCols} 列", EditorStyles.miniLabel);
|
||
}
|
||
}
|
||
EditorGUILayout.EndVertical();
|
||
|
||
EditorGUILayout.Space(10);
|
||
|
||
// ===== 主内容区域 =====
|
||
if (isFileLoaded)
|
||
{
|
||
DrawMainContent();
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绘制文件选择区域
|
||
/// </summary>
|
||
private void DrawFileSelection()
|
||
{
|
||
EditorGUILayout.BeginVertical("box");
|
||
EditorGUILayout.LabelField("Excel 文件选择", EditorStyles.boldLabel);
|
||
|
||
// 文件路径输入框和浏览按钮
|
||
EditorGUILayout.BeginHorizontal();
|
||
EditorGUILayout.LabelField("文件路径:", GUILayout.Width(70));
|
||
excelFilePath = EditorGUILayout.TextField(excelFilePath);
|
||
|
||
if (GUILayout.Button("浏览...", GUILayout.Width(70)))
|
||
{
|
||
string selected = EditorUtility.OpenFilePanel("选择 Excel 文件", "", "xlsx");
|
||
if (!string.IsNullOrEmpty(selected))
|
||
{
|
||
excelFilePath = selected;
|
||
}
|
||
}
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
// 加载按钮
|
||
EditorGUILayout.BeginHorizontal();
|
||
GUI.enabled = !string.IsNullOrEmpty(excelFilePath) && File.Exists(excelFilePath);
|
||
|
||
if (GUILayout.Button("🔄 加载文件", GUILayout.Height(30)))
|
||
{
|
||
LoadExcelFile();
|
||
}
|
||
|
||
// 刷新按钮(仅在已加载时显示)
|
||
if (isFileLoaded)
|
||
{
|
||
if (GUILayout.Button("🔃 刷新数据", GUILayout.Height(30)))
|
||
{
|
||
LoadExcelFile();
|
||
}
|
||
}
|
||
|
||
GUI.enabled = true;
|
||
EditorGUILayout.EndHorizontal();
|
||
|
||
EditorGUILayout.EndVertical();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绘制主要内容区域(工作表列表 + 数据表格)
|
||
/// </summary>
|
||
private void DrawMainContent()
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
// ===== 左侧:工作表列表 =====
|
||
EditorGUILayout.BeginVertical("box", GUILayout.Width(200));
|
||
EditorGUILayout.LabelField("工作表列表", EditorStyles.boldLabel);
|
||
|
||
sheetListScrollPosition = EditorGUILayout.BeginScrollView(
|
||
sheetListScrollPosition,
|
||
GUILayout.ExpandHeight(true)
|
||
);
|
||
|
||
for (int i = 0; i < sheetNames.Count; i++)
|
||
{
|
||
// 高亮显示选中的工作表
|
||
bool isSelected = (i == selectedSheetIndex);
|
||
GUI.backgroundColor = isSelected ? Color.cyan : Color.white;
|
||
|
||
if (GUILayout.Button($"📄 {sheetNames[i]}", GUILayout.Height(25)))
|
||
{
|
||
selectedSheetIndex = i;
|
||
LoadSheetData(i);
|
||
}
|
||
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
|
||
EditorGUILayout.EndScrollView();
|
||
EditorGUILayout.EndVertical();
|
||
|
||
// ===== 右侧:数据表格 =====
|
||
EditorGUILayout.BeginVertical("box", GUILayout.ExpandWidth(true));
|
||
|
||
if (sheetData != null)
|
||
{
|
||
EditorGUILayout.LabelField(
|
||
$"工作表: {sheetNames[selectedSheetIndex]}",
|
||
EditorStyles.boldLabel
|
||
);
|
||
|
||
DrawDataTable();
|
||
}
|
||
else
|
||
{
|
||
EditorGUILayout.LabelField("请选择一个工作表查看数据", EditorStyles.centeredGreyMiniLabel);
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 绘制数据表格
|
||
/// </summary>
|
||
private void DrawDataTable()
|
||
{
|
||
if (sheetData == null || maxRows == 0 || maxCols == 0)
|
||
return;
|
||
|
||
dataScrollPosition = EditorGUILayout.BeginScrollView(
|
||
dataScrollPosition,
|
||
GUILayout.ExpandWidth(true),
|
||
GUILayout.ExpandHeight(true)
|
||
);
|
||
|
||
// 限制显示的行列数
|
||
int displayRows = Mathf.Min(maxRows, MAX_DISPLAY_ROWS);
|
||
int displayCols = Mathf.Min(maxCols, MAX_DISPLAY_COLS);
|
||
|
||
// 提示信息(如果数据被截断)
|
||
if (maxRows > MAX_DISPLAY_ROWS || maxCols > MAX_DISPLAY_COLS)
|
||
{
|
||
EditorGUILayout.HelpBox(
|
||
$"数据过大,仅显示前 {displayRows} 行 × {displayCols} 列",
|
||
MessageType.Warning
|
||
);
|
||
}
|
||
|
||
// 使用 GUILayout 绘制表格
|
||
EditorGUILayout.BeginVertical();
|
||
|
||
for (int row = 0; row < displayRows; row++)
|
||
{
|
||
EditorGUILayout.BeginHorizontal();
|
||
|
||
// 行号
|
||
EditorGUILayout.LabelField(
|
||
$"{row + 1}",
|
||
GUILayout.Width(40)
|
||
);
|
||
|
||
// 每列的数据
|
||
for (int col = 0; col < displayCols; col++)
|
||
{
|
||
string cellValue = sheetData[row, col] ?? "";
|
||
|
||
// 第一行(表头)使用不同样式
|
||
if (row == 0)
|
||
{
|
||
GUI.backgroundColor = new Color(0.8f, 0.9f, 1f);
|
||
EditorGUILayout.LabelField(
|
||
cellValue,
|
||
EditorStyles.boldLabel,
|
||
GUILayout.Width(CELL_WIDTH),
|
||
GUILayout.Height(CELL_HEIGHT)
|
||
);
|
||
GUI.backgroundColor = Color.white;
|
||
}
|
||
else
|
||
{
|
||
EditorGUILayout.LabelField(
|
||
cellValue,
|
||
GUILayout.Width(CELL_WIDTH),
|
||
GUILayout.Height(CELL_HEIGHT)
|
||
);
|
||
}
|
||
}
|
||
|
||
EditorGUILayout.EndHorizontal();
|
||
}
|
||
|
||
EditorGUILayout.EndVertical();
|
||
EditorGUILayout.EndScrollView();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载 Excel 文件,获取所有工作表名称
|
||
/// </summary>
|
||
private void LoadExcelFile()
|
||
{
|
||
try
|
||
{
|
||
if (!File.Exists(excelFilePath))
|
||
{
|
||
statusMessage = "❌ 文件不存在!";
|
||
Debug.LogError($"文件不存在: {excelFilePath}");
|
||
return;
|
||
}
|
||
|
||
// 清空之前的数据
|
||
sheetNames.Clear();
|
||
sheetData = null;
|
||
selectedSheetIndex = 0;
|
||
|
||
// 使用 EPPlus 读取 Excel
|
||
FileInfo fileInfo = new FileInfo(excelFilePath);
|
||
using (ExcelPackage package = new ExcelPackage(fileInfo))
|
||
{
|
||
// 获取所有工作表名称
|
||
// 注意:使用名称访问更可靠,Worksheets集合的索引可能不是从0开始
|
||
Debug.Log($"[EPPlus测试] Worksheets.Count = {package.Workbook.Worksheets.Count}");
|
||
|
||
foreach (ExcelWorksheet worksheet in package.Workbook.Worksheets)
|
||
{
|
||
sheetNames.Add(worksheet.Name);
|
||
Debug.Log($"[EPPlus测试] 发现工作表: '{worksheet.Name}'");
|
||
}
|
||
|
||
if (sheetNames.Count == 0)
|
||
{
|
||
statusMessage = "⚠️ Excel 文件中没有工作表";
|
||
isFileLoaded = false;
|
||
return;
|
||
}
|
||
|
||
isFileLoaded = true;
|
||
statusMessage = $"✅ 成功加载文件,共 {sheetNames.Count} 个工作表";
|
||
|
||
// 自动加载第一个工作表
|
||
LoadSheetData(0);
|
||
|
||
Debug.Log($"[EPPlus测试] 成功加载: {Path.GetFileName(excelFilePath)}");
|
||
Debug.Log($"[EPPlus测试] 工作表列表: {string.Join(", ", sheetNames)}");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
statusMessage = $"❌ 加载失败: {ex.Message}";
|
||
isFileLoaded = false;
|
||
Debug.LogError($"[EPPlus测试] 加载失败: {ex.Message}\n{ex.StackTrace}");
|
||
EditorUtility.DisplayDialog("加载失败", ex.Message, "确定");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 加载指定工作表的数据
|
||
/// 使用工作表名称来访问,避免索引问题(EPPlus的Worksheets集合索引可能不连续)
|
||
/// </summary>
|
||
private void LoadSheetData(int sheetIndex)
|
||
{
|
||
try
|
||
{
|
||
if (sheetIndex < 0 || sheetIndex >= sheetNames.Count)
|
||
return;
|
||
|
||
// 获取要加载的工作表名称
|
||
string sheetName = sheetNames[sheetIndex];
|
||
|
||
FileInfo fileInfo = new FileInfo(excelFilePath);
|
||
using (ExcelPackage package = new ExcelPackage(fileInfo))
|
||
{
|
||
// 使用名称访问工作表(更可靠,避免索引问题)
|
||
ExcelWorksheet worksheet = package.Workbook.Worksheets[sheetName];
|
||
|
||
if (worksheet == null)
|
||
{
|
||
statusMessage = $"⚠️ 无法读取工作表: {sheetName}";
|
||
Debug.LogError($"[EPPlus测试] 工作表 '{sheetName}' 不存在");
|
||
return;
|
||
}
|
||
|
||
// 获取有效数据范围
|
||
if (worksheet.Dimension == null)
|
||
{
|
||
statusMessage = $"⚠️ 工作表 '{sheetName}' 为空";
|
||
sheetData = null;
|
||
maxRows = 0;
|
||
maxCols = 0;
|
||
Debug.LogWarning($"[EPPlus测试] 工作表 '{sheetName}' 没有数据");
|
||
return;
|
||
}
|
||
|
||
maxRows = worksheet.Dimension.End.Row;
|
||
maxCols = worksheet.Dimension.End.Column;
|
||
|
||
// 创建二维数组存储数据
|
||
sheetData = new string[maxRows, maxCols];
|
||
|
||
// 读取所有单元格数据
|
||
// 注意:EPPlus 的索引从 1 开始,不是 0
|
||
for (int row = 1; row <= maxRows; row++)
|
||
{
|
||
for (int col = 1; col <= maxCols; col++)
|
||
{
|
||
var cell = worksheet.Cells[row, col];
|
||
sheetData[row - 1, col - 1] = cell.Value?.ToString() ?? "";
|
||
}
|
||
}
|
||
|
||
statusMessage = $"✅ 已加载工作表: {sheetName} ({maxRows}行 × {maxCols}列)";
|
||
|
||
// 重置滚动位置
|
||
dataScrollPosition = Vector2.zero;
|
||
|
||
Debug.Log($"[EPPlus测试] 成功加载工作表: '{sheetName}'");
|
||
Debug.Log($"[EPPlus测试] 数据范围: {maxRows} 行 × {maxCols} 列");
|
||
|
||
// 打印前几行数据用于调试
|
||
if (maxRows > 0 && maxCols > 0)
|
||
{
|
||
Debug.Log($"[EPPlus测试] 第1行第1列: {sheetData[0, 0]}");
|
||
if (maxRows > 1)
|
||
{
|
||
Debug.Log($"[EPPlus测试] 第2行第1列: {sheetData[1, 0]}");
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
statusMessage = $"❌ 读取工作表失败: {ex.Message}";
|
||
Debug.LogError($"[EPPlus测试] 读取工作表失败: {ex.Message}\n{ex.StackTrace}");
|
||
}
|
||
}
|
||
}
|
||
}
|