添加项目文件。
This commit is contained in:
218
MoviconWebApi/API/DeviceStateApi/Data.cs
Normal file
218
MoviconWebApi/API/DeviceStateApi/Data.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
142
MoviconWebApi/API/DeviceStateApi/Endpoint.cs
Normal file
142
MoviconWebApi/API/DeviceStateApi/Endpoint.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
39
MoviconWebApi/API/DeviceStateApi/Mapper.cs
Normal file
39
MoviconWebApi/API/DeviceStateApi/Mapper.cs
Normal 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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
116
MoviconWebApi/API/DeviceStateApi/Models.cs
Normal file
116
MoviconWebApi/API/DeviceStateApi/Models.cs
Normal 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; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user