소스 검색

随手拍重办统计

qinchaoyue 1 개월 전
부모
커밋
c11539fec0

+ 3 - 1
src/Hotline.Api/Controllers/OrderController.cs

@@ -6494,6 +6494,7 @@ public class OrderController : BaseController
         }
 
         await _orderSpecialRepository.AddAsync(special, HttpContext.RequestAborted);
+        await _publisher.PublishAsync(new AddOrderSpecialNotify(order.Id, order.SourceChannel, dto.ReTransactError), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted);
     }
 
     /// <summary>
@@ -6909,10 +6910,11 @@ public class OrderController : BaseController
             }
         }
 
+        var isInstaShot = order.SourceChannel.Contains("随手拍");
         var rsp = new
         {
             SpecialTimeType = EnumExts.GetDescriptions<ETimeType>(),
-            SpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
+            SpecialReason = isInstaShot ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason) : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason),
             InstaShotSpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason),
             Step = step,
             IsTerminate =

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

@@ -15,6 +15,9 @@ using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Snapshot;
 using XF.Utility.EnumExtensions;
 using Amazon.Runtime.Internal.Util;
+using System.Collections;
+using Mapster;
+using Hotline.Share.Dtos.Settings;
 
 namespace Hotline.Api.Controllers.Snapshot;
 
@@ -25,11 +28,13 @@ public class BiSnapshotController : BaseController
 {
     private readonly IBiSnapshotApplication _biSnapshotApplication;
     private readonly IIndustryRepository _industryRepository;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
 
-    public BiSnapshotController(IBiSnapshotApplication biSnapshotApplication, IIndustryRepository industryRepository)
+    public BiSnapshotController(IBiSnapshotApplication biSnapshotApplication, IIndustryRepository industryRepository, ISystemDicDataCacheManager systemDicDataCacheManager)
     {
         _biSnapshotApplication = biSnapshotApplication;
         _industryRepository = industryRepository;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
     }
 
     /// <summary>
@@ -261,4 +266,19 @@ public class BiSnapshotController : BaseController
     [HttpGet("compliant-statistics-detail")]
     public async Task<PagedDto<CompliantStatisticsDetailsOutDto>> CompliantStatisticsDetailsAsync([FromQuery] CompliantStatisticsDetailsInDto dto)
         => (await _biSnapshotApplication.GetCompliantStatisticsDetails(dto).ToPagedListAsync(dto)).ToPaged();
+
+    /// <summary>
+    /// 重办统计-随手拍
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("re_transact-statistics")]
+    public async Task<ReTransactStatisticsOutDto> GetReTransactStatisticsAsync([FromQuery] ReTransactStatisticsInDto dto)
+    {
+        return new ReTransactStatisticsOutDto
+        {
+            Headers = _systemDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason).Adapt<IList<SystemDicDataOutDto>>(),
+            Data = _biSnapshotApplication.GetReTransactStatistics(dto)
+        };
+    }
 }

+ 72 - 5
src/Hotline.Application/Snapshot/BiSnapshotApplication.cs

@@ -23,6 +23,7 @@ using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
 using NPOI.SS.Formula.Functions;
+using Org.BouncyCastle.Asn1.Pkcs;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -697,17 +698,13 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
         var query = _orderSnapshotRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((snapshot, order) => snapshot.Id == order.Id)
             .Where((snapshot, order) => order.CreationTime >= dto.StartTime && order.CreationTime <= dto.EndTime && order.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")) == dto.OrgCode)
-            .Select((snapshot, order) => new SnapshotDepartmentAveTimeStatisticsDetailsOutDto(), true) ;
+            .Select((snapshot, order) => new SnapshotDepartmentAveTimeStatisticsDetailsOutDto(), true);
         return query;
     }
 
     [ExportExcel("检查合规统计", "OrgName")]
     public ISugarQueryable<CompliantStatisticsOutDto> GetCompliantStatistics(CompliantStatisticsInDto dto)
     {
-        bool IsCenter = _sessionContext.OrgIsCenter;
-        var orgLevel = _sessionContext.OrgLevel;
-        string orgLevelStr = (_sessionContext.RequiredOrgId.Length + 3).ToString();
-
         var query = _orderSnapshotRepository.Queryable(includeDeleted: true)
             .LeftJoin<Order>((snapshot, order) => snapshot.Id == order.Id)
             .LeftJoin<OrderSendBackAudit>((snapshot, order, back) => snapshot.Id == back.OrderId && back.State == ESendBackAuditState.End)
@@ -764,4 +761,74 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
         }, true);
     }
 
+    public List<Dictionary<string, object>> GetReTransactStatistics(ReTransactStatisticsInDto dto)
+    {
+        var rawData = _orderSnapshotRepository.Queryable(includeDeleted: true)
+            .LeftJoin<Order>((snapshot, order) => order.Id == snapshot.Id)
+            .Where((snapshot, order) => snapshot.SpecialReasonId != null)
+            .GroupBy((snapshot, order) => new
+            {
+                OrgCode = order.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                SpecialReasonId = snapshot.SpecialReasonId,
+                snapshot.SpecialReasonName
+            })
+            .Select((snapshot, order) => new 
+            { 
+                OrgCode = order.ActualHandleOrgCode.Substring(SqlFunc.MappingColumn<int>("0"), SqlFunc.MappingColumn<int>("6")),
+                OrderCountNum = SqlFunc.AggregateCount(snapshot.Id),
+                SpecialReasonId = snapshot.SpecialReasonId,
+                SpecialReasonName = snapshot.SpecialReasonName
+            }, true) 
+            .MergeTable()
+            .LeftJoin<SystemOrganize>((it, o) => it.OrgCode == o.Id)
+            .Select((it, o) => new
+            {
+                OrgName = o.Name,
+                OrgCode = it.OrgCode,
+                OrderCountNum = it.OrderCountNum,
+                SpecialReasonId = it.SpecialReasonId,
+                SpecialReasonName = it.SpecialReasonName
+            }).ToList();
+
+        // 2. 处理 Pivot 逻辑
+        var pivotResult = new List<Dictionary<string, object>>();
+
+        // 先获取所有 OrgCode 和 OrgName
+        var orgGroups = rawData.GroupBy(x => new { x.OrgCode, x.OrgName });
+
+        // 先获取所有可能的 SpecialReasonId(动态列)
+        var specialReasons = rawData
+            .Select(x => x.SpecialReasonId)
+            .Distinct()
+            .ToList();
+
+        // 3. 遍历 OrgCode 进行聚合转换
+        foreach (var orgGroup in orgGroups)
+        {
+            var row = new Dictionary<string, object>
+            {
+                ["OrgName"] = orgGroup.Key.OrgName,
+                ["OrgCode"] = orgGroup.Key.OrgCode
+            };
+
+            // 初始化 SpecialReasonId 列
+            foreach (var reason in specialReasons)
+            {
+                row[reason] = 0; // 先默认 0
+            }
+
+            // 填充对应的 OrderCountNum
+            foreach (var item in orgGroup)
+            {
+                if (item.SpecialReasonId != null)
+                {
+                    row[item.SpecialReasonId] = item.OrderCountNum;
+                }
+            }
+
+            pivotResult.Add(row);
+        }
+
+        return pivotResult;
+    }
 }

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

@@ -95,4 +95,5 @@ public interface IBiSnapshotApplication
     ISugarQueryable<CompliantStatisticsOutDto> GetCompliantStatistics(CompliantStatisticsInDto dto);
 
     ISugarQueryable<CompliantStatisticsDetailsOutDto> GetCompliantStatisticsDetails(CompliantStatisticsDetailsInDto dto);
+    List<Dictionary<string, object>> GetReTransactStatistics(ReTransactStatisticsInDto dto);
 }

+ 7 - 0
src/Hotline.Application/Snapshot/IOrderSnapshotApplication.cs

@@ -136,4 +136,11 @@ public interface IOrderSnapshotApplication
     /// <returns></returns>
     Task<OrderSnapshot> UpdateSafetyAsync(string orderId, bool isSafetyDepartment, string remark);
     ISugarQueryable<CitizenRewardOutDto> GetCitizenRewardItems(CitizenRewardInDto dto);
+
+    /// <summary>
+    /// 更新随手拍工单重办原因
+    /// </summary>
+    /// <param name="orderId"></param>
+    /// <param name="firstErrorId"></param>
+    Task UpdateSpecialReasonAsync(string orderId, string errorId, string errorName);
 }

+ 23 - 0
src/Hotline.Application/Snapshot/Notifications/SnapshotHandler.cs

@@ -26,6 +26,7 @@ using Hotline.FlowEngine.Workflows;
 using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using Microsoft.Extensions.Logging;
+using Hotline.Orders.Notifications;
 
 namespace Hotline.Application.Snapshot.Notifications;
 
@@ -135,3 +136,25 @@ public class SnapshotPushNotificationHandler : INotificationHandler<PostGuiderSy
         await _snapshotApplication.PostOrderGuiderSystemAsync(notification.OrderId, cancellationToken);
     }
 }
+
+public class AddOrderSpecialHandler : INotificationHandler<AddOrderSpecialNotify>
+{
+    private readonly IOrderSnapshotApplication _orderSnapshotApplication;
+    private readonly ISystemSettingCacheManager _systemSettingCacheManager;
+
+    public AddOrderSpecialHandler(IOrderSnapshotApplication orderSnapshotApplication, ISystemSettingCacheManager systemSettingCacheManager)
+    {
+        _orderSnapshotApplication = orderSnapshotApplication;
+        _systemSettingCacheManager = systemSettingCacheManager;
+    }
+
+    public async Task Handle(AddOrderSpecialNotify notification, CancellationToken cancellationToken)
+    {
+        if (notification.SourceChannel.Contains("随手拍") && _systemSettingCacheManager.Snapshot == true)
+        {
+            var item = notification.Reasons.FirstOrDefault();
+            if (item == null) return;
+            await _orderSnapshotApplication.UpdateSpecialReasonAsync(notification.OrderId, item.ErrorId, item.ErrorName);
+        }
+    }
+}

+ 9 - 0
src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs

@@ -580,4 +580,13 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
         return query;
 
     }
+
+    public async Task UpdateSpecialReasonAsync(string orderId, string errorId, string errorName)
+    {
+        await _orderSnapshotRepository.Updateable()
+            .SetColumns(m => m.SpecialReasonId, errorId)
+            .SetColumns(m => m.SpecialReasonName, errorName)
+            .Where(m => m.Id == orderId)
+            .ExecuteCommandAsync();
+    }
 }

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

@@ -1,4 +1,5 @@
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Settings;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Requests;
@@ -2684,3 +2685,24 @@ public class CompliantStatisticsDetailsOutDto
     public string HotspotName { get; set; }
 
 }
+
+public class ReTransactStatisticsInDto
+{
+    [Required]
+    public DateTime StartTime { get; set; }
+    [Required]
+    public DateTime EndTime { get; set; }
+}
+
+public class ReTransactStatisticsOutDto
+{
+    /// <summary>
+    /// 表头
+    /// </summary>
+    public IList<SystemDicDataOutDto> Headers { get; set; }
+
+    /// <summary>
+    /// 数据
+    /// </summary>
+    public List<Dictionary<string, object>> Data {get; set; }
+}

+ 18 - 0
src/Hotline/Orders/Notifications/OrderSpecialNotify.cs

@@ -0,0 +1,18 @@
+using Hotline.Share.Dtos.Order;
+using MediatR;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Orders.Notifications
+{
+    /// <summary>
+    /// 添加工单重办通知
+    /// </summary>
+    /// <param name="OrderId">工单Id</param>
+    /// <param name="SourceChannel">工单来源</param>
+    /// <param name="Reasons">重办原因</param>
+    public record AddOrderSpecialNotify(string OrderId, string SourceChannel, List<OrderSpecialDetailDto> Reasons) : INotification;
+}

+ 14 - 0
src/Hotline/Snapshot/OrderSnapshot.cs

@@ -366,4 +366,18 @@ public class OrderSnapshot : CreationSoftDeleteEntity
     /// </summary>
     [SugarColumn(ColumnDescription = "网格员系统是否回调", DefaultValue = "f")]
     public bool IsGuidSystemCallBack { get; set; }
+
+    #region 重办信息
+    /// <summary>
+    /// 重办原因Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "重办原因Id")]
+    public string? SpecialReasonId { get; set; }
+
+    /// <summary>
+    /// 重办原因
+    /// </summary>
+    [SugarColumn(ColumnDescription = "重办原因")]
+    public string? SpecialReasonName { get; set; }
+    #endregion
 }

+ 5 - 0
test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs

@@ -4,6 +4,7 @@ using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
 using Hotline.Snapshot.Interfaces;
 using Hotline.Users;
 using Mapster;
@@ -94,5 +95,9 @@ public class BiSnapshotApplicationTest : TestBase
 
         var a = await _biSnapshotApplication.GetSnapshotDepartmentAveTimeStatistics(inDto.Adapt<SnapshotDepartmentAveTimeStatisticsInDto>()).ToListAsync();
         a.ShouldNotBeNull();
+
+        var b = _biSnapshotApplication.GetReTransactStatistics(inDto.Adapt<ReTransactStatisticsInDto>());
+        b.ShouldNotBeNull();
+        var c = b.ToJson();
     }
 }