using F9WebAiTest.Application.Common; using F9WebAiTest.Application.Dtos.Prod; using F9WebAiTest.Domain.Common; using F9WebAiTest.Domain.Entities.Base; using F9WebAiTest.Domain.Entities.Prod; using SysDept = F9WebAiTest.Domain.Entities.SYS.Departments; namespace F9WebAiTest.Application.Services.Prod; /// 秤大丝:以落丝记录为主表,按车台录入 4 个丝量值并汇总把数/丝量/缫折/台产 public interface ICdsService { Task> GetPagedAsync(int pageIndex, int pageSize, DateTime? date, long? deptId); Task GetEditAsync(long lsjlId); Task SaveAsync(CdsSaveDto dto); Task DeleteAsync(long lsjlId); } public class CdsService : ICdsService { private readonly IRepository _lsjlRepo; private readonly IRepository _cdsLsjlRepo; private readonly IRepository _cdsChetaiRepo; private readonly IRepository _deptRepo; private readonly IRepository _zkRepo; public CdsService( IRepository lsjlRepo, IRepository cdsLsjlRepo, IRepository cdsChetaiRepo, IRepository deptRepo, IRepository zkRepo) { _lsjlRepo = lsjlRepo; _cdsLsjlRepo = cdsLsjlRepo; _cdsChetaiRepo = cdsChetaiRepo; _deptRepo = deptRepo; _zkRepo = zkRepo; } public async Task> GetPagedAsync(int pageIndex, int pageSize, DateTime? date, long? deptId) { var lsjls = await _lsjlRepo.GetAllAsync(); var q = lsjls.AsQueryable(); if (date.HasValue) q = q.Where(x => x.WorkDate.Date == date.Value.Date); if (deptId.HasValue) q = q.Where(x => x.DeptId == deptId.Value); var depts = await _deptRepo.GetAllAsync(); var deptDict = depts.ToDictionary(d => d.Id, d => d.Name); var zks = await _zkRepo.GetAllAsync(); var zkDict = zks.ToDictionary(z => z.Id, z => z.ZhuangKouName); var sums = (await _cdsLsjlRepo.GetAllAsync()).ToDictionary(x => x.LsjlId); var total = q.LongCount(); var items = q.OrderByDescending(x => x.WorkDate).ThenBy(x => x.Jizu).ThenBy(x => x.Huishu) .Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); return new PageResult { Items = items.Select(x => { sums.TryGetValue(x.Id, out var sum); return new CdsListItemDto { LsjlId = x.Id, WorkDate = x.WorkDate, DeptId = x.DeptId, DeptName = deptDict.GetValueOrDefault(x.DeptId, ""), Jizu = x.Jizu, Huishu = x.Huishu, Guige = x.Guige, ZhuangKouName = zkDict.GetValueOrDefault(x.GyzkId, ""), Yanse = x.Yanse, Isbanche = x.Isbanche, IsbancheName = x.Isbanche ? "半车" : "整车", Chetaishu = x.Chetaishu, ChetaiStart = x.ChetaiStart, ChetaiEnd = x.ChetaiEnd, Hours = x.Hours, Tongshu = x.Tongshu, Meitongjianliang = x.Meitongjianliang, YingchengNum = YingchengNum(x), IsWeighed = sum != null, Num = sum?.Num ?? 0, Siliang = sum?.Siliang ?? 0, Jianliang = sum?.Jianliang ?? 0, Saozhe = sum?.Saozhe ?? 0, Taichan = sum?.Taichan ?? 0 }; }).ToList(), Total = total, PageIndex = pageIndex, PageSize = pageSize }; } public async Task GetEditAsync(long lsjlId) { var lsjl = await _lsjlRepo.GetByIdAsync(lsjlId); if (lsjl == null) throw new ServiceException("落丝记录不存在", 404); var dept = await _deptRepo.GetByIdAsync(lsjl.DeptId); var zk = await _zkRepo.GetByIdAsync(lsjl.GyzkId); var records = await _cdsChetaiRepo.FindAsync(x => x.LsjlId == lsjlId); List chetais; if (records.Count > 0) { chetais = records.OrderBy(r => r.Chetaihao).Select(ToDto).ToList(); } else { // 首次称重:按车台范围初始化空行 chetais = new List(); for (var i = lsjl.ChetaiStart; i <= lsjl.ChetaiEnd; i++) chetais.Add(new CdsChetaiDto { Chetaihao = i }); } return new CdsEditDto { LsjlId = lsjl.Id, DeptName = dept?.Name ?? "", Jizu = lsjl.Jizu, Huishu = lsjl.Huishu, ZhuangKouName = zk?.ZhuangKouName ?? "", Yanse = lsjl.Yanse, Isbanche = lsjl.Isbanche, IsbancheName = lsjl.Isbanche ? "半车" : "整车", Guige = lsjl.Guige, ChetaiStart = lsjl.ChetaiStart, ChetaiEnd = lsjl.ChetaiEnd, Chetaishu = lsjl.Chetaishu, YingchengNum = YingchengNum(lsjl), Chetais = chetais }; } public async Task SaveAsync(CdsSaveDto dto) { if (dto.LsjlId == 0) throw new ServiceException("落丝记录无效"); var lsjl = await _lsjlRepo.GetByIdAsync(dto.LsjlId); if (lsjl == null) throw new ServiceException("落丝记录不存在", 404); if (dto.Chetais == null || dto.Chetais.Count == 0) throw new ServiceException("请先录入丝量数据"); var invalid = dto.Chetais.Where(i => i.Chetaihao < lsjl.ChetaiStart || i.Chetaihao > lsjl.ChetaiEnd).ToList(); if (invalid.Count > 0) throw new ServiceException($"车台号超出范围 [{lsjl.ChetaiStart}-{lsjl.ChetaiEnd}]"); // 车台明细:个数 = 丝量 > 0 的个数;小计丝量 = 4 个丝量之和 var items = dto.Chetais.Select(i => { var t = new CdsChetaiDto { Chetaihao = i.Chetaihao, Sl1 = Math.Max(0, i.Sl1), Sl2 = Math.Max(0, i.Sl2), Sl3 = Math.Max(0, i.Sl3), Sl4 = Math.Max(0, i.Sl4) }; CalChetai(t); return t; }).OrderBy(i => i.Chetaihao).ToList(); var num = items.Sum(x => x.Num); if (num == 0) throw new ServiceException("请至少录入一个丝量值"); // 车台明细先删后建 var olds = await _cdsChetaiRepo.FindAsync(x => x.LsjlId == dto.LsjlId); if (olds.Count > 0) await _cdsChetaiRepo.HardDeleteRangeAsync(olds); foreach (var t in items) { await _cdsChetaiRepo.AddAsync(new CdsChetai { LsjlId = dto.LsjlId, Chetaihao = t.Chetaihao, Sl1 = t.Sl1, Sl2 = t.Sl2, Sl3 = t.Sl3, Sl4 = t.Sl4, Num = t.Num, Siliang = t.Siliang }); } var siliang = items.Sum(x => x.Siliang); // 汇总:茧量 / 缫折 / 实绩台产 var cdsLsjl = await _cdsLsjlRepo.FirstOrDefaultAsync(x => x.LsjlId == dto.LsjlId); if (cdsLsjl == null) { cdsLsjl = new CdsLsjl { LsjlId = dto.LsjlId }; await _cdsLsjlRepo.AddAsync(cdsLsjl); } cdsLsjl.Num = num; cdsLsjl.Siliang = siliang; CalZhibiao(cdsLsjl, lsjl); await _cdsLsjlRepo.UpdateAsync(cdsLsjl); } /// 清除称重数据(汇总 + 车台明细物理删除,便于重新称重) public async Task DeleteAsync(long lsjlId) { if (lsjlId == 0) throw new ServiceException("落丝记录无效"); var chetais = await _cdsChetaiRepo.FindAsync(x => x.LsjlId == lsjlId); if (chetais.Count > 0) await _cdsChetaiRepo.HardDeleteRangeAsync(chetais); var lsjlSum = await _cdsLsjlRepo.FirstOrDefaultAsync(x => x.LsjlId == lsjlId); if (lsjlSum != null) await _cdsLsjlRepo.HardDeleteAsync(lsjlSum); } // ==================== 计算口径(对齐 F9 Cds_Lsjl_CalZhibiaoCommand) ==================== /// 应秤数 = 车台数 × 4 ×(半车 0.5 / 整车 1) private static int YingchengNum(LsjlRecord lsjl) => (int)Math.Round(lsjl.Chetaishu * 4 * (lsjl.Isbanche ? 0.5 : 1), MidpointRounding.AwayFromZero); private static void CalChetai(CdsChetaiDto item) { item.Num = (item.Sl1 > 0 ? 1 : 0) + (item.Sl2 > 0 ? 1 : 0) + (item.Sl3 > 0 ? 1 : 0) + (item.Sl4 > 0 ? 1 : 0); item.Siliang = item.Sl1 + item.Sl2 + item.Sl3 + item.Sl4; } /// /// 茧量 = 落丝桶数 × 每桶茧量;缫折 = 茧量 / 丝量 × 100;实绩台产 = 丝量 / 落丝时长 / 车台数。 /// F9 口径:缫折 ≤ 100 视为异常数据,不落指标。 /// private static void CalZhibiao(CdsLsjl target, LsjlRecord lsjl) { if (lsjl.Meitongjianliang == 0 || lsjl.Tongshu == 0) { target.Jianliang = 0; target.Saozhe = 0; target.Taichan = 0; return; } if (target.Num <= 0 || target.Siliang <= 0 || lsjl.Hours <= 0 || lsjl.Chetaishu <= 0) { target.Jianliang = 0; target.Saozhe = 0; target.Taichan = 0; return; } var jianliang = lsjl.Tongshu * lsjl.Meitongjianliang; var saozhe = Math.Round((decimal)jianliang / target.Siliang * 100, 2, MidpointRounding.AwayFromZero); var taichan = Math.Round((decimal)target.Siliang / (decimal)lsjl.Hours / lsjl.Chetaishu, 2, MidpointRounding.AwayFromZero); if (saozhe > 100) { target.Jianliang = jianliang; target.Saozhe = saozhe; target.Taichan = taichan; } else { target.Jianliang = jianliang; target.Saozhe = 0; target.Taichan = 0; } } private static CdsChetaiDto ToDto(CdsChetai r) => new() { Chetaihao = r.Chetaihao, Sl1 = r.Sl1, Sl2 = r.Sl2, Sl3 = r.Sl3, Sl4 = r.Sl4, Num = r.Num, Siliang = r.Siliang }; }