xf преди 1 година
родител
ревизия
a945a428d7

+ 4 - 0
src/Hotline.Api.Sdk/Hotline.Api.Sdk.csproj

@@ -12,4 +12,8 @@
     <PackageReference Include="Fw.Utility.UnifyResponse" Version="1.0.0" />
   </ItemGroup>
 
+  <ItemGroup>
+    <ProjectReference Include="..\Hotline.Share\Hotline.Share.csproj" />
+  </ItemGroup>
+
 </Project>

+ 32 - 12
src/Hotline.Api.Sdk/HotlineAuthenticator.cs

@@ -1,11 +1,13 @@
-using RestSharp;
+using System.Net;
+using Fw.Utility.UnifyResponse;
+using RestSharp;
 using RestSharp.Authenticators;
 
 namespace Hotline.Api.Sdk;
 
 public class HotlineAuthenticator : AuthenticatorBase
 {
-    private readonly string _tokenKey = "X-Auth-Token";
+    private readonly string _tokenKey = "Bearer";
     private readonly string _baseUrl;
     private readonly string _apiKey;
     private readonly string _apiSecret;
@@ -23,6 +25,7 @@ public class HotlineAuthenticator : AuthenticatorBase
         {
             Token = await GetTokenAsync(default);
         }
+
         return new HeaderParameter(_tokenKey, Token);
     }
 
@@ -30,21 +33,31 @@ public class HotlineAuthenticator : AuthenticatorBase
     {
         var options = new RestClientOptions(_baseUrl);
         using var client = new RestClient(options);
-        var request = new RestRequest("api/v1/Identity/login/token")
-            .AddJsonBody(new { username = _apiKey, password = _apiSecret });
+        //var request = new RestRequest("api/v1/Identity/login/token")
+        //    .AddJsonBody(new TokenRequest { Username = _apiKey, Password = _apiSecret });
         try
         {
-            var response = await client.GetAsync(request, cancellationToken);
-            if (!response.IsSuccessful)
+            var response = await client.PostJsonAsync<TokenRequest, ApiResponse<string>>("api/v1/Identity/login/token",
+                   new TokenRequest { Username = _apiKey, Password = _apiSecret }, cancellationToken);
+            if (!response?.IsSuccess ?? false)
                 throw new HttpRequestException(
-                    $"呼叫中心服务授权请求失败,HttpCode: {response.StatusCode}, Error: {response.ErrorMessage}");
-            var token = response.Headers?.FirstOrDefault(d => d.Name == _tokenKey);
-            if (token is null)
+                    $"呼叫中心服务授权请求失败,HttpCode: {response.Code}, Error: {response.Error}");
+            var token = response?.Result;
+            if (string.IsNullOrEmpty(token))
                 throw new HttpRequestException("呼叫中心服务授权失败");
-            if (token?.Value is null)
-                throw new HttpRequestException("呼叫中心token无效");
 
-            return token.Value.ToString();
+            return token;
+            //var response = await client.GetAsync(request, cancellationToken);
+            //if (!response.IsSuccessful)
+            //    throw new HttpRequestException(
+            //        $"呼叫中心服务授权请求失败,HttpCode: {response.StatusCode}, Error: {response.ErrorMessage}");
+            //var token = response.Headers?.FirstOrDefault(d => d.Name == _tokenKey);
+            //if (token is null)
+            //    throw new HttpRequestException("呼叫中心服务授权失败");
+            //if (token?.Value is null)
+            //    throw new HttpRequestException("呼叫中心token无效");
+
+            //return token.Value.ToString();
         }
         catch (Exception e)
         {
@@ -52,4 +65,11 @@ public class HotlineAuthenticator : AuthenticatorBase
         }
 
     }
+
+    public class TokenRequest
+    {
+        public string Username { get; set; }
+
+        public string Password { get; set; }
+    }
 }

+ 69 - 0
src/Hotline.Api.Sdk/HotlineClient.cs

@@ -0,0 +1,69 @@
+using Fw.Utility.UnifyResponse;
+using RestSharp;
+
+namespace Hotline.Api.Sdk;
+
+public class HotlineClient : IHotlineClient, IDisposable
+{
+    private readonly RestClient _client;
+
+    public HotlineClient(string baseUrl, string apiKey, string apiSecret)
+    {
+        var options = new RestClientOptions(baseUrl)
+        {
+            Authenticator = new HotlineAuthenticator(baseUrl, apiKey, apiSecret)
+        };
+        _client = new RestClient(options);
+    }
+
+    public async Task<ApiResponse<TResponse>> ExecuteAsync<TRequest, TResponse>(string path, Method httpMethod,
+        TRequest request, CancellationToken cancellationToken)
+        where TRequest : class
+    {
+        var req = new RestRequest(path, httpMethod)
+            .AddJsonBody(request);
+
+        try
+        {
+            var response = await _client.ExecuteAsync<ApiResponse<TResponse>>(req, cancellationToken);
+            if (!response?.IsSuccessful ?? false)
+                throw new HttpRequestException(
+                    $"请求热线服务失败, Code: {response.StatusCode}, Error: {response.ErrorMessage}");
+
+            return response.Data;
+        }
+        catch (Exception e)
+        {
+            throw new HttpRequestException($"请求热线服务失败,Error: {e.Message}");
+        }
+    }
+
+    public async Task<ApiResponse> ExecuteAsync<TRequest>(string path, Method httpMethod, TRequest request,
+        CancellationToken cancellationToken) 
+        where TRequest : class
+    {
+        var req = new RestRequest(path, httpMethod)
+            .AddJsonBody(request);
+
+        try
+        {
+            var response = await _client.ExecuteAsync<ApiResponse>(req, cancellationToken);
+            if (!response?.IsSuccessful ?? false)
+                throw new HttpRequestException(
+                    $"请求热线服务失败, Code: {response.StatusCode}, Error: {response.ErrorMessage}");
+
+            return response.Data;
+        }
+        catch (Exception e)
+        {
+            throw new HttpRequestException($"请求热线服务失败,Error: {e.Message}");
+        }
+    }
+
+    /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
+    public void Dispose()
+    {
+        _client?.Dispose();
+        GC.SuppressFinalize(this);
+    }
+}

+ 7 - 34
src/Hotline.Api.Sdk/IHotlineClient.cs

@@ -8,41 +8,14 @@ using RestSharp;
 
 namespace Hotline.Api.Sdk
 {
-    public interface IHotlineClient
+    public partial interface IHotlineClient
     {
-        Task<ApiResponse<TResponse>> ExecuteAsync<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken)
-            where TRequest : HotlineRequest;
-    }
-
-    public abstract class HotlineRequest
-    {
-        public abstract string Path();
-        public abstract Method HttpMethod();
-    }
-
-    public class HotlineClient : IHotlineClient, IDisposable
-    {
-        private readonly RestClient _client;
-
-        public HotlineClient(string baseUrl, string apiKey, string apiSecret)
-        {
-            var options = new RestClientOptions(baseUrl)
-            {
-                Authenticator = new HotlineAuthenticator(baseUrl, apiKey, apiSecret)
-            };
-            _client = new RestClient(options);
-        }
-
-        public async Task<ApiResponse<TResponse>> ExecuteAsync<TRequest, TResponse>(TRequest request, CancellationToken cancellationToken) where TRequest : HotlineRequest
-        {
-            throw new NotImplementedException();
-        }
+        Task<ApiResponse<TResponse>> ExecuteAsync<TRequest, TResponse>(string path, Method httpMethod, TRequest request,
+            CancellationToken cancellationToken)
+            where TRequest : class;
 
-        /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
-        public void Dispose()
-        {
-            _client?.Dispose();
-            GC.SuppressFinalize(this);
-        }
+        Task<ApiResponse> ExecuteAsync<TRequest>(string path, Method httpMethod, TRequest request,
+            CancellationToken cancellationToken)
+            where TRequest : class;
     }
 }

+ 17 - 0
src/Hotline.Api.Sdk/Order/IHotlineClient.Order.cs

@@ -0,0 +1,17 @@
+using Hotline.Share.Dtos.Order;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Fw.Utility.UnifyResponse;
+using RestSharp;
+
+namespace Hotline.Api.Sdk
+{
+    public partial interface IHotlineClient
+    {
+        public Task<ApiResponse> DelayProvinceResultAsync(DelayProvinceResultDto request, CancellationToken cancellationToken) =>
+            ExecuteAsync<DelayProvinceResultDto>("api/v1/order/delay/province/result", Method.Post, request, cancellationToken);
+    }
+}

+ 254 - 219
src/Hotline.Api/Controllers/OrderController.cs

@@ -76,7 +76,7 @@ public class OrderController : BaseController
     private readonly IRepository<OrderObserve> _orderObserveRepository;
 
 
-	public OrderController(
+    public OrderController(
         IOrderDomainService orderDomainService,
         IOrderRepository orderRepository,
         IWorkflowApplication workflowApplication,
@@ -110,7 +110,7 @@ public class OrderController : BaseController
         IRepeatableEventDetailRepository repeatableEventDetailRepository,
         IRepository<OrderWord> orderWrodRepository,
         IRepository<OrderObserve> orderObserveRepository
-		)
+        )
     {
         _orderDomainService = orderDomainService;
         _orderRepository = orderRepository;
@@ -146,7 +146,7 @@ public class OrderController : BaseController
         _orderWrodRepository = orderWrodRepository;
         _orderObserveRepository = orderObserveRepository;
 
-	}
+    }
 
     #region 工单发布
 
@@ -603,15 +603,15 @@ public class OrderController : BaseController
     /// <param name="dto"></param>
     /// <returns></returns>
     [Permission(EPermission.QueryOrderRedoRecord)]
-	[HttpGet("redo")]
-	public async Task<PagedDto<OrderRedo>> QueryOrderRedo([FromQuery] QueryOrderRedoRecordDto dto)
-	{
-		var (total, items) = await _orderRedoRepository.Queryable()
-			.Includes(x => x.Order)
-			.WhereIF(!string.IsNullOrEmpty(dto.Keyword),
-				d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
-			.OrderByDescending(x => x.CreationTime)
-			.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+    [HttpGet("redo")]
+    public async Task<PagedDto<OrderRedo>> QueryOrderRedo([FromQuery] QueryOrderRedoRecordDto dto)
+    {
+        var (total, items) = await _orderRedoRepository.Queryable()
+            .Includes(x => x.Order)
+            .WhereIF(!string.IsNullOrEmpty(dto.Keyword),
+                d => d.Order.Title.Contains(dto.Keyword!) || d.Order.No.Contains(dto.Keyword!))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
 
         return new PagedDto<OrderRedo>(total, items);
     }
@@ -831,9 +831,44 @@ public class OrderController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpPost("delay/province/result")]
-    public async Task DelayProvinceResult()
+    public async Task DelayProvinceResult([FromBody] DelayProvinceResultDto dto)
     {
-        //pass, reject
+        var orderDelay = await _orderDelayRepository.Queryable()
+            .Includes(d => d.Order)
+            .Includes(d=>d.Workflow)
+            .FirstAsync(d => d.Order.ProvinceNo == dto.No && d.DelayState == EDelayState.Examining,
+                HttpContext.RequestAborted);
+        if (orderDelay is null)
+            throw new UserFriendlyException("无效省工单编号");
+
+        if (dto.IsPass)
+        {
+            var nextDtos =
+                await _workflowApplication.GetNextStepsAsync(orderDelay.WorkflowId, HttpContext.RequestAborted);
+            var nextStep = nextDtos.Steps.FirstOrDefault(d => d.Key == "end");
+            if (nextStep is null)
+                throw new UserFriendlyException("未查询到结束节点");
+
+            var nextDto = new NextWorkflowDto
+            {
+                WorkflowId = orderDelay.WorkflowId,
+                StepExpiredTime = orderDelay.Workflow.ExpiredTime,
+                NextStepCode = nextStep.Key,
+                NextStepName = nextStep.Value,
+                NextMainHandler = nextStep.Key,
+                Opinion = dto.Opinion
+            };
+            await _workflowApplication.NextAsync(nextDto, HttpContext.RequestAborted);
+        }
+        else
+        {
+            var rejectDto = new RejectDto
+            {
+                WorkflowId = orderDelay.WorkflowId,
+                Opinion = dto.Opinion,
+            };
+            await _workflowApplication.RejectAsync(rejectDto, HttpContext.RequestAborted);
+        }
     }
 
     /// <summary>
@@ -1443,7 +1478,7 @@ public class OrderController : BaseController
             .Where(x => x.OrderId == id).Distinct().ToListAsync();
         var repeatables = _mapper.Map<List<RepeatableEventDetailOpDto>>(repeatablesMap);
         dto.RepeatableEventDetails = repeatables;
-		return dto;
+        return dto;
     }
 
     /// <summary>
@@ -1511,15 +1546,15 @@ public class OrderController : BaseController
         {
             var reAdds = dto.RepeatableEventDetails.Where(x => string.IsNullOrEmpty(x.OrderId) && !x.IsDeleted).ToList();
             var reDeletes = dto.RepeatableEventDetails.Where(x => !string.IsNullOrEmpty(x.OrderId) && x.IsDeleted).ToList();
-			reAdds.ForEach(x => x.OrderId = dto.Id);
-	        List<RepeatableEventDetail> repeatables = _mapper.Map<List<RepeatableEventDetail>>(reAdds);
-	        await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted);
-	        if (reDeletes?.Any()?? false)
-	        {
+            reAdds.ForEach(x => x.OrderId = dto.Id);
+            List<RepeatableEventDetail> repeatables = _mapper.Map<List<RepeatableEventDetail>>(reAdds);
+            await _repeatableEventDetailRepository.AddRangeAsync(repeatables, HttpContext.RequestAborted);
+            if (reDeletes?.Any() ?? false)
+            {
                 await _repeatableEventDetailRepository.DeleteAsync(reDeletes, HttpContext.RequestAborted);
-			}
+            }
         }
-		_mapper.Map(dto, order);
+        _mapper.Map(dto, order);
         await _orderRepository.UpdateOrderNavAsync(order, HttpContext.RequestAborted);
     }
 
@@ -1623,7 +1658,7 @@ public class OrderController : BaseController
             ChannelOptions = _sysDicDataCacheManager.GetSysDicDataCache(TimeLimitBaseDataConsts.SourceChannel),
             AcceptTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.AcceptType),
             EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
-            PushTypeOptions =_sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType),
+            PushTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.PushType),
             GenderOptions = EnumExts.GetDescriptions<EGender>(),
             IdentityTypeOptions = EnumExts.GetDescriptions<EIdentityType>(),
             LicenceTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.LicenceType),
@@ -1649,8 +1684,8 @@ public class OrderController : BaseController
             NationOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Nation),
             MarketTypeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.MarketType),
             IndustryClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.IndustryClassify),
-            BrandOptions =_sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Brand),
-            ObjectClassifyOptions =_sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ObjectClassify),
+            BrandOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.Brand),
+            ObjectClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ObjectClassify),
             ComplainClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ComplainClassify),
             ReportClassifyOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.ReportClassify),
             SalesModeOptions = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.SalesMode),
@@ -1663,23 +1698,23 @@ public class OrderController : BaseController
         return rsp;
     }
 
-	/// <summary>
-	/// 扩展信息新增页面基础数据
-	/// </summary>
-	/// <returns></returns>
-	[HttpPost("order_repeatable_event")]
-	public async Task<bool> RepeatableEvent(QueryRepeatableEventDto dto)
-	{
-		var exp = Expressionable.Create<Order>()
-			.OrIF(!string.IsNullOrEmpty(dto.HotspotSpliceName), x => x.HotspotSpliceName.EndsWith(dto.HotspotSpliceName!))
-			.OrIF(!string.IsNullOrEmpty(dto.Address), x => x.Address != null && x.Address.EndsWith(dto.Address!));
-		var count = await _orderRepository.Queryable()
-			.Where(exp.ToExpression())
-			.Where(d => d.CreationTime.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd"))
-			.CountAsync();
-		var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RepeatableEventNum);
-		return count >= int.Parse(setting?.SettingValue[0] ?? "0");
-	}
+    /// <summary>
+    /// 扩展信息新增页面基础数据
+    /// </summary>
+    /// <returns></returns>
+    [HttpPost("order_repeatable_event")]
+    public async Task<bool> RepeatableEvent(QueryRepeatableEventDto dto)
+    {
+        var exp = Expressionable.Create<Order>()
+            .OrIF(!string.IsNullOrEmpty(dto.HotspotSpliceName), x => x.HotspotSpliceName.EndsWith(dto.HotspotSpliceName!))
+            .OrIF(!string.IsNullOrEmpty(dto.Address), x => x.Address != null && x.Address.EndsWith(dto.Address!));
+        var count = await _orderRepository.Queryable()
+            .Where(exp.ToExpression())
+            .Where(d => d.CreationTime.ToString("yyyy-MM-dd") == DateTime.Now.ToString("yyyy-MM-dd"))
+            .CountAsync();
+        var setting = _systemSettingCacheManager.GetSetting(SettingConstants.RepeatableEventNum);
+        return count >= int.Parse(setting?.SettingValue[0] ?? "0");
+    }
 
     #endregion
 
@@ -1917,24 +1952,24 @@ public class OrderController : BaseController
         await _repeatableEventDetailRepository.RemoveAsync(x => x.RepeatableId == dto.Id);
     }
 
-	/// <summary>
-	/// 删除重复性事件明细
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.DeleteRepeatableEventDetail)]
-	[HttpDelete("repeatable_event_detail/{id}")]
-    public async Task Delete([FromBody] string id  )
+    /// <summary>
+    /// 删除重复性事件明细
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.DeleteRepeatableEventDetail)]
+    [HttpDelete("repeatable_event_detail/{id}")]
+    public async Task Delete([FromBody] string id)
     {
-	    await _repeatableEventDetailRepository.RemoveAsync(x => x.Id == id);
+        await _repeatableEventDetailRepository.RemoveAsync(x => x.Id == id);
     }
 
-	/// <summary>
-	/// 更新重复性事件
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.UpdateRepeatableEvent)]
+    /// <summary>
+    /// 更新重复性事件
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.UpdateRepeatableEvent)]
     [HttpPut("repeatable_event")]
     public async Task Update([FromBody] RepeatableEventUpdateDto dto)
     {
@@ -1990,168 +2025,168 @@ public class OrderController : BaseController
             .Includes(x => x.Details, y => y.Order)
             .FirstAsync(x => x.Id == dto.Id);
     }
-	#endregion
-
-	#region 工单词库
-	/// <summary>
-	/// 新增工单词库
-	/// </summary>
-	/// <param name="dtos"></param>
-	/// <returns></returns>
-	[Permission(EPermission.AddOrderWord)]
-	[HttpPost("order_word")]
-	public async Task Add([FromBody] OrderWordAddDto dto)
-	{
-		var word = _mapper.Map<OrderWord>(dto);
-		await _orderWrodRepository.AddAsync(word, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 删除工单词库
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.DeleteOrderWord)]
-	[HttpDelete("order_word")]
-	public async Task Delete([FromBody] OrderWordDeleteDto dto)
-	{
+    #endregion
+
+    #region 工单词库
+    /// <summary>
+    /// 新增工单词库
+    /// </summary>
+    /// <param name="dtos"></param>
+    /// <returns></returns>
+    [Permission(EPermission.AddOrderWord)]
+    [HttpPost("order_word")]
+    public async Task Add([FromBody] OrderWordAddDto dto)
+    {
+        var word = _mapper.Map<OrderWord>(dto);
+        await _orderWrodRepository.AddAsync(word, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 删除工单词库
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.DeleteOrderWord)]
+    [HttpDelete("order_word")]
+    public async Task Delete([FromBody] OrderWordDeleteDto dto)
+    {
         await _orderRepository.RemoveOrderWrodBatchAsync(dto.Ids, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 更新工单词库
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.UpdateOrderWord)]
-	[HttpPut("order_word")]
-	public async Task Update([FromBody] OrderWordUpdateDto dto)
-	{
-		var word = await _orderWrodRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-		if (word is null)
-			throw UserFriendlyException.SameMessage("无效工单词库");
-		_mapper.Map(dto, word);
-		word.LastModificationName = _sessionContext.UserName;
-		await _orderWrodRepository.UpdateAsync(word, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 获取工单词库列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.OrderWordList)]
-	[HttpGet("order_word/list")]
-	public async Task<PagedDto<OrderWordDto>> List([FromQuery] OrderWordListDto dto)
-	{
-		var (total, items) = await _orderWrodRepository.Queryable()
-			.WhereIF(!string.IsNullOrEmpty(dto.Tag), x => x.Tag == dto.Tag!)
-			.WhereIF(!string.IsNullOrEmpty(dto.Classify), x => x.Classify.Contains(dto.Classify!))
-			.WhereIF(!string.IsNullOrEmpty(dto.Synonym), x => x.Synonym != null && x.Synonym.Contains(dto.Synonym!))
-			.OrderByDescending(x => x.CreationTime)
-			.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-		return new PagedDto<OrderWordDto>(total, _mapper.Map<IReadOnlyList<OrderWordDto>>(items));
-	}
-
-	/// <summary>
-	/// 获取工单词库
-	/// </summary>
-	/// <param name="id"></param>
-	/// <returns></returns>
-	[HttpGet("order_word/{id}")]
-	public async Task<OrderWord> OrderWordEntity(string id)
-	{
-		return await _orderWrodRepository.Queryable()
-			.FirstAsync(x => x.Id == id);
-	}
-
-	/// <summary>
-	/// 获取工单词库基本信息
-	/// </summary>
-	/// <returns></returns>
-	[HttpGet("order_word/base")]
-	public async Task<object> Base()
-	{
-		var rsp = new
-		{
-			OrderWordClassify = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderWordClassify),
-		};
-		return rsp;
-	}
-	#endregion
-
-	#region 工单观察
-	/// <summary>
-	/// 新增工单观察
-	/// </summary>
-	/// <param name="dtos"></param>
-	/// <returns></returns>
-	[Permission(EPermission.AddOrderObserve)]
-	[HttpPost("order_observe")]
-	public async Task Add([FromBody] OrderObserveAddDto dto)
-	{
-		var observe = _mapper.Map<OrderObserve>(dto);
-		await _orderObserveRepository.AddAsync(observe, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 删除工单观察
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.DeleteOrderObserve)]
-	[HttpDelete("order_observe")]
-	public async Task Delete([FromBody] OrderObserveDeleteDto dto)
-	{
-		await _orderRepository.RemoveOrderObserveBatchAsync(dto.Ids, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 更新工单观察
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.UpdateOrderObserve)]
-	[HttpPut("order_observe")]
-	public async Task Update([FromBody] OrderObserveUpdateDto dto)
-	{
-		var word = await _orderObserveRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
-		if (word is null)
-			throw UserFriendlyException.SameMessage("无效工单观察");
-		_mapper.Map(dto, word);
-		await _orderObserveRepository.UpdateAsync(word, HttpContext.RequestAborted);
-	}
-
-	/// <summary>
-	/// 获取工单观察列表
-	/// </summary>
-	/// <param name="dto"></param>
-	/// <returns></returns>
-	[Permission(EPermission.OrderObserveList)]
-	[HttpGet("order_observe/list")]
-	public async Task<PagedDto<OrderObserveDto>> List([FromQuery] OrderObserveListDto dto)
-	{
-		var (total, items) = await _orderObserveRepository.Queryable()
-            .Includes(x=>x.Order)
-			.WhereIF(dto.IsProvince.HasValue, x => x.Order.IsProvince == dto.IsProvince)
-			.WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!))
-			.WhereIF(!string.IsNullOrEmpty(dto.No), x =>  x.Order.No.Contains(dto.No!))
-			.OrderByDescending(x => x.CreationTime)
-			.ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
-		return new PagedDto<OrderObserveDto>(total, _mapper.Map<IReadOnlyList<OrderObserveDto>>(items));
-	}
-
-	/// <summary>
-	/// 获取工单观察
-	/// </summary>
-	/// <param name="id"></param>
-	/// <returns></returns>
-	[HttpGet("order_observe/{id}")]
-	public async Task<OrderObserve> OrderObserveEntity(string id)
-	{
-		return await _orderObserveRepository.Queryable()
-			.FirstAsync(x => x.Id == id);
-	}
-	#endregion
+    }
+
+    /// <summary>
+    /// 更新工单词库
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.UpdateOrderWord)]
+    [HttpPut("order_word")]
+    public async Task Update([FromBody] OrderWordUpdateDto dto)
+    {
+        var word = await _orderWrodRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+        if (word is null)
+            throw UserFriendlyException.SameMessage("无效工单词库");
+        _mapper.Map(dto, word);
+        word.LastModificationName = _sessionContext.UserName;
+        await _orderWrodRepository.UpdateAsync(word, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 获取工单词库列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.OrderWordList)]
+    [HttpGet("order_word/list")]
+    public async Task<PagedDto<OrderWordDto>> List([FromQuery] OrderWordListDto dto)
+    {
+        var (total, items) = await _orderWrodRepository.Queryable()
+            .WhereIF(!string.IsNullOrEmpty(dto.Tag), x => x.Tag == dto.Tag!)
+            .WhereIF(!string.IsNullOrEmpty(dto.Classify), x => x.Classify.Contains(dto.Classify!))
+            .WhereIF(!string.IsNullOrEmpty(dto.Synonym), x => x.Synonym != null && x.Synonym.Contains(dto.Synonym!))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderWordDto>(total, _mapper.Map<IReadOnlyList<OrderWordDto>>(items));
+    }
+
+    /// <summary>
+    /// 获取工单词库
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("order_word/{id}")]
+    public async Task<OrderWord> OrderWordEntity(string id)
+    {
+        return await _orderWrodRepository.Queryable()
+            .FirstAsync(x => x.Id == id);
+    }
+
+    /// <summary>
+    /// 获取工单词库基本信息
+    /// </summary>
+    /// <returns></returns>
+    [HttpGet("order_word/base")]
+    public async Task<object> Base()
+    {
+        var rsp = new
+        {
+            OrderWordClassify = _sysDicDataCacheManager.GetSysDicDataCache(SysDicTypeConsts.OrderWordClassify),
+        };
+        return rsp;
+    }
+    #endregion
+
+    #region 工单观察
+    /// <summary>
+    /// 新增工单观察
+    /// </summary>
+    /// <param name="dtos"></param>
+    /// <returns></returns>
+    [Permission(EPermission.AddOrderObserve)]
+    [HttpPost("order_observe")]
+    public async Task Add([FromBody] OrderObserveAddDto dto)
+    {
+        var observe = _mapper.Map<OrderObserve>(dto);
+        await _orderObserveRepository.AddAsync(observe, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 删除工单观察
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.DeleteOrderObserve)]
+    [HttpDelete("order_observe")]
+    public async Task Delete([FromBody] OrderObserveDeleteDto dto)
+    {
+        await _orderRepository.RemoveOrderObserveBatchAsync(dto.Ids, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 更新工单观察
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.UpdateOrderObserve)]
+    [HttpPut("order_observe")]
+    public async Task Update([FromBody] OrderObserveUpdateDto dto)
+    {
+        var word = await _orderObserveRepository.GetAsync(dto.Id, HttpContext.RequestAborted);
+        if (word is null)
+            throw UserFriendlyException.SameMessage("无效工单观察");
+        _mapper.Map(dto, word);
+        await _orderObserveRepository.UpdateAsync(word, HttpContext.RequestAborted);
+    }
+
+    /// <summary>
+    /// 获取工单观察列表
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
+    [Permission(EPermission.OrderObserveList)]
+    [HttpGet("order_observe/list")]
+    public async Task<PagedDto<OrderObserveDto>> List([FromQuery] OrderObserveListDto dto)
+    {
+        var (total, items) = await _orderObserveRepository.Queryable()
+            .Includes(x => x.Order)
+            .WhereIF(dto.IsProvince.HasValue, x => x.Order.IsProvince == dto.IsProvince)
+            .WhereIF(!string.IsNullOrEmpty(dto.Title), x => x.Order.Title.Contains(dto.Title!))
+            .WhereIF(!string.IsNullOrEmpty(dto.No), x => x.Order.No.Contains(dto.No!))
+            .OrderByDescending(x => x.CreationTime)
+            .ToPagedListAsync(dto.PageIndex, dto.PageSize, HttpContext.RequestAborted);
+        return new PagedDto<OrderObserveDto>(total, _mapper.Map<IReadOnlyList<OrderObserveDto>>(items));
+    }
+
+    /// <summary>
+    /// 获取工单观察
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
+    [HttpGet("order_observe/{id}")]
+    public async Task<OrderObserve> OrderObserveEntity(string id)
+    {
+        return await _orderObserveRepository.Queryable()
+            .FirstAsync(x => x.Id == id);
+    }
+    #endregion
 
 }

+ 95 - 66
src/Hotline.Application/Handlers/FlowEngine/EndWorkflowHandler.cs

@@ -39,7 +39,7 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
     private readonly IRepository<OrderVisit> _orderVisitRepository;
     private readonly IRepository<OrderDelay> _orderDelayRepository;
 
-	public EndWorkflowHandler(
+    public EndWorkflowHandler(
         IKnowledgeDomainService knowledgeDomainService,
         IOrderDomainService orderDomainService,
         ITelDomainService telDomainService,
@@ -55,7 +55,7 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
         ICircularRecordDomainService circularRecordDomainService,
         IRepository<OrderDelay> orderDelayRepository,
         IRepository<OrderVisit> orderVisitRepository
-		)
+        )
     {
         _knowledgeDomainService = knowledgeDomainService;
         _orderDomainService = orderDomainService;
@@ -71,8 +71,8 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
         _circularRecordRepository = circularRecordRepository;
         _circularRecordDomainService = circularRecordDomainService;
         _orderDelayRepository = orderDelayRepository;
-        _orderVisitRepository = orderVisitRepository; 
-	}
+        _orderVisitRepository = orderVisitRepository;
+    }
 
     /// <summary>Handles a notification</summary>
     /// <param name="notification">The notification</param>
@@ -80,6 +80,8 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
     public async Task Handle(EndWorkflowNotify notification, CancellationToken cancellationToken)
     {
         var workflow = notification.Workflow;
+        //审批是否通过
+        var isReviewPass = workflow.IsReviewPass();
 
         switch (workflow.ModuleCode)
         {
@@ -111,53 +113,72 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
                 var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
                 if (screen != null)
                 {
-                    screen.Status = EScreenStatus.End;
-                    screen.ReplyContent = workflow.ActualOpinion;
-                    await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
-                    var visitDetail = await _orderVisitedDetailRepository.GetAsync(screen.VisitDetailId, cancellationToken);
-                    if (visitDetail != null)
+                    if (isReviewPass)
                     {
-                        var screenSatisfy = new Kv() { Key = "6", Value = "甄别满意" };
-                        visitDetail.OrgProcessingResults = screenSatisfy;
-                        visitDetail.OrgHandledAttitude = screenSatisfy;
-                        await _orderVisitedDetailRepository.UpdateAsync(visitDetail, cancellationToken);
-                        //推省上数据
-                        if (screen.Publish != null && screen.Publish.Value)
+
+                        screen.Status = EScreenStatus.End;
+                        screen.ReplyContent = workflow.ActualOpinion;
+                        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
+                        var visitDetail =
+                            await _orderVisitedDetailRepository.GetAsync(screen.VisitDetailId, cancellationToken);
+                        if (visitDetail != null)
                         {
-                            //获取回访信息
-	                        var visit = await _orderVisitRepository.Queryable().Includes(x=>x.Order).Includes(x=>x.OrderVisitDetails)
-                                .Where(x=>x.Id == screen.VisitId).FirstAsync(cancellationToken);
-	                        if (visit != null)
-	                        {
-                                //获取回访明细
-		                        var visitDe = visit.OrderVisitDetails.First(x => x.Id == screen.VisitDetailId);
-								//推省上
-								_capPublisher.Publish(EventNames.HotlineOrderVisited,
-									new PublishVisitDto()
-									{
-										Order = _mapper.Map<OrderDto>(visit.Order),
-										No = visit.No,
-										VisitType = visit.VisitType,
-										VisitName = visit.CreatorName,
-										VisitTime = visit.VisitTime,
-										VisitRemark = visitDe.VisitContent,
-										AreaCode = visit.Order.AreaCode!,
-										SubjectResultSatifyCode = visitDe.OrgProcessingResults?.Key,
-										FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
-										ClientGuid = ""
-									});
-							}
+                            var screenSatisfy = new Kv() { Key = "6", Value = "甄别满意" };
+                            visitDetail.OrgProcessingResults = screenSatisfy;
+                            visitDetail.OrgHandledAttitude = screenSatisfy;
+                            await _orderVisitedDetailRepository.UpdateAsync(visitDetail, cancellationToken);
+                            //推省上数据
+                            if (screen.Publish != null && screen.Publish.Value)
+                            {
+                                //获取回访信息
+                                var visit = await _orderVisitRepository.Queryable().Includes(x => x.Order)
+                                    .Includes(x => x.OrderVisitDetails)
+                                    .Where(x => x.Id == screen.VisitId).FirstAsync(cancellationToken);
+                                if (visit != null)
+                                {
+                                    //获取回访明细
+                                    var visitDe = visit.OrderVisitDetails.First(x => x.Id == screen.VisitDetailId);
+                                    //推省上
+                                    _capPublisher.Publish(EventNames.HotlineOrderVisited,
+                                        new PublishVisitDto()
+                                        {
+                                            Order = _mapper.Map<OrderDto>(visit.Order),
+                                            No = visit.No,
+                                            VisitType = visit.VisitType,
+                                            VisitName = visit.CreatorName,
+                                            VisitTime = visit.VisitTime,
+                                            VisitRemark = visitDe.VisitContent,
+                                            AreaCode = visit.Order.AreaCode!,
+                                            SubjectResultSatifyCode = visitDe.OrgProcessingResults?.Key,
+                                            FirstSatisfactionCode = visit.Order.FirstVisitResultCode!,
+                                            ClientGuid = ""
+                                        });
+                                }
 
-						}
+                            }
+                        }
+                    }
+                    else
+                    {
+                        screen.Status = EScreenStatus.Refuse;
+                        screen.ReplyContent = workflow.ActualOpinion;
+                        await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
                     }
-				}
+                }
                 break;
             case WorkflowModuleConsts.BulletinApply:
                 var bulletin = await _bulletinRepository.GetAsync(workflow.ExternalId, cancellationToken);
                 if (bulletin != null)
                 {
-                    bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewPass;
-                    bulletin.BulletinTime = DateTime.Now;
+                    if (isReviewPass)
+                    {
+                        bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewPass;
+                        bulletin.BulletinTime = DateTime.Now;
+                    }
+                    else
+                    {
+                        bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewNoPass;
+                    }
                     await _bulletinRepository.UpdateAsync(bulletin, cancellationToken);
                 }
                 break;
@@ -165,42 +186,50 @@ public class EndWorkflowHandler : INotificationHandler<EndWorkflowNotify>
                 var circular = await _circularRepository.GetAsync(workflow.ExternalId, cancellationToken);
                 if (circular != null)
                 {
-                    //更新审核状态
-                    circular.CircularState = Share.Enums.Article.ECircularState.ReviewPass;
-                    circular.CircularTime = DateTime.Now;
-                    await _circularRepository.UpdateAsync(circular, cancellationToken);
-                    //更新阅读数量
-                    if (circular.CircularType == Share.Enums.Article.ECircularType.Person)
+                    if (isReviewPass)
                     {
-                        //个人
-                        var userlist = await _circularReadGroupRepository.Queryable()
-                           .Where(x => x.CircularId == circular.Id)
-                           .Select(x => x.UserId)
-                           .ToListAsync(cancellationToken);
-                        if (userlist!=null && userlist.Count>0)
+                        //更新审核状态
+                        circular.CircularState = Share.Enums.Article.ECircularState.ReviewPass;
+                        circular.CircularTime = DateTime.Now;
+                        await _circularRepository.UpdateAsync(circular, cancellationToken);
+                        //更新阅读数量
+                        if (circular.CircularType == Share.Enums.Article.ECircularType.Person)
                         {
-                            await _circularRecordDomainService.RecordUserHandle(userlist, true);
+                            //个人
+                            var userlist = await _circularReadGroupRepository.Queryable()
+                               .Where(x => x.CircularId == circular.Id)
+                               .Select(x => x.UserId)
+                               .ToListAsync(cancellationToken);
+                            if (userlist != null && userlist.Count > 0)
+                            {
+                                await _circularRecordDomainService.RecordUserHandle(userlist, true);
+                            }
+                        }
+                        else
+                        {
+                            //部门
+                            var orglist = await _circularReadGroupRepository.Queryable()
+                                .Where(x => x.CircularId == circular.Id)
+                                .Select(x => x.OrgId)
+                                .ToListAsync(cancellationToken);
+                            if (orglist != null && orglist.Count > 0)
+                            {
+                                await _circularRecordDomainService.RecordOrgHandle(orglist, true);
+                            }
                         }
                     }
                     else
                     {
-                        //部门
-                        var orglist = await _circularReadGroupRepository.Queryable()
-                            .Where(x => x.CircularId == circular.Id)
-                            .Select(x => x.OrgId)
-                            .ToListAsync(cancellationToken);
-                        if (orglist!=null && orglist.Count>0)
-                        {
-                            await _circularRecordDomainService.RecordOrgHandle(orglist, true);
-                        }
+                        circular.CircularState = Share.Enums.Article.ECircularState.ReviewNoPass;
+                        await _circularRepository.UpdateAsync(circular, cancellationToken);
                     }
                 }
                 break;
             case WorkflowModuleConsts.OrderDelay:
                 var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                if (delay!=null)
+                if (delay != null)
                 {
-                    delay.DelayState = EDelayState.Pass;
+                    delay.DelayState = isReviewPass ? EDelayState.Pass : EDelayState.NoPass;
                     await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
 
                     //处理工单延期TODO

+ 2 - 2
src/Hotline.Application/Handlers/FlowEngine/NextStepHandler.cs

@@ -87,7 +87,7 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
 
                 if (nextTag is not null)
                 {
-                    if(nextTag.Type == TagDefaults.TagType.Org)
+                    if (nextTag.Type == TagDefaults.TagType.Org)
                     {
                         switch (nextTag.Value)
                         {
@@ -105,7 +105,7 @@ public class NextStepHandler : INotificationHandler<NextStepNotify>
                         switch (currentTag.Value)
                         {
                             case TagDefaults.TagValue.Province:
-                                
+
                                 break;
                         }
                     }

+ 91 - 91
src/Hotline.Application/Handlers/FlowEngine/RejectHandler.cs

@@ -1,96 +1,96 @@
-using DotNetCore.CAP;
-using Hotline.Article;
-using Hotline.FlowEngine.Notifications;
-using Hotline.FlowEngine.WorkflowModules;
-using Hotline.Orders;
-using Hotline.Share.Dtos.Order;
-using Hotline.Share.Enums.Order;
-using Hotline.Share.Mq;
-using MapsterMapper;
-using MediatR;
-using Microsoft.Extensions.Logging;
-using OracleInternal.SqlAndPlsqlParser.LocalParsing;
-using XF.Domain.Repository;
+//using DotNetCore.CAP;
+//using Hotline.Article;
+//using Hotline.FlowEngine.Notifications;
+//using Hotline.FlowEngine.WorkflowModules;
+//using Hotline.Orders;
+//using Hotline.Share.Dtos.Order;
+//using Hotline.Share.Enums.Order;
+//using Hotline.Share.Mq;
+//using MapsterMapper;
+//using MediatR;
+//using Microsoft.Extensions.Logging;
+//using OracleInternal.SqlAndPlsqlParser.LocalParsing;
+//using XF.Domain.Repository;
 
-namespace Hotline.Application.Handlers.FlowEngine;
+//namespace Hotline.Application.Handlers.FlowEngine;
 
-public class RejectHandler : INotificationHandler<RejectNotify>
-{
-    private readonly IOrderDomainService _orderDomainService;
-    private readonly IOrderRepository _orderRepository;
-    private readonly ICapPublisher _capPublisher;
-    private readonly IMapper _mapper;
-    private readonly ILogger<RejectHandler> _logger;
-    private readonly IRepository<OrderScreen> _orderScreenRepository;
-    private readonly IRepository<Bulletin> _bulletinRepository;
-    private readonly IRepository<Circular> _circularRepository;
-    private readonly IRepository<OrderDelay> _orderDelayRepository;
+//public class RejectHandler : INotificationHandler<RejectNotify>
+//{
+//    private readonly IOrderDomainService _orderDomainService;
+//    private readonly IOrderRepository _orderRepository;
+//    private readonly ICapPublisher _capPublisher;
+//    private readonly IMapper _mapper;
+//    private readonly ILogger<RejectHandler> _logger;
+//    private readonly IRepository<OrderScreen> _orderScreenRepository;
+//    private readonly IRepository<Bulletin> _bulletinRepository;
+//    private readonly IRepository<Circular> _circularRepository;
+//    private readonly IRepository<OrderDelay> _orderDelayRepository;
 
-	public RejectHandler(
-        IOrderDomainService orderDomainService,
-        IOrderRepository orderRepository,
-        ICapPublisher capPublisher,
-        IMapper mapper,
-        ILogger<RejectHandler> logger,
-        IRepository<OrderScreen> orderScreenRepository,
-        IRepository<Bulletin> bulletinRepository,
-        IRepository<Circular> circularRepository,
-        IRepository<OrderDelay> orderDelayRepository)
-    {
-        _orderDomainService = orderDomainService;
-        _orderRepository = orderRepository;
-        _capPublisher = capPublisher;
-        _mapper = mapper;
-        _logger = logger;
-        _orderScreenRepository = orderScreenRepository;
-        _bulletinRepository = bulletinRepository;
-        _circularRepository = circularRepository;
-        _orderDelayRepository = orderDelayRepository;
-	}
+//    public RejectHandler(
+//        IOrderDomainService orderDomainService,
+//        IOrderRepository orderRepository,
+//        ICapPublisher capPublisher,
+//        IMapper mapper,
+//        ILogger<RejectHandler> logger,
+//        IRepository<OrderScreen> orderScreenRepository,
+//        IRepository<Bulletin> bulletinRepository,
+//        IRepository<Circular> circularRepository,
+//        IRepository<OrderDelay> orderDelayRepository)
+//    {
+//        _orderDomainService = orderDomainService;
+//        _orderRepository = orderRepository;
+//        _capPublisher = capPublisher;
+//        _mapper = mapper;
+//        _logger = logger;
+//        _orderScreenRepository = orderScreenRepository;
+//        _bulletinRepository = bulletinRepository;
+//        _circularRepository = circularRepository;
+//        _orderDelayRepository = orderDelayRepository;
+//    }
 
-    /// <summary>Handles a notification</summary>
-    /// <param name="notification">The notification</param>
-    /// <param name="cancellationToken">Cancellation token</param>
-    public async Task Handle(RejectNotify notification, CancellationToken cancellationToken)
-    {
-        var workflow = notification.Workflow;
-        var data = notification.Dto;
+//    /// <summary>Handles a notification</summary>
+//    /// <param name="notification">The notification</param>
+//    /// <param name="cancellationToken">Cancellation token</param>
+//    public async Task Handle(RejectNotify notification, CancellationToken cancellationToken)
+//    {
+//        var workflow = notification.Workflow;
+//        var data = notification.Dto;
 
-        switch (workflow.ModuleCode)
-        {
-            case WorkflowModuleConsts.OrderDelay:
-                var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                if (delay!=null)
-                {
-                    delay.DelayState = EDelayState.NoPass;
-                    await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
-                }
-                break;
-            case WorkflowModuleConsts.OrderScreen:
-	            var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
-	            if (screen != null)
-	            {
-		            screen.Status = EScreenStatus.Refuse;
-		            screen.ReplyContent = workflow.ActualOpinion;
-		            await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
-	            }
-	            break;
-            case WorkflowModuleConsts.BulletinApply:
-                var bulletin = await _bulletinRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                if (bulletin != null)
-                {
-                    bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewNoPass;
-                    await _bulletinRepository.UpdateAsync(bulletin, cancellationToken);
-                }
-                break;
-            case WorkflowModuleConsts.CircularApply:
-                var circular = await _circularRepository.GetAsync(workflow.ExternalId, cancellationToken);
-                if (circular != null)
-                {
-                    circular.CircularState = Share.Enums.Article.ECircularState.ReviewNoPass;
-                    await _circularRepository.UpdateAsync(circular, cancellationToken);
-                }
-                break;
-		}
-    }
-}
+//        switch (workflow.ModuleCode)
+//        {
+//            case WorkflowModuleConsts.OrderDelay:
+//                var delay = await _orderDelayRepository.GetAsync(workflow.ExternalId, cancellationToken);
+//                if (delay != null)
+//                {
+//                    delay.DelayState = EDelayState.NoPass;
+//                    await _orderDelayRepository.UpdateAsync(delay, cancellationToken);
+//                }
+//                break;
+//            case WorkflowModuleConsts.OrderScreen:
+//                var screen = await _orderScreenRepository.GetAsync(workflow.ExternalId, cancellationToken);
+//                if (screen != null)
+//                {
+//                    screen.Status = EScreenStatus.Refuse;
+//                    screen.ReplyContent = workflow.ActualOpinion;
+//                    await _orderScreenRepository.UpdateAsync(screen, cancellationToken);
+//                }
+//                break;
+//            case WorkflowModuleConsts.BulletinApply:
+//                var bulletin = await _bulletinRepository.GetAsync(workflow.ExternalId, cancellationToken);
+//                if (bulletin != null)
+//                {
+//                    bulletin.BulletinState = Share.Enums.Article.EBulletinState.ReviewNoPass;
+//                    await _bulletinRepository.UpdateAsync(bulletin, cancellationToken);
+//                }
+//                break;
+//            case WorkflowModuleConsts.CircularApply:
+//                var circular = await _circularRepository.GetAsync(workflow.ExternalId, cancellationToken);
+//                if (circular != null)
+//                {
+//                    circular.CircularState = Share.Enums.Article.ECircularState.ReviewNoPass;
+//                    await _circularRepository.UpdateAsync(circular, cancellationToken);
+//                }
+//                break;
+//        }
+//    }
+//}

+ 5 - 0
src/Hotline.Share/Dtos/FlowEngine/DefinitionDto.cs

@@ -36,6 +36,11 @@ namespace Hotline.Share.Dtos.FlowEngine
 
         public string? Description { get; set; }
 
+        /// <summary>
+        /// 流程类型
+        /// </summary>
+        public EFlowType FlowType { get; set; }
+
         public List<StepDefineBasic> Steps { get; set; }
         
         public string ExternalData { get; set; }

+ 26 - 0
src/Hotline.Share/Dtos/Order/DelayProvinceResultDto.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Hotline.Share.Dtos.Order
+{
+    public class DelayProvinceResultDto
+    {
+        /// <summary>
+        /// 省工单编号
+        /// </summary>
+        public string No { get; set; }
+
+        /// <summary>
+        /// 是否通过审批
+        /// </summary>
+        public bool IsPass { get; set; }
+
+        /// <summary>
+        /// 办理意见
+        /// </summary>
+        public string Opinion { get; set; }
+    }
+}

+ 21 - 0
src/Hotline.Share/Enums/FlowEngine/EFlowType.cs

@@ -0,0 +1,21 @@
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.FlowEngine;
+
+/// <summary>
+/// 流程类型
+/// </summary>
+public enum EFlowType
+{
+    /// <summary>
+    /// 办理
+    /// </summary>
+    [Description("办理")]
+    Handle = 0,
+
+    /// <summary>
+    /// 审核
+    /// </summary>
+    [Description("审核")]
+    Review = 10,
+}

+ 19 - 0
src/Hotline.Share/Enums/FlowEngine/EReviewResult.cs

@@ -0,0 +1,19 @@
+namespace Hotline.Share.Enums.FlowEngine;
+
+public enum EReviewResult
+{
+    /// <summary>
+    /// 未知
+    /// </summary>
+    Unknown = 0,
+
+    /// <summary>
+    /// 通过
+    /// </summary>
+    Approval = 1,
+
+    /// <summary>
+    /// 审核失败
+    /// </summary>
+    Failed = 2,
+}

+ 5 - 0
src/Hotline/FlowEngine/Definitions/WorkflowDefinition.cs

@@ -34,6 +34,11 @@ public class WorkflowDefinition : CreationEntity
 
     public EDefinitionStatus Status { get; set; }
 
+    /// <summary>
+    /// 流程类型
+    /// </summary>
+    public EFlowType FlowType { get; set; }
+
     #region Method
 
     public StepDefine FindStartStepDefine() =>

+ 4 - 4
src/Hotline/FlowEngine/Notifications/WorkflowNotify.cs

@@ -30,10 +30,10 @@ public record JumpNotify(Workflow Workflow, WorkflowStep TargetStep, RecallDto D
 
 public record RedoNotify(Workflow Workflow, RecallDto Dto, bool IsOrgToCenter) : INotification;
 
-/// <summary>
-/// 否决(审批不通过)
-/// </summary>
-public record RejectNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotification;
+///// <summary>
+///// 否决(审批不通过)
+///// </summary>
+//public record RejectNotify(Workflow Workflow, BasicWorkflowDto Dto) : INotification;
 
 public record EndWorkflowNotify(Workflow Workflow, WorkflowTrace Trace) : INotification;
 

+ 19 - 1
src/Hotline/FlowEngine/Workflows/Workflow.cs

@@ -16,6 +16,16 @@ public partial class Workflow : CreationEntity
 {
     public string DefinitionId { get; set; }
 
+    /// <summary>
+    /// 流程类型
+    /// </summary>
+    public EFlowType FlowType { get; set; }
+
+    /// <summary>
+    /// 审核结果
+    /// </summary>
+    public EReviewResult ReviewResult { get; set; }
+
     #region 业务模块(冗余)
 
     public string? ModuleId { get; set; }
@@ -349,10 +359,16 @@ public partial class Workflow
     /// <summary>
     /// 流程结束
     /// </summary>
-    public void Complete()
+    public void Complete(EReviewResult? reviewResult = null)
     {
+        if (FlowType is EFlowType.Review && !reviewResult.HasValue)
+            throw new UserFriendlyException("无审核结果");
+
         Status = EWorkflowStatus.Completed;
         EndTime = DateTime.Now;
+        if (FlowType is EFlowType.Review && ReviewResult is EReviewResult.Unknown)
+            ReviewResult = reviewResult.Value;
+
         SetAllDuration();
 
         UpdateActualOption();
@@ -687,6 +703,8 @@ public partial class Workflow
         AllDuration = (EndTime - CreationTime).Value.TotalMinutes;
     }
 
+    public bool IsReviewPass() => FlowType == EFlowType.Review && ReviewResult == EReviewResult.Approval;
+
     #endregion
 }
 

+ 6 - 6
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -354,7 +354,7 @@ namespace Hotline.FlowEngine.Workflows
             //检查是否流转到流程终点
             if (nextStepDefine.StepType is EStepType.End)
             {
-                var endTrace = await WorkflowEndAsync(workflow, dto, nextStepDefine, currentStep, cancellationToken);
+                var endTrace = await WorkflowEndAsync(workflow, dto, nextStepDefine, currentStep, EReviewResult.Approval, cancellationToken);
                 return;
             }
 
@@ -752,9 +752,9 @@ namespace Hotline.FlowEngine.Workflows
             await HandleStepAsync(currentStep, workflow, dto, null, cancellationToken);
 
             var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
-            var endTrace = await WorkflowEndAsync(workflow, dto, endStepDefine, currentStep, cancellationToken);
+            var endTrace = await WorkflowEndAsync(workflow, dto, endStepDefine, currentStep, EReviewResult.Failed, cancellationToken);
 
-            await _mediator.Publish(new RejectNotify(workflow, dto), cancellationToken);
+            //await _mediator.Publish(new RejectNotify(workflow, dto), cancellationToken);
         }
 
         /// <summary>
@@ -865,7 +865,7 @@ namespace Hotline.FlowEngine.Workflows
             var endStepDefine = workflow.WorkflowDefinition.FindEndStepDefine();
 
             var basicDto = _mapper.Map<BasicWorkflowDto>(dto);
-            var endTrace = await WorkflowEndAsync(workflow, basicDto, endStepDefine, currentStep, cancellationToken);
+            var endTrace = await WorkflowEndAsync(workflow, basicDto, endStepDefine, currentStep, EReviewResult.Unknown, cancellationToken);
 
             await _mediator.Publish(new CancelWorkflowNotify(workflow), cancellationToken);
         }
@@ -877,7 +877,7 @@ namespace Hotline.FlowEngine.Workflows
         /// 流程结束
         /// </summary>
         private async Task<WorkflowTrace> WorkflowEndAsync(Workflow workflow, BasicWorkflowDto dto, StepDefine endStepDefine,
-            WorkflowStep currentStep, CancellationToken cancellationToken)
+            WorkflowStep currentStep, EReviewResult reviewResult, CancellationToken cancellationToken)
         {
             //create endStep
             var endStep = await CreateEndStepAsync(workflow, endStepDefine, currentStep, cancellationToken);
@@ -885,7 +885,7 @@ namespace Hotline.FlowEngine.Workflows
             //update endTrace
             var endTrace = await NextTraceAsync(workflow, dto, endStep, cancellationToken);
 
-            workflow.Complete();
+            workflow.Complete(reviewResult);
 
             await _workflowRepository.UpdateAsync(workflow, cancellationToken);