# 🚀 充电桩管理系统 - 快速启动指南

## 📦 文件清单

已创建的文件：
```
Charge/
├── ChargeStation.cs                      # 充电桩数据模型
├── ChargeStationDataService.cs           # 数据服务（单例）
├── ChargeStationManagementForm.cs        # 管理窗口主类
├── ChargeStationManagementForm.Designer.cs # 窗口UI设计
├── ChargeStationManagementExample.cs     # 示例代码
├── README_ChargeStationManagement.md     # 详细使用说明
└── QUICKSTART.md                         # 本文件
```

## ⚡ 5分钟快速上手

### 步骤1：在主窗口添加菜单（推荐方式）

如果您的主窗口有菜单栏，添加一个菜单项：

```csharp
// 在主窗口的 InitializeComponent() 或构造函数中添加

// 方法1: 如果有工具栏
var btnChargeManagement = new ToolStripButton("充电桩管理");
btnChargeManagement.Click += (s, e) => {
    var form = new StandardScene.Charge.ChargeStationManagementForm();
    form.Show();
};
toolStrip.Items.Add(btnChargeManagement);

// 方法2: 如果有菜单栏
var menuItemCharge = new ToolStripMenuItem("充电桩管理(&C)");
menuItemCharge.Click += (s, e) => {
    var form = new StandardScene.Charge.ChargeStationManagementForm();
    form.Show();
};
menuStrip.Items.Add(menuItemCharge);

// 方法3: 如果有按钮面板
var btnChargeManagement = new Button
{
    Text = "充电桩管理",
    Size = new Size(120, 40),
    Location = new Point(10, 10)
};
btnChargeManagement.Click += (s, e) => {
    var form = new StandardScene.Charge.ChargeStationManagementForm();
    form.Show();
};
this.Controls.Add(btnChargeManagement);
```

### 步骤2：初始化测试数据（首次运行）

在程序启动时或通过菜单调用：

```csharp
// 在主窗口的 Load 事件或启动代码中
StandardScene.Charge.ChargeStationManagementExample.InitializeTestData();
```

### 步骤3：打开管理窗口

点击您添加的菜单项或按钮，即可打开充电桩管理窗口。

---

## 🎯 集成到 AbstractChargeMission

如果您想将充电桩数据与充电任务关联，在 `AbstractChargeMission.cs` 中添加：

### 1. 引用命名空间

```csharp
using StandardScene.Charge;
```

### 2. 在选择充电站点时使用充电桩数据

```csharp
// 在 Execute() 方法的充电决策部分
var dataService = ChargeStationDataService.Instance;

// 获取空闲的充电桩
var idleStations = dataService.GetIdleStations();

// 根据充电桩的站点ID筛选
targetPlan = Commons.GetNearestPlan((Car)car, site =>
    site.fields.ContainsKey("group") && 
    site.fields.ContainsKey("Charge") &&
    GetChargeType(car).Contains(site.fields["group"]) &&
    idleStations.Any(s => s.SiteId == site.id) // 确保站点有空闲充电桩
);
```

### 3. 在开始充电时更新充电桩状态

```csharp
// 在车辆到达充电站时
public override void ArriveAction(Car car, Site site)
{
    var dataService = ChargeStationDataService.Instance;
    var station = dataService.GetAllStations()
        .FirstOrDefault(s => s.SiteId == site.id && s.Status == ChargeStationStatus.Idle);
    
    if (station != null)
    {
        dataService.UpdateStationStatus(station.StationId, ChargeStationStatus.Charging);
        car.tags.Add("chargingStationId", station.StationId);
        
        Diagnosis.Log($"车辆 {car.name} 开始在充电桩 {station.Name} 充电", 
            "Charge", true);
    }
}
```

### 4. 在离开充电站时更新充电桩状态

```csharp
// 在车辆离开充电站时
public override void LeaveAction(Car car, Site site)
{
    if (car.tags.TryGetValue("chargingStationId", out var stationId))
    {
        var dataService = ChargeStationDataService.Instance;
        dataService.UpdateStationStatus(stationId, ChargeStationStatus.Idle);
        car.tags.Remove("chargingStationId");
        
        Diagnosis.Log($"车辆 {car.name} 充电完成，充电桩 {stationId} 恢复空闲", 
            "Charge", true);
    }
}
```

---

## 📊 在主界面显示充电桩统计

在主窗口添加实时统计显示：

```csharp
// 添加一个 Timer 定时更新统计信息
private Timer chargeStationStatusTimer;
private Label lblChargeStationStatus;

private void InitializeChargeStationMonitor()
{
    // 创建状态标签
    lblChargeStationStatus = new Label
    {
        Text = "充电桩: 加载中...",
        AutoSize = true,
        Location = new Point(10, 10),
        Font = new Font("微软雅黑", 10F, FontStyle.Bold)
    };
    this.Controls.Add(lblChargeStationStatus);
    
    // 创建定时器（每3秒更新一次）
    chargeStationStatusTimer = new Timer
    {
        Interval = 3000,
        Enabled = true
    };
    chargeStationStatusTimer.Tick += UpdateChargeStationStatus;
    chargeStationStatusTimer.Start();
}

private void UpdateChargeStationStatus(object sender, EventArgs e)
{
    try
    {
        var dataService = StandardScene.Charge.ChargeStationDataService.Instance;
        var stations = dataService.GetAllStations();
        
        var idle = stations.Count(s => s.Status == StandardScene.Charge.ChargeStationStatus.Idle);
        var charging = stations.Count(s => s.Status == StandardScene.Charge.ChargeStationStatus.Charging);
        var fault = stations.Count(s => s.Status == StandardScene.Charge.ChargeStationStatus.Fault);
        
        lblChargeStationStatus.Text = $"充电桩: 总数 {stations.Count} | " +
                                     $"空闲 {idle} | 充电中 {charging} | 故障 {fault}";
        
        // 根据状态设置颜色
        if (fault > 0)
            lblChargeStationStatus.ForeColor = Color.Red;
        else if (idle == 0 && charging > 0)
            lblChargeStationStatus.ForeColor = Color.Orange;
        else
            lblChargeStationStatus.ForeColor = Color.Green;
    }
    catch (Exception ex)
    {
        lblChargeStationStatus.Text = $"充电桩: 获取状态失败 - {ex.Message}";
        lblChargeStationStatus.ForeColor = Color.Gray;
    }
}
```

---

## 🔧 配置充电桩与站点的映射

### 方式1: 在站点属性中添加充电桩编号

修改地图站点的 `fields`：

```csharp
// 为站点添加充电桩编号
site.fields.Add("ChargeStationId", "CS20240115123456");
```

### 方式2: 在充电桩管理界面直接设置站点ID

在充电桩管理窗口中，编辑充电桩时填写"站点ID"字段。

### 方式3: 自动关联（代码实现）

```csharp
// 自动将充电桩与最近的充电站点关联
public void AutoAssignStationsToSites()
{
    var dataService = ChargeStationDataService.Instance;
    var allStations = dataService.GetAllStations();
    var chargeSites = SimpleLib.GetAllSites()
        .Where(s => s.fields.ContainsKey("Charge"))
        .ToList();
    
    foreach (var station in allStations)
    {
        if (station.SiteId == null || station.SiteId == 0)
        {
            // 根据名称或其他规则自动匹配站点
            var matchedSite = chargeSites.FirstOrDefault(s => 
                s.fields.ContainsKey("name") && 
                s.fields["name"].Contains(station.Name)
            );
            
            if (matchedSite != null)
            {
                station.SiteId = matchedSite.id;
                dataService.UpdateStation(station, out _);
                
                Diagnosis.Log($"自动关联充电桩 {station.Name} 到站点 {matchedSite.id}", 
                    "ChargeStation", true);
            }
        }
    }
}
```

---

## 📱 添加快捷键

为管理窗口添加快捷键（在主窗口）：

```csharp
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
    // Ctrl+C 打开充电桩管理
    if (keyData == (Keys.Control | Keys.C))
    {
        var form = new StandardScene.Charge.ChargeStationManagementForm();
        form.Show();
        return true;
    }
    
    return base.ProcessCmdKey(ref msg, keyData);
}
```

---

## 🎨 自定义界面样式

如果需要调整窗口样式，修改 `ChargeStationManagementForm.Designer.cs`：

```csharp
// 修改窗口大小
this.Size = new Size(1400, 800);

// 修改按钮颜色
btnAdd.BackColor = Color.FromArgb(144, 238, 144); // 浅绿色
btnSave.BackColor = Color.FromArgb(135, 206, 250); // 浅蓝色
btnDelete.BackColor = Color.FromArgb(255, 182, 193); // 浅红色

// 修改字体
this.Font = new Font("微软雅黑", 9F);
```

---

## 🐛 常见问题

### Q1: 窗口打不开
**A**: 检查是否正确引用了命名空间：
```csharp
using StandardScene.Charge;
```

### Q2: 数据保存失败
**A**: 确保 `Data` 文件夹有写入权限：
```bash
# Windows
右键 Data 文件夹 -> 属性 -> 安全 -> 确保当前用户有"写入"权限
```

### Q3: 找不到充电桩数据
**A**: 首次运行时需要初始化数据：
```csharp
ChargeStationManagementExample.InitializeTestData();
```

### Q4: 充电桩状态不更新
**A**: 手动刷新数据：
```csharp
ChargeStationDataService.Instance.Reload();
```

---

## 📚 进阶功能

### 实时监控充电桩通信状态

```csharp
// 定期 Ping 充电桩 IP
private async Task<bool> PingChargeStation(string ip, int port)
{
    try
    {
        using (var client = new System.Net.Sockets.TcpClient())
        {
            var result = client.BeginConnect(ip, port, null, null);
            var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(3));
            
            if (success)
            {
                client.EndConnect(result);
                return true;
            }
            return false;
        }
    }
    catch
    {
        return false;
    }
}
```

### 充电桩数据可视化

```csharp
// 在主界面添加充电桩状态图表
private void DrawChargeStationChart(Graphics g)
{
    var dataService = ChargeStationDataService.Instance;
    var stations = dataService.GetAllStations();
    
    int x = 10, y = 10, size = 40;
    
    foreach (var station in stations)
    {
        Color color = station.Status switch
        {
            ChargeStationStatus.Idle => Color.Green,
            ChargeStationStatus.Charging => Color.Yellow,
            ChargeStationStatus.Fault => Color.Red,
            ChargeStationStatus.Offline => Color.Gray,
            _ => Color.White
        };
        
        g.FillRectangle(new SolidBrush(color), x, y, size, size);
        g.DrawString(station.Name, this.Font, Brushes.Black, x, y + size + 5);
        
        x += size + 10;
        if (x > this.Width - 100)
        {
            x = 10;
            y += size + 30;
        }
    }
}
```

---

## 🎉 完成

现在您已经完成了充电桩管理系统的集成！

**下一步**：
1. ✅ 添加菜单项或按钮
2. ✅ 初始化测试数据
3. ✅ 打开管理窗口测试
4. ✅ 将充电桩数据集成到充电任务
5. ✅ 添加实时监控和统计

**需要帮助？**
- 查看 `README_ChargeStationManagement.md` 获取详细文档
- 参考 `ChargeStationManagementExample.cs` 查看示例代码
- 检查日志中的 `ChargeStation` 标签

---

**版本**: 1.0.0  
**最后更新**: 2024-01-15



