414 lines
11 KiB
Markdown
414 lines
11 KiB
Markdown
# 🚀 充电桩管理系统 - 快速启动指南
|
||||
|
|
|
|||
|
|
## 📦 文件清单
|
|||
|
|
|
|||
|
|
已创建的文件:
|
|||
|
|
```
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
|
|||
|
|
|