feat: 日志列表
This commit is contained in:
@@ -1,14 +1,14 @@
|
|||||||
import type { Group, LogFilter, LogsResponse } from "@/types/models";
|
import type { ApiResponse, Group, LogFilter, LogsResponse } from "@/types/models";
|
||||||
import http from "@/utils/http";
|
import http from "@/utils/http";
|
||||||
|
|
||||||
export const logApi = {
|
export const logApi = {
|
||||||
// 获取日志列表
|
// 获取日志列表
|
||||||
getLogs: (params: LogFilter): Promise<LogsResponse> => {
|
getLogs: (params: LogFilter): Promise<ApiResponse<LogsResponse>> => {
|
||||||
return http.get("/logs", { params });
|
return http.get("/logs", { params });
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取分组列表(用于筛选)
|
// 获取分组列表(用于筛选)
|
||||||
getGroups: (): Promise<Group[]> => {
|
getGroups: (): Promise<ApiResponse<Group[]>> => {
|
||||||
return http.get("/groups");
|
return http.get("/groups");
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { keysApi } from "@/api/keys";
|
import { keysApi } from "@/api/keys";
|
||||||
import type { APIKey, Group, KeyStatus } from "@/types/models";
|
import type { APIKey, Group, KeyStatus } from "@/types/models";
|
||||||
import { getGroupDisplayName } from "@/utils/display";
|
import { getGroupDisplayName, maskKey } from "@/utils/display";
|
||||||
import {
|
import {
|
||||||
AddCircleOutline,
|
AddCircleOutline,
|
||||||
AlertCircleOutline,
|
AlertCircleOutline,
|
||||||
@@ -142,13 +142,6 @@ async function loadKeys() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function maskKey(key: string): string {
|
|
||||||
if (key.length <= 8) {
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyKey(key: KeyRow) {
|
function copyKey(key: KeyRow) {
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.writeText(key.key_value)
|
.writeText(key.key_value)
|
||||||
|
@@ -1,3 +1,10 @@
|
|||||||
|
// 通用 API 响应结构
|
||||||
|
export interface ApiResponse<T> {
|
||||||
|
code: number;
|
||||||
|
message: string;
|
||||||
|
data: T;
|
||||||
|
}
|
||||||
|
|
||||||
// 密钥状态
|
// 密钥状态
|
||||||
export type KeyStatus = "active" | "invalid" | undefined;
|
export type KeyStatus = "active" | "invalid" | undefined;
|
||||||
|
|
||||||
@@ -69,32 +76,47 @@ export interface TaskInfo {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Based on backend response
|
||||||
export interface RequestLog {
|
export interface RequestLog {
|
||||||
id: string;
|
id: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
group_id: number;
|
group_id: number;
|
||||||
key_id: number;
|
key_id: number;
|
||||||
|
is_success: boolean;
|
||||||
source_ip: string;
|
source_ip: string;
|
||||||
status_code: number;
|
status_code: number;
|
||||||
request_path: string;
|
request_path: string;
|
||||||
request_body_snippet: string;
|
duration_ms: number;
|
||||||
|
error_message: string;
|
||||||
|
user_agent: string;
|
||||||
|
retries: number;
|
||||||
|
group_name?: string;
|
||||||
|
key_value?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Pagination {
|
||||||
|
page: number;
|
||||||
|
page_size: number;
|
||||||
|
total_items: number;
|
||||||
|
total_pages: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogsResponse {
|
export interface LogsResponse {
|
||||||
total: number;
|
items: RequestLog[];
|
||||||
page: number;
|
pagination: Pagination;
|
||||||
size: number;
|
|
||||||
data: RequestLog[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LogFilter {
|
export interface LogFilter {
|
||||||
page: number;
|
page?: number;
|
||||||
size: number;
|
page_size?: number;
|
||||||
group_id?: number;
|
group_name?: string;
|
||||||
start_time?: string;
|
key_value?: string;
|
||||||
end_time?: string;
|
is_success?: boolean | null;
|
||||||
status_code?: number;
|
status_code?: number | null;
|
||||||
source_ip?: string;
|
source_ip?: string;
|
||||||
|
error_contains?: string;
|
||||||
|
start_time?: string | null;
|
||||||
|
end_time?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardStats {
|
export interface DashboardStats {
|
||||||
|
@@ -37,3 +37,15 @@ export function formatDisplayName(name: string): string {
|
|||||||
export function getGroupDisplayName(group: Group): string {
|
export function getGroupDisplayName(group: Group): string {
|
||||||
return group.display_name || formatDisplayName(group.name);
|
return group.display_name || formatDisplayName(group.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Masks a long key string for display.
|
||||||
|
* @param key The key string.
|
||||||
|
* @returns The masked key.
|
||||||
|
*/
|
||||||
|
export function maskKey(key: string): string {
|
||||||
|
if (!key || key.length <= 8) {
|
||||||
|
return key || "";
|
||||||
|
}
|
||||||
|
return `${key.substring(0, 4)}...${key.substring(key.length - 4)}`;
|
||||||
|
}
|
||||||
|
@@ -1,102 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { NCard, NH3, NSpace, NTag, NText } from "naive-ui";
|
import LogTable from "@/components/logs/LogTable.vue";
|
||||||
// 这里可以添加日志管理相关的逻辑
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="logs-container">
|
<div>
|
||||||
<n-space vertical size="large">
|
<log-table />
|
||||||
<!-- 占位符内容 -->
|
|
||||||
<div class="content-placeholder">
|
|
||||||
<n-card :bordered="false" class="placeholder-card">
|
|
||||||
<n-space vertical align="center" size="large">
|
|
||||||
<div class="placeholder-icon">📋</div>
|
|
||||||
<n-h3 class="placeholder-title">日志管理功能</n-h3>
|
|
||||||
<n-text depth="2" class="placeholder-description">
|
|
||||||
此功能正在开发中,将提供完整的系统日志查看和管理功能,包括实时日志、历史记录和日志分析。
|
|
||||||
</n-text>
|
|
||||||
|
|
||||||
<n-space wrap size="medium" class="placeholder-features">
|
|
||||||
<n-tag type="info" size="medium">📝 实时日志流</n-tag>
|
|
||||||
<n-tag type="info" size="medium">🔍 日志搜索过滤</n-tag>
|
|
||||||
<n-tag type="info" size="medium">📈 错误统计分析</n-tag>
|
|
||||||
<n-tag type="info" size="medium">💾 日志导出功能</n-tag>
|
|
||||||
</n-space>
|
|
||||||
</n-space>
|
|
||||||
</n-card>
|
|
||||||
</div>
|
|
||||||
</n-space>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.page-header-card {
|
|
||||||
background: rgba(255, 255, 255, 0.98);
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
||||||
animation: fadeInUp 0.2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-title {
|
|
||||||
font-size: 2.25rem;
|
|
||||||
font-weight: 700;
|
|
||||||
margin: 0;
|
|
||||||
letter-spacing: -0.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.page-subtitle {
|
|
||||||
font-size: 1.1rem;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-placeholder {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
min-height: 400px;
|
|
||||||
animation: fadeInUp 0.2s ease-out 0.1s both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-card {
|
|
||||||
text-align: center;
|
|
||||||
max-width: 500px;
|
|
||||||
padding: 48px 32px;
|
|
||||||
background: rgba(255, 255, 255, 0.98);
|
|
||||||
border-radius: var(--border-radius-lg);
|
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-icon {
|
|
||||||
font-size: 4rem;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-title {
|
|
||||||
font-size: 1.5rem;
|
|
||||||
font-weight: 600;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-description {
|
|
||||||
font-size: 1rem;
|
|
||||||
line-height: 1.6;
|
|
||||||
text-align: center;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.placeholder-features {
|
|
||||||
justify-content: center;
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px);
|
|
||||||
}
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
Reference in New Issue
Block a user