添加项目文件。

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,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; }
}
}