add log store and types

This commit is contained in:
2026-03-20 15:29:36 +08:00
parent 8948ce7d5a
commit f5e873d1ae
3 changed files with 240 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
import { api } from '@/utils/request'
import type {
PaginatedData,
OperationLogRecord,
OperationLogFilters,
} from '@/types/api'
export type { OperationLogRecord }
interface UserLookup {
id: number
username: string
}
export const useOperationLogStore = defineStore('operationLog', () => {
const logs = ref<OperationLogRecord[]>([])
const loading = ref(false)
const pagination = reactive({
page: 1,
per_page: 20,
total: 0,
})
const filters = reactive<OperationLogFilters>({
user_id: undefined,
action: undefined,
target_type: undefined,
created_at_range: null,
})
const users = ref<UserLookup[]>([])
const userMap = computed(
() => new Map(users.value.map((u) => [u.id, u.username])),
)
async function loadLookups() {
try {
const data = await api.get<PaginatedData<UserLookup>>('/api/v1/users', {
per_page: 200,
})
users.value = data.items
} catch (err: unknown) {
console.warn('加载用户列表失败', err)
}
}
async function fetchLogs() {
loading.value = true
try {
const data = await api.get<PaginatedData<OperationLogRecord>>(
'/api/v1/logs/operations',
{
page: pagination.page,
per_page: pagination.per_page,
user_id: filters.user_id || undefined,
action: filters.action || undefined,
target_type: filters.target_type || undefined,
created_at_from: filters.created_at_range?.[0] || undefined,
created_at_to: filters.created_at_range?.[1] || undefined,
},
)
logs.value = data.items
pagination.total = data.total
pagination.page = data.page
} catch (err: unknown) {
logs.value = []
pagination.total = 0
const msg = err instanceof Error ? err.message : '获取操作日志列表失败'
message.error(msg)
} finally {
loading.value = false
}
}
function resetFilters() {
filters.user_id = undefined
filters.action = undefined
filters.target_type = undefined
filters.created_at_range = null
pagination.page = 1
}
return {
logs,
loading,
pagination,
filters,
users,
userMap,
loadLookups,
fetchLogs,
resetFilters,
}
})
+96
View File
@@ -0,0 +1,96 @@
import { api } from '@/utils/request'
import type {
PaginatedData,
RequestLogRecord,
RequestLogFilters,
} from '@/types/api'
export type { RequestLogRecord }
interface UserLookup {
id: number
username: string
}
export const useRequestLogStore = defineStore('requestLog', () => {
const logs = ref<RequestLogRecord[]>([])
const loading = ref(false)
const pagination = reactive({
page: 1,
per_page: 20,
total: 0,
})
const filters = reactive<RequestLogFilters>({
user_id: undefined,
method: undefined,
path: '',
status_code: undefined,
created_at_range: null,
})
const users = ref<UserLookup[]>([])
const userMap = computed(
() => new Map(users.value.map((u) => [u.id, u.username])),
)
async function loadLookups() {
try {
const data = await api.get<PaginatedData<UserLookup>>('/api/v1/users', {
per_page: 200,
})
users.value = data.items
} catch (err: unknown) {
console.warn('加载用户列表失败', err)
}
}
async function fetchLogs() {
loading.value = true
try {
const data = await api.get<PaginatedData<RequestLogRecord>>(
'/api/v1/logs/requests',
{
page: pagination.page,
per_page: pagination.per_page,
user_id: filters.user_id || undefined,
method: filters.method || undefined,
path: filters.path || undefined,
status_code: filters.status_code || undefined,
created_at_from: filters.created_at_range?.[0] || undefined,
created_at_to: filters.created_at_range?.[1] || undefined,
},
)
logs.value = data.items
pagination.total = data.total
pagination.page = data.page
} catch (err: unknown) {
logs.value = []
pagination.total = 0
const msg = err instanceof Error ? err.message : '获取请求日志列表失败'
message.error(msg)
} finally {
loading.value = false
}
}
function resetFilters() {
filters.user_id = undefined
filters.method = undefined
filters.path = ''
filters.status_code = undefined
filters.created_at_range = null
pagination.page = 1
}
return {
logs,
loading,
pagination,
filters,
users,
userMap,
loadLookups,
fetchLogs,
resetFilters,
}
})
+51
View File
@@ -253,6 +253,57 @@ export interface DashboardBreakdownParams {
data_type?: string
}
/** ─── 请求日志 ─── */
export interface RequestLogRecord {
id: number
user_id: number | null
method: string
path: string
status_code: number
ip: string
response_code: number
duration_ms: number
created_at: string
}
export interface RequestLogDetail extends RequestLogRecord {
user_agent: string | null
request_body: Record<string, unknown> | null
}
export interface RequestLogFilters {
user_id: number | undefined
method: string | undefined
path: string
status_code: number | undefined
created_at_range: [string, string] | null
}
/** ─── 操作日志 ─── */
export interface OperationLogRecord {
id: number
user_id: number | null
action: string
target_type: string
target_id: number
description: string
ip: string
created_at: string
}
export interface OperationLogDetail extends OperationLogRecord {
detail: Record<string, unknown> | null
}
export interface OperationLogFilters {
user_id: number | undefined
action: string | undefined
target_type: string | undefined
created_at_range: [string, string] | null
}
/** 业务异常 */
export class ApiError extends Error {
code: number