From 138943603ac70f25500d8daba79e58c302cbd817 Mon Sep 17 00:00:00 2001
From: sunpengfei <i@angelzzz.com>
Date: 星期一, 04 八月 2025 13:41:38 +0800
Subject: [PATCH] feat:角色开发

---
 FlexJobApi.User.Application/FlexJobApi.User.Application.xml               |   39 +++
 FlexJobApi.User.Application/Auths/Commands/PasswordLoginCommandHandler.cs |    6 
 FlexJobApi.User.Application/Roles/Commands/DeleteRoleCommandHandler.cs    |   35 ++
 FlexJobApi.Core/Models/User/Roles/Commands/SaveRoleCommand.cs             |   50 +++
 FlexJobApi.Application/Dictionaries/DictionaryAppService.cs               |    2 
 FlexJobApi.Application/FlexJobApi.Application.xml                         |    2 
 FlexJobApi.Core/Models/User/Menus/Commands/DeleteMenuCommand.cs           |   11 
 FlexJobApi.Core/Entities/Users/RoleResource.cs                            |   10 
 FlexJobApi.Core/Utils/PagedListUtils/PagedListUtils.cs                    |   91 +++++++
 FlexJobApi.User.Application/Roles/Queries/GetRoleQueryHandler.cs          |   47 +++
 FlexJobApi.Core/Utils/PagedListUtils/PagedListQuery.cs                    |   27 +
 FlexJobApi.User.Application/Roles/Queries/GetRolesQueryHandler.cs         |    7 
 FlexJobApi.Core/FlexJobApi.Core.xml                                       |  158 ++++++++++++-
 FlexJobApi.Core/Models/User/Auths/Commands/PasswordLoginCommand.cs        |    9 
 FlexJobApi.Core/Models/User/Roles/Queries/GetRoleQuery.cs                 |   77 ++++++
 FlexJobApi.Core/Models/User/Roles/Commands/DeleteRoleCommand.cs           |   11 
 FlexJobApi.User.Application/Roles/Commands/SaveRoleCommandHandler.cs      |   60 +++++
 FlexJobApi.Core/Utils/DeleteUtils/DeleteCommand.cs                        |   23 +
 18 files changed, 618 insertions(+), 47 deletions(-)

diff --git a/FlexJobApi.Application/Dictionaries/DictionaryAppService.cs b/FlexJobApi.Application/Dictionaries/DictionaryAppService.cs
index 6a092d0..2e6f38b 100644
--- a/FlexJobApi.Application/Dictionaries/DictionaryAppService.cs
+++ b/FlexJobApi.Application/Dictionaries/DictionaryAppService.cs
@@ -18,7 +18,7 @@
         /// </summary>
         /// <param name="query"></param>
         /// <returns></returns>
-        public Task<GetDictionaryDatasQueryResult> GetDictionaryDatasQuery(GetDictionaryDatasQuery query)
+        public Task<GetDictionaryDatasQueryResult> GetDictionaryDatas(GetDictionaryDatasQuery query)
         {
             return mediator.Send(query);
         }
diff --git a/FlexJobApi.Application/FlexJobApi.Application.xml b/FlexJobApi.Application/FlexJobApi.Application.xml
index ca30bbe..1cd4ea2 100644
--- a/FlexJobApi.Application/FlexJobApi.Application.xml
+++ b/FlexJobApi.Application/FlexJobApi.Application.xml
@@ -14,7 +14,7 @@
             璧勬簮
             </summary>
         </member>
-        <member name="M:FlexJobApi.Application.DictionaryAppService.GetDictionaryDatasQuery(FlexJobApi.Core.GetDictionaryDatasQuery)">
+        <member name="M:FlexJobApi.Application.DictionaryAppService.GetDictionaryDatas(FlexJobApi.Core.GetDictionaryDatasQuery)">
             <summary>
             鑾峰彇瀛楀吀鏁版嵁鍒嗛〉鍒楄〃
             </summary>
diff --git a/FlexJobApi.Core/Entities/Users/RoleResource.cs b/FlexJobApi.Core/Entities/Users/RoleResource.cs
index 3509cdb..d6713bd 100644
--- a/FlexJobApi.Core/Entities/Users/RoleResource.cs
+++ b/FlexJobApi.Core/Entities/Users/RoleResource.cs
@@ -22,18 +22,18 @@
         public Role Role { get; set; }
 
         /// <summary>
-        /// 鑿滃崟Id
+        /// 璧勬簮Id
         /// </summary>
-        public Guid MenuId { get; set; }
+        public Guid ResourceId { get; set; }
 
         /// <summary>
-        /// 鑿滃崟
+        /// 璧勬簮
         /// </summary>
-        public Menu Menu { get; set; }
+        public Resource Resource { get; set; }
 
         /// <summary>
         /// 鏁版嵁鏉冮檺
         /// </summary>
-        public EnumRoleWebApiDataPower? DataPower { get; set; }
+        public EnumRoleWebApiDataPower DataPower { get; set; }
     }
 }
diff --git a/FlexJobApi.Core/FlexJobApi.Core.xml b/FlexJobApi.Core/FlexJobApi.Core.xml
index 688e833..7a83241 100644
--- a/FlexJobApi.Core/FlexJobApi.Core.xml
+++ b/FlexJobApi.Core/FlexJobApi.Core.xml
@@ -989,14 +989,14 @@
             瑙掕壊
             </summary>
         </member>
-        <member name="P:FlexJobApi.Core.RoleResource.MenuId">
+        <member name="P:FlexJobApi.Core.RoleResource.ResourceId">
             <summary>
-            鑿滃崟Id
+            璧勬簮Id
             </summary>
         </member>
-        <member name="P:FlexJobApi.Core.RoleResource.Menu">
+        <member name="P:FlexJobApi.Core.RoleResource.Resource">
             <summary>
-            鑿滃崟
+            璧勬簮
             </summary>
         </member>
         <member name="P:FlexJobApi.Core.RoleResource.DataPower">
@@ -1969,11 +1969,6 @@
             鍒犻櫎鑿滃崟
             </summary>
         </member>
-        <member name="P:FlexJobApi.Core.DeleteMenuCommand.Ids">
-            <summary>
-            Id
-            </summary>
-        </member>
         <member name="T:FlexJobApi.Core.SaveMenuCommand">
             <summary>
             淇濆瓨鑿滃崟
@@ -2604,6 +2599,116 @@
             鍝嶅簲绫诲瀷鍚嶇О
             </summary>
         </member>
+        <member name="T:FlexJobApi.Core.DeleteRoleCommand">
+            <summary>
+            鍒犻櫎瑙掕壊
+            </summary>
+        </member>
+        <member name="T:FlexJobApi.Core.SaveRoleCommand">
+            <summary>
+            淇濆瓨瑙掕壊
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.Id">
+            <summary>
+            Id
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.Name">
+            <summary>
+            鍚嶇О
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.UserType">
+            <summary>
+            鐢ㄦ埛绫诲瀷
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.ClientType">
+            <summary>
+            瀹㈡埛绔被鍨�
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.MinLevel">
+            <summary>
+            鏈�浣庣骇鍒�
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.MenuIds">
+            <summary>
+            鑿滃崟Id
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.SaveRoleCommand.Resources">
+            <summary>
+            璧勬簮
+            </summary>
+        </member>
+        <member name="T:FlexJobApi.Core.GetRoleQuery">
+            <summary>
+            鏌ヨ瑙掕壊璇︽儏
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQuery.Id">
+            <summary>
+            Id
+            </summary>
+        </member>
+        <member name="T:FlexJobApi.Core.GetRoleQueryResult">
+            <summary>
+            鏌ヨ瑙掕壊璇︽儏-缁撴灉
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.Id">
+            <summary>
+            Id
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.Name">
+            <summary>
+            鍚嶇О
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.UserType">
+            <summary>
+            鐢ㄦ埛绫诲瀷
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.ClientType">
+            <summary>
+            瀹㈡埛绔被鍨�
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.MinLevel">
+            <summary>
+            鏈�浣庣骇鍒�
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.MenuIds">
+            <summary>
+            鑿滃崟Id
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResult.Resources">
+            <summary>
+            璧勬簮
+            </summary>
+        </member>
+        <member name="T:FlexJobApi.Core.GetRoleQueryResultResource">
+            <summary>
+            鏌ヨ瑙掕壊璇︽儏-缁撴灉-璧勬簮
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResultResource.ResourceId">
+            <summary>
+            璧勬簮Id
+            </summary>
+        </member>
+        <member name="P:FlexJobApi.Core.GetRoleQueryResultResource.DataPower">
+            <summary>
+            鏁版嵁鏉冮檺
+            </summary>
+        </member>
         <member name="T:FlexJobApi.Core.GetRolesQuery">
             <summary>
             鏌ヨ瑙掕壊鍒嗛〉鍒楄〃
@@ -2757,6 +2862,11 @@
             <param name="modelBuilder"></param>
             <param name="dbContextLocator"></param>
             <returns></returns>
+        </member>
+        <member name="T:FlexJobApi.Core.DeleteCommand">
+            <summary>
+            鍒犻櫎鍛戒护
+            </summary>
         </member>
         <member name="P:FlexJobApi.Core.EnumModel.Name">
             <summary>
@@ -3036,7 +3146,7 @@
             <summary>
             鏌ヨ鍒嗛〉鍒楄〃
             </summary>
-            <typeparam name="TCallback"></typeparam>
+            <typeparam name="TResult"></typeparam>
             <typeparam name="TItem"></typeparam>
         </member>
         <member name="P:FlexJobApi.Core.PagedListQuery`2.PageModel">
@@ -3059,9 +3169,9 @@
             椤电爜
             </summary>
         </member>
-        <member name="P:FlexJobApi.Core.PagedListQueryPageModel.TotalCount">
+        <member name="P:FlexJobApi.Core.PagedListQueryPageModel.OrderInput">
             <summary>
-            鎬绘暟
+            鎺掑簭
             </summary>
         </member>
         <member name="T:FlexJobApi.Core.PagedListQueryPageModelOrderInput">
@@ -3100,11 +3210,35 @@
             鏌ヨ鍒嗛〉鍒楄〃-鍒嗛〉淇℃伅
             </summary>
         </member>
+        <member name="P:FlexJobApi.Core.PagedListQueryResultPageModel.TotalCount">
+            <summary>
+            鎬绘暟
+            </summary>
+        </member>
         <member name="P:FlexJobApi.Core.PagedListQueryResultPageModel.TotalPage">
             <summary>
             椤垫暟
             </summary>
         </member>
+        <member name="M:FlexJobApi.Core.PagedListUtils.ToPagedListAsync``1(System.Linq.IQueryable{``0},FlexJobApi.Core.PagedListQueryPageModel,System.Threading.CancellationToken)">
+            <summary>
+            鏌ヨ鍒嗛〉鍒楄〃鏁版嵁
+            </summary>
+            <typeparam name="TItem"></typeparam>
+            <param name="q"></param>
+            <param name="page"></param>
+            <param name="cancellationToken"></param>
+            <returns></returns>
+        </member>
+        <member name="M:FlexJobApi.Core.PagedListUtils.OrderBy``1(System.Linq.IQueryable{``0},System.Collections.Generic.List{FlexJobApi.Core.PagedListQueryPageModelOrderInput})">
+            <summary>
+            鎺掑簭
+            </summary>
+            <typeparam name="T"></typeparam>
+            <param name="q"></param>
+            <param name="orders"></param>
+            <returns></returns>
+        </member>
         <member name="P:FlexJobApi.Core.ResourceModel.TraceId">
             <summary>
             璺熻釜Id
diff --git a/FlexJobApi.Core/Models/User/Auths/Commands/PasswordLoginCommand.cs b/FlexJobApi.Core/Models/User/Auths/Commands/PasswordLoginCommand.cs
index ebb0089..abc5183 100644
--- a/FlexJobApi.Core/Models/User/Auths/Commands/PasswordLoginCommand.cs
+++ b/FlexJobApi.Core/Models/User/Auths/Commands/PasswordLoginCommand.cs
@@ -43,6 +43,15 @@
     /// </summary>
     public class PasswordLoginCommandCallback
     {
+        /// <summary>
+        /// 鐢ㄦ埛璁块棶浠ょ墝
+        /// </summary>
+        public string AccessToken { get; set; }
+
+        /// <summary>
+        /// 鍒锋柊浠ょ墝
+        /// </summary>
+        public string RefreshToken { get; set; }
 
     }
 }
diff --git a/FlexJobApi.Core/Models/User/Menus/Commands/DeleteMenuCommand.cs b/FlexJobApi.Core/Models/User/Menus/Commands/DeleteMenuCommand.cs
index f955f7a..28ca271 100644
--- a/FlexJobApi.Core/Models/User/Menus/Commands/DeleteMenuCommand.cs
+++ b/FlexJobApi.Core/Models/User/Menus/Commands/DeleteMenuCommand.cs
@@ -11,17 +11,8 @@
     /// <summary>
     /// 鍒犻櫎鑿滃崟
     /// </summary>
-    public class DeleteMenuCommand : IRequest<int>
+    public class DeleteMenuCommand : DeleteCommand, IRequest<int>
     {
-        public DeleteMenuCommand()
-        {
-            Ids = [];
-        }
 
-        /// <summary>
-        /// Id
-        /// </summary>
-        [Required]
-        public List<Guid> Ids { get; set; }
     }
 }
diff --git a/FlexJobApi.Core/Models/User/Roles/Commands/DeleteRoleCommand.cs b/FlexJobApi.Core/Models/User/Roles/Commands/DeleteRoleCommand.cs
index 1aafd0f..4aaadfa 100644
--- a/FlexJobApi.Core/Models/User/Roles/Commands/DeleteRoleCommand.cs
+++ b/FlexJobApi.Core/Models/User/Roles/Commands/DeleteRoleCommand.cs
@@ -1,12 +1,17 @@
-锘縰sing System;
+锘縰sing MediatR;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace FlexJobApi.Core.Models.User.Roles.Commands
+namespace FlexJobApi.Core
 {
-    internal class DeleteRoleCommand
+    /// <summary>
+    /// 鍒犻櫎瑙掕壊
+    /// </summary>
+    public class DeleteRoleCommand : DeleteCommand, IRequest<int>
     {
+
     }
 }
diff --git a/FlexJobApi.Core/Models/User/Roles/Commands/SaveRoleCommand.cs b/FlexJobApi.Core/Models/User/Roles/Commands/SaveRoleCommand.cs
index c32b741..45452a1 100644
--- a/FlexJobApi.Core/Models/User/Roles/Commands/SaveRoleCommand.cs
+++ b/FlexJobApi.Core/Models/User/Roles/Commands/SaveRoleCommand.cs
@@ -1,12 +1,56 @@
-锘縰sing System;
+锘縰sing MediatR;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace FlexJobApi.Core.Models.User.Roles.Commands
+namespace FlexJobApi.Core
 {
-    internal class SaveRoleCommand
+    /// <summary>
+    /// 淇濆瓨瑙掕壊
+    /// </summary>
+    public class SaveRoleCommand : IRequest<Guid>
     {
+        public SaveRoleCommand()
+        {
+            MenuIds = [];
+            Resources = [];
+        }
+
+        /// <summary>
+        /// Id
+        /// </summary>
+        public Guid? Id { get; set; }
+
+        /// <summary>
+        /// 鍚嶇О
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 鐢ㄦ埛绫诲瀷
+        /// </summary>
+        public EnumUserType UserType { get; set; }
+
+        /// <summary>
+        /// 瀹㈡埛绔被鍨�
+        /// </summary>
+        public EnumClientType ClientType { get; set; }
+
+        /// <summary>
+        /// 鏈�浣庣骇鍒�
+        /// </summary>
+        public int MinLevel { get; set; }
+
+        /// <summary>
+        /// 鑿滃崟Id
+        /// </summary>
+        public List<Guid> MenuIds { get; set; }
+
+        /// <summary>
+        /// 璧勬簮
+        /// </summary>
+        public List<GetRoleQueryResultResource> Resources { get; set; }
     }
 }
diff --git a/FlexJobApi.Core/Models/User/Roles/Queries/GetRoleQuery.cs b/FlexJobApi.Core/Models/User/Roles/Queries/GetRoleQuery.cs
index 119b93e..bb9ba7b 100644
--- a/FlexJobApi.Core/Models/User/Roles/Queries/GetRoleQuery.cs
+++ b/FlexJobApi.Core/Models/User/Roles/Queries/GetRoleQuery.cs
@@ -1,12 +1,83 @@
-锘縰sing System;
+锘縰sing MediatR;
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
 
-namespace FlexJobApi.Core.Models.User.Roles.Queries
+namespace FlexJobApi.Core
 {
-    internal class GetRoleQuery
+    /// <summary>
+    /// 鏌ヨ瑙掕壊璇︽儏
+    /// </summary>
+    public class GetRoleQuery : IRequest<GetRoleQueryResult>
     {
+        /// <summary>
+        /// Id
+        /// </summary>
+        public Guid Id { get; set; }
+    }
+
+    /// <summary>
+    /// 鏌ヨ瑙掕壊璇︽儏-缁撴灉
+    /// </summary>
+    public class GetRoleQueryResult
+    {
+        public GetRoleQueryResult()
+        {
+            MenuIds = [];
+            Resources = [];
+        }
+
+        /// <summary>
+        /// Id
+        /// </summary>
+        public Guid Id { get; set; }
+
+        /// <summary>
+        /// 鍚嶇О
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// 鐢ㄦ埛绫诲瀷
+        /// </summary>
+        public EnumUserType UserType { get; set; }
+
+        /// <summary>
+        /// 瀹㈡埛绔被鍨�
+        /// </summary>
+        public EnumClientType ClientType { get; set; }
+
+        /// <summary>
+        /// 鏈�浣庣骇鍒�
+        /// </summary>
+        public int MinLevel { get; set; }
+
+        /// <summary>
+        /// 鑿滃崟Id
+        /// </summary>
+        public List<Guid> MenuIds { get; set; }
+
+        /// <summary>
+        /// 璧勬簮
+        /// </summary>
+        public List<GetRoleQueryResultResource> Resources { get; set; }
+    }
+
+    /// <summary>
+    /// 鏌ヨ瑙掕壊璇︽儏-缁撴灉-璧勬簮
+    /// </summary>
+    public class GetRoleQueryResultResource
+    {
+        /// <summary>
+        /// 璧勬簮Id
+        /// </summary>
+        public Guid ResourceId { get; set; }
+
+        /// <summary>
+        /// 鏁版嵁鏉冮檺
+        /// </summary>
+        public EnumRoleWebApiDataPower DataPower { get; set; }
     }
 }
diff --git a/FlexJobApi.Core/Utils/DeleteUtils/DeleteCommand.cs b/FlexJobApi.Core/Utils/DeleteUtils/DeleteCommand.cs
new file mode 100644
index 0000000..2b9edb9
--- /dev/null
+++ b/FlexJobApi.Core/Utils/DeleteUtils/DeleteCommand.cs
@@ -0,0 +1,23 @@
+锘縰sing System;
+using System.Collections.Generic;
+using System.ComponentModel.DataAnnotations;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FlexJobApi.Core
+{
+    /// <summary>
+    /// 鍒犻櫎鍛戒护
+    /// </summary>
+    public abstract class DeleteCommand
+    {
+        protected DeleteCommand()
+        {
+            Ids = [];
+        }
+
+        [Required]
+        public List<Guid> Ids { get; set; }
+    }
+}
diff --git a/FlexJobApi.Core/Utils/PagedListUtils/PagedListQuery.cs b/FlexJobApi.Core/Utils/PagedListUtils/PagedListQuery.cs
index eaf9bfa..6ae8a7e 100644
--- a/FlexJobApi.Core/Utils/PagedListUtils/PagedListQuery.cs
+++ b/FlexJobApi.Core/Utils/PagedListUtils/PagedListQuery.cs
@@ -10,12 +10,17 @@
     /// <summary>
     /// 鏌ヨ鍒嗛〉鍒楄〃
     /// </summary>
-    /// <typeparam name="TCallback"></typeparam>
+    /// <typeparam name="TResult"></typeparam>
     /// <typeparam name="TItem"></typeparam>
-    public abstract class PagedListQuery<TCallback, TItem>
-        where TCallback : PagedListQueryResult<TItem>, new()
+    public abstract class PagedListQuery<TResult, TItem>
+        where TResult : PagedListQueryResult<TItem>, new()
         where TItem : class, new()
     {
+        protected PagedListQuery()
+        {
+            PageModel = new PagedListQueryPageModel();
+        }
+
         /// <summary>
         /// 鍒嗛〉淇℃伅
         /// </summary>
@@ -27,6 +32,13 @@
     /// </summary>
     public class PagedListQueryPageModel
     {
+        public PagedListQueryPageModel()
+        {
+            Page = 1;
+            Rows = 40;
+            OrderInput = [];
+        }
+
         /// <summary>
         /// 琛屾暟
         /// </summary>
@@ -38,9 +50,9 @@
         public int Page { get; set; }
 
         /// <summary>
-        /// 鎬绘暟
+        /// 鎺掑簭
         /// </summary>
-        public int TotalCount { get; set; }
+        public List<PagedListQueryPageModelOrderInput> OrderInput { get; set; }
     }
 
     /// <summary>
@@ -88,6 +100,11 @@
     public class PagedListQueryResultPageModel : PagedListQueryPageModel
     {
         /// <summary>
+        /// 鎬绘暟
+        /// </summary>
+        public int TotalCount { get; set; }
+
+        /// <summary>
         /// 椤垫暟
         /// </summary>
         public int TotalPage { get; set; }
diff --git a/FlexJobApi.Core/Utils/PagedListUtils/PagedListUtils.cs b/FlexJobApi.Core/Utils/PagedListUtils/PagedListUtils.cs
index 32c3b55..3ff720c 100644
--- a/FlexJobApi.Core/Utils/PagedListUtils/PagedListUtils.cs
+++ b/FlexJobApi.Core/Utils/PagedListUtils/PagedListUtils.cs
@@ -1,12 +1,99 @@
-锘縰sing System;
+锘縰sing FlexJobApi.User.Application;
+using Furion.DatabaseAccessor;
+using Furion.FriendlyException;
+using Mapster;
+using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
 using System.Text;
+using System.Threading;
 using System.Threading.Tasks;
 
 namespace FlexJobApi.Core
 {
-    public class PagedListUtils
+    public static class PagedListUtils
     {
+        /// <summary>
+        /// 鏌ヨ鍒嗛〉鍒楄〃鏁版嵁
+        /// </summary>
+        /// <typeparam name="TItem"></typeparam>
+        /// <param name="q"></param>
+        /// <param name="page"></param>
+        /// <param name="cancellationToken"></param>
+        /// <returns></returns>
+        public static async Task<PagedListQueryResult<TItem>> ToPagedListAsync<TItem>(this IQueryable<TItem> q, PagedListQueryPageModel page, CancellationToken cancellationToken = default)
+            where TItem : class, new()
+        {
+            var pagedList = await q
+                .OrderBy(page.OrderInput)
+                .ToPagedListAsync(page.Page, page.Rows, cancellationToken);
+            var result = new PagedListQueryResult<TItem>();
+            result.PageModel = page.Adapt<PagedListQueryResultPageModel>();
+            result.PageModel.TotalCount = pagedList.TotalCount;
+            result.PageModel.TotalPage = pagedList.TotalPages;
+            result.Data = pagedList.Items.ToList();
+            return result;
+        }
+
+        /// <summary>
+        /// 鎺掑簭
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="q"></param>
+        /// <param name="orders"></param>
+        /// <returns></returns>
+        public static IQueryable<T> OrderBy<T>(this IQueryable<T> q, List<PagedListQueryPageModelOrderInput> orders)
+        {
+            if (orders.IsNull()) return q;
+
+            var entityType = typeof(T);
+            int index = 0;
+
+            foreach (var order in orders)
+            {
+                if (string.IsNullOrEmpty(order.Property)) continue;
+
+                // 鑾峰彇鎺掑簭瀛楁鐨勫睘鎬т俊鎭�
+                var propertyInfo = entityType.GetProperty(order.Property);
+                if (propertyInfo == null) throw Oops.Oh(EnumErrorCodeType.s404, $"璇ユ帓搴忓瓧娈祘order.Property}");
+
+                // 鍒涘缓琛ㄨ揪寮忔爲
+                var parameter = Expression.Parameter(entityType, "x");
+                var propertyAccess = Expression.Property(parameter, propertyInfo);
+                var lambda = Expression.Lambda(propertyAccess, parameter);
+
+                string methodName;
+                if (index == 0)
+                {
+                    // 棣栨鎺掑簭
+                    methodName = order.Order == EnumPagedListOrder.Ascending 
+                        ? "OrderBy" 
+                        : "OrderByDescending";
+                }
+                else
+                {
+                    // 浜屾鍙婁互鍚庢帓搴�
+                    methodName = order.Order == EnumPagedListOrder.Ascending 
+                        ? "ThenBy" 
+                        : "ThenByDescending";
+                }
+
+                // 璋冪敤鐩稿簲鐨勬帓搴忔柟娉�
+                var resultExpression = Expression.Call(
+                    typeof(Queryable),
+                    methodName,
+                    [entityType, propertyInfo.PropertyType],
+                    q.Expression,
+                    Expression.Quote(lambda)
+                );
+
+                q = q.Provider.CreateQuery<T>(resultExpression);
+                index++;
+            }
+
+            return q;
+        }
     }
 }
diff --git a/FlexJobApi.User.Application/Auths/Commands/PasswordLoginCommandHandler.cs b/FlexJobApi.User.Application/Auths/Commands/PasswordLoginCommandHandler.cs
index 1e83a74..71f3444 100644
--- a/FlexJobApi.User.Application/Auths/Commands/PasswordLoginCommandHandler.cs
+++ b/FlexJobApi.User.Application/Auths/Commands/PasswordLoginCommandHandler.cs
@@ -54,7 +54,11 @@
             };
             JwtUtils.GenerateToken(logier);
 
-            return new PasswordLoginCommandCallback();
+            return new PasswordLoginCommandCallback
+            { 
+                AccessToken = logier.AccessToken,
+                RefreshToken = logier.RefreshToken,
+            };
         }
     }
 }
diff --git a/FlexJobApi.User.Application/FlexJobApi.User.Application.xml b/FlexJobApi.User.Application/FlexJobApi.User.Application.xml
index 0ddf471..8ccf9d9 100644
--- a/FlexJobApi.User.Application/FlexJobApi.User.Application.xml
+++ b/FlexJobApi.User.Application/FlexJobApi.User.Application.xml
@@ -236,6 +236,45 @@
             <param name="query"></param>
             <returns></returns>
         </member>
+        <member name="T:FlexJobApi.User.Application.DeleteRoleCommandHandler">
+            <summary>
+            鍒犻櫎瑙掕壊
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.DeleteRoleCommandHandler.#ctor(Furion.DatabaseAccessor.IRepository{FlexJobApi.Core.Role})">
+            <summary>
+            鍒犻櫎瑙掕壊
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.DeleteRoleCommandHandler.Handle(FlexJobApi.Core.DeleteRoleCommand,System.Threading.CancellationToken)">
+            <inheritdoc/>
+        </member>
+        <member name="T:FlexJobApi.User.Application.SaveRoleCommandHandler">
+            <summary>
+            淇濆瓨瑙掕壊
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.SaveRoleCommandHandler.#ctor(Furion.DatabaseAccessor.IRepository{FlexJobApi.Core.Role})">
+            <summary>
+            淇濆瓨瑙掕壊
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.SaveRoleCommandHandler.Handle(FlexJobApi.Core.SaveRoleCommand,System.Threading.CancellationToken)">
+            <inheritdoc/>
+        </member>
+        <member name="T:FlexJobApi.User.Application.GetRoleQueryHandler">
+            <summary>
+            鑾峰彇瑙掕壊璇︽儏
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.GetRoleQueryHandler.#ctor(Furion.DatabaseAccessor.IRepository{FlexJobApi.Core.Role})">
+            <summary>
+            鑾峰彇瑙掕壊璇︽儏
+            </summary>
+        </member>
+        <member name="M:FlexJobApi.User.Application.GetRoleQueryHandler.Handle(FlexJobApi.Core.GetRoleQuery,System.Threading.CancellationToken)">
+            <inheritdoc/>
+        </member>
         <member name="T:FlexJobApi.User.Application.GetRolesQueryHandler">
             <summary>
             鏌ヨ瑙掕壊鍒嗛〉鍒楄〃
diff --git a/FlexJobApi.User.Application/Roles/Commands/DeleteRoleCommandHandler.cs b/FlexJobApi.User.Application/Roles/Commands/DeleteRoleCommandHandler.cs
new file mode 100644
index 0000000..e7a874d
--- /dev/null
+++ b/FlexJobApi.User.Application/Roles/Commands/DeleteRoleCommandHandler.cs
@@ -0,0 +1,35 @@
+锘縰sing FlexJobApi.Core;
+using Furion.DatabaseAccessor;
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FlexJobApi.User.Application
+{
+    /// <summary>
+    /// 鍒犻櫎瑙掕壊
+    /// </summary>
+    public class DeleteRoleCommandHandler(
+            IRepository<Role> rep
+        ) : IRequestHandler<DeleteRoleCommand, int>
+    {
+        private readonly IRepository<Role> rep = rep;
+
+        /// <inheritdoc/>
+        public async Task<int> Handle(DeleteRoleCommand request, CancellationToken cancellationToken)
+        {
+            var entities = await rep.AsQueryable()
+                .Include(it => it.RoleMenus)
+                .Include(it => it.RoleResources)
+                .Where(it => request.Ids.Contains(it.Id))
+                .ToListAsync(cancellationToken);
+            return entities.Any()
+                ? await rep.DeleteNowAsync(entities, cancellationToken)
+                : 0;
+        }
+    }
+}
diff --git a/FlexJobApi.User.Application/Roles/Commands/SaveRoleCommandHandler.cs b/FlexJobApi.User.Application/Roles/Commands/SaveRoleCommandHandler.cs
new file mode 100644
index 0000000..781349f
--- /dev/null
+++ b/FlexJobApi.User.Application/Roles/Commands/SaveRoleCommandHandler.cs
@@ -0,0 +1,60 @@
+锘縰sing FlexJobApi.Core;
+using Furion.DatabaseAccessor;
+using Furion.FriendlyException;
+using Mapster;
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FlexJobApi.User.Application
+{
+    /// <summary>
+    /// 淇濆瓨瑙掕壊
+    /// </summary>
+    public class SaveRoleCommandHandler(
+            IRepository<Role> rep
+        ) : IRequestHandler<SaveRoleCommand, Guid>
+    {
+        private readonly IRepository<Role> rep = rep;
+
+        /// <inheritdoc/>
+        public async Task<Guid> Handle(SaveRoleCommand request, CancellationToken cancellationToken)
+        {
+            if (request.Id.HasValue)
+            {
+                var entity = await rep.AsQueryable()
+                    .Include(it => it.RoleMenus)
+                    .Include(it => it.RoleResources)
+                    .FirstOrDefaultAsync(it => it.Id == request.Id, cancellationToken);
+                if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, "瑙掕壊");
+                request.Adapt(entity);
+                await rep.UpdateAsync(entity);
+                return entity.Id;
+            }
+            else
+            {
+                var entity = new Role();
+                request.Adapt(entity);
+                entity.RoleMenus = request.MenuIds
+                    .Select(it => new RoleMenu
+                    {
+                        MenuId = it
+                    })
+                    .ToList();
+                entity.RoleResources = request.Resources
+                    .Select(it => new RoleResource
+                    {
+                        ResourceId = it.ResourceId,
+                        DataPower = it.DataPower
+                    })
+                    .ToList();
+                await rep.InsertAsync(entity);
+                return entity.Id;
+            }
+        }
+    }
+}
diff --git a/FlexJobApi.User.Application/Roles/Queries/GetRoleQueryHandler.cs b/FlexJobApi.User.Application/Roles/Queries/GetRoleQueryHandler.cs
new file mode 100644
index 0000000..a538abb
--- /dev/null
+++ b/FlexJobApi.User.Application/Roles/Queries/GetRoleQueryHandler.cs
@@ -0,0 +1,47 @@
+锘縰sing FlexJobApi.Core;
+using Furion.DatabaseAccessor;
+using Furion.FriendlyException;
+using Mapster;
+using MediatR;
+using Microsoft.EntityFrameworkCore;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace FlexJobApi.User.Application
+{
+    /// <summary>
+    /// 鑾峰彇瑙掕壊璇︽儏
+    /// </summary>
+    public class GetRoleQueryHandler(
+            IRepository<Role> rep
+        ) : IRequestHandler<GetRoleQuery, GetRoleQueryResult>
+    {
+        private readonly IRepository<Role> rep = rep;
+
+        /// <inheritdoc/>
+        public async Task<GetRoleQueryResult> Handle(GetRoleQuery request, CancellationToken cancellationToken)
+        {
+            var entity = await rep.AsQueryable().AsNoTracking()
+                .Where(it => it.Id == request.Id)
+                .ProjectToType<GetRoleQueryResult>()
+                .FirstOrDefaultAsync(cancellationToken);
+
+            if (entity == null) throw Oops.Oh(EnumErrorCodeType.s404, "璇ヨ鑹�");
+
+            entity.MenuIds = await rep.Change<RoleMenu>().AsQueryable().AsNoTracking()
+                .Where(it => it.RoleId == request.Id)
+                .Select(it => it.MenuId)
+                .ToListAsync(cancellationToken);
+
+            entity.Resources = await rep.Change<RoleResource>().AsQueryable().AsNoTracking()
+                .Where(it => it.RoleId == request.Id)
+                .ProjectToType<GetRoleQueryResultResource>()
+                .ToListAsync(cancellationToken);
+
+            return entity;
+        }
+    }
+}
diff --git a/FlexJobApi.User.Application/Roles/Queries/GetRolesQueryHandler.cs b/FlexJobApi.User.Application/Roles/Queries/GetRolesQueryHandler.cs
index 49fd796..7ecb4e0 100644
--- a/FlexJobApi.User.Application/Roles/Queries/GetRolesQueryHandler.cs
+++ b/FlexJobApi.User.Application/Roles/Queries/GetRolesQueryHandler.cs
@@ -1,5 +1,6 @@
 锘縰sing FlexJobApi.Core;
 using Furion.DatabaseAccessor;
+using Mapster;
 using MediatR;
 using Microsoft.EntityFrameworkCore;
 using System;
@@ -32,7 +33,11 @@
             {
                 q = q.Where(it => it.ClientType == request.ClientType);
             }
-            throw new NotImplementedException();
+            var result = q
+                .ProjectToType<GetRolesQueryResultItem>()
+                .ToPagedListAsync(request.PageModel, cancellationToken);
+
+            return result;
         }
     }
 }

--
Gitblit v1.9.1