fix: 审批流程编辑器按步骤类型过滤可选用户
- 审核阶段: 只显示 admin/superadmin/dba/auditor 角色用户 - 执行阶段: 只显示 admin/superadmin/dba 角色用户 - 全选按钮也基于过滤后的用户列表 - UserDropdown 改用 fixed 定位避免 overflow 裁剪
This commit is contained in:
1 parent
aaa7666d66
commit
1f9d373c08
1 file changed
+33
-7
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useCallback } from 'react';
|
||||
import { useState, useEffect, useCallback, useRef } from 'react';
|
||||
import {
|
||||
Plus, Edit2, Eye, ToggleLeft, ToggleRight, GitBranch, Users, CheckCircle,
|
||||
ArrowRight, Shield, Trash2, X, ChevronDown, ChevronUp,
|
||||
@@ -99,15 +99,30 @@ interface UserDropdownProps {
|
||||
|
||||
function UserDropdown({ users, selectedIds, label, onToggle, onToggleAll, onClear, getUserName }: UserDropdownProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const triggerRef = useRef<HTMLButtonElement>(null);
|
||||
const ids = Array.isArray(selectedIds) ? selectedIds : [];
|
||||
const allSelected = ids.length === users.length && users.length > 0;
|
||||
const [dropdownPos, setDropdownPos] = useState({ top: 0, left: 0, width: 0 });
|
||||
|
||||
const updatePos = () => {
|
||||
if (triggerRef.current) {
|
||||
const rect = triggerRef.current.getBoundingClientRect();
|
||||
setDropdownPos({ top: rect.bottom + 4, left: rect.left, width: rect.width });
|
||||
}
|
||||
};
|
||||
|
||||
const handleToggle = () => {
|
||||
if (!open) updatePos();
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
{/* Trigger */}
|
||||
<button
|
||||
ref={triggerRef}
|
||||
type="button"
|
||||
onClick={() => setOpen(!open)}
|
||||
onClick={handleToggle}
|
||||
className={`w-full flex items-center justify-between px-3 py-2 rounded-lg text-sm transition-colors ${
|
||||
selectedIds.length === 0
|
||||
? 'bg-[var(--dg-bg-tertiary)] border border-red-500/40 text-[var(--dg-text-muted)]'
|
||||
@@ -142,11 +157,14 @@ function UserDropdown({ users, selectedIds, label, onToggle, onToggleAll, onClea
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Dropdown */}
|
||||
{/* Dropdown — fixed positioning to escape overflow clipping */}
|
||||
{open && (
|
||||
<>
|
||||
<div className="fixed inset-0 z-40" onClick={() => setOpen(false)} />
|
||||
<div className="absolute left-0 right-0 top-full mt-1 z-50 bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-lg shadow-xl max-h-52 overflow-y-auto">
|
||||
<div
|
||||
className="fixed z-50 bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-lg shadow-xl max-h-52 overflow-y-auto"
|
||||
style={{ top: dropdownPos.top, left: dropdownPos.left, width: dropdownPos.width }}
|
||||
>
|
||||
{/* Select all / Clear */}
|
||||
<div className="flex items-center justify-between px-3 py-2 border-b border-[var(--dg-border)]">
|
||||
<button
|
||||
@@ -262,12 +280,20 @@ function WorkflowEditorModal({ workflow, users, onClose, onSaved }: EditorProps)
|
||||
});
|
||||
};
|
||||
|
||||
const getEligibleUsers = (stepType: string) => {
|
||||
if (stepType === 'audit') return users.filter(u => ['admin', 'superadmin', 'dba', 'auditor'].includes(u.role));
|
||||
if (stepType === 'execute') return users.filter(u => ['admin', 'superadmin', 'dba'].includes(u.role));
|
||||
return users;
|
||||
};
|
||||
|
||||
const toggleAllUsers = (idx: number) => {
|
||||
const step = steps[idx];
|
||||
if (step.approver_ids.length === users.length) {
|
||||
const eligible = getEligibleUsers(step.step_type);
|
||||
const allSelected = step.approver_ids.length === eligible.length && eligible.length > 0;
|
||||
if (allSelected) {
|
||||
updateStep(idx, { approver_ids: [] });
|
||||
} else {
|
||||
updateStep(idx, { approver_ids: users.map((u) => u.id) });
|
||||
updateStep(idx, { approver_ids: eligible.map((u) => u.id) });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -417,7 +443,7 @@ function WorkflowEditorModal({ workflow, users, onClose, onSaved }: EditorProps)
|
||||
{step.step_type !== 'submit' && (
|
||||
<div className="pl-9 mt-2">
|
||||
<UserDropdown
|
||||
users={users}
|
||||
users={getEligibleUsers(step.step_type)}
|
||||
selectedIds={step.approver_ids}
|
||||
label={step.step_type === 'audit' ? '审核人员' : '执行人员'}
|
||||
onToggle={(uid) => toggleUser(idx, uid)}
|
||||
|
||||
Reference in new issue
Block a user