From 56f00f45585be93ad86b05ddd173a7ea320d5bc8 Mon Sep 17 00:00:00 2001
From: haoliang <821644@qq.com>
Date: Wed, 13 May 2026 12:27:02 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=BA=A7=E9=87=8F=E6=8A=A5?=
=?UTF-8?q?=E8=A1=A8=E4=B8=89=E7=BB=B4=E5=BA=A6API=E7=AB=AF=E7=82=B9?=
=?UTF-8?q?=EF=BC=88=E6=9C=BA=E5=BA=8A/=E5=91=98=E5=B7=A5/=E7=A8=8B?=
=?UTF-8?q?=E5=BA=8F=E5=90=84=E5=90=ABsummary+list=EF=BC=89=EF=BC=8C?=
=?UTF-8?q?=E4=BB=8Ecnc=5Fproduction=5Fsegment=E5=AE=9E=E6=97=B6=E8=AE=A1?=
=?UTF-8?q?=E7=AE=97?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Production/MachineProductionListItem.cs | 26 ++
.../Production/ProgramProductionListItem.cs | 26 ++
.../Production/WorkerProductionListItem.cs | 26 ++
.../Impl/DailyProductionRepository.cs | 301 ++++++++++++++++++
.../Interface/IDailyProductionRepository.cs | 6 +
src/CncService/Impl/ProductionService.cs | 48 +++
.../Interface/IProductionService.cs | 18 ++
.../Controllers/ProductionController.cs | 72 +++++
8 files changed, 523 insertions(+)
create mode 100644 src/CncModels/Dto/Production/MachineProductionListItem.cs
create mode 100644 src/CncModels/Dto/Production/ProgramProductionListItem.cs
create mode 100644 src/CncModels/Dto/Production/WorkerProductionListItem.cs
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