using DotNetCore.CAP; using Hotline.Api.Filter; using Hotline.Application.CallCenter; using Hotline.Application.ExportExcel; using Hotline.Application.FlowEngine; using Hotline.Application.Orders; using Hotline.Application.Quality; using Hotline.Application.Snapshot; using Hotline.Application.Systems; using Hotline.Authentications; using Hotline.Caching.Interfaces; using Hotline.CallCenter.Calls; using Hotline.Configurations; using Hotline.ContingencyManagement.Notifies; using Hotline.EventBus; using Hotline.File; using Hotline.FlowEngine.Definitions; using Hotline.FlowEngine.WorkflowModules; using Hotline.FlowEngine.Workflows; using Hotline.Import; using Hotline.Orders; using Hotline.Orders.Notifications; using Hotline.OrderTranspond; using Hotline.Push.FWMessage; using Hotline.Push.Notifies; using Hotline.Repository.SqlSugar.CallCenter; using Hotline.Repository.SqlSugar.Extensions; using Hotline.Repository.SqlSugar.Ts; using Hotline.SeedData; using Hotline.Settings; using Hotline.Settings.Hotspots; using Hotline.Settings.TimeLimitDomain; using Hotline.Settings.TimeLimits; using Hotline.Share.Dtos; using Hotline.Share.Dtos.CallCenter; using Hotline.Share.Dtos.File; using Hotline.Share.Dtos.FlowEngine; using Hotline.Share.Dtos.FlowEngine.Workflow; using Hotline.Share.Dtos.Order; using Hotline.Share.Dtos.Order.Detail; using Hotline.Share.Dtos.Order.Handle; using Hotline.Share.Dtos.Order.Migration; using Hotline.Share.Dtos.Order.Publish; using Hotline.Share.Dtos.Org; using Hotline.Share.Dtos.Settings; using Hotline.Share.Dtos.Snapshot; using Hotline.Share.Enums.CallCenter; using Hotline.Share.Enums.FlowEngine; using Hotline.Share.Enums.Order; using Hotline.Share.Enums.Push; using Hotline.Share.Enums.Settings; using Hotline.Share.Mq; using Hotline.Share.Requests; using Hotline.Share.Tools; using Hotline.Snapshot; using Hotline.Snapshot.Interfaces; using Hotline.Tools; using Hotline.Users; using Hotline.YbEnterprise.Sdk; using Mapster; using MapsterMapper; using MediatR; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Options; using MiniExcelLibs; using SqlSugar; using System.Text; using System.Text.Json; using FluentValidation; using Hotline.Validators.FlowEngine; using XF.Domain.Authentications; using XF.Domain.Cache; using XF.Domain.Entities; using XF.Domain.Exceptions; using XF.Domain.Repository; using XF.Utility.EnumExtensions; using OrderDto = Hotline.Share.Dtos.Order.OrderDto; namespace Hotline.Api.Controllers; /// /// 工单 /// public class OrderController : BaseController { #region 注入 private readonly IOrderDomainService _orderDomainService; private readonly BaseDataApplication _baseDataApplication; private readonly IOrderRepository _orderRepository; private readonly IWorkflowApplication _workflowApplication; private readonly IWorkflowDomainService _workflowDomainService; private readonly IRepository _hotspotTypeRepository; private readonly ISystemOrganizeRepository _organizeRepository; private readonly IDefinitionDomainService _definitionDomainService; private readonly ISystemDicDataCacheManager _sysDicDataCacheManager; private readonly ITypedCache _typeCache; private readonly ISessionContext _sessionContext; private readonly IMapper _mapper; private readonly IMediator _mediator; private readonly IRepository _orderPublishRepository; private readonly IRepository _orderVisitRepository; private readonly IRepository _orderVisitedDetailRepository; private readonly ICapPublisher _capPublisher; private readonly IOrderDelayRepository _orderDelayRepository; private readonly ITimeLimitDomainService _timeLimitDomainService; private readonly ISystemSettingCacheManager _systemSettingCacheManager; private readonly IRepository _orderRedoRepository; private readonly IRepository _orderSuperviseRepository; private readonly IRepository _orderUrgeRepository; private readonly IFileRepository _fileRepository; private readonly IOrderScreenRepository _orderScreenRepository; private readonly IRepository _orderPublishHistoryRepository; private readonly IRepositoryTextSearch _repositoryts; private readonly IQualityApplication _qualityApplication; private readonly IRepository _workflowRepository; private readonly IRepository _workflowStepRepository; private readonly ICitizenRepository _citizenRepository; private readonly IRepository _labelDetailRepository; private readonly IRepository _repeatableEventRepository; private readonly IRepeatableEventDetailRepository _repeatableEventDetailRepository; private readonly IRepository _orderWrodRepository; private readonly IRepository _orderObserveRepository; private readonly IRepository _orderVisitApplyRepository; private readonly IRepository _orderFinalityRepository; private readonly IRepository _orderSendBackRepository; private readonly IRepository _orderSpecialRepository; private readonly IRepository _workflowTraceRepository; private readonly IOrderApplication _orderApplication; private readonly IPushDomainService _pushDomainService; private readonly ILogger _logger; private readonly IRepository _orderSendBackAuditRepository; private readonly IRepository _userRepository; private readonly IExportApplication _exportApplication; private readonly IRepository _transpondCityRawDataRepository; private readonly IRepository _orderSpecialDetailRepository; private readonly IOrderSecondaryHandlingApplication _orderSecondaryHandlingApplication; private readonly IRepository _orderCopyRepository; private readonly IRepository _externalCitizensRepository; private readonly IRepository _orderModifyingRecordsRepository; private readonly ICallApplication _callApplication; private readonly ICallNativeRepository _callNativeRepository; private readonly IOptionsSnapshot _appOptions; private readonly IOrderSendBackAuditApplication _orderSendBackAuditApplication; private readonly Publisher _publisher; private readonly IOrderAnalysisApplication _orderAnalysisApplication; private readonly ICalcExpireTime _expireTime; private readonly IRepository _orderPushTypeRepository; private readonly IRepository _orderRevokeRepository; private readonly IOrderTerminateRepository _orderTerminateRepository; private readonly ISystemLogApplication _systemLogApplication; private readonly IRepository _orderCarboncopy; private readonly IOrderSnapshotRepository _orderSnapshotRepository; private readonly IOrderSnapshotApplication _orderSnapshotApplication; private readonly IIndustryRepository _industryRepository; private readonly IRepository _sysDicDataRepository; public OrderController( IOrderDomainService orderDomainService, IOrderRepository orderRepository, IWorkflowApplication workflowApplication, IWorkflowDomainService workflowDomainService, IRepository hotspotTypeRepository, ISystemOrganizeRepository organizeRepository, IDefinitionDomainService definitionDomainService, ISystemDicDataCacheManager sysDicDataCacheManager, ISessionContext sessionContext, IMapper mapper, IMediator mediator, IRepository orderPublishRepository, IRepository orderVisitRepository, IRepository orderVisitedDetailRepository, ICapPublisher capPublisher, IOrderDelayRepository orderDelayRepository, //ITimeLimitDomainService timeLimitDomainService, ISystemSettingCacheManager systemSettingCacheManager, IRepository orderRedoRepository, IRepository orderSuperviseRepository, IRepository orderUrgeRepository, IFileRepository fileRepository, IOrderScreenRepository orderScreenRepository, IRepository orderPublishHistoryRepository, IRepositoryTextSearch repositoryts, IQualityApplication qualityApplication, IRepository workflowRepository, IRepository workflowStepRepository, ICitizenRepository citizenRepository, IRepository labelDetailRepository, IRepository repeatableEventRepository, IRepeatableEventDetailRepository repeatableEventDetailRepository, IRepository orderWrodRepository, IRepository orderObserveRepository, IRepository orderFinalityRepository, IRepository orderVisitApplyRepository, IRepository orderSendBackRepository, IRepository orderSpecialRepository, IRepository workflowTraceRepository, IOrderApplication orderApplication, IPushDomainService pushDomainService, ILogger logger, ITypedCache cacheResponse, IRepository orderSendBackAuditRepository, IRepository userRepository, IExportApplication exportApplication, IRepository transpondCityRawDataRepository, IRepository orderSpecialDetailRepository, IOrderSecondaryHandlingApplication orderSecondaryHandlingApplication, IRepository orderCopyRepository, IRepository externalCitizensRepository, ICallApplication callApplication, IOptionsSnapshot appOptions, IRepository orderModifyingRecordsRepository, IOrderSendBackAuditApplication orderSendBackAuditApplication, Publisher publisher, IOrderAnalysisApplication orderAnalysisApplication, ICalcExpireTime expireTime, IRepository orderPushTypeRepository, ICallNativeRepository callNativeRepository, IRepository orderRevokeRepository, BaseDataApplication baseDataApplication, IOrderTerminateRepository orderTerminateRepository, IRepository orderCarboncopy, ITypedCache typeCache, ISystemLogApplication systemLogApplication, IOrderSnapshotRepository orderSnapshotRepository, IIndustryRepository industryRepository, IOrderSnapshotApplication orderSnapshotApplication, IRepository sysDicDataRepository) { _orderDomainService = orderDomainService; _orderRepository = orderRepository; _workflowApplication = workflowApplication; _workflowDomainService = workflowDomainService; _hotspotTypeRepository = hotspotTypeRepository; _organizeRepository = organizeRepository; _definitionDomainService = definitionDomainService; _sysDicDataCacheManager = sysDicDataCacheManager; _sessionContext = sessionContext; _mapper = mapper; _mediator = mediator; _orderPublishRepository = orderPublishRepository; _orderVisitRepository = orderVisitRepository; _orderVisitedDetailRepository = orderVisitedDetailRepository; _capPublisher = capPublisher; _orderDelayRepository = orderDelayRepository; //_timeLimitDomainService = timeLimitDomainService; _systemSettingCacheManager = systemSettingCacheManager; _orderRedoRepository = orderRedoRepository; _orderSuperviseRepository = orderSuperviseRepository; _orderUrgeRepository = orderUrgeRepository; _fileRepository = fileRepository; _orderScreenRepository = orderScreenRepository; _orderPublishHistoryRepository = orderPublishHistoryRepository; _repositoryts = repositoryts; _qualityApplication = qualityApplication; _workflowRepository = workflowRepository; _workflowStepRepository = workflowStepRepository; _citizenRepository = citizenRepository; _labelDetailRepository = labelDetailRepository; _repeatableEventRepository = repeatableEventRepository; _repeatableEventDetailRepository = repeatableEventDetailRepository; _orderWrodRepository = orderWrodRepository; _orderObserveRepository = orderObserveRepository; _orderFinalityRepository = orderFinalityRepository; _orderVisitApplyRepository = orderVisitApplyRepository; _orderSendBackRepository = orderSendBackRepository; _orderSpecialRepository = orderSpecialRepository; _workflowTraceRepository = workflowTraceRepository; _logger = logger; _orderApplication = orderApplication; _pushDomainService = pushDomainService; _orderSendBackAuditRepository = orderSendBackAuditRepository; _userRepository = userRepository; _exportApplication = exportApplication; _transpondCityRawDataRepository = transpondCityRawDataRepository; _orderSpecialDetailRepository = orderSpecialDetailRepository; _orderSecondaryHandlingApplication = orderSecondaryHandlingApplication; _orderCopyRepository = orderCopyRepository; _externalCitizensRepository = externalCitizensRepository; _orderModifyingRecordsRepository = orderModifyingRecordsRepository; _callApplication = callApplication; _appOptions = appOptions; _orderSendBackAuditApplication = orderSendBackAuditApplication; _publisher = publisher; _orderAnalysisApplication = orderAnalysisApplication; _expireTime = expireTime; _orderPushTypeRepository = orderPushTypeRepository; _callNativeRepository = callNativeRepository; _baseDataApplication = baseDataApplication; _orderTerminateRepository = orderTerminateRepository; _orderCarboncopy = orderCarboncopy; _orderRevokeRepository = orderRevokeRepository; _typeCache = typeCache; _baseDataApplication = baseDataApplication; _systemLogApplication = systemLogApplication; _orderSnapshotRepository = orderSnapshotRepository; _industryRepository = industryRepository; _orderSnapshotApplication = orderSnapshotApplication; _sysDicDataRepository = sysDicDataRepository; } #endregion #region 工单发布 /// /// 发布待办(集合) /// /// /// [HttpGet("publish/items")] public async Task> GetPublishOrderListAsync([FromQuery] QueryOrderPublishDto dto) { var orders = await _orderApplication.GetPublishOrderList(dto) .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); return _mapper.Map>(orders); //return (await query.ToFixedListAsync(dto.QueryIndex, 200, HttpContext.RequestAborted)) // .Adapt>(); } /// /// 发布待办 /// /// /// [HttpGet("publish/count")] public async Task GetPublishOrderCount([FromQuery] QueryOrderPublishDto dto) { return await _orderApplication.GetPublishOrderList(dto).CountAsync(HttpContext.RequestAborted); } /// /// 发布待办数据--导出 /// /// /// [HttpPost("publishorder/export")] public async Task ExportPublishOrders([FromBody] ExportExcelDto dto) { var query = _orderApplication.GetPublishOrderList(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var orderDtos = _mapper.Map>(orders); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orderDtos .Select(stu => _mapper.Map(stu, typeof(PublishDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "发布待办数据"); } /// /// 查询(工单发布) /// /// /// [HttpGet("publish")] [Obsolete("前端不再调用,择机删除")] public async Task> PublishOrderList([FromQuery] QueryOrderPublishDto dto) { var (total, items) = await _orderRepository.Queryable() .Includes(d => d.OrderTags) //.Includes(d => d.OrderPublish) .Where(x => x.Status == EOrderStatus.Filed) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No.Contains(dto.No)) .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.Contains(dto.Title)) //.WhereIF(dto.PubState == EPubState.Pub, d => d.Status >= EOrderStatus.Published) //.WhereIF(dto.PubState == EPubState.NoPub, d => d.Status == EOrderStatus.Filed) .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel) //.WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTagCode == dto.OrderTag!) //工单标签 .WhereIF(!string.IsNullOrEmpty(dto.OrderTag), d => d.OrderTags.Any(ot => ot.DicDataValue == dto.OrderTag)) //工单标签 .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName == dto.CenterToOrgHandlerName!) //派单人 .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName == dto.NameOrNo! || d.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席 .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊) .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型 .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot)) .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.FromPhone == dto.FromPhone) //来电号码 //.WhereIF(!string.IsNullOrEmpty(dto.PubMan), // d => d.AcceptorName.Contains(dto.PubMan!) || d.AcceptorStaffNo.Contains(dto.PubMan!)) //.WhereIF(dto.PubRange == EPublicState.Pub, d => d.OrderPublish.PublishState) //.WhereIF(dto.PubRange == EPublicState.NoPub, d => !d.OrderPublish.PublishState) .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == true, d => d.Source == ESource.ProvinceStraight) .WhereIF(dto.IsProvinceOrder.HasValue && dto.IsProvinceOrder == false, d => d.Source != ESource.ProvinceStraight) .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.CenterFiled, d => d.ProcessType == EProcessType.Zhiban) .WhereIF(dto.FiledType != null && dto.FiledType == FiledType.OrgFiled, d => d.ProcessType == EProcessType.Jiaoban) .WhereIF(dto.IsCountersign != null && dto.IsCountersign == true, d => d.CounterSignType != null) .WhereIF(dto.IsCountersign != null && dto.IsCountersign == false, d => d.CounterSignType == null) .WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptType)) .WhereIF(dto.HotspotIds.Any(), d => dto.HotspotIds.Contains(d.HotspotId)) //.WhereIF(dto.Resolve.HasValue, d => d.OrderPublish.Resolve == dto.Resolve) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) .WhereIF(dto.FiledTimeStart.HasValue, d => d.FiledTime >= dto.FiledTimeStart) .WhereIF(dto.FiledTimeEnd.HasValue, d => d.FiledTime <= dto.FiledTimeEnd) .WhereIF(dto.QuerySelf.HasValue && dto.QuerySelf.Value, d => d.WaitForPublisherId == _sessionContext.RequiredUserId) .WhereIF(dto.IsOverTime == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //是 超期 .WhereIF(dto.IsOverTime == false, d => (d.ExpiredTime > DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime > d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //否 超期 .OrderByDescending(d => d.FiledTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 批量发布工单 /// /// /// [HttpPost("batch-publish")] public async Task BatchPublishOrder([FromBody] BatchPublishOrderDto dto) { //任务 127 市州通用-会签件需支持批量发布 //会签件也需支持批量发布;若会签件要批量发布,就默认不公开,只对实际办理部门进行回访即可 var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.CounterSignType != null); //var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id)); if (hasHuiQian) throw UserFriendlyException.SameMessage("选择的工单中含有会签工单, 不能批量发布. 请排除会签工单."); var hasProvince = false; //if (hasProvince) // throw UserFriendlyException.SameMessage("选择的工单中含有省工单, 不能批量发布. 请排除省工单."); if (_appOptions.Value.IsYiBin || _appOptions.Value.IsZiGong) { hasProvince = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.IsProvince); } else { hasProvince = await _orderRepository.Queryable().AnyAsync(x => dto.Ids.Contains(x.Id) && x.Source == ESource.ProvinceStraight); } if (hasProvince) throw UserFriendlyException.SameMessage("选择的工单中含有省工单, 不能批量发布. 请排除省工单."); var orderList = await _orderRepository.Queryable().Where(x => dto.Ids.Contains(x.Id)).ToListAsync(); foreach (var order in orderList) { if (order != null && order.Status == EOrderStatus.Filed) { try { await _orderDomainService.OrderPublishAsync(order, HttpContext.RequestAborted); } catch { } } } } /// /// 发布工单 /// /// [HttpPost("publish")] [LogFilter("发布工单")] public async Task PublishOrder([FromBody] PublishOrderDto dto) { //验证订单 var order = await _orderRepository.GetAsync(dto.Id, HttpContext.RequestAborted) ?? throw UserFriendlyException.SameMessage("未找到工单,无法发布"); if (order.Status != EOrderStatus.Filed) throw UserFriendlyException.SameMessage("当前状态无法发布"); var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled; if (enabled) { // 获取上一次被取消发布的发布信息 var publishedDeleted = await _orderPublishRepository.Queryable().Where(m => m.OrderId == dto.Id && m.IsDeleted == true) .OrderByDescending(m => m.CreationTime).FirstAsync(HttpContext.RequestAborted); if (publishedDeleted != null && _sessionContext.RequiredUserId != publishedDeleted.CreatorId) { throw UserFriendlyException.SameMessage($"该工单被取消发布过, 之前的发布人是 [{publishedDeleted.CreatorName}], 您不能发布;"); } } //新增发布工单 var orderPublish = _mapper.Map(dto); orderPublish.OrderId = order.Id; orderPublish.No = order.No; string id = await _orderPublishRepository.AddAsync(orderPublish); order.Publish(orderPublish.PublishState); await _orderRepository.UpdateAsync(order); //推省上 var publishPublishOrder = _mapper.Map(orderPublish); publishPublishOrder.Order = _mapper.Map(order); //查询实际办理附件 if (!string.IsNullOrEmpty(order.ActualHandleStepId)) { var actualHandleStep = await _workflowStepRepository.GetAsync(order.ActualHandleStepId, HttpContext.RequestAborted); publishPublishOrder.FileJsons = actualHandleStep?.FileJson; } await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder); //推应急管理局 //是否开启 var isOpenContingencyManagement = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenContingencyManagement)?.SettingValue[0]; if (isOpenContingencyManagement == "true") await _publisher.PublishAsync(new ContingencyManagementNotify(order, dto.ArrangeTitle, dto.ArrangeContent, dto.ArrangeOpinion), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted); // 取消发布功能开关 var cancelPublishOrderEnabled = _systemSettingCacheManager.CancelPublishOrderEnabled; // 取消发布的工单 var publishOrder = await _orderPublishRepository.Queryable(includeDeleted: true) .Where(m => m.OrderId == order.Id && m.IsDeleted == true) .FirstAsync(HttpContext.RequestAborted); // 若取消发布的工单,已经被回访过了,没有经过重新办理,再次发布后,自动跳过回访环节,展示取消发布前的回访结果 if (publishOrder != null && cancelPublishOrderEnabled == true) { var history = new OrderPublishHistory { ArrangeTitleBefor = publishOrder.ArrangeTitle, ArrangeTitleAfter = dto.ArrangeTitle, ArrangeContentBefor = publishOrder.ArrangeContent, ArrangeContentAfter = dto.ArrangeContent, ArrangeOpinionBefor = publishOrder.ArrangeOpinion, ArrangeOpinionAfter = dto.ArrangeOpinion, PublishStateBefor = publishOrder.PublishState, PublishStateAfter = dto.PublishState, No = publishOrder.No, OrderId = publishOrder.OrderId, OrderPublishId = publishOrder.Id }; await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted); await _orderPublishRepository.RemoveAsync(publishOrder, false, HttpContext.RequestAborted); return; } var orderVisit = new OrderVisit(); orderVisit.No = order.No; orderVisit.OrderId = order.Id; orderVisit.VisitState = EVisitState.WaitForVisit; orderVisit.PublishTime = DateTime.Now; orderVisit.IsCanHandle = true; if (!order.IsProvince) { orderVisit.EmployeeId = _sessionContext.RequiredUserId; } if (_appOptions.Value.IsZiGong) { orderVisit.EmployeeId = string.Empty; } if (order is { FileOrgIsCenter: true, CounterSignType: null } && !order.IsProvince) { orderVisit.VisitState = EVisitState.Visited; orderVisit.VisitTime = DateTime.Now; orderVisit.VisitType = EVisitType.OtherVisit; orderVisit.NowEvaluate = new Kv() { Key = "4", Value = "满意" }; if (_appOptions.Value.IsZiGong) { // 根据禅道 自贡需求 Id_361, 第一条, 3小条需求; // 直办件归档后自动回访量需统计在“胡玲”的默认回访量中; orderVisit.EmployeeId = _systemSettingCacheManager.DefaultVisitEmployeeId; } } if (order.CounterSignType != ECounterSignType.Center) { orderVisit.IsCanAiVisit = true; } string visitId = await _orderVisitRepository.AddAsync(orderVisit); await _orderSnapshotApplication.UpdateLabelAsync(order.Id, dto.SnapshotLabels); //新增回访信息 var visitedDetail = new List(); var seatDetail = new OrderVisitDetail(); seatDetail.VisitId = visitId; seatDetail.VisitTarget = EVisitTarget.Seat; foreach (var item in dto.IdNames) { var orgDetail = new OrderVisitDetail(); orgDetail.VisitId = visitId; orgDetail.VisitOrgCode = item.Key; orgDetail.VisitOrgName = item.Value; orgDetail.VisitTarget = EVisitTarget.Org; if (order is { CounterSignType: null, FileOrgIsCenter: true }) { var satisfy = new Kv() { Key = "4", Value = "满意" }; orgDetail.OrgProcessingResults = satisfy; //orgDetail.OrgHandledAttitude = satisfy; } visitedDetail.Add(orgDetail); } if (order is { FileOrgIsCenter: true, CounterSignType: null, IsProvince: false }) { seatDetail.VoiceEvaluate = EVoiceEvaluate.Satisfied; seatDetail.SeatEvaluate = ESeatEvaluate.Satisfied; order.Visited("4", "满意"); order.Status = EOrderStatus.Visited; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); } visitedDetail.Add(seatDetail); await _orderVisitedDetailRepository.AddRangeAsync(visitedDetail, HttpContext.RequestAborted); //handle publish trace var acceptor = new UserInfo(orderPublish.CreatorId, orderPublish.CreatorName, orderPublish.CreatorOrgId, orderPublish.CreatorOrgName); var handler = new UserInfo(orderPublish.CreatorId, orderPublish.CreatorName, orderPublish.CreatorOrgId, orderPublish.CreatorOrgName); //上面回访人取值当前操作人,所以暂时可取值SessionContext,如需求有变需取值ordervisit中指定的回访人 var visitAcceptor = string.IsNullOrEmpty(orderVisit.EmployeeId) ? new UserInfo() : new UserInfo(_sessionContext.UserId, _sessionContext.UserName, _sessionContext.OrgId, _sessionContext.OrgName, _sessionContext.OrgIsCenter); await _workflowDomainService.HandlePublishTraceAsync(order.WorkflowId, orderPublish.Id, acceptor, handler, orderPublish.CreationTime, visitAcceptor, orderVisit.Id, HttpContext.RequestAborted); //需求251 某些工单需自动发送短信 //任何类型的省工单都不需要发送短信 var isOpenSendEndSms = _systemSettingCacheManager.GetSetting(SettingConstants.IsOpenSendEndSms)?.SettingValue[0]; if (isOpenSendEndSms == "true") { try { if (order.Source != ESource.ProvinceStraight && order.FileOrgIsCenter.Value == false) { var code = ""; //受理类型为“投诉、举报” if ((order.AcceptTypeCode == "30" || order.AcceptTypeCode == "35") && orderVisit.VisitState != EVisitState.Visited) { code = "1017"; orderVisit.VisitState = EVisitState.SMSVisiting; await _orderVisitRepository.UpdateAsync(orderVisit); } else code = "1018"; var messageDto = new Share.Dtos.Push.MessageDto { PushBusiness = EPushBusiness.SearchSms, ExternalId = visitId, OrderId = order.Id, PushPlatform = EPushPlatform.Sms, Remark = order.Title, Name = order.FromName, TemplateCode = code, Params = new List() { order.No, order.Password }, TelNumber = order.Contact, }; await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted); // 发送短信后推送一个 48小时的延迟消息队列. 当消息队列收到消息时, 判断用户是否回复了, 如果未回复短信就 默认满意 var delaySecond = _systemSettingCacheManager.DefaultVisitSmsDelaySecond; await _capPublisher.PublishDelayAsync( TimeSpan.FromSeconds(delaySecond), EventNames.UpdateVisitDelaySms, messageDto, cancellationToken: HttpContext.RequestAborted); } } catch (Exception) { } } if (orderVisit.VisitState == EVisitState.Visited && !order.IsProvince) { //推省上 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisited, new PublishVisitDto() { Order = _mapper.Map(order), No = orderVisit.No, VisitType = orderVisit.VisitType, VisitName = orderVisit.CreatorName, VisitTime = orderVisit.VisitTime, VisitRemark = orderVisit.NowEvaluate?.Value, AreaCode = order.AreaCode!, SubjectResultSatifyCode = orderVisit.NowEvaluate?.Key, FirstSatisfactionCode = orderVisit.NowEvaluate?.Key, ClientGuid = "" }, cancellationToken: HttpContext.RequestAborted); } //推送回访信息 //推门户 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderVisitedWeb, new PublishVisitAllDto() { Id = orderVisit.Id, Order = _mapper.Map(order), OrderVisitDetails = _mapper.Map>(orderVisit.OrderVisitDetails), VisitName = _sessionContext.UserName, VisitTime = orderVisit.VisitTime, VisitType = orderVisit.VisitType, VisitState = orderVisit.VisitState, PublishTime = orderVisit.PublishTime, }, cancellationToken: HttpContext.RequestAborted); } /// /// 发布页面基础信息 /// /// [HttpGet("publish-order-pagebase/{id}")] public async Task PublishOrderPageBase(string id) { var order = await _orderRepository.Queryable() .Includes(d => d.OrderExtension) .FirstAsync(d => d.Id == id); if (order is null) throw UserFriendlyException.SameMessage("未知工单,无法发布"); var res = new PublishOrderPageBaseDto() { SourceChannel = order.SourceChannel, OrderTitle = order.Title, Content = order.Content, ActualOpinion = order.FileOpinion, NetizenEvaluateType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.NetizenEvaluateType) .Select(x => new Kv { Key = x.DicDataValue, Value = x.DicDataName }).ToList() }; var (idName, idNames) = await _workflowDomainService.GetHandleOrgsAsync(order.WorkflowId, HttpContext.RequestAborted); res.ActualHandleOrgName = new Kv() { Key = order.ActualHandleOrgCode, Value = order.ActualHandleOrgName }; res.idNames = order.CounterSignType == null ? null : idNames.Where(d => d.Key != idName.Key).ToList(); if (_systemSettingCacheManager.Snapshot) { res.IsSnapshot = await _orderSnapshotRepository.AnyAsync(m => m.Id == order.Id); res.SnapshotLabel = _sysDicDataCacheManager.SnapshotOrderLabel; } return res; } /// /// 已发布列表 /// /// /// [HttpGet("published")] [Obsolete("前端不再调用,择机删除")] public async Task> PublishedOrderList([FromQuery] PublishedPagedRequest dto) { var (total, items) = await _orderPublishRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.StartsWith(dto.Keyword!)) .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.Order.No.Contains(dto.No!)) .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Order.Title.Contains(dto.Title!)) .WhereIF(dto.CreationTimeStart.HasValue, d => d.Order.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.Order.CreationTime <= dto.CreationTimeEnd) .WhereIF(!string.IsNullOrEmpty(dto.FromPhone), d => d.Order.FromPhone == dto.FromPhone) //来电号码 .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.Order.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) //接办部门(综合查询模糊) .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.Order.AcceptTypeCode == dto.AcceptType) //受理类型 .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.Order.HotspotSpliceName != null && d.Order.HotspotSpliceName.Contains(dto.Hotspot)) .WhereIF(!string.IsNullOrEmpty(dto.PublishName), d => d.CreatorName.Contains(dto.PublishName!)) .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.Order.AcceptorName == dto.NameOrNo! || d.Order.AcceptorStaffNo == dto.NameOrNo!) //受理人/坐席 .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime) .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime) .WhereIF(dto.Resolve.HasValue, x => x.Resolve == dto.Resolve) .WhereIF(dto.IsOverTime == true, d => (d.Order.ExpiredTime < DateTime.Now && d.Order.Status < EOrderStatus.Filed) || (d.Order.ExpiredTime < d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //是 超期 .WhereIF(dto.IsOverTime == false, d => (d.Order.ExpiredTime > DateTime.Now && d.Order.Status < EOrderStatus.Filed) || (d.Order.ExpiredTime > d.Order.ActualHandleTime && d.Order.Status >= EOrderStatus.Filed)) //否 超期 .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 发布列表(集合) /// /// /// [HttpGet("published/items")] public async Task> GetPublishedOrderListAsync([FromQuery] PublishedPagedRequest dto) { //var query = _orderApplication.GetPublishedOrder(dto); //return (await query.ToFixedListAsync(dto.QueryIndex, 200, HttpContext.RequestAborted)) //.Adapt>(); var orderPublishs = await _orderApplication.GetPublishedOrder(dto) .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); return _mapper.Map>(orderPublishs); } /// /// 发布列表(总条数) /// /// /// [HttpGet("published/count")] public async Task GetPublishedOrderCountAsync([FromQuery] PublishedPagedRequest dto) { return await _orderApplication.GetPublishedOrder(dto).CountAsync(); } /// /// 发布列表数据--导出 /// /// /// [HttpPost("publishedorder/export")] public async Task ExportPublishedOrders([FromBody] ExportExcelDto dto) { var query = _orderApplication.GetPublishedOrder(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var orderDtos = _mapper.Map>(orders); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orderDtos .Select(stu => _mapper.Map(stu, typeof(PublishedDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "发布列表数据"); } /// /// 发布详情 /// /// /// [HttpGet("published-order/{id}")] public async Task PublishedOrder(string id) { var publishedOrder = await _orderPublishRepository.GetAsync(id, HttpContext.RequestAborted); if (publishedOrder is null) { throw UserFriendlyException.SameMessage("未知数据!"); } var pubentity = _mapper.Map(publishedOrder); var visit = await _orderVisitRepository.Queryable().Includes(x => x.OrderVisitDetails) .OrderByDescending(x => x.CreationTime) .FirstAsync(x => x.OrderId == publishedOrder.OrderId, HttpContext.RequestAborted); if (visit != null) { var details = visit.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList(); if (details != null && details.Count > 0) { pubentity.IdNames = new List(); details.ForEach(f => pubentity.IdNames.Add(new Kv() { Key = f.VisitOrgCode, Value = f.VisitOrgName })); } } if (_systemSettingCacheManager.Snapshot) { await _orderSnapshotRepository.GetAsync(pubentity.OrderId) .Then(m => { pubentity.Labels = m.Labels; }); } return pubentity; } /// /// 修改发布内容 /// /// /// [HttpPost("published-order-modify")] [LogFilter("修改发布内容")] public async Task PublishedModify([FromBody] PublishOrderModifyDto dto) { var publishOrder = await _orderPublishRepository.Queryable() .Includes(x => x.Order) .Where(x => x.Id == dto.Id) .FirstAsync(HttpContext.RequestAborted); if (publishOrder is null) { throw UserFriendlyException.SameMessage("无效数据"); } var history = new OrderPublishHistory(); history.ArrangeTitleBefor = publishOrder.ArrangeTitle; history.ArrangeTitleAfter = dto.ArrangeTitle; history.ArrangeContentBefor = publishOrder.ArrangeContent; history.ArrangeContentAfter = dto.ArrangeContent; history.ArrangeOpinionBefor = publishOrder.ArrangeOpinion; history.ArrangeOpinionAfter = dto.ArrangeOpinion; history.PublishStateBefor = publishOrder.PublishState; history.PublishStateAfter = dto.PublishState; history.No = publishOrder.No; history.OrderId = publishOrder.OrderId; history.OrderPublishId = publishOrder.Id; publishOrder.ArrangeTitle = dto.ArrangeTitle; publishOrder.ArrangeContent = dto.ArrangeContent; publishOrder.ArrangeOpinion = dto.ArrangeOpinion; publishOrder.PublishState = dto.PublishState; await _orderPublishRepository.UpdateAsync(publishOrder, HttpContext.RequestAborted); await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted); //推省上 var publishPublishOrder = _mapper.Map(publishOrder); publishPublishOrder.Order = _mapper.Map(publishOrder.Order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderPublishOrder, publishPublishOrder); } /// /// 发布修改记录 /// /// /// [HttpGet("published-history-list/{id}")] public async Task> QueryPublishedHistory(string id) { return await _orderPublishHistoryRepository.Queryable().Where(x => x.OrderPublishId == id) .OrderByDescending(x => x.CreationTime).ToListAsync(HttpContext.RequestAborted); } /// /// 查询发布平移待办理人 /// [HttpGet("published/migration")] public async Task> PublishMigration() { var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan); var roles = setting?.SettingValue.ToList(); var users = await _userRepository.Queryable() .Includes(d => d.Organization) .Includes(d => d.Roles) .WhereIF(!_appOptions.Value.IsZiGong && !_appOptions.Value.IsLuZhou, d => d.Roles.Any(x => roles.Contains(x.Name))) .WhereIF(_appOptions.Value.IsZiGong || _appOptions.Value.IsLuZhou, d => d.OrgId == OrgSeedData.CenterId) .ToListAsync(HttpContext.RequestAborted); return users.Select(d => new OrderMigrationHandler { UserId = d.Id, Username = d.Name, OrgId = d.OrgId, OrgName = d.Organization.Name, RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList()) }).ToList(); } /// /// 发布平移 /// [HttpPost("publish/migration")] public async Task PublishMigrationBatch([FromBody] PublishMigrationDto dto) { var orders = await _orderRepository.Queryable() .Where(d => dto.OrderIds.Contains(d.Id) && d.Status == EOrderStatus.Filed) .ToListAsync(HttpContext.RequestAborted); foreach (var order in orders) { order.WaitForPublisherId = dto.UserId; } await _orderRepository.UpdateRangeAsync(orders, HttpContext.RequestAborted); } /// /// 列表页面基础数据 /// /// [HttpGet("publish/base-data")] public async Task PublishBaseData() { var rsp = new { ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel), AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag) }; return rsp; } /// /// 取消发布 /// /// /// [HttpPut("publish/cancel")] [LogFilter("取消发布")] public async Task PublishCancelAsync([FromBody] PublishCancelInDto dto) { var enabled = _systemSettingCacheManager.CancelPublishOrderEnabled; if (enabled == false) return "取消发布功能已被关闭"; var publish = await _orderPublishRepository.GetAsync(dto.OrderPublishId) ?? throw UserFriendlyException.SameMessage("发布单不存在"); publish.IsDeleted = true; var order = await _orderRepository.GetAsync(publish.OrderId, HttpContext.RequestAborted) ?? throw UserFriendlyException.SameMessage("工单不存在"); if (order.Status != EOrderStatus.Published && order.Status != EOrderStatus.Visited) throw UserFriendlyException.SameMessage("工单状态非[已发布]和[已回访], 不可取消发布."); await _orderPublishRepository.UpdateAsync(publish); order.Status = EOrderStatus.Filed; // 被取消的工单继续由之前发布的用户继续发布; order.WaitForPublisherId = publish.CreatorId; await _orderRepository.UpdateAsync(order); return "取消成功"; } #endregion #region 工单回访 /// /// 回访列表 /// /// /// [HttpGet("visit")] public async Task> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto) { var (total, items) = await _orderApplication.QueryOrderVisitList(dto) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); //var orderVisits = await _orderApplication.QueryOrderVisitList(dto) // .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); //return _mapper.Map<>() } /// /// 回访列表--导出 /// /// /// [HttpPost("visit/export")] public async Task ExportOrderVisit([FromBody] ExportExcelDto dto) { var query = _orderApplication.QueryOrderVisitList(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var orderDtos = _mapper.Map>(orders); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orderDtos .Select(stu => _mapper.Map(stu, typeof(OrderVisitDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); var excelTitle = dto.QueryDto.VisitStateQuery == EVisitStateQuery.NoVisit ? "回访待办数据" : "回访列表数据"; return ExcelStreamResult(stream, excelTitle); } /// /// 发送 回访短信 /// /// [HttpPost("visit/sms")] public async Task VisitPushSMSAsync([FromBody] VisitSmsInDto dto) => await _orderApplication.VisitPushSMSAsync(dto, HttpContext.RequestAborted); /// /// 回访查询基础数据 /// /// [HttpGet("visit/basedata")] public Dictionary VisitBaseData() { var voiceEvaluate = EnumExts.GetDescriptions(); var seatEvaluate = EnumExts.GetDescriptions(); if (_appOptions.Value.IsZiGong == true) { voiceEvaluate = EnumExtensions.GetEnumKeyValueList(); seatEvaluate = EnumExtensions.GetEnumKeyValueList(); } var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction); var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner); if (_appOptions.Value.IsZiGong == false) { seatEvaluate = seatEvaluate.Where(m => new int[] { -1, 1, 3 }.Contains(m.Key) == false).ToList(); visitSatisfaction = visitSatisfaction.Where(x => x.DicDataValue != "-1").ToList(); visitManner = visitManner.Where(x => x.DicDataValue != "-1").ToList(); } return new Dictionary { { "seatEvaluate", seatEvaluate }, { "visitType", EnumExts.GetDescriptions() }, { "voiceEvaluate", voiceEvaluate }, { "visitSatisfaction", visitSatisfaction }, { "visitMananer", visitManner }, { "visitStateQuery", EnumExts.GetDescriptions() }, { "sourceChannel", _sysDicDataCacheManager.SourceChannel }, { "aiVisitResult", EnumExts.GetDescriptions() } }; } /// /// 回访详情 /// /// [HttpGet("visit/{id}")] [AllowAnonymous] public async Task VisitInfo(string id) { var orderVisit = await _orderVisitRepository.Queryable() .Includes(x => x.Order) .Includes(x => x.Employee) .Includes(x => x.OrderVisitDetails.OrderBy(d => d.VisitTarget).ToList()) .FirstAsync(x => x.Id == id, HttpContext.RequestAborted); if (orderVisit is null) { throw UserFriendlyException.SameMessage("未知工单回访"); } int visitCount = await _orderVisitRepository.CountAsync( x => x.OrderId == orderVisit.OrderId && x.VisitState == Share.Enums.Order.EVisitState.Visited, HttpContext.RequestAborted); //int againCount = await _orderVisitRepository.CountAsync( // x => x.OrderId == orderVisit.OrderId && x.AgainState == EAgainState.DoAgain, HttpContext.RequestAborted); var voiceEvaluate = EnumExts.GetDescriptions(); var seatEvaluate = EnumExts.GetDescriptions(); if (_appOptions.Value.IsZiGong == true) { voiceEvaluate = EnumExtensions.GetEnumKeyValueList(); seatEvaluate = EnumExtensions.GetEnumKeyValueList(); } var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction); var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner); if (_appOptions.Value.IsZiGong == false) { seatEvaluate = seatEvaluate.Where(m => new int[] { -1, 1, 3 }.Contains(m.Key) == false).ToList(); visitSatisfaction = visitSatisfaction.Where(x => x.DicDataValue != "-1").ToList(); visitManner = visitManner.Where(x => x.DicDataValue != "-1").ToList(); } var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason); //var callRecord = await _trCallRecordRepository.GetAsync(x => x.CallAccept == orderVisit.CallId); //由CallAccept改为OtherAccept //var callRecord = await _trCallRecordRepository.GetAsync(x => x.OtherAccept == orderVisit.CallId && string.IsNullOrEmpty(x.OtherAccept) == false, HttpContext.RequestAborted); var recordingFileUrl = ""; var recordingBaseAddress = ""; var recordingAbsolutePath = ""; var aiVisitVoiceBaseUrl = ""; if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun) { var callRecord = await _callApplication.GetTianrunCallAsync(orderVisit.CallId, HttpContext.RequestAborted); if (callRecord != null) { recordingFileUrl = callRecord.RecordingFileUrl; recordingBaseAddress = callRecord.RecordingBaseAddress; recordingAbsolutePath = callRecord.RecordingAbsolutePath; } } else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang) { CallNative? call = null; if (orderVisit.CallId == null && orderVisit.VisitTime.HasValue) { call = await _callApplication.GetCallByTimeAndToNoAsync(orderVisit.Order.Contact, orderVisit.VisitTime.Value, HttpContext.RequestAborted); } call = await _callApplication.GetCallAsync(orderVisit.CallId, HttpContext.RequestAborted); if (call is not null) { if (call.AudioFile.IsNullOrEmpty()) { call = await _callApplication.GetCallByCallNoAsync(call.CallNo, HttpContext.RequestAborted); } if (call is not null) { recordingFileUrl = call.AudioFile; recordingBaseAddress = call.AudioFile; recordingAbsolutePath = call.AudioFile; } } } //获取系统配置智能回访语音URL头 aiVisitVoiceBaseUrl = _systemSettingCacheManager.GetSetting(SettingConstants.AiVisitVoiceBaseUrl)?.SettingValue[0]; var histories = new List(); if (_appOptions.Value.IsZiGong) { histories = await _orderVisitRepository.Queryable() .Includes(m => m.OrderVisitDetails) .Where(m => m.OrderId == orderVisit.OrderId) .Where(m => m.VisitState == EVisitState.None && m.NowEvaluate != null) .Select(m => new OrderVisitDetailHistoryDto { VoiceEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.VoiceEvaluate).First(), SeatEvaluate = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Seat).Select(s => s.SeatEvaluate).First(), VisitOrgName = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitOrgName).First(), OrgProcessingResults = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgProcessingResults) .First(), OrgHandledAttitude = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.OrgHandledAttitude).First(), VisitContent = m.OrderVisitDetails.Where(n => n.VisitTarget == EVisitTarget.Org).Select(s => s.VisitContent).First(), VisitTime = m.VisitTime, CallId = m.CallId }).ToListAsync(); } var seat = orderVisit.OrderVisitDetails.FirstOrDefault(m => m.VisitTarget == EVisitTarget.Seat); //if (orderVisit.VisitState == EVisitState.WaitForVisit) if (seat.VoiceEvaluate == null) { if (!_appOptions.Value.IsYiBin) { // 如果是待回访, 就取用户电话评价时评价的内容; var callNative = await _callApplication.GetReplyVoiceOrDefaultByOrderIdAsync(orderVisit.OrderId); seat.VoiceEvaluate = callNative; } } if (seat.SeatEvaluate is null) { if (_appOptions.Value.IsYiBin) { var seatEvaluateTemp = await _callApplication.GetSeatDefaultByOrderIdAsync(orderVisit.OrderId); seat.SeatEvaluate = seatEvaluateTemp; } } return new { OrderVisitModel = _mapper.Map(orderVisit), VisitCount = visitCount, //AgainCount = againCount, VisitSatisfaction = visitSatisfaction, DissatisfiedReason = dissatisfiedReason, VisitManner = visitManner, ViceEvaluate = voiceEvaluate, SeatEvaluate = seatEvaluate, RecordingFileUrl = recordingFileUrl, RecordingBaseAddress = recordingBaseAddress, RecordingAbsolutePath = recordingAbsolutePath, AiVisitVoiceBaseUrl = aiVisitVoiceBaseUrl, Histories = histories }; } /// /// 回访明细 /// /// [HttpGet("visit/detail")] public async Task> VisitDetailList([FromQuery] VisitDetailListDto dto) { var (total, items) = await _orderVisitedDetailRepository.Queryable() .Includes(x => x.OrderVisit, s => s.Order) .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit, x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.WaitForVisit || x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.NoSatisfiedWaitForVisit) .WhereIF(dto.VisitState == EVisitStateQuery.Visited, x => x.OrderVisit.VisitState == Share.Enums.Order.EVisitState.Visited) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.OrderVisit.Order.Title.Contains(dto.Keyword!) || d.OrderVisit.Order.No.Contains(dto.Keyword!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 回访保存 /// /// [HttpPost("visit")] [LogFilterAlpha("工单回访")] public async Task Visit([FromBody] VisitDto dto) { // 发送延迟关联通话记录消息 dto.CallId = await _callApplication.PublishVisitRelevanceCallIdAsync(dto.Adapt(), HttpContext.RequestAborted); dto.CallId = await _callApplication.GetOrSetCallIdAsync(dto.CallId, HttpContext.RequestAborted); await _orderApplication.SaveOrderVisit(dto, HttpContext.RequestAborted); } /// /// 批量保存回访 /// /// /// [HttpPost("visit/batch")] [LogFilter("批量工单回访")] public async Task VisitBatch([FromBody] VisitBatchInDto dto) { var errorMessage = new StringBuilder(); var outDto = new VisitBatchOutDto(); var orderIds = dto.Visit.Select(m => m.OrderId).ToList(); var hasHuiQian = await _orderRepository.Queryable().AnyAsync(x => orderIds.Contains(x.Id) && x.CounterSignType != null); if (hasHuiQian) throw UserFriendlyException.SameMessage("选择的回访单中含有会签工单, 不能批量回访. 请排除会签工单."); var hasProvince = await _orderRepository.Queryable().AnyAsync(x => orderIds.Contains(x.Id) && x.IsProvince == true); if (hasProvince) throw UserFriendlyException.SameMessage("选择的回访单中含有省工单, 不能批量回访. 请排除省工单."); foreach (var visit in dto.Visit) { try { var details = await _orderVisitedDetailRepository .Queryable() .Where(m => m.VisitId == visit.VisitId) .ToListAsync(); var seatDetail = details.First(m => m.VisitTarget == EVisitTarget.Seat); var seatDetailDto = new VisitDetailDto() { Id = seatDetail.Id, VisitId = visit.VisitId, VisitContent = dto.SeatVisitContent, SeatEvaluate = dto.SeatEvaluate, VisitTarget = EVisitTarget.Seat, }; if (seatDetail.VoiceEvaluate == null) seatDetailDto.VoiceEvaluate = EVoiceEvaluate.DefaultSatisfied; var visitDto = new VisitDto { Id = visit.VisitId, IsPutThrough = true, IsAgain = false, VisitDetails = new List() }; visitDto.VisitDetails.Add(seatDetailDto); var orgDetails = details.Where(m => m.VisitTarget == EVisitTarget.Org).ToList(); foreach (var orgDetail in orgDetails) { visitDto.VisitDetails.Add( new() { Id = orgDetail.Id, VisitId = visit.VisitId, VisitContent = dto.OrgVisitContent, VisitTarget = EVisitTarget.Org, OrgNoSatisfiedReason = dto.OrgNoSatisfiedReason, OrgProcessingResults = dto.OrgProcessingResults, OrgHandledAttitude = dto.OrgHandledAttitude, VisitOrgName = orgDetail.VisitOrgName, VisitOrgCode = orgDetail.VisitOrgCode, }); } if (visitDto.CallId != null) { visitDto.CallId = await _callApplication.GetOrSetCallIdAsync(visitDto.CallId, HttpContext.RequestAborted); } await _orderApplication.SaveOrderVisit(visitDto, HttpContext.RequestAborted); await _orderVisitRepository.Updateable() .Where(m => m.Id == visit.VisitId) .SetColumns(m => m.IsBatchVisit == true) .ExecuteCommandAsync(); outDto.CompleteCount += 1; } catch (Exception e) { outDto.ErrorCount += 1; errorMessage.Append($"【{visit.No}】 保存失败."); _logger.LogError($"orderVisitId:{visit.VisitId} 保存回访失败, err: {e.Message}"); } finally { outDto.TotalCount += 1; } } outDto.ErrorMessage = errorMessage.ToString(); return outDto; } /// /// 批量保存回访基础数据 /// /// /// [HttpGet("visit/batch-basedata")] public Dictionary VisitBatchBaseDat() { //return _baseDataApplication // .SeatEvaluate() // .DissatisfiedReason() // .VisitSatisfaction() // .VisitManner() // .Build(); return new Dictionary { { "seatEvaluate", EnumExts.GetDescriptions() }, { "dissatisfiedReason", _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason) }, { "visitSatisfaction", _sysDicDataCacheManager.GetVisitSatisfaction() }, { "visitManner", _sysDicDataCacheManager.VisitMananer } }; } /// /// 扭转列表 /// /// /// [HttpGet("visit/judge-query")] public async Task> VisitJudgeQuery([FromQuery] VisitJudgeQueryReq dto) { var (total, items) = await _orderRepository.VisitJudgeQuery(dto) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 扭转列表查询基础数据 /// /// [HttpGet("visit/judge-query-basedata")] public async Task VisitJudgeQueryBaseData() { return new { FiledTypeOptions = EnumExts.GetDescriptions(), AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), OrgsOptions = await _organizeRepository.GetOrgJson(), CallForwardingOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.CallForwardingSource), JudgeStateOptions = EnumExts.GetDescriptions() }; } /// /// 扭转列表导出 /// /// /// [HttpPost("visit/judge-query-export")] public async Task VisitJudgeQueryExport([FromBody] ExportExcelDto dto) { var query = _orderRepository.VisitJudgeQuery(dto.QueryDto); List datas; if (dto.IsExportAll) { datas = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); datas = items; } var orderDtos = _mapper.Map>(datas); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orderDtos .Select(stu => _mapper.Map(stu, typeof(OrderVisitDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "扭转明细"); } /// /// 扭转满意度 /// /// /// [HttpPost("visit/judge")] public async Task JudgeVisit([FromBody] JudgeVisitReq dto) { int error = 0; var list = await _orderVisitRepository.Queryable().Where(x => dto.Ids.Contains(x.Id) && x.VisitState == EVisitState.Visited) .ToListAsync(HttpContext.RequestAborted); list.ForEach(visit => { visit.JudgeState = dto.IsAgree ? EJudgeState.Agreed : EJudgeState.UnAgreed; visit.JudgeUserId = _sessionContext.RequiredUserId; visit.JudgeUserName = _sessionContext.UserName; visit.JudgeTime = DateTime.Now; visit.JudgeContent = dto.JudgeContent; }); await _orderVisitRepository.UpdateRangeAsync(list, HttpContext.RequestAborted); return new JudgeVisitRsp() { ErrorCount = error, SuccessCount = dto.Ids.Count - error }; } /// /// 回访平移 /// /// /// [HttpPost("visit/migration")] public async Task VisitMigrationBatch([FromBody] DistributionVisitDto dto) { var visits = await _orderVisitRepository.Queryable() .Where(d => (d.VisitState == EVisitState.WaitForVisit || d.VisitState == EVisitState.SMSUnsatisfied) && dto.Ids.Contains(d.Id)) .ToListAsync(HttpContext.RequestAborted); foreach (var visit in visits) { visit.EmployeeId = dto.UserId; } await _orderVisitRepository.UpdateRangeAsync(visits, HttpContext.RequestAborted); } /// /// 查询回访平移待办理人 /// [HttpGet("ordervisit/migration")] public async Task> VisitMigration() { var setting = _systemSettingCacheManager.GetSetting(SettingConstants.OrderVisitRole); var roles = setting?.SettingValue.ToList(); var users = await _userRepository.Queryable() .Includes(d => d.Organization) .Includes(d => d.Roles) .WhereIF(!_appOptions.Value.IsZiGong, d => d.Roles.Any(x => roles.Contains(x.Name))) .WhereIF(_appOptions.Value.IsZiGong, d => d.OrgId == OrgSeedData.CenterId) .ToListAsync(HttpContext.RequestAborted); return users.Select(d => new OrderMigrationHandler { UserId = d.Id, Username = d.Name, OrgId = d.OrgId, OrgName = d.Organization.Name, RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList()) }).ToList(); } /// /// 设置未接通 /// /// /// [HttpPut("visit/put_through")] public async Task VisitPutThrough([FromBody] VisitPutThroughDto dto) { await _orderVisitRepository.Updateable().SetColumns(x => new OrderVisit { IsPutThrough = false }).Where(x => x.Id == dto.id) .ExecuteCommandAsync(HttpContext.RequestAborted); } /// /// 部门满意度明细 /// /// /// [HttpGet("org-visitdetail-list")] public async Task> OrgVisitDetailList([FromQuery] OrgVisitDetailListReq dto) { //特殊需求:管理员账号使用该查询条件查询的数据,与富顺的账号查询的数据一致; var isAdmin = _orderDomainService.IsCheckAdmin(); var orgId = isAdmin ? "001059" : _sessionContext.RequiredOrgId; var query = _orderRepository.OrgVisitDetailFiltrationList(dto, orgId); var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 部门满意度明细导出 /// /// /// [HttpPost("org-visitdetail-list-export")] public async Task OrgVisitDetailListExport([FromBody] ExportExcelDto dto) { //特殊需求:管理员账号使用该查询条件查询的数据,与富顺的账号查询的数据一致; var isAdmin = _orderDomainService.IsCheckAdmin(); var orgId = isAdmin ? "001059" : _sessionContext.RequiredOrgId; var query = _orderRepository.OrgVisitDetailFiltrationList(dto.QueryDto, orgId); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orders .Select(stu => _mapper.Map(stu, typeof(OrgVisitDetailListResp), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "部门满意度明细"); } #endregion #region 二次回访申请 /// /// 可二次回访申请列表 /// /// /// [HttpGet("visitapply/visitagainlist")] public async Task> OrderVisitAgainList([FromQuery] OrderVisitAgainListDto dto) { var (total, items) = await _orderVisitedDetailRepository.Queryable() .Includes(x => x.OrderVisit, x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderVisit.Order.No.Contains(dto.Keyword)) .Where(x => x.OrderVisit.VisitState == EVisitState.Visited && (x.OrderVisit.VisitType == EVisitType.SmsVisit || x.OrderVisit.VisitType == EVisitType.ChipVoiceVisit)) .Where(x => SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "1" || SqlFunc.JsonField(x.OrgProcessingResults, "Key") == "2") .Where(x => x.OrderVisit.IsCanHandle) .Where(x => x.VisitTarget == EVisitTarget.Org) .OrderByDescending(x => x.OrderVisit.VisitTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 二次回访申请 /// /// /// /// [HttpPost("visitapply/add")] [LogFilter("新增工单二次回访申请")] public async Task ApplyOrderVisit([FromBody] AddVisitApplyDto dto) { var orderVisitApply = _mapper.Map(dto); //验证是否可以申请二次回访 var isAny = await _orderVisitApplyRepository.AnyAsync( x => x.OrderId == orderVisitApply.OrderId && x.VisitApplyState != EVisitApplyState.NoPass, HttpContext.RequestAborted); if (isAny) throw UserFriendlyException.SameMessage("当前状态不能申请二次回访"); var orderModel = await _orderRepository.GetAsync(x => x.Id == orderVisitApply.OrderId, HttpContext.RequestAborted); if (orderModel?.CounterSignType != null) throw UserFriendlyException.SameMessage("会签件不能申请二次回访"); var orderVisitModel = await _orderVisitRepository.GetAsync(x => x.Id == dto.OrderVisitId && x.IsCanHandle, HttpContext.RequestAborted); if (orderVisitModel == null) throw UserFriendlyException.SameMessage("当前状态不能进行二次回访"); orderVisitModel.IsCanHandle = false; await _orderVisitRepository.UpdateAsync(orderVisitModel, HttpContext.RequestAborted); orderVisitApply.EmployeeId = _sessionContext.RequiredUserId; orderVisitApply.VisitApplyState = EVisitApplyState.Examining; await _orderVisitApplyRepository.AddAsync(orderVisitApply, HttpContext.RequestAborted); } /// /// 二次回访审核 /// /// /// [HttpPost("visitapply/examin")] [LogFilter("新增工单二次回访审核")] public async Task ExaminOrderVisit([FromBody] ExaminOrderVisitDto dto) { //获取二次回访申请 var visitApplyModel = await _orderVisitApplyRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (visitApplyModel == null) throw UserFriendlyException.SameMessage("无效申请"); if (visitApplyModel.VisitApplyState != EVisitApplyState.Examining) throw UserFriendlyException.SameMessage("当前状态不能审核"); if (dto.IsPass) visitApplyModel.VisitApplyState = EVisitApplyState.Pass; else visitApplyModel.VisitApplyState = EVisitApplyState.NoPass; visitApplyModel.ExaminOpinion = dto.ExaminOpinion; visitApplyModel.ExaminManId = _sessionContext.RequiredUserId; visitApplyModel.ExaminTime = DateTime.Now; await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted); //处理通过后的业务 if (dto.IsPass) { //处理申请单 visitApplyModel.VisitApplyState = EVisitApplyState.Pass; await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted); //处理原回访数据 var visitModel = await _orderVisitRepository.GetAsync(visitApplyModel.OrderVisitId, HttpContext.RequestAborted); if (visitModel != null) { visitModel.VisitState = EVisitState.None; await _orderVisitRepository.UpdateAsync(visitModel, HttpContext.RequestAborted); //处理新回访数据 //查询原回访数据子表 var visitModelNew = _mapper.Map(visitModel); visitModelNew.InitId(); visitModelNew.CreationTime = DateTime.Now; visitModelNew.CreatorId = string.Empty; visitModelNew.CreatorName = string.Empty; visitModelNew.CreatorOrgId = string.Empty; visitModelNew.CreatorOrgName = string.Empty; visitModelNew.CreatorOrgLevel = 0; visitModelNew.AreaId = string.Empty; visitModelNew.VisitState = EVisitState.WaitForVisit; visitModelNew.IsCanHandle = false; var id = await _orderVisitRepository.AddAsync(visitModelNew, HttpContext.RequestAborted); var visitModelDetail = await _orderVisitedDetailRepository.Queryable() .Where(x => x.VisitId == visitModel.Id).ToListAsync(HttpContext.RequestAborted); var visitDetailListNew = new List(); foreach (var item in visitModelDetail) { var visitDetail = new OrderVisitDetail(); visitDetail.VisitId = id; visitDetail.VisitOrgCode = item.VisitOrgCode; visitDetail.VisitOrgName = item.VisitOrgName; visitDetail.VisitTarget = item.VisitTarget; visitDetailListNew.Add(visitDetail); } await _orderVisitedDetailRepository.AddRangeAsync(visitDetailListNew, HttpContext.RequestAborted); } } else { //处理申请单 visitApplyModel.VisitApplyState = EVisitApplyState.NoPass; visitApplyModel.ExaminManId = _sessionContext.RequiredUserId; visitApplyModel.ExaminOpinion = dto.ExaminOpinion; visitApplyModel.ExaminTime = DateTime.Now; await _orderVisitApplyRepository.UpdateAsync(visitApplyModel, HttpContext.RequestAborted); var visitModel = await _orderVisitRepository.GetAsync(visitApplyModel.OrderVisitId, HttpContext.RequestAborted); if (visitModel != null) { visitModel.IsCanHandle = true; await _orderVisitRepository.UpdateAsync(visitModel, HttpContext.RequestAborted); } } } /// /// 二次回访申请列表 /// /// /// [HttpGet("visitapply/list")] public async Task> VisitApplyList([FromQuery] VisitApplyListDto dto) { var (total, items) = await _orderVisitApplyRepository.Queryable() .Includes(d => d.Order) .Includes(d => d.OrderVisit, d => d.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList()) .Includes(d => d.OrderVisit, d => d.Employee) .Includes(d => d.Employee) .WhereIF(dto.VisitApplyState != null, x => x.VisitApplyState == dto.VisitApplyState) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.OrderNo.Contains(dto.Keyword)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取二次回访申请 /// /// /// [HttpGet("visitapply/{id}")] public async Task VisitApplyEntity(string id) { var model = await _orderVisitApplyRepository.GetExtAsync(x => x.Id == id, x => x.Includes(d => d.Order)); return _mapper.Map(model); } /// /// 页面基础信息 /// /// [HttpGet("visitapply/basedata")] public async Task VisitApplyBaseData() { var rsp = new { VisitApplyState = EnumExts.GetDescriptions() }; return rsp; } #endregion #region 工单重办 /// /// 重办查询 /// /// /// [HttpGet("redo")] public async Task> QueryOrderRedo([FromQuery] QueryOrderRedoRecordDto dto) { var (total, items) = await _orderRedoRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, items); } /// /// 重办详情 /// /// /// [HttpGet("redo/{id}")] public async Task GetOrderRedo(string id) { return await _orderRedoRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); } ///// ///// 发起重办 ///// //[HttpPost("redo")] //[LogFilter("新增工单重办")] //public async Task AddRedo([FromBody] OrderRedoStartFlowDto dto) //{ // var redo = _mapper.Map(dto.Data); // redo.CreatorName = _sessionContext.UserName ?? string.Empty; // redo.CreatorOrgName = _sessionContext.OrgName ?? string.Empty; // //redo.TimeLimitCount = dto.Workflow.Extension.TimeLimitCount; // //redo.TimeLimitUnit = dto.Workflow.Extension.TimeLimitUnit; // //todo // var handler = dto.Workflow.NextHandlers.First(); // redo.RedoOrgCode = handler.Key; // redo.RedoOrgCode = handler.Value; // var id = await _orderRedoRepository.AddAsync(redo, HttpContext.RequestAborted); // try // { // var order = await _orderRepository.GetAsync(dto.Data.OrderId, HttpContext.RequestAborted); // if (order == null) // throw UserFriendlyException.SameMessage("无效工单编号"); // if (string.IsNullOrEmpty(order.WorkflowId)) // throw UserFriendlyException.SameMessage("无效工单流程编号"); // var redoFlowDto = _mapper.Map(dto.Workflow); // redoFlowDto.WorkflowId = order.WorkflowId; // await _workflowApplication.RedoAsync(redoFlowDto, HttpContext.RequestAborted); // return id; // } // catch (Exception e) // { // await _orderRedoRepository.RemoveAsync(id, cancellationToken: HttpContext.RequestAborted); // throw new UserFriendlyException($"发起重办失败,{e.Message}"); // } //} /// /// 重办基础数据 /// /// [HttpGet("base-data-redo")] public async Task BaseDataRedo() { var rsp = new { OrderRedoReasonOptions = EnumExts.GetDescriptions(), }; return rsp; } #endregion #region 工单延期 /// /// 可申请延期工单 /// /// /// [HttpGet("candelay")] public async Task> CanDelayOrderList([FromQuery] CanDelayOrderListDto dto) { var (total, items) = await _orderRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)) .Where(d => d.Status != EOrderStatus.WaitForAccept && d.Status != EOrderStatus.Filed && SqlFunc.Subqueryable() .Where(s => s.OrderId == d.Id && s.DelayState == EDelayState.Examining).NotAny()) .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 申请延期 /// /// /// [HttpPost("delay")] [LogFilter("新增工单延期申请")] public async Task ApplyDelay([FromBody] StartWorkflowDto dto) { var delaydto = dto.Data; if (string.IsNullOrEmpty(dto.Workflow.Opinion)) throw UserFriendlyException.SameMessage("办理意见不能为空!"); //验证工单是否可以申请 var order = await _orderRepository.GetAsync(delaydto.OrderId, HttpContext.RequestAborted); if (order is null) throw UserFriendlyException.SameMessage("无效工单"); //验证工单是否在办理中 if (order.Status == EOrderStatus.WaitForAccept || order.Status >= EOrderStatus.Filed) throw UserFriendlyException.SameMessage("当前工单状态不能申请延期"); bool IsHas = await _orderDelayRepository.AnyAsync( x => x.OrderId == delaydto.OrderId && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted); if (IsHas) throw UserFriendlyException.SameMessage("该存在延期申请正在审核"); if (_appOptions.Value.IsZiGong && DateTime.Now > order.ExpiredTime) { throw UserFriendlyException.SameMessage("已经超期的工单无法发起延期申请!"); } //验证延期次数 var setting = _systemSettingCacheManager.GetSetting(SettingConstants.DelayNum); if (int.Parse(setting?.SettingValue[0]) != 0 && !_sessionContext.OrgIsCenter) { int count = await _orderDelayRepository.CountAsync(x => x.OrderId == delaydto.OrderId && x.ApplyOrgCode.Substring(SqlFunc.MappingColumn("0"), SqlFunc.MappingColumn("6")) == _sessionContext.RequiredOrgId.Substring(SqlFunc.MappingColumn("0"), SqlFunc.MappingColumn("6")) && x.DelayState == EDelayState.Pass); if (_appOptions.Value.IsZiGong) { count = await _orderDelayRepository.CountAsync(x => x.OrderId == delaydto.OrderId && x.ApplyOrgCode == _sessionContext.RequiredOrgId && (x.DelayState == EDelayState.Pass || x.DelayState == EDelayState.NoPass)); } if (count >= int.Parse(setting?.SettingValue[0])) throw UserFriendlyException.SameMessage("延期申请已超过系统预定设置,不能申请"); } var model = _mapper.Map(delaydto); model.EmployeeId = _sessionContext.RequiredUserId; model.EmployeeName = _sessionContext.UserName; model.ApplyOrgName = _sessionContext.OrgName; model.ApplyOrgCode = _sessionContext.RequiredOrgId; model.DelayApplyType = EDelayApplyType.LocalApply; model.BeforeDelay = order.ExpiredTime; model.DelayState = EDelayState.Examining; model.DelayReason = dto.Workflow.Opinion; if (model.BeforeDelay != null) { //model.AfterDelay = _timeLimitDomainService var startTime = DateTime.Now; if (order.CenterToOrgTime.HasValue) { startTime = order.CenterToOrgTime.Value; } model.AfterDelay = (await _expireTime .CalcEndTime(model.BeforeDelay.Value, startTime, delaydto.DelayUnit, delaydto.DelayNum, order.AcceptTypeCode))?.EndTime; //todo } model.ApplyDelayTime = DateTime.Now; model.No = order.No; model.InitId(); if (dto.Data.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted); await _orderDelayRepository.AddAsync(model, HttpContext.RequestAborted); try { var startDto = _mapper.Map(dto.Workflow); startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderDelay; startDto.Opinion = model.DelayReason; startDto.Title = "申请延期流程"; // string workFlowId = await _workflowApplication.StartWorkflowAsync(startDto, model.Id, // cancellationToken: HttpContext.RequestAborted); //model.WorkflowId = workFlowId; //await _orderDelayRepository.UpdateAsync(model, HttpContext.RequestAborted); // await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted); await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted); } catch (Exception ex) { await _orderDelayRepository.RemoveAsync(model.Id, false, HttpContext.RequestAborted); throw new UserFriendlyException($"工单延期流程失败!, {ex.Message}", "工单延期流程失败"); } } /// /// 工单延期修改后下一步流程 /// [HttpPost("delay/initial_nextFlow")] [LogFilter("开始工单延期流程")] public async Task InitialNextFlow([FromBody] DelayNextFlowDto dto) { var delay = await _orderDelayRepository.GetAsync(dto.Data.Id); _mapper.Map(dto.Data, delay); if (dto.Data.Files.Any()) delay.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, delay.Id, "", HttpContext.RequestAborted); else delay.FileJson = new List(); await _orderDelayRepository.UpdateAsync(delay, HttpContext.RequestAborted); try { dto.NextWorkflow.WorkflowId = delay.WorkflowId; await _workflowDomainService.NextAsync(_sessionContext, dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted); } catch (Exception e) { throw new UserFriendlyException($"工单延期下一步流程失败!, {e.Message}", "工单延期下一步流程失败"); } } /// /// 批量审批延期 /// [HttpPost("delay/batch_audit")] [LogFilter("批量审批延期")] public async Task BatchAuditDelay([FromBody] BatchDelayNextFlowDto dto) { var result = new StringBuilder(); var fail = 0; var success = 0; foreach (var item in dto.DelayId) { try { var workflow = dto.NextWorkflow; if (workflow.NextHandlers.Any() && workflow.NextHandlers.Count() == 1) { var handler = workflow.NextHandlers.FirstOrDefault(); if (string.IsNullOrEmpty(handler.UserId)) { workflow.NextHandlers = new List(); } } var delay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == item) .FirstAsync(HttpContext.RequestAborted); workflow.WorkflowId = delay.WorkflowId; var workflowEntuty = await _workflowDomainService.GetWorkflowAsync(workflow.WorkflowId, withDefine: true, withSteps: true, cancellationToken: HttpContext.RequestAborted); var currentStep = workflowEntuty.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle); NextStepsWithOpinionDto next = null; try { next = await _workflowApplication.GetNextStepsAsync(delay.WorkflowId, HttpContext.RequestAborted); } catch (UserFriendlyException e) { if (e.Message.Contains("未找到对应节点")) { result.Append("无权审核:" + delay.No); fail++; } else { throw; } } if (next == null) continue; if (!delay.Order.IsProvince) { if (next.Steps.Any(x => x.Value == "省审批")) { next.Steps.Remove(next.Steps.First(x => x.Value == "省审批")); } } if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审") { if (next.Steps.Any(x => x.Value == "中心终审")) { next.Steps.Remove(next.Steps.First(x => x.Value == "中心终审")); } } var isBatch = next.Steps.Where(x => x.Value == workflow.NextStepName).Any(); if (isBatch) { var step = next.Steps.Where(x => x.Value == workflow.NextStepName).FirstOrDefault(); workflow.NextStepCode = step.Key; workflow.NextStepName = step.Value; } else { result.Append("无权审核:" + delay.No); fail++; continue; } workflow.StepId = next.StepId; workflow.ReviewResult = dto.IsPass ? EReviewResult.Approval : EReviewResult.Failed; if (workflow.ReviewResult == EReviewResult.Approval) { await _workflowDomainService.NextAsync(_sessionContext, workflow, cancellationToken: HttpContext.RequestAborted); } else { var reject = workflow.Adapt(); await _workflowApplication.RejectAsync(reject, HttpContext.RequestAborted); } success++; } catch (UserFriendlyException e) { result.Append(e.Message); fail++; } } return $"总共: {dto.DelayId.Length}, 成功: {success}, 失败: {fail}, 失败原因: {result.ToString()}"; } /// /// 延期查询流程办理下一步可选节点 /// /// /// [HttpGet("delay/{workflowId}/nextsteps")] public async Task OrderDelayNextsteps(string workflowId) { //var workflow = await _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted); var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withDefine: true, withSteps: true, cancellationToken: HttpContext.RequestAborted); var currentStep = workflow.Steps.FirstOrDefault(d => d.Status == EWorkflowStepStatus.WaitForAccept || d.Status == EWorkflowStepStatus.WaitForHandle); if (workflow != null) { var orderDelay = await _orderDelayRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId) .FirstAsync(HttpContext.RequestAborted); if (orderDelay != null) { var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted); if (!orderDelay.Order.IsProvince) { if (result.Steps.Any(x => x.Value == "省审批")) { result.Steps.Remove(result.Steps.First(x => x.Value == "省审批")); } } if (!_sessionContext.OrgIsCenter && currentStep.Name != "中心初审") { if (result.Steps.Any(x => x.Value == "中心终审")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审")); } } return result; } } return null; } /// /// 取消工单延期 /// /// /// [HttpPost("delay/cancel")] [LogFilter("取消工单延期")] public async Task CancelDelay([FromBody] CancelDelayDto dto) { var orderDelay = await _orderDelayRepository.GetAsync(x => x.OrderId == dto.Id && x.DelayState == EDelayState.Examining, HttpContext.RequestAborted); if (orderDelay != null) { if (orderDelay.DelayApplyType == EDelayApplyType.ProvinceApply) { throw UserFriendlyException.SameMessage("当前处于【省平台】审批,无法取消"); } await _workflowDomainService.TerminateAsync(new TerminateDto() { WorkflowId = orderDelay.WorkflowId, Opinion = "" }, HttpContext.RequestAborted); orderDelay.DelayState = EDelayState.Withdraw; await _orderDelayRepository.UpdateAsync(orderDelay, HttpContext.RequestAborted); } else { throw UserFriendlyException.SameMessage("无效数据"); } } /// /// 延期列表 /// /// [HttpGet("delay")] public async Task> DelayList([FromQuery] DelayListDto dto) { var isAdmin = _orderDomainService.IsCheckAdmin(); var query = _orderDelayRepository.Queryable(); if (!isAdmin) { query.Where(d => SqlFunc.Subqueryable() .Where(step => step.ExternalId == d.Id && ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) || (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) || (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId)) || (step.FlowAssignType == EFlowAssignType.OrgAndRole && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId) && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) )) .Any()); if (!_sessionContext.OrgIsCenter) { query.Where(d => d.AutomaticDelayNum == 0 || d.AutomaticDelayNum == null); } } var (total, items) = await query .Includes(d => d.Order) .Includes(d => d.Workflow) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!)) .WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining) .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining) .WhereIF(dto.DelayState != null, d => d.DelayState == dto.DelayState) .WhereIF(dto.DataScope is 1, d => d.CreatorId == _sessionContext.RequiredUserId) .WhereIF(dto.QueryDelayState is EQueryDelayState.Examining, d => d.DelayState == EDelayState.Examining) .WhereIF(dto.QueryDelayState is EQueryDelayState.Pass, d => d.DelayState == EDelayState.Pass) .WhereIF(dto.QueryDelayState is EQueryDelayState.NoPass, d => d.DelayState == EDelayState.NoPass) .WhereIF(!string.IsNullOrEmpty(dto.CurrentStepName), d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandleStepName == dto.CurrentStepName) //当前节点 .WhereIF(!string.IsNullOrEmpty(dto.ActualHandlerName), d => !SqlFunc.IsNullOrEmpty(d.WorkflowId) && d.Workflow.ActualHandlerName == dto.ActualHandlerName) // 审批人 .WhereIF(!string.IsNullOrEmpty(dto.OrgLevelOneName), d => d.Order.OrgLevelOneName == dto.OrgLevelOneName) //一级部门 .WhereIF(dto.StartCreationTime.HasValue && dto.EndCreationTime.HasValue, d => d.CreationTime >= dto.StartCreationTime && d.CreationTime <= dto.EndCreationTime) // 申请时间 .OrderByDescending(d => d.ApplyDelayTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 延期列表 /// /// [HttpGet("wait_delay")] public async Task> WaitDelayList([FromQuery] DelayListDto dto) { var isAdmin = _orderDomainService.IsCheckAdmin(); var isHandled = dto.IsApply.HasValue && dto.IsApply.Value; var (total, items) = await _orderDelayRepository .Queryable(hasHandled: isHandled, isAdmin: isAdmin) .Includes(d => d.Order) .Includes(d => d.Workflow) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)) //.WhereIF(dto.IsApply == true, d => d.DelayState != EDelayState.Examining) .WhereIF(dto.IsApply == false, d => d.DelayState == EDelayState.Examining) //.WhereIF(dto.DelayState != null, x => x.DelayState == dto.DelayState) //.Where(x=>x.DelayState == EDelayState.Examining) .OrderByDescending(d => d.ApplyDelayTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 延期详情 /// /// /// [HttpGet("delay/{id}")] public async Task DelayEntity(string id) { var model = await _orderDelayRepository.Queryable() .Includes(d => d.Order) .Includes(d => d.Workflow, x => x.Steps) .FirstAsync(d => d.Id == id); var rspModel = _mapper.Map(model); //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId); rspModel.IsCanHandle = model.Workflow?.IsCanHandle( _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false; rspModel.Handle = false; if (!string.IsNullOrEmpty(rspModel.WorkflowId)) { rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, HttpContext.RequestAborted); } if (rspModel.FileJson != null && rspModel.FileJson.Any()) { var ids = rspModel.FileJson.Select(x => x.Id).ToList(); rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); } return rspModel; } /// /// 计算期满时间 /// /// /// [HttpPost("delay/calc-endtime")] public async Task DelayCalcEndTime([FromBody] DelayCalcEndTimeDto dto) { if (dto.BeginTime.HasValue) { // return _timeLimitDomainService.CalcEndTime(dto.BeginTime.Value, dto.DelayUnit, dto.DelayNum, 0, 0); return await _expireTime.CalcEndTime(dto.BeginTime.Value, dto.BeginTime.Value, dto.DelayUnit, dto.DelayNum, 0, 0); } return null; } /// /// 查询工单延期流程开启参数 /// /// [HttpGet("delay/startflow")] public async Task GetDelayFlowStartOptions() { var result = await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderDelay, HttpContext.RequestAborted); if (_sessionContext.OrgIsCenter) { if (result.Steps.Any(x => x.Value == "中心初审")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审")); } } else { if (result.Steps.Any(x => x.Value == "中心终审")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心终审")); } } return result; } /// /// 延期页面基础信息 /// /// [HttpGet("delay/basedata")] public async Task DelayBaseData() { var rsp = new { DelayState = EnumExts.GetDescriptions(), QueryDelayState = EnumExts.GetDescriptions(), TimeType = EnumExts.GetDescriptions() }; return rsp; } #endregion #region 工单甄别 /// /// 工单甄别待申请列表 /// /// /// [HttpGet("mayscreen")] public async Task> MayScreenList([FromQuery] MayScreenListDto dto) { if (_appOptions.Value.IsYiBin) dto.ScreenType = EOrderScreenType.Org; dto.CreationTimeEnd = DateTime.Now; dto.CreationTimeStart = DateTime.Now; if (dto.IsHomePage != null && dto.IsHomePage == true) { // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5); dto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5); } var (total, items) = await _orderApplication.MayScreenList(dto) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 工单甄别待申请列表导出 /// /// [HttpPost("mayscreen/_export")] public async Task ScreenListExport([FromBody] ExportExcelDto dto) { if (_appOptions.Value.IsYiBin) dto.QueryDto.ScreenType = EOrderScreenType.Org; dto.QueryDto.CreationTimeEnd = DateTime.Now; dto.QueryDto.CreationTimeStart = DateTime.Now; if (dto.QueryDto.IsHomePage != null && dto.QueryDto.IsHomePage == true) { // dto.CreationTimeStart = _timeLimitDomainService.CalcWorkTimeReduce(DateTime.Now, 5); dto.QueryDto.CreationTimeStart = await _expireTime.CalcWorkTimeReduce(DateTime.Now, 5); } var query = _orderApplication.MayScreenList(dto.QueryDto); List data; if (dto.IsExportAll) { data = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); data = items; } var dataDtos = _mapper.Map>(data); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = dataDtos .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单甄别待申请列表数据"); } /// /// 工单甄别列表 /// /// /// [HttpGet("screen")] public async Task> ScreenList([FromQuery] ScreenListDto dto) { var (total, items) = await _orderApplication.OrderScreenList(dto) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 工单甄别列表导出 /// /// [HttpPost("screen_list/_export")] public async Task ScreenListExport([FromBody] ExportExcelDto dto) { var query = _orderApplication.OrderScreenList(dto.QueryDto); List data; if (dto.IsExportAll) { data = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); data = items; } var dataDtos = _mapper.Map>(data); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = dataDtos .Select(stu => _mapper.Map(stu, typeof(OrderScreenListDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单甄别数据"); } /// /// 开始工单甄别流程 /// [HttpPost("screen/startflow")] [LogFilter("开始工单甄别流程")] public async Task StartFlow([FromBody] StartWorkflowDto dto) { var screenAny = await _orderScreenRepository.AnyAsync(x => x.VisitDetailId == dto.Data.VisitDetailId && x.ScreenType == dto.Data.ScreenType && (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval)); if (screenAny) throw UserFriendlyException.SameMessage("该工单已提起甄别申请,正在审批过程中,不能申请"); var isNoPass = await _orderScreenRepository.AnyAsync(x => x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId); if (isNoPass) throw UserFriendlyException.SameMessage("该工单已被拒绝过甄别申请,不能再次申请"); var setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyNum); int count = await _orderScreenRepository.CountAsync(x => x.OrderId == dto.Data.OrderId && x.Status == EScreenStatus.Refuse && x.ScreenType == dto.Data.ScreenType && x.VisitDetailId == dto.Data.VisitDetailId); if (count > int.Parse(setting?.SettingValue[0]) && int.Parse(setting?.SettingValue[0]) > -1) throw UserFriendlyException.SameMessage("甄别申请已超过系统预定设置,不能申请"); var visit = await _orderVisitRepository.GetAsync(dto.Data.VisitId, HttpContext.RequestAborted); setting = _systemSettingCacheManager.GetSetting(SettingConstants.ScreenApplyEndTime); var endTime = DateTime.Now; if (int.Parse(setting?.SettingValue[0]) > 0) { //endTime = _timeLimitDomainService endTime = (await _expireTime .CalcEndTime(visit.VisitTime.Value, visit.VisitTime.Value, ETimeType.WorkDay, int.Parse(setting?.SettingValue[0]), 0, 0)).EndTime; if (DateTime.Now > endTime) throw UserFriendlyException.SameMessage("甄别申请时限已超过系统预定设置,不能申请"); } var visitDetail = await _orderVisitedDetailRepository.GetAsync(dto.Data.VisitDetailId, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong && visitDetail.ScreenByEndTime.HasValue) { if (DateTime.Now > visitDetail.ScreenByEndTime && !_sessionContext.OrgIsCenter) { throw UserFriendlyException.SameMessage("超过2个工作日不能申请甄别,不能申请"); } } var order = await _orderRepository.GetAsync(dto.Data.OrderId, HttpContext.RequestAborted); if (order.IsProvince) { var orderAny = await _orderScreenRepository.AnyAsync(x => x.OrderId == dto.Data.OrderId && (x.Status == EScreenStatus.Apply || x.Status == EScreenStatus.Approval)); if (orderAny) { throw UserFriendlyException.SameMessage("当前工单为省工单,已发起甄别申请,请等待省上返回结果!"); } } var model = _mapper.Map(dto.Data); model.Status = EScreenStatus.Approval; model.ApplyEndTime = endTime; // model.TimeConsuming = _timeLimitDomainService.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false); model.TimeConsuming = await _expireTime.CalcWorkTimeToDecimal(visit.VisitTime.Value, DateTime.Now, false); model.InitId(); if (dto.Data.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, model.Id, "", HttpContext.RequestAborted); else model.FileJson = new List(); await _orderScreenRepository.AddAsync(model, HttpContext.RequestAborted); var workflowId = string.Empty; try { //二次回访会改写数据 //await _orderRepository.OrderScreenRevisionVisit(visit.Id, false, HttpContext.RequestAborted); var startDto = _mapper.Map(dto.Workflow); startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderScreen; startDto.Opinion = dto.Data.Content; startDto.Title = "申请甄别流程"; //workflowId = await _workflowApplication.StartWorkflowAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted); //await _workflowDomainService.StartAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted); await _workflowDomainService.StartToFirstStepAsync(startDto, model.Id, cancellationToken: HttpContext.RequestAborted); } catch (Exception e) { await _orderScreenRepository.RemoveAsync(model.Id); model.Id = string.Empty; throw new UserFriendlyException($"工单开启甄别流程失败!, {e.Message}", "工单开启甄别流程失败"); } } /// /// 工单甄别修改后下一步流程 /// [HttpPost("screen/initial_nextFlow")] [LogFilter("办理工单甄别流程")] public async Task InitialNextFlow([FromBody] ScreenNextFlowDto dto) { var screen = await _orderScreenRepository.GetAsync(dto.Data.Id); var visitDetail = await _orderVisitedDetailRepository.GetAsync(screen.VisitDetailId, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong && visitDetail.ScreenByEndTime.HasValue) { if (DateTime.Now > visitDetail.ScreenByEndTime && !_sessionContext.OrgIsCenter) { throw UserFriendlyException.SameMessage("超过2个工作日不能申请甄别,不能申请"); } } if (dto.Data.Files.Any()) screen.FileJson = await _fileRepository.AddFileAsync(dto.Data.Files, screen.Id, "", HttpContext.RequestAborted); else screen.FileJson = new List(); screen.Content = dto.Data.Content; screen.TypeDicId = dto.Data.TypeDicId; screen.TypeDicName = dto.Data.TypeDicName; screen.SendBackApply = false; screen.SendBackApplyNum++; await _orderScreenRepository.UpdateAsync(screen, HttpContext.RequestAborted); try { dto.NextWorkflow.WorkflowId = screen.WorkflowId; //await _workflowApplication.NextAsync(dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted); await _workflowDomainService.NextAsync(_sessionContext, dto.NextWorkflow, cancellationToken: HttpContext.RequestAborted); } catch (Exception e) { throw new UserFriendlyException($"工单甄别下一步流程失败!, {e.Message}", "工单甄别下一步流程失败"); } } /// /// 查询工单甄别流程开启参数 /// /// [HttpGet("screen/startflow")] public async Task GetScreenFlowStartOptionsAsync() { //return await _workflowApplication.GetStartOptionsAsync(WorkflowModuleConsts.OrderScreen, // HttpContext.RequestAborted); var result = await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderScreen, HttpContext.RequestAborted); if (_sessionContext.OrgIsCenter) { if (result.Steps.Any(x => x.Value == "中心初审")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心初审")); } } else { if (result.Steps.Any(x => x.Value == "中心班长")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长")); } } return result; } /// /// 查询工单甄别流程参数 /// /// [HttpGet("screen/workflow/{id}")] public async Task GetScreenWorkFlowAsync(string id) { var workflow = await _workflowRepository.Queryable().FirstAsync(x => x.ExternalId == id); return workflow.Id; } /// /// 甄别查询流程办理下一步可选节点 /// /// /// [HttpGet("screen/{workflowId}/nextsteps")] public async Task OrderScreenNextsteps(string workflowId) { var workflow = await _workflowRepository.GetAsync(workflowId, HttpContext.RequestAborted); if (workflow != null) { var orderScreen = await _orderScreenRepository.Queryable().Includes(x => x.Order).Where(x => x.Id == workflow.ExternalId) .FirstAsync(HttpContext.RequestAborted); if (orderScreen != null) { var result = await _workflowApplication.GetNextStepsAsync(workflowId, HttpContext.RequestAborted); if (!orderScreen.Order.IsProvince) { if (result.Steps.Any(x => x.Value == "省审批")) { result.Steps.Remove(result.Steps.First(x => x.Value == "省审批")); } } if (!_sessionContext.OrgIsCenter) { if (result.Steps.Any(x => x.Value == "中心班长")) { result.Steps.Remove(result.Steps.First(x => x.Value == "中心班长")); } } return result; } } return null; } /// /// 列表页面基础数据 /// /// [HttpGet("screen/base")] public async Task ScreenBaseData() { var rsp = new { ScreenStatus = EnumExts.GetDescriptions(), OrderScreenType = EnumExts.GetDescriptions(), QueryScreenType = EnumExts.GetDescriptions(), ScreenType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ScreenType), CounterSignType = EnumExts.GetDescriptions(), AcceptType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), SourceChannel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SourceChannel), VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction), DissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason), }; return rsp; } /// /// 甄别详情 /// /// /// [HttpGet("screen/{id}")] public async Task ScreenEntity(string id) { var model = await _orderScreenRepository.Queryable(canView: false) .Includes(x => x.Order) .Includes(x => x.Workflow, d => d.Steps) .Includes(x => x.Visit, d => d.Order) .FirstAsync(x => x.Id == id); var rspModel = _mapper.Map(model); //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId); rspModel.IsCanHandle = model.Workflow?.IsCanHandle( _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false; if (model.Status == EScreenStatus.SendBack && model.SendBackApply) rspModel.IsCanHandle = false; rspModel.Handle = false; if (!string.IsNullOrEmpty(rspModel.WorkflowId)) { rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, HttpContext.RequestAborted); } if (rspModel.FileJson != null && rspModel.FileJson.Any()) { var ids = rspModel.FileJson.Select(x => x.Id).ToList(); rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); } return rspModel; } /// /// 甄别详情 /// /// /// [HttpGet("screen/visitdetail/{id}")] public async Task VisitDetailScreenEntity(string id) { var model = await _orderScreenRepository.Queryable(canView: false) .Includes(x => x.Order) .Includes(x => x.Workflow, d => d.Steps) .Includes(x => x.Visit, d => d.Order) .FirstAsync(x => x.VisitDetailId == id); var rspModel = _mapper.Map(model); //rspModel.IsCanHandle = model.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId); rspModel.IsCanHandle = model.Workflow?.IsCanHandle( _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles) ?? false; if (model.Status == EScreenStatus.SendBack && model.SendBackApply) rspModel.IsCanHandle = false; rspModel.Handle = false; if (!string.IsNullOrEmpty(rspModel.WorkflowId)) { rspModel.Handle = await _workflowDomainService.CheckCurrentIsStartStepAsync(rspModel.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, HttpContext.RequestAborted); } if (rspModel.FileJson != null && rspModel.FileJson.Any()) { var ids = rspModel.FileJson.Select(x => x.Id).ToList(); rspModel.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); } return rspModel; } /// /// 更新甄别提起截至时限 /// /// /// [HttpPut("order_screen_endtime")] [LogFilter("更新甄别提起截至时限")] public async Task Update([FromBody] OrderScreenEndTimeDto dto) { await _orderVisitedDetailRepository.Updateable().SetColumns(x => new OrderVisitDetail { ScreenByEndTime = dto.ScreenByEndTime }) .Where(x => x.Id == dto.Id).ExecuteCommandAsync(); } #endregion #region 工单督办 /// /// 工单督办列表 /// /// /// [HttpGet("supervise")] public async Task> SuperviseList([FromQuery] SuperviseListDto dto) { var (total, items) = await _orderSuperviseRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!)) .WhereIF(dto.SuperviseState > -1, x => x.State == dto.SuperviseState) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) .Where(x => x.OrgId == _sessionContext.OrgId) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 申请督办 /// /// /// [HttpPost("supervise/apply")] [LogFilter("新增工单督办")] public async Task ApplySupervise([FromBody] ApplyOrderSuperviseDto dto) { if (!dto.SuperviseOrgDtos.Any()) throw UserFriendlyException.SameMessage("请选择被督办部门"); //验证工单是否可以申请 var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted); if (order is null) throw UserFriendlyException.SameMessage("无效工单"); foreach (var item in dto.SuperviseOrgDtos) { var model = _mapper.Map(dto); model.OrgId = item.OrgId; model.OrgName = item.OrgName; model.LaunchOrgName = _sessionContext.OrgName; model.CrUser = _sessionContext.UserName; model.State = 0; model.InitId(); if (dto.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted); await _orderSuperviseRepository.AddAsync(model, HttpContext.RequestAborted); if (dto.AcceptSms) { //发送短信 try { var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue; //查询部门所有账号 var userlist = await _userRepository.Queryable().Where(x => x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) && x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync(); //发送短信 foreach (var user in userlist) { var messageDto = new Share.Dtos.Push.MessageDto { PushBusiness = EPushBusiness.OrderSupervise, ExternalId = order.Id, OrderId = order.Id, PushPlatform = EPushPlatform.Sms, Remark = order.Title, Name = user.Name, TemplateCode = "1003", Params = new List() { order.No }, TelNumber = user.PhoneNo, }; await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted); } } catch { } } var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; CityBaseConfiguration cityBase = JsonSerializer.Deserialize(setting); //推省上 if (!string.IsNullOrEmpty(model.Id) && (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId))) { var orderDto = _mapper.Map(order); var supervise = await _orderSuperviseRepository.GetAsync(x => x.Id == model.Id); if (supervise != null) { var superviseDto = _mapper.Map(supervise); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderUrgeInform, new PublishUrgeDto() { Order = orderDto, Urge = _mapper.Map(superviseDto), ClientGuid = "" }); //try //{ // await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto() // { // Order = orderDto, // Supervise = superviseDto, // ClientGuid = "" // }, HttpContext.RequestAborted); //} //catch (Exception e) //{ // _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message); //} } } } } /// /// 回复督办 /// /// /// [HttpPost("supervise/reply")] [LogFilter("回复工单督办")] public async Task ReplySupervise([FromBody] ReplyOrderSuperviseDto dto) { //验证是否存在督办 var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (supervise is null) throw UserFriendlyException.SameMessage("无效督办"); if (supervise.State > 0) throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复"); _mapper.Map(dto, supervise); supervise.ReplyId = _sessionContext.UserId; supervise.ReUser = _sessionContext.UserName; supervise.ReplyTime = DateTime.Now; supervise.State = 1; if (dto.Files.Any()) supervise.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, supervise.Id, "", HttpContext.RequestAborted); await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted); var order = await _orderRepository.GetAsync(supervise.OrderId, HttpContext.RequestAborted); //推省上 if (supervise.Province.HasValue && supervise.Province.Value) { var orderDto = _mapper.Map(order); var superviseDto = _mapper.Map(supervise); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderSuperviseResult, new PublishSuperviseDto() { Order = orderDto, Supervise = superviseDto, ClientGuid = "" }, cancellationToken: HttpContext.RequestAborted); //try //{ // await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto() // { // Order = orderDto, // Supervise = superviseDto, // ClientGuid = "" // }, HttpContext.RequestAborted); //} //catch (Exception e) //{ // _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message); //} } } /// /// 签收督办 /// /// /// [HttpPost("supervise/sign")] [LogFilter("签收工单督办")] public async Task SignSupervise([FromBody] SignOrderSuperviseDto dto) { //验证是否存在督办 var supervise = await _orderSuperviseRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (supervise is null) throw UserFriendlyException.SameMessage("无效督办"); //supervise.State = 2; supervise.SignTime = DateTime.Now; supervise.SignUser = _sessionContext.UserName; await _orderSuperviseRepository.UpdateAsync(supervise, HttpContext.RequestAborted); var order = await _orderRepository.GetAsync(supervise.OrderId, HttpContext.RequestAborted); //推省上 if (supervise.Province.HasValue && supervise.Province.Value) { var orderDto = _mapper.Map(order); var superviseDto = _mapper.Map(supervise); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderSuperviseCourse, new PublishSuperviseDto() { Order = orderDto, Supervise = superviseDto, ClientGuid = "" }, cancellationToken: HttpContext.RequestAborted); //try //{ // await _provinceService.SendSuperviseProcessInfo(new PublishSuperviseDto() // { // Order = orderDto, // Supervise = superviseDto, // ClientGuid = "" // }, HttpContext.RequestAborted); //} //catch (Exception e) //{ // _logger.LogError("_provinceService.SendSuperviseProcessInfo throw exception: {ex}", e.Message); //} } } /// /// 督办详情 /// /// /// [HttpGet("supervise/{id}")] public async Task SuperviseEntity(string id) { var orderSupervise = await _orderSuperviseRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); var orderSuperviseDto = new OrderSuperviseDto(); if (orderSupervise != null) { orderSuperviseDto = _mapper.Map(orderSupervise); if (orderSuperviseDto.FileJson != null && orderSuperviseDto.FileJson.Any()) { var ids = orderSuperviseDto.FileJson.Select(x => x.Id).ToList(); var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); orderSuperviseDto.Files = files.Where(x => x.Classify == "督办申请").ToList(); orderSuperviseDto.ReplyFiles = files.Where(x => x.Classify == "督办回复").ToList(); } } return orderSuperviseDto; } #endregion #region 工单催办 /// /// 工单催办列表 /// /// /// [HttpGet("urge")] public async Task> UrgeList([FromQuery] UrgeListDto dto) { var (total, items) = await _orderUrgeRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!)) .WhereIF(dto.UrgeState > -1, x => x.State == dto.UrgeState) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) .Where(x => x.OrgId == _sessionContext.OrgId) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 批量催办 /// /// /// [HttpPost("urge/add")] [LogFilter("批量催办工单")] public async Task UrgeAdd([FromBody] OrderUrgeAddDto dto) { if (dto is null) throw UserFriendlyException.SameMessage("参数错误"); if (dto.OrderIds == null || dto.OrderIds.Count == 0) throw UserFriendlyException.SameMessage("请选择要催办的工单"); if (string.IsNullOrEmpty(dto.UrgeContent)) throw UserFriendlyException.SameMessage("请填写催办内容"); foreach (var item in dto.OrderIds) { var order = await _orderRepository.GetAsync(item, HttpContext.RequestAborted); if (order != null) { var model = new OrderUrge { OrderId = order.Id, OrgId = order.CurrentHandleOrgId, OrgName = order.CurrentHandleOrgName, CreatorOrgName = _sessionContext.OrgName, CrUser = _sessionContext.UserName, State = 0, ApplyContent = dto.UrgeContent }; model.InitId(); await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted); if (dto.AcceptSms) { try { var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue; //查询部门所有账号 var userlist = await _userRepository.Queryable().Where(x => x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) && x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync(); foreach (var user in userlist) { //发送短信 var messageDto = new Share.Dtos.Push.MessageDto { PushBusiness = EPushBusiness.OrderUrge, ExternalId = order.Id, OrderId = order.Id, PushPlatform = EPushPlatform.Sms, Remark = order.Title, Name = user.Name, TemplateCode = "1002", Params = new List() { order.No }, TelNumber = user.PhoneNo, }; await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted); } } catch { } } } } } /// /// 申请催办 /// /// /// [HttpPost("urge/apply")] [LogFilter("新增工单催办")] public async Task ApplyUrge([FromBody] ApplyOrderUrgeDto dto) { if (!dto.UrgeOrgDtos.Any()) throw UserFriendlyException.SameMessage("请选择被催办部门"); //验证工单是否可以申请 var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted); if (order is null) throw UserFriendlyException.SameMessage("无效工单"); foreach (var item in dto.UrgeOrgDtos) { var model = _mapper.Map(dto); model.OrgId = item.OrgId; model.OrgName = item.OrgName; model.CreatorOrgName = _sessionContext.OrgName; model.CrUser = _sessionContext.UserName; model.State = 0; model.InitId(); if (dto.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted); await _orderUrgeRepository.AddAsync(model, HttpContext.RequestAborted); if (dto.AcceptSms) { try { var acceptSmsRoleIds = _systemSettingCacheManager.GetSetting(SettingConstants.AcceptSmsRoleIds)?.SettingValue; //查询部门所有账号 var userlist = await _userRepository.Queryable().Where(x => x.OrgId == model.OrgId && !string.IsNullOrEmpty(x.PhoneNo) && x.Roles.Any(d => acceptSmsRoleIds.Contains(d.Id))).ToListAsync(); foreach (var user in userlist) { //发送短信 var messageDto = new Share.Dtos.Push.MessageDto { PushBusiness = EPushBusiness.OrderUrge, ExternalId = order.Id, OrderId = order.Id, PushPlatform = EPushPlatform.Sms, Remark = order.Title, Name = user.Name, TemplateCode = "1002", Params = new List() { order.No }, TelNumber = user.PhoneNo, }; await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted); } } catch { } } var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; CityBaseConfiguration cityBase = JsonSerializer.Deserialize(setting); //推省上 if (!string.IsNullOrEmpty(model.Id) && (cityBase.CityProvince.OrgId.Equals(model.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(model.OrgId))) { var orderDto = _mapper.Map(order); var urge = await _orderUrgeRepository.GetAsync(x => x.Id == model.Id); if (urge != null) { var urgeDto = _mapper.Map(urge); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderUrgeInform, new PublishUrgeDto() { Order = orderDto, Urge = urgeDto, ClientGuid = "" }); } } } } /// /// 回复催办 /// /// /// [HttpPost("urge/reply")] [LogFilter("回复工单催办")] public async Task ReplyUrge([FromBody] ReplyOrderUrgeDto dto) { //验证是否存在催办 var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (urge is null) throw UserFriendlyException.SameMessage("无效催办"); if (urge.State > 0) throw UserFriendlyException.SameMessage("督办已回复,请勿重复回复"); _mapper.Map(dto, urge); urge.ReplyId = _sessionContext.UserId; urge.ReUser = _sessionContext.UserName; urge.ReplyContent = dto.ReplyContent; urge.ReplyTime = DateTime.Now; urge.State = 1; if (dto.Files.Any()) urge.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, urge.Id, "", HttpContext.RequestAborted); else urge.ReplyFileJson = new List(); await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted); } /// /// 签收催办 /// /// /// [HttpPost("urge/sign")] [LogFilter("签收工单催办")] public async Task SignUrge([FromBody] SignOrderUrgeDto dto) { //验证是否存在催办 var urge = await _orderUrgeRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (urge is null) throw UserFriendlyException.SameMessage("无效催办"); urge.State = 2; urge.SignUser = _sessionContext.UserName; urge.SignTime = DateTime.Now; await _orderUrgeRepository.UpdateAsync(urge, HttpContext.RequestAborted); } /// /// 催办详情 /// /// /// [HttpGet("urge/{id}")] public async Task UrgeEntity(string id) { var orderUrge = await _orderUrgeRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); var orderUrgeDto = new OrderUrgeDto(); if (orderUrge != null) { orderUrgeDto = _mapper.Map(orderUrge); if (orderUrgeDto.FileJson != null && orderUrgeDto.FileJson.Any()) { var ids = orderUrgeDto.FileJson.Select(x => x.Id).ToList(); orderUrgeDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); } } return orderUrgeDto; } #endregion #region 工单办理 /// /// 工单列表 /// /// /// [HttpGet] public async Task> Query([FromQuery] QueryOrderDto dto) { //var query = _orderApplication.QueryOrders(dto); //var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted); //return new PagedDto(total, _mapper.Map>(items)); var orders = await _orderApplication.QueryOrders(dto) .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); var list = _mapper.Map>(orders); if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter) list = list.Select(p => p.DataMask()).ToList(); return list; } /// /// 查询工单(固定数据量) /// [HttpGet("fixed")] public async Task> QueryFixed([FromQuery] QueryOrderFixedDto dto) { var hasSetting = Int32.TryParse( _systemSettingCacheManager.GetSetting(SettingConstants.FixedQueryCount)?.SettingValue[0], out var queryCount); var query = _orderApplication.QueryOrders(dto); var orders = await query.ToFixedListAsync(dto.QueryIndex, hasSetting ? queryCount : null, HttpContext.RequestAborted); return _mapper.Map>(orders); } /// /// 查询总数 /// [HttpGet("count")] public async Task Count([FromQuery] QueryOrderDto dto) { var query = _orderApplication.QueryOrders(dto); return await query.CountAsync(HttpContext.RequestAborted); } [HttpPost("order/export")] public async Task ExportOrders([FromBody] ExportExcelDto dto) { var query = _orderApplication.QueryOrders(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var orderDtos = _mapper.Map>(orders); if (_appOptions.Value.IsLuZhou && !_sessionContext.OrgIsCenter) orderDtos = orderDtos.Select(p => p.DataMask()).ToList(); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = orderDtos .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单数据"); } /// /// 历史工单 /// /// /// [HttpGet("history")] public async Task> Query([FromQuery] QueryOrderHistoryDto dto) { var (total, items) = await _orderRepository.Queryable() .Includes(x => x.OrderScreens) .Where(d => d.Contact == dto.PhoneNo) .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)) .Select(m => new OrderHistoryOutDto { IsScreen = m.OrderScreens.Any(x => x.Status == EScreenStatus.End), }, true) .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 历史工单(全量) /// /// /// [HttpGet("history_all")] public async Task> QueryAll([FromQuery] QueryOrderHistoryDto dto) { var query = _orderRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo) .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)); //随手拍 bool.TryParse( _systemSettingCacheManager.GetSetting(SettingConstants.Snapshot)?.SettingValue[0], out bool isSnapshotEnable); if (isSnapshotEnable && !string.IsNullOrEmpty(dto.IndustryId)) { query.Where(d => d.OrderSnapshot.IndustryId == dto.IndustryId); } //var (total, items) = await _orderRepository.Queryable() // .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.Contact == dto.PhoneNo) // .WhereIF(!string.IsNullOrEmpty(dto.OrderId), d => d.Id != dto.OrderId) // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)) // .OrderByDescending(d => d.CreationTime) // .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); var (total, items) = await query .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 查询重复工单 /// [HttpGet("duplicate")] public async Task> Query([FromQuery] QueryOrderDuplicateDto dto) { if (!dto.OrderIds.Any()) return new PagedDto(0, new List()); var (total, items) = await _orderRepository.Queryable() .Where(d => dto.OrderIds.Contains(d.Id)) .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 查询工单详情 /// /// /// [HttpGet("{id}")] public async Task Get(string id) { var order = await _orderRepository.Queryable() .Includes(d => d.OrderExtension) .Includes(d => d.OrderDelays) .Includes(d => d.OrderPublish) .Includes(d => d.OrderPushTypes) .Includes(d => d.OrderComplements) .Includes(d => d.OrderTags) //.Includes(d => d.OrderScreens) .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.OrderVisitDetails) .Includes(d => d.OrderVisits.Where(x => x.VisitState == EVisitState.Visited).ToList(), x => x.Employee) .FirstAsync(d => d.Id == id); if (order == null) return new(); var dto = _mapper.Map(order); //处理中心意见 dto.CenterOpinion = order.CenterToOrgOpinion; //班长代办-- 判断不是会签件 流程判断业务类型 //var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor); //var settingStr = setting?.SettingValue; //var roles = _sessionContext.Roles; //foreach (var item in settingStr) //{ // if (roles != null && roles.Contains(item)) dto.CanHandle = true; //} if (!string.IsNullOrEmpty(order.WorkflowId)) { bool canInsteadHandle = false; //班长代办 var settingEnable = _systemSettingCacheManager.GetSetting(SettingConstants.ChargeDAffaires); var isEnable = settingEnable != null && settingEnable.SettingValue.Any() ? int.Parse(settingEnable?.SettingValue[0]) : 0; if (isEnable > 0) { var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor); var settingStr = setting?.SettingValue; var roles = _sessionContext.Roles; if ((settingStr?.Any() ?? false) && roles.Any()) { var intersectRoles = settingStr.Intersect(roles); canInsteadHandle = intersectRoles.Any(); } if (canInsteadHandle) { var unhandleSteps = await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted); // 会签多节点 不允许班长代办 归档没有待办节点 if (unhandleSteps.Count != 1) canInsteadHandle = false; if (isEnable < 3 && unhandleSteps.Count == 1) { var type = isEnable - 1; var step = unhandleSteps.FirstOrDefault(d => d.BusinessType == (EBusinessType)type); canInsteadHandle = step != null && !string.IsNullOrEmpty(step.Id); if (canInsteadHandle && step.IsInCountersign()) canInsteadHandle = false; } } } var result = await _workflowDomainService.GetWorkflowHandlePermissionAsync( order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, cancellationToken: HttpContext.RequestAborted); dto.Workflow = _mapper.Map(result.Workflow); dto.CountersignId = result.CountersignId; dto.CanHandle = result.CanHandle; dto.CanPrevious = result.CanPrevious; dto.CanInsteadHandle = !dto.CanHandle && canInsteadHandle; if (result.Trace is not null) { dto.PreviousOpinion = result.Trace!.Opinion; var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id && x.TraceId == result.Trace.Id) .OrderByDescending(x => x.CreationTime).FirstAsync(); if (sendBack is { Id: not null }) { //dto.SendBackOpinion = !string.IsNullOrEmpty(sendBack.Content) ? sendBack.Content : string.Empty; if (sendBack.State == ESendBackAuditState.Refuse) { dto.SendBackRefuseOpinion = sendBack.AuditContent; dto.SendBackAuditTime = sendBack.AuditTime; } } } // // order.CurrentStepAcceptTime = DateTime.Now; // await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); // // result.Workflow.UpdateCurrentStepAcceptTime(order.CurrentStepAcceptTime.Value); // await _mediator.Publish(new GetOrderDetailNotify(result.Workflow, // _sessionContext.RequiredUserId, _sessionContext.UserName, // _sessionContext.RequiredOrgId, _sessionContext.OrgName, // _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName)); if (result.CanHandle) { var acceptTime = await _workflowDomainService.AcceptAsync(result.Workflow, _sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.RequiredOrgId, _sessionContext.OrgName, _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName, HttpContext.RequestAborted); if (acceptTime != null) { order.ActualHandleStepAcceptTime = acceptTime; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); } } } dto.IsRed = string.IsNullOrEmpty(dto.SignerId) || !order.ActualHandleStepAcceptTime.HasValue; //var dto = _mapper.Map(order!); //dto.CountersignId = countersignId; //dto.CanHandle = order.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId); dto.IsCanDelay = !order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining); if (order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId)) { dto.CanHandle = false; } dto.SpecialNum = await _orderSpecialRepository.CountAsync(x => x.OrderId == order.Id); dto.IsCanCancelDelay = order.OrderDelays.Any(x => x.DelayState == EDelayState.Examining && x.ApplyOrgCode == _sessionContext.RequiredOrgId); var delayModel = order.OrderDelays.MaxBy(x => x.CreationTime); if (delayModel != null) { if (delayModel.IsProDelay) { dto.ProvinceDelayString = "该工单已向省平台发送延期申请!延期状态:" + delayModel.DelayState.GetDescription(); } var workFlow = await _workflowRepository.GetAsync(delayModel.WorkflowId); switch (delayModel.DelayState) { case EDelayState.Examining: dto.DelayString = "延期状态:审批中 当前节点:" + workFlow?.ActualHandleStepName; break; case EDelayState.Pass: dto.DelayString = "已延期" + delayModel?.DelayNum + "个" + delayModel?.DelayUnit.GetDescription(); break; case EDelayState.NoPass: dto.DelayString = "延期状态:拒绝 当前节点:" + workFlow?.ActualHandleStepName; break; case EDelayState.Withdraw: dto.DelayString = "延期状态:撤销 当前节点:" + workFlow?.ActualHandleStepName; break; default: break; } } else { dto.DelayString = ""; dto.ProvinceDelayString = ""; } //dto.CanPrevious = canPrevious; if (order.OrderPublish != null) { dto.PublishState = order.OrderPublish.PublishState; } if (dto.FileJson != null && dto.FileJson.Any()) { var ids = order.FileJson.Select(x => x.Id).ToList(); var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); //x.Classify == "办理上传" && dto.Files = files.Where(x => string.IsNullOrEmpty(x.FlowKey)).ToList(); } //var call = await _trCallRecordRepository.Queryable().Where(x => x.CallAccept == order.CallId).FirstAsync();//由CallAccept改为OtherAccept //var call = await _trCallRecordRepository.Queryable().Where(x => x.OtherAccept == order.CallId).FirstAsync(); //if (call != null) //{ // dto.RecordingBaseAddress = call.RecordingBaseAddress; // dto.RecordingAbsolutePath = call.RecordingAbsolutePath; //} if (!string.IsNullOrEmpty(order.CallId)) { if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun) { var callRecord = await _callApplication.GetTianrunCallAsync(order.CallId, HttpContext.RequestAborted); if (callRecord != null) { dto.RecordingBaseAddress = callRecord.RecordingBaseAddress; dto.RecordingAbsolutePath = callRecord.RecordingAbsolutePath; } } else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang) { var call = await _callApplication.GetCallAsync(order.CallId, HttpContext.RequestAborted); if (call is not null) { dto.RecordingBaseAddress = call.AudioFile; dto.RecordingAbsolutePath = call.AudioFile; } } } var repeatablesMap = await _repeatableEventDetailRepository.Queryable() .Includes(x => x.Order) .Where(x => x.OrderId == id).Distinct().ToListAsync(); var repeatables = _mapper.Map>(repeatablesMap); dto.RepeatableEventDetails = repeatables; if (!string.IsNullOrEmpty(dto.WorkflowId)) { var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, withTraces: true, cancellationToken: HttpContext.RequestAborted); List remarks = workflow.Steps.Where(x => !string.IsNullOrEmpty(x.Remark)).Select(x => new OrderRemarksDto { Remark = x.Remark, RemarkTime = x.HandleTime, RemarkUser = x.HandlerName }).ToList(); dto.OrderRemarks = remarks; if (order.Status == EOrderStatus.SendBack || order.Status == EOrderStatus.BackToUnAccept) { var backTrace = workflow.Traces.Where(x => x.Status == EWorkflowStepStatus.Handled).OrderByDescending(x => x.CreationTime).First(); backTrace.Opinion = backTrace.Opinion.Replace("流程归档", ""); dto.SendBackOpinion = string.IsNullOrEmpty(backTrace.Opinion) ? string.Empty : backTrace.HandlerOrgName + " " + backTrace.Opinion; //var sendBack = await _orderSendBackAuditRepository.Queryable().Where(x => x.OrderId == dto.Id).OrderByDescending(x => x.CreationTime).FirstAsync(); //dto.SendBackOpinion = sendBack is { Id: not null } && !string.IsNullOrEmpty(sendBack.Content) ? sendBack.Content : string.Empty; } } //工单是否在退回审批中 if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == order.Id && x.State == ESendBackAuditState.Apply, HttpContext.RequestAborted)) { dto.IsReturnUnderApproval = true; } //省退回 var orderSendback = await _orderSendBackRepository.Queryable().Where(x => x.OrderId == order.Id).OrderByDescending(x => x.AuditTime) .FirstAsync(); if (orderSendback is not null) { string stateStr = ""; // 0 待审核 1 审核通过 2 审核不通过 switch (orderSendback.State) { case 0: stateStr = "待审核"; break; case 1: stateStr = "审核通过"; break; case 2: stateStr = "审核不通过"; break; default: stateStr = "未知"; break; } dto.ProvinceSendBackString = "该工单已向省平台发送退回申请!退回状态:" + stateStr; } var isProvinceorderRevoke = await _orderRevokeRepository.Queryable().AnyAsync(x => x.OrderId == order.Id && x.IsProRevoke == true); if (isProvinceorderRevoke) { dto.ProvinceRevokeString = "该工单已由省平台发送撤单!请直接归档办理!"; } //省甄别 var orderScreen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == order.Id && x.IsProScreen == true) .OrderByDescending(x => x.CreationTime) .FirstAsync(); if (orderScreen != null) { dto.ProvinceScreenString = "该工单已向省平台发送甄别申请!甄别状态:" + orderScreen.Status.GetDescription(); } //终止 var orderTerminateList = await _orderTerminateRepository.Queryable().Where(x => x.OrderId == order.Id).ToListAsync(); dto.OrderTerminateStatus = orderTerminateList.Any(x => x.Status == ETerminateStatus.End) ? "同意" : orderTerminateList.Any(x => x.Status == ETerminateStatus.Refuse) ? "不同意" : orderTerminateList.Any(x => x.Status == ETerminateStatus.Approval || x.Status == ETerminateStatus.SendBack) ? "审批中" : null; if (_systemSettingCacheManager.Snapshot) { await _orderSnapshotRepository.Queryable() .Where(m => m.Id == order.Id) .Select(m => new { m.IndustryId, m.IndustryName }) .FirstAsync(HttpContext.RequestAborted) .Then(async snapshot => { dto.IndustryName = snapshot.IndustryName; dto.IndustryId = snapshot.IndustryId; }); } return _sessionContext.OrgIsCenter ? dto : dto.DataMask(); } /// /// 上传附件 /// /// /// //[HttpPost] //[LogFilterAlpha("上传附件")] //public async Task UploadFiles(OrderUploadFiles dto) { // var fileJson = await _fileRepository.AddFileAsync(dto.Files, dto.Id, "", HttpContext.RequestAborted); // if (fileJson.Any()) // { // var order = await _orderRepository.GetAsync(dto.Id); // if (order.FileJson != null && order.FileJson.Any()) // { // order.FileJson.AddRange(fileJson); // } // else { // order.FileJson = fileJson; // } // await _orderRepository.Updateable().SetColumns(x => new Order { FileJson = order.FileJson }).Where(x => x.Id == dto.Id).ExecuteCommandAsync(); // } //} /// /// 新增工单 /// /// /// [HttpPost] [LogFilterAlpha("新增工单")] public async Task Add([FromBody] AddOrderDto dto) { dto.InitAddress(); //泸州任务 311 投诉件需限制受理内容的字数等需求 if (_appOptions.Value.IsLuZhou && dto.AcceptTypeCode == "35") { if (dto.Content.Length < 25) throw UserFriendlyException.SameMessage("保存失败,投诉类型受理内容字数需要至少25个字!"); if (dto.Title.Contains("咨询") || dto.Title.Contains("建议") || dto.Title.Contains("求助") || dto.Title.Contains("举报") || dto.Content.Contains("咨询") || dto.Content.Contains("建议") || dto.Content.Contains("求助") || dto.Title.Contains("举报")) throw UserFriendlyException.SameMessage("保存失败!投诉类型标题和受理内容不能出现'咨询、建议、求助、举报'"); } //todo dto validation //交通工单校验 var valid = await _orderDomainService.OrderValidation(dto, HttpContext.RequestAborted); if (valid.Validation) throw UserFriendlyException.SameMessage(valid.Result); if (!string.IsNullOrEmpty(dto.CallId)) { dto.CallId = await _callApplication.GetOrSetCallIdAsync(dto.CallId, HttpContext.RequestAborted); var exists = await _orderRepository.AnyAsync(d => d.CallId == dto.CallId, HttpContext.RequestAborted); if (exists) throw new UserFriendlyException($"来电已保存工单, phone:{dto.FromPhone}, callId: {dto.CallId}", "来电已保存工单"); exists = await _systemLogApplication.HasByIpUrlAsync(dto.CallId); if (exists) { // IpUrl 里面存的是 callId, 用来判断是工单的 CallId 是否已经被修复过了. // 存入的地方是 Hotline.Application.CallCenter.OrderRelateCallHandlerAsync throw new UserFriendlyException($"来电已保存工单, phone:{dto.FromPhone}, callId: {dto.CallId} !", "来电已保存工单!"); } } var order = _mapper.Map(dto); order.SignerId = _sessionContext.UserId; order.SignerName = _sessionContext.UserName; order.InitId(); if (dto.Files.Any()) order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted); // 工单推送分类 if (dto.OrderPushTypes.Any()) { var pushTypeAny = await _orderPushTypeRepository.AnyAsync(x => x.OrderId == order.Id); if (pushTypeAny) await _orderPushTypeRepository.RemoveAsync(x => x.OrderId == order.Id); dto.OrderPushTypes.ForEach(x => x.OrderId = order.Id); var orderPushTypes = _mapper.Map>(dto.OrderPushTypes); await _orderPushTypeRepository.AddRangeAsync(orderPushTypes); var pushTypes = dto.OrderPushTypes.Select(x => x.PushType); order.PushType = string.Join(",", pushTypes); } if (dto.Tags != null && dto.Tags.Any()) { var orderTags = new List(); foreach (var item in dto.Tags) { orderTags.Add(new SystemDicData() { Id = item }); } order.OrderTags = orderTags; var dicData = await _sysDicDataRepository.Queryable().Where(p => dto.Tags.Contains(p.Id)).Select(p => p.DicDataValue).ToListAsync(); if (dicData != null && dicData.Any()) { order.OrderTagCode = String.Join(", ", dicData); } } await _orderDomainService.AddAsync(order, true, HttpContext.RequestAborted); if (_systemSettingCacheManager.Snapshot && dto.IndustryId.NotNullOrEmpty() && dto.IndustryName.NotNullOrEmpty()) { var snapshot = new OrderSnapshot { Id = order.Id, IndustryId = dto.IndustryId, IndustryName = dto.IndustryName }; await _orderSnapshotRepository.AddAsync(snapshot, HttpContext.RequestAborted); order.Latitude = 29.33924; order.Longitude = 104.779307; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); } //订阅此事件的内部处理工单数据只能更新各自业务的字段,不能全部更新 //新增工单其他处理事件 (受理短信) if (!string.IsNullOrEmpty(order.Contact) && order.Contact.Length == 11) { await _publisher.PublishAsync(new AddOrderNotify(order), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted); } //if (dto.Tags.Any()) await _repositoryts.AddVectorAsync(orderId, DateTime.Now, dto.Tags, HttpContext.RequestAborted); if (dto.RepeatableEventDetails?.Any() ?? false) { dto.RepeatableEventDetails.ForEach(x => x.OrderId = order.Id); List repeatables = _mapper.Map>(dto.RepeatableEventDetails); await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted); } //工单ID跟通话记录相关联 //var callRecord = await _trCallRecordRepository.GetAsync(p => p.CallAccept == order.CallId, HttpContext.RequestAborted);//由CallAccept改为OtherAccept //var callRecord = await _trCallRecordRepository.GetAsync(p => p.OtherAccept == order.CallId && string.IsNullOrEmpty(p.OtherAccept) == false, HttpContext.RequestAborted); //if (callRecord != null && string.IsNullOrEmpty(callRecord.ExternalId)) //{ // callRecord.ExternalId = order.Id; // callRecord.CallOrderType = Share.Enums.CallCenter.ECallOrderType.Order; // await _trCallRecordRepository.UpdateAsync(callRecord, HttpContext.RequestAborted); //} if (!string.IsNullOrEmpty(order.CallId)) await _callApplication.RelateTianrunCallWithOrderAsync(order.CallId, order.Id, HttpContext.RequestAborted); //内容分词 await _orderApplication.OrderParticiple(dto.Content, order.Id, order.No, order.Title, order.CreationTime, HttpContext.RequestAborted); //敏感分词 await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted); //知识库引用 await _orderApplication.AddKnowledgeQuote(order.Id, order.Title, order.No, order.KnowledgeQuote, HttpContext.RequestAborted); ////sms //try //{ // if (order.AcceptSms) // { // _logger.LogInformation($"推送短信: orderNo: {order.No}"); // var messageDto = new Share.Dtos.Push.MessageDto // { // PushBusiness = EPushBusiness.OrderAccept, // ExternalId = order.Id, // OrderId = order.Id, // PushPlatform = EPushPlatform.Sms, // //Content = // // $"温馨提示:您的来电已受理(流水号:{order.No};提取码:{order.Password},可通过网站(http://hotline.12345lm.cn)进行查询,谢谢。【宜宾12345热线平台】)", // Remark = order.Title, // Name = order.FromName, // TemplateCode = "1005", // Params = new List() { order.No, order.Password }, // TelNumber = order.Contact, // }; // await _mediator.Publish(new PushMessageNotify(messageDto), HttpContext.RequestAborted); // //await _pushDomainService.PushAsync(MessageDto, HttpContext.RequestAborted); // order.SmsSended = true; // await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); // } //} //catch (Exception e) //{ // _logger.LogError("新增工单发送短信失败,Error:{err}", e.Message); //} //2024-10-09 取消新增保存副本工单业务 //// 副本工单 //var copy = new OrderCopy(); //_mapper.Map(order, copy); //copy.OrderId = order.Id; //copy.AuditTime = DateTime.Now; //copy.AuditUserId = _sessionContext.UserId; //copy.AuditUserName = _sessionContext.UserName; //copy.InitId(); //await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted); return new { Id = order.Id, No = order.No, Password = order.Password, CallId = order.CallId }; } /// /// 提供ds调用 /// [HttpPost("add-anonymous")] [AllowAnonymous] [LogFilter("省平台调用记录")] public async Task AddAnonymous([FromBody] AddOrderDto dto) { return await _orderApplication.ReceiveOrderFromExternalAsync(dto, HttpContext.RequestAborted); } /// /// 提供ds调用--获取当天催办数量 /// [HttpGet("get-orderurge-count")] [AllowAnonymous] public async Task GetOrderUrgeCount() { var totle = await _orderUrgeRepository.Queryable() .Where(p => p.CreationTime >= Convert.ToDateTime(DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 00:00:00"))) .Where(p => p.CreationTime <= Convert.ToDateTime(DateTime.Now.AddDays(-1).ToString("yyyy-MM-dd 23:59:59"))) .CountAsync(); return new SubmitCaseTotalnfo() { Totle = totle }; } /// /// 提供ds调用 /// [HttpPost("update-orderfiles")] [AllowAnonymous] public async Task UpdateOrderFilesAnonymous([FromBody] UpdateOrderFilesDto dto) { await _orderApplication.UpdateOrderFilesAnonymousAsync(dto, HttpContext.RequestAborted); } /// /// 删除工单 /// /// /// [HttpDelete("{id}")] [LogFilter("删除工单")] public async Task Remove(string id) { var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted); if (order == null) return; if (order.Status != EOrderStatus.WaitForAccept) throw UserFriendlyException.SameMessage("非草稿工单不可删除"); await _orderRepository.RemoveAsync(order); } /// /// 更新工单信息 /// /// /// [HttpPut] [LogFilter("更新工单")] public async Task Update([FromBody] UpdateOrderDto dto) { dto.InitAddress(); //泸州任务 311 投诉件需限制受理内容的字数等需求 if (_appOptions.Value.IsLuZhou && dto.AcceptTypeCode == "35") { if (dto.Content.Length < 25) throw UserFriendlyException.SameMessage("保存失败,投诉类型受理内容字数需要至少25个字!"); if (dto.Title.Contains("咨询") || dto.Title.Contains("建议") || dto.Title.Contains("求助") || dto.Title.Contains("举报") || dto.Content.Contains("咨询") || dto.Content.Contains("建议") || dto.Content.Contains("求助") || dto.Title.Contains("举报")) throw UserFriendlyException.SameMessage("保存失败!投诉类型标题和受理内容不能出现'咨询、建议、求助、举报'"); } //交通工单校验 var valid = await _orderDomainService.OrderValidation(dto, HttpContext.RequestAborted); if (valid.Validation) throw UserFriendlyException.SameMessage(valid.Result); var order = await _orderRepository.Queryable() .FirstAsync(d => d.Id == dto.Id); if (order == null) throw UserFriendlyException.SameMessage("无效工单编号"); if (_appOptions.Value.IsZiGong != true) { if (dto.IsEdit != true && order.Status > EOrderStatus.HandOverToUnAccept) throw UserFriendlyException.SameMessage("工单已发起流程,不可编辑"); } // 副本工单 var copy = new OrderCopy(); _mapper.Map(order, copy); copy.OrderId = order.Id; copy.AuditTime = DateTime.Now; copy.AuditUserId = _sessionContext.UserId; copy.AuditUserName = _sessionContext.UserName; copy.InitId(); await _orderCopyRepository.AddAsync(copy, HttpContext.RequestAborted); if (order.Content != dto.Content) await _orderApplication.OrderParticiple(dto.Content, dto.Id, order.No, order.Title, order.CreationTime, HttpContext.RequestAborted); if (dto.RepeatableEventDetails?.Any() ?? false) { var reAdds = dto.RepeatableEventDetails.Where(x => string.IsNullOrEmpty(x.OrderId) && !x.IsDeleted) .ToList(); var reDeletes = dto.RepeatableEventDetails.Where(x => !string.IsNullOrEmpty(x.OrderId) && x.IsDeleted) .ToList(); reAdds.ForEach(x => x.OrderId = dto.Id); List repeatables = _mapper.Map>(reAdds); await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted); if (reDeletes?.Any() ?? false) { await _repeatableEventDetailRepository.DeleteAsync(reDeletes, HttpContext.RequestAborted); } } string acceptTypeCode = order.AcceptTypeCode; _mapper.Map(dto, order); if (order.SourceChannelCode != AppDefaults.SourceChannel.DianHua) order.CallId = null; if (dto.IsEdit && !string.IsNullOrEmpty(dto.CenterOpinion) && order.CenterToOrgOpinion != dto.CenterOpinion) order.CenterToOrgOpinion = dto.CenterOpinion; if (dto.IsEdit && !string.IsNullOrEmpty(dto.FileOpinion) && order.FileOpinion != dto.FileOpinion) order.FileOpinion = dto.FileOpinion; if (dto.Files.Any()) order.FileJson = await _fileRepository.AddFileAsync(dto.Files, order.Id, "", HttpContext.RequestAborted); else order.FileJson = new List(); var pushTypeAny = await _orderPushTypeRepository.AnyAsync(x => x.OrderId == order.Id); if (pushTypeAny) { await _orderPushTypeRepository.RemoveAsync(x => x.OrderId == order.Id); order.PushType = string.Empty; } // 工单推送分类 if (dto.OrderPushTypes.Any()) { dto.OrderPushTypes.ForEach(x => x.OrderId = order.Id); var orderPushTypes = _mapper.Map>(dto.OrderPushTypes); await _orderPushTypeRepository.AddRangeAsync(orderPushTypes); var pushTypes = dto.OrderPushTypes.Select(x => x.PushType); order.PushType = string.Join(",", pushTypes); } order.OrderTags = new List(); if (dto.Tags != null && dto.Tags.Any()) { var orderTags = new List(); foreach (var item in dto.Tags) { orderTags.Add(new SystemDicData() { Id = item }); } order.OrderTags = orderTags; var dicData = await _sysDicDataRepository.Queryable().Where(p => dto.Tags.Contains(p.Id)).Select(p => p.DicDataValue).ToListAsync(); if (dicData != null && dicData.Any()) { order.OrderTagCode = String.Join(", ", dicData); } } else order.OrderTagCode = string.Empty; //处理工单的期满时间 //首先是工单编辑页面提交的、流程已经开启、工单未归档的工单才能修改期满时间 if (dto.IsEdit && !string.IsNullOrEmpty(order.WorkflowId) && order.Status < EOrderStatus.Filed && dto.AcceptTypeCode != acceptTypeCode) { //查询当前工单的实际办理节点,如果在热线中心不处理,如果在部门需要更新期满时间 var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, withTraces: true, cancellationToken: HttpContext.RequestAborted); var nowWorkflow = workflow.Steps.Where(p => p.Id == order.ActualHandleStepId && p.BusinessType >= EBusinessType.Department && p.BusinessType <= EBusinessType.DepartmentLeader) .FirstOrDefault(); //在部门、中心到部门的交办时间不为空 if (nowWorkflow != null && order.CenterToOrgTime.HasValue) { //计算期满时间 ExpiredTimeWithConfig expiredTimeConfig = await _expireTime.CalcExpiredTime(order.CenterToOrgTime.Value, order.CenterToOrgTime.Value, EFlowDirection.CenterToOrg, order.Adapt()); if (expiredTimeConfig is not null && expiredTimeConfig.ExpiredTime > order.ExpiredTime) { order.ExpiredTime = expiredTimeConfig.ExpiredTime; order.NearlyExpiredTime = expiredTimeConfig.NearlyExpiredTime; order.NearlyExpiredTimeOne = expiredTimeConfig.NearlyExpiredTimeOne; } order.TimeLimit = expiredTimeConfig.TimeText; order.TimeLimitCount = expiredTimeConfig.Count; order.TimeLimitUnit = expiredTimeConfig.TimeType; } } await _orderRepository.UpdateNav(order, new UpdateNavRootOptions { IgnoreColumns = ["CallId"] }).Include(d => d.OrderExtension) .Include(d => d.OrderTags).ExecuteCommandAsync(); //订阅此事件的内部处理工单数据只能更新各自业务的字段,不能全部更新 //修改工单其他处理事件 (受理短信) await _publisher.PublishAsync(new UpdateOrderNotify(order), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted); //敏感分词 await _orderApplication.OrderSensitiveParticiple(dto.Content, order.Id, HttpContext.RequestAborted); //知识库引用 await _orderApplication.AddKnowledgeQuote(order.Id, order.Title, order.No, order.KnowledgeQuote, HttpContext.RequestAborted); return new { Id = order.Id, No = order.No, Password = order.Password, CallId = order.CallId }; } /// /// 开始工单办理流程 /// [HttpPost("startflow")] public async Task StartFlow([FromBody] StartWorkflowDto dto) { var validator = new BasicWorkflowDtoValidator(); var validResult = await validator.ValidateAsync(dto.Workflow, HttpContext.RequestAborted); if (!validResult.IsValid) throw new UserFriendlyException( $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}"); var order = await _orderDomainService.GetOrderAsync(dto.Data.OrderId, withExtension: true, cancellationToken: HttpContext.RequestAborted); if (!string.IsNullOrEmpty(order.WorkflowId)) throw new UserFriendlyException($"该工单已开启办理流程, No:{order.No}", "该工单已开启办理流程"); //交通工单校验 // UpdateOrderDto upOrder = _mapper.Map(order); //var valid = await _orderDomainService.OrderValidation(upOrder, HttpContext.RequestAborted); //if (valid.Validation) // throw UserFriendlyException.SameMessage(valid.Result); ExpiredTimeWithConfig expiredTimeConfig; var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; CityBaseConfiguration cityBase = JsonSerializer.Deserialize(setting); if (dto.Workflow.NextHandlers.Any(d => d.Key == cityBase.CityProvince.OrgId || d.Key == cityBase.CityProvinceAssign.OrgId)) { if (dto.Workflow.NextHandlers.Any(d => d.Key == cityBase.CityProvince.OrgId) && order.OrderExtension is null) { throw UserFriendlyException.SameMessage("该工单不存在拓展信息,不能推送至全国12315平台!"); } var timeResult = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, ETimeType.WorkDay, 45, 80, 50); expiredTimeConfig = new ExpiredTimeWithConfig { Count = 45, TimeType = ETimeType.WorkDay, TimeText = "45个工作日", ExpiredTime = timeResult.EndTime, NearlyExpiredTime = timeResult.NearlyExpiredTime, NearlyExpiredTimeOne = timeResult.NearlyExpiredTimeOne, }; } else { if (_appOptions.Value.IsZiGong) { if (dto.Workflow.FlowDirection.HasValue && dto.Workflow.FlowDirection == EFlowDirection.CenterToCenter) { expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToCenter, order.Adapt()); } else { expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToOrg, order.Adapt()); } } else { //期满时间 expiredTimeConfig = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, EFlowDirection.CenterToOrg, order.Adapt()); } } order.IsForwarded = dto.Workflow.IsForwarded; _mapper.Map(expiredTimeConfig, order); if (dto.Workflow.BusinessType is EBusinessType.Department or EBusinessType.DepartmentLeader) order.ProcessType = EProcessType.Jiaoban; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); try { var startDto = _mapper.Map(dto.Workflow); startDto.DefinitionModuleCode = WorkflowModuleConsts.OrderHandle; startDto.Title = order.Title; var (workflow, startStep) = await _workflowDomainService.StartAsync(startDto, order.Id, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted); await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted); } catch (Exception e) { _logger.LogError($"工单开启流程失败!, {e.Message}, {e.StackTrace}"); throw new UserFriendlyException($"工单开启流程失败!, {e.Message}, {e.StackTrace}", "工单开启流程失败"); } if ((_appOptions.Value.IsYiBin || _appOptions.Value.IsLuZhou) && order.Transpond.HasValue && order.Transpond.Value) { //开启流程处理事件,处理市州互转 await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted); } } /// /// 查询工单办理流程开启参数 /// /// 4 [HttpGet("startflow")] public async Task GetFlowStartOptions([FromQuery] string? orderId) { var outDto = await _workflowApplication.GetStartStepsAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted); if (orderId.NotNullOrEmpty()) { outDto.Opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted); outDto.Content = (await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted))?.Content; } //随手拍 bool.TryParse(_systemSettingCacheManager.GetSetting(SettingConstants.Snapshot)?.SettingValue[0], out bool isSnapshotEnable); if (isSnapshotEnable) { var orderSnapshot = await _orderSnapshotRepository.GetAsync(orderId, HttpContext.RequestAborted); if (orderSnapshot != null && string.CompareOrdinal(orderSnapshot.IndustryName, "安全隐患") == 0) { outDto.Steps = outDto.Steps.Where(d => d.BusinessType != EBusinessType.Send).ToList(); } } return outDto; } /// /// 工单办理 /// [HttpPost("handle")] public async Task Handle([FromBody] NextWorkflowDto dto) { var validator = new BasicWorkflowDtoValidator(); var validResult = await validator.ValidateAsync(dto.Workflow, HttpContext.RequestAborted); if (!validResult.IsValid) throw new UserFriendlyException( $"非法参数, {string.Join(',', validResult.Errors.Select(d => d.ErrorMessage))}"); var order = await _orderApplication.SaveOrderWorkflowInfo(dto, HttpContext.RequestAborted); // 随手拍业务处理 if (_systemSettingCacheManager.Snapshot) { await _orderSnapshotApplication.SaveOrderWorkflowInfo(dto); } var workflow = await _workflowDomainService.GetWorkflowAsync(dto.Workflow.WorkflowId, withDefine: true, withSteps: true, withTraces: true, cancellationToken: HttpContext.RequestAborted); //await _workflowApplication.NextAsync(dto.WorkflowDto, order.ExpiredTime, HttpContext.RequestAborted); var startStep = workflow.Steps.First(d => d.Id == dto.Workflow.StepId); await HandleOrderAsync(order, workflow, startStep, dto.Data, dto.Workflow, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong && dto.Data.Transpond.HasValue && dto.Data.Transpond.Value) { var count = await _transpondCityRawDataRepository.Queryable() .CountAsync(m => m.OrderCode == order.No && m.CityName == order.TranspondCityName && m.Direction == ETranspondDirection.Out, HttpContext.RequestAborted); //处理市州互转 if (count == 0) await _publisher.PublishAsync(new OrderStartWorkflowNotify(order.Id), PublishStrategy.ParallelWhenAll, HttpContext.RequestAborted); } } /// /// 工单批量标注是否安全生产 /// /// /// [HttpPut("sign/bath")] public async Task OrderSignBathAsync([FromBody] OrderSignBathInDto dto) { var stringBuilder = new StringBuilder(); foreach (var orderId in dto.OrderIds) { var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted); if (order is null) { continue; } var snapshot = await _orderSnapshotApplication.UpdateSafetyAsync(orderId, dto.IsSafetyDepartment, dto.Remark); if (snapshot is null) { stringBuilder.Append($"随手拍: {order.No} 不存在"); continue; } var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withDefine: true, withSteps: true, withTraces: true, cancellationToken: HttpContext.RequestAborted); NextStepsWithOpinionDto nextSteps; try { nextSteps = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, HttpContext.RequestAborted); } catch (UserFriendlyException e) { if (e.Message.Contains("未找到对应节点")) { stringBuilder.AppendLine($"{order.No} 修改成功"); continue; } throw; } var stepInfo = nextSteps.Steps.FirstOrDefault(m => m.BusinessType == EBusinessType.Send); if (stepInfo == null) { stringBuilder.Append($"下一步节点: [派单组] 未找到"); continue; } var data = new OrderHandleFlowDto { OrderId = orderId, IsSafetyDepartment = dto.IsSafetyDepartment }; var workflowDto = new NextWorkflowDto { WorkflowId = order.WorkflowId, StepId = nextSteps.StepId, NextStepCode = stepInfo.Key, NextStepName = stepInfo.Value, Opinion = dto.Remark, BackToCountersignEnd = false, IsSms = false, IsForwarded = false, HandlerType = EHandlerType.OrgLevel, BusinessType = EBusinessType.Send, FlowDirection = EFlowDirection.CenterToCenter, }; var startStep = workflow.Steps.First(d => d.Id == nextSteps.StepId); await HandleOrderAsync(order, workflow, startStep, data, workflowDto, HttpContext.RequestAborted); stringBuilder.AppendLine($"{orderId} 标注完成;"); } return stringBuilder.ToString(); } private async Task HandleOrderAsync(Order order, Workflow workflow, WorkflowStep startStep, OrderHandleFlowDto orderHandleFlowDto, BasicWorkflowDto workflowDto, CancellationToken cancellationToken) { var isAutoFillSummaryOpinion = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsAutoFillSummaryOpinion).SettingValue[0]); switch (orderHandleFlowDto.OrderAssignMode) { case EOrderAssignMode.AdjoinLevel: // 逐级 var nextDto = _mapper.Map(workflowDto); nextDto.WorkflowId = startStep.WorkflowId; nextDto.StepId = startStep.Id; if (workflowDto.BusinessType == EBusinessType.Send) { // 宜宾需求: 1.是否是派单节点 2.是否存在历史派单节点 3.存在获取上个派单节点 4.不存在走平均派单 if (_appOptions.Value.IsYiBin || _appOptions.Value.IsZiGong) { var sendOrderTraces = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send); if (sendOrderTraces.Any()) { var sendOrderTrace = workflow.Traces.Where(x => x.BusinessType == EBusinessType.Send) .OrderByDescending(x => x.CreationTime) .FirstOrDefault(); nextDto.NextHandlers = new List { new() { Key = sendOrderTrace.HandlerId, Value = sendOrderTrace.HandlerName, UserId = sendOrderTrace.HandlerId, Username = sendOrderTrace.HandlerName, OrgId = sendOrderTrace.HandlerOrgId, OrgName = sendOrderTrace.HandlerOrgName, FlowAssignType = EFlowAssignType.User } }; } else { await AverageSendOrderAsync(nextDto, HttpContext.RequestAborted); } } else { await AverageSendOrderAsync(nextDto, HttpContext.RequestAborted); } // var flowStepHandler = nextDto.NextHandlers.FirstOrDefault(); // await _orderRepository.Updateable().SetColumns(o => new Order() // { // CenterToOrgHandlerId = flowStepHandler.UserId, // CenterToOrgHandlerName = flowStepHandler.Username // }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } var (_, currentStep, _, _) = await _workflowDomainService.NextAsync(_sessionContext, nextDto, order.ExpiredTime, isAutoFillSummaryOpinion, cancellationToken: cancellationToken); if (currentStep.BusinessType is EBusinessType.Send) { await _orderRepository.Updateable().SetColumns(o => new Order() { CenterToOrgHandlerId = currentStep.HandlerId, CenterToOrgHandlerName = currentStep.HandlerName }).Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } break; case EOrderAssignMode.CrossLevel: // 跨级 if (!orderHandleFlowDto.CrossSteps.Any()) throw new UserFriendlyException("跨级指派参数异常"); orderHandleFlowDto.CrossSteps = orderHandleFlowDto.CrossSteps.OrderBy(d => d.Sort).ToList(); var stepCount = orderHandleFlowDto.CrossSteps.Count; var unhandleSteps = new List { startStep }; for (int i = 0; i < stepCount; i++) { var crossStep = orderHandleFlowDto.CrossSteps[i]; var tempSteps = new List(); foreach (var unhandleStep in unhandleSteps) { var lowerLevelHandlers = crossStep.NextHandlers.Where(d => d.OrgId.StartsWith(unhandleStep.HandlerOrgId)).ToList(); if (!lowerLevelHandlers.Any()) continue; var nextflowDto = _mapper.Map(crossStep); nextflowDto.WorkflowId = unhandleStep.WorkflowId; nextflowDto.StepId = unhandleStep.Id; nextflowDto.IsStartCountersign = lowerLevelHandlers.Count > 1; nextflowDto.NextHandlers = lowerLevelHandlers; if (unhandleStep.Id != startStep.Id) nextflowDto.Opinion = "跨级派单,自动办理"; var operater = new FakeSessionContext { OrgId = unhandleStep.HandlerOrgId, OrgName = unhandleStep.HandlerOrgName, }; var (_, _, _, nextSteps) = await _workflowDomainService.NextAsync(operater, nextflowDto, order.ExpiredTime, isAutoFillSummaryOpinion, cancellationToken: cancellationToken); tempSteps.AddRange(nextSteps); } unhandleSteps = tempSteps; } break; case EOrderAssignMode.MainAndSecondary: //主协办暂只支持指派给部门办理,且主办部门有且只有一个一级部门 nextDto = _mapper.Map(workflowDto); nextDto.WorkflowId = startStep.WorkflowId; nextDto.StepId = startStep.Id; nextDto.HandlerType = EHandlerType.OrgLevel; nextDto.FlowDirection = EFlowDirection.CenterToOrg; var secondaryOrgs = orderHandleFlowDto.SecondaryOrgs.DistinctBy(d => d.Id).ToList(); var nextHandleOrgs = secondaryOrgs .Where(d => d.Level == 1 && d.Id.StartsWith(OrgSeedData.CenterId)) .ToList(); if (nextHandleOrgs.Any()) nextDto.NextHandlers.AddRange(nextHandleOrgs.Select(d => new StepAssignInfo { Key = d.Id, Value = d.Name, OrgId = d.Id, OrgName = d.Name, FlowAssignType = EFlowAssignType.Org })); nextDto.IsStartCountersign = nextDto.NextHandlers.Count > 1; await HandleNextInMainAndSecondaryAsync(_sessionContext, workflow.WorkflowDefinition, secondaryOrgs, nextDto, order.ExpiredTime, isAutoFillSummaryOpinion, cancellationToken); //抄送 var ccs = orderHandleFlowDto.Copys .Where(d => !string.IsNullOrEmpty(d.OrgId) || !string.IsNullOrEmpty(d.RoleId) || !string.IsNullOrEmpty(d.UserId)) .Select(d => _mapper.Map(d)) .Distinct() .ToList(); ccs.ForEach(d => d.OrderId = order.Id); await _orderCarboncopy.AddRangeAsync(ccs, HttpContext.RequestAborted); break; default: throw new ArgumentOutOfRangeException(); } } private async Task HandleNextInMainAndSecondaryAsync(ISessionContext current, WorkflowDefinition definition, List orgs, NextWorkflowDto? flowDto, DateTime? expiredTime, bool isAutoFillSummaryOpinion, CancellationToken cancellation) { if (flowDto is null || !flowDto.NextHandlers.Any()) return; var (_, _, _, currentSteps) = await _workflowDomainService.NextAsync(current, flowDto, expiredTime, isAutoFillSummaryOpinion, cancellationToken: cancellation); foreach (var currentStep in currentSteps) { var currentStepHandlerOrgId = currentStep?.HandlerOrgId; if (string.IsNullOrEmpty(currentStepHandlerOrgId)) throw new UserFriendlyException($"数据异常, 待办部门id为空, stepId: {currentStep.Id}"); var nextStepHandlerOrgLevel = currentStepHandlerOrgId.CalcOrgLevel() + 1; var nextHandlers = orgs.Where(d => d.Level == nextStepHandlerOrgLevel && d.Id.StartsWith(currentStepHandlerOrgId)) .Select(d => new StepAssignInfo { Key = d.Id, Value = d.Name, OrgId = d.Id, OrgName = d.Name, FlowAssignType = EFlowAssignType.Org }) .ToList(); if (nextHandlers.Any()) { var nextStepDefine = definition.FindStepDefines(currentStep.NextSteps.Select(d => d.Code)) .FirstOrDefault(d => d.HandlerType == EHandlerType.OrgLevel && d.HandlerTypeItems.Any(x => x.Key == nextStepHandlerOrgLevel.ToString())); if (nextStepDefine == null) throw new UserFriendlyException($"流程模板未配置该部门等级, defineId: {definition.Id}, level: {nextStepHandlerOrgLevel}"); var nextDto = new NextWorkflowDto { WorkflowId = flowDto.WorkflowId, StepId = currentStep.Id, NextStepCode = nextStepDefine.Code, NextStepName = nextStepDefine.Name, FlowDirection = EFlowDirection.OrgToOrg, HandlerType = nextStepDefine.HandlerType, StepType = nextStepDefine.StepType, IsSms = false, NextHandlers = nextHandlers, IsStartCountersign = nextHandlers.Count > 1, BusinessType = nextStepDefine.BusinessType, }; await HandleNextInMainAndSecondaryAsync(current, definition, orgs, nextDto, expiredTime, isAutoFillSummaryOpinion, cancellation); } } } private async Task AverageSendOrderAsync(NextWorkflowDto nextDto, CancellationToken cancellationToken) { // 平均派单 var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); if (averageSendOrder) { if (!nextDto.NextHandlers.Any()) { var handler = await _orderDomainService.AverageOrder(cancellationToken); nextDto.NextHandlers = new List { handler }; } } } /// /// 跨级指派查询下一步可选节点及办理对象参数 /// /// [HttpGet("nextsteps/cross")] public async Task> GetCrossLevelStepsOptions([FromQuery] GetCrossLevelStepsDto dto) { return await _workflowApplication.GetCrossLevelStepsAsync(dto, HttpContext.RequestAborted); } /// /// 查询工单办理下一步可选节点(带推荐部门) /// [HttpGet("nextsteps/{orderId}")] public async Task> GetNextStepsWithRecommend(string orderId) { var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted); if (string.IsNullOrEmpty(order.WorkflowId)) throw UserFriendlyException.SameMessage("该工单未开启流程"); var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, HttpContext.RequestAborted); dto.ExpiredTime = order.ExpiredTime; dto.Content = order.Content; var rsp = _mapper.Map>(dto); foreach (var step in rsp.Steps) { if (dto.CurrentStepBusinessType is not EBusinessType.Send || step.BusinessType is not EBusinessType.Department) continue; var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted); if (org is null) continue; step.RecommendOrgId = org.Id; step.RecommendOrgName = org.Name; } rsp.LeaderSMS = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LeaderSMS) .Select(m => new Kv { Key = m.Id, Value = m.DicDataName }).ToList(); var opinion = await _typeCache.GetAsync($"tmp_opinion_{orderId}{_sessionContext.UserId}", HttpContext.RequestAborted); if (opinion.NotNullOrEmpty()) { rsp.Opinion = opinion; } rsp.TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity) .ToList().Adapt>(); rsp.CounterSignType = order.CounterSignType; await _orderSnapshotApplication.GetNextStepsDatabaseAsync(rsp, orderId); return rsp; } /// /// 临时保存 /// [HttpPost("steps/temp")] public async Task TempSaveAsync([FromBody] StepTempInDto dto) { if (dto.OrderId.IsNullOrEmpty() || dto.Opinion.IsNullOrEmpty()) return; await _typeCache.SetAsync($"tmp_opinion_{dto.OrderId}{_sessionContext.UserId}", dto.Opinion, TimeSpan.FromDays(3), HttpContext.RequestAborted); } /// /// 查询工单办理下一步可选节点(带推荐部门) /// [HttpGet("nextsteps_commission/{orderId}")] public async Task> GetNextStepsWithRecommendCommission(string orderId) { var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted); if (string.IsNullOrEmpty(order.WorkflowId)) throw UserFriendlyException.SameMessage("该工单未开启流程"); var unhandleSteps = await _workflowDomainService.GetUnhandleStepsByOthersAsync(order.WorkflowId, HttpContext.RequestAborted); if (unhandleSteps.Count > 1) throw UserFriendlyException.SameMessage("会签工单不允许班长代办"); if (unhandleSteps.Count < 1) throw UserFriendlyException.SameMessage("未查询到流程信息"); var stepOne = unhandleSteps.First(); if (stepOne.IsInCountersign()) throw UserFriendlyException.SameMessage("会签工单不允许班长代办"); var dto = await _workflowApplication.GetNextStepsAsync(order.WorkflowId, stepOne.Id, HttpContext.RequestAborted); dto.ExpiredTime = order.ExpiredTime; var rsp = _mapper.Map>(dto); foreach (var step in rsp.Steps) { if (dto.CurrentStepBusinessType is not EBusinessType.Send || step.BusinessType is not EBusinessType.Department) continue; var org = await _organizeRepository.GetAsync(d => d.AreaCode == order.AreaCode, HttpContext.RequestAborted); if (org is null) continue; step.RecommendOrgId = org.Id; step.RecommendOrgName = org.Name; } return rsp; } /// /// 结束会签 /// [HttpPost("endcs")] public async Task EndCountersign([FromBody] EndCountersignDto dto) { await _orderApplication.EndCountersignAsync(dto, HttpContext.RequestAborted); } /// /// 查询工单办理的期满时间配置 /// [HttpGet("time-config")] public async Task GetOrderHandleTimeConfigByAcceptType(EFlowDirection flowDirection, string? acceptTypeCode) { return flowDirection switch { //EFlowDirection.CenterToOrg => _timeLimitDomainService.GetOrderTimeLimitConfig(acceptTypeCode), EFlowDirection.CenterToOrg => _expireTime.GetOrderTimeLimitConfig(acceptTypeCode), //EFlowDirection.OrgToCenter => _timeLimitDomainService.GetOrderTimeLimitConfig(), EFlowDirection.OrgToCenter => _expireTime.GetOrderTimeLimitConfig(), _ => throw new ArgumentOutOfRangeException(nameof(flowDirection), flowDirection, null) }; } /// /// 列表页面基础数据 /// /// [HttpGet("base-data")] public async Task BaseData() { var wfModule = await _workflowApplication.GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted); var definition = wfModule.Definition; var rsp = new { TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity), AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel), OrgsOptions = await _organizeRepository.GetOrgJson(), EmergencyLevelOptions = EnumExts.GetDescriptions(), PushTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType), OrderStatusOptions = EnumExts.GetDescriptions(), CurrentStepOptions = definition?.Steps.Select(x => new Kv(x.Code, x.Name)), IdentityTypeOptions = EnumExts.GetDescriptions(), OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag), FocusOnEvents = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.FocusOnEvent) }; return rsp; } /// /// 新增页面基础数据 /// /// [HttpGet("base-data-add")] public async Task BaseDataAdd() { //是否行政执法类工单 var IsOpenJudicialManagement = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.IsOpenJudicialManagement).SettingValue[0]); //重点关注事件 var FocusOnEvents = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.FocusOnEvent).ToList(); if (!IsOpenJudicialManagement) { var xingzhengzhifa = FocusOnEvents.FirstOrDefault(d => d.DicDataValue == "2"); if (xingzhengzhifa is not null) FocusOnEvents.Remove(xingzhengzhifa); } //List FocusOnEvents = new() //{ // new Kv { Key = "0", Value = "紧急工单" }, // new Kv { Key = "1", Value = "形式主义工单" }, // new Kv { Key = "3", Value = "敏感类工单" } //}; //if (IsOpenJudicialManagement) // FocusOnEvents.Add(new Kv { Key = "2", Value = "行政执法类工单" }); ////todo 宜宾add 1,3 ////todo 自贡add 4 //FocusOnEvents.Add(new Kv { Key = "4", Value = "24小时办结" }); var industryItems = await _industryRepository.Queryable() .Select(d => new { d.Id, d.Name, }) .ToListAsync(); var rsp = new { Industry = industryItems, TranspondCity = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.TranspondCity), ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel), AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), //EmergencyLevelOptions = EnumExts.GetDescriptions(), PushTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType), GenderOptions = EnumExts.GetDescriptions(), IdentityTypeOptions = EnumExts.GetDescriptions(), LicenceTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LicenceType), AgeRangeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AgeRange), OrderTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderType), OrderTags = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderTag), FocusOnEvents }; return rsp; } /// /// 扩展信息新增页面基础数据 /// /// [HttpGet("base-data-ext")] public async Task BaseDataExtension() { var rsp = new { LicenceTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LicenceType), IdentityTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ProviderIdentityType), IdentityOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Identity), NationalityOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Nationality), NationOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Nation), MarketTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.MarketType), IndustryClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.IndustryClassify), BrandOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Brand), ObjectClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ObjectClassify), ComplainClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ComplainClassify), ReportClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReportClassify), SalesModeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SalesMode), ECommercePlatformOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ECommercePlatform), PatentTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PatentType), AffairTargetOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AffairTarget), ComplainTypeOptions = EnumExts.GetDescriptions().Select(d => new Kv(d.Key.ToString(), d.Value)), SalesChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SalesChannel), }; return rsp; } /// /// 扩展信息新增页面基础数据 /// /// [HttpPost("order_repeatable_event")] public async Task RepeatableEvent(QueryRepeatableEventDto dto) { var exp = Expressionable.Create() .OrIF(!string.IsNullOrEmpty(dto.HotspotSpliceName), x => x.HotspotSpliceName.EndsWith(dto.HotspotSpliceName!)) .OrIF(!string.IsNullOrEmpty(dto.Address), x => x.Address != null && x.Address.EndsWith(dto.Address!)); var count = await _orderRepository.Queryable() .Where(exp.ToExpression()) .Where(d => d.CreationTime.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd")) .CountAsync(); var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RepeatableEventNum); return count >= int.Parse(setting?.SettingValue[0] ?? "0"); } /// /// 触发平均派单 /// /// [HttpPost("trigger_average_order")] [AllowAnonymous] public async Task TriggerAverageOrder() { await _orderDomainService.TriggerAverageOrder(HttpContext.RequestAborted); } /// /// 批量归档(暂时只支持派单组节点操作) /// /// 成功总量 [HttpPost("batch-file")] public async Task BatchFile([FromBody] OrderBatchFileDto dto) { var orders = await _orderRepository.Queryable() .Includes(w => w.Workflow, d => d.WorkflowDefinition) .Includes(w => w.Workflow, d => d.Steps) .Includes(w => w.Workflow, d => d.Traces) .Includes(w => w.Workflow, d => d.Countersigns) .Where(d => dto.OrderIds.Contains(d.Id)) .ToListAsync(HttpContext.RequestAborted); var success = 0; foreach (var order in orders) { //非派单组节点办理时不允许操作 var unhandleSteps = order.Workflow.Steps .Where(d => d.Status != EWorkflowStepStatus.Handled) .ToList(); if (unhandleSteps.Count == 0 || unhandleSteps.Count > 2 || unhandleSteps.First().BusinessType != EBusinessType.Send) continue; var startStep = order.Workflow.Steps.Where(d => d.StepType == EStepType.Start && d.IsOrigin) .MaxBy(d => d.CreationTime); if (startStep?.Status is not EWorkflowStepStatus.Handled || string.IsNullOrEmpty(startStep.Opinion)) continue; var opinion = startStep.Opinion; await _workflowDomainService.JumpToEndAsync(_sessionContext, order.Workflow, opinion, dto.Files, order.ExpiredTime, cancellationToken: HttpContext.RequestAborted); success++; } return $"批量办理{dto.OrderIds.Count}件,成功{success}件"; } /// /// 查询工单办理流程明细 /// [HttpGet("traces/{workflowId}")] public async Task> GetOrderTraces(string workflowId) { var traces = await _workflowTraceRepository.Queryable() .Includes(d => d.OrderPublish) .Includes(d => d.OrderVisit, x => x.OrderVisitDetails) .Where(d => d.WorkflowId == workflowId) .OrderBy(d => d.CreationTime) .ToTreeAsync(d => d.Traces, d => d.ParentId, null); return _mapper.Map>(traces); } /// /// 流转到坐席的次数 /// /// [HttpGet("count-of-flow-to-seat/{orderId}")] public async Task FlowToSeatCountAsync(string orderId) { var order = await _orderRepository.Queryable() .Includes(d => d.WorkflowTraces) .FirstAsync(d => d.Id == orderId, HttpContext.RequestAborted); return order.WorkflowTraces.Count(d => d.IsOrigin && d.BusinessType == EBusinessType.Seat); } #endregion #region 工单待办 ///// ///// 查询待办工单 ///// //[HttpGet("waited")] //public async Task> QueryWaited([FromQuery] QueryOrderWaitedDto dto) //{ // var isHandledStep = dto.IsHandled.HasValue && dto.IsHandled.Value; // if (isHandledStep) // dto.QueryType = null; // var isAdmin = _orderDomainService.IsCheckAdmin(); // var query = _orderRepository // .Queryable(hasHandledStep: isHandledStep, isAdmin: isAdmin) // .Includes(d => d.OrderSpecials); // if (dto.QueryType is 1 || dto.QueryType is 2) // { // query.WhereIF(dto.QueryType is 1, d => d.IsForwarded == false) // .WhereIF(dto.QueryType is 2, d => d.IsForwarded == true) // .Where(d => SqlFunc.Subqueryable().Where(os => os.OrderId == d.Id && os.IsDeleted == false && os.SpecialType == ESpecialType.ReTransact) // .NotAny()) // ; // } // var (total, items) = await query // .Where(d => d.Status != EOrderStatus.WaitForAccept && // d.Status != EOrderStatus.BackToUnAccept && // d.Status != EOrderStatus.SpecialToUnAccept && // d.Status != EOrderStatus.HandOverToUnAccept) // .WhereIF(dto.QueryType is 3, // d => SqlFunc.Subqueryable().Where(os => os.OrderId == d.Id && os.IsDeleted == false && os.SpecialType == ESpecialType.ReTransact).Any()) // .Where(d => SqlFunc.Subqueryable().Where(od => od.OrderId == d.Id && od.IsDeleted == false && od.DelayState == EDelayState.Examining).NotAny()) // .Where(d => SqlFunc.Subqueryable().Where(osba => osba.OrderId == d.Id && osba.IsDeleted == false && osba.State == ESendBackAuditState.Apply) // .NotAny()) // .Where(d => SqlFunc.Subqueryable().Where(s => s.OrderId == d.Id && s.State == 0 && s.IsDeleted == false).NotAny()) // .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince) // .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword)) // .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) // .WhereIF(!string.IsNullOrEmpty(dto.AreaCode), d => d.AreaCode == dto.AreaCode) // .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue) // .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null) // .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, // d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || // (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办 // .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, // d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办 // .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC) // .Where(d => d.Status != EOrderStatus.BackToProvince) // .WhereIF(!isHandledStep || _appOptions.Value.IsYiBin,d=>d.Status < EOrderStatus.Filed) // //.Where(d => SqlFunc.Subqueryable().Where(os => os.OrderId == d.Id).NotAny()) // //.Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State > 0)) // .WhereIF(dto.StartTime.HasValue, d => d.StartTime >= dto.StartTime) // .WhereIF(dto.EndTime.HasValue, d => d.StartTime <= dto.EndTime) // .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value) // .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status) // //.OrderByDescending(d => d.IsUrgent) // .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.StartTime, OrderByType.Desc) // .OrderByIF(dto is { SortField: "creationTime", SortRule: 0 }, d => d.CreationTime, OrderByType.Asc) //创建时间升序 // .OrderByIF(dto is { SortField: "creationTime", SortRule: 1 }, d => d.CreationTime, OrderByType.Desc) //创建时间降序 // .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序 // .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序 // .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //期满时间升序 // .OrderByIF(dto is { SortField: "expiredTime", SortRule: 1 }, d => d.ExpiredTime, OrderByType.Desc) //期满时间降序 // .ToPagedListAsync(dto, HttpContext.RequestAborted); // return new PagedDto(total, _mapper.Map>(items)); //} /// /// 列表页面基础数据 /// /// [HttpGet("waited/base-data")] public async Task WaitedBaseData() { var wfModule = await _workflowApplication.GetWorkflowModuleAsync(WorkflowModuleConsts.OrderHandle, HttpContext.RequestAborted); var definition = wfModule.Definition; var rsp = new { OrderStatusOptions = EnumExts.GetDescriptions(), CurrentStepOptions = definition?.Steps.Select(x => new Kv(x.Code, x.Name)) }; return rsp; } /// /// 工单待办 /// [HttpGet("waited")] public async Task> QueryWaited([FromQuery] QueryOrderWaitedDto dto) { var orders = await _orderApplication .QueryWaited(dto) .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); return _mapper.Map>(orders); } [HttpGet("waited/count")] public async Task QueryWaitedCount([FromQuery] QueryOrderWaitedDto dto) { return await _orderApplication .QueryWaited(dto) .CountAsync(HttpContext.RequestAborted); } /// /// 查询坐席待办 /// [HttpGet("waited/sign")] public async Task> QueryWaitedForSeat([FromQuery] QueryOrderWaitedDto dto) { var orders = await _orderApplication .QueryWaitedForSeat(dto) .ToPageListWithoutTotalAsync(dto, HttpContext.RequestAborted); return _mapper.Map>(orders); } [HttpGet("waited/sign/count")] public async Task QueryWaitedForSeatCount([FromQuery] QueryOrderWaitedDto dto) { return await _orderApplication .QueryWaitedForSeat(dto) .CountAsync(HttpContext.RequestAborted); } /// /// 查询中心待办 //TODO /// [HttpGet("waited/center")] public async Task> QueryWaitedForCenter([FromQuery] QueryOrderWaitedCenterDto dto) { var (total, items) = await _orderRepository.Queryable() .Includes(d => d.Workflow.Steps) .Where(d => SqlFunc.Subqueryable() .WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), step => step.BusinessType == EBusinessType.Send && step.HandlerName.Contains(dto.CenterToOrgHandlerName)) .Where(step => step.ExternalId == d.Id && step.HandlerOrgId == OrgSeedData.CenterId && step.Status < EWorkflowStepStatus.Handled).Any() || (string.IsNullOrEmpty(d.WorkflowId) && string.IsNullOrEmpty(dto.CenterToOrgHandlerName)) ) .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC) .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed) .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No!) .WhereIF(!string.IsNullOrEmpty(dto.Title), d => d.Title.StartsWith(dto.Title!)) .WhereIF(dto is { StCreationTime: not null, EndCreationTime: not null }, d => d.CreationTime >= dto.StCreationTime && d.CreationTime <= dto.EndCreationTime) .WhereIF(dto is { StartTimeSt: not null, StartTimeEnd: not null }, d => d.StartTime >= dto.StartTimeSt && d.StartTime <= dto.StartTimeEnd) .WhereIF(!string.IsNullOrEmpty(dto.StepName), d => d.ActualHandleStepName == dto.StepName) .WhereIF(!string.IsNullOrEmpty(dto.ActualHandleOrgName), d => d.ActualHandleOrgName.Contains(dto.ActualHandleOrgName)) .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status) .WhereIF(!string.IsNullOrEmpty(dto.SourceChannelCode), d => d.SourceChannelCode == dto.SourceChannelCode) //任务:308 市州通用-【中心待办件】新增“来源渠道”查询条件 .WhereIF(!string.IsNullOrEmpty(dto.AcceptorName), d => d.AcceptorName!.Contains(dto.AcceptorName!)) .WhereIF(dto.ExpiredStatus is EExpiredStatus.Normal, d => DateTime.Now < d.NearlyExpiredTime) .WhereIF(dto.ExpiredStatus is EExpiredStatus.GoingToExpired, d => DateTime.Now > d.NearlyExpiredTime && DateTime.Now < d.ExpiredTime) .WhereIF(dto.ExpiredStatus is EExpiredStatus.Expired, d => DateTime.Now >= d.ExpiredTime) //.WhereIF(!string.IsNullOrEmpty(dto.CenterToOrgHandlerName), d => d.CenterToOrgHandlerName.Contains(dto.CenterToOrgHandlerName)) .WhereIF(dto.IsUrgent.HasValue, d => d.IsUrgent == dto.IsUrgent!.Value) .OrderByIF(string.IsNullOrEmpty(dto.SortField), d => d.CreationTime, OrderByType.Desc) .OrderByIF(dto is { SortField: "startTime", SortRule: 0 }, d => d.StartTime, OrderByType.Asc) //受理时间升序 .OrderByIF(dto is { SortField: "startTime", SortRule: 1 }, d => d.StartTime, OrderByType.Desc) //受理时间降序 .OrderByIF(dto is { SortField: "expiredTime", SortRule: 0 }, d => d.ExpiredTime, OrderByType.Asc) //期满时间升序 .OrderByIF(dto is { SortField: "expiredTime", SortRule: 1 }, d => d.ExpiredTime, OrderByType.Desc) //期满时间降序 .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 查询中心待办基础数据 /// /// [HttpGet("waited/center/base")] public async Task> WaitedForCenterBaseData() { var rsp = new Dictionary { { "orderStatus", EnumExts.GetDescriptions() }, { "expiredStatus", EnumExts.GetDescriptions() }, { "stepNames", new string[] { "话务部", "派单组", "班长审批" } }, { "channelOptions", _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel) } //任务:308 市州通用-【中心待办件】新增“来源渠道”查询条件 }; if (_systemSettingCacheManager.Snapshot) { var industry = await _industryRepository.Queryable() .Select(d => new { d.Id, d.Name, }) .ToListAsync(); rsp.Add("industry", industry); } return rsp; } /// /// 首页查询 /// /// /// [HttpGet("waited/home")] public async Task QueryWaitedHome([FromQuery] QueryOrderWaitedDto dto) { var isHandled = dto.IsHandled.HasValue && dto.IsHandled.Value; //if (dto.EndTime.HasValue) // dto.EndTime = dto.EndTime.Value.AddDays(1).AddSeconds(-1); var (total, items) = await _orderRepository .Queryable(hasHandled: isHandled) .Includes(d => d.OrderSpecials) .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.No.Contains(dto.Keyword) || d.Title.Contains(dto.Keyword)) .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue) .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null) .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办 .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办 .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime) .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime) .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC) .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed) //.Where(d => SqlFunc.Subqueryable().Where(os => os.OrderId == d.Id).NotAny()) .Where(d => d.OrderSpecials.Any() == false || d.OrderSpecials.Any(s => s.State == 0) == false) .OrderByDescending(d => d.StartTime) .ToPagedListAsync(dto, HttpContext.RequestAborted); var page1 = new PagedDto(total, _mapper.Map>(items)); dto.IsHandled = false; isHandled = dto.IsHandled.HasValue && dto.IsHandled.Value; EOrderStatus[] handleStatuses = EnumExts.GetFields().Select(d => (EOrderStatus)d.Key).ToArray(); handleStatuses = handleStatuses.WhereIF(dto.IsHandled.HasValue, d => dto.IsHandled!.Value ? d is not EOrderStatus.WaitForAccept and not EOrderStatus.BackToUnAccept and not EOrderStatus.SpecialToUnAccept and not EOrderStatus.HandOverToUnAccept : d is EOrderStatus.WaitForAccept or EOrderStatus.BackToUnAccept or EOrderStatus.SpecialToUnAccept or EOrderStatus.HandOverToUnAccept) .ToArray(); var (total2, items2) = await _orderRepository.Queryable() .LeftJoin((d, step) => d.Id == step.ExternalId) .Where((d, step) => ((string.IsNullOrEmpty(d.WorkflowId) && (string.IsNullOrEmpty(d.SignerId) || d.SignerId == _sessionContext.RequiredUserId)) || (!string.IsNullOrEmpty(d.WorkflowId) && ((step.FlowAssignType == EFlowAssignType.User && !string.IsNullOrEmpty(step.HandlerId) && step.HandlerId == _sessionContext.RequiredUserId) || (step.FlowAssignType == EFlowAssignType.Org && !string.IsNullOrEmpty(step.HandlerOrgId) && step.HandlerOrgId == _sessionContext.RequiredOrgId) || (step.FlowAssignType == EFlowAssignType.Role && !string.IsNullOrEmpty(step.RoleId) && _sessionContext.Roles.Contains(step.RoleId))) && (((dto.IsHandled.HasValue && dto.IsHandled == false) && step.Status != EWorkflowStepStatus.Handled) || ((dto.IsHandled.HasValue && dto.IsHandled == true) && step.Status == EWorkflowStepStatus.Handled))))) .WhereIF(dto.IsProvince.HasValue, d => d.IsProvince == dto.IsProvince) .WhereIF(dto.IsHandled.HasValue, d => handleStatuses.Contains(d.Status)) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.StartsWith(dto.Keyword!)) .WhereIF(!string.IsNullOrEmpty(dto.No), d => d.No == dto.No) .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == true, d => d.CounterSignType.HasValue) .WhereIF(dto.IsCounterSign.HasValue && dto.IsCounterSign == false, d => d.CounterSignType == null) .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == true, d => (d.ExpiredTime < DateTime.Now && d.Status < EOrderStatus.Filed) || (d.ExpiredTime < d.ActualHandleTime && d.Status >= EOrderStatus.Filed)) //超期 未办 .WhereIF(dto.ExpiredOrAlmostOverdue.HasValue && dto.ExpiredOrAlmostOverdue == false, d => d.NearlyExpiredTime < DateTime.Now && d.ExpiredTime > DateTime.Now) //即将超期 未办 .WhereIF(dto.StartTime.HasValue, d => d.CreationTime >= dto.StartTime) .WhereIF(dto.EndTime.HasValue, d => d.CreationTime <= dto.EndTime) .Where(d => d.Source < ESource.MLSQ || d.Source > ESource.WZSC) .Where(d => d.Status != EOrderStatus.BackToProvince && d.Status < EOrderStatus.Filed) .OrderBy(d => d.Status) .OrderByIF(dto.IsHandled == true, d => d.StartTime, OrderByType.Desc) .OrderByIF(dto.IsHandled == false, d => d.CreationTime, OrderByType.Desc) .Select((d, step) => d) .ToPagedListAsync(dto, HttpContext.RequestAborted); var page2 = new PagedDto(total2, _mapper.Map>(items2)); return new { Waited = page1, Sign = page2 }; } #endregion #region 业务工单退回 /// /// 工单退回退回(返回前一节点) /// [HttpPost("order_previous")] public async Task Previous([FromBody] OrderPreviousDto dto) { var oneSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.OneOrgSendBack)?.SettingValue[0]); var twoSendBack = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.TwoOrgSendBack)?.SettingValue[0]); //var workflow = await _workflowDomainService.GetWorkflowAsync(dto.WorkflowId, withSteps: true, cancellationToken: HttpContext.RequestAborted); var order = await _orderRepository .Queryable() .Includes(d => d.Workflow) .FirstAsync(d => d.Id == dto.OrderId); dto.ExpiredTime = order.ExpiredTime; var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync( dto.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted); var audit = new OrderSendBackAudit { OrderId = dto.OrderId, State = ESendBackAuditState.Apply, Content = dto.Opinion, SendBackData = dto, ApplyOrgId = currentStep.AcceptorOrgId, ApplyOrgName = currentStep!.AcceptorOrgName, SendBackOrgId = prevStep.HandlerOrgId, //prevStep.AcceptorOrgId, SendBackOrgName = prevStep.HandlerOrgName, //prevStep!.AcceptorOrgName, SendBackStepName = prevStep.Name, WorkflowStepSendBackCrTime = currentStep.CreationTime, WorkflowOrgId = _sessionContext.RequiredOrgId, WorkflowUserId = _sessionContext.RequiredUserId, WorkflowRoleIds = _sessionContext.Roles.ToList(), Status = order.Status, TraceId = currentStep.Id }; audit.InitId(); if (dto.Files.Any()) audit.FileJson = await _fileRepository.AddFileAsync(dto.Files, audit.Id, "", HttpContext.RequestAborted); // if (_appOptions.Value.IsZiGong && prevStep.BusinessType == EBusinessType.Send) // { // // 平均派单 // var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); // if (averageSendOrder) // { // var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); // dto.Handler = handler; // } // } //todo 需整理各个地市退回业务的需求(指派类型及指派对象) //if (workflow.FlowType == EFlowType.Handle) //该逻辑需放在退回操作前依据业务判断 //{ // prevStep.FlowAssignType = prevStep.BusinessType is EBusinessType.Seat ? EFlowAssignType.Role : // prevStep.BusinessType is EBusinessType.Send ? EFlowAssignType.User : EFlowAssignType.Org; //} if (oneSendBack || twoSendBack) { var sendBack = await _orderSendBackAuditRepository.Queryable() .Where(x => x.OrderId == dto.OrderId && x.State == ESendBackAuditState.Apply).AnyAsync(); if (sendBack) throw UserFriendlyException.SameMessage("当前工单已经生成退回记录"); var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == order.Id && x.State == 0) .AnyAsync(); if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息!"); if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行退回!"); if (oneSendBack && isOrgToCenter && _appOptions.Value.IsZiGong) { if (order.SendBackAuditEndTime.HasValue && order.SendBackAuditEndTime.Value < DateTime.Now) throw UserFriendlyException.SameMessage("工单截至退回时间【" + order.SendBackAuditEndTime.Value.ToString("yyyy-MM-dd HH:mm:ss") + "】,无法进行退回!"); var sendBackAgain = await _orderSendBackAuditRepository.Queryable() .Where(x => x.OrderId == dto.OrderId && x.IsReturnAgain == false).AnyAsync(); if (sendBackAgain) throw UserFriendlyException.SameMessage("工单已不允许退回!"); } if ((oneSendBack && isOrgToCenter) || (twoSendBack && isSecondToFirstOrgLevel)) { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = EOrderStatus.SendBackAudit }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } else { audit.State = ESendBackAuditState.End; audit.AuditUser = "默认通过"; audit.AuditTime = DateTime.Now; // if (prevStep.BusinessType == EBusinessType.Send && dto.Handler != null) // { // await _orderRepository.Updateable().SetColumns(o => new Orders.Order() // { CenterToOrgHandlerId = dto.Handler.UserId, CenterToOrgHandlerName = dto.Handler.Username }) // .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); // } var (workflow, currentStep1, prevDefine, prevStep1, newStep, flowDirection) = await _workflowApplication.PreviousAsync(dto, async (workflow1, prevStepDefine, prevStep1, newStep) => { var stepAssignInfo = await _orderApplication.GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo); newStep.Assign(stepAssignInfo); }, HttpContext.RequestAborted); if (prevStep.BusinessType == EBusinessType.Send) { await _orderRepository.Updateable().SetColumns(o => new Order() { CenterToOrgHandlerId = newStep.HandlerId, CenterToOrgHandlerName = newStep.HandlerName }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; if (currentStep.AcceptorOrgId != OrgSeedData.CenterId && prevStep.BusinessType == EBusinessType.Send) order.SendBackNum = order.SendBackNum.HasValue ? order.SendBackNum.Value + 1 : 1; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType, SendBackNum = order.SendBackNum }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); //发送短信TODO } } else { audit.State = ESendBackAuditState.End; audit.AuditUser = "默认通过"; audit.AuditTime = DateTime.Now; // if (prevStep.BusinessType == EBusinessType.Send && dto.Handler != null) // { // await _orderRepository.Updateable().SetColumns(o => new Orders.Order() // { CenterToOrgHandlerId = dto.Handler.UserId, CenterToOrgHandlerName = dto.Handler.Username }) // .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); // } var (workflow, currentStep1, prevDefine, prevStep1, newStep, flowDirection) = await _workflowApplication.PreviousAsync(dto, async (workflow1, prevStepDefine, prevStep1, newStep) => { var stepAssignInfo = await _orderApplication.GetOrderPreviousAssignInfoAsync(workflow1, prevStepDefine, prevStep1, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo); newStep.Assign(stepAssignInfo); }, HttpContext.RequestAborted); if (prevStep.BusinessType == EBusinessType.Send) { await _orderRepository.Updateable().SetColumns(o => new Order() { CenterToOrgHandlerId = newStep.HandlerId, CenterToOrgHandlerName = newStep.HandlerName }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } var processType = flowDirection == EFlowDirection.OrgToCenter || flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; if (currentStep.AcceptorOrgId != OrgSeedData.CenterId && prevStep.BusinessType == EBusinessType.Send) order.SendBackNum = order.SendBackNum.HasValue ? order.SendBackNum.Value + 1 : 1; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType, SendBackNum = order.SendBackNum }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); //发送短信TODO } await _orderSendBackAuditRepository.AddAsync(audit, HttpContext.RequestAborted); } /// /// 工单业务退回审批 /// /// /// [HttpPost("order_previous_audit")] public async Task Audit([FromBody] AuditSendBackDto dto) { if (dto.State == ESendBackAuditState.Refuse && string.IsNullOrEmpty(dto.AuditContent)) throw UserFriendlyException.SameMessage("退回拒绝,请填写审批拒绝原因"); //验证是否存在退回 var sendBack = await _orderSendBackAuditRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (sendBack is null) throw UserFriendlyException.SameMessage("无效退回"); if (sendBack.State != ESendBackAuditState.Apply) throw UserFriendlyException.SameMessage("退回已审批,请勿重复审批"); _mapper.Map(dto, sendBack); sendBack.AuditId = _sessionContext.UserId; sendBack.AuditUser = _sessionContext.UserName; sendBack.AuditTime = DateTime.Now; //执行退回 if (sendBack.State == ESendBackAuditState.End) { var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId); if (_appOptions.Value.IsZiGong) { var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync( order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), HttpContext.RequestAborted); if (prevStep.BusinessType == EBusinessType.Send) { // 平均派单 var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); if (averageSendOrder) { var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); sendBack.SendBackData.Handler = handler; } await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { CenterToOrgHandlerId = sendBack.SendBackData.Handler.UserId, CenterToOrgHandlerName = sendBack.SendBackData.Handler.Username }) .Where(o => o.Id == sendBack.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } } //string applicantId, string applicantOrgId, string[] applicantRoleIds, // ISessionContext current, CancellationToken cancellationToken); sendBack.SendBackData.ExpiredTime = order.ExpiredTime; var result = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), cancellationToken: HttpContext.RequestAborted); //var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted); var processType = result.flowDirection == EFlowDirection.OrgToCenter || result.flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; if (sendBack.ApplyOrgId != OrgSeedData.CenterId && sendBack.SendBackOrgId == OrgSeedData.CenterId) order.SendBackNum = order.SendBackNum.HasValue ? order.SendBackNum.Value + 1 : 1; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType, SendBackNum = order.SendBackNum }) .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); //发送短信TODO } else { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value }) .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted); } /// /// 工单业务批量退回审批 /// /// [HttpPost("order_previous_audit_batch")] public async Task AuditBatch([FromBody] BatchAuditSendBackDto dto) { foreach (string id in dto.Ids) { if (dto.State == ESendBackAuditState.Refuse && string.IsNullOrEmpty(dto.AuditContent)) throw UserFriendlyException.SameMessage("退回拒绝,请填写审批拒绝原因"); //验证是否存在退回 var sendBack = await _orderSendBackAuditRepository.GetAsync(id, HttpContext.RequestAborted); if (sendBack is null) throw UserFriendlyException.SameMessage("无效退回"); if (sendBack.State != ESendBackAuditState.Apply) throw UserFriendlyException.SameMessage("退回已审批,请勿重复审批"); _mapper.Map(dto, sendBack); sendBack.AuditId = _sessionContext.UserId; sendBack.AuditUser = _sessionContext.UserName; sendBack.AuditTime = DateTime.Now; //执行退回 if (sendBack.State == ESendBackAuditState.End) { var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == sendBack.OrderId); if (_appOptions.Value.IsZiGong) { var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync( order.WorkflowId, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), HttpContext.RequestAborted); if (prevStep.BusinessType == EBusinessType.Send) { // 平均派单 var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); if (averageSendOrder) { var handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); sendBack.SendBackData.Handler = handler; } await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { CenterToOrgHandlerId = sendBack.SendBackData.Handler.UserId, CenterToOrgHandlerName = sendBack.SendBackData.Handler.Username }) .Where(o => o.Id == sendBack.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } } sendBack.SendBackData.ExpiredTime = order.ExpiredTime; var result = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, sendBack.WorkflowOrgId, sendBack.WorkflowRoleIds.ToArray(), cancellationToken: HttpContext.RequestAborted); //var flowDirection = await _workflowApplication.PreviousAsync(sendBack.SendBackData, sendBack.WorkflowUserId, HttpContext.RequestAborted); var processType = result.flowDirection == EFlowDirection.OrgToCenter || result.flowDirection == EFlowDirection.CenterToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; if (sendBack.ApplyOrgId != OrgSeedData.CenterId && sendBack.SendBackOrgId == OrgSeedData.CenterId) order.SendBackNum = order.SendBackNum.HasValue ? order.SendBackNum.Value + 1 : 1; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ProcessType = processType, SendBackNum = order.SendBackNum }) .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); //发送短信TODO } else { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = sendBack.Status.Value }) .Where(o => o.Id == sendBack.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } await _orderSendBackAuditRepository.UpdateAsync(sendBack, HttpContext.RequestAborted); } } /// /// 工单业务退回审批列表 /// /// /// [HttpGet("order_previous_list")] public async Task> AuditList([FromQuery] SendBackListDto dto) { var query = _orderSendBackAuditApplication.AuditList(dto); var (total, items) = await query.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 工单业务退回审批列表导出 /// /// [HttpPost("order_previous_list/_export")] public async Task OrgDataListDetailExport([FromBody] ExportExcelDto dto) { var query = _orderSendBackAuditApplication.AuditList(dto.QueryDto); List data; if (dto.IsExportAll) { data = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); data = items; } var dataDtos = _mapper.Map>(data); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = dataDtos .Select(stu => _mapper.Map(stu, typeof(SendBackDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单退回列表数据"); } /// /// 退回详情 /// /// /// [HttpGet("order_previous/{id}")] public async Task OrderSendBackEntity(string id) { var res = await _orderSendBackAuditRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); var resDto = _mapper.Map(res); if (res.FileJson != null && res.FileJson.Any()) { var ids = res.FileJson.Select(x => x.Id).ToList(); var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); resDto.Files = files.Where(x => x.Classify == "退回附件" && string.IsNullOrEmpty(x.FlowKey)).ToList(); } return resDto; } /// /// 列表页面基础数据 /// /// [HttpGet("order_previous/base-data")] public async Task OrderSendBackBaseData() { var rsp = new { AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), ESendBackAuditState = EnumExts.GetDescriptions(), }; return rsp; } /// /// 查询工单退回目标步节点信息 /// [HttpGet("previous/targetStep/{orderId}")] public async Task GetPreviousTargetStepInfo(string orderId) { var order = await _orderDomainService.GetOrderAsync(orderId, cancellationToken: HttpContext.RequestAborted); if (string.IsNullOrEmpty(order.WorkflowId)) throw UserFriendlyException.SameMessage("该工单未开启流程"); var (currentStep, prevStep, isOrgToCenter, isSecondToFirstOrgLevel) = await _workflowApplication.GetPreviousInformationAsync( order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, _sessionContext.Roles, HttpContext.RequestAborted); return new TargetStepInfo { CurrentBusinessType = currentStep.BusinessType, TargetBusinessType = prevStep.BusinessType }; } #endregion #region 省工单退回 /// /// 工单退回列表 /// /// /// [HttpGet("send_back")] public async Task> UrgeList([FromQuery] OrderSendBackListDto dto) { var (total, items) = await _orderSendBackRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!)) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) .WhereIF(dto.State is > 0, d => d.State > 0) .WhereIF(dto.State is 0, d => d.State == 0) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 批量省工单退回 /// /// /// [HttpPost("send_back/batch")] public async Task BatchApplyUrge([FromBody] BatchOrderSendBackAddDto dto) { int count = dto.OrderIds.Count; int successCount = 0; int errorCount = 0; var SendDatas = new List(); foreach (var item in dto.OrderIds) { //验证工单是否可以申请 var order = await _orderRepository.GetAsync(item.OrderId, HttpContext.RequestAborted); if (order is null) { errorCount++; continue; } if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince || (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001")) { errorCount++; continue; } if (order.Source <= ESource.HotlineImport) { errorCount++; continue; } var model = new OrderSendBack() { Content = dto.Content, OrderId = item.OrderId, Destination = ESendBackDestination.Province }; await _orderSendBackRepository.AddAsync(model, HttpContext.RequestAborted); if (!string.IsNullOrEmpty(model.Id)) { order.Status = EOrderStatus.BackToProvince; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); successCount++; var sendBackDto = _mapper.Map(model); var OrderDto = _mapper.Map(order); SendDatas.Add(new PublishOrderSendBackModelDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" }); } } //推省上 await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious, new PublishOrderSendBackDto() { SendDatas = SendDatas }); return new { Count = count, ErrorCount = errorCount, SuccessCount = successCount }; } /// /// 退回申请 /// /// /// [HttpPost("send_back/apply")] [LogFilter("新增工单退回申请")] public async Task ApplyUrge([FromBody] OrderSendBackAddDto dto) { //验证工单是否可以申请 var order = await _orderRepository.GetAsync(dto.OrderId, HttpContext.RequestAborted); if (order is null) throw UserFriendlyException.SameMessage("无效工单"); if (order.Status >= EOrderStatus.Filed || order.Status == EOrderStatus.BackToProvince || !order.IsProvince || (!string.IsNullOrEmpty(order.ActualHandleOrgCode) && order.ActualHandleOrgCode != "001")) throw UserFriendlyException.SameMessage("工单状态无效,请确认当前工单状态"); if (order.Source <= ESource.HotlineImport) throw UserFriendlyException.SameMessage("工单来源无效,请确认当前工单来源"); var model = _mapper.Map(dto); model.InitId(); if (dto.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted); await _orderSendBackRepository.AddAsync(model, HttpContext.RequestAborted); if (!string.IsNullOrEmpty(model.Id)) { order.Status = EOrderStatus.BackToProvince; await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); var sendBackDto = _mapper.Map(model); var OrderDto = _mapper.Map(order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious, new PublishOrderSendBackDto() { SendDatas = new List() { new PublishOrderSendBackModelDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" } } }); } } /// /// 退回审核 /// /// /// [HttpPost("send_back/audit")] [LogFilter("审核工单退回申请")] public async Task ReplyUrge([FromBody] AuditOrderSendBackDto dto) { //验证是否存在退回 var sendBack = await _orderSendBackRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (sendBack is null) throw UserFriendlyException.SameMessage("无效退回"); if (sendBack.State > 0) throw UserFriendlyException.SameMessage("退回已审核,请勿重复审核"); _mapper.Map(dto, sendBack); sendBack.AuditName = _sessionContext.UserName; sendBack.AuditTime = DateTime.Now; await _orderSendBackRepository.UpdateAsync(sendBack, HttpContext.RequestAborted); //推省上 if (sendBack.State == 1) { var order = await _orderRepository.GetAsync(sendBack.OrderId); var sendBackDto = _mapper.Map(sendBack); var OrderDto = _mapper.Map(order); //await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowPrevious, // new PublishOrderSendBackDto() { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" }); //try //{ // await _provinceService.GetCaseBackApply( // new PublishOrderSendBackDto { Order = OrderDto, SendBack = sendBackDto, ClientGuid = "" }, // HttpContext.RequestAborted); //} //catch (Exception e) //{ // _logger.LogError("_provinceService.GetCaseBackApply throw exception: {ex}", e.Message); //} } } /// /// 退回详情 /// /// /// [HttpGet("send_back/{id}")] public async Task SendBackEntity(string id) { return await _orderSendBackRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); } #endregion #region 工单特提 /// /// 工单特提信息 /// /// /// [HttpPost("special")] [LogFilter("新增工单特提")] public async Task Add([FromBody] OrderSpecialAddDto dto) { var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0) .AnyAsync(); if (specialAny) throw UserFriendlyException.SameMessage("工单已存在待审批特提信息!"); var order = await _orderRepository.Queryable().Includes(d => d.Workflow).FirstAsync(d => d.Id == dto.OrderId); await _orderApplication.SpecialVerify(dto, order, HttpContext.RequestAborted); dto.Cause ??= dto.Reason; var orderSpecial = _mapper.Map(dto); orderSpecial.OrgId = _sessionContext.RequiredOrgId; orderSpecial.OrgName = _sessionContext.OrgName; orderSpecial.Status = order.Status; var audit = true; var specialAduit = _systemSettingCacheManager.GetSetting(SettingConstants.SpecialAduit); if (bool.Parse(specialAduit?.SettingValue[0])) { //if (!dto.Audit) model.State = 1; //取消根据进入界面判断是否审批 最新按照系统配置设定 var setting = _systemSettingCacheManager.GetSetting(SettingConstants.SeatsMonitor); var settingStr = setting?.SettingValue; var roles = _sessionContext.Roles; foreach (var item in settingStr) { if (roles != null && roles.Contains(item)) audit = false; } } else { audit = false; } if (!audit) orderSpecial.State = 1; orderSpecial.InitId(); if (dto.Files.Any()) orderSpecial.FileJson = await _fileRepository.AddFileAsync(dto.Files, orderSpecial.Id, "", HttpContext.RequestAborted); if (orderSpecial.State == 1) { var recall = new RecallDto { WorkflowId = dto.WorkflowId!, NextStepCode = dto.NextStepCode, NextStepName = dto.NextStepName, NextHandlers = dto.NextHandlers, Opinion = "【特提理由】" + dto.Reason, FlowDirection = dto.FlowDirection, HandlerType = dto.HandlerType, BusinessType = dto.BusinessType }; ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig(); if (dto.FlowDirection is EFlowDirection.OrgToOrg) { expiredTime.ExpiredTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } else { if (_appOptions.Value.IsZiGong) { if (dto.FlowDirection != null) { expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, dto.FlowDirection.Value, order.Adapt()); } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } order.ProcessType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; if (expiredTime.ExpiredTime > order.ExpiredTime) { order.ExpiredTime = expiredTime.ExpiredTime; order.NearlyExpiredTime = expiredTime.NearlyExpiredTime; order.NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne; var orderDto = _mapper.Map(order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); } var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync(recall, dto.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall, expiredTime.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall, async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) => { var basicWorkflowDto = _mapper.Map(dto); var stepAssignInfo = await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep, basicWorkflowDto, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted); targetStepNew.Assign(stepAssignInfo); }, HttpContext.RequestAborted); if (string.IsNullOrEmpty(currentStep?.HandlerOrgId)) { orderSpecial.OrgId = currentStep.HandlerOrgId; orderSpecial.OrgName = currentStep.HandlerOrgName; orderSpecial.StepName = currentStep.Name; orderSpecial.StepCode = currentStep.Code; } if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send) { orderSpecial.NextHandlers = new List { newStep.GetWorkflowStepHandler() }; } if (dto.BusinessType == EBusinessType.Send) { order.CenterToOrgHandlerId = newStep.HandlerId; order.CenterToOrgHandlerName = newStep.HandlerName; } _mapper.Map(workflow, order); order.FileEmpty(); order.Status = targetStepDefine.StepType is EStepType.Start ? EOrderStatus.SpecialToUnAccept : EOrderStatus.Special; if (orderSpecial.Status >= EOrderStatus.Filed) { var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId); if (publish != null) { var publishHistory = _mapper.Map(publish); publishHistory.OrderPublishId = publish.Id; publishHistory.ArrangeTitleAfter = publish.ArrangeTitle; publishHistory.ArrangeTitleBefor = publish.ArrangeTitle; publishHistory.ArrangeContentAfter = publish.ArrangeContent; publishHistory.ArrangeContentBefor = publish.ArrangeContent; publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion; publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion; await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted); await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted); } var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None); if (visit != null) { visit.VisitState = EVisitState.None; await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted); } } await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; var cityBase = JsonSerializer.Deserialize(setting); if (order != null && (cityBase.CityProvince.OrgId.Equals(orderSpecial.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(orderSpecial.OrgId) || cityBase.CityEnterprise.OrgId.Equals(orderSpecial.OrgId) || cityBase.PublicSecurity.OrgId.Equals(orderSpecial.OrgId))) { if (orderSpecial.Status < EOrderStatus.Filed) { await _capPublisher.PublishAsync(EventNames.HotlineOrderFlowRecalled, new PublishSpecialDto { Order = _mapper.Map(order), Special = _mapper.Map(orderSpecial) }, cancellationToken: HttpContext.RequestAborted); } } } else { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = EOrderStatus.SpecialAudit }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } await _orderSpecialRepository.AddAsync(orderSpecial, HttpContext.RequestAborted); } /// /// 工单重办信息 /// /// /// [HttpPost("re_transact")] [LogFilter("工单重办")] public async Task Add([FromBody] OrderReTransactDto dto) { var order = await _orderRepository .Queryable() .Includes(d => d.Workflow) .FirstAsync(d => d.Id == dto.OrderId); if (order.Workflow.IsInCountersign) throw UserFriendlyException.SameMessage("工单会签中,无法进行重办!"); var specialAny = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0) .AnyAsync(); if (specialAny) throw UserFriendlyException.SameMessage(order.No + " 工单已存在待审批特提信息!"); var screen = await _orderScreenRepository.Queryable().Where(x => x.OrderId == dto.OrderId && (int)x.Status < 2).AnyAsync(); if (screen) throw UserFriendlyException.SameMessage(order.No + " 工单存在甄别中的信息!"); if (await _orderSendBackAuditRepository.AnyAsync(x => x.OrderId == dto.OrderId && x.State == ESendBackAuditState.Apply, HttpContext.RequestAborted)) { throw UserFriendlyException.SameMessage(order.No + " 工单存在正在审核中的退回,不能办理"); } var model = _mapper.Map(dto); // var workflow = await _workflowDomainService.GetWorkflowAsync(order.WorkflowId, withSteps: true, // cancellationToken: HttpContext.RequestAborted); // var currentStep = workflow.Steps.FirstOrDefault(x => x.Status != EWorkflowStepStatus.Handled); // if (currentStep is null) // currentStep = workflow.Steps.OrderByDescending(x => x.CreationTime).FirstOrDefault(x => x.StepType == EStepType.End); // model.OrgId = currentStep is null ? _sessionContext.RequiredOrgId : currentStep.HandlerOrgId; // model.OrgName = currentStep is null ? _sessionContext.OrgName : currentStep.HandlerOrgName; model.OrgId = _sessionContext.RequiredOrgId; model.OrgName = _sessionContext.OrgName; // var step = await _workflowDomainService.FindLastStepAsync(model.WorkflowId, HttpContext.RequestAborted); // model.StepName = step.Name; // model.StepCode = step.Code; model.State = 1; model.SpecialType = dto.SpecialType; model.LastFileOpinion = order.FileOpinion; model.FirstFileOpinion = order.FileOpinion; var firstSpecial = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId).FirstAsync(); if (firstSpecial is not null) model.FirstFileOpinion = firstSpecial.FirstFileOpinion; model.InitId(); if (dto.Files.Any()) model.FileJson = await _fileRepository.AddFileAsync(dto.Files, model.Id, "", HttpContext.RequestAborted); // await _orderSpecialRepository.AddAsync(model, HttpContext.RequestAborted); if (dto.ReTransactError != null && dto.ReTransactError.Any()) { List details = new(); foreach (var item in dto.ReTransactError) { var detail = new OrderSpecialDetail(); _mapper.Map(item, detail); detail.SpecialId = model.Id; details.Add(detail); } await _orderSpecialDetailRepository.AddRangeAsync(details, HttpContext.RequestAborted); } if (model.State == 1) { //var handler = dto.NextHandlers.FirstOrDefault(); // if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send) // { // // 平均派单 // var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); // if (averageSendOrder) // { // handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); // dto.NextHandlers = new List { handler }; // await _orderSpecialRepository.Updateable().SetColumns(x => new OrderSpecial { NextHandlers = dto.NextHandlers }) // .Where(x => x.Id == model.Id).ExecuteCommandAsync(); // } // } var recall = new RecallDto { WorkflowId = dto.WorkflowId!, NextStepCode = dto.NextStepCode, NextStepName = dto.NextStepName, NextHandlers = dto.NextHandlers, Opinion = dto.Reason, FlowDirection = dto.FlowDirection, HandlerType = dto.HandlerType, BusinessType = dto.BusinessType, }; DateTime endTime = order.ExpiredTime!.Value; //todo //宜宾需求:1. 坐席申请特提:指派给申请人办理 2. 派单员申请特提:所有派单员都能办 3.其他特提场景:按节点原配置办理 var processType = dto.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; // 计算期满时间 if (dto.AlterTime) { DateTime startTime = DateTime.Now; if (order.CenterToOrgTime.HasValue && processType == EProcessType.Jiaoban) { startTime = order.CenterToOrgTime.Value; } else if (processType == EProcessType.Zhiban) { startTime = order.StartTime.Value; } var expiredTime = // _timeLimitDomainService.CalcEndTime( await _expireTime.CalcEndTime( DateTime.Now, startTime, ETimeType.WorkDay, dto.TimeLimit.Value, order.AcceptTypeCode); if (expiredTime.EndTime < order.ExpiredTime.Value) { expiredTime.EndTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } endTime = expiredTime.EndTime; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.EndTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); var orderDto = _mapper.Map(order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); } // if (dto.BusinessType == EBusinessType.Send && recall.NextHandlers.Any()) // { // var flowStepHandler = recall.NextHandlers.FirstOrDefault(); // await _orderRepository.Updateable().SetColumns(o => new Orders.Order() // { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username }) // .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); // } // StepAssignInfo? stepAssignInfo = null; // if (handler is not null) // { // stepAssignInfo = _mapper.Map(handler); // stepAssignInfo.FlowAssignType = EFlowAssignType.User; // } // var reverseFlowStepAssignInfo = _orderDomainService.GetOrderRecallAssignInfo(dto.BusinessType, stepAssignInfo); var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync( recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Redo, endTime, order.Status >= EOrderStatus.Filed, EHandleMode.Redo, async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) => { var stepAssignInfo = recall.NextHandlers.FirstOrDefault() ?? await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep, recall, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted); targetStepNew.Assign(stepAssignInfo); }, HttpContext.RequestAborted); //记录特提后最新的流程节点 if (newStep != null && !string.IsNullOrEmpty(newStep.Id)) model.NewCurrentStepId = newStep.Id; if (string.IsNullOrEmpty(currentStep?.HandlerOrgId)) { model.OrgId = currentStep.HandlerOrgId; model.OrgName = currentStep.HandlerOrgName; model.StepName = currentStep.Name; model.StepCode = currentStep.Code; } if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send) { model.NextHandlers = new List { newStep.GetWorkflowStepHandler() }; } if (dto.BusinessType == EBusinessType.Send) { order.CenterToOrgHandlerId = newStep.HandlerId; order.CenterToOrgHandlerName = newStep.HandlerName; } //await _workflowApplication.RecallAsync(recall, endTime, order.Status >= EOrderStatus.Filed, EWorkflowTraceType.Redo, // HttpContext.RequestAborted); //var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == dto.OrderId); //if (publish != null) //{ // var publishHistory = _mapper.Map(publish); // publishHistory.OrderPublishId = publish.Id; // publishHistory.ArrangeTitleAfter = publish.ArrangeTitle; // publishHistory.ArrangeTitleBefor = publish.ArrangeTitle; // publishHistory.ArrangeContentAfter = publish.ArrangeContent; // publishHistory.ArrangeContentBefor = publish.ArrangeContent; // publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion; // publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion; // await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted); // await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted); //} //var reTransactNum = order.ReTransactNum.HasValue ? order.ReTransactNum.Value + 1 : 1; var orderStatus = EOrderStatus.SendBack; var orderStartStatus = EOrderStatus.BackToUnAccept; if (_appOptions.Value.IsZiGong) { orderStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.SendBack : EOrderStatus.Special; orderStartStatus = model.SpecialType == ESpecialType.SendBack ? EOrderStatus.BackToUnAccept : EOrderStatus.SpecialToUnAccept; } //ReTransactNum = reTransactNum, order.Status = model.StepType == EStepType.Start ? orderStartStatus : orderStatus; order.ProcessType = processType; await _orderRepository.Updateable(order) .UpdateColumns(d => new { d.CenterToOrgHandlerId, d.CenterToOrgHandlerName, d.ProcessType, d.Status }) .ExecuteCommandAsync(HttpContext.RequestAborted); // 重办清空已取消发布的工单的回访信息 await _orderDomainService.VisitNoneByCancelPublishAsync(order.Id, HttpContext.RequestAborted); //var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == dto.OrderId && x.VisitState != EVisitState.None); //if (visit != null) //{ // visit.VisitState = EVisitState.None; // await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted); //} } await _orderSpecialRepository.AddAsync(model, HttpContext.RequestAborted); } /// /// 审批工单特提信息 /// /// /// [HttpPut("special")] [LogFilter("审批工单特提")] public async Task Update([FromBody] AuditOrderSpecialDto dto) { var special = await _orderSpecialRepository .Queryable() .Includes(d => d.Order) .FirstAsync(d => d.Id == dto.Id); if (special is null) throw UserFriendlyException.SameMessage("无效特提审批信息!"); if (special.State != 0) throw UserFriendlyException.SameMessage("无效特提审批信息,特提审批信息错误,该信息已审核!"); special.State = dto.State; special.Opinion = dto.Opinion; if (dto.Files.Any()) special.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted); else special.ReplyFileJson = new List(); //await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted); var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId); if (special.State == 1) { //var handler = dto.NextHandlers.FirstOrDefault(); // if (_appOptions.Value.IsZiGong && special.BusinessType == EBusinessType.Send) // { // // 平均派单 // var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); // if (averageSendOrder) // { // handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); // special.NextHandlers = new List { handler }; // await _orderSpecialRepository.Updateable().SetColumns(x => new OrderSpecial { NextHandlers = special.NextHandlers }) // .Where(x => x.Id == special.Id).ExecuteCommandAsync(); // } // } var recall = new RecallDto { WorkflowId = special.WorkflowId!, NextStepCode = special.NextStepCode, NextStepName = special.NextStepName, NextHandlers = special.NextHandlers, // Opinion = dto.Opinion, Opinion = "【特提理由】" + special.Reason, FlowDirection = special.FlowDirection, HandlerType = special.HandlerType.Value, BusinessType = special.BusinessType.Value }; ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig(); if (dto.FlowDirection is EFlowDirection.OrgToOrg) { expiredTime.ExpiredTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } else { if (_appOptions.Value.IsZiGong) { if (dto.FlowDirection != null) { expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, dto.FlowDirection.Value, order.Adapt()); } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } if (expiredTime.ExpiredTime < order.ExpiredTime) { expiredTime.ExpiredTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne, ProcessType = processType, Status = EOrderStatus.Special }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); var orderDto = _mapper.Map(order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); //} // if (special.BusinessType == EBusinessType.Send && recall.NextHandlers.Any()) // { // var flowStepHandler = recall.NextHandlers.FirstOrDefault(); // await _orderRepository.Updateable().SetColumns(o => new Orders.Order() // { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username }) // .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); // } //todo 特提重办,按审批通过时间依据中心派至部门的规则计算期满时间,更新order var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync( recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall, expiredTime.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall, async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) => { var stepAssignInfo = recall.NextHandlers.FirstOrDefault() ?? await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep, recall, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted); targetStepNew.Assign(stepAssignInfo); }, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send) { special.NextHandlers = new List { newStep.GetWorkflowStepHandler() }; } if (dto.BusinessType == EBusinessType.Send) { order.CenterToOrgHandlerId = newStep.HandlerId; order.CenterToOrgHandlerName = newStep.HandlerName; await _orderRepository.Updateable(order) .UpdateColumns(d => new { d.CenterToOrgHandlerId, d.CenterToOrgHandlerName }) .ExecuteCommandAsync(HttpContext.RequestAborted); } if (order.Status >= EOrderStatus.Filed) { var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == special.OrderId); if (publish != null) { var publishHistory = _mapper.Map(publish); publishHistory.OrderPublishId = publish.Id; publishHistory.ArrangeTitleAfter = publish.ArrangeTitle; publishHistory.ArrangeTitleBefor = publish.ArrangeTitle; publishHistory.ArrangeContentAfter = publish.ArrangeContent; publishHistory.ArrangeContentBefor = publish.ArrangeContent; publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion; publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion; await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted); await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted); } var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == special.OrderId && x.VisitState != EVisitState.None); if (visit != null) { visit.VisitState = EVisitState.None; await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted); } } var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; CityBaseConfiguration cityBase = JsonSerializer.Deserialize(setting); if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) || cityBase.CityEnterprise.OrgId.Equals(special.OrgId) || cityBase.PublicSecurity.OrgId.Equals(special.OrgId))) { if (order.Status < EOrderStatus.Filed) { await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled, new PublishSpecialDto { Order = _mapper.Map(order), Special = _mapper.Map(special) }, cancellationToken: HttpContext.RequestAborted); } } } else { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = special.Status.Value }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted); } /// /// 批量审批工单特提 /// /// /// [HttpPut("special_batch")] [LogFilter("批量审批工单特提")] public async Task UpdateBatch([FromBody] BatchAuditOrderSpecialDto dto) { foreach (string id in dto.ids) { var special = await _orderSpecialRepository .Queryable() .Includes(d => d.Order) .FirstAsync(d => d.Id == id); if (special is null) throw UserFriendlyException.SameMessage("无效特提审批信息!"); if (special.State != 0) throw UserFriendlyException.SameMessage("无效特提审批信息,特提审批信息错误,该信息已审核!"); special.State = dto.State; special.Opinion = dto.Opinion; if (dto.Files.Any()) special.ReplyFileJson = await _fileRepository.AddFileAsync(dto.Files, special.Id, "", HttpContext.RequestAborted); else special.ReplyFileJson = new List(); // await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted); var order = await _orderRepository.GetAsync(x => x.Id == special.OrderId); if (special.State == 1) { // var handler = dto.NextHandlers.FirstOrDefault(); // if (_appOptions.Value.IsZiGong && special.BusinessType == EBusinessType.Send) // { // // 平均派单 // var averageSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.AverageSendOrder).SettingValue[0]); // if (averageSendOrder) // { // handler = await _orderDomainService.AverageOrder(HttpContext.RequestAborted); // special.NextHandlers = new List { handler }; // await _orderSpecialRepository.Updateable().SetColumns(x => new OrderSpecial { NextHandlers = special.NextHandlers }) // .Where(x => x.Id == special.Id).ExecuteCommandAsync(); // } // } var recall = new RecallDto { WorkflowId = special.WorkflowId!, NextStepCode = special.NextStepCode, NextStepName = special.NextStepName, NextHandlers = special.NextHandlers, Opinion = "【特提理由】" + dto.Opinion, FlowDirection = special.FlowDirection, HandlerType = special.HandlerType.Value, BusinessType = special.BusinessType.Value }; ExpiredTimeWithConfig? expiredTime = new ExpiredTimeWithConfig(); if (dto.FlowDirection is EFlowDirection.OrgToOrg) { expiredTime.ExpiredTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } else { if (_appOptions.Value.IsZiGong) { if (dto.FlowDirection != null) { expiredTime = await _expireTime.CalcExpiredTime(DateTime.Now, DateTime.Now, dto.FlowDirection.Value, order.Adapt()); } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } else { expiredTime = await _expireTime.CalcEndTime(DateTime.Now, DateTime.Now, order.AcceptTypeCode); } } if (expiredTime.ExpiredTime < order.ExpiredTime) { expiredTime.ExpiredTime = order.ExpiredTime.Value; expiredTime.NearlyExpiredTime = order.NearlyExpiredTime.Value; expiredTime.NearlyExpiredTimeOne = order.NearlyExpiredTimeOne.Value; } var processType = special.FlowDirection is EFlowDirection.OrgToCenter or EFlowDirection.CenterToCenter or EFlowDirection.FiledToCenter ? EProcessType.Zhiban : EProcessType.Jiaoban; await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { ExpiredTime = expiredTime.ExpiredTime, NearlyExpiredTime = expiredTime.NearlyExpiredTime, NearlyExpiredTimeOne = expiredTime.NearlyExpiredTimeOne, ProcessType = processType, Status = EOrderStatus.Special }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); var orderDto = _mapper.Map(order); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); //} // if (special.BusinessType == EBusinessType.Send && recall.NextHandlers.Any()) // { // var flowStepHandler = recall.NextHandlers.FirstOrDefault(); // await _orderRepository.Updateable().SetColumns(o => new Orders.Order() // { CenterToOrgHandlerId = flowStepHandler.UserId, CenterToOrgHandlerName = flowStepHandler.Username }) // .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); // } //todo 特提重办,按审批通过时间依据中心派至部门的规则计算期满时间,更新order var (workflow, targetStepDefine, currentStep, targetStep, newStep, isOrgToCenter) = await _workflowDomainService.RecallAsync( recall, recall.NextHandlers.FirstOrDefault(), EWorkflowTraceType.Recall, expiredTime.ExpiredTime, order.Status >= EOrderStatus.Filed, EHandleMode.Recall, async (workflow, currentStep, targetStepDefine, targetStep, targetStepNew) => { var stepAssignInfo = recall.NextHandlers.FirstOrDefault() ?? await _orderApplication.GetOrderRecallAssignInfoAsync(workflow, targetStepDefine, targetStep, recall, HttpContext.RequestAborted); if (stepAssignInfo is null) return; var validator = new StepAssignInfoValidator(); await validator.ValidateAndThrowAsync(stepAssignInfo, HttpContext.RequestAborted); targetStepNew.Assign(stepAssignInfo); }, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong && dto.BusinessType == EBusinessType.Send) { special.NextHandlers = new List { newStep.GetWorkflowStepHandler() }; } if (dto.BusinessType == EBusinessType.Send) { order.CenterToOrgHandlerId = newStep.HandlerId; order.CenterToOrgHandlerName = newStep.HandlerName; await _orderRepository.Updateable(order) .UpdateColumns(d => new { d.CenterToOrgHandlerId, d.CenterToOrgHandlerName }) .ExecuteCommandAsync(HttpContext.RequestAborted); } if (order.Status >= EOrderStatus.Filed) { var publish = await _orderPublishRepository.GetAsync(x => x.OrderId == special.OrderId); if (publish != null) { var publishHistory = _mapper.Map(publish); publishHistory.OrderPublishId = publish.Id; publishHistory.ArrangeTitleAfter = publish.ArrangeTitle; publishHistory.ArrangeTitleBefor = publish.ArrangeTitle; publishHistory.ArrangeContentAfter = publish.ArrangeContent; publishHistory.ArrangeContentBefor = publish.ArrangeContent; publishHistory.ArrangeOpinionAfter = publish.ArrangeOpinion; publishHistory.ArrangeOpinionBefor = publish.ArrangeOpinion; await _orderPublishHistoryRepository.AddAsync(publishHistory, HttpContext.RequestAborted); await _orderPublishRepository.RemoveAsync(publish, false, HttpContext.RequestAborted); } var visit = await _orderVisitRepository.GetAsync(x => x.OrderId == special.OrderId && x.VisitState != EVisitState.None); if (visit != null) { visit.VisitState = EVisitState.None; await _orderVisitRepository.UpdateAsync(visit, HttpContext.RequestAborted); } } var setting = _systemSettingCacheManager.GetSetting(SettingConstants.CityBaseConfiguration)?.SettingValue[0]; CityBaseConfiguration cityBase = JsonSerializer.Deserialize(setting); if (order != null && (cityBase.CityProvince.OrgId.Equals(special.OrgId) || cityBase.CityProvinceAssign.OrgId.Equals(special.OrgId) || cityBase.CityEnterprise.OrgId.Equals(special.OrgId) || cityBase.PublicSecurity.OrgId.Equals(special.OrgId))) { if (order.Status < EOrderStatus.Filed) { await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderFlowRecalled, new PublishSpecialDto { Order = _mapper.Map(order), Special = _mapper.Map(special) }, cancellationToken: HttpContext.RequestAborted); } } } else { await _orderRepository.Updateable().SetColumns(o => new Orders.Order() { Status = special.Status.Value }) .Where(o => o.Id == order.Id).ExecuteCommandAsync(HttpContext.RequestAborted); } await _orderSpecialRepository.UpdateAsync(special, HttpContext.RequestAborted); } } /// /// 获取工单特提信息列表 /// /// /// [HttpGet("special/list")] public async Task> List([FromQuery] OrderSpecialListDto dto) { var (total, items) = await _orderSpecialRepository.Queryable() .Includes(x => x.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!)) .WhereIF(dto.State.HasValue, x => x.State == dto.State) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 特提列表 /// /// /// [HttpGet("special/getspeciallist")] public async Task> GetSpecialList([FromQuery] SpecialPagedListDto pagedDto) { RefAsync total = 0; var dataList = await _orderRepository.Queryable() .LeftJoin((x, p) => x.Id == p.OrderId) .WhereIF(pagedDto.StartTime.HasValue, (x, p) => p.CreationTime >= pagedDto.StartTime) .WhereIF(pagedDto.EndTime.HasValue, (x, p) => p.CreationTime <= pagedDto.EndTime) .WhereIF(!string.IsNullOrEmpty(pagedDto.No), (x, p) => x.No.Contains(pagedDto.No)) .WhereIF(pagedDto.State.HasValue, (x, p) => p.State == pagedDto.State) .Select((x, p) => new { index = SqlFunc.RowNumber($"{p.CreationTime} desc ", $"{p.OrderId}"), x.Title, x.Status, x.No, x.AcceptType, x.AcceptTypeCode, x.HotspotName, x.HotspotId, x.HotspotSpliceName, x.ActualHandleTime, x.ExpiredTime, x.NearlyExpiredTime, x.NearlyExpiredTimeOne, p.NextStepName, p.NextStepCode, p.StepName, p.StepCode, p.CreatorName, p.CreatorOrgName, p.CreationTime, p.State, p.Opinion, SpecialId = p.Id, p.OrderId, p.WorkflowId }) //将结果合并成一个表 .MergeTable() //取第一条数据 .Where(d => d.index == 1) .OrderByDescending(d => d.CreationTime) //转分页数据 .ToPageListAsync(pagedDto.PageIndex, pagedDto.PageSize, total); //返回数据 return new PagedDto(total.Value, _mapper.Map>(dataList)); } /// /// 工单列表 /// /// /// [HttpGet("special/apply_list")] public async Task> SpecialList([FromQuery] QueryOrderDto dto) { var query = _orderRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || d.No.Contains(dto.Keyword!)) //.WhereIF(!string.IsNullOrEmpty(dto.Content), d => d.Content.Contains(dto.Content!)) .WhereIF(!string.IsNullOrEmpty(dto.AcceptType), d => d.AcceptTypeCode == dto.AcceptType) //受理类型 //.WhereIF(dto.AcceptTypes.Any(), d => dto.AcceptTypes.Contains(d.AcceptTypeCode)) //受理类型 .WhereIF(!string.IsNullOrEmpty(dto.Channel), d => d.SourceChannelCode == dto.Channel) //来源渠道 .WhereIF(!string.IsNullOrEmpty(dto.Hotspot), d => d.HotspotSpliceName != null && d.HotspotSpliceName.Contains(dto.Hotspot)) .WhereIF(!string.IsNullOrEmpty(dto.TransferPhone), d => d.TransferPhone.Contains(dto.TransferPhone!)) //.WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId)//接办部门 .WhereIF(!string.IsNullOrEmpty(dto.OrgId), d => d.CurrentHandleOrgId == dto.OrgId) //接办部门 .WhereIF(!string.IsNullOrEmpty(dto.NameOrNo), d => d.AcceptorName.Contains(dto.NameOrNo!) || d.AcceptorStaffNo.Contains(dto.NameOrNo!)) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) //.WhereIF(dto.EmergencyLevels.Any(), d => dto.EmergencyLevels.Contains(d.EmergencyLevel)) .WhereIF(!string.IsNullOrEmpty(dto.PhoneNo), d => d.FromPhone.Contains(dto.PhoneNo!) || d.Contact.Contains(dto.PhoneNo!)) //.WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.PushTypeCode == dto.PushTypeCode) .WhereIF(!string.IsNullOrEmpty(dto.PushTypeCode), d => d.OrderPushTypes.Any(opt => opt.PushTypeCode == dto.PushTypeCode)) //推送分类 .WhereIF(dto.ExpiredTimeStart.HasValue, d => d.ExpiredTime >= dto.ExpiredTimeStart) .WhereIF(dto.ExpiredTimeEnd.HasValue, d => d.ExpiredTime <= dto.ExpiredTimeEnd) .WhereIF(dto.Status.HasValue, d => d.Status == dto.Status) //工单状态 .WhereIF(dto.Status != null && dto.Status == EOrderStatus.BackToUnAccept, d => d.Status <= EOrderStatus.HandOverToUnAccept); if (!_sessionContext.OrgIsCenter && _sessionContext.OrgId.Length >= 6) { var oneCode = _sessionContext.OrgId.Substring(0, 6); query = query.Where(x => x.AcceptorOrgCode.StartsWith(oneCode) && !x.AcceptorOrgCode.StartsWith(_sessionContext.OrgId)); } var (total, items) = await query .OrderByDescending(d => d.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取工单特提信息 /// /// /// [HttpGet("special/{id}")] public async Task SpecialEntity(string id) { var item = await _orderSpecialRepository.Queryable() .Includes(x => x.Order) .FirstAsync(x => x.Id == id); var itemDto = new OrderSpecialDto(); if (item != null) { itemDto = _mapper.Map(item); if (itemDto.FileJson != null && itemDto.FileJson.Any()) { var ids = itemDto.FileJson.Select(x => x.Id).ToList(); itemDto.Files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); } } return itemDto; } /// /// 列表页面基础数据 /// /// [HttpGet("special/base/{id}")] public async Task SpecialBaseData(string id) { var step = await _workflowApplication.GetRecallStepsAsync(id, HttpContext.RequestAborted); var specialSeats = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialSeats).SettingValue[0]); var specialSendOrder = bool.Parse(_systemSettingCacheManager.GetSetting(SettingConstants.SpecialSendOrder).SettingValue[0]); var order = await _orderRepository.Queryable().Where(d => d.WorkflowId == id).FirstAsync(HttpContext.RequestAborted); if (order == null) throw UserFriendlyException.SameMessage("无效工单信息!"); var baseTypeId = string.Empty; if (!_sessionContext.Roles.Contains("banzhang")) { if (step != null && step.Steps.Any() && _sessionContext.Roles.Contains("zuoxi") && specialSeats && !_sessionContext.Roles.Contains("paidanyuan")) { step.Steps = step.Steps.Where(x => x.Key.ToLower() == "start").ToList(); if (step.Steps.Any()) baseTypeId = step.Steps[0].Key; } if (step != null && step.Steps.Any() && _sessionContext.Roles.Contains("paidanyuan") && specialSendOrder && !_sessionContext.Roles.Contains("zuoxi")) { step.Steps = step.Steps.Where(d => d.BusinessType is EBusinessType.Send).ToList(); if (step.Steps.Any()) baseTypeId = step.Steps[0].Key; } } var rsp = new { SpecialTimeType = EnumExts.GetDescriptions(), SpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason), InstaShotSpecialReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason), Step = step, IsTerminate = await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(), BaseTypeId = baseTypeId }; return rsp; } /// /// 重办基础数据 /// /// [HttpGet("reTransact/base/{id}")] public async Task ReTransactBaseData(string id) { var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted); var isInstaShot = order.SourceChannel.Contains("随手拍"); var defaultStepKey = string.Empty; List orgs = new(); if (order == null) throw UserFriendlyException.SameMessage("无效工单信息!"); //中心会签调取方法 var org = await _workflowDomainService.GetLevelOneOrgsAsync(order.WorkflowId, HttpContext.RequestAborted); orgs.AddRange(org); var step = await _workflowApplication.GetRecallStepsAsync(order.WorkflowId, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong) { step.Steps = step.Steps.Where(x => x.Key.ToLower() != "start").ToList(); if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any()) { var stepdDefault = step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1) .FirstOrDefault(); defaultStepKey = stepdDefault.Key; } } //获取部门信息 var rsp = new { SpecialTimeType = EnumExts.GetDescriptions(), SpecialReason = isInstaShot ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason) : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason), ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType), IsTerminate = await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(), Step = step, Orgs = orgs, DefaultStepKey = defaultStepKey }; return rsp; } /// /// 退回基础数据 /// /// [HttpGet("sendback/base/{id}")] public async Task SendBackBaseData(string id) { var order = await _orderRepository.GetAsync(id, HttpContext.RequestAborted); var isInstaShot = order.SourceChannel.Contains("随手拍"); var defaultStepKey = string.Empty; var defaultHandlerKey = string.Empty; List orgs = new(); if (order == null) throw UserFriendlyException.SameMessage("无效工单信息!"); //中心会签调取方法 var org = await _workflowDomainService.GetLevelOneOrgsAsync(order.WorkflowId, HttpContext.RequestAborted); orgs.AddRange(org); var step = await _workflowApplication.GetRecallStepsAsync(order.WorkflowId, HttpContext.RequestAborted); if (_appOptions.Value.IsZiGong) { step.Steps = step.Steps.Where(x => x.Key.ToLower() != "start").ToList(); if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any()) { var stepdDefault = step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1) .FirstOrDefault(); defaultStepKey = stepdDefault.Key; } } if (_appOptions.Value.IsYiBin) { if (order.FileOrgIsCenter.Value) { var stepdDefault = step.Steps.Where(x => x.Key.ToLower() == "start").FirstOrDefault(); defaultStepKey = stepdDefault.Key; defaultHandlerKey = stepdDefault.Handler.Key; } if (!order.FileOrgIsCenter.Value) { if (step.Steps.Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1).Any()) { var stepdDefault = step.Steps .Where(x => x.BusinessType == EBusinessType.Department && x.OrgLevel == 1 && x.StepType == EStepType.Normal) .FirstOrDefault(); defaultStepKey = stepdDefault.Key; defaultHandlerKey = stepdDefault.Handler.Key; } } } //获取部门信息 var rsp = new { SpecialTimeType = EnumExts.GetDescriptions(), SpecialReason = isInstaShot ? _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.InstaShotSpecialReason) : _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SpecialReason), ReTransactErrorType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReTransactErrorType), IsTerminate = await _orderTerminateRepository.Queryable().Where(d => d.OrderId == order.Id && d.Status == ETerminateStatus.End).AnyAsync(), Step = step, Orgs = orgs, DefaultStepKey = defaultStepKey, DefaultHandlerKey = defaultHandlerKey }; return rsp; } /// /// 部门批量重提 该部门及下级部门回访结果 不满意 未评价 视为满意 /// /// [HttpPost("org_batch_special")] [AllowAnonymous] public async Task OrgBatchSpecial([FromBody] OrgBatchSpecialDto model) { //部门信息 var org = await _organizeRepository.Queryable().Where(o => o.Id == model.OrgId).FirstAsync(HttpContext.RequestAborted); if (org is null) throw UserFriendlyException.SameMessage("部门信息不存在 请检查部门信息是否正确!"); //用户信息 && !u.Name.Contains("测试") var user = await _userRepository.Queryable().Where(u => u.OrgId == model.OrgId).FirstAsync(HttpContext.RequestAborted); if (user is null) throw UserFriendlyException.SameMessage("用户信息不存在 请检查部门下用户信息是否正确!"); //工单信息 中心会签件不处理 var orders = await _orderRepository.Queryable(isAdmin: true) .Includes(o => o.Workflow) .Includes(o => o.OrderVisits) .Where(o => (o.CounterSignType == null || o.CounterSignType == ECounterSignType.Department) && o.OrderVisits.Any(ov => ov.VisitState == EVisitState.Visited && ov.VisitTime >= model.StartTime && ov.VisitTime <= model.EndTime && ov.OrderVisitDetails.Any(ord => ord.VisitOrgCode.StartsWith(model.OrgId) && (SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "2" || SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "7" || SqlFunc.JsonField(ord.OrgProcessingResults, "Key") == "-1") ))).ToListAsync(); if (!orders.Any()) throw UserFriendlyException.SameMessage(org.Name + " 部门及下级部门不存在回访结果为不满意、未评价、视为满意的工单!"); foreach (var order in orders) { var nextStep = await _workflowStepRepository.Queryable().Where(step => step.WorkflowId == order.WorkflowId && step.HandlerOrgId == model.OrgId && step.StepType == EStepType.Normal).OrderByDescending(step => step.CreationTime) .FirstAsync(HttpContext.RequestAborted); if (nextStep is null) continue; var dto = new OrderReTransactDto { AlterTime = true, BusinessType = EBusinessType.Department, FlowDirection = EFlowDirection.FiledToOrg, HandlerType = EHandlerType.OrgLevel, NextHandlers = new List { new() { Key = org.Id, Value = org.Name, OrgId = org.Id, OrgName = org.Name, UserId = user.Id, Username = user.Name, FlowAssignType = EFlowAssignType.Org } }, NextStepCode = nextStep.Code, NextStepName = nextStep.Name, OrderId = order.Id, Cause = "不满意二次办理", Reason = "部门回访不满意 批量特提", SpecialType = ESpecialType.SendBack, StepType = EStepType.Normal, TimeLimit = 5, TimeLimitUnit = ETimeType.WorkDay, WorkflowId = order.WorkflowId }; await Add(dto); } } #endregion #region 市民信息 /// /// 新增市民信息 /// /// /// [HttpPost("citizen")] [LogFilter("新增市民信息")] public async Task Add([FromBody] CitizenAddDto dto) { var citizen = await _citizenRepository.CountAsync(x => x.PhoneNumber == dto.PhoneNumber, HttpContext.RequestAborted); if (citizen > 0) throw UserFriendlyException.SameMessage("市民联系电话信息重复"); await _citizenRepository.AddAsync(dto, HttpContext.RequestAborted); } /// /// 删除市民信息 /// /// /// [HttpDelete("citizen")] [LogFilter("删除市民信息")] public async Task Delete([FromBody] CitizenDeleteDto dto) { await _citizenRepository.RemoveAsync(x => x.Id == dto.Id); } /// /// 更新市民信息 /// /// /// [HttpPut("citizen")] [LogFilter("更新市民信息")] public async Task Update([FromBody] CitizenUpdateDto dto) { var citizen = await _citizenRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (citizen is null) throw UserFriendlyException.SameMessage("无效市民信息"); _mapper.Map(dto, citizen); citizen.LastModificationName = _sessionContext.UserName; await _citizenRepository.UpdateAsync(citizen, HttpContext.RequestAborted); } /// /// 获取市民信息列表 /// /// /// [HttpGet("citizen/list")] public async Task> List([FromQuery] CitizenListDto dto) { var (total, items) = await _citizenRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.PhoneNumber), x => x.PhoneNumber.Contains(dto.PhoneNumber!)) .WhereIF(!string.IsNullOrEmpty(dto.Label), x => x.Label != null && x.Label.Contains(dto.Label!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取市民信息 /// /// /// [HttpGet("citizen/{id}")] public async Task CitizenEntity(string id) { return await _citizenRepository.Queryable() .Includes(x => x.labelDetails) .FirstAsync(x => x.Id == id); } /// /// 获取市民信息 /// /// /// [HttpGet("citizen_phone/{phone}")] public async Task Citizen(string phone) { //市民基本信息 var citizen = await _citizenRepository.Queryable() .Includes(x => x.labelDetails) .FirstAsync(x => x.PhoneNumber == phone); //var calls = await _trCallRecordRepository.Queryable().Where(x => x.CallDirection == 0 && x.CPN == phone).OrderBy(x => x.CreatedTime).ToListAsync(); //var oneCallTime = calls != null && calls.Count() > 0 ? calls[0].CreatedTime : DateTime.Now; //var lastNum = calls != null && calls.Count() > 0 ? calls.Count() - 1 : -1; //var lastCallTime = lastNum >= 0 ? calls[lastNum].CreatedTime : DateTime.Now; var oneCallTime = DateTime.Now; var lastCallTime = DateTime.Now; if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun) { var calls = await _callApplication.QueryTianrunCallsAsync(phone, ECallDirection.In, cancellationToken: HttpContext.RequestAborted); oneCallTime = calls.FirstOrDefault()?.CreatedTime ?? DateTime.Now; var count = calls.Count; lastCallTime = count > 1 ? calls[count - 2].CreatedTime : oneCallTime; } else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang) { var calls = await _callApplication.QueryCallsAsync(phone, ECallDirection.In, cancellationToken: HttpContext.RequestAborted); oneCallTime = calls.FirstOrDefault()?.BeginIvrTime ?? DateTime.Now; var count = calls.Count; lastCallTime = count > 1 ? calls[count - 2].CreationTime : oneCallTime; } //工单历史 var oders = await _orderRepository.Queryable().Where(x => x.Contact == phone) .OrderBy(x => x.CreationTime, OrderByType.Desc).ToListAsync(); var allOrderNum = oders.Count; var endOrderNum = oders.Count(x => (int)x.Status >= 300); var handOrderNum = oders.Count(x => (int)x.Status < 300); var DissatisfactionNum = await _orderVisitedDetailRepository.Queryable() .Includes(x => x.OrderVisit) .Includes(x => x.OrderVisit, v => v.Order) .Where(x => x.OrderVisit.Order.Contact == phone && (SqlFunc.JsonField(x.OrgProcessingResults, "Value") == "不满意" || SqlFunc.JsonField(x.OrgProcessingResults, "Value") == "非常不满意")) .Distinct().Select(x => new { x.OrderVisit.OrderId }).CountAsync(); //来电历史 //var callsHistory = await _trCallRecordRepository.Queryable().Where(x => x.CPN == phone || x.CDPN == phone).ToListAsync(); var allCallNum = 0; var connectNum = 0; var callBackNum = 0; //if (callsHistory != null && callsHistory.Any()) //{ // allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In); // connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0); // callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out); //} if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.TianRun) { var callsHistory = await _callApplication.QueryTianrunCallsAsync(phone, cancellationToken: HttpContext.RequestAborted); if (callsHistory != null && callsHistory.Any()) { allCallNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In); connectNum = callsHistory.Count(x => x.CallDirection == ECallDirection.In && x.Duration > 0); callBackNum = callsHistory.Count(x => x.CallDirection == ECallDirection.Out); } } else if (_appOptions.Value.GetDefaultAppScopeConfiguration().CallCenterType == AppDefaults.CallCenterType.XingTang) { var histories = await _callApplication.QueryCallsAsync(phone, cancellationToken: HttpContext.RequestAborted); if (histories.Any()) { allCallNum = histories.Count(x => x.Direction == ECallDirection.In); connectNum = histories.Count(x => x.Direction == ECallDirection.In && x.Duration > 0); callBackNum = histories.Count(x => x.Direction == ECallDirection.Out); } } //关注诉求 var hotspotNames = string.Join(",", oders.Select(x => x.HotspotName).Distinct().Take(5).ToList()); var rsp = new { Citizen = citizen, OneCallTime = oneCallTime, LastCallTime = lastCallTime, Order = new { allOrderNum = allOrderNum, endOrderNum = endOrderNum, handOrderNum = handOrderNum, DissatisfactionNum = DissatisfactionNum }, CallHistory = new { AllCallNum = allCallNum, ConnectNum = connectNum, CallBackNum = callBackNum }, HotspotNames = hotspotNames, }; return rsp; } /// /// 新增市民标签信息 /// /// /// [HttpPost("citizen_label")] public async Task Add([FromBody] LabelDetailAddDto dto) { var label = await _labelDetailRepository.CountAsync(x => x.CitizenId == dto.CitizenId && x.Label == dto.Label, HttpContext.RequestAborted); if (label > 0) throw UserFriendlyException.SameMessage("市民联系标签信息重复"); await _citizenRepository.LabelAddAsync(dto, HttpContext.RequestAborted); } /// /// 删除市民标签信息 /// /// /// [HttpDelete("citizen_label")] public async Task Delete([FromBody] LabelDetailDeleteDto dto) { var label = await _labelDetailRepository.GetAsync(x => x.Id == dto.Id, HttpContext.RequestAborted); if (label == null || (label.CreatorName != _sessionContext.UserName)) throw UserFriendlyException.SameMessage("市民联系标签信息错误"); await _citizenRepository.LabelDeleteAsync(label, HttpContext.RequestAborted); } /// /// 获取市民标签信息列表 /// /// /// [HttpGet("citizen_label/list")] public async Task> List([FromQuery] CitizenQueryDto dto) { var (total, items) = await _labelDetailRepository.Queryable() .Includes(x => x.Citizen) .WhereIF(!string.IsNullOrEmpty(dto.Label), x => x.Label.Contains(dto.Label!)) .WhereIF(!string.IsNullOrEmpty(dto.CreatorName), x => x.CreatorName != null && x.CreatorName.Contains(dto.CreatorName!)) .Where(x => x.CitizenId == dto.CitizenId) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } #endregion #region 重复性事件 /// /// 新增重复性事件 /// /// /// [HttpPost("repeatable_event")] [LogFilter("新增重复性事件")] public async Task Add([FromBody] RepeatableEventAddDto dto) { var repeatable = _mapper.Map(dto); var repeatableId = await _repeatableEventRepository.AddAsync(repeatable, HttpContext.RequestAborted); List detail; if (!string.IsNullOrEmpty(repeatableId) && dto.Details.Any()) dto.Details.ForEach(x => x.RepeatableId = repeatableId); detail = _mapper.Map>(dto.Details); if (detail.Any()) await _repeatableEventDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted); } /// /// 删除重复性事件 /// /// /// [HttpDelete("repeatable_event")] [LogFilter("删除重复性事件")] public async Task Delete([FromBody] RepeatableEventDeleteDto dto) { await _repeatableEventRepository.RemoveAsync(x => x.Id == dto.Id); await _repeatableEventDetailRepository.RemoveAsync(x => x.RepeatableId == dto.Id); } /// /// 删除重复性事件明细 /// /// /// [HttpDelete("repeatable_event_detail/{id}")] [LogFilter("删除重复性事件")] public async Task Delete([FromBody] string id) { await _repeatableEventDetailRepository.RemoveAsync(x => x.Id == id); } /// /// 更新重复性事件 /// /// /// [HttpPut("repeatable_event")] [LogFilter("更新重复性事件")] public async Task Update([FromBody] RepeatableEventUpdateDto dto) { var repeatable = await _repeatableEventRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (repeatable is null) throw UserFriendlyException.SameMessage("无效重复性事件"); _mapper.Map(dto, repeatable); repeatable.LastModificationName = _sessionContext.UserName; await _repeatableEventRepository.UpdateAsync(repeatable, HttpContext.RequestAborted); List detail; if (dto.Details.Any()) dto.Details.ForEach(x => x.RepeatableId = dto.Id); await _repeatableEventDetailRepository.DeleteAsync(dto.Id, HttpContext.RequestAborted); detail = _mapper.Map>(dto.Details); if (detail.Any()) await _repeatableEventDetailRepository.AddRangeAsync(detail, HttpContext.RequestAborted); } /// /// 获取重复性事件列表 /// /// /// [HttpGet("repeatable_event/list")] public async Task> List([FromQuery] RepeatableEventListDto dto) { var (total, items) = await _repeatableEventRepository.Queryable() .Includes(x => x.Details) .Includes(x => x.Details, y => y.Order) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Title.Contains(dto.Keyword!) || (d.KeyWords != null && d.KeyWords.Contains(dto.Keyword!))) .WhereIF(dto.CreationTimeStart.HasValue, d => d.CreationTime >= dto.CreationTimeStart) .WhereIF(dto.CreationTimeEnd.HasValue, d => d.CreationTime <= dto.CreationTimeEnd) .WhereIF(!string.IsNullOrEmpty(dto.Code), x => x.Code != null && x.Code.Contains(dto.Code!)) .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Title.Contains(dto.Title!)) .WhereIF(!string.IsNullOrEmpty(dto.KeyWords), x => x.KeyWords != null && x.KeyWords.Contains(dto.KeyWords!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取重复性事件 /// /// /// [HttpGet("repeatable_event")] public async Task CitizenEntity([FromQuery] RepeatableEventEntityDto dto) { var repeatableEvent = await _repeatableEventRepository.Queryable() .Includes(x => x.Details.WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.Title.Contains(dto.Keyword!)) .ToList()) .Includes(x => x.Details, y => y.Order) .FirstAsync(x => x.Id == dto.Id); return _mapper.Map(repeatableEvent); } #endregion #region 工单词库 /// /// 新增工单词库 /// /// /// [HttpPost("order_word")] [LogFilter("新增工单词库")] public async Task Add([FromBody] OrderWordAddDto dto) { var word = _mapper.Map(dto); await _orderWrodRepository.AddAsync(word, HttpContext.RequestAborted); } /// /// 删除工单词库 /// /// /// [HttpDelete("order_word")] [LogFilter("删除工单词库")] public async Task Delete([FromBody] OrderWordDeleteDto dto) { await _orderRepository.RemoveOrderWrodBatchAsync(dto.Ids, HttpContext.RequestAborted); } /// /// 更新工单词库 /// /// /// [HttpPut("order_word")] [LogFilter("更新工单词库")] public async Task Update([FromBody] OrderWordUpdateDto dto) { var word = await _orderWrodRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (word is null) throw UserFriendlyException.SameMessage("无效工单词库"); _mapper.Map(dto, word); word.LastModificationName = _sessionContext.UserName; await _orderWrodRepository.UpdateAsync(word, HttpContext.RequestAborted); } /// /// 获取工单词库列表 /// /// /// [HttpGet("order_word/list")] public async Task> List([FromQuery] OrderWordListDto dto) { var (total, items) = await _orderWrodRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.Tag), x => x.Tag == dto.Tag!) .WhereIF(!string.IsNullOrEmpty(dto.Classify), x => x.Classify.Contains(dto.Classify!)) .WhereIF(!string.IsNullOrEmpty(dto.Synonym), x => x.Synonym != null && x.Synonym.Contains(dto.Synonym!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取工单词库 /// /// /// [HttpGet("order_word/{id}")] public async Task OrderWordEntity(string id) { return await _orderWrodRepository.Queryable() .FirstAsync(x => x.Id == id); } /// /// 获取工单词库基本信息 /// /// [HttpGet("order_word/base")] public async Task Base() { var rsp = new { OrderWordClassify = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderWordClassify), }; return rsp; } #endregion #region 工单观察、关注 /// /// 新增工单观察 /// /// /// [HttpPost("order_observe")] [LogFilter("新增工单观察")] public async Task Add([FromBody] OrderObserveAddDto dto) { var ids = dto.OrderIds.Select(x => x.OrderId).ToList(); var list = await _orderObserveRepository.Queryable().In(x => x.OrderId, ids).Select(x => x.OrderId) .ToListAsync(); if (list.Any()) dto.OrderIds = ids.Except(list).Select(x => new OrdersObserveAddDto { OrderId = x }).ToList(); if (!dto.OrderIds.Any()) throw UserFriendlyException.SameMessage("无效工单观察,当前所选工单都已观察"); var observe = _mapper.Map>(dto.OrderIds); await _orderObserveRepository.AddRangeAsync(observe, HttpContext.RequestAborted); } /// /// 删除工单观察 /// /// /// [HttpDelete("order_observe")] [LogFilter("删除工单观察")] public async Task Delete([FromBody] OrderObserveDeleteDto dto) { await _orderRepository.RemoveOrderObserveBatchAsync(dto.Ids, HttpContext.RequestAborted); } /// /// 更新工单观察 /// /// /// [HttpPut("order_observe")] [LogFilter("更新工单观察")] public async Task Update([FromBody] OrderObserveUpdateDto dto) { var word = await _orderObserveRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (word is null) throw UserFriendlyException.SameMessage("无效工单观察"); _mapper.Map(dto, word); await _orderObserveRepository.UpdateAsync(word, HttpContext.RequestAborted); } /// /// 获取工单观察列表 /// /// /// [HttpGet("order_observe/list")] public async Task> List([FromQuery] OrderObserveListDto dto) { var quer = _orderApplication.OrderObserveList(dto); var (total, items) = await quer.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取工单观察列表导出 /// /// /// [HttpPost("order_observe/list/export")] public async Task ListExport([FromBody] ExportExcelDto dto) { var query = _orderApplication.OrderObserveList(dto.QueryDto); List data; if (dto.IsExportAll) { data = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); data = items; } var dataDtos = _mapper.Map>(data); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = dataDtos .Select(stu => _mapper.Map(stu, typeof(OrderObserveDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单关注列表"); } /// /// 获取工单观察 /// /// /// [HttpGet("order_observe/{id}")] public async Task OrderObserveEntity(string id) { return await _orderObserveRepository.Queryable() .FirstAsync(x => x.Id == id); } /// /// 列表页面基础数据 /// /// [HttpGet("order_observe/base-data")] public async Task OrderObserveBaseData() { var rsp = new { AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType) }; return rsp; } #endregion #region 工单终结 /// /// 新增工单终结 /// /// /// [HttpPost("order_finality")] [LogFilter("新增工单终结")] public async Task Add([FromBody] OrderFinalityAddDto dto) { var ids = dto.OrderIds.Select(x => x.OrderId).ToList(); var list = await _orderFinalityRepository.Queryable().In(x => x.OrderId, ids).Select(x => x.OrderId) .ToListAsync(); if (list.Any()) dto.OrderIds = ids.Except(list).Select(x => new OrdersFinalityAddDto { OrderId = x }).ToList(); if (!dto.OrderIds.Any()) throw UserFriendlyException.SameMessage("无效工单终结,当前所选工单都已终结"); var observe = _mapper.Map>(dto.OrderIds); await _orderFinalityRepository.AddRangeAsync(observe, HttpContext.RequestAborted); } /// /// 删除工单终结 /// /// /// [HttpDelete("order_finality")] [LogFilter("删除工单终结")] public async Task Delete([FromBody] OrderFinalityDeleteDto dto) { await _orderRepository.RemoveOrderFinalityBatchAsync(dto.Ids, HttpContext.RequestAborted); } /// /// 更新工单终结 /// /// /// [HttpPut("order_finality")] [LogFilter("更新工单终结")] public async Task Update([FromBody] OrderFinalityUpdateDto dto) { var word = await _orderFinalityRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (word is null) throw UserFriendlyException.SameMessage("无效工单观察"); _mapper.Map(dto, word); await _orderFinalityRepository.UpdateAsync(word, HttpContext.RequestAborted); } /// /// 获取工单终结列表 /// /// /// [HttpGet("order_finality/list")] public async Task> List([FromQuery] OrderFinalityListDto dto) { var (total, items) = await _orderFinalityRepository.Queryable() .Includes(x => x.Order) .WhereIF(dto.IsProvince.HasValue, x => x.Order.IsProvince == dto.IsProvince) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.Order.No.Contains(dto.Keyword!) || x.Order.Title.Contains(dto.Keyword!)) //.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!)) //.WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 获取工单终结 /// /// /// [HttpGet("order_finality/{id}")] public async Task OrderFinalityEntity(string id) { return await _orderFinalityRepository.Queryable() .FirstAsync(x => x.Id == id); } #endregion #region 超期查询 /// /// 工单即将超期列表 /// /// /// [HttpGet("order/about_expire/list")] public async Task> AboutList([FromQuery] AboutToExpireListDto dto) { var (total, items) = await _orderApplication.GetAboutToExpireAsync(dto) .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 工单即将超期列表(不查总条数) /// /// /// [HttpGet("order/about_expire/list_items")] public async Task> AboutListAsnc([FromQuery] AboutToExpireListDto dto) { return (await _orderApplication.GetAboutToExpireAsync(dto).ToFixedListAsync(dto.PageIndex - 1, dto.PageSize, HttpContext.RequestAborted)) .Adapt>(); } /// /// 工单即将超期列表总条数 /// /// /// [HttpGet("order/about_expire/list_count")] public async Task AboutListCountAsnc([FromQuery] AboutToExpireListDto dto) { return await _orderApplication.GetAboutToExpireAsync(dto).CountAsync(HttpContext.RequestAborted); } /// /// 工单即将超期列表(优化测试) /// /// /// [HttpGet("order/about_expire/list_optimize")] public async Task> GetAboutToExpireAsyncV1([FromQuery] AboutToExpireListDto dto) { var (t, i) = await _orderApplication.GetAboutToExpireAsync(dto) .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(t, _mapper.Map>(i)); } /// /// 工单即将超期列表导出 /// /// [HttpPost("order/about_expire/_export")] public async Task AboutListExport([FromBody] ExportExcelDto dto) { var query = _orderApplication.GetAboutToExpireAsync(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var ordersDtos = _mapper.Map>(orders); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = ordersDtos .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单即将超期列表数据"); } ///// ///// 工单即将超期节点列表 ///// ///// ///// //[HttpGet("order/about_expire_node/list")] //public async Task> AboutNodeList([FromQuery] AboutToExpireListDto dto) //{ // return await _orderApplication.GetAboutToExpireNodeAsync(dto, HttpContext.RequestAborted); //} /// /// 工单超期列表 /// /// /// [HttpGet("order/expire/list")] public async Task> ExpireList([FromQuery] AboutToExpireListDto dto) { var (total, items) = await _orderApplication.GetToExpireAsync(dto) .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 工单超期列表导出 /// /// [HttpPost("order/expire/_export")] public async Task ExpireListExport([FromBody] ExportExcelDto dto) { var query = _orderApplication.GetToExpireAsync(dto.QueryDto); List orders; if (dto.IsExportAll) { orders = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); orders = items; } var ordersDtos = _mapper.Map>(orders); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = ordersDtos .Select(stu => _mapper.Map(stu, typeof(OrderDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "工单超期列表数据"); } ///// ///// 工单超期节点列表 ///// ///// ///// //[HttpGet("order/expire_node/list")] //public async Task> NodeList([FromQuery] AboutToExpireListDto dto) //{ // return await _orderApplication.GetToExpireNodeAsync(dto, HttpContext.RequestAborted); //} #endregion #region 工单签收 /// /// 工单签收 /// [HttpPost("sign/{orderId}")] [LogFilter("工单签收")] public async Task Sign(string orderId) { var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted); if (order == null) throw new UserFriendlyException($"无效工单编号, orderId: {orderId}", "无效工单编号"); if (order.IsSigned()) throw UserFriendlyException.SameMessage("该工单已被签收"); order.Sign(_sessionContext.RequiredUserId, _sessionContext.UserName); order.AutoAccept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.StaffNo); if (!string.IsNullOrEmpty(order.WorkflowId)) { var workflow = await _workflowDomainService.SignToSomebodyAsync( order.WorkflowId, _sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.RequiredOrgId, _sessionContext.OrgName, HttpContext.RequestAborted); order.HandlerOrgs = workflow.HandlerOrgs; order.HandlerUsers = workflow.HandlerUsers; order.FlowedOrgIds = workflow.FlowedOrgIds; order.FlowedUserIds = workflow.FlowedUserIds; } await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); } #endregion #region 导入工单 /// /// 下载工单导入模板 /// /// [HttpGet("download-order-template")] public async Task DownLoadOrderTemplate() { List list = new List(); ExcelContent excelContent = new ExcelContent() { ExternalId = "自编号" }; list.Add(excelContent); return _exportApplication.ExportData(list, "demo.xlsx"); } /// /// 导入工单 /// TODO 回访信息需要写回访表? /// TODO 工单是否需要写发布表? /// TODO 是否自动签收工单? /// TODO SourceChannel 是否和 Source 相同? /// /// /// [HttpPost("import-order")] public async Task ImportOrder(IFormFile file) { using (var stream = new MemoryStream()) { file.CopyTo(stream); var list = MiniExcel.Query(stream).ToList(); int count = 0; int errorCount = 0; int addCount = 0; int modifyCount = 0; var allowSources = new Dictionary { { "麻辣社区", "MLSQ" }, { "人民网", "RMW" }, { "省长信箱", "SZXX" }, { "问政四川", "WZSC" } }; var errorMessage = new StringBuilder(); if (list == null || list.Count == 0) { return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount, ErrorMessage = "数据为空" }; } count = list.Count; var i = 0; foreach (var item in list) { i++; try { var validationResult = item.ValidateObject(false); if (validationResult.NotNullOrEmpty()) { errorMessage.Append($"第{i + 1}行: {validationResult}\r\n"); errorCount++; continue; } var allowSource = allowSources.FirstOrDefault(m => m.Key == item.Source).Value; if (allowSource.IsNullOrEmpty()) { errorCount++; continue; } var SourceCode = (ESource)Enum.Parse(typeof(ESource), allowSource); var acceptType = _sysDicDataCacheManager.AcceptType .FirstOrDefault(m => m.DicDataName == item.AcceptType); if (acceptType == null) { errorMessage.Append($"第{i + 1}行: 不能通过受理类型 {item.AcceptType} 查询到对应的受理类型Code\r\n"); continue; } var order = await _orderRepository.GetAsync(x => x.ExternalId == item.ExternalId && x.Source == SourceCode, HttpContext.RequestAborted) ?? new Orders.Order(); item.Source = SourceCode.ToString(); order = _mapper.Map(item, order); order.AcceptTypeCode = acceptType.DicDataValue; order.SourceChannel = SourceCode.GetDescription(); order.SourceChannelCode = ((int)SourceCode).ToString(); order.Status = EOrderStatus.Visited; #region 处理数据开始 // order.Source = SourceCode; //来源 //处理热点 //处理一级热点 string hotspotId = ""; string hotspotName = ""; string hotspotFullName = ""; var hotspotOne = await _hotspotTypeRepository.Queryable() .FirstAsync(x => x.HotSpotName == item.HotspotNameOne, HttpContext.RequestAborted); if (hotspotOne != null) { hotspotId = hotspotOne.Id; hotspotName = hotspotOne.HotSpotName; hotspotFullName = hotspotOne.HotSpotFullName; var hotspotTwo = await _hotspotTypeRepository.Queryable() .FirstAsync(x => x.HotSpotName == item.HotspotNameTwo && x.ParentId == hotspotId, HttpContext.RequestAborted); if (hotspotTwo != null) { hotspotId = hotspotTwo.Id; hotspotName = hotspotTwo.HotSpotName; hotspotFullName = hotspotTwo.HotSpotFullName; var hotspotThree = await _hotspotTypeRepository.Queryable() .FirstAsync(x => x.HotSpotName == item.HotspotNameThree && x.ParentId == hotspotId, HttpContext.RequestAborted); if (hotspotThree != null) { hotspotId = hotspotThree.Id; hotspotName = hotspotThree.HotSpotName; hotspotFullName = hotspotThree.HotSpotFullName; var hotspotFour = await _hotspotTypeRepository.Queryable() .FirstAsync(x => x.HotSpotName == item.HotspotNameFour && x.ParentId == hotspotId, HttpContext.RequestAborted); if (hotspotFour != null) { hotspotId = hotspotFour.Id; hotspotName = hotspotFour.HotSpotName; hotspotFullName = hotspotFour.HotSpotFullName; var hotspotFive = await _hotspotTypeRepository.Queryable() .FirstAsync(x => x.HotSpotName == item.HotspotNameFive && x.ParentId == hotspotId, HttpContext.RequestAborted); if (hotspotFive != null) { hotspotId = hotspotFive.Id; hotspotName = hotspotFive.HotSpotName; hotspotFullName = hotspotFive.HotSpotFullName; } } } } } order.HotspotId = hotspotId; order.HotspotName = hotspotName; order.HotspotSpliceName = hotspotFullName; //处理部门 var orgOne = await _organizeRepository.Queryable() .FirstAsync(x => x.Name == item.OrgLevelOneName, HttpContext.RequestAborted); if (orgOne != null) { order.OrgLevelOneCode = orgOne.Id; order.OrgLevelOneName = orgOne.Name; var orgTwo = await _organizeRepository.Queryable() .FirstAsync(x => x.Name == item.OrgLevelTwoName && x.ParentId == order.OrgLevelOneCode, HttpContext.RequestAborted); if (orgTwo != null) { order.OrgLevelTwoCode = orgTwo.Id; order.OrgLevelTwoName = orgTwo.Name; } } //承办部门 var ActualHandleOrg = await _organizeRepository.Queryable() .FirstAsync(x => x.Name == item.ActualHandleOrgName, HttpContext.RequestAborted); if (ActualHandleOrg != null) { order.ActualHandleOrgCode = ActualHandleOrg.Id; } //处理地址 order.FullAddress = $"{order.Address}{order.Street}"; order.FirstVisitResultCode = _sysDicDataCacheManager .GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction) .FirstOrDefault(m => m.DicDataName == item.VisitResult)?.DicDataValue ?? order.FirstVisitResultCode; #endregion if (order.Id.IsNullOrEmpty()) { //order.Source = item; var id = await _orderDomainService.AddAsync(order, false, HttpContext.RequestAborted); if (!string.IsNullOrEmpty(id)) { addCount++; } else { errorCount++; } } else { // _mapper.Map(item, order); await _orderRepository.UpdateAsync(order, HttpContext.RequestAborted); modifyCount++; } } catch (Exception ex) { errorCount++; } } return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ModifyCount = modifyCount, ErrorMessage = errorMessage.ToString() }; } } /// /// 导入基础数据 /// /// [HttpGet("import-basedata")] public async Task ImportBaseData() { var rsp = new { Source = EnumExts.GetDescriptions(), }; return rsp; } #endregion #region 二次办理 /// /// 新增二次办理 /// /// /// [HttpPost("secondary_handling")] [LogFilter("新增二次办理")] public async Task OrderSecondaryHandlingAdd([FromBody] AddOrderSecondaryHandlingDto dto) { await _orderSecondaryHandlingApplication.AddAsync(dto, HttpContext.RequestAborted); } /// /// 二次办理退回 /// /// /// [HttpPost("secondary_handling/send_back")] [LogFilter("二次办理退回")] public async Task OrderSecondaryHandlingSendBackAsync([FromBody] SendBackOrderSecondaryHandlingDto dto) { await _orderSecondaryHandlingApplication.SendBackAsync(dto, HttpContext.RequestAborted); } /// /// 二次办理审批 /// /// /// [HttpPut("secondary_handling/audit")] [LogFilter("二次办理审批")] public async Task OrderSecondaryHandlingAudit([FromBody] AuditOrderSecondaryHandlingDto dto) { var model = await _orderSecondaryHandlingApplication.Entity(dto.Id, HttpContext.RequestAborted); if (model == null || model.State != ESecondaryHandlingState.Apply) throw UserFriendlyException.SameMessage("无效二次办理审批信息!"); await _orderSecondaryHandlingApplication.AuditAsync(dto, model, HttpContext.RequestAborted); } /// /// 二次办理批量审批 /// /// /// [HttpPut("secondary_handling/batch_audit")] [LogFilter("二次办理批量审批")] public async Task OrderSecondaryHandlingBatchAudit([FromBody] AuditOrderSecondaryHandlingDto dto) { foreach (var item in dto.Ids) { var model = await _orderSecondaryHandlingApplication.Entity(item, HttpContext.RequestAborted); if (model == null || model.State != ESecondaryHandlingState.Apply) throw UserFriendlyException.SameMessage("无效二次办理审批信息!"); await _orderSecondaryHandlingApplication.AuditAsync(dto, model, HttpContext.RequestAborted); } } /// /// 二次办理申请列表 /// /// [HttpGet("secondary_handling/apply")] public async Task> OrderSecondaryHandlingApplyQuery([FromQuery] MayScreenListDto dto) { var query = _orderSecondaryHandlingApplication.ApplyQuery(dto, HttpContext.RequestAborted); var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 二次办理申请列表导出 /// /// [HttpPost("secondary_handling/apply_export")] public async Task OrderSecondaryHandlingApplyExport([FromBody] ExportExcelDto dto) { var query = _orderSecondaryHandlingApplication.ApplyQuery(dto.QueryDto, HttpContext.RequestAborted); List visitDetails; if (dto.IsExportAll) { visitDetails = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); visitDetails = items; } var visitDetailsDtos = _mapper.Map>(visitDetails); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = visitDetailsDtos .Select(stu => _mapper.Map(stu, typeof(OrderVisitDetailDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "二次办理申请列表数据"); } /// /// 二次办理列表 /// /// [HttpGet("secondary_handling")] public async Task> OrderSecondaryHandlingQuery([FromQuery] SecondaryHandlingListDto dto) { var query = _orderSecondaryHandlingApplication.Query(dto, HttpContext.RequestAborted); var (total, items) = await query.ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 二次办理列表导出 /// /// [HttpPost("secondary_handling/_export")] public async Task OrderSecondaryHandlingExport([FromBody] ExportExcelDto dto) { var query = _orderSecondaryHandlingApplication.Query(dto.QueryDto, HttpContext.RequestAborted); List secondaryHandling; if (dto.IsExportAll) { secondaryHandling = await query.ToListAsync(HttpContext.RequestAborted); } else { var (_, items) = await query.ToPagedListAsync(dto.QueryDto, HttpContext.RequestAborted); secondaryHandling = items; } var secondaryHandlingDtos = _mapper.Map>(secondaryHandling); dynamic? dynamicClass = DynamicClassHelper.CreateDynamicClass(dto.ColumnInfos); var dtos = secondaryHandlingDtos .Select(stu => _mapper.Map(stu, typeof(OrderSecondaryHandlingDto), dynamicClass)) .Cast() .ToList(); var stream = ExcelHelper.CreateStream(dtos); return ExcelStreamResult(stream, "二次办理列表数据"); } /// /// 获取实体 /// /// /// [HttpGet("secondary_handling/{id}")] public async Task OrderSecondaryHandlingEntity(string id) { var model = await _orderSecondaryHandlingApplication.Entity(id, HttpContext.RequestAborted); var dto = _mapper.Map(model); if (model.FileJson != null && model.FileJson.Any()) { var ids = model.FileJson.Select(x => x.Id).ToList(); var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted); dto.Files = files.Where(x => x.Classify == "二次办理申请").ToList(); } return dto; } /// /// 列表页面基础数据 /// /// [HttpGet("secondary_handling/base")] public async Task SecondaryHandlingBaseData() { var rsp = new { Status = EnumExts.GetDescriptions(), CounterSignType = EnumExts.GetDescriptions(), AcceptType = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType), SourceChannel = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SourceChannel), VisitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction), DissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason), }; return rsp; } #endregion #region 副本工单 /// /// 获取副本工单列表 /// /// /// [HttpGet("order_copy/list")] public async Task> OrderCopyList([FromQuery] OrderCopyListDto dto) { var (total, items) = await _orderCopyRepository.Queryable() .Where(x => x.OrderId == dto.OrderId) .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 查询工单修改记录 /// /// /// [HttpGet("order_modify_records/list")] public async Task> OrderModifyRecordsList([FromQuery] PagedKeywordRequest dto) { var (total, items) = await _orderCopyRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.Keyword), x => x.No.Contains(dto.Keyword!)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 修改明细 /// /// /// [HttpGet("order_modify_records/getinfo/{id}")] public async Task GetModifyRecordsInfo(string id) { //修改前数据 var modifyRecordsInfo = await _orderCopyRepository.GetAsync(p => p.Id == id, HttpContext.RequestAborted); if (modifyRecordsInfo is null) throw UserFriendlyException.SameMessage("修改明细查询失败!"); //如何取修改后的数据 var copyNew = await _orderCopyRepository.Queryable().OrderBy(x => x.CreationTime) .FirstAsync(p => p.OrderId == modifyRecordsInfo.OrderId && p.CreationTime > modifyRecordsInfo.CreationTime); OrderDto newInfo = null; if (copyNew != null) { newInfo = _mapper.Map(copyNew); } else { var order = await _orderRepository.Queryable().FirstAsync(d => d.Id == modifyRecordsInfo.OrderId); if (order is not null) { newInfo = _mapper.Map(order); newInfo.CenterOpinion = order.CenterToOrgOpinion; } } var oldInfo = _mapper.Map(modifyRecordsInfo); oldInfo.CenterOpinion = modifyRecordsInfo.CenterToOrgOpinion; return new { OldInfo = oldInfo, NewInfo = newInfo }; } #endregion #region 外部市民管理 /// /// 下载外部市民导入模板 /// /// [HttpGet("download-externalcitizens-template")] public async Task DownLoadCitizensTemplate() { List list = new List(); ExternalCitizensExcelContent excelContent = new ExternalCitizensExcelContent() { }; list.Add(excelContent); return _exportApplication.ExportData(list, "demo.xlsx"); } /// /// 导入外部市民 /// /// /// [HttpPost("import-externalcitizens")] public async Task ImportExternalcitizens(IFormFile file) { using (var stream = new MemoryStream()) { file.CopyTo(stream); var list = MiniExcel.Query(stream).ToList(); int count = 0; int errorCount = 0; int addCount = 0; //int modifyCount = 0; List listreturn = new List(); if (list != null && list.Count > 0) { count = list.Count; foreach (var item in list) { try { var externalcitizens = await _externalCitizensRepository.GetAsync(x => x.PhoneNum == item.PhoneNum, HttpContext.RequestAborted); if (externalcitizens is null) { externalcitizens = _mapper.Map(item); var id = await _externalCitizensRepository.AddAsync(externalcitizens, HttpContext.RequestAborted); if (!string.IsNullOrEmpty(id)) { addCount++; listreturn.Add(item); } else { errorCount++; } } else { listreturn.Add(item); //_mapper.Map(item, externalcitizens); //await _externalCitizensRepository.UpdateAsync(externalcitizens, HttpContext.RequestAborted); //modifyCount++; } } catch (Exception ex) { errorCount++; } } } return new { Count = count, ErrorCount = errorCount, AddCount = addCount, ResultList = listreturn /*, ModifyCount = modifyCount*/ }; } } /// /// 外部市民列表 /// /// [HttpGet("externalcitizens-list")] public async Task> QueryExternalcitizens([FromQuery] QueryExternalcitizensRequest dto) { var (total, items) = await _externalCitizensRepository.Queryable() .WhereIF(!string.IsNullOrEmpty(dto.PhoneNum), x => x.PhoneNum.Contains(dto.PhoneNum)) .WhereIF(!string.IsNullOrEmpty(dto.Name), x => x.Name.Contains(dto.Name)) .OrderByDescending(x => x.CreationTime) .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 删除外部市民 /// /// /// [HttpDelete("del-externalcitizens")] public async Task DelExternalcitizens(string[] ids) { var list = await _externalCitizensRepository.Queryable().In(ids).ToListAsync(HttpContext.RequestAborted); await _externalCitizensRepository.RemoveRangeAsync(list, HttpContext.RequestAborted); } /// /// 修改外部市民 /// /// /// [HttpPost("modify-externalcitizens")] public async Task ModifyExternalcitizens([FromBody] ModifyExternalcitizensDto dto) { if (dto.PhoneNum.Length != 11) throw UserFriendlyException.SameMessage("手机号不合法"); bool isHas = await _externalCitizensRepository.Queryable().AnyAsync(x => x.Id != dto.Id && x.PhoneNum == dto.PhoneNum); if (isHas) throw UserFriendlyException.SameMessage("已存在当前电话,请核对后再修改"); var model = await _externalCitizensRepository.GetAsync(dto.Id, HttpContext.RequestAborted); if (model == null) throw UserFriendlyException.SameMessage("无效数据"); model.PhoneNum = dto.PhoneNum; model.Name = dto.Name; await _externalCitizensRepository.UpdateAsync(model, HttpContext.RequestAborted); } #endregion #region 工单期满时间、来源方式修改 /// /// 修改期满时间 /// /// /// [HttpPost("update-orderexpired-time")] public async Task UpdateOrderExpiredTime([FromBody] UpdateOrderExpiredTimeDto dto) { if (dto == null || string.IsNullOrEmpty(dto.Id) || !dto.ExpiredTime.HasValue) throw UserFriendlyException.SameMessage("参数信息有误!"); var orderData = await _orderRepository.GetAsync(p => p.Id == dto.Id, HttpContext.RequestAborted); if (orderData == null) throw UserFriendlyException.SameMessage("工单查询失败!"); #region 写入操作记录 OrderModifyingRecords orderModifyingRecords = new() { OrderId = orderData.Id, OrderNo = orderData.No, ProvinceNo = orderData.ProvinceNo, UpdateOrderType = EUpdateType.ExpiredTime, OldValue = orderData.ExpiredTime == null ? "" : orderData.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss"), NewValue = dto.ExpiredTime.Value.ToString("yyyy-MM-dd HH:mm:ss") }; await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted); #endregion //写入新的数据 orderData.ExpiredTime = dto.ExpiredTime; await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted); //向省上推送数据 if (dto.IsPush && orderData.Status > EOrderStatus.WaitForAccept) { var orderDto = _mapper.Map(orderData); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); } } /// /// 修改来源方式 /// /// /// [HttpPost("update-order-sourcechannel")] [AllowAnonymous] public async Task UpdateOrderSourceChannel([FromBody] UpdateOrderSourceChannelDto dto) { if (dto == null || dto.Ids == null || dto.Ids.Count == 0) throw UserFriendlyException.SameMessage("参数信息有误!"); foreach (var item in dto.Ids) { var orderData = await _orderRepository.GetAsync(p => p.Id == item || p.ProvinceNo == item, HttpContext.RequestAborted); if (orderData != null) { #region 写入操作记录 OrderModifyingRecords orderModifyingRecords = new() { OrderId = orderData.Id, OrderNo = orderData.No, ProvinceNo = orderData.ProvinceNo, UpdateOrderType = EUpdateType.SourceChannel, OldValue = orderData.SourceChannelCode + "_" + orderData.SourceChannel, NewValue = "QT_其他" }; await _orderModifyingRecordsRepository.AddAsync(orderModifyingRecords, HttpContext.RequestAborted); #endregion orderData.SourceChannel = "其他"; orderData.SourceChannelCode = "QT"; // await _orderRepository.UpdateAsync(orderData, HttpContext.RequestAborted); //向省上推送数据 if (dto.IsPush) { var orderDto = _mapper.Map(orderData); await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.HotlineOrderExpiredTimeUpdate, orderDto, cancellationToken: HttpContext.RequestAborted); } } } } /// /// 根据工单ID获取修改记录 /// /// [HttpGet("get-order-modifying-records-list")] public async Task> GetOrderModifyingRecordsList([FromQuery] string Id) { var list = await _orderModifyingRecordsRepository.Queryable().Where(p => p.OrderId == Id).OrderByDescending(p => p.CreationTime) .ToListAsync(); return _mapper.Map>(list); } /// /// 获取修改记录 /// /// [HttpGet("get-order-modifying-records-all-list")] public async Task> GetOrderModifyingRecordsAllList([FromQuery] OrderModifyingRecordsRequest dto) { var list = await _orderModifyingRecordsRepository.Queryable() .WhereIF(dto.StartTime.HasValue, p => p.CreationTime >= dto.StartTime) .WhereIF(dto.EndTime.HasValue, p => p.CreationTime <= dto.EndTime) .WhereIF(!string.IsNullOrEmpty(dto.OrderNo), p => p.OrderNo.Contains(dto.OrderNo)) .WhereIF(!string.IsNullOrEmpty(dto.ProvinceNo), p => p.ProvinceNo.Contains(dto.ProvinceNo)) .WhereIF(dto.UpdateOrderType == "0", p => p.UpdateOrderType == EUpdateType.ExpiredTime) .WhereIF(dto.UpdateOrderType == "1", p => p.UpdateOrderType == EUpdateType.SourceChannel) .OrderByDescending(p => p.CreationTime) .ToListAsync(); return _mapper.Map>(list); } #endregion #region 工单平移 /// /// 查询工单平移待办理人 /// /// [HttpGet("migration/{orderId}")] public async Task Migration(string orderId) { var order = await _orderRepository.GetAsync(orderId, HttpContext.RequestAborted); var step = new WorkflowStep(); var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi); if (string.IsNullOrEmpty(order.SignerId)) throw UserFriendlyException.SameMessage("工单尚未签收,暂不支持平移"); if (!string.IsNullOrEmpty(order.WorkflowId)) { var steps = await _workflowStepRepository.Queryable() .Where(d => d.ExternalId == orderId && d.Status != EWorkflowStepStatus.Handled) .ToListAsync(HttpContext.RequestAborted); if (steps.Count > 1) throw UserFriendlyException.SameMessage("多个待办理节点暂不支持平移"); step = steps.First(); if (step.BusinessType is not EBusinessType.Seat and not EBusinessType.Send) throw UserFriendlyException.SameMessage("当前办理节点非中心暂不支持平移"); setting = step.BusinessType is EBusinessType.Seat ? _systemSettingCacheManager.GetSetting(SettingConstants.RoleZuoXi) : _systemSettingCacheManager.GetSetting(SettingConstants.RolePaiDan); } var roles = setting?.SettingValue.ToList(); var users = await _userRepository.Queryable() .Includes(d => d.Organization) .Includes(d => d.Roles) .Where(d => d.Roles.Any(x => roles.Contains(x.Name))) .ToListAsync(HttpContext.RequestAborted); return new GetOrderMigrationDto { StepId = step.Id, OrderId = orderId, Handlers = users.Select(d => new OrderMigrationHandler { UserId = d.Id, Username = d.Name, OrgId = d.OrgId, OrgName = d.Organization.Name, RoleNames = string.Join(',', d.Roles.Select(x => x.DisplayName).ToList()) }).ToList() }; } /// /// 工单平移 /// [HttpPost("change-handler")] public async Task ChangeHandler([FromBody] ChangeHandlerDto dto) { var special = await _orderSpecialRepository.Queryable().Where(x => x.OrderId == dto.OrderId && x.State == 0).AnyAsync(); if (special) throw UserFriendlyException.SameMessage("当前工单特提审批中,请审批后再操作!"); if (string.IsNullOrEmpty(dto.StepId)) { await _orderRepository.Updateable() .SetColumns(o => new Orders.Order() { SignerId = dto.Handler.UserId, SignerName = dto.Handler.Username, Status = EOrderStatus.HandOverToUnAccept }) .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } else { var step = await _workflowStepRepository.Queryable() .Includes(d => d.WorkflowTrace) .FirstAsync(d => d.Id == dto.StepId, HttpContext.RequestAborted); if (step is null) throw UserFriendlyException.SameMessage("无效节点编号"); await _workflowDomainService.ChangeHandlerBatchAsync( new List<(string userId, string username, string orgId, string orgName, string? roleId, string? roleName, ICollection steps)> { new(dto.Handler.UserId, dto.Handler.Username, dto.Handler.OrgId, dto.Handler.OrgName, step.RoleId, step.RoleName, new List { step }) }, HttpContext.RequestAborted); var status = EOrderStatus.HandOver; if (step.BusinessType == EBusinessType.Seat && step.StepType == EStepType.Start) { status = EOrderStatus.HandOverToUnAccept; await _orderRepository.Updateable() .SetColumns(o => new Orders.Order() { Status = status, SignerId = dto.Handler.UserId }) .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } else if (step.BusinessType == EBusinessType.Send) { await _orderRepository.Updateable() .SetColumns(o => new Orders.Order() { Status = status, CenterToOrgHandlerId = dto.Handler.UserId, CenterToOrgHandlerName = dto.Handler.Username }) .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } else { await _orderRepository.Updateable() .SetColumns(o => new Orders.Order() { Status = status }) .Where(o => o.Id == dto.OrderId).ExecuteCommandAsync(HttpContext.RequestAborted); } } } #endregion #region 分析报告 /// /// 新增分析报告 /// /// /// [HttpPost("analysis")] [LogFilter("新增分析报告")] public async Task OrderAnalysisAdd([FromBody] AddOrderAnalysisDto dto) { await _orderAnalysisApplication.AddAsync(dto, HttpContext.RequestAborted); } /// /// 修改分析报告 /// /// /// [HttpPut("analysis")] [LogFilter("修改分析报告")] public async Task OrderAnalysisUpdate([FromBody] UpdateOrderAnalysisDto dto) { await _orderAnalysisApplication.UpdateAsync(dto, HttpContext.RequestAborted); } /// /// 删除分析报告 /// /// /// [HttpDelete("analysis")] [LogFilter("删除分析报告")] public async Task OrderAnalysisDelete([FromBody] DeleteOrderAnalysisDto dto) { await _orderAnalysisApplication.DeleteAsync(dto, HttpContext.RequestAborted); } /// /// 分析报告列表 /// /// /// [HttpGet("analysis_list")] [LogFilter("分析报告列表")] public async Task> OrderAnalysisListQuery([FromQuery] OrderAnalysisListDto dto) { var (total, items) = await _orderAnalysisApplication.ListQuery(dto, HttpContext.RequestAborted) .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, items); } /// /// 分析报告明细 /// /// /// [HttpGet("analysis_detail")] [LogFilter("分析报告明细")] public async Task> OrderAnalysisDetailQuery([FromQuery] OrderAnalysisDetailDto dto) { var (total, items) = await _orderAnalysisApplication.DetailQuery(dto, HttpContext.RequestAborted) .ToPagedListAsync(dto, HttpContext.RequestAborted); return new PagedDto(total, _mapper.Map>(items)); } /// /// 生成分析报告 /// /// /// [HttpGet("analysis_report")] [LogFilter("生成分析报告")] public async Task OrderAnalysisReportQuery([FromQuery] OrderAnalysisDetailDto dto) { return await _orderAnalysisApplication.ReportQuery(dto, HttpContext.RequestAborted); } #endregion }