using IBigBreenService;
|
using Microsoft.IdentityModel.Tokens;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime;
|
using SqlSugar;
|
using System;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using WIDESEA_Common.CommonEnum;
|
using WIDESEA_Common.LocationEnum;
|
using WIDESEA_Common.OrderEnum;
|
using WIDESEA_Common.TaskEnum;
|
using WIDESEA_Core;
|
using WIDESEA_Core.BaseRepository;
|
using WIDESEA_Core.Helper;
|
using WIDESEA_Model.Models;
|
using WIDESEA_Model.Models.Basic;
|
|
namespace BigGreenService
|
{
|
public class BigGreenService : IBigGreenService
|
{
|
private readonly IRepository<Dt_StockInfoDetail> _stockInfoDetailRepository;
|
private readonly IRepository<Dt_OutboundOrder> _outBoundOrderRepository;
|
private readonly IRepository<Dt_LocationInfo> _locationInfoRepository;
|
private readonly IRepository<Dt_OutboundOrderDetail> _outBoundOrderDetailRepository;
|
private readonly IRepository<Dt_InboundOrderDetail> _inboundOrderDetailRepository;
|
private readonly IRepository<Dt_Task_Hty> _taskHtyRepository;
|
private readonly IRepository<Dt_Task> _taskRepository;
|
private readonly IRepository<Dt_StockInfo> _stockInfoRepository;
|
private readonly IRepository<Dt_MaterialExpirationDate> _materialExpirationDateRepository;
|
private readonly IRepository<Dt_InboundOrder> _inboundRepository;
|
|
public BigGreenService(IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IRepository<Dt_OutboundOrder> outBoundOrderRepository, IRepository<Dt_LocationInfo> locationInfoRepository, IRepository<Dt_OutboundOrderDetail> outBoundOrderDetailRepository, IRepository<Dt_InboundOrderDetail> inboundOrderDetailRepository, IRepository<Dt_Task> taskRepository, IRepository<Dt_Task_Hty> taskHtyRepository, IRepository<Dt_StockInfo> stockInfoRepository, IRepository<Dt_MaterialExpirationDate> materialExpirationDateRepository,IRepository<Dt_InboundOrder> inboundRepository)
|
{
|
_stockInfoDetailRepository = stockInfoDetailRepository;
|
_outBoundOrderRepository = outBoundOrderRepository;
|
_locationInfoRepository = locationInfoRepository;
|
_outBoundOrderDetailRepository = outBoundOrderDetailRepository;
|
_inboundOrderDetailRepository = inboundOrderDetailRepository;
|
_taskRepository = taskRepository;
|
_taskHtyRepository = taskHtyRepository;
|
_stockInfoRepository = stockInfoRepository;
|
_materialExpirationDateRepository = materialExpirationDateRepository;
|
_inboundRepository = inboundRepository;
|
}
|
public WebResponseContent GetBigGreenData()
|
{
|
//计算总库存数量
|
var totalStockQuantity = _stockInfoDetailRepository.Db.Queryable<Dt_StockInfoDetail>().Sum(x => (decimal?)x.StockQuantity) ?? 0;
|
|
//计算待出库订单
|
var targetStatus = new List<int>
|
{
|
(int)OutOrderStatusEnum.出库中,
|
(int)OutOrderStatusEnum.未开始
|
};
|
var targetInStatus = new List<int>
|
{
|
(int)InOrderStatusEnum.入库中,
|
(int)InOrderStatusEnum.未开始
|
};
|
var unOutBound = _outBoundOrderRepository.Db.Queryable<Dt_OutboundOrder>().Where(x => targetStatus.Contains(x.OrderStatus) && x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd")).Count();
|
var unInBound = _inboundRepository.Db.Queryable<Dt_InboundOrder>().Where(x => targetInStatus.Contains(x.OrderStatus) && x.CreateDate.ToString("MM-dd") == DateTime.Now.ToString("MM-dd")).Count();
|
|
//计算库位利用率
|
var totalLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Select(x=>x.Id).Count();
|
var inStockLocation = _locationInfoRepository.Db.Queryable<Dt_LocationInfo>().Where(x => x.LocationStatus == (int)LocationStatusEnum.InStock).Count();
|
decimal locationUtilizationRate = totalLocation == 0
|
? 0
|
: Math.Round((decimal)inStockLocation / totalLocation, 4) * 100;
|
|
//计算入库任务和出库任务完成数量
|
var inboundCount = _taskHtyRepository.Db.Queryable<Dt_Task_Hty>().Where(x => x.TaskType >= 500 && x.TaskType < 900 && x.CreateDate.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd")).Count();
|
var outboundCount = _taskHtyRepository.Db.Queryable<Dt_Task_Hty>().Where(x => x.TaskType >= 100 && x.TaskType < 500 && x.CreateDate.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd")).Count();
|
|
//计算有货料箱数量
|
var inStockPallet = _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletType == (int)PalletTypeEnum.None && !string.IsNullOrEmpty(x.LocationCode)).Count();
|
//计算空箱数量
|
var freeStockPallet = _stockInfoRepository.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletType == (int)PalletTypeEnum.Empty && !string.IsNullOrEmpty(x.LocationCode)).Count();
|
// 4. 获取近7日每日出入库明细(核心修改:调用上面的方法)
|
var dailyInOutBoundList = Get7DaysDailyInOutBound();
|
|
List<StockInfoDetailExtDTO> nearExpirationList = GetMaterialsNearExpiration();
|
//获取作业统计
|
var completeTask = SimpleStatistics();
|
//任务
|
List<Dt_Task> tasks = _taskRepository.QueryData();
|
|
var bigGreenData = new BigGreenDataDto
|
{
|
TotalStockQuantity = totalStockQuantity,
|
UnOutBoundOrderCount = unOutBound,
|
LocationUtilizationRate = locationUtilizationRate,
|
DailyInOutBoundList = dailyInOutBoundList,
|
TaskList = tasks,
|
InboundCount = inboundCount,
|
OutboundCount = outboundCount,
|
InStockPallet = inStockPallet,
|
FreeStockPallet = freeStockPallet,
|
CompleteTask = completeTask,
|
NearExpirationList = nearExpirationList,
|
UnInBoundOrderCount = unInBound
|
};
|
return WebResponseContent.Instance.OK(data: bigGreenData);
|
}
|
|
/// <summary>
|
/// 获取近7日每日出入库明细
|
/// </summary>
|
/// <returns>每日出入库明细列表</returns>
|
private List<DailyInOutBoundDto> Get7DaysDailyInOutBound()
|
{
|
// 1. 定义时间范围(近7个自然日)
|
DateTime endDate = DateTime.Today;
|
DateTime startDate = endDate.AddDays(-6);
|
// 生成近7日所有日期(确保无缺失,即使某一天无数据也返回0)
|
var all7Days = Enumerable.Range(0, 7)
|
.Select(i => endDate.AddDays(-i).ToString("MM-dd"))
|
.Reverse() // 按日期升序排列(从7天前到今日)
|
.ToList();
|
|
// 2. 查询每日出库明细(按日期分组)
|
var dailyOutboundList = _outBoundOrderRepository.Db
|
.Queryable<Dt_OutboundOrder>()
|
.Where(x => x.CreateDate >= startDate
|
&& x.CreateDate < endDate.AddDays(1))
|
|
.Select(x => new
|
{
|
Date = x.CreateDate.ToString("MM-dd"),
|
x.OrderStatus
|
})
|
.ToList()
|
.GroupBy(x => x.Date)
|
.ToDictionary(k => k.Key, g => g.Count(x => x.OrderStatus == (int)OutOrderStatusEnum.出库完成)); // 转为字典方便匹配
|
|
// 3. 查询每日入库明细(按日期分组)
|
var dailyInboundList = _inboundRepository.Db
|
.Queryable<Dt_InboundOrder>()
|
.Where(x => x.CreateDate >= startDate
|
&& x.CreateDate < endDate.AddDays(1))
|
.Select(x => new
|
{
|
Date = x.CreateDate.ToString("MM-dd"),
|
x.OrderStatus
|
})
|
.ToList()
|
.GroupBy(x => x.Date)
|
.ToDictionary(k => k.Key, g => g.Count(x => x.OrderStatus == (int)InOrderStatusEnum.入库完成)); // 转为字典方便匹配
|
|
// 4. 合并每日数据(确保7天日期完整,无数据补0)
|
var dailyInOutBoundList = all7Days.Select(date => new DailyInOutBoundDto
|
{
|
Date = date,
|
DailyOutboundQuantity = dailyOutboundList.ContainsKey(date) ? dailyOutboundList[date] : 0,
|
DailyInboundQuantity = dailyInboundList.ContainsKey(date) ? dailyInboundList[date] : 0,
|
|
}).ToList();
|
|
return dailyInOutBoundList;
|
}
|
|
public List<SimpleStatisticsDTO> SimpleStatistics()
|
{
|
var today = DateTime.Now.Date;
|
var threeDaysAgo = today.AddDays(-3);
|
|
var targetStatuses = new List<int> { (int)InOrderStatusEnum.入库中, (int)InOrderStatusEnum.未开始,
|
(int)OutOrderStatusEnum.未开始, (int)OutOrderStatusEnum.出库中 };
|
var failReturnStatuses = new List<int> {4,2};
|
|
var inboundToday = QueryInboundOrders(today, today, targetStatuses);
|
var outboundToday = QueryOutboundOrders(today, today, targetStatuses);
|
var inboundFail3Days = QueryInboundOrders(threeDaysAgo, today, failReturnStatuses, isReturnStatus: true);
|
var outboundFail3Days = QueryOutboundOrders(threeDaysAgo, today, failReturnStatuses, isReturnStatus: true);
|
|
|
return new List<SimpleStatisticsDTO> { new()
|
{
|
inboundOrders = inboundToday,
|
outboundOrders = outboundToday,
|
inboundReturnFailOrders = inboundFail3Days,
|
outboundReturnFailOrders = outboundFail3Days
|
}};
|
}
|
|
|
private List<Dt_InboundOrder> QueryInboundOrders(DateTime startDate, DateTime endDate,
|
List<int> statusList, bool isReturnStatus = false)
|
{
|
return _inboundRepository.QueryData(x =>
|
x.CreateDate.Date >= startDate &&
|
x.CreateDate.Date <= endDate &&
|
(isReturnStatus ? statusList.Contains(x.ReturnToMESStatus) : statusList.Contains(x.OrderStatus))).ToList();
|
}
|
|
|
private List<Dt_OutboundOrder> QueryOutboundOrders(DateTime startDate, DateTime endDate,
|
List<int> statusList, bool isReturnStatus = false)
|
{
|
return _outBoundOrderRepository.QueryData(x =>
|
x.CreateDate.Date >= startDate &&
|
x.CreateDate.Date <= endDate &&
|
(isReturnStatus ? statusList.Contains(x.ReturnToMESStatus) : statusList.Contains(x.OrderStatus))).ToList();
|
}
|
|
/// <summary>
|
/// 大屏/汇总数据返回DTO(大绿数据汇总)
|
/// </summary>
|
public class BigGreenDataDto
|
{
|
/// <summary>
|
/// 入库完成数量
|
/// </summary>
|
public int InboundCount { get; set; }
|
/// <summary>
|
/// 出库完成数量
|
/// </summary>
|
public int OutboundCount { get; set; }
|
/// <summary>
|
/// 总库存数量
|
/// </summary>
|
public decimal TotalStockQuantity { get; set; }
|
|
/// <summary>
|
/// 待出库订单数量(出库中+未开始)
|
/// </summary>
|
public int UnOutBoundOrderCount { get; set; }
|
|
public int UnInBoundOrderCount { get; set; }
|
|
/// <summary>
|
/// 空闲库位数量
|
/// </summary>
|
public int FreeLocationCount { get; set; }
|
|
/// <summary>
|
/// 占用库位数量(已存库)
|
/// </summary>
|
public int InStockLocationCount { get; set; }
|
|
/// <summary>
|
/// 库位利用率(小数形式,如0.85对应85%)
|
/// </summary>
|
public decimal LocationUtilizationRate { get; set; }
|
|
/// <summary>
|
/// 近7日每日出入库明细
|
/// </summary>
|
public List<DailyInOutBoundDto> DailyInOutBoundList { get; set; } = new List<DailyInOutBoundDto>();
|
|
/// <summary>
|
/// 近7日净入库量(入库-出库)
|
/// </summary>
|
public decimal NetStock7Days { get; set; }
|
|
/// <summary>
|
/// 近7日净入库量(入库-出库)
|
/// </summary>
|
public decimal TotalStockChangeRate { get; set; }
|
|
/// <summary>
|
/// 任务列表
|
/// </summary>
|
public List<Dt_Task> TaskList { get; set; } = new List<Dt_Task>();
|
|
public int InStockPallet { get; set; }
|
|
public int FreeStockPallet { get; set; }
|
|
public List<SimpleStatisticsDTO> CompleteTask { get; set; }
|
|
public List<StockInfoDetailExtDTO> NearExpirationList { get; set; }
|
}
|
|
/// <summary>
|
/// 每日出入库明细DTO
|
/// </summary>
|
public class DailyInOutBoundDto
|
{
|
/// <summary>
|
/// 日期(格式:yyyy-MM-dd)
|
/// </summary>
|
public string Date { get; set; }
|
|
/// <summary>
|
/// 当日出库总量
|
/// </summary>
|
public decimal DailyOutboundQuantity { get; set; }
|
|
/// <summary>
|
/// 当日入库总量
|
/// </summary>
|
public decimal DailyInboundQuantity { get; set; }
|
|
}
|
|
public class SimpleStatisticsDTO
|
{
|
public List<Dt_InboundOrder> inboundOrders { get; set; }
|
public List<Dt_OutboundOrder> outboundOrders { get; set; }
|
public List<Dt_InboundOrder> inboundReturnFailOrders { get; set; }
|
public List<Dt_OutboundOrder> outboundReturnFailOrders { get; set; }
|
}
|
|
|
public class StockInfoDetailExtDTO : Dt_StockInfoDetail
|
{
|
public string LocationCode { get; set; }
|
public string PalletCode { get; set; }
|
public int DaysToExpiration { get; set; }
|
}
|
|
///<summary>
|
///获取近30天要过期的物料
|
/// </summary>
|
public List<StockInfoDetailExtDTO> GetMaterialsNearExpiration()
|
{
|
List<StockInfoDetailExtDTO> resultDTO = new List<StockInfoDetailExtDTO>();
|
|
var nearExpirationList = _stockInfoDetailRepository.QueryData()
|
.Join(
|
_stockInfoRepository.QueryData(),
|
detail => detail.StockId,
|
stock => stock.Id,
|
(detail, stock) => new
|
{
|
Detail = detail,
|
LocationCode = stock.LocationCode,
|
PalletCode = stock.PalletCode
|
}
|
)
|
.Where(x => x.Detail.ValidDate.HasValue
|
&& (x.Detail.ValidDate.Value - x.Detail.CreateDate).TotalDays <= 30)
|
.ToList();
|
|
|
if (!nearExpirationList.Any())
|
{
|
return resultDTO;
|
}
|
|
|
foreach (var item in nearExpirationList)
|
{
|
int daysToExpire = item.Detail.ValidDate.HasValue
|
? Math.Max(0, (item.Detail.ValidDate.Value - item.Detail.CreateDate).Days)
|
: 0;
|
|
var extDetail = new StockInfoDetailExtDTO
|
{
|
MaterielCode = item.Detail.MaterielCode,
|
MaterielName = item.Detail.MaterielName,
|
BatchNo = item.Detail.BatchNo,
|
SupplyCode = item.Detail.SupplyCode,
|
StockQuantity = item.Detail.StockQuantity,
|
CreateDate = item.Detail.CreateDate,
|
ValidDate = item.Detail.ValidDate,
|
LocationCode = item.LocationCode,
|
PalletCode = item.PalletCode,
|
Barcode = item.Detail.Barcode,
|
DaysToExpiration = daysToExpire
|
};
|
|
|
resultDTO.Add(extDetail);
|
}
|
|
resultDTO = resultDTO.OrderBy(d => d.DaysToExpiration).ToList();
|
|
return resultDTO;
|
}
|
}
|
}
|