79 Commits ead03f75f1 ... 69a94581b3

Author SHA1 Message Date
  tangjiang 69a94581b3 1 day ago
  tangjiang 2a6dde382a 修改知识库超期未更新查询 1 day ago
  tangjiang e86b22d6b1 1 day ago
  tangjiang fe6735270a 1 day ago
  tangjiang a9ecfd1bfc 1 day ago
  tangjiang b92f2f11db 修改知识库超期更新bug 1 day ago
  tangjiang 4f09d1d0d0 修改12315拓展信息订单号长度 1 day ago
  tangjiang 5784c86833 修改知识库超期未更新统计bug 1 day ago
  Dun.Jason b8d86f3832 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  Dun.Jason 2efbc7fb05 查询部门手机号 3 days ago
  tangjiang 3d7ca686dc 修改兴唐白名单查询不抛异常 3 days ago
  tangjiang e79fad5f18 是否开启白名单查询 3 days ago
  tangjiang afb4b6a368 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 78bdb2ab52 黑白名单操作记录新增排序 3 days ago
  qinchaoyue c27ff088f9 Merge branch 'feature/snapshot' into test 3 days ago
  qinchaoyue 0296df0717 非受理返回不增加积分 3 days ago
  guqiang 6bb49c5d97 Merge branch 'feature/exam' into test 3 days ago
  guqiang 26957836f0 调整题库编辑接口 3 days ago
  guqiang 8cbe9eecc7 Merge branch 'feature/exam' into test 3 days ago
  guqiang e9da1d04ce 调整题库修改接口 3 days ago
  qinchaoyue 7121e70203 Merge branch 'feature/snapshot' into test 3 days ago
  qinchaoyue 6b78a4bbbe 修复设置安全卫士 3 days ago
  qinchaoyue a4283f95c9 Merge branch 'feature/snapshot' into test 3 days ago
  qinchaoyue fce6aeab8b 修复异常 3 days ago
  qinchaoyue a13a95fbf2 Merge branch 'feature/snapshot' into test 3 days ago
  qinchaoyue 4ea4a84d45 返回市民Id 3 days ago
  qinchaoyue f27f1d442c 设置安全卫士 3 days ago
  qinchaoyue caece43095 Merge branch 'feature/snapshot' into test 3 days ago
  qinchaoyue c1e79dd808 新增查询条件 3 days ago
  libin e512aa1696 Merge branch 'test' into lib/test 3 days ago
  libin 7d32bfc294 常用意见列表优化 3 days ago
  qinchaoyue 8b4c1f5571 保存 3 days ago
  qinchaoyue 1179d48a91 修改通过公告多选志愿者类型 3 days ago
  tangjiang 40820c48f2 修改回访结果接收后如果工单状态未已归档才处理成已回访,其他状态不处理 3 days ago
  qinchaoyue 890bce81d3 完成随手拍积分统计 3 days ago
  tangjiang a53282aa37 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 702348c59d 格式化代码 3 days ago
  xf 9554e8b9b8 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  xf a2a090ad36 逻辑删除字段默认设置为false 3 days ago
  tangjiang a8ed5f1ded Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 991ee113c7 自贡任务 525 延期列表菜单的更多查询中“当前节点”改为下拉选择 3 days ago
  Dun.Jason 7c3a87a3ca Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  Dun.Jason 0eaae45b44 智能回访 3 days ago
  libin 2bc5cb8223 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  libin b336c95dc1 知识库查询新增查询条件 3 days ago
  qinchaoyue 60a5151a6c 随手拍通知公告功能 3 days ago
  tangjiang bc97214b19 修改运营商为空判断 3 days ago
  tangjiang 73b79edc11 自贡任务 524 调整【知识检索】页面的常用知识前十显示规则 3 days ago
  tangjiang 938c84a875 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang f4dc1eec7e 自贡任务 522 在【数据统计->知识库统计】目录下新增【超期未更新统计】菜单 3 days ago
  libin 1ee1318cc8 常用意见导出 3 days ago
  qinchaoyue 30c5725e33 保存 3 days ago
  libin 2b60265631 Merge branch 'test' into lib/test 3 days ago
  libin 66e610a6da 常用意见导出优化 3 days ago
  tangjiang d6e3effbda Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 2e019034e6 排班统计修改bug 3 days ago
  xf 96e9c2e084 简化全局查询过滤器实现,注释旧方法 3 days ago
  tangjiang 11afe37e20 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 7b5713d7e7 排班统计bug修复,观察件增加id 3 days ago
  libin 90c7552d8a Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  libin a45ce1d075 导出日志修改 3 days ago
  xf dc31020c86 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  xf b6f4482111 3 days ago
  tangjiang b886298249 值班管理统计修改bug 3 days ago
  tangjiang df12e39440 格式化代码 3 days ago
  tangjiang b8b6065dd8 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang ddf84b7549 修改观察件bug 3 days ago
  qinchaoyue 62394351bc 微信登录接口增加日志 3 days ago
  qinchaoyue 333592524a 保存 3 days ago
  xf 45c68a88bb Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  xf 17e7791484 优化日志记录与软删除过滤逻辑 3 days ago
  Dun.Jason c7c21a3a8c Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  Dun.Jason 60ca0064b7 旅游督办 3 days ago
  tangjiang 6045ce2564 Merge branch 'test' of http://110.188.24.182:10023/Fengwo/hotline into test 3 days ago
  tangjiang 99d8d1a0f0 号码归属地增加基础查询信息 3 days ago
  libin e9fe105d49 Merge branch 'test' into lib/test 3 days ago
  libin 627572987b 工单业务量统计 3 days ago
  qinchaoyue 8832a3fbe2 完成随手拍消息 4 days ago
  qinchaoyue 82f00fabc6 保存 4 days ago
76 changed files with 1364 additions and 305 deletions
  1. 22 22
      src/Hotline.Ai.Jths/AiVisitService.cs
  2. 112 2
      src/Hotline.Api/Controllers/CallController.cs
  3. 12 4
      src/Hotline.Api/Controllers/CallNativeContrroller.cs
  4. 1 1
      src/Hotline.Api/Controllers/FwThirdController.cs
  5. 4 2
      src/Hotline.Api/Controllers/HomeController.cs
  6. 2 4
      src/Hotline.Api/Controllers/IdentityController.cs
  7. 10 3
      src/Hotline.Api/Controllers/KnowledgeApplyController.cs
  8. 68 6
      src/Hotline.Api/Controllers/KnowledgeCommonController.cs
  9. 40 39
      src/Hotline.Api/Controllers/KnowledgeController.cs
  10. 4 35
      src/Hotline.Api/Controllers/ObservationPieceController.cs
  11. 31 21
      src/Hotline.Api/Controllers/OrderController.cs
  12. 3 2
      src/Hotline.Api/Controllers/SchedulingController.cs
  13. 9 0
      src/Hotline.Api/Controllers/Snapshot/BiSnapshotController.cs
  14. 11 54
      src/Hotline.Api/Controllers/Snapshot/SnapshotBulletinController.cs
  15. 10 0
      src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs
  16. 9 0
      src/Hotline.Api/Controllers/Snapshot/SnapshotUserController.cs
  17. 8 5
      src/Hotline.Api/Controllers/SysController.cs
  18. 26 10
      src/Hotline.Api/Controllers/SystemMobilAreaController.cs
  19. 4 2
      src/Hotline.Api/Controllers/WorkflowController.cs
  20. 2 2
      src/Hotline.Api/config/appsettings.Development.json
  21. 12 0
      src/Hotline.Application/Exam/Service/Questions/QuestionService.cs
  22. 9 0
      src/Hotline.Application/Knowledge/IKnowApplication.cs
  23. 22 8
      src/Hotline.Application/Knowledge/KnowApplication.cs
  24. 5 40
      src/Hotline.Application/ObservationPiece/ObservationPieceApplication.cs
  25. 13 12
      src/Hotline.Application/OrderApp/OrderApplication.cs
  26. 24 2
      src/Hotline.Application/Snapshot/BiSnapshotApplication.cs
  27. 7 0
      src/Hotline.Application/Snapshot/Contracts/IBiSnapshotApplication.cs
  28. 11 0
      src/Hotline.Application/Snapshot/Contracts/INotificationApplication.cs
  29. 2 0
      src/Hotline.Application/Snapshot/Contracts/ISnapshotApplication.cs
  30. 26 1
      src/Hotline.Application/Snapshot/Contracts/ISnapshotBulletinApplication.cs
  31. 7 0
      src/Hotline.Application/Snapshot/Contracts/ISnapshotUserApplication.cs
  32. 0 0
      src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs
  33. 12 0
      src/Hotline.Application/Snapshot/NotificationApplication.cs
  34. 15 1
      src/Hotline.Application/Snapshot/Notifications/SnapshotHandler.cs
  35. 17 1
      src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs
  36. 109 2
      src/Hotline.Application/Snapshot/SnapshotBulletinApplication.cs
  37. 32 1
      src/Hotline.Application/Snapshot/SnapshotPointsApplication.cs
  38. 17 0
      src/Hotline.Application/Snapshot/SnapshotUserApplication.cs
  39. 0 0
      src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs
  40. 1 0
      src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs
  41. 19 0
      src/Hotline.Repository.SqlSugar/Snapshot/NotificationReceiverRepository.cs
  42. 19 0
      src/Hotline.Repository.SqlSugar/Snapshot/NotificationRepository.cs
  43. 10 0
      src/Hotline.Share/Dtos/Knowledge/KnowedgeStatisticsDto.cs
  44. 4 0
      src/Hotline.Share/Dtos/ObservationPiece/ObservationPieceListDto.cs
  45. 27 0
      src/Hotline.Share/Dtos/Settings/SystemCommonOpinionDto.cs
  46. 1 0
      src/Hotline.Share/Dtos/Settings/SystemMobilAreaDto.cs
  47. 62 0
      src/Hotline.Share/Dtos/Snapshot/NotifyDto.cs
  48. 9 0
      src/Hotline.Share/Dtos/Snapshot/PointsDto.cs
  49. 6 1
      src/Hotline.Share/Dtos/Snapshot/SnapshotBulletinDto.cs
  50. 36 0
      src/Hotline.Share/Dtos/Snapshot/SnapshotUserInfoDto.cs
  51. 28 0
      src/Hotline.Share/Dtos/Snapshot/StatisticsDto.cs
  52. 5 0
      src/Hotline.Share/Dtos/WebPortal/QueryKnowledgeList.cs
  53. 17 0
      src/Hotline.Share/Enums/Snapshot/ENotificationType.cs
  54. 5 0
      src/Hotline.Share/Mq/EventNames.Snapshot.cs
  55. 5 0
      src/Hotline.Share/Tools/DateTimeExtensions.cs
  56. 13 12
      src/Hotline/Orders/Order.cs
  57. 10 0
      src/Hotline/Settings/SettingConstants.cs
  58. 19 0
      src/Hotline/Snapshot/Contracts/INotificationDomainService.cs
  59. 0 0
      src/Hotline/Snapshot/IRepository/IIndustryLogRepository.cs
  60. 12 0
      src/Hotline/Snapshot/IRepository/INotificationReceiverRepository.cs
  61. 12 0
      src/Hotline/Snapshot/IRepository/INotificationRepository.cs
  62. 27 0
      src/Hotline/Snapshot/Notification.cs
  63. 27 0
      src/Hotline/Snapshot/NotificationReceiver.cs
  64. 40 0
      src/Hotline/Snapshot/Services/NotificationDomainService.cs
  65. 14 3
      src/Hotline/Snapshot/Services/SnapshotPointsDomainService.cs
  66. 19 0
      src/Hotline/Snapshot/SnapshotBulletin.cs
  67. 0 1
      src/Hotline/Validators/Exams/Questions/UpdateQuestionTagDtoValidator.cs
  68. 1 1
      src/Hotline/Validators/Order/AddOrderDtoValidator.cs
  69. 1 1
      src/XF.Domain.Repository/Entity.cs
  70. 9 0
      test/Hotline.Tests/Application/BiSnapshotApplicationTest.cs
  71. 35 3
      test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs
  72. 36 1
      test/Hotline.Tests/Application/PointsRecordApplicationTest.cs
  73. 91 0
      test/Hotline.Tests/Application/SnapshotBulletionApplicationTest.cs
  74. 8 0
      test/Hotline.Tests/Application/SnapshotUserApplicationTest.cs
  75. 2 0
      test/Hotline.Tests/Mock/Interfaces/IOrderServiceStartWorkflow.cs
  76. 6 0
      test/Hotline.Tests/Mock/OrderServiceStartWorkflow.cs

+ 22 - 22
src/Hotline.Ai.Jths/AiVisitService.cs

@@ -114,24 +114,24 @@ namespace Hotline.Ai.Jths
                 taskData.VariableList = new List<Variable>();
                
                
-                if (!string.IsNullOrEmpty(item.Order.FromName))
-                {
-                    //来电名称
-                    //开发环境 :OC_SCENE_VAR_FIELD11
-                    //生产环境:OC_SCENE_VAR_FIELD12
-                    taskData.VariableList.Add(new Variable() { Code = visitFromNameKey, Value = item.Order.FromName });
-                }
-                else
-                {
-                    //来电名称
-                    //开发环境 :OC_SCENE_VAR_FIELD11
-                    //生产环境:OC_SCENE_VAR_FIELD12
-                    taskData.VariableList.Add(new Variable() { Code = visitFromNameKey, Value = "市民" });
-                }
-                //来电性别
-                //开发环境: OC_SCENE_VAR_FIELD14
-                //生产环境:OC_SCENE_VAR_FIELD14
-                taskData.VariableList.Add(new Variable() { Code = visitFromGenderKey, Value = item.Order.FromGender == EGender.Female ? "女士" : "先生" });
+                //if (!string.IsNullOrEmpty(item.Order.FromName))
+                //{
+                //    //来电名称
+                //    //开发环境 :OC_SCENE_VAR_FIELD11
+                //    //生产环境:OC_SCENE_VAR_FIELD12
+                //    taskData.VariableList.Add(new Variable() { Code = visitFromNameKey, Value = item.Order.FromName });
+                //}
+                //else
+                //{
+                //    //来电名称
+                //    //开发环境 :OC_SCENE_VAR_FIELD11
+                //    //生产环境:OC_SCENE_VAR_FIELD12
+                //    taskData.VariableList.Add(new Variable() { Code = visitFromNameKey, Value = "市民" });
+                //}
+                ////来电性别
+                ////开发环境: OC_SCENE_VAR_FIELD14
+                ////生产环境:OC_SCENE_VAR_FIELD14
+                //taskData.VariableList.Add(new Variable() { Code = visitFromGenderKey, Value = item.Order.FromGender == EGender.Female ? "女士" : "先生" });
                 //来电时间
                 //开发环境:OC_SCENE_VAR_FIELD17
                 //生产环境:OC_SCENE_VAR_FIELD19
@@ -141,10 +141,10 @@ namespace Hotline.Ai.Jths
                 //生产环境:OC_SCENE_VAR_FIELD20
                 taskData.VariableList.Add(new Variable() { Code = visitOrderTitleKey, Value = item.Order.Title });
 
-                //是否来电工单
-                //开发环境:
-                //生产环境:
-                taskData.VariableList.Add(new Variable() { Code = visitIsCallOrderKey, Value = item.Order.SourceChannelCode == "RGDH" ? "income" : "outbound" });
+                ////是否来电工单
+                ////开发环境:
+                ////生产环境:
+                //taskData.VariableList.Add(new Variable() { Code = visitIsCallOrderKey, Value = item.Order.SourceChannelCode == "RGDH" ? "income" : "outbound" });
                 taskDataList.Add(taskData);
             }
             requestData.TaskDataList = taskDataList;

+ 112 - 2
src/Hotline.Api/Controllers/CallController.cs

@@ -27,6 +27,7 @@ using Microsoft.AspNetCore.Authorization;
 using Hotline.Share.Dtos.Order;
 using Hotline.Tools;
 using XF.Domain.Authentications;
+using Hotline.Caching.Services;
 
 namespace Hotline.Api.Controllers
 {
@@ -37,7 +38,10 @@ namespace Hotline.Api.Controllers
         private readonly IMapper _mapper;
         private readonly IOptionsSnapshot<CallCenterConfiguration> _callcenterOptions;
         private readonly ISystemSettingCacheManager _systemSettingCacheManager;
-        private readonly IRepository<TelOperationXthx> _telOperationXthxRepository;
+        private readonly IRepository<TelOperationXthx> _telOperationXthxRepository; 
+        private readonly IUserCacheManager _userCacheManager;
+        private readonly ISessionContext _sessionContext;
+        private readonly IRepository<TelActionRecord> _telActionRecordRepository;
 
         public CallController(
             ICallApplication callApplication,
@@ -45,7 +49,10 @@ namespace Hotline.Api.Controllers
             IMapper mapper,
             IOptionsSnapshot<CallCenterConfiguration> callcenterOptions,
             ISystemSettingCacheManager systemSettingCacheManager,
-            IRepository<TelOperationXthx> telOperationXthxRepository)
+            IRepository<TelOperationXthx> telOperationXthxRepository,
+            IUserCacheManager userCacheManager,
+            ISessionContext sessionContext,
+            IRepository<TelActionRecord> telActionRecordRepository)
         {
             _callApplication = callApplication;
             _publisher = publisher;
@@ -53,6 +60,9 @@ namespace Hotline.Api.Controllers
             _callcenterOptions = callcenterOptions;
             _systemSettingCacheManager = systemSettingCacheManager;
             _telOperationXthxRepository = telOperationXthxRepository;
+            _userCacheManager = userCacheManager;
+            _sessionContext = sessionContext;
+            _telActionRecordRepository = telActionRecordRepository;
         }
 
         /// <summary>
@@ -115,6 +125,106 @@ namespace Hotline.Api.Controllers
         public Task SignOut(string telNo)
             => _callApplication.SingOutAsync(telNo, HttpContext.RequestAborted);
 
+        /// <summary>
+        /// 分机动作开始
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("call-action-record-begin")]
+        public async Task CallActionRecordBegin(int actionType)
+        {
+            var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
+
+            if (work is null)
+                throw UserFriendlyException.SameMessage("分机未签入,不能操作");
+
+            if (actionType == 0)//小休
+            {
+                var isResting = await _telActionRecordRepository.AnyAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, HttpContext.RequestAborted);
+                if (isResting)
+                    throw UserFriendlyException.SameMessage("当前坐席正在休息");
+                else
+                {
+                    var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, EActionType.TelRest);
+                    await _telActionRecordRepository.AddAsync(telAction, HttpContext.RequestAborted);
+                    work.OldExtensionStatus = work.ExtensionStatus;
+                    work.ExtensionStatus = EExtensionStatus.TelRest;
+                    _userCacheManager.SetWorkByUser(work);
+                }
+                return;
+            }
+
+            //判断如果已经存在未结束的该动作就不新增
+            var ishas = await _telActionRecordRepository.AnyAsync(x => x.TelNo == work.TelNo && x.ActionType == (EActionType)actionType && !x.EndTime.HasValue, HttpContext.RequestAborted);
+            if (!ishas)
+            {
+                var telAction = new TelActionRecord(work.UserId, work.UserName, work.TelNo, work.QueueId, (EActionType)actionType);
+                await _telActionRecordRepository.AddAsync(telAction, HttpContext.RequestAborted);
+            }
+            //动作写入成功,修改话机动作状态
+            work.OldExtensionStatus = work.ExtensionStatus;
+            switch (actionType)
+            {
+                case 1://整理
+                    work.ExtensionStatus = EExtensionStatus.Arrange;
+                    break;
+                case 2://保持
+                    work.ExtensionStatus = EExtensionStatus.Hold;
+                    break;
+                default:
+                    break;
+            }
+            _userCacheManager.SetWorkByUser(work);
+        }
+
+        /// <summary>
+        /// 分机动作结束
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("call-action-record-end")]
+        public async Task CallActionRecordEnd(int actionType)
+        {
+            var work = _userCacheManager.GetWorkByUser(_sessionContext.RequiredUserId);
+            if (work is null)
+                throw UserFriendlyException.SameMessage("分机未签入,不能操作");
+
+            if (actionType == 0)//小休
+            {
+                var telRest = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == EActionType.TelRest && !x.EndTime.HasValue, HttpContext.RequestAborted);
+                if (telRest is null)
+                    throw UserFriendlyException.SameMessage("未查询到分机休息信息");
+                else
+                {
+                    telRest.EndAction();
+                    await _telActionRecordRepository.UpdateAsync(telRest);
+                    work.OldExtensionStatus = work.ExtensionStatus;
+                    work.ExtensionStatus = EExtensionStatus.Ready;
+                    _userCacheManager.SetWorkByUser(work);
+                }
+                return;
+            }
+
+            var telAction = await _telActionRecordRepository.GetAsync(x => x.TelNo == work.TelNo && x.ActionType == (EActionType)actionType && !x.EndTime.HasValue, HttpContext.RequestAborted);
+            if (telAction != null)
+            {
+                telAction.EndAction();
+                await _telActionRecordRepository.UpdateAsync(telAction);
+            }
+            //动作结束成功,修改话机动作状态
+            work.OldExtensionStatus = work.ExtensionStatus;
+            switch (actionType)
+            {
+                case 1://整理
+                    work.ExtensionStatus = EExtensionStatus.Arrange;
+                    break;
+                case 2://保持
+                    work.ExtensionStatus = EExtensionStatus.Hold;
+                    break;
+                default:
+                    break;
+            }
+            _userCacheManager.SetWorkByUser(work);
+        }
+
         /// <summary>
         /// 查询当前用户的分机状态
         /// </summary>

+ 12 - 4
src/Hotline.Api/Controllers/CallNativeContrroller.cs

@@ -255,6 +255,7 @@ namespace Hotline.Api.Controllers
                 .WhereIF(!string.IsNullOrEmpty(dto.LogAction), p => p.LogAction == dto.LogAction)
                 .WhereIF(!string.IsNullOrEmpty(dto.UserName), p => p.CreatorName == dto.UserName)
                 .WhereIF(!string.IsNullOrEmpty(dto.PhoneNum), p => p.PhoneNum == dto.PhoneNum)
+                .OrderByDescending(p => p.CreationTime)
                 .ToPagedListAsync(dto, HttpContext.RequestAborted);
             return new PagedDto<WhiteBlackLog>(total, items);
         }
@@ -267,11 +268,18 @@ namespace Hotline.Api.Controllers
         [HttpGet("verify-white-list/{phone}")]
         public async Task<bool> VerifyWhiteList(string phone)
         {
-            var isEx = await _db.Queryable<XingtangWhitePhone>().Where(p => p.Phone == phone && p.ValidDateTime >= DateTime.Now).AnyAsync();
-            if (isEx)
-                return true;
-            else
+            try
+            {
+                var isEx = await _db.Queryable<XingtangWhitePhone>().Where(p => p.Phone == phone && p.ValidDateTime >= DateTime.Now).AnyAsync();
+                if (isEx)
+                    return true;
+                else
+                    return false;
+            }
+            catch (Exception)
+            {
                 return false;
+            }
         }
         #endregion
     }

+ 1 - 1
src/Hotline.Api/Controllers/FwThirdController.cs

@@ -533,7 +533,7 @@ namespace Hotline.Api.Controllers
                 .Where(p => p.IsPublic == true && p.Status == EKnowledgeStatus.OnShelf)
                 .WhereIF(!string.IsNullOrEmpty(dto.Title), p => p.Title.Contains(dto.Title))
                 .WhereIF(!string.IsNullOrEmpty(typeSpliceNameTags), p => SqlFunc.JsonArrayAny(p.Keywords, typeSpliceNameTags) == true)
-                .WhereIF(!string.IsNullOrEmpty(typeSpliceName), x => x.KnowledgeType.Any(t => t.KnowledgeTypeSpliceName.EndsWith("营商环境")))
+                .WhereIF(dto.KnowledgeType == 1, x => x.KnowledgeType.Any(t => t.KnowledgeTypeSpliceName.EndsWith("营商环境")))
                 .OrderByDescending(p => p.CreationTime)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 

+ 4 - 2
src/Hotline.Api/Controllers/HomeController.cs

@@ -212,7 +212,7 @@ public class HomeController : BaseController
             OldHotlineOrderState = _systemSettingCacheManager.GetSetting(SettingConstants.OldHotlineOrderState).SettingValue[0],
             FileExt = _systemSettingCacheManager.GetSetting(SettingConstants.FileExt).SettingValue[0],
             NationalPlatformWordLimit = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.NationalPlatformWordLimit).SettingValue[0]),
-            HandleOpinionWordLimit= int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.HandleOpinionWordLimit).SettingValue[0]),
+            HandleOpinionWordLimit = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.HandleOpinionWordLimit).SettingValue[0]),
             CallInOpenType = int.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.CallInOpenType).SettingValue[0]),
             Snapshot = _systemSettingCacheManager.Snapshot,
             IsTelRest = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsTelRest).SettingValue[0]),
@@ -224,7 +224,9 @@ public class HomeController : BaseController
             RecordDownLoadPrefix = _systemSettingCacheManager.GetSetting(SettingConstants.RecordDownLoadPrefix).SettingValue?.FirstOrDefault(),
             Luzhouhcp = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.LuZhouHaoChaPing).SettingValue[0]),
             LocationCenter = locationCenter,
-            IsEarly = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsEarly).SettingValue[0])
+            IsEarly = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsEarly).SettingValue[0]),
+            IsOpenWhiteList = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsOpenWhiteList).SettingValue[0])
+
         };
         return rsp;
     }

+ 2 - 4
src/Hotline.Api/Controllers/IdentityController.cs

@@ -125,12 +125,9 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <summary>
     /// 第三方登录
     /// </summary>
-    /// <param name=""></param>
-    /// <param name="_identityAppService"></param>
-    /// <param name=""></param>
-    /// <param name=""></param>
     /// <returns></returns>
     [AllowAnonymous]
+    [LogFilterAlpha("老系统微信用户登录")]
     [HttpPost("third/login")]
     public async Task<Dictionary<string, object>> GetThirdLoginAsync([FromBody] ThirdOpenIdInDto dto)
             => await _identityAppService.GetThredTokenAsync(dto, HttpContext.RequestAborted);
@@ -141,6 +138,7 @@ jxrWXHbT1FB6DqkdOnBbQqS1Azqz5HxLlSyEK3F60e3SgB5iZsDZ
     /// <param name="openId"></param>
     /// <returns></returns>
     [HttpGet("third/refresh")]
+    [LogFilterAlpha("微信用户刷新Token")]
     [AllowAnonymous]
     public async Task<Dictionary<string, object>> RefreshTokenAsync(string openId)
         => await _identityAppService.RefreshTokenAsync(openId, HttpContext.RequestAborted);

+ 10 - 3
src/Hotline.Api/Controllers/KnowledgeApplyController.cs

@@ -1,6 +1,5 @@
 using Hotline.Application.Knowledge;
 using Hotline.KnowledgeBase;
-using Hotline.Permissions;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Knowledge;
@@ -41,8 +40,14 @@ namespace Hotline.Api.Controllers
         /// <param name="userRepository"></param>
         /// <param name="systemOrganizeRepository"></param>
         /// <param name="knowledgeDomainService"></param>
-        public KnowledgeApplyController(IRepositoryWorkflow<Knowledge> knowledgeRepository, IRepository<KnowledgeApply> knowledgeApplyRepository, ISessionContext sessionContext
-            , IMapper mapper, IKnowApplication knowApplication, IRepository<User> userRepository, ISystemOrganizeRepository systemOrganizeRepository, IKnowledgeDomainService knowledgeDomainService)
+        public KnowledgeApplyController(IRepositoryWorkflow<Knowledge> knowledgeRepository,
+            IRepository<KnowledgeApply> knowledgeApplyRepository,
+            ISessionContext sessionContext
+            , IMapper mapper,
+            IKnowApplication knowApplication,
+            IRepository<User> userRepository,
+            ISystemOrganizeRepository systemOrganizeRepository,
+            IKnowledgeDomainService knowledgeDomainService)
         {
             _knowledgeRepository = knowledgeRepository;
             _knowledgeApplyRepository = knowledgeApplyRepository;
@@ -268,5 +273,7 @@ namespace Hotline.Api.Controllers
         }
 
         #endregion
+
+
     }
 }

+ 68 - 6
src/Hotline.Api/Controllers/KnowledgeCommonController.cs

@@ -1,9 +1,14 @@
-using Hotline.KnowledgeBase;
-using Hotline.Permissions;
+using Hotline.Application.Knowledge;
+using Hotline.KnowledgeBase;
+using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
+using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Knowledge;
+using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Requests;
+using Hotline.Tools;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
 using SqlSugar;
@@ -27,6 +32,7 @@ namespace Hotline.Api.Controllers
         private readonly ISessionContext _sessionContext;
         private readonly ISystemOrganizeRepository _systemOrganizeRepository;
         private readonly IRepository<Hotspot> _hotspotTypeRepository;
+        private readonly IKnowApplication _knowApplication;
 
         /// <summary>
         /// 
@@ -34,10 +40,19 @@ namespace Hotline.Api.Controllers
         /// <param name="knowledgeTypeRepository"></param>
         /// <param name="knowledgeTypeDomainService"></param>
         /// <param name="knowledgeStandardRepository"></param>
+        /// <param name="sessionContext"></param>
         /// <param name="mapper"></param>
-        public KnowledgeCommonController(IRepository<KnowledgeType> knowledgeTypeRepository, IKnowledgeTypeDomainService knowledgeTypeDomainService,
-            IRepository<KnowledgeStandard> knowledgeStandardRepository, ISessionContext sessionContext,
-            IMapper mapper, ISystemOrganizeRepository systemOrganizeRepository, IRepository<Hotspot> hotspotTypeRepository)
+        /// <param name="systemOrganizeRepository"></param>
+        /// <param name="hotspotTypeRepository"></param>
+        /// <param name="knowApplication"></param>
+        public KnowledgeCommonController(IRepository<KnowledgeType> knowledgeTypeRepository,
+            IKnowledgeTypeDomainService knowledgeTypeDomainService,
+            IRepository<KnowledgeStandard> knowledgeStandardRepository,
+            ISessionContext sessionContext,
+            IMapper mapper,
+            ISystemOrganizeRepository systemOrganizeRepository,
+            IRepository<Hotspot> hotspotTypeRepository,
+             IKnowApplication knowApplication)
         {
             _knowledgeTypeRepository = knowledgeTypeRepository;
             _knowledgeTypeDomainService = knowledgeTypeDomainService;
@@ -46,6 +61,7 @@ namespace Hotline.Api.Controllers
             _sessionContext = sessionContext;
             _systemOrganizeRepository = systemOrganizeRepository;
             _hotspotTypeRepository = hotspotTypeRepository;
+            _knowApplication = knowApplication;
         }
         #endregion
 
@@ -158,7 +174,7 @@ namespace Hotline.Api.Controllers
                      KnowledgeNum = SqlFunc.Subqueryable<Knowledge>()
                          .InnerJoin<KnowledgeRelationType>((k, krt) => k.Id == krt.KnowledgeId)
                          .InnerJoin<KnowledgeType>((k, krt, t) => krt.KnowledgeTypeId == t.Id)
-                         .Where((k, krt, t) => t.SpliceName.StartsWith(x.SpliceName) &&  k.IsDeleted == false && t.IsDeleted == false)
+                         .Where((k, krt, t) => t.SpliceName.StartsWith(x.SpliceName) && k.IsDeleted == false && t.IsDeleted == false)
                          .WhereIF(!string.IsNullOrEmpty(attribution) && !isCenter, (k, krt, t) => k.Attribution == attribution)
                          .WhereIF(status != null, k => k.Status == status)
                          .DistinctCount(k => k.Id)
@@ -318,5 +334,51 @@ namespace Hotline.Api.Controllers
         }
         #endregion
 
+        #region 知识超期未更新统计
+        /// <summary>
+        /// 知识超期未更新统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpGet("get-know-overdue-statistics-list")]
+        public async Task<PagedDto<KnowedgeStatisticsDto>> GetKnowOverdueStatisticsList([FromQuery] PagedKeywordRequest dto)
+        {
+            var (total, items) = await _knowApplication.GetKnowedgeStatistics(dto)
+                .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+            return new PagedDto<KnowedgeStatisticsDto>(total, items);
+        }
+
+        /// <summary>
+        ///知识超期未更新统计导出
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        [HttpPost("get-know-overdue-statistics-list-export")]
+        public async Task<FileStreamResult> GetKnowOverdueStatisticsListExport([FromBody] ExportExcelDto<PagedKeywordRequest> dto)
+        {
+            var query = _knowApplication.GetKnowedgeStatistics(dto.QueryDto);
+            List<KnowedgeStatisticsDto> data;
+            if (dto.IsExportAll)
+            {
+                data = await query.ToListAsync(HttpContext.RequestAborted);
+            }
+            else
+            {
+                var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted);
+                data = items;
+            }
+
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<KnowedgeStatisticsDto>(dto.ColumnInfos);
+
+            var dtos = data
+                .Select(stu => _mapper.Map(stu, typeof(KnowedgeStatisticsDto), dynamicClass))
+                .Cast<object>()
+                .ToList();
+
+            var stream = ExcelHelper.CreateStream(dtos);
+
+            return ExcelStreamResult(stream, "知识超期未更新统计");
+        }
+        #endregion
     }
 }

+ 40 - 39
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -7,17 +7,21 @@ using Hotline.Application.FlowEngine;
 using Hotline.Application.Knowledge;
 using Hotline.Application.Systems;
 using Hotline.Application.Tools;
+using Hotline.Caching.Interfaces;
+using Hotline.Configurations;
 using Hotline.File;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.Workflows;
 using Hotline.KnowledgeBase;
 using Hotline.KnowledgeBase.Notifies;
+using Hotline.Pdf;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Repository.SqlSugar.Ts;
 using Hotline.Settings;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Enums.Article;
@@ -30,18 +34,14 @@ using Mapster;
 using MapsterMapper;
 using MediatR;
 using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Options;
+using MiniExcelLibs;
 using SqlSugar;
 using System.Text;
-using Hotline.Configurations;
-using Microsoft.Extensions.Options;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
-using Hotline.Caching.Interfaces;
-using MiniExcelLibs;
-using Hotline.Pdf;
-using Hotline.Share.Dtos.FlowEngine.Workflow;
 
 namespace Hotline.Api.Controllers
 {
@@ -459,32 +459,32 @@ namespace Hotline.Api.Controllers
             await _knowledgeRepository.Updateable(kns)
                 .UpdateColumns(d => d.IsPublic)
                 .Where(d => d.Status == EKnowledgeStatus.OnShelf)
-				.ExecuteCommandAsync(HttpContext.RequestAborted);
-        }
-
-		/// <summary>
-		/// 批量下架
-		/// </summary>
-		/// <returns></returns>
-		[HttpPost("unshelve-batch")]
-		public async Task UnshelveBatch([FromBody] UnshelveBatchRequest request)
-		{
-			var kns = request.KnowledgeIds.Select(d => new Knowledge
-			{
-				Id = d,
-				Status = EKnowledgeStatus.OffShelf
-			}).ToList();
-			await _knowledgeRepository.Updateable(kns)
-				.UpdateColumns(d => d.Status)
-				.ExecuteCommandAsync(HttpContext.RequestAborted);
-		}
-
-
-		/// <summary>
-		/// 批量审核
-		/// </summary>
-		/// <returns></returns>
-		[HttpPost("batch_audit")]
+                .ExecuteCommandAsync(HttpContext.RequestAborted);
+        }
+
+        /// <summary>
+        /// 批量下架
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("unshelve-batch")]
+        public async Task UnshelveBatch([FromBody] UnshelveBatchRequest request)
+        {
+            var kns = request.KnowledgeIds.Select(d => new Knowledge
+            {
+                Id = d,
+                Status = EKnowledgeStatus.OffShelf
+            }).ToList();
+            await _knowledgeRepository.Updateable(kns)
+                .UpdateColumns(d => d.Status)
+                .ExecuteCommandAsync(HttpContext.RequestAborted);
+        }
+
+
+        /// <summary>
+        /// 批量审核
+        /// </summary>
+        /// <returns></returns>
+        [HttpPost("batch_audit")]
         public async Task<string> KnowledgeBatchAuditAsync([FromBody] KnowledgeBatchAuditInDto dto)
         {
             var result = new StringBuilder();
@@ -566,7 +566,7 @@ namespace Hotline.Api.Controllers
             var knowledge = await _knowledgeRepository.GetAsync(dto.Data.Id, HttpContext.RequestAborted);
             if (knowledge == null)
                 throw UserFriendlyException.SameMessage("无效知识库数据");
-            if ((knowledge.Status == EKnowledgeStatus.OnShelf  && knowledge.ExpiredTime >= DateTime.Now) || knowledge.Status == EKnowledgeStatus.Auditing)
+            if ((knowledge.Status == EKnowledgeStatus.OnShelf && knowledge.ExpiredTime >= DateTime.Now) || knowledge.Status == EKnowledgeStatus.Auditing)
                 throw UserFriendlyException.SameMessage("知识库数据不可删除");
             if (knowledge.Status == EKnowledgeStatus.Drafts || knowledge.Status == EKnowledgeStatus.Revert)
             {
@@ -640,7 +640,8 @@ namespace Hotline.Api.Controllers
             var query = _knowledgeRepository.Queryable()
                 .Where(x => x.Status == EKnowledgeStatus.OnShelf)
                 .Where(x => (x.ExpiredTime != null && x.ExpiredTime >= DateTime.Now) || x.ExpiredTime == null)
-                .OrderByDescending(x => x.SearchNum);
+                .OrderByIF(_appOptions.Value.IsZiGong == true, p => p.PageView, OrderByType.Desc)
+                .OrderByIF(_appOptions.Value.IsZiGong == false, p => p.SearchNum, OrderByType.Desc);
 
             if (_sessionContext.OrgIsCenter == false)
             {
@@ -698,7 +699,7 @@ namespace Hotline.Api.Controllers
             var knowledge = await _knowledgeRepository.Queryable()
                 .Includes(x => x.SourceOrganize)
                 .Includes(x => x.KnowledgeTypes)
-                .Includes(x=>x.KnowledgeOrganizes)
+                .Includes(x => x.KnowledgeOrganizes)
                 .Includes(x => x.HotspotType)
                 .FirstAsync(p => p.Id == Id, HttpContext.RequestAborted);
             if (knowledge is null)
@@ -752,8 +753,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("info/export")]
-		[LogFilterAlpha("导出日志")]
-		public async Task<IActionResult> KnowledgeInfoExport([FromBody] KnowledgeInfoExportInDto dto)
+        [LogFilterAlpha("导出日志")]
+        public async Task<IActionResult> KnowledgeInfoExport([FromBody] KnowledgeInfoExportInDto dto)
         {
             if (dto.Ids.Length > 1)
             {
@@ -1838,8 +1839,8 @@ namespace Hotline.Api.Controllers
         /// <param name="dto"></param>
         /// <returns></returns>
         [HttpPost("pageview/export")]
-		[LogFilterAlpha("导出日志")]
-		public async Task<FileStreamResult> GetPageViewListAsync([FromBody] ExportExcelDto<PageViewInDto> dto)
+        [LogFilterAlpha("导出日志")]
+        public async Task<FileStreamResult> GetPageViewListAsync([FromBody] ExportExcelDto<PageViewInDto> dto)
         {
             var items = (await _knowApplication.GetPageViewListAsync(dto.QueryDto, HttpContext.RequestAborted))
                 .Item2;

+ 4 - 35
src/Hotline.Api/Controllers/ObservationPieceController.cs

@@ -1,9 +1,4 @@
-using Hotline.Application.FlowEngine;
-using Hotline.Application.ObservationPiece;
-using Hotline.Application.OrderApp;
-using Hotline.Configurations;
-using Hotline.File;
-using Hotline.FlowEngine.Workflows;
+using Hotline.Application.ObservationPiece;
 using Hotline.Orders;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Share.Dtos;
@@ -12,7 +7,6 @@ using Hotline.Share.Dtos.Order;
 using Hotline.Tools;
 using MapsterMapper;
 using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Options;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
@@ -24,45 +18,20 @@ namespace Hotline.Api.Controllers
     {
         private readonly ISessionContext _sessionContext;
         private readonly IMapper _mapper;
-        private readonly IFileRepository _fileRepository;
-        private readonly IWorkflowApplication _workflowApplication;
-        private readonly IRepository<Workflow> _workflowRepository;
-        private readonly IWorkflowDomainService _workflowDomainService;
-        private readonly IOrderRepository _orderRepository;
-        private readonly IOrderDomainService _orderDomainService;
-        private readonly IOrderTerminateRepository _orderTerminateRepository;
-        private readonly IOrderApplication _orderApplication;
-        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
         private readonly IRepository<ObservationPiece> _observationPieceRepository;
         private readonly IObservationPieceApplication _observationPieceApplication;
 
         public ObservationPieceController(
             ISessionContext sessionContext,
             IMapper mapper,
-            IFileRepository fileRepository,
-            IWorkflowApplication workflowApplication,
-            IRepository<Workflow> workflowRepository,
-            IWorkflowDomainService workflowDomainService,
-            IOrderRepository orderRepository,
-            IOrderDomainService orderDomainService,
-            IOrderTerminateRepository orderTerminateRepository,
-            IOrderApplication orderApplication,
-            IOptionsSnapshot<AppConfiguration> appOptions,
-            IRepository<ObservationPiece> observationPieceRepository
+            IRepository<ObservationPiece> observationPieceRepository,
+             IObservationPieceApplication observationPieceApplication
             )
         {
             _sessionContext = sessionContext;
             _mapper = mapper;
-            _fileRepository = fileRepository;
-            _workflowApplication = workflowApplication;
-            _workflowRepository = workflowRepository;
-            _workflowDomainService = workflowDomainService;
-            _orderRepository = orderRepository;
-            _orderDomainService = orderDomainService;
-            _orderTerminateRepository = orderTerminateRepository;
-            _orderApplication = orderApplication;
-            _appOptions = appOptions;
             _observationPieceRepository = observationPieceRepository;
+            _observationPieceApplication = observationPieceApplication;
         }
 
         /// <summary>

+ 31 - 21
src/Hotline.Api/Controllers/OrderController.cs

@@ -2891,8 +2891,22 @@ public class OrderController : BaseController
     [HttpGet("delay/basedata")]
     public async Task<object> DelayBaseData()
     {
+        var delayStatisticalNodes = _systemSettingCacheManager.GetSetting(SettingConstants.DelayStatisticalNodes).SettingValue;
+        var delayStatisticalNodesList = new List<Kv>();
+        if (delayStatisticalNodes != null && delayStatisticalNodes.Any())
+        {
+            foreach (var item in delayStatisticalNodes)
+            {
+                delayStatisticalNodesList.Add(new Kv
+                {
+                    Key = item,
+                    Value = item
+                });
+            }
+        }
         var rsp = new
         {
+            DelayStatisticalNodes= delayStatisticalNodesList,
             DelayState = EnumExts.GetDescriptions<EDelayState>(),
             QueryDelayState = EnumExts.GetDescriptions<EQueryDelayState>(),
             TimeType = EnumExts.GetDescriptions<ETimeType>(),
@@ -3705,8 +3719,7 @@ public class OrderController : BaseController
         var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
         //查询部门所有账号
         var userlist = await _userRepository.Queryable().Where(x =>
-            x.OrgId == orgCode && !string.IsNullOrEmpty(x.PhoneNo) &&
-            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+            x.OrgId == orgCode && !string.IsNullOrEmpty(x.PhoneNo)).ToListAsync();
         if (userlist != null && userlist.Count > 0)
         {
             k.Key = userlist[0].Name;
@@ -3843,31 +3856,28 @@ public class OrderController : BaseController
                     {
                         #region 旅游督办短信内容
 
-                        var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
+                        //var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue;
                         //查询部门所有账号
-                        var userlist = await _userRepository.Queryable().Where(x =>
-                            x.OrgId == model.OrgId && x.PhoneNo == dto.PhoneNo &&
-                            x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
+                        //var userlist = await _userRepository.Queryable().Where(x =>
+                        //    x.OrgId == model.OrgId && x.PhoneNo == dto.PhoneNo &&
+                        //    x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync();
 
                         var Contact = !string.IsNullOrEmpty(order.FromPhone) ? order.FromPhone : order.Contact;
 
                         //发送短信
-                        if (userlist != null && userlist.Count > 0)
+                        var messageDto = new Share.Dtos.Push.MessageDto
                         {
-                            var messageDto = new Share.Dtos.Push.MessageDto
-                            {
-                                PushBusiness = EPushBusiness.OrderSupervise,
-                                ExternalId = order.Id,
-                                OrderId = order.Id,
-                                PushPlatform = EPushPlatform.Sms,
-                                Remark = order.Title,
-                                Name = userlist[0].Name,
-                                TemplateCode = "1022",
-                                Params = new List<string>() { dto.ApplyContent, order.No, Contact, order.Content },
-                                TelNumber = userlist[0].PhoneNo,
-                            };
-                            await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
-                        }
+                            PushBusiness = EPushBusiness.OrderSupervise,
+                            ExternalId = order.Id,
+                            OrderId = order.Id,
+                            PushPlatform = EPushPlatform.Sms,
+                            Remark = order.Title,
+                            Name = dto.PhoneNo,//userlist[0].Name,
+                            TemplateCode = "1022",
+                            Params = new List<string>() { dto.ApplyContent, order.No, Contact, order.Content },
+                            TelNumber = dto.PhoneNo,
+                        };
+                        await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted);
 
                         #endregion
                     }

+ 3 - 2
src/Hotline.Api/Controllers/SchedulingController.cs

@@ -468,13 +468,14 @@ namespace Hotline.Api.Controllers
         private ISugarQueryable<SchedulingStatisticsDto> GetList(PagedKeywordRequest dto)
         {
             return _schedulingRepository.Queryable()
+                     .Where(p => p.WorkingTime.ToString() != "00:00:00")
                     .WhereIF(dto.StartTime.HasValue, p => p.SchedulingTime >= dto.StartTime)
                     .WhereIF(dto.EndTime.HasValue, p => p.SchedulingTime <= dto.EndTime)
                     .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.SchedulingUserName == dto.Keyword)
-                    .GroupBy(p => p.SchedulingTime.Value.ToString("yyyy-MM-dd"))
+                    .GroupBy(p => new { Date=p.SchedulingTime.Value.ToString("yyyy-MM"), p.SchedulingUserName })
                     .Select(p => new SchedulingStatisticsDto
                     {
-                        Date = p.SchedulingTime.Value.ToString("yyyy-MM-dd"),
+                        Date = p.SchedulingTime.Value.ToString("yyyy-MM"),
                         UserName = p.SchedulingUserName,
                         Count = SqlFunc.AggregateCount(p.SchedulingUserName)
                     })

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

@@ -327,4 +327,13 @@ public class BiSnapshotController : BaseController
     [HttpGet("re_transact-statistics-detail")]
     public async Task<PagedDto<ReTransactStatisticsDetailsOutDto>> GetReTransactStatisticsDetailAsync([FromQuery] ReTransactStatisticsDetailsInDto dto)
         => (await _biSnapshotApplication.GetReTransactStatisticsDetail(dto).ToPagedListAsync(dto)).ToPaged();
+
+    /// <summary>
+    /// 随手拍区域积分统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("county_points")]
+    public async Task<IList<SnapshotCountyPointsStatisticsOutDto>> Get([FromQuery] SnapshotCountyPointsStatisticsInDto dto)
+        => await _biSnapshotApplication.GetAreaPointsStatistics(dto).ToListAsync(HttpContext.RequestAborted);
 }

+ 11 - 54
src/Hotline.Api/Controllers/Snapshot/SnapshotBulletinController.cs

@@ -15,6 +15,7 @@ using Hotline.Share.Tools;
 using XF.Utility.EnumExtensions;
 using Hotline.Snapshot.IRepository;
 using Hotline.Application.Snapshot.Contracts;
+using Hotline.Share.Dtos.Settings;
 
 namespace Hotline.Api.Controllers.Snapshot;
 
@@ -22,17 +23,17 @@ public class SnapshotBulletinController : BaseController
 {
     private readonly ISnapshotBulletinRepository _bulletinRepository;
     private readonly ISnapshotBulletinApplication _bulletinApplication;
-    private readonly ISessionContext _sessionContext;
     private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
     private readonly ISystemOrganizeRepository _organizeRepository;
+    private readonly ISafetyTypeRepository _safetyTypeRepository;
 
-    public SnapshotBulletinController(ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, ISystemDicDataCacheManager systemDicDataCacheManager, ISystemOrganizeRepository organizeRepository, ISnapshotBulletinApplication bulletinApplication)
+    public SnapshotBulletinController(ISnapshotBulletinRepository bulletinRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISystemOrganizeRepository organizeRepository, ISnapshotBulletinApplication bulletinApplication, ISafetyTypeRepository safetyTypeRepository)
     {
         _bulletinRepository = bulletinRepository;
-        _sessionContext = sessionContext;
         _systemDicDataCacheManager = systemDicDataCacheManager;
         _organizeRepository = organizeRepository;
         _bulletinApplication = bulletinApplication;
+        _safetyTypeRepository = safetyTypeRepository;
     }
 
     #region 公告
@@ -91,7 +92,6 @@ public class SnapshotBulletinController : BaseController
         await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
     }
 
-
     /// <summary>
     /// 公告审核
     /// </summary>
@@ -99,37 +99,7 @@ public class SnapshotBulletinController : BaseController
     /// <returns></returns>
     [HttpPost("bulletin/examine")]
     public async Task ExamineBulletin([FromBody] ExamineBulletinDto dto)
-    {
-        var bulletin = await _bulletinRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-        if (bulletin == null)
-            throw UserFriendlyException.SameMessage("无效数据");
-
-        if (bulletin.BulletinState != EBulletinState.InReview)
-            throw UserFriendlyException.SameMessage("当前状态不能审核");
-
-        if (dto.IsPass)
-        {
-            bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewPass;
-            bulletin.BulletinTime = DateTime.Now;
-            bulletin.ExaminOpinion = dto.Reason;
-            bulletin.ExaminTime = DateTime.Now;
-            bulletin.ExaminManId = _sessionContext.RequiredUserId;
-            await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
-            var publishBulletin = bulletin.Adapt<PublishBulletinDto>();
-
-            //await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlinePushBulletin, publishBulletin, cancellationToken: HttpContext.RequestAborted);
-
-            //todo await _bulletinService.PushBulletin(publishBulletin, HttpContext.RequestAborted);
-        }
-        else
-        {
-            bulletin.ExaminOpinion = dto.Reason;
-            bulletin.ExaminTime = DateTime.Now;
-            bulletin.ExaminManId = _sessionContext.RequiredUserId;
-            bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewNoPass;
-            await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
-        }
-    }
+        => await _bulletinApplication.ExamineBulletinAsync(dto, HttpContext.RequestAborted);
 
     /// <summary>
     /// 提交公告
@@ -138,18 +108,7 @@ public class SnapshotBulletinController : BaseController
     /// <returns></returns>
     [HttpGet("bulletin/commit")]
     public async Task CommitBulletin(string id)
-    {
-        var bulletin = await _bulletinRepository.GetAsync(id, HttpContext.RequestAborted);
-        if (bulletin == null)
-            throw UserFriendlyException.SameMessage("无效数据");
-
-        if (bulletin.BulletinState != EBulletinState.Draft && bulletin.BulletinState != EBulletinState.ReviewNoPass)
-            throw UserFriendlyException.SameMessage("当前状态不能提交");
-
-        bulletin.BulletinState = EBulletinState.InReview;
-        bulletin.CommitTime = DateTime.Now;
-        await _bulletinRepository.UpdateAsync(bulletin, HttpContext.RequestAborted);
-    }
+        => await _bulletinApplication.CommitBulletinAsync(id, HttpContext.RequestAborted);
 
     /// <summary>
     /// 修改公告
@@ -195,13 +154,7 @@ public class SnapshotBulletinController : BaseController
     /// <returns></returns>
     [HttpPost("bulletin/add")]
     public async Task AddBulletin([FromBody] AddSnapshotBulletinInDto dto)
-    {
-        var model = dto.Adapt<SnapshotBulletin>();
-        model.BulletinState = Share.Enums.Article.EBulletinState.Draft;
-        model.ReadedNum = 0;
-        if (model.BulletinTime.HasValue == false) model.BulletinTime = DateTime.Now;
-        await _bulletinRepository.AddAsync(model, HttpContext.RequestAborted);
-    }
+        => await _bulletinApplication.AddBulletinAsync(dto, HttpContext.RequestAborted);
 
     /// <summary>
     /// 列表页面基础数据
@@ -226,11 +179,15 @@ public class SnapshotBulletinController : BaseController
     [HttpGet("bulletin/addbasedata")]
     public async Task<object> BulletinAddBaseData()
     {
+        var safetyTypes = await _safetyTypeRepository.Queryable()
+            .Select(m => new SystemDicDataOutDto { Id =  m.Id, DicDataName = m.Name , DicDataValue = m.Id})
+            .ToListAsync(HttpContext.RequestAborted);
         var rsp = new
         {
             BulletinType = _systemDicDataCacheManager.SnapshotBulletinType,
             BulletinSource = _systemDicDataCacheManager.SnapshotBulletinSource,
             OrgsOptions = await _organizeRepository.GetOrgJson(),
+            SafetyTypes = safetyTypes
         };
         return rsp;
     }

+ 10 - 0
src/Hotline.Api/Controllers/Snapshot/SnapshotController.cs

@@ -373,6 +373,16 @@ public class SnapshotController : BaseController
             await _snapshotApplication.PostOrderGuiderSystemAsync(orderId, HttpContext.RequestAborted);
         }
     }
+
+    /// <summary>
+    /// 获取消息
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("notification")]
+    public async Task<IList<GetNotifyOutDto>> GetNotificationAsync([FromQuery] GetNotifyInDto dto)
+        => await _snapshotApplication.GetNotificationAsync(dto, HttpContext.RequestAborted);
+
     #region 积分
     /// <summary>
     /// 积分榜

+ 9 - 0
src/Hotline.Api/Controllers/Snapshot/SnapshotUserController.cs

@@ -62,4 +62,13 @@ public class SnapshotUserController : BaseController
     [HttpDelete("citizen_relation")]
     public async Task DeleteCitizenRelationSafetyType([FromBody] DeleteCitizenRelationSafetyTypeInDto dto)
         => await _snapshotUserApplication.DeleteCitizenRelationSafetyAsync(dto);
+
+    /// <summary>
+    /// 搜索安全志愿者
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [HttpGet("citizen")]
+    public async Task<PagedDto<GetThirdCitizenOutDto>> GetThirdCitizenAsync([FromQuery] GetThirdCitizenInDto dto)
+        => (await _snapshotUserApplication.GetThirdCitizenAsync(dto).ToPagedListAsync(dto)).ToPaged();
 }

+ 8 - 5
src/Hotline.Api/Controllers/SysController.cs

@@ -37,6 +37,8 @@ using XF.Domain.Exceptions;
 using XF.Domain.Repository;
 using XF.Utility.EnumExtensions;
 using Hotline.Tools;
+using Hotline.Share.Dtos.TrCallCenter;
+using Hotline.Share.Dtos.WebPortal;
 
 namespace Hotline.Api.Controllers
 {
@@ -599,14 +601,15 @@ namespace Hotline.Api.Controllers
         /// </summary>
         /// <returns></returns>
         [HttpGet("open-common")]
-        public async Task<PagedDto<SystemCommonOpinion>> QueryOpenCommonOpinionList([FromQuery] QueryCommonDto dto)
+        public async Task<PagedDto<SystemCommonOpinionDto>> QueryOpenCommonOpinionList([FromQuery] QueryCommonDto dto)
         {
             var (total, items) = await _commonOpinionRepository.Queryable()
                 .WhereIF(dto.IsOpen != null, x => x.IsOpen == dto.IsOpen)
                 .WhereIF(!string.IsNullOrEmpty(dto.UserName), x => x.CreatorName.Contains(dto.UserName))
                 .WhereIF(dto.CommonType != null, x => x.CommonType == dto.CommonType)
                 .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-            return new PagedDto<SystemCommonOpinion>(total, items);
+
+            return new PagedDto<SystemCommonOpinionDto>(total, _mapper.Map<IReadOnlyList<SystemCommonOpinionDto>>(items));
         }
 
         /// <summary>export
@@ -634,10 +637,10 @@ namespace Hotline.Api.Controllers
                 (total, items) = await query.ToPagedListAsync(dto.QueryDto.PageIndex, dto.QueryDto.PageSize, HttpContext.RequestAborted);
             }
 
-            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SystemCommonOpinion>(dto.ColumnInfos);
+            dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass<SystemCommonOpinionDto>(dto.ColumnInfos);
 
-            var dtos = _mapper.Map<ICollection<SystemCommonOpinion>>(items)
-                              .Select(stu => _mapper.Map(stu, typeof(SystemCommonOpinion), dynamicClass))
+            var dtos = _mapper.Map<ICollection<SystemCommonOpinionDto>>(items)
+                              .Select(stu => _mapper.Map(stu, typeof(SystemCommonOpinionDto), dynamicClass))
                               .Cast<object>()
                               .ToList();
 

+ 26 - 10
src/Hotline.Api/Controllers/SystemMobilAreaController.cs

@@ -33,6 +33,22 @@ namespace Hotline.Api.Controllers
             _systemMobilAreaApplication = systemMobilAreaApplication;
         }
 
+        /// <summary>
+        /// 基础信息
+        /// </summary>
+        /// <returns></returns>
+        [HttpGet("get-base-data")]
+        public async Task<List<Kv>> GetBaseData()
+        {
+            var data = new List<Kv>
+            {
+                new Kv() { Key = "1", Value = "中国电信" },
+                new Kv() { Key = "2", Value = "中国移动" },
+                new Kv() { Key = "3", Value = "中国联通" }
+            };
+            return data;
+        }
+
         /// <summary>
         /// 新增
         /// </summary>
@@ -41,15 +57,15 @@ namespace Hotline.Api.Controllers
         [HttpPost("add-system-mobil-area")]
         public async Task AddSystemMobilArea([FromBody] AddSystemMobilAreaDto dto)
         {
-            if (!string.IsNullOrEmpty(dto.TelCode))
+            if (string.IsNullOrEmpty(dto.TelCode))
                 throw UserFriendlyException.SameMessage("座机编号不能为空!");
-            if (!string.IsNullOrEmpty(dto.MobileCode))
+            if (string.IsNullOrEmpty(dto.MobileCode))
                 throw UserFriendlyException.SameMessage("手机编号不能为空!");
-            if (!string.IsNullOrEmpty(dto.MobileAreaName))
+            if (string.IsNullOrEmpty(dto.MobileAreaName))
                 throw UserFriendlyException.SameMessage("归属地不能为空!");
-            if (!string.IsNullOrEmpty(dto.OFlag))
+            if (string.IsNullOrEmpty(dto.OFlag))
                 throw UserFriendlyException.SameMessage("运营商不能为空!");
-            if (!string.IsNullOrEmpty(dto.OperatorName))
+            if (string.IsNullOrEmpty(dto.OperatorName))
                 throw UserFriendlyException.SameMessage("卡类型不能为空!");
 
             var data = await _systemMobilAreaRepository.AnyAsync(p => p.TelCode == dto.TelCode && p.MobileCode == dto.MobileCode && p.OFlag == p.OFlag, HttpContext.RequestAborted);
@@ -90,15 +106,15 @@ namespace Hotline.Api.Controllers
         [HttpPost("update-system-mobil-area")]
         public async Task UpdateSystemMobilAreaDetail([FromBody] UpdateSystemMobilAreaDto dto)
         {
-            if (!string.IsNullOrEmpty(dto.TelCode))
+            if (string.IsNullOrEmpty(dto.TelCode))
                 throw UserFriendlyException.SameMessage("座机编号不能为空!");
-            if (!string.IsNullOrEmpty(dto.MobileCode))
+            if (string.IsNullOrEmpty(dto.MobileCode))
                 throw UserFriendlyException.SameMessage("手机编号不能为空!");
-            if (!string.IsNullOrEmpty(dto.MobileAreaName))
+            if (string.IsNullOrEmpty(dto.MobileAreaName))
                 throw UserFriendlyException.SameMessage("归属地不能为空!");
-            if (!string.IsNullOrEmpty(dto.OFlag))
+            if (string.IsNullOrEmpty(dto.OFlag))
                 throw UserFriendlyException.SameMessage("运营商不能为空!");
-            if (!string.IsNullOrEmpty(dto.OperatorName))
+            if (string.IsNullOrEmpty(dto.OperatorName))
                 throw UserFriendlyException.SameMessage("卡类型不能为空!");
             var isCheack = await _systemMobilAreaRepository.AnyAsync(p => p.Id != dto.Id && p.TelCode == dto.TelCode
             && p.MobileCode == dto.MobileCode && p.OFlag == p.OFlag, HttpContext.RequestAborted);

+ 4 - 2
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -181,7 +181,8 @@ public class WorkflowController : BaseController
     /// </summary>
     /// <param name="dto"></param>
     /// <returns></returns>
-    [HttpGet("definition/export")]
+    [HttpPost("definition/export")]
+    [LogFilterAlpha("导出日志")]
     public async Task<FileStreamResult> QueryDefinitionsExport([FromBody] ExportExcelDto<QueryDefinitionDto> dto)
     {
         var query = _definitionRepository.Queryable()
@@ -328,7 +329,8 @@ public class WorkflowController : BaseController
     /// 查询所有工作流模块导出
     /// </summary>
     /// <returns></returns>
-    [HttpGet("wfmodules/export")]
+    [HttpPost("wfmodules/export")]
+    [LogFilterAlpha("导出日志")]
     public async Task<FileStreamResult> QueryWfModulesExport([FromBody] ExportExcelDto<QueryCommonDto> dto)
     {
         var items = await _wfModuleRepository.Queryable().Includes(d => d.Definition).ToListAsync(HttpContext.RequestAborted);

+ 2 - 2
src/Hotline.Api/config/appsettings.Development.json

@@ -68,13 +68,13 @@
     }
   },
     "ConnectionStrings": {
-        "Hotline": "PORT=5432;DATABASE=hotline;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
+        "Hotline": "PORT=5432;DATABASE=hotline_dev;HOST=110.188.24.182;PASSWORD=fengwo11!!;USER ID=dev;"
     },
   "Cache": {
     "Host": "110.188.24.182",
     "Port": 50179,
     "Password": "fengwo123!$!$",
-    "Database": 3 //hl:3, dev:5, test:2, demo:4
+    "Database": 5 //hl:3, dev:5, test:2, demo:4
   },
   "Swagger": true,
   "AccLog":  false,

+ 12 - 0
src/Hotline.Application/Exam/Service/Questions/QuestionService.cs

@@ -753,6 +753,10 @@ namespace Hotline.Application.Exam.Service.Questions
 
             actionRequest.QuestionSourcewareDtos.ResolveOperationStatus(all);
 
+            _addQuestionDto.QuestionSourcewareDtos = _mapper.Map<List<UpdateQuestionSourcewareDto>, List<AddQuestionSourcewareDto>>(actionRequest.QuestionSourcewareDtos);
+
+            _addQuestionDto.QuestionSourcewareDtos.ResolveOperationStatus();
+
             questionSourcewares.AddRangeExt(await AddSourcewares(_addQuestionDto, cancellationToken));
 
             questionSourcewares.AddRangeExt(await UpdateSourcewares(actionRequest, all, cancellationToken));
@@ -776,6 +780,10 @@ namespace Hotline.Application.Exam.Service.Questions
 
             actionRequest.QuestionKnowladgeDtos.ResolveOperationStatus(all);
 
+            _addQuestionDto.QuestionKnowladgeDtos = _mapper.Map<List<UpdateQuestionKnowladgeDto>, List<AddQuestionKnowladgeDto>>(actionRequest.QuestionKnowladgeDtos);
+
+            _addQuestionDto.QuestionKnowladgeDtos.ResolveOperationStatus();
+
             questionKnowladges.AddRangeExt(await AddKnowladges(_addQuestionDto, cancellationToken));
 
             questionKnowladges.AddRangeExt(await UpdateKnowladges(actionRequest, all, cancellationToken));
@@ -860,6 +868,8 @@ namespace Hotline.Application.Exam.Service.Questions
 
             actionRequest.QuestionOptionsDtos.ResolveOperationStatus(all);
 
+            _addQuestionDto.QuestionOptionsDtos = _mapper.Map<List<UpdateQuestionOptionsDto>, List<AddQuestionOptionsDto>>(actionRequest.QuestionOptionsDtos);
+
             _addQuestionDto.QuestionOptionsDtos.ResolveOperationStatus();
 
             questionOptions.AddRangeExt(await AddQuestionOptions(_addQuestionDto, cancellationToken));
@@ -885,6 +895,8 @@ namespace Hotline.Application.Exam.Service.Questions
 
             actionRequest.QuestionTagDtos.ResolveOperationStatus(all);
 
+            _addQuestionDto.QuestionTagDtos = _mapper.Map<List<UpdateQuestionTagDto>, List<AddQuestionTagDto>>(actionRequest.QuestionTagDtos);
+
             questionTags.AddRangeExt(await AddQuestionTags(_addQuestionDto, cancellationToken));
 
             questionTags.AddRangeExt(await UpdateQuestionTags(actionRequest, all, cancellationToken));

+ 9 - 0
src/Hotline.Application/Knowledge/IKnowApplication.cs

@@ -1,7 +1,9 @@
 using Hotline.KnowledgeBase;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Knowledge;
+using Hotline.Share.Requests;
 using Microsoft.AspNetCore.Mvc;
+using SqlSugar;
 
 namespace Hotline.Application.Knowledge
 {
@@ -77,5 +79,12 @@ namespace Hotline.Application.Knowledge
         /// <param name="dto"></param>
         /// <returns></returns>
         Task<(int, List<KnowledgeRetrievalDataDto>)> KnowRetrievalAsync(KnowledgeRetrievalPagedListDto dto);
+
+        /// <summary>
+        /// 知识超期未更新统计
+        /// </summary>
+        /// <param name="dto"></param>
+        /// <returns></returns>
+        ISugarQueryable<KnowedgeStatisticsDto> GetKnowedgeStatistics(PagedKeywordRequest dto);
     }
 }

+ 22 - 8
src/Hotline.Application/Knowledge/KnowApplication.cs

@@ -1,23 +1,17 @@
-using DocumentFormat.OpenXml.EMMA;
-using Hotline.Application.Tools;
+using Hotline.Application.Tools;
 using Hotline.Configurations;
 using Hotline.KnowledgeBase;
 using Hotline.Pdf;
 using Hotline.Repository.SqlSugar.Extensions;
-using Hotline.Settings;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Knowledge;
-using Hotline.Share.Enums.Article;
 using Hotline.Share.Enums.KnowledgeBase;
+using Hotline.Share.Requests;
 using Hotline.Share.Tools;
-using Hotline.Users;
 using Mapster;
 using MapsterMapper;
-using Microsoft.AspNetCore.Http;
-using Microsoft.AspNetCore.Mvc;
 using Microsoft.Extensions.Options;
-using Org.BouncyCastle.Utilities.IO;
 using PanGu;
 using SqlSugar;
 using XF.Domain.Authentications;
@@ -521,5 +515,25 @@ namespace Hotline.Application.Knowledge
             }
             return await sugar.Select<KnowledgeRetrievalDataDto>().ToPagedListAsync(dto.PageIndex, dto.PageSize);
         }
+
+        public ISugarQueryable<KnowedgeStatisticsDto> GetKnowedgeStatistics(PagedKeywordRequest dto)
+        {
+            return _knowledgeRepository.Queryable()
+                    .Includes(p => p.SourceOrganize)
+                    .WhereIF(dto.StartTime.HasValue, p => p.LastModificationTime >= dto.StartTime)
+                    .WhereIF(dto.EndTime.HasValue, p => p.LastModificationTime <= dto.EndTime)
+                    .WhereIF(!string.IsNullOrEmpty(dto.Keyword), p => p.SourceOrganize.Name.Contains(dto.Keyword))
+                  //  .GroupBy(p => new { p.SourceOrganize.Name, p.LastModificationTime })
+                    .Select(p => new KnowedgeStatisticsDto
+                    {
+                       // Index = SqlFunc.RowNumber($"{p.LastModificationTime} desc "),\
+                       Index= SqlFunc.RowNumber($"{p.LastModificationTime} desc ", $"{p.SourceOrganize.Name}"),
+                        LastModificationTime = p.LastModificationTime,
+                        OrgName = p.SourceOrganize.Name
+                    })
+                    .MergeTable()
+                    .Where(p => p.Index == 1)
+                    .OrderByDescending(p => p.LastModificationTime);
+        }
     }
 }

+ 5 - 40
src/Hotline.Application/ObservationPiece/ObservationPieceApplication.cs

@@ -1,12 +1,4 @@
-using Hotline.Application.FlowEngine;
-using Hotline.Application.OrderApp;
-using Hotline.Configurations;
-using Hotline.File;
-using Hotline.FlowEngine.Workflows;
-using Hotline.Orders;
-using Hotline.Share.Dtos.ObservationPiece;
-using MapsterMapper;
-using Microsoft.Extensions.Options;
+using Hotline.Share.Dtos.ObservationPiece;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
@@ -17,44 +9,14 @@ namespace Hotline.Application.ObservationPiece
     public class ObservationPieceApplication : IObservationPieceApplication, IScopeDependency
     {
         private readonly ISessionContext _sessionContext;
-        private readonly IMapper _mapper;
-        private readonly IFileRepository _fileRepository;
-        private readonly IWorkflowApplication _workflowApplication;
-        private readonly IRepository<Workflow> _workflowRepository;
-        private readonly IWorkflowDomainService _workflowDomainService;
-        private readonly IOrderRepository _orderRepository;
-        private readonly IOrderDomainService _orderDomainService;
-        private readonly IOrderTerminateRepository _orderTerminateRepository;
-        private readonly IOrderApplication _orderApplication;
-        private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
         private readonly IRepository<Hotline.Orders.ObservationPiece> _observationPieceRepository;
 
         public ObservationPieceApplication(
             ISessionContext sessionContext,
-            IMapper mapper,
-            IFileRepository fileRepository,
-            IWorkflowApplication workflowApplication,
-            IRepository<Workflow> workflowRepository,
-            IWorkflowDomainService workflowDomainService,
-            IOrderRepository orderRepository,
-            IOrderDomainService orderDomainService,
-            IOrderTerminateRepository orderTerminateRepository,
-            IOrderApplication orderApplication,
-            IOptionsSnapshot<AppConfiguration> appOptions,
             IRepository<Hotline.Orders.ObservationPiece> observationPieceRepository
             )
         {
             _sessionContext = sessionContext;
-            _mapper = mapper;
-            _fileRepository = fileRepository;
-            _workflowApplication = workflowApplication;
-            _workflowRepository = workflowRepository;
-            _workflowDomainService = workflowDomainService;
-            _orderRepository = orderRepository;
-            _orderDomainService = orderDomainService;
-            _orderTerminateRepository = orderTerminateRepository;
-            _orderApplication = orderApplication;
-            _appOptions = appOptions;
             _observationPieceRepository = observationPieceRepository;
         }
 
@@ -98,6 +60,8 @@ namespace Hotline.Application.ObservationPiece
                 .WhereIF(dto.Type == "1" && dto.DataSoure == "1", p => p.ObserveOrgId == _sessionContext.RequiredOrgId)
                 .Select(p => new ObservationPieceListDto
                 {
+                    Id = p.Id,
+                    OrderId = p.OrderId,
                     No = p.No,
                     Title = p.Order.Title,
                     AcceptType = p.Order.AcceptType,
@@ -119,7 +83,6 @@ namespace Hotline.Application.ObservationPiece
                 })
                 .OrderByIF(dto.Type == "1", p => p.ReplyTime, OrderByType.Desc)
                 .OrderByIF(dto.Type == "0", p => p.CreationTime, OrderByType.Desc);
-
             return query;
         }
 
@@ -160,6 +123,8 @@ namespace Hotline.Application.ObservationPiece
 
                 .Select(p => new ObservationPieceListDto
                 {
+                    Id = p.Id,
+                    OrderId = p.OrderId,
                     No = p.No,
                     Title = p.Order.Title,
                     AcceptType = p.Order.AcceptType,

+ 13 - 12
src/Hotline.Application/OrderApp/OrderApplication.cs

@@ -3648,6 +3648,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
         var query = _orderRepository.UnionAll(query1, query2, query3, query4)
                                     .LeftJoin<User>((x, y) => x.UserId == y.Id)
                                     .GroupBy((x, y) => new { x.UserId, y.Name })
+                                    .Where((x, y) => y.OrgId == OrgSeedData.CenterId)
                                     .Select((x, y) => new OrderVolumeDataListVo
                                     {
                                         UserId = x.UserId,
@@ -5625,17 +5626,17 @@ public class OrderApplication : IOrderApplication, IScopeDependency
     /// <returns></returns>
     public async Task<List<SendOrderReportOutDto>> SendOrderReportAsync_LZ(QuerySendOrderRequest dto)
     {
-		var itemsHandled = _workflowTraceRepository.Queryable()
-			   .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
-			   .Where((x, w) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.Status == EWorkflowStepStatus.Handled && !SqlFunc.JsonListObjectAny(x.NextHandlers, "OrgId", OrgSeedData.CenterId) && (x.Name =="派单组" || x.Name == "班长审批"))
-			   .Where((x, w) => x.HandleTime >= dto.StartTime.Value)
-			   .Where((x, w) => x.HandleTime <= dto.EndTime.Value)
-			   .WhereIF(!string.IsNullOrEmpty(dto.UserName), (x, w) => x.HandlerName == dto.UserName)
-			   .GroupBy((x, w) => new { x.HandlerId,x.HandlerName,x.Name})
-			   .Select((x, w) => new BiOrderSendVo
-			   {
-				   UserId = x.HandlerId,
-				   UserName = x.HandlerName,
+        var itemsHandled = _workflowTraceRepository.Queryable()
+               .LeftJoin<Workflow>((x, w) => x.WorkflowId == w.Id)
+               .Where((x, w) => w.ModuleCode == WorkflowModuleConsts.OrderHandle && x.Status == EWorkflowStepStatus.Handled && !SqlFunc.JsonListObjectAny(x.NextHandlers, "OrgId", OrgSeedData.CenterId) && (x.Name == "派单组" || x.Name == "班长审批"))
+               .Where((x, w) => x.HandleTime >= dto.StartTime.Value)
+               .Where((x, w) => x.HandleTime <= dto.EndTime.Value)
+               .WhereIF(!string.IsNullOrEmpty(dto.UserName), (x, w) => x.HandlerName == dto.UserName)
+               .GroupBy((x, w) => new { x.HandlerId, x.HandlerName, x.Name })
+               .Select((x, w) => new BiOrderSendVo
+               {
+                   UserId = x.HandlerId,
+                   UserName = x.HandlerName,
                    StepName = x.Name,
                    SendOrderNum = SqlFunc.AggregateDistinctCount(w.ExternalId),
                    NoSendOrderNum = 0,
@@ -5743,7 +5744,7 @@ public class OrderApplication : IOrderApplication, IScopeDependency
                 .Where((x, su) => x.ModuleCode == WorkflowModuleConsts.OrderHandle && x.BusinessType == EBusinessType.Send)
                 .Where((x, su) => x.CreationTime >= dto.StartTime.Value && x.CreationTime <= dto.EndTime.Value && su.UserId == dto.UserId)
                 .WhereIF(dto.TitleCode.ToUpper() == "NOSENDORDERNUM", (x, su) => x.Status != EWorkflowStepStatus.Handled)
-                .WhereIF(dto.TitleCode.ToUpper() == "SENDORDERNUM", (x, su) => x.Status == EWorkflowStepStatus.Handled )
+                .WhereIF(dto.TitleCode.ToUpper() == "SENDORDERNUM", (x, su) => x.Status == EWorkflowStepStatus.Handled)
                 .GroupBy((x, su) => x.ExternalId)
                 .Select((x, su) => new { Id = x.ExternalId })
                 .MergeTable()

+ 24 - 2
src/Hotline.Application/Snapshot/BiSnapshotApplication.cs

@@ -5,6 +5,7 @@ using Hotline.Settings;
 using Hotline.Settings.Hotspots;
 using Hotline.Share.Attributes;
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Order;
 using Hotline.Share.Enums.Snapshot;
@@ -36,8 +37,9 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
     private readonly ICommunityInfoRepository _communityInfoRepository;
     private readonly IRepository<SystemArea> _systemAreaRepository;
     private readonly IOptionsSnapshot<AppConfiguration> _appOptions;
+    private readonly ISnapshotPointsRecordRepository _snapshotPointsRecordRepository;
 
-    public BiSnapshotApplication(IOrderSnapshotRepository orderSnapshotRepository, IRedPackRecordRepository redPackRecordRepository, IIndustryRepository industryRepository, IIndustryCaseRepository industryCaseRepository, IRedPackAuditRepository redPackAuditRepository, IRepository<Hotspot> hotspotTypeRepository, ISessionContext sessionContext, IOrderRepository orderRepository, ICommunityInfoRepository communityInfoRepository, IRepository<SystemArea> systemAreaRepository, IOptionsSnapshot<AppConfiguration> appOptions)
+    public BiSnapshotApplication(IOrderSnapshotRepository orderSnapshotRepository, IRedPackRecordRepository redPackRecordRepository, IIndustryRepository industryRepository, IIndustryCaseRepository industryCaseRepository, IRedPackAuditRepository redPackAuditRepository, IRepository<Hotspot> hotspotTypeRepository, ISessionContext sessionContext, IOrderRepository orderRepository, ICommunityInfoRepository communityInfoRepository, IRepository<SystemArea> systemAreaRepository, IOptionsSnapshot<AppConfiguration> appOptions, ISnapshotPointsRecordRepository snapshotPointsRecordRepository)
     {
         _orderSnapshotRepository = orderSnapshotRepository;
         _redPackRecordRepository = redPackRecordRepository;
@@ -50,6 +52,7 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
         _communityInfoRepository = communityInfoRepository;
         _systemAreaRepository = systemAreaRepository;
         _appOptions = appOptions;
+        _snapshotPointsRecordRepository = snapshotPointsRecordRepository;
     }
 
     public ISugarQueryable<HotspotStatisticsOutDto> GetHotspotStatistics(HotspotStatisticsInDto dto)
@@ -734,7 +737,7 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
             .LeftJoin<OrderSendBackAudit>((snapshot, order, back) => snapshot.Id == back.OrderId && back.State == ESendBackAuditState.End)
             .LeftJoin<OrderVisit>((snapshot, order, back, visit) => snapshot.Id == visit.OrderId && visit.VisitState == EVisitState.Visited)
             .LeftJoin<OrderSecondaryHandling>((snapshot, order, back, visit, second) => snapshot.Id == second.OrderId && second.State == ESecondaryHandlingState.End)
-            .Where((snapshot, order) => snapshot.CreationTime >= dto.StartTime && snapshot.CreationTime <= dto.EndTime 
+            .Where((snapshot, order) => snapshot.CreationTime >= dto.StartTime && snapshot.CreationTime <= dto.EndTime
             && order.ActualHandleOrgCode != null && order.ActualHandleOrgCode != "001")
             .GroupBy((snapshot, order) => new
             {
@@ -972,4 +975,23 @@ public class BiSnapshotApplication : IBiSnapshotApplication, IScopeDependency
             .Select((snapshot, order) => new IndustryStatisticsDetailsOutDto(), true);
         return query;
     }
+
+    public ISugarQueryable<SnapshotCountyPointsStatisticsOutDto> GetAreaPointsStatistics(SnapshotCountyPointsStatisticsInDto dto)
+    {
+        var query = _snapshotPointsRecordRepository.Queryable(includeDeleted: true)
+            .LeftJoin<Order>((points, order) => points.OrderId == order.Id)
+            .Where((points, order) => order.CreationTime >= dto.StartTime && order.CreationTime <= dto.EndTime && order.County != "" && order.County != null)
+            .GroupBy((points, order) => order.County)
+            .Select((points, order) => new SnapshotCountyPointsStatisticsOutDto
+            {
+                CountyName = order.County,
+                Points = SqlFunc.AggregateSum(SqlFunc.IIF(points.Direction == EPointsDirection.In, points.Points, 0)),
+                ExchangePoints = SqlFunc.AggregateSum(SqlFunc.IIF(points.Source == EPointsSource.Exchange, points.Points, 0)),
+            });
+#if DEBUG
+        var sql = query.ToSqlString();
+#endif
+        return query;
+    }
+
 }

+ 7 - 0
src/Hotline.Application/Snapshot/Contracts/IBiSnapshotApplication.cs

@@ -111,4 +111,11 @@ public interface IBiSnapshotApplication
     /// <param name="dto"></param>
     /// <returns></returns>
     ISugarQueryable<IndustryStatisticsDetailsOutDto> GetIndustryStatisticsDetails(IndustryStatisticsDetailsInDto dto);
+
+    /// <summary>
+    /// 区域积分统计
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<SnapshotCountyPointsStatisticsOutDto> GetAreaPointsStatistics(SnapshotCountyPointsStatisticsInDto dto);
 }

+ 11 - 0
src/Hotline.Application/Snapshot/Contracts/INotificationApplication.cs

@@ -0,0 +1,11 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Snapshot.Contracts;
+
+public interface INotificationApplication
+{
+}

+ 2 - 0
src/Hotline.Application/Snapshot/Contracts/ISnapshotApplication.cs

@@ -233,4 +233,6 @@ public interface ISnapshotApplication
     /// <param name="requestAborted"></param>
     /// <returns></returns>
     Task<int> GetPointsTotalAsync(PointItemsInDto dto, CancellationToken requestAborted);
+
+    Task<IList<GetNotifyOutDto>> GetNotificationAsync(GetNotifyInDto dto, CancellationToken requestAborted);
 }

+ 26 - 1
src/Hotline.Application/Snapshot/Contracts/ISnapshotBulletinApplication.cs

@@ -1,4 +1,5 @@
-using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Dtos.Article;
+using Hotline.Share.Dtos.Snapshot;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -9,6 +10,29 @@ using System.Threading.Tasks;
 namespace Hotline.Application.Snapshot.Contracts;
 public interface ISnapshotBulletinApplication
 {
+    /// <summary>
+    /// 新增公告
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="requestAborted"></param>
+    /// <returns></returns>
+    Task<string> AddBulletinAsync(AddSnapshotBulletinInDto dto, CancellationToken requestAborted);
+
+    /// <summary>
+    /// 审核公告
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <param name="requestAborted"></param>
+    /// <returns></returns>
+    Task ExamineBulletinAsync(ExamineBulletinDto dto, CancellationToken requestAborted);
+
+    /// <summary>
+    /// 发送通知公告
+    /// </summary>
+    /// <param name="bullutionId"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task NotifyUserAsync(string bullutionId, CancellationToken token);
 
     /// <summary>
     /// 处理通知公告图片附件路径
@@ -17,4 +41,5 @@ public interface ISnapshotBulletinApplication
     /// <returns></returns>
     string GetSiteUrls(string sHtmlText);
     ISugarQueryable<SnapshotBulletinItemsOutDto> QueryBulletinItems(SnapshotBulletinItemsInDto dto);
+    Task CommitBulletinAsync(string id, CancellationToken requestAborted);
 }

+ 7 - 0
src/Hotline.Application/Snapshot/Contracts/ISnapshotUserApplication.cs

@@ -21,4 +21,11 @@ public interface ISnapshotUserApplication
     /// <param name="dto"></param>
     /// <returns></returns>
     Task DeleteCitizenRelationSafetyAsync(DeleteCitizenRelationSafetyTypeInDto dto);
+
+    /// <summary>
+    /// 获取第三方市民列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    ISugarQueryable<GetThirdCitizenOutDto> GetThirdCitizenAsync(GetThirdCitizenInDto dto);
 }

File diff suppressed because it is too large
+ 0 - 0
src/Hotline.Application/Snapshot/DefaultSnapshotApplication.cs


+ 12 - 0
src/Hotline.Application/Snapshot/NotificationApplication.cs

@@ -0,0 +1,12 @@
+using Hotline.Application.Snapshot.Contracts;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Application.Snapshot;
+
+public class NotificationApplication : INotificationApplication
+{
+}

+ 15 - 1
src/Hotline.Application/Snapshot/Notifications/SnapshotHandler.cs

@@ -38,10 +38,12 @@ namespace Hotline.Application.Snapshot.Notifications;
 public class SnapshotHandler : ICapSubscribe, IScopeDependency
 {
     private readonly ISnapshotApplication _snapshotApplication;
+    private readonly ISnapshotBulletinApplication _snapshotBulletinApplication;
 
-    public SnapshotHandler(ISnapshotApplication snapshotApplication)
+    public SnapshotHandler(ISnapshotApplication snapshotApplication, ISnapshotBulletinApplication snapshotBulletinApplication)
     {
         _snapshotApplication = snapshotApplication;
+        _snapshotBulletinApplication = snapshotBulletinApplication;
     }
 
     /// <summary>
@@ -55,6 +57,18 @@ public class SnapshotHandler : ICapSubscribe, IScopeDependency
     {
         await _snapshotApplication.GuiderSystemReplyDelayAsync(message.OrderId, cancellationToken);
     }
+
+    /// <summary>
+    /// 通知公告审核通过
+    /// </summary>
+    /// <param name="bulletinId"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    [CapSubscribe(EventNames.BulletinIsPass, Group = "snapshot")]
+    public async Task BulletinIsPassHandler(string bulletinId, CancellationToken token)
+    {
+        await _snapshotBulletinApplication.NotifyUserAsync(bulletinId, token);
+    }
 }
 
 /// <summary>

+ 17 - 1
src/Hotline.Application/Snapshot/SnapshotApplicationBase.cs

@@ -87,8 +87,9 @@ public abstract class SnapshotApplicationBase
     private readonly ICitizenRepository _citizenRepository;
     private readonly ISnapshotPointsRecordRepository _pointsRecordRepository;
     private readonly IOptionsSnapshot<MqConfiguration> _mqConfiguration;
+    private readonly INotificationReceiverRepository _notificationReceiverRepository;
 
-    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRedPackRecordRepository redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IInviteCodeRecordRepository inviteCodeRecordRepository, IInviteCodeRepository inviteCodeRepository, ICitizenRepository citizenRepository, ISnapshotPointsRecordRepository snapshotPointsRecordRepository, IOptionsSnapshot<MqConfiguration> mqConfiguration)
+    public SnapshotApplicationBase(IThirdIdentiyService thirdLoginService, IIndustryRepository industryRepository, ISnapshotBulletinRepository bulletinRepository, ISessionContext sessionContext, IRedPackRecordRepository redPackRecordRepository, IRepository<Order> orderRepository, IThirdAccountRepository thirdAccountRepository, IOrderSnapshotRepository orderSnapshotRepository, ISystemSettingCacheManager systemSettingCacheManager, ISystemAreaDomainService systemAreaDomainService, IFileRepository fileRepository, ISystemDicDataCacheManager systemDicDataCacheManager, ISnapshotOrderPublishRepository snapshotOrderPublishRepository, IRepository<WorkflowTrace> workflowTraceRepository, IPractitionerRepository practitionerRepository, IRepository<SystemArea> systemAreaRepository, IVolunteerRepository volunteerRepository, IVolunteerReportRepository volunteerReportRepository, ISystemLogRepository systemLog, IGuiderSystemService guiderSystemService, ICapPublisher capPublisher, Publisher publisher, IFileDomainService fileDomainService, ICommunityInfoRepository communityInfoRepository, IRedPackAuditRepository redPackAuditRepository, IOrderVisitRepository orderVisitRepository, IOrderVisitDetailRepository orderVisitDetailRepository, IRedPackGuiderAuditRepository redPackGuiderAuditRepository, IInviteCodeRecordRepository inviteCodeRecordRepository, IInviteCodeRepository inviteCodeRepository, ICitizenRepository citizenRepository, ISnapshotPointsRecordRepository snapshotPointsRecordRepository, IOptionsSnapshot<MqConfiguration> mqConfiguration, INotificationReceiverRepository notificationReceiverRepository)
     {
         _thirdLoginService = thirdLoginService;
         _industryRepository = industryRepository;
@@ -123,6 +124,7 @@ public abstract class SnapshotApplicationBase
         _citizenRepository = citizenRepository;
         _pointsRecordRepository = snapshotPointsRecordRepository;
         _mqConfiguration = mqConfiguration;
+        _notificationReceiverRepository = notificationReceiverRepository;
     }
 
     #region 小程序
@@ -392,6 +394,20 @@ public abstract class SnapshotApplicationBase
             .SumAsync(m => m.Points);
     }
 
+    public async Task<IList<GetNotifyOutDto>> GetNotificationAsync(GetNotifyInDto dto, CancellationToken requestAborted)
+    {
+        var items = await _notificationReceiverRepository.Queryable()
+            .LeftJoin<Notification>((m , notify) => m.NotificationId == notify.Id)
+            .Where(m => m.ReceiverId == _sessionContext.UserId)
+            .Select((m, notify) => new GetNotifyOutDto 
+            {
+                NotificationId = m.NotificationId,
+                Title = notify.Title ,
+                CreationTime = m.CreationTime
+            }, true)
+            .ToFixedListAsync(dto, requestAborted);
+        return items;
+    }
 
     /// <summary>
     /// 获取工单详情

+ 109 - 2
src/Hotline.Application/Snapshot/SnapshotBulletinApplication.cs

@@ -1,9 +1,19 @@
-using Hotline.Application.Snapshot.Contracts;
+using DocumentFormat.OpenXml.Vml.Office;
+using DotNetCore.CAP;
+using Hotline.Application.Snapshot.Contracts;
 using Hotline.Caching.Interfaces;
+using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Attributes;
+using Hotline.Share.Dtos.Article;
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.Article;
+using Hotline.Share.Enums.Snapshot;
+using Hotline.Share.Tools;
+using Hotline.Snapshot;
+using Hotline.Snapshot.Contracts;
 using Hotline.Snapshot.IRepository;
+using Mapster;
 using Microsoft.AspNetCore.Http;
 using SqlSugar;
 using System;
@@ -12,7 +22,9 @@ using System.Linq;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading.Tasks;
+using XF.Domain.Authentications;
 using XF.Domain.Dependency;
+using XF.Domain.Exceptions;
 
 namespace Hotline.Application.Snapshot;
 public class SnapshotBulletinApplication : ISnapshotBulletinApplication, IScopeDependency
@@ -20,11 +32,81 @@ public class SnapshotBulletinApplication : ISnapshotBulletinApplication, IScopeD
 
     private readonly ISystemSettingCacheManager _systemSettingCacheManager;
     private readonly ISnapshotBulletinRepository _bulletinRepository;
+    private readonly INotificationDomainService _notificationDomainService;
+    private readonly ISessionContext _sessionContext;
+    private readonly ISafetyTypeRepository _safetyTypeRepository;
+    private readonly ICapPublisher _capPublisher;
 
-    public SnapshotBulletinApplication(ISystemSettingCacheManager systemSettingCacheManager, ISnapshotBulletinRepository bulletinRepository)
+    public SnapshotBulletinApplication(ISystemSettingCacheManager systemSettingCacheManager, ISnapshotBulletinRepository bulletinRepository, INotificationDomainService notificationDomainService, ISessionContext sessionContext, ISafetyTypeRepository safetyTypeRepository, ICapPublisher capPublisher)
     {
         _systemSettingCacheManager = systemSettingCacheManager;
         _bulletinRepository = bulletinRepository;
+        _notificationDomainService = notificationDomainService;
+        _sessionContext = sessionContext;
+        _safetyTypeRepository = safetyTypeRepository;
+        _capPublisher = capPublisher;
+    }
+
+    public async Task ExamineBulletinAsync(ExamineBulletinDto dto, CancellationToken token)
+    {
+        var bulletin = await _bulletinRepository.GetAsync(dto.Id, token)
+            ?? throw UserFriendlyException.SameMessage("无效数据");
+        if (bulletin.BulletinState != EBulletinState.InReview)
+            throw UserFriendlyException.SameMessage("当前状态不能审核");
+
+        if (dto.IsPass == false)
+        {
+            bulletin.ExaminOpinion = dto.Reason;
+            bulletin.ExaminTime = DateTime.Now;
+            bulletin.ExaminManId = _sessionContext.RequiredUserId;
+            bulletin.BulletinState = EBulletinState.ReviewNoPass;
+            await _bulletinRepository.UpdateAsync(bulletin, token);
+            return;
+        }
+
+        bulletin.BulletinState = EBulletinState.ReviewPass;
+        bulletin.BulletinTime = DateTime.Now;
+        bulletin.ExaminOpinion = dto.Reason;
+        bulletin.ExaminTime = DateTime.Now;
+        bulletin.ExaminManId = _sessionContext.RequiredUserId;
+        await _bulletinRepository.UpdateAsync(bulletin, token);
+
+        await _capPublisher.PublishAsync(Share.Mq.EventNames.BulletinIsPass, bulletin.Id, cancellationToken: token);
+    }
+
+    /// <summary>
+    /// 执行发送通知公告
+    /// </summary>
+    /// <param name="bullutionId"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    public async Task NotifyUserAsync(string bullutionId, CancellationToken token)
+    {
+        await _bulletinRepository.GetAsync(bullutionId, token)
+            .Then(async bulletion =>
+            {
+                if (bulletion!.IsSnapshot == false) return;
+                if (bulletion!.SafetyTypeId!.IsNullOrEmpty()) return;
+                foreach (var safetyTypeId in bulletion!.SafetyTypeId!)
+                {
+                    await _safetyTypeRepository.Queryable()
+                        .LeftJoin<CitizenRelationSafetyType>((safety, relation) => safety.Id == relation.SafetyTypeId)
+                        .LeftJoin<Citizen>((safety, relation, citizen) => relation.CitizenId == citizen.Id)
+                        .Where((safety, relation, citizen) => safety.Id == safetyTypeId)
+                        .Select((safety, relation, citizen) => relation.CitizenId)
+                        .ToListAsync(token)
+                        .Then(async citizenIds =>
+                        {
+                            var inDto = bulletion.Adapt<AddNotifyInDto>();
+                            inDto.UserIds = citizenIds;
+                            if (bulletion.VideoPath.NotNullOrEmpty())
+                            {
+                                inDto.NotifyType = ENotificationType.Video;
+                            }
+                            await _notificationDomainService.AddNotifyAsync(inDto, token);
+                        });
+                }
+            });
     }
 
     /// <summary>
@@ -88,4 +170,29 @@ public class SnapshotBulletinApplication : ISnapshotBulletinApplication, IScopeD
             .Select<SnapshotBulletinItemsOutDto>();
         return query;
     }
+
+
+    public async Task CommitBulletinAsync(string id, CancellationToken requestAborted)
+    {
+        var bulletin = await _bulletinRepository.GetAsync(id, requestAborted);
+        if (bulletin == null)
+            throw UserFriendlyException.SameMessage("无效数据");
+
+        if (bulletin.BulletinState != EBulletinState.Draft && bulletin.BulletinState != EBulletinState.ReviewNoPass)
+            throw UserFriendlyException.SameMessage("当前状态不能提交");
+
+        bulletin.BulletinState = EBulletinState.InReview;
+        bulletin.CommitTime = DateTime.Now;
+        await _bulletinRepository.UpdateAsync(bulletin, requestAborted);
+    }
+
+
+    public async Task<string> AddBulletinAsync(AddSnapshotBulletinInDto dto, CancellationToken token)
+    {
+        var model = dto.Adapt<SnapshotBulletin>();
+        model.BulletinState = EBulletinState.Draft;
+        model.ReadedNum = 0;
+        if (model.BulletinTime.HasValue == false) model.BulletinTime = DateTime.Now;
+        return await _bulletinRepository.AddAsync(model, token);
+    }
 }

+ 32 - 1
src/Hotline.Application/Snapshot/SnapshotPointsApplication.cs

@@ -4,6 +4,7 @@ using Hotline.Share.Dtos.Snapshot;
 using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Tools;
+using Hotline.Snapshot;
 using Hotline.Snapshot.IRepository;
 using SqlSugar;
 using System;
@@ -19,18 +20,23 @@ public class SnapshotPointsApplication : ISnapshotPointsApplication, IScopeDepen
 {
     private readonly ISnapshotPointsRecordRepository _snapshotPointsRecordRepository;
     private readonly ICitizenRepository _citizenRepository;
+    private readonly ISafetyTypeRepository _safetyTypeRepository;
 
-    public SnapshotPointsApplication(ISnapshotPointsRecordRepository snapshotPointsRecordRepository, ICitizenRepository citizenRepository)
+    public SnapshotPointsApplication(ISnapshotPointsRecordRepository snapshotPointsRecordRepository, ICitizenRepository citizenRepository, ISafetyTypeRepository safetyTypeRepository)
     {
         _snapshotPointsRecordRepository = snapshotPointsRecordRepository;
         _citizenRepository = citizenRepository;
+        _safetyTypeRepository = safetyTypeRepository;
     }
 
     public ISugarQueryable<PointsItemsOutDto> GetPointsItems(PointsItemsInDto dto)
     {
         var query = _snapshotPointsRecordRepository.Queryable()
             .LeftJoin<Citizen>((points, citizen) => points.UserId == citizen.Id)
+            .LeftJoin<Order>((points, citizen, order) => order.Id == points.OrderId)
             .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (points, citizen) => citizen.PhoneNumber.Contains(dto.PhoneNumber!))
+            .WhereIF(dto.County.NotNullOrEmpty(), (points, citizen, order) => order.County == dto.County)
+            .WhereIF(dto.StartTime != null && dto.EndTime != null, (points, citizen) => points.CreationTime >= dto.StartTime && points.CreationTime <= dto.EndTime)
             .Where((points, citizen) => points.CreationTime >= dto.StartTime && points.CreationTime <= dto.EndTime)
             .GroupBy((points, citizen) => new { points.UserId, citizen.IsSecurityMax, citizen.Name, citizen.PhoneNumber })
             .Select((points, citizen) => new PointsItemsOutDto
@@ -59,5 +65,30 @@ public class SnapshotPointsApplication : ISnapshotPointsApplication, IScopeDepen
             .SetColumns(citizen => citizen.IsSecurityMax, dto.IsSecurityMax)
             .Where(citizen => citizen.Id == dto.UserId)
             .ExecuteCommandAsync(token);
+        await _citizenRepository.Queryable()
+            .Includes(m => m.SafetyTypes)
+            .Where(m => m.Id == dto.UserId)
+            .FirstAsync(token)
+            .Then(async citizen =>
+            {
+                await _safetyTypeRepository.Queryable()
+                    .Where(m => m.Name == "安全卫士")
+                    .FirstAsync(token)
+                    .Then(async safetyType =>
+                    {
+                        if (dto.IsSecurityMax)
+                            citizen.SafetyTypes.Add(safetyType);
+                        else
+                        {
+                            var delete = citizen.SafetyTypes.Where(m => m.Name == "安全卫士").ToList();
+                            foreach (var item in delete)
+                            {
+                                citizen.SafetyTypes.Remove(item);
+                            }
+                        }
+                        await _citizenRepository.UpdateNav(citizen).Include(m => m.SafetyTypes)
+                                .ExecuteCommandAsync();
+                    });
+            });
     }
 }

+ 17 - 0
src/Hotline.Application/Snapshot/SnapshotUserApplication.cs

@@ -10,6 +10,7 @@ using Hotline.Snapshot.IRepository;
 using Hotline.ThirdAccountDomainServices;
 using Hotline.Tools;
 using Mapster;
+using NPOI.POIFS.Properties;
 using SqlSugar;
 using System;
 using System.Collections.Generic;
@@ -60,6 +61,9 @@ public class SnapshotUserApplication : ISnapshotUserApplication, IScopeDependenc
             .LeftJoin<CitizenRelationSafetyType>((citizen, relation) => citizen.Id == relation.CitizenId)
             .LeftJoin<SafetyType>((citizen, relation, safety) => relation.SafetyTypeId == safety.Id)
             .WhereIF(dto.SafetyTypeId.NotNullOrEmpty(), (citizen, relation, safety) => safety.Id == dto.SafetyTypeId)
+            .WhereIF(dto.Name.NotNullOrEmpty(), (citizen, relation, safety) => citizen.Name.Contains(dto.Name))
+            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (citizen, relation, safety) => citizen.PhoneNumber.Contains(dto.PhoneNumber))
+            .Where((citizen, relation, safety) => safety.Id != null)
             .Select((citizen, relation, safety) => new CitizenRelationSafetyTypeOutDto
             {
                 CitizenId = citizen.Id,
@@ -88,4 +92,17 @@ public class SnapshotUserApplication : ISnapshotUserApplication, IScopeDependenc
                 .ExecuteCommand();
         }
     }
+
+    public ISugarQueryable<GetThirdCitizenOutDto> GetThirdCitizenAsync(GetThirdCitizenInDto dto)
+    {
+        var query = _citizenRepository.Queryable(includeDeleted: true)
+            .LeftJoin<ThirdAccount>((citizen, third) => citizen.Id == third.ExternalId)
+            .WhereIF(dto.PhoneNumber.NotNullOrEmpty(), (citizen, third) => citizen.PhoneNumber.Contains(dto.PhoneNumber))
+            .Select((citizen, third) => new GetThirdCitizenOutDto { CitizenId = citizen.Id}, true);
+#if DEBUG
+        var sql = query.ToSqlString();
+#endif
+
+        return query;
+    }
 }

File diff suppressed because it is too large
+ 0 - 0
src/Hotline.Application/Snapshot/ZiGongSnapshotApplication.cs


+ 1 - 0
src/Hotline.Repository.SqlSugar/Extensions/SqlSugarStartupExtensions.cs

@@ -129,6 +129,7 @@ namespace Hotline.Repository.SqlSugar.Extensions
                 db =>
                 {
                     SetDbAop(db, services);
+                    db.QueryFilter.AddTableFilter<ISoftDelete>(entity => !entity.IsDeleted);
                 }
             );
 

+ 19 - 0
src/Hotline.Repository.SqlSugar/Snapshot/NotificationReceiverRepository.cs

@@ -0,0 +1,19 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Snapshot;
+using Hotline.Snapshot.IRepository;
+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 NotificationReceiverRepository : BaseRepository<NotificationReceiver>, INotificationReceiverRepository, IScopeDependency
+{
+    public NotificationReceiverRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
+    {
+    }
+}

+ 19 - 0
src/Hotline.Repository.SqlSugar/Snapshot/NotificationRepository.cs

@@ -0,0 +1,19 @@
+using Hotline.Repository.SqlSugar.DataPermissions;
+using Hotline.Snapshot;
+using Hotline.Snapshot.IRepository;
+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 NotificationRepository : BaseRepository<Notification>, INotificationRepository, IScopeDependency
+{
+    public NotificationRepository(ISugarUnitOfWork<HotlineDbContext> uow, IDataPermissionFilterBuilder dataPermissionFilterBuilder, IServiceProvider serviceProvider) : base(uow, dataPermissionFilterBuilder, serviceProvider)
+    {
+    }
+}

+ 10 - 0
src/Hotline.Share/Dtos/Knowledge/KnowedgeStatisticsDto.cs

@@ -0,0 +1,10 @@
+namespace Hotline.Share.Dtos.Knowledge
+{
+    public class KnowedgeStatisticsDto
+    {
+        public int Index { get; set; }
+        public string? OrgName { get; set; }
+
+        public DateTime? LastModificationTime { get; set; }
+    }
+}

+ 4 - 0
src/Hotline.Share/Dtos/ObservationPiece/ObservationPieceListDto.cs

@@ -2,6 +2,10 @@
 {
     public class ObservationPieceListDto
     {
+        public string Id { get; set; }
+
+        public string OrderId { get; set; }
+
         public string? No { get; set; }
 
         public string? Title { get; set; }

+ 27 - 0
src/Hotline.Share/Dtos/Settings/SystemCommonOpinionDto.cs

@@ -0,0 +1,27 @@
+using Hotline.Share.Enums.Settings;
+using Novacode;
+using System.Data;
+
+namespace Hotline.Share.Dtos.Settings
+{
+    public class SystemCommonOpinionDto
+    {
+        public string? Content { get; set; }
+        public ECommonType? CommonType { get; set; }
+        public string? CommonTypeText { get; set; }
+        public bool? IsOpen { get; set; }
+        public string? IsOpenText => IsOpen == true ? "公开常用意见" : "个人常用意见";
+        public string? AreaId { get; set; }
+        public ECommonAttributionType? AttributionType { get; set; }
+        public string? AttributionTypeText { get; set; }
+        public string? CreatorId { get; set; }
+        public string? CreatorName { get; set; }
+        public string? CreatorOrgId { get; set; }
+        public int? CreatorOrgLevel { get; set; }
+        public string? CreatorOrgName { get; set; }
+        public string? Id { get; set; }
+        public string? OldId { get; set; }
+        public int OrderBy { get; set; }
+        public DateTime? CreationTime { get; set; }
+    }
+}

+ 1 - 0
src/Hotline.Share/Dtos/Settings/SystemMobilAreaDto.cs

@@ -104,6 +104,7 @@ namespace Hotline.Share.Dtos.Settings
         /// 运营商
         /// </summary>
         public string OFlag { get; set; }
+        public string OFlagText => OFlag == "1" ? "中国电信" : OFlag == "2" ? "中国移动" : OFlag == "3" ? "中国联通" : "其他";
 
         /// <summary>
         /// 卡类型

+ 62 - 0
src/Hotline.Share/Dtos/Snapshot/NotifyDto.cs

@@ -0,0 +1,62 @@
+using Hotline.Share.Enums.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Snapshot;
+
+public class NotifyDto
+{
+}
+
+public class AddNotifyInDto
+{
+
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string Title { get; set; }
+
+    /// <summary>
+    /// 内容
+    /// </summary>
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 类型
+    /// </summary>
+    public ENotificationType NotifyType { get; set; }
+
+    /// <summary>
+    /// 用户
+    /// </summary>
+    public IList<string> UserIds { get; set; }
+}
+
+public class GetNotifyInDto : QueryFixedDto
+{
+    /// <summary>
+    /// 消息类型
+    /// </summary>
+    public ENotificationType NotifyType { get; set; }
+}
+
+public class GetNotifyOutDto
+{
+    /// <summary>
+    /// 通知Id
+    /// </summary>
+    public string NotificationId { get; set; }
+
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string Title { get; set; }
+
+    /// <summary>
+    /// 创建时间
+    /// </summary>
+    public DateTime CreationTime { get; set; }
+}

+ 9 - 0
src/Hotline.Share/Dtos/Snapshot/PointsDto.cs

@@ -38,6 +38,15 @@ public record PointsItemsInDto : PagedKeywordRequest
     /// 联系方式
     /// </summary>
     public string? PhoneNumber { get; set; }
+
+    /// <summary>
+    /// 区域名称
+    /// </summary>
+    public string? County { get; set; }
+
+    public DateTime? StartTime { get; set; }
+
+    public DateTime? EndTime { get; set; }
 }
 
 public class PointsItemsOutDto

+ 6 - 1
src/Hotline.Share/Dtos/Snapshot/SnapshotBulletinDto.cs

@@ -263,7 +263,7 @@ public class AddSnapshotBulletinInDto
     /// <summary>
     /// 志愿者类型Id
     /// </summary>
-    public string? SafetyTypeId { get; set; }
+    public IList<string>? SafetyTypeId { get; set; }
 
     /// <summary>
     /// 时间
@@ -279,4 +279,9 @@ public class AddSnapshotBulletinInDto
     /// 视频地址
     /// </summary>
     public string? VideoPath { get; set; }
+
+    /// <summary>
+    /// 视频封面
+    /// </summary>
+    public string? VideoCoverImgUrl { get; set; }
 }

+ 36 - 0
src/Hotline.Share/Dtos/Snapshot/SnapshotUserInfoDto.cs

@@ -57,6 +57,16 @@ public record CitizenRelationSafetyTypeInDto : PagedRequest
     /// 志愿者类型
     /// </summary>
     public string? SafetyTypeId { get; set; }
+
+    /// <summary>
+    /// 名字
+    /// </summary>
+    public string? Name { get; set; }
+
+    /// <summary>
+    /// 手机号码
+    /// </summary>
+    public string? PhoneNumber { get; set; }
 }
 
 public class CitizenRelationSafetyTypeOutDto
@@ -124,3 +134,29 @@ public class CitizenIdRelationSafetyTypeId
     /// </summary>
     public string SafetyTypeId { get; set; }
 }
+
+public record GetThirdCitizenInDto : PagedRequest
+{
+    /// <summary>
+    /// 电话号码
+    /// </summary>
+    public string? PhoneNumber { get; set; }
+}
+
+public class GetThirdCitizenOutDto
+{
+    /// <summary>
+    /// Id
+    /// </summary>
+    public string CitizenId { get; set; }
+
+    /// <summary>
+    /// Name
+    /// </summary>
+    public string Name { get; set; }
+
+    /// <summary>
+    /// 电话
+    /// </summary>
+    public string PhoneNumber { get; set; }
+}

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

@@ -3113,3 +3113,31 @@ public class IndustryStatisticsDetailsOutDto
     public string FileOpinion { get; set; }
 
 }
+
+public class SnapshotCountyPointsStatisticsInDto
+{
+    [Required]
+    public DateTime StartTime { get; set; }
+
+    [Required]
+    public DateTime EndTime { get; set; }
+
+}
+
+public class SnapshotCountyPointsStatisticsOutDto
+{
+    /// <summary>
+    /// 区域名称
+    /// </summary>
+    public string CountyName { get; set; }
+
+    /// <summary>
+    /// 积分
+    /// </summary>
+    public long Points { get; set; }
+
+    /// <summary>
+    /// 兑换积分
+    /// </summary>
+    public long ExchangePoints { get; set; }
+}

+ 5 - 0
src/Hotline.Share/Dtos/WebPortal/QueryKnowledgeList.cs

@@ -29,6 +29,11 @@ namespace Hotline.Share.Dtos.WebPortal
         /// 知识标签
         /// </summary>
         public string? KnowledgeBaseTags { get; set; }
+
+        /// <summary>
+        /// 是否企业
+        /// </summary>
+        public int? KnowledgeType { get; set; }
     }
 
     public class QueryKnowledgeInfo

+ 17 - 0
src/Hotline.Share/Enums/Snapshot/ENotificationType.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Enums.Snapshot;
+
+public enum ENotificationType
+{
+    [Description("消息")]
+    Message = 0,
+
+    [Description("视频")]
+    Video = 1
+}

+ 5 - 0
src/Hotline.Share/Mq/EventNames.Snapshot.cs

@@ -11,4 +11,9 @@ public partial class  EventNames
     /// 延迟检查网格员系统是否回复
     /// </summary>
     public const string GuiderSystemReplyDelay = "snapshot.guider.reply.delay";
+
+    /// <summary>
+    /// 通知公告审核通过
+    /// </summary>
+    public const string BulletinIsPass = "snapshot.bulletin.pass";
 }

+ 5 - 0
src/Hotline.Share/Tools/DateTimeExtensions.cs

@@ -35,6 +35,11 @@ public static class DateTimeExtensions
         return dateTime.ToString("yyyy-MM-dd HH:mm:ss");
     }
 
+    public static string ToShortDateTimeString(this DateTime dateTime)
+    {
+        return dateTime.ToString("yyyy-MM-dd");
+    }
+
     public static long ToUnixTimeMilliseconds(this DateTime value)
     {
         return new DateTimeOffset(value).ToUnixTimeMilliseconds();

+ 13 - 12
src/Hotline/Orders/Order.cs

@@ -963,16 +963,16 @@ namespace Hotline.Orders
         [SugarColumn(ColumnDescription = "重办次数")]
         public int? ReTransactNum { get; set; }
 
-		/// <summary>
-		/// 回访重办次数
-		/// </summary>
-		[SugarColumn(ColumnDescription = "重办次数")]
-		public int? VisitReTransactNum { get; set; }
-
-		/// <summary>
-		/// 派单退回次数
-		/// </summary>
-		[SugarColumn(ColumnDescription = "派单退回次数")]
+        /// <summary>
+        /// 回访重办次数
+        /// </summary>
+        [SugarColumn(ColumnDescription = "重办次数")]
+        public int? VisitReTransactNum { get; set; }
+
+        /// <summary>
+        /// 派单退回次数
+        /// </summary>
+        [SugarColumn(ColumnDescription = "派单退回次数")]
         public int? SendBackNum { get; set; }
 
         /// <summary>
@@ -1180,7 +1180,7 @@ namespace Hotline.Orders
         /// <summary>
         /// 预警信息
         /// </summary>
-        [Navigate(NavigateType.OneToOne, nameof(Id),nameof(OrderEarlyWarning.OrderId))]
+        [Navigate(NavigateType.OneToOne, nameof(Id), nameof(OrderEarlyWarning.OrderId))]
         public OrderEarlyWarning OrderEarlyWarning { get; set; }
 
         /// <summary>
@@ -1367,7 +1367,8 @@ namespace Hotline.Orders
             FirstVisitResult = result;
 
             //Progress = EProgress.Visited;
-            Status = EOrderStatus.Visited;
+            if (Status >= EOrderStatus.Filed)
+                Status = EOrderStatus.Visited;
         }
 
         public void CenterToOrg(string timelimit, int timelimitCount, ETimeType timilimitUnit,

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

@@ -781,6 +781,11 @@ namespace Hotline.Settings
         /// </summary>
         public const string ScreenStatisticalNodes = "ScreenStatisticalNodes";
 
+        /// <summary>
+        /// 延期统计查询节点
+        /// </summary>
+        public const string DelayStatisticalNodes = "DelayStatisticalNodes";
+
         /// <summary>
         /// 小休审批人角色
         /// </summary>
@@ -815,5 +820,10 @@ namespace Hotline.Settings
         /// 话务管理未接允许关联工单
         /// </summary>
         public const string IsCallBindOrder = "IsCallBindOrder";
+
+        /// <summary>
+        /// 是否开启白名单查询
+        /// </summary>
+        public const string IsOpenWhiteList = "IsOpenWhiteList";
     }
 }

+ 19 - 0
src/Hotline/Snapshot/Contracts/INotificationDomainService.cs

@@ -0,0 +1,19 @@
+using Hotline.Share.Dtos.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Snapshot.Contracts;
+
+public interface INotificationDomainService
+{
+    /// <summary>
+    /// 添加通知
+    /// </summary>
+    /// <param name="inDto"></param>
+    /// <param name="token"></param>
+    /// <returns></returns>
+    Task AddNotifyAsync(AddNotifyInDto inDto, CancellationToken token);
+}

+ 0 - 0
src/Hotline/Snapshot/IRepository/IndustryLogRepository.cs → src/Hotline/Snapshot/IRepository/IIndustryLogRepository.cs


+ 12 - 0
src/Hotline/Snapshot/IRepository/INotificationReceiverRepository.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.IRepository;
+
+public interface INotificationReceiverRepository : IRepository<NotificationReceiver>
+{
+}

+ 12 - 0
src/Hotline/Snapshot/IRepository/INotificationRepository.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.IRepository;
+
+public interface INotificationRepository : IRepository<Notification>
+{
+}

+ 27 - 0
src/Hotline/Snapshot/Notification.cs

@@ -0,0 +1,27 @@
+using Hotline.Share.Enums.Snapshot;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot;
+
+public class Notification : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 标题
+    /// </summary>
+    public string Title { get; set; }
+
+    /// <summary>
+    /// 内容
+    /// </summary>
+    public string Content { get; set; }
+
+    /// <summary>
+    /// 类型
+    /// </summary>
+    public ENotificationType NotifyType { get; set; }
+}

+ 27 - 0
src/Hotline/Snapshot/NotificationReceiver.cs

@@ -0,0 +1,27 @@
+using SqlSugar;
+using System.ComponentModel;
+using XF.Domain.Repository;
+
+namespace Hotline.Snapshot;
+
+[Description("通知关联消息")]
+public class NotificationReceiver : CreationSoftDeleteEntity
+{
+    /// <summary>
+    /// 通知ID
+    /// </summary>
+    [SugarColumn(ColumnDescription = "通知Id")]
+    public string NotificationId { get; set; }
+
+    /// <summary>
+    /// 接收人ID
+    /// </summary>
+    [SugarColumn(ColumnDescription = "接收人ID")]
+    public string ReceiverId { get; set; }
+
+    /// <summary>
+    /// 是否已读
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否已读")]
+    public bool IsRead { get; set; }
+}

+ 40 - 0
src/Hotline/Snapshot/Services/NotificationDomainService.cs

@@ -0,0 +1,40 @@
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Snapshot.Contracts;
+using Hotline.Snapshot.IRepository;
+using Mapster;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Dependency;
+
+namespace Hotline.Snapshot.Services;
+
+public class NotificationDomainService : INotificationDomainService, IScopeDependency
+{
+    private readonly INotificationRepository _notificationRepository;
+    private readonly INotificationReceiverRepository _notificationReceiverRepository;
+
+    public NotificationDomainService(INotificationRepository notificationRepository, INotificationReceiverRepository notificationReceiverRepository)
+    {
+        _notificationRepository = notificationRepository;
+        _notificationReceiverRepository = notificationReceiverRepository;
+    }
+
+    public async Task AddNotifyAsync(AddNotifyInDto inDto, CancellationToken token)
+    {
+        var entity = inDto.Adapt<Notification>();
+        var id = await _notificationRepository.AddAsync(entity, token);
+        var items = new List<NotificationReceiver>();
+        foreach (var userId in inDto.UserIds)
+        {
+            items.Add(new NotificationReceiver { 
+                NotificationId = id,
+                ReceiverId = userId,
+                IsRead = false
+            });
+        }
+        await _notificationReceiverRepository.AddRangeAsync(items, token);
+    }
+}

+ 14 - 3
src/Hotline/Snapshot/Services/SnapshotPointsDomainService.cs

@@ -1,4 +1,5 @@
-using Hotline.Share.Enums.Snapshot;
+using Hotline.Orders;
+using Hotline.Share.Enums.Snapshot;
 using Hotline.Snapshot.Contracts;
 using Hotline.Snapshot.IRepository;
 using System;
@@ -27,11 +28,21 @@ public class SnapshotPointsDomainService : ISnapshotPointsDomainService, IScopeD
         if (status == null) return;
         var order = await _orderSnapshotRepository.Queryable()
             .LeftJoin<Industry>((snapshot, industry) => snapshot.IndustryId == industry.Id)
+            .LeftJoin<Order>((snapshot, industry, order) => order.Id == snapshot.Id)
             .Where((snapshot, industry) => snapshot.Id == orderId)
-            .Select((snapshot, industry) => new { snapshot.Id, industry.ReportPoints , industry.ArgeePoints , industry.RefusePoints,  industry.Name,
-                snapshot.CreatorId})
+            .Select((snapshot, industry, order) => new 
+            {
+                snapshot.Id,
+                industry.ReportPoints,
+                industry.ArgeePoints, 
+                industry.RefusePoints,
+                industry.Name,
+                snapshot.CreatorId,
+                order.HotspotId
+            })
             .FirstAsync();
         if (order == null) return;
+        if (order.HotspotId != null && order.HotspotId.StartsWith("18") == true) return;
         
         if (order.ReportPoints.HasValue == false)
             throw new UserFriendlyException($"{order.Name} 行业未配置积分");

+ 19 - 0
src/Hotline/Snapshot/SnapshotBulletin.cs

@@ -175,5 +175,24 @@ public class SnapshotBulletin : CreationEntity
     {
         ReadedNum++;
     }
+
+    /// <summary>
+    /// 是否随手拍
+    /// </summary>
+    [SugarColumn(ColumnDescription = "是否随手拍")]
+    public bool? IsSnapshot { get; set; }
+
+    /// <summary>
+    /// 志愿者类型Id
+    /// </summary>
+    [SugarColumn(ColumnDescription = "志愿者类型Id", ColumnDataType = "json", IsJson = true)]
+    public List<string>? SafetyTypeId { get; set; }
+
+    /// <summary>
+    /// 视频封面
+    /// </summary>
+    [SugarColumn(ColumnDescription = "视频封面")]
+    public string? VideoCoverImgUrl { get; set; }
+
 }
 

+ 0 - 1
src/Hotline/Validators/Exams/Questions/UpdateQuestionTagDtoValidator.cs

@@ -13,7 +13,6 @@ namespace Hotline.Validators.Exams.Questions
         public UpdateQuestionTagDtoValidator()
         {
             RuleFor(m => m.TagId).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, typeof(ExamTag).GetDescription()));
-            RuleFor(m=>m.Id).NotEmpty().WithMessage(x => string.Format(ExamErrorMessage.IsRequired, x.GetType().GetDescription(nameof(ExamQuestionTag.Id))));
         }
     }
 }

+ 1 - 1
src/Hotline/Validators/Order/AddOrderDtoValidator.cs

@@ -114,7 +114,7 @@ public class AddOrderDtoValidator : AbstractValidator<AddOrderDto>
         #endregion
 
         #region 投诉详情
-        RuleFor(d => d.OrderExtension.ExternalOrderNo).MaximumLength(15).When(d => d.OrderExtension != null).WithMessage("订单号最多15字符");
+        RuleFor(d => d.OrderExtension.ExternalOrderNo).MaxLengthWithChineseChar(45).When(d => d.OrderExtension != null).WithMessage("订单号最多45字符");
         RuleFor(d => d.OrderExtension.Patentee).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("专利权人最多50字符");
         RuleFor(d => d.OrderExtension.PatentName).MaxLengthWithChineseChar(200).When(d => d.OrderExtension != null).WithMessage("专利名称最多200字符");
         RuleFor(d => d.OrderExtension.PatentNo).MaxLengthWithChineseChar(50).When(d => d.OrderExtension != null).WithMessage("专利号最多50字符");

+ 1 - 1
src/XF.Domain.Repository/Entity.cs

@@ -79,7 +79,7 @@ public abstract class SoftDeleteEntity : Entity, IHasDeletionTime, ISoftDelete
     [SugarColumn(ColumnDescription = "删除时间")]
     public DateTime? DeletionTime { get; set; }
 
-    [SugarColumn(ColumnDescription = "是否删除")]
+    [SugarColumn(ColumnDescription = "是否删除", DefaultValue = "f")]
     public bool IsDeleted { get; set; }
 
     public void SoftDelete()

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

@@ -13,6 +13,7 @@ using Mapster;
 using Microsoft.AspNetCore.Http;
 using Microsoft.Extensions.DependencyInjection;
 using Shouldly;
+using SqlSugar;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -110,6 +111,14 @@ public class BiSnapshotApplicationTest : TestBase
 
         var e = _biSnapshotApplication.GetIndustryStatistics(inDto.Adapt<IndustryStatisticsInDto>());
         e.ShouldNotBeNull();
+
+        var areaPointsInDto = new SnapshotCountyPointsStatisticsInDto
+        {
+            StartTime = DateTime.Now.AddDays(-30),
+            EndTime = DateTime.Now,
+        };
+        var areaPointsOutDto = _biSnapshotApplication.GetAreaPointsStatistics(areaPointsInDto).ToList();
+        areaPointsOutDto.ShouldNotBeNull();
     }
 
     [Fact]

+ 35 - 3
test/Hotline.Tests/Application/OrderSnapshotApplicationTest.cs

@@ -11,6 +11,7 @@ using Hotline.Repository.SqlSugar.Snapshot;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Enums.CallCenter;
 using Hotline.Share.Enums.Snapshot;
 using Hotline.Share.Requests;
 using Hotline.Share.Tools;
@@ -112,6 +113,37 @@ public class OrderSnapshotApplicationTest : TestBase
             });
     }
 
+    [Theory]
+    [InlineData(true)]
+    [InlineData(false)]
+    public async Task SnapshotOrder_AddPoints_Test(bool 是受理范围)
+    {
+        var order = _orderServiceMock.CreateSnapshotOrder(SetWeiXin, "安全隐患")
+            .StepHandle(async order =>
+            {
+                if (是受理范围 == false)
+                {
+                    var entity = _orderRepository.Get(order.Id);
+                    entity.HotspotId = "181301";
+                    await _orderRepository.UpdateAsync(entity);
+                }
+            })
+            .办理到一级部门(SetZuoXi)
+            .办理到归档(Set一级部门, data =>
+            {
+                data.CompliantType = ECompliantType.First;
+                data.VerifyType = "现场";
+                data.IsCheckList = true;
+            }).GetCreateResult();
+        var points = await _pointsRecordRepository.Queryable()
+            .Where(m => m.OrderId == order.Id && m.Direction == EPointsDirection.In && m.Source == EPointsSource.Report)
+            .FirstAsync();
+        if (是受理范围)
+            points.ShouldNotBeNull();
+        else
+            points.ShouldBeNull();
+    }
+
     /// <summary>
     /// 随手拍网格员超时:
     /// </summary>
@@ -267,7 +299,7 @@ public class OrderSnapshotApplicationTest : TestBase
                 baseData.AuditTypeCode.ShouldNotBeNull();
                 baseData.Amount.ShouldNotBeNull();
 
-                var specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10 , No = order.No, Status = 1}).ToListAsync();
+                var specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10, No = order.No, Status = 1 }).ToListAsync();
                 var specialRedAudit = specialRedAuditItems.FirstOrDefault();
                 specialRedAudit.ShouldNotBeNull();
                 var a = _systemDicDataCacheManager.SnapshotReplenishType.First();
@@ -288,7 +320,7 @@ public class OrderSnapshotApplicationTest : TestBase
                 };
 
                 await _redPackApplication.UpdateRedPackSpecialRecordAsync(inDto); // 补充发放
-                specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10 , Status = 1, No = order.No}).ToListAsync();
+                specialRedAuditItems = await _redPackApplication.GetRedPackSpecialAuditItems(new SnapshotOrderAuditItemsInDto() { PageIndex = 1, PageSize = 10, Status = 1, No = order.No }).ToListAsync();
                 specialRedAudit = specialRedAuditItems.First();
                 specialRedAudit.ShouldNotBeNull();
                 specialRedAudit.BankCardNo.ShouldBe(inDto.BankCardNo);
@@ -329,7 +361,7 @@ public class OrderSnapshotApplicationTest : TestBase
                 }); // 添加备注
 
                 SetWeiXin();
-                redPackItems =  await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Received }, CancellationToken.None);
+                redPackItems = await _snapshotApplication.GetRedPacksAsync(new RedPacksInDto() { Status = ERedPackPickupStatus.Received }, CancellationToken.None);
                 redPackRecord = redPackItems.Where(m => m.OrderId == order.Id).FirstOrDefault();
                 redPackRecord.ShouldNotBeNull();
                 redPackRecord.Amount.ShouldBe(11);

+ 36 - 1
test/Hotline.Tests/Application/PointsRecordApplicationTest.cs

@@ -2,8 +2,10 @@
 using Hotline.Application.Snapshot.Contracts;
 using Hotline.Identity.Accounts;
 using Hotline.Identity.Roles;
+using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Dtos.Snapshot;
+using Hotline.Snapshot.IRepository;
 using Hotline.ThirdAccountDomainServices;
 using Hotline.ThirdAccountDomainServices.Interfaces;
 using Hotline.Users;
@@ -15,6 +17,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using XF.Domain.Authentications;
 using XF.Domain.Cache;
 using XF.Domain.Repository;
 
@@ -24,10 +27,17 @@ public class PointsRecordApplicationTest : TestBase
 {
     private readonly ISnapshotPointsApplication _pointsRecordApplication;
     private readonly ISnapshotApplication _snapshotApplication;
-    public PointsRecordApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccounSupplierFactory thirdAccountDomainFactory, ISnapshotPointsApplication pointsRecordApplication, ISnapshotApplication snapshotApplication, IServiceProvider serviceProvider) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory, serviceProvider)
+    private readonly ISessionContext _sessionContext;
+    private readonly ICitizenRepository _citizenRepository;
+    private readonly ISafetyTypeRepository _safetyTypeRepository;
+
+    public PointsRecordApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccounSupplierFactory thirdAccountDomainFactory, ISnapshotPointsApplication pointsRecordApplication, ISnapshotApplication snapshotApplication, IServiceProvider serviceProvider, ISessionContext sessionContext, ICitizenRepository citizenRepository, ISafetyTypeRepository safetyTypeRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory, serviceProvider)
     {
         _pointsRecordApplication = pointsRecordApplication;
         _snapshotApplication = snapshotApplication;
+        _sessionContext = sessionContext;
+        _citizenRepository = citizenRepository;
+        _safetyTypeRepository = safetyTypeRepository;
     }
 
     [Fact]
@@ -42,6 +52,31 @@ public class PointsRecordApplicationTest : TestBase
         items.ShouldNotBeNull();
     }
 
+    [Fact]
+    public async Task UpdateIsSecurityMax_Test()
+    {
+        SetWeiXin();
+        var inDto = new UpdateIsSecurityMaxAsync
+        {
+            UserId = _sessionContext.UserId,
+            IsSecurityMax = false
+        };
+        await _pointsRecordApplication.UpdateIsSecurityMaxAsync(inDto, CancellationToken.None);
+        var citizen = await _citizenRepository.Queryable()
+            .Where(m => m.Id == inDto.UserId)
+            .Includes(m => m.SafetyTypes)
+            .FirstAsync();
+        citizen.SafetyTypes.Any(m => m.Name == "安全卫士").ShouldBeFalse();
+
+        inDto.IsSecurityMax = true;
+        await _pointsRecordApplication.UpdateIsSecurityMaxAsync(inDto, CancellationToken.None);
+        citizen = await _citizenRepository.Queryable()
+            .Where(m => m.Id == inDto.UserId)
+            .Includes(m => m.SafetyTypes)
+            .FirstAsync();
+        citizen.SafetyTypes.Any(m => m.Name == "安全卫士").ShouldBeTrue();
+    }
+
     [Fact]
     public async Task GetPointsRank_Test()
     {

+ 91 - 0
test/Hotline.Tests/Application/SnapshotBulletionApplicationTest.cs

@@ -0,0 +1,91 @@
+using Hotline.Api.Controllers;
+using Hotline.Application.Snapshot.Contracts;
+using Hotline.Caching.Interfaces;
+using Hotline.Identity.Accounts;
+using Hotline.Identity.Roles;
+using Hotline.Repository.SqlSugar.Snapshot;
+using Hotline.Settings;
+using Hotline.Share.Dtos.Article;
+using Hotline.Share.Dtos.Snapshot;
+using Hotline.Share.Tools;
+using Hotline.Snapshot.IRepository;
+using Hotline.ThirdAccountDomainServices;
+using Hotline.ThirdAccountDomainServices.Interfaces;
+using Hotline.Users;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.DependencyInjection;
+using Shouldly;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Authentications;
+using XF.Domain.Cache;
+using XF.Domain.Repository;
+
+namespace Hotline.Tests.Application;
+
+public class SnapshotBulletionApplicationTest : TestBase
+{
+    private readonly ISnapshotBulletinApplication _snapshotBulletinApplication;
+    private readonly ISystemDicDataCacheManager _systemDicDataCacheManager;
+    private readonly ISafetyTypeRepository _safetyTypeRepository;
+    private readonly ISnapshotUserApplication _snapshotUserApplication;
+    private readonly ISessionContext _sessionContext;
+    private readonly ISnapshotApplication _snapshotApplication;
+    private readonly ISnapshotBulletinRepository _bulletinRepository;
+
+    public SnapshotBulletionApplicationTest(IAccountRepository accountRepository, IRepository<Role> roleRepository, UserController userController, IServiceScopeFactory scopeFactory, IRepository<User> userRepository, IHttpContextAccessor httpContextAccessor, IThirdIdentiyService thirdIdentiyService, IThirdAccountRepository thirdAccountRepository, ITypedCache<SystemSetting> cacheSettingData, ThirdAccounSupplierFactory thirdAccountDomainFactory, IServiceProvider serviceProvider, ISnapshotBulletinApplication snapshotBulletinApplication, ISystemDicDataCacheManager systemDicDataCacheManager, ISafetyTypeRepository safetyTypeRepository, ISnapshotUserApplication snapshotUserApplication, ISessionContext sessionContext, ISnapshotApplication snapshotApplication, ISnapshotBulletinRepository bulletinRepository) : base(accountRepository, roleRepository, userController, scopeFactory, userRepository, httpContextAccessor, thirdIdentiyService, thirdAccountRepository, cacheSettingData, thirdAccountDomainFactory, serviceProvider)
+    {
+        _snapshotBulletinApplication = snapshotBulletinApplication;
+        _systemDicDataCacheManager = systemDicDataCacheManager;
+        _safetyTypeRepository = safetyTypeRepository;
+        _snapshotUserApplication = snapshotUserApplication;
+        _sessionContext = sessionContext;
+        _snapshotApplication = snapshotApplication;
+        _bulletinRepository = bulletinRepository;
+    }
+
+    [Fact]
+    public async Task Bulletin_Test()
+    {
+        SetWeiXin();
+        var bulletinType =  _systemDicDataCacheManager.SnapshotBulletinType.First();
+        var safetyType = await _safetyTypeRepository.Queryable().FirstAsync();
+        var addRelationInDto = new AddCitizenRelationSafetyTypeInDto { SafetyTypeId = safetyType.Id, CitizenIds = [_sessionContext.UserId] };
+        await _snapshotUserApplication.AddCitizenRelationSafetyType(addRelationInDto, CancellationToken.None);
+        var inDto = new AddSnapshotBulletinInDto
+        {
+            Title = "测试公告" + DateTime.Now.ToLongDateTimeString(),
+            Content = "没什么内容",
+            BulletinTime = DateTime.Now,
+            IsSnapshot = true,
+            BulletinTypeId = bulletinType.DicDataValue,
+            BulletinTypeName = bulletinType.DicDataName,
+            SafetyTypeId = [safetyType.Id],
+            VideoCoverImgUrl = "222222",
+            VideoPath = "333333"
+        };
+        var bulletinId = await _snapshotBulletinApplication.AddBulletinAsync(inDto, CancellationToken.None);
+        var bulletin = await _bulletinRepository.GetAsync(bulletinId);
+        bulletin.IsSnapshot.ShouldBe(true);
+        bulletin.SafetyTypeId.First().ShouldBe(safetyType.Id);
+        bulletin.VideoPath.ShouldBe(inDto.VideoPath);
+        bulletin.VideoCoverImgUrl.ShouldBe(inDto.VideoCoverImgUrl);
+        await _snapshotBulletinApplication.CommitBulletinAsync(bulletinId, CancellationToken.None);
+        var examineDto = new ExamineBulletinDto
+        {
+            Id = bulletinId,
+            IsPass = true,
+            Reason = "审核通过"
+        };
+        await _snapshotBulletinApplication.ExamineBulletinAsync(examineDto, CancellationToken.None);
+        Thread.Sleep(5 * 1000);
+        //await _snapshotBulletinApplication.NotifyUserAsync(bulletinId, CancellationToken.None);
+
+
+        var notifyItems = await _snapshotApplication.GetNotificationAsync(new GetNotifyInDto(), CancellationToken.None);
+        notifyItems.Any(m => m.Title == inDto.Title).ShouldBeTrue();
+    }
+}

+ 8 - 0
test/Hotline.Tests/Application/SnapshotUserApplicationTest.cs

@@ -37,6 +37,13 @@ public class SnapshotUserApplicationTest : TestBase
     [Fact]
     public async Task SnapshotUserApplication_Test()
     {
+        var searchInDto = new GetThirdCitizenInDto
+        {
+            PhoneNumber = "33"
+        };
+        var citizenSearchItems = await _snapshotUserApplication.GetThirdCitizenAsync(searchInDto).ToListAsync();
+        citizenSearchItems.ShouldNotBeNull();
+        citizenSearchItems.Count.ShouldNotBe(0);
         var newSafetyType = new SafetyType { Name = "安全卫士" };
         var safetyType = await _safetyTypeRepository.Queryable().Where(m => m.Name == newSafetyType.Name).FirstAsync();
         safetyType ??= new SafetyType
@@ -94,6 +101,7 @@ public class SnapshotUserApplicationTest : TestBase
         await _snapshotUserApplication.DeleteCitizenRelationSafetyAsync(deleteInDto);
 
         items = await _snapshotUserApplication.GetCitizenRelationSafetyType(inDto).ToListAsync();
+        items.Any(m => m.SafetyTypeId.IsNullOrEmpty()).ShouldBeFalse();
         item = items.FirstOrDefault(m => m.CitizenId == citizen.Id && m.SafetyTypeId == safetyType.Id);
         item.ShouldBeNull();
         inDto = new CitizenRelationSafetyTypeInDto

+ 2 - 0
test/Hotline.Tests/Mock/Interfaces/IOrderServiceStartWorkflow.cs

@@ -13,4 +13,6 @@ public interface IOrderServiceStartWorkflow
     CreateOrderOutDto GetCreateResult();
     OrderServiceMock 办理到一级部门(Action action = null);
     OrderServiceMock 办理到归档(Action action = null);
+
+    IOrderServiceStartWorkflow StepHandle(Func<CreateOrderOutDto, Task> handle);
 }

+ 6 - 0
test/Hotline.Tests/Mock/OrderServiceStartWorkflow.cs

@@ -46,6 +46,12 @@ public class OrderServiceStartWorkflow : IOrderServiceStartWorkflow
         return _orderServiceMock.CreateOrderOutDto;
     }
 
+    public IOrderServiceStartWorkflow StepHandle(Func<CreateOrderOutDto, Task> handle)
+    {
+        handle(_orderServiceMock.CreateOrderOutDto).GetAwaiter().GetResult();
+        return this;
+    }
+
     public OrderServiceMock 办理到一级部门(Action action = null)
     {
         action?.Invoke();

Some files were not shown because too many files changed in this diff