完善机组车台功能,并导入机组车台 / 车间班次数据

一、机组车台功能完善
- 车间下拉改为只取「前缫」职责类型的部门(新增接口 /api/jizuchetai/qianxian-deps)
- 补齐校验:车间、机组号、开始车台号必填;结束车台号不得小于开始车台号;同车间同机组不可重复
- 前端页面同步调整:车间改为下拉选择、增加必填提示、表格加 row-key

二、数据导入(新增 ProdSeedData,幂等导入器)
- biz_prod_qs_jzct:机组车台 35 条(其中 11 条已删除)→ 有效 24 条
- biz_prod_qs_cjbc:车间班次 7 条(其中 1 条已删除)→ 有效 6 条
- F9 的部门 Id 通过部门名称映射到本系统部门;已删除的数据不导入;
  已存在且一致的数据不重复写入,缺失的自动补回
This commit is contained in:
yanpeng200212
2026-10-14 09:42:06 +08:00
parent 0e6d4dce53
commit 8c4c464362
9 changed files with 817 additions and 44 deletions
@@ -68,6 +68,9 @@ public static class DbSeeder
GongyingshangSeedData.Seed(fsql);
EmployeeSeedData.Seed(fsql);
// 6.655 生产模块基础数据(机组车台 + 车间班次,F9 导出数据幂等导入)
ProdSeedData.Seed(fsql, snowflake);
// 6.66 基础数据菜单(工种管理、账期管理、注册表、原料庄口、物资目录、往来单位)
SeedWorkTypeMenus(fsql, snowflake);
SeedZhangqiMenus(fsql, snowflake);
@@ -0,0 +1,202 @@
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;
/// <summary>
/// 生产模块基础数据种子(来源于 F9 系统导出):
/// 1) biz_prod_qs_jzct —— 机组车台
/// 2) biz_prod_qs_cjbc —— 车间班次
/// 幂等:按「车间 + 机组」/「车间 + 班次」匹配,存在则校正,不存在则新增;已删除的数据不导入。
/// </summary>
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<JzctItem>(JzctResource);
if (items.Count == 0) return;
var deptMap = BuildDeptMap(fsql);
var existing = fsql.Select<JizuChetai>().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<long>();
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<JizuChetai>().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<CjbcItem>(CjbcResource);
if (items.Count == 0) return;
var deptMap = BuildDeptMap(fsql);
var existing = fsql.Select<ChejianBanci>().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<long>();
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<ChejianBanci>().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}");
}
}
// ==================== 公共 ====================
/// <summary>建立 F9 部门 Id → 本系统部门 Id 的映射(以部门名称为桥梁)</summary>
private static Dictionary<long, long> BuildDeptMap(IFreeSql fsql)
{
var f9NameMap = BusinessSeedData.DeptData.ToDictionary(x => x.Id, x => x.Name);
var localNameMap = fsql.Select<SysDept.Department>().ToList()
.GroupBy(d => d.Name)
.ToDictionary(g => g.Key, g => g.First().Id);
var map = new Dictionary<long, long>();
foreach (var (f9Id, name) in f9NameMap)
{
if (localNameMap.TryGetValue(name, out var localId)) map[f9Id] = localId;
}
return map;
}
private static List<T> Load<T>(string resourceName)
{
var asm = Assembly.GetExecutingAssembly();
using var stream = asm.GetManifestResourceStream(resourceName);
if (stream == null) return new List<T>();
return JsonSerializer.Deserialize<List<T>>(stream, JsonOpts) ?? new List<T>();
}
// ---- 数据项 ----
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; }
}
}
@@ -0,0 +1,51 @@
[
{
"id": 18269488810037248,
"deleted_at": "",
"dep_id": 16043931070369792,
"banci": 1,
"kaoqin_dayhours": 9
},
{
"id": 18500791564242944,
"deleted_at": "10/12/2025 13:05:07.557",
"dep_id": 16043931070369792,
"banci": 2,
"kaoqin_dayhours": 6
},
{
"id": 20744935502254080,
"deleted_at": "",
"dep_id": 16047387197837312,
"banci": 1,
"kaoqin_dayhours": 9
},
{
"id": 25443995760988160,
"deleted_at": "",
"dep_id": 22308600831545344,
"banci": 1,
"kaoqin_dayhours": 9
},
{
"id": 25444063712907264,
"deleted_at": "",
"dep_id": 22308683820044288,
"banci": 1,
"kaoqin_dayhours": 9
},
{
"id": 25444106268315648,
"deleted_at": "",
"dep_id": 22308683820044288,
"banci": 2,
"kaoqin_dayhours": 9
},
{
"id": 35745732161966080,
"deleted_at": "",
"dep_id": 22308600831545344,
"banci": 2,
"kaoqin_dayhours": 9
}
]
@@ -0,0 +1,422 @@
[
{
"id": 16003469039112192,
"created_by": null,
"created_at": "14/11/2025 11:52:04.367",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "14/11/2025 11:53:55.33",
"dep_id": 101122,
"jizu": 23424,
"chetai_start": 324,
"chetai_end": 2342
},
{
"id": 16047842267238400,
"created_by": null,
"created_at": "14/11/2025 14:48:23.753",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "14/11/2025 15:26:50.25",
"dep_id": 106,
"jizu": 111,
"chetai_start": 111,
"chetai_end": 118
},
{
"id": 16047909204135936,
"created_by": null,
"created_at": "14/11/2025 14:48:39.71",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "14/11/2025 14:48:48.147",
"dep_id": 107,
"jizu": 111,
"chetai_start": 119,
"chetai_end": 125
},
{
"id": 16054811803783168,
"created_by": null,
"created_at": "14/11/2025 15:16:05.42",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "14/11/2025 15:26:47.48",
"dep_id": 107,
"jizu": 100,
"chetai_start": 100,
"chetai_end": 110
},
{
"id": 17090359817408512,
"created_by": null,
"created_at": "17/11/2025 11:50:59.307",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "20/11/2025 17:47:04.083",
"dep_id": 16047387197837312,
"jizu": 7,
"chetai_start": 3,
"chetai_end": 6
},
{
"id": 17124677390438400,
"created_by": null,
"created_at": "17/11/2025 14:07:21.253",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "17/11/2025 15:44:43.493",
"dep_id": 16043931070369792,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 3
},
{
"id": 17149134003769344,
"created_by": null,
"created_at": "17/11/2025 15:44:32.167",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "20/11/2025 17:47:08.097",
"dep_id": 16043931070369792,
"jizu": 100,
"chetai_start": 5,
"chetai_end": 11
},
{
"id": 17895860616564736,
"created_by": null,
"created_at": "19/11/2025 17:11:45.693",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "20/11/2025 17:47:05.973",
"dep_id": 16047387197837312,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 18
},
{
"id": 18267185730293760,
"created_by": null,
"created_at": "20/11/2025 17:47:16.487",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 20
},
{
"id": 18267223122513920,
"created_by": null,
"created_at": "20/11/2025 17:47:25.383",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 2,
"chetai_start": 21,
"chetai_end": 40
},
{
"id": 18267258883149824,
"created_by": null,
"created_at": "20/11/2025 17:47:33.907",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 3,
"chetai_start": 41,
"chetai_end": 60
},
{
"id": 18267293058338816,
"created_by": null,
"created_at": "20/11/2025 17:47:42.057",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 4,
"chetai_start": 61,
"chetai_end": 80
},
{
"id": 18267333134913536,
"created_by": null,
"created_at": "20/11/2025 17:47:51.61",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 5,
"chetai_start": 81,
"chetai_end": 100
},
{
"id": 18267372687200256,
"created_by": null,
"created_at": "20/11/2025 17:48:01.04",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16043931070369792,
"jizu": 6,
"chetai_start": 101,
"chetai_end": 120
},
{
"id": 18267414189838336,
"created_by": null,
"created_at": "20/11/2025 17:48:10.937",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 20
},
{
"id": 18267443470274560,
"created_by": null,
"created_at": "20/11/2025 17:48:17.917",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 2,
"chetai_start": 21,
"chetai_end": 40
},
{
"id": 18267488391270400,
"created_by": null,
"created_at": "20/11/2025 17:48:28.627",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 3,
"chetai_start": 41,
"chetai_end": 60
},
{
"id": 18267530309144576,
"created_by": null,
"created_at": "20/11/2025 17:48:38.62",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 4,
"chetai_start": 61,
"chetai_end": 80
},
{
"id": 18267562336849920,
"created_by": null,
"created_at": "20/11/2025 17:48:46.257",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 5,
"chetai_start": 81,
"chetai_end": 100
},
{
"id": 18267593483751424,
"created_by": null,
"created_at": "20/11/2025 17:48:53.683",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 16047387197837312,
"jizu": 6,
"chetai_start": 101,
"chetai_end": 120
},
{
"id": 18500840679542784,
"created_by": null,
"created_at": "21/11/2025 09:15:44.15",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "24/11/2025 14:30:02.643",
"dep_id": 16043931070369792,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 100
},
{
"id": 20436938137800704,
"created_by": null,
"created_at": "26/11/2025 17:29:05.753",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "10/12/2025 13:06:18.217",
"dep_id": 16047387197837312,
"jizu": 7,
"chetai_start": 121,
"chetai_end": 140
},
{
"id": 25444260044083200,
"created_by": "余华",
"created_at": "10/12/2025 13:06:24.337",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 20
},
{
"id": 25444289462931456,
"created_by": "余华",
"created_at": "10/12/2025 13:06:31.34",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 2,
"chetai_start": 21,
"chetai_end": 40
},
{
"id": 25444329623392256,
"created_by": "余华",
"created_at": "10/12/2025 13:06:40.917",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 3,
"chetai_start": 41,
"chetai_end": 60
},
{
"id": 25444371641929728,
"created_by": "余华",
"created_at": "10/12/2025 13:06:50.933",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 4,
"chetai_start": 61,
"chetai_end": 80
},
{
"id": 25444402046439424,
"created_by": "余华",
"created_at": "10/12/2025 13:06:58.183",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 5,
"chetai_start": 81,
"chetai_end": 100
},
{
"id": 25444430567706624,
"created_by": "余华",
"created_at": "10/12/2025 13:07:04.983",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308600831545344,
"jizu": 6,
"chetai_start": 101,
"chetai_end": 120
},
{
"id": 25444457453195264,
"created_by": "余华",
"created_at": "10/12/2025 13:07:11.393",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 1,
"chetai_start": 1,
"chetai_end": 20
},
{
"id": 25444480718999552,
"created_by": "余华",
"created_at": "10/12/2025 13:07:16.94",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 2,
"chetai_start": 21,
"chetai_end": 40
},
{
"id": 25444507617071104,
"created_by": "余华",
"created_at": "10/12/2025 13:07:23.353",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 3,
"chetai_start": 41,
"chetai_end": 60
},
{
"id": 25444531084201984,
"created_by": "余华",
"created_at": "10/12/2025 13:07:28.947",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 4,
"chetai_start": 61,
"chetai_end": 80
},
{
"id": 25444554995929088,
"created_by": "余华",
"created_at": "10/12/2025 13:07:34.65",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 5,
"chetai_start": 81,
"chetai_end": 100
},
{
"id": 25444577833914368,
"created_by": "余华",
"created_at": "10/12/2025 13:07:40.093",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": null,
"dep_id": 22308683820044288,
"jizu": 6,
"chetai_start": 101,
"chetai_end": 120
},
{
"id": 37410963145625600,
"created_by": "余华",
"created_at": "12/1/2026 13:37:48.69",
"update_by": null,
"updated_at": "1/1/1970 00:00:00",
"deleted_at": "13/2/2026 13:59:24.617",
"dep_id": 22308683820044288,
"jizu": -1,
"chetai_start": 0,
"chetai_end": 0
}
]