Преглед на файлове

Merge branch 'feature/snapshot' into dev

qinchaoyue преди 2 месеца
родител
ревизия
990b9221bf

+ 19 - 1
src/Hotline.Api/Controllers/Snapshot/BiSnapshotController.cs

@@ -51,6 +51,24 @@ public class BiSnapshotController : BaseController
     [HttpGet("statistics/details")]
     public async Task<PagedDto<SnapshotStatisticsDetailOutDto>> GetSnapshotStatisticsDetailAsync([FromQuery] SnapshotStatisticsDetailInDto dto)
         => (await _biSnapshotApplication.GetSnapshotStatisticsDetail(dto).ToPagedListAsync(dto)).ToPaged();
-    
+
+
+    /// <summary>
+    /// 市民红包审核统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("redpack/audit")]
+    public async Task<IList<RedPackStatisticsOutDto>> GetRedPackAuditStatisticsAsync([FromQuery] RedPackStatisticsInDto dto)
+        => await _biSnapshotApplication.GetRedPackAuditStatisticsAsync(dto, HttpContext.RequestAborted);
+
+    /// <summary>
+    /// 市民红包审核统计详情
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("redpack/audit/details")]
+    public async Task<PagedDto<RedPackStatisticsDetailsOutDto>> GetRedPackAuditStatisticsDetailsAsync([FromQuery] RedPackStatisticsDetailsInDto dto)
+        => (await _biSnapshotApplication.GetRedPackAuditStatisticsDetails(dto).ToPagedListAsync(dto)).ToPaged();
 
 }

+ 132 - 13
src/Hotline.Application/Snapshot/BiSnapshotApplication.cs

@@ -7,6 +7,8 @@ using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.Tools;
+using Mapster;
 using NPOI.SS.Formula.Functions;
 using SqlSugar;
 using System;
@@ -22,10 +24,125 @@ namespace Hotline.Application.Snapshot;
 public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
 {
     public readonly IOrderSnapshotRepository _orderSnapshotRepository;
+    public readonly IRedPackRecordRepository _redPackRecordRepository;
+    public readonly IIndustryRepository _industryRepository;
+    public readonly IIndustryCaseRepository _industryCaseRepository;
+    public readonly IRedPackAuditRepository _redPackAuditRepository;
 
-    public BiSnapshotApplication(IOrderSnapshotRepository orderSnapshotRepository)
+    public BiSnapshotApplication(IOrderSnapshotRepository orderSnapshotRepository, IRedPackRecordRepository redPackRecordRepository, IIndustryRepository industryRepository, IIndustryCaseRepository industryCaseRepository, IRedPackAuditRepository redPackAuditRepository)
     {
         _orderSnapshotRepository = orderSnapshotRepository;
+        _redPackRecordRepository = redPackRecordRepository;
+        _industryRepository = industryRepository;
+        _industryCaseRepository = industryCaseRepository;
+        _redPackAuditRepository = redPackAuditRepository;
+    }
+
+    /// <summary>
+    /// 市民红包审批统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="requestAborted"></param>
+    /// <returns></returns>
+    /// <exception cref="NotImplementedException"></exception>
+    public async Task<IList<RedPackStatisticsOutDto>> GetRedPackAuditStatisticsAsync(RedPackStatisticsInDto dto, CancellationToken requestAborted)
+    {
+        var industries = await _industryRepository.Queryable(includeDeleted: true)
+            .LeftJoin<IndustryCase>((industry, industryCase) => industry.Id == industryCase.IndustryId && industryCase.IsEnable == true)
+            .Select((industry, industryCase) => new RedPackStatisticsOutDto
+            {
+                Id = industry.Id,
+                Name = industry.Name,
+                CaseId = industryCase.Id,
+                CaseName = industryCase.Name,
+                ShouldAmount = industryCase.CitizenReadPackAmount == null ? industry.CitizenReadPackAmount : industryCase.CitizenReadPackAmount,
+            }).ToListAsync();
+
+        var redPackOutDto = await _redPackAuditRepository.Queryable(includeDeleted: true)
+            .LeftJoin<OrderSnapshot>((audit, snapshot) => audit.OrderId == snapshot.Id)
+            .LeftJoin<RedPackRecord>((audit, snapshot, record) => record.RedPackAuditId == audit.Id)
+            .LeftJoin<SupplementRecord>((audit, snapshot, record, supplement) => supplement.RedPackAuditId == audit.Id)
+            .Where((audit, snapshot) => audit.CreationTime >= dto.StartTime && audit.CreationTime <= dto.EndTime)
+            .GroupBy((audit, snapshot) => new { snapshot.IndustryCase, snapshot.IndustryId, snapshot.IndustryName })
+            .Select((audit, snapshot, record, supplement) => new RedPackStatisticsOutDto
+            {
+                Id = snapshot.IndustryId,
+                Name = snapshot.IndustryName,
+                CaseId = snapshot.IndustryCase,
+                ApprovalAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, audit.ApprovedAmount, 0)), //审批同意总金额
+                ApprovalCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.Status == ERedPackAuditStatus.Agree, 1, 0)), // 审批同意总个数
+                SentAmount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, audit.AcutalAmount, 0)), // 发送成功金额
+                SentCount = SqlFunc.AggregateSum(SqlFunc.IIF(audit.IsSend == true, 1, 0)), // 发送成功个数
+                SendFailAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, record.Amount, 0)), //发送失败金额
+                SendFailCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Fail, 1, 0)), // 发送失败个数
+                PendingAmount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, audit.ApprovedAmount, 0)), // 待发金额
+                PendingCount = SqlFunc.AggregateSum(SqlFunc.IIF(record.DistributionState == EReadPackSendStatus.Unsend, 1, 0)), // 待发个数
+                SupplementAmount = SqlFunc.AggregateSum(supplement.ReplenishAmount), // 补充红包金额
+                SupplementCount = SqlFunc.AggregateCount(supplement.Id), // 补充红包数
+            }).ToListAsync();
+
+        foreach (var industry in industries)
+        {
+            var item = redPackOutDto
+                .WhereIF(industry.CaseId != null, m => m.CaseId == industry.CaseId)
+                .WhereIF(industry.CaseId == null, m => m.Id == industry.Id)
+                .FirstOrDefault();
+
+            var config = new TypeAdapterConfig();
+            config.ForType<RedPackStatisticsOutDto, RedPackStatisticsOutDto>()
+                .Ignore(dest => dest.CaseId)
+                .Ignore(dest => dest.CaseName)
+                .Ignore(dest => dest.ShouldAmount);
+            item?.Adapt(industry, config);
+            if (industry.CaseId == null)
+            {
+                industry.IndustryName = $"{industry.Name}({industry.ShouldAmount?.ToString("f2")})";
+                industry.IndustryType = 1;
+            }
+            else
+            {
+                industry.IndustryType = 2;
+                if (industry.CaseName == industry.Name)
+                    industry.IndustryName = $"{industry.Name}({industry.ShouldAmount?.ToString("f2")})";
+                else
+                { 
+                    industry.IndustryName = $"{industry.Name}-{industry.CaseName}({industry.ShouldAmount?.ToString("f2")})";
+                }
+            }
+        }
+        return industries;
+    }
+
+    public ISugarQueryable<RedPackStatisticsDetailsOutDto> GetRedPackAuditStatisticsDetails(RedPackStatisticsDetailsInDto dto)
+    {
+        dto.ValidateObject();
+        dto.FieldName = dto.FieldName.ToLower();
+        var query = _orderSnapshotRepository.Queryable(includeDeleted: true)
+            .LeftJoin<Order>((snapshot, order) => order.Id == snapshot.Id)
+            .LeftJoin<RedPackAudit>((snapshot, order, audit) => snapshot.Id == audit.OrderId)
+            .LeftJoin<RedPackRecord>((snapshot, order, audit, record) => audit.Id == record.RedPackAuditId)
+            .LeftJoin<SupplementRecord>((snapshot, order, audit, record, supplement) => audit.Id == supplement.RedPackAuditId)
+            .Where((snapshot, order, audit) => audit.CreationTime >= dto.StartTime && audit.CreationTime <= dto.EndTime)
+            .WhereIF(dto.IndustryType == 1, (snapshot, order, audit) => snapshot.IndustryId == dto.IndustryId)
+            .WhereIF(dto.IndustryType == 2, (snapshot, order, audit) => snapshot.IndustryCase == dto.IndustryId);
+        query = dto.FieldName switch
+        {
+            "approvalamount" => query.Where((snapshot, order, audit) => audit.Status == ERedPackAuditStatus.Agree),
+            "approvalcount" => query.Where((snapshot, order, audit) => audit.Status == ERedPackAuditStatus.Agree),
+            "sentamount" => query.Where((snapshot, order, audit) => audit.IsSend == true),
+            "sentcount" => query.Where((snapshot, order, audit) => audit.IsSend == true),
+            "sendfailamount" => query.Where((snapshot, order, audit, record) => record.DistributionState == EReadPackSendStatus.Fail),
+            "sendfailcount" => query.Where((snapshot, order, audit, record) => record.DistributionState == EReadPackSendStatus.Fail),
+            "pendingamount" => query.Where((snapshot, order, audit, record) => record.DistributionState == EReadPackSendStatus.Unsend),
+            "pendingcount" => query.Where((snapshot, order, audit, record) => record.DistributionState == EReadPackSendStatus.Unsend),
+            "supplementamount" => query.Where((snapshot, order, audit, record, supplement) => supplement.Id != null),
+            "supplementcount" => query.Where((snapshot, order, audit, record, supplement) => supplement.Id != null),
+            _ => throw new UserFriendlyException($"不支持输入字段: {dto.FieldName}")
+        };
+        return query.Select((snapshot, order, audit, record, supplement) => new RedPackStatisticsDetailsOutDto
+        {
+            CreationTime = order.CreationTime
+        }, true);
     }
 
     public async Task<SnapshotStatisticsOutDto> GetSnapshotStatisticsAsync(SnapshotStatisticsInDto dto, CancellationToken token)
@@ -41,9 +158,9 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
             .Where((snapshot) => snapshot.CreationTime >= dto.StartTime && snapshot.CreationTime <= dto.EndTime)
             .Select((snapshot, order, redPackAudit, special, guiderAudit, record, second, orderSpecial) => new SnapshotStatisticsOutDto
             {
-                WZSLFWNJS = 0, // 未在受理范围内件数,
-                SSPZ12345JS = SqlFunc.AggregateSum(SqlFunc.IIF(order.SourceChannelCode != "SSP", 1, 0)), // 随手拍转12345件数,
-                SLFWNZJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.SourceChannelCode ==  "SSP", 1, 0)), // 受理范围内总件数,
+                WZSLFWNJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.HotspotName == "非受理范围", 1, 0)), // 未在受理范围内件数,
+                SSPZ12345JS = SqlFunc.AggregateSum(SqlFunc.IIF(order.SourceChannelCode == "SJP12345", 1, 0)), // 随手拍转12345件数,
+                SLFWNZJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.HotspotName != "非受理范围" && order.SourceChannelCode == "SJP12345", 1, 0)), // 受理范围内总件数,
                 SLFWNPGWGYSXSNHFJS = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsGuidSystemCallBack == true && snapshot.GuidSystemCallBackTime.Value.AddHours(-4) > snapshot.SendGuidSystemTime, 1, 0)), // 受理范围内派给网格员四小时内回复件数,
                 SLFWNPGWGYCGSXSHFJS = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsGuidSystemCallBack == true && snapshot.GuidSystemCallBackTime.Value.AddHours(-4) <= snapshot.SendGuidSystemTime, 1, 0)), // 受理范围内派给网格员超过四小时回复件数
                 SLFWNPGWGYWHFJS = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsGuidSystemCallBack == false, 1, 0)), // 受理范围内派给网格员未回复件数
@@ -76,23 +193,25 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
                 SLFWNDBMHQJJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.CounterSignType != null, 1, 0)), // 受理范围内多部门会签件件数
                 SLFWNRXZXGDJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.FileOrgIsCenter == true, 1, 0)), // 受理范围内热线中心归档件数
                 RXZXFQHQJJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.CounterSignType != null && order.CounterSignType == ECounterSignType.Center, 1, 0)), // 热线中心发起会签件件数
-                AQYH = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsDangerDepartment== true, 1, 0)), // 安全隐患
+                AQYH = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsDangerDepartment == true, 1, 0)), // 安全隐患
                 YWCAQYHZG = SqlFunc.AggregateSum(SqlFunc.IIF(snapshot.IsRectifyDepartment == true, 1, 0)), // 已完成安全隐患整改
-                SQYQGDJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderDelays.Count(m => m.DelayState == Share.Enums.Order.EDelayState.Pass) > 0, 1, 0)), // 申请延期工单件数
-                SQYQGDCS = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderDelays.Count() > 0, order.OrderDelays.Count(m => m.DelayState == Share.Enums.Order.EDelayState.Pass), 0)), // 申请延期工单次数
+                SQYQGDJS = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderDelays.Count(m => m.DelayState == EDelayState.Pass) > 0, 1, 0)), // 申请延期工单件数
+                SQYQGDCS = SqlFunc.AggregateSum(SqlFunc.IIF(order.OrderDelays.Count() > 0, order.OrderDelays.Count(m => m.DelayState == EDelayState.Pass), 0)), // 申请延期工单次数
                 CQJ = SqlFunc.AggregateSum(SqlFunc.IIF(order.Status >= EOrderStatus.Filed && order.ExpiredTime < order.FiledTime, 1, 0)), // 超期件
-                ECBLJSTHBM = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && second.ApplyOrgName != "市民热线服务中心", 1, 0)), // 二次办理件数 - 退回部门
-                ECBLJSHFBMYCB = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "2", 1, 0)), // 二次办理件数-回访不满意重办
-                ECBLJSTTDYYJBM = 0, // 二次办理件数-特提到原一级部门
-                ECBLJSHFMY = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && (SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "5" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "4" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "-1" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "0"), 1, 0)), // 二次办理件数-回访满意
+                ECBLJSTHBM = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && second.ApplyOrgId != "001", 1, 0)), // 二次办理件数 - 退回部门
+                ECBLJSHFBMYCB = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled, 1, 0)), // 二次办理件数-回访不满意重办
+                ECBLJSTTDYYJBM = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled, 1, 0)), // 二次办理件数-特提到原一级部门
+                ECBLJSHFMY = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && (SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "5" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "4" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "-1" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "0"), 1, 0)), // 二次办理件数-回访满意
                 // ECBLGDMYL = , // 二次办理工单满意率
-                ECBLGDJSTMBMHFMYD = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && second.ApplyOrgName != "市民热线服务中心" && (SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "5" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "4" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "-1" || SqlFunc.JsonField(second.VisitDetail.OrgHandledAttitude, "Key") == "0"), 1, 0)), // 二次办理工单件数-退回部门回访满意
+                ECBLGDJSTMBMHFMYD = SqlFunc.AggregateSum(SqlFunc.IIF(second.State == ESecondaryHandlingState.Handled && second.ApplyOrgId != "001" && (SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "5" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "4" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "-1" || SqlFunc.JsonField(order.OrgProcessingResults, "Key") == "0"), 1, 0)), // 二次办理工单件数-退回部门回访满意
                 // ECBLGDMYLTHBM = , // 二次办理工单满意率-退回部门
                 // ECBLGDMYLHFBMYCB = 0, // 二次办理工单满意率-回访不满意重办
 
                 TTDYYJBMJS = SqlFunc.AggregateSum(SqlFunc.IIF(orderSpecial.State == 1 && orderSpecial.SpecialType == ESpecialType.Special && orderSpecial.NextStepName == "一级部门", 1, 0)), // 特提到原一级部门件数
                 TTDPDZJS = SqlFunc.AggregateSum(SqlFunc.IIF(orderSpecial.State == 1 && orderSpecial.SpecialType == ESpecialType.Special && orderSpecial.NextStepName == "派单组", 1, 0)), // 特提到派单组件数
-                QTTTJS = SqlFunc.AggregateSum(SqlFunc.IIF(orderSpecial.State == 1 && orderSpecial.IsDeleted == false && orderSpecial.SpecialType == ESpecialType.Special && (orderSpecial.NextStepName != "一级部门" || orderSpecial.NextStepName != "派单组"), 1, 0)), // 其他特提件数
+                QTTTJS = SqlFunc.AggregateSum(SqlFunc.IIF(orderSpecial.State == 1 && orderSpecial.SpecialType == ESpecialType.Special && (orderSpecial.NextStepName != "一级部门" || orderSpecial.NextStepName != "派单组"), 1, 0)), // 其他特提件数
+
+
             });
         return await query.FirstAsync();
     }

+ 2 - 0
src/Hotline.Application/Snapshot/IBiSnapshotApplication.cs

@@ -11,6 +11,8 @@ using System.Threading.Tasks;
 namespace Hotline.Application.Snapshot;
 public interface IBiSnapshotApplication
 {
+    Task<IList<RedPackStatisticsOutDto>> GetRedPackAuditStatisticsAsync(RedPackStatisticsInDto dto, CancellationToken requestAborted);
+    ISugarQueryable<RedPackStatisticsDetailsOutDto> GetRedPackAuditStatisticsDetails(RedPackStatisticsDetailsInDto dto);
     Task<SnapshotStatisticsOutDto> GetSnapshotStatisticsAsync(SnapshotStatisticsInDto dto, CancellationToken token);
     ISugarQueryable<SnapshotStatisticsDetailOutDto> GetSnapshotStatisticsDetail(SnapshotStatisticsDetailInDto dto);
 }

+ 48 - 45
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -105,7 +105,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
                 WXOpenId = third?.OpenId,
                 No = order.No,
                 PickupStatus = ERedPackPickupStatus.Unreceived,
-                DistributionState = EReadPackSendStatus.Successful,
+                DistributionState = EReadPackSendStatus.Unsend,
             };
             if (redPackAudit.ApprovedAmount.HasValue)
                 entity.Amount = redPackAudit.ApprovedAmount.Value;
@@ -167,7 +167,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
                     PhoneNumber = order.FromPhone,
                     No = order.No,
                     PickupStatus = ERedPackPickupStatus.Unreceived,
-                    DistributionState = EReadPackSendStatus.Successful,
+                    DistributionState = EReadPackSendStatus.Unsend,
                 };
                 if (redPackAudit.ApprovedAmount.HasValue)
                     entity.Amount = redPackAudit.ApprovedAmount.Value;
@@ -262,7 +262,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             .LeftJoin<OrderSnapshot>((redPackAudit, snapshot) => redPackAudit.OrderId == snapshot.Id)
             .LeftJoin<Order>((redPackAudit, snapshot, order) => redPackAudit.OrderId == order.Id)
             .LeftJoin<SpecialRedPackAudit>((redPackAudit, snapshot, order, special) => redPackAudit.OrderId == special.OrderId)
-            .Where((redPackAudit, snapshot, order, special) => (redPackAudit.Status == ERedPackAuditStatus.Agree && snapshot.IndustryName == "安全隐患" && order.OrderTagCode!.Contains("DHZY")) || (redPackAudit.Status == ERedPackAuditStatus.Agree && order.CreationTime >=beginTime && order.CreationTime <= endTime && redPackAudit.ApprovedAmount == 20 && order.AcceptTypeCode != "30" && snapshot.IndustryName != "电气焊作业申报"))
+            .Where((redPackAudit, snapshot, order, special) => (redPackAudit.Status == ERedPackAuditStatus.Agree && snapshot.IndustryName == "安全隐患" && order.OrderTagCode!.Contains("DHZY")) || (redPackAudit.Status == ERedPackAuditStatus.Agree && order.CreationTime >= beginTime && order.CreationTime <= endTime && redPackAudit.ApprovedAmount == 20 && order.AcceptTypeCode != "30" && snapshot.IndustryName != "电气焊作业申报"))
             .WhereIF(dto.Status == 0, (redPackAudit, snapshot, order, special) => special.Id == null)
             .WhereIF(dto.Status == 1, (redPackAudit, snapshot, order, special) => special.Status == ERedPackAuditStatus.Agree)
             .WhereIF(dto.Status == 2, (redPackAudit, snapshot, order, special) => special.Status == ERedPackAuditStatus.Refuse)
@@ -273,8 +273,8 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             .WhereIF(dto.IsDeal.HasValue, (redPackAudit, snapshot, order, special) => snapshot.IsDeal == dto.IsDeal)
             .WhereIF(dto.IsTruth.HasValue, (redPackAudit, snapshot, order, special) => snapshot.IsTruth == dto.IsTruth)
             .WhereIF(dto.IsTruthDepartment.HasValue, (redPackAudit, snapshot, order, special) => snapshot.IsTruthDepartment == dto.IsTruthDepartment)
-            .WhereIF(dto.BeginAuditTime.HasValue && dto.EndAuditTime.HasValue, (redPackAudit, snapshot, order, special) => redPackAudit.AuditTime >=  dto.BeginAuditTime && redPackAudit.AuditTime <= dto.EndAuditTime)
-            .WhereIF(dto.BeginFiledTime.HasValue && dto.EndFiledTime.HasValue, (redPackAudit, snapshot, order, special) => order.FiledTime >=  dto.BeginFiledTime && order.FiledTime <= dto.EndFiledTime)
+            .WhereIF(dto.BeginAuditTime.HasValue && dto.EndAuditTime.HasValue, (redPackAudit, snapshot, order, special) => redPackAudit.AuditTime >= dto.BeginAuditTime && redPackAudit.AuditTime <= dto.EndAuditTime)
+            .WhereIF(dto.BeginFiledTime.HasValue && dto.EndFiledTime.HasValue, (redPackAudit, snapshot, order, special) => order.FiledTime >= dto.BeginFiledTime && order.FiledTime <= dto.EndFiledTime)
             .WhereIF(dto.IsIssued.HasValue, (redPackAudit, snapshot, order, special) => redPackAudit.IsSend == dto.IsIssued)
             .WhereIF(dto.IndustryId.NotNullOrEmpty(), (redPackAudit, snapshot, order, special) => snapshot.IndustryId == dto.IndustryId)
             .WhereIF(dto.ConfigAmount.HasValue, (redPackAudit, snapshot, order, special) => special.ShouldAmount == dto.ConfigAmount)
@@ -282,7 +282,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             .WhereIF(dto.ApprovedAmount.HasValue, (redPackAudit, snapshot, order, special) => special.ApprovedAmount == dto.ApprovedAmount)
             .WhereIF(dto.IsDanger.HasValue, (redPackAudit, snapshot, order, special) => snapshot.IsDanger == dto.IsDanger)
             .OrderByDescending((redPackAudit, snapshot, order, special) => redPackAudit.CreationTime)
-                        .Select((redPackAudit, snapshot,order, special) => new SnapshotOrderAuditItemsOutDto
+                        .Select((redPackAudit, snapshot, order, special) => new SnapshotOrderAuditItemsOutDto
                         {
                             Id = redPackAudit.Id,
                             RedPackAuditId = redPackAudit.Id,
@@ -505,24 +505,25 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     {
         var audit = await _redPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
         audit.AcutalAmount = dto.AcutalAmount;
-        if (dto.IsSend == false)
-        {
-            await _redPackRecordRepository.Queryable()
-                .Where(m => m.RedPackAuditId == audit.Id)
-                .FirstAsync()
-                .Then(async (record) =>
-                {
-                    if (dto.FailCase != null)
-                    {
-                        record.FailCase = dto.FailCase.Value;
-                        record.DistributionState = EReadPackSendStatus.Fail;
-                        if (record.FailCase == ERedPackPickupFailCase.Excuse)
-                            record.PickupStatus = ERedPackPickupStatus.Excuse;
-                    }
-                    await _redPackRecordRepository.UpdateAsync(record);
-                });
-        }
+        audit.IsSend = dto.IsSend;
         audit.SendRemarks = dto.SendRemarks;
+        await _redPackRecordRepository.Queryable()
+            .Where(m => m.RedPackAuditId == audit.Id)
+            .FirstAsync()
+            .Then(async (record) =>
+            {
+                if (dto.FailCase != null)
+                {
+                    record.FailCase = dto.FailCase.Value;
+                    record.DistributionState = EReadPackSendStatus.Fail;
+                    if (record.FailCase == ERedPackPickupFailCase.Excuse)
+                        record.PickupStatus = ERedPackPickupStatus.Excuse;
+                }
+                if (dto.IsSend)
+                    record.DistributionState = EReadPackSendStatus.Successful;
+                await _redPackRecordRepository.UpdateAsync(record);
+            });
+
         await _redPackAuditRepository.UpdateAsync(audit);
     }
 
@@ -533,28 +534,29 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     /// <returns></returns>
     public async Task UpdateRedPackRecordAsync(UpdateRedPackRecordInDto dto)
     {
-        var record = await _redPackRecordRepository.Queryable()
-            .Where(m => m.RedPackAuditId == dto.RedPackAuditId)
-            .FirstAsync() ?? throw UserFriendlyException.SameMessage("审核记录不存在");
-        record.DistributionState = EReadPackSendStatus.Successful;
-        record.PickupStatus = ERedPackPickupStatus.Received;
+        //var record = await _redPackRecordRepository.Queryable()
+        //    .Where(m => m.RedPackAuditId == dto.RedPackAuditId)
+        //    .FirstAsync() ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        //record.DistributionState = EReadPackSendStatus.Successful;
+        //record.PickupStatus = ERedPackPickupStatus.Received;
         var audit = await _redPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        var orderNo = await _orderRepository.Queryable().Where(m => m.Id == audit.OrderId).Select(m => m.No).FirstAsync();
 
         dto.Adapt(audit);
         audit.IsSend = true;
         audit.AcutalAmount = dto.ReplenishAmount;
         await _redPackAuditRepository.UpdateAsync(audit);
-        await _redPackRecordRepository.UpdateAsync(record);
+        //await _redPackRecordRepository.UpdateAsync(record);
 
         var entity = dto.Adapt<SupplementRecord>();
         var industryName = await _orderSnapshotRepository.Queryable()
-            .Where(m => m.Id == record.OrderId)
+            .Where(m => m.Id == audit.OrderId)
             .Select(m => new { m.IndustryName, m.IndustryId })
             .FirstAsync();
-        entity.OrderId = record.OrderId;
-        entity.RedPackRecordId = record.Id;
+        entity.OrderId = audit.OrderId;
+        //entity.RedPackRecordId = record.Id;
         entity.RedPackAuditId = audit.Id;
-        entity.No = record.No;
+        entity.No = orderNo;
         entity.IndustryName = industryName.IndustryName;
         entity.IndustryId = industryName.IndustryId;
         await _supplementRecordRepository.AddAsync(entity);
@@ -572,28 +574,29 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     /// <returns></returns>
     public async Task UpdateRedPackSpecialRecordAsync(UpdateRedPackRecordInDto dto)
     {
-        var record = await _redPackRecordRepository.Queryable()
-            .Where(m => m.RedPackAuditId == dto.RedPackAuditId)
-            .FirstAsync() ?? throw UserFriendlyException.SameMessage("审核记录不存在");
-        record.DistributionState = EReadPackSendStatus.Successful;
-        record.PickupStatus = ERedPackPickupStatus.Received;
+        //var record = await _redPackRecordRepository.Queryable()
+        //    .Where(m => m.RedPackAuditId == dto.RedPackAuditId)
+        //    .FirstAsync() ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        //record.DistributionState = EReadPackSendStatus.Successful;
+        //record.PickupStatus = ERedPackPickupStatus.Received;
         var audit = await _specialRedPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        var orderNo = await _orderRepository.Queryable().Where(m => m.Id == audit.OrderId).Select(m => m.No).FirstAsync();
 
         dto.Adapt(audit);
         audit.IsSend = true;
         audit.AcutalAmount = dto.ReplenishAmount;
         await _specialRedPackAuditRepository.UpdateAsync(audit);
-        await _redPackRecordRepository.UpdateAsync(record);
+        //await _redPackRecordRepository.UpdateAsync(record);
 
         var entity = dto.Adapt<SupplementRecord>();
         var industryName = await _orderSnapshotRepository.Queryable()
-            .Where(m => m.Id == record.OrderId)
+            .Where(m => m.Id == audit.OrderId)
             .Select(m => new { m.IndustryName, m.IndustryId })
             .FirstAsync();
-        entity.OrderId = record.OrderId;
-        entity.RedPackRecordId = record.Id;
+        entity.OrderId = audit.OrderId;
+        //entity.RedPackRecordId = record.Id;
         entity.RedPackAuditId = audit.Id;
-        entity.No = record.No;
+        entity.No = orderNo;
         entity.IndustryName = industryName.IndustryName;
         entity.IndustryId = industryName.IndustryId;
         await _supplementRecordRepository.AddAsync(entity);
@@ -726,7 +729,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         if (_specialRedPackAuditRepository.ExistByOrderId(audit.OrderId)) throw UserFriendlyException.SameMessage("已审核, 不可重复审核");
         var specialAudit = audit.Adapt<SpecialRedPackAudit>();
         if (dto.AuditTypeId.NotNullOrEmpty())
-        { 
+        {
             var specialType = _systemDic.SnapshotRedPackSpecialType.FirstOrDefault(m => m.Id == dto.AuditTypeId);
             if (specialType != null)
             {
@@ -776,7 +779,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
             outDto.Name = snapshot.AwardName;
             outDto.Amount = snapshot.AwardAmount;
         }
-        var audit = await _specialRedPackAuditRepository.Queryable().Where(m => m.OrderId == orderId).FirstAsync() 
+        var audit = await _specialRedPackAuditRepository.Queryable().Where(m => m.OrderId == orderId).FirstAsync()
             ?? throw new UserFriendlyException("审核记录不存在");
         if (audit != null)
         {

+ 1 - 1
src/Hotline.Share/Dtos/Order/OrderStartFlowDto.cs

@@ -171,7 +171,7 @@ namespace Hotline.Share.Dtos.Order
         public bool? IsRectifyDepartment { get; set; }
 
         /// <summary>
-        /// 线索分类
+        /// 线索分类Id
         /// </summary>
         public string? IndustryCase { get; set; }
 

+ 314 - 0
src/Hotline.Share/Dtos/Snapshot/StatisticsDto.cs

@@ -1,15 +1,329 @@
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Requests;
+using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
 using System.ComponentModel.DataAnnotations;
 using System.Linq;
 using System.Text;
+using System.Text.Json.Serialization;
 using System.Threading.Tasks;
 using XF.Utility.EnumExtensions;
+using JsonIgnoreAttribute = System.Text.Json.Serialization.JsonIgnoreAttribute;
 
 namespace Hotline.Share.Dtos.Snapshot;
 
+public record RedPackStatisticsDetailsInDto : PagedRequest
+{
+    [Required]
+    public DateTime StartTime { get; set; }
+    [Required]
+    public DateTime EndTime { get; set; }
+
+    /// <summary>
+    /// 字段名称
+    /// </summary>
+    [Required]
+    public string FieldName { get; set; }
+
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [Required]
+    public string? IndustryId { get; set; }
+
+    /// <summary>
+    /// 行业类型
+    /// </summary>
+    [Required]
+    public int IndustryType { get; set; }
+}
+
+public class RedPackStatisticsDetailsOutDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string Id { get; set; }
+
+    /// <summary>
+    /// 过期状态
+    /// </summary>
+    public EExpiredStatus ExpiredStatus { get; set; }
+
+    /// <summary>
+    /// 过期状态
+    /// </summary>
+    public string ExpiredStatusText => ExpiredStatus.GetDescription();
+
+    /// <summary>
+    /// 受理编号
+    /// </summary>
+    public string No { get; set; }
+
+    /// <summary>
+    /// 信件状态
+    /// </summary>
+    public EOrderStatus Status { get; set; }
+
+    /// <summary>
+    /// 信件状态
+    /// </summary>
+    public string StatusTxt => Status.GetDescription();
+
+    /// <summary>
+    /// 来源
+    /// </summary>
+    public string SourceChannel { get; set; }
+
+    /// <summary>
+    /// 当前节点
+    /// </summary>
+    public string CurrentStepName { get; set; }
+
+    /// <summary>
+    /// 重办次数
+    /// </summary>
+    public int ReTransactNum { get; set; }
+
+    /// <summary>
+    /// 是否紧急
+    /// </summary>
+    public bool IsUrgent { get; set; }
+
+    /// <summary>
+    /// 是否紧急
+    /// </summary>
+    public string IsUrgentTxt => IsUrgent ? "紧急" : "-";
+
+    /// <summary>
+    /// 期满时间
+    /// </summary>
+    public DateTime? ExpiredTime { get; set; }
+
+    /// <summary>
+    /// 是否超期
+    /// </summary>
+    public bool IsExpired
+    {
+        get
+        {
+            if (ExpiredTime.HasValue)
+                return DateTime.Now > ExpiredTime.Value;
+            return false;
+        }
+    }
+
+    /// <summary>
+    /// 受理时间
+    /// </summary>
+    public DateTime CreationTime { get; set; }
+
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string Title { get; set; }
+
+    /// <summary>
+    /// 行业
+    /// </summary>
+    public string IndustryName { get; set; }
+
+    /// <summary>
+    /// 办理时长
+    /// </summary>
+    public double CreationTimeHandleDuration { get; set; }
+
+    /// <summary>
+    /// 区域
+    /// </summary>
+    public string County { get; set; }
+
+    /// <summary>
+    /// 电话
+    /// </summary>
+    public string Contact { get; set; }
+
+    /// <summary>
+    /// 受理期满时间
+    /// </summary>
+    public DateTime? AcceptExpiredTime { get; set; }
+
+    /// <summary>
+    /// 接办部门
+    /// </summary>
+    public string ActualHandleOrgName { get; set; }
+
+    /// <summary>
+    /// 接办时间
+    /// </summary>
+    public DateTime? StartTime { get; set; }
+
+    /// <summary>
+    /// 办结时间
+    /// </summary>
+    public DateTime? CenterToOrgTime { get; set; }
+
+    /// <summary>
+    /// 受理类型
+    /// </summary>
+    public string AcceptType { get; set; }
+
+    /// <summary>
+    /// 热点类型
+    /// </summary>
+    public string HotspotName { get; set; }
+
+    /// <summary>
+    /// 受理人
+    /// </summary>
+    public string AcceptorName { get; set; }
+
+    /// <summary>
+    /// 受理内容
+    /// </summary>
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 办理结果
+    /// </summary>
+    public string FileOpinion { get; set; }
+}
+
+public class RedPackStatisticsInDto
+{
+    public DateTime StartTime { get; set; }
+    public DateTime EndTime { get; set; }
+}
+
+public class RedPackStatisticsOutDto
+{
+    /// <summary>
+    /// 行业类型
+    /// </summary>
+    [JsonIgnore]
+    [Newtonsoft.Json.JsonIgnore]
+    public string CaseName { get; set; }
+
+    /// <summary>
+    /// 行业类型Id
+    /// </summary>
+    [JsonIgnore]
+    [Newtonsoft.Json.JsonIgnore]
+    public string CaseId { get; set; }
+
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    [JsonIgnore]
+    [Newtonsoft.Json.JsonIgnore]
+    public string? Id { get; set; }
+
+    /// <summary>
+    /// 行业名字
+    /// </summary>
+    [JsonIgnore]
+    [Newtonsoft.Json.JsonIgnore]
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 配置金额(后端逻辑用, 前端不显示)
+    /// </summary>
+    [JsonIgnore]
+    [Newtonsoft.Json.JsonIgnore]
+    public double? ShouldAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 审批同意总金额
+    /// </summary>
+    public double? ApprovalAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 审批同意总金额
+    /// </summary>
+    public string? ApprovalAmountTxt => ApprovalAmount?.ToString("f2");
+
+    /// <summary>
+    /// 审批同意总个数
+    /// </summary>
+    public int ApprovalCount { get; set; }
+
+    /// <summary>
+    /// 发送成功金额
+    /// </summary>
+    public double? SentAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 发送成功金额
+    /// </summary>
+    public string? SentAmountTxt => SentAmount?.ToString("f2");
+
+    /// <summary>
+    /// 发送成功个数
+    /// </summary>
+    public int SentCount { get; set; }
+
+    /// <summary>
+    /// 发送失败金额
+    /// </summary>
+    public double SendFailAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 发送失败金额
+    /// </summary>
+    public string? SendFailAmountTxt => SendFailAmount.ToString("f2");
+
+    /// <summary>
+    /// 发送失败个数
+    /// </summary>
+    public int SendFailCount { get; set; }
+
+    /// <summary>
+    /// 待发金额
+    /// </summary>
+    public double? PendingAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 待发金额
+    /// </summary>
+    public string? PendingAmountTxt => PendingAmount?.ToString("f2");
+
+    /// <summary>
+    /// 待发个数
+    /// </summary>
+    public int PendingCount { get; set; }
+
+    /// <summary>
+    /// 补充红包金额
+    /// </summary>
+    public double? SupplementAmount { get; set; } = 0;
+
+    /// <summary>
+    /// 补充红包金额
+    /// </summary>
+    public string? SupplementAmountTxt => SupplementAmount?.ToString("f2");
+
+    /// <summary>
+    /// 补充红包数
+    /// </summary>
+    public int SupplementCount { get; set; }
+
+    /// <summary>
+    /// 行业类型名称
+    /// </summary>
+    public string? IndustryName { get; set; }
+
+    /// <summary>
+    /// 行业Id
+    /// </summary>
+    public string? IndustryId { get; set; }
+
+    /// <summary>
+    /// 行业类型
+    /// </summary>
+    public int IndustryType { get; set; }
+}
+
 /// <summary>
 /// 随手拍统计输出Dto
 /// </summary>

+ 1 - 1
src/Hotline/Snapshot/OrderSnapshot.cs

@@ -147,7 +147,7 @@ public class OrderSnapshot : CreationSoftDeleteEntity
     public bool? IsRectifyDepartment { get; set; }
 
     /// <summary>
-    /// 线索分类
+    /// 线索分类Id
     /// </summary>
     [SugarColumn(ColumnDescription = "线索分类")]
     public string? IndustryCase { get; set; }

+ 2 - 2
src/Hotline/Snapshot/SupplementRecord.cs

@@ -36,8 +36,8 @@ public class SupplementRecord : FullStateEntity
     /// <summary>
     /// RedPackRecordId
     /// </summary>
-    [SugarColumn(ColumnDescription = "RedPackRecordId")]
-    public string RedPackRecordId { get; set; }
+    //[SugarColumn(ColumnDescription = "RedPackRecordId")]
+    //public string RedPackRecordId { get; set; }
 
     /// <summary>
     /// 行业