Browse Source

Merge branch 'master' of http://git.fway.com.cn/Fengwo/hotline

田爽 1 year ago
parent
commit
c39b5b91e0

+ 92 - 27
src/Hotline.Api/Controllers/OrderController.cs

@@ -62,6 +62,7 @@ public class OrderController : BaseController
     private readonly IRepository<OrderUrge> _orderUrgeRepository;
     private readonly IFileRepository _fileRepository;
     private readonly IRepository<OrderScreen> _orderScreenRepository;
+    private readonly IRepository<OrderPublishHistory> _orderPublishHistoryRepository;
 
 
     public OrderController(
@@ -84,11 +85,12 @@ public class OrderController : BaseController
         IRepository<OrderDelay> orderDelayRepository,
         ITimeLimitApplication timeLimitApplication,
         ISystemSettingCacheManager systemSettingCacheManager,
-         IRepository<OrderRedo> orderRedoRepository,
-         IRepository<OrderSupervise> orderSuperviseRepository,
-         IRepository<OrderUrge> orderUrgeRepository,
+        IRepository<OrderRedo> orderRedoRepository,
+        IRepository<OrderSupervise> orderSuperviseRepository,
+        IRepository<OrderUrge> orderUrgeRepository,
         IFileRepository fileRepository,
-        IRepository<OrderScreen> orderScreenRepository
+        IRepository<OrderScreen> orderScreenRepository,
+        IRepository<OrderPublishHistory> orderPublishHistoryRepository
         )
     {
         _orderDomainService = orderDomainService;
@@ -115,6 +117,7 @@ public class OrderController : BaseController
         _orderUrgeRepository = orderUrgeRepository;
         _fileRepository = fileRepository;
         _orderScreenRepository = orderScreenRepository;
+        _orderPublishHistoryRepository = orderPublishHistoryRepository;
 
     }
 
@@ -182,7 +185,7 @@ public class OrderController : BaseController
 
         var orderVisit = new OrderVisit();
         orderVisit.No = order.No;
-        orderVisit.OrderId = id;
+        orderVisit.OrderId = order.Id;
         orderVisit.VisitState = EVisitState.WaitForVisit;
         orderVisit.PublishTime = DateTime.Now;
         string visitId = await _orderVisitRepository.AddAsync(orderVisit);
@@ -278,10 +281,10 @@ public class OrderController : BaseController
             throw UserFriendlyException.SameMessage("未知数据!");
         }
         var pubentity = _mapper.Map<PublishedEntityDto>(publishedOrder);
-        var visit = await _orderVisitRepository.Queryable().Includes(x => x.VisitDetails).FirstAsync(x => x.Id == publishedOrder.OrderId, HttpContext.RequestAborted);
+        var visit = await _orderVisitRepository.Queryable().Includes(x => x.OrderVisitDetails).FirstAsync(x => x.Id == publishedOrder.OrderId, HttpContext.RequestAborted);
         if (visit!=null)
         {
-            var details = visit.VisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList();
+            var details = visit.OrderVisitDetails.Where(x => x.VisitTarget == EVisitTarget.Org).ToList();
             if (details!=null && details.Count>0)
             {
                 pubentity.IdNames = new List<IdName>();
@@ -291,7 +294,53 @@ public class OrderController : BaseController
         return pubentity;
     }
 
+    /// <summary>
+    /// 修改发布内容
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.PublishedModify)]
+    [HttpPost("published-order-modify")]
+    public async Task PublishedModify([FromBody]PublishOrderModifyDto dto)
+    {
+        var publishOrder = await _orderPublishRepository.GetAsync(dto.Id, 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.No = publishOrder.No;
+        history.OrderId = publishOrder.OrderId;
+        history.OrderPublishId = publishOrder.Id;
 
+
+        publishOrder.ArrangeTitle = dto.ArrangeTitle;
+        publishOrder.ArrangeContent = dto.ArrangeContent;
+        publishOrder.ArrangeOpinion = dto.ArrangeOpinion;
+
+        await _orderPublishRepository.UpdateAsync(publishOrder, HttpContext.RequestAborted);
+        await _orderPublishHistoryRepository.AddAsync(history, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 发布修改记录
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [Permission(EPermission.QueryPublishedHistory)]
+    [HttpGet("published-history-list/{id}")]
+    public async Task<List<OrderPublishHistory>> QueryPublishedHistory(string id)
+    {
+        return  await _orderPublishHistoryRepository.Queryable().Where(x => x.OrderPublishId == id).OrderByDescending(x=>x.CreationTime).ToListAsync(HttpContext.RequestAborted);
+    }
     #endregion
 
     #region 工单回访
@@ -303,17 +352,18 @@ public class OrderController : BaseController
     /// <returns></returns>
     [Permission(EPermission.QueryOrderVisitList)]
     [HttpGet("visit")]
-    public async Task<PagedDto<OrderVisit>> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto)
+    public async Task<PagedDto<OrderVisitDto>> QueryOrderVisitList([FromQuery] QueryOrderVisitDto dto)
     {
         var (total, items) = await _orderVisitRepository.Queryable()
             .Includes(x => x.Order)
             .Includes(x => x.Employee)
+            .Includes(x => x.OrderVisitDetails)
             .WhereIF(dto.VisitState == EVisitStateQuery.NoVisit, x => x.VisitState == Share.Enums.Order.EVisitState.WaitForVisit || x.VisitState == Share.Enums.Order.EVisitState.NoSatisfiedWaitForVisit)
             .WhereIF(dto.VisitState == EVisitStateQuery.Visited, x => x.VisitState == Share.Enums.Order.EVisitState.Visited)
             .WhereIF(!string.IsNullOrEmpty(dto.Keyword), d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
             .OrderBy(x => x.CreationTime)
             .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-        return new PagedDto<OrderVisit>(total, _mapper.Map<IReadOnlyList<OrderVisit>>(items));
+        return new PagedDto<OrderVisitDto>(total, _mapper.Map<IReadOnlyList<OrderVisitDto>>(items));
     }
 
     /// <summary>
@@ -327,6 +377,7 @@ public class OrderController : BaseController
         var orderVisit = await _orderVisitRepository.Queryable()
            .Includes(x => x.Order)
            .Includes(x => x.Employee)
+           .Includes(x=>x.OrderVisitDetails)
            .FirstAsync(x => x.Id == id, HttpContext.RequestAborted);
 
         if (orderVisit is null)
@@ -336,11 +387,13 @@ public class OrderController : BaseController
 
         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<EVoiceEvaluate>();
+        var seatEvaluate = EnumExts.GetDescriptions<ESeatEvaluate>();
         var visitSatisfaction = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitSatisfaction);
         var dissatisfiedReason = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.DissatisfiedReason);
         var visitManner = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.VisitManner);
 
-        return new { OrderVisitModel = orderVisit, VisitCount = visitCount, AgainCount = againCount, VisitSatisfaction = visitSatisfaction, DissatisfiedReason = dissatisfiedReason, VisitManner = visitManner };
+        return new { OrderVisitModel = orderVisit, VisitCount = visitCount, AgainCount = againCount, VisitSatisfaction = visitSatisfaction, DissatisfiedReason = dissatisfiedReason, VisitManner = visitManner,ViceEvaluate= voiceEvaluate, SeatEvaluate = seatEvaluate };
     }
 
     /// <summary>
@@ -375,36 +428,48 @@ public class OrderController : BaseController
         //var visit = await _orderVisitRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
         var visit = await _orderVisitRepository.Queryable()
             .Includes(d => d.Order)
+            .Includes(d => d.OrderVisitDetails)
             .FirstAsync(d => d.Id == dto.Id, HttpContext.RequestAborted);
         if (visit is null)
             throw UserFriendlyException.SameMessage("未知回访信息");
 
-        var first = dto.VisitDetails.First(x => x.VisitTarget == EVisitTarget.Org);
+        var first = dto.VisitDetails.FirstOrDefault(x => x.VisitTarget == EVisitTarget.Org);
 
 
         //更新主表
-        visit.VisitState = Share.Enums.Order.EVisitState.Visited;
-        visit.VisitTime = DateTime.Now;
+        if (dto.IsPutThrough)
+        {
+            visit.VisitState = Share.Enums.Order.EVisitState.Visited;
+            visit.VisitTime = DateTime.Now;
+            visit.VisitType = EVisitType.ArtificialVisit;
+        }
         visit.IsPutThrough = dto.IsPutThrough;
         visit.AgainState = dto.IsAgain ? EAgainState.NeedAgain : EAgainState.NoAgain;
         visit.EmployeeId = _sessionContext.UserId;
-        visit.NowEvaluate = first.OrgProcessingResults;
+        if (first!=null)
+        {
+            visit.NowEvaluate = first.OrgProcessingResults;
+        }
         //await _orderVisitRepository.UpdateAsync(visit,HttpContext.RequestAborted);
 
         //update order
-        visit.Order.Visited(first.OrgProcessingResults.Id, first.OrgProcessingResults.Name);
-
-        //更新明細
-        //var visitDetails = _mapper.Map <List<OrderVisitDetail>>(dto.VisitDetails); 
-        //await _orderVisitedDetailRepository.UpdateRangeAsync(visitDetails, HttpContext.RequestAborted);
-        visit.VisitDetails = _mapper.Map<List<OrderVisitDetail>>(dto.VisitDetails);
-
-        _orderVisitRepository.UpdateNav(visit);
-
-        var orderDto = _mapper.Map<OrderDto>(visit.Order);
-
-        //推省上
-        _capPublisher.Publish(EventNames.HotlineOrderVisited, new PublishVisitDto() { Order = orderDto, No = visit.No, VisitType = visit.VisitType, VisitName = visit.Employee.Name, VisitTime = visit.VisitTime, VisitRemark = first.VisitContent, AreaCode = visit.Order.AreaCode!, SubjectResultSatifyCode = first.OrgProcessingResults.Id, FirstSatisfactionCode = visit.Order.FirstVisitResultCode!, ClientGuid = "" });
+        if (dto.IsPutThrough)
+        {
+            if (first!=null)
+            {
+                visit.Order.Visited(first.OrgProcessingResults.Id, first.OrgProcessingResults.Name);
+            }
+            _mapper.Map(dto.VisitDetails,visit.OrderVisitDetails);
+            await _orderVisitRepository.UpdateAsync(visit,HttpContext.RequestAborted);
+            await _orderVisitedDetailRepository.UpdateRangeAsync(visit.OrderVisitDetails, HttpContext.RequestAborted);
+            await _orderRepository.UpdateAsync(visit.Order, HttpContext.RequestAborted);
+            var orderDto = _mapper.Map<OrderDto>(visit.Order);
+            if (first!=null)
+            {
+                //推省上
+                _capPublisher.Publish(EventNames.HotlineOrderVisited, new PublishVisitDto() { Order = orderDto, No = visit.No, VisitType = visit.VisitType, VisitName = visit.CreatorName, VisitTime = visit.VisitTime, VisitRemark = first.VisitContent, AreaCode = visit.Order.AreaCode!, SubjectResultSatifyCode = first.OrgProcessingResults.Id, FirstSatisfactionCode = visit.Order.FirstVisitResultCode!, ClientGuid = "" });
+            }
+        }
     }
 
     #endregion

+ 12 - 5
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -38,6 +38,7 @@ public class WorkflowController : BaseController
     private readonly IWfModuleDomainService _wfModuleDomainService;
     private readonly IRepository<WorkflowModule> _wfModuleRepository;
     private readonly ISessionContext _sessionContext;
+    private IRepository<WorkflowTrace> _workflowTraceRepository;
     private readonly IMapper _mapper;
 
     public WorkflowController(
@@ -53,7 +54,9 @@ public class WorkflowController : BaseController
         IWfModuleDomainService wfModuleDomainService,
         IRepository<WorkflowModule> wfModuleRepository,
         ISessionContext sessionContext,
-        IMapper mapper)
+        IRepository<WorkflowTrace> workflowTraceRepository,
+        IMapper mapper
+        )
     {
         _definitionDomainService = definitionDomainService;
         _definitionRepository = definitionRepository;
@@ -68,6 +71,7 @@ public class WorkflowController : BaseController
         _wfModuleRepository = wfModuleRepository;
         _sessionContext = sessionContext;
         _mapper = mapper;
+        _workflowTraceRepository = workflowTraceRepository;
     }
 
     /// <summary>
@@ -449,9 +453,12 @@ public class WorkflowController : BaseController
     [HttpGet("{workflowId}/traces")]
     public async Task<WorkflowDto> GetWorkflowTraces(string workflowId)
     {
-        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, withTraces: true,
-            cancellationToken: HttpContext.RequestAborted);
-        workflow.Traces = workflow.Traces.Where(d => !string.IsNullOrEmpty(d.AcceptUserId)).ToList();
+        var workflow = await _workflowDomainService.GetWorkflowAsync(workflowId, cancellationToken: HttpContext.RequestAborted);
+        workflow.Traces = await _workflowTraceRepository.Queryable()
+                .Where(d => d.WorkflowId == workflow.Id && !string.IsNullOrEmpty(d.AcceptUserId))
+                .OrderBy(d => d.CreationTime)
+                .ToTreeAsync(d => d.Traces, d => d.ParentId, null);
+
         return _mapper.Map<WorkflowDto>(workflow);
     }
 
@@ -499,7 +506,7 @@ public class WorkflowController : BaseController
                 orgs.Add(new IdName(orgCode, orgName));
             }
         }
-        return orgs.DistinctBy(d=>d.Id).ToList();
+        return orgs.DistinctBy(d => d.Id).ToList();
     }
 
     [HttpGet("base-data")]

+ 19 - 7
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -248,19 +248,31 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
                 //当前操作人所属部门的下级部门并且属于配置orgLevel的部门
                 var levels = stepDefine.HandlerClassifies.Select(d => d.Id).Select(d => int.Parse(d));
                 var levelOneOrg = _sessionContext.RequiredOrgCode.GetUpperOrgCode();
-                var orgs1 = await _organizeRepository.QueryAsync(d =>
-                    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg) &&
-                    levels.Contains(d.OrgLevel));
+                //var orgs1 = await _organizeRepository.QueryAsync(d =>
+                //    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg) &&
+                //    levels.Contains(d.OrgLevel));
+
+                var orgs1 = await _organizeRepository.Queryable()
+                    .Where(d => d.IsEnable && levels.Contains(d.OrgLevel))
+                    .WhereIF(!levelOneOrg.IsCenter(), d => d.OrgCode.StartsWith(levelOneOrg))
+                    .ToListAsync(cancellationToken);
+
                 handlers = orgs1.Select(d => new IdName(d.OrgCode, d.OrgName)).ToList();
                 break;
             case EHandlerType.OrgType:
                 var types = stepDefine.HandlerClassifies.Select(d => d.Id)
                     .Select(d => Enum.Parse<EOrgType>(d));
                 var levelOneOrg1 = _sessionContext.RequiredOrgCode.GetUpperOrgCode();
-                var org2 = await _organizeRepository.QueryAsync(d =>
-                    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg1) &&
-                    types.Contains(d.OrgType));
-                handlers = org2.Select(d => new IdName(d.OrgCode, d.OrgName)).ToList();
+                //var org2 = await _organizeRepository.QueryAsync(d =>
+                //    d.IsEnable && d.OrgCode.StartsWith(levelOneOrg1) &&
+                //    types.Contains(d.OrgType));
+
+                var orgs2 = await _organizeRepository.Queryable()
+                .Where(d => d.IsEnable && types.Contains(d.OrgType))
+                    .WhereIF(!levelOneOrg1.IsCenter(), d => d.OrgCode.StartsWith(levelOneOrg1))
+                    .ToListAsync(cancellationToken);
+
+                handlers = orgs2.Select(d => new IdName(d.OrgCode, d.OrgName)).ToList();
                 break;
             default:
                 throw new ArgumentOutOfRangeException();

+ 7 - 0
src/Hotline.Application/Mappers/OrderMapperConfigs.cs

@@ -83,5 +83,12 @@ public class OrderMapperConfigs : IRegister
         config.ForType<Order, OrderWaitedDto>()
             .Inherits<Order, OrderDto>();
 
+        config.ForType<OrderVisit, OrderVisitDto>()
+            .IgnoreIf((s, d) => s.Employee == null, d => d.EmployeeName)
+            .Map(d => d.EmployeeName, s => s.Employee.Name);
+
+        config.ForType<VisitDetailDto, OrderVisitDetail>()
+            .Map(d => d.VoiceEvaluate, s => s.VoiceEvaluate)
+            .Map(d => d.SeatEvaluate, s => s.SeatEvaluate);
     }
 }

+ 6 - 0
src/Hotline.Share/Dtos/FlowEngine/WorkflowStepDto.cs

@@ -39,6 +39,12 @@ public class WorkflowStepDto
 
     public EWorkflowStepStatus Status { get; set; }
 
+    /// <summary>
+    /// 被指派办理对象(依据不同指派方式可能为:orgCode或userId),该字段subStep才会存在,stepBox不存在
+    /// 采用list类型,兼容多个办理对象可以办理同一个节点的场景
+    /// </summary>
+    public List<IdName> Handlers { get; set; } = new();
+
     #region 办理参数
 
     /// <summary>

+ 92 - 0
src/Hotline.Share/Dtos/Order/OrderDto.cs

@@ -693,6 +693,98 @@ namespace Hotline.Share.Dtos.Order
     }
 
 
+    public class PublishOrderModifyDto
+    {
+        /// <summary>
+        /// 发布ID
+        /// </summary>
+        public string Id { get; set; }
+
+
+        /// <summary>
+        /// 整理标题
+        /// </summary>
+        public string ArrangeTitle { get; set; }
+
+        /// <summary>
+        /// 整理内容
+        /// </summary>
+        public string ArrangeContent { get; set; }
+
+        /// <summary>
+        /// 整理结果
+        /// </summary>
+        public string ArrangeOpinion { get; set; }
+    }
+
+
+    public class OrderVisitDto
+    {
+        public string Id { get; set; }
+
+        public OrderDto Order { get; set; }
+
+        /// <summary>
+        /// 回访状态
+        /// </summary>
+        public EVisitState VisitState { get; set; }
+
+        public string VisitStateText => VisitState.GetDescription();
+
+        /// <summary>
+        /// 回访方式
+        /// </summary>
+        public EVisitType? VisitType { get; set; }
+
+        public string VisitTypeText => VisitType?.GetDescription()??string.Empty;
+
+
+        /// <summary>
+        /// 发布时间
+        /// </summary>
+        public DateTime PublishTime { get; set; }
+
+        /// <summary>
+        /// 回访人
+        /// </summary>
+        public string? EmployeeId { get; set; }
+
+        public string? EmployeeName { get; set; }
+
+        public string CreationTime { get; set; }
+
+        /// <summary>
+        /// 是否接通
+        /// </summary>
+        public bool? IsPutThrough { get; set; }
+
+        /// <summary>
+        /// 重办状态
+        /// </summary>
+        public EAgainState? AgainState { get; set; }
+
+        public string AgainStateText => AgainState?.GetDescription()??string.Empty;
+
+        /// <summary>
+        /// 回访时间
+        /// </summary>
+        public DateTime? VisitTime { get; set; }
+
+        /// <summary>
+        /// 回访明细
+        /// </summary>
+        public List<OrderVisitDetailDto> OrderVisitDetails { get; set; }
+    }
+
+    public class OrderVisitDetailDto
+    {
+        public EVoiceEvaluate? VoiceEvaluate { get; set; }
+
+        public ESeatEvaluate? SeatEvaluate { get; set; }
+
+        public EVisitTarget VisitTarget { get; set; }
+    }
+
     public class PublishVisitDto
     {
         /// <summary>

+ 8 - 8
src/Hotline.Share/Dtos/Order/QueryOrderDto.cs

@@ -174,7 +174,7 @@ namespace Hotline.Share.Dtos.Order
         /// 语音评价(话务评价)
         /// </summary>
         public EVoiceEvaluate? VoiceEvaluate { get; set; }
-
+                               
         /// <summary>
         /// 话务员评价(话务评价)
         /// </summary>
@@ -183,37 +183,37 @@ namespace Hotline.Share.Dtos.Order
         /// <summary>
         /// 部门办件结果
         /// </summary>
-        public IdName OrgProcessingResults { get; set; }
+        public IdName? OrgProcessingResults { get; set; }
 
         /// <summary>
         /// 不满意原因
         /// </summary>
-        public IdName OrgNoSatisfiedReason { get; set; }
+        public IdName? OrgNoSatisfiedReason { get; set; }
 
         /// <summary>
         /// 部门办件态度
         /// </summary>
-        public IdName OrgHandledAttitude { get; set; }
+        public IdName? OrgHandledAttitude { get; set; }
 
         /// <summary>
         /// 回访内容
         /// </summary>
-        public string VisitContent { get; set; }
+        public string? VisitContent { get; set; }
 
         /// <summary>
         /// 回访部门名称
         /// </summary>
-        public string VisitOrgName { get; set; }
+        public string? VisitOrgName { get; set; }
 
         /// <summary>
         /// 回访部门Code
         /// </summary>
-        public string VisitOrgCode { get; set; }
+        public string? VisitOrgCode { get; set; }
 
         /// <summary>
         /// 回访对象类型 10:话务员 20:部门
         /// </summary>
-        public EVisitTarget VisitTarget { get; set; }
+        public EVisitTarget? VisitTarget { get; set; }
     }
 
     public record QueryOrderRedoRecordDto: PagedKeywordRequest

+ 1 - 1
src/Hotline.Share/Hotline.Share.csproj

@@ -7,7 +7,7 @@
     <GenerateDocumentationFile>True</GenerateDocumentationFile>
     <NoWarn>$(NoWarn);1591;8618;</NoWarn>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-    <Version>1.0.16</Version>
+    <Version>1.0.17</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 7 - 0
src/Hotline/FlowEngine/Workflows/StepBasicEntity.cs

@@ -45,6 +45,13 @@ public abstract class StepBasicEntity : CreationEntity
     /// </summary>
     public ECountersignMode CountersignMode { get; set; }
 
+    /// <summary>
+    /// 被指派办理对象(依据不同指派方式可能为:orgCode或userId),该字段subStep才会存在,stepBox不存在
+    /// 采用list类型,兼容多个办理对象可以办理同一个节点的场景
+    /// </summary>
+    [SugarColumn(ColumnDataType = "json", IsJson = true)]
+    public List<IdName> Handlers { get; set; } = new();
+
     #region 办理参数
 
     /// <summary>

+ 0 - 7
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -9,13 +9,6 @@ public class WorkflowStep : StepBasicEntity
     [SugarColumn(ColumnDataType = "json", IsJson = true)]
     public List<NextStep> NextSteps { get; set; }
 
-    /// <summary>
-    /// 被指派办理对象(依据不同指派方式可能为:orgCode或userId),该字段subStep才会存在,stepBox不存在
-    /// 采用list类型,兼容多个办理对象可以办理同一个节点的场景
-    /// </summary>
-    [SugarColumn(ColumnDataType = "json", IsJson = true)]
-    public List<IdName> Handlers { get; set; } = new();
-
     /// <summary>
     /// 前一级节点Id(stepBox此字段为上级stepBoxId,step为上级stepId),汇总节点无此字段(因可能有多个上级来源)
     /// </summary>

+ 1 - 1
src/Hotline/Orders/OrderDomainService.cs

@@ -121,7 +121,7 @@ public class OrderDomainService : IOrderDomainService, IScopeDependency
 
         if (order.OrderVisits.Any())
             await _orderVisitRepository.RemoveNav(order.OrderVisits)
-                .Include(d => d.VisitDetails)
+                .Include(d => d.OrderVisitDetails)
                 .ExecuteCommandAsync();
     }
 

+ 1 - 0
src/Hotline/Orders/OrderPublish.cs

@@ -36,6 +36,7 @@ public class OrderPublish : CreationEntity
     /// <summary>
     /// 整理结果
     /// </summary>
+    [SugarColumn(ColumnDataType = "varchar(2000)")]
     public string ArrangeOpinion { get; set; }
 
     /// <summary>

+ 64 - 0
src/Hotline/Orders/OrderPublishHistory.cs

@@ -0,0 +1,64 @@
+using SqlSugar;
+using XF.Domain.Repository;
+
+namespace Hotline.Orders
+{
+    public class OrderPublishHistory: CreationEntity
+    {
+        /// <summary>
+        /// 工单编号(冗余)
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 工单ID
+        /// </summary>
+        public string OrderId { get; set; }
+
+        /// <summary>
+        /// 发布ID
+        /// </summary>
+        public string OrderPublishId { get; set; }
+
+        /// <summary>
+        /// 工单
+        /// </summary>
+        [Navigate(NavigateType.OneToOne, nameof(OrderId))]
+        public Order Order { get; set; }
+
+        /// <summary>
+        /// 整改标题修改前
+        /// </summary>
+        public string ArrangeTitleBefor { get; set; }
+
+        /// <summary>
+        /// 整理标题修改后
+        /// </summary>
+        public string ArrangeTitleAfter { get; set; }
+
+        /// <summary>
+        /// 整理内容修改前
+        /// </summary>
+        [SugarColumn(ColumnDataType = "varchar(2000)")]
+        public string ArrangeContentBefor { get; set; }
+        
+        /// <summary>
+        /// 整理内容修改后
+        /// </summary>
+        [SugarColumn(ColumnDataType = "varchar(2000)")]
+        public string ArrangeContentAfter { get; set; }
+
+        /// <summary>
+        /// 整理结果修改前
+        /// </summary>
+        [SugarColumn(ColumnDataType = "varchar(2000)")]
+        public string ArrangeOpinionBefor { get; set; }
+
+        /// <summary>
+        /// 整理结果修改后
+        /// </summary>
+        [SugarColumn(ColumnDataType = "varchar(2000)")]
+        public string ArrangeOpinionAfter { get; set; }
+
+    }
+}

+ 1 - 1
src/Hotline/Orders/OrderVisit.cs

@@ -79,7 +79,7 @@ public class OrderVisit : CreationEntity
     /// 回访明细
     /// </summary>
     [Navigate(NavigateType.OneToMany, nameof(OrderVisitDetail.VisitId))]
-    public List<OrderVisitDetail> VisitDetails { get; set; }
+    public List<OrderVisitDetail> OrderVisitDetails { get; set; }
 
     /// <summary>
     /// 当前评价结果

+ 14 - 0
src/Hotline/Permissions/EPermission.cs

@@ -900,6 +900,19 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName = "OrderPublish",Name ="发布详情",Description = "发布详情")]
         PublishedOrder = 500204,
+
+        /// <summary>
+        /// 修改发布
+        /// </summary>
+        [Display(GroupName = "OrderPublish",Name ="修改发布",Description ="修改发布")]
+        PublishedModify = 500205,
+
+        /// <summary>
+        /// 修改记录
+        /// </summary>
+        [Display(GroupName = "OrderPublish",Name = "修改记录",Description ="修改记录")]
+        QueryPublishedHistory = 500206,
+
         #endregion
 
         #region 工单回访管理
@@ -927,6 +940,7 @@ namespace Hotline.Permissions
         /// </summary>
         [Display(GroupName = "OrderVisit",Name = "回访", Description = "回访")]
         Visit = 500303,
+
         #endregion
 
         #region 工单重办管理

+ 4 - 4
src/Hotline/SeedData/OrgSeedData.cs

@@ -6,17 +6,17 @@ namespace Hotline.SeedData
 {
     public class OrgSeedData : ISeedData<SystemOrganize>
     {
-        public static readonly string CallCenterId = "08dac6ae-3096-4156-828e-b34e9c1fb5da";
-        public static readonly string CallCenterCode = "001";
+        public static readonly string CenterId = "08dac6ae-3096-4156-828e-b34e9c1fb5da";
+        public static readonly string CenterCode = "001";
 
         public IEnumerable<SystemOrganize> HasData() =>
         new[]
         {
             new SystemOrganize
             {
-                Id = CallCenterId,
+                Id = CenterId,
                 OrgName = "12345政务服务便民热线",
-                OrgCode = CallCenterCode,
+                OrgCode = CenterCode,
                 OrgLevel = 0,
                 IsEnable = true,
             }

+ 2 - 2
src/Hotline/SeedData/UserSeedData.cs

@@ -16,8 +16,8 @@ public class UserSeedData : ISeedData<User>
             {
                 Id = SysAccountSeedData.Id,
                 Name = "系统管理员",
-                OrgId = OrgSeedData.CallCenterId,
-                OrgCode = OrgSeedData.CallCenterCode
+                OrgId = OrgSeedData.CenterId,
+                OrgCode = OrgSeedData.CenterCode
             }
         };
 }

+ 17 - 2
src/Hotline/Settings/SystemOrganize.cs

@@ -89,7 +89,7 @@ public static class OrgExtensions
     public static bool CheckIfOrgLevelIs(this string orgCode, int orgLevel)
     {
         ////中心算做一级部门
-        //if (orgLevel == 1 && orgCode == OrgSeedData.CallCenterCode)
+        //if (orgLevel == 1 && orgCode == OrgSeedData.CenterCode)
         //    return true;
 
         var level = orgCode.CalcOrgLevel();
@@ -107,7 +107,7 @@ public static class OrgExtensions
         if (string.IsNullOrEmpty(orgCode))
             throw UserFriendlyException.SameMessage("无效部门编码");
         ////中心算做一级部门
-        //if (orgLevel == 1 && orgCode == OrgSeedData.CallCenterCode) return orgCode;
+        //if (orgLevel == 1 && orgCode == OrgSeedData.CenterCode) return orgCode;
 
         return orgCode.Substring(0, 3 * orgLevel);
     }
@@ -121,4 +121,19 @@ public static class OrgExtensions
             throw new UserFriendlyException("非法部门编码");
         return orgCode.Substring(orgCode.Length - 3, 3);
     }
+
+    public static bool IsCenter(this string orgCode)
+    {
+        if (string.IsNullOrEmpty(orgCode))
+            throw UserFriendlyException.SameMessage("无效部门编码");
+        return orgCode == OrgSeedData.CenterCode;
+    }
+
+    public static bool IsBelongCenter(this string orgCode)
+    {
+        if (string.IsNullOrEmpty(orgCode))
+            throw UserFriendlyException.SameMessage("无效部门编码");
+        var upperOrg = orgCode.GetUpperOrgCode();
+        return IsCenter(upperOrg);
+    }
 }

+ 27 - 7
src/Hotline/Settings/TimeLimits/TimeLimitDomainService.cs

@@ -64,10 +64,10 @@ namespace Hotline.Settings.TimeLimits
         /// </summary>
         /// <param name="beginTime"></param>
         /// <param name="endTime"></param>
+        /// <param name="isCenter"></param>
         /// <returns></returns>
         public int CalcWorkTime(DateTime beginTime, DateTime endTime,bool isCenter)
         {
-            //TODO
             if (isCenter)
             {
                 //如果是中心,采用中心计算方式
@@ -122,6 +122,8 @@ namespace Hotline.Settings.TimeLimits
                 {
                     DateTime WorkBeginTime = DateTime.Parse(DateTime.Now.ToShortDateString() + " " + workTime.SettingValue[0] + ":00");
                     DateTime WorkEndTime = DateTime.Parse(DateTime.Now.ToShortDateString() + " " + workTime.SettingValue[1] + ":00");
+
+                    //处理开始时间
                     if (beginTime < WorkBeginTime)
                     {
                         beginTime = WorkBeginTime;
@@ -134,16 +136,33 @@ namespace Hotline.Settings.TimeLimits
                         }
                     }
 
+                    int minutes = 0;
                     while (true)
                     {
+                        if (IsWorkDay(beginTime))
+                        {
+                            if(endTime.Date == WorkEndTime.Date)
+                            {
+                                if (endTime>WorkEndTime)
+                                {
+                                    endTime = WorkEndTime;
+                                }
+                                TimeSpan sp = new TimeSpan(endTime.Ticks - WorkEndTime.Ticks);
+                                minutes += (int)sp.TotalMinutes;
+                                return minutes;
+                            }
+                            else
+                            {
 
+                            }
+                        }
+                        else
+                        {
+                            beginTime = beginTime.AddDays(1);
+                            WorkEndTime = WorkEndTime.AddDays(1);
+                        }
                     }
-
-
-
                 }
-                
-
                 return 0;
             }
         }
@@ -152,9 +171,9 @@ namespace Hotline.Settings.TimeLimits
         /// <summary>
         /// 计算工作日
         /// </summary>
-        ///         
         /// <param name="beginTime"></param>
         /// <param name="busCode"></param>
+        /// <param name="isCenter"></param>
         /// <returns></returns>
         public TimeResult? CalcEndTime(DateTime beginTime, string busCode,bool isCenter)
         {
@@ -173,6 +192,7 @@ namespace Hotline.Settings.TimeLimits
         /// <param name="beginTime"></param>
         /// <param name="timeType"></param>
         /// <param name="timeValue"></param>
+        /// <param name="isCenter"></param>
         /// <returns></returns>
         public TimeResult CalcEndTime(DateTime beginTime, ETimeType timeType, int timeValue,bool isCenter)
         {