feat: 用户管理列表增加来源字段(auth_source),支持本地/LDAP筛选
This commit is contained in:
1 parent
ac07e6ef38
commit
8384006ae9
5 files changed
+196
-117
No files matched your search
@@ -24,6 +24,7 @@ interface UserItem {
|
||||
is_active: boolean;
|
||||
created_at: string;
|
||||
last_login?: string | null;
|
||||
auth_source?: string; // 'local' | 'ldap'
|
||||
}
|
||||
|
||||
interface UserActivity {
|
||||
@@ -70,6 +71,12 @@ const statusOptions = [
|
||||
{ value: 'disabled', label: '禁用' },
|
||||
];
|
||||
|
||||
const sourceOptions = [
|
||||
{ value: '', label: '全部来源' },
|
||||
{ value: 'local', label: '本地' },
|
||||
{ value: 'ldap', label: 'LDAP' },
|
||||
];
|
||||
|
||||
const BATCH_OPTIONS = [
|
||||
{ key: 'enable', label: '批量启用', icon: UserCheck },
|
||||
{ key: 'disable', label: '批量禁用', icon: UserX },
|
||||
@@ -124,6 +131,7 @@ export default function UsersPage() {
|
||||
const [search, setSearch] = useState('');
|
||||
const [roleFilter, setRoleFilter] = useState('');
|
||||
const [statusFilter, setStatusFilter] = useState('');
|
||||
const [sourceFilter, setSourceFilter] = useState('');
|
||||
const [users, setUsers] = useState<UserItem[]>([]);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [page, setPage] = useState(1);
|
||||
@@ -159,7 +167,10 @@ export default function UsersPage() {
|
||||
|
||||
useEffect(() => { fetchUsers(); }, [fetchUsers]);
|
||||
|
||||
const filtered = users;
|
||||
const filtered = users.filter(u => {
|
||||
if (sourceFilter && u.auth_source !== sourceFilter) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
const allSelected = filtered.length > 0 && filtered.every(u => selectedIds.has(u.id));
|
||||
|
||||
@@ -298,9 +309,16 @@ export default function UsersPage() {
|
||||
>
|
||||
{statusOptions.map(s => <option key={s.value} value={s.value}>{s.label}</option>)}
|
||||
</select>
|
||||
{(search || roleFilter || statusFilter) && (
|
||||
<select
|
||||
className="px-3 py-2.5 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded-lg text-sm focus:border-blue-400 focus:outline-none"
|
||||
value={sourceFilter}
|
||||
onChange={e => setSourceFilter(e.target.value)}
|
||||
>
|
||||
{sourceOptions.map(s => <option key={s.value} value={s.value}>{s.label}</option>)}
|
||||
</select>
|
||||
{(search || roleFilter || statusFilter || sourceFilter) && (
|
||||
<button
|
||||
onClick={() => { setSearch(''); setRoleFilter(''); setStatusFilter(''); setPage(1); }}
|
||||
onClick={() => { setSearch(''); setRoleFilter(''); setStatusFilter(''); setSourceFilter(''); setPage(1); }}
|
||||
className="flex items-center gap-1 text-xs text-[var(--dg-text-muted)] hover:text-[var(--dg-text-primary)] transition-colors"
|
||||
>
|
||||
<RotateCcw className="w-3 h-3" /> 重置
|
||||
@@ -382,6 +400,7 @@ export default function UsersPage() {
|
||||
<th className="text-left px-4 py-3 font-semibold">邮箱</th>
|
||||
<th className="text-left px-4 py-3 font-semibold">最后登录</th>
|
||||
<th className="text-left px-4 py-3 font-semibold">状态</th>
|
||||
<th className="text-left px-4 py-3 font-semibold">来源</th>
|
||||
<th className="text-left px-4 py-3 font-semibold">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -432,6 +451,15 @@ export default function UsersPage() {
|
||||
/>
|
||||
</button>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<span className={`inline-flex px-2 py-0.5 rounded text-xs font-medium ${
|
||||
user.auth_source === 'ldap'
|
||||
? 'bg-blue-500/15 text-blue-400'
|
||||
: 'bg-[var(--dg-bg-tertiary)] text-[var(--dg-text-muted)]'
|
||||
}`}>
|
||||
{user.auth_source === 'ldap' ? 'LDAP' : '本地'}
|
||||
</span>
|
||||
</td>
|
||||
<td className="px-4 py-3.5">
|
||||
<div className="flex gap-1.5">
|
||||
<button
|
||||
|
||||
Reference in new issue
Block a user