From af4404160a9e8d14c09f1e6acab2ba00cb7fc91b Mon Sep 17 00:00:00 2001
From: xiazhengtongxue <133085197+xiazhengtongxue@users.noreply.github.com>
Date: 星期日, 19 四月 2026 16:32:04 +0800
Subject: [PATCH] fix(WMS): 修复首页、3D、websocket
---
Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs | 644 +++++++++++++++++++++++++++++++++------------------------
1 files changed, 373 insertions(+), 271 deletions(-)
diff --git a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
index 0d6498d..b80970b 100644
--- a/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
+++ b/Code/WMS/WIDESEA_WMSServer/WIDESEA_WMSServer/Controllers/Dashboard/DashboardController.cs
@@ -1,271 +1,373 @@
-using Microsoft.AspNetCore.Mvc;
-using SqlSugar;
-using WIDESEA_Core;
-using WIDESEA_Model.Models;
-
-namespace WIDESEA_WMSServer.Controllers.Dashboard
-{
- /// <summary>
- /// 浠〃鐩�
- /// </summary>
- [Route("api/Dashboard")]
- [ApiController]
- public class DashboardController : ControllerBase
- {
- private readonly ISqlSugarClient _db;
-
- public DashboardController(ISqlSugarClient db)
- {
- _db = db;
- }
-
- /// <summary>
- /// 鎬昏鏁版嵁
- /// </summary>
- [HttpGet("Overview")]
- public async Task<WebResponseContent> Overview()
- {
- try
- {
- var today = DateTime.Today;
- var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
-
- // 浠婃棩鍏ュ簱鏁�
- var todayInbound = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= today && t.TaskType >= 500 && t.TaskType < 600)
- .CountAsync();
-
- // 浠婃棩鍑哄簱鏁�
- var todayOutbound = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= today && t.TaskType >= 100 && t.TaskType < 200)
- .CountAsync();
-
- // 鏈湀鍏ュ簱鏁�
- var monthInbound = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 500 && t.TaskType < 600)
- .CountAsync();
-
- // 鏈湀鍑哄簱鏁�
- var monthOutbound = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 100 && t.TaskType < 200)
- .CountAsync();
-
- // 褰撳墠鎬诲簱瀛�
- var totalStock = await _db.Queryable<Dt_StockInfo>().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}");
- }
- }
-
- /// <summary>
- /// 姣忔棩缁熻
- /// </summary>
- /// <remarks>
- /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜鏃ユ湡鍒嗙粍銆�
- /// SqlSugar 鐨� GroupBy 涓嶆敮鎸佸 .Date 杩欐牱鐨勮绠楀垪鐩存帴鐢熸垚 SQL GROUP BY锛�
- /// 鍥犳閲囩敤姝ゆ柟寮忎互纭繚璺ㄦ暟鎹簱鍏煎鎬с��
- /// </remarks>
- [HttpGet("DailyStats")]
- public async Task<WebResponseContent> DailyStats([FromQuery] int days = 30)
- {
- try
- {
- if (days <= 0) days = 30;
- if (days > 365) days = 365;
-
- var startDate = DateTime.Today.AddDays(-days + 1);
-
- var query = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= startDate)
- .Select(t => new { t.InsertTime, t.TaskType })
- .ToListAsync();
-
- var result = query
- .GroupBy(t => t.InsertTime.Date)
- .Select(g => new
- {
- Date = g.Key.ToString("yyyy-MM-dd"),
- Inbound = g.Count(t => t.TaskType >= 500 && t.TaskType < 600),
- Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
- })
- .OrderBy(x => x.Date)
- .ToList();
-
- return WebResponseContent.Instance.OK(null, result);
- }
- catch (Exception ex)
- {
- return WebResponseContent.Instance.Error($"姣忔棩缁熻鑾峰彇澶辫触: {ex.Message}");
- }
- }
-
- /// <summary>
- /// 姣忓懆缁熻
- /// </summary>
- /// <remarks>
- /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜 ISO 8601 鍛ㄩ敭鍒嗙粍銆�
- /// 鍛ㄩ敭涓� "YYYY-Www" 鏍煎紡锛屾棤娉曠洿鎺ュ湪 SQL 灞傜敤 GROUP BY 瀹炵幇銆�
- /// </remarks>
- [HttpGet("WeeklyStats")]
- public async Task<WebResponseContent> WeeklyStats([FromQuery] int weeks = 12)
- {
- try
- {
- if (weeks <= 0) weeks = 12;
-
- var startDate = DateTime.Today.AddDays(-weeks * 7);
-
- var query = await _db.Queryable<Dt_Task_Hty>()
- .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 >= 500 && t.TaskType < 600),
- 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}";
- }
-
- /// <summary>
- /// 姣忔湀缁熻
- /// </summary>
- /// <remarks>
- /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜骞存湀鍒嗙粍銆�
- /// SqlSugar 鐨� GroupBy 涓嶆敮鎸佸尶鍚嶅璞� (Year, Month) 鐩存帴鏄犲皠鍒� SQL GROUP BY锛�
- /// 鍥犳閲囩敤姝ゆ柟寮忎互纭繚璺ㄦ暟鎹簱鍏煎鎬с��
- /// </remarks>
- [HttpGet("MonthlyStats")]
- public async Task<WebResponseContent> MonthlyStats([FromQuery] int months = 12)
- {
- try
- {
- if (months <= 0) months = 12;
-
- var startDate = DateTime.Today.AddMonths(-months + 1);
- startDate = new DateTime(startDate.Year, startDate.Month, 1);
-
- var query = await _db.Queryable<Dt_Task_Hty>()
- .Where(t => t.InsertTime >= startDate)
- .Select(t => new { t.InsertTime, t.TaskType })
- .ToListAsync();
-
- var result = query
- .GroupBy(t => new { t.InsertTime.Year, t.InsertTime.Month })
- .Select(g => new
- {
- Month = $"{g.Key.Year}-{g.Key.Month:D2}",
- Inbound = g.Count(t => t.TaskType >= 500 && t.TaskType < 600),
- Outbound = g.Count(t => t.TaskType >= 100 && t.TaskType < 200)
- })
- .OrderBy(x => x.Month)
- .ToList();
-
- return WebResponseContent.Instance.OK(null, result);
- }
- catch (Exception ex)
- {
- return WebResponseContent.Instance.Error($"姣忔湀缁熻鑾峰彇澶辫触: {ex.Message}");
- }
- }
-
- /// <summary>
- /// 搴撳瓨搴撻緞鍒嗗竷
- /// </summary>
- [HttpGet("StockAgeDistribution")]
- public async Task<WebResponseContent> StockAgeDistribution()
- {
- try
- {
- var today = DateTime.Today;
-
- // 浣跨敤 SQL 鐩存帴鍒嗙粍缁熻锛岄伩鍏嶅姞杞芥墍鏈夋暟鎹埌鍐呭瓨
- var result = new[]
- {
- new { Range = "7澶╁唴", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 7).CountAsync() },
- new { Range = "7-30澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 7 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 30).CountAsync() },
- new { Range = "30-90澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 30 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 90).CountAsync() },
- new { Range = "90澶╀互涓�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 90).CountAsync() }
- };
-
- return WebResponseContent.Instance.OK(null, result);
- }
- catch (Exception ex)
- {
- return WebResponseContent.Instance.Error($"搴撳瓨搴撻緞鍒嗗竷鑾峰彇澶辫触: {ex.Message}");
- }
- }
-
- /// <summary>
- /// 鍚勪粨搴撳簱瀛樺垎甯�
- /// </summary>
- /// <remarks>
- /// 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛岄伩鍏嶅姞杞藉叏閮ㄥ簱瀛樿褰曞埌鍐呭瓨銆�
- /// </remarks>
- [HttpGet("StockByWarehouse")]
- public async Task<WebResponseContent> StockByWarehouse()
- {
- try
- {
- // 鏌ヨ浠撳簱鍚嶇О
- var warehouses = await _db.Queryable<Dt_Warehouse>()
- .Select(w => new { w.WarehouseId, w.WarehouseName })
- .ToListAsync();
- var warehouseDict = warehouses.ToDictionary(w => w.WarehouseId, w => w.WarehouseName);
-
- // 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛屼粎杩斿洖鑱氬悎缁撴灉
- var stockGroups = await _db.Queryable<Dt_StockInfo>()
- .GroupBy(s => s.WarehouseId)
- .Select(s => new { s.WarehouseId, Count = SqlFunc.AggregateCount(s.Id) })
- .ToListAsync();
-
- var result = stockGroups
- .Select(g => new
- {
- Warehouse = warehouseDict.TryGetValue(g.WarehouseId, out var name) ? name : $"浠撳簱{g.WarehouseId}",
- Count = g.Count
- })
- .ToList();
-
- return WebResponseContent.Instance.OK(null, result);
- }
- catch (Exception ex)
- {
- return WebResponseContent.Instance.Error($"鍚勪粨搴撳簱瀛樺垎甯冭幏鍙栧け璐�: {ex.Message}");
- }
- }
- }
-}
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
+using WIDESEA_Common.LocationEnum;
+using WIDESEA_Core;
+using WIDESEA_Model.Models;
+
+namespace WIDESEA_WMSServer.Controllers.Dashboard
+{
+ /// <summary>
+ /// 浠〃鐩�
+ /// </summary>
+ [Route("api/Dashboard")]
+ [ApiController]
+ public class DashboardController : ControllerBase
+ {
+ private readonly ISqlSugarClient _db;
+
+ public DashboardController(ISqlSugarClient db)
+ {
+ _db = db;
+ }
+
+ /// <summary>
+ /// 鎬昏鏁版嵁
+ /// </summary>
+ [HttpGet("Overview"), AllowAnonymous]
+ public async Task<WebResponseContent> Overview()
+ {
+ try
+ {
+ var today = DateTime.Today;
+ var firstDayOfMonth = new DateTime(today.Year, today.Month, 1);
+
+ // 浠婃棩鍏ュ簱鏁�
+ var todayInbound = await _db.Queryable<Dt_Task_Hty>()
+ .Where(t => t.InsertTime >= today && t.TaskType >= 500 && t.TaskType < 600)
+ .CountAsync();
+
+ // 浠婃棩鍑哄簱鏁�
+ var todayOutbound = await _db.Queryable<Dt_Task_Hty>()
+ .Where(t => t.InsertTime >= today && t.TaskType >= 100 && t.TaskType < 200)
+ .CountAsync();
+
+ // 鏈湀鍏ュ簱鏁�
+ var monthInbound = await _db.Queryable<Dt_Task_Hty>()
+ .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 500 && t.TaskType < 600)
+ .CountAsync();
+
+ // 鏈湀鍑哄簱鏁�
+ var monthOutbound = await _db.Queryable<Dt_Task_Hty>()
+ .Where(t => t.InsertTime >= firstDayOfMonth && t.TaskType >= 100 && t.TaskType < 200)
+ .CountAsync();
+
+ // 褰撳墠鎬诲簱瀛�
+ var totalStock = await _db.Queryable<Dt_StockInfo>().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}");
+ }
+ }
+
+ /// <summary>
+ /// 姣忔棩缁熻
+ /// </summary>
+ [HttpGet("DailyStats"), AllowAnonymous]
+ public async Task<WebResponseContent> DailyStats([FromQuery] int days = 30)
+ {
+ try
+ {
+ if (days <= 0) days = 30;
+ if (days > 365) days = 365;
+
+ var startDate = DateTime.Today.AddDays(-days + 1);
+ var endDate = DateTime.Today; // 鍖呭惈浠婂ぉ
+
+ var query = await _db.Queryable<Dt_Task_Hty>()
+ .Where(t => t.InsertTime >= startDate && t.InsertTime <= endDate)
+ .Select(t => new { t.InsertTime, t.TaskType })
+ .ToListAsync();
+
+ // 鐢熸垚鏃ユ湡鑼冨洿
+ var allDates = new List<DateTime>();
+ for (var date = startDate; date <= endDate; date = date.AddDays(1))
+ {
+ allDates.Add(date);
+ }
+
+ // 鎸夋棩鏈熷垎缁勭粺璁�
+ var groupedData = query
+ .GroupBy(t => t.InsertTime.Date)
+ .Select(g => new
+ {
+ Date = g.Key,
+ 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);
+
+ // 琛ュ叏缂哄け鏃ユ湡
+ var result = allDates.Select(date =>
+ {
+ if (groupedData.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 WebResponseContent.Instance.OK(null, result);
+ }
+ catch (Exception ex)
+ {
+ return WebResponseContent.Instance.Error($"姣忔棩缁熻鑾峰彇澶辫触: {ex.Message}");
+ }
+ }
+ /// <summary>
+ /// 姣忓懆缁熻
+ /// </summary>
+ /// <remarks>
+ /// 娉ㄦ剰锛氭暟鎹湪 SQL 灞傝繃婊ゅ悗锛屽湪搴旂敤灞傛寜 ISO 8601 鍛ㄩ敭鍒嗙粍銆�
+ /// 鍛ㄩ敭涓� "YYYY-Www" 鏍煎紡锛屾棤娉曠洿鎺ュ湪 SQL 灞傜敤 GROUP BY 瀹炵幇銆�
+ /// </remarks>
+ [HttpGet("WeeklyStats"), AllowAnonymous]
+ public async Task<WebResponseContent> WeeklyStats([FromQuery] int weeks = 12)
+ {
+ try
+ {
+ if (weeks <= 0) weeks = 12;
+
+ var startDate = DateTime.Today.AddDays(-weeks * 7);
+
+ var query = await _db.Queryable<Dt_Task_Hty>()
+ .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}";
+ }
+
+ /// <summary>
+ /// 姣忔湀缁熻
+ /// </summary>
+ /// <remarks>
+ /// 鎸夊勾鏈堢粺璁″叆绔欏拰鍑虹珯浠诲姟鏁伴噺
+ /// </remarks>
+ [HttpGet("MonthlyStats"), AllowAnonymous]
+ public async Task<WebResponseContent> MonthlyStats([FromQuery] int months = 12)
+ {
+ try
+ {
+ if (months <= 0) months = 12;
+
+ 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)
+ .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<DateTime>();
+ 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<object>();
+ foreach (var month in allMonths)
+ {
+ var monthKey = $"{month.Year}-{month.Month:D2}";
+
+ if (statsDict.TryGetValue(monthKey, out var stat))
+ {
+ result.Add(new
+ {
+ Month = monthKey,
+ Inbound = stat.Inbound,
+ Outbound = stat.Outbound
+ });
+ }
+ else
+ {
+ result.Add(new
+ {
+ Month = monthKey,
+ Inbound = 0,
+ Outbound = 0
+ });
+ }
+ }
+
+ return WebResponseContent.Instance.OK(null, result);
+ }
+ catch (Exception ex)
+ {
+ // 璁板綍寮傚父鏃ュ織锛堝疄闄呴」鐩腑寤鸿浣跨敤鏃ュ織妗嗘灦锛�
+ // _logger.LogError(ex, "姣忔湀缁熻鑾峰彇澶辫触");
+
+ return WebResponseContent.Instance.Error($"姣忔湀缁熻鑾峰彇澶辫触: {ex.Message}");
+ }
+ }
+
+ /// <summary>
+ /// 搴撳瓨搴撻緞鍒嗗竷
+ /// </summary>
+ [HttpGet("StockAgeDistribution"), AllowAnonymous]
+ public async Task<WebResponseContent> StockAgeDistribution()
+ {
+ try
+ {
+ var today = DateTime.Today;
+
+ // 浣跨敤 SQL 鐩存帴鍒嗙粍缁熻锛岄伩鍏嶅姞杞芥墍鏈夋暟鎹埌鍐呭瓨
+ var result = new[]
+ {
+ new { Range = "7澶╁唴", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 7).CountAsync() },
+ new { Range = "7-30澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 7 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 30).CountAsync() },
+ new { Range = "30-90澶�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 30 && SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) <= 90).CountAsync() },
+ new { Range = "90澶╀互涓�", Count = await _db.Queryable<Dt_StockInfo>().Where(s => SqlFunc.DateDiff(DateType.Day, s.CreateDate, today) > 90).CountAsync() }
+ };
+
+ return WebResponseContent.Instance.OK(null, result);
+ }
+ catch (Exception ex)
+ {
+ return WebResponseContent.Instance.Error($"搴撳瓨搴撻緞鍒嗗竷鑾峰彇澶辫触: {ex.Message}");
+ }
+ }
+
+ /// <summary>
+ /// 鍚勪粨搴撳簱瀛樺垎甯�
+ /// </summary>
+ /// <remarks>
+ /// 浣跨敤 SQL GROUP BY 鍦ㄦ暟鎹簱灞傞潰鑱氬悎锛岄伩鍏嶅姞杞藉叏閮ㄥ簱瀛樿褰曞埌鍐呭瓨銆�
+ /// </remarks>
+ [HttpGet("StockByWarehouse"), AllowAnonymous]
+ public async Task<WebResponseContent> StockByWarehouse()
+ {
+ try
+ {
+ // 鏌ヨ鎵�鏈変粨搴撲俊鎭�
+ var warehouses = await _db.Queryable<Dt_Warehouse>()
+ .Select(w => new { w.WarehouseId, w.WarehouseName })
+ .ToListAsync();
+
+ // 鏌ヨ鎵�鏈夎揣浣嶄俊鎭紝鎸変粨搴撳垎缁勭粺璁℃�绘暟
+ var locationGroups = await _db.Queryable<Dt_LocationInfo>()
+ .GroupBy(l => l.WarehouseId)
+ .Select(l => new
+ {
+ WarehouseId = l.WarehouseId,
+ TotalLocations = SqlFunc.AggregateCount(l.Id)
+ })
+ .ToListAsync();
+
+ // 鏌ヨ鐘舵�佷笉涓篎ree鐨勮揣浣嶄俊鎭紙鏈夎揣璐т綅锛夛紝鎸変粨搴撳垎缁勭粺璁�
+ var occupiedLocationGroups = await _db.Queryable<Dt_LocationInfo>()
+ .Where(l => l.LocationStatus != (int)LocationStatusEnum.Free)
+ .GroupBy(l => l.WarehouseId)
+ .Select(l => new
+ {
+ WarehouseId = l.WarehouseId,
+ OccupiedLocations = SqlFunc.AggregateCount(l.Id)
+ })
+ .ToListAsync();
+
+ // 灏嗕粨搴撲俊鎭笌璐т綅缁熻淇℃伅鍚堝苟
+ var result = warehouses.Select(w =>
+ {
+ var totalLocations = locationGroups.FirstOrDefault(lg => lg.WarehouseId == w.WarehouseId)?.TotalLocations ?? 0;
+ var occupiedLocations = occupiedLocationGroups.FirstOrDefault(og => og.WarehouseId == w.WarehouseId)?.OccupiedLocations ?? 0;
+ var emptyLocations = totalLocations - occupiedLocations;
+
+ var occupiedPercentage = totalLocations > 0 ? Math.Round((double)occupiedLocations / totalLocations * 100, 2) : 0.0;
+ var emptyPercentage = totalLocations > 0 ? Math.Round((double)emptyLocations / totalLocations * 100, 2) : 0.0;
+
+ return new
+ {
+ Warehouse = w.WarehouseName,
+ Total = totalLocations,
+ HasStock = occupiedLocations,
+ NoStock = emptyLocations,
+ HasStockPercentage = $"{occupiedPercentage}%",
+ NoStockPercentage = $"{emptyPercentage}%"
+ };
+ }).ToList();
+
+ return WebResponseContent.Instance.OK(null, result);
+ }
+ catch (Exception ex)
+ {
+ return WebResponseContent.Instance.Error($"鍚勪粨搴撳簱瀛樺垎甯冭幏鍙栧け璐�: {ex.Message}");
+ }
+ }
+ }
+}
--
Gitblit v1.9.3