瀏覽代碼

Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test

田爽 2 月之前
父節點
當前提交
4ef1c72533
共有 43 個文件被更改,包括 1074 次插入92 次删除
  1. 4 1
      src/Hotline.Api/Controllers/ArticleController.cs
  2. 6 6
      src/Hotline.Api/Controllers/Bi/BiOrderController.cs
  3. 3 1
      src/Hotline.Api/Controllers/HomeController.cs
  4. 77 3
      src/Hotline.Api/Controllers/OrderController.cs
  5. 27 0
      src/Hotline.Api/Controllers/Snapshot/BiSnapshotController.cs
  6. 47 25
      src/Hotline.Api/Controllers/Snapshot/RedPackController.cs
  7. 1 0
      src/Hotline.Api/Controllers/UserController.cs
  8. 50 26
      src/Hotline.Api/Realtimes/RealtimeService.cs
  9. 15 2
      src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs
  10. 16 0
      src/Hotline.Application/Snapshot/BiSnapshotApplication.cs
  11. 13 0
      src/Hotline.Application/Snapshot/IBiSnapshotApplication.cs
  12. 30 0
      src/Hotline.Application/Snapshot/IRedPackApplication.cs
  13. 190 3
      src/Hotline.Application/Snapshot/RedPackApplication.cs
  14. 4 4
      src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs
  15. 3 0
      src/Hotline.Application/StatisticalReport/CallReport/YiBinCallReportApplication.cs
  16. 2 2
      src/Hotline.Application/StatisticalReport/OrderReportApplication.cs
  17. 24 0
      src/Hotline.Repository.SqlSugar/Snapshot/SpecialRedPackAuditRepository.cs
  18. 6 3
      src/Hotline.Share/Dtos/Article/BulletinDto.cs
  19. 18 0
      src/Hotline.Share/Dtos/Article/NotificationWaitSendDto.cs
  20. 15 0
      src/Hotline.Share/Dtos/CallCenter/BiQueryCallsDto.cs
  21. 119 0
      src/Hotline.Share/Dtos/Snapshot/OrderDto.cs
  22. 40 0
      src/Hotline.Share/Dtos/Snapshot/StatisticsDto.cs
  23. 1 1
      src/Hotline/Article/Bulletin.cs
  24. 1 1
      src/Hotline/Article/Circular.cs
  25. 7 0
      src/Hotline/Article/CircularRecordDomainService.cs
  26. 21 0
      src/Hotline/Article/NotificationWaitSend.cs
  27. 2 0
      src/Hotline/Caching/Interfaces/IRealtimeCacheManager.cs
  28. 5 0
      src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs
  29. 5 0
      src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs
  30. 5 0
      src/Hotline/Caching/Services/RealtimeCacheManager.cs
  31. 5 0
      src/Hotline/Caching/Services/SysDicDataCacheManager.cs
  32. 5 0
      src/Hotline/Caching/Services/SystemSettingCacheManager.cs
  33. 13 0
      src/Hotline/SeedData/SystemDicDataSeedData.cs
  34. 15 0
      src/Hotline/Settings/SettingConstants.cs
  35. 5 0
      src/Hotline/Settings/SysDicTypeConsts.cs
  36. 12 0
      src/Hotline/Snapshot/Interfaces/ISpecialRedPackAuditRepository.cs
  37. 137 0
      src/Hotline/Snapshot/SpecialRedPackAudit.cs
  38. 18 0
      src/Hotline/Snapshot/SupplementRecord.cs
  39. 2 2
      src/TianQue.Sdk/TiqnQueService.cs
  40. 1 7
      test/Hotline.Tests/Application/KnowApplicationTest.cs
  41. 1 1
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs
  42. 67 1
      test/Hotline.Tests/Application/RedPackApplicationTest.cs
  43. 36 3
      test/Hotline.Tests/Mock/OrderServiceMock.cs

+ 4 - 1
src/Hotline.Api/Controllers/ArticleController.cs

@@ -255,6 +255,7 @@ namespace Hotline.Api.Controllers
             circular.SourceOrgId = dto.SourceOrgId;
             circular.SourceOrgName = dto.SourceOrgName;
             circular.NeedReadNum = dto.CircularReadGroups.Count;
+            circular.LostEfficacyTime = DateTime.Now.AddYears(50);
             await _circularRepository.UpdateAsync(circular, HttpContext.RequestAborted);
             //移除子表重新添加
             await _circularReadGroupRepository.RemoveAsync(x => x.CircularId == dto.Id, false, HttpContext.RequestAborted);
@@ -302,6 +303,7 @@ namespace Hotline.Api.Controllers
             model.CircularState = ECircularState.Draft;
             model.ReadedNum = 0;
             model.NeedReadNum = model.CircularReadGroups.Count;
+            model.LostEfficacyTime = DateTime.Now.AddYears(50);
             var id = await _circularRepository.AddAsync(model, HttpContext.RequestAborted);
             //子表
             var list = dto.CircularReadGroups;
@@ -542,7 +544,7 @@ namespace Hotline.Api.Controllers
             bulletin.Content = dto.Content;
             bulletin.BulletinTypeId = dto.BulletinTypeId;
             bulletin.BulletinTypeName = dto.BulletinTypeName;
-            bulletin.LoseEfficacyTime = dto.LoseEfficacyTime;
+            bulletin.LoseEfficacyTime = DateTime.Now.AddYears(50);
             bulletin.PushRanges = dto.PushRanges;
             bulletin.DisplayLocation = dto.DisplayLocation;
             bulletin.SourceOrgId = dto.SourceOrgId;
@@ -581,6 +583,7 @@ namespace Hotline.Api.Controllers
             model.BulletinState = Share.Enums.Article.EBulletinState.Draft;
             model.ReadedNum = 0;
             model.IsArrive = false;
+            model.LoseEfficacyTime = DateTime.Now.AddYears(50);
             await _bulletinRepository.AddAsync(model, HttpContext.RequestAborted);
         }
 

+ 6 - 6
src/Hotline.Api/Controllers/Bi/BiOrderController.cs

@@ -6005,20 +6005,20 @@ namespace Hotline.Api.Controllers.Bi
             //中国政府网“我向总理说句话”
             var ZGZFW = new OnlineMassLineReportRes();
             ZGZFW.SourceChannel = "中国政府网“我向总理说句话”";
-            ZGZFW.SumCount = nowList.Where(x => x.IsProvince == true && x.No.StartsWith("ZGZFW")).Count(); //中国政府网“我向总理说句话”
-            ZGZFW.PreviousCount = oldList.Where(x => x.IsProvince == true && x.No.StartsWith("ZGZFW")).Count(); //中国政府网“我向总理说句话”
+            ZGZFW.SumCount = nowList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("ZGZFW")).Count(); //中国政府网“我向总理说句话”
+            ZGZFW.PreviousCount = oldList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("ZGZFW")).Count(); //中国政府网“我向总理说句话”
             returnList.Add(ZGZFW);
             //国家政务服务平台“投诉与建议”
             var GJZWFWPT = new OnlineMassLineReportRes();
             GJZWFWPT.SourceChannel = "国家政务服务平台“投诉与建议”";
-            GJZWFWPT.SumCount = nowList.Where(x => x.IsProvince == true && x.No.StartsWith("GJZWFWPT")).Count(); //国家政务服务平台“投诉与建议”
-            GJZWFWPT.PreviousCount = oldList.Where(x => x.IsProvince == true && x.No.StartsWith("GJZWFWPT")).Count(); //国家政务服务平台“投诉与建议”
+            GJZWFWPT.SumCount = nowList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("GJZWFWPT")).Count(); //国家政务服务平台“投诉与建议”
+            GJZWFWPT.PreviousCount = oldList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("GJZWFWPT")).Count(); //国家政务服务平台“投诉与建议”
             returnList.Add(GJZWFWPT);
             //省12345政务服务便民热线
             var Province12345 = new OnlineMassLineReportRes();
             Province12345.SourceChannel = "省12345政务服务便民热线";
-            Province12345.SumCount = nowList.Where(x => x.IsProvince == true && x.No.StartsWith("GJZWFWPT")==false && x.No.StartsWith("ZGZFW")==false).Count(); //国家政务服务平台“投诉与建议”
-            Province12345.PreviousCount = oldList.Where(x => x.IsProvince == true && x.No.StartsWith("GJZWFWPT")==false && x.No.StartsWith("ZGZFW")==false).Count(); //国家政务服务平台“投诉与建议”
+            Province12345.SumCount = nowList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("GJZWFWPT")==false && x.ReceiveProvinceNo.StartsWith("ZGZFW")==false).Count(); //国家政务服务平台“投诉与建议”
+            Province12345.PreviousCount = oldList.Where(x => x.IsProvince == true && x.ReceiveProvinceNo.StartsWith("GJZWFWPT")==false && x.ReceiveProvinceNo.StartsWith("ZGZFW")==false).Count(); //国家政务服务平台“投诉与建议”
             returnList.Add(Province12345);
             //市政府网站“市长与网民”
             var SZYSM = new OnlineMassLineReportRes();

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

@@ -193,7 +193,9 @@ public class HomeController : BaseController
             NationalPlatformWordLimit = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NationalPlatformWordLimit).SettingValue[0]),
             HandleOpinionWordLimit= int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.HandleOpinionWordLimit).SettingValue[0]),
             CallInOpenType = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOpenType).SettingValue[0]),
-            Snapshot = _systemSettingCacheManager.Snapshot
+            Snapshot = _systemSettingCacheManager.Snapshot,
+            IsTelRest = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsTelRest).SettingValue[0]),
+            TelRestNum = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TelRestNum).SettingValue[0])
         };
         return rsp;
     }

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

@@ -77,6 +77,10 @@ using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
 using OrderDto = Hotline.Share.Dtos.Order.OrderDto;
 using System.Threading;
+using Hotline.Realtimes;
+using Hotline.Article;
+using Hotline.Share.Dtos.Article;
+using Hotline.Api.Realtimes;
 
 namespace Hotline.Api.Controllers;
 
@@ -158,6 +162,8 @@ public class OrderController : BaseController
     private readonly IRepository<SystemDicData> _sysDicDataRepository;
     private readonly IRepository<SystemOrganize> _systemOrganizeRepository;
     private readonly IRepository<OrderComplement> _orderComplementRepository;
+    private readonly IRealtimeService _realtimeService;
+    private readonly IRepository<NotificationWaitSend> _notificationWaitSendRepository;
 
     public OrderController(
         IOrderDomainService orderDomainService,
@@ -231,7 +237,9 @@ public class OrderController : BaseController
         IOrderSnapshotApplication orderSnapshotApplication,
         IRepository<SystemDicData> sysDicDataRepository,
         IRepository<SystemOrganize> systemOrganizeRepository,
-        IRepository<OrderComplement> orderComplementRepository)
+        IRepository<OrderComplement> orderComplementRepository,
+        IRealtimeService realtimeService,
+        IRepository<NotificationWaitSend> notificationWaitSendRepository)
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -305,6 +313,8 @@ public class OrderController : BaseController
         _sysDicDataRepository = sysDicDataRepository;
         _systemOrganizeRepository = systemOrganizeRepository;
         _orderComplementRepository = orderComplementRepository;
+        _realtimeService = realtimeService;
+        _notificationWaitSendRepository = notificationWaitSendRepository;
     }
 
     #endregion
@@ -8951,7 +8961,7 @@ public class OrderController : BaseController
 
     #region 添加补充
     /// <summary>
-    /// 添加补充
+    /// 添加补充 _notificationWaitSendRepository
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
@@ -8978,7 +8988,71 @@ public class OrderController : BaseController
             IsProComplement = false
         };
 
-        await _orderComplementRepository.AddAsync(complement, HttpContext.RequestAborted);
+        var id = await _orderComplementRepository.AddAsync(complement, HttpContext.RequestAborted);
+        if (!string.IsNullOrEmpty(id))
+        {
+            //获取当前办理节点数据
+            var work = await _workflowStepRepository.GetAsync(p => p.Id == data.ActualHandleStepId, HttpContext.RequestAborted);
+            if (work != null)
+            {
+                //获取办理指定类型
+                var workflowStepHandler = work.GetWorkflowStepHandler();
+                if (workflowStepHandler != null)
+                {
+                    List<string> users = [];
+                    if (!string.IsNullOrEmpty(workflowStepHandler.UserId)) //指定用户
+                    {
+                        users.Add(workflowStepHandler.UserId);
+                    }
+                    else if (!string.IsNullOrEmpty(workflowStepHandler.RoleId))//指定角色
+                    {
+                        //查询指定角色下面所有的用户
+                        var userlist = await _userRepository.Queryable().Where(x =>
+                            x.OrgId == workflowStepHandler.OrgId && x.Roles.Any(d => workflowStepHandler.RoleId.Contains(d.Id))).Select(p => p.Id).ToListAsync();
+                        if (userlist != null && userlist.Count > 0)
+                            users.AddRange(userlist);
+                    }
+                    else if (!string.IsNullOrEmpty(workflowStepHandler.OrgId))//指定部门
+                    {
+                        //添加成功以后查询需要发送的人员信息
+                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+
+                        //查询指定部门下面经办人的信息
+                        var userlist = await _userRepository.Queryable().Where(x =>
+                            x.OrgId == workflowStepHandler.OrgId && x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).Select(p => p.Id).ToListAsync();
+                        if (userlist != null && userlist.Count > 0)
+                            users.AddRange(userlist);
+                    }
+                    if (users != null && users.Count > 0)
+                    {
+                        var msg = @"工单" + data.No + "有补充内容,请注意查收!";
+                        foreach (var item in users)
+                        {
+                            //发送消息
+                            await _realtimeService.OrderComplementAsync(item, msg, HttpContext.RequestAborted);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    /// <summary>
+    /// 根据userid查询补充消息
+    /// </summary>
+    /// <param name="userId"></param>
+    /// <returns></returns>
+    [HttpGet("get_notification_wait_send/{userId}")]
+    public async Task<List<NotificationWaitSendDto>> GetNotificationWaitSend(string userId)
+    {
+        var data = await _notificationWaitSendRepository.Queryable()
+                .Where(p => p.UserId == userId && p.Method == RealtimeMethods.OrderComplementRecord&&p.State=="0")
+                .ToListAsync();
+        if (data != null && data.Count > 0)
+        {
+            await _notificationWaitSendRepository.RemoveRangeAsync(data, HttpContext.RequestAborted);
+        }
+        return _mapper.Map<List<NotificationWaitSendDto>>(data);
     }
     #endregion
 }

+ 27 - 0
src/Hotline.Api/Controllers/Snapshot/BiSnapshotController.cs

@@ -0,0 +1,27 @@
+using Hotline.Application.Snapshot;
+using Hotline.Share.Dtos.Snapshot;
+using Microsoft.AspNetCore.Mvc;
+
+namespace Hotline.Api.Controllers.Snapshot;
+
+/// <summary>
+/// 随手拍统计
+/// </summary>
+public class BiSnapshotController : BaseController
+{
+    private readonly IBiSnapshotApplication _biSnapshotApplication;
+
+    public BiSnapshotController(IBiSnapshotApplication biSnapshotApplication)
+    {
+        _biSnapshotApplication = biSnapshotApplication;
+    }
+
+    /// <summary>
+    /// 随手拍统计
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("statistics")]
+    public async Task<SnapshotStatisticsOutDto> GetSnapshotStatisticsAsync([FromBody] SnapshotStatisticsInDto dto)
+        =>  await _biSnapshotApplication.GetSnapshotStatisticsAsync(dto, HttpContext.RequestAborted);
+
+}

+ 47 - 25
src/Hotline.Api/Controllers/Snapshot/RedPackController.cs

@@ -9,6 +9,9 @@ using Hotline.Caching.Interfaces;
 using XF.Utility.EnumExtensions;
 using Hotline.Share.Enums.Snapshot;
 using Quartz.Impl.Triggers;
+using Hotline.Orders;
+using XF.Domain.Exceptions;
+using Mapster;
 
 namespace Hotline.Api.Controllers.Snapshot;
 
@@ -19,16 +22,48 @@ public class RedPackController : BaseController
     private readonly ISystemDicDataCacheManager _sysDic;
     private readonly ISnapshotSMSTemplateRepository _snapshotSMSTemplateRepository;
     private readonly IOrderSnapshotRepository _orderSnapshotRepository;
+    private readonly IOrderRepository _orderRepository;
 
-    public RedPackController(IRedPackApplication redPackApplication, IIndustryRepository industryRepository, ISystemDicDataCacheManager sysDic, ISnapshotSMSTemplateRepository snapshotSMSTemplateRepository, IOrderSnapshotRepository orderSnapshotRepository)
+    public RedPackController(IRedPackApplication redPackApplication, IIndustryRepository industryRepository, ISystemDicDataCacheManager sysDic, ISnapshotSMSTemplateRepository snapshotSMSTemplateRepository, IOrderSnapshotRepository orderSnapshotRepository, IOrderRepository orderRepository)
     {
         _redPackApplication = redPackApplication;
         _industryRepository = industryRepository;
         _sysDic = sysDic;
         _snapshotSMSTemplateRepository = snapshotSMSTemplateRepository;
         _orderSnapshotRepository = orderSnapshotRepository;
+        _orderRepository = orderRepository;
     }
 
+    #region 特殊红包
+    /// <summary>
+    /// 特殊红包审批集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("special")]
+    public async Task<PagedDto<SnapshotOrderAuditItemsOutDto>> GetRedPackSpecialItems([FromQuery] SnapshotOrderAuditItemsInDto dto)
+        => (await _redPackApplication.GetRedPackSpecialAuditItems(dto).ToPagedListAsync(dto)).ToPaged();
+
+    /// <summary>
+    /// 特殊红包审核通过或拒绝
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("audit/special")]
+    public async Task UpdateRedPackSpecialAuditAsync([FromBody] UpdateRedPackSpecialAuditInDto dto)
+        => await _redPackApplication.AuditRedPackSpecialAuditAsync(dto);
+
+    /// <summary>
+    /// 特殊红包审核详情信息(OrderId)
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("audit/special/{id}")]
+    public async Task<SnapshotOrderAuditSpecialDetailOutDto> GetRedPackSpecialAuditBaseDataAsync(string id)
+    {
+        return await _redPackApplication.GetRedPackSpecialAuditBaseDataAsync(id);
+    }
+    #endregion
+
     #region 红包审核
     /// <summary>
     /// 获取市民红包审批列表
@@ -110,31 +145,9 @@ public class RedPackController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpGet("record/basedata/{id}")]
-    public async Task<Dictionary<string, object>> UpdateRedPackRecordBaseDataAsync(string id)
+    public async Task<GetRedPackRecordBaseDataOutDto> UpdateRedPackRecordBaseDataAsync(string id)
     {
-        var snapshot = await _orderSnapshotRepository.Queryable()
-            .Where(m => m.Id == id)
-            .Select(m => new
-            {
-                m.Id,
-                m.AwardBankCardNo,
-                m.AwardOpenBank,
-                m.AwardName,
-                m.AwardAmount
-            })
-            .FirstAsync();
-        var dic = new Dictionary<string, object>()
-        {
-            { "replenishType", _sysDic.SnapshotReplenishType }
-        };
-        if (snapshot != null)
-        {
-            dic.Add("bankCardNo", snapshot.AwardBankCardNo);
-            dic.Add("openBank", snapshot.AwardOpenBank);
-            dic.Add("name", snapshot.AwardName);
-            dic.Add("amount", snapshot.AwardAmount);
-        }
-        return dic;
+        return await _redPackApplication.GetRedPackRecordBaseDataAsync(id); ;
     }
 
     /// <summary>
@@ -146,6 +159,15 @@ public class RedPackController : BaseController
     public async Task UpdateRedPackRecordAsync([FromBody] UpdateRedPackRecordInDto dto)
         => await _redPackApplication.UpdateRedPackRecordAsync(dto);
 
+    /// <summary>
+    /// 添加补充发放信息(特殊红包)
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpPut("record/special")]
+    public async Task UpdateRedPackSpecialRecordAsync([FromBody] UpdateRedPackRecordInDto dto)
+        => await _redPackApplication.UpdateRedPackSpecialRecordAsync(dto);
+
     /// <summary>
     /// 补充发放集合基础信息
     /// </summary>

+ 1 - 0
src/Hotline.Api/Controllers/UserController.cs

@@ -161,6 +161,7 @@ public class UserController : BaseController
     public async Task<PagedDto<UserDto>> QueryPaged([FromQuery] UserPagedDto dto)
     {
         var query =  _userApplication.QueryPaged(dto);
+        Console.WriteLine(query.ToSqlString());
         var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted);
 
         //var (total, items) = await _userRepository.Queryable(includeDeleted: true)

+ 50 - 26
src/Hotline.Api/Realtimes/RealtimeService.cs

@@ -1,4 +1,5 @@
-using Hotline.Article;
+using DocumentFormat.OpenXml.Spreadsheet;
+using Hotline.Article;
 using Hotline.Caching.Interfaces;
 using Hotline.Caching.Services;
 using Hotline.Realtimes;
@@ -18,17 +19,20 @@ public class RealtimeService : IRealtimeService, IScopeDependency
     private readonly IRealtimeCacheManager _realtimeCacheManager;
     private readonly IRepository<CircularRecord> _circularRecordRepository;
     private readonly IRepository<User> _userRepository;
+    private readonly IRepository<NotificationWaitSend> _notificationWaitSendRepository;
 
     public RealtimeService(
         IHubContext<HotlineHub> hubContext,
         IRealtimeCacheManager realtimeCacheManager,
         IRepository<CircularRecord> circularRecordRepository,
-        IRepository<User> userRepository)
+        IRepository<User> userRepository,
+        IRepository<NotificationWaitSend> notificationWaitSendRepository)
     {
         _hubContext = hubContext;
         _realtimeCacheManager = realtimeCacheManager;
         _circularRecordRepository = circularRecordRepository;
         _userRepository = userRepository;
+        _notificationWaitSendRepository = notificationWaitSendRepository;
     }
 
     #region 通讯通知
@@ -123,14 +127,34 @@ public class RealtimeService : IRealtimeService, IScopeDependency
     #endregion
 
     /// <summary>
-    /// 工单补充消息通知
+    /// 工单补充消息通知 
     /// </summary>
     /// <param name="userId"></param>
     /// <param name="msg"></param>
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
-    public Task OrderComplementAsync(string userId, string msg, CancellationToken cancellationToken) =>
-        SendToUserAsync(userId, RealtimeMethods.OrderComplementRecord, msg, cancellationToken);
+    public async Task OrderComplementAsync(string userId, string msg, CancellationToken cancellationToken)
+    {
+        var connection = await _realtimeCacheManager.GetConnectionOtherAsync(userId, cancellationToken);
+        if (connection == null)
+        {
+            //如果没有建立链接,写入数据库
+            NotificationWaitSend notificationWait = new NotificationWaitSend()
+            {
+                UserId = userId,
+                Msg = msg,
+                Method = RealtimeMethods.OrderComplementRecord,
+                State = "0"
+            };
+            await _notificationWaitSendRepository.AddAsync(notificationWait, cancellationToken);
+        }
+        else
+        {
+            //如果建立了链接直接发消息
+            await _hubContext.Clients.Client(connection.ConnectionId).SendAsync(RealtimeMethods.OrderComplementRecord, msg, cancellationToken);
+        }
+    }
+
 
     #region 系统信息通知
 
@@ -162,7 +186,7 @@ public class RealtimeService : IRealtimeService, IScopeDependency
                 {
                     await SendToUserAsync(user.Id, RealtimeMethods.CircularRecord,
                         new CircularRecoordDto()
-                            { CircularType = Share.Enums.Article.ECircularType.Org, Count = record.RecordCount },
+                        { CircularType = Share.Enums.Article.ECircularType.Org, Count = record.RecordCount },
                         cancellationToken);
                 }
                 catch
@@ -176,37 +200,37 @@ public class RealtimeService : IRealtimeService, IScopeDependency
 
     #region 大屏.数据展示
 
-    public Task BsDataShowChanged1Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged1Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea1, obj, cancellationToken);
-    public Task BsDataShowChanged2Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged2Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea2, obj, cancellationToken);
-    public Task BsDataShowChanged3Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged3Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea3, obj, cancellationToken);
-    public Task BsDataShowChanged4Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged4Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea4, obj, cancellationToken);
-    public Task BsDataShowChanged5Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged5Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea5, obj, cancellationToken);
-    public Task BsDataShowChanged6Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged6Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea6, obj, cancellationToken);
-    public Task BsDataShowChanged7Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged7Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea7, obj, cancellationToken);
-    public Task BsDataShowChanged8Async(object obj, CancellationToken cancellationToken) => 
+    public Task BsDataShowChanged8Async(object obj, CancellationToken cancellationToken) =>
         SendToGroupAsync(RealtimeGroupNames.BigScreenDataShow, RealtimeMethods.BsDataShowArea8, obj, cancellationToken);
 
-	#endregion
+    #endregion
 
-	#region 大屏坐席数据
-	public Task BsSeatStateDataShowChangedAsync1(object obj, CancellationToken cancellationToken) =>
-		SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea1, obj, cancellationToken);
+    #region 大屏坐席数据
+    public Task BsSeatStateDataShowChangedAsync1(object obj, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea1, obj, cancellationToken);
 
-	public Task BsSeatStateDataShowChangedAsync2(object obj, CancellationToken cancellationToken) =>
-		SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea2, obj, cancellationToken);
+    public Task BsSeatStateDataShowChangedAsync2(object obj, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea2, obj, cancellationToken);
 
-	public Task BsSeatStateDataShowChangedAsync3(object obj, CancellationToken cancellationToken) =>
-		SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea3, obj, cancellationToken);
+    public Task BsSeatStateDataShowChangedAsync3(object obj, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea3, obj, cancellationToken);
 
-	public Task BsSeatStateDataShowChangedAsync4(object obj, CancellationToken cancellationToken) =>
-		SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea4, obj, cancellationToken);
+    public Task BsSeatStateDataShowChangedAsync4(object obj, CancellationToken cancellationToken) =>
+        SendToGroupAsync(RealtimeGroupNames.BigScreenSeatState, RealtimeMethods.BsSeatStateDataShowArea4, obj, cancellationToken);
     #endregion
 
     #region 数据大屏
@@ -227,7 +251,7 @@ public class RealtimeService : IRealtimeService, IScopeDependency
     /// <param name="cancellationToken"></param>
     /// <returns></returns>
     public Task OrderHandlingDetailAsync(object obj, CancellationToken cancellationToken) =>
-        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderHandlingDetail,obj, cancellationToken);
+        SendToGroupAsync(RealtimeGroupNames.BigDataScreen, RealtimeMethods.OrderHandlingDetail, obj, cancellationToken);
 
     /// <summary>
     /// 推送二次办理中工单概览
@@ -292,6 +316,6 @@ public class RealtimeService : IRealtimeService, IScopeDependency
 
     #endregion
 
-   
+
 
 }

+ 15 - 2
src/Hotline.Application/Jobs/XingTangCallsSyncJob.cs

@@ -130,7 +130,8 @@ namespace Hotline.Application.Jobs
                     if (calls.Any())
                     {
                         //推省上
-                        await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
+                        //await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
+                        await PublishMessageAsync(calls);
                     }
                     _logger.LogInformation($"旧方法同步通话记录成功,数量:{calls.Count}");
                 }
@@ -176,7 +177,8 @@ namespace Hotline.Application.Jobs
                     if (calls.Any())
                     {
                         //推省上
-                        await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
+                        await PublishMessageAsync(calls);
+                        // await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
                     }
                     _logger.LogInformation($"新方法同步通话记录成功,数量:{calls.Count}");
                 }
@@ -195,6 +197,17 @@ namespace Hotline.Application.Jobs
             }
         }
 
+        private async Task PublishMessageAsync(List<CallNative> calls)
+        {
+            if (_systemSettingCacheManager.IsNoPushCallNativeOutNoFile)
+            {
+                var removeCalls = calls.Where(m => m.Direction == ECallDirection.Out && m.AudioFile.IsNullOrEmpty()).ToList();
+                calls = calls.Except(removeCalls).ToList();
+            }
+            //推省上
+            await _capPublisher.PublishAsync(EventNames.HotlineCallAdd, calls.Adapt<List<CallNativeDto>>());
+        }
+
         private async Task<string> GetCallIdAsync(string callNo, CancellationToken cancellation)
         {
             if (string.IsNullOrEmpty(callNo)) return string.Empty;

+ 16 - 0
src/Hotline.Application/Snapshot/BiSnapshotApplication.cs

@@ -0,0 +1,16 @@
+using Hotline.Share.Dtos.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Application.Snapshot;
+public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
+{
+    public Task<SnapshotStatisticsOutDto> GetSnapshotStatisticsAsync(SnapshotStatisticsInDto dto, CancellationToken token)
+    {
+        throw new NotImplementedException();
+    }
+}

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

@@ -0,0 +1,13 @@
+using Hotline.Share.Dtos.Snapshot;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Snapshot;
+public interface IBiSnapshotApplication
+{
+    Task<SnapshotStatisticsOutDto> GetSnapshotStatisticsAsync(SnapshotStatisticsInDto dto, CancellationToken token);
+}

+ 30 - 0
src/Hotline.Application/Snapshot/IRedPackApplication.cs

@@ -23,6 +23,7 @@ public interface IRedPackApplication
     /// <param name="dto"></param>
     /// <returns></returns>
     Task AuditRedPackGuiderAuditAsync(UpdateRedPackGuiderAuditInDto dto);
+    Task AuditRedPackSpecialAuditAsync(UpdateRedPackSpecialAuditInDto dto);
 
     /// <summary>
     /// 获取特提参数
@@ -65,6 +66,14 @@ public interface IRedPackApplication
     /// <returns></returns>
     ISugarQueryable<SnapshotOrderGuiderAuditItemsOutDto> GetRedPackGuiderAuditItems(SnapshotOrderGuiderAuditItemsInDto dto);
 
+    /// <summary>
+    /// 获取补充发放记录基础数据
+    /// </summary>
+    /// <param name="v"></param>
+    /// <param name="orderId"></param>
+    /// <returns></returns>
+    Task<GetRedPackRecordBaseDataOutDto> GetRedPackRecordBaseDataAsync(string orderId);
+
     /// <summary>
     /// 红包发放明细
     /// </summary>
@@ -86,6 +95,20 @@ public interface IRedPackApplication
     ISugarQueryable<SnapshotRedPackRecordItemsOutDto> GetRedPackRecordItems(SnapshotRedPackRecordItemsInDto dto);
     ISugarQueryable<SnapshotRedPackRecordSupplementItemsOutDto> GetRedPackRecordSupplementItems(SnapshotRedPackRecordSupplementItemsInDto dto);
 
+    /// <summary>
+    /// 特殊红包审核详情信息
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    Task<SnapshotOrderAuditSpecialDetailOutDto> GetRedPackSpecialAuditBaseDataAsync(string id);
+
+    /// <summary>
+    /// 特殊红包审批集合
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<SnapshotOrderAuditItemsOutDto> GetRedPackSpecialAuditItems(SnapshotOrderAuditItemsInDto dto);
+
     /// <summary>
     /// 审核添加备注
     /// </summary>
@@ -99,4 +122,11 @@ public interface IRedPackApplication
     /// <param name="dto"></param>
     /// <returns></returns>
     Task UpdateRedPackRecordAsync(UpdateRedPackRecordInDto dto);
+
+    /// <summary>
+    /// 添加补充发放信息(特殊红包)
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    Task UpdateRedPackSpecialRecordAsync(UpdateRedPackRecordInDto dto);
 }

+ 190 - 3
src/Hotline.Application/Snapshot/RedPackApplication.cs

@@ -1,4 +1,6 @@
-using Hotline.Orders;
+using DocumentFormat.OpenXml.Office2010.Excel;
+using Hotline.Caching.Interfaces;
+using Hotline.Orders;
 using Hotline.Push.FWMessage;
 using Hotline.Share.Attributes;
 using Hotline.Share.Dtos;
@@ -21,6 +23,7 @@ using XF.Domain.Dependency;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
+using static NPOI.SS.Format.CellNumberFormatter;
 
 namespace Hotline.Application.Snapshot;
 public class RedPackApplication : IRedPackApplication, IScopeDependency
@@ -29,6 +32,11 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     private readonly IOrderRepository _orderRepository;
     private readonly ISnapshotSMSTemplateRepository _snapshotSMSTemplateRepository;
     private readonly IIndustryRepository _industryRepository;
+    private readonly ISpecialRedPackAuditRepository _specialRedPackAuditRepository;
+
+    /// <summary>
+    /// 市民红包审核仓储
+    /// </summary>
     private readonly IRedPackAuditRepository _redPackAuditRepository;
     private readonly IRedPackRecordRepository _redPackRecordRepository;
     private readonly IRepository<OrderSpecial> _orderSpecialRepository;
@@ -38,8 +46,9 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
     private readonly ISupplementRecordRepository _supplementRecordRepository;
     private readonly IPushDomainService _pushDomainService;
     private readonly ILogger<RedPackApplication> _logger;
+    private readonly ISystemDicDataCacheManager _systemDic;
 
-    public RedPackApplication(IOrderSnapshotRepository orderSnapshotRepository, ISnapshotSMSTemplateRepository snapshotSMSTemplateRepository, IOrderRepository orderRepository, IIndustryRepository industryRepository, IRedPackAuditRepository redPackAuditRepository, IRedPackRecordRepository redPackRecordRepository, IRepository<OrderSpecial> orderSpecialRepository, ISessionContext sessionContext, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IThirdAccountRepository thirdAccountRepository, ISupplementRecordRepository supplementRecordRepository, IPushDomainService pushDomainService, ILogger<RedPackApplication> logger)
+    public RedPackApplication(IOrderSnapshotRepository orderSnapshotRepository, ISnapshotSMSTemplateRepository snapshotSMSTemplateRepository, IOrderRepository orderRepository, IIndustryRepository industryRepository, IRedPackAuditRepository redPackAuditRepository, IRedPackRecordRepository redPackRecordRepository, IRepository<OrderSpecial> orderSpecialRepository, ISessionContext sessionContext, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IThirdAccountRepository thirdAccountRepository, ISupplementRecordRepository supplementRecordRepository, IPushDomainService pushDomainService, ILogger<RedPackApplication> logger, ISpecialRedPackAuditRepository specialRedPackAuditRepository, ISystemDicDataCacheManager systemDic)
     {
         _orderSnapshotRepository = orderSnapshotRepository;
         _snapshotSMSTemplateRepository = snapshotSMSTemplateRepository;
@@ -54,6 +63,8 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         _supplementRecordRepository = supplementRecordRepository;
         _pushDomainService = pushDomainService;
         _logger = logger;
+        _specialRedPackAuditRepository = specialRedPackAuditRepository;
+        _systemDic = systemDic;
     }
 
     /// <summary>
@@ -70,8 +81,13 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         if (redPackAudit.Status != ERedPackAuditStatus.Pending) throw UserFriendlyException.SameMessage("已审核, 不可重复审核");
         redPackAudit.SMSTemplateId = dto.SMSTemplateId;
         redPackAudit.Status = status;
-        redPackAudit.Remark = dto.Opinion;
+        redPackAudit.AuditRemark = dto.Opinion;
         redPackAudit.IsSendSMS = dto.IsSendSms;
+        redPackAudit.AuditId = _sessionContext.UserId;
+        redPackAudit.AuditName = _sessionContext.UserName;
+        redPackAudit.AuditTime = DateTime.Now;
+        redPackAudit.AuditOrgId = _sessionContext.OrgId;
+        redPackAudit.AuditOrgName = _sessionContext.OrgName;
         var order = await _orderRepository.Queryable()
             .Where(m => m.Id == redPackAudit.OrderId)
             .Select(m => new { m.Id, m.No, m.FromName, m.FromPhone })
@@ -232,6 +248,67 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         return outDto;
     }
 
+    /// <summary>
+    /// 特殊红包审批列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [ExportExcel("特殊红包审批")]
+    public ISugarQueryable<SnapshotOrderAuditItemsOutDto> GetRedPackSpecialAuditItems(SnapshotOrderAuditItemsInDto dto)
+    {
+        var beginTime = new DateTime(2024, 8, 1);
+        var endTime = new DateTime(2024, 9, 30, 23, 59, 59);
+        var query = _redPackAuditRepository.Queryable()
+            .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) => (snapshot.IndustryName == "安全隐患" && order.OrderTagCode!.Contains("DHZY")) || (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)
+            .OrderByDescending((redPackAudit, snapshot, order, special) => redPackAudit.CreationTime)
+                        .Select((redPackAudit, snapshot,order) => new SnapshotOrderAuditItemsOutDto
+                        {
+                            Id = redPackAudit.Id,
+                            RedPackAuditId = redPackAudit.Id,
+                            OrderId = order.Id,
+                            No = order.No,
+                            Title = order.Title,
+                            IndustryName = snapshot.IndustryName,
+                            IndustryId = snapshot.IndustryId,
+                            SourceChannel = order.SourceChannel,
+                            SourceChannelCode = order.SourceChannelCode,
+                            Status = order.Status,
+                            IsDanger = snapshot.IsDanger,
+                            FromPhone = order.FromPhone,
+                            FromName = order.FromName,
+                            AuditTime = redPackAudit.AuditTime,
+                            ApprovedAmount = redPackAudit.ApprovedAmount,
+                            AcutalAmount = redPackAudit.AcutalAmount,
+                            IsIssued = redPackAudit.IsIssued,
+                            //RecordRemark = record.Remark,
+                            County = order.County,
+                            // IsRectify = s.IsRepetition
+                            IsDeal = snapshot.IsDeal,
+                            NetworkENumber = snapshot.NetworkENumber,
+                            IsTruth = snapshot.IsTruth,
+                            IsTruthDepartment = snapshot.IsTruthDepartment,
+                            IsRepetition = snapshot.IsRepetition,
+                            CreationTime = order.CreationTime,
+                            OrgLevelOneCode = order.OrgLevelOneCode,
+                            OrgLevelOneName = order.OrgLevelOneName,
+                            AuditId = redPackAudit.AuditId,
+                            AuditName = redPackAudit.AuditName,
+                            AuditOrgId = redPackAudit.AuditOrgId,
+                            AuditOrgName = redPackAudit.AuditOrgName,
+                            AuditRemark = redPackAudit.AuditRemark,
+                            //BankCardNo = record.BankCardNo,
+                            //OpenBank = record.OpenBank,
+                            AuditStatus = redPackAudit.Status,
+                        });
+        return query;
+    }
+
     /// <summary>
     /// 红包审核集合
     /// </summary>
@@ -438,10 +515,50 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         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("审核记录不存在");
 
         dto.Adapt(audit);
         await _redPackAuditRepository.UpdateAsync(audit);
+        await _redPackRecordRepository.UpdateAsync(record);
+
+        var entity = dto.Adapt<SupplementRecord>();
+        var industryName = await _orderSnapshotRepository.Queryable()
+            .Where(m => m.Id == record.OrderId)
+            .Select(m => new { m.IndustryName, m.IndustryId })
+            .FirstAsync();
+        entity.OrderId = record.OrderId;
+        entity.RedPackRecordId = record.Id;
+        entity.RedPackAuditId = audit.Id;
+        entity.No = record.No;
+        entity.IndustryName = industryName.IndustryName;
+        entity.IndustryId = industryName.IndustryId;
+        await _supplementRecordRepository.AddAsync(entity);
+
+        if (dto.IsSendSMS)
+        {
+            // TODO: 发送短信
+        }
+    }
+
+    /// <summary>
+    /// 添加补充发放信息(特殊红包)
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <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 audit = await _specialRedPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+
+        dto.Adapt(audit);
+        await _specialRedPackAuditRepository.UpdateAsync(audit);
+        await _redPackRecordRepository.UpdateAsync(record);
 
         var entity = dto.Adapt<SupplementRecord>();
         var industryName = await _orderSnapshotRepository.Queryable()
@@ -462,6 +579,7 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         }
     }
 
+
     #region 红包发放记录
 
     /// <summary>
@@ -577,6 +695,75 @@ public class RedPackApplication : IRedPackApplication, IScopeDependency
         return query;
     }
 
+    public async Task AuditRedPackSpecialAuditAsync(UpdateRedPackSpecialAuditInDto dto)
+    {
+        var audit = await _redPackAuditRepository.GetAsync(dto.RedPackAuditId) ?? throw UserFriendlyException.SameMessage("审核记录不存在");
+        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)
+            {
+                specialAudit.AuditType = specialType.DicDataName;
+                specialAudit.AuditTypeCode = specialType.DicDataValue;
+            }
+        }
+        specialAudit.Status = dto.Status;
+        specialAudit.ApprovedAmount = dto.ApprovedAmount;
+        specialAudit.AuditId = _sessionContext.UserId;
+        specialAudit.AuditName = _sessionContext.UserName;
+        specialAudit.AuditOrgId = _sessionContext.OrgId;
+        specialAudit.AuditOrgName = _sessionContext.OrgName;
+        await _specialRedPackAuditRepository.AddAsync(specialAudit);
+    }
+
+    public async Task<SnapshotOrderAuditSpecialDetailOutDto> GetRedPackSpecialAuditBaseDataAsync(string id)
+    {
+        var outDto = new SnapshotOrderAuditSpecialDetailOutDto();
+        var order = await _orderRepository.GetAsync(id) ?? throw new UserFriendlyException("工单不存在");
+        outDto.Order = order.Adapt<SnapshotOrderAuditOrderDetailOutDto>();
+        outDto.AuditType = _systemDic.SnapshotRedPackSpecialType;
+        outDto.AuditComBox = EnumExts.GetDescriptions<ERedPackAuditStatus>().Where(m => m.Key != 0).ToList();
+        var audit = await _redPackAuditRepository.GetAsync(m => m.OrderId == id);
+        outDto.AuditDetail = audit.Adapt<SnapshotOrderAuditSpecialAuditDetailOutDto>();
+        return outDto;
+    }
+
+    public async Task<GetRedPackRecordBaseDataOutDto> GetRedPackRecordBaseDataAsync(string orderId)
+    {
+        var snapshot = await _orderSnapshotRepository.Queryable()
+            .Where(m => m.Id == orderId)
+            .Select(m => new
+            {
+                m.Id,
+                m.AwardBankCardNo,
+                m.AwardOpenBank,
+                m.AwardName,
+                m.AwardAmount
+            })
+            .FirstAsync();
+        var outDto = new GetRedPackRecordBaseDataOutDto();
+        if (snapshot != null)
+        {
+            outDto.BankCardNo = snapshot.AwardBankCardNo;
+            outDto.OpenBank = snapshot.AwardOpenBank;
+            outDto.Name = snapshot.AwardName;
+            outDto.Amount = snapshot.AwardAmount;
+        }
+        var audit = await _specialRedPackAuditRepository.Queryable().Where(m => m.OrderId == orderId).FirstAsync() 
+            ?? throw new UserFriendlyException("审核记录不存在");
+        if (audit != null)
+        {
+            outDto.AuditType = audit.AuditType;
+            outDto.AuditTypeCode = audit.AuditTypeCode;
+            outDto.RedPackAuditId = audit.Id;
+        }
+        outDto.OrderId = orderId;
+        outDto.ReplenishType = _systemDic.SnapshotReplenishType;
+        return outDto;
+    }
+
 
     #endregion
 }

+ 4 - 4
src/Hotline.Application/Snapshot/SnapshotOrderApplication.cs

@@ -278,15 +278,15 @@ public class SnapshotOrderApplication : IOrderSnapshotApplication, IScopeDepende
         {
             throw UserFriendlyException.SameMessage("随手拍工单标记不能为空");
         }
-        snapshot.Labels = labels;
-        snapshot.LabelName = string.Join('|', labels.Select(m => m.Value));
+        snapshot!.Labels = labels;
+        snapshot.LabelName = string.Join('|', labels!.Select(m => m.Value));
         //if (labels.Any(m => m.Key == "yzg"))
         //    snapshot.IsRectifyDepartment = true;
         //if (labels.Any(m => m.Key == "wzg"))
         //    snapshot.IsRectifyDepartment = false;
-        if (labels.Any(m => m.Key == "ss"))
+        if (labels!.Any(m => m.Key == "ss"))
             snapshot.IsTruthDepartment = true;
-        if (labels.Any(m => m.Key == "bss"))
+        if (labels!.Any(m => m.Key == "bss"))
             snapshot.IsTruthDepartment = false;
         snapshot.LabelTime = DateTime.Now;
         snapshot.LabelUserName = _sessionContext.UserName;

+ 3 - 0
src/Hotline.Application/StatisticalReport/CallReport/YiBinCallReportApplication.cs

@@ -339,6 +339,8 @@ public class YiBinCallReportApplication : CallReportApplicationBase, ICallReport
         return  _trCallRecordRepository.Queryable()
             .WhereIF(dto.RingStartTime.HasValue, x => x.BeginRingTime >= dto.RingStartTime)
             .WhereIF(dto.RingEndTime.HasValue, x => x.BeginRingTime <= dto.RingEndTime)
+            .WhereIF(dto.EndRingStartTime.HasValue,x=>x.EndRingTimg >= dto.EndRingStartTime)
+            .WhereIF(dto.EndRingEndTime.HasValue,x=>x.EndRingTimg <= dto.EndRingEndTime)
             .WhereIF(!string.IsNullOrEmpty(dto.EmpId), x => x.UserId == dto.EmpId)
             .WhereIF(dto.AnsweredStartTime.HasValue, x => x.AnsweredTime >= dto.AnsweredStartTime)
             .WhereIF(dto.AnsweredEndTime.HasValue, x => x.AnsweredTime <= dto.AnsweredEndTime)
@@ -363,6 +365,7 @@ public class YiBinCallReportApplication : CallReportApplicationBase, ICallReport
                 TelNo = x.TelNo,
                 AnsweredTime = x.AnsweredTime,
                 RingTimeBegin  = x.BeginRingTime,
+                RingTimeEnd = x.EndRingTimg,
                 SeatName = x.UserName
             });
     }

+ 2 - 2
src/Hotline.Application/StatisticalReport/OrderReportApplication.cs

@@ -2773,7 +2773,7 @@ namespace Hotline.Application.StatisticalReport
                    SourceChannel = p.Order.SourceChannel,
                    SourceChannelCode = p.Order.SourceChannelCode,
                    SpecialCreationTime = p.CreationTime,
-                   Name = SqlFunc.Subqueryable<WorkflowStep>().Where(s => s.Id == p.NewCurrentStepId).Select(s => s.HandlerName)
+                   Name = SqlFunc.Subqueryable<WorkflowTrace>().Where(s => s.Id == p.NewCurrentStepId).Select(s => s.HandlerName)
                })
            //将结果合并成一个表
            .MergeTable()
@@ -2842,7 +2842,7 @@ namespace Hotline.Application.StatisticalReport
                     SourceChannel = p.Order.SourceChannel,
                     SourceChannelCode = p.Order.SourceChannelCode,
                     SpecialCreationTime = p.CreationTime,
-                    Name = SqlFunc.Subqueryable<WorkflowStep>().Where(s => s.Id == p.NewCurrentStepId).Select(s => s.HandlerName)
+                    Name = SqlFunc.Subqueryable<WorkflowTrace>().Where(s => s.Id == p.NewCurrentStepId).Select(s => s.HandlerName)
                 })
             //将结果合并成一个表
             .MergeTable()

+ 24 - 0
src/Hotline.Repository.SqlSugar/Snapshot/SpecialRedPackAuditRepository.cs

@@ -0,0 +1,24 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Interfaces;
+using MediatR;
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Repository.SqlSugar.Snapshot;
+public class SpecialRedPackAuditRepository : BaseRepository<SpecialRedPackAudit>, ISpecialRedPackAuditRepository, IScopeDependency
+{
+    public SpecialRedPackAuditRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
+    {
+    }
+
+    public bool ExistByOrderId(string orderId)
+    {
+        return Queryable().Where(m => m.OrderId == orderId).Any();
+    }
+}

+ 6 - 3
src/Hotline.Share/Dtos/Article/BulletinDto.cs

@@ -251,7 +251,10 @@ namespace Hotline.Share.Dtos.Article
         public bool? IsTimeOut { get; set; }
     }
 
+    public record AddCircularMessage: AddCircularDto
+    {
 
+    }
     public record AddCircularDto
     {
         /// <summary>
@@ -282,7 +285,7 @@ namespace Hotline.Share.Dtos.Article
         /// <summary>
         /// 失效时间
         /// </summary>
-        public DateTime LostEfficacyTime { get; set; }
+        public DateTime? LostEfficacyTime { get; set; }
 
         /// <summary>
         /// 来源单位ID
@@ -328,7 +331,7 @@ namespace Hotline.Share.Dtos.Article
         /// <summary>
         /// 失效时间
         /// </summary>
-        public DateTime LoseEfficacyTime { get; set; }
+        public DateTime? LoseEfficacyTime { get; set; }
 
         /// <summary>
         /// 发布范围  EPushRange
@@ -376,7 +379,7 @@ namespace Hotline.Share.Dtos.Article
         /// <summary>
         /// 失效时间
         /// </summary>
-        public DateTime LoseEfficacyTime { get; set; }
+        public DateTime? LoseEfficacyTime { get; set; }
 
         /// <summary>
         /// 发布范围  EPushRange

+ 18 - 0
src/Hotline.Share/Dtos/Article/NotificationWaitSendDto.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Article
+{
+    public class NotificationWaitSendDto
+    {
+        public string Id { get; set; }
+
+        public string Msg { get; set; }
+
+        public string? Method { get; set; }
+
+    }
+}

+ 15 - 0
src/Hotline.Share/Dtos/CallCenter/BiQueryCallsDto.cs

@@ -645,6 +645,16 @@ public record QuerySeatMonthCallDetailRequest:PagedRequest
     /// </summary>
     public DateTime? RingEndTime { get;set; }
 
+    /// <summary>
+    /// 振铃结束时间开始
+    /// </summary>
+    public DateTime? EndRingStartTime { get; set; }
+
+    /// <summary>
+    /// 振铃结束时间结束
+    /// </summary>
+    public DateTime? EndRingEndTime { get; set; }
+
     /// <summary>
     /// 点数进入明细类型(1:呼入接通总量 2:有效接通量 3:接通秒挂量 4:超时接通量 5:按时接通量 6:呼入未接通总量 7:未接通秒挂量 8:超时未接通量)
     /// </summary>
@@ -668,6 +678,11 @@ public class QuerySeatMonthCallDetailResp
     /// </summary>
     public DateTime? RingTimeBegin { get; set; }
 
+    /// <summary>
+    /// 振铃结束时间
+    /// </summary>
+    public DateTime? RingTimeEnd { get; set; }
+
     /// <summary>
     /// 接通时间
     /// </summary>

+ 119 - 0
src/Hotline.Share/Dtos/Snapshot/OrderDto.cs

@@ -702,6 +702,58 @@ public class GetRedPackAuditSMSTemplateInDto
     public ESnapshotSMSStatus Status { get; set; }
 }
 
+public class SnapshotOrderAuditSpecialDetailOutDto
+{ 
+    /// <summary>
+    /// 工单信息
+    /// </summary>
+    public SnapshotOrderAuditOrderDetailOutDto Order { get; set; }
+
+    /// <summary>
+    /// 审核信息
+    /// </summary>
+    public SnapshotOrderAuditSpecialAuditDetailOutDto AuditDetail { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    public IEnumerable<KeyValuePair<int, string>> AuditComBox { get; set; }
+
+    /// <summary>
+    /// 审核类型
+    /// </summary>
+    public IEnumerable<SystemDicDataOutDto> AuditType { get; set; }
+}
+
+public class SnapshotOrderAuditSpecialAuditDetailOutDto
+{
+    /// <summary>
+    /// 审批人
+    /// </summary>
+    public string? AuditId { get; set; }
+
+    /// <summary>
+    /// 审批人
+    /// </summary>
+    public string? AuditName { get; set; }
+
+    /// <summary>
+    /// 审批部门
+    /// </summary>
+    public string? AuditOrgId { get; set; }
+
+    /// <summary>
+    /// 审批部门名称
+    /// </summary>
+    public string? AuditOrgName { get; set; }
+
+    /// <summary>
+    /// 审批意见
+    /// </summary>
+    public string? AuditRemark { get; set; }
+
+}
+
 public class SnapshotOrderAuditDetailOutDto
 {
     /// <summary>
@@ -860,6 +912,36 @@ public class UpdateRedPackGuiderAuditInDto
     public string Opinion { get; set; }
 }
 
+public class UpdateRedPackSpecialAuditInDto
+{
+    /// <summary>
+    /// 审核Id
+    /// </summary>
+    [Required]
+    public string RedPackAuditId { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    public ERedPackAuditStatus Status { get; set; }
+
+    /// <summary>
+    /// 审批类型
+    /// </summary>
+    public string? AuditTypeId { get; set; }
+
+    /// <summary>
+    /// 审核意见
+    /// </summary>
+    public string Opinion { get; set; }
+
+    /// <summary>
+    /// 审批金额
+    /// </summary>
+    public double? ApprovedAmount { get; set; }
+
+}
+
 public class UpdateRedPackAuditInDto
 {
     /// <summary>
@@ -889,6 +971,43 @@ public class UpdateRedPackAuditInDto
     public bool IsSendSms { get; set; }
 }
 
+public class GetRedPackRecordBaseDataOutDto
+{
+    /// <summary>
+    /// 金额
+    /// </summary>
+    public double? Amount { get; set; }
+
+    /// <summary>
+    /// 名字
+    /// </summary>
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 开户银行
+    /// </summary>
+    public string? OpenBank { get; set; }
+
+    /// <summary>
+    /// 银行卡号
+    /// </summary>
+    public string? BankCardNo { get; set; }
+
+    /// <summary>
+    /// 补充奖励类型
+    /// </summary>
+    public string? AuditType { get; set; }
+
+    /// <summary>
+    /// 补充奖励类型
+    /// </summary>
+    public string? AuditTypeCode { get; set; }
+    public string OrderId { get; set; }
+
+    public IReadOnlyCollection<SystemDicDataOutDto> ReplenishType { get; set; }
+
+    public string? RedPackAuditId { get; set; }
+}
 public class GetAuditBackBaseDataOutDto
 {
     /// <summary>

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

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Snapshot;
+
+/// <summary>
+/// 随手拍统计输出Dto
+/// </summary>
+public class SnapshotStatisticsOutDto
+{ 
+    /// <summary>
+    /// 随手拍来件数
+    /// </summary>
+    public int SuiShouPaiLaiJianShu { get; set; }
+}
+
+/// <summary>
+/// 随手拍统计输入Dto
+/// </summary>
+public class SnapshotStatisticsInDto
+{
+    /// <summary>
+    /// 开始时间
+    /// </summary>
+    [Required]
+    public DateTime StartTime { get; set; }
+
+    /// <summary>
+    /// 结束时间
+    /// </summary>
+    [Required]
+    public DateTime EndTime { get; set; }
+}
+public class StatisticsDto
+{
+}

+ 1 - 1
src/Hotline/Article/Bulletin.cs

@@ -33,7 +33,7 @@ namespace Hotline.Article
         /// <summary>
         /// 失效时间
         /// </summary>
-        public DateTime LoseEfficacyTime { get; set; }
+        public DateTime? LoseEfficacyTime { get; set; }
 
         /// <summary>
         /// 公告状态

+ 1 - 1
src/Hotline/Article/Circular.cs

@@ -50,7 +50,7 @@ namespace Hotline.Article
         /// <summary>
         /// 失效时间
         /// </summary>
-        public DateTime LostEfficacyTime { get; set; }
+        public DateTime? LostEfficacyTime { get; set; }
 
         /// <summary>
         /// 通知状态

+ 7 - 0
src/Hotline/Article/CircularRecordDomainService.cs

@@ -1,4 +1,6 @@
 using Hotline.Realtimes;
+using Hotline.Share.Dtos.Article;
+using Hotline.Share.Enums.Article;
 using XF.Domain.Dependency;
 using XF.Domain.Repository;
 
@@ -104,5 +106,10 @@ namespace Hotline.Article
                 catch{}
             }
         }
+
+        //public async Task AddCircularMessage(AddCircularMessage dto,ECircularType circularType,List<string> ids,,CancellationToken cancellationToken = default)
+        //{
+
+        //}
     }
 }

+ 21 - 0
src/Hotline/Article/NotificationWaitSend.cs

@@ -0,0 +1,21 @@
+using XF.Domain.Repository;
+
+namespace Hotline.Article
+{
+    /// <summary>
+    /// 消息待推送
+    /// </summary>
+    public class NotificationWaitSend : CreationEntity
+    {
+        public string UserId { get; set; }
+
+        public string Msg { get; set; }
+
+        public string? Method { get; set; }
+
+        /// <summary>
+        /// 0:待发,1:已发
+        /// </summary>
+        public string? State { get; set; }
+    }
+}

+ 2 - 0
src/Hotline/Caching/Interfaces/IRealtimeCacheManager.cs

@@ -12,5 +12,7 @@ namespace Hotline.Caching.Interfaces
         Task<RealtimeConnection> GetConnectionAsync(string userId, CancellationToken cancellationToken);
 
         Task<bool> IsInGroupAsync(string useId, string groupName, CancellationToken cancellationToken);
+
+        Task<RealtimeConnection> GetConnectionOtherAsync(string userId, CancellationToken cancellationToken);
     }
 }

+ 5 - 0
src/Hotline/Caching/Interfaces/ISysDicDataCacheManager.cs

@@ -77,5 +77,10 @@ namespace Hotline.Caching.Interfaces
         /// 兴唐动作状态映射
         /// </summary>
         IReadOnlyCollection<SystemDicDataOutDto> XingTangOperationMap { get; }
+
+        /// <summary>
+        /// 随手拍特殊红包审核类型
+        /// </summary>
+        IReadOnlyCollection<SystemDicDataOutDto> SnapshotRedPackSpecialType { get; }
     }
 }

+ 5 - 0
src/Hotline/Caching/Interfaces/ISystemSettingCacheManager.cs

@@ -105,5 +105,10 @@ namespace Hotline.Caching.Interfaces
         /// 是否开启自动填写办理意见至汇总节点
         /// </summary>
         bool IsAutoFillSummaryOpinion { get; }
+
+        /// <summary>
+        /// 是否不推送呼出的无文件的通话记录
+        /// </summary>
+        bool IsNoPushCallNativeOutNoFile { get; }
     }
 }

+ 5 - 0
src/Hotline/Caching/Services/RealtimeCacheManager.cs

@@ -28,4 +28,9 @@ public class RealtimeCacheManager : IRealtimeCacheManager, IScopeDependency
         var connection = await GetConnectionAsync(useId, cancellationToken);
         return connection.IsInGroup(groupName);
     }
+
+    public async Task<RealtimeConnection> GetConnectionOtherAsync(string userId, CancellationToken cancellationToken)
+    {
+        return await _cacheConnection.GetAsync(userId, cancellationToken);
+    }
 }

+ 5 - 0
src/Hotline/Caching/Services/SysDicDataCacheManager.cs

@@ -137,6 +137,11 @@ namespace Hotline.Caching.Services
         /// </summary>
         public IReadOnlyCollection<SystemDicDataOutDto> VisitSatisfaction => GetOrAdd(SysDicTypeConsts.VisitSatisfaction);
 
+        /// <summary>
+        /// 随手拍特殊红包审核类型
+        /// </summary>
+        public IReadOnlyCollection<SystemDicDataOutDto> SnapshotRedPackSpecialType => GetOrAdd(SysDicTypeConsts.SnapshotRedPackSpecialType);
+
         /// <summary>
         /// 兴唐动作状态映射
         /// </summary>

+ 5 - 0
src/Hotline/Caching/Services/SystemSettingCacheManager.cs

@@ -204,5 +204,10 @@ namespace Hotline.Caching.Services
         /// 是否开启自动填写办理意见至汇总节点
         /// </summary>
         public bool IsAutoFillSummaryOpinion => GetOrDefault(null, SettingConstants.IsAutoFillSummaryOpinion, "是否开启自动填写办理意见至汇总节点", false, "是否开启自动填写办理意见至汇总节点");
+
+        /// <summary>
+        /// 是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)
+        /// </summary>
+        public bool IsNoPushCallNativeOutNoFile => GetOrDefault("08dd23d1-5c5b-4262-8c99-8c83710723ea", SettingConstants.IsNoPushCallNativeOutNoFile, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)", true, "是否不推送呼出的无文件的通话记录(true: 不推送, false: 推送)");
     }
 }

+ 13 - 0
src/Hotline/SeedData/SystemDicDataSeedData.cs

@@ -29,6 +29,15 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
                 new() { Id = "08dd5190-3fbb-4156-864e-9ebbe46b498e", DicDataValue = "30", DicDataName = "400", Sort = 7},
                 ];
         }
+        if (dicTypeCode == SysDicTypeConsts.SnapshotRedPackSpecialType)
+        {
+            return [
+                new() {  Id = "08dd4bf7-b7c6-471b-8ee5-deb5a1c4776a", DicDataValue = "dqh", DicDataName = "电气焊类", Sort = 1},
+                new() {  Id = "08dd4bf7-b7ab-4729-80b2-b2c5db5d221c", DicDataValue = "qp", DicDataName = "气瓶类", Sort = 2},
+                new() {  Id = "08dd4bf7-b352-4b52-8a96-78f73197c22e", DicDataValue = "dde", DicDataName = "电动车类", Sort = 3},
+                new() {  Id = "08dd4bf7-b349-48ea-8f54-fb8b29070fa3", DicDataValue = "xftd", DicDataName = "消防通道", Sort = 4},
+                ];
+        }
         if (dicTypeCode == SysDicTypeConsts.SnapshotOrderLabel)
         {
             return [
@@ -208,6 +217,10 @@ public class SystemDicDataSeedData : ISeedData<SystemDicData>
         {
             dicType = ["08dbefe5-1cc5-4069-8d69-33afd978f68d", "兴唐动作状态映射"];
         }
+        if (dicTypeCode == SysDicTypeConsts.SnapshotRedPackSpecialType)
+        {
+            dicType = ["08dd4bf7-b7cd-471b-8729-73b3ceaae8f5", "随手拍特殊红包审批类型"];
+        }
 
         return new SystemDicType
         {

+ 15 - 0
src/Hotline/Settings/SettingConstants.cs

@@ -713,5 +713,20 @@ namespace Hotline.Settings
         /// 兴唐恒信 - 分机状态变更接收
         /// </summary>
         public const string XthxVerificationStatusAdd = "XthxVerificationStatusAdd";
+
+        /// <summary>
+        /// 是否启用小休计时
+        /// </summary>
+        public const string IsTelRest = "IsTelRest";
+
+        /// <summary>
+        /// 小休计时秒数
+        /// </summary>
+        public const string TelRestNum = "TelRestNum";
+
+        /// <summary>
+        /// 是否不推送呼出的无文件的通话记录
+        /// </summary>
+        public const string IsNoPushCallNativeOutNoFile = "IsNoPushCallNativeOutNoFile";
     }
 }

+ 5 - 0
src/Hotline/Settings/SysDicTypeConsts.cs

@@ -311,4 +311,9 @@ public class SysDicTypeConsts
     /// 兴唐动作状态映射
     /// </summary>
     public static string XingTangOperationMap = "XingTangOperationMap";
+
+    /// <summary>
+    /// 随手拍特殊红包审核类型
+    /// </summary>
+    public static string SnapshotRedPackSpecialType = "SnapshotRedPackSpecialType";
 }

+ 12 - 0
src/Hotline/Snapshot/Interfaces/ISpecialRedPackAuditRepository.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot.Interfaces;
+public interface ISpecialRedPackAuditRepository : IRepository<SpecialRedPackAudit>
+{
+    bool ExistByOrderId(string orderId);
+}

+ 137 - 0
src/Hotline/Snapshot/SpecialRedPackAudit.cs

@@ -0,0 +1,137 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+using Hotline.Orders;
+using Hotline.Share.Enums.Snapshot;
+
+namespace Hotline.Snapshot;
+
+/// <summary>
+/// 特殊红包审核
+/// 在特殊红包审核界面审核通过/不通过后生成数据
+/// </summary>
+[Description("特殊市民红包审核")]
+public class SpecialRedPackAudit : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 关联工单编号
+    /// <inheritdoc cref="Order"/>表的Id字段
+    /// </summary>    
+    [SugarColumn(ColumnDescription = "关联工单编号")]
+    public string OrderId { get; set; }
+
+    /// <summary>
+    /// 领取手机号码
+    /// </summary>
+    [SugarColumn(ColumnDescription = "领取红包手机号码")]
+    public string? PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 审核状态
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审核状态")]
+    public ERedPackAuditStatus Status { get; set; }
+
+    /// <summary>
+    /// 审批时间
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审批时间")]
+    public DateTime? AuditTime { get; set; }
+
+    /// <summary>
+    /// 配置金额
+    /// </summary>
+    [SugarColumn(ColumnDescription = "配置金额")]
+    public double ShouldAmount { get; set; }
+
+    /// <summary>
+    /// 审批金额
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审批金额")]
+    public double? ApprovedAmount { get; set; }
+
+    /// <summary>
+    /// 实发金额
+    /// </summary>
+    [SugarColumn(ColumnDescription = "实发金额")]
+    public double? AcutalAmount { get; set; }
+
+    /// <summary>
+    /// 市民奖励发放结果
+    /// </summary>
+    [SugarColumn(ColumnDescription = "市民奖励发放结果")]
+    public bool IsSend { get; set; }
+
+    /// <summary>
+    /// 市民奖励发放备注
+    /// </summary>
+    [SugarColumn(ColumnDescription = "市民奖励发放备注")]
+    public string? SendRemarks { get; set; }
+
+    /// <summary>
+    /// 操作人
+    /// </summary>
+    [SugarColumn(ColumnDescription = "操作人")]
+    public string? AuditId { get; set; }
+
+    /// <summary>
+    /// 操作人
+    /// </summary>
+    [SugarColumn(ColumnDescription = "操作人")]
+    public string? AuditName { get; set; }
+
+    /// <summary>
+    /// 审批部门
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审批部门")]
+    public string? AuditOrgId { get; set; }
+
+    /// <summary>
+    /// 审批部门名称
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审批部门名称")]
+    public string? AuditOrgName { get; set; }
+
+    /// <summary>
+    /// 审批意见
+    /// </summary>
+    [SugarColumn(ColumnDescription = "审批意见")]
+    public string? AuditRemark { get; set; }
+
+    public string? Remark { get; set; }
+
+    /// <summary>
+    /// 是否已发放
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否已发放")]
+    public bool? IsIssued { get; set; }
+
+    /// <summary>
+    /// 短信Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "短信Id")]
+    public string? SMSTemplateId { get; set; }
+
+    /// <summary>
+    /// 是否发送短信
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否发送短信")]
+    public bool? IsSendSMS { get; set; }
+
+    /// <summary>
+    /// 特殊红包审核,审批类型
+    /// </summary>
+    [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
+    public string? AuditType { get; set; }
+
+    /// <summary>
+    /// 特殊红包审核,审批类型
+    /// </summary>
+    [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
+    public string? AuditTypeCode { get; set; }
+}

+ 18 - 0
src/Hotline/Snapshot/SupplementRecord.cs

@@ -93,9 +93,27 @@ public class SupplementRecord : FullStateEntity
     [SugarColumn(ColumnDescription = "开户行")]
     public string? OpenBank { get; set; }
 
+    /// <summary>
+    /// 补充发放人姓名
+    /// </summary>
+    [SugarColumn(ColumnDescription = "补充发放人姓名")]
+    public string? Name { get; set; }
+
     /// <summary>
     /// 是否发送短信
     /// </summary>
     [SugarColumn(ColumnDescription = "是否发送短信")]
     public bool IsSendSMS { get; set; }
+
+    /// <summary>
+    /// 特殊红包审核,审批类型
+    /// </summary>
+    [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
+    public string? AuditType { get; set; }
+
+    /// <summary>
+    /// 特殊红包审核,审批类型
+    /// </summary>
+    [SugarColumn(ColumnDescription = "特殊红包审核,审批类型")]
+    public string? AuditTypeCode { get; set; }
 }

+ 2 - 2
src/TianQue.Sdk/TiqnQueService.cs

@@ -98,8 +98,8 @@ public class TiqnQueService : IGuiderSystemService, IScopeDependency
             Message = result.Msg,
             Result = new GuiderSystemOutDto
             {
-                GuiderSystemId = result.Data.AppealNumber,
-                JsonData = result.Data.ToJson()
+                GuiderSystemId = result.Data?.AppealNumber,
+                JsonData = result.Data?.ToJson()
             }
         };
     }

+ 1 - 7
test/Hotline.Tests/Application/KnowApplicationTest.cs

@@ -33,13 +33,7 @@ public class KnowApplicationTest : TestBase
     private readonly IRepository<KnowledgeWord> _knowledgeWordRepository;
     private readonly IRepository<KnowledgeHotWord> _knowledgeHotWordRepository;
 
-    public KnowApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository,
-        UserController userController, IServiceScopeFactory scopeFactory,
-        IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor,
-        IKnowApplication knowApplication, IMediator mediator, IRepository<KnowledgeBase.Knowledge> knowledgeRepository,
-        IKnowledgeDomainService knowledgeDomainService, IRepository<KnowledgeWord> knowledgeWordRepository,
-        IRepository<KnowledgeHotWord> knowledgeHotWordRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData)
-        : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
+    public KnowApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IKnowApplication knowApplication, IMediator mediator, IRepository<KnowledgeBase.Knowledge> knowledgeRepository, IKnowledgeDomainService knowledgeDomainService, IRepository<KnowledgeWord> knowledgeWordRepository, IRepository<KnowledgeHotWord> knowledgeHotWordRepository, IThirdIdentiyService thirdService, IThirdAccountRepository thirdAccount, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdService, thirdAccount, cacheSettingData)
     {
         _knowApplication = knowApplication;
         _mediator = mediator;

+ 1 - 1
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -69,7 +69,7 @@ public class OrderSnapshotApplicationTest : TestBase
             .办理到网格员(SetZuoXi)
             .StepHandle(async order =>
             {
-                Thread.Sleep(20 * 1000);
+                Thread.Sleep(5 * 1000);
                 var orderEntity = await _orderRepository.GetAsync(order.Id);
                 orderEntity.ActualHandleStepName.ShouldBe("工单标记");
             }

+ 67 - 1
test/Hotline.Tests/Application/RedPackApplicationTest.cs

@@ -1,11 +1,15 @@
 using Hotline.Api.Controllers;
 using Hotline.Application.Snapshot;
+using Hotline.Caching.Interfaces;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
+using Hotline.Repository.SqlSugar.Snapshot;
 using Hotline.Settings;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Snapshot.Interfaces;
+using Hotline.Tests.Mock;
 using Hotline.Users;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
@@ -24,11 +28,73 @@ public class RedPackApplicationTest : TestBase
 {
     private readonly IRedPackApplication _redPackApplication;
     private readonly IRedPackRecordRepository _redPackRecordRepository;
+    private readonly OrderServiceMock _orderServiceMock;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+    private readonly IIndustryRepository _industryRepository;
+    private readonly ISpecialRedPackAuditRepository _specialRedPackAuditRepository;
 
-    public RedPackApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IRedPackApplication redPackApplication, IRedPackRecordRepository redPackRecordRepository, ITypedCache<SystemSetting> cacheSettingData) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
+    public RedPackApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, IRedPackApplication redPackApplication, IRedPackRecordRepository redPackRecordRepository, ITypedCache<SystemSetting> cacheSettingData, OrderServiceMock orderServiceMock, ISystemDicDataCacheManager systemDicDataCacheManager, IIndustryRepository industryRepository, ISpecialRedPackAuditRepository specialRedPackAuditRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData)
     {
         _redPackApplication = redPackApplication;
         _redPackRecordRepository = redPackRecordRepository;
+        _orderServiceMock = orderServiceMock;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+        _industryRepository = industryRepository;
+        _specialRedPackAuditRepository = specialRedPackAuditRepository;
+    }
+
+    /// <summary>
+    /// 获取特殊红包集合
+    /// </summary>
+    /// <returns></returns>
+    [Fact]
+    public async Task GetRedPackSpecialAuditItems_Test()
+    {
+        var dhzy = _systemDicDataCacheManager.OrderTag.Where(m => m.DicDataName == "动火作业").FirstOrDefault();
+        dhzy.ShouldNotBeNull("SysDicTypeConsts.OrderTag 缺少动作火作业基础信息");
+        SetZuoXi();
+        SetSettingCache(SettingConstants.OvertimeBack, "0.00027778");
+        var industryItems = await _industryRepository.Queryable().Where(m => m.Name == "安全隐患").Select(d => new { d.Id, d.Name, }).ToListAsync();
+        var industry = industryItems.First();
+        var order = _orderServiceMock.CreateOrder(industryId: industry.Id, industryName: industry.Name, tags: [dhzy.Id])
+            .办理到网格员()
+            .StepHandle(async order => Thread.Sleep(5 * 1000))
+            .办理到派单员(Set班长)
+            .办理到一级部门(SetPaiDanYuan)
+            .办理到归档(Set一级部门)
+            .发布工单(SetZuoXi, _systemDicDataCacheManager.SnapshotOrderLabel.Where(m => m.DicDataValue == "bss").Select(m => new Kv(m.DicDataName, m.DicDataName)).ToList())
+            .部门审核市民红包(Set应急管理局)
+            .StepHandle(async order => 
+            {
+                var items = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0)).ToListAsync();
+                items.Where(m => m.No == order.No).Count().ShouldBe(1);
+                items = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, -1)).ToListAsync();
+                items.Where(m => m.No == order.No).Count().ShouldBe(1);
+                items = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 1)).ToListAsync();
+                items.Where(m => m.No == order.No).Count().ShouldBe(0, "审批同意不应该存在数据");
+                items = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 2)).ToListAsync();
+                items.Where(m => m.No == order.No).Count().ShouldBe(0);
+            })
+            .部门审核特殊红包(Set应急管理局, 29)
+            .StepHandle(async order =>
+            {
+                var special = await _specialRedPackAuditRepository.Queryable().Where(m => m.OrderId == order.Id).FirstAsync();
+                special.ApprovedAmount.ShouldBe(29);
+                special.Status.ShouldBe(ERedPackAuditStatus.Agree);
+                special.AuditRemark.ShouldBe("红包审核通过");
+                var redPackAudit = await _redPackApplication.GetRedPackSpecialAuditBaseDataAsync(order.Id);
+                redPackAudit.AuditDetail.AuditId.ShouldNotBeNull();
+                redPackAudit.AuditDetail.AuditName.ShouldNotBeNull();
+                redPackAudit.AuditDetail.AuditOrgId.ShouldNotBeNull();
+                redPackAudit.AuditDetail.AuditOrgName.ShouldNotBeNull();
+                redPackAudit.AuditDetail.AuditRemark.ShouldNotBeNull("审核意见不能为空");
+                redPackAudit.AuditDetail.AuditRemark.ShouldBe("红包审核通过");
+
+                var items = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 1)).ToListAsync();
+                items.Count.ShouldNotBe(0, $"工单No: {order.No}");
+            })
+            .GetCreateResult();
+
     }
 
     /// <summary>

+ 36 - 3
test/Hotline.Tests/Mock/OrderServiceMock.cs

@@ -26,6 +26,7 @@ using Hotline.Share.Dtos;
 using Hotline.FlowEngine.Notifications;
 using Hotline.Api.Controllers.Bi;
 using XF.Domain.Exceptions;
+using System;
 
 namespace Hotline.Tests.Mock;
 public class OrderServiceMock
@@ -41,8 +42,9 @@ public class OrderServiceMock
     public readonly ISessionContext _sessionContext;
     public readonly IOrderServiceStartWorkflow _orderServiceStartWorkflow;
     public readonly RedPackController _redPackController;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
 
-    public OrderServiceMock(OrderController orderController, IRepository<Order> orderRepository, IOrderVisitRepository orderVisitRepository, SnapshotController snapshotController, ISessionContext sessionContext, IOrderServiceStartWorkflow orderServiceStartWorkflow, ISystemSettingCacheManager systemSettingCacheManager, RedPackController redPackController)
+    public OrderServiceMock(OrderController orderController, IRepository<Order> orderRepository, IOrderVisitRepository orderVisitRepository, SnapshotController snapshotController, ISessionContext sessionContext, IOrderServiceStartWorkflow orderServiceStartWorkflow, ISystemSettingCacheManager systemSettingCacheManager, RedPackController redPackController, ISystemDicDataCacheManager systemDicDataCacheManager)
     {
         _orderController = orderController;
         _orderController.ControllerContext = new ControllerContext
@@ -62,9 +64,10 @@ public class OrderServiceMock
         _systemSettingCacheManager = systemSettingCacheManager;
         _redPackController = redPackController;
         _redPackController.ControllerContext = new ControllerContext
-        { 
+        {
             HttpContext = new DefaultHttpContext(),
         };
+        _systemDicDataCacheManager = systemDicDataCacheManager;
     }
 
     public IOrderServiceStartWorkflow CreateSnapshotOrder(Action action)
@@ -100,7 +103,7 @@ public class OrderServiceMock
         return _orderServiceStartWorkflow;
     }
 
-    public IOrderServiceStartWorkflow CreateOrder(string callId = "", string industryId = "", string industryName = "")
+    public IOrderServiceStartWorkflow CreateOrder(string callId = "", string industryId = "", string industryName = "", List<string> tags = null)
     {
         var json = "{\"sourceChannel\":\"因特网\",\"sourceChannelCode\":\"YTW\",\"transferPhone\":null,\"fromPhone\":null,\"acceptorName\":\"单元测试\",\"acceptorStaffNo\":\"\",\"fromName\":\"1233333333\",\"fromGender\":1,\"identityType\":1,\"licenceType\":null,\"licenceTypeCode\":null,\"licenceNo\":null,\"ageRange\":null,\"ageRangeCode\":null,\"contact\":\"12333333333\",\"isSecret\":false,\"acceptSms\":false,\"no\":null,\"title\":\"\",\"hotspotId\":\"1912\",\"eventCategoryId\":null,\"incidentTime\":null,\"incidentPurpose\":null,\"areaCode\":\"519800\",\"city\":\"省内\",\"street\":null,\"isRepeat\":\"false\",\"pushType\":null,\"pushTypeCode\":null,\"content\":\"单元测试内容\",\"duplicateIds\":[],\"duplicateTitle\":null,\"callAddress\":null,\"repeatableEventDetails\":[],\"orderExtension\":null,\"transpond\":false,\"isEnforcementOrder\":false,\"focusOnEventsArr\":[],\"focusOnEvents\":null,\"isFormalistWorkOrder\":false,\"isSensitiveWorkOrders\":false,\"isUrgent\":false,\"isThreePartyConference\":false,\"is24HoursComplete\":false,\"company\":null,\"orderPushTypes\":[],\"acceptType\":\"咨询\",\"acceptTypeCode\":\"10\",\"files\":[],\"hotspotSpliceName\":\"互联互通-转接乐山市12345\",\"hotspotName\":\"转接乐山市12345\",\"hotspotCode\":\"1912\",\"hotspotExternal\":\"19\",\"county\":\"\",\"town\":\"\"}";
         AddOrderDto = json.FromJson<AddOrderDto>();
@@ -113,11 +116,20 @@ public class OrderServiceMock
         AddOrderDto.IndustryId = industryId;
         AddOrderDto.IndustryName = industryName;
         AddOrderDto.Title = "单元测试" + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
+        if (tags.NotNullOrEmpty())
+            AddOrderDto.Tags = tags;
         CreateOrderOutDto = _orderController.Add(AddOrderDto).GetAwaiter().GetResult().ToJson().FromJson<CreateOrderOutDto>();
         _orderServiceStartWorkflow.orderServiceMock = this;
         return _orderServiceStartWorkflow;
     }
 
+    public OrderServiceMock UpdateOrder()
+    {
+        UpdateOrderDto order = _orderController.Get(CreateOrderOutDto.Id).GetAwaiter().GetResult();
+        _orderController.Update(order).GetAwaiter().GetResult();
+        return this;
+    }
+
     public CreateOrderOutDto GetCreateResult()
     {
         return CreateOrderOutDto;
@@ -473,4 +485,25 @@ public class OrderServiceMock
         return this;
     }
 
+    public OrderServiceMock 部门审核特殊红包(Action action, double? approvedAmount = 0)
+    {
+        action?.Invoke();
+        var baseData = _redPackController.GetRedPackSpecialItems(new SnapshotOrderAuditItemsInDto(null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, 0)).GetAwaiter().GetResult();
+        var item = baseData.Items.FirstOrDefault(m => m.No == CreateOrderOutDto.No);
+        var basedata = _systemDicDataCacheManager.SnapshotRedPackSpecialType.First();
+        if (item == null)
+            throw UserFriendlyException.SameMessage("获取特殊审核红包信息错误, 不存在被测试的对象.");
+        var inDto = new UpdateRedPackSpecialAuditInDto
+        {
+            AuditTypeId = basedata.Id,
+            ApprovedAmount = approvedAmount,
+            RedPackAuditId = item.RedPackAuditId,
+            Status = ERedPackAuditStatus.Agree,
+            Opinion = "红包审核通过",
+        };
+
+        _redPackController.UpdateRedPackSpecialAuditAsync(inDto).GetAwaiter().GetResult();
+        return this;
+
+    }
 }