xf 2 vuotta sitten
vanhempi
commit
1d9e543816

+ 16 - 10
src/Hotline.Api/Controllers/OrderController.cs

@@ -95,6 +95,11 @@ public class OrderController : BaseController
         return new PagedDto<OrderDto>(total, _mapper.Map<IReadOnlyList<OrderDto>>(items));
     }
 
+    /// <summary>
+    /// 查询工单详情
+    /// </summary>
+    /// <param name="id"></param>
+    /// <returns></returns>
     [HttpGet("{id}")]
     public async Task<OrderDto> Get(string id)
     {
@@ -131,6 +136,11 @@ public class OrderController : BaseController
         await _orderRepository.RemoveAsync(order);
     }
 
+    /// <summary>
+    /// 更新工单信息
+    /// </summary>
+    /// <param name="dto"></param>
+    /// <returns></returns>
     [HttpPut]
     public async Task Update([FromBody] UpdateOrderDto dto)
     {
@@ -176,15 +186,12 @@ public class OrderController : BaseController
     /// </summary>
     /// <returns></returns>
     [HttpGet("base-data")]
-    public async Task<object> BaseData()
+    public dynamic BaseData()
     {
-        var baseHotspots = await _hotSpotTypeRepository.Queryable().Where(d => string.IsNullOrEmpty(d.ParentId))
-            .ToListAsync();
         return new
         {
             AcceptTypeOptions = EnumExts.GetDescriptions<EAcceptType>(),
             ChannelOptions = EnumExts.GetDescriptions<EChannel>(),
-            BaseHotspots = baseHotspots.Select(d => new KeyValuePair<string, string>(d.ProvinceCode, d.HotSpotName)).ToList(),
             OrgsOptions = _organizeRepository.GetOrgJson(),
             EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
             PushTypeOptions = EnumExts.GetDescriptions<EPushType>(),
@@ -193,14 +200,12 @@ public class OrderController : BaseController
     }
 
     /// <summary>
-    /// 新增页面
+    /// 新增页面基础数据
     /// </summary>
     /// <returns></returns>
     [HttpGet("base-data-add")]
-    public async Task<object> BaseDataAdd()
+    public dynamic BaseDataAdd()
     {
-        var baseHotspots = await _hotSpotTypeRepository.Queryable().Where(d => string.IsNullOrEmpty(d.ParentId))
-            .ToListAsync();
         return new
         {
             ChannelOptions = EnumExts.GetDescriptions<EChannel>(),
@@ -211,13 +216,13 @@ public class OrderController : BaseController
             OrderTypeOptions = EnumExts.GetDescriptions<EOrderType>(),
             AcceptTypeOptions = EnumExts.GetDescriptions<EAcceptType>(),
             EmergencyLevelOptions = EnumExts.GetDescriptions<EEmergencyLevel>(),
-            BaseHotspots = baseHotspots.Select(d => new KeyValuePair<string, string>(d.ProvinceCode, d.HotSpotName)).ToList(),
             PushTypeOptions = EnumExts.GetDescriptions<EPushType>(),
+            //todo 是否重复
         };
     }
 
     /// <summary>
-    /// 扩展信息新增页面
+    /// 扩展信息新增页面基础数据
     /// </summary>
     /// <returns></returns>
     [HttpGet("base-data-ext")]
@@ -227,6 +232,7 @@ public class OrderController : BaseController
         return new
         {
             //LicenceTypeOptions = SysDicTypeConsts.LicenceType,
+            ComplainTypeOptions = EnumExts.GetDescriptions<EComplainType>()
         };
     }
 

+ 1 - 1
src/Hotline.Api/appsettings.Development.json

@@ -94,7 +94,7 @@
     }
   },
   "DatabaseConfiguration": {
-    "ApplyDbMigrations": false,
+    "ApplyDbMigrations": true,
     "ApplySeed": false
   }
 }

+ 9 - 1
src/Hotline.Application/FlowEngine/IWorkflowApplication.cs

@@ -1,5 +1,8 @@
-using Hotline.FlowEngine.Workflows;
+using Hotline.FlowEngine;
+using Hotline.FlowEngine.Definitions;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Enums.FlowEngine;
 
 namespace Hotline.Application.FlowEngine
 {
@@ -24,5 +27,10 @@ namespace Hotline.Application.FlowEngine
         Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(string moduleCode, string externalId, CancellationToken cancellationToken);
 
         Task<IReadOnlyList<NextStepOptions>> GetNextStepOptionsAsync(Workflow workflow, CancellationToken cancellationToken);
+
+        /// <summary>
+        /// 查询指派办理人的处理方式及实际办理人
+        /// </summary>
+        Task<FlowAssignMode> GetFlowAssignModeAsync(StepDefine StepDefine, List<IdName> Handlers, CancellationToken cancellationToken);
     }
 }

+ 27 - 0
src/Hotline.Application/FlowEngine/WorkflowApplication.cs

@@ -10,6 +10,7 @@ using Hotline.Users;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
+using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 
 namespace Hotline.Application.FlowEngine;
@@ -163,6 +164,32 @@ public class WorkflowApplication : IWorkflowApplication, IScopeDependency
         return items;
     }
 
+    /// <summary>
+    /// 指派下一节点办理人
+    /// </summary>
+    public async Task AssignAsync<TEntity>(TEntity entity, EFlowAssignType flowAssignType, IEnumerable<string> handlers, CancellationToken cancellationToken) 
+        where TEntity : IWorkflow
+    {
+        switch (flowAssignType)
+        {
+            case EFlowAssignType.Org:
+            case EFlowAssignType.User:
+                entity.Assign(flowAssignType, handlers);
+                break;
+            case EFlowAssignType.Role:
+                var roles = await _roleRepository.Queryable()
+                    .Includes(d => d.Accounts)
+                    .Where(d => handlers.Contains(d.Name))
+                    .ToListAsync();
+                var userIds = roles.SelectMany(d => d.Accounts).Select(d => d.Id);
+                entity.Assign(EFlowAssignType.User, userIds);
+                break;
+            default:
+                throw new ArgumentOutOfRangeException(nameof(flowAssignType), flowAssignType, null);
+        }
+
+    }
+
 
     #region private
 

+ 14 - 2
src/Hotline.Application/Handlers/FlowEngine/StartWorkflowHandler.cs

@@ -3,21 +3,31 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.Application.FlowEngine;
 using Hotline.FlowEngine.Notifies;
 using Hotline.Orders;
 using Hotline.Settings;
 using Hotline.Share.Enums.Order;
 using MediatR;
+using XF.Domain.Exceptions;
 
 namespace Hotline.Application.Handlers.FlowEngine
 {
     public class StartWorkflowHandler : INotificationHandler<StartWorkflowNotify>
     {
+        private readonly IWorkflowApplication _workflowApplication;
         private readonly IOrderDomainService _orderDomainService;
+        private readonly IOrderRepository _orderRepository;
 
-        public StartWorkflowHandler(IOrderDomainService orderDomainService)
+        public StartWorkflowHandler(
+            IWorkflowApplication workflowApplication,
+            IOrderDomainService orderDomainService,
+            IOrderRepository orderRepository
+            )
         {
+            _workflowApplication = workflowApplication;
             _orderDomainService = orderDomainService;
+            _orderRepository = orderRepository;
         }
 
         /// <summary>Handles a notification</summary>
@@ -27,11 +37,13 @@ namespace Hotline.Application.Handlers.FlowEngine
         {
             var workflow = notification.Workflow;
             var data = notification.Dto;
+            var assignMode = await _workflowApplication.GetFlowAssignModeAsync(notification.StepDefine,
+                data.Handlers.ToList(), cancellationToken);
 
             switch (workflow.ModuleCode)
             {
                 case WorkflowModuleConsts.OrderManage:
-                    await _orderDomainService.OrderManageAsync(EOrderStatus.WaitForSign, notification.FlowAssignType, 
+                    await _orderDomainService.OrderManageAsync(EOrderStatus.WaitForSign, notification.FlowAssignType,
                         false, notification.IsCountersignStart,
                         workflow.ExternalId, workflow.CurrentStepTime, workflow.CurrentStepName,
                         data.Handlers.Select(d => d.Id), cancellationToken);

+ 8 - 21
src/Hotline.Application/Orders/IOrderApplication.cs

@@ -3,31 +3,18 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
-using Hotline.FlowEngine.Workflows;
-using Hotline.Orders;
-using XF.Domain.Dependency;
+using Hotline.Share.Enums.Order;
+using XF.Domain.Entities;
 
 namespace Hotline.Application.Orders
 {
     public interface IOrderApplication
     {
-        Task<Order> GetAsync(string id);
-    }
-
-    public class OrderApplication : IOrderApplication, IScopeDependency
-    {
-        private readonly IWorkflowDomainService _workflowDomainService;
-
-        public OrderApplication(IWorkflowDomainService workflowDomainService)
-        {
-            _workflowDomainService = workflowDomainService;
-        }
-
-        public async Task<Order> GetAsync(string id)
-        {
-            //var order = 
-
-            throw new NotImplementedException();
-        }
+        /// <summary>
+        /// 工单办理(每个节点都会触发)
+        /// </summary>
+        Task OrderManageAsync(EOrderStatus status, EFlowAssignType assignType, bool isCountersignEnd, bool isCountersignStart,
+            string orderId, DateTime currentStepTime, string CurrentStepName,
+            IEnumerable<string> handlers, CancellationToken cancellationToken);
     }
 }

+ 78 - 0
src/Hotline.Application/Orders/OrderApplication.cs

@@ -0,0 +1,78 @@
+using Hotline.FlowEngine.Workflows;
+using Hotline.Orders;
+using Hotline.Share.Enums.Order;
+using Hotline.Users;
+using XF.Domain.Dependency;
+using XF.Domain.Entities;
+using XF.Domain.Exceptions;
+
+namespace Hotline.Application.Orders;
+
+public class OrderApplication : IOrderApplication, IScopeDependency
+{
+    private readonly IWorkflowDomainService _workflowDomainService;
+    private readonly IOrderRepository _orderRepository;
+
+    public OrderApplication(
+        IWorkflowDomainService workflowDomainService,
+        IOrderRepository orderRepository
+        )
+    {
+        _workflowDomainService = workflowDomainService;
+        _orderRepository = orderRepository;
+    }
+
+    /// <summary>
+    /// 工单办理(每个节点都会触发)
+    /// </summary>
+    public async Task OrderManageAsync(EOrderStatus status, EFlowAssignType assignType, bool isCountersignEnd, bool isCountersignStart,
+        string orderId, DateTime currentStepTime, string CurrentStepName, IEnumerable<string> handlers,
+        CancellationToken cancellationToken)
+    {
+        var order = await _orderRepository.GetAsync(orderId, cancellationToken);
+        if (order == null)
+            throw new UserFriendlyException($"无效工单编号, orderId: {orderId}", "无效工单编号");
+        if (order.Status is EOrderStatus.Filed) return;
+
+        //order.Assign(assignType, handlers);
+        await AssignAsync(order, assignType, handlers, cancellationToken);
+
+        //1.如果order未处于会签中,则判断是否发起会签(isstartCountersign) 2.如果处于会签中,则判断会签是否结束(isCountersignEnd)
+        if (order.Status is EOrderStatus.Countersigning && isCountersignEnd)
+        {
+            order.Status = EOrderStatus.WaitForSign;
+        }
+        else if (order.Status is not EOrderStatus.Countersigning && isCountersignStart)
+        {
+            order.Status = EOrderStatus.Countersigning;
+        }
+
+        order.CurrentStepTime = currentStepTime;
+        order.CurrentStepName = CurrentStepName;
+        order.Status = status;
+
+        await _orderRepository.UpdateAsync(order, cancellationToken);
+    }
+
+    private async Task AssignAsync(Order order, EFlowAssignType assignType, IEnumerable<string> handlers, CancellationToken cancellationToken)
+    {
+        switch (assignType)
+        {
+            case EFlowAssignType.Org:
+                order.AssignOrgCodes.AddRange(handlers);
+                order.AssignOrgCodes = order.AssignOrgCodes.Distinct().ToList();
+                break;
+            case EFlowAssignType.User:
+                order.AssignUserIds.AddRange(handlers);
+                order.AssignUserIds = order.AssignUserIds.Distinct().ToList();
+                break;
+            case EFlowAssignType.Role:
+                var users =
+                    AssignRoles.AddRange(handlers);
+                AssignRoles = AssignRoles.Distinct().ToList();
+                break;
+            default:
+                throw new ArgumentOutOfRangeException(nameof(type), type, null);
+        }
+    }
+}

+ 30 - 1
src/Hotline.Share/Enums/Order/EComplainType.cs

@@ -1,7 +1,36 @@
-namespace Hotline.Share.Enums.Order;
+using System.ComponentModel;
+
+namespace Hotline.Share.Enums.Order;
 
 [Flags]
 public enum EComplainType
 {
     //修理、重做、更换、退货、补足商品数量、退赔费用、赔偿损失、停止侵权、核定侵权责任
+
+    [Description("修理")]
+    Repair = 1,
+
+    [Description("重做")]
+    Redo = 1 << 1,
+
+    [Description("更换")]
+    Change = 1 << 2,
+
+    [Description("退货")]
+    ReturnGoods = 1 << 3,
+
+    [Description("补足商品数量")]
+    Complement = 1 << 4,
+
+    [Description("退赔费用")]
+    Refund = 1 << 5,
+
+    [Description("赔偿损失")]
+    Compensation = 1 << 6,
+
+    [Description("停止侵权")]
+    StopInfringement = 1 << 7,
+
+    [Description("核定侵权责任")]
+    AuthorizedInfringement = 1 << 8
 }

+ 16 - 0
src/Hotline/FlowEngine/FlowAssignMode.cs

@@ -0,0 +1,16 @@
+using XF.Domain.Entities;
+
+namespace Hotline.FlowEngine;
+
+public class FlowAssignMode
+{
+    /// <summary>
+    /// 流程指派类型
+    /// </summary>
+    public EFlowAssignType FlowAssignType { get; set; }
+
+    /// <summary>
+    /// 办理人/办理部门(UserIds/OrgCodes)
+    /// </summary>
+    public List<string> Handlers { get; set; }
+}

+ 4 - 3
src/Hotline/FlowEngine/Notifies/WorkflowNotify.cs

@@ -1,13 +1,14 @@
-using Hotline.FlowEngine.Workflows;
+using Hotline.FlowEngine.Definitions;
+using Hotline.FlowEngine.Workflows;
 using Hotline.Share.Dtos.FlowEngine;
 using MediatR;
 using XF.Domain.Entities;
 
 namespace Hotline.FlowEngine.Notifies;
 
-public record WorkflowNotify(Workflow Workflow, EFlowAssignType FlowAssignType, List<IdName> Handlers) : INotification;
+public record WorkflowNotify(Workflow Workflow, StepDefine StepDefine, BasicWorkflowDto Dto) : INotification;
 
-public record StartWorkflowNotify(Workflow Workflow, EFlowAssignType FlowAssignType, List<IdName> Handlers, BasicWorkflowDto Dto, bool IsCountersignStart) : WorkflowNotify(Workflow, FlowAssignType, Handlers);
+public record StartWorkflowNotify(Workflow Workflow, StepDefine StepDefine, BasicWorkflowDto Dto, bool IsCountersignStart) : WorkflowNotify(Workflow, StepDefine, Dto);
 
 public record NextStepNotify(Workflow Workflow, EFlowAssignType FlowAssignType, List<IdName> Handlers, BasicWorkflowDto Dto, bool IsCountersignStart, bool IsCountersignEnd) : WorkflowNotify(Workflow, FlowAssignType, Handlers);
 

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

@@ -1,5 +1,7 @@
 using Hotline.FlowEngine.Definitions;
 using Hotline.Share.Dtos.FlowEngine;
+using Hotline.Share.Enums.FlowEngine;
+using XF.Domain.Entities;
 
 namespace Hotline.FlowEngine.Workflows
 {

+ 2 - 1
src/Hotline/FlowEngine/Workflows/WorkflowDomainService.cs

@@ -9,6 +9,7 @@ using MediatR;
 using SqlSugar;
 using XF.Domain.Authentications;
 using XF.Domain.Dependency;
+using XF.Domain.Entities;
 using XF.Domain.Exceptions;
 using XF.Utility.SequentialId;
 
@@ -96,7 +97,7 @@ namespace Hotline.FlowEngine.Workflows
 
             //publish
             var assignMode = nextStepBoxDefine.GetFlowAssignMode(dto.Handlers);
-            _mediator.Publish(new StartWorkflowNotify(workflow, assignMode.assignType, assignMode.handlers, dto, isStartCountersign), cancellationToken);
+            _mediator.Publish(new StartWorkflowNotify(workflow, nextStepBoxDefine, dto, isStartCountersign), cancellationToken);
         }
 
         public async Task<Workflow> GetWorkflowAsync(string workflowId,

+ 3 - 3
src/Hotline/Orders/IOrderDomainService.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using Hotline.FlowEngine;
 using Hotline.Share.Enums.Order;
 using XF.Domain.Entities;
 
@@ -20,8 +21,7 @@ namespace Hotline.Orders
         /// <summary>
         /// 工单办理(每个节点都会触发)
         /// </summary>
-        Task OrderManageAsync(EOrderStatus status, EFlowAssignType assignType, bool isCountersignEnd, bool isCountersignStart,
-            string orderId, DateTime currentStepTime, string CurrentStepName,
-            IEnumerable<string> handlers, CancellationToken cancellationToken);
+        Task OrderManageAsync(EOrderStatus status, FlowAssignMode assignMode, bool isCountersignEnd, bool isCountersignStart,
+            string orderId, DateTime currentStepTime, string CurrentStepName, CancellationToken cancellationToken);
     }
 }

+ 29 - 20
src/XF.Domain.Repository/Entity.cs

@@ -1,6 +1,7 @@
 using SqlSugar;
 using XF.Domain.Entities;
 using XF.Domain.Events;
+using XF.Domain.Extensions;
 
 namespace XF.Domain.Repository;
 
@@ -142,27 +143,29 @@ public abstract class WorkflowEntity : FullStateEntity, IWorkflow
     [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
     public List<string> AssignOrgCodes { get; set; } = new();
 
-    [SugarColumn(ColumnDataType = "varchar(2000)", IsJson = true)]
+    [SugarColumn(ColumnDataType = "longtext", IsJson = true)]
     public List<string> AssignUserIds { get; set; } = new();
 
-    [SugarColumn(ColumnDataType = "varchar(600)", IsJson = true)]
-    public List<string> AssignRoles { get; set; } = new();
+    //[SugarColumn(ColumnDataType = "varchar(600)", IsJson = true)]
+    //public List<string> AssignRoles { get; set; } = new();
 
     public void Assign(EFlowAssignType type, string handler)
     {
         switch (type)
         {
             case EFlowAssignType.Org:
-                if (!AssignOrgCodes.Exists(d => d == handler))
-                    AssignOrgCodes.Add(handler);
+                var orgCodes = handler.GetHigherOrgCodes(true).ToList();
+                AssignOrgCodes.AddRange(orgCodes);
+                AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
                 if (!AssignUserIds.Exists(d => d == handler))
                     AssignUserIds.Add(handler);
                 break;
             case EFlowAssignType.Role:
-                if (!AssignRoles.Exists(d => d == handler))
-                    AssignRoles.Add(handler);
+                //if (!AssignRoles.Exists(d => d == handler))
+                //    AssignRoles.Add(handler);
+                throw new NotImplementedException();
                 break;
             default:
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);
@@ -174,7 +177,8 @@ public abstract class WorkflowEntity : FullStateEntity, IWorkflow
         switch (type)
         {
             case EFlowAssignType.Org:
-                AssignOrgCodes.AddRange(handlers);
+                var orgCodes = handlers.SelectMany(d => d.GetHigherOrgCodes(true)).ToList();
+                AssignOrgCodes.AddRange(orgCodes);
                 AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
@@ -182,8 +186,9 @@ public abstract class WorkflowEntity : FullStateEntity, IWorkflow
                 AssignUserIds = AssignUserIds.Distinct().ToList();
                 break;
             case EFlowAssignType.Role:
-                AssignRoles.AddRange(handlers);
-                AssignRoles = AssignRoles.Distinct().ToList();
+                //AssignRoles.AddRange(handlers);
+                //AssignRoles = AssignRoles.Distinct().ToList();
+                throw new NotImplementedException();
                 break;
             default:
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);
@@ -235,27 +240,29 @@ public abstract class PositionWorkflowEntity : PositionEntity, IWorkflow
     [SugarColumn(ColumnDataType = "varchar(1000)", IsJson = true)]
     public List<string> AssignOrgCodes { get; set; } = new();
 
-    [SugarColumn(ColumnDataType = "varchar(2000)", IsJson = true)]
+    [SugarColumn(ColumnDataType = "longtext", IsJson = true)]
     public List<string> AssignUserIds { get; set; } = new();
 
-    [SugarColumn(ColumnDataType = "varchar(600)", IsJson = true)]
-    public List<string> AssignRoles { get; set; } = new();
+    //[SugarColumn(ColumnDataType = "varchar(600)", IsJson = true)]
+    //public List<string> AssignRoles { get; set; } = new();
 
     public void Assign(EFlowAssignType type, string handler)
     {
         switch (type)
         {
             case EFlowAssignType.Org:
-                if (!AssignOrgCodes.Exists(d => d == handler))
-                    AssignOrgCodes.Add(handler);
+                var orgCodes = handler.GetHigherOrgCodes(true).ToList();
+                AssignOrgCodes.AddRange(orgCodes);
+                AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
                 if (!AssignUserIds.Exists(d => d == handler))
                     AssignUserIds.Add(handler);
                 break;
             case EFlowAssignType.Role:
-                if (!AssignRoles.Exists(d => d == handler))
-                    AssignRoles.Add(handler);
+                //if (!AssignRoles.Exists(d => d == handler))
+                //    AssignRoles.Add(handler);
+                throw new NotImplementedException();
                 break;
             default:
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);
@@ -267,7 +274,8 @@ public abstract class PositionWorkflowEntity : PositionEntity, IWorkflow
         switch (type)
         {
             case EFlowAssignType.Org:
-                AssignOrgCodes.AddRange(handlers);
+                var orgCodes = handlers.SelectMany(d => d.GetHigherOrgCodes(true)).ToList();
+                AssignOrgCodes.AddRange(orgCodes);
                 AssignOrgCodes = AssignOrgCodes.Distinct().ToList();
                 break;
             case EFlowAssignType.User:
@@ -275,8 +283,9 @@ public abstract class PositionWorkflowEntity : PositionEntity, IWorkflow
                 AssignUserIds = AssignUserIds.Distinct().ToList();
                 break;
             case EFlowAssignType.Role:
-                AssignRoles.AddRange(handlers);
-                AssignRoles = AssignRoles.Distinct().ToList();
+                //AssignRoles.AddRange(handlers);
+                //AssignRoles = AssignRoles.Distinct().ToList();
+                throw new NotImplementedException();
                 break;
             default:
                 throw new ArgumentOutOfRangeException(nameof(type), type, null);

+ 8 - 8
src/XF.Domain/Entities/IDataPermission.cs

@@ -28,10 +28,10 @@ namespace XF.Domain.Entities
         /// </summary>
         List<string> AssignUserIds { get; set; }
 
-        /// <summary>
-        /// 指派角色名称
-        /// </summary>
-        List<string> AssignRoles { get; set; }
+        ///// <summary>
+        ///// 指派角色名称
+        ///// </summary>
+        //List<string> AssignRoles { get; set; }
 
         void Assign(EFlowAssignType type, string handler);
 
@@ -50,9 +50,9 @@ namespace XF.Domain.Entities
         /// </summary>
         User = 1,
 
-        /// <summary>
-        /// 指派到角色
-        /// </summary>
-        Role = 2,
+        ///// <summary>
+        ///// 指派到角色
+        ///// </summary>
+        //Role = 2,
     }
 }

+ 32 - 0
src/XF.Domain/Extensions/OrgExtensions.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using XF.Domain.Exceptions;
+
+namespace XF.Domain.Extensions
+{
+    public static class OrgExtensions
+    {
+        public static List<string> GetHigherOrgCodes(this string orgCode, bool withSelf = false)
+        {
+            if (string.IsNullOrEmpty(orgCode))
+                return new();
+            var length = orgCode.Length;
+            if (length % 3 != 0)
+                throw new UserFriendlyException($"非法OrgCode, code: {orgCode}");
+
+            var rsp = new List<string>();
+            if (withSelf)
+                rsp.Add(orgCode);
+            var code = orgCode.Substring(0, length - 3);
+            while (code.Length > 0)
+            {
+                rsp.Add(code);
+                code = code.Substring(0, code.Length - 3);
+            }
+            return rsp;
+        }
+    }
+}