using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using WIDESEA_Common.LocationEnum;
using WIDESEA_Common.StockEnum;
using WIDESEA_Core;
using WIDESEA_Model.Models;
namespace WIDESEA_WMSServer.Controllers.Dashboard
{
///
/// 仪表盘
///
[Route("api/Dashboard")]
[ApiController]
public class DashboardController : ControllerBase
{
private readonly ISqlSugarClient _db;
public DashboardController(ISqlSugarClient db)
{
_db = db;
}
///
/// 总览数据
///
[HttpGet("Overview"), AllowAnonymous]
public async Task Overview()
{
try
{
var today = DateTime.Today;
var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
// 今日入库数
var todayInbound = await _db.Queryable()
.Where(t => t.InsertTime >= today && t.TaskType >= 500 && t.TaskType < 600)
.CountAsync();
// 今日出库数
var todayOutbound = await _db.Queryable()
.Where(t => t.InsertTime >= today && t.TaskType >= 100 && t.TaskType < 200)
.CountAsync();
// 本月入库数
var monthInbound = await _db.Queryable()
.Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 500 && t.TaskType < 600)
.CountAsync();
// 本月出库数
var monthOutbound = await _db.Queryable()
.Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 100 && t.TaskType < 200)
.CountAsync();
// 当前总库存
var totalStock = await _db.Queryable().CountAsync();
return WebResponseContent.Instance.OK(null, new
{
TodayInbound = todayInbound,
TodayOutbound = todayOutbound,
MonthInbound = monthInbound,
MonthOutbound = monthOutbound,
TotalStock = totalStock
});
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error($"总览数据获取失败: {ex.Message}");
}
}
///
/// 每日统计(按巷道号分组,指定仓库)
///
[HttpGet("DailyStats"), AllowAnonymous]
public async Task DailyStats([FromQuery] int days = 10)
{
try
{
if (days <= 0) days = 30;
if (days > 365) days = 365;
var startDate = DateTime.Today.AddDays(-days + 1);
var endDate = DateTime.Today; // 包含今天
// 指定要统计的仓库(巷道号)
var specifiedRoadways = new List
{
"GWSC1", "CWSC1", "HCSC1", "ZJSC1", "FJSC1"
};
var query = await _db.Queryable()
.Where(t => t.InsertTime >= startDate && t.InsertTime <= endDate)
.Where(t => specifiedRoadways.Contains(t.Roadway)) // 只查询指定巷道号的数据
.Select(t => new { t.InsertTime, t.TaskType, t.Roadway })
.ToListAsync();
// 生成日期范围
var allDates = new List();
for (var date = startDate; date <= endDate; date = date.AddDays(1))
{
allDates.Add(date);
}
// 按巷道号和日期分组统计
var groupedData = query
.GroupBy(t => new { t.Roadway, Date = t.InsertTime.Date })
.Select(g => new
{
Roadway = g.Key.Roadway,
Date = g.Key.Date,
Inbound = g.Count(t => t.TaskType >= 200 && t.TaskType < 300),
Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
})
.ToList();
// 构建结果:每个指定仓库对应一个日期列表
var result = specifiedRoadways.Select(roadway =>
{
// 获取该巷道号的分组数据字典
var roadwayData = groupedData
.Where(g => g.Roadway == roadway)
.ToDictionary(x => x.Date, x => x);
// 补全缺失日期,确保每天都有数据(默认为0)
var dailyStats = allDates.Select(date =>
{
if (roadwayData.TryGetValue(date, out var data))
{
return new
{
Date = date.ToString("MM-dd"),
Inbound = data.Inbound,
Outbound = data.Outbound
};
}
else
{
return new
{
Date = date.ToString("MM-dd"),
Inbound = 0,
Outbound = 0
};
}
})
.OrderBy(x => x.Date)
.ToList();
return new
{
Roadway = roadway,
DailyStats = dailyStats
};
})
.ToList();
return WebResponseContent.Instance.OK(null, result);
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error($"每日统计获取失败: {ex.Message}");
}
}
///
/// 每周统计
///
///
/// 注意:数据在 SQL 层过滤后,在应用层按 ISO 8601 周键分组。
/// 周键为 "YYYY-Www" 格式,无法直接在 SQL 层用 GROUP BY 实现。
///
[HttpGet("WeeklyStats"), AllowAnonymous]
public async Task WeeklyStats([FromQuery] int weeks = 12)
{
try
{
if (weeks <= 0) weeks = 12;
var startDate = DateTime.Today.AddDays(-weeks * 7);
var query = await _db.Queryable()
.Where(t => t.InsertTime >= startDate)
.Select(t => new { t.InsertTime, t.TaskType })
.ToListAsync();
var result = query
.GroupBy(t => GetWeekKey(t.InsertTime))
.Select(g => new
{
Week = g.Key,
Inbound = g.Count(t => t.TaskType >= 200 && t.TaskType < 300),
Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
})
.OrderBy(x => x.Week)
.ToList();
return WebResponseContent.Instance.OK(null, result);
}
catch (Exception ex)
{
return WebResponseContent.Instance.Error($"每周统计获取失败: {ex.Message}");
}
}
private string GetWeekKey(DateTime date)
{
// 获取周一开始的周 (ISO 8601)
var diff = (7 + (date.DayOfWeek - DayOfWeek.Monday)) % 7;
var monday = date.AddDays(-diff);
var weekNum = System.Globalization.CultureInfo.InvariantCulture
.Calendar.GetWeekOfYear(monday, System.Globalization.CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
return $"{monday.Year}-W{weekNum:D2}";
}
///
/// 按年月统计入站和出站任务数量
///
[HttpGet("MonthlyStats"), AllowAnonymous]
public async Task MonthlyStats(int months, string roadway)
{
try
{
if (months <= 0) months = 12;
var startDate = DateTime.Today.AddMonths(-months + 1);
startDate = new DateTime(startDate.Year, startDate.Month, 1);
// 仓库名称映射
var roadwayNames = new Dictionary
{
{ "GWSC1", "高温1号仓库" },
{ "CWSC1", "常温1号仓库" },
{ "HCSC1", "分容1号仓库" },
{ "FJSC1", "负极卷1号仓库" },
{ "ZJSC1", "正极卷1号仓库" },
};
// 构建查询
var query = _db.Queryable()
.Where(t => t.InsertTime >= startDate);
// 如果指定了道路,添加道路过滤条件
if (!string.IsNullOrEmpty(roadway))
{
query = query.Where(t => t.Roadway == roadway);
}
var monthlyStats = await query
.GroupBy(t => new { t.InsertTime.Year, t.InsertTime.Month })
.Select(t => new
{
Year = t.InsertTime.Year,
Month = t.InsertTime.Month,
Inbound = SqlFunc.AggregateSum(
SqlFunc.IIF(t.TaskType >= 200 && t.TaskType < 300, 1, 0)
),
Outbound = SqlFunc.AggregateSum(
SqlFunc.IIF(t.TaskType >= 100 && t.TaskType < 200, 1, 0)
)
})
.OrderBy(t => t.Year)
.OrderBy(t => t.Month)
.ToListAsync();
// 生成所有需要统计的月份列表
var allMonths = new List();
var currentMonth = startDate;
var endMonth = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1);
while (currentMonth <= endMonth)
{
allMonths.Add(currentMonth);
currentMonth = currentMonth.AddMonths(1);
}
// 将查询结果转换为字典,方便查找
var statsDict = monthlyStats.ToDictionary(
s => $"{s.Year}-{s.Month:D2}",
s => new { s.Inbound, s.Outbound }
);
// 构建完整的结果列表,包含所有月份
var result = new List