| | |
| | | using Microsoft.AspNetCore.Mvc;
|
| | | using SqlSugar;
|
| | | using WIDESEA_Common.LocationEnum;
|
| | | using WIDESEA_Common.StockEnum;
|
| | | using WIDESEA_Core;
|
| | | using WIDESEA_Model.Models;
|
| | |
|
| | |
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// 每日统计
|
| | | /// 每日统计(按巷道号分组,指定仓库)
|
| | | /// </summary>
|
| | | [HttpGet("DailyStats"), AllowAnonymous]
|
| | | public async Task<WebResponseContent> DailyStats([FromQuery] int days = 30)
|
| | | public async Task<WebResponseContent> DailyStats([FromQuery] int days = 10)
|
| | | {
|
| | | try
|
| | | {
|
| | |
| | | var startDate = DateTime.Today.AddDays(-days + 1);
|
| | | var endDate = DateTime.Today; // 包含今天
|
| | |
|
| | | // 指定要统计的仓库(巷道号)
|
| | | var specifiedRoadways = new List<string>
|
| | | {
|
| | | "GWSC1", "CWSC1", "HCSC1", "ZJSC1", "FJSC1"
|
| | | };
|
| | |
|
| | | var query = await _db.Queryable<Dt_Task_Hty>()
|
| | | .Where(t => t.InsertTime >= startDate && t.InsertTime <= endDate)
|
| | | .Select(t => new { t.InsertTime, t.TaskType })
|
| | | .Where(t => specifiedRoadways.Contains(t.Roadway)) // 只查询指定巷道号的数据
|
| | | .Select(t => new { t.InsertTime, t.TaskType, t.Roadway })
|
| | | .ToListAsync();
|
| | |
|
| | | // 生成日期范围
|
| | |
| | | allDates.Add(date);
|
| | | }
|
| | |
|
| | | // 按日期分组统计
|
| | | // 按巷道号和日期分组统计
|
| | | var groupedData = query
|
| | | .GroupBy(t => t.InsertTime.Date)
|
| | | .GroupBy(t => new { t.Roadway, Date = t.InsertTime.Date })
|
| | | .Select(g => new
|
| | | {
|
| | | Date = g.Key,
|
| | | 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)
|
| | | })
|
| | | .ToDictionary(x => x.Date, x => x);
|
| | | .ToList();
|
| | |
|
| | | // 补全缺失日期
|
| | | var result = allDates.Select(date =>
|
| | | // 构建结果:每个指定仓库对应一个日期列表
|
| | | var result = specifiedRoadways.Select(roadway =>
|
| | | {
|
| | | if (groupedData.TryGetValue(date, out var data))
|
| | | // 获取该巷道号的分组数据字典
|
| | | var roadwayData = groupedData
|
| | | .Where(g => g.Roadway == roadway)
|
| | | .ToDictionary(x => x.Date, x => x);
|
| | |
|
| | | // 补全缺失日期,确保每天都有数据(默认为0)
|
| | | var dailyStats = allDates.Select(date =>
|
| | | {
|
| | | return new
|
| | | if (roadwayData.TryGetValue(date, out var data))
|
| | | {
|
| | | Date = date.ToString("MM-dd"),
|
| | | Inbound = data.Inbound,
|
| | | Outbound = data.Outbound
|
| | | };
|
| | | }
|
| | | else
|
| | | 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
|
| | | {
|
| | | return new
|
| | | {
|
| | | Date = date.ToString("MM-dd"),
|
| | | Inbound = 0,
|
| | | Outbound = 0
|
| | | };
|
| | | }
|
| | | Roadway = roadway,
|
| | | DailyStats = dailyStats
|
| | | };
|
| | | })
|
| | | .OrderBy(x => x.Date)
|
| | | .ToList();
|
| | |
|
| | | return WebResponseContent.Instance.OK(null, result);
|
| | |
| | | return $"{monday.Year}-W{weekNum:D2}";
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// 每月统计
|
| | | /// </summary>
|
| | | /// <remarks>
|
| | | /// 按年月统计入站和出站任务数量
|
| | | /// </remarks>
|
| | | [HttpGet("MonthlyStats"), AllowAnonymous]
|
| | | public async Task<WebResponseContent> MonthlyStats([FromQuery] int months = 12)
|
| | | public async Task<WebResponseContent> MonthlyStats(int months, string roadway)
|
| | | {
|
| | | try
|
| | | {
|
| | |
| | | var startDate = DateTime.Today.AddMonths(-months + 1);
|
| | | startDate = new DateTime(startDate.Year, startDate.Month, 1);
|
| | |
|
| | | var monthlyStats = await _db.Queryable<Dt_Task_Hty>()
|
| | | .Where(t => t.InsertTime >= startDate)
|
| | | // 仓库名称映射
|
| | | var roadwayNames = new Dictionary<string, string>
|
| | | {
|
| | |
|
| | | { "GWSC1", "高温1号仓库" },
|
| | | { "CWSC1", "常温1号仓库" },
|
| | | { "HCSC1", "分容1号仓库" },
|
| | | { "FJSC1", "负极卷1号仓库" },
|
| | | { "ZJSC1", "正极卷1号仓库" },
|
| | | };
|
| | |
|
| | | // 构建查询
|
| | | var query = _db.Queryable<Dt_Task_Hty>()
|
| | | .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
|
| | | {
|
| | |
| | | {
|
| | | Month = monthKey,
|
| | | Inbound = stat.Inbound,
|
| | | Outbound = stat.Outbound
|
| | | Outbound = stat.Outbound,
|
| | | Roadway = roadway,
|
| | | RoadwayName = !string.IsNullOrEmpty(roadway) && roadwayNames.ContainsKey(roadway)
|
| | | ? roadwayNames[roadway]
|
| | | : null
|
| | | });
|
| | | }
|
| | | else
|
| | |
| | | {
|
| | | Month = monthKey,
|
| | | Inbound = 0,
|
| | | Outbound = 0
|
| | | Outbound = 0,
|
| | | Roadway = roadway,
|
| | | RoadwayName = !string.IsNullOrEmpty(roadway) && roadwayNames.ContainsKey(roadway)
|
| | | ? roadwayNames[roadway]
|
| | | : null
|
| | | });
|
| | | }
|
| | | }
|
| | |
| | | }
|
| | | catch (Exception ex)
|
| | | {
|
| | | // 记录异常日志(实际项目中建议使用日志框架)
|
| | | // _logger.LogError(ex, "每月统计获取失败");
|
| | |
|
| | | return WebResponseContent.Instance.Error($"每月统计获取失败: {ex.Message}");
|
| | | }
|
| | | }
|
| | |
|
| | | /// <summary>
|
| | | /// 库存库龄分布
|
| | | /// </summary>
|
| | |
| | | return WebResponseContent.Instance.Error($"各仓库库存分布获取失败: {ex.Message}");
|
| | | }
|
| | | }
|
| | | /// <summary>
|
| | | /// 查询各仓库电池/有货数量和空托盘数量
|
| | | /// </summary>
|
| | | /// <remarks>
|
| | | /// 仓库ID规则:1=高温库, 2=常温库, 3=化成库, 6/7=极卷库
|
| | | /// <br/>
|
| | | /// 统计规则:
|
| | | /// <br/>
|
| | | /// - 高温/常温/化成库:统计 电池数量(StockStatus=6) 和 空托盘数量(StockStatus=22)
|
| | | /// <br/>
|
| | | /// - 极卷库(6/7):统计 有货数量(StockStatus≠22) 和 空托盘数量(StockStatus=22)
|
| | | /// <br/>
|
| | | /// 通过返回数据中的 StockStatus 和 Count 可以进一步查询明细电池。
|
| | | /// </remarks>
|
| | | [HttpGet("StockAndTrayCount"), AllowAnonymous]
|
| | | public async Task<WebResponseContent> StockAndTrayCount()
|
| | | {
|
| | | try
|
| | | {
|
| | | var warehouseIds = new[] { 1, 2, 3, 6, 7 };
|
| | |
|
| | | var warehouseNames = new Dictionary<int, string>
|
| | | {
|
| | | { 1, "高温库" },
|
| | | { 2, "常温库" },
|
| | | { 3, "化成库" },
|
| | | { 6, "极卷库" },
|
| | | { 7, "极卷库" }
|
| | | };
|
| | |
|
| | | var result = new List<object>();
|
| | |
|
| | | foreach (var warehouseId in warehouseIds)
|
| | | {
|
| | | var warehouseName = warehouseNames.GetValueOrDefault(warehouseId, $"仓库{warehouseId}");
|
| | |
|
| | | if (warehouseId == 6 || warehouseId == 7)
|
| | | {
|
| | | var totalCount = await _db.Queryable<Dt_StockInfo>()
|
| | | .Where(s => s.WarehouseId == warehouseId)
|
| | | .CountAsync();
|
| | |
|
| | | var emptyTrayCount = await _db.Queryable<Dt_StockInfo>()
|
| | | .Where(s => s.WarehouseId == warehouseId && s.StockStatus == (int)StockStatusEmun.空托盘库存)
|
| | | .CountAsync();
|
| | |
|
| | | result.Add(new
|
| | | {
|
| | | WarehouseId = warehouseId,
|
| | | WarehouseName = warehouseName,
|
| | | HasGoodsCount = totalCount - emptyTrayCount,
|
| | | EmptyTrayCount = emptyTrayCount,
|
| | | });
|
| | | }
|
| | | else
|
| | | {
|
| | | var batteryCount = await _db.Queryable<Dt_StockInfo>()
|
| | | .Where(s => s.WarehouseId == warehouseId && s.StockStatus == (int)StockStatusEmun.入库完成)
|
| | | .LeftJoin<Dt_StockInfoDetail>((s, d) => s.Id == d.StockId)
|
| | | .CountAsync();
|
| | |
|
| | | var emptyTrayCount = await _db.Queryable<Dt_StockInfo>()
|
| | | .Where(s => s.WarehouseId == warehouseId && s.StockStatus == (int)StockStatusEmun.空托盘库存)
|
| | | .CountAsync();
|
| | |
|
| | | result.Add(new
|
| | | {
|
| | | WarehouseId = warehouseId,
|
| | | WarehouseName = warehouseName,
|
| | | BatteryCount = batteryCount,
|
| | | EmptyTrayCount = emptyTrayCount,
|
| | | });
|
| | | }
|
| | | }
|
| | |
|
| | | return WebResponseContent.Instance.OK(null, result);
|
| | | }
|
| | | catch (Exception ex)
|
| | | {
|
| | | return WebResponseContent.Instance.Error($"电池和空托盘数量查询失败: {ex.Message}");
|
| | | }
|
| | | }
|
| | | }
|
| | | } |