新增API端点 GET /api/admin/machine/{id}/latest-tags:从log_collect_raw.raw_json解析最新采集数据,提取6个Tag各带独立采集时间返回;补全三维度产量报表接口定义和实现

main
haoliang 1 month ago
parent 56f00f4558
commit 287281e7b3

@ -30,94 +30,48 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
// 混合查询已汇总日期用daily_production未汇总日期从segment实时计算
string baseSql = @"
SELECT dp.id, dp.machine_id AS MachineId, m.name AS MachineName, dp.production_date AS ProductionDate,
dp.program_name AS ProgramName, dp.total_quantity AS TotalQuantity, dp.segment_count AS SegmentCount,
dp.total_run_time AS TotalRunTime, dp.total_cutting_time AS TotalCuttingTime, dp.total_cycle_time AS TotalCycleTime
FROM cnc_daily_production dp
LEFT JOIN cnc_machine m ON dp.machine_id = m.id
WHERE 1=1";
string realtimeSql = @"
SELECT 0 AS Id, seg.machine_id AS MachineId, m.name AS MachineName, seg.production_date AS ProductionDate,
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,
COUNT(*) AS SegmentCount,
cr_runtime.run_hours AS TotalRunTime,
cr_runtime.cut_hours AS TotalCuttingTime,
NULL AS TotalCycleTime
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,
COALESCE(ROUND(SUM(max_min.delta)/3600,1), 0) AS cut_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 NOT EXISTS (
SELECT 1 FROM cnc_daily_production dp
WHERE dp.machine_id = seg.machine_id AND dp.production_date = seg.production_date
)";
var parameters = new DynamicParameters();
// 日期过滤
if (query?.StartDate.HasValue == true)
{
baseSql += " AND dp.production_date >= @StartDate";
realtimeSql += " AND seg.production_date >= @StartDate";
parameters.Add("StartDate", query.StartDate);
}
if (query?.EndDate.HasValue == true)
{
baseSql += " AND dp.production_date <= @EndDate";
realtimeSql += " AND seg.production_date <= @EndDate";
parameters.Add("EndDate", query.EndDate);
}
// 兼容旧的单日期查询
if (query?.Date.HasValue == true && query.StartDate == null)
{
baseSql += " AND dp.production_date = @Date";
realtimeSql += " AND seg.production_date = @Date";
parameters.Add("Date", query.Date);
}
// 车间过滤
string baseSql = @"SELECT dp.machine_id AS MachineId, m.name AS MachineName,
dp.program_name AS ProgramName, dp.production_date AS ProductionDate,
CAST(dp.total_quantity AS SIGNED) AS Quantity,
dp.segment_count AS SegmentCount,
dp.total_run_time AS TotalRunTime, dp.total_cutting_time AS TotalCuttingTime
FROM cnc_daily_production dp
JOIN cnc_machine m ON dp.machine_id = m.id
WHERE dp.total_quantity > 0";
string realtimeSql = @"SELECT seg.machine_id AS MachineId, m.name AS MachineName,
seg.program_name AS ProgramName, seg.production_date AS ProductionDate,
CAST(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 SIGNED) AS Quantity,
COUNT(*) AS SegmentCount, 0 AS TotalRunTime, 0 AS TotalCuttingTime
FROM cnc_production_segment seg
JOIN cnc_machine m ON seg.machine_id = m.id
WHERE 1=1";
if (query?.WorkshopId.HasValue == true)
{
baseSql += " AND m.workshop_id = @WorkshopId";
realtimeSql += " AND m.workshop_id = @WorkshopId";
parameters.Add("WorkshopId", query.WorkshopId);
}
// 机床过滤
if (query?.MachineId.HasValue == true)
{
baseSql += " AND dp.machine_id = @MachineId";
realtimeSql += " AND seg.machine_id = @MachineId";
parameters.Add("MachineId", query.MachineId);
}
// 工人过滤通过worker_machine关联表
if (query?.WorkerId.HasValue == true)
{
baseSql += " AND EXISTS (SELECT 1 FROM cnc_worker_machine wm WHERE wm.machine_id = dp.machine_id AND wm.worker_id = @WorkerId)";
realtimeSql += " AND EXISTS (SELECT 1 FROM cnc_worker_machine wm WHERE wm.machine_id = seg.machine_id AND wm.worker_id = @WorkerId)";
parameters.Add("WorkerId", query.WorkerId);
}
realtimeSql += " GROUP BY seg.machine_id, seg.production_date, seg.program_name, m.name";
string unionSql = $"{baseSql} UNION ALL {realtimeSql}";
string countSql = $"SELECT COUNT(*) FROM ({unionSql}) AS t";
int offset = (query.Page - 1) * query.PageSize;
string paging = $" ORDER BY ProductionDate DESC, MachineName LIMIT @Limit OFFSET @Offset";
parameters.Add("Limit", query.PageSize);
parameters.Add("Offset", offset);
var items = conn.Query<DailyProductionListItem>(unionSql + paging, parameters).ToList();
int total = conn.ExecuteScalar<int>(countSql, parameters);
return new PagedResult<DailyProductionListItem>
@ -143,7 +97,10 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
string sql = @"SELECT dp.* FROM cnc_daily_production dp LEFT JOIN cnc_machine m ON dp.machine_id = m.id WHERE dp.production_date BETWEEN @Start AND @End ORDER BY dp.production_date DESC";
string sql = @"SELECT dp.* FROM cnc_daily_production dp
LEFT JOIN cnc_machine m ON dp.machine_id = m.id
WHERE dp.production_date BETWEEN @Start AND @End
ORDER BY dp.production_date DESC";
return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate }).ToList();
}
}
@ -152,7 +109,9 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
string sql = @"SELECT SUM(dp.total_quantity) FROM cnc_daily_production dp LEFT JOIN cnc_machine m ON dp.machine_id = m.id WHERE dp.production_date BETWEEN @Start AND @End";
string sql = @"SELECT SUM(dp.total_quantity) FROM cnc_daily_production dp
LEFT JOIN cnc_machine m ON dp.machine_id = m.id
WHERE dp.production_date BETWEEN @Start AND @End";
if (workshopId.HasValue)
{
sql += " AND m.workshop_id = @WorkshopId";
@ -166,7 +125,8 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
string sql = @"SELECT SUM(total_quantity) FROM cnc_daily_production WHERE production_date BETWEEN @Start AND @End";
string sql = @"SELECT SUM(total_quantity) FROM cnc_daily_production
WHERE production_date BETWEEN @Start AND @End";
var res = conn.ExecuteScalar<decimal?>(sql, new { Start = startDate, End = endDate });
return res ?? 0m;
}
@ -176,12 +136,15 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
string sql = @"SELECT m.id AS Id, m.id AS MachineId, m.name AS MachineName, SUM(dp.total_quantity) AS TotalQuantity, NULL AS ProgramName, NULL AS ProductionDate, NULL AS SegmentCount, NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
FROM cnc_daily_production dp
JOIN cnc_machine m ON dp.machine_id = m.id
WHERE dp.production_date BETWEEN @Start AND @End
GROUP BY m.id, m.name
ORDER BY SUM(dp.total_quantity) DESC LIMIT @Top";
string sql = @"SELECT m.id AS Id, m.id AS MachineId, m.name AS MachineName,
SUM(dp.total_quantity) AS TotalQuantity, NULL AS ProgramName,
NULL AS ProductionDate, NULL AS SegmentCount,
NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
FROM cnc_daily_production dp
JOIN cnc_machine m ON dp.machine_id = m.id
WHERE dp.production_date BETWEEN @Start AND @End
GROUP BY m.id, m.name
ORDER BY SUM(dp.total_quantity) DESC LIMIT @Top";
return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate, Top = top }).ToList();
}
}
@ -190,20 +153,20 @@ namespace CncRepository.Impl
{
using (var conn = CreateConnection())
{
string sql = @"SELECT 0 AS Id, NULL AS MachineId, NULL AS MachineName, SUM(total_quantity) AS TotalQuantity, NULL AS ProductionDate, NULL AS ProgramName, NULL AS SegmentCount, NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
FROM cnc_daily_production
WHERE production_date BETWEEN @Start AND @End
GROUP BY machine_id
ORDER BY SUM(total_quantity) DESC LIMIT @Top";
string sql = @"SELECT 0 AS Id, NULL AS MachineId, NULL AS MachineName,
SUM(total_quantity) AS TotalQuantity, NULL AS ProductionDate,
NULL AS ProgramName, NULL AS SegmentCount,
NULL AS TotalRunTime, NULL AS TotalCuttingTime, NULL AS TotalCycleTime
FROM cnc_daily_production
WHERE production_date BETWEEN @Start AND @End
GROUP BY machine_id
ORDER BY SUM(total_quantity) DESC LIMIT @Top";
return conn.Query<DailyProduction>(sql, new { Start = startDate, End = endDate, Top = top }).ToList();
}
}
#region 三维度产量报表
/// <summary>
/// 机床维度统计卡片从cnc_production_segment实时计算
/// </summary>
public MachineProductionSummaryResponse GetMachineSummary(DateTime startDate, DateTime endDate, int? workshopId)
{
using (var conn = CreateConnection())
@ -214,48 +177,29 @@ namespace CncRepository.Impl
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<MachineProductionSummaryResponse>(sql, parameters);
if (result == null)
{
return new MachineProductionSummaryResponse();
}
// 计算平均单机产量
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";
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<string>(topSql, parameters) ?? "";
return result;
}
}
/// <summary>
/// 机床维度明细列表(按机床+程序聚合,产量降序)
/// </summary>
public List<MachineProductionListItem> GetMachineList(DateTime startDate, DateTime endDate, int? workshopId, int? machineId)
{
using (var conn = CreateConnection())
@ -268,49 +212,27 @@ namespace CncRepository.Impl
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
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
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);
}
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<MachineProductionListItem>(sql, parameters).ToList();
// 计算排行和日夜班标识
for (int i = 0; i < items.Count; i++)
{
items[i].Rank = i + 1;
items[i].DayStatus = items[i].DayStatus ?? "";
}
for (int i = 0; i < items.Count; i++) { items[i].Rank = i + 1; items[i].DayStatus = items[i].DayStatus ?? ""; }
return items;
}
}
/// <summary>
/// 员工维度统计卡片通过cnc_worker_machine关联产量分段表
/// </summary>
public WorkerProductionSummaryResponse GetWorkerSummary(DateTime startDate, DateTime endDate)
{
using (var conn = CreateConnection())
@ -322,35 +244,21 @@ namespace CncRepository.Impl
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<WorkerProductionSummaryResponse>(sql, new { Start = startDate, End = endDate });
if (result == null)
{
return new WorkerProductionSummaryResponse();
}
// 计算人均产量
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";
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<string>(topSql, new { Start = startDate, End = endDate }) ?? "";
return result;
}
}
/// <summary>
/// 员工维度明细列表通过cnc_worker_machine关联产量降序
/// </summary>
public List<WorkerProductionListItem> GetWorkerList(DateTime startDate, DateTime endDate, int? workerId)
{
using (var conn = CreateConnection())
@ -364,41 +272,25 @@ namespace CncRepository.Impl
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);
}
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<WorkerProductionListItem>(sql, parameters).ToList();
if (items.Count == 0) return items;
// 计算总量用于百分比
int grandTotal = items.Sum(x => x.TotalQuantity);
for (int i = 0; i < items.Count; i++)
if (items.Count > 0)
{
items[i].Rank = i + 1;
if (grandTotal > 0)
int grandTotal = items.Sum(x => x.TotalQuantity);
for (int i = 0; i < items.Count; i++)
{
items[i].Percentage = Math.Round((decimal)items[i].TotalQuantity / grandTotal * 100, 1);
items[i].Rank = i + 1;
if (grandTotal > 0) items[i].Percentage = Math.Round((decimal)items[i].TotalQuantity / grandTotal * 100, 1);
}
}
return items;
}
}
/// <summary>
/// 程序维度统计卡片按program_name聚合
/// </summary>
public ProgramProductionSummaryResponse GetProgramSummary(DateTime startDate, DateTime endDate, int? workshopId)
{
using (var conn = CreateConnection())
@ -409,48 +301,25 @@ namespace CncRepository.Impl
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);
}
if (workshopId.HasValue) { sql += " AND m.workshop_id = @WorkshopId"; parameters.Add("WorkshopId", workshopId.Value); }
var result = conn.QuerySingleOrDefault<ProgramProductionSummaryResponse>(sql, parameters);
if (result == null)
{
return new ProgramProductionSummaryResponse();
}
// 计算平均单程序产量
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";
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<string>(topSql, parameters) ?? "";
return result;
}
}
/// <summary>
/// 程序维度明细列表按program_name聚合产量降序
/// </summary>
public List<ProgramProductionListItem> GetProgramList(DateTime startDate, DateTime endDate, string programName)
{
using (var conn = CreateConnection())
@ -462,38 +331,22 @@ namespace CncRepository.Impl
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);
}
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<ProgramProductionListItem>(sql, parameters).ToList();
if (items.Count == 0) return items;
// 计算总量用于百分比
int grandTotal = items.Sum(x => x.TotalQuantity);
for (int i = 0; i < items.Count; i++)
if (items.Count > 0)
{
items[i].Rank = i + 1;
if (items[i].MachineCount > 0)
int grandTotal = items.Sum(x => x.TotalQuantity);
for (int i = 0; i < items.Count; i++)
{
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);
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;
}
}

@ -0,0 +1,106 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Dapper;
using MySqlConnector;
using Newtonsoft.Json.Linq;
using CncModels.Dto.Machine;
using CncRepository.Base;
using CncRepository.Interface;
namespace CncRepository.Impl
{
/// <summary>
/// 设备最新Tag数据仓储查询日志库 raw_json按 Tag ID 提取指标)
/// </summary>
public class MachineLatestTagRepository : LogRepository, IMachineLatestTagRepository
{
private readonly string _businessConn;
/// <summary>
/// 初始化,同时持有日志库和业务库连接字符串
/// </summary>
/// <param name="logConn">cnc_log 连接字符串</param>
/// <param name="businessConn">cnc_business 连接字符串</param>
public MachineLatestTagRepository(string logConn, string businessConn) : base(logConn)
{
_businessConn = businessConn;
}
/// <summary>
/// 获取指定设备的最新6个Tag及其采集时间
/// </summary>
/// <param name="machineId">设备ID</param>
/// <returns>6个Tag数据列表找不到时返回空列表</returns>
public List<MachineLatestTagItem> GetLatestTags(int machineId)
{
// 1. 从业务库获取设备的 device_code
string deviceCode;
using (var bconn = new MySqlConnection(_businessConn))
{
deviceCode = bconn.ExecuteScalar<string>(
"SELECT device_code FROM cnc_machine WHERE id = @Id",
new { Id = machineId });
}
if (string.IsNullOrEmpty(deviceCode))
return new List<MachineLatestTagItem>();
// 2. 从日志库获取最新一条成功的 raw_json
string rawJson;
using (var conn = CreateConnection())
{
rawJson = conn.ExecuteScalar<string>(
"SELECT raw_json FROM log_collect_raw WHERE is_success = 1 ORDER BY request_time DESC LIMIT 1");
}
if (string.IsNullOrEmpty(rawJson))
return new List<MachineLatestTagItem>();
// 3. 解析 JSON提取6个目标 Tag
var targetTags = new[] { "_io_status", "Tag5", "Tag8", "Tag1", "Tag9", "Tag26" };
var result = new List<MachineLatestTagItem>();
try
{
var devices = JArray.Parse(rawJson);
foreach (JObject d in devices.OfType<JObject>())
{
string dev = d?.Value<string>("device") ?? "";
// 模糊匹配raw_json 中的 device 可能是 device_code 的一部分(分隔符可能不同)
if (!deviceCode.Contains(dev) && !dev.Contains(deviceCode.Replace("_", "-")))
continue;
var tags = d?.Value<JArray>("tags");
if (tags == null)
continue;
foreach (JObject t in tags.OfType<JObject>())
{
string tagId = t?.Value<string>("id") ?? "";
if (!targetTags.Contains(tagId))
continue;
string timeStr = t?.Value<string>("time") ?? "";
DateTime? collectTime = null;
if (DateTime.TryParse(timeStr, out var ct))
collectTime = ct;
result.Add(new MachineLatestTagItem
{
Id = tagId,
Desc = t?.Value<string>("desc") ?? "",
Value = t?.Value<string>("value") ?? "",
CollectTime = collectTime
});
}
break; // 找到匹配设备后退出
}
}
catch
{
// JSON 解析失败返回空列表
}
return result;
}
}
}

@ -0,0 +1,18 @@
using System.Collections.Generic;
using CncModels.Dto.Machine;
namespace CncRepository.Interface
{
/// <summary>
/// 设备最新Tag数据仓储接口查询日志库
/// </summary>
public interface IMachineLatestTagRepository
{
/// <summary>
/// 获取指定设备的最新6个Tag及其采集时间
/// </summary>
/// <param name="machineId">设备ID</param>
/// <returns>6个Tag数据列表</returns>
List<MachineLatestTagItem> GetLatestTags(int machineId);
}
}

@ -18,17 +18,23 @@ namespace CncService.Impl
private readonly ICollectAddressRepository _addressRepository;
private readonly IWorkerMachineRepository _workerMachineRepository;
private readonly IBrandRepository _brandRepository;
private readonly IMachineLatestTagRepository _latestTagRepository;
private readonly ICollectAnalysisRepository _collectAnalysisRepository;
public MachineService(
IMachineRepository machineRepository,
ICollectAddressRepository addressRepository,
IWorkerMachineRepository workerMachineRepository,
IBrandRepository brandRepository)
IBrandRepository brandRepository,
IMachineLatestTagRepository latestTagRepository,
ICollectAnalysisRepository collectAnalysisRepository)
{
_machineRepository = machineRepository ?? throw new ArgumentNullException(nameof(machineRepository));
_addressRepository = addressRepository ?? throw new ArgumentNullException(nameof(addressRepository));
_workerMachineRepository = workerMachineRepository ?? throw new ArgumentNullException(nameof(workerMachineRepository));
_brandRepository = brandRepository ?? throw new ArgumentNullException(nameof(brandRepository));
_latestTagRepository = latestTagRepository ?? throw new ArgumentNullException(nameof(latestTagRepository));
_collectAnalysisRepository = collectAnalysisRepository ?? throw new ArgumentNullException(nameof(collectAnalysisRepository));
}
/// <inheritdoc/>
@ -157,12 +163,19 @@ namespace CncService.Impl
}
/// <inheritdoc/>
public List<MachineCollectRecordItem> GetCollectRecords(int id)
public List<MachineCollectRecordItem> GetCollectRecords(int id, DateTime? date = null)
{
if (id <= 0) throw new BusinessException(ErrorCode.BadRequest, "无效的机床ID");
var machine = _machineRepository.GetById(id);
if (machine == null) throw new BusinessException(ErrorCode.NotFound, "机床未找到");
return _machineRepository.GetRecentCollectRecords(id);
var queryDate = date ?? DateTime.Today;
return _collectAnalysisRepository.GetRecordsByMachineAndDate(id, queryDate);
}
/// <inheritdoc/>
public List<MachineLatestTagItem> GetLatestTags(int machineId)
{
return _latestTagRepository.GetLatestTags(machineId);
}
}
}

@ -82,10 +82,18 @@ namespace CncService.Interface
List<MachineTrendItem> GetProductionTrend(int id);
/// <summary>
/// 获取机床近期采集记录
/// 获取机床采集记录从日志库log_collect_analysis查询支持日期筛选
/// </summary>
/// <param name="id">机床ID</param>
/// <param name="date">筛选日期,默认今天</param>
/// <returns>采集记录列表</returns>
List<MachineCollectRecordItem> GetCollectRecords(int id);
List<MachineCollectRecordItem> GetCollectRecords(int id, DateTime? date = null);
/// <summary>
/// 获取设备最新Tag数据6个指标各带独立采集时间
/// </summary>
/// <param name="machineId">设备ID</param>
/// <returns>6个Tag数据列表</returns>
List<MachineLatestTagItem> GetLatestTags(int machineId);
}
}

@ -1,3 +1,4 @@
using System;
using System.Web.Http;
using CncModels.Dto;
using CncModels.Dto.Machine;
@ -155,5 +156,17 @@ namespace CncWebApi.Controllers
var result = _machineService.GetCollectRecords(id);
return Ok(ApiResponse<object>.Success(new { items = result }));
}
/// <summary>
/// 获取设备最新Tag数据6个指标各带独立采集时间
/// GET /api/admin/machine/{id}/latest-tags
/// </summary>
[HttpGet]
[Route("{id:int}/latest-tags")]
public IHttpActionResult GetLatestTags(int id)
{
var result = _machineService.GetLatestTags(id);
return Ok(ApiResponse<object>.Success(new { items = result }));
}
}
}

@ -127,7 +127,9 @@ namespace CncWebApi.Infrastructure
new CncRepository.Impl.MachineRepository(_businessConn),
new CncRepository.Impl.CollectAddressRepository(_businessConn),
new CncRepository.Impl.WorkerMachineRepository(_businessConn),
new CncRepository.Impl.BrandRepository(_businessConn));
new CncRepository.Impl.BrandRepository(_businessConn),
new CncRepository.Impl.MachineLatestTagRepository(_logConn, _businessConn),
new CncRepository.Impl.Log.CollectAnalysisRepository(_logConn));
}
private IBrandService ResolveBrandService()

Loading…
Cancel
Save