添加项目文件。

This commit is contained in:
2025-09-15 17:59:48 +08:00
parent 872f090cc2
commit e7adae128e
91 changed files with 14260 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.ClearDataApi
{
public static class Data
{
internal static async Task<List<ClearDataResponse>?> GetClearData(ClearDataRequest request, IFreeSql freeSql)
{
try
{
// 构建查询
var query = freeSql.Select<ClearData>();
// 根据设备编号过滤
if (!string.IsNullOrWhiteSpace(request.DeviceCode))
{
query = query.Where(x => x.DeviceCode == request.DeviceCode);
}
// 根据开始时间过滤
if (!string.IsNullOrWhiteSpace(request.StartTime) && DateTime.TryParse(request.StartTime, out DateTime startTime))
{
query = query.Where(x => x.CreateTime >= startTime);
}
// 根据结束时间过滤
if (!string.IsNullOrWhiteSpace(request.EndTime) && DateTime.TryParse(request.EndTime, out DateTime endTime))
{
query = query.Where(x => x.CreateTime <= endTime);
}
// 按创建时间降序排序
query = query.OrderByDescending(x => x.CreateTime);
// 执行查询并映射到响应模型
var result = await query.ToListAsync(x => new ClearDataResponse
{
DeviceCode = x.DeviceCode,
DeviceName = x.DeviceName,
program_process = x.program_process,
vehicle_model = x.vehicle_model,
locomotive_number = x.locomotive_number,
repair_process = x.repair_process,
component_name = x.component_name,
part_position = x.part_position,
part_num = x.part_num,
part_qrid = x.part_qrid,
AgentTank_Level = x.AgentTank_Level,
Test_CleaningAgentTankAdd=x.Test_CleaningAgentTankAdd,
Test_CleaningAgentTankHeat=x.Test_CleaningAgentTankHeat,
Test_FrameworkPerModelCleaningAgentUsage = x.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = x.Test_FrameworkPerModelWaterUsage,
WaterTank_Temp = x.WaterTank_Temp,
AgentTank_Temp = x.AgentTank_Temp,
SoakingTank1_Temp = x.SoakingTank1_Temp,
SoakingTank2_Temp = x.SoakingTank2_Temp,
Test_ElectricSurveillance=x.Test_ElectricSurveillance,
Test_FrameworkPerModelCleaningDuration=x.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkProgramProcess=x.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage=x.Test_FrameworkProgramProcessPercentage,
Test_SteamSurveillance= x.Test_SteamSurveillance,
Test_WaterTankAdd= x.Test_WaterTankAdd,
Test_WaterTankHeat= x.Test_WaterTankHeat,
WaterTank_Level=x.WaterTank_Level,
CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return result;
}
catch (Exception ex)
{
// 记录异常日志(可以根据实际需求添加日志记录)
Console.WriteLine($"获取清洗数据失败:{ex.Message}");
return null;
}
}
}
}

View File

@@ -0,0 +1,100 @@
using Azure;
using Azure.Core;
using FastEndpoints;
using MoviconWebApi.API.ClearDataQrApi;
using MoviconWebApi.Common;
namespace MoviconWebApi.API.ClearDataApi
{
/// <summary>
/// 获取清洗数据端点
/// </summary>
public class Endpoint : Endpoint<ClearDataRequest, ApiResponse<List<ClearDataResponse>>>
{
private readonly IFreeSql _freeSql;
/// <summary>
/// 构造函数注入FreeSql实例
/// </summary>
/// <param name="freeSql">FreeSql实例</param>
public Endpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
// 配置路由支持GET和POST两种方式
//Post("/cleardata/list");
Get("/cleardata/listbycode");
// 允许匿名访问(根据实际需求可以改为需要认证)
AllowAnonymous();
// 配置摘要信息用于Swagger文档
Summary(s =>
{
s.Summary = "获取清洗数据列表";
s.Description = "根据设备编号、开始时间、结束时间查询清洗数据";
s.Response< ApiResponse<List<ClearDataResponse>>>(200, "成功返回清洗数据列表");
s.Response(404, "未找到数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(ClearDataRequest request, CancellationToken ct)
{
try
{
// 调用Data层方法获取数据
var dataList = await Data.GetClearData(request, _freeSql);
if (dataList == null || dataList.Count == 0)
{
// 未找到数据返回404
//await Send.NotFoundAsync(ct);
//Response = dataList ?? new List<ClearDataQrResponse>();
//await Send.OkAsync(new List<ClearDataResponse>(), ct);
// 没有数据
Response = ApiResponse<List<ClearDataResponse>>.Success(
new List<ClearDataResponse>(),
"暂无数据"
);
}
else
{
//await Send.OkAsync(dataList, ct);
// 现在的代码
Response = ApiResponse<List<ClearDataResponse>>.Success(
dataList,
"查询成功"
);
}
}
catch (Exception ex)
{
// 记录错误日志
Logger.LogError(ex, "获取清洗数据失败");
// 返回错误响应
Response = ApiResponse<List<ClearDataResponse>>.Error(
"500",
"服务器内部错误"
);
//// 记录错误日志
//Logger.LogError(ex, "获取清洗数据失败");
//// 返回500错误
//await Send.ErrorsAsync(500, ct);
}
}
}
}

View File

@@ -0,0 +1,33 @@
using Azure.Core;
using FastEndpoints;
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.ClearDataApi
{
public class Mapper : Mapper<ClearDataRequest, ClearDataResponse, ClearData>
{
/// <summary>
/// 请求体映射为数据库实体
/// </summary>
/// <param name="r"></param>
/// <returns></returns>
public override ClearData ToEntity(ClearDataRequest r)
{
return new ClearData()
{
AgentTank_Level = "",
};
}
///// <summary>
///// 数据库实体类映射为返回体,我这里返回体就是一个string,就没必要用
///// </summary>
///// <param name="e"></param>
///// <returns></returns>
//public override async Task<ClearDataResponse> FromEntityAsync(ClearData Model )
//{
// return await base.FromEntityAsync(Model,new CancellationToken());
//}
}
}

View File

@@ -0,0 +1,61 @@
using Newtonsoft.Json;
namespace MoviconWebApi.API.ClearDataApi
{
public class ClearDataRequest
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public string? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public string? EndTime { get; set; }
}
public class ClearDataResponse
{
public string? DeviceCode { get; set; }
public string? DeviceName { get; set; }
public string? program_process { get; set; }
public string? vehicle_model { get; set; }
public string? locomotive_number { get; set; }
public string? repair_process { get; set; }
public string? component_name { get; set; }
public string? part_position { get; set; }
public string? part_num { get; set; }
public string? part_qrid { get; set; }
public string? Test_FrameworkProgramProcessPercentage { get; set; }
public string? Test_FrameworkProgramProcess { get; set; }
public string? Test_FrameworkPerModelCleaningDuration { get; set; }
public string? Test_FrameworkPerModelCleaningAgentUsage { get; set; }
public string? Test_FrameworkPerModelWaterUsage { get; set; }
public string? WaterTank_Temp { get; set; }
public string? AgentTank_Temp { get; set; }
public string? WaterTank_Level { get; set; }
public string? AgentTank_Level { get; set; }
public string? SoakingTank1_Temp { get; set; }
public string? SoakingTank2_Temp { get; set; }
public string? Test_WaterTankHeat { get; set; }
public string? Test_WaterTankAdd { get; set; }
public string? Test_CleaningAgentTankHeat { get; set; }
public string? Test_CleaningAgentTankAdd { get; set; }
public string? Test_ElectricSurveillance { get; set; }
public string? Test_SteamSurveillance { get; set; }
[JsonIgnore]
public string? CreateTime { get; set; }
}
}

View File

@@ -0,0 +1,293 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.ClearDataQrApi
{
/// <summary>
/// 清洗数据二维码查询数据访问层
/// </summary>
public static class Data
{
/// <summary>
/// 根据设备编号和部件二维码查询清洗数据
/// </summary>
/// <param name="request">查询请求参数</param>
/// <param name="freeSql">FreeSql实例</param>
/// <returns>清洗数据列表</returns>
public static async Task<List<ClearDataQrResponse>> GetClearDataByQr(
ClearDataQrRequest request,
IFreeSql freeSql)
{
try
{
// 使用FreeSql的Fluent API构建查询
var query = freeSql.Select<ClearData>();
// 添加设备编号条件
if (!string.IsNullOrWhiteSpace(request.DeviceCode))
{
query = query.Where(x => x.DeviceCode == request.DeviceCode);
}
// 添加部件二维码条件
if (!string.IsNullOrWhiteSpace(request.PartQRCode))
{
query = query.Where(x => x.part_qrid == request.PartQRCode);
}
// 按创建时间降序排序
query = query.OrderByDescending(x => x.CreateTime);
// 执行查询并映射到响应模型
var result = await query.ToListAsync(x => new ClearDataQrResponse
{
DeviceCode = x.DeviceCode,
DeviceName = x.DeviceName,
program_process = x.program_process,
vehicle_model = x.vehicle_model,
locomotive_number = x.locomotive_number,
repair_process = x.repair_process,
component_name = x.component_name,
part_position = x.part_position,
part_num = x.part_num,
part_qrid = x.part_qrid,
AgentTank_Level = x.AgentTank_Level,
Test_CleaningAgentTankAdd = x.Test_CleaningAgentTankAdd,
Test_CleaningAgentTankHeat = x.Test_CleaningAgentTankHeat,
Test_FrameworkPerModelCleaningAgentUsage = x.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = x.Test_FrameworkPerModelWaterUsage,
WaterTank_Temp = x.WaterTank_Temp,
AgentTank_Temp = x.AgentTank_Temp,
SoakingTank1_Temp = x.SoakingTank1_Temp,
SoakingTank2_Temp = x.SoakingTank2_Temp,
Test_ElectricSurveillance = x.Test_ElectricSurveillance,
Test_FrameworkPerModelCleaningDuration = x.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkProgramProcess = x.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = x.Test_FrameworkProgramProcessPercentage,
Test_SteamSurveillance = x.Test_SteamSurveillance,
Test_WaterTankAdd = x.Test_WaterTankAdd,
Test_WaterTankHeat = x.Test_WaterTankHeat,
WaterTank_Level = x.WaterTank_Level,
CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return result;
}
catch (Exception ex)
{
// 记录异常(在生产环境中应使用适当的日志框架)
Console.WriteLine($"查询清洗数据时出错: {ex.Message}");
throw;
}
}
/// <summary>
/// 分页查询清洗数据
/// </summary>
/// <param name="request">分页查询请求参数</param>
/// <param name="freeSql">FreeSql实例</param>
/// <returns>分页数据和总数</returns>
public static async Task<(List<ClearDataQrResponse> Data, long Total)> GetClearDataPagedByQr(
ClearDataQrPagedRequest request,
IFreeSql freeSql)
{
try
{
// 使用FreeSql的Fluent API构建查询
var query = freeSql.Select<ClearData>();
// 添加设备编号条件
if (!string.IsNullOrWhiteSpace(request.DeviceCode))
{
query = query.Where(x => x.DeviceCode == request.DeviceCode);
}
// 添加部件二维码条件
if (!string.IsNullOrWhiteSpace(request.PartQRCode))
{
query = query.Where(x => x.part_qrid == request.PartQRCode);
}
// 按创建时间降序排序
query = query.OrderByDescending(x => x.CreateTime);
// 获取总数
var total = await query.CountAsync();
// 分页查询并映射到响应模型
var data = await query
.Page(request.PageIndex, request.PageSize)
.ToListAsync(x => new ClearDataQrResponse
{
DeviceCode = x.DeviceCode,
DeviceName = x.DeviceName,
program_process = x.program_process,
vehicle_model = x.vehicle_model,
locomotive_number = x.locomotive_number,
repair_process = x.repair_process,
component_name = x.component_name,
part_position = x.part_position,
part_num = x.part_num,
part_qrid = x.part_qrid,
AgentTank_Level = x.AgentTank_Level,
Test_CleaningAgentTankAdd = x.Test_CleaningAgentTankAdd,
Test_CleaningAgentTankHeat = x.Test_CleaningAgentTankHeat,
Test_FrameworkPerModelCleaningAgentUsage = x.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = x.Test_FrameworkPerModelWaterUsage,
WaterTank_Temp = x.WaterTank_Temp,
AgentTank_Temp = x.AgentTank_Temp,
SoakingTank1_Temp = x.SoakingTank1_Temp,
SoakingTank2_Temp = x.SoakingTank2_Temp,
Test_ElectricSurveillance = x.Test_ElectricSurveillance,
Test_FrameworkPerModelCleaningDuration = x.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkProgramProcess = x.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = x.Test_FrameworkProgramProcessPercentage,
Test_SteamSurveillance = x.Test_SteamSurveillance,
Test_WaterTankAdd = x.Test_WaterTankAdd,
Test_WaterTankHeat = x.Test_WaterTankHeat,
WaterTank_Level = x.WaterTank_Level,
CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return (data, total);
}
catch (Exception ex)
{
// 记录异常(在生产环境中应使用适当的日志框架)
Console.WriteLine($"分页查询清洗数据时出错: {ex.Message}");
throw;
}
}
/// <summary>
/// 获取最新的清洗数据记录
/// </summary>
/// <param name="request">查询请求(可包含设备编号筛选)</param>
/// <param name="freeSql">FreeSql实例</param>
/// <returns>最新的清洗数据记录如果没有则返回null</returns>
public static async Task<ClearDataQrResponse?> GetLatestClearData(
ClearDataQrRequest request,
IFreeSql freeSql)
{
try
{
// 使用FreeSql的Fluent API构建查询
var query = freeSql.Select<ClearData>();
// 添加设备编号条件(如果提供)
if (!string.IsNullOrWhiteSpace(request.DeviceCode))
{
query = query.Where(x => x.DeviceCode == request.DeviceCode);
}
// 添加部件二维码条件(如果提供)
if (!string.IsNullOrWhiteSpace(request.PartQRCode))
{
query = query.Where(x => x.part_qrid == request.PartQRCode);
}
// 按创建时间降序排序,取第一条
var result = await query
.OrderByDescending(x => x.CreateTime)
.Limit(1)
.FirstAsync(x => new ClearDataQrResponse
{
DeviceCode = x.DeviceCode,
DeviceName = x.DeviceName,
program_process = x.program_process,
vehicle_model = x.vehicle_model,
locomotive_number = x.locomotive_number,
repair_process = x.repair_process,
component_name = x.component_name,
part_position = x.part_position,
part_num = x.part_num,
part_qrid = x.part_qrid,
AgentTank_Level = x.AgentTank_Level,
Test_CleaningAgentTankAdd = x.Test_CleaningAgentTankAdd,
Test_CleaningAgentTankHeat = x.Test_CleaningAgentTankHeat,
Test_FrameworkPerModelCleaningAgentUsage = x.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = x.Test_FrameworkPerModelWaterUsage,
WaterTank_Temp = x.WaterTank_Temp,
AgentTank_Temp = x.AgentTank_Temp,
SoakingTank1_Temp = x.SoakingTank1_Temp,
SoakingTank2_Temp = x.SoakingTank2_Temp,
Test_ElectricSurveillance = x.Test_ElectricSurveillance,
Test_FrameworkPerModelCleaningDuration = x.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkProgramProcess = x.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = x.Test_FrameworkProgramProcessPercentage,
Test_SteamSurveillance = x.Test_SteamSurveillance,
Test_WaterTankAdd = x.Test_WaterTankAdd,
Test_WaterTankHeat = x.Test_WaterTankHeat,
WaterTank_Level = x.WaterTank_Level,
CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return result;
}
catch (Exception ex)
{
// 记录异常(在生产环境中应使用适当的日志框架)
Console.WriteLine($"获取最新清洗数据时出错: {ex.Message}");
throw;
}
}
/// <summary>
/// 根据部件二维码获取所有相关的清洗记录
/// </summary>
/// <param name="partQRCode">部件二维码</param>
/// <param name="freeSql">FreeSql实例</param>
/// <returns>清洗数据列表</returns>
public static async Task<List<ClearDataQrResponse>> GetClearDataByPartQRCode(
string partQRCode,
IFreeSql freeSql)
{
try
{
// 使用FreeSql的Fluent API构建查询
var result = await freeSql.Select<ClearData>()
.Where(x => x.part_qrid == partQRCode)
.OrderByDescending(x => x.CreateTime)
.ToListAsync(x => new ClearDataQrResponse
{
DeviceCode = x.DeviceCode,
DeviceName = x.DeviceName,
program_process = x.program_process,
vehicle_model = x.vehicle_model,
locomotive_number = x.locomotive_number,
repair_process = x.repair_process,
component_name = x.component_name,
part_position = x.part_position,
part_num = x.part_num,
part_qrid = x.part_qrid,
AgentTank_Level = x.AgentTank_Level,
Test_CleaningAgentTankAdd = x.Test_CleaningAgentTankAdd,
Test_CleaningAgentTankHeat = x.Test_CleaningAgentTankHeat,
Test_FrameworkPerModelCleaningAgentUsage = x.Test_FrameworkPerModelCleaningAgentUsage,
Test_FrameworkPerModelWaterUsage = x.Test_FrameworkPerModelWaterUsage,
WaterTank_Temp = x.WaterTank_Temp,
AgentTank_Temp = x.AgentTank_Temp,
SoakingTank1_Temp = x.SoakingTank1_Temp,
SoakingTank2_Temp = x.SoakingTank2_Temp,
Test_ElectricSurveillance = x.Test_ElectricSurveillance,
Test_FrameworkPerModelCleaningDuration = x.Test_FrameworkPerModelCleaningDuration,
Test_FrameworkProgramProcess = x.Test_FrameworkProgramProcess,
Test_FrameworkProgramProcessPercentage = x.Test_FrameworkProgramProcessPercentage,
Test_SteamSurveillance = x.Test_SteamSurveillance,
Test_WaterTankAdd = x.Test_WaterTankAdd,
Test_WaterTankHeat = x.Test_WaterTankHeat,
WaterTank_Level = x.WaterTank_Level,
CreateTime = x.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return result;
}
catch (Exception ex)
{
// 记录异常(在生产环境中应使用适当的日志框架)
Console.WriteLine($"根据二维码查询清洗数据时出错: {ex.Message}");
throw;
}
}
}
}

View File

@@ -0,0 +1,257 @@
using Azure;
using FastEndpoints;
using Microsoft.Extensions.Logging;
using MoviconWebApi.Common;
namespace MoviconWebApi.API.ClearDataQrApi
{
/// <summary>
/// 根据设备编号和部件二维码查询清洗数据端点
/// </summary>
public class GetByQrEndpoint : Endpoint<ClearDataQrRequest, ApiResponse<List<ClearDataQrResponse>>>
{
private readonly IFreeSql _freeSql;
public GetByQrEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/cleardata-qr/list");
AllowAnonymous();
Summary(s =>
{
s.Summary = "根据设备编号和部件二维码查询清洗数据";
s.Description = "可以通过设备编号、部件二维码或两者组合查询清洗数据";
s.Response<ApiResponse<List<ClearDataQrResponse>>>(200, "成功返回清洗数据列表");
s.Response(404, "未找到数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(ClearDataQrRequest request, CancellationToken ct)
{
try
{
var dataList = await Data.GetClearDataByQr(request, _freeSql);
if (dataList == null || dataList.Count == 0)
{
Response = ApiResponse<List<ClearDataQrResponse>>.Success(
new List<ClearDataQrResponse>(), "暂无数据");// "暂无数据"
}
else
{
Response = ApiResponse<List<ClearDataQrResponse>>.Success(
dataList, "查询成功");// "查询成功"
}
}
catch (Exception ex)
{
//Logger.LogError(ex, "根据二维码查询清洗数据失败");
//await Send.ErrorsAsync(500, ct);
Logger.LogError(ex, "根据二维码查询清洗数据失败");
Response = ApiResponse<List<ClearDataQrResponse>>.Error(
"500",
"服务器内部错误"
);
}
}
}
/// <summary>
/// 分页查询清洗数据端点
/// </summary>
public class GetPagedByQrEndpoint : Endpoint<ClearDataQrPagedRequest, ClearDataQrPagedResponse>
{
private readonly IFreeSql _freeSql;
public GetPagedByQrEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Post("/cleardata-qr/paged");
AllowAnonymous();
Summary(s =>
{
s.Summary = "分页查询清洗数据";
s.Description = "根据设备编号和部件二维码分页查询清洗数据";
s.Response<ClearDataQrPagedResponse>(200, "成功返回分页数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(ClearDataQrPagedRequest request, CancellationToken ct)
{
try
{
// 验证分页参数
if (request.PageIndex < 1)
request.PageIndex = 1;
if (request.PageSize < 1)
request.PageSize = 20;
if (request.PageSize > 100)
request.PageSize = 100;
// 调用Data层方法获取元组返回值
var (data, total) = await Data.GetClearDataPagedByQr(request, _freeSql);
// 构建响应对象
Response = new ClearDataQrPagedResponse
{
Items = data,
TotalCount = total,
PageIndex = request.PageIndex,
PageSize = request.PageSize
};
}
catch (Exception ex)
{
Logger.LogError(ex, "分页查询清洗数据失败");
await Send.ErrorsAsync(500, ct);
}
}
}
/// <summary>
/// 获取最新清洗数据端点
/// </summary>
public class GetLatestByQrEndpoint : Endpoint<ClearDataQrRequest, ClearDataQrResponse>
{
private readonly IFreeSql _freeSql;
public GetLatestByQrEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/cleardata-qr/latest");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取最新的清洗数据";
s.Description = "根据设备编号和部件二维码获取最新的一条清洗数据";
s.Response<ClearDataQrResponse>(200, "成功返回最新清洗数据");
s.Response(404, "未找到数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(ClearDataQrRequest request, CancellationToken ct)
{
try
{
// 调用重构后的方法直接传递request对象
var latestData = await Data.GetLatestClearData(request, _freeSql);
if (latestData == null)
{
//await Send.NotFoundAsync(ct);
Response = latestData ?? new ClearDataQrResponse();
}
else
{
Response = latestData;
}
}
catch (Exception ex)
{
Logger.LogError(ex, "获取最新清洗数据失败");
await Send.ErrorsAsync(500, ct);
}
}
}
/// <summary>
/// 根据部件二维码获取所有清洗记录端点
/// </summary>
public class GetByPartQrCodeRequest
{
/// <summary>
/// 部件二维码(必填)
/// </summary>
public string PartQRCode { get; set; } = string.Empty;
}
public class GetByPartQrCodeEndpoint : Endpoint<GetByPartQrCodeRequest, List<ClearDataQrResponse>>
{
private readonly IFreeSql _freeSql;
public GetByPartQrCodeEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/cleardata-qr/by-qrcode/{PartQRCode}");
AllowAnonymous();
Summary(s =>
{
s.Summary = "根据部件二维码获取所有清洗记录";
s.Description = "仅根据部件二维码查询该部件的所有清洗历史记录";
s.Response<List<ClearDataQrResponse>>(200, "成功返回清洗数据列表");
s.Response(400, "请求参数错误");
s.Response(404, "未找到数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(GetByPartQrCodeRequest request, CancellationToken ct)
{
try
{
// 验证参数
if (string.IsNullOrWhiteSpace(request.PartQRCode))
{
AddError("PartQRCode", "部件二维码不能为空");
await Send.ErrorsAsync(400, ct);
return;
}
// 调用重构后的方法
var dataList = await Data.GetClearDataByPartQRCode(request.PartQRCode, _freeSql);
if (dataList == null || dataList.Count == 0)
{
//await Send.NotFoundAsync(ct);
Response = dataList ?? new List<ClearDataQrResponse>();
}
else
{
Response = dataList;
}
}
catch (Exception ex)
{
Logger.LogError(ex, "根据部件二维码查询清洗数据失败");
await Send.ErrorsAsync(500, ct);
}
}
}
}

View File

@@ -0,0 +1,99 @@
namespace MoviconWebApi.API.ClearDataQrApi
{
/// <summary>
/// 数据映射器
/// </summary>
public static class Mapper
{
/// <summary>
/// 将数据库实体映射到响应模型
/// </summary>
/// <param name="entity">数据库实体</param>
/// <returns>响应模型</returns>
public static ClearDataQrResponse ToResponse(dynamic entity)
{
if (entity == null) return null;
var response = new ClearDataQrResponse
{
DeviceCode = entity.DeviceCode?.ToString(),
DeviceName = entity.DeviceName?.ToString(),
program_process = entity.program_process?.ToString(),
vehicle_model = entity.vehicle_model?.ToString(),
locomotive_number = entity.locomotive_number?.ToString(),
repair_process = entity.repair_process?.ToString(),
component_name = entity.component_name?.ToString(),
part_position = entity.part_position?.ToString(),
part_num = entity.part_num?.ToString(),
part_qrid = entity.part_qrid?.ToString(),
Test_FrameworkPerModelCleaningDuration = entity.Test_FrameworkPerModelCleaningDuration?.ToString(),
Test_FrameworkPerModelCleaningAgentUsage = entity.Test_FrameworkPerModelCleaningAgentUsage?.ToString(),
Test_FrameworkPerModelWaterUsage = entity.Test_FrameworkPerModelWaterUsage?.ToString(),
WaterTank_Temp = entity.WaterTank_Temp?.ToString(),
AgentTank_Temp = entity.AgentTank_Temp?.ToString(),
SoakingTank1_Temp = entity.SoakingTank1_Temp?.ToString(),
SoakingTank2_Temp = entity.SoakingTank2_Temp?.ToString()
};
// 处理时间字段
if (entity.CreateTime != null)
{
if (entity.CreateTime is DateTime dt)
{
response.CreateTime = dt.ToString("yyyy-MM-dd HH:mm:ss");
}
else
{
response.CreateTime = entity.CreateTime.ToString();
}
}
return response;
}
/// <summary>
/// 格式化日期时间
/// </summary>
/// <param name="dateTimeString">日期时间字符串</param>
/// <returns>格式化后的字符串</returns>
public static string FormatDateTime(string dateTimeString)
{
if (string.IsNullOrWhiteSpace(dateTimeString))
return dateTimeString;
if (DateTime.TryParse(dateTimeString, out DateTime dateTime))
{
return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
}
return dateTimeString;
}
/// <summary>
/// 解析数值类型
/// </summary>
/// <param name="value">原始值</param>
/// <returns>数值或null</returns>
public static double? ParseDouble(object value)
{
if (value == null) return null;
if (value is double d)
return d;
if (value is float f)
return f;
if (value is decimal dec)
return (double)dec;
if (value is int i)
return i;
if (double.TryParse(value.ToString(), out double result))
return result;
return null;
}
}
}

View File

@@ -0,0 +1,109 @@
namespace MoviconWebApi.API.ClearDataQrApi
{
/// <summary>
/// 清洗数据二维码查询请求模型
/// </summary>
public class ClearDataQrRequest
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 部件二维码
/// </summary>
public string? PartQRCode { get; set; }
}
/// <summary>
/// 清洗数据响应模型
/// </summary>
public class ClearDataQrResponse
{
public string? DeviceCode { get; set; }
public string? DeviceName { get; set; }
public string? program_process { get; set; }
public string? vehicle_model { get; set; }
public string? locomotive_number { get; set; }
public string? repair_process { get; set; }
public string? component_name { get; set; }
public string? part_position { get; set; }
public string? part_num { get; set; }
public string? part_qrid { get; set; }
public string? Test_FrameworkProgramProcessPercentage { get; set; }
public string? Test_FrameworkProgramProcess { get; set; }
public string? Test_FrameworkPerModelCleaningDuration { get; set; }
public string? Test_FrameworkPerModelCleaningAgentUsage { get; set; }
public string? Test_FrameworkPerModelWaterUsage { get; set; }
public string? WaterTank_Temp { get; set; }
public string? AgentTank_Temp { get; set; }
public string? WaterTank_Level { get; set; }
public string? AgentTank_Level { get; set; }
public string? SoakingTank1_Temp { get; set; }
public string? SoakingTank2_Temp { get; set; }
public string? Test_WaterTankHeat { get; set; }
public string? Test_WaterTankAdd { get; set; }
public string? Test_CleaningAgentTankHeat { get; set; }
public string? Test_CleaningAgentTankAdd { get; set; }
public string? Test_ElectricSurveillance { get; set; }
public string? Test_SteamSurveillance { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string? CreateTime { get; set; }
}
/// <summary>
/// 分页查询请求模型
/// </summary>
public class ClearDataQrPagedRequest : ClearDataQrRequest
{
/// <summary>
/// 页码从1开始
/// </summary>
public int PageIndex { get; set; } = 1;
/// <summary>
/// 每页数据量
/// </summary>
public int PageSize { get; set; } = 20;
}
/// <summary>
/// 分页响应模型
/// </summary>
public class ClearDataQrPagedResponse
{
/// <summary>
/// 数据列表
/// </summary>
public List<ClearDataQrResponse> Items { get; set; } = new List<ClearDataQrResponse>();
/// <summary>
/// 总记录数
/// </summary>
public long TotalCount { get; set; }
/// <summary>
/// 当前页码
/// </summary>
public int PageIndex { get; set; }
/// <summary>
/// 每页数量
/// </summary>
public int PageSize { get; set; }
/// <summary>
/// 总页数
/// </summary>
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)TotalCount / PageSize) : 0;
}
}

View File

@@ -0,0 +1,103 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.ClearStaticApi
{
/// <summary>
/// 清洗统计数据访问类
/// </summary>
public static class Data
{
/// <summary>
/// 获取清洗统计数据
/// </summary>
/// <param name="request">请求参数</param>
/// <param name="freeSql">FreeSql实例</param>
/// <returns>清洗统计响应</returns>
internal static async Task<ClearStaticResponse?> GetClearStatic(ClearStaticRequest request, IFreeSql freeSql)
{
try
{
// 获取当前日期信息
var today = DateTime.Today;
var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
var firstDayOfYear = new DateTime(today.Year, 1, 1);
// 构建基础查询
var query = freeSql.Select<DeviceState>();
// 构建基础查询
//var queryDeviceState = freeSql.Select<DeviceState>();
var CurRunClearData = freeSql.Select<CurRunClearState>().Where(a => a.Test_PartsEquipmentStatus == "1").OrderByDescending(a => a.CreateTime).First();
// 根据设备编号过滤
if (!string.IsNullOrWhiteSpace(request.DeviceCode))
{
query = query.Where(x => x.DeviceCode == request.DeviceCode);
}
// 计算累计作业数量
var totalJobCount = await query.CountAsync();
// 计算本年度作业数
var yearJobCount = await query
.Where(x => x.CreateTime >= firstDayOfYear)
.CountAsync();
// 计算本月作业数
var monthJobCount = await query
.Where(x => x.CreateTime >= firstDayOfMonth)
.CountAsync();
// 计算今日作业数
var todayJobCount = await query
.Where(x => x.CreateTime >= today)
.CountAsync();
// 计算累计作业时长
// 注意这里假设ClearData表中有一个字段表示清洗时长可能需要根据实际情况调整
var totalJobHours = await query
.SumAsync(x => Convert.ToDecimal(x.RunTime)) / 60; // 假设时长单位是秒,转换为小时
// 计算本年作业时长
var yearJobHours = await query
.Where(x => x.CreateTime >= firstDayOfYear)
.SumAsync(x => Convert.ToDecimal(x.RunTime)) / 60;
// 计算本月作业时长
var monthJobHours = await query
.Where(x => x.CreateTime >= firstDayOfMonth)
.SumAsync(x => Convert.ToDecimal(x.RunTime)) / 60;
// 计算今日作业时长
var todayJobHours = await query
.Where(x => x.CreateTime >= today)
.SumAsync(x => Convert.ToDecimal(x.RunTime)) / 60;
// 返回结果
return new ClearStaticResponse
{
TotalJobCount = (int)totalJobCount,
YearJobCount = (int)yearJobCount,
MonthJobCount = (int)monthJobCount,
TodayJobCount = (int)todayJobCount,
TotalJobHours = Math.Round(totalJobHours, 2),
YearJobHours = Math.Round(yearJobHours, 2),
MonthJobHours = Math.Round(monthJobHours, 2),
TodayJobHours = Math.Round(todayJobHours, 2),
CurrentVehicleModel = CurRunClearData != null ? CurRunClearData.vehicle_model : "",
CurrentLocomotiveNumber = CurRunClearData != null ? CurRunClearData.locomotive_number : "",
CurrentRepairProcess = CurRunClearData != null ? CurRunClearData.repair_process : "",
CurrentWheelNumber = "", // 假设part_num字段存储车轮编号
UpdateTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
};
}
catch (Exception ex)
{
// 记录异常日志
Console.WriteLine($"获取清洗统计数据失败:{ex.Message}");
return null;
}
}
}
}

View File

@@ -0,0 +1,80 @@
using Azure;
using FastEndpoints;
using Microsoft.Extensions.Logging;
using MoviconWebApi.Common;
namespace MoviconWebApi.API.ClearStaticApi
{
/// <summary>
/// 获取清洗统计数据端点
/// </summary>
public class Endpoint : Endpoint<ClearStaticRequest, ApiResponse<ClearStaticResponse>>
{
private readonly IFreeSql _freeSql;
/// <summary>
/// 构造函数注入FreeSql实例
/// </summary>
/// <param name="freeSql">FreeSql实例</param>
public Endpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
// 配置路由支持GET方式
Get("/clearstatic/summary");
// 允许匿名访问(根据实际需求可以改为需要认证)
AllowAnonymous();
// 配置摘要信息用于Swagger文档
Summary(s =>
{
s.Summary = "获取清洗统计数据";
s.Description = "根据设备编号获取清洗统计数据,包括作业数量、作业时长等";
s.Response<ApiResponse<ClearStaticResponse>>(200, "成功返回清洗统计数据");
s.Response(404, "未找到数据");
s.Response(500, "服务器内部错误");
});
}
public override async Task HandleAsync(ClearStaticRequest request, CancellationToken ct)
{
try
{
// 调用Data层方法获取数据
var staticData = await Data.GetClearStatic(request, _freeSql);
if (staticData == null)
{
// 未找到数据返回空数据但状态码200
Response = ApiResponse<ClearStaticResponse>.Success(
new ClearStaticResponse(),
"暂无数据"
);
}
else
{
// 返回统计数据
Response = ApiResponse<ClearStaticResponse>.Success(
staticData,
"查询成功"
);
}
}
catch (Exception ex)
{
// 记录错误日志
Logger.LogError(ex, "获取清洗统计数据失败");
// 返回错误响应
Response = ApiResponse<ClearStaticResponse>.Error(
"500",
"服务器内部错误"
);
}
}
}
}

View File

@@ -0,0 +1,28 @@
namespace MoviconWebApi.API.ClearStaticApi
{
/// <summary>
/// 清洗统计数据映射工具类
/// </summary>
public static class Mapper
{
/// <summary>
/// 格式化小数为两位小数的字符串
/// </summary>
/// <param name="value">原始值</param>
/// <returns>格式化后的字符串</returns>
public static string FormatDecimal(decimal value)
{
return value.ToString("0.00");
}
/// <summary>
/// 格式化日期时间为yyyy-MM-dd HH:mm:ss格式
/// </summary>
/// <param name="dateTime">日期时间</param>
/// <returns>格式化后的字符串</returns>
public static string FormatDateTime(DateTime dateTime)
{
return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
}
}
}

View File

@@ -0,0 +1,84 @@
namespace MoviconWebApi.API.ClearStaticApi
{
/// <summary>
/// 清洗统计请求模型
/// </summary>
public class ClearStaticRequest
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
}
/// <summary>
/// 清洗统计响应模型
/// </summary>
public class ClearStaticResponse
{
/// <summary>
/// 累计作业数量
/// </summary>
public int TotalJobCount { get; set; }
/// <summary>
/// 本年度作业数
/// </summary>
public int YearJobCount { get; set; }
/// <summary>
/// 本月作业数
/// </summary>
public int MonthJobCount { get; set; }
/// <summary>
/// 今日作业数
/// </summary>
public int TodayJobCount { get; set; }
/// <summary>
/// 累计作业时长(时)
/// </summary>
public decimal TotalJobHours { get; set; }
/// <summary>
/// 本年作业时长(时)
/// </summary>
public decimal YearJobHours { get; set; }
/// <summary>
/// 本月作业时长(时)
/// </summary>
public decimal MonthJobHours { get; set; }
/// <summary>
/// 今日作业时长(时)
/// </summary>
public decimal TodayJobHours { get; set; }
/// <summary>
/// 当前机型
/// </summary>
public string? CurrentVehicleModel { get; set; }
/// <summary>
/// 当前车号
/// </summary>
public string? CurrentLocomotiveNumber { get; set; }
/// <summary>
/// 当前修程
/// </summary>
public string? CurrentRepairProcess { get; set; }
/// <summary>
/// 车轮编号
/// </summary>
public string? CurrentWheelNumber { get; set; }
/// <summary>
/// 更新时间
/// </summary>
public string? UpdateTime { get; set; }
}
}

View File

@@ -0,0 +1,171 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.DeviceAlarmApi
{
public static class DeviceAlarmData
{
/// <summary>
/// 获取设备报警列表
/// </summary>
public static async Task<List<DeviceAlarmResponse>> GetDeviceAlarmList(
IFreeSql freeSql,
DeviceAlarmRequest request)
{
try
{
var query = freeSql.Select<DeviceAlarm>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode),
a => a.DeviceCode == request.DeviceCode)
.WhereIf(request.DeviceState > 0,
a => a.DeviceState == request.DeviceState);
// 处理时间范围查询
if (!string.IsNullOrWhiteSpace(request.StartTime) && DateTime.TryParse(request.StartTime, out var startTime))
{
query = query.Where(a => a.StartTime >= startTime);
}
if (!string.IsNullOrWhiteSpace(request.EndTime) && DateTime.TryParse(request.EndTime, out var endTime))
{
query = query.Where(a => a.EndTime <= endTime);
}
var data = await query
.OrderByDescending(a => a.StartTime)
.ToListAsync(a => new DeviceAlarmResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
DeviceState = a.DeviceState,
AlarmMessage = a.AlarmMessage,
StartTime = a.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = a.EndTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return data ?? new List<DeviceAlarmResponse>();
}
catch (Exception ex)
{
throw new Exception($"获取设备报警数据失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取设备报警分页数据
/// </summary>
public static async Task<(List<DeviceAlarmResponse> Items, long Total)> GetDeviceAlarmPagedList(
IFreeSql freeSql,
DeviceAlarmPagedRequest request)
{
try
{
var query = freeSql.Select<DeviceAlarm>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode),
a => a.DeviceCode == request.DeviceCode)
.WhereIf(request.DeviceState > 0,
a => a.DeviceState == request.DeviceState);
// 处理时间范围查询
if (!string.IsNullOrWhiteSpace(request.StartTime) && DateTime.TryParse(request.StartTime, out var startTime))
{
query = query.Where(a => a.StartTime >= startTime);
}
if (!string.IsNullOrWhiteSpace(request.EndTime) && DateTime.TryParse(request.EndTime, out var endTime))
{
query = query.Where(a => a.EndTime <= endTime);
}
var total = await query.CountAsync();
var data = await query
.OrderByDescending(a => a.StartTime)
.Page(request.PageNumber, request.PageSize)
.ToListAsync(a => new DeviceAlarmResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
DeviceState = a.DeviceState,
AlarmMessage = a.AlarmMessage,
StartTime = a.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = a.EndTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return (data ?? new List<DeviceAlarmResponse>(), total);
}
catch (Exception ex)
{
throw new Exception($"获取设备报警分页数据失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取最新的设备报警记录
/// </summary>
public static async Task<DeviceAlarmResponse?> GetLatestDeviceAlarm(
IFreeSql freeSql,
DeviceAlarmRequest request)
{
try
{
var query = freeSql.Select<DeviceAlarm>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode),
a => a.DeviceCode == request.DeviceCode)
.WhereIf(request.DeviceState > 0,
a => a.DeviceState == request.DeviceState);
var data = await query
.OrderByDescending(a => a.StartTime)
.FirstAsync(a => new DeviceAlarmResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
DeviceState = a.DeviceState,
AlarmMessage = a.AlarmMessage,
StartTime = a.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = a.EndTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return data;
}
catch (Exception ex)
{
throw new Exception($"获取最新设备报警数据失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取指定设备的活动报警EndTime为最大值表示未结束
/// </summary>
public static async Task<List<DeviceAlarmResponse>> GetActiveAlarms(
IFreeSql freeSql,
string? deviceCode)
{
try
{
var query = freeSql.Select<DeviceAlarm>()
.WhereIf(!string.IsNullOrWhiteSpace(deviceCode),
a => a.DeviceCode == deviceCode)
.Where(a => a.EndTime == DateTime.MaxValue || a.EndTime > DateTime.Now);
var data = await query
.OrderByDescending(a => a.StartTime)
.ToListAsync(a => new DeviceAlarmResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
DeviceState = a.DeviceState,
AlarmMessage = a.AlarmMessage,
StartTime = a.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = a.EndTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return data ?? new List<DeviceAlarmResponse>();
}
catch (Exception ex)
{
throw new Exception($"获取活动报警数据失败: {ex.Message}", ex);
}
}
}
}

View File

@@ -0,0 +1,174 @@
using Azure;
using FastEndpoints;
using MoviconWebApi.Common;
using MoviconWebApi.Entities;
using System;
namespace MoviconWebApi.API.DeviceAlarmApi
{
/// <summary>
/// 设备报警列表查询端点
/// </summary>
public class GetDeviceAlarmListEndpoint : Endpoint<DeviceAlarmRequest, ApiResponse<List<DeviceAlarmResponse>>>
{
private readonly IFreeSql _freeSql;
public GetDeviceAlarmListEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/devicealarm/list");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取设备报警列表";
s.Description = "根据设备编号、时间范围和设备状态查询设备报警";
s.Response<ApiResponse<List<DeviceAlarmResponse>>>(200, "成功返回设备报警列表");
});
}
public override async Task HandleAsync(DeviceAlarmRequest req, CancellationToken ct)
{
try
{
var data = await DeviceAlarmData.GetDeviceAlarmList(_freeSql, req);
Response = ApiResponse<List<DeviceAlarmResponse>>.Success(data, "success");
}
catch (Exception ex)
{
Response = ApiResponse<List<DeviceAlarmResponse>>.Error("500", $"获取数据失败: {ex.Message}");
}
}
}
/// <summary>
/// 设备报警分页查询端点
/// </summary>
public class GetDeviceAlarmPagedEndpoint : Endpoint<DeviceAlarmPagedRequest, ApiResponse<DeviceAlarmPagedResponse>>
{
private readonly IFreeSql _freeSql;
public GetDeviceAlarmPagedEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Post("/devicealarm/paged");
AllowAnonymous();
Summary(s =>
{
s.Summary = "分页获取设备报警";
s.Description = "根据设备编号、时间范围和设备状态分页查询设备报警";
s.Response<ApiResponse<DeviceAlarmPagedResponse>>(200, "成功返回设备报警分页数据");
});
}
public override async Task HandleAsync(DeviceAlarmPagedRequest req, CancellationToken ct)
{
try
{
var (items, total) = await DeviceAlarmData.GetDeviceAlarmPagedList(_freeSql, req);
var pagedResponse = new DeviceAlarmPagedResponse
{
Items = items,
Total = total
};
Response = ApiResponse<DeviceAlarmPagedResponse>.Success(pagedResponse, "success");
}
catch (Exception ex)
{
Response = ApiResponse<DeviceAlarmPagedResponse>.Error("500", $"获取数据失败: {ex.Message}");
}
}
}
/// <summary>
/// 获取最新设备报警端点
/// </summary>
public class GetLatestDeviceAlarmEndpoint : Endpoint<DeviceAlarmRequest, ApiResponse<DeviceAlarmResponse>>
{
private readonly IFreeSql _freeSql;
public GetLatestDeviceAlarmEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/devicealarm/latest");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取最新设备报警";
s.Description = "根据设备编号获取最新的设备报警记录";
s.Response<ApiResponse<DeviceAlarmResponse>>(200, "成功返回最新设备报警");
});
}
public override async Task HandleAsync(DeviceAlarmRequest req, CancellationToken ct)
{
try
{
var data = await DeviceAlarmData.GetLatestDeviceAlarm(_freeSql, req);
if (data == null)
{
Response = ApiResponse<DeviceAlarmResponse>.Error("404", "未找到设备报警记录");
}
else
{
Response = ApiResponse<DeviceAlarmResponse>.Success(data, "success");
}
}
catch (Exception ex)
{
Response = ApiResponse<DeviceAlarmResponse>.Error("500", $"获取数据失败: {ex.Message}");
}
}
}
/// <summary>
/// 获取活动报警端点
/// </summary>
public class GetActiveAlarmsEndpoint : Endpoint<DeviceAlarmRequest, ApiResponse<List<DeviceAlarmResponse>>>
{
private readonly IFreeSql _freeSql;
public GetActiveAlarmsEndpoint(IFreeSql freeSql)
{
_freeSql = freeSql;
}
public override void Configure()
{
Get("/devicealarm/active");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取活动报警";
s.Description = "获取指定设备的所有活动(未结束)报警";
s.Response<ApiResponse<List<DeviceAlarmResponse>>>(200, "成功返回活动报警列表");
});
}
public override async Task HandleAsync(DeviceAlarmRequest req, CancellationToken ct)
{
try
{
var data = await DeviceAlarmData.GetActiveAlarms(_freeSql, req.DeviceCode);
Response = ApiResponse<List<DeviceAlarmResponse>>.Success(data, "success");
}
catch (Exception ex)
{
Response = ApiResponse<List<DeviceAlarmResponse>>.Error("500", $"获取数据失败: {ex.Message}");
}
}
}
}

View File

@@ -0,0 +1,42 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.DeviceAlarmApi
{
/// <summary>
/// 设备报警数据映射器
/// </summary>
public static class DeviceAlarmMapper
{
/// <summary>
/// 将实体映射到响应模型
/// </summary>
public static DeviceAlarmResponse ToResponse(this DeviceAlarm entity)
{
return new DeviceAlarmResponse
{
DeviceCode = entity.DeviceCode,
DeviceName = entity.DeviceName,
DeviceState = entity.DeviceState,
AlarmMessage = entity.AlarmMessage,
StartTime = entity.StartTime.ToString("yyyy-MM-dd HH:mm:ss"),
EndTime = entity.EndTime.ToString("yyyy-MM-dd HH:mm:ss")
};
}
/// <summary>
/// 批量映射
/// </summary>
public static List<DeviceAlarmResponse> ToResponseList(this IEnumerable<DeviceAlarm> entities)
{
return entities.Select(e => e.ToResponse()).ToList();
}
/// <summary>
/// 判断报警是否活动
/// </summary>
public static bool IsActive(this DeviceAlarm entity)
{
return entity.EndTime == DateTime.MaxValue || entity.EndTime > DateTime.Now;
}
}
}

View File

@@ -0,0 +1,96 @@
namespace MoviconWebApi.API.DeviceAlarmApi
{
/// <summary>
/// 设备报警查询请求
/// </summary>
public class DeviceAlarmRequest
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public string? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public string? EndTime { get; set; }
/// <summary>
/// 设备状态0表示返回所有状态记录
/// </summary>
public int DeviceState { get; set; } = 0;
}
/// <summary>
/// 设备报警分页查询请求
/// </summary>
public class DeviceAlarmPagedRequest : DeviceAlarmRequest
{
/// <summary>
/// 页码
/// </summary>
public int PageNumber { get; set; } = 1;
/// <summary>
/// 每页大小
/// </summary>
public int PageSize { get; set; } = 10;
}
/// <summary>
/// 设备报警响应
/// </summary>
public class DeviceAlarmResponse
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string? DeviceName { get; set; }
/// <summary>
/// 设备状态
/// </summary>
public int? DeviceState { get; set; }
/// <summary>
/// 报警信息
/// </summary>
public string? AlarmMessage { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public string? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public string? EndTime { get; set; }
}
/// <summary>
/// 设备报警分页响应
/// </summary>
public class DeviceAlarmPagedResponse
{
/// <summary>
/// 数据列表
/// </summary>
public List<DeviceAlarmResponse> Items { get; set; } = new List<DeviceAlarmResponse>();
/// <summary>
/// 总数
/// </summary>
public long Total { get; set; }
}
}

View File

@@ -0,0 +1,218 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.DeviceStateApi
{
public static class Data
{
/// <summary>
/// 获取设备状态列表
/// </summary>
public static async Task<List<DeviceStateResponse>> GetDeviceStateListAsync(
IFreeSql db,
DeviceStateRequest request)
{
try
{
// 1) 校验时间范围
var hasStart = DateTime.TryParse(request.StartTime, out var startTime);
var hasEnd = DateTime.TryParse(request.EndTime, out var endTime);
if (!hasStart || !hasEnd)
{
// 未提供有效时间范围返回空列表遵循列表查询返回空集合不返回404的约定
return new List<DeviceStateResponse>();
}
if (endTime < startTime)
{
// 纠正时间顺序或直接返回空
return new List<DeviceStateResponse>();
}
var totalMinutes = (endTime - startTime).TotalMinutes;
if (totalMinutes <= 0)
{
return new List<DeviceStateResponse>();
}
// 2) 基础查询(按设备、时间过滤)
var baseQuery = db.Select<DeviceState>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode), x => x.DeviceCode == request.DeviceCode)
.Where(x => x.CreateTime >= startTime && x.CreateTime <= endTime);
// 3) 聚合统计:仅选择必要字段到内存做聚合,避免类型不兼容问题
var lightList = await baseQuery.ToListAsync(a => new
{
a.PowerOnTime,
a.RunTime,
a.StandbyTime,
a.FaultTime,
a.ShutdownTime,
a.FaultNum,
a.JobNum
});
long totalPowerOn = lightList.Sum(x => (long)(x.PowerOnTime ?? 0));
long totalRun = lightList.Sum(x => (long)(x.RunTime ?? 0));
long totalStandby = lightList.Sum(x => (long)(x.StandbyTime ?? 0));
long totalFault = lightList.Sum(x => (long)(x.FaultTime ?? 0));
long totalShutdown = lightList.Sum(x => (long)(x.ShutdownTime ?? 0));
long totalFaultCount = lightList.Sum(x => (long)(x.FaultNum ?? 0));
long totalJobCount = lightList.Sum(x => (long)(x.JobNum ?? 0));
// 若该时间段内没有任何记录,返回空集合
var hasAnyData = (totalPowerOn + totalRun + totalStandby + totalFault + totalShutdown + totalFaultCount + totalJobCount) > 0;
if (!hasAnyData)
{
return new List<DeviceStateResponse>();
}
// 4) 计算使用率:默认按(开机+运行+待机+故障)/ 时间段总分钟
var usedMinutes = totalPowerOn + totalRun + totalStandby + totalFault; // 排除关机
double ratio = usedMinutes <= 0 ? 0 : Math.Min(100.0, Math.Max(0.0, usedMinutes * 100.0 / totalMinutes));
var useRatioText = $"{Math.Round(ratio, 2)}%";
// 5) 获取设备名称(取时间段内最新一条的名称,避免跨设备统计导致名称混淆)
string? deviceName = null;
try
{
deviceName = await db.Select<DeviceState>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode), x => x.DeviceCode == request.DeviceCode)
.Where(x => x.CreateTime >= startTime && x.CreateTime <= endTime)
.OrderByDescending(x => x.CreateTime)
.FirstAsync(x => x.DeviceName);
}
catch
{
// 忽略设备名获取失败,不影响主逻辑
}
// 6) 组装单条汇总结果
var summary = new DeviceStateResponse
{
DeviceCode = string.IsNullOrWhiteSpace(request.DeviceCode) ? null : request.DeviceCode,
DeviceName = deviceName,
PowerOnTime = (int)totalPowerOn,
RunTime = (int)totalRun,
StandbyTime = (int)totalStandby,
FaultTime = (int)totalFault,
ShutdownTime = (int)totalShutdown,
UseRatio = useRatioText,
FaultNum = (int)totalFaultCount,
JobNum = (int)totalJobCount,
CreateTime = endTime.ToString("yyyy-MM-dd HH:mm:ss")
};
return new List<DeviceStateResponse> { summary };
}
catch (Exception ex)
{
throw new Exception($"查询设备状态数据失败: {ex.Message}", ex);
}
}
/// <summary>
/// 分页获取设备状态
/// </summary>
public static async Task<(List<DeviceStateResponse>, long)> GetDeviceStatePagedAsync(
IFreeSql db,
DeviceStatePagedRequest request)
{
try
{
var query = db.Select<DeviceState>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode),
a => a.DeviceCode == request.DeviceCode);
if (!string.IsNullOrWhiteSpace(request.StartTime) &&
DateTime.TryParse(request.StartTime, out var startTime))
{
query = query.Where(a => a.CreateTime >= startTime);
}
if (!string.IsNullOrWhiteSpace(request.EndTime) &&
DateTime.TryParse(request.EndTime, out var endTime))
{
query = query.Where(a => a.CreateTime <= endTime);
}
var total = await query.CountAsync();
var data = await query
.OrderByDescending(a => a.CreateTime)
.Page(request.PageIndex, request.PageSize)
.ToListAsync(a => new DeviceStateResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
PowerOnTime = a.PowerOnTime,
RunTime = a.RunTime,
StandbyTime = a.StandbyTime,
FaultTime = a.FaultTime,
ShutdownTime = a.ShutdownTime,
UseRatio = a.UseRatio,
FaultNum = a.FaultNum,
JobNum = a.JobNum,
CreateTime = a.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return (data ?? new List<DeviceStateResponse>(), total);
}
catch (Exception ex)
{
throw new Exception($"分页查询设备状态数据失败: {ex.Message}", ex);
}
}
/// <summary>
/// 获取最新的设备状态记录
/// </summary>
public static async Task<DeviceStateResponse?> GetLatestDeviceStateAsync(
IFreeSql db,
DeviceStateRequest request)
{
try
{
var query = db.Select<DeviceState>()
.WhereIf(!string.IsNullOrWhiteSpace(request.DeviceCode),
a => a.DeviceCode == request.DeviceCode);
if (!string.IsNullOrWhiteSpace(request.StartTime) &&
DateTime.TryParse(request.StartTime, out var startTime))
{
query = query.Where(a => a.CreateTime >= startTime);
}
if (!string.IsNullOrWhiteSpace(request.EndTime) &&
DateTime.TryParse(request.EndTime, out var endTime))
{
query = query.Where(a => a.CreateTime <= endTime);
}
var data = await query
.OrderByDescending(a => a.CreateTime)
.FirstAsync(a => new DeviceStateResponse
{
DeviceCode = a.DeviceCode,
DeviceName = a.DeviceName,
PowerOnTime = a.PowerOnTime,
RunTime = a.RunTime,
StandbyTime = a.StandbyTime,
FaultTime = a.FaultTime,
ShutdownTime = a.ShutdownTime,
UseRatio = a.UseRatio,
FaultNum = a.FaultNum,
JobNum = a.JobNum,
CreateTime = a.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
});
return data;
}
catch (Exception ex)
{
throw new Exception($"查询最新设备状态数据失败: {ex.Message}", ex);
}
}
}
}

View File

@@ -0,0 +1,142 @@
using Azure;
using FastEndpoints;
using MoviconWebApi.Common;
namespace MoviconWebApi.API.DeviceStateApi
{
/// <summary>
/// 获取设备状态列表
/// </summary>
public class GetListEndpoint : Endpoint<DeviceStateRequest, ApiResponse<List<DeviceStateResponse>>>
{
private readonly IFreeSql _db;
public GetListEndpoint(IFreeSql db)
{
_db = db;
}
public override void Configure()
{
Get("/devicestate/list");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取设备状态列表";
s.Description = "根据设备编号和时间范围查询设备状态数据";
s.Response<ApiResponse<List<DeviceStateResponse>>>(200, "成功返回设备状态数据列表");
});
}
public override async Task HandleAsync(DeviceStateRequest req, CancellationToken ct)
{
try
{
var data = await Data.GetDeviceStateListAsync(_db, req);
Response = ApiResponse<List<DeviceStateResponse>>.Success(data, "success");
}
catch (Exception ex)
{
Response = ApiResponse<List<DeviceStateResponse>>.Error(
"500",
$"查询失败: {ex.Message}",
new List<DeviceStateResponse>());
}
}
}
/// <summary>
/// 分页获取设备状态
/// </summary>
public class GetPagedEndpoint : Endpoint<DeviceStatePagedRequest, ApiResponse<DeviceStatePagedResponse>>
{
private readonly IFreeSql _db;
public GetPagedEndpoint(IFreeSql db)
{
_db = db;
}
public override void Configure()
{
Post("/devicestate/paged");
AllowAnonymous();
Summary(s =>
{
s.Summary = "分页获取设备状态";
s.Description = "分页查询设备状态数据,支持设备编号和时间范围筛选";
s.Response<ApiResponse<DeviceStatePagedResponse>>(200, "成功返回分页数据");
});
}
public override async Task HandleAsync(DeviceStatePagedRequest req, CancellationToken ct)
{
try
{
var (items, total) = await Data.GetDeviceStatePagedAsync(_db, req);
var pagedResponse = new DeviceStatePagedResponse
{
Items = items,
Total = total
};
Response = ApiResponse<DeviceStatePagedResponse>.Success(pagedResponse, "success");
}
catch (Exception ex)
{
Response = ApiResponse<DeviceStatePagedResponse>.Error(
"500",
$"查询失败: {ex.Message}",
new DeviceStatePagedResponse());
}
}
}
/// <summary>
/// 获取最新的设备状态记录
/// </summary>
public class GetLatestEndpoint : Endpoint<DeviceStateRequest, ApiResponse<DeviceStateResponse>>
{
private readonly IFreeSql _db;
public GetLatestEndpoint(IFreeSql db)
{
_db = db;
}
public override void Configure()
{
Get("/devicestate/latest");
AllowAnonymous();
Summary(s =>
{
s.Summary = "获取最新的设备状态记录";
s.Description = "获取指定设备的最新状态记录";
s.Response<ApiResponse<DeviceStateResponse>>(200, "成功返回最新记录");
s.Response<ApiResponse<DeviceStateResponse>>(404, "未找到记录");
});
}
public override async Task HandleAsync(DeviceStateRequest req, CancellationToken ct)
{
try
{
var data = await Data.GetLatestDeviceStateAsync(_db, req);
if (data == null)
{
Response = ApiResponse<DeviceStateResponse>.Error("404", "未找到数据", null);
}
else
{
Response = ApiResponse<DeviceStateResponse>.Success(data, "success");
}
}
catch (Exception ex)
{
Response = ApiResponse<DeviceStateResponse>.Error(
"500",
$"查询失败: {ex.Message}",
null);
}
}
}
}

View File

@@ -0,0 +1,39 @@
using MoviconWebApi.Entities;
namespace MoviconWebApi.API.DeviceStateApi
{
/// <summary>
/// 设备状态数据映射器
/// </summary>
public static class Mapper
{
/// <summary>
/// 将实体映射到响应模型
/// </summary>
public static DeviceStateResponse ToResponse(this DeviceState entity)
{
return new DeviceStateResponse
{
DeviceCode = entity.DeviceCode,
DeviceName = entity.DeviceName,
PowerOnTime = entity.PowerOnTime,
RunTime = entity.RunTime,
StandbyTime = entity.StandbyTime,
FaultTime = entity.FaultTime,
ShutdownTime = entity.ShutdownTime,
UseRatio = entity.UseRatio,
FaultNum = entity.FaultNum,
JobNum = entity.JobNum,
CreateTime = entity.CreateTime.ToString("yyyy-MM-dd HH:mm:ss")
};
}
/// <summary>
/// 将实体列表映射到响应模型列表
/// </summary>
public static List<DeviceStateResponse> ToResponseList(this List<DeviceState> entities)
{
return entities?.Select(e => e.ToResponse()).ToList() ?? new List<DeviceStateResponse>();
}
}
}

View File

@@ -0,0 +1,116 @@
namespace MoviconWebApi.API.DeviceStateApi
{
/// <summary>
/// 设备状态查询请求
/// </summary>
public class DeviceStateRequest
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 开始时间
/// </summary>
public string? StartTime { get; set; }
/// <summary>
/// 结束时间
/// </summary>
public string? EndTime { get; set; }
}
/// <summary>
/// 设备状态分页请求
/// </summary>
public class DeviceStatePagedRequest : DeviceStateRequest
{
/// <summary>
/// 页码从1开始
/// </summary>
public int PageIndex { get; set; } = 1;
/// <summary>
/// 每页数量
/// </summary>
public int PageSize { get; set; } = 10;
}
/// <summary>
/// 设备状态响应
/// </summary>
public class DeviceStateResponse
{
/// <summary>
/// 设备编号
/// </summary>
public string? DeviceCode { get; set; }
/// <summary>
/// 设备名称
/// </summary>
public string? DeviceName { get; set; }
/// <summary>
/// 开机时长(分钟)
/// </summary>
public int? PowerOnTime { get; set; }
/// <summary>
/// 运行时长(分钟)
/// </summary>
public int? RunTime { get; set; }
/// <summary>
/// 待机时长(分钟)
/// </summary>
public int? StandbyTime { get; set; }
/// <summary>
/// 故障时长(分钟)
/// </summary>
public int? FaultTime { get; set; }
/// <summary>
/// 关机时长(分钟)
/// </summary>
public int? ShutdownTime { get; set; }
/// <summary>
/// 使用率
/// </summary>
public string? UseRatio { get; set; }
/// <summary>
/// 故障次数
/// </summary>
public int? FaultNum { get; set; }
/// <summary>
/// 作业次数
/// </summary>
public int? JobNum { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string? CreateTime { get; set; }
}
/// <summary>
/// 设备状态分页响应
/// </summary>
public class DeviceStatePagedResponse
{
/// <summary>
/// 数据列表
/// </summary>
public List<DeviceStateResponse> Items { get; set; } = new();
/// <summary>
/// 总记录数
/// </summary>
public long Total { get; set; }
}
}