Browse Source

Merge branch 'master' of http://git.12345lm.cn/Fengwo/hotline

TANG JIANG 1 year ago
parent
commit
9b67396d66

+ 99 - 3
src/Hotline.Api/Controllers/KnowledgeController.cs

@@ -3,8 +3,8 @@ using Hotline.Application.Knowledge;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.FlowEngine.WorkflowModules;
 using Hotline.KnowledgeBase;
 using Hotline.KnowledgeBase;
 using Hotline.KnowledgeBase.Notifies;
 using Hotline.KnowledgeBase.Notifies;
-using Hotline.Orders;
 using Hotline.Permissions;
 using Hotline.Permissions;
+using Hotline.Quality;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Repository.SqlSugar.Extensions;
 using Hotline.Repository.SqlSugar.Ts;
 using Hotline.Repository.SqlSugar.Ts;
 using Hotline.Settings;
 using Hotline.Settings;
@@ -13,11 +13,14 @@ using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.FlowEngine;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos.Knowledge;
 using Hotline.Share.Dtos.Order;
 using Hotline.Share.Dtos.Order;
+using Hotline.Share.Dtos.Quality;
 using Hotline.Share.Enums.KnowledgeBase;
 using Hotline.Share.Enums.KnowledgeBase;
 using Hotline.Users;
 using Hotline.Users;
 using MapsterMapper;
 using MapsterMapper;
 using MediatR;
 using MediatR;
 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc;
+using Org.BouncyCastle.Utilities;
+using Polly.Caching;
 using SqlSugar;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Authentications;
 using XF.Domain.Exceptions;
 using XF.Domain.Exceptions;
@@ -47,6 +50,7 @@ namespace Hotline.Api.Controllers
 		private readonly IRepository<KnowledgeCorrection> _knowledgeCorrectionRepository;
 		private readonly IRepository<KnowledgeCorrection> _knowledgeCorrectionRepository;
 		private readonly IRepository<KnowledgeCollect> _knowledgeCollectRepository;
 		private readonly IRepository<KnowledgeCollect> _knowledgeCollectRepository;
 		private readonly ISystemDomainService _systemDomainService;
 		private readonly ISystemDomainService _systemDomainService;
+		private readonly IRepository<KnowledgeComment> _knowledgeCommentRepository;
 
 
 
 
 		public KnowledgeController(
 		public KnowledgeController(
@@ -66,7 +70,8 @@ namespace Hotline.Api.Controllers
 		   IRepository<KnowledgeQuestions> knowledgeQuestionsRepository,
 		   IRepository<KnowledgeQuestions> knowledgeQuestionsRepository,
 		   IRepository<KnowledgeCorrection> knowledgeCorrectionRepository,
 		   IRepository<KnowledgeCorrection> knowledgeCorrectionRepository,
 		   IRepository<KnowledgeCollect> knowledgeCollectRepository,
 		   IRepository<KnowledgeCollect> knowledgeCollectRepository,
-		   ISystemDomainService systemDomainService
+		   ISystemDomainService systemDomainService,
+		   IRepository<KnowledgeComment> knowledgeCommentRepository
 		   )
 		   )
 		{
 		{
 			_knowledgeRepository = knowledgeRepository;
 			_knowledgeRepository = knowledgeRepository;
@@ -86,6 +91,7 @@ namespace Hotline.Api.Controllers
 			_knowledgeCorrectionRepository = knowledgeCorrectionRepository;
 			_knowledgeCorrectionRepository = knowledgeCorrectionRepository;
 			_knowledgeCollectRepository = knowledgeCollectRepository;
 			_knowledgeCollectRepository = knowledgeCollectRepository;
 			_systemDomainService = systemDomainService;
 			_systemDomainService = systemDomainService;
+			_knowledgeCommentRepository = knowledgeCommentRepository;
 		}
 		}
 
 
 		#endregion
 		#endregion
@@ -166,6 +172,19 @@ namespace Hotline.Api.Controllers
 				throw UserFriendlyException.SameMessage("知识上架失败");
 				throw UserFriendlyException.SameMessage("知识上架失败");
 		}
 		}
 
 
+		/// <summary>
+		/// 知识库-标题
+		/// </summary>
+		/// <param name="title"></param>
+		/// <returns></returns>
+		[HttpGet("title")]
+		public async Task<bool> KnowledgeTitle([FromQuery] KnowledgeTitleDto dto) {
+			var count = await _knowledgeRepository.Queryable()
+				.WhereIF(!string.IsNullOrEmpty(dto.Id),x=>x.Id != dto.Id)
+				.Where(x => x.Title == dto.Title).CountAsync();
+			return count > 0;
+		}
+
 		/// <summary>
 		/// <summary>
 		/// 知识库-修改
 		/// 知识库-修改
 		/// </summary>
 		/// </summary>
@@ -217,6 +236,8 @@ namespace Hotline.Api.Controllers
 			await StartFlow(delete.Id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, startDto);
 			await StartFlow(delete.Id, WorkflowModuleConsts.KnowledgeDelete, EKnowledgeApplyType.Delete, startDto);
 		}
 		}
 
 
+		//public async Task SearchNum()
+
 		/// <summary>
 		/// <summary>
 		/// 知识库-知识修改-查询详情
 		/// 知识库-知识修改-查询详情
 		/// </summary>
 		/// </summary>
@@ -259,7 +280,6 @@ namespace Hotline.Api.Controllers
 			var knowledge = await _knowledgeDomainService.KnowledgeInfo(Id, HttpContext.RequestAborted);
 			var knowledge = await _knowledgeDomainService.KnowledgeInfo(Id, HttpContext.RequestAborted);
 			if (knowledge is null)
 			if (knowledge is null)
 				throw UserFriendlyException.SameMessage("知识查询失败!");
 				throw UserFriendlyException.SameMessage("知识查询失败!");
-
 			//转化
 			//转化
 			var knowledgeShowInfoDto = _mapper.Map<KnowledgeInfoDto>(knowledge);
 			var knowledgeShowInfoDto = _mapper.Map<KnowledgeInfoDto>(knowledge);
 
 
@@ -1020,5 +1040,81 @@ namespace Hotline.Api.Controllers
 			}
 			}
 		}
 		}
 		#endregion
 		#endregion
+
+		#region 知识评论
+
+		/// <summary>
+		/// 新增知识评论
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[Permission(EPermission.AddKnowledgeComment)]
+		[HttpPost("knowledge_comment")]
+		public async Task Add([FromBody] KnowledgeCommentAddDto dto)
+		{
+			var model = _mapper.Map<KnowledgeComment>(dto);
+			await _knowledgeCommentRepository.AddAsync(model, HttpContext.RequestAborted);
+			if (!string.IsNullOrEmpty(dto.ReplyId))
+			{
+				var comment = await _knowledgeCommentRepository.GetAsync(dto.ReplyId);
+				if (comment != null) 
+				{
+					comment.ReplyNum++;
+					await _knowledgeCommentRepository.UpdateAsync(comment, HttpContext.RequestAborted);
+				}
+			}
+		}
+
+		/// <summary>
+		/// 删除知识评论
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[Permission(EPermission.DeleteKnowledgeComment)]
+		[HttpDelete("knowledge_comment")]
+		public async Task Delete([FromBody] KnowledgeCommentDeleteDto dto)
+		{
+			var comment = await _knowledgeCommentRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+			if (comment is null)
+				throw UserFriendlyException.SameMessage("无效评论");
+			if (comment.CreatorId != _sessionContext.UserId)
+				throw UserFriendlyException.SameMessage("只有评论者可以删除当前评论");
+			await _knowledgeCommentRepository.RemoveAsync(x => x.Id == dto.Id);
+		}
+
+		/// <summary>
+		/// 修改知识评论
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[Permission(EPermission.UpdateKnowledgeComment)]
+		[HttpPut("knowledge_comment")]
+		public async Task Update([FromBody] KnowledgeCommentUpdateDto dto)
+		{
+			var comment = await _knowledgeCommentRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+			if (comment is null)
+				throw UserFriendlyException.SameMessage("无效评论");
+			_mapper.Map(dto, comment);
+			await _knowledgeCommentRepository.UpdateAsync(comment, HttpContext.RequestAborted);
+		}
+
+		/// <summary>
+		/// 知识评论列表
+		/// </summary>
+		/// <param name="dto"></param>
+		/// <returns></returns>
+		[Permission(EPermission.KnowledgeCommentList)]
+		[HttpGet("knowledge_comment/list")]
+		public async Task<List<KnowledgeCommentDto>> List([FromQuery] KnowledgeCommentListDto dto)
+		{
+			var comments = await _knowledgeCommentRepository.Queryable()
+				.WhereIF(!string.IsNullOrEmpty(dto.KnowledgeId), x => x.KnowledgeId == dto.KnowledgeId)
+				.WhereIF(!string.IsNullOrEmpty(dto.ReplyId), x => x.ReplyId == dto.ReplyId)
+				.WhereIF(dto.All.HasValue && dto.All == false, x => x.CreatorId == _sessionContext.UserId)
+				.OrderByDescending(x => x.CreationTime)
+				.ToListAsync();
+			return new List<KnowledgeCommentDto>(_mapper.Map<IReadOnlyList<KnowledgeCommentDto>>(comments));
+		}
+		#endregion
 	}
 	}
 }
 }

+ 2 - 2
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -439,8 +439,8 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         {
         {
             if (currentStep.IsCountersignEndStep)
             if (currentStep.IsCountersignEndStep)
             {
             {
-                //当前待办节点为会签汇总节点时:检查是否为顶级会签发起节点(csstate==none),t:按配置往下走,f:继续往上汇总,不需要重复往下指派
-                if (currentStep.CountersignStartStepId != workflow.TopCountersignStepId)
+                //当前待办节点为会签汇总节点时:检查是否为顶级会签汇总节点,t:按配置往下走,f:继续往上汇总,不需要重复往下指派
+                if (!currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
                 {
                 {
                     //查找当前节点对应会签开始节点的上级作为下一个cs汇总节点的汇总对象
                     //查找当前节点对应会签开始节点的上级作为下一个cs汇总节点的汇总对象
                     var startCountersignStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
                     var startCountersignStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);

+ 133 - 0
src/Hotline.Share/Dtos/Knowledge/KnowledgeCommentDto.cs

@@ -0,0 +1,133 @@
+using Hotline.Share.Enums.Quality;
+using Hotline.Share.Requests;
+
+namespace Hotline.Share.Dtos.Knowledge
+{
+	public class KnowledgeCommentDto : KnowledgeCommentBaseDto
+	{
+		/// <summary>
+		/// 知识库ID
+		/// </summary>
+		public string KnowledgeId { get; set; }
+
+		/// <summary>
+		/// 知识库
+		/// </summary>
+		public KnowledgeDto Knowledge { get; set; }
+
+		/// <summary>
+		/// 评论内容
+		/// </summary>
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 回复ID
+		/// </summary>
+		public string? ReplyId { get; set; }
+
+		/// <summary>
+		/// 匿名
+		/// </summary>
+		public bool Cryptonym { get; set; }
+
+		/// <summary>
+		/// 回复数
+		/// </summary>
+		public int ReplyNum { get; set; } = 0;
+	}
+
+	public class KnowledgeCommentAddDto
+	{
+		/// <summary>
+		/// 知识库ID
+		/// </summary>
+		public string KnowledgeId { get; set; }
+
+		/// <summary>
+		/// 知识库
+		/// </summary>
+		public KnowledgeDto Knowledge { get; set; }
+
+		/// <summary>
+		/// 评论内容
+		/// </summary>
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 回复ID
+		/// </summary>
+		public string? ReplyId { get; set; }
+
+		/// <summary>
+		/// 匿名
+		/// </summary>
+		public bool Cryptonym { get; set; }
+
+		/// <summary>
+		/// 回复数
+		/// </summary>
+		public int ReplyNum { get; set; } = 0;
+	}
+
+	public class KnowledgeCommentDeleteDto
+	{
+		public string Id { get; set; }
+	}
+
+	public class KnowledgeCommentUpdateDto : KnowledgeCommentAddDto
+	{
+		public string Id { get; set; }
+	}
+	public class KnowledgeCommentBaseDto
+	{
+		public DateTime? LastModificationTime { get; set; }
+
+		public bool IsDeleted { get; set; }
+
+		/// <summary>
+		/// 删除时间
+		/// </summary>
+		public DateTime? DeletionTime { get; set; }
+
+
+		/// <summary>
+		/// 创建时间
+		/// </summary>
+		public DateTime CreationTime { get; set; }
+
+		public string Id { get; set; }
+
+		/// <summary>
+		/// 组织Id
+		/// </summary>
+		public string? CreatorOrgId { get; set; }
+
+
+		public string? CreatorOrgName { get; set; }
+
+		/// <summary>
+		/// 创建人
+		/// </summary>
+		public string? CreatorId { get; set; }
+
+		public string? CreatorName { get; set; }
+	}
+
+	public record KnowledgeCommentListDto : PagedKeywordRequest
+	{
+		/// <summary>
+		/// 知识库ID
+		/// </summary>
+		public string KnowledgeId { get; set; }
+
+		/// <summary>
+		/// 回复ID
+		/// </summary>
+		public string? ReplyId { get; set; }
+
+		/// <summary>
+		/// 查询全部
+		/// </summary>
+		public bool? All { get; set; }
+	}
+}

+ 13 - 0
src/Hotline.Share/Dtos/Knowledge/KnowledgeDto.cs

@@ -231,6 +231,19 @@ namespace Hotline.Share.Dtos.Knowledge
 		public string? CreatorName { get; set; }
 		public string? CreatorName { get; set; }
 	}
 	}
 
 
+    public class KnowledgeTitleDto {
+
+		/// <summary>
+		/// ID
+		/// </summary>
+		public string? Id { get; set; }
+
+		/// <summary>
+		/// 标题
+		/// </summary>
+		public string Title { get; set; }
+
+	}
 
 
 
 
 	public class AddStartFlowDto : StartWorkflowDto<AddKnowledgeDto>
 	public class AddStartFlowDto : StartWorkflowDto<AddKnowledgeDto>

+ 54 - 409
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -238,8 +238,6 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// <summary>
         /// 受理(接办)
         /// 受理(接办)
         /// </summary>
         /// </summary>
-
-        //new
         public async Task AcceptAsync(Workflow workflow,
         public async Task AcceptAsync(Workflow workflow,
             string userId, string? userName,
             string userId, string? userName,
             string orgId, string? orgName,
             string orgId, string? orgName,
@@ -255,33 +253,6 @@ namespace Hotline.FlowEngine.Workflows
 
 
             if (currentStep.Handlers.All(d => d.Key != orgId && d.Key != userId)) return;
             if (currentStep.Handlers.All(d => d.Key != orgId && d.Key != userId)) return;
 
 
-            //if (currentStep.HandlerType is EHandlerType.AssignedOrg or EHandlerType.OrgLevel or EHandlerType.OrgType
-            //   || (currentStep.InstanceMode is EInstanceMode.Dynamic && !currentStep.DynamicShouldTerminal())//动态并且非结束节点
-            //       || (currentStep.IsInCountersign() && !currentStep.IsCountersignEndStep)//会签并且非会签节点
-            //       )
-            //{
-            //    //orgId
-            //    if (currentStep.Handlers.All(d => d.Key != orgId)) return;
-            //}
-            //else
-            //{
-            //    //userId
-            //    if (currentStep.Handlers.All(d => d.Key != userId)) return;
-            //}
-
-            //if (currentStep.HandlerType is EHandlerType.AssignedUser or EHandlerType.Role
-            //&& !currentStep.IsInCountersign()
-            //&& currentStep.InstanceMode is EInstanceMode.Config
-            //)
-            //{
-            //    //userId
-            //    if (currentStep.Handlers.All(d => d.Key != userId)) return;
-            //}
-            //else
-            //{
-            //    //orgId
-            //    if (currentStep.Handlers.All(d => d.Key != orgId)) return;
-            //}
             if (currentStep.StepType is EStepType.End)
             if (currentStep.StepType is EStepType.End)
                 throw new UserFriendlyException("当前流程已流转到最终步骤");
                 throw new UserFriendlyException("当前流程已流转到最终步骤");
 
 
@@ -318,6 +289,7 @@ namespace Hotline.FlowEngine.Workflows
         public async Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto, StepDefine nextStepDefine,
         public async Task NextAsync(Workflow workflow, WorkflowStep currentStep, NextWorkflowDto dto, StepDefine nextStepDefine,
             FlowAssignInfo flowAssignInfo, DateTime expiredTime, CancellationToken cancellationToken)
             FlowAssignInfo flowAssignInfo, DateTime expiredTime, CancellationToken cancellationToken)
         {
         {
+            //todo 1.汇总节点的创建不能简单看上级节点发起的是否全办完
             ValidatePermission(workflow);
             ValidatePermission(workflow);
             CheckWhetherRunnable(workflow.Status);
             CheckWhetherRunnable(workflow.Status);
 
 
@@ -367,13 +339,23 @@ namespace Hotline.FlowEngine.Workflows
             //操作为回到会签汇总时,更新开始会签节点的会签办理状态
             //操作为回到会签汇总时,更新开始会签节点的会签办理状态
             if (currentStep.IsInCountersign() && dto.BackToCountersignEnd)
             if (currentStep.IsInCountersign() && dto.BackToCountersignEnd)
             {
             {
-                var countersignStartStep = workflow.Steps.FirstOrDefault(d => d.StartCountersignId == currentStep.CountersignId);
+                var targetStep = currentStep;
+                if (currentStep.IsCountersignEndStep)
+                {
+                    var csStartStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.CountersignStartStepId);
+                    if (csStartStep is null)
+                        throw new UserFriendlyException("未查询到会签开始节点");
+                    targetStep = csStartStep;
+                }
+
+                var countersignStartStep = workflow.Steps.FirstOrDefault(d => d.Id == targetStep.PrevStepId);
                 if (countersignStartStep is null)
                 if (countersignStartStep is null)
-                    throw new UserFriendlyException("未查询到会签开始节点");
-                if (!countersignStartStep.IsStartCountersign)
-                    throw new UserFriendlyException("查询到会签开始节点状态异常");
+                    throw new UserFriendlyException("未查询到目标节点的前一节点");
 
 
-                countersignStartStep.CountersignSteps.First(d => d.StepId == currentStep.Id).Completed = true;
+                var csStep = countersignStartStep.CountersignSteps.FirstOrDefault(d => d.StepId == targetStep.Id);
+                if (csStep is null)
+                    throw new UserFriendlyException("未查询到当前待办节点");
+                csStep.Completed = true;
                 updateSteps.Add(countersignStartStep);
                 updateSteps.Add(countersignStartStep);
             }
             }
 
 
@@ -468,19 +450,18 @@ namespace Hotline.FlowEngine.Workflows
                 {
                 {
                     //todo check if current is topend f: csStartStep.prev
                     //todo check if current is topend f: csStartStep.prev
                     //todo t: check if dto.StartCs t: csconfig f: config
                     //todo t: check if dto.StartCs t: csconfig f: config
-                    if (currentStep.CountersignStartStepId == workflow.TopCountersignStepId)
+                    if (currentStep.IsTopCountersignEndStep(workflow.TopCountersignStepId))
                     {
                     {
                         if (dto.IsStartCountersign)
                         if (dto.IsStartCountersign)
                         {
                         {
                             //todo 依据会签策略创建会签下一级节点
                             //todo 依据会签策略创建会签下一级节点
-                            nextSteps = await CreateStepsAsync(workflow, nextStepDefine, currentStep, dto, dto.NextHandlers,
-                                EWorkflowStepStatus.WaitForAccept, currentStep.GetNextStepCountersignPosition(),
-                                expiredTime, false, cancellationToken);
+                            nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
+                                expiredTime, cancellationToken);
                         }
                         }
                         else
                         else
                         {
                         {
                             //todo 创建普通节点(根据配置)
                             //todo 创建普通节点(根据配置)
-                            nextSteps = await CreateStepsByDefineAsync(workflow, nextStepDefine, currentStep, dto, expiredTime, cancellationToken);
+                            nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, expiredTime, cancellationToken);
                         }
                         }
                     }
                     }
                     else
                     else
@@ -504,48 +485,56 @@ namespace Hotline.FlowEngine.Workflows
                     else
                     else
                     {
                     {
                         //todo 依据会签策略创建会签下一级节点
                         //todo 依据会签策略创建会签下一级节点
-                        nextSteps = await CreateStepsAsync(workflow, nextStepDefine, currentStep, dto, dto.NextHandlers,
-                            EWorkflowStepStatus.WaitForAccept, currentStep.GetNextStepCountersignPosition(),
-                            expiredTime, false, cancellationToken);
+                        nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
+                            expiredTime, cancellationToken);
                     }
                     }
                 }
                 }
             }
             }
-            else if (dto.IsStartCountersign)
+            else if (dto.IsStartCountersign)//top
             {
             {
                 //todo 依据会签策略创建会签下一级节点
                 //todo 依据会签策略创建会签下一级节点
-                nextSteps = await CreateStepsAsync(workflow, nextStepDefine, currentStep, dto, dto.NextHandlers,
-                    EWorkflowStepStatus.WaitForAccept, currentStep.GetNextStepCountersignPosition(),
-                        expiredTime, false, cancellationToken);
+                nextSteps = await CreateCountersignStepsAsync(workflow, nextStepDefine, currentStep, dto,
+                    expiredTime, cancellationToken);
             }
             }
             else if (currentStep.InstanceMode is EInstanceMode.Dynamic && !currentStep.DynamicShouldTerminal())
             else if (currentStep.InstanceMode is EInstanceMode.Dynamic && !currentStep.DynamicShouldTerminal())
             {
             {
                 //todo 创建动态下一级节点
                 //todo 创建动态下一级节点
                 nextSteps = await CreateStepsAsync(workflow, nextStepDefine, currentStep, dto, dto.NextHandlers,
                 nextSteps = await CreateStepsAsync(workflow, nextStepDefine, currentStep, dto, dto.NextHandlers,
-                    EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
+                    null, EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
                     expiredTime, false, cancellationToken);
                     expiredTime, false, cancellationToken);
             }
             }
             else
             else
             {
             {
                 //todo 创建普通节点(根据配置)
                 //todo 创建普通节点(根据配置)
-                nextSteps = await CreateStepsByDefineAsync(workflow, nextStepDefine, currentStep, dto, expiredTime, cancellationToken);
+                nextSteps = await CreateConfigStepsAsync(workflow, nextStepDefine, currentStep, dto, expiredTime, cancellationToken);
             }
             }
 
 
             return nextSteps;
             return nextSteps;
         }
         }
 
 
+        private Task<List<WorkflowStep>> CreateCountersignStepsAsync(
+            Workflow workflow,
+            StepDefine stepDefine,
+            WorkflowStep prevStep,
+            BasicWorkflowDto dto,
+            DateTime expiredTime,
+            CancellationToken cancellationToken
+        )
+        {
+            var countersignId = prevStep.IsStartCountersign ? prevStep.StartCountersignId : prevStep.CountersignId;
+
+            return CreateStepsAsync(workflow, stepDefine, prevStep, dto, dto.NextHandlers, countersignId,
+                  EWorkflowStepStatus.WaitForAccept, prevStep.GetNextStepCountersignPosition(),
+                  expiredTime, false, cancellationToken);
+        }
+
         /// <summary>
         /// <summary>
         /// 根据传入节点的上一节点创建会签汇总节点(汇总传入节点的前一节点)
         /// 根据传入节点的上一节点创建会签汇总节点(汇总传入节点的前一节点)
         /// </summary>
         /// </summary>
-        /// <param name="workflow"></param>
-        /// <param name="currentStep"></param>
-        /// <param name="dto"></param>
-        /// <param name="cancellationToken"></param>
-        /// <returns></returns>
-        /// <exception cref="UserFriendlyException"></exception>
-        private async Task<List<WorkflowStep>> CreateCsEndStepsByPrevStepAsync(Workflow workflow, WorkflowStep currentStep, BasicWorkflowDto dto,
-            CancellationToken cancellationToken)
+        private async Task<List<WorkflowStep>> CreateCsEndStepsByPrevStepAsync(Workflow workflow, WorkflowStep step,
+            BasicWorkflowDto dto, CancellationToken cancellationToken)
         {
         {
-            var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == currentStep.PrevStepId);
+            var prevStep = workflow.Steps.FirstOrDefault(d => d.Id == step.PrevStepId);
             if (prevStep is null)
             if (prevStep is null)
                 throw new UserFriendlyException("未查询到当前节点上级节点");
                 throw new UserFriendlyException("未查询到当前节点上级节点");
             var nextSteps = new List<WorkflowStep>();
             var nextSteps = new List<WorkflowStep>();
@@ -683,7 +672,7 @@ namespace Hotline.FlowEngine.Workflows
                 if (lastStep is null || lastStep.StepType is EStepType.End)
                 if (lastStep is null || lastStep.StepType is EStepType.End)
                     throw new UserFriendlyException($"流程流转数据异常,未结束流程出现endStep, flowId: {workflow.Id}", "流程流转数据异常");
                     throw new UserFriendlyException($"流程流转数据异常,未结束流程出现endStep, flowId: {workflow.Id}", "流程流转数据异常");
 
 
-                var targetSteps = await CreateStepsByDefineAsync(workflow, targetStepDefine, lastStep, dto, workflow.ExpiredTime, cancellationToken);
+                var targetSteps = await CreateConfigStepsAsync(workflow, targetStepDefine, lastStep, dto, workflow.ExpiredTime, cancellationToken);
                 targetStep = targetSteps.First();
                 targetStep = targetSteps.First();
 
 
                 workflow.EndCountersign();
                 workflow.EndCountersign();
@@ -931,39 +920,6 @@ namespace Hotline.FlowEngine.Workflows
         /// <summary>
         /// <summary>
         /// 办理节点
         /// 办理节点
         /// </summary>
         /// </summary>
-        //private async Task HandleStepAsync(Workflow workflow, BasicWorkflowDto dto, WorkflowStep currentStepBox, WorkflowStep currentStep,
-        //    ECounterSignType counterSignType, CancellationToken cancellationToken)
-        //{
-        //    if (currentStep.Status is EWorkflowStepStatus.Handled or EWorkflowStepStatus.Created)
-        //        throw UserFriendlyException.SameMessage("当前节点状态无法办理");
-
-        //    if (currentStep.Status is EWorkflowStepStatus.WaitForAccept)
-        //        await AcceptAsync(workflow,
-        //            _sessionContext.RequiredUserId,
-        //            _sessionContext.UserName,
-        //            _sessionContext.RequiredOrgId,
-        //            _sessionContext.OrgName,
-        //            cancellationToken);
-        //    if (currentStep.StepType is EStepType.End)
-        //        throw new UserFriendlyException("当前流程已流转到最终步骤");
-
-        //    //创建会签数据
-        //    if (dto.IsStartCountersign)
-        //        await StartCountersignAsync(workflow, dto, currentStepBox, currentStep, counterSignType, cancellationToken);
-
-        //    _mapper.Map(dto, currentStep);
-
-        //    //step办理状态
-        //    currentStep.Handled(
-        //        _sessionContext.RequiredUserId, _sessionContext.UserName,
-        //        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-        //        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-        //        dto.NextStepCode);
-
-        //    //stepBox办理状态
-        //    currentStepBox.CheckStepBoxStatusAndUpdate();
-        //}
-        //new
         private async Task HandleStepAsync(WorkflowStep step, Workflow workflow, BasicWorkflowDto dto,
         private async Task HandleStepAsync(WorkflowStep step, Workflow workflow, BasicWorkflowDto dto,
              ECounterSignType? counterSignType, CancellationToken cancellationToken)
              ECounterSignType? counterSignType, CancellationToken cancellationToken)
         {
         {
@@ -1273,7 +1229,7 @@ namespace Hotline.FlowEngine.Workflows
             //var targetStepBoxNew = await CreateStepAsync(workflow, targetStepDefine, dto, EWorkflowStepStatus.WaitForAccept,
             //var targetStepBoxNew = await CreateStepAsync(workflow, targetStepDefine, dto, EWorkflowStepStatus.WaitForAccept,
             //     targetPrevStepBox, targetPrevStep, traceStatus, workflow.ExpiredTime, cancellationToken);
             //     targetPrevStepBox, targetPrevStep, traceStatus, workflow.ExpiredTime, cancellationToken);
 
 
-            var targetStepsNew = await CreateStepsByDefineAsync(workflow, targetStepDefine, targetPrevStep, dto, workflow.ExpiredTime, cancellationToken);
+            var targetStepsNew = await CreateConfigStepsAsync(workflow, targetStepDefine, targetPrevStep, dto, workflow.ExpiredTime, cancellationToken);
 
 
             //更新当前办理节点信息
             //更新当前办理节点信息
             workflow.UpdateWorkflowCurrentStepInfo(dto.IsStartCountersign, nextStep: targetStepsNew.First());
             workflow.UpdateWorkflowCurrentStepInfo(dto.IsStartCountersign, nextStep: targetStepsNew.First());
@@ -1311,60 +1267,6 @@ namespace Hotline.FlowEngine.Workflows
                 throw UserFriendlyException.SameMessage("无办理权限");
                 throw UserFriendlyException.SameMessage("无办理权限");
         }
         }
 
 
-        //private async Task<(WorkflowStep startStepBox, WorkflowStep startStep, WorkflowStep firstStepBox)> CreateStartAndFirstStepAsync(
-        //    Workflow workflow, BasicWorkflowDto dto, CancellationToken cancellationToken)
-        //{
-        //    if (workflow.Steps.Any())
-        //        throw UserFriendlyException.SameMessage("无法重复创建开始节点");
-
-        //    var startStepDefinition = workflow.WorkflowDefinition.Steps.FirstOrDefault(d => d.StepType == EStepType.Start);
-        //    if (startStepDefinition == null)
-        //        throw new UserFriendlyException($"模板未配置开始节点, defineCode: {workflow.WorkflowDefinition.Code}", "模板未配置开始节点");
-
-        //    var startStepBox = CreateStepBox(workflow.Id, startStepDefinition, string.Empty);
-        //    await _workflowStepRepository.AddAsync(startStepBox, cancellationToken);
-
-
-        //    //start节点的办理人分类默认为用户,即为当前发起流程的操作员
-        //    var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
-
-        //    //开始节点的下一个节点(工单业务:话务员节点)
-        //    var firstStepCode = workflow.WorkflowDefinition.FindStartStepDefine().NextSteps.First().Code;
-        //    var startStep = await CreateStartSubStepAsync(handler, firstStepCode, startStepBox, dto, cancellationToken);
-
-        //    //开始节点trace
-        //    await CreateTraceAsync(workflow, startStep, cancellationToken: cancellationToken);
-
-        //    //创建firstStep
-        //    var firsStepDefine = workflow.WorkflowDefinition.FindStepDefine(firstStepCode);
-        //    var firstStepBox = await CreateStepAsync(workflow, firsStepDefine, dto, EWorkflowStepStatus.WaitForHandle,
-        //        startStepBox, startStep, EWorkflowTraceStatus.Normal, workflow.ExpiredTime, cancellationToken);
-
-        //    return (startStepBox, startStep, firstStepBox);
-        //}
-
-        //private async Task<(WorkflowStep stepBox, WorkflowStep step)> CreateEndStepAsync(
-        //    Workflow workflow,
-        //    StepDefine endStepDefine,
-        //    WorkflowStep prevStepBox,
-        //    WorkflowStep prevStep,
-        //    CancellationToken cancellationToken)
-        //{
-        //    if (workflow.Steps.Any(d => d.StepType == EStepType.End))
-        //        throw UserFriendlyException.SameMessage("无法重复创建结束节点");
-
-        //    var stepBox = CreateStepBox(workflow.Id, endStepDefine, prevStepBox.Id);
-        //    await _workflowStepRepository.AddAsync(stepBox, cancellationToken);
-
-        //    var handler = new Kv { Key = _sessionContext.RequiredUserId, Value = _sessionContext.UserName };
-        //    var step = await CreateEndSubStepAsync(handler, stepBox, prevStep, cancellationToken);
-
-        //    //end trace
-        //    await CreateTraceAsync(workflow, step, cancellationToken: cancellationToken);
-
-        //    return (stepBox, step);
-        //}
-
         private async Task<WorkflowStep> CreateEndStepAsync(
         private async Task<WorkflowStep> CreateEndStepAsync(
             Workflow workflow,
             Workflow workflow,
             StepDefine endStepDefine,
             StepDefine endStepDefine,
@@ -1394,52 +1296,7 @@ namespace Hotline.FlowEngine.Workflows
             return step;
             return step;
         }
         }
 
 
-        /// <summary>
-        /// 创建节点(不含开始、结束节点)
-        /// </summary>
-        //private async Task<WorkflowStep> CreateStepAsync(
-        //Workflow workflow,
-        //StepDefine stepBoxDefine,
-        //BasicWorkflowDto dto,
-        //EWorkflowStepStatus status,
-        //WorkflowStep prevStepBox,
-        //WorkflowStep prevStep,
-        //EWorkflowTraceStatus traceStatus,
-        //DateTime expiredTime,
-        //CancellationToken cancellationToken)
-        //{
-        //    if (stepBoxDefine.StepType is EStepType.Start or EStepType.End)
-        //        throw new UserFriendlyException("该方法不支持创建开始或结束节点");
-        //    var stepBox = workflow.Steps.FirstOrDefault(d => d.Code == stepBoxDefine.Code);
-        //    if (stepBox == null)
-        //    {
-        //        stepBox = CreateStepBox(workflow.Id, stepBoxDefine, prevStepBox.Id);
-        //        await _workflowStepRepository.AddAsync(stepBox, cancellationToken);
-        //        workflow.Steps.Add(stepBox);
-        //    }
-        //    else if (stepBox.Status != EWorkflowStepStatus.Created)
-        //    {
-        //        stepBox.Status = EWorkflowStepStatus.Created;
-        //        await _workflowStepRepository.UpdateAsync(stepBox, cancellationToken);
-        //    }
-
-        //    //下一节点为汇总节点时,同一会签只需要创建一次汇总节点
-        //    if (stepBoxDefine.StepType is EStepType.Summary && prevStep.CountersignPosition == ECountersignPosition.Inner)
-        //    {
-        //        var step = stepBox.Steps.FirstOrDefault(d =>
-        //            d.IsInCountersign && d.CountersignId == prevStep.CountersignId);
-        //        if (step != null)
-        //            return stepBox;
-        //    }
-
-        //    await CreateSubStepsAsync(workflow, stepBoxDefine, dto, stepBox, status, prevStep, traceStatus, expiredTime, cancellationToken);
-
-
-        //    return stepBox;
-        //}
-
-        //new
-        public async Task<List<WorkflowStep>> CreateStepsByDefineAsync(
+        public async Task<List<WorkflowStep>> CreateConfigStepsAsync(
             Workflow workflow,
             Workflow workflow,
             StepDefine stepDefine,
             StepDefine stepDefine,
             WorkflowStep prevStep,
             WorkflowStep prevStep,
@@ -1459,21 +1316,18 @@ namespace Hotline.FlowEngine.Workflows
                 handlers = dto.NextHandlers;
                 handlers = dto.NextHandlers;
             }
             }
 
 
-            //var countersignId = prevStep.HasStartedCountersign() ? prevStep.StartCountersignId : prevStep.CountersignId;
-
-            return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, handlers,
+            return await CreateStepsAsync(workflow, stepDefine, prevStep, dto, handlers, null,
                 EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
                 EWorkflowStepStatus.WaitForAccept, ECountersignPosition.None,
                 expiredTime, true, cancellationToken);
                 expiredTime, true, cancellationToken);
         }
         }
 
 
-        //new
         private async Task<List<WorkflowStep>> CreateStepsAsync(
         private async Task<List<WorkflowStep>> CreateStepsAsync(
             Workflow workflow,
             Workflow workflow,
             StepDefine stepDefine,
             StepDefine stepDefine,
             WorkflowStep prevStep,
             WorkflowStep prevStep,
             BasicWorkflowDto dto,
             BasicWorkflowDto dto,
             List<Kv> handlers,
             List<Kv> handlers,
-            //string? countersignId,
+            string? countersignId,
             EWorkflowStepStatus stepStatus,
             EWorkflowStepStatus stepStatus,
             ECountersignPosition csPosition,
             ECountersignPosition csPosition,
             DateTime expiredTime,
             DateTime expiredTime,
@@ -1481,7 +1335,9 @@ namespace Hotline.FlowEngine.Workflows
             CancellationToken cancellationToken
             CancellationToken cancellationToken
             )
             )
         {
         {
-            var countersignId = prevStep.IsStartCountersign ? prevStep.StartCountersignId : prevStep.CountersignId;
+            //var countersignId = prevStep.IsStartCountersign
+            //    ? prevStep.StartCountersignId
+            //    : prevStep.IsInCountersign() ? prevStep.Id : null;
 
 
             List<WorkflowStep> steps = new();
             List<WorkflowStep> steps = new();
             if (dto.IsStartCountersign)
             if (dto.IsStartCountersign)
@@ -1515,114 +1371,9 @@ namespace Hotline.FlowEngine.Workflows
             return steps;
             return steps;
         }
         }
 
 
-        //private async Task<WorkflowStep> CreateStartSubStepAsync(
-        //    Kv handler,
-        //    string nextStepCode,
-        //    WorkflowStep stepBox,
-        //    BasicWorkflowDto dto,
-        //    CancellationToken cancellationToken)
-        //{
-        //    //开始节点既不发起会签,也不处于会签中
-        //    var subStep = CreateSubStep(stepBox, new List<Kv> { handler }, nextStepCode, null,
-        //        null, null, EWorkflowStepStatus.Handled, ECountersignPosition.None, DateTime.Today,
-        //        _mapper.Map<StepExtension>(dto.Extension));
-        //    subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName,
-        //        _sessionContext.RequiredOrgId, _sessionContext.OrgName);
-
-        //    //step办理状态
-        //    subStep.Handle(_sessionContext.RequiredUserId, _sessionContext.UserName,
-        //        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-        //        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-        //        nextStepCode);
-
-        //    subStep.Opinion = "流程开启";
-        //    stepBox.Steps.Add(subStep);
-        //    await _workflowStepRepository.AddAsync(subStep, cancellationToken);
-        //    return subStep;
-        //}
-
-        //private async Task<WorkflowStep> CreateEndSubStepAsync(
-        //    Kv handler,
-        //    WorkflowStep currentStepBox,
-        //    WorkflowStep prevStep,
-        //    CancellationToken cancellationToken)
-        //{
-        //    var subStep = CreateSubStep(currentStepBox, new List<Kv> { handler }, null, null, prevStep.Id,
-        //        null, EWorkflowStepStatus.Handled, ECountersignPosition.None, DateTime.Today, new());
-        //    subStep.Accept(_sessionContext.RequiredUserId, _sessionContext.UserName, _sessionContext.RequiredOrgId,
-        //        _sessionContext.OrgName);
-        //    subStep.Handle(_sessionContext.RequiredUserId, _sessionContext.UserName,
-        //        _sessionContext.RequiredOrgId, _sessionContext.OrgName,
-        //        _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-        //        string.Empty);
-
-        //    currentStepBox.Steps.Add(subStep);
-        //    await _workflowStepRepository.AddAsync(subStep, cancellationToken);
-        //    return subStep;
-        //}
-
-        //private async Task CreateSubStepsAsync(
-        //    Workflow workflow,
-        //    StepDefine stepBoxDefine,
-        //    BasicWorkflowDto dto,
-        //    WorkflowStep stepBox,
-        //    EWorkflowStepStatus stepStatus,
-        //    WorkflowStep prevStep,
-        //    EWorkflowTraceStatus traceStatus,
-        //    DateTime expiredTime,
-        //    CancellationToken cancellationToken = default)
-        //{
-        //    var countersignStatus = stepBoxDefine.StepType is EStepType.Summary
-        //        ? prevStep.IsInCountersign()
-        //            ? ECountersignPosition.Inner
-        //            : ECountersignPosition.None
-        //        : prevStep.GetNextStepCountersignPosition();
-
-        //    var countersignId = dto.IsStartCountersign ? prevStep.StartCountersignId : prevStep.CountersignId;
-
-        //    List<WorkflowStep> subSteps;
-        //    var stepExtension = _mapper.Map<StepExtension>(dto.Extension);
-        //    if (stepBoxDefine.HandlerType is EHandlerType.AssignedUser or EHandlerType.AssignedOrg)
-        //    {
-        //        subSteps = CreateSubSteps(dto.IsStartCountersign, stepBox, stepBox.HandlerClassifies, dto.NextStepCode, dto.NextMainHandler,
-        //            prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime, stepExtension);
-        //    }
-        //    else
-        //    {
-        //        if (stepBoxDefine.HandlerType != EHandlerType.Role && !dto.NextHandlers.Any())
-        //            throw new UserFriendlyException("未指定节点处理者");
-        //        subSteps = CreateSubSteps(dto.IsStartCountersign, stepBox, dto.NextHandlers, dto.NextStepCode, dto.NextMainHandler,
-        //            prevStep?.Id, countersignId, stepStatus, countersignStatus, expiredTime, stepExtension);
-        //    }
-        //    stepBox.Steps.AddRange(subSteps);
-        //    await _workflowStepRepository.AddRangeAsync(subSteps, cancellationToken);
-
-        //    //create traces
-        //    foreach (var step in subSteps)
-        //    {
-        //        await CreateTraceAsync(workflow, step, traceStatus, cancellationToken);
-        //    }
-        //}
-
-
         /// <summary>
         /// <summary>
         /// 查询未完成节点
         /// 查询未完成节点
         /// </summary>
         /// </summary>
-        /// <param name="stepBoxes"></param>
-        /// <param name="orgCode"></param>
-        /// <param name="userId"></param>
-        /// <returns></returns>
-        //private (WorkflowStep, WorkflowStep) GetUnCompleteStep(List<WorkflowStep> stepBoxes, string orgCode, string userId)
-        //{
-        //    var (stepBox, step) = GetStep(stepBoxes, orgCode, userId, d => d != EWorkflowStepStatus.Handled);
-        //    if (step == null)
-        //        throw new UserFriendlyException(
-        //            $"未找到对应节点, workflowId: {stepBoxes.FirstOrDefault()?.WorkflowId} orgCode:{orgCode}, userId: {userId}",
-        //            "未找到对应节点");
-        //    return (stepBox, step);
-        //}
-
-        //new
         private WorkflowStep GetUnHandleStep(List<WorkflowStep> steps, string orgCode, string userId)
         private WorkflowStep GetUnHandleStep(List<WorkflowStep> steps, string orgCode, string userId)
         {
         {
             var step = GetStep(steps, orgCode, userId, d => d != EWorkflowStepStatus.Handled);
             var step = GetStep(steps, orgCode, userId, d => d != EWorkflowStepStatus.Handled);
@@ -1633,116 +1384,10 @@ namespace Hotline.FlowEngine.Workflows
             return step;
             return step;
         }
         }
 
 
-        //private (WorkflowStep, WorkflowStep) GetUnCompleteStepOrDefault(List<WorkflowStep> stepBoxes, string orgCode, string userId) =>
-        //    GetStep(stepBoxes, orgCode, userId, d => d != EWorkflowStepStatus.Handled);
-
-        //private (WorkflowStep, WorkflowStep) GetStep(List<WorkflowStep> stepBoxes, string orgCode, string userId, Func<EWorkflowStepStatus, bool> predicate)
-        //{
-        //    if (!stepBoxes.Any()) throw new UserFriendlyException("该流程中暂无节点");
-        //    foreach (var stepBox in stepBoxes)
-        //    {
-        //        foreach (var step in stepBox.Steps)
-        //        {
-        //            if (predicate(step.Status) && (step.Handlers.Any(d => d.Id == orgCode) || step.Handlers.Any(d => d.Id == userId)))
-        //                return (stepBox, step);
-        //        }
-        //    }
-
-        //    return new();
-        //}
-
-        //new
         private WorkflowStep? GetStep(List<WorkflowStep> steps, string orgCode, string userId, Func<EWorkflowStepStatus, bool> predicate) =>
         private WorkflowStep? GetStep(List<WorkflowStep> steps, string orgCode, string userId, Func<EWorkflowStepStatus, bool> predicate) =>
             steps.FirstOrDefault(d =>
             steps.FirstOrDefault(d =>
                 predicate(d.Status) && d.Handlers.Any(x => x.Key == orgCode || x.Key == userId));
                 predicate(d.Status) && d.Handlers.Any(x => x.Key == orgCode || x.Key == userId));
 
 
-        //private WorkflowStep CreateStepBox(string workflowId, StepDefine stepDefine, string prevStepBoxId)
-        //{
-        //    var stepBox = _mapper.Map<WorkflowStep>(stepDefine);
-        //    stepBox.WorkflowId = workflowId;
-        //    stepBox.PrevStepId = prevStepBoxId;
-        //    stepBox.NextStepCode = string.Empty;
-        //    stepBox.Opinion = string.Empty;
-        //    stepBox.CountersignStartStepCode = stepDefine.CountersignStartStepCode;
-        //    stepBox.CountersignEndStepCode = stepDefine.CountersignEndStepCode;
-        //    return stepBox;
-        //}
-
-        //private List<WorkflowStep> CreateSubSteps(
-        //    bool isPrevStartCountersign,
-        //    WorkflowStep stepBox,
-        //    List<Kv> handlers,
-        //    string nextStepCode,
-        //    string? nextMainHandler,
-        //    string? prevStepId,
-        //    string? countersignId,
-        //    EWorkflowStepStatus stepStatus,
-        //    ECountersignPosition countersignPosition,
-        //    DateTime expiredTime,
-        //    StepExtension extension)
-        //{
-        //    if (countersignPosition is ECountersignPosition.None && !string.IsNullOrEmpty(countersignId))
-        //        throw UserFriendlyException.SameMessage("非法参数");
-        //    if (countersignPosition is not ECountersignPosition.None && string.IsNullOrEmpty(countersignId))
-        //        throw UserFriendlyException.SameMessage("非法参数");
-
-        //    //依据是否发起会签创建step,发起会签表示一个handler创建一个step,未发起会签默认作为或签处理,只创建一个step
-        //    var steps = new List<WorkflowStep>();
-        //    if (isPrevStartCountersign)
-        //    {
-        //        foreach (var handler in handlers)
-        //        {
-        //            var step = CreateSubStep(stepBox, new List<Kv> { handler }, nextStepCode, nextMainHandler,
-        //                prevStepId, countersignId, stepStatus, countersignPosition, expiredTime, extension);
-
-        //            steps.Add(step);
-        //        }
-        //    }
-        //    else
-        //    {
-        //        var step = CreateSubStep(stepBox, handlers, nextStepCode, nextMainHandler,
-        //            prevStepId, countersignId, stepStatus, countersignPosition, expiredTime, extension);
-
-        //        steps.Add(step);
-        //    }
-
-        //    return steps;
-        //}
-
-        //private WorkflowStep CreateSubStep(
-        //    WorkflowStep stepBox,
-        //    List<Kv> handlers,
-        //    string nextStepCode,
-        //    string? nextMainHandler,
-        //    string? prevStepId,
-        //    string? prevStepCode,
-        //    string? countersignId,
-        //    EWorkflowStepStatus stepStatus,
-        //    ECountersignPosition countersignPosition,
-        //    DateTime expiredTime)
-        //{
-        //    if (!handlers.Any())
-        //        throw new UserFriendlyException("非法参数");
-        //    var step = _mapper.Map<WorkflowStep>(stepBox);
-        //    var handlerIds = handlers.Select(d => d.Key).ToList();
-        //    var isMain = handlers.Count == 1 || (handlers.Count > 1 || handlerIds.First() == nextMainHandler);
-
-        //    step.ParentId = stepBox.Id;
-        //    step.Handlers = handlers;
-        //    step.NextStepCode = step.StepType is EStepType.End ? string.Empty : nextStepCode;
-        //    step.IsMain = isMain;
-        //    step.PrevStepId = prevStepId;
-        //    step.PrevStepCode = prevStepCode;
-        //    step.CountersignId = countersignId;
-        //    step.Status = stepStatus;
-        //    step.CountersignPosition = countersignPosition;
-        //    step.StepExpiredTime = expiredTime;
-        //    step.TimeLimit = GetTimeLimit("");//todo 过期时间
-
-        //    return step;
-        //}
-
-        //new
         private WorkflowStep CreateStep(
         private WorkflowStep CreateStep(
             StepDefine stepDefine,
             StepDefine stepDefine,
             WorkflowStep prevStep,
             WorkflowStep prevStep,

+ 11 - 1
src/Hotline/FlowEngine/Workflows/WorkflowStep.cs

@@ -228,7 +228,7 @@ public class WorkflowStep : StepBasicEntity
     {
     {
         //if (!HasStartedCountersign())
         //if (!HasStartedCountersign())
         //    throw new UserFriendlyException("该节点未发起会签");
         //    throw new UserFriendlyException("该节点未发起会签");
-        //outer的情况也属于特殊会签
+        //outer属于特殊会签
         return CountersignSteps.All(d => d.Completed);
         return CountersignSteps.All(d => d.Completed);
     }
     }
 
 
@@ -238,6 +238,16 @@ public class WorkflowStep : StepBasicEntity
     /// <returns></returns>
     /// <returns></returns>
     public bool DynamicShouldTerminal() => TerminalDynamicMark == PrevChosenStepCode;
     public bool DynamicShouldTerminal() => TerminalDynamicMark == PrevChosenStepCode;
 
 
+    /// <summary>
+    /// 是否是顶级会签汇总节点
+    /// </summary>
+    public bool IsTopCountersignEndStep(string? topCountersignStepId)
+    {
+        if (string.IsNullOrEmpty(topCountersignStepId))
+            throw new UserFriendlyException($"无效顶级会签节点编号,流程可能未处于会签中, wfId: {WorkflowId}");
+        return IsCountersignEndStep && CountersignStartStepId == topCountersignStepId;
+    }
+
     #endregion
     #endregion
 }
 }
 
 

+ 52 - 0
src/Hotline/KnowledgeBase/KnowledgeComment.cs

@@ -0,0 +1,52 @@
+using SqlSugar;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Repository;
+
+namespace Hotline.KnowledgeBase
+{
+	[Description("知识库评论")]
+	public class KnowledgeComment : FullStateEntity
+	{
+		/// <summary>
+		/// 知识库ID
+		/// </summary>
+		[SugarColumn(ColumnDescription = "知识库ID")]
+		public string KnowledgeId { get; set; }
+
+		/// <summary>
+		/// 知识库
+		/// </summary>
+		[Navigate(NavigateType.OneToOne, nameof(KnowledgeId))]
+		public Knowledge Knowledge { get; set; }
+
+		/// <summary>
+		/// 评论内容
+		/// </summary>
+		[SugarColumn(ColumnDescription = "评论内容", ColumnDataType = "varchar(2000)")]
+		public string? Content { get; set; }
+
+		/// <summary>
+		/// 回复ID
+		/// </summary>
+		[SugarColumn(ColumnDescription = "回复ID")]
+		public string? ReplyId { get; set; }
+
+		/// <summary>
+		/// 匿名
+		/// </summary>
+		[SugarColumn(ColumnDescription = "匿名")]
+		public bool Cryptonym { get; set; }= false;
+
+		/// <summary>
+		/// 回复数
+		/// </summary>
+		[SugarColumn(ColumnDescription = "回复数")]
+		public int ReplyNum { get; set; } = 0;
+
+	}
+}

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

@@ -952,6 +952,32 @@ namespace Hotline.Permissions
 		AddKnowledgeScore = 400902,
 		AddKnowledgeScore = 400902,
 		#endregion
 		#endregion
 
 
+		#region 知识评论
+		/// <summary>
+		/// 知识评论列表
+		/// </summary>
+		[Display(GroupName = "KnowledgeComment", Name = "知识评论列表", Description = "知识评论列表")]
+		KnowledgeCommentList = 401000,
+
+		/// <summary>
+		/// 新增知识评论
+		/// </summary>
+		[Display(GroupName = "KnowledgeComment", Name = "新增知识评论", Description = "新增知识评论")]
+		AddKnowledgeComment = 401001,
+
+		/// <summary>
+		/// 删除知识评论
+		/// </summary>
+		[Display(GroupName = "KnowledgeComment", Name = "删除知识评论", Description = "删除知识评论")]
+		DeleteKnowledgeComment = 401002,
+
+		/// <summary>
+		/// 修改知识评论
+		/// </summary>
+		[Display(GroupName = "KnowledgeComment", Name = "修改知识评论", Description = "修改知识评论")]
+		UpdateKnowledgeComment = 401003,
+		#endregion
+
 		#endregion
 		#endregion
 
 
 		#region 业务管理(500)
 		#region 业务管理(500)

+ 3 - 0
src/XF.Domain.Repository/Entity.cs

@@ -2,6 +2,7 @@
 using XF.Domain.Entities;
 using XF.Domain.Entities;
 using XF.Domain.Events;
 using XF.Domain.Events;
 using XF.Domain.Extensions;
 using XF.Domain.Extensions;
+using XF.Utility.SequentialId;
 
 
 namespace XF.Domain.Repository;
 namespace XF.Domain.Repository;
 
 
@@ -288,4 +289,6 @@ public abstract class PositionWorkflowEntity : PositionEntity, IWorkflow
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);
         }
         }
     }
     }
+
+    public void InitId() => Id = SequentialStringGenerator.Create();
 }
 }