Update: Js 4 Log.html 95% --next move the loglevel to settingserver
This commit is contained in:
5364
web/static/js/keys-YEK3YJ77.js
Normal file
5364
web/static/js/keys-YEK3YJ77.js
Normal file
File diff suppressed because it is too large
Load Diff
2924
web/static/js/logs-SSK3L2XT.js
Normal file
2924
web/static/js/logs-SSK3L2XT.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1609,7 +1609,7 @@ var LogList = class {
|
||||
const requestTime = new Date(log.RequestTime).toLocaleString();
|
||||
const checkedAttr = isChecked ? "checked" : "";
|
||||
return `
|
||||
<tr class="table-row" data-log-id="${log.ID}" ${errorMessageAttr}>
|
||||
<tr class="table-row group" data-log-id="${log.ID}" ${errorMessageAttr}>
|
||||
<td class="table-cell">
|
||||
<input type="checkbox" class="h-4 w-4 rounded border-zinc-300 text-blue-600 focus:ring-blue-500" ${checkedAttr}>
|
||||
</td>
|
||||
@@ -1620,10 +1620,26 @@ var LogList = class {
|
||||
<td class="table-cell">${errorInfo.statusCodeHtml}</td>
|
||||
<td class="table-cell">${modelNameFormatted}</td>
|
||||
<td class="table-cell text-muted-foreground text-xs">${requestTime}</td>
|
||||
<td class="table-cell">
|
||||
<button class="btn btn-ghost btn-icon btn-sm" aria-label="\u67E5\u770B\u8BE6\u60C5">
|
||||
<i class="fas fa-ellipsis-h h-4 w-4"></i>
|
||||
</button>
|
||||
<td class="table-cell relative">
|
||||
<!-- [MODIFIED] - 2. \u66FF\u6362\u539F\u6709\u6309\u94AE\u4E3A\u60AC\u6D6E\u64CD\u4F5C\u83DC\u5355 -->
|
||||
<div class="flex items-center justify-center">
|
||||
<!-- \u9ED8\u8BA4\u663E\u793A\u7684\u56FE\u6807 -->
|
||||
<span class="text-zinc-400 group-hover:opacity-0 transition-opacity">
|
||||
<i class="fas fa-ellipsis-h h-4 w-4"></i>
|
||||
</span>
|
||||
<!-- \u60AC\u6D6E\u65F6\u663E\u793A\u7684\u64CD\u4F5C\u6309\u94AE -->
|
||||
<div class="absolute right-2 top-1/2 -translate-y-1/2 flex items-center bg-zinc-100 dark:bg-zinc-700 rounded-full shadow-md opacity-0 group-hover:opacity-100 transition-opacity duration-200 z-10">
|
||||
<button class="px-2 py-1 text-zinc-500 hover:text-blue-500" data-action="view-log-details" title="\u67E5\u770B\u8BE6\u60C5">
|
||||
<i class="fas fa-eye"></i>
|
||||
</button>
|
||||
<button class="px-2 py-1 text-zinc-500 hover:text-green-500" data-action="copy-api-key" title="\u590D\u5236APIKey">
|
||||
<i class="fas fa-copy"></i>
|
||||
</button>
|
||||
<button class="px-2 py-1 text-zinc-500 hover:text-red-500" data-action="delete-log" title="\u5220\u9664\u65E5\u5FD7">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
@@ -2559,8 +2575,14 @@ var LogsPage = class {
|
||||
this.elements.selectAllCheckbox.addEventListener("change", (event) => this.handleSelectAllChange(event));
|
||||
}
|
||||
if (this.elements.tableBody) {
|
||||
this.elements.tableBody.addEventListener("change", (event) => {
|
||||
if (event.target.type === "checkbox") this.handleSelectionChange(event.target);
|
||||
this.elements.tableBody.addEventListener("click", (event) => {
|
||||
const checkbox = event.target.closest('input[type="checkbox"]');
|
||||
const actionButton = event.target.closest("button[data-action]");
|
||||
if (checkbox) {
|
||||
this.handleSelectionChange(checkbox);
|
||||
} else if (actionButton) {
|
||||
this._handleLogRowAction(actionButton);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (this.elements.searchInput) {
|
||||
@@ -2663,6 +2685,115 @@ var LogsPage = class {
|
||||
deleteSelectedBtn.disabled = !hasSelection;
|
||||
}
|
||||
}
|
||||
async _handleLogRowAction(button) {
|
||||
const action = button.dataset.action;
|
||||
const row = button.closest(".table-row");
|
||||
const isDarkMode = document.documentElement.classList.contains("dark");
|
||||
if (!row) return;
|
||||
const logId = parseInt(row.dataset.logId, 10);
|
||||
const log = this.state.logs.find((l) => l.ID === logId);
|
||||
if (!log) {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "error", title: "\u627E\u4E0D\u5230\u65E5\u5FD7\u6570\u636E", showConfirmButton: false, timer: 2e3 });
|
||||
return;
|
||||
}
|
||||
switch (action) {
|
||||
case "view-log-details": {
|
||||
const detailsHtml = `
|
||||
<div class="space-y-3 text-left text-sm p-2">
|
||||
<div class="flex"><p class="w-24 font-semibold text-zinc-500 shrink-0">\u72B6\u6001\u7801</p><p class="font-mono text-zinc-800 dark:text-zinc-200">${log.StatusCode || "N/A"}</p></div>
|
||||
<div class="flex"><p class="w-24 font-semibold text-zinc-500 shrink-0">\u72B6\u6001</p><p class="font-mono text-zinc-800 dark:text-zinc-200">${log.Status || "N/A"}</p></div>
|
||||
<div class="flex"><p class="w-24 font-semibold text-zinc-500 shrink-0">\u6A21\u578B</p><p class="font-mono text-zinc-800 dark:text-zinc-200">${log.ModelName || "N/A"}</p></div>
|
||||
<div class="border-t border-zinc-200 dark:border-zinc-700 my-2"></div>
|
||||
<div>
|
||||
<p class="font-semibold text-zinc-500 mb-1">\u9519\u8BEF\u6D88\u606F</p>
|
||||
<div class="max-h-40 overflow-y-auto bg-zinc-100 dark:bg-zinc-800 p-2 rounded-md text-zinc-700 dark:text-zinc-300 break-words text-xs">
|
||||
${log.ErrorMessage ? log.ErrorMessage.replace(/\n/g, "<br>") : "\u65E0\u9519\u8BEF\u6D88\u606F\u3002"}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
Swal.fire({
|
||||
target: "#main-content-wrapper",
|
||||
width: "32rem",
|
||||
backdrop: `rgba(0,0,0,0.5)`,
|
||||
heightAuto: false,
|
||||
customClass: {
|
||||
popup: `swal2-custom-style rounded-xl ${document.documentElement.classList.contains("dark") ? "swal2-dark" : ""}`,
|
||||
title: "text-lg font-bold",
|
||||
htmlContainer: "m-0 text-left"
|
||||
},
|
||||
title: "\u65E5\u5FD7\u8BE6\u60C5",
|
||||
html: detailsHtml,
|
||||
showCloseButton: false,
|
||||
showConfirmButton: false
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "copy-api-key": {
|
||||
const key = dataStore.keys.get(log.KeyID);
|
||||
if (key && key.APIKey) {
|
||||
navigator.clipboard.writeText(key.APIKey).then(() => {
|
||||
Swal.fire({ toast: true, position: "top-end", customClass: { popup: `swal2-custom-style ${document.documentElement.classList.contains("dark") ? "swal2-dark" : ""}` }, icon: "success", title: "API Key \u5DF2\u590D\u5236", showConfirmButton: false, timer: 1500 });
|
||||
}).catch((err) => {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "error", title: "\u590D\u5236\u5931\u8D25", text: err.message, showConfirmButton: false, timer: 2e3 });
|
||||
});
|
||||
} else {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "warning", title: "\u672A\u627E\u5230\u5B8C\u6574\u7684API Key", showConfirmButton: false, timer: 2e3 });
|
||||
return;
|
||||
}
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
navigator.clipboard.writeText(key.APIKey).then(() => {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "success", title: "API Key \u5DF2\u590D\u5236", showConfirmButton: false, timer: 1500 });
|
||||
}).catch((err) => {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "error", title: "\u590D\u5236\u5931\u8D25", text: err.message, showConfirmButton: false, timer: 2e3 });
|
||||
});
|
||||
} else {
|
||||
Swal.fire({
|
||||
icon: "error",
|
||||
title: "\u590D\u5236\u5931\u8D25",
|
||||
text: "\u6B64\u529F\u80FD\u9700\u8981\u5B89\u5168\u8FDE\u63A5 (HTTPS) \u6216\u5728 localhost \u73AF\u5883\u4E0B\u4F7F\u7528\u3002",
|
||||
target: "#main-content-wrapper",
|
||||
customClass: { popup: `swal2-custom-style ${document.documentElement.classList.contains("dark") ? "swal2-dark" : ""}` }
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "delete-log": {
|
||||
Swal.fire({
|
||||
width: "20rem",
|
||||
backdrop: `rgba(0,0,0,0.5)`,
|
||||
heightAuto: false,
|
||||
customClass: { popup: `swal2-custom-style ${document.documentElement.classList.contains("dark") ? "swal2-dark" : ""}` },
|
||||
title: "\u786E\u8BA4\u5220\u9664",
|
||||
text: `\u60A8\u786E\u5B9A\u8981\u5220\u9664\u8FD9\u6761\u65E5\u5FD7\u5417\uFF1F\u6B64\u64CD\u4F5C\u4E0D\u53EF\u64A4\u9500\u3002`,
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "\u786E\u8BA4\u5220\u9664",
|
||||
cancelButtonText: "\u53D6\u6D88",
|
||||
reverseButtons: false,
|
||||
confirmButtonColor: "#ef4444",
|
||||
cancelButtonColor: "#6b7280",
|
||||
focusCancel: true,
|
||||
target: "#main-content-wrapper"
|
||||
}).then(async (result) => {
|
||||
if (result.isConfirmed) {
|
||||
try {
|
||||
const url = `/admin/logs?ids=${logId}`;
|
||||
const { success, message } = await apiFetchJson(url, { method: "DELETE" });
|
||||
if (success) {
|
||||
Swal.fire({ toast: true, position: "top-end", icon: "success", title: "\u5220\u9664\u6210\u529F", showConfirmButton: false, timer: 2e3, timerProgressBar: true });
|
||||
this.loadAndRenderLogs();
|
||||
} else {
|
||||
throw new Error(message || "\u5220\u9664\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");
|
||||
}
|
||||
} catch (error) {
|
||||
Swal.fire({ icon: "error", title: "\u64CD\u4F5C\u5931\u8D25", text: error.message, target: "#main-content-wrapper" });
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
changePageSize(newSize) {
|
||||
this.state.filters.page_size = newSize;
|
||||
this.state.filters.page = 1;
|
||||
1237
web/static/js/main.css
Normal file
1237
web/static/js/main.css
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user