|
|
|
|
@ -1,17 +1,14 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Concurrent;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using Dapper;
|
|
|
|
|
using MySqlConnector;
|
|
|
|
|
using CncModels.Entity;
|
|
|
|
|
using CncModels.Enum;
|
|
|
|
|
using log4net;
|
|
|
|
|
|
|
|
|
|
namespace CncCollector.Core
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 零件产量分段跟踪引擎。
|
|
|
|
|
/// 为每台机床维护内存中的当前活跃段状态,检测程序切换和手动清零。
|
|
|
|
|
/// 零件产量跟踪引擎。
|
|
|
|
|
/// 基于数据库 cnc_daily_production 表对比加工零件总数(Tag1)计算当日产量。
|
|
|
|
|
/// 记录不可变:每条记录创建后仅 end_total_count 可更新。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class ProductionTracker : IDisposable
|
|
|
|
|
{
|
|
|
|
|
@ -19,16 +16,6 @@ namespace CncCollector.Core
|
|
|
|
|
private readonly string _connectionString;
|
|
|
|
|
private readonly object _lock = new object();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 内存缓存:machineId → 当前活跃段ID(减少DB查询)
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly ConcurrentDictionary<int, long> _activeSegmentIds = new ConcurrentDictionary<int, long>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 内存缓存:machineId → 上一次采集的 (programName, partCount)
|
|
|
|
|
/// </summary>
|
|
|
|
|
private readonly ConcurrentDictionary<int, Tuple<string, decimal?>> _lastCollectState = new ConcurrentDictionary<int, Tuple<string, decimal?>>();
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化产量跟踪器
|
|
|
|
|
/// </summary>
|
|
|
|
|
@ -39,241 +26,213 @@ namespace CncCollector.Core
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 处理一次采集结果:检测程序切换/手动清零,管理活跃段
|
|
|
|
|
/// 处理一次采集结果:基于数据库最新记录对比加工零件总数,计算当日产量。
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="machineId">机床ID</param>
|
|
|
|
|
/// <param name="programName">当前NC程序名</param>
|
|
|
|
|
/// <param name="partCount">当前零件数</param>
|
|
|
|
|
/// <param name="totalPartCount">加工零件总数(Tag1)</param>
|
|
|
|
|
/// <param name="collectTime">采集时间</param>
|
|
|
|
|
public void Track(int machineId, string programName, decimal? partCount, DateTime collectTime)
|
|
|
|
|
/// <returns>
|
|
|
|
|
/// logText:描述本次处理结果的文本
|
|
|
|
|
/// changed:数据库是否发生了变更
|
|
|
|
|
/// todayTotal:当前机床当日总产量 = SUM(end_total_count - base_total_count)
|
|
|
|
|
/// </returns>
|
|
|
|
|
public (string logText, bool changed, decimal todayTotal) Track(
|
|
|
|
|
int machineId, string programName, decimal? totalPartCount, DateTime collectTime)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(programName)) return;
|
|
|
|
|
// 前置校验:程序名为空 或 零件总数为空 → 跳过
|
|
|
|
|
if (string.IsNullOrEmpty(programName) || !totalPartCount.HasValue)
|
|
|
|
|
{
|
|
|
|
|
var skipReason = string.IsNullOrEmpty(programName)
|
|
|
|
|
? "程序名为空"
|
|
|
|
|
: "加工零件总数为空";
|
|
|
|
|
_log.Debug($"机床{machineId}: 跳过产量跟踪({skipReason})");
|
|
|
|
|
return ($"跳过:{skipReason}", false, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lock (_lock)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 获取上次采集状态
|
|
|
|
|
Tuple<string, decimal?> lastState;
|
|
|
|
|
bool hasLast = _lastCollectState.TryGetValue(machineId, out lastState);
|
|
|
|
|
|
|
|
|
|
// 检测是否需要结账
|
|
|
|
|
bool needClose = false;
|
|
|
|
|
string closeReason = "";
|
|
|
|
|
string logText;
|
|
|
|
|
bool changed;
|
|
|
|
|
|
|
|
|
|
if (hasLast)
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
{
|
|
|
|
|
string lastProgram = lastState.Item1;
|
|
|
|
|
decimal? lastPartCount = lastState.Item2;
|
|
|
|
|
conn.Open();
|
|
|
|
|
|
|
|
|
|
// 查询当天最新一条记录
|
|
|
|
|
var record = GetCurrentRecord(conn, machineId);
|
|
|
|
|
|
|
|
|
|
// 情况1:NC程序名变化
|
|
|
|
|
if (!string.Equals(lastProgram, programName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
if (record == null)
|
|
|
|
|
{
|
|
|
|
|
needClose = true;
|
|
|
|
|
closeReason = SegmentCloseReason.ProgramChange;
|
|
|
|
|
_log.Info($"机床{machineId}: 程序切换 {lastProgram} → {programName}({closeReason})");
|
|
|
|
|
// 当天首次采集 → 创建记录
|
|
|
|
|
InsertRecord(conn, machineId, programName,
|
|
|
|
|
totalPartCount.Value, totalPartCount.Value);
|
|
|
|
|
logText = "当天首次采集,创建记录";
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
// 情况2:同程序下 part_count 下降(手动清零)
|
|
|
|
|
else if (partCount.HasValue && lastPartCount.HasValue && partCount.Value < lastPartCount.Value)
|
|
|
|
|
else if (record.ProductionDate != DateTime.Today)
|
|
|
|
|
{
|
|
|
|
|
needClose = true;
|
|
|
|
|
closeReason = SegmentCloseReason.ManualReset;
|
|
|
|
|
_log.Info($"机床{machineId}: 零件数下降 {lastPartCount} → {partCount}({closeReason})");
|
|
|
|
|
// 防御性检查:跨天(理论上不会发生,因为查询条件限定了 CURDATE())
|
|
|
|
|
InsertRecord(conn, machineId, programName,
|
|
|
|
|
totalPartCount.Value, totalPartCount.Value);
|
|
|
|
|
logText = "跨天首次采集,创建记录";
|
|
|
|
|
changed = true;
|
|
|
|
|
}
|
|
|
|
|
else if (string.Equals(record.ProgramName, programName, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
(logText, changed) = HandleSameProgram(conn, record, totalPartCount.Value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
(logText, changed) = HandleProgramChange(conn, record, programName, totalPartCount.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 结账当前活跃段
|
|
|
|
|
// 修复:使用结账前最后已知的零件数(lastPartCount),而非当前观测值(partCount)
|
|
|
|
|
// 当 manual_reset 时 partCount 是复位后的值(如0),当 program_change 时 partCount 是新程序的值
|
|
|
|
|
// 正确的 endPartCount 应该是结账段最后观测到的最大计数值
|
|
|
|
|
if (needClose)
|
|
|
|
|
{
|
|
|
|
|
var closingEndCount = hasLast ? lastState.Item2 : partCount;
|
|
|
|
|
CloseActiveSegment(machineId, closingEndCount, closeReason, collectTime);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 确保有活跃段
|
|
|
|
|
long activeSegmentId = EnsureActiveSegment(machineId, programName, partCount, collectTime);
|
|
|
|
|
// 计算当日总产量 = 当天所有记录的 (end - base) 之和
|
|
|
|
|
var todayTotal = conn.ExecuteScalar<decimal>(
|
|
|
|
|
@"SELECT COALESCE(SUM(end_total_count - base_total_count), 0)
|
|
|
|
|
FROM cnc_daily_production
|
|
|
|
|
WHERE machine_id = @Mid AND production_date = CURDATE()",
|
|
|
|
|
new { Mid = machineId });
|
|
|
|
|
|
|
|
|
|
// 更新活跃段的实时 end_part_count
|
|
|
|
|
if (activeSegmentId > 0 && partCount.HasValue)
|
|
|
|
|
{
|
|
|
|
|
UpdateSegmentEndCount(activeSegmentId, partCount.Value);
|
|
|
|
|
_log.Info($"机床{machineId}: {logText}(当日累计产量={todayTotal:F5})");
|
|
|
|
|
return (logText, changed, todayTotal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新内存缓存
|
|
|
|
|
_lastCollectState[machineId] = Tuple.Create(programName, partCount);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_log.Error($"产量跟踪处理失败(machine_id={machineId})", ex);
|
|
|
|
|
// 写入告警:产量跟踪失败意味着产量数据可能丢失
|
|
|
|
|
|
|
|
|
|
// 写入告警
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var conn2 = new MySqlConnection(_connectionString))
|
|
|
|
|
{
|
|
|
|
|
conn2.Execute(@"INSERT INTO cnc_alert (alert_type, machine_id, title, detail, is_resolved, created_at)
|
|
|
|
|
VALUES (@Type, @Mid, @Title, @Detail, 0, NOW())",
|
|
|
|
|
new { Type = "production_error", Mid = machineId, Title = "产量跟踪处理异常",
|
|
|
|
|
Detail = $"机床{machineId}产量跟踪失败: {ex.Message}" });
|
|
|
|
|
conn2.Execute(
|
|
|
|
|
@"INSERT INTO cnc_alert (alert_type, machine_id, title, detail, is_resolved, created_at)
|
|
|
|
|
VALUES (@Type, @Mid, @Title, @Detail, 0, NOW())",
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
Type = "production_error",
|
|
|
|
|
Mid = machineId,
|
|
|
|
|
Title = "产量跟踪处理异常",
|
|
|
|
|
Detail = $"机床{machineId}产量跟踪失败: {ex.Message}"
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch { /* 告警写入失败不影响主流程 */ }
|
|
|
|
|
|
|
|
|
|
return ($"异常:{ex.Message}", false, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 服务停止时结账所有活跃段
|
|
|
|
|
/// 查询当天最新一条日产量记录
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void CloseAllActiveSegments()
|
|
|
|
|
private DailyProductionRecord GetCurrentRecord(MySqlConnection conn, int machineId)
|
|
|
|
|
{
|
|
|
|
|
_log.Info("正在结账所有活跃段(服务停止)...");
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
{
|
|
|
|
|
// 结账所有活跃段:is_settled=0 且 end_time IS NULL
|
|
|
|
|
// 正确计算quantity:保留当前end_part_count,用end-start计算产量
|
|
|
|
|
conn.Execute(@"UPDATE cnc_production_segment
|
|
|
|
|
SET end_time = NOW(),
|
|
|
|
|
end_part_count = COALESCE(end_part_count, start_part_count),
|
|
|
|
|
quantity = GREATEST(0, COALESCE(end_part_count, start_part_count) - start_part_count),
|
|
|
|
|
close_reason = @Reason, is_settled = 1, updated_at = NOW()
|
|
|
|
|
WHERE is_settled = 0 AND end_time IS NULL",
|
|
|
|
|
new { Reason = SegmentCloseReason.ServiceStop });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_activeSegmentIds.Clear();
|
|
|
|
|
_lastCollectState.Clear();
|
|
|
|
|
_log.Info("所有活跃段已结账");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_log.Error("结账所有活跃段失败", ex);
|
|
|
|
|
}
|
|
|
|
|
return conn.QueryFirstOrDefault<DailyProductionRecord>(
|
|
|
|
|
@"SELECT id AS Id, machine_id AS MachineId, production_date AS ProductionDate,
|
|
|
|
|
program_name AS ProgramName, base_total_count AS BaseTotalCount,
|
|
|
|
|
end_total_count AS EndTotalCount
|
|
|
|
|
FROM cnc_daily_production
|
|
|
|
|
WHERE machine_id = @Mid AND production_date = CURDATE()
|
|
|
|
|
ORDER BY id DESC
|
|
|
|
|
LIMIT 1",
|
|
|
|
|
new { Mid = machineId });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 结账指定机床的活跃段
|
|
|
|
|
/// 处理同程序情况:对比 end_total_count 与当前的 totalPartCount
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="machineId">机床ID</param>
|
|
|
|
|
/// <param name="endPartCount">结束时的零件数</param>
|
|
|
|
|
/// <param name="reason">关闭原因</param>
|
|
|
|
|
/// <param name="endTime">结束时间</param>
|
|
|
|
|
public void CloseActiveSegment(int machineId, decimal? endPartCount, string reason, DateTime endTime)
|
|
|
|
|
private (string logText, bool changed) HandleSameProgram(
|
|
|
|
|
MySqlConnection conn, DailyProductionRecord record, decimal totalPartCount)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
if (totalPartCount > record.EndTotalCount)
|
|
|
|
|
{
|
|
|
|
|
long segmentId;
|
|
|
|
|
if (!_activeSegmentIds.TryGetValue(machineId, out segmentId))
|
|
|
|
|
{
|
|
|
|
|
// 从DB查找
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
{
|
|
|
|
|
segmentId = conn.ExecuteScalar<long>(
|
|
|
|
|
"SELECT id FROM cnc_production_segment WHERE machine_id=@MId AND is_settled=0 AND end_time IS NULL ORDER BY start_time DESC LIMIT 1",
|
|
|
|
|
new { MId = machineId });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (segmentId <= 0) return;
|
|
|
|
|
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
{
|
|
|
|
|
// 获取 start_part_count 计算 quantity
|
|
|
|
|
var startCount = conn.ExecuteScalar<decimal?>(
|
|
|
|
|
"SELECT start_part_count FROM cnc_production_segment WHERE id=@Id", new { Id = segmentId });
|
|
|
|
|
|
|
|
|
|
decimal? quantity = null;
|
|
|
|
|
if (startCount.HasValue && endPartCount.HasValue)
|
|
|
|
|
{
|
|
|
|
|
quantity = Math.Max(0, endPartCount.Value - startCount.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
conn.Execute(@"UPDATE cnc_production_segment
|
|
|
|
|
SET end_time = @EndTime, end_part_count = @EndPartCount, quantity = @Quantity,
|
|
|
|
|
close_reason = @Reason, is_settled = 1, updated_at = NOW()
|
|
|
|
|
WHERE id = @Id",
|
|
|
|
|
new { Id = segmentId, EndTime = endTime, EndPartCount = endPartCount, Quantity = quantity, Reason = reason });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_activeSegmentIds.TryRemove(machineId, out _);
|
|
|
|
|
_log.Debug($"机床{machineId}: 结账段{segmentId}({reason},quantity={endPartCount})");
|
|
|
|
|
// 正常加工增长 → 更新结束计数
|
|
|
|
|
conn.Execute(
|
|
|
|
|
"UPDATE cnc_daily_production SET end_total_count = @Count WHERE id = @Id",
|
|
|
|
|
new { Id = record.Id, Count = totalPartCount });
|
|
|
|
|
return ("正常加工,更新结束总零件数", true);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
|
|
|
|
if (totalPartCount == record.EndTotalCount)
|
|
|
|
|
{
|
|
|
|
|
_log.Error($"结账活跃段失败(machine_id={machineId})", ex);
|
|
|
|
|
// 无变化 → 跳过
|
|
|
|
|
return ("无变化", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// totalPartCount < record.EndTotalCount → 数据异常,不写库
|
|
|
|
|
_log.Warn($"机床{record.MachineId}: 数据异常,加工零件总数从{record.EndTotalCount}变为{totalPartCount},不更新数据库");
|
|
|
|
|
return ("数据异常:加工零件总数变小", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 确保指定机床有一个活跃段,没有则创建
|
|
|
|
|
/// 处理程序切换:旧程序→新程序,创建新记录
|
|
|
|
|
/// </summary>
|
|
|
|
|
private long EnsureActiveSegment(int machineId, string programName, decimal? partCount, DateTime collectTime)
|
|
|
|
|
private (string logText, bool changed) HandleProgramChange(
|
|
|
|
|
MySqlConnection conn, DailyProductionRecord oldRecord,
|
|
|
|
|
string newProgramName, decimal totalPartCount)
|
|
|
|
|
{
|
|
|
|
|
long segmentId;
|
|
|
|
|
|
|
|
|
|
if (_activeSegmentIds.TryGetValue(machineId, out segmentId) && segmentId > 0)
|
|
|
|
|
return segmentId;
|
|
|
|
|
|
|
|
|
|
// 从DB查找
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
if (totalPartCount >= oldRecord.EndTotalCount)
|
|
|
|
|
{
|
|
|
|
|
segmentId = conn.ExecuteScalar<long>(
|
|
|
|
|
"SELECT id FROM cnc_production_segment WHERE machine_id=@MId AND is_settled=0 AND end_time IS NULL ORDER BY start_time DESC LIMIT 1",
|
|
|
|
|
new { MId = machineId });
|
|
|
|
|
|
|
|
|
|
if (segmentId <= 0)
|
|
|
|
|
{
|
|
|
|
|
// 创建新段
|
|
|
|
|
var now = DateTime.Now;
|
|
|
|
|
segmentId = conn.ExecuteScalar<long>(@"INSERT INTO cnc_production_segment
|
|
|
|
|
(machine_id, program_name, production_date, start_time, start_part_count, is_settled, created_at, updated_at)
|
|
|
|
|
VALUES (@MachineId, @ProgramName, @ProductionDate, @StartTime, @StartPartCount, 0, @CreatedAt, @UpdatedAt);
|
|
|
|
|
SELECT LAST_INSERT_ID();",
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
MachineId = machineId,
|
|
|
|
|
ProgramName = programName,
|
|
|
|
|
ProductionDate = collectTime.Date,
|
|
|
|
|
StartTime = collectTime,
|
|
|
|
|
StartPartCount = partCount ?? 0,
|
|
|
|
|
CreatedAt = now,
|
|
|
|
|
UpdatedAt = now
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
_log.Debug($"机床{machineId}: 创建新段{segmentId}(程序={programName}, startCount={partCount})");
|
|
|
|
|
}
|
|
|
|
|
// 合法程序切换 → 创建新记录
|
|
|
|
|
// 关键:新记录的 base 使用旧记录的 end,保证产量连续
|
|
|
|
|
InsertRecord(conn, oldRecord.MachineId, newProgramName,
|
|
|
|
|
oldRecord.EndTotalCount, totalPartCount);
|
|
|
|
|
_log.Info($"机床{oldRecord.MachineId}: 程序切换 {oldRecord.ProgramName} → {newProgramName}," +
|
|
|
|
|
$"新记录 base={oldRecord.EndTotalCount} end={totalPartCount}");
|
|
|
|
|
return ("程序切换,创建新记录", true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_activeSegmentIds[machineId] = segmentId;
|
|
|
|
|
return segmentId;
|
|
|
|
|
// totalPartCount < oldRecord.EndTotalCount → 数据异常,不写库
|
|
|
|
|
_log.Warn($"机床{oldRecord.MachineId}: 程序切换时数据异常," +
|
|
|
|
|
$"旧程序{oldRecord.ProgramName} end={oldRecord.EndTotalCount}," +
|
|
|
|
|
$"新程序{newProgramName} total={totalPartCount}");
|
|
|
|
|
return ("数据异常", false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 更新活跃段的实时 end_part_count
|
|
|
|
|
/// 插入一条新的日产量记录
|
|
|
|
|
/// </summary>
|
|
|
|
|
private void UpdateSegmentEndCount(long segmentId, decimal partCount)
|
|
|
|
|
private void InsertRecord(MySqlConnection conn, int machineId,
|
|
|
|
|
string programName, decimal baseTotalCount, decimal endTotalCount)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var conn = new MySqlConnection(_connectionString))
|
|
|
|
|
conn.Execute(
|
|
|
|
|
@"INSERT INTO cnc_daily_production
|
|
|
|
|
(machine_id, production_date, program_name, base_total_count, end_total_count, created_at, updated_at)
|
|
|
|
|
VALUES (@MachineId, CURDATE(), @ProgramName, @BaseCount, @EndCount, NOW(), NOW())",
|
|
|
|
|
new
|
|
|
|
|
{
|
|
|
|
|
conn.Execute("UPDATE cnc_production_segment SET end_part_count = @Count, updated_at = NOW() WHERE id = @Id",
|
|
|
|
|
new { Id = segmentId, Count = partCount });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
_log.Error($"更新活跃段end_part_count失败(segment_id={segmentId})", ex);
|
|
|
|
|
}
|
|
|
|
|
MachineId = machineId,
|
|
|
|
|
ProgramName = programName,
|
|
|
|
|
BaseCount = baseTotalCount,
|
|
|
|
|
EndCount = endTotalCount
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 日产量记录的数据库行映射
|
|
|
|
|
/// </summary>
|
|
|
|
|
private class DailyProductionRecord
|
|
|
|
|
{
|
|
|
|
|
public int Id { get; set; }
|
|
|
|
|
public int MachineId { get; set; }
|
|
|
|
|
public DateTime ProductionDate { get; set; }
|
|
|
|
|
public string ProgramName { get; set; }
|
|
|
|
|
public decimal BaseTotalCount { get; set; }
|
|
|
|
|
public decimal EndTotalCount { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 释放资源(当前无需要清理的资源)
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
CloseAllActiveSegments();
|
|
|
|
|
// 无内存缓存需清理,连接由 using 管理
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|