新增生产-前缫看台排班,并导入机组车台与看台排班数据

功能:
- 后端新增 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:
yanpeng200212
2026-10-22 10:49:13 +08:00
parent a8890c81e9
commit a30d1cdcce
16 changed files with 2123 additions and 422 deletions
@@ -0,0 +1,169 @@
using F9WebAiTest.Application.Common;
using F9WebAiTest.Application.Dtos.Prod;
using F9WebAiTest.Application.Services.Prod;
using F9WebAiTest.Domain.Common;
using F9WebAiTest.Domain.Enums.SYS.Employees;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace F9WebAiTest.Api.Controllers.Prod;
/// <summary>看台排班(生产-前缫):车头工 / 挡车工 / 值班长</summary>
[ApiController]
[Route("api/prod/ktpb")]
[Authorize]
public class KtpbController : ControllerBase
{
private readonly IKtpbService _svc;
public KtpbController(IKtpbService svc) => _svc = svc;
// ---------- 下拉 ----------
/// <summary>车间下拉(职责类型=前缫)</summary>
[HttpGet("qianxian-deps")]
public async Task<IActionResult> GetQianxianDeps()
=> Ok(ApiResult<List<ChejianbanciDepOptionDto>>.Ok(await _svc.GetQianxianDepsAsync()));
/// <summary>机组下拉(含车台范围,来源于机组车台)</summary>
[HttpGet("jizu-options")]
public async Task<IActionResult> GetJizuOptions([FromQuery] long depId)
=> Ok(ApiResult<List<KtpbJizuOptionDto>>.Ok(await _svc.GetJizuOptionsAsync(depId)));
// ---------- 车头工 ----------
[HttpGet("ctg")]
public async Task<IActionResult> GetCtgPaged([FromQuery] long depId = 0, [FromQuery] Prod_Banci_Enum? banci = null,
[FromQuery] int? jizu = null, [FromQuery] string like = "", [FromQuery] int pageIndex = 1,
[FromQuery] int pageSize = 20)
=> Ok(ApiResult<PageResult<KtpbctgReadDto_View>>.Ok(
await _svc.GetCtgPagedAsync(depId, banci, jizu, like ?? string.Empty, pageIndex, pageSize)));
[HttpGet("ctg/{id}")]
public async Task<IActionResult> GetCtgById(long id)
{
try { return Ok(ApiResult<KtpbctgReadDto_View>.Ok(await _svc.GetCtgByIdAsync(id))); }
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpPost("ctg")]
public async Task<IActionResult> CreateCtg([FromBody] KtpbctgReadDto_View dto)
{
try
{
await _svc.CreateCtgAsync(dto);
return Ok(ApiResult<object>.Ok(null, "新增成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpPut("ctg/{id}")]
public async Task<IActionResult> UpdateCtg(long id, [FromBody] KtpbctgReadDto_View dto)
{
try
{
await _svc.UpdateCtgAsync(id, dto);
return Ok(ApiResult<object>.Ok(null, "修改成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpDelete("ctg/{id}")]
public async Task<IActionResult> DeleteCtg(long id)
{
try
{
await _svc.DeleteCtgAsync(id);
return Ok(ApiResult<object>.Ok(null, "删除成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
// ---------- 挡车工 ----------
[HttpGet("dcg")]
public async Task<IActionResult> GetDcgPaged([FromQuery] long depId = 0, [FromQuery] Prod_Banci_Enum? banci = null,
[FromQuery] int? jizu = null, [FromQuery] string like = "", [FromQuery] int pageIndex = 1,
[FromQuery] int pageSize = 20)
=> Ok(ApiResult<PageResult<KtpbdcgReadDto_View>>.Ok(
await _svc.GetDcgPagedAsync(depId, banci, jizu, like ?? string.Empty, pageIndex, pageSize)));
/// <summary>某「车间+班次+机组」下的整组排班(批量编辑弹窗)</summary>
[HttpGet("dcg/group")]
public async Task<IActionResult> GetDcgGroup([FromQuery] long depId, [FromQuery] Prod_Banci_Enum banci,
[FromQuery] int jizu)
{
try { return Ok(ApiResult<List<KtpbdcgReadDto_View>>.Ok(await _svc.GetDcgGroupAsync(depId, banci, jizu))); }
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
/// <summary>整组替换保存(传空集合表示清空该组)</summary>
[HttpPost("dcg/batch")]
public async Task<IActionResult> SaveDcgBatch([FromBody] KtpbdcgBatchDto dto)
{
try
{
var count = await _svc.SaveDcgBatchAsync(dto);
return Ok(ApiResult<object>.Ok(count, count > 0 ? $"已保存 {count} 条排班" : "已清空该组排班"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpDelete("dcg/{id}")]
public async Task<IActionResult> DeleteDcg(long id)
{
try
{
await _svc.DeleteDcgAsync(id);
return Ok(ApiResult<object>.Ok(null, "删除成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
// ---------- 值班长 ----------
[HttpGet("zbz")]
public async Task<IActionResult> GetZbzPaged([FromQuery] long depId = 0, [FromQuery] Prod_Banci_Enum? banci = null,
[FromQuery] string like = "", [FromQuery] int pageIndex = 1, [FromQuery] int pageSize = 20)
=> Ok(ApiResult<PageResult<KtpbzbzReadDto_View>>.Ok(
await _svc.GetZbzPagedAsync(depId, banci, like ?? string.Empty, pageIndex, pageSize)));
[HttpGet("zbz/{id}")]
public async Task<IActionResult> GetZbzById(long id)
{
try { return Ok(ApiResult<KtpbzbzReadDto_View>.Ok(await _svc.GetZbzByIdAsync(id))); }
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpPost("zbz")]
public async Task<IActionResult> CreateZbz([FromBody] KtpbzbzReadDto_View dto)
{
try
{
await _svc.CreateZbzAsync(dto);
return Ok(ApiResult<object>.Ok(null, "新增成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpPut("zbz/{id}")]
public async Task<IActionResult> UpdateZbz(long id, [FromBody] KtpbzbzReadDto_View dto)
{
try
{
await _svc.UpdateZbzAsync(id, dto);
return Ok(ApiResult<object>.Ok(null, "修改成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
[HttpDelete("zbz/{id}")]
public async Task<IActionResult> DeleteZbz(long id)
{
try
{
await _svc.DeleteZbzAsync(id);
return Ok(ApiResult<object>.Ok(null, "删除成功"));
}
catch (ServiceException ex) { return StatusCode(ex.Code, ApiResult<object>.Fail(ex.Message, ex.Code)); }
}
}
Binary file not shown.
@@ -27,6 +27,7 @@ public static class DependencyInjection
services.AddScoped<IXdjyService, XdjyService>(); services.AddScoped<IXdjyService, XdjyService>();
services.AddScoped<IHbjyService, HbjyService>(); services.AddScoped<IHbjyService, HbjyService>();
services.AddScoped<IChejianBanciService, ChejianBanciService>(); services.AddScoped<IChejianBanciService, ChejianBanciService>();
services.AddScoped<IKtpbService, KtpbService>();
services.AddScoped<INotificationService, NotificationService>(); services.AddScoped<INotificationService, NotificationService>();
services.AddScoped<IReportService, ReportService>(); services.AddScoped<IReportService, ReportService>();
@@ -0,0 +1,70 @@
using F9WebAiTest.Domain.Enums.SYS.Employees;
namespace F9WebAiTest.Application.Dtos.Prod;
// ==================== 车头工看台排班 ====================
/// <summary>车头工看台排班(列表/编辑)</summary>
public class KtpbctgReadDto_View
{
public long Id { get; set; }
public long DepId { get; set; }
public string DeptName { get; set; } = "";
public Prod_Banci_Enum Banci { get; set; }
public string BanciName { get; set; } = "";
public int Jizu { get; set; }
public long Ygid1 { get; set; }
public string Ygid1Name { get; set; } = "";
public long Ygid2 { get; set; }
public string Ygid2Name { get; set; } = "";
}
// ==================== 挡车工看台排班 ====================
/// <summary>挡车工看台排班(列表/编辑)</summary>
public class KtpbdcgReadDto_View
{
public long Id { get; set; }
public long DepId { get; set; }
public string DeptName { get; set; } = "";
public Prod_Banci_Enum Banci { get; set; }
public string BanciName { get; set; } = "";
public int Jizu { get; set; }
public int ChetaiStart { get; set; }
public int ChetaiEnd { get; set; }
public long YgId { get; set; }
public string YgName { get; set; } = "";
public double Dangcheshu { get; set; }
}
/// <summary>挡车工批量编辑:一个「车间 + 班次 + 机组」下的整组排班替换</summary>
public class KtpbdcgBatchDto
{
public long DepId { get; set; }
public Prod_Banci_Enum Banci { get; set; }
public int Jizu { get; set; }
/// <summary>该组下的全部挡车工排班(为空表示清空该组)</summary>
public List<KtpbdcgReadDto_View> Items { get; set; } = new();
}
// ==================== 值班长排班 ====================
/// <summary>值班长排班(列表/编辑)</summary>
public class KtpbzbzReadDto_View
{
public long Id { get; set; }
public long DepId { get; set; }
public string DeptName { get; set; } = "";
public Prod_Banci_Enum Banci { get; set; }
public string BanciName { get; set; } = "";
public long YgId { get; set; }
public string YgName { get; set; } = "";
}
/// <summary>机组下拉项(来源于机组车台)</summary>
public class KtpbJizuOptionDto
{
public int Jizu { get; set; }
public int ChetaiStart { get; set; }
public int ChetaiEnd { get; set; }
}
@@ -0,0 +1,443 @@
using F9WebAiTest.Application.Common;
using F9WebAiTest.Application.Dtos.Prod;
using F9WebAiTest.Domain.Common;
using F9WebAiTest.Domain.Entities.Base;
using F9WebAiTest.Domain.Entities.Prod;
using F9WebAiTest.Domain.Enums.SYS.Departments;
using F9WebAiTest.Domain.Enums.SYS.Employees;
using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments;
using SysEmp = F9WebAiTest.Domain.Entities.SYS.Employees;
namespace F9WebAiTest.Application.Services.Prod;
/// <summary>
/// 看台排班(生产-前缫):车头工 / 挡车工 / 值班长三类排班的查询与维护。
/// 对应 F9 WinClient\F9.Business.Prod\QS\KTPB 下的 Page_KTPB 与三个编辑页。
/// </summary>
public interface IKtpbService
{
/// <summary>车间下拉(职责类型=前缫)</summary>
Task<List<ChejianbanciDepOptionDto>> GetQianxianDepsAsync();
/// <summary>指定车间的机组下拉(含车台范围,来源于机组车台)</summary>
Task<List<KtpbJizuOptionDto>> GetJizuOptionsAsync(long depId);
// 车头工
Task<PageResult<KtpbctgReadDto_View>> GetCtgPagedAsync(long depId, Prod_Banci_Enum? banci, int? jizu,
string keyword, int pageIndex, int pageSize);
Task<KtpbctgReadDto_View> GetCtgByIdAsync(long id);
Task CreateCtgAsync(KtpbctgReadDto_View dto);
Task UpdateCtgAsync(long id, KtpbctgReadDto_View dto);
Task DeleteCtgAsync(long id);
// 挡车工
Task<PageResult<KtpbdcgReadDto_View>> GetDcgPagedAsync(long depId, Prod_Banci_Enum? banci, int? jizu,
string keyword, int pageIndex, int pageSize);
/// <summary>取某个「车间+班次+机组」下的整组排班(批量编辑弹窗用)</summary>
Task<List<KtpbdcgReadDto_View>> GetDcgGroupAsync(long depId, Prod_Banci_Enum banci, int jizu);
/// <summary>整组替换:先删除该组旧排班,再按提交内容重建(挡车数由服务端重算)</summary>
Task<int> SaveDcgBatchAsync(KtpbdcgBatchDto dto);
Task DeleteDcgAsync(long id);
// 值班长
Task<PageResult<KtpbzbzReadDto_View>> GetZbzPagedAsync(long depId, Prod_Banci_Enum? banci,
string keyword, int pageIndex, int pageSize);
Task<KtpbzbzReadDto_View> GetZbzByIdAsync(long id);
Task CreateZbzAsync(KtpbzbzReadDto_View dto);
Task UpdateZbzAsync(long id, KtpbzbzReadDto_View dto);
Task DeleteZbzAsync(long id);
}
public class KtpbService : IKtpbService
{
private readonly IRepository<KtpbCtg> _ctgRepo;
private readonly IRepository<KtpbDcg> _dcgRepo;
private readonly IRepository<KtpbZbz> _zbzRepo;
private readonly IRepository<JizuChetai> _jzctRepo;
private readonly IRepository<SysDept.Department> _deptRepo;
private readonly IRepository<SysEmp.Employee> _empRepo;
public KtpbService(IRepository<KtpbCtg> ctgRepo, IRepository<KtpbDcg> dcgRepo, IRepository<KtpbZbz> zbzRepo,
IRepository<JizuChetai> jzctRepo, IRepository<SysDept.Department> deptRepo,
IRepository<SysEmp.Employee> empRepo)
{
_ctgRepo = ctgRepo;
_dcgRepo = dcgRepo;
_zbzRepo = zbzRepo;
_jzctRepo = jzctRepo;
_deptRepo = deptRepo;
_empRepo = empRepo;
}
// ==================== 下拉 ====================
public async Task<List<ChejianbanciDepOptionDto>> GetQianxianDepsAsync()
{
var depts = await _deptRepo.GetAllAsync();
return depts
.Where(d => d.DutyType == Department_DutyType_Enum.前缫)
.OrderBy(d => d.SortOrder).ThenBy(d => d.Id)
.Select(d => new ChejianbanciDepOptionDto { Id = d.Id, Name = d.Name })
.ToList();
}
public async Task<List<KtpbJizuOptionDto>> GetJizuOptionsAsync(long depId)
{
var list = await _jzctRepo.FindAsync(x => x.DepartmentId == depId);
return list.OrderBy(x => x.Jizu)
.Select(x => new KtpbJizuOptionDto
{
Jizu = x.Jizu,
ChetaiStart = x.ChetaiStart,
ChetaiEnd = x.ChetaiEnd
})
.ToList();
}
// ==================== 车头工 ====================
public async Task<PageResult<KtpbctgReadDto_View>> GetCtgPagedAsync(long depId, Prod_Banci_Enum? banci,
int? jizu, string keyword, int pageIndex, int pageSize)
{
if (pageIndex <= 0) pageIndex = 1;
if (pageSize <= 0) pageSize = 20;
var deptDict = await GetDeptDictAsync();
var empDict = await GetEmpDictAsync();
var all = await _ctgRepo.GetAllAsync();
var q = all.AsEnumerable();
if (depId > 0) q = q.Where(x => x.DeptId == depId);
if (banci.HasValue) q = q.Where(x => x.Banci == banci.Value);
if (jizu.HasValue && jizu.Value > 0) q = q.Where(x => x.Jizu == jizu.Value);
var views = q.OrderBy(x => x.DeptId).ThenBy(x => x.Banci).ThenBy(x => x.Jizu)
.Select(x => ToCtgView(x, deptDict, empDict)).ToList();
if (!string.IsNullOrWhiteSpace(keyword))
{
var kw = keyword.Trim();
views = views.Where(x => x.DeptName.Contains(kw) || x.BanciName.Contains(kw)
|| x.Jizu.ToString().Contains(kw) || x.Ygid1Name.Contains(kw) || x.Ygid2Name.Contains(kw)).ToList();
}
return Paged(views, pageIndex, pageSize);
}
public async Task<KtpbctgReadDto_View> GetCtgByIdAsync(long id)
{
var e = await _ctgRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
return ToCtgView(e, await GetDeptDictAsync(), await GetEmpDictAsync());
}
public async Task CreateCtgAsync(KtpbctgReadDto_View dto)
{
await ValidateGroupAsync(dto.DepId, dto.Banci, dto.Jizu, 0);
if (dto.Ygid1 <= 0) throw new ServiceException("请选择车头工1");
await _ctgRepo.AddAsync(new KtpbCtg
{
DeptId = dto.DepId,
Banci = dto.Banci,
Jizu = dto.Jizu,
Ygid1 = dto.Ygid1,
Ygid2 = dto.Ygid2
});
await _ctgRepo.SaveChangesAsync();
}
public async Task UpdateCtgAsync(long id, KtpbctgReadDto_View dto)
{
var e = await _ctgRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
await ValidateGroupAsync(dto.DepId, dto.Banci, dto.Jizu, id);
if (dto.Ygid1 <= 0) throw new ServiceException("请选择车头工1");
e.DeptId = dto.DepId;
e.Banci = dto.Banci;
e.Jizu = dto.Jizu;
e.Ygid1 = dto.Ygid1;
e.Ygid2 = dto.Ygid2;
await _ctgRepo.UpdateAsync(e);
await _ctgRepo.SaveChangesAsync();
}
public async Task DeleteCtgAsync(long id)
{
var e = await _ctgRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
await _ctgRepo.DeleteAsync(e);
await _ctgRepo.SaveChangesAsync();
}
// ==================== 挡车工 ====================
public async Task<PageResult<KtpbdcgReadDto_View>> GetDcgPagedAsync(long depId, Prod_Banci_Enum? banci,
int? jizu, string keyword, int pageIndex, int pageSize)
{
if (pageIndex <= 0) pageIndex = 1;
if (pageSize <= 0) pageSize = 20;
var deptDict = await GetDeptDictAsync();
var empDict = await GetEmpDictAsync();
var all = await _dcgRepo.GetAllAsync();
var q = all.AsEnumerable();
if (depId > 0) q = q.Where(x => x.DeptId == depId);
if (banci.HasValue) q = q.Where(x => x.Banci == banci.Value);
if (jizu.HasValue && jizu.Value > 0) q = q.Where(x => x.Jizu == jizu.Value);
var views = q.OrderBy(x => x.DeptId).ThenBy(x => x.Banci).ThenBy(x => x.Jizu)
.ThenBy(x => x.ChetaiStart)
.Select(x => ToDcgView(x, deptDict, empDict)).ToList();
if (!string.IsNullOrWhiteSpace(keyword))
{
var kw = keyword.Trim();
views = views.Where(x => x.DeptName.Contains(kw) || x.BanciName.Contains(kw)
|| x.YgName.Contains(kw) || x.Jizu.ToString().Contains(kw)
|| x.ChetaiStart.ToString().Contains(kw) || x.ChetaiEnd.ToString().Contains(kw)).ToList();
}
return Paged(views, pageIndex, pageSize);
}
public async Task<List<KtpbdcgReadDto_View>> GetDcgGroupAsync(long depId, Prod_Banci_Enum banci, int jizu)
{
if (depId <= 0) throw new ServiceException("请选择车间");
var deptDict = await GetDeptDictAsync();
var empDict = await GetEmpDictAsync();
var list = await _dcgRepo.FindAsync(x => x.DeptId == depId && x.Banci == banci && x.Jizu == jizu);
return list.OrderBy(x => x.ChetaiStart).ThenBy(x => x.ChetaiEnd)
.Select(x => ToDcgView(x, deptDict, empDict)).ToList();
}
public async Task<int> SaveDcgBatchAsync(KtpbdcgBatchDto dto)
{
if (dto.DepId <= 0) throw new ServiceException("请选择车间");
if (dto.Jizu <= 0) throw new ServiceException("请选择机组");
var items = dto.Items ?? new List<KtpbdcgReadDto_View>();
foreach (var it in items)
{
if (it.YgId <= 0) throw new ServiceException("存在未选择挡车工的记录");
if (it.ChetaiStart <= 0) throw new ServiceException($"挡车工「{it.YgName}」的起始车台必须大于 0");
if (it.ChetaiEnd < it.ChetaiStart)
throw new ServiceException($"挡车工「{it.YgName}」的结束车台不能小于起始车台");
}
var jzct = await _jzctRepo.FirstOrDefaultAsync(x => x.DepartmentId == dto.DepId && x.Jizu == dto.Jizu);
if (jzct != null)
{
foreach (var it in items)
{
if (it.ChetaiStart < jzct.ChetaiStart || it.ChetaiEnd > jzct.ChetaiEnd)
throw new ServiceException(
$"挡车工「{it.YgName}」的车台范围 {it.ChetaiStart}-{it.ChetaiEnd} 超出该机组车台范围 " +
$"{jzct.ChetaiStart}-{jzct.ChetaiEnd}");
}
}
// 整组替换:先删后建(对齐 F9 BatchReplaceKtpbdcgCommand)
var olds = await _dcgRepo.FindAsync(x => x.DeptId == dto.DepId && x.Banci == dto.Banci && x.Jizu == dto.Jizu);
if (olds.Count > 0) await _dcgRepo.HardDeleteRangeAsync(olds);
var dangche = RecalcDangcheshu(items);
foreach (var it in items)
{
await _dcgRepo.AddAsync(new KtpbDcg
{
DeptId = dto.DepId,
Banci = dto.Banci,
Jizu = dto.Jizu,
ChetaiStart = it.ChetaiStart,
ChetaiEnd = it.ChetaiEnd,
YgId = it.YgId,
Dangcheshu = dangche.GetValueOrDefault(BuildDcgKey(it.ChetaiStart, it.ChetaiEnd, it.YgId), 0)
});
}
await _dcgRepo.SaveChangesAsync();
return items.Count;
}
public async Task DeleteDcgAsync(long id)
{
var e = await _dcgRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
await _dcgRepo.DeleteAsync(e);
await _dcgRepo.SaveChangesAsync();
}
/// <summary>
/// 挡车数计算(移植 F9 Page_KTPBDCG_Edit.CalculateSingleDangcheshu):
/// 每个车台默认权重 1;若该车台被多条记录共享,且同时是某记录的起始点与某记录的结束点(接壤车台),权重取 0.5。
/// </summary>
private static Dictionary<string, double> RecalcDangcheshu(List<KtpbdcgReadDto_View> records)
{
var result = new Dictionary<string, double>();
if (records.Count == 0) return result;
var counts = new Dictionary<int, int>();
var starts = new HashSet<int>();
var ends = new HashSet<int>();
foreach (var r in records)
{
starts.Add(r.ChetaiStart);
ends.Add(r.ChetaiEnd);
for (var i = r.ChetaiStart; i <= r.ChetaiEnd; i++)
counts[i] = counts.GetValueOrDefault(i) + 1;
}
foreach (var r in records)
{
double total = 0;
for (var i = r.ChetaiStart; i <= r.ChetaiEnd; i++)
{
double weight = 1;
if (counts.GetValueOrDefault(i) > 1 && starts.Contains(i) && ends.Contains(i)) weight = 0.5;
total += weight;
}
result[BuildDcgKey(r.ChetaiStart, r.ChetaiEnd, r.YgId)] = Math.Round(total, 2);
}
return result;
}
private static string BuildDcgKey(int start, int end, long ygId) => $"{start}-{end}-{ygId}";
// ==================== 值班长 ====================
public async Task<PageResult<KtpbzbzReadDto_View>> GetZbzPagedAsync(long depId, Prod_Banci_Enum? banci,
string keyword, int pageIndex, int pageSize)
{
if (pageIndex <= 0) pageIndex = 1;
if (pageSize <= 0) pageSize = 20;
var deptDict = await GetDeptDictAsync();
var empDict = await GetEmpDictAsync();
var all = await _zbzRepo.GetAllAsync();
var q = all.AsEnumerable();
if (depId > 0) q = q.Where(x => x.DeptId == depId);
if (banci.HasValue) q = q.Where(x => x.Banci == banci.Value);
var views = q.OrderBy(x => x.DeptId).ThenBy(x => x.Banci).ThenBy(x => x.Id)
.Select(x => ToZbzView(x, deptDict, empDict)).ToList();
if (!string.IsNullOrWhiteSpace(keyword))
{
var kw = keyword.Trim();
views = views.Where(x => x.DeptName.Contains(kw) || x.BanciName.Contains(kw) || x.YgName.Contains(kw))
.ToList();
}
return Paged(views, pageIndex, pageSize);
}
public async Task<KtpbzbzReadDto_View> GetZbzByIdAsync(long id)
{
var e = await _zbzRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
return ToZbzView(e, await GetDeptDictAsync(), await GetEmpDictAsync());
}
public async Task CreateZbzAsync(KtpbzbzReadDto_View dto)
{
if (dto.DepId <= 0) throw new ServiceException("请选择车间");
if (dto.YgId <= 0) throw new ServiceException("请选择值班长");
var dup = await _zbzRepo.AnyAsync(x => x.DeptId == dto.DepId && x.Banci == dto.Banci && x.YgId == dto.YgId);
if (dup) throw new ServiceException("该车间该班次已存在此值班长排班");
await _zbzRepo.AddAsync(new KtpbZbz { DeptId = dto.DepId, Banci = dto.Banci, YgId = dto.YgId });
await _zbzRepo.SaveChangesAsync();
}
public async Task UpdateZbzAsync(long id, KtpbzbzReadDto_View dto)
{
var e = await _zbzRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
if (dto.DepId <= 0) throw new ServiceException("请选择车间");
if (dto.YgId <= 0) throw new ServiceException("请选择值班长");
var dup = await _zbzRepo.AnyAsync(x => x.Id != id && x.DeptId == dto.DepId
&& x.Banci == dto.Banci && x.YgId == dto.YgId);
if (dup) throw new ServiceException("该车间该班次已存在此值班长排班");
e.DeptId = dto.DepId;
e.Banci = dto.Banci;
e.YgId = dto.YgId;
await _zbzRepo.UpdateAsync(e);
await _zbzRepo.SaveChangesAsync();
}
public async Task DeleteZbzAsync(long id)
{
var e = await _zbzRepo.GetByIdAsync(id) ?? throw new ServiceException("记录不存在", 404);
await _zbzRepo.DeleteAsync(e);
await _zbzRepo.SaveChangesAsync();
}
// ==================== 公共 ====================
/// <summary>车头工:同一「车间+班次+机组」只能有一条排班</summary>
private async Task ValidateGroupAsync(long depId, Prod_Banci_Enum banci, int jizu, long excludeId)
{
if (depId <= 0) throw new ServiceException("请选择车间");
if (jizu <= 0) throw new ServiceException("请选择机组");
var dup = await _ctgRepo.AnyAsync(x => x.Id != excludeId && x.DeptId == depId
&& x.Banci == banci && x.Jizu == jizu);
if (dup) throw new ServiceException("该车间该班次该机组已有车头工排班");
}
private async Task<Dictionary<long, string>> GetDeptDictAsync()
=> (await _deptRepo.GetAllAsync()).ToDictionary(d => d.Id, d => d.Name);
private async Task<Dictionary<long, string>> GetEmpDictAsync()
=> (await _empRepo.GetAllAsync()).ToDictionary(e => e.Id, e => e.Name);
private static KtpbctgReadDto_View ToCtgView(KtpbCtg x, Dictionary<long, string> deptDict,
Dictionary<long, string> empDict) => new()
{
Id = x.Id,
DepId = x.DeptId,
DeptName = deptDict.GetValueOrDefault(x.DeptId, ""),
Banci = x.Banci,
BanciName = x.Banci.ToString(),
Jizu = x.Jizu,
Ygid1 = x.Ygid1,
Ygid1Name = empDict.GetValueOrDefault(x.Ygid1, ""),
Ygid2 = x.Ygid2,
Ygid2Name = empDict.GetValueOrDefault(x.Ygid2, "")
};
private static KtpbdcgReadDto_View ToDcgView(KtpbDcg x, Dictionary<long, string> deptDict,
Dictionary<long, string> empDict) => new()
{
Id = x.Id,
DepId = x.DeptId,
DeptName = deptDict.GetValueOrDefault(x.DeptId, ""),
Banci = x.Banci,
BanciName = x.Banci.ToString(),
Jizu = x.Jizu,
ChetaiStart = x.ChetaiStart,
ChetaiEnd = x.ChetaiEnd,
YgId = x.YgId,
YgName = empDict.GetValueOrDefault(x.YgId, ""),
Dangcheshu = x.Dangcheshu
};
private static KtpbzbzReadDto_View ToZbzView(KtpbZbz x, Dictionary<long, string> deptDict,
Dictionary<long, string> empDict) => new()
{
Id = x.Id,
DepId = x.DeptId,
DeptName = deptDict.GetValueOrDefault(x.DeptId, ""),
Banci = x.Banci,
BanciName = x.Banci.ToString(),
YgId = x.YgId,
YgName = empDict.GetValueOrDefault(x.YgId, "")
};
private static PageResult<T> Paged<T>(List<T> all, int pageIndex, int pageSize) => new()
{
Items = all.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(),
Total = all.Count,
PageIndex = pageIndex,
PageSize = pageSize
};
}
@@ -0,0 +1,41 @@
using FreeSql.DataAnnotations;
using F9WebAiTest.Domain.Common;
using F9WebAiTest.Domain.Enums.SYS.Employees;
namespace F9WebAiTest.Domain.Entities.Prod;
// 看台排班(对应 F9 生产-前缫 的 KTPB 三张表:车头工 / 挡车工 / 值班长)
// 排班以「车间 + 班次」为组织单元;挡车工/车头工再细分「机组」。
/// <summary>车头工看台排班(biz_prod_qs_ktpb_ctg)</summary>
[Table(Name = "KtpbCtgs")]
public class KtpbCtg : BaseEntity
{
public long DeptId { get; set; } // 车间(前缫车间)
public Prod_Banci_Enum Banci { get; set; } // 班次(甲/乙)
public int Jizu { get; set; } // 机组
public long Ygid1 { get; set; } // 车头工1
public long Ygid2 { get; set; } // 车头工2
}
/// <summary>挡车工看台排班(biz_prod_qs_ktpb_dcg)</summary>
[Table(Name = "KtpbDcgs")]
public class KtpbDcg : BaseEntity
{
public long DeptId { get; set; } // 车间
public Prod_Banci_Enum Banci { get; set; } // 班次
public int Jizu { get; set; } // 机组
public int ChetaiStart { get; set; } // 起始车台号
public int ChetaiEnd { get; set; } // 结束车台号
public long YgId { get; set; } // 挡车工
public double Dangcheshu { get; set; } // 挡车数(相邻车台各 0.5 的口径,保存时重算)
}
/// <summary>值班长排班(biz_prod_qs_ktpb_zbz)</summary>
[Table(Name = "KtpbZbzs")]
public class KtpbZbz : BaseEntity
{
public long DeptId { get; set; } // 车间
public Prod_Banci_Enum Banci { get; set; } // 班次
public long YgId { get; set; } // 值班长
}
@@ -718,7 +718,8 @@ public static class DbSeeder
new (string Name, string Path, string Component, string Permission, string Icon, int Sort)[] new (string Name, string Path, string Component, string Permission, string Icon, int Sort)[]
{ {
("落丝记录", "/prod/qianxian/lsjl", "prod/lsjl/index", "prod:lsjl:list", "Document", 1), ("落丝记录", "/prod/qianxian/lsjl", "prod/lsjl/index", "prod:lsjl:list", "Document", 1),
("车间班次", "/prod/qianxian/chejianbanci", "base/chejianbanci/index", "prod:chejianbanci:list", "Timer", 2) ("车间班次", "/prod/qianxian/chejianbanci", "base/chejianbanci/index", "prod:chejianbanci:list", "Timer", 2),
("看台排班", "/prod/qianxian/ktpb", "prod/ktpb/index", "prod:ktpb:list", "Grid", 3)
}); });
EnsureTopMenuWithChildren(fsql, snowflake, "/prod/houxian", "生产-后缫", "DataLine", 6, EnsureTopMenuWithChildren(fsql, snowflake, "/prod/houxian", "生产-后缫", "DataLine", 6,
@@ -7,6 +7,7 @@ using F9WebAiTest.Domain.Entities.Base;
using F9WebAiTest.Domain.Entities.Prod; using F9WebAiTest.Domain.Entities.Prod;
using F9WebAiTest.Domain.Enums.SYS.Employees; using F9WebAiTest.Domain.Enums.SYS.Employees;
using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments; using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments;
using SysEmp = F9WebAiTest.Domain.Entities.SYS.Employees;
namespace F9WebAiTest.Infrastructure.Data; 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 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 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() private static readonly JsonSerializerOptions JsonOpts = new()
{ {
@@ -31,6 +35,10 @@ public static class ProdSeedData
{ {
SeedJizuChetai(fsql); SeedJizuChetai(fsql);
SeedChejianBanci(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> /// <summary>建立 F9 部门 Id → 本系统部门 Id 的映射(以部门名称为桥梁)</summary>
private static Dictionary<long, long> BuildDeptMap(IFreeSql fsql) private static Dictionary<long, long> BuildDeptMap(IFreeSql fsql)
{ {
@@ -199,4 +360,37 @@ public static class ProdSeedData
[JsonPropertyName("banci")] public int Banci { get; set; } [JsonPropertyName("banci")] public int Banci { get; set; }
[JsonPropertyName("kaoqin_dayhours")] public double KaoqinDayhours { 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; }
}
} }
@@ -1,422 +1,26 @@
[ [
{ {"id":18267185730293760,"deleted_at":null,"dep_id":16043931070369792,"jizu":1,"chetai_start":1,"chetai_end":20},
"id": 16003469039112192, {"id":18267223122513920,"deleted_at":null,"dep_id":16043931070369792,"jizu":2,"chetai_start":21,"chetai_end":40},
"created_by": null, {"id":18267258883149824,"deleted_at":null,"dep_id":16043931070369792,"jizu":3,"chetai_start":41,"chetai_end":60},
"created_at": "14/11/2025 11:52:04.367", {"id":18267293058338816,"deleted_at":null,"dep_id":16043931070369792,"jizu":4,"chetai_start":61,"chetai_end":80},
"update_by": null, {"id":18267333134913536,"deleted_at":null,"dep_id":16043931070369792,"jizu":5,"chetai_start":81,"chetai_end":100},
"updated_at": "1/1/1970 00:00:00", {"id":18267372687200256,"deleted_at":null,"dep_id":16043931070369792,"jizu":6,"chetai_start":101,"chetai_end":120},
"deleted_at": "14/11/2025 11:53:55.33", {"id":18267414189838336,"deleted_at":null,"dep_id":16047387197837312,"jizu":1,"chetai_start":1,"chetai_end":20},
"dep_id": 101122, {"id":18267443470274560,"deleted_at":null,"dep_id":16047387197837312,"jizu":2,"chetai_start":21,"chetai_end":40},
"jizu": 23424, {"id":18267488391270400,"deleted_at":null,"dep_id":16047387197837312,"jizu":3,"chetai_start":41,"chetai_end":60},
"chetai_start": 324, {"id":18267530309144576,"deleted_at":null,"dep_id":16047387197837312,"jizu":4,"chetai_start":61,"chetai_end":80},
"chetai_end": 2342 {"id":18267562336849920,"deleted_at":null,"dep_id":16047387197837312,"jizu":5,"chetai_start":81,"chetai_end":100},
}, {"id":18267593483751424,"deleted_at":null,"dep_id":16047387197837312,"jizu":6,"chetai_start":101,"chetai_end":120},
{ {"id":25444260044083200,"deleted_at":null,"dep_id":22308600831545344,"jizu":1,"chetai_start":1,"chetai_end":20},
"id": 16047842267238400, {"id":25444289462931456,"deleted_at":null,"dep_id":22308600831545344,"jizu":2,"chetai_start":21,"chetai_end":40},
"created_by": null, {"id":25444329623392256,"deleted_at":null,"dep_id":22308600831545344,"jizu":3,"chetai_start":41,"chetai_end":60},
"created_at": "14/11/2025 14:48:23.753", {"id":25444371641929728,"deleted_at":null,"dep_id":22308600831545344,"jizu":4,"chetai_start":61,"chetai_end":80},
"update_by": null, {"id":25444402046439424,"deleted_at":null,"dep_id":22308600831545344,"jizu":5,"chetai_start":81,"chetai_end":100},
"updated_at": "1/1/1970 00:00:00", {"id":25444430567706624,"deleted_at":null,"dep_id":22308600831545344,"jizu":6,"chetai_start":101,"chetai_end":120},
"deleted_at": "14/11/2025 15:26:50.25", {"id":25444457453195264,"deleted_at":null,"dep_id":22308683820044288,"jizu":1,"chetai_start":1,"chetai_end":20},
"dep_id": 106, {"id":25444480718999552,"deleted_at":null,"dep_id":22308683820044288,"jizu":2,"chetai_start":21,"chetai_end":40},
"jizu": 111, {"id":25444507617071104,"deleted_at":null,"dep_id":22308683820044288,"jizu":3,"chetai_start":41,"chetai_end":60},
"chetai_start": 111, {"id":25444531084201984,"deleted_at":null,"dep_id":22308683820044288,"jizu":4,"chetai_start":61,"chetai_end":80},
"chetai_end": 118 {"id":25444554995929088,"deleted_at":null,"dep_id":22308683820044288,"jizu":5,"chetai_start":81,"chetai_end":100},
}, {"id":25444577833914368,"deleted_at":null,"dep_id":22308683820044288,"jizu":6,"chetai_start":101,"chetai_end":120}
{ ]
"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
}
]
@@ -0,0 +1,35 @@
[
{"id":28679759856668672,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"ygid_1":25394251403628544,"ygid_2":25394252687085568},
{"id":28679881613119488,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"ygid_1":25394250963226624,"ygid_2":25394262359150592},
{"id":28680097309396992,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"ygid_1":25394277458644992,"ygid_2":25394289907339264},
{"id":28680552307494912,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"ygid_1":25394262090715136,"ygid_2":25394283020292096},
{"id":28680630204108800,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":3,"ygid_1":25394270579986432,"ygid_2":25394277022437376},
{"id":28680704229380096,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"ygid_1":25394267270680576,"ygid_2":25394252900995072},
{"id":28680809309278208,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":5,"ygid_1":25394253106515968,"ygid_2":25394287445282816},
{"id":28680902095671296,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"ygid_1":25394255677624320,"ygid_2":25394257221128192},
{"id":28681049068277760,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"ygid_1":25394255895728128,"ygid_2":25394256793309184},
{"id":28681224268550144,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"ygid_1":25394271423041536,"ygid_2":25394275898363904},
{"id":28681355063726080,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":3,"ygid_1":25394256373878784,"ygid_2":25394258567499776},
{"id":28681491718344704,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"ygid_1":25394254591299584,"ygid_2":25394268763852800},
{"id":28681656072146944,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":5,"ygid_1":25394257665724416,"ygid_2":25394262770192384},
{"id":28681864378060800,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"ygid_1":25394271871832064,"ygid_2":25394298862178304},
{"id":32345734678319104,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"ygid_1":25394253521752064,"ygid_2":25394263684550656},
{"id":56622802173693952,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"ygid_1":25394269191671808,"ygid_2":25394322589356032},
{"id":56622892196040704,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"ygid_1":25394266616369152,"ygid_2":25394277928407040},
{"id":56623050757509120,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"ygid_1":25394267681722368,"ygid_2":25394272979128320},
{"id":56623178239184896,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"ygid_1":25394317203869696,"ygid_2":25394331179290624},
{"id":76302819312799744,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"ygid_1":25394318558629888,"ygid_2":25394285343936512},
{"id":76303037706014720,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"ygid_1":25394277232152576,"ygid_2":25394292637831168},
{"id":93614566272929792,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"ygid_1":93227931605667840,"ygid_2":25394275269218304},
{"id":93614668416815104,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"ygid_1":93224498219716608,"ygid_2":93590450325164032},
{"id":93614844455948288,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"ygid_1":93224782811631616,"ygid_2":93225053415542784},
{"id":93624586561654784,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"ygid_1":25394252687085568,"ygid_2":25394298644074496},
{"id":93624684989386752,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"ygid_1":25394252473176064,"ygid_2":25394352024981504},
{"id":93624758398095360,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"ygid_1":25394313286389760,"ygid_2":25394334945775616},
{"id":93624861590556672,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"ygid_1":25394261000196096,"ygid_2":25394320357986304},
{"id":93624972055941120,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"ygid_1":25394301747859456,"ygid_2":25394321599500288},
{"id":93625060534784000,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"ygid_1":25394318810288128,"ygid_2":25394343514738688},
{"id":120347729640558592,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"ygid_1":93225232566849536,"ygid_2":93590965738016768},
{"id":120348037049487360,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"ygid_1":93225456668512256,"ygid_2":25394269623685120},
{"id":121079483326271488,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"ygid_1":93226261979074560,"ygid_2":93225788580564992}
]
@@ -0,0 +1,204 @@
[
{"id":120344961106317312,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":1,"chetai_end":4,"yg_id":89529295612940288,"dangcheshu":3.5},
{"id":120344961139871744,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":4,"chetai_end":7,"yg_id":93233888171659264,"dangcheshu":3.5},
{"id":120344961156648960,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":8,"chetai_end":10,"yg_id":87098603226533888,"dangcheshu":3},
{"id":120344961173426176,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":11,"chetai_end":14,"yg_id":93241010255040512,"dangcheshu":3.5},
{"id":120344961190203392,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":14,"chetai_end":17,"yg_id":93233703257378816,"dangcheshu":3.5},
{"id":120344961206980608,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":1,"chetai_start":18,"chetai_end":20,"yg_id":93237556027592704,"dangcheshu":3},
{"id":120389028775202816,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":1,"chetai_end":4,"yg_id":25394323948310528,"dangcheshu":3.5},
{"id":120389028812951552,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":4,"chetai_end":7,"yg_id":25394323277221888,"dangcheshu":3.5},
{"id":120389028833923072,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":8,"chetai_end":10,"yg_id":25394286870663168,"dangcheshu":3},
{"id":120389028859088896,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":11,"chetai_end":14,"yg_id":25394273205620736,"dangcheshu":3.5},
{"id":120389028880060416,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":14,"chetai_end":17,"yg_id":25394307603107840,"dangcheshu":3.5},
{"id":120389028901031936,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":1,"chetai_start":18,"chetai_end":20,"yg_id":25394291484397568,"dangcheshu":3},
{"id":120389304567468032,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":25394274388414464,"dangcheshu":3.5},
{"id":120389304592633856,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394292184846336,"dangcheshu":3.5},
{"id":120389304609411072,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394272094130176,"dangcheshu":3},
{"id":120389304626188288,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":25394354193436672,"dangcheshu":3.5},
{"id":120389304638771200,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":25394302033072128,"dangcheshu":3.5},
{"id":120389304655548416,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":25394303777902592,"dangcheshu":3},
{"id":120389564396212224,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":41,"chetai_end":44,"yg_id":25394273868320768,"dangcheshu":3.5},
{"id":120389564429766656,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":44,"chetai_end":47,"yg_id":25394300577648640,"dangcheshu":3.5},
{"id":120389564446543872,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":48,"chetai_end":50,"yg_id":25394307166900224,"dangcheshu":3},
{"id":120389564463321088,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":51,"chetai_end":54,"yg_id":25394267904020480,"dangcheshu":3.5},
{"id":120389564480098304,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":54,"chetai_end":57,"yg_id":25394309872226304,"dangcheshu":3.5},
{"id":120389564496875520,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":3,"chetai_start":58,"chetai_end":60,"yg_id":25394309482156032,"dangcheshu":3},
{"id":120389903656685568,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":25394308739764224,"dangcheshu":3.5},
{"id":120389903681851392,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":25394330747277312,"dangcheshu":3.5},
{"id":120389903698628608,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":25394326401978368,"dangcheshu":3},
{"id":120389903715405824,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":25394294764343296,"dangcheshu":3.5},
{"id":120389903732183040,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":55117587129831424,"dangcheshu":3.5},
{"id":120389903748960256,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":25394285914361856,"dangcheshu":3},
{"id":120390213137600512,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":81,"chetai_end":84,"yg_id":25394264351444992,"dangcheshu":3.5},
{"id":120390213166960640,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":84,"chetai_end":87,"yg_id":25394303547215872,"dangcheshu":3.5},
{"id":120390213183737856,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":88,"chetai_end":90,"yg_id":25394324619399168,"dangcheshu":3},
{"id":120390213204709376,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":91,"chetai_end":94,"yg_id":56616898418184192,"dangcheshu":3.5},
{"id":120390213221486592,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":94,"chetai_end":97,"yg_id":25394335637835776,"dangcheshu":3.5},
{"id":120390213238263808,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":5,"chetai_start":98,"chetai_end":100,"yg_id":25394308521660416,"dangcheshu":3},
{"id":120404584362414080,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":1,"chetai_end":4,"yg_id":25394312703381504,"dangcheshu":3.5},
{"id":120404584391774208,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":4,"chetai_end":7,"yg_id":25394315442262016,"dangcheshu":3.5},
{"id":120404584408551424,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":8,"chetai_end":10,"yg_id":25394305950552064,"dangcheshu":3},
{"id":120404584425328640,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":11,"chetai_end":14,"yg_id":25394326620082176,"dangcheshu":3.5},
{"id":120404584442105856,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":14,"chetai_end":17,"yg_id":25394299948503040,"dangcheshu":3.5},
{"id":120404584458883072,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":1,"chetai_start":18,"chetai_end":20,"yg_id":25394311185043456,"dangcheshu":3},
{"id":120411788704485376,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":1,"chetai_end":4,"yg_id":25394278435917824,"dangcheshu":3.5},
{"id":120411788729651200,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":4,"chetai_end":7,"yg_id":25394306164461568,"dangcheshu":3.5},
{"id":120411788742234112,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":8,"chetai_end":10,"yg_id":25394335184850944,"dangcheshu":3},
{"id":120411788759011328,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":11,"chetai_end":14,"yg_id":25394254381584384,"dangcheshu":3.5},
{"id":120411788775788544,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":14,"chetai_end":17,"yg_id":25394264573743104,"dangcheshu":3.5},
{"id":120411788792565760,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":1,"chetai_start":18,"chetai_end":20,"yg_id":25394261629341696,"dangcheshu":3},
{"id":120413456527527936,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":3,"chetai_start":41,"chetai_end":45,"yg_id":25394325974159360,"dangcheshu":5},
{"id":120413456552693760,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":3,"chetai_start":46,"chetai_end":50,"yg_id":25394257451814912,"dangcheshu":5},
{"id":120413456569470976,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":3,"chetai_start":51,"chetai_end":55,"yg_id":25394253316231168,"dangcheshu":5},
{"id":120413456586248192,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":3,"chetai_start":56,"chetai_end":60,"yg_id":25394259884511232,"dangcheshu":5},
{"id":120414505472626688,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":5,"chetai_start":81,"chetai_end":85,"yg_id":25394284488298496,"dangcheshu":5},
{"id":120414505501986816,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":5,"chetai_start":86,"chetai_end":90,"yg_id":25394258324230144,"dangcheshu":5},
{"id":120414505518764032,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":5,"chetai_start":91,"chetai_end":95,"yg_id":25394308257419264,"dangcheshu":5},
{"id":120414505531346944,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":5,"chetai_start":96,"chetai_end":100,"yg_id":25394265102225408,"dangcheshu":5},
{"id":120415064866951168,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":101,"chetai_end":104,"yg_id":25394267052576768,"dangcheshu":3.5},
{"id":120415064887922688,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":104,"chetai_end":107,"yg_id":25394265983029248,"dangcheshu":3.5},
{"id":120415064908894208,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":108,"chetai_end":110,"yg_id":25394300376322048,"dangcheshu":3},
{"id":120415064925671424,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":111,"chetai_end":114,"yg_id":25394315178020864,"dangcheshu":3.5},
{"id":120415064942448640,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":114,"chetai_end":117,"yg_id":25394333142224896,"dangcheshu":3.5},
{"id":120415064959225856,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":6,"chetai_start":118,"chetai_end":120,"yg_id":25394308953673728,"dangcheshu":3},
{"id":120415827617910784,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":25394276531703808,"dangcheshu":3.5},
{"id":120415827634688000,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":25394328620765184,"dangcheshu":3.5},
{"id":120415827651465216,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":25394277718691840,"dangcheshu":3},
{"id":120415827668242432,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":25394338246692864,"dangcheshu":3.5},
{"id":120415827685019648,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":25394316000104448,"dangcheshu":3.5},
{"id":120415827705991168,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":25394288552579072,"dangcheshu":3},
{"id":120416422688985088,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":25394273654411264,"dangcheshu":3.5},
{"id":120416422701568000,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394288808431616,"dangcheshu":3.5},
{"id":120416422705762304,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394260790480896,"dangcheshu":3},
{"id":120416422718345216,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":25394336363450368,"dangcheshu":3.5},
{"id":120416422726733824,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":25394280528875520,"dangcheshu":3.5},
{"id":120416422735122432,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":25394293594132480,"dangcheshu":3},
{"id":120544922305564672,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":5,"chetai_start":81,"chetai_end":85,"yg_id":25394323059118080,"dangcheshu":5},
{"id":120544922322341888,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":5,"chetai_start":86,"chetai_end":90,"yg_id":25394253727272960,"dangcheshu":5},
{"id":120544922339119104,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":5,"chetai_start":91,"chetai_end":95,"yg_id":25394255010729984,"dangcheshu":5},
{"id":120544922355896320,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":5,"chetai_start":96,"chetai_end":100,"yg_id":25394284916117504,"dangcheshu":5},
{"id":120545630580903936,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":101,"chetai_end":104,"yg_id":25394268558331904,"dangcheshu":3.5},
{"id":120545630606069760,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":104,"chetai_end":107,"yg_id":25394273444696064,"dangcheshu":3.5},
{"id":120545630622846976,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":108,"chetai_end":110,"yg_id":25394336074043392,"dangcheshu":3},
{"id":120545630639624192,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":111,"chetai_end":114,"yg_id":25394343724453888,"dangcheshu":3.5},
{"id":120545630656401408,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":114,"chetai_end":117,"yg_id":25394294344912896,"dangcheshu":3.5},
{"id":120545630668984320,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":6,"chetai_start":118,"chetai_end":120,"yg_id":25394282781216768,"dangcheshu":3},
{"id":121885127797116928,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":25394320131493888,"dangcheshu":3.5},
{"id":121885127826477056,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394353119694848,"dangcheshu":3.5},
{"id":121885127843254272,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394331602915328,"dangcheshu":3},
{"id":121885127860031488,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":102725859500101632,"dangcheshu":3.5},
{"id":121885127876808704,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":25394321809215488,"dangcheshu":3.5},
{"id":121885127893585920,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":25394352679292928,"dangcheshu":3},
{"id":121885246168764416,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":41,"chetai_end":44,"yg_id":58023703778168832,"dangcheshu":3.5},
{"id":121885246189735936,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":44,"chetai_end":47,"yg_id":25394345465090048,"dangcheshu":3.5},
{"id":121885246202318848,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":48,"chetai_end":50,"yg_id":25394310325211136,"dangcheshu":3},
{"id":121885246219096064,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":51,"chetai_end":54,"yg_id":57706516936921088,"dangcheshu":3.5},
{"id":121885246235873280,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":54,"chetai_end":57,"yg_id":36260154701778944,"dangcheshu":3.5},
{"id":121885246252650496,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":3,"chetai_start":58,"chetai_end":60,"yg_id":89158837713506304,"dangcheshu":3},
{"id":121885553049210880,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":41,"chetai_end":44,"yg_id":25394298417582080,"dangcheshu":3.5},
{"id":121885553074376704,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":44,"chetai_end":47,"yg_id":25394331879739392,"dangcheshu":3.5},
{"id":121885553086959616,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":48,"chetai_end":50,"yg_id":25394332085260288,"dangcheshu":3},
{"id":121885553107931136,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":51,"chetai_end":54,"yg_id":25394322836819968,"dangcheshu":3.5},
{"id":121885553124708352,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":54,"chetai_end":57,"yg_id":25394343061753856,"dangcheshu":3.5},
{"id":121885553145679872,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":3,"chetai_start":58,"chetai_end":60,"yg_id":25394287898267648,"dangcheshu":3},
{"id":121885819202965504,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":25394336598331392,"dangcheshu":3.5},
{"id":121885819228131328,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":25394343292440576,"dangcheshu":3.5},
{"id":121885819244908544,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":25394351068680192,"dangcheshu":3},
{"id":121885819270074368,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":25394331397394432,"dangcheshu":3.5},
{"id":121885819291045888,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":25394308014149632,"dangcheshu":3.5},
{"id":121885819312017408,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":25394351525859328,"dangcheshu":3},
{"id":121885952749604864,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":81,"chetai_end":84,"yg_id":25394342315167744,"dangcheshu":3.5},
{"id":121885952774770688,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":84,"chetai_end":87,"yg_id":25394307397586944,"dangcheshu":3.5},
{"id":121885952791547904,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":88,"chetai_end":90,"yg_id":25394348786978816,"dangcheshu":3},
{"id":121885952812519424,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":91,"chetai_end":94,"yg_id":25394310102913024,"dangcheshu":3.5},
{"id":121885952829296640,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":94,"chetai_end":97,"yg_id":75481403743014912,"dangcheshu":3.5},
{"id":121885952846073856,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":5,"chetai_start":98,"chetai_end":100,"yg_id":25394310966939648,"dangcheshu":3},
{"id":121886067652562944,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":101,"chetai_end":104,"yg_id":25394251827253248,"dangcheshu":3.5},
{"id":121886067673534464,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":104,"chetai_end":107,"yg_id":25394340423536640,"dangcheshu":3.5},
{"id":121886067690311680,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":108,"chetai_end":110,"yg_id":25394301508784128,"dangcheshu":3},
{"id":121886067707088896,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":111,"chetai_end":114,"yg_id":25394313785511936,"dangcheshu":3.5},
{"id":121886067723866112,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":114,"chetai_end":117,"yg_id":25394260090032128,"dangcheshu":3.5},
{"id":121886067740643328,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"jizu":6,"chetai_start":118,"chetai_end":120,"yg_id":25394254805209088,"dangcheshu":3},
{"id":121887275310125056,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":57707023516569600,"dangcheshu":3.5},
{"id":121887275335290880,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":55473100082384896,"dangcheshu":3.5},
{"id":121887275352068096,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":36260136813072384,"dangcheshu":3},
{"id":121887275368845312,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":56619152755920896,"dangcheshu":3.5},
{"id":121887275385622528,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":25394305396903936,"dangcheshu":3.5},
{"id":121887275402399744,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":114291502120701952,"dangcheshu":3},
{"id":123606871947874304,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":101,"chetai_end":104,"yg_id":84087718895685632,"dangcheshu":3.5},
{"id":123606871968845824,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":104,"chetai_end":107,"yg_id":88552717080858624,"dangcheshu":3.5},
{"id":123606871989817344,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":108,"chetai_end":110,"yg_id":93241166341869568,"dangcheshu":3},
{"id":123606872006594560,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":111,"chetai_end":114,"yg_id":93238232686268416,"dangcheshu":3.5},
{"id":123606872023371776,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":114,"chetai_end":117,"yg_id":84084713496514560,"dangcheshu":3.5},
{"id":123606872040148992,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"jizu":6,"chetai_start":118,"chetai_end":120,"yg_id":84089998294388736,"dangcheshu":3},
{"id":123662101523730432,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":81,"chetai_end":82,"yg_id":111640051850416128,"dangcheshu":2},
{"id":123662102295482368,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":83,"chetai_end":84,"yg_id":121069184883888128,"dangcheshu":2},
{"id":123662102370979840,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":85,"chetai_end":86,"yg_id":93228252994211840,"dangcheshu":2},
{"id":123662102400339968,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":87,"chetai_end":88,"yg_id":93227633852026880,"dangcheshu":2},
{"id":123662102425505792,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":89,"chetai_end":90,"yg_id":111639830290501632,"dangcheshu":2},
{"id":123662102442283008,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":91,"chetai_end":92,"yg_id":93227022582550528,"dangcheshu":2},
{"id":123662102467448832,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":93,"chetai_end":94,"yg_id":111640631461285888,"dangcheshu":2},
{"id":123662102488420352,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":95,"chetai_end":96,"yg_id":111639603936497664,"dangcheshu":2},
{"id":123662102509391872,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":97,"chetai_end":98,"yg_id":111640416700338176,"dangcheshu":2},
{"id":123662102526169088,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":5,"chetai_start":99,"chetai_end":100,"yg_id":111639258053218304,"dangcheshu":2},
{"id":123696286305095680,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":58372032244486144,"dangcheshu":3.5},
{"id":123696286464479232,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394319879835648,"dangcheshu":3.5},
{"id":123696286519005184,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394312409780224,"dangcheshu":3},
{"id":123696286539976704,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":55473760022564864,"dangcheshu":3.5},
{"id":123696286560948224,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":55471125118849024,"dangcheshu":3.5},
{"id":123696286569336832,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":55462259811422208,"dangcheshu":3},
{"id":123712008896909312,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":25394320567701504,"dangcheshu":3.5},
{"id":123712008926269440,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394333368717312,"dangcheshu":3.5},
{"id":123712008947240960,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394272303845376,"dangcheshu":3},
{"id":123712008964018176,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":25394288103788544,"dangcheshu":3.5},
{"id":123712008984989696,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":25394274837204992,"dangcheshu":3.5},
{"id":123712009001766912,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":25394346626912256,"dangcheshu":3},
{"id":123712112307474432,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":41,"chetai_end":44,"yg_id":25394262979907584,"dangcheshu":3.5},
{"id":123712112332640256,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":44,"chetai_end":47,"yg_id":25394337118425088,"dangcheshu":3.5},
{"id":123712112353611776,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":48,"chetai_end":50,"yg_id":25394302385393664,"dangcheshu":3},
{"id":123712112374583296,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":51,"chetai_end":54,"yg_id":25394346350088192,"dangcheshu":3.5},
{"id":123712112391360512,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":54,"chetai_end":57,"yg_id":25394342852038656,"dangcheshu":3.5},
{"id":123712112408137728,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":3,"chetai_start":58,"chetai_end":60,"yg_id":25394287084572672,"dangcheshu":3},
{"id":123715314398531584,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":25394316927045632,"dangcheshu":3.5},
{"id":123715314415308800,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":25394330747277312,"dangcheshu":3.5},
{"id":123715314432086016,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":25394323495325696,"dangcheshu":3},
{"id":123715314444668928,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":25394303983423488,"dangcheshu":3.5},
{"id":123715314457251840,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":55117587129831424,"dangcheshu":3.5},
{"id":123715314465640448,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":25394291484397568,"dangcheshu":3},
{"id":123715494162206720,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":81,"chetai_end":84,"yg_id":25394328411049984,"dangcheshu":3.5},
{"id":123715494187372544,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":84,"chetai_end":87,"yg_id":25394309238886400,"dangcheshu":3.5},
{"id":123715494204149760,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":88,"chetai_end":90,"yg_id":25394301273903104,"dangcheshu":3},
{"id":123715494216732672,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":91,"chetai_end":94,"yg_id":25394311449284608,"dangcheshu":3.5},
{"id":123715494233509888,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":94,"chetai_end":97,"yg_id":25394338452213760,"dangcheshu":3.5},
{"id":123715494262870016,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"jizu":5,"chetai_start":98,"chetai_end":100,"yg_id":25394319443628032,"dangcheshu":3},
{"id":124085100756340736,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":1,"chetai_end":4,"yg_id":25394300791558144,"dangcheshu":3.5},
{"id":124085100798283776,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":4,"chetai_end":7,"yg_id":25394348992499712,"dangcheshu":3.5},
{"id":124085100819255296,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":8,"chetai_end":10,"yg_id":25394250522824704,"dangcheshu":3},
{"id":124085100848615424,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":11,"chetai_end":14,"yg_id":25394251181330432,"dangcheshu":3.5},
{"id":124085100873781248,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":14,"chetai_end":17,"yg_id":25394300154023936,"dangcheshu":3.5},
{"id":124085100898947072,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":1,"chetai_start":18,"chetai_end":20,"yg_id":25394274627489792,"dangcheshu":3},
{"id":124085260844535808,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":21,"chetai_end":24,"yg_id":25394297989763072,"dangcheshu":3.5},
{"id":124085260886478848,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":24,"chetai_end":27,"yg_id":25394285700452352,"dangcheshu":3.5},
{"id":124085260907450368,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":28,"chetai_end":30,"yg_id":25394258097737728,"dangcheshu":3},
{"id":124085260924227584,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":31,"chetai_end":34,"yg_id":25394289043312640,"dangcheshu":3.5},
{"id":124085260941004800,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":34,"chetai_end":37,"yg_id":25394260572377088,"dangcheshu":3.5},
{"id":124085260957782016,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":2,"chetai_start":38,"chetai_end":40,"yg_id":25394276103884800,"dangcheshu":3},
{"id":124085321473200128,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":3,"chetai_start":41,"chetai_end":45,"yg_id":25394275688648704,"dangcheshu":5},
{"id":124085321494171648,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":3,"chetai_start":46,"chetai_end":50,"yg_id":25394257451814912,"dangcheshu":5},
{"id":124085321510948864,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":3,"chetai_start":51,"chetai_end":55,"yg_id":25394267476201472,"dangcheshu":5},
{"id":124085321523531776,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":3,"chetai_start":56,"chetai_end":60,"yg_id":25394259020484608,"dangcheshu":5},
{"id":124085394332454912,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":61,"chetai_end":64,"yg_id":25394288347058176,"dangcheshu":3.5},
{"id":124085394353426432,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":64,"chetai_end":67,"yg_id":25394266192744448,"dangcheshu":3.5},
{"id":124085394395369472,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":68,"chetai_end":70,"yg_id":25394282345009152,"dangcheshu":3},
{"id":124085394416340992,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":71,"chetai_end":74,"yg_id":25394284706402304,"dangcheshu":3.5},
{"id":124085394433118208,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":74,"chetai_end":77,"yg_id":25394293271171072,"dangcheshu":3.5},
{"id":124085394449895424,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"jizu":4,"chetai_start":78,"chetai_end":80,"yg_id":25394248987709440,"dangcheshu":3},
{"id":124422175993106432,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":101,"chetai_end":103,"yg_id":93237880561864704,"dangcheshu":2.5},
{"id":124422176030855168,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":103,"chetai_end":105,"yg_id":93590060657545216,"dangcheshu":2.5},
{"id":124422176056020992,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":106,"chetai_end":108,"yg_id":93240184245587968,"dangcheshu":2.5},
{"id":124422176081186816,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":108,"chetai_end":110,"yg_id":88556029159149568,"dangcheshu":2.5},
{"id":124422176106352640,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":111,"chetai_end":113,"yg_id":93238706298687488,"dangcheshu":2.5},
{"id":124422176131518464,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":113,"chetai_end":115,"yg_id":88553603400208384,"dangcheshu":2.5},
{"id":124422176152489984,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":116,"chetai_end":118,"yg_id":93236409787224064,"dangcheshu":2.5},
{"id":124422176181850112,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"jizu":6,"chetai_start":118,"chetai_end":120,"yg_id":93239113490108416,"dangcheshu":2.5}
]
@@ -0,0 +1,9 @@
[
{"id":30318522743656448,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"yg_id":25394296936992768},
{"id":30318912478384128,"deleted_at":null,"dep_id":16043931070369792,"banci":1,"yg_id":25394278175870976},
{"id":30318977318129664,"deleted_at":null,"dep_id":16047387197837312,"banci":1,"yg_id":25394284219863040},
{"id":30574578740760576,"deleted_at":null,"dep_id":22308683820044288,"banci":1,"yg_id":25394286337986560},
{"id":30574628829138944,"deleted_at":null,"dep_id":22308683820044288,"banci":2,"yg_id":25394249843347456},
{"id":32372395503259648,"deleted_at":null,"dep_id":22308600831545344,"banci":1,"yg_id":25394250304720896},
{"id":56641710280675328,"deleted_at":null,"dep_id":22308600831545344,"banci":2,"yg_id":25394284219863040}
]
@@ -0,0 +1,144 @@
<script setup>
/**
* 职工选择弹窗(单选 / 多选)
* 对应 WinForms 端的 F9ModalPageUserControl 职工选择页,数据源为 /api/sys/employee。
*/
import { ref, watch } from 'vue';
import { ElMessage } from 'element-plus';
import request from '../../utils/request';
const props = defineProps({
modelValue: Boolean,
title: { type: String, default: '选择职工' },
multiple: Boolean,
depId: { type: [Number, String], default: 0 },
width: { type: String, default: '820px' },
});
const emit = defineEmits(['update:modelValue', 'confirm']);
const visible = ref(false);
const loading = ref(false);
const rows = ref([]);
const total = ref(0);
const keyword = ref('');
const pageIndex = ref(1);
const pageSize = ref(20);
const current = ref(null);
const selected = ref([]);
watch(() => props.modelValue, async (v) => {
visible.value = v;
if (!v) return;
keyword.value = '';
pageIndex.value = 1;
current.value = null;
selected.value = [];
await query();
});
watch(visible, (v) => emit('update:modelValue', v));
async function query() {
loading.value = true;
try {
const res = await request.get('/sys/employee', {
params: {
depId: props.depId || 0,
like: keyword.value,
pageIndex: pageIndex.value,
pageSize: pageSize.value,
},
});
rows.value = res.data?.items || [];
total.value = Number(res.data?.total || 0);
} catch {
rows.value = [];
total.value = 0;
} finally {
loading.value = false;
}
}
function onSearch() {
pageIndex.value = 1;
query();
}
function onPageChange(p) {
pageIndex.value = p;
query();
}
function onRowClick(row) {
if (props.multiple) return;
current.value = row;
}
function onRowDblClick(row) {
if (props.multiple) return;
current.value = row;
confirm();
}
function confirm() {
const picked = props.multiple ? selected.value : current.value ? [current.value] : [];
if (!picked.length) {
ElMessage.warning('请选择职工');
return;
}
visible.value = false;
emit('confirm', props.multiple ? picked.map((x) => ({ ...x })) : { ...picked[0] });
}
</script>
<template>
<el-dialog v-model="visible" :title="title" :width="width" append-to-body destroy-on-close>
<div class="es-toolbar">
<el-input
v-model="keyword"
placeholder="姓名 / 工号"
clearable
style="width: 200px"
@keyup.enter="onSearch"
@clear="onSearch"
/>
<el-button type="primary" @click="onSearch">查询</el-button>
<span v-if="multiple" class="es-tip">已选 {{ selected.length }} 人</span>
</div>
<el-table
v-loading="loading"
:data="rows"
border
size="small"
height="400"
highlight-current-row
@row-click="onRowClick"
@row-dblclick="onRowDblClick"
@selection-change="selected = $event"
>
<el-table-column v-if="multiple" type="selection" width="45" />
<el-table-column type="index" label="序号" width="55" />
<el-table-column prop="name" label="姓名" width="110" />
<el-table-column prop="code" label="工号" width="120" />
<el-table-column prop="depName" label="部门" min-width="140" show-overflow-tooltip />
<el-table-column prop="gangwei" label="岗位" min-width="120" show-overflow-tooltip />
</el-table>
<el-pagination
class="es-page"
:current-page="pageIndex"
:page-size="pageSize"
:total="total"
layout="total, prev, pager, next"
@current-change="onPageChange"
/>
<template #footer>
<el-button @click="visible = false">取消</el-button>
<el-button type="primary" @click="confirm">确定</el-button>
</template>
</el-dialog>
</template>
<style scoped>
.es-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.es-tip { color: var(--el-text-color-secondary); font-size: 13px; }
.es-page { margin-top: 10px; justify-content: flex-end; }
</style>
+1
View File
@@ -65,6 +65,7 @@ export const componentMap = {
'prod/lsjl/index': () => import('../views/prod/lsjl/index.vue'), 'prod/lsjl/index': () => import('../views/prod/lsjl/index.vue'),
'prod/xdjy/index': () => import('../views/prod/xdjy/index.vue'), 'prod/xdjy/index': () => import('../views/prod/xdjy/index.vue'),
'prod/hbjy/index': () => import('../views/prod/hbjy/index.vue'), 'prod/hbjy/index': () => import('../views/prod/hbjy/index.vue'),
'prod/ktpb/index': () => import('../views/prod/ktpb/index.vue'),
'notification/messages/index': () => import('../views/notification/messages/index.vue'), 'notification/messages/index': () => import('../views/notification/messages/index.vue'),
'notification/subscribe/index': () => import('../views/notification/subscribe/index.vue'), 'notification/subscribe/index': () => import('../views/notification/subscribe/index.vue'),
'notification/type/index': () => import('../views/notification/type/index.vue'), 'notification/type/index': () => import('../views/notification/type/index.vue'),
+650
View File
@@ -0,0 +1,650 @@
<script setup>
/**
* 看台排班(生产-前缫)
* 对应 WinForms 端 WinClient\F9.Business.Prod\QS\KTPB\Page_KTPB
* - 车头工:一个「车间+班次+机组」一条记录(2 名车头工)
* - 挡车工:一个「车间+班次+机组」一组记录,按车台区间分派挡车工,挡车数自动计算
* - 值班长:一个「车间+班次」可有多名值班长
*/
import { ref, reactive, computed, onMounted } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import request from '../../../utils/request';
import EmployeeSelect from '../../../components/select/EmployeeSelect.vue';
const TABS = [
{ name: 'dcg', label: '挡车工' },
{ name: 'ctg', label: '车头工' },
{ name: 'zbz', label: '值班长' },
];
const BANCI = [
{ value: 1, label: '甲班' },
{ value: 2, label: '乙班' },
];
const tab = ref('dcg');
const deps = ref([]);
const jizuOptions = ref([]);
const filter = reactive({ depId: 0, banci: 1, jizu: 0, keyword: '' });
const state = reactive({
dcg: { rows: [], total: 0, loading: false, pageIndex: 1, pageSize: 20 },
ctg: { rows: [], total: 0, loading: false, pageIndex: 1, pageSize: 20 },
zbz: { rows: [], total: 0, loading: false, pageIndex: 1, pageSize: 20 },
});
const cur = computed(() => state[tab.value]);
const depName = computed(() => deps.value.find((d) => d.id === filter.depId)?.name || '');
const banciName = computed(() => BANCI.find((b) => b.value === filter.banci)?.label || '');
// ==================== 通用查询 ====================
async function loadDeps() {
const res = await request.get('/prod/ktpb/qianxian-deps');
deps.value = res.data || [];
if (deps.value.length && !filter.depId) filter.depId = deps.value[0].id;
}
async function loadJizu() {
if (!filter.depId) {
jizuOptions.value = [];
return;
}
const res = await request.get('/prod/ktpb/jizu-options', { params: { depId: filter.depId } });
jizuOptions.value = res.data || [];
if (!jizuOptions.value.some((x) => x.jizu === filter.jizu)) {
filter.jizu = jizuOptions.value.length ? jizuOptions.value[0].jizu : 0;
}
}
async function loadList(resetPage = false) {
const s = cur.value;
if (resetPage) s.pageIndex = 1;
s.loading = true;
try {
const res = await request.get(`/prod/ktpb/${tab.value}`, {
params: {
depId: filter.depId || 0,
banci: filter.banci || null,
jizu: tab.value === 'zbz' ? null : filter.jizu || null,
like: filter.keyword,
pageIndex: s.pageIndex,
pageSize: s.pageSize,
},
});
s.rows = res.data?.items || [];
s.total = Number(res.data?.total || 0);
} finally {
s.loading = false;
}
}
async function onDepChange() {
await loadJizu();
await loadList(true);
}
async function onSearch() {
await loadList(true);
}
async function onPageChange(p) {
cur.value.pageIndex = p;
await loadList();
}
async function onTabChange(name) {
await loadList();
}
onMounted(async () => {
await loadDeps();
await loadJizu();
await loadList(true);
});
// ==================== 挡车工:整组批量编辑 ====================
const dcgDlg = reactive({
visible: false,
loading: false,
saving: false,
depId: 0,
banci: 1,
jizu: 0,
chetaiStart: 0,
chetaiEnd: 0,
rows: [],
});
const dcgDepName = computed(() => deps.value.find((d) => d.id === dcgDlg.depId)?.name || '');
const dcgBanciName = computed(() => BANCI.find((b) => b.value === dcgDlg.banci)?.label || '');
const dcgTotalChetai = computed(() =>
dcgDlg.chetaiStart && dcgDlg.chetaiEnd ? dcgDlg.chetaiEnd - dcgDlg.chetaiStart + 1 : 0
);
const dcgAssigned = computed(() => {
const set = new Set();
dcgDlg.rows.forEach((r) => {
const s = Number(r.chetaiStart) || 0;
const e = Number(r.chetaiEnd) || 0;
for (let i = s; i <= e; i++) set.add(i);
});
return set.size;
});
async function openDcgGroup() {
if (!filter.depId) return ElMessage.warning('请先选择车间');
if (!filter.jizu) return ElMessage.warning('请先选择机组');
const opt = jizuOptions.value.find((x) => x.jizu === filter.jizu);
dcgDlg.depId = filter.depId;
dcgDlg.banci = filter.banci;
dcgDlg.jizu = filter.jizu;
dcgDlg.chetaiStart = opt?.chetaiStart || 0;
dcgDlg.chetaiEnd = opt?.chetaiEnd || 0;
dcgDlg.visible = true;
dcgDlg.loading = true;
try {
const res = await request.get('/prod/ktpb/dcg/group', {
params: { depId: dcgDlg.depId, banci: dcgDlg.banci, jizu: dcgDlg.jizu },
});
dcgDlg.rows = (res.data || []).map((x) => ({
id: x.id,
ygId: x.ygId,
ygName: x.ygName,
chetaiStart: x.chetaiStart,
chetaiEnd: x.chetaiEnd,
dangcheshu: x.dangcheshu,
}));
recalcDangche(dcgDlg.rows);
} finally {
dcgDlg.loading = false;
}
}
function draftDcgRow(name, start, end) {
dcgDlg.rows.push({ id: 0, ygId: 0, ygName: name, chetaiStart: start, chetaiEnd: end, dangcheshu: 0 });
}
function appendEmployees(picked) {
const exist = new Set(dcgDlg.rows.map((r) => String(r.ygId)));
let next = dcgDlg.chetaiStart;
if (dcgDlg.rows.length) {
next = Math.max(...dcgDlg.rows.map((r) => Number(r.chetaiEnd) || 0)) + 1;
}
picked.forEach((e) => {
if (exist.has(String(e.id))) return;
if (next > dcgDlg.chetaiEnd) next = dcgDlg.chetaiEnd;
draftDcgRow(e.name, next, next);
exist.add(String(e.id));
next += 1;
});
recalcDangche(dcgDlg.rows);
}
function removeDcgRow(index) {
dcgDlg.rows.splice(index, 1);
recalcDangche(dcgDlg.rows);
}
function clearDcgRows() {
dcgDlg.rows = [];
}
/**
* 挡车数计算(与后端 KtpbService.RecalcDangcheshu 完全一致):
* 单台车权重 1;若该车台被多条记录共享,且同时是某记录起点与某记录终点(接壤),权重 0.5。
*/
function recalcDangche(rows) {
const counts = {};
const starts = new Set();
const ends = new Set();
rows.forEach((r) => {
const s = Number(r.chetaiStart) || 0;
const e = Number(r.chetaiEnd) || 0;
if (!s || e < s) return;
starts.add(s);
ends.add(e);
for (let i = s; i <= e; i++) counts[i] = (counts[i] || 0) + 1;
});
rows.forEach((r) => {
const s = Number(r.chetaiStart) || 0;
const e = Number(r.chetaiEnd) || 0;
let total = 0;
for (let i = s; i <= e; i++) {
let w = 1;
if ((counts[i] || 0) > 1 && starts.has(i) && ends.has(i)) w = 0.5;
total += w;
}
r.dangcheshu = Math.round(total * 100) / 100;
});
}
const empPicker = reactive({ visible: false, multiple: false, target: '' });
function pickEmployee(target) {
empPicker.target = target;
empPicker.multiple = target === 'dcg';
empPicker.visible = true;
}
function onEmployeePicked(picked) {
if (empPicker.target === 'dcg') {
appendEmployees(picked);
} else if (empPicker.target === 'ctg1') {
ctgForm.ygid1 = picked.id;
ctgForm.ygid1Name = picked.name;
} else if (empPicker.target === 'ctg2') {
ctgForm.ygid2 = picked.id;
ctgForm.ygid2Name = picked.name;
} else if (empPicker.target === 'zbz') {
zbzForm.ygId = picked.id;
zbzForm.ygName = picked.name;
}
}
async function saveDcgGroup() {
for (const r of dcgDlg.rows) {
if (!r.ygId) return ElMessage.warning('存在未选择挡车工的记录');
if (!r.chetaiStart) return ElMessage.warning(`挡车工「${r.ygName}」请填写起始车台`);
if (!r.chetaiEnd || Number(r.chetaiEnd) < Number(r.chetaiStart)) {
return ElMessage.warning(`挡车工「${r.ygName}」结束车台不能小于起始车台`);
}
if (Number(r.chetaiStart) < dcgDlg.chetaiStart || Number(r.chetaiEnd) > dcgDlg.chetaiEnd) {
return ElMessage.warning(`挡车工「${r.ygName}」车台范围必须在本机组 ${dcgDlg.chetaiStart}-${dcgDlg.chetaiEnd} 内`);
}
}
recalcDangche(dcgDlg.rows);
dcgDlg.saving = true;
try {
const res = await request.post('/prod/ktpb/dcg/batch', {
depId: dcgDlg.depId,
banci: dcgDlg.banci,
jizu: dcgDlg.jizu,
items: dcgDlg.rows.map((r) => ({
ygId: r.ygId,
ygName: r.ygName,
chetaiStart: Number(r.chetaiStart),
chetaiEnd: Number(r.chetaiEnd),
dangcheshu: r.dangcheshu,
})),
});
ElMessage.success(res.message || '保存成功');
dcgDlg.visible = false;
await loadList();
} finally {
dcgDlg.saving = false;
}
}
async function deleteDcg(row) {
await ElMessageBox.confirm(
`确定删除「${row.deptName} ${row.banciName}班 机组${row.jizu}」中 ${row.ygName} 的排班吗?`,
'提示',
{ type: 'warning' }
);
await request.delete(`/prod/ktpb/dcg/${row.id}`);
ElMessage.success('删除成功');
await loadList();
}
// ==================== 车头工 ====================
const ctgDlg = reactive({ visible: false, saving: false, id: 0 });
const ctgForm = reactive({
depId: 0,
banci: 1,
jizu: 0,
ygid1: 0,
ygid1Name: '',
ygid2: 0,
ygid2Name: '',
});
function openCtg(row) {
ctgDlg.id = row?.id || 0;
ctgForm.depId = row?.depId || filter.depId;
ctgForm.banci = row?.banci || filter.banci;
ctgForm.jizu = row?.jizu || filter.jizu;
ctgForm.ygid1 = row?.ygid1 || 0;
ctgForm.ygid1Name = row?.ygid1Name || '';
ctgForm.ygid2 = row?.ygid2 || 0;
ctgForm.ygid2Name = row?.ygid2Name || '';
ctgDlg.visible = true;
}
async function saveCtg() {
if (!ctgForm.depId) return ElMessage.warning('请选择车间');
if (!ctgForm.jizu) return ElMessage.warning('请选择机组');
if (!ctgForm.ygid1) return ElMessage.warning('请选择车头工1');
ctgDlg.saving = true;
try {
const payload = {
depId: ctgForm.depId,
banci: ctgForm.banci,
jizu: ctgForm.jizu,
ygid1: ctgForm.ygid1,
ygid2: ctgForm.ygid2 || 0,
};
if (ctgDlg.id) {
await request.put(`/prod/ktpb/ctg/${ctgDlg.id}`, payload);
ElMessage.success('修改成功');
} else {
await request.post('/prod/ktpb/ctg', payload);
ElMessage.success('新增成功');
}
ctgDlg.visible = false;
await loadList();
} finally {
ctgDlg.saving = false;
}
}
async function deleteCtg(row) {
await ElMessageBox.confirm(`确定删除「${row.deptName} ${row.banciName}班 机组${row.jizu}」的车头工排班吗?`, '提示', {
type: 'warning',
});
await request.delete(`/prod/ktpb/ctg/${row.id}`);
ElMessage.success('删除成功');
await loadList();
}
// ==================== 值班长 ====================
const zbzDlg = reactive({ visible: false, saving: false, id: 0 });
const zbzForm = reactive({ depId: 0, banci: 1, ygId: 0, ygName: '' });
function openZbz(row) {
zbzDlg.id = row?.id || 0;
zbzForm.depId = row?.depId || filter.depId;
zbzForm.banci = row?.banci || filter.banci;
zbzForm.ygId = row?.ygId || 0;
zbzForm.ygName = row?.ygName || '';
zbzDlg.visible = true;
}
async function saveZbz() {
if (!zbzForm.depId) return ElMessage.warning('请选择车间');
if (!zbzForm.ygId) return ElMessage.warning('请选择值班长');
zbzDlg.saving = true;
try {
const payload = { depId: zbzForm.depId, banci: zbzForm.banci, ygId: zbzForm.ygId };
if (zbzDlg.id) {
await request.put(`/prod/ktpb/zbz/${zbzDlg.id}`, payload);
ElMessage.success('修改成功');
} else {
await request.post('/prod/ktpb/zbz', payload);
ElMessage.success('新增成功');
}
zbzDlg.visible = false;
await loadList();
} finally {
zbzDlg.saving = false;
}
}
async function deleteZbz(row) {
await ElMessageBox.confirm(`确定删除「${row.deptName} ${row.banciName}班」值班长 ${row.ygName} 的排班吗?`, '提示', {
type: 'warning',
});
await request.delete(`/prod/ktpb/zbz/${row.id}`);
ElMessage.success('删除成功');
await loadList();
}
</script>
<template>
<div class="ktpb-page">
<el-card shadow="never">
<el-tabs v-model="tab" @tab-change="onTabChange">
<el-tab-pane v-for="t in TABS" :key="t.name" :label="t.label" :name="t.name" />
</el-tabs>
<div class="toolbar">
<span class="lbl">车间</span>
<el-select v-model="filter.depId" placeholder="全部车间" clearable style="width: 160px" @change="onDepChange">
<el-option v-for="d in deps" :key="d.id" :label="d.name" :value="d.id" />
</el-select>
<span class="lbl">班次</span>
<el-select v-model="filter.banci" style="width: 110px" @change="onSearch">
<el-option v-for="b in BANCI" :key="b.value" :label="b.label" :value="b.value" />
</el-select>
<template v-if="tab !== 'zbz'">
<span class="lbl">机组</span>
<el-select v-model="filter.jizu" placeholder="全部机组" clearable style="width: 130px" @change="onSearch">
<el-option
v-for="j in jizuOptions"
:key="j.jizu"
:label="`机组${j.jizu}(${j.chetaiStart}-${j.chetaiEnd})`"
:value="j.jizu"
/>
</el-select>
</template>
<el-input
v-model="filter.keyword"
placeholder="姓名 / 车台"
clearable
style="width: 180px"
@keyup.enter="onSearch"
@clear="onSearch"
/>
<el-button type="primary" @click="onSearch">查询</el-button>
<div class="right">
<el-button v-if="tab === 'dcg'" type="primary" @click="openDcgGroup">排班维护(按机组)</el-button>
<el-button v-else type="primary" @click="tab === 'ctg' ? openCtg(null) : openZbz(null)">新增</el-button>
</div>
</div>
<!-- 挡车工 -->
<el-table v-if="tab === 'dcg'" v-loading="state.dcg.loading" :data="state.dcg.rows" border size="small">
<el-table-column type="index" label="序号" width="55" />
<el-table-column prop="deptName" label="车间" min-width="120" show-overflow-tooltip />
<el-table-column label="班次" width="80" align="center">
<template #default="{ row }">{{ row.banciName }}班</template>
</el-table-column>
<el-table-column prop="jizu" label="机组" width="70" align="center" />
<el-table-column prop="ygName" label="挡车工" width="110" />
<el-table-column label="车台范围" width="110" align="center">
<template #default="{ row }">{{ row.chetaiStart }} - {{ row.chetaiEnd }}</template>
</el-table-column>
<el-table-column prop="dangcheshu" label="挡车数" width="90" align="right" />
<el-table-column label="操作" width="90" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="danger" @click="deleteDcg(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 车头工 -->
<el-table v-else-if="tab === 'ctg'" v-loading="state.ctg.loading" :data="state.ctg.rows" border size="small">
<el-table-column type="index" label="序号" width="55" />
<el-table-column prop="deptName" label="车间" min-width="120" show-overflow-tooltip />
<el-table-column label="班次" width="80" align="center">
<template #default="{ row }">{{ row.banciName }}班</template>
</el-table-column>
<el-table-column prop="jizu" label="机组" width="70" align="center" />
<el-table-column prop="ygid1Name" label="车头工1" width="120" />
<el-table-column prop="ygid2Name" label="车头工2" width="120" />
<el-table-column label="操作" width="130" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="openCtg(row)">修改</el-button>
<el-button link type="danger" @click="deleteCtg(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 值班长 -->
<el-table v-else v-loading="state.zbz.loading" :data="state.zbz.rows" border size="small">
<el-table-column type="index" label="序号" width="55" />
<el-table-column prop="deptName" label="车间" min-width="140" show-overflow-tooltip />
<el-table-column label="班次" width="90" align="center">
<template #default="{ row }">{{ row.banciName }}班</template>
</el-table-column>
<el-table-column prop="ygName" label="值班长" width="140" />
<el-table-column label="操作" width="130" align="center" fixed="right">
<template #default="{ row }">
<el-button link type="primary" @click="openZbz(row)">修改</el-button>
<el-button link type="danger" @click="deleteZbz(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
class="pager"
:current-page="cur.pageIndex"
:page-size="cur.pageSize"
:total="cur.total"
layout="total, prev, pager, next, jumper"
@current-change="onPageChange"
/>
</el-card>
<!-- ============ 挡车工整组排班 ============ -->
<el-dialog v-model="dcgDlg.visible" title="挡车工排班维护" width="880px" destroy-on-close>
<div class="dlg-head">
<el-tag type="info">{{ dcgDepName }}</el-tag>
<el-tag type="info">{{ dcgBanciName }}</el-tag>
<el-tag type="info">机组 {{ dcgDlg.jizu }}(车台 {{ dcgDlg.chetaiStart }}-{{ dcgDlg.chetaiEnd }})</el-tag>
<el-tag :type="dcgAssigned === dcgTotalChetai ? 'success' : 'warning'">
已分配 {{ dcgAssigned }} / {{ dcgTotalChetai }} 台
</el-tag>
</div>
<div class="dlg-toolbar">
<el-button type="primary" size="small" @click="pickEmployee('dcg')">添加挡车工</el-button>
<el-button size="small" @click="clearDcgRows">清空</el-button>
<span class="hint">车台结束号与下一行起始号接壤时,该车台各按 0.5 台计(挡车数自动计算)</span>
</div>
<el-table v-loading="dcgDlg.loading" :data="dcgDlg.rows" border size="small" height="380">
<el-table-column type="index" label="序号" width="55" />
<el-table-column label="挡车工" min-width="150">
<template #default="{ row, $index }">
<span v-if="row.ygName">{{ row.ygName }}</span>
<el-button v-else link type="primary" @click="pickEmployee('dcg')">选择</el-button>
</template>
</el-table-column>
<el-table-column label="起始车台" width="120" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.chetaiStart"
:min="dcgDlg.chetaiStart"
:max="dcgDlg.chetaiEnd"
:controls="false"
size="small"
style="width: 90px"
@change="recalcDangche(dcgDlg.rows)"
/>
</template>
</el-table-column>
<el-table-column label="结束车台" width="120" align="center">
<template #default="{ row }">
<el-input-number
v-model="row.chetaiEnd"
:min="dcgDlg.chetaiStart"
:max="dcgDlg.chetaiEnd"
:controls="false"
size="small"
style="width: 90px"
@change="recalcDangche(dcgDlg.rows)"
/>
</template>
</el-table-column>
<el-table-column prop="dangcheshu" label="挡车数" width="90" align="right" />
<el-table-column label="操作" width="80" align="center">
<template #default="{ $index }">
<el-button link type="danger" @click="removeDcgRow($index)">删除</el-button>
</template>
</el-table-column>
</el-table>
<template #footer>
<el-button @click="dcgDlg.visible = false">取消</el-button>
<el-button type="primary" :loading="dcgDlg.saving" @click="saveDcgGroup">保存</el-button>
</template>
</el-dialog>
<!-- ============ 车头工 ============ -->
<el-dialog v-model="ctgDlg.visible" :title="ctgDlg.id ? '修改车头工排班' : '新增车头工排班'" width="520px">
<el-form label-width="90px">
<el-form-item label="车间">
<el-select v-model="ctgForm.depId" placeholder="请选择车间" style="width: 100%">
<el-option v-for="d in deps" :key="d.id" :label="d.name" :value="d.id" />
</el-select>
</el-form-item>
<el-form-item label="班次">
<el-select v-model="ctgForm.banci" style="width: 100%">
<el-option v-for="b in BANCI" :key="b.value" :label="b.label" :value="b.value" />
</el-select>
</el-form-item>
<el-form-item label="机组">
<el-input-number v-model="ctgForm.jizu" :min="1" :max="99" :controls="false" style="width: 100%" />
</el-form-item>
<el-form-item label="车头工1">
<el-input :model-value="ctgForm.ygid1Name" readonly placeholder="点击选择">
<template #append>
<el-button @click="pickEmployee('ctg1')">选择</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item label="车头工2">
<el-input :model-value="ctgForm.ygid2Name" readonly placeholder="点击选择(可空)">
<template #append>
<el-button @click="pickEmployee('ctg2')">选择</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="ctgDlg.visible = false">取消</el-button>
<el-button type="primary" :loading="ctgDlg.saving" @click="saveCtg">保存</el-button>
</template>
</el-dialog>
<!-- ============ 值班长 ============ -->
<el-dialog v-model="zbzDlg.visible" :title="zbzDlg.id ? '修改值班长排班' : '新增值班长排班'" width="480px">
<el-form label-width="90px">
<el-form-item label="车间">
<el-select v-model="zbzForm.depId" placeholder="请选择车间" style="width: 100%">
<el-option v-for="d in deps" :key="d.id" :label="d.name" :value="d.id" />
</el-select>
</el-form-item>
<el-form-item label="班次">
<el-select v-model="zbzForm.banci" style="width: 100%">
<el-option v-for="b in BANCI" :key="b.value" :label="b.label" :value="b.value" />
</el-select>
</el-form-item>
<el-form-item label="值班长">
<el-input :model-value="zbzForm.ygName" readonly placeholder="点击选择">
<template #append>
<el-button @click="pickEmployee('zbz')">选择</el-button>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="zbzDlg.visible = false">取消</el-button>
<el-button type="primary" :loading="zbzDlg.saving" @click="saveZbz">保存</el-button>
</template>
</el-dialog>
<EmployeeSelect
v-model="empPicker.visible"
:multiple="empPicker.multiple"
:dep-id="dcgDlg.visible ? dcgDlg.depId : filter.depId"
@confirm="onEmployeePicked"
/>
</div>
</template>
<style scoped>
.ktpb-page :deep(.el-card__body) { padding-top: 6px; }
.toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }
.toolbar .lbl { color: var(--el-text-color-regular); font-size: 13px; }
.toolbar .right { margin-left: auto; }
.pager { margin-top: 10px; justify-content: flex-end; }
.dlg-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.dlg-toolbar { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.dlg-toolbar .hint { color: var(--el-text-color-secondary); font-size: 12px; }
</style>
+135
View File
@@ -0,0 +1,135 @@
# 工作进度-12:生产-前缫「看台排班」+ 机组车台/看台排班数据导入
> 时间:2026-10-22(承接工作进度-11)
> 需求:仿照 `D:\AntaiProject - 副本` 生产-前缫的「机组车台 / 看台排班」,在本系统落地看台排班功能,并导入随附的 4 张表数据:
> `biz_prod_qs_jzct`(机组车台)、`biz_prod_qs_ktpb_ctg`(车头工)、`biz_prod_qs_ktpb_dcg`(挡车工)、`biz_prod_qs_ktpb_zbz`(值班长)。
> 参考实现:`WinClient\F9.Business.Prod\QS\KTPB\`(Page_KTPB、Page_KTPBCTG_Edit、Page_KTPBDCG_Edit、Page_KTPBZBZ_Edit)、`Application\CQRS\Business\PROD\QS\KTPB\`、`Domain\Entities\Business\PROD\QS\KTPB\`。
---
## 一、功能设计
```
生产-前缫
├── 落丝记录
├── 车间班次
└── 看台排班(新增) /prod/qianxian/ktpb
顶部:车间(职责类型=前缫)+ 班次(甲/乙)+ 机组 + 关键字
页签:挡车工 / 车头工 / 值班长
├── 挡车工:按「车间+班次+机组」整组维护
│ 弹窗内可批量添加挡车工(多选职工),逐行填起止车台,
│ 挡车数自动计算(接壤车台各计 0.5),实时显示「已分配 x / y 台」
├── 车头工:一个「车间+班次+机组」一条记录,含车头工1 / 车头工2
└── 值班长:一个「车间+班次」可有多名值班长
```
与 F9 的对应关系:
| F9 | 本系统 |
|---|---|
| `Page_KTPB`(三个页签 + 车间/班次/机组过滤) | `views/prod/ktpb/index.vue` |
| `Page_KTPBDCG_Edit`(整组批量编辑 + 挡车数计算) | 挡车工弹窗 + `POST /dcg/batch` |
| `Page_KTPBCTG_Edit` / `Page_KTPBZBZ_Edit` | 车头工 / 值班长弹窗 |
| `BatchReplaceKtpbdcgCommand` | `KtpbService.SaveDcgBatchAsync`(先删后建) |
**挡车数算法**(移植 `CalculateSingleDangcheshu`):每台车权重默认 1;若某车台被多条记录覆盖,且同时是某记录的起点与另一记录的终点(接壤),该车台权重取 0.5,最后四舍五入保留两位。前后端实现完全一致。
---
## 二、后端
### 2.1 实体(`Domain/Entities/PROD/Ktpb.cs`)
| 类 | 表 | 主要字段 |
|---|---|---|
| `KtpbCtg` | `KtpbCtgs` | DeptId、Banci、Jizu、Ygid1、Ygid2 |
| `KtpbDcg` | `KtpbDcgs` | DeptId、Banci、Jizu、ChetaiStart、ChetaiEnd、YgId、Dangcheshu |
| `KtpbZbz` | `KtpbZbzs` | DeptId、Banci、YgId |
### 2.2 服务与接口(`KtpbService` / `KtpbController`,路由 `api/prod/ktpb`)
```
GET qianxian-deps 车间下拉(DutyType=前缫)
GET jizu-options?depId= 机组下拉(含车台范围,取机组车台)
GET ctg?depId=&banci=&jizu=&like= 车头工分页
POST ctg | PUT ctg/{id} | DELETE ctg/{id}
GET dcg?depId=&banci=&jizu=&like= 挡车工分页
GET dcg/group?depId=&banci=&jizu= 某机组整组排班
POST dcg/batch 整组替换(空集合=清空)
DELETE dcg/{id}
GET zbz?depId=&banci=&like= 值班长分页
POST zbz | PUT zbz/{id} | DELETE zbz/{id}
```
校验规则:
- 车头工:同「车间+班次+机组」唯一,车头工1 必填。
- 挡车工:起始车台>0、结束≥起始、必须落在该机组车台范围内;保存时服务端重算挡车数。
- 值班长:同「车间+班次+值班长」不重复。
### 2.3 数据导入(`ProdSeedData`,幂等)
新增 3 个内嵌资源 `SeedData/biz_prod_qs_ktpb_ctg.json`、`_dcg.json`、`_zbz.json`,并把 `biz_prod_qs_jzct.json` 按本次导出数据重新生成。
映射规则:
- **部门**:xlsx 中的 `dep_id` 是 F9 部门 Id,经 `BusinessSeedData.DeptData`(F9 Id → 部门名)映射到本系统 `Departments.Id`;
- **职工**:F9 职工导出时保留了原始雪花 Id,本系统 `Employees.Id` 与之一致,直接按 Id 关联(不存在的职工行跳过);
- **清洗**:剔除 `deleted_at` 非空的软删除行(4 张表中大量为测试/删除数据)、部门无法映射或不在前缫四车间的行、机组/车台号非法行;
- **去重**:机组车台按「车间+机组」保留规范行(优先 `起始号 = (机组-1)*20+1`);车头工按「车间+班次+机组」;值班长按「车间+班次+值班长」;挡车工按整行;
- **幂等**:机组车台按「车间+机组」upsert;车头工按「车间+班次+机组」upsert;挡车工按「车间+班次+机组」整组已存在则跳过;值班长按唯一键跳过。
导入结果(本次启动日志):
```
[ProdSeed] 机组车台:来源 24 条,新增 0,更新 0(此前已导入)
[ProdSeed] 车头工看台排班:来源 33 条,新增 33 条
[ProdSeed] 挡车工看台排班:来源 202 条,新增 202 条(34 组)
[ProdSeed] 值班长看台排班:来源 7 条,新增 7 条
```
> 原始 xlsx 行数:机组车台 35、车头工 75、挡车工 4543、值班长 13;其中挡车工 4341 行是 F9 里已软删除的历史/测试数据,故有效数据仅 202 行。
### 2.4 菜单
`DbSeeder.SeedProdMenus` 在生产-前缫下新增第 3 个子菜单「看台排班」,权限标识 `prod:ktpb:list`,admin 自动授权。
---
## 三、前端
| 文件 | 说明 |
|---|---|
| `views/prod/ktpb/index.vue` | 看台排班主页面(三页签 + 过滤 + 分页 + 三个弹窗) |
| `components/select/EmployeeSelect.vue` | 职工选择弹窗(单选/多选,支持按部门过滤与姓名/工号搜索) |
| `router/index.js` | 注册 `prod/ktpb/index` 路由组件 |
前端交互要点:
- 挡车工维护必须先在顶部选定「车间 + 机组」,弹窗内展示该机组车台范围;
- 弹窗顶部实时显示「已分配 x / y 台」,未满额时标签变黄,避免漏排;
- 起止车台用 `el-input-number` 限制在机组范围内,改动即刷新挡车数;
- 车头工/值班长新建时默认带出当前过滤的车间与班次。
---
## 四、验证记录
| 项 | 结果 |
|---|---|
| `dotnet build` | ✅ 0 错误 |
| `vite build` | ✅ 通过(仅既有体积/SignalR 注释警告) |
| 菜单 | ✅ 生产-前缫 → 落丝记录 / 车间班次 / 看台排班 |
| 车间下拉 | ✅ 前缫车间、前缫一~四车间 |
| 机组下拉(前缫一车间) | ✅ 机组1-6,车台 1-20 / 21-40 / … / 101-120 |
| 挡车工列表 | ✅ 202 条,姓名/车台/挡车数正确(3.5、3、3.5…) |
| 车头工列表 | ✅ 33 条 |
| 值班长列表 | ✅ 7 条 |
| 整组保存 + 挡车数重算 | ✅ 行1 1-10、行2 10-20 → 9.5 / 10.5(接壤车台各 0.5) |
| 超范围校验 | ✅ 车台 1-99 于机组1(1-20)返回 400「超出该机组车台范围 1-20」 |
| 测试数据清理 | ✅ 临时数据删除后组内 0 行 |
---
## 五、说明与后续
1. 职工姓名沿用 F9 档案原文(部分带「宁兴」等后缀,如「谢群生宁兴」),属于基础数据层面的既有情况,本次未改动。
2. 「机组车台」维护页面仍在 基础数据 下(`/base/jizuchetai`);F9 是放在生产-前缫组内。如需完全对齐,可把该菜单整体平移到生产-前缫(数据接口不变)。
3. 挡车工排班目前按「整组替换」保存,没有保留历史版本;若需要留痕,可增加排班生效日期 + 版本表。
4. 后续若要支持「按班组/按日期」排班(F9 另有班组维度),可在现有三张表上扩展 BanCi 组合键。