feat: 实现 FOD 日志数据采集 CLI 应用

This commit is contained in:
ssss
2026-07-02 18:13:56 +08:00
parent c4e5ac0360
commit 3dcd9f7c0b
52 changed files with 3144 additions and 354 deletions

View File

@@ -55,69 +55,112 @@
| chk_qfod_charger | CHECK | charger_index IN (0, 1) |
| chk_qfod_coil | CHECK | coil_index IN (0, 1, 2) |
> **数据库兼容性**`IN (0, 1)` 语法在 SQLite、PostgreSQL、MySQL 中均可使用。若使用其他数据库,需验证 CHECK 约束语法兼容性。
---
## 6. EF Core 模型
### 实体类
```csharp
// Models/QfodRecord.cs
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace WCTDataMiner.Models;
[Table("qfod_record")]
[Index(nameof(ScenarioId), Name = "idx_qfod_scenario")]
[Index(nameof(ChargerIndex), nameof(CoilIndex), Name = "idx_qfod_charger_coil")]
[Index(nameof(FodType), Name = "idx_qfod_fod_type")]
[Index(nameof(DeltaQ), Name = "idx_qfod_delta_q")]
public class QfodRecord
{
[Key]
[Column("id")]
public Guid Id { get; set; } = Guid.NewGuid();
[Required]
[Column("scenario_id")]
public Guid ScenarioId { get; set; }
[Required]
[Column("charger_index")]
public byte ChargerIndex { get; set; }
[Required]
[Column("coil_index")]
public byte CoilIndex { get; set; }
[Required]
[Column("delta_q")]
public int DeltaQ { get; set; }
[Required]
[Column("current_q")]
public float CurrentQ { get; set; }
[Required]
[Column("raw_q")]
public float RawQ { get; set; }
[Required]
[Column("fod_type")]
public byte FodType { get; set; }
[Required]
[Column("is_deleted")]
public bool IsDeleted { get; set; } = false;
[Required]
[Column("created_at")]
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
[ForeignKey(nameof(ScenarioId))]
// Navigation Properties
public TestScenario Scenario { get; set; } = null!;
}
```
### 配置类
```csharp
// Data/Configurations/QfodRecordConfiguration.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using WCTDataMiner.Models;
namespace WCTDataMiner.Data.Configurations;
public class QfodRecordConfiguration : IEntityTypeConfiguration<QfodRecord>
{
public void Configure(EntityTypeBuilder<QfodRecord> builder)
{
builder.ToTable("qfod_record");
builder.HasKey(e => e.Id);
builder.Property(e => e.Id).HasColumnName("id");
builder.Property(e => e.ScenarioId)
.IsRequired()
.HasColumnName("scenario_id");
builder.Property(e => e.ChargerIndex)
.IsRequired()
.HasColumnName("charger_index");
builder.Property(e => e.CoilIndex)
.IsRequired()
.HasColumnName("coil_index");
builder.Property(e => e.DeltaQ)
.IsRequired()
.HasColumnName("delta_q");
builder.Property(e => e.CurrentQ)
.IsRequired()
.HasColumnName("current_q");
builder.Property(e => e.RawQ)
.IsRequired()
.HasColumnName("raw_q");
builder.Property(e => e.FodType)
.IsRequired()
.HasColumnName("fod_type");
builder.Property(e => e.IsDeleted)
.IsRequired()
.HasDefaultValue(false)
.HasColumnName("is_deleted");
builder.Property(e => e.CreatedAt)
.IsRequired()
.HasDefaultValueSql("NOW()")
.HasColumnName("created_at");
// 索引
builder.HasIndex(e => e.ScenarioId).HasDatabaseName("idx_qfod_scenario");
builder.HasIndex(e => new { e.ChargerIndex, e.CoilIndex }).HasDatabaseName("idx_qfod_charger_coil");
builder.HasIndex(e => e.FodType).HasDatabaseName("idx_qfod_fod_type");
builder.HasIndex(e => e.DeltaQ).HasDatabaseName("idx_qfod_delta_q");
// CHECK 约束
builder.HasCheckConstraint("chk_qfod_charger", "charger_index IN (0, 1)");
builder.HasCheckConstraint("chk_qfod_coil", "coil_index IN (0, 1, 2)");
// 关系配置
builder.HasOne(e => e.Scenario)
.WithMany(e => e.QfodRecords)
.HasForeignKey(e => e.ScenarioId)
.IsRequired();
}
}
```
---
## 7. 检测通道组合