docs: 完善数据模型设计
- 重命名 log_file 为 test_scenario(测试场景) - 拆分维度表:tx_panel、tx_hardware、tx_software、rx_type - 采用星型模型设计,消除数据冗余 - 为所有表添加软删除字段 is_deleted - 更新关系说明,包含全局查询过滤器配置 - 更新 ER 图和查询示例 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
189
docs/data-model/entities/Ploss记录.md
Normal file
189
docs/data-model/entities/Ploss记录.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# ploss_record 实体
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`ploss_record`
|
||||
|
||||
**描述**:存储 Ploss FOD 格式解析数据,对应日志格式 `FOD-> (1)...(13)`
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键 |
|
||||
| scenario_id | UUID | FK, NOT NULL | 关联测试场景 |
|
||||
| rx_type | TINYINT | NOT NULL | 接收端类型标识 |
|
||||
| rx_power | SMALLINT | NOT NULL | 接收端功率(mW) |
|
||||
| tx_power | SMALLINT | NOT NULL | 发射端功率(mW) |
|
||||
| vcoil | SMALLINT | NOT NULL | 发射线圈电压 |
|
||||
| vin | SMALLINT | NOT NULL | 输入电压 |
|
||||
| isns | SMALLINT | NOT NULL | 输入电流采样值 |
|
||||
| ploss | INT | NOT NULL | **核心值**:计算损耗(负数=安全) |
|
||||
| threshold | INT | NOT NULL | **安全红线**:当前功率段阈值 |
|
||||
| trigger_count | SMALLINT | NOT NULL, DEFAULT 0 | 触发计数器 |
|
||||
| fod_result | SMALLINT | NOT NULL, DEFAULT 0 | FOD判定结果 |
|
||||
| protocol_type | TINYINT | NOT NULL | 充电协议类型 |
|
||||
| pwm_duty | SMALLINT | NOT NULL | PWM占空比 |
|
||||
| coil_index | TINYINT | NOT NULL | 充电线圈索引 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 外键
|
||||
|
||||
| 外键 | 引用表 | 说明 |
|
||||
|------|--------|------|
|
||||
| scenario_id | test_scenario.id | 关联测试场景(必需) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 派生字段
|
||||
|
||||
> **注意**:以下字段不落库,查询时动态计算
|
||||
|
||||
| 字段 | 计算公式 | 说明 |
|
||||
|------|----------|------|
|
||||
| margin | threshold - ploss | 安全余量(>0 安全,<0 危险) |
|
||||
|
||||
---
|
||||
|
||||
## 5. 索引
|
||||
|
||||
| 索引名 | 字段 | 用途 |
|
||||
|--------|------|------|
|
||||
| idx_ploss_scenario | scenario_id | 按测试场景查询 |
|
||||
| idx_ploss_rx_power | rx_power | 阈值表匹配 |
|
||||
| idx_ploss_ploss | ploss | 损耗值查询 |
|
||||
| idx_ploss_threshold | threshold | 阈值查询 |
|
||||
| idx_ploss_fod_result | fod_result | FOD结果筛选 |
|
||||
|
||||
---
|
||||
|
||||
## 6. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/PlossRecord.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("ploss_record")]
|
||||
[Index(nameof(ScenarioId), Name = "idx_ploss_scenario")]
|
||||
[Index(nameof(RxPower), Name = "idx_ploss_rx_power")]
|
||||
[Index(nameof(Ploss), Name = "idx_ploss_ploss")]
|
||||
[Index(nameof(Threshold), Name = "idx_ploss_threshold")]
|
||||
[Index(nameof(FodResult), Name = "idx_ploss_fod_result")]
|
||||
public class PlossRecord
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[Column("scenario_id")]
|
||||
public Guid ScenarioId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("rx_type")]
|
||||
public byte RxType { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("rx_power")]
|
||||
public short RxPower { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("tx_power")]
|
||||
public short TxPower { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("vcoil")]
|
||||
public short Vcoil { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("vin")]
|
||||
public short Vin { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("isns")]
|
||||
public short Isns { get; set; }
|
||||
|
||||
/// <summary>核心判定值:负数表示安全</summary>
|
||||
[Required]
|
||||
[Column("ploss")]
|
||||
public int Ploss { get; set; }
|
||||
|
||||
/// <summary>安全红线:当前功率段阈值</summary>
|
||||
[Required]
|
||||
[Column("threshold")]
|
||||
public int Threshold { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("trigger_count")]
|
||||
public short TriggerCount { get; set; } = 0;
|
||||
|
||||
[Required]
|
||||
[Column("fod_result")]
|
||||
public short FodResult { get; set; } = 0;
|
||||
|
||||
[Required]
|
||||
[Column("protocol_type")]
|
||||
public byte ProtocolType { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("pwm_duty")]
|
||||
public short PwmDuty { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("coil_index")]
|
||||
public byte CoilIndex { 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))]
|
||||
public TestScenario Scenario { get; set; } = null!;
|
||||
|
||||
/// <summary>派生属性:安全余量</summary>
|
||||
[NotMapped]
|
||||
public int Margin => Threshold - Ploss;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 动态阈值表
|
||||
|
||||
> 阈值根据 RxPower 动态查表(不落库)
|
||||
|
||||
| Rx Power 区间 | Threshold | 备注 |
|
||||
|---------------|-----------|------|
|
||||
| 0-5000 mW | 350 mW | 低功率最敏感 |
|
||||
| 5000-10000 mW | 500 mW | |
|
||||
| 10000-15000 mW | 750 mW | |
|
||||
| 15000-30000 mW | 1000 mW | |
|
||||
| 30000-50000 mW | 1250 mW | 高功率 |
|
||||
|
||||
```csharp
|
||||
// Services/ThresholdCalculator.cs
|
||||
public static int GetThresholdByPower(int rxPower)
|
||||
{
|
||||
if (rxPower <= 5000) return 350;
|
||||
if (rxPower <= 10000) return 500;
|
||||
if (rxPower <= 15000) return 750;
|
||||
if (rxPower <= 30000) return 1000;
|
||||
return 1250;
|
||||
}
|
||||
```
|
||||
132
docs/data-model/entities/Qfod记录.md
Normal file
132
docs/data-model/entities/Qfod记录.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# qfod_record 实体
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`qfod_record`
|
||||
|
||||
**描述**:存储 Qfod 格式解析数据,对应日志格式 `X#:Q A->B C D E`
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键 |
|
||||
| scenario_id | UUID | FK, NOT NULL | 关联测试场景 |
|
||||
| charger_index | TINYINT | NOT NULL | 充电器索引(0 或 1) |
|
||||
| coil_index | TINYINT | NOT NULL | 线圈索引(0、1、2) |
|
||||
| delta_q | INT | NOT NULL | Q值变化量(ΔQ = current_q - raw_q) |
|
||||
| current_q | FLOAT | NOT NULL | 当前实时 Q值 |
|
||||
| raw_q | FLOAT | NOT NULL | 原始 Q值 |
|
||||
| fod_type | TINYINT | NOT NULL | 异物类型编码 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 外键
|
||||
|
||||
| 外键 | 引用表 | 说明 |
|
||||
|------|--------|------|
|
||||
| scenario_id | test_scenario.id | 关联测试场景(必需) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 索引
|
||||
|
||||
| 索引名 | 字段 | 用途 |
|
||||
|--------|------|------|
|
||||
| idx_qfod_scenario | scenario_id | 按测试场景查询 |
|
||||
| idx_qfod_charger_coil | (charger_index, coil_index) | 按检测通道查询 |
|
||||
| idx_qfod_fod_type | fod_type | 按异物类型统计 |
|
||||
| idx_qfod_delta_q | delta_q | 阈值分析 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 约束
|
||||
|
||||
| 约束名 | 类型 | 定义 |
|
||||
|--------|------|------|
|
||||
| chk_qfod_charger | CHECK | charger_index IN (0, 1) |
|
||||
| chk_qfod_coil | CHECK | coil_index IN (0, 1, 2) |
|
||||
|
||||
---
|
||||
|
||||
## 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))]
|
||||
public TestScenario Scenario { get; set; } = null!;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 检测通道组合
|
||||
|
||||
| ChargerIndex | CoilIndex | 检测通道 |
|
||||
|--------------|-----------|----------|
|
||||
| 0 | 0 | 充电器0-线圈0 |
|
||||
| 0 | 1 | 充电器0-线圈1 |
|
||||
| 0 | 2 | 充电器0-线圈2 |
|
||||
| 1 | 0 | 充电器1-线圈0 |
|
||||
| 1 | 1 | 充电器1-线圈1 |
|
||||
| 1 | 2 | 充电器1-线圈2 |
|
||||
89
docs/data-model/entities/RxType维度.md
Normal file
89
docs/data-model/entities/RxType维度.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# rx_type 维度表
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`rx_type`
|
||||
|
||||
**描述**:RX类型维度表,存储接收端类型(模组品牌或手机型号)
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键,自动生成 |
|
||||
| name | VARCHAR(100) | UNIQUE, NOT NULL | RX类型名称 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 类型示例
|
||||
|
||||
| 类型分类 | name 示例 |
|
||||
|----------|----------|
|
||||
| 模组 | 伏达、易冲、YBZ、... |
|
||||
| 手机 | iPhone15、Samsung-S24、小米14、... |
|
||||
|
||||
---
|
||||
|
||||
## 4. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/RxType.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("rx_type")]
|
||||
public class RxType
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(100)]
|
||||
[Column("name")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[Column("is_deleted")]
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
[Required]
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Navigation Properties
|
||||
public ICollection<TestScenario> TestScenarios { get; set; } = [];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 使用说明
|
||||
|
||||
RX类型在解析文件名时自动创建,无需预置数据:
|
||||
|
||||
```csharp
|
||||
// 获取或创建RX类型
|
||||
public async Task<RxType> GetOrCreateAsync(string name)
|
||||
{
|
||||
var existing = await context.RxTypes
|
||||
.FirstOrDefaultAsync(r => r.Name == name);
|
||||
|
||||
if (existing != null) return existing;
|
||||
|
||||
var newRxType = new RxType { Name = name };
|
||||
context.RxTypes.Add(newRxType);
|
||||
await context.SaveChangesAsync();
|
||||
return newRxType;
|
||||
}
|
||||
```
|
||||
80
docs/data-model/entities/TxHardware维度.md
Normal file
80
docs/data-model/entities/TxHardware维度.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# tx_hardware 维度表
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`tx_hardware`
|
||||
|
||||
**描述**:TX硬件版本维度表,存储所有硬件版本号
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键,自动生成 |
|
||||
| version | VARCHAR(50) | UNIQUE, NOT NULL | 硬件版本号 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/TxHardware.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("tx_hardware")]
|
||||
public class TxHardware
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
[Column("version")]
|
||||
public string Version { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[Column("is_deleted")]
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
[Required]
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Navigation Properties
|
||||
public ICollection<TestScenario> TestScenarios { get; set; } = [];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 使用说明
|
||||
|
||||
硬件版本在解析文件名时自动创建,无需预置数据:
|
||||
|
||||
```csharp
|
||||
// 获取或创建硬件版本
|
||||
public async Task<TxHardware> GetOrCreateAsync(string version)
|
||||
{
|
||||
var existing = await context.TxHardwares
|
||||
.FirstOrDefaultAsync(h => h.Version == version);
|
||||
|
||||
if (existing != null) return existing;
|
||||
|
||||
var newHardware = new TxHardware { Version = version };
|
||||
context.TxHardwares.Add(newHardware);
|
||||
await context.SaveChangesAsync();
|
||||
return newHardware;
|
||||
}
|
||||
```
|
||||
89
docs/data-model/entities/TxPanel维度.md
Normal file
89
docs/data-model/entities/TxPanel维度.md
Normal file
@@ -0,0 +1,89 @@
|
||||
# tx_panel 维度表
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`tx_panel`
|
||||
|
||||
**描述**:TX面板类型维度表,存储所有可用的面板类型
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键,自动生成 |
|
||||
| name | VARCHAR(50) | UNIQUE, NOT NULL | 面板类型名称 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 面板类型枚举值
|
||||
|
||||
| name | 说明 |
|
||||
|------|------|
|
||||
| none | 无面板 |
|
||||
| single-mold | 单充模具面板 |
|
||||
| single-rapid | 单充快速成型面板 |
|
||||
| single-3d | 单充3D打印面板 |
|
||||
| dual-mold | 双充模具面板 |
|
||||
| dual-rapid | 双充快速成型面板 |
|
||||
| dual-3d | 双充3D打印面板 |
|
||||
|
||||
---
|
||||
|
||||
## 4. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/TxPanel.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("tx_panel")]
|
||||
public class TxPanel
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
[Column("name")]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[Column("is_deleted")]
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
[Required]
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Navigation Properties
|
||||
public ICollection<TestScenario> TestScenarios { get; set; } = [];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 初始化数据
|
||||
|
||||
```csharp
|
||||
// Data/SeedData.cs
|
||||
public static readonly TxPanel[] DefaultTxPanels = [
|
||||
new() { Name = "none" },
|
||||
new() { Name = "single-mold" },
|
||||
new() { Name = "single-rapid" },
|
||||
new() { Name = "single-3d" },
|
||||
new() { Name = "dual-mold" },
|
||||
new() { Name = "dual-rapid" },
|
||||
new() { Name = "dual-3d" }
|
||||
];
|
||||
```
|
||||
80
docs/data-model/entities/TxSoftware维度.md
Normal file
80
docs/data-model/entities/TxSoftware维度.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# tx_software 维度表
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`tx_software`
|
||||
|
||||
**描述**:TX软件版本维度表,存储所有软件版本号(hex版本)
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键,自动生成 |
|
||||
| version | VARCHAR(50) | UNIQUE, NOT NULL | 软件版本号(hex版本) |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 创建时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/TxSoftware.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("tx_software")]
|
||||
public class TxSoftware
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
[Column("version")]
|
||||
public string Version { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
[Column("is_deleted")]
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
[Required]
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Navigation Properties
|
||||
public ICollection<TestScenario> TestScenarios { get; set; } = [];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 使用说明
|
||||
|
||||
软件版本在解析文件名时自动创建,无需预置数据:
|
||||
|
||||
```csharp
|
||||
// 获取或创建软件版本
|
||||
public async Task<TxSoftware> GetOrCreateAsync(string version)
|
||||
{
|
||||
var existing = await context.TxSoftwares
|
||||
.FirstOrDefaultAsync(s => s.Version == version);
|
||||
|
||||
if (existing != null) return existing;
|
||||
|
||||
var newSoftware = new TxSoftware { Version = version };
|
||||
context.TxSoftwares.Add(newSoftware);
|
||||
await context.SaveChangesAsync();
|
||||
return newSoftware;
|
||||
}
|
||||
```
|
||||
230
docs/data-model/entities/测试场景.md
Normal file
230
docs/data-model/entities/测试场景.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# test_scenario 实体
|
||||
|
||||
> 所属模块:[数据模型概览](../概览.md)
|
||||
|
||||
---
|
||||
|
||||
## 1. 表定义
|
||||
|
||||
**表名**:`test_scenario`
|
||||
|
||||
**描述**:存储测试场景,通过外键关联各维度表,test_purpose 直接存储
|
||||
|
||||
---
|
||||
|
||||
## 2. 字段定义
|
||||
|
||||
| 列名 | 类型 | 约束 | 说明 |
|
||||
|------|------|------|------|
|
||||
| id | UUID | PK, NOT NULL | 主键,自动生成 |
|
||||
| tx_panel_id | UUID | FK, NOT NULL | 关联TX面板维度 |
|
||||
| tx_hardware_id | UUID | FK, NOT NULL | 关联TX硬件版本维度 |
|
||||
| tx_software_id | UUID | FK, NOT NULL | 关联TX软件版本维度 |
|
||||
| rx_type_id | UUID | FK, NOT NULL | 关联RX类型维度 |
|
||||
| test_purpose | VARCHAR(200) | NULL | 测试目的(直接存储) |
|
||||
| test_date | DATE | NOT NULL | 测试日期 |
|
||||
| test_sequence | INT | NOT NULL, DEFAULT 1 | 测试次数序号 |
|
||||
| qfod_count | INT | NOT NULL, DEFAULT 0 | 包含的 Qfod 记录数 |
|
||||
| ploss_count | INT | NOT NULL, DEFAULT 0 | 包含的 Ploss 记录数 |
|
||||
| is_deleted | BOOLEAN | NOT NULL, DEFAULT FALSE | 软删除标记 |
|
||||
| created_at | TIMESTAMP | NOT NULL, DEFAULT NOW() | 入库时间 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 外键
|
||||
|
||||
| 外键 | 引用表 | 说明 |
|
||||
|------|--------|------|
|
||||
| tx_panel_id | tx_panel.id | 关联TX面板维度(必需) |
|
||||
| tx_hardware_id | tx_hardware.id | 关联TX硬件版本维度(必需) |
|
||||
| tx_software_id | tx_software.id | 关联TX软件版本维度(必需) |
|
||||
| rx_type_id | rx_type.id | 关联RX类型维度(必需) |
|
||||
|
||||
---
|
||||
|
||||
## 4. 索引
|
||||
|
||||
| 索引名 | 字段 | 用途 |
|
||||
|--------|------|------|
|
||||
| idx_scenario_tx_panel | tx_panel_id | 按面板类型筛选 |
|
||||
| idx_scenario_tx_hardware | tx_hardware_id | 按硬件版本筛选 |
|
||||
| idx_scenario_tx_software | tx_software_id | 按软件版本筛选 |
|
||||
| idx_scenario_rx_type | rx_type_id | 按RX类型筛选 |
|
||||
| idx_scenario_test_date | test_date | 按测试日期查询 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 唯一约束
|
||||
|
||||
| 约束名 | 字段组合 | 说明 |
|
||||
|--------|----------|------|
|
||||
| uq_scenario | (tx_panel_id, tx_hardware_id, tx_software_id, rx_type_id, test_purpose, test_date, test_sequence) | 相同属性组合不重复创建 |
|
||||
|
||||
---
|
||||
|
||||
## 6. EF Core 模型
|
||||
|
||||
```csharp
|
||||
// Models/TestScenario.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace WCTDataMiner.Models;
|
||||
|
||||
[Table("test_scenario")]
|
||||
[Index(nameof(TxPanelId), Name = "idx_scenario_tx_panel")]
|
||||
[Index(nameof(TxHardwareId), Name = "idx_scenario_tx_hardware")]
|
||||
[Index(nameof(TxSoftwareId), Name = "idx_scenario_tx_software")]
|
||||
[Index(nameof(RxTypeId), Name = "idx_scenario_rx_type")]
|
||||
[Index(nameof(TestDate), Name = "idx_scenario_test_date")]
|
||||
public class TestScenario
|
||||
{
|
||||
[Key]
|
||||
[Column("id")]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[Column("tx_panel_id")]
|
||||
public Guid TxPanelId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("tx_hardware_id")]
|
||||
public Guid TxHardwareId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("tx_software_id")]
|
||||
public Guid TxSoftwareId { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("rx_type_id")]
|
||||
public Guid RxTypeId { get; set; }
|
||||
|
||||
[MaxLength(200)]
|
||||
[Column("test_purpose")]
|
||||
public string? TestPurpose { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("test_date")]
|
||||
public DateOnly TestDate { get; set; }
|
||||
|
||||
[Required]
|
||||
[Column("test_sequence")]
|
||||
public int TestSequence { get; set; } = 1;
|
||||
|
||||
[Required]
|
||||
[Column("qfod_count")]
|
||||
public int QfodCount { get; set; } = 0;
|
||||
|
||||
[Required]
|
||||
[Column("ploss_count")]
|
||||
public int PlossCount { get; set; } = 0;
|
||||
|
||||
[Required]
|
||||
[Column("is_deleted")]
|
||||
public bool IsDeleted { get; set; } = false;
|
||||
|
||||
[Required]
|
||||
[Column("created_at")]
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// Navigation Properties - 维度表
|
||||
[ForeignKey(nameof(TxPanelId))]
|
||||
public TxPanel TxPanel { get; set; } = null!;
|
||||
|
||||
[ForeignKey(nameof(TxHardwareId))]
|
||||
public TxHardware TxHardware { get; set; } = null!;
|
||||
|
||||
[ForeignKey(nameof(TxSoftwareId))]
|
||||
public TxSoftware TxSoftware { get; set; } = null!;
|
||||
|
||||
[ForeignKey(nameof(RxTypeId))]
|
||||
public RxType RxType { get; set; } = null!;
|
||||
|
||||
// Navigation Properties - 数据记录
|
||||
public ICollection<QfodRecord> QfodRecords { get; set; } = [];
|
||||
public ICollection<PlossRecord> PlossRecords { get; set; } = [];
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 场景创建流程
|
||||
|
||||
### 从文件名解析
|
||||
|
||||
```csharp
|
||||
// Services/ScenarioService.cs
|
||||
public async Task<TestScenario> GetOrCreateFromFileNameAsync(string fileName)
|
||||
{
|
||||
// 1. 解析文件名
|
||||
var parts = ParseFileName(fileName);
|
||||
// 格式: TX面板-TX硬件-TX软件-RX类型-测试目的-年月日-测试次数.log
|
||||
|
||||
// 2. 获取或创建各维度
|
||||
var txPanel = await txPanelService.GetOrCreateAsync(parts.TxPanel);
|
||||
var txHardware = await txHardwareService.GetOrCreateAsync(parts.TxHardware);
|
||||
var txSoftware = await txSoftwareService.GetOrCreateAsync(parts.TxSoftware);
|
||||
var rxType = await rxTypeService.GetOrCreateAsync(parts.RxType);
|
||||
|
||||
// 3. 检查场景是否已存在
|
||||
var existing = await context.TestScenarios
|
||||
.FirstOrDefaultAsync(s =>
|
||||
s.TxPanelId == txPanel.Id &&
|
||||
s.TxHardwareId == txHardware.Id &&
|
||||
s.TxSoftwareId == txSoftware.Id &&
|
||||
s.RxTypeId == rxType.Id &&
|
||||
s.TestPurpose == parts.TestPurpose &&
|
||||
s.TestDate == parts.TestDate &&
|
||||
s.TestSequence == parts.TestSequence);
|
||||
|
||||
if (existing != null) return existing;
|
||||
|
||||
// 4. 创建新场景
|
||||
var scenario = new TestScenario
|
||||
{
|
||||
TxPanelId = txPanel.Id,
|
||||
TxHardwareId = txHardware.Id,
|
||||
TxSoftwareId = txSoftware.Id,
|
||||
RxTypeId = rxType.Id,
|
||||
TestPurpose = parts.TestPurpose,
|
||||
TestDate = parts.TestDate,
|
||||
TestSequence = parts.TestSequence
|
||||
};
|
||||
|
||||
context.TestScenarios.Add(scenario);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return scenario;
|
||||
}
|
||||
```
|
||||
|
||||
### 手动创建
|
||||
|
||||
```csharp
|
||||
public async Task<TestScenario> CreateAsync(CreateScenarioRequest request)
|
||||
{
|
||||
// 1. 验证维度是否存在
|
||||
var txPanel = await context.TxPanels.FindAsync(request.TxPanelId)
|
||||
?? throw new NotFoundException("TX面板不存在");
|
||||
var txHardware = await context.TxHardwares.FindAsync(request.TxHardwareId)
|
||||
?? throw new NotFoundException("TX硬件版本不存在");
|
||||
// ... 其他维度验证
|
||||
|
||||
// 2. 创建场景
|
||||
var scenario = new TestScenario
|
||||
{
|
||||
TxPanelId = request.TxPanelId,
|
||||
TxHardwareId = request.TxHardwareId,
|
||||
TxSoftwareId = request.TxSoftwareId,
|
||||
RxTypeId = request.RxTypeId,
|
||||
TestPurpose = request.TestPurpose,
|
||||
TestDate = request.TestDate,
|
||||
TestSequence = request.TestSequence
|
||||
};
|
||||
|
||||
context.TestScenarios.Add(scenario);
|
||||
await context.SaveChangesAsync();
|
||||
|
||||
return scenario;
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user