using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using FreeSql;
using F9WebAiTest.Application.Interfaces.SnowflakeID;
using F9WebAiTest.Domain.Entities.Base;
using F9WebAiTest.Domain.Entities.Prod;
using F9WebAiTest.Domain.Enums.SYS.Employees;
using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments;
namespace F9WebAiTest.Infrastructure.Data;
///
/// 生产模块基础数据种子(来源于 F9 系统导出):
/// 1) biz_prod_qs_jzct —— 机组车台
/// 2) biz_prod_qs_cjbc —— 车间班次
/// 幂等:按「车间 + 机组」/「车间 + 班次」匹配,存在则校正,不存在则新增;已删除的数据不导入。
///
public static class ProdSeedData
{
private const string JzctResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_prod_qs_jzct.json";
private const string CjbcResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_prod_qs_cjbc.json";
private static readonly JsonSerializerOptions JsonOpts = new()
{
PropertyNameCaseInsensitive = true,
NumberHandling = JsonNumberHandling.AllowReadingFromString
};
public static void Seed(IFreeSql fsql, ISnowflakeIdGenerator snowflake)
{
SeedJizuChetai(fsql);
SeedChejianBanci(fsql);
}
// ==================== 机组车台 ====================
private static void SeedJizuChetai(IFreeSql fsql)
{
try
{
var items = Load(JzctResource);
if (items.Count == 0) return;
var deptMap = BuildDeptMap(fsql);
var existing = fsql.Select().ToList()
.GroupBy(x => (x.DepartmentId, x.Jizu))
.ToDictionary(g => g.Key, g => g.First());
int added = 0, updated = 0, skipped = 0;
var unmappedDeps = new HashSet();
foreach (var item in items)
{
if (!string.IsNullOrWhiteSpace(item.DeletedAt)) { skipped++; continue; }
if (!deptMap.TryGetValue(item.DepId, out var deptId))
{
unmappedDeps.Add(item.DepId);
skipped++;
continue;
}
var key = (deptId, item.Jizu);
if (existing.TryGetValue(key, out var e))
{
if (e.ChetaiStart != item.ChetaiStart || e.ChetaiEnd != item.ChetaiEnd)
{
e.ChetaiStart = item.ChetaiStart;
e.ChetaiEnd = item.ChetaiEnd;
fsql.Update().SetSource(e).ExecuteAffrows();
updated++;
}
}
else
{
fsql.Insert(new JizuChetai
{
DepartmentId = deptId,
Jizu = item.Jizu,
ChetaiStart = item.ChetaiStart,
ChetaiEnd = item.ChetaiEnd
}).ExecuteAffrows();
added++;
}
}
Console.WriteLine($"[ProdSeed] 机组车台:来源 {items.Count} 条,新增 {added} 条,更新 {updated} 条,跳过(已删除/无法映射){skipped} 条");
if (unmappedDeps.Count > 0)
Console.WriteLine($"[ProdSeed] 提示:以下 F9 部门 Id 未匹配到本系统部门,已跳过 -> {string.Join(", ", unmappedDeps)}");
}
catch (Exception ex)
{
Console.WriteLine($"[ProdSeed] 机组车台导入跳过:{ex.Message}");
}
}
// ==================== 车间班次 ====================
private static void SeedChejianBanci(IFreeSql fsql)
{
try
{
var items = Load(CjbcResource);
if (items.Count == 0) return;
var deptMap = BuildDeptMap(fsql);
var existing = fsql.Select().ToList()
.GroupBy(x => (x.DeptId, x.Banci))
.ToDictionary(g => g.Key, g => g.First());
int added = 0, updated = 0, skipped = 0;
var unmappedDeps = new HashSet();
foreach (var item in items)
{
if (!string.IsNullOrWhiteSpace(item.DeletedAt)) { skipped++; continue; }
if (!deptMap.TryGetValue(item.DepId, out var deptId))
{
unmappedDeps.Add(item.DepId);
skipped++;
continue;
}
var banci = (Prod_Banci_Enum)item.Banci;
var key = (deptId, banci);
if (existing.TryGetValue(key, out var e))
{
if (Math.Abs(e.KaoqinDayhours - item.KaoqinDayhours) > 0.001)
{
e.KaoqinDayhours = item.KaoqinDayhours;
fsql.Update().SetSource(e).ExecuteAffrows();
updated++;
}
}
else
{
fsql.Insert(new ChejianBanci
{
DeptId = deptId,
Banci = banci,
KaoqinDayhours = item.KaoqinDayhours
}).ExecuteAffrows();
added++;
}
}
Console.WriteLine($"[ProdSeed] 车间班次:来源 {items.Count} 条,新增 {added} 条,更新 {updated} 条,跳过(已删除/无法映射){skipped} 条");
if (unmappedDeps.Count > 0)
Console.WriteLine($"[ProdSeed] 提示:以下 F9 部门 Id 未匹配到本系统部门,已跳过 -> {string.Join(", ", unmappedDeps)}");
}
catch (Exception ex)
{
Console.WriteLine($"[ProdSeed] 车间班次导入跳过:{ex.Message}");
}
}
// ==================== 公共 ====================
/// 建立 F9 部门 Id → 本系统部门 Id 的映射(以部门名称为桥梁)
private static Dictionary BuildDeptMap(IFreeSql fsql)
{
var f9NameMap = BusinessSeedData.DeptData.ToDictionary(x => x.Id, x => x.Name);
var localNameMap = fsql.Select().ToList()
.GroupBy(d => d.Name)
.ToDictionary(g => g.Key, g => g.First().Id);
var map = new Dictionary();
foreach (var (f9Id, name) in f9NameMap)
{
if (localNameMap.TryGetValue(name, out var localId)) map[f9Id] = localId;
}
return map;
}
private static List Load(string resourceName)
{
var asm = Assembly.GetExecutingAssembly();
using var stream = asm.GetManifestResourceStream(resourceName);
if (stream == null) return new List();
return JsonSerializer.Deserialize>(stream, JsonOpts) ?? new List();
}
// ---- 数据项 ----
private class JzctItem
{
[JsonPropertyName("id")] public long Id { get; set; }
[JsonPropertyName("deleted_at")] public string? DeletedAt { get; set; }
[JsonPropertyName("dep_id")] public long DepId { get; set; }
[JsonPropertyName("jizu")] public int Jizu { get; set; }
[JsonPropertyName("chetai_start")] public int ChetaiStart { get; set; }
[JsonPropertyName("chetai_end")] public int ChetaiEnd { get; set; }
}
private class CjbcItem
{
[JsonPropertyName("id")] public long Id { get; set; }
[JsonPropertyName("deleted_at")] public string? DeletedAt { get; set; }
[JsonPropertyName("dep_id")] public long DepId { get; set; }
[JsonPropertyName("banci")] public int Banci { get; set; }
[JsonPropertyName("kaoqin_dayhours")] public double KaoqinDayhours { get; set; }
}
}