feat: 功能优化和增加餐饮分析

This commit is contained in:
2025-10-14 12:32:02 +08:00
parent 5d468fe23c
commit 62e3fbe37b
8 changed files with 190 additions and 47 deletions

View File

@@ -82,4 +82,15 @@ public class BalanceSummaryController : ControllerBase
{
return await _balanceSummaryService.BalanceRecordAnalysisByFactoryAsync(request);
}
/// <summary>
/// 餐次和营业点就餐分析,统计金额和人数/人次
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpGet("shiftAndBusinessPlace/analysis/amountAndUserCountAndCostCount")]
public async Task<ShiftAndBusinessPlaceAnalysisResponse> ShiftAndBusinessPlaceAnalysisAsync([FromQuery] BalanceRecordPageDetailRequest request)
{
return await _balanceSummaryService.ShiftAndBusinessPlaceAnalysisAsync(request);
}
}

View File

@@ -19,6 +19,11 @@ public class BalanceRecordByBusinessPlaceResponse
/// </summary>
public int Total { get; set; }
/// <summary>
/// 消费次数
/// </summary>
public int CostCount => Pagination.Total;
/// <summary>
/// 分页数据
/// </summary>
@@ -28,6 +33,9 @@ public class BalanceRecordByBusinessPlaceResponse
[Excel("BalanceRecordDetail")]
public class BalanceRecordDetailPageResponse : IExcelExportable
{
/// <summary>
/// id
/// </summary>
public long Id { get; set; }
/// <summary>
@@ -108,6 +116,15 @@ public class BalanceRecordDetailPageResponse : IExcelExportable
/// </summary>
public BalanceRecordSourceEnumType Source { get; set; }
// /// <summary>
// /// 消费人数
// /// </summary>
// public int UserCount { get; set; }
//
// /// <summary>
// /// 消费次数
// /// </summary>
// public int CostCount { get; set; }
/// <summary>
/// 厂区

View File

@@ -0,0 +1,75 @@
using System.Text.Json.Serialization;
using Dlhis.Entity.Canteen.Enums;
using Dlhis.ExcelHelper;
using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.Utils.Extensions;
namespace Dlhis.Canteen.Order.Response;
public class ShiftAndBusinessPlaceAnalysisResponse
{
/// <summary>
/// 消费总金额
/// </summary>
public decimal Amount { get; set; }
/// <summary>
/// 消费人数
/// </summary>
public int Total { get; set; }
/// <summary>
/// 消费次数
/// </summary>
public int CostCount => Pagination.Total;
/// <summary>
/// 分页数据
/// </summary>
public Pagination<ShiftAndBusinessPlaceAnalysisItemResponse> Pagination { get; set; }
}
[Excel("ShiftAndBusinessPlaceAnalysis")]
public class ShiftAndBusinessPlaceAnalysisItemResponse : IExcelExportable
{
/// <summary>
/// 消费额
/// </summary>
[JsonIgnore]
public decimal CurrentAmount { get; set; }
/// <summary>
/// 消费额
/// </summary>
[Excel("消费额")]
public string Amount => Math.Abs(CurrentAmount).ToString("F2");
/// <summary>
/// 营业点
/// </summary>
[Excel("营业点")]
public string BusinessPlaceName { get; set; }
/// <summary>
/// 餐次
/// </summary>
public ShiftEnumType? ShiftType { get; set; }
/// <summary>
/// 餐次
/// </summary>
[Excel("餐次")]
public string ShiftTypeDesc => ShiftType?.GetDescription();
/// <summary>
/// 消费人数
/// </summary>
[Excel("消费人数")]
public int UserCount { get; set; }
/// <summary>
/// 消费次数
/// </summary>
[Excel("消费次数")]
public int CostCount { get; set; }
}

View File

@@ -18,4 +18,6 @@ public interface IBalanceSummaryService : IScopeDependency
Task<BalanceRecordAnalysisShiftAmountAndCountResponse> BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request);
Task<Pagination<BalanceRecordAnalysisFactoryAmountAndCountResponse>> BalanceRecordAnalysisByFactoryAsync(SummaryCommonDto request);
Task<ShiftAndBusinessPlaceAnalysisResponse> ShiftAndBusinessPlaceAnalysisAsync(BalanceRecordPageDetailRequest request);
}

View File

@@ -298,16 +298,7 @@ public class BalanceService : IBalanceService
//var myCodes = request.BusinessplaceCodes;
var queryable = _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<DepartmentEntity>((record, department) => record.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, department, bPlace) => record.BusinessPlaceCode == bPlace.Code)
.WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End)
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.Where(record => myCodes.Contains(record.BusinessPlaceCode))
.WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType))
.WhereIF(request.Search.IsPresent(), record => record.UserCode == request.Search || record.Name == request.Search);
var page = await queryable
var page = await GetBaseQuery()
.OrderBy(record => new { CostDate = SqlFunc.Desc(record.CostDate), CostDateTime = SqlFunc.Desc(record.CostDateTime) })
.Select((record, department, bPlace) => new BalanceRecordDetailPageResponse
{
@@ -339,16 +330,28 @@ public class BalanceService : IBalanceService
//ignore
}
var amount = await queryable.SumAsync(record => SqlFunc.Abs(record.Amount));
var total = await queryable.Select(record => record.UserCode).Distinct().CountAsync();
var amount = await GetBaseQuery().SumAsync(record => SqlFunc.Abs(record.Amount));
var userCount = await GetBaseQuery().Select(record => record.UserCode).Distinct().CountAsync();
return new BalanceRecordByBusinessPlaceResponse
{
Amount = amount,
Total = total,
Total = userCount,
Pagination = page,
};
ISugarQueryable<BalanceRecordEntity, DepartmentEntity, BusinessPlaceEntity> GetBaseQuery()
{
return _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<DepartmentEntity>((record, department) => record.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, department, bPlace) => record.BusinessPlaceCode == bPlace.Code)
.WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End)
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.Where(record => myCodes.Contains(record.BusinessPlaceCode))
.WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType))
.WhereIF(request.Search.IsPresent(), record => record.UserCode == request.Search || record.Name == request.Search);
}
}
@@ -362,16 +365,14 @@ public class BalanceService : IBalanceService
//var myCodes = request.BusinessplaceCodes;
var queryable = _dbContext.Queryable<BalanceRecordEntity>()
var rows = await _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<DepartmentEntity>((record, department) => record.DepartmentNo == department.No)
.LeftJoin<BusinessPlaceEntity>((record, department, bPlace) => record.BusinessPlaceCode == bPlace.Code)
.WhereIF(request.SearchDateTimePeriod.HasValue(), record => record.CostDate >= request.SearchDateTimePeriod.Start && record.CostDate <= request.SearchDateTimePeriod.End)
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.Where(record => myCodes.Contains(record.BusinessPlaceCode))
.WhereIF(request.ShiftTypes.IsPresent(), record => request.ShiftTypes.Contains(record.ShiftType))
.WhereIF(request.Search.IsPresent(), record => record.UserCode == request.Search || record.Name == request.Search);
var rows = await queryable
.WhereIF(request.Search.IsPresent(), record => record.UserCode == request.Search || record.Name == request.Search)
.OrderBy(record => new { CostDate = SqlFunc.Desc(record.CostDate), CostDateTime = SqlFunc.Desc(record.CostDateTime) })
.Select((record, department, bPlace) => new BalanceRecordDetailPageResponse
{

View File

@@ -12,6 +12,7 @@ using Kurisu.AspNetCore.DataAccess.Dto;
using Kurisu.AspNetCore.DataAccess.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Extensions;
using Kurisu.AspNetCore.DataAccess.SqlSugar.Services;
using Kurisu.AspNetCore.Utils.Extensions;
using SqlSugar;
namespace Dlhis.Canteen.Order.Services.Implements;
@@ -34,8 +35,7 @@ public class BalanceSummaryService : IBalanceSummaryService
request.BusinessPlaceCodes = new List<Guid> { request.BusinessPlaceCode.Value };
}
var queryable = GetQueryable(request);
var list = await queryable.ToListAsync();
var list = await GetQueryable(request).ToListAsync();
var sum = list.Sum(x => Math.Abs(x.Amount));
@@ -96,13 +96,11 @@ public class BalanceSummaryService : IBalanceSummaryService
public async Task<BalanceRecordAnalysisShiftAmountResponse> BalanceRecordShiftAnalysisAmountAsync(BalanceRecordAnalysisByShiftRequest request)
{
var queryable = GetQueryable(request);
var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount));
var amount = await GetQueryable(request).SumAsync(x => SqlFunc.Abs(x.Amount));
var count = typeof(ShiftEnumType).GetFields(BindingFlags.Public | BindingFlags.Static).Length;
var result = await queryable.GroupBy(x => new { x.CostDate, x.ShiftType })
var result = await GetQueryable(request).GroupBy(x => new { x.CostDate, x.ShiftType })
.Select(x => new { x.CostDate, x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)) })
.ToPageListAsync(request.PageIndex, count * request.PageSize);
@@ -129,11 +127,9 @@ public class BalanceSummaryService : IBalanceSummaryService
public async Task<BalanceRecordAnalysisShiftAmountAndCountResponse> BalanceRecordShiftAnalysisAmountAndCountAsync(BalanceRecordAnalysisByShiftRequest request)
{
var queryable = GetQueryable(request);
var amount = await GetQueryable(request).SumAsync(x => SqlFunc.Abs(x.Amount));
var amount = await queryable.SumAsync(x => SqlFunc.Abs(x.Amount));
var result = await queryable.GroupBy(x => new { x.ShiftType })
var result = await GetQueryable(request).GroupBy(x => new { x.ShiftType })
.Select(x => new { x.ShiftType, Amount = SqlFunc.AggregateSum(SqlFunc.Abs(x.Amount)), Count = SqlFunc.AggregateDistinctCount(x.UserCode) })
.ToListAsync();
@@ -151,9 +147,7 @@ public class BalanceSummaryService : IBalanceSummaryService
public async Task<Pagination<BalanceRecordAnalysisFactoryAmountAndCountResponse>> BalanceRecordAnalysisByFactoryAsync(SummaryCommonDto request)
{
var queryable = GetQueryable(request);
var page = await queryable
var page = await GetQueryable(request)
.GroupBy(x => new { x.TenantId })
.Select(x => new BalanceRecordAnalysisFactoryAmountAndCountResponse
{
@@ -176,6 +170,45 @@ public class BalanceSummaryService : IBalanceSummaryService
return page;
}
public async Task<ShiftAndBusinessPlaceAnalysisResponse> ShiftAndBusinessPlaceAnalysisAsync(BalanceRecordPageDetailRequest request)
{
var page = await QueryableShiftAndBusinessPlaceAnalysis(request)
.GroupBy((record, bPlace) => new { record.ShiftType, record.BusinessPlaceCode, bPlace.Name })
.Select((record, bPlace) => new ShiftAndBusinessPlaceAnalysisItemResponse
{
ShiftType = record.ShiftType,
BusinessPlaceName = bPlace.Name,
UserCount = SqlFunc.AggregateDistinctCount(record.UserCode),
CostCount = SqlFunc.AggregateCount(record.Id),
CurrentAmount = SqlFunc.AggregateSum(record.Amount),
})
.ToPageListAsync(request);
var amount = await QueryableShiftAndBusinessPlaceAnalysis(request).SumAsync(record => SqlFunc.Abs(record.Amount));
var userCount = await QueryableShiftAndBusinessPlaceAnalysis(request).Select(record => record.UserCode).Distinct().CountAsync();
return new ShiftAndBusinessPlaceAnalysisResponse
{
Amount = amount,
Total = userCount,
Pagination = page,
};
ISugarQueryable<BalanceRecordEntity, BusinessPlaceEntity> QueryableShiftAndBusinessPlaceAnalysis(BalanceRecordPageDetailRequest internalRequest)
{
return _dbContext.Queryable<BalanceRecordEntity>()
.LeftJoin<BusinessPlaceEntity>((record, bPlace) => record.BusinessPlaceCode == bPlace.Code)
.WhereIF(internalRequest.SearchDateTimePeriod.HasValue(), record => record.CostDate >= internalRequest.SearchDateTimePeriod.Start && record.CostDate <= internalRequest.SearchDateTimePeriod.End)
.WhereIF(internalRequest.ShiftTypes.IsPresent(), record => internalRequest.ShiftTypes.Contains(record.ShiftType))
.Where(record => record.Type == BalanceRecordTypeEnumType.Out && record.Status == BalanceRecordStatusEnumType.Valid)
.WhereIF(internalRequest.Search.IsPresent(), (record, bPlace) => bPlace.Name.Contains(internalRequest.Search))
.Where(record => record.BusinessPlaceCode.HasValue)
;
}
}
//**************************************************************help method***********************************************************************
/// <summary>