概览页增加后台登录记录
登录成功/失败写入 admin_login_logs,系统概览下方展示全部账号的时间、IP、设备等信息。
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
import { query } from '../db/client.js'
|
||||
|
||||
export type AdminLoginLogRow = {
|
||||
[column: string]: unknown
|
||||
id: number
|
||||
user_id: number | null
|
||||
username: string
|
||||
role: string
|
||||
ip: string
|
||||
location: string
|
||||
user_agent: string
|
||||
success: boolean
|
||||
failure_reason: string
|
||||
created_at: string
|
||||
}
|
||||
|
||||
type AdminLoginLogCreateInput = {
|
||||
userId?: number | string | null
|
||||
username?: string
|
||||
role?: string
|
||||
ip?: string
|
||||
location?: string
|
||||
userAgent?: string
|
||||
success?: boolean
|
||||
failureReason?: string
|
||||
createdAt: string
|
||||
}
|
||||
|
||||
type AdminLoginLogListInput = {
|
||||
username?: string
|
||||
dateFrom?: string
|
||||
dateTo?: string
|
||||
page?: number | string
|
||||
pageSize?: number | string
|
||||
}
|
||||
|
||||
export async function createAdminLoginLog(
|
||||
input: AdminLoginLogCreateInput,
|
||||
): Promise<AdminLoginLogRow | null> {
|
||||
const result = await query<AdminLoginLogRow>(
|
||||
`
|
||||
INSERT INTO admin_login_logs (
|
||||
user_id,
|
||||
username,
|
||||
role,
|
||||
ip,
|
||||
location,
|
||||
user_agent,
|
||||
success,
|
||||
failure_reason,
|
||||
created_at
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING *
|
||||
`,
|
||||
[
|
||||
input.userId || null,
|
||||
String(input.username || '').trim(),
|
||||
String(input.role || '').trim(),
|
||||
String(input.ip || '').trim(),
|
||||
String(input.location || '').trim(),
|
||||
String(input.userAgent || '').trim(),
|
||||
input.success !== false,
|
||||
String(input.failureReason || '').trim(),
|
||||
input.createdAt,
|
||||
],
|
||||
)
|
||||
|
||||
return result.rows[0] || null
|
||||
}
|
||||
|
||||
export async function listAdminLoginLogs(
|
||||
queryInput: AdminLoginLogListInput = {},
|
||||
): Promise<{ items: AdminLoginLogRow[]; total: number }> {
|
||||
const conditions: string[] = []
|
||||
const params: unknown[] = []
|
||||
|
||||
if (queryInput.username) {
|
||||
params.push(String(queryInput.username).trim())
|
||||
conditions.push(`username = $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.dateFrom) {
|
||||
params.push(queryInput.dateFrom)
|
||||
conditions.push(`created_at >= $${params.length}`)
|
||||
}
|
||||
|
||||
if (queryInput.dateTo) {
|
||||
params.push(queryInput.dateTo)
|
||||
conditions.push(`created_at <= $${params.length}`)
|
||||
}
|
||||
|
||||
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''
|
||||
const page = Math.max(1, Number(queryInput.page) || 1)
|
||||
const pageSize = Math.min(100, Math.max(1, Number(queryInput.pageSize) || 20))
|
||||
const offset = (page - 1) * pageSize
|
||||
|
||||
const totalResult = await query<{ total: number }>(
|
||||
`SELECT COUNT(*)::int AS total FROM admin_login_logs ${whereClause}`,
|
||||
params,
|
||||
)
|
||||
|
||||
params.push(pageSize)
|
||||
params.push(offset)
|
||||
const itemsResult = await query<AdminLoginLogRow>(
|
||||
`
|
||||
SELECT *
|
||||
FROM admin_login_logs
|
||||
${whereClause}
|
||||
ORDER BY id DESC
|
||||
LIMIT $${params.length - 1} OFFSET $${params.length}
|
||||
`,
|
||||
params,
|
||||
)
|
||||
|
||||
return {
|
||||
items: itemsResult.rows,
|
||||
total: Number(totalResult.rows[0]?.total || 0),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user