新增工资/仓储/生产日报等模块,移除旧考勤模块

- 新增 PayRoll(工资)、Wms(仓储)、Prod(车速/缫丝/考勤/丝片检测/丝片台账/纤检日报/质量日报) 模块
- 新增对应 Domain 实体、Application DTO/Service、Api Controller 与前端页面
- 移除旧 Attendance 考勤模块(Controller/Service/Entity/DTO 及 5 个前端页面),由 Prod/Kaoqin 取代
- 调整路由、仪表盘、Lsjl 流丝记录实体与服务
- 更新业务种子数据与 DbSeeder
- 补充工作进度文档 14-27
This commit is contained in:
yanpeng200212
2026-10-27 09:09:57 +08:00
parent 69c4052a64
commit 1f1b184411
119 changed files with 21576 additions and 1668 deletions
@@ -0,0 +1,159 @@
using F9WebAiTest.Application.Common;
using F9WebAiTest.Application.Dtos.Prod;
using F9WebAiTest.Domain.Common;
using F9WebAiTest.Domain.Entities.Prod;
namespace F9WebAiTest.Application.Services.Prod;
/// <summary>丝片台帐:每日一条,记录浸丝 / 返丝 / 编丝 / 整理片数</summary>
public interface ISptzService
{
Task<PageResult<SptzListItemDto>> GetPagedAsync(int pageIndex, int pageSize, DateTime dateFrom, DateTime dateTo);
Task<SptzSaveDto> GetForEditAsync(long id);
Task<SptzDefaultsDto> GetDefaultsAsync(DateTime date);
Task<long> SaveAsync(SptzSaveDto dto);
Task DeleteAsync(long id);
}
public class SptzService : ISptzService
{
private readonly IRepository<Sptz> _sptzRepo;
private readonly IRepository<Spjc> _spjcRepo;
public SptzService(IRepository<Sptz> sptzRepo, IRepository<Spjc> spjcRepo)
{
_sptzRepo = sptzRepo;
_spjcRepo = spjcRepo;
}
public async Task<PageResult<SptzListItemDto>> GetPagedAsync(int pageIndex, int pageSize, DateTime dateFrom, DateTime dateTo)
{
var all = await _sptzRepo.GetAllAsync();
var from = dateFrom.Date;
var to = dateTo.Date;
var q = all.AsQueryable().Where(x => x.Date.Date >= from && x.Date.Date <= to);
var total = q.LongCount();
var items = q.OrderBy(x => x.Date).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
return new PageResult<SptzListItemDto>
{
Items = items.Select(ToListDto).ToList(),
Total = total, PageIndex = pageIndex, PageSize = pageSize
};
}
public async Task<SptzSaveDto> GetForEditAsync(long id)
{
var e = await _sptzRepo.GetByIdAsync(id);
if (e == null) throw new ServiceException("丝片台帐不存在或已删除", 404);
return new SptzSaveDto
{
Id = e.Id,
Date = e.Date,
DateLast = e.DateLast,
JsShangcun = e.JsShangcun,
JsXiasi = e.JsXiasi,
JsJinsi = e.JsJinsi,
FsFsps = e.FsFsps,
BsBsps = e.BsBsps,
ZlZhengpin = e.ZlZhengpin,
ZlTichu = e.ZlTichu,
Memo = e.Memo
};
}
/// <summary>
/// 新增默认值:上一本台账日期 + 其上存(= 上一日今存),并按当日「丝片检查」汇总出整理正品/剔除片数。
/// </summary>
public async Task<SptzDefaultsDto> GetDefaultsAsync(DateTime date)
{
var target = date.Date;
var all = await _sptzRepo.GetAllAsync();
var latest = all.Where(x => x.Date.Date < target).OrderByDescending(x => x.Date).FirstOrDefault();
var latestAny = all.OrderByDescending(x => x.Date).FirstOrDefault();
var spjcs = (await _spjcRepo.GetAllAsync()).Where(x => x.Date.Date == target).ToList();
var tichu = spjcs.Sum(x => x.QsJiahua + x.QsYouwu + x.QsHeidian + x.QsShangsi
+ x.QsYetiao + x.QsXiaosipian + x.QsQita);
var zhengpin = spjcs.Sum(x => x.Pianshu + x.PianshuXuegong) - tichu;
return new SptzDefaultsDto
{
Date = target,
DateLast = latest?.Date,
JsShangcun = latest?.JsJincun ?? 0,
LatestDate = latestAny?.Date,
ZlTichu = tichu,
ZlZhengpin = zhengpin,
HasSpjc = spjcs.Count > 0
};
}
public async Task<long> SaveAsync(SptzSaveDto dto)
{
var date = dto.Date.Date;
Sptz e;
if (dto.Id > 0)
{
e = await _sptzRepo.GetByIdAsync(dto.Id);
if (e == null) throw new ServiceException("丝片台帐不存在或已删除", 404);
var dup = await _sptzRepo.FirstOrDefaultAsync(x => x.Id != dto.Id && x.Date.Date == date);
if (dup != null) throw new ServiceException($"已存在 {date:yyyy-MM-dd} 的丝片台帐!");
}
else
{
var exists = await _sptzRepo.AnyAsync(x => x.Date.Date == date);
if (exists) throw new ServiceException($"已存在 {date:yyyy-MM-dd} 的丝片台帐!");
e = new Sptz();
await _sptzRepo.AddAsync(e);
}
e.Date = date;
e.DateLast = dto.DateLast == default ? date.AddDays(-1) : dto.DateLast.Date;
e.JsShangcun = dto.JsShangcun;
e.JsXiasi = dto.JsXiasi;
e.JsJinsi = dto.JsJinsi;
e.FsFsps = dto.FsFsps;
e.BsBsps = dto.BsBsps;
e.ZlZhengpin = dto.ZlZhengpin;
e.ZlTichu = dto.ZlTichu;
e.Memo = dto.Memo ?? "";
// 派生值由服务端重算(与 F9 一致):上日遗留/今日新增 = 上存 − 浸丝;今存 = 下丝 + 上日遗留/今日新增
e.JsSrylJrxz = e.JsShangcun - e.JsJinsi;
e.JsJincun = e.JsXiasi + e.JsSrylJrxz;
await _sptzRepo.UpdateAsync(e);
return e.Id;
}
public async Task DeleteAsync(long id)
{
var e = await _sptzRepo.GetByIdAsync(id);
if (e == null) throw new ServiceException("丝片台帐不存在或已删除", 404);
// 日期带唯一索引,物理删除避免「删除后重建」撞索引(与煮茧日报同一策略)
await _sptzRepo.HardDeleteAsync(e);
}
private static SptzListItemDto ToListDto(Sptz x) => new()
{
Id = x.Id,
Date = x.Date,
DateLast = x.DateLast,
JsShangcun = x.JsShangcun,
JsXiasi = x.JsXiasi,
JsJinsi = x.JsJinsi,
JsSrylJrxz = x.JsSrylJrxz,
JsJincun = x.JsJincun,
FsFsps = x.FsFsps,
BsBsps = x.BsBsps,
ZlZhengpin = x.ZlZhengpin,
ZlTichu = x.ZlTichu,
Memo = x.Memo
};
}