New
This commit is contained in:
77
frontend/js/pages/logs/index.js
Normal file
77
frontend/js/pages/logs/index.js
Normal file
@@ -0,0 +1,77 @@
|
||||
// Filename: frontend/js/pages/logs/index.js
|
||||
|
||||
import { apiFetchJson } from '../../services/api.js';
|
||||
import LogList from './logList.js';
|
||||
|
||||
class LogsPage {
|
||||
constructor() {
|
||||
this.state = {
|
||||
logs: [],
|
||||
// [修正] 暂时将分页状态设为默认值,直到后端添加分页支持
|
||||
pagination: { page: 1, pages: 1, total: 0 },
|
||||
isLoading: true,
|
||||
filters: { page: 1, page_size: 20 }
|
||||
};
|
||||
|
||||
this.elements = {
|
||||
tableBody: document.getElementById('logs-table-body'),
|
||||
};
|
||||
|
||||
this.initialized = !!this.elements.tableBody;
|
||||
|
||||
if (this.initialized) {
|
||||
this.logList = new LogList(this.elements.tableBody);
|
||||
}
|
||||
}
|
||||
|
||||
async init() {
|
||||
if (!this.initialized) {
|
||||
console.error("LogsPage: Could not initialize. Essential container element 'logs-table-body' is missing.");
|
||||
return;
|
||||
}
|
||||
this.initEventListeners();
|
||||
await this.loadAndRenderLogs();
|
||||
}
|
||||
|
||||
initEventListeners() {
|
||||
// 分页和筛选的事件监听器将在后续任务中添加
|
||||
}
|
||||
|
||||
async loadAndRenderLogs() {
|
||||
this.state.isLoading = true;
|
||||
this.logList.renderLoading();
|
||||
|
||||
try {
|
||||
const url = `/admin/logs?page=${this.state.filters.page}&page_size=${this.state.filters.page_size}`;
|
||||
const responseData = await apiFetchJson(url);
|
||||
|
||||
// [核心修正] 调整条件以匹配当前 API 返回的 { success: true, data: [...] } 结构
|
||||
if (responseData && responseData.success && Array.isArray(responseData.data)) {
|
||||
|
||||
// [核心修正] 直接从 responseData.data 获取日志数组
|
||||
this.state.logs = responseData.data;
|
||||
|
||||
// [临时] 由于当前响应不包含分页信息,我们暂时不更新 this.state.pagination
|
||||
// 等待后端完善分页后,再恢复这里的逻辑
|
||||
|
||||
this.logList.render(this.state.logs);
|
||||
|
||||
// this.renderPaginationControls();
|
||||
} else {
|
||||
console.error("API response for logs is incorrect:", responseData);
|
||||
this.logList.render([]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load logs:", error);
|
||||
// this.logList.renderError(error);
|
||||
} finally {
|
||||
this.state.isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 导出符合 main.js 规范的 default 函数
|
||||
export default function() {
|
||||
const page = new LogsPage();
|
||||
page.init();
|
||||
}
|
||||
60
frontend/js/pages/logs/logList.js
Normal file
60
frontend/js/pages/logs/logList.js
Normal file
@@ -0,0 +1,60 @@
|
||||
// Filename: frontend/js/pages/logs/logList.js
|
||||
|
||||
class LogList {
|
||||
constructor(container) {
|
||||
this.container = container;
|
||||
if (!this.container) {
|
||||
console.error("LogList: container element (tbody) not found.");
|
||||
}
|
||||
}
|
||||
|
||||
renderLoading() {
|
||||
if (!this.container) return;
|
||||
this.container.innerHTML = `<tr><td colspan="9" class="p-8 text-center text-muted-foreground"><i class="fas fa-spinner fa-spin mr-2"></i> 加载日志中...</td></tr>`;
|
||||
}
|
||||
|
||||
render(logs) {
|
||||
if (!this.container) return;
|
||||
|
||||
if (!logs || logs.length === 0) {
|
||||
this.container.innerHTML = `<tr><td colspan="9" class="p-8 text-center text-muted-foreground">没有找到相关的日志记录。</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
const logsHtml = logs.map(log => this.createLogRowHtml(log)).join('');
|
||||
this.container.innerHTML = logsHtml;
|
||||
}
|
||||
|
||||
createLogRowHtml(log) {
|
||||
// [后端协作点] 假设后端未来会提供 GroupDisplayName 和 APIKeyName
|
||||
const groupName = log.GroupDisplayName || (log.GroupID ? `Group #${log.GroupID}` : 'N/A');
|
||||
const apiKeyName = log.APIKeyName || (log.KeyID ? `Key #${log.KeyID}` : 'N/A');
|
||||
|
||||
const errorTag = log.IsSuccess
|
||||
? `<span class="inline-flex items-center rounded-md bg-green-500/10 px-2 py-1 text-xs font-medium text-green-600">成功</span>`
|
||||
: `<span class="inline-flex items-center rounded-md bg-destructive/10 px-2 py-1 text-xs font-medium text-destructive">${log.ErrorCode || '失败'}</span>`;
|
||||
|
||||
// 使用 toLocaleString 格式化时间,更符合用户本地习惯
|
||||
const requestTime = new Date(log.RequestTime).toLocaleString();
|
||||
|
||||
return `
|
||||
<tr class="border-b border-b-border transition-colors hover:bg-muted/80" data-log-id="${log.ID}">
|
||||
<td class="p-4 align-middle"><input type="checkbox" class="h-4 w-4 rounded border-zinc-300 text-blue-600 focus:ring-blue-500"></td>
|
||||
<td class="p-4 align-middle font-mono text-muted-foreground">#${log.ID}</td>
|
||||
<td class="p-4 align-middle font-medium font-mono">${apiKeyName}</td>
|
||||
<td class="p-4 align-middle">${groupName}</td>
|
||||
<td class="p-4 align-middle text-foreground">${log.ErrorMessage || (log.IsSuccess ? '' : '未知错误')}</td>
|
||||
<td class="p-4 align-middle">${errorTag}</td>
|
||||
<td class="p-4 align-middle font-mono">${log.ModelName}</td>
|
||||
<td class="p-4 align-middle text-muted-foreground text-xs">${requestTime}</td>
|
||||
<td class="p-4 align-middle">
|
||||
<button class="btn btn-ghost btn-icon btn-sm" aria-label="查看详情">
|
||||
<i class="fas fa-ellipsis-h h-4 w-4"></i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
export default LogList;
|
||||
Reference in New Issue
Block a user