新增生产-前缫看台排班,并导入机组车台与看台排班数据
功能: - 后端新增 KtpbCtgs / KtpbDcgs / KtpbZbzs 三张表、KtpbService 与 api/prod/ktpb 接口 (车头工、挡车工、值班长分页查询与维护,挡车工按车间+班次+机组整组替换保存) - 挡车数按 F9 口径自动重算:接壤车台各计 0.5,保存时服务端重新计算并校验车台范围 - 前端新增 /prod/qianxian/ktpb 看台排班页(三页签 + 车间/班次/机组过滤 + 批量编辑弹窗) - 新增通用职工选择弹窗 EmployeeSelect(单选/多选,按部门过滤) - 生产-前缫菜单下新增「看台排班」,权限 prod:ktpb:list 数据导入: - 重新生成 biz_prod_qs_jzct.json,新增 ktpb_ctg / ktpb_dcg / ktpb_zbz 三个内嵌资源 - F9 部门 Id 经 DeptData 映射到本系统部门;职工按原始雪花 Id 关联 - 剔除软删除/脏数据:机组车台 24 条、车头工 33 条、挡车工 202 条(34 组)、值班长 7 条 - 导入幂等:机组车台按车间+机组 upsert,排班按业务唯一键去重,已维护的组不覆盖 其他:同步工作进度-12 文档与开发数据库快照
This commit is contained in:
@@ -7,6 +7,7 @@ using F9WebAiTest.Domain.Entities.Base;
|
||||
using F9WebAiTest.Domain.Entities.Prod;
|
||||
using F9WebAiTest.Domain.Enums.SYS.Employees;
|
||||
using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments;
|
||||
using SysEmp = F9WebAiTest.Domain.Entities.SYS.Employees;
|
||||
|
||||
namespace F9WebAiTest.Infrastructure.Data;
|
||||
|
||||
@@ -20,6 +21,9 @@ 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 const string KtpbCtgResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_prod_qs_ktpb_ctg.json";
|
||||
private const string KtpbDcgResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_prod_qs_ktpb_dcg.json";
|
||||
private const string KtpbZbzResource = "F9WebAiTest.Infrastructure.Data.SeedData.biz_prod_qs_ktpb_zbz.json";
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOpts = new()
|
||||
{
|
||||
@@ -31,6 +35,10 @@ public static class ProdSeedData
|
||||
{
|
||||
SeedJizuChetai(fsql);
|
||||
SeedChejianBanci(fsql);
|
||||
// 看台排班(车头工 / 挡车工 / 值班长)
|
||||
SeedKtpbCtg(fsql);
|
||||
SeedKtpbDcg(fsql);
|
||||
SeedKtpbZbz(fsql);
|
||||
}
|
||||
|
||||
// ==================== 机组车台 ====================
|
||||
@@ -154,8 +162,161 @@ public static class ProdSeedData
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 车头工看台排班 ====================
|
||||
private static void SeedKtpbCtg(IFreeSql fsql)
|
||||
{
|
||||
try
|
||||
{
|
||||
var items = Load<KtpbCtgItem>(KtpbCtgResource);
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var deptMap = BuildDeptMap(fsql);
|
||||
var empIds = BuildEmpIdSet(fsql);
|
||||
var existing = fsql.Select<KtpbCtg>().ToList()
|
||||
.GroupBy(x => (x.DeptId, x.Banci, x.Jizu))
|
||||
.ToDictionary(g => g.Key, g => g.First());
|
||||
|
||||
int added = 0, updated = 0, skipped = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.DeletedAt)) { skipped++; continue; }
|
||||
if (!deptMap.TryGetValue(item.DepId, out var deptId)) { skipped++; continue; }
|
||||
if (!empIds.Contains(item.Ygid1)) { skipped++; continue; }
|
||||
|
||||
var ygid2 = empIds.Contains(item.Ygid2) ? item.Ygid2 : 0;
|
||||
var banci = (Prod_Banci_Enum)item.Banci;
|
||||
var key = (deptId, banci, item.Jizu);
|
||||
if (existing.TryGetValue(key, out var e))
|
||||
{
|
||||
if (e.Ygid1 != item.Ygid1 || e.Ygid2 != ygid2)
|
||||
{
|
||||
e.Ygid1 = item.Ygid1;
|
||||
e.Ygid2 = ygid2;
|
||||
fsql.Update<KtpbCtg>().SetSource(e).ExecuteAffrows();
|
||||
updated++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fsql.Insert(new KtpbCtg
|
||||
{
|
||||
DeptId = deptId,
|
||||
Banci = banci,
|
||||
Jizu = item.Jizu,
|
||||
Ygid1 = item.Ygid1,
|
||||
Ygid2 = ygid2
|
||||
}).ExecuteAffrows();
|
||||
added++;
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine($"[ProdSeed] 车头工看台排班:来源 {items.Count} 条,新增 {added} 条,更新 {updated} 条,跳过 {skipped} 条");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ProdSeed] 车头工看台排班导入跳过:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 挡车工看台排班 ====================
|
||||
private static void SeedKtpbDcg(IFreeSql fsql)
|
||||
{
|
||||
try
|
||||
{
|
||||
var items = Load<KtpbDcgItem>(KtpbDcgResource);
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var deptMap = BuildDeptMap(fsql);
|
||||
var empIds = BuildEmpIdSet(fsql);
|
||||
// 已有排班的「车间+班次+机组」整组跳过,避免每次启动重复插入(人工维护的排班不被覆盖)
|
||||
var existGroups = fsql.Select<KtpbDcg>().ToList()
|
||||
.Select(x => (x.DeptId, x.Banci, x.Jizu))
|
||||
.ToHashSet();
|
||||
|
||||
int added = 0, skipped = 0;
|
||||
var handledGroups = new HashSet<(long, Prod_Banci_Enum, int)>();
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.DeletedAt)) { skipped++; continue; }
|
||||
if (!deptMap.TryGetValue(item.DepId, out var deptId)) { skipped++; continue; }
|
||||
if (!empIds.Contains(item.YgId)) { skipped++; continue; }
|
||||
if (item.ChetaiStart <= 0 || item.ChetaiEnd < item.ChetaiStart) { skipped++; continue; }
|
||||
|
||||
var banci = (Prod_Banci_Enum)item.Banci;
|
||||
var group = (deptId, banci, item.Jizu);
|
||||
if (existGroups.Contains(group)) { skipped++; continue; }
|
||||
|
||||
fsql.Insert(new KtpbDcg
|
||||
{
|
||||
DeptId = deptId,
|
||||
Banci = banci,
|
||||
Jizu = item.Jizu,
|
||||
ChetaiStart = item.ChetaiStart,
|
||||
ChetaiEnd = item.ChetaiEnd,
|
||||
YgId = item.YgId,
|
||||
Dangcheshu = item.Dangcheshu
|
||||
}).ExecuteAffrows();
|
||||
handledGroups.Add(group);
|
||||
added++;
|
||||
}
|
||||
|
||||
Console.WriteLine($"[ProdSeed] 挡车工看台排班:来源 {items.Count} 条,新增 {added} 条({handledGroups.Count} 组),跳过 {skipped} 条");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ProdSeed] 挡车工看台排班导入跳过:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 值班长看台排班 ====================
|
||||
private static void SeedKtpbZbz(IFreeSql fsql)
|
||||
{
|
||||
try
|
||||
{
|
||||
var items = Load<KtpbZbzItem>(KtpbZbzResource);
|
||||
if (items.Count == 0) return;
|
||||
|
||||
var deptMap = BuildDeptMap(fsql);
|
||||
var empIds = BuildEmpIdSet(fsql);
|
||||
var exist = fsql.Select<KtpbZbz>().ToList()
|
||||
.Select(x => (x.DeptId, x.Banci, x.YgId))
|
||||
.ToHashSet();
|
||||
|
||||
int added = 0, skipped = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(item.DeletedAt)) { skipped++; continue; }
|
||||
if (!deptMap.TryGetValue(item.DepId, out var deptId)) { skipped++; continue; }
|
||||
if (!empIds.Contains(item.YgId)) { skipped++; continue; }
|
||||
|
||||
var banci = (Prod_Banci_Enum)item.Banci;
|
||||
if (!exist.Add((deptId, banci, item.YgId))) { skipped++; continue; }
|
||||
|
||||
fsql.Insert(new KtpbZbz
|
||||
{
|
||||
DeptId = deptId,
|
||||
Banci = banci,
|
||||
YgId = item.YgId
|
||||
}).ExecuteAffrows();
|
||||
added++;
|
||||
}
|
||||
|
||||
Console.WriteLine($"[ProdSeed] 值班长看台排班:来源 {items.Count} 条,新增 {added} 条,跳过 {skipped} 条");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"[ProdSeed] 值班长看台排班导入跳过:{ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== 公共 ====================
|
||||
|
||||
/// <summary>本系统存在的职工 Id 集合(F9 职工导出时保留了原始雪花 Id,可直接比对)</summary>
|
||||
private static HashSet<long> BuildEmpIdSet(IFreeSql fsql)
|
||||
=> fsql.Select<SysEmp.Employee>().ToList().Select(e => e.Id).ToHashSet();
|
||||
|
||||
|
||||
/// <summary>建立 F9 部门 Id → 本系统部门 Id 的映射(以部门名称为桥梁)</summary>
|
||||
private static Dictionary<long, long> BuildDeptMap(IFreeSql fsql)
|
||||
{
|
||||
@@ -199,4 +360,37 @@ public static class ProdSeedData
|
||||
[JsonPropertyName("banci")] public int Banci { get; set; }
|
||||
[JsonPropertyName("kaoqin_dayhours")] public double KaoqinDayhours { get; set; }
|
||||
}
|
||||
|
||||
private class KtpbCtgItem
|
||||
{
|
||||
[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("jizu")] public int Jizu { get; set; }
|
||||
[JsonPropertyName("ygid_1")] public long Ygid1 { get; set; }
|
||||
[JsonPropertyName("ygid_2")] public long Ygid2 { get; set; }
|
||||
}
|
||||
|
||||
private class KtpbDcgItem
|
||||
{
|
||||
[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("jizu")] public int Jizu { get; set; }
|
||||
[JsonPropertyName("chetai_start")] public int ChetaiStart { get; set; }
|
||||
[JsonPropertyName("chetai_end")] public int ChetaiEnd { get; set; }
|
||||
[JsonPropertyName("yg_id")] public long YgId { get; set; }
|
||||
[JsonPropertyName("dangcheshu")] public double Dangcheshu { get; set; }
|
||||
}
|
||||
|
||||
private class KtpbZbzItem
|
||||
{
|
||||
[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("yg_id")] public long YgId { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user