# BaseDesignToolEditor 使用说明

## 概述

`BaseDesignToolEditor` 是为策划工具统一设计的编辑器基类，封装了常见的功能，包括：
- ✅ Docs路径的选择和保存
- ✅ 自动检查并拉取Docs仓库的最新更新
- ✅ 检查是否有未提交的更改（提示但不强制）
- ✅ 自动切换Design_SubModule到main分支
- ✅ 统一的UI框架（工具栏、路径选择、数据编辑区）
- ✅ Git命令执行的封装

## 功能特点

### 1. 自动Git管理
- **自动Fetch**: 检查远程仓库更新
- **智能提醒**: 如果有未提交的更改，会提示用户但允许继续（不强制）
- **自动Pull**: 如果远程有更新，自动拉取
- **冲突检测**: 如果拉取时有冲突，会友好提示

### 2. 分支管理
- 自动检查Design_SubModule是否在main分支
- 如果不在main分支，自动切换

### 3. 路径管理
- EditorPrefs自动保存和恢复用户上次选择的路径
- 提供便捷的路径选择对话框

### 4. 统一UI
- 工具栏显示工具名称
- 路径选择区域
- 加载按钮
- 数据编辑区域

## 使用方法

### 基本用法

创建一个新的Editor工具时，继承 `BaseDesignToolEditor` 并实现必需的抽象方法：

```csharp
using UnityEditor;
using UnityEngine;
using DesignTools;

namespace DesignTools.YourCategory
{
    public class YourConfigEditor : BaseDesignToolEditor
    {
        // 1. 定义MenuItem来显示窗口
        [MenuItem("策划工具/你的分类/你的工具")]
        public static void ShowWindow()
        {
            var window = GetWindow<YourConfigEditor>("你的工具");
            window.minSize = window.GetMinWindowSize(); // 可选：使用默认大小或自定义
            window.Show();
        }

        // 2. 实现必需的抽象方法

        /// <summary>
        /// 返回保存路径的EditorPrefs键（需要唯一）
        /// </summary>
        protected override string GetDocsPathPrefKey()
        {
            return "YourConfigEditor_DocsPath";
        }

        /// <summary>
        /// 返回窗口标题
        /// </summary>
        protected override string GetWindowTitle()
        {
            return "你的工具配置工具";
        }

        /// <summary>
        /// 加载具体的配置数据
        /// 在Git检查和更新完成后调用
        /// </summary>
        protected override void LoadConfigData()
        {
            // 使用 GetDocsConfigFilePath() 获取Excel文件路径
            string excelPath = GetDocsConfigFilePath("YourExcel.xlsx");
            
            // 加载你的Excel数据
            // LoadYourExcelData(excelPath);
            
            // 加载其他必要数据
            // ...
        }

        /// <summary>
        /// 绘制数据编辑器UI
        /// </summary>
        protected override void DrawDataEditor()
        {
            // 使用 scrollPosition 管理滚动视图
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            // 绘制你的数据编辑UI
            // ...
            
            EditorGUILayout.EndScrollView();
        }
    }
}
```

### 可选的虚方法覆盖

#### 1. 自定义窗口尺寸

```csharp
protected override Vector2 GetMinWindowSize()
{
    return new Vector2(1200, 700); // 自定义最小窗口大小
}
```

#### 2. 禁用Design_SubModule分支检查

```csharp
protected override bool NeedCheckDesignSubModuleBranch()
{
    return false; // 如果不需要检查分支，返回false
}
```

#### 3. 自定义Docs配置路径

```csharp
protected override string GetDocsConfigPath()
{
    return "custom/config/path"; // 默认是 "config"
}
```

#### 4. 自定义路径验证

```csharp
protected override bool ValidateDocsPath()
{
    // 先调用基类的验证
    if (!base.ValidateDocsPath())
    {
        return false;
    }
    
    // 添加你自己的验证逻辑
    // ...
    
    return true;
}
```

## 完整示例

以下是一个完整的示例，展示如何使用基类创建一个简单的配置工具：

```csharp
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using OfficeOpenXml;
using DesignTools;

namespace DesignTools.Examples
{
    public class SimpleConfigEditor : BaseDesignToolEditor
    {
        private List<string> dataList = new List<string>();
        
        [MenuItem("策划工具/示例/简单配置工具")]
        public static void ShowWindow()
        {
            var window = GetWindow<SimpleConfigEditor>("简单配置工具");
            window.minSize = window.GetMinWindowSize();
            window.Show();
        }

        protected override string GetDocsPathPrefKey()
        {
            return "SimpleConfigEditor_DocsPath";
        }

        protected override string GetWindowTitle()
        {
            return "简单配置工具";
        }

        protected override void LoadConfigData()
        {
            // 清空旧数据
            dataList.Clear();
            
            // 获取Excel文件路径
            string excelPath = GetDocsConfigFilePath("SimpleConfig.xlsx");
            
            // 使用EPPlus加载Excel
            using (var package = new ExcelPackage(new System.IO.FileInfo(excelPath)))
            {
                var worksheet = package.Workbook.Worksheets[0];
                int rowCount = worksheet.Dimension.Rows;
                
                for (int row = 2; row <= rowCount; row++)
                {
                    string data = worksheet.Cells[row, 1].Text;
                    if (!string.IsNullOrEmpty(data))
                    {
                        dataList.Add(data);
                    }
                }
            }
            
            Debug.Log($"加载了 {dataList.Count} 条数据");
        }

        protected override void DrawDataEditor()
        {
            EditorGUILayout.BeginVertical("box");
            EditorGUILayout.LabelField($"共有 {dataList.Count} 条数据", EditorStyles.boldLabel);
            EditorGUILayout.EndVertical();
            
            EditorGUILayout.Space(5);
            
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            
            foreach (var data in dataList)
            {
                EditorGUILayout.LabelField(data);
            }
            
            EditorGUILayout.EndScrollView();
        }
    }
}
```

## 基类提供的受保护字段

可以在子类中直接使用以下字段：

```csharp
protected string docsRootPath;           // Docs根目录路径
protected bool isDataLoaded;             // 数据是否已加载
protected Vector2 scrollPosition;        // 滚动位置
```

## 基类提供的受保护常量

```csharp
protected const string DESIGN_SUBMODULE_PATH = "Assets/Design_SubModule";
```

## 基类提供的工具方法

### 1. 获取配置文件路径

```csharp
// 获取 Docs/config/YourFile.xlsx 的完整路径
string path = GetDocsConfigFilePath("YourFile.xlsx");
```

### 2. 获取Docs下的任意路径

```csharp
// 获取 Docs/custom/path/file.txt 的完整路径
string path = GetDocsFullPath("custom/path/file.txt");
```

### 3. 执行Git命令

```csharp
string result = ExecuteGitCommand(
    workingDirectory: docsRootPath,
    arguments: "log -1 --oneline",
    out bool success
);

if (success)
{
    Debug.Log($"Git命令执行成功: {result}");
}
```

## 注意事项

1. **唯一的PrefsKey**: 确保每个编辑器工具使用唯一的 `GetDocsPathPrefKey()` 返回值
2. **异常处理**: 基类已经处理了 `LoadData()` 的异常，子类在 `LoadConfigData()` 中只需关注具体逻辑
3. **进度条**: Git操作时会自动显示进度条，无需在子类中处理
4. **EPPlus许可证**: 如果使用EPPlus，记得在子类的 `OnEnable()` 中设置许可证上下文

```csharp
protected override void OnEnable()
{
    base.OnEnable(); // 调用基类的OnEnable
    ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
}
```

## 迁移现有工具

如果要将现有的Editor工具迁移到使用基类，步骤如下：

1. 将类声明改为继承 `BaseDesignToolEditor`
2. 删除重复的字段定义（如 `docsRootPath`、`isDataLoaded` 等）
3. 删除 `ExecuteGitCommand`、`CheckAndUpdateDocsRepository` 等方法
4. 实现必需的抽象方法
5. 修改 `LoadData()` 逻辑，将具体加载逻辑移到 `LoadConfigData()` 中
6. 修改 `OnGUI()`，删除路径选择和工具栏部分，只保留 `DrawDataEditor()` 的实现

## 未来扩展

基类还可以继续扩展以下功能：
- 语言表加载的通用封装
- Excel读取的辅助方法
- ArtTableSO加载的通用方法
- 数据验证的通用框架
- 数据保存和导出的通用方法

如有需要，可以继续向基类添加通用功能。
