diff --git a/src/CncModels/Dto/Production/MachineProductionListItem.cs b/src/CncModels/Dto/Production/MachineProductionListItem.cs new file mode 100644 index 0000000..7225c79 --- /dev/null +++ b/src/CncModels/Dto/Production/MachineProductionListItem.cs @@ -0,0 +1,26 @@ +namespace CncModels.Dto.Production +{ + /// + /// 机床产量明细列表项(机床维度排行) + /// + public class MachineProductionListItem + { + /// 排行名次 + public int Rank { get; set; } + + /// 机床名称 + public string MachineName { get; set; } + + /// 程序名 + public string ProgramName { get; set; } + + /// 总产量 + public int TotalQuantity { get; set; } + + /// 运行时长(小时) + public decimal? RunTime { get; set; } + + /// 日夜班标识 + public string DayStatus { get; set; } + } +} diff --git a/src/CncModels/Dto/Production/ProgramProductionListItem.cs b/src/CncModels/Dto/Production/ProgramProductionListItem.cs new file mode 100644 index 0000000..b5c4fd4 --- /dev/null +++ b/src/CncModels/Dto/Production/ProgramProductionListItem.cs @@ -0,0 +1,26 @@ +namespace CncModels.Dto.Production +{ + /// + /// 程序产量明细列表项(程序维度排行) + /// + public class ProgramProductionListItem + { + /// 排行名次 + public int Rank { get; set; } + + /// 程序名 + public string ProgramName { get; set; } + + /// 使用机床数 + public int MachineCount { get; set; } + + /// 总产量 + public int TotalQuantity { get; set; } + + /// 平均单机产量 + public decimal AvgPerMachine { get; set; } + + /// 产量占比(百分比) + public decimal Percentage { get; set; } + } +} diff --git a/src/CncModels/Dto/Production/WorkerProductionListItem.cs b/src/CncModels/Dto/Production/WorkerProductionListItem.cs new file mode 100644 index 0000000..a0dc5e9 --- /dev/null +++ b/src/CncModels/Dto/Production/WorkerProductionListItem.cs @@ -0,0 +1,26 @@ +namespace CncModels.Dto.Production +{ + /// + /// 员工产量明细列表项(员工维度排行) + /// + public class WorkerProductionListItem + { + /// 排行名次 + public int Rank { get; set; } + + /// 员工姓名 + public string WorkerName { get; set; } + + /// 操作机床数 + public int MachineCount { get; set; } + + /// 程序数量 + public int ProgramCount { get; set; } + + /// 总产量 + public int TotalQuantity { get; set; } + + /// 产量占比(百分比) + public decimal Percentage { get; set; } + } +} diff --git a/src/CncRepository/Impl/DailyProductionRepository.cs b/src/CncRepository/Impl/DailyProductionRepository.cs index eef14b0..8b0be80 100644 --- a/src/CncRepository/Impl/DailyProductionRepository.cs +++ b/src/CncRepository/Impl/DailyProductionRepository.cs @@ -198,5 +198,306 @@ namespace CncRepository.Impl return conn.Query(sql, new { Start = startDate, End = endDate, Top = top }).ToList(); } } + + #region 三维度产量报表 + + /// + /// 机床维度统计卡片(从cnc_production_segment实时计算) + /// + public MachineProductionSummaryResponse GetMachineSummary(DateTime startDate, DateTime endDate, int? workshopId) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT COALESCE(SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END), 0) AS TotalQuantity, + COUNT(DISTINCT seg.machine_id) AS RunningMachineCount + FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + WHERE seg.production_date BETWEEN @Start AND @End"; + + var parameters = new DynamicParameters(); + parameters.Add("Start", startDate); + parameters.Add("End", endDate); + + if (workshopId.HasValue) + { + sql += " AND m.workshop_id = @WorkshopId"; + parameters.Add("WorkshopId", workshopId.Value); + } + + var result = conn.QuerySingleOrDefault(sql, parameters); + if (result == null) + { + return new MachineProductionSummaryResponse(); + } + + // 计算平均单机产量 + if (result.RunningMachineCount > 0) + { + result.AvgPerMachine = Math.Round((decimal)result.TotalQuantity / result.RunningMachineCount, 1); + } + + // 查询最高单产机床名称 + string topSql = @"SELECT m.name FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + WHERE seg.production_date BETWEEN @Start AND @End"; + if (workshopId.HasValue) + { + topSql += " AND m.workshop_id = @WorkshopId"; + } + topSql += @" GROUP BY seg.machine_id + ORDER BY SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END) DESC LIMIT 1"; + result.TopMachineName = conn.ExecuteScalar(topSql, parameters) ?? ""; + + return result; + } + } + + /// + /// 机床维度明细列表(按机床+程序聚合,产量降序) + /// + public List GetMachineList(DateTime startDate, DateTime endDate, int? workshopId, int? machineId) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT m.name AS MachineName, seg.program_name AS ProgramName, + SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END) AS TotalQuantity, + cr_runtime.run_hours AS RunTime + FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + LEFT JOIN ( + SELECT cr.machine_id, DATE(cr.collect_time) AS d, + COALESCE(ROUND(SUM(max_min.delta)/3600,1), 0) AS run_hours + FROM cnc_collect_record cr + JOIN ( + SELECT machine_id, DATE(collect_time) AS dd, MAX(cutting_time)-MIN(cutting_time) AS delta + FROM cnc_collect_record GROUP BY machine_id, DATE(collect_time) + ) max_min ON cr.machine_id = max_min.machine_id AND DATE(cr.collect_time) = max_min.dd + GROUP BY cr.machine_id, DATE(cr.collect_time) + ) cr_runtime ON cr_runtime.machine_id = seg.machine_id AND cr_runtime.d = seg.production_date + WHERE seg.production_date BETWEEN @Start AND @End"; + + var parameters = new DynamicParameters(); + parameters.Add("Start", startDate); + parameters.Add("End", endDate); + + if (workshopId.HasValue) + { + sql += " AND m.workshop_id = @WorkshopId"; + parameters.Add("WorkshopId", workshopId.Value); + } + if (machineId.HasValue) + { + sql += " AND seg.machine_id = @MachineId"; + parameters.Add("MachineId", machineId.Value); + } + + sql += " GROUP BY seg.machine_id, seg.program_name, m.name, cr_runtime.run_hours ORDER BY TotalQuantity DESC"; + + var items = conn.Query(sql, parameters).ToList(); + + // 计算排行和日夜班标识 + for (int i = 0; i < items.Count; i++) + { + items[i].Rank = i + 1; + items[i].DayStatus = items[i].DayStatus ?? ""; + } + + return items; + } + } + + /// + /// 员工维度统计卡片(通过cnc_worker_machine关联产量分段表) + /// + public WorkerProductionSummaryResponse GetWorkerSummary(DateTime startDate, DateTime endDate) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT COALESCE(SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END), 0) AS TotalQuantity, + COUNT(DISTINCT w.id) AS ActiveWorkerCount + FROM cnc_production_segment seg + JOIN cnc_worker_machine wm ON seg.machine_id = wm.machine_id + JOIN cnc_worker w ON wm.worker_id = w.id + WHERE seg.production_date BETWEEN @Start AND @End"; + + var result = conn.QuerySingleOrDefault(sql, new { Start = startDate, End = endDate }); + if (result == null) + { + return new WorkerProductionSummaryResponse(); + } + + // 计算人均产量 + if (result.ActiveWorkerCount > 0) + { + result.AvgPerWorker = Math.Round((decimal)result.TotalQuantity / result.ActiveWorkerCount, 1); + } + + // 查询最高产量员工名称 + string topSql = @"SELECT w.name FROM cnc_production_segment seg + JOIN cnc_worker_machine wm ON seg.machine_id = wm.machine_id + JOIN cnc_worker w ON wm.worker_id = w.id + WHERE seg.production_date BETWEEN @Start AND @End + GROUP BY w.id, w.name + ORDER BY SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END) DESC LIMIT 1"; + result.TopWorkerName = conn.ExecuteScalar(topSql, new { Start = startDate, End = endDate }) ?? ""; + + return result; + } + } + + /// + /// 员工维度明细列表(通过cnc_worker_machine关联,产量降序) + /// + public List GetWorkerList(DateTime startDate, DateTime endDate, int? workerId) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT w.name AS WorkerName, + COUNT(DISTINCT wm.machine_id) AS MachineCount, + COUNT(DISTINCT seg.program_name) AS ProgramCount, + COALESCE(SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END), 0) AS TotalQuantity + FROM cnc_worker w + JOIN cnc_worker_machine wm ON wm.worker_id = w.id + LEFT JOIN cnc_production_segment seg ON seg.machine_id = wm.machine_id + AND seg.production_date BETWEEN @Start AND @End"; + + var parameters = new DynamicParameters(); + parameters.Add("Start", startDate); + parameters.Add("End", endDate); + + if (workerId.HasValue) + { + sql += " AND w.id = @WorkerId"; + parameters.Add("WorkerId", workerId.Value); + } + + sql += " GROUP BY w.id, w.name ORDER BY TotalQuantity DESC"; + + var items = conn.Query(sql, parameters).ToList(); + if (items.Count == 0) return items; + + // 计算总量用于百分比 + int grandTotal = items.Sum(x => x.TotalQuantity); + + for (int i = 0; i < items.Count; i++) + { + items[i].Rank = i + 1; + if (grandTotal > 0) + { + items[i].Percentage = Math.Round((decimal)items[i].TotalQuantity / grandTotal * 100, 1); + } + } + + return items; + } + } + + /// + /// 程序维度统计卡片(按program_name聚合) + /// + public ProgramProductionSummaryResponse GetProgramSummary(DateTime startDate, DateTime endDate, int? workshopId) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT COALESCE(SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END), 0) AS TotalQuantity, + COUNT(DISTINCT seg.program_name) AS RunningProgramCount + FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + WHERE seg.production_date BETWEEN @Start AND @End"; + + var parameters = new DynamicParameters(); + parameters.Add("Start", startDate); + parameters.Add("End", endDate); + + if (workshopId.HasValue) + { + sql += " AND m.workshop_id = @WorkshopId"; + parameters.Add("WorkshopId", workshopId.Value); + } + + var result = conn.QuerySingleOrDefault(sql, parameters); + if (result == null) + { + return new ProgramProductionSummaryResponse(); + } + + // 计算平均单程序产量 + if (result.RunningProgramCount > 0) + { + result.AvgPerProgram = Math.Round((decimal)result.TotalQuantity / result.RunningProgramCount, 1); + } + + // 查询最高产量程序名称 + string topSql = @"SELECT seg.program_name FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + WHERE seg.production_date BETWEEN @Start AND @End"; + if (workshopId.HasValue) + { + topSql += " AND m.workshop_id = @WorkshopId"; + } + topSql += @" GROUP BY seg.program_name + ORDER BY SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END) DESC LIMIT 1"; + result.TopProgramName = conn.ExecuteScalar(topSql, parameters) ?? ""; + + return result; + } + } + + /// + /// 程序维度明细列表(按program_name聚合,产量降序) + /// + public List GetProgramList(DateTime startDate, DateTime endDate, string programName) + { + using (var conn = CreateConnection()) + { + string sql = @"SELECT seg.program_name AS ProgramName, + COUNT(DISTINCT seg.machine_id) AS MachineCount, + COALESCE(SUM(CASE WHEN seg.is_settled=1 THEN seg.quantity + ELSE COALESCE(seg.end_part_count, seg.start_part_count) - seg.start_part_count END), 0) AS TotalQuantity + FROM cnc_production_segment seg + LEFT JOIN cnc_machine m ON seg.machine_id = m.id + WHERE seg.production_date BETWEEN @Start AND @End"; + + var parameters = new DynamicParameters(); + parameters.Add("Start", startDate); + parameters.Add("End", endDate); + + if (!string.IsNullOrWhiteSpace(programName)) + { + sql += " AND seg.program_name = @ProgramName"; + parameters.Add("ProgramName", programName); + } + + sql += " GROUP BY seg.program_name ORDER BY TotalQuantity DESC"; + + var items = conn.Query(sql, parameters).ToList(); + if (items.Count == 0) return items; + + // 计算总量用于百分比 + int grandTotal = items.Sum(x => x.TotalQuantity); + + for (int i = 0; i < items.Count; i++) + { + items[i].Rank = i + 1; + if (items[i].MachineCount > 0) + { + items[i].AvgPerMachine = Math.Round((decimal)items[i].TotalQuantity / items[i].MachineCount, 1); + } + if (grandTotal > 0) + { + items[i].Percentage = Math.Round((decimal)items[i].TotalQuantity / grandTotal * 100, 1); + } + } + + return items; + } + } + + #endregion } } diff --git a/src/CncRepository/Interface/IDailyProductionRepository.cs b/src/CncRepository/Interface/IDailyProductionRepository.cs index ea5486d..1480d5c 100644 --- a/src/CncRepository/Interface/IDailyProductionRepository.cs +++ b/src/CncRepository/Interface/IDailyProductionRepository.cs @@ -19,5 +19,11 @@ namespace CncRepository.Interface decimal GetTotalByWorkerAndDateRange(int workerId, DateTime startDate, DateTime endDate); List GetMachineRankByDateRange(DateTime startDate, DateTime endDate, int top); List GetWorkerRankByDateRange(DateTime startDate, DateTime endDate, int top); + MachineProductionSummaryResponse GetMachineSummary(DateTime startDate, DateTime endDate, int? workshopId); + List GetMachineList(DateTime startDate, DateTime endDate, int? workshopId, int? machineId); + WorkerProductionSummaryResponse GetWorkerSummary(DateTime startDate, DateTime endDate); + List GetWorkerList(DateTime startDate, DateTime endDate, int? workerId); + ProgramProductionSummaryResponse GetProgramSummary(DateTime startDate, DateTime endDate, int? workshopId); + List GetProgramList(DateTime startDate, DateTime endDate, string programName); } } diff --git a/src/CncService/Impl/ProductionService.cs b/src/CncService/Impl/ProductionService.cs index ff7dab5..b1261e1 100644 --- a/src/CncService/Impl/ProductionService.cs +++ b/src/CncService/Impl/ProductionService.cs @@ -104,5 +104,53 @@ namespace CncService.Impl } return result; } + + /// + public MachineProductionSummaryResponse GetMachineSummary(DateTime? startDate, DateTime? endDate, int? workshopId) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetMachineSummary(s, e, workshopId); + } + + /// + public List GetMachineList(DateTime? startDate, DateTime? endDate, int? workshopId, int? machineId) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetMachineList(s, e, workshopId, machineId); + } + + /// + public WorkerProductionSummaryResponse GetWorkerSummary(DateTime? startDate, DateTime? endDate) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetWorkerSummary(s, e); + } + + /// + public List GetWorkerList(DateTime? startDate, DateTime? endDate, int? workerId) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetWorkerList(s, e, workerId); + } + + /// + public ProgramProductionSummaryResponse GetProgramSummary(DateTime? startDate, DateTime? endDate, int? workshopId) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetProgramSummary(s, e, workshopId); + } + + /// + public List GetProgramList(DateTime? startDate, DateTime? endDate, string programName = null) + { + var s = startDate ?? DateTime.Today; + var e = endDate ?? DateTime.Today; + return _dailyProductionRepository.GetProgramList(s, e, programName); + } } } diff --git a/src/CncService/Interface/IProductionService.cs b/src/CncService/Interface/IProductionService.cs index 40d5e18..b61d85e 100644 --- a/src/CncService/Interface/IProductionService.cs +++ b/src/CncService/Interface/IProductionService.cs @@ -26,5 +26,23 @@ namespace CncService.Interface /// 获取某条产量记录的修正历史 /// List GetAdjustmentHistory(int recordId); + + /// 获取设备产量汇总(按日期范围) + MachineProductionSummaryResponse GetMachineSummary(DateTime? startDate, DateTime? endDate, int? workshopId); + + /// 获取设备产量明细列表(按日期范围) + List GetMachineList(DateTime? startDate, DateTime? endDate, int? workshopId, int? machineId); + + /// 获取员工产量汇总(按日期范围) + WorkerProductionSummaryResponse GetWorkerSummary(DateTime? startDate, DateTime? endDate); + + /// 获取员工产量明细列表(按日期范围) + List GetWorkerList(DateTime? startDate, DateTime? endDate, int? workerId); + + /// 获取程序产量汇总(按日期范围) + ProgramProductionSummaryResponse GetProgramSummary(DateTime? startDate, DateTime? endDate, int? workshopId); + + /// 获取程序产量明细列表(按日期范围) + List GetProgramList(DateTime? startDate, DateTime? endDate, string programName); } } diff --git a/src/CncWebApi/Controllers/ProductionController.cs b/src/CncWebApi/Controllers/ProductionController.cs index fbeee1c..7577954 100644 --- a/src/CncWebApi/Controllers/ProductionController.cs +++ b/src/CncWebApi/Controllers/ProductionController.cs @@ -84,5 +84,77 @@ namespace CncWebApi.Controllers // 导出功能暂不实现,返回提示 return Ok(ApiResponse.Fail(40001, "导出功能尚未实现")); } + + /// + /// 机床维度统计卡片 + /// GET /api/admin/production/machine/summary + /// + [HttpGet] + [Route("machine/summary")] + public IHttpActionResult GetMachineSummary(DateTime? startDate = null, DateTime? endDate = null, int? workshopId = null) + { + var result = _productionService.GetMachineSummary(startDate, endDate, workshopId); + return Ok(ApiResponse.Success(result)); + } + + /// + /// 机床维度明细列表 + /// GET /api/admin/production/machine/list + /// + [HttpGet] + [Route("machine/list")] + public IHttpActionResult GetMachineList(DateTime? startDate = null, DateTime? endDate = null, int? workshopId = null, int? machineId = null) + { + var result = _productionService.GetMachineList(startDate, endDate, workshopId, machineId); + return Ok(ApiResponse.Success(new { items = result })); + } + + /// + /// 员工维度统计卡片 + /// GET /api/admin/production/worker/summary + /// + [HttpGet] + [Route("worker/summary")] + public IHttpActionResult GetWorkerSummary(DateTime? startDate = null, DateTime? endDate = null) + { + var result = _productionService.GetWorkerSummary(startDate, endDate); + return Ok(ApiResponse.Success(result)); + } + + /// + /// 员工维度明细列表 + /// GET /api/admin/production/worker/list + /// + [HttpGet] + [Route("worker/list")] + public IHttpActionResult GetWorkerList(DateTime? startDate = null, DateTime? endDate = null, int? workerId = null) + { + var result = _productionService.GetWorkerList(startDate, endDate, workerId); + return Ok(ApiResponse.Success(new { items = result })); + } + + /// + /// 程序维度统计卡片 + /// GET /api/admin/production/program/summary + /// + [HttpGet] + [Route("program/summary")] + public IHttpActionResult GetProgramSummary(DateTime? startDate = null, DateTime? endDate = null, int? workshopId = null) + { + var result = _productionService.GetProgramSummary(startDate, endDate, workshopId); + return Ok(ApiResponse.Success(result)); + } + + /// + /// 程序维度明细列表 + /// GET /api/admin/production/program/list + /// + [HttpGet] + [Route("program/list")] + public IHttpActionResult GetProgramList(DateTime? startDate = null, DateTime? endDate = null, string programName = null) + { + var result = _productionService.GetProgramList(startDate, endDate, programName); + return Ok(ApiResponse.Success(new { items = result })); + } } }