LqStatisticsService.cs 9.11 KB
using NCC.Common.Core.Manager;
using NCC.Common.Enum;
using NCC.Common.Extension;
using NCC.Common.Filter;
using NCC.Dependency;
using NCC.DynamicApiController;
using NCC.FriendlyException;
using NCC.Extend.Interfaces.LqStatistics;
using NCC.Extend.Entitys.Dto.LqStatistics;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using NCC.Extend.Entitys.lq_mdxx;
using NCC.Extend.Entitys.Dto.LqMdxx;
using NCC.System.Entitys.Permission;
using Microsoft.Extensions.Logging;

namespace NCC.Extend.LqStatistics
{
    /// <summary>
    /// 绿纤统计服务
    /// </summary>
    [ApiDescriptionSettings(Tag = "绿纤统计服务", Name = "LqStatistics", Order = 200, Groups = new[] { "Default" })]
    [Route("api/Extend/[controller]")]
    public class LqStatisticsService : ILqStatisticsService, IDynamicApiController, ITransient
    {
        private readonly ISqlSugarRepository<LqMdxxEntity> _lqMdxxRepository;
        private readonly SqlSugarScope _db;
        private readonly IUserManager _userManager;
        private readonly ILogger<LqStatisticsService> _logger;

        /// <summary>
        /// 初始化一个<see cref="LqStatisticsService"/>类型的新实例
        /// </summary>
        public LqStatisticsService(
            ISqlSugarRepository<LqMdxxEntity> lqMdxxRepository,
            IUserManager userManager,
            ILogger<LqStatisticsService> logger)
        {
            _lqMdxxRepository = lqMdxxRepository;
            _db = _lqMdxxRepository.Context;
            _userManager = userManager;
            _logger = logger;
        }

        #region     获取门店业绩统计列表
        /// <summary>
        /// 获取门店业绩统计列表
        /// </summary>
        /// <remarks>
        /// 查询所有门店的目标业绩、完成业绩、完成率等关键指标
        /// 
        /// 返回数据包含:
        /// - 门店编码和店名
        /// - 目标业绩(生命线)
        /// - 完成业绩(实付业绩)
        /// - 完成率(百分比)
        /// - 开单数量
        /// 
        /// 数据来源:v_store_performance_simple 视图
        /// </remarks>
        /// <returns>门店业绩统计列表</returns>
        /// <response code="200">成功返回门店业绩统计列表</response>
        /// <response code="500">服务器内部错误</response>
        [HttpGet]
        public async Task<List<StorePerformanceOutput>> GetStorePerformanceList()
        {
            try
            {
                var result = await _db.Ado.SqlQueryAsync<StorePerformanceOutput>(
                    "SELECT " +
                    "store_code AS StoreCode, " +
                    "store_name AS StoreName, " +
                    "target_performance AS TargetPerformance, " +
                    "actual_performance AS ActualPerformance, " +
                    "completion_rate AS CompletionRate, " +
                    "order_count AS OrderCount " +
                    "FROM v_store_performance_simple " +
                    "ORDER BY actual_performance DESC");

                return result ?? new List<StorePerformanceOutput>();
            }
            catch (Exception ex)
            {
                throw NCCException.Oh(ErrorCode.COM1005, ex.Message);
            }
        }
        #endregion

        #region 门店统计信息
        /// <summary>
        /// 获取门店统计信息
        /// </summary>
        /// <remarks>
        /// 统计各个门店在员工数量、项目数(耗卡里面的项目数量)和消耗业绩(耗卡里面的金额)
        /// 可以传入日期,然后去统计本月一号到传入的日期
        /// 
        /// 示例请求:
        /// ```json
        /// {
        ///   "queryDate": "2025-09-14"
        /// }
        /// ```
        /// 
        /// 参数说明:
        /// - queryDate: 查询日期,系统会自动计算本月1号到该日期的统计范围
        /// </remarks>
        /// <param name="input">查询参数</param>
        /// <returns>门店统计结果</returns>
        /// <response code="200">查询成功</response>
        /// <response code="400">参数错误</response>
        /// <response code="500">服务器内部错误</response>
        [HttpPost("StoreStatistics")]
        public async Task<StoreStatisticsOutput> GetStoreStatistics([FromBody] StoreStatisticsInput input)
        {
            try
            {
                _logger.LogInformation("开始查询门店统计信息,查询日期:{QueryDate}", input.QueryDate);

                // 计算查询时间范围:本月1号到传入日期
                var startDate = new DateTime(input.QueryDate.Year, input.QueryDate.Month, 1);
                var endDate = input.QueryDate.Date.AddDays(1).AddSeconds(-1); // 包含当天结束时间

                _logger.LogInformation("统计时间范围:{StartDate} 到 {EndDate}", startDate, endDate);

                // 1. 查询门店基础信息
                var storeList = await _db.Queryable<LqMdxxEntity>()
                    .Select(it => new StoreStatisticsInfo
                    {
                        StoreId = it.Id,
                        StoreCode = it.Mdbm,
                        StoreName = it.Dm,
                        City = it.Cs,
                        BusinessUnit = it.Syb,
                        EmployeeCount = 0,
                        ProjectCount = 0,
                        ConsumeAmount = 0
                    })
                    .ToListAsync();

                _logger.LogInformation("查询到门店数量:{Count}", storeList.Count);

                // 2. 查询员工数量(按门店统计)
                var employeeCounts = await _db.Queryable<UserEntity>()
                    .Where(u => !string.IsNullOrEmpty(u.Mdid) && u.DeleteMark != 1)
                    .GroupBy(u => u.Mdid)
                    .Select(g => new { StoreId = g.Mdid, Count = SqlFunc.AggregateCount(g.Id) })
                    .ToListAsync();

                _logger.LogInformation("查询到员工统计数量:{Count}", employeeCounts.Count);

                // 3. 从视图查询项目数和消耗业绩
                var consumeStats = await _db.SqlQueryable<dynamic>(@"
                    SELECT 
                        store_id,
                        SUM(total_project_count) as total_project_count,
                        SUM(total_consume_amount) as total_consume_amount
                    FROM v_store_daily_consume_stats 
                    WHERE consume_date >= @startDate AND consume_date <= @endDate
                    GROUP BY store_id")
                    .AddParameters(new { startDate = startDate.ToString("yyyy-MM-dd"), endDate = input.QueryDate.ToString("yyyy-MM-dd") })
                    .ToListAsync();

                _logger.LogInformation("查询到消耗统计数量:{Count}", consumeStats.Count);

                // 4. 合并统计数据
                foreach (var store in storeList)
                {
                    // 匹配员工数量
                    var employeeCount = employeeCounts.FirstOrDefault(e => e.StoreId == store.StoreId);
                    if (employeeCount != null)
                    {
                        store.EmployeeCount = employeeCount.Count;
                    }

                    // 匹配项目数和消耗业绩
                    var consumeStat = consumeStats.FirstOrDefault(c => c.store_id?.ToString() == store.StoreId);
                    if (consumeStat != null)
                    {
                        store.ProjectCount = Convert.ToDecimal(consumeStat.total_project_count ?? 0);
                        store.ConsumeAmount = Convert.ToDecimal(consumeStat.total_consume_amount ?? 0);
                    }
                }

                // 5. 计算汇总统计
                var summary = new StoreSummaryInfo
                {
                    TotalStoreCount = storeList.Count,
                    TotalEmployeeCount = storeList.Sum(s => s.EmployeeCount),
                    TotalProjectCount = storeList.Sum(s => s.ProjectCount),
                    TotalConsumeAmount = storeList.Sum(s => s.ConsumeAmount)
                };

                var result = new StoreStatisticsOutput
                {
                    StartDate = startDate,
                    EndDate = input.QueryDate,
                    StoreList = storeList.OrderByDescending(s => s.ConsumeAmount).ToList(),
                    Summary = summary
                };

                _logger.LogInformation("门店统计查询完成,门店数:{StoreCount},总员工数:{EmployeeCount},总项目数:{ProjectCount},总消耗业绩:{ConsumeAmount}",
                    summary.TotalStoreCount, summary.TotalEmployeeCount, summary.TotalProjectCount, summary.TotalConsumeAmount);

                return result;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "查询门店统计信息时发生错误,查询日期:{QueryDate}", input.QueryDate);
                throw NCCException.Oh(ErrorCode.COM1000, "查询门店统计信息失败");
            }
        }
        #endregion
    }
}