Przeglądaj źródła

fix(approval): support tenant-scoped approver search

Add an approval-flow candidate user endpoint so approver selection can search current-tenant users by ID, account, or name, including tenant admins. Bump Web to 2.4.163 and server to 1.0.127.

Co-authored-by: Cursor <cursoragent@cursor.com>
skygu 2 dni temu
rodzic
commit
6dcb2d3067

+ 1 - 1
Web/package.json

@@ -1,7 +1,7 @@
 {
 	"name": "admin.net",
 	"type": "module",
-	"version": "2.4.167",
+	"version": "2.4.168",
 	"packageManager": "pnpm@10.32.1",
 	"lastBuildTime": "2026.03.15",
 	"description": "Admin.NET 站在巨人肩膀上的 .NET 通用权限开发框架",

+ 9 - 6
Web/src/views/approvalFlow/component/LogicFlow/Property/PropertyCommon.vue

@@ -245,8 +245,8 @@
 <script setup lang="ts">
 import { reactive, ref, computed, watch } from 'vue';
 import { ElMessage } from 'element-plus';
-import { getAPI } from '/@/utils/axios-utils';
-import { SysUserApi, SysRoleApi, SysOrgApi } from '/@/api-services/api';
+import { axiosInstance, getAPI, serveConfig } from '/@/utils/axios-utils';
+import { SysRoleApi, SysOrgApi } from '/@/api-services/api';
 
 const props = defineProps({
 	nodeData: { type: Object, default: () => ({}) },
@@ -274,14 +274,18 @@ const isParallelGateway = computed(() => {
 const userLoading = ref(false);
 const userOptions = ref<Array<{ id: number; account: string; realName: string }>>([]);
 const selectedUserIds = ref<number[]>([]);
+const escSelectedUserIds = ref<number[]>([]);
 
 const searchUsers = async (query: string) => {
 	if (!query) return;
 	userLoading.value = true;
 	try {
-		const res = await getAPI(SysUserApi).apiSysUserPagePost({ page: 1, pageSize: 20, realName: query } as any);
-		const items = res.data.result?.items ?? [];
-		const existing = userOptions.value.filter((o) => selectedUserIds.value.includes(o.id));
+		const res = await axiosInstance.get(`${serveConfig.basePath}/api/approvalFlow/candidateUsers`, {
+			params: { keyword: query, pageSize: 20 },
+		});
+		const items = res.data.result ?? [];
+		const selectedIds = new Set([...selectedUserIds.value, ...escSelectedUserIds.value]);
+		const existing = userOptions.value.filter((o) => selectedIds.has(o.id));
 		const merged = [...existing];
 		for (const u of items) {
 			if (u.id && !merged.some((m) => m.id === u.id)) {
@@ -347,7 +351,6 @@ const onOrgChange = () => {
 };
 
 // ── 升级目标选择状态 ──
-const escSelectedUserIds = ref<number[]>([]);
 const escSelectedRoleIds = ref<number[]>([]);
 const escSelectedOrgIds = ref<number[]>([]);
 

+ 3 - 3
server/Admin.NET.Web.Entry/Admin.NET.Web.Entry.csproj

@@ -11,9 +11,9 @@
     <GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
     <Copyright>Admin.NET</Copyright>
     <Description>Admin.NET 通用权限开发平台</Description>
-    <AssemblyVersion>1.0.129</AssemblyVersion>
-    <FileVersion>1.0.129</FileVersion>
-    <Version>1.0.129</Version>
+    <AssemblyVersion>1.0.130</AssemblyVersion>
+    <FileVersion>1.0.130</FileVersion>
+    <Version>1.0.130</Version>
   </PropertyGroup>
 
   <ItemGroup>

+ 33 - 0
server/Plugins/Admin.NET.Plugin.ApprovalFlow/Service/ApprovalFlow/ApprovalFlowService.cs

@@ -16,15 +16,18 @@ public class ApprovalFlowService : IDynamicApiController, ITransient
 {
     private readonly SqlSugarRepository<ApprovalFlow> _approvalFlowRep;
     private readonly SqlSugarRepository<ApprovalFlowVersion> _versionRep;
+    private readonly SqlSugarRepository<SysUser> _sysUserRep;
     private readonly UserManager _userManager;
 
     public ApprovalFlowService(
         SqlSugarRepository<ApprovalFlow> approvalFlowRep,
         SqlSugarRepository<ApprovalFlowVersion> versionRep,
+        SqlSugarRepository<SysUser> sysUserRep,
         UserManager userManager)
     {
         _approvalFlowRep = approvalFlowRep;
         _versionRep = versionRep;
+        _sysUserRep = sysUserRep;
         _userManager = userManager;
     }
 
@@ -117,6 +120,36 @@ public class ApprovalFlowService : IDynamicApiController, ITransient
         return await _approvalFlowRep.AsQueryable().Select<ApprovalFlowOutput>().ToListAsync();
     }
 
+    /// <summary>
+    /// 搜索审批人候选用户
+    /// </summary>
+    [HttpGet]
+    [ApiDescriptionSettings(Name = "CandidateUsers")]
+    [DisplayName("搜索审批人候选用户")]
+    public async Task<List<ApprovalCandidateUserOutput>> CandidateUsers([FromQuery] ApprovalCandidateUserInput input)
+    {
+        var keyword = input.Keyword?.Trim();
+        var pageSize = input.PageSize is > 0 and <= 100 ? input.PageSize : 20;
+        var keywordId = long.TryParse(keyword, out var parsedId) ? parsedId : 0;
+
+        return await _sysUserRep.AsQueryable()
+            .Where(u => u.TenantId == _userManager.TenantId)
+            .Where(u => u.AccountType != AccountTypeEnum.SuperAdmin)
+            .WhereIF(!string.IsNullOrWhiteSpace(keyword), u =>
+                u.Id == keywordId ||
+                u.Account.Contains(keyword!) ||
+                u.RealName.Contains(keyword!))
+            .OrderBy(u => new { u.OrderNo, u.Id })
+            .Select(u => new ApprovalCandidateUserOutput
+            {
+                Id = u.Id,
+                Account = u.Account,
+                RealName = u.RealName,
+            })
+            .Take(pageSize)
+            .ToListAsync();
+    }
+
     /// <summary>
     /// 获取今天创建的最大编号
     /// </summary>

+ 38 - 1
server/Plugins/Admin.NET.Plugin.ApprovalFlow/Service/ApprovalFlow/Dto/ApprovalFlowDto.cs

@@ -85,4 +85,41 @@ public class ApprovalFlowDto
     /// 软删除
     /// </summary>
     public bool IsDelete { get; set; }
-}
+}
+
+/// <summary>
+/// 审批人候选用户查询输入参数
+/// </summary>
+public class ApprovalCandidateUserInput
+{
+    /// <summary>
+    /// 关键字:支持用户Id、账号、姓名
+    /// </summary>
+    public string? Keyword { get; set; }
+
+    /// <summary>
+    /// 返回数量
+    /// </summary>
+    public int PageSize { get; set; } = 20;
+}
+
+/// <summary>
+/// 审批人候选用户输出参数
+/// </summary>
+public class ApprovalCandidateUserOutput
+{
+    /// <summary>
+    /// 用户Id
+    /// </summary>
+    public long Id { get; set; }
+
+    /// <summary>
+    /// 账号
+    /// </summary>
+    public string? Account { get; set; }
+
+    /// <summary>
+    /// 姓名
+    /// </summary>
+    public string? RealName { get; set; }
+}