Files
Edu/apps/admin-portal/src/hooks/use-login-logs.ts
SpecialX 7cf9aec20e feat(admin-portal): 完成参考项目差距闭环 - 4 批次补齐 + Vitest 测试
差距分析闭环(workline §7-§8):
- P0:审计子模块 3 页 + 学校组织 7 页
- P1:系统设置 4 Card + 公告管理 + 邀请码管理
- P2:文件管理 + AI 配置
- P6:5 测试文件 / 69 用例全过

共享基础设施:
- permissions +11 权限点 +14 路由
- view-models +20 接口
- i18n +100 key
- graphql-client +25 operation
- fixtures/handlers +15 mock +20 handler

质量:typecheck + lint 零错误,vitest 69/69 通过,arch.db 已更新
2026-07-13 13:05:29 +08:00

62 lines
1.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 登录日志 Hooks
*
* contract §2.4loginLogs
*/
import { useCallback, useState } from "react";
import { useGraphQuery } from "./use-graphql";
import { LOGIN_LOGS_QUERY } from "@/lib/graphql-client";
import type {
LoginLogViewModel,
PaginatedResult,
ListFilter,
} from "@/types/view-models";
interface LoginLogsResponse {
loginLogs: PaginatedResult<LoginLogViewModel>;
}
interface LoginLogFilter extends Partial<ListFilter> {
action?: string;
status?: string;
startDate?: number;
endDate?: number;
}
export function useLoginLogs(filter: LoginLogFilter) {
const result = useGraphQuery<LoginLogsResponse>(LOGIN_LOGS_QUERY, {
filter,
});
return {
...result,
data: result.data?.loginLogs ?? null,
};
}
export function useLoginLogFilter(initial?: Partial<LoginLogFilter>) {
const [filter, setFilter] = useState<LoginLogFilter>({
page: 1,
pageSize: 20,
...initial,
});
const setPage = useCallback(
(page: number) => setFilter((f) => ({ ...f, page })),
[],
);
const setSearch = useCallback(
(search: string) => setFilter((f) => ({ ...f, search, page: 1 })),
[],
);
const setAction = useCallback(
(action: string) =>
setFilter((f) => ({ ...f, action: action || undefined, page: 1 })),
[],
);
const setStatus = useCallback(
(status: string) =>
setFilter((f) => ({ ...f, status: status || undefined, page: 1 })),
[],
);
return { filter, setFilter, setPage, setSearch, setAction, setStatus };
}