feat: 在线状态改为基于last_ping_time实时判断,删除is_online列;新增online_timeout配置项(默认300秒);全链路修改Repository/Service/Collector/测试

feat/windows-service-status-auto
haoliang 12 hours ago
parent 0563da73e8
commit ccdfec31bb

@ -0,0 +1,25 @@
-- ============================================================
-- 迁移脚本06: 删除is_online列 + 新增在线超时配置项
-- 幂等执行先加配置再删列IF EXISTS
-- ============================================================
-- 1. 新增系统配置项:在线超时阈值(秒)
INSERT INTO cnc_sys_config (config_key, config_value, value_type, description, updated_at)
SELECT 'online_timeout', '300', 'number', '在线超时阈值(秒)超过此时间未Ping的机床判定为离线', NOW()
FROM DUAL
WHERE NOT EXISTS (SELECT 1 FROM cnc_sys_config WHERE config_key = 'online_timeout');
-- 2. 删除 is_online 列幂等IF EXISTS 在 MariaDB 10.0.2+ 支持)
-- 注意MariaDB 不支持 ALTER TABLE DROP COLUMN IF EXISTS用存储过程实现
DROP PROCEDURE IF EXISTS drop_column_if_exists;
DELIMITER //
CREATE PROCEDURE drop_column_if_exists()
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'cnc_machine' AND COLUMN_NAME = 'is_online') THEN
ALTER TABLE cnc_machine DROP COLUMN is_online;
END IF;
END //
DELIMITER ;
CALL drop_column_if_exists();
DROP PROCEDURE IF EXISTS drop_column_if_exists;

@ -13,7 +13,7 @@
</el-card> </el-card>
<el-card shadow="hover"> <el-card shadow="hover">
<template #header><div style="display:flex;justify-content:space-between"><span>字段映射列表</span><el-button size="small" @click="addMapping">+ </el-button></div></template> <template #header><div style="display:flex;justify-content:space-between"><span>字段映射列表</span><el-button size="small" @click="addMapping">+ </el-button></div></template>
<el-table :data="form.mappings" border stripe size="small" style="width:100%" row-class-name="mapping-row" :row-style="({row}) => row.isEnabled === 0 ? { opacity: 0.5 } : {}"> <el-table :data="form.mappings" border stripe size="small" style="width:100%" row-class-name="mapping-row" :row-style="({row}: any) => row.isEnabled === 0 ? { opacity: 0.5 } : {}">
<el-table-column label="标准字段" min-width="180"><template #default="{row}"><el-select v-model="row.standardField" style="width:100%"><el-option v-for="f in standardFields" :key="f" :label="f" :value="f" /></el-select></template></el-table-column> <el-table-column label="标准字段" min-width="180"><template #default="{row}"><el-select v-model="row.standardField" style="width:100%"><el-option v-for="f in standardFields" :key="f" :label="f" :value="f" /></el-select></template></el-table-column>
<el-table-column label="字段名" min-width="140"><template #default="{row}"><el-input v-model="row.fieldName" /></template></el-table-column> <el-table-column label="字段名" min-width="140"><template #default="{row}"><el-input v-model="row.fieldName" /></template></el-table-column>
<el-table-column label="匹配方式" min-width="110"><template #default="{row}"><el-select v-model="row.matchBy" style="width:100%"><el-option label="id" value="id" /><el-option label="desc" value="desc" /></el-select></template></el-table-column> <el-table-column label="匹配方式" min-width="110"><template #default="{row}"><el-select v-model="row.matchBy" style="width:100%"><el-option label="id" value="id" /><el-option label="desc" value="desc" /></el-select></template></el-table-column>

@ -247,10 +247,10 @@ namespace CncCollector.Core
using (var conn = new MySqlConnection(_businessConnStr)) using (var conn = new MySqlConnection(_businessConnStr))
{ {
if (onlineIds.Count > 0) if (onlineIds.Count > 0)
conn.Execute(@"UPDATE cnc_machine SET is_online = 1, last_ping_time = NOW(), updated_at = NOW() WHERE id IN @Ids", conn.Execute(@"UPDATE cnc_machine SET last_ping_time = NOW(), updated_at = NOW() WHERE id IN @Ids",
new { Ids = onlineIds }); new { Ids = onlineIds });
if (offlineIds.Count > 0) if (offlineIds.Count > 0)
conn.Execute(@"UPDATE cnc_machine SET is_online = 0, last_ping_time = NOW(), updated_at = NOW() WHERE id IN @Ids", conn.Execute(@"UPDATE cnc_machine SET last_ping_time = NOW(), updated_at = NOW() WHERE id IN @Ids",
new { Ids = offlineIds }); new { Ids = offlineIds });
} }
@ -309,7 +309,7 @@ namespace CncCollector.Core
// 加载此地址下的机床列表 // 加载此地址下的机床列表
machines = conn.Query<Machine>( machines = conn.Query<Machine>(
"SELECT id as Id, device_code as DeviceCode, name as Name, workshop_id as WorkshopId, collect_address_id as CollectAddressId, ip_address as IpAddress, brand_id as BrandId, is_enabled as IsEnabled, is_online as IsOnline, last_ping_time as LastPingTime, last_collect_time as LastCollectTime, last_device_status as LastDeviceStatus, last_run_status as LastRunStatus, last_program_name as LastProgramName, last_part_count as LastPartCount, last_operate_mode as LastOperateMode, last_machining_status as LastMachiningStatus, created_at as CreatedAt, updated_at as UpdatedAt FROM cnc_machine WHERE collect_address_id = @AddrId AND is_enabled = 1", "SELECT id as Id, device_code as DeviceCode, name as Name, workshop_id as WorkshopId, collect_address_id as CollectAddressId, ip_address as IpAddress, brand_id as BrandId, is_enabled as IsEnabled, last_ping_time as LastPingTime, last_collect_time as LastCollectTime, last_device_status as LastDeviceStatus, last_run_status as LastRunStatus, last_program_name as LastProgramName, last_part_count as LastPartCount, last_operate_mode as LastOperateMode, last_machining_status as LastMachiningStatus, created_at as CreatedAt, updated_at as UpdatedAt FROM cnc_machine WHERE collect_address_id = @AddrId AND is_enabled = 1",
new { AddrId = _address.Id }).AsList(); new { AddrId = _address.Id }).AsList();
} }

@ -31,10 +31,7 @@ namespace CncModels.Entity
/// <summary>是否启用</summary> /// <summary>是否启用</summary>
public int IsEnabled { get; set; } public int IsEnabled { get; set; }
/// <summary>是否在线</summary> /// <summary>最近Ping时间在线状态由 last_ping_time 实时计算)</summary>
public int IsOnline { get; set; }
/// <summary>最近Ping时间</summary>
public DateTime? LastPingTime { get; set; } public DateTime? LastPingTime { get; set; }
/// <summary>最近采集时间</summary> /// <summary>最近采集时间</summary>

@ -44,12 +44,13 @@ namespace CncRepository.Impl.Dashboard
) all_days"; ) all_days";
/// <summary>汇总卡片数据</summary> /// <summary>汇总卡片数据</summary>
public DashboardSummaryResponse GetSummary() public DashboardSummaryResponse GetSummary(int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var onlineCount = conn.ExecuteScalar<int>(@"SELECT COUNT(1) FROM cnc_machine WHERE is_online = 1"); var onlineCount = conn.ExecuteScalar<int>(@"SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1 AND last_ping_time IS NOT NULL AND last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND",
var totalMachines = conn.ExecuteScalar<int>(@"SELECT COUNT(1) FROM cnc_machine"); new { OnlineTimeout = onlineTimeout });
var totalMachines = conn.ExecuteScalar<int>(@"SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1");
// 今日总产量:直接从产量分段实时计算(今日一定没有日终汇总) // 今日总产量:直接从产量分段实时计算(今日一定没有日终汇总)
var todayProduction = conn.ExecuteScalar<int>(@" var todayProduction = conn.ExecuteScalar<int>(@"
SELECT COALESCE(SUM(CASE WHEN is_settled=1 THEN quantity SELECT COALESCE(SUM(CASE WHEN is_settled=1 THEN quantity
@ -130,7 +131,7 @@ namespace CncRepository.Impl.Dashboard
} }
/// <summary>机床排行</summary> /// <summary>机床排行</summary>
public List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top) public List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top, int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
@ -138,7 +139,7 @@ namespace CncRepository.Impl.Dashboard
SELECT m.id AS MachineId, SELECT m.id AS MachineId,
m.name AS MachineName, m.name AS MachineName,
COALESCE(SUM(ad.day_quantity), 0) AS Quantity, COALESCE(SUM(ad.day_quantity), 0) AS Quantity,
CAST(m.is_online AS SIGNED) AS Status, (CASE WHEN m.is_enabled = 1 AND m.last_ping_time IS NOT NULL AND m.last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND THEN 1 ELSE 0 END) AS Status,
(SELECT seg.program_name FROM cnc_production_segment seg (SELECT seg.program_name FROM cnc_production_segment seg
WHERE seg.machine_id = m.id AND seg.production_date = CURDATE() WHERE seg.machine_id = m.id AND seg.production_date = CURDATE()
ORDER BY seg.id DESC LIMIT 1) AS Program ORDER BY seg.id DESC LIMIT 1) AS Program
@ -162,10 +163,10 @@ namespace CncRepository.Impl.Dashboard
) )
GROUP BY seg.machine_id, seg.production_date GROUP BY seg.machine_id, seg.production_date
) ad ON ad.machine_id = m.id ) ad ON ad.machine_id = m.id
GROUP BY m.id, m.name, m.is_online GROUP BY m.id, m.name, m.is_enabled, m.last_ping_time
ORDER BY Quantity DESC ORDER BY Quantity DESC
LIMIT @Top"; LIMIT @Top";
var rows = conn.Query<MachineRankResponse>(sql, new { StartDate = startDate, EndDate = endDate, Top = top }).ToList(); var rows = conn.Query<MachineRankResponse>(sql, new { StartDate = startDate, EndDate = endDate, Top = top, OnlineTimeout = onlineTimeout }).ToList();
// 填充排名 // 填充排名
for (int i = 0; i < rows.Count; i++) rows[i].Rank = i + 1; for (int i = 0; i < rows.Count; i++) rows[i].Rank = i + 1;
return rows; return rows;
@ -244,12 +245,14 @@ namespace CncRepository.Impl.Dashboard
} }
/// <summary>机床状态分布</summary> /// <summary>机床状态分布</summary>
public object GetMachineStatusDistribution() public object GetMachineStatusDistribution(int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var online = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1 AND is_online = 1"); var online = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1 AND last_ping_time IS NOT NULL AND last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND",
var offline = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1 AND is_online = 0"); new { OnlineTimeout = onlineTimeout });
var offline = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 1 AND (last_ping_time IS NULL OR last_ping_time < NOW() - INTERVAL @OnlineTimeout SECOND)",
new { OnlineTimeout = onlineTimeout });
var disabled = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 0"); var disabled = conn.ExecuteScalar<int>("SELECT COUNT(1) FROM cnc_machine WHERE is_enabled = 0");
return new { online, offline, disabled }; return new { online, offline, disabled };
} }

@ -17,18 +17,22 @@ namespace CncRepository.Impl
public MachineRepository(string connectionString) : base(connectionString) { } public MachineRepository(string connectionString) : base(connectionString) { }
/// <summary>机床SELECT列映射模板snake_case列名 → PascalCase属性名</summary> /// <summary>机床SELECT列映射模板snake_case列名 → PascalCase属性名</summary>
private const string SelectColumns = @"id as Id, device_code as DeviceCode, name as Name, workshop_id as WorkshopId, collect_address_id as CollectAddressId, ip_address as IpAddress, brand_id as BrandId, is_enabled as IsEnabled, is_online as IsOnline, last_ping_time as LastPingTime, last_collect_time as LastCollectTime, last_device_status as LastDeviceStatus, last_run_status as LastRunStatus, last_program_name as LastProgramName, last_part_count as LastPartCount, last_operate_mode as LastOperateMode, last_machining_status as LastMachiningStatus, created_at as CreatedAt, updated_at as UpdatedAt"; /// <summary>在线判断SQL片段已启用且最近Ping在超时阈值内视为在线。参数 @OnlineTimeout</summary>
private const string OnlineExpr = "(CASE WHEN is_enabled = 1 AND last_ping_time IS NOT NULL AND last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND THEN 1 ELSE 0 END)";
public Machine GetById(int id) private const string SelectColumns = @"id as Id, device_code as DeviceCode, name as Name, workshop_id as WorkshopId, collect_address_id as CollectAddressId, ip_address as IpAddress, brand_id as BrandId, is_enabled as IsEnabled, {0} as IsOnline, last_ping_time as LastPingTime, last_collect_time as LastCollectTime, last_device_status as LastDeviceStatus, last_run_status as LastRunStatus, last_program_name as LastProgramName, last_part_count as LastPartCount, last_operate_mode as LastOperateMode, last_machining_status as LastMachiningStatus, created_at as CreatedAt, updated_at as UpdatedAt";
public Machine GetById(int id, int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = $"SELECT {SelectColumns} FROM cnc_machine WHERE id = @Id"; var cols = string.Format(SelectColumns, OnlineExpr);
return conn.QuerySingleOrDefault<Machine>(sql, new { Id = id }); var sql = $"SELECT {cols} FROM cnc_machine WHERE id = @Id";
return conn.QuerySingleOrDefault<Machine>(sql, new { Id = id, OnlineTimeout = onlineTimeout });
} }
} }
public MachineDetailResponse GetDetailById(int id) public MachineDetailResponse GetDetailById(int id, int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
@ -37,7 +41,8 @@ namespace CncRepository.Impl
m.collect_address_id as CollectAddressId, m.collect_address_id as CollectAddressId,
m.brand_id as BrandId, b.brand_name as BrandName, m.brand_id as BrandId, b.brand_name as BrandName,
m.ip_address as IpAddress, m.ip_address as IpAddress,
m.is_enabled as IsEnabled, m.is_online as IsOnline, m.is_enabled as IsEnabled,
(CASE WHEN m.is_enabled = 1 AND m.last_ping_time IS NOT NULL AND m.last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND THEN 1 ELSE 0 END) as IsOnline,
w.id as WorkerId, w.name as WorkerName, w.id as WorkerId, w.name as WorkerName,
m.last_program_name as LastProgramName, m.last_collect_time as LastCollectTime m.last_program_name as LastProgramName, m.last_collect_time as LastCollectTime
FROM cnc_machine m FROM cnc_machine m
@ -46,16 +51,17 @@ namespace CncRepository.Impl
LEFT JOIN cnc_worker_machine wm ON m.id = wm.machine_id LEFT JOIN cnc_worker_machine wm ON m.id = wm.machine_id
LEFT JOIN cnc_worker w ON wm.worker_id = w.id LEFT JOIN cnc_worker w ON wm.worker_id = w.id
WHERE m.id = @Id"; WHERE m.id = @Id";
return conn.QuerySingleOrDefault<MachineDetailResponse>(sql, new { Id = id }); return conn.QuerySingleOrDefault<MachineDetailResponse>(sql, new { Id = id, OnlineTimeout = onlineTimeout });
} }
} }
public PagedResult<MachineListItem> GetList(MachineQuery query) public PagedResult<MachineListItem> GetList(MachineQuery query, int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var where = " WHERE 1=1"; var where = " WHERE 1=1";
var p = new DynamicParameters(); var p = new DynamicParameters();
p.Add("OnlineTimeout", onlineTimeout);
if (!string.IsNullOrWhiteSpace(query.Keyword)) if (!string.IsNullOrWhiteSpace(query.Keyword))
{ {
where += " AND (m.name LIKE @Keyword OR m.device_code LIKE @Keyword)"; where += " AND (m.name LIKE @Keyword OR m.device_code LIKE @Keyword)";
@ -68,8 +74,10 @@ namespace CncRepository.Impl
} }
if (query.IsOnline.HasValue) if (query.IsOnline.HasValue)
{ {
where += " AND m.is_online = @IsOnline"; if (query.IsOnline.Value == 1)
p.Add("IsOnline", query.IsOnline.Value); where += " AND m.is_enabled = 1 AND m.last_ping_time IS NOT NULL AND m.last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND";
else
where += " AND (m.is_enabled = 0 OR m.last_ping_time IS NULL OR m.last_ping_time < NOW() - INTERVAL @OnlineTimeout SECOND)";
} }
if (query.BrandId.HasValue) if (query.BrandId.HasValue)
{ {
@ -78,7 +86,9 @@ namespace CncRepository.Impl
} }
var limit = query.PageSize; var limit = query.PageSize;
var offset = query.Offset; var offset = query.Offset;
var sql = @"SELECT m.id as Id, m.device_code as DeviceCode, m.name as Name, m.workshop_id as WorkshopId, ws.name as WorkshopName, m.collect_address_id as CollectAddressId, m.brand_id as BrandId, b.brand_name as BrandName, m.ip_address as IpAddress, m.is_enabled as IsEnabled, m.is_online as IsOnline, m.last_program_name as LastProgramName, m.last_collect_time as LastCollectTime, w.id as WorkerId, w.name as WorkerName var sql = @"SELECT m.id as Id, m.device_code as DeviceCode, m.name as Name, m.workshop_id as WorkshopId, ws.name as WorkshopName, m.collect_address_id as CollectAddressId, m.brand_id as BrandId, b.brand_name as BrandName, m.ip_address as IpAddress, m.is_enabled as IsEnabled,
(CASE WHEN m.is_enabled = 1 AND m.last_ping_time IS NOT NULL AND m.last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND THEN 1 ELSE 0 END) as IsOnline,
m.last_program_name as LastProgramName, m.last_collect_time as LastCollectTime, w.id as WorkerId, w.name as WorkerName
FROM cnc_machine m FROM cnc_machine m
LEFT JOIN cnc_workshop ws ON m.workshop_id = ws.id LEFT JOIN cnc_workshop ws ON m.workshop_id = ws.id
LEFT JOIN cnc_brand b ON m.brand_id = b.id LEFT JOIN cnc_brand b ON m.brand_id = b.id
@ -103,8 +113,8 @@ namespace CncRepository.Impl
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = @"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) var sql = @"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES (@DeviceCode, @Name, @WorkshopId, @CollectAddressId, @IpAddress, @BrandId, @IsEnabled, @IsOnline, @CreatedAt, @UpdatedAt); VALUES (@DeviceCode, @Name, @WorkshopId, @CollectAddressId, @IpAddress, @BrandId, @IsEnabled, @CreatedAt, @UpdatedAt);
SELECT LAST_INSERT_ID();"; SELECT LAST_INSERT_ID();";
return conn.QuerySingle<int>(sql, entity); return conn.QuerySingle<int>(sql, entity);
} }
@ -114,7 +124,7 @@ namespace CncRepository.Impl
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = @"UPDATE cnc_machine SET device_code = @DeviceCode, name = @Name, workshop_id = @WorkshopId, collect_address_id = @CollectAddressId, ip_address = @IpAddress, brand_id = @BrandId, is_enabled = @IsEnabled, is_online = @IsOnline, updated_at = @UpdatedAt, last_program_name = @LastProgramName, last_collect_time = @LastCollectTime, last_device_status = @LastDeviceStatus, last_run_status = @LastRunStatus, last_machining_status = @LastMachiningStatus WHERE id = @Id"; var sql = @"UPDATE cnc_machine SET device_code = @DeviceCode, name = @Name, workshop_id = @WorkshopId, collect_address_id = @CollectAddressId, ip_address = @IpAddress, brand_id = @BrandId, is_enabled = @IsEnabled, updated_at = @UpdatedAt, last_program_name = @LastProgramName, last_collect_time = @LastCollectTime, last_device_status = @LastDeviceStatus, last_run_status = @LastRunStatus, last_machining_status = @LastMachiningStatus WHERE id = @Id";
return conn.Execute(sql, entity) > 0; return conn.Execute(sql, entity) > 0;
} }
} }
@ -147,39 +157,33 @@ namespace CncRepository.Impl
} }
} }
public Machine GetByDeviceCode(string deviceCode) public Machine GetByDeviceCode(string deviceCode, int onlineTimeout = 300)
{
using (var conn = CreateConnection())
{
var sql = $"SELECT {SelectColumns} FROM cnc_machine WHERE device_code = @DeviceCode";
return conn.QuerySingleOrDefault<Machine>(sql, new { DeviceCode = deviceCode });
}
}
public List<Machine> GetEnabledByAddressId(int collectAddressId)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = $"SELECT {SelectColumns} FROM cnc_machine WHERE collect_address_id = @CollectAddressId AND is_enabled = 1"; var cols = string.Format(SelectColumns, OnlineExpr);
return conn.Query<Machine>(sql, new { CollectAddressId = collectAddressId }).ToList(); var sql = $"SELECT {cols} FROM cnc_machine WHERE device_code = @DeviceCode";
return conn.QuerySingleOrDefault<Machine>(sql, new { DeviceCode = deviceCode, OnlineTimeout = onlineTimeout });
} }
} }
public List<Machine> GetEnabledOnline() public List<Machine> GetEnabledByAddressId(int collectAddressId, int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = $"SELECT {SelectColumns} FROM cnc_machine WHERE is_enabled = 1 AND is_online = 1"; var cols = string.Format(SelectColumns, OnlineExpr);
return conn.Query<Machine>(sql).ToList(); var sql = $"SELECT {cols} FROM cnc_machine WHERE collect_address_id = @CollectAddressId AND is_enabled = 1";
return conn.Query<Machine>(sql, new { CollectAddressId = collectAddressId, OnlineTimeout = onlineTimeout }).ToList();
} }
} }
public void UpdateOnlineStatus(int id, bool isOnline) public List<Machine> GetEnabledOnline(int onlineTimeout = 300)
{ {
using (var conn = CreateConnection()) using (var conn = CreateConnection())
{ {
var sql = @"UPDATE cnc_machine SET is_online = @IsOnline, updated_at = NOW() WHERE id = @Id"; var cols = string.Format(SelectColumns, OnlineExpr);
conn.Execute(sql, new { Id = id, IsOnline = isOnline ? 1 : 0 }); var sql = $"SELECT {cols} FROM cnc_machine WHERE is_enabled = 1 AND last_ping_time IS NOT NULL AND last_ping_time >= NOW() - INTERVAL @OnlineTimeout SECOND";
return conn.Query<Machine>(sql, new { OnlineTimeout = onlineTimeout }).ToList();
} }
} }

@ -9,17 +9,17 @@ namespace CncRepository.Interface
/// </summary> /// </summary>
public interface IDashboardRepository public interface IDashboardRepository
{ {
DashboardSummaryResponse GetSummary(); DashboardSummaryResponse GetSummary(int onlineTimeout = 300);
List<WorkshopProductionResponse> GetWorkshopProduction(DateTime startDate, DateTime endDate); List<WorkshopProductionResponse> GetWorkshopProduction(DateTime startDate, DateTime endDate);
List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top); List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top, int onlineTimeout = 300);
List<WorkerRankResponse> GetWorkerRank(DateTime startDate, DateTime endDate, int top); List<WorkerRankResponse> GetWorkerRank(DateTime startDate, DateTime endDate, int top);
List<dynamic> GetProductionTrend(int days); List<dynamic> GetProductionTrend(int days);
object GetMachineStatusDistribution(); object GetMachineStatusDistribution(int onlineTimeout = 300);
List<AlertListItem> GetRecentAlerts(int count); List<AlertListItem> GetRecentAlerts(int count);
} }

@ -10,18 +10,17 @@ namespace CncRepository.Interface
/// </summary> /// </summary>
public interface IMachineRepository public interface IMachineRepository
{ {
Machine GetById(int id); Machine GetById(int id, int onlineTimeout = 300);
MachineDetailResponse GetDetailById(int id); MachineDetailResponse GetDetailById(int id, int onlineTimeout = 300);
PagedResult<MachineListItem> GetList(MachineQuery query); PagedResult<MachineListItem> GetList(MachineQuery query, int onlineTimeout = 300);
int Create(Machine entity); int Create(Machine entity);
bool Update(Machine entity); bool Update(Machine entity);
bool Delete(int id); bool Delete(int id);
int BatchDelete(List<int> ids); int BatchDelete(List<int> ids);
bool ToggleEnabled(int id); bool ToggleEnabled(int id);
Machine GetByDeviceCode(string deviceCode); Machine GetByDeviceCode(string deviceCode, int onlineTimeout = 300);
List<Machine> GetEnabledByAddressId(int collectAddressId); List<Machine> GetEnabledByAddressId(int collectAddressId, int onlineTimeout = 300);
List<Machine> GetEnabledOnline(); List<Machine> GetEnabledOnline(int onlineTimeout = 300);
void UpdateOnlineStatus(int id, bool isOnline);
void UpdateLastCollect(int id, Machine entity); void UpdateLastCollect(int id, Machine entity);
/// <summary>设置机床所属的采集地址</summary> /// <summary>设置机床所属的采集地址</summary>
void SetCollectAddress(int machineId, int? collectAddressId); void SetCollectAddress(int machineId, int? collectAddressId);

@ -20,18 +20,29 @@ namespace CncService.Impl
private readonly IBrandRepository _brandRepository; private readonly IBrandRepository _brandRepository;
private readonly IWorkshopRepository _workshopRepository; private readonly IWorkshopRepository _workshopRepository;
private readonly ICollectRawRepository _collectRawRepository; private readonly ICollectRawRepository _collectRawRepository;
private readonly ISysConfigRepository _sysConfigRepository;
public CollectAddressService(ICollectAddressRepository collectAddressRepository, public CollectAddressService(ICollectAddressRepository collectAddressRepository,
IMachineRepository machineRepository, IMachineRepository machineRepository,
IBrandRepository brandRepository, IBrandRepository brandRepository,
IWorkshopRepository workshopRepository, IWorkshopRepository workshopRepository,
ICollectRawRepository collectRawRepository) ICollectRawRepository collectRawRepository,
ISysConfigRepository sysConfigRepository)
{ {
_collectAddressRepository = collectAddressRepository; _collectAddressRepository = collectAddressRepository;
_machineRepository = machineRepository; _machineRepository = machineRepository;
_brandRepository = brandRepository; _brandRepository = brandRepository;
_workshopRepository = workshopRepository; _workshopRepository = workshopRepository;
_collectRawRepository = collectRawRepository; _collectRawRepository = collectRawRepository;
_sysConfigRepository = sysConfigRepository;
}
/// <summary>从sys_config读取在线超时阈值</summary>
private int GetOnlineTimeout()
{
var cfg = _sysConfigRepository.GetByKey("online_timeout");
if (cfg != null && int.TryParse(cfg.ConfigValue, out var val) && val > 0) return val;
return 300;
} }
public PagedResult<CollectAddressListItem> GetList(CollectAddressQuery query) public PagedResult<CollectAddressListItem> GetList(CollectAddressQuery query)
@ -161,7 +172,7 @@ namespace CncService.Impl
MachineName = m.Name ?? m.DeviceCode, MachineName = m.Name ?? m.DeviceCode,
DeviceCode = m.DeviceCode, DeviceCode = m.DeviceCode,
WorkshopName = workshopName, WorkshopName = workshopName,
IsOnline = m.IsOnline == 1, IsOnline = m.IsEnabled == 1 && m.LastPingTime.HasValue && (DateTime.Now - m.LastPingTime.Value).TotalSeconds <= GetOnlineTimeout(),
ProgramName = m.LastProgramName ProgramName = m.LastProgramName
}); });
} }

@ -14,20 +14,31 @@ namespace CncService.Impl
private readonly IDashboardRepository _dashboardRepository; private readonly IDashboardRepository _dashboardRepository;
private readonly ICollectorHeartbeatRepository _collectorHeartbeatRepository; private readonly ICollectorHeartbeatRepository _collectorHeartbeatRepository;
private readonly IWindowsServiceChecker _serviceChecker; private readonly IWindowsServiceChecker _serviceChecker;
private readonly ISysConfigRepository _sysConfigRepository;
public DashboardService(IDashboardRepository dashboardRepository, public DashboardService(IDashboardRepository dashboardRepository,
ICollectorHeartbeatRepository collectorHeartbeatRepository, ICollectorHeartbeatRepository collectorHeartbeatRepository,
ISysConfigRepository sysConfigRepository,
IWindowsServiceChecker serviceChecker = null) IWindowsServiceChecker serviceChecker = null)
{ {
_dashboardRepository = dashboardRepository ?? throw new ArgumentNullException(nameof(dashboardRepository)); _dashboardRepository = dashboardRepository ?? throw new ArgumentNullException(nameof(dashboardRepository));
_collectorHeartbeatRepository = collectorHeartbeatRepository ?? throw new ArgumentNullException(nameof(collectorHeartbeatRepository)); _collectorHeartbeatRepository = collectorHeartbeatRepository ?? throw new ArgumentNullException(nameof(collectorHeartbeatRepository));
_sysConfigRepository = sysConfigRepository ?? throw new ArgumentNullException(nameof(sysConfigRepository));
_serviceChecker = serviceChecker; _serviceChecker = serviceChecker;
} }
/// <summary>从sys_config读取online_timeout默认300秒</summary>
private int GetOnlineTimeout()
{
var cfg = _sysConfigRepository.GetByKey("online_timeout");
if (cfg != null && int.TryParse(cfg.ConfigValue, out var val) && val > 0) return val;
return 300;
}
/// <inheritdoc/> /// <inheritdoc/>
public DashboardSummaryResponse GetSummary() public DashboardSummaryResponse GetSummary()
{ {
return _dashboardRepository.GetSummary(); return _dashboardRepository.GetSummary(GetOnlineTimeout());
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -43,7 +54,7 @@ namespace CncService.Impl
{ {
var s = startDate ?? DateTime.Today; var s = startDate ?? DateTime.Today;
var e = endDate ?? DateTime.Today; var e = endDate ?? DateTime.Today;
return _dashboardRepository.GetMachineRank(s, e, top); return _dashboardRepository.GetMachineRank(s, e, top, GetOnlineTimeout());
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -63,7 +74,7 @@ namespace CncService.Impl
/// <inheritdoc/> /// <inheritdoc/>
public object GetMachineStatusDistribution() public object GetMachineStatusDistribution()
{ {
return _dashboardRepository.GetMachineStatusDistribution(); return _dashboardRepository.GetMachineStatusDistribution(GetOnlineTimeout());
} }
/// <inheritdoc/> /// <inheritdoc/>

@ -65,7 +65,6 @@ namespace CncService.Impl
BrandId = request.BrandId, BrandId = request.BrandId,
IpAddress = request.IpAddress, IpAddress = request.IpAddress,
IsEnabled = 1, IsEnabled = 1,
IsOnline = 0,
CreatedAt = DateTime.Now, CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now UpdatedAt = DateTime.Now
}; };

@ -19,15 +19,26 @@ namespace CncService.Impl
private readonly IWorkerRepository _workerRepository; private readonly IWorkerRepository _workerRepository;
private readonly IWorkerMachineRepository _workerMachineRepository; private readonly IWorkerMachineRepository _workerMachineRepository;
private readonly IMachineRepository _machineRepository; private readonly IMachineRepository _machineRepository;
private readonly ISysConfigRepository _sysConfigRepository;
public WorkerService( public WorkerService(
IWorkerRepository workerRepository, IWorkerRepository workerRepository,
IWorkerMachineRepository workerMachineRepository, IWorkerMachineRepository workerMachineRepository,
IMachineRepository machineRepository) IMachineRepository machineRepository,
ISysConfigRepository sysConfigRepository)
{ {
_workerRepository = workerRepository ?? throw new ArgumentNullException(nameof(workerRepository)); _workerRepository = workerRepository ?? throw new ArgumentNullException(nameof(workerRepository));
_workerMachineRepository = workerMachineRepository ?? throw new ArgumentNullException(nameof(workerMachineRepository)); _workerMachineRepository = workerMachineRepository ?? throw new ArgumentNullException(nameof(_workerMachineRepository));
_machineRepository = machineRepository ?? throw new ArgumentNullException(nameof(machineRepository)); _machineRepository = machineRepository ?? throw new ArgumentNullException(nameof(machineRepository));
_sysConfigRepository = sysConfigRepository ?? throw new ArgumentNullException(nameof(sysConfigRepository));
}
/// <summary>从sys_config读取在线超时阈值</summary>
private int GetOnlineTimeout()
{
var cfg = _sysConfigRepository.GetByKey("online_timeout");
if (cfg != null && int.TryParse(cfg.ConfigValue, out var val) && val > 0) return val;
return 300;
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -193,7 +204,7 @@ namespace CncService.Impl
DeviceCode = m.DeviceCode, DeviceCode = m.DeviceCode,
WorkshopName = workshopName, WorkshopName = workshopName,
BrandName = brandName, BrandName = brandName,
IsOnline = m.IsOnline == 1, IsOnline = m.IsEnabled == 1 && m.LastPingTime.HasValue && (DateTime.Now - m.LastPingTime.Value).TotalSeconds <= GetOnlineTimeout(),
ProgramName = m.LastProgramName ProgramName = m.LastProgramName
}); });
} }

@ -114,6 +114,7 @@ namespace CncWebApi.Infrastructure
return new CncService.Impl.DashboardService( return new CncService.Impl.DashboardService(
new CncRepository.Impl.Dashboard.DashboardRepository(_businessConn), new CncRepository.Impl.Dashboard.DashboardRepository(_businessConn),
new CncRepository.Impl.Log.CollectorHeartbeatRepository(_logConn), new CncRepository.Impl.Log.CollectorHeartbeatRepository(_logConn),
new CncRepository.Impl.SysConfigRepository(_businessConn),
serviceChecker); serviceChecker);
} }
@ -141,7 +142,8 @@ namespace CncWebApi.Infrastructure
new CncRepository.Impl.MachineRepository(_businessConn), new CncRepository.Impl.MachineRepository(_businessConn),
new CncRepository.Impl.BrandRepository(_businessConn), new CncRepository.Impl.BrandRepository(_businessConn),
new CncRepository.Impl.WorkshopRepository(_businessConn), new CncRepository.Impl.WorkshopRepository(_businessConn),
new CncRepository.Impl.Log.CollectRawRepository(_logConn)); new CncRepository.Impl.Log.CollectRawRepository(_logConn),
new CncRepository.Impl.SysConfigRepository(_businessConn));
} }
private IWorkerService ResolveWorkerService() private IWorkerService ResolveWorkerService()
@ -149,7 +151,8 @@ namespace CncWebApi.Infrastructure
return new CncService.Impl.WorkerService( return new CncService.Impl.WorkerService(
new CncRepository.Impl.WorkerRepository(_businessConn), new CncRepository.Impl.WorkerRepository(_businessConn),
new CncRepository.Impl.WorkerMachineRepository(_businessConn), new CncRepository.Impl.WorkerMachineRepository(_businessConn),
new CncRepository.Impl.MachineRepository(_businessConn)); new CncRepository.Impl.MachineRepository(_businessConn),
new CncRepository.Impl.SysConfigRepository(_businessConn));
} }
private IProductionService ResolveProductionService() private IProductionService ResolveProductionService()

@ -665,7 +665,6 @@ namespace CncModels.Tests
Assert.Null(m0.IpAddress); Assert.Null(m0.IpAddress);
Assert.Equal(0, m0.BrandId); Assert.Equal(0, m0.BrandId);
Assert.Equal(0, m0.IsEnabled); Assert.Equal(0, m0.IsEnabled);
Assert.Equal(0, m0.IsOnline);
Assert.Null(m0.LastPingTime); Assert.Null(m0.LastPingTime);
Assert.Null(m0.LastCollectTime); Assert.Null(m0.LastCollectTime);
Assert.Null(m0.LastDeviceStatus); Assert.Null(m0.LastDeviceStatus);
@ -687,7 +686,6 @@ namespace CncModels.Tests
IpAddress = "192.168.0.10", IpAddress = "192.168.0.10",
BrandId = 3, BrandId = 3,
IsEnabled = 1, IsEnabled = 1,
IsOnline = 1,
LastPingTime = new DateTime(2026, 4, 28, 12, 0, 0), LastPingTime = new DateTime(2026, 4, 28, 12, 0, 0),
LastCollectTime = new DateTime(2026, 4, 28, 12, 5, 0), LastCollectTime = new DateTime(2026, 4, 28, 12, 5, 0),
LastDeviceStatus = "OK", LastDeviceStatus = "OK",
@ -707,7 +705,6 @@ namespace CncModels.Tests
Assert.Equal("192.168.0.10", m.IpAddress); Assert.Equal("192.168.0.10", m.IpAddress);
Assert.Equal(3, m.BrandId); Assert.Equal(3, m.BrandId);
Assert.Equal(1, m.IsEnabled); Assert.Equal(1, m.IsEnabled);
Assert.Equal(1, m.IsOnline);
Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), m.LastPingTime); Assert.Equal(new DateTime(2026, 4, 28, 12, 0, 0), m.LastPingTime);
Assert.Equal(new DateTime(2026, 4, 28, 12, 5, 0), m.LastCollectTime); Assert.Equal(new DateTime(2026, 4, 28, 12, 5, 0), m.LastCollectTime);
Assert.Equal("OK", m.LastDeviceStatus); Assert.Equal("OK", m.LastDeviceStatus);

@ -41,7 +41,6 @@ namespace CncRepository.Tests
BrandId = 1, BrandId = 1,
IpAddress = "10.1.1.8", IpAddress = "10.1.1.8",
IsEnabled = 1, IsEnabled = 1,
IsOnline = 0,
CreatedAt = DateTime.Now, CreatedAt = DateTime.Now,
UpdatedAt = DateTime.Now UpdatedAt = DateTime.Now
}; };

@ -38,8 +38,8 @@ namespace CncService.Tests
{ {
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())"); VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
} }
TestDb.Execute(@"INSERT INTO cnc_alert (alert_type, machine_id, title, is_resolved, created_at) TestDb.Execute(@"INSERT INTO cnc_alert (alert_type, machine_id, title, is_resolved, created_at)
VALUES (@alertType, 1, '', @isResolved, NOW())", VALUES (@alertType, 1, '', @isResolved, NOW())",

@ -180,8 +180,8 @@ namespace CncService.Tests
{ {
var addressId = InsertTestAddress(); var addressId = InsertTestAddress();
// 关联机床 // 关联机床
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, @addressId, '0.0.0.0', 1, 1, 0, NOW(), NOW())", VALUES ('M001', '1', 1, @addressId, '0.0.0.0', 1, 1, NOW(), NOW())",
new { addressId }); new { addressId });
var result = _service.Delete(addressId); var result = _service.Delete(addressId);

@ -12,12 +12,12 @@ namespace CncService.Tests
// Fake repositories to isolate DashboardService.GetCollectorStatus tests // Fake repositories to isolate DashboardService.GetCollectorStatus tests
public class FakeDashboardRepository : IDashboardRepository public class FakeDashboardRepository : IDashboardRepository
{ {
public DashboardSummaryResponse GetSummary() => new DashboardSummaryResponse(); public DashboardSummaryResponse GetSummary(int something) => new DashboardSummaryResponse();
public List<WorkshopProductionResponse> GetWorkshopProduction(DateTime startDate, DateTime endDate) => new List<WorkshopProductionResponse>(); public List<WorkshopProductionResponse> GetWorkshopProduction(DateTime startDate, DateTime endDate) => new List<WorkshopProductionResponse>();
public List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top) => new List<MachineRankResponse>(); public List<MachineRankResponse> GetMachineRank(DateTime startDate, DateTime endDate, int top, int something) => new List<MachineRankResponse>();
public List<WorkerRankResponse> GetWorkerRank(DateTime startDate, DateTime endDate, int top) => new List<WorkerRankResponse>(); public List<WorkerRankResponse> GetWorkerRank(DateTime startDate, DateTime endDate, int top) => new List<WorkerRankResponse>();
public List<dynamic> GetProductionTrend(int days) => new List<dynamic>(); public List<dynamic> GetProductionTrend(int days) => new List<dynamic>();
public object GetMachineStatusDistribution() => new object(); public object GetMachineStatusDistribution(int something) => new object();
public List<AlertListItem> GetRecentAlerts(int count) => new List<AlertListItem>(); public List<AlertListItem> GetRecentAlerts(int count) => new List<AlertListItem>();
} }
@ -42,6 +42,13 @@ namespace CncService.Tests
true, "Stopped"); true, "Stopped");
} }
public class FakeSysConfigRepository : ISysConfigRepository
{
public SysConfig GetByKey(string configKey) => new SysConfig { ConfigKey = configKey, ConfigValue = "300" };
public List<SysConfig> GetAll() => new List<SysConfig>();
public bool UpdateValue(int id, string value) => true;
}
public class DashboardServiceTests public class DashboardServiceTests
{ {
[Fact] [Fact]
@ -53,7 +60,7 @@ namespace CncService.Tests
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest); var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.NotInstalled); var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.NotInstalled);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, checker); var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
// Act // Act
var resultObj = svc.GetCollectorStatus(); var resultObj = svc.GetCollectorStatus();
@ -77,7 +84,7 @@ namespace CncService.Tests
var dashboardRepo = new FakeDashboardRepository(); var dashboardRepo = new FakeDashboardRepository();
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest); var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Running); var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Running);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, checker); var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
var resultObj = svc.GetCollectorStatus(); var resultObj = svc.GetCollectorStatus();
var t = resultObj.GetType(); var t = resultObj.GetType();
@ -96,7 +103,7 @@ namespace CncService.Tests
var dashboardRepo = new FakeDashboardRepository(); var dashboardRepo = new FakeDashboardRepository();
var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest); var heartbeatRepo = new FakeCollectorHeartbeatRepository(latest);
var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Starting); var checker = new FakeWindowsServiceChecker(CncService.Interface.ServiceStatusEnum.Starting);
var svc = new DashboardService(dashboardRepo, heartbeatRepo, checker); var svc = new DashboardService(dashboardRepo, heartbeatRepo, new FakeSysConfigRepository(), checker);
var resultObj = svc.GetCollectorStatus(); var resultObj = svc.GetCollectorStatus();
var t = resultObj.GetType(); var t = resultObj.GetType();

@ -51,8 +51,8 @@ namespace CncService.Tests
// 插入机床+日产量数据 // 插入机床+日产量数据
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())"); VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_daily_production (machine_id, production_date, program_name, total_quantity, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_daily_production (machine_id, production_date, program_name, total_quantity, created_at, updated_at)
VALUES (1, CURDATE(), 'O0001', 100, NOW(), NOW())"); VALUES (1, CURDATE(), 'O0001', 100, NOW(), NOW())");
@ -75,8 +75,8 @@ namespace CncService.Tests
{ {
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())"); VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_daily_production (machine_id, production_date, program_name, total_quantity, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_daily_production (machine_id, production_date, program_name, total_quantity, created_at, updated_at)
VALUES (1, CURDATE(), 'O0001', 150, NOW(), NOW())"); VALUES (1, CURDATE(), 'O0001', 150, NOW(), NOW())");

@ -65,13 +65,13 @@ namespace CncService.Tests
/// <summary>创建CollectAddressService</summary> /// <summary>创建CollectAddressService</summary>
public static CollectAddressService CreateCollectAddressService() public static CollectAddressService CreateCollectAddressService()
{ {
return new CollectAddressService(NewCollectAddressRepo(), NewMachineRepo(), NewBrandRepo(), NewWorkshopRepo(), NewCollectRawRepo()); return new CollectAddressService(NewCollectAddressRepo(), NewMachineRepo(), NewBrandRepo(), NewWorkshopRepo(), NewCollectRawRepo(), NewSysConfigRepo());
} }
/// <summary>创建WorkerService</summary> /// <summary>创建WorkerService</summary>
public static WorkerService CreateWorkerService() public static WorkerService CreateWorkerService()
{ {
return new WorkerService(NewWorkerRepo(), NewWorkerMachineRepo(), NewMachineRepo()); return new WorkerService(NewWorkerRepo(), NewWorkerMachineRepo(), NewMachineRepo(), NewSysConfigRepo());
} }
/// <summary>创建ProductionService</summary> /// <summary>创建ProductionService</summary>
@ -101,7 +101,7 @@ namespace CncService.Tests
/// <summary>创建DashboardService</summary> /// <summary>创建DashboardService</summary>
public static DashboardService CreateDashboardService() public static DashboardService CreateDashboardService()
{ {
return new DashboardService(NewDashboardRepo(), NewCollectorHeartbeatRepo()); return new DashboardService(NewDashboardRepo(), NewCollectorHeartbeatRepo(), NewSysConfigRepo());
} }
/// <summary>创建CollectDataService</summary> /// <summary>创建CollectDataService</summary>

@ -44,8 +44,8 @@ namespace CncService.Tests
{ {
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES (@code, '', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())", VALUES (@code, '', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())",
new { code = deviceCode }); new { code = deviceCode });
return TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine"); return TestDb.QuerySingle<int>("SELECT MAX(id) FROM cnc_machine");
} }

@ -242,8 +242,8 @@ namespace CncService.Tests
// 先插入有效的采集地址 // 先插入有效的采集地址
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())"); VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
var ex = Assert.Throws<BusinessException>(() => _service.Delete(1)); var ex = Assert.Throws<BusinessException>(() => _service.Delete(1));
Assert.Equal(ErrorCode.DataReferenced, ex.Code); Assert.Equal(ErrorCode.DataReferenced, ex.Code);
@ -292,9 +292,9 @@ namespace CncService.Tests
// 先插入一个有效的采集地址满足cnc_machine的外键约束 // 先插入一个有效的采集地址满足cnc_machine的外键约束
TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_collect_address (name, url, brand_id, collect_interval, is_enabled, created_at, updated_at)
VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())"); VALUES ('', 'http://test', 1, 30, 1, NOW(), NOW())");
TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, is_online, created_at, updated_at) TestDb.Execute(@"INSERT INTO cnc_machine (device_code, name, workshop_id, collect_address_id, ip_address, brand_id, is_enabled, created_at, updated_at)
VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW()), VALUES ('M001', '1', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW()),
('M002', '2', 1, 1, '0.0.0.0', 1, 1, 0, NOW(), NOW())"); ('M002', '2', 1, 1, '0.0.0.0', 1, 1, NOW(), NOW())");
var count = _service.GetMachineCount(1); var count = _service.GetMachineCount(1);
Assert.Equal(2, count); Assert.Equal(2, count);

@ -48,11 +48,11 @@ namespace CncWebApi.Tests
#region Service 创建 #region Service 创建
private static IAuthService CreateAuthService() => new AuthService(SysConfigRepo(), _jwtSecret); private static IAuthService CreateAuthService() => new AuthService(SysConfigRepo(), _jwtSecret);
private static IDashboardService CreateDashboardService() => new DashboardService(DashboardRepo(), HeartbeatRepo()); private static IDashboardService CreateDashboardService() => new DashboardService(DashboardRepo(), HeartbeatRepo(), SysConfigRepo());
private static IMachineService CreateMachineService() => new MachineService(MachineRepo(), CollectAddressRepo(), WorkerMachineRepo(), BrandRepo()); private static IMachineService CreateMachineService() => new MachineService(MachineRepo(), CollectAddressRepo(), WorkerMachineRepo(), BrandRepo());
private static IBrandService CreateBrandService() => new BrandService(BrandRepo(), BrandFieldMappingRepo(), CollectAddressRepo()); private static IBrandService CreateBrandService() => new BrandService(BrandRepo(), BrandFieldMappingRepo(), CollectAddressRepo());
private static ICollectAddressService CreateCollectAddressService() => new CollectAddressService(CollectAddressRepo(), MachineRepo(), BrandRepo(), WorkshopRepo(), CollectRawRepo()); private static ICollectAddressService CreateCollectAddressService() => new CollectAddressService(CollectAddressRepo(), MachineRepo(), BrandRepo(), WorkshopRepo(), CollectRawRepo(), SysConfigRepo());
private static IWorkerService CreateWorkerService() => new WorkerService(WorkerRepo(), WorkerMachineRepo(), MachineRepo()); private static IWorkerService CreateWorkerService() => new WorkerService(WorkerRepo(), WorkerMachineRepo(), MachineRepo(), SysConfigRepo());
private static IProductionService CreateProductionService() => new ProductionService(DailyProductionRepo(), ProductionSegmentRepo(), ProductionAdjustmentRepo()); private static IProductionService CreateProductionService() => new ProductionService(DailyProductionRepo(), ProductionSegmentRepo(), ProductionAdjustmentRepo());
private static IAlertService CreateAlertService() => new AlertService(AlertRepo()); private static IAlertService CreateAlertService() => new AlertService(AlertRepo());
private static IWorkshopService CreateWorkshopService() => new WorkshopService(WorkshopRepo()); private static IWorkshopService CreateWorkshopService() => new WorkshopService(WorkshopRepo());

Loading…
Cancel
Save