Procházet zdrojové kódy

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

Dun.Jason před 1 rokem
rodič
revize
6f5d4beda2

+ 7 - 1
src/Hotline.Ai.Jths/AiQualityService.cs

@@ -75,7 +75,7 @@ namespace Hotline.Ai.Jths
 			req.AddHeader("content-type", "application/json");
 			req.AddHeader("token", "");
 			req.AddHeader("version", "1.0");
-			var sign = MD5Encrypt(request.ToString());
+			var sign = Base64En(MD5Encrypt(request.ToString()));
 			req.AddHeader("sign", sign);
 			req.AddHeader("signType", "md5");
 			req.AddHeader("appkey", "MTAwMDAx");
@@ -113,5 +113,11 @@ namespace Hotline.Ai.Jths
 				sb.Append(t[i].ToString("x").PadLeft(2, '0'));
 			return sb.ToString();
 		}
+
+		private static string Base64En(string? model) 
+		{
+			var bytes = Encoding.UTF8.GetBytes(model);
+			return Convert.ToBase64String(bytes);
+		}
 	}
 }

+ 35 - 23
src/Hotline.Api/Controllers/OrderController.cs

@@ -1108,9 +1108,11 @@ public class OrderController : BaseController
             .FirstAsync(x => x.Id == id);
         var rspModel = _mapper.Map<OrderDelayDto>(model);
         rspModel.IsCanHandle = model.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
-        var files = await _fileRepository.Queryable()
-            .Where(x => x.Key == rspModel.Id && string.IsNullOrEmpty(x.FlowKey)).ToListAsync();
-        if (files.Any()) rspModel.Files = _mapper.Map<List<FileDto>>(files);
+        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;
     }
 
@@ -1347,9 +1349,11 @@ public class OrderController : BaseController
             .FirstAsync(x => x.Id == id);
         var rspModel = _mapper.Map<OrderScreenListDto>(model);
         rspModel.IsCanHandle = model.Workflow.CanHandle(_sessionContext.RequiredUserId, _sessionContext.RequiredOrgId);
-        var files = await _fileRepository.Queryable()
-            .Where(x => x.Key == rspModel.Id && string.IsNullOrEmpty(x.FlowKey)).ToListAsync();
-        if (files.Any()) rspModel.Files = _mapper.Map<List<FileDto>>(files);
+        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;
     }
 
@@ -1557,14 +1561,13 @@ public class OrderController : BaseController
         if (orderSupervise != null)
         {
             orderSuperviseDto = _mapper.Map<OrderSuperviseDto>(orderSupervise);
-            var files = await _fileRepository.Queryable().Where(x => x.Key == orderSupervise.Id).ToListAsync();
-            if (files.Any())
-            {
-                var applyFiles = files.Where(x => x.Classify == "督办申请").ToList();
-                if (applyFiles.Any()) orderSuperviseDto.Files = _mapper.Map<List<FileDto>>(applyFiles);
-                var replyFiles = files.Where(x => x.Classify == "督办回复").ToList();
-                if (replyFiles.Any()) orderSuperviseDto.ReplyFiles = _mapper.Map<List<FileDto>>(replyFiles);
-            }
+			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;
@@ -1709,9 +1712,12 @@ public class OrderController : BaseController
         if (orderUrge != null)
         {
             orderUrgeDto = _mapper.Map<OrderUrgeDto>(orderUrge);
-            var files = await _fileRepository.Queryable().Where(x => x.Key == orderUrge.Id).ToListAsync();
-            if (files.Any()) orderUrgeDto.Files = _mapper.Map<List<FileDto>>(files);
-        }
+            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;
     }
@@ -1824,9 +1830,12 @@ public class OrderController : BaseController
 
         var dto = _mapper.Map<OrderDto>(order!);
 
-        var files = await _fileRepository.Queryable()
-            .Where(x => x.Key == dto.Id && x.Classify == "办理上传" && string.IsNullOrEmpty(x.FlowKey)).ToListAsync();
-        dto.Files = _mapper.Map<List<FileDto>>(files);
+        if (dto.FileJson != null && dto.FileJson.Any())
+        {
+	        var ids = order.FileJson.Select(x => x.Id).ToList();
+	        var files = await _fileRepository.GetFilesAsync(ids, HttpContext.RequestAborted);
+            dto.Files = files.Where(x => x.Classify == "办理上传" && string.IsNullOrEmpty(x.FlowKey)).ToList();
+		}
 
         var call = await _trCallRecordRepository.Queryable().Where(x => x.CallAccept == order.CallId).FirstAsync();
         if (call != null) dto.RecordingFileUrl = call.RecordingFileUrl;
@@ -2508,9 +2517,12 @@ public class OrderController : BaseController
         if (item != null)
         {
             itemDto = _mapper.Map<OrderSpecialDto>(item);
-            var files = await _fileRepository.Queryable().Where(x => x.Key == item.Id).ToListAsync();
-            if (files.Any()) itemDto.Files = _mapper.Map<List<FileDto>>(files);
-        }
+            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;
     }

+ 10 - 15
src/Hotline.Api/Controllers/WorkflowController.cs

@@ -465,25 +465,20 @@ public class WorkflowController : BaseController
         var workflowDto = _mapper.Map<WorkflowDto>(workflow);
         if (workflowDto.Traces.Any())
         {
-            foreach (var item in workflowDto.Traces)
-            {
-                if (item.FileJson != null && item.FileJson.Any())
-                {
-                    var files = await _fileRepository.Queryable().Where(x => x.FlowKey == item.StepId).ToListAsync();
-                    if (files.Any()) item.Files = _mapper.Map<List<FileDto>>(files);
-                }
-            }
+	        workflowDto.Traces = await _fileRepository.WorkflowTraceRecursion(workflowDto.Traces, HttpContext.RequestAborted);
         }
-
         return workflowDto;
     }
 
-    /// <summary>
-    /// 查询被督办/催办部门
-    /// </summary>
-    /// <param name="workflowId"></param>
-    /// <returns></returns>
-    [HttpGet("{workflowId}/urge")]
+   
+
+
+	/// <summary>
+	/// 查询被督办/催办部门
+	/// </summary>
+	/// <param name="workflowId"></param>
+	/// <returns></returns>
+	[HttpGet("{workflowId}/urge")]
     public async Task<IReadOnlyList<Kv>> GetUrgeOrgs(string workflowId)
     {
         /*

+ 3 - 18
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -141,28 +141,13 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
             _sessionContext.RequiredUserId, _sessionContext.RequiredOrgId, externalId, expiredTimeConfig?.TimeText,
             expiredTimeConfig.Count, expiredTimeConfig.TimeType, expiredTimeConfig.ExpiredTime, cancellationToken);
 
-        //startstep
-        var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
-        if (startStepDefine.InstanceMode is EInstanceMode.Config)
-            nextSteps.First(d => d.Code == dto.NextStepCode).Selected = true;
-        var startStep = new WorkflowStep
-        {
-            WorkflowId = workflow.Id,
-            Handlers = new List<Kv> { new(_sessionContext.RequiredUserId, _sessionContext.UserName) },
-            NextSteps = nextSteps,
-            IsMain = true,
-            IsOrigin = true,
-            Status = EWorkflowStepStatus.WaitForHandle,
-            PrevChosenStepCode = null,
-            StepExpiredTime = workflow.ExpiredTime,
-        };
-        startStep.InitId();
+        var startStep = _workflowDomainService.CreateStartStep(workflow, startStepDefine, dto, 
+            new List<Kv> { new(_sessionContext.RequiredUserId, _sessionContext.UserName) });
+
         if (dto.Files.Any())
             startStep.FileJson =
                 await _fileRepository.AddFileAsync(dto.Files, workflow.ExternalId, startStep.Id, cancellationToken);
 
-        var startDefine = workflow.WorkflowDefinition.FindStartStepDefine();
-        _mapper.Map(startDefine, startStep);
         await _workflowStepRepository.AddAsync(startStep, cancellationToken);
         workflow.Steps.Add(startStep);
 

+ 22 - 0
src/Hotline.Repository.SqlSugar/File/FileRepository.cs

@@ -2,6 +2,7 @@
 using Hotline.Orders;
 using Hotline.Repository.SqlSugar.DataPermissions;
 using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using MapsterMapper;
 using Microsoft.AspNetCore.Http;
 using Newtonsoft.Json;
@@ -45,5 +46,26 @@ namespace Hotline.Repository.SqlSugar.File
 			await AddRangeAsync(newFiles, cancellationToken);
 			return newFiles.Select(x=> new FileJson { Id = x.Id,FileId = x.Additions,Path = x.Path}).ToList();
 		}
+
+		public async Task<List<FileDto>> GetFilesAsync(List<string> ids, CancellationToken cancellationToken) 
+		{
+			var files = await Queryable().In(x=>x.Id,ids).ToListAsync(cancellationToken);
+			return files.Any() ? _mapper.Map<List<FileDto>>(files) : new List<FileDto>();
+		}
+
+		public async Task<List<WorkflowTraceDto>> WorkflowTraceRecursion(List<WorkflowTraceDto> dto, CancellationToken cancellationToken)
+		{
+			foreach (var item in dto)
+			{
+				if (item.FileJson != null && item.FileJson.Any())
+				{
+					var ids = item.FileJson.Select(x => x.Id).ToList();
+					item.Files = await GetFilesAsync(ids, cancellationToken);
+				}
+
+				if (item.Traces != null && item.Traces.Any()) item.Traces =  await WorkflowTraceRecursion(item.Traces, cancellationToken);
+			}
+			return dto;
+		}
 	}
 }

+ 2 - 0
src/Hotline.Share/Dtos/Order/QueryOrderDto.cs

@@ -354,6 +354,8 @@ namespace Hotline.Share.Dtos.Order
         public bool IsCanHandle { get; set; }
 
         public List<FileDto> Files { get; set; }
+
+        public List<FileJson> FileJson { get; set; }
 	}
 
 

+ 2 - 2
src/Hotline.Share/Dtos/Users/UserDto.cs

@@ -104,9 +104,9 @@ public record UpdateUserDto
     public string? OrgId { get; set; }
 
     /// <summary>
-    /// 部门编码(冗余)
+    /// 用户类型
     /// </summary>
-    public string? OrgCode { get; set; }
+    public EUserType UserType { get; set; }
 
     /// <summary>
     /// 默认分机号

+ 3 - 0
src/Hotline/File/IFileRepository.cs

@@ -1,5 +1,6 @@
 using Hotline.Orders;
 using Hotline.Share.Dtos.File;
+using Hotline.Share.Dtos.FlowEngine.Workflow;
 using System;
 using System.Collections.Generic;
 using System.Linq;
@@ -12,5 +13,7 @@ namespace Hotline.File
 	public interface IFileRepository : IRepository<File>
 	{
 		Task<List<FileJson>> AddFileAsync(List<FileDto> files ,string id, string flowId = "",CancellationToken cancellationToken = default);
+		Task<List<FileDto>> GetFilesAsync(List<string> ids, CancellationToken cancellationToken);
+		Task<List<WorkflowTraceDto>> WorkflowTraceRecursion(List<WorkflowTraceDto> dto, CancellationToken cancellationToken);
 	}
 }

+ 5 - 0
src/Hotline/FlowEngine/Workflows/IWorkflowDomainService.cs

@@ -130,5 +130,10 @@ namespace Hotline.FlowEngine.Workflows
         /// 新增流程流转记录
         /// </summary>
         Task AddTracesAsync(string workflowId, List<WorkflowTrace> traces, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 创建开始节点
+        /// </summary>
+        WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto, List<Kv> handlers);
     }
 }

+ 53 - 12
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -5,6 +5,7 @@ using Hotline.FlowEngine.WorkflowModules;
 using Hotline.Settings;
 using Hotline.Share.Dtos;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Dtos.FlowEngine.Definition;
 using Hotline.Share.Enums.FlowEngine;
 using Hotline.Share.Enums.Settings;
 using MapsterMapper;
@@ -766,8 +767,43 @@ namespace Hotline.FlowEngine.Workflows
             await _workflowTraceRepository.AddRangeAsync(traces, cancellationToken);
         }
 
+        /// <summary>
+        /// 创建开始节点
+        /// </summary>
+        public WorkflowStep CreateStartStep(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto, List<Kv> handles)
+        {
+            //startstep
+            var nextSteps = _mapper.Map<List<StepSimple>>(startStepDefine.NextSteps);
+            if (startStepDefine.InstanceMode is EInstanceMode.Config)
+            {
+                var selectedStep = nextSteps.FirstOrDefault(d => d.Code == dto.NextStepCode);
+                if (selectedStep is not null)
+                    selectedStep.Selected = true;
+            }
+            var startStep = _mapper.Map<WorkflowStep>(startStepDefine);
+            startStep.WorkflowId = workflow.Id;
+            startStep.Handlers = handles;
+            startStep.NextSteps = nextSteps;
+            startStep.IsMain = true;
+            startStep.IsOrigin = true;
+            startStep.Status = EWorkflowStepStatus.WaitForHandle;
+            startStep.PrevChosenStepCode = null;
+            startStep.StepExpiredTime = workflow.ExpiredTime;
+            
+            startStep.InitId();
+            return startStep;
+        }
+
         #region private method
 
+        public async Task<WorkflowStep> CreateStartStepAsync(Workflow workflow, StepDefine startStepDefine, BasicWorkflowDto dto,
+            List<Kv> handles, CancellationToken cancellationToken)
+        {
+            var startStep = CreateStartStep(workflow, startStepDefine, dto, handles);
+            await _workflowStepRepository.AddAsync(startStep, cancellationToken);
+            return startStep;
+        }
+
         //更新目标节点前一节点的会签办理完成状态
         private void PrevStepCsHandled(Workflow workflow, WorkflowStep targetStep, ref List<WorkflowStep> updateSteps)
         {
@@ -1255,13 +1291,19 @@ namespace Hotline.FlowEngine.Workflows
         }
 
         private async Task<bool> RecallAsync(Workflow workflow, BasicWorkflowDto dto, FlowAssignInfo flowAssignInfo,
-            StepDefine targetStepDefine,
-            WorkflowStep targetStep, EWorkflowTraceStatus traceStatus, CancellationToken cancellationToken)
+            StepDefine targetStepDefine, WorkflowStep targetStep,
+            EWorkflowTraceStatus traceStatus, CancellationToken cancellationToken)
         {
+            var targetIsStartStep = targetStepDefine.StepType is EStepType.Start;
+
             //get targetStep's previous
-            var targetPrevStep = workflow.Steps.FirstOrDefault(d => d.Id == targetStep.PrevStepId);
-            if (targetPrevStep == null)
-                throw new UserFriendlyException($"{nameof(RecallAsync)}, 未找到目标节点的前一节点, flowId: {workflow.Id}");
+            WorkflowStep? targetPrevStep = null;
+            if (!targetIsStartStep)
+            {
+                targetPrevStep = workflow.Steps.FirstOrDefault(d => d.Id == targetStep.PrevStepId);
+                if (targetPrevStep == null)
+                    throw new UserFriendlyException($"{nameof(RecallAsync)}, 未找到目标节点的前一节点, flowId: {workflow.Id}");
+            }
 
             //查询所有目标节点之后的节点,然后删掉(包括目标节点)
             var removeSteps = GetStepsBehindTargetStep(workflow.Steps, targetStep);
@@ -1276,19 +1318,18 @@ namespace Hotline.FlowEngine.Workflows
             if (workflow.Status is EWorkflowStatus.Completed)
                 workflow.SetStatusRunnable();
 
-            //recreate targetStep
-            //var targetStepBoxNew = await CreateStepAsync(workflow, targetStepDefine, dto, EWorkflowStepStatus.WaitForAccept,
-            //     targetPrevStepBox, targetPrevStep, traceStatus, workflow.ExpiredTime, cancellationToken);
-
-            var targetStepsNew = await CreateConfigStepsAsync(workflow, targetStepDefine, targetPrevStep, dto,
-                flowAssignInfo, cancellationToken);
+            var targetStepNew = targetIsStartStep
+                ? await CreateStartStepAsync(workflow, targetStepDefine, dto,
+                    new List<Kv> { new(_sessionContext.RequiredUserId, _sessionContext.UserName) }, cancellationToken)
+                : (await CreateConfigStepsAsync(workflow, targetStepDefine, targetPrevStep, dto, flowAssignInfo,
+                    cancellationToken)).First();
 
             //更新当前办理节点信息
             workflow.UpdateWorkflowCurrentStepInfo(dto.IsStartCountersign,
                 _sessionContext.RequiredUserId, _sessionContext.UserName,
                 _sessionContext.RequiredOrgId, _sessionContext.OrgName,
                 _sessionContext.OrgAreaCode, _sessionContext.OrgAreaName,
-                nextStep: targetStepsNew.First());
+                nextStep: targetStepNew);
 
             //calc workflow expired time
             var isOrgToCenter = CheckIfFlowFromOrgToCenter(workflow, targetStep);