From 04d36e4d9e8b269700f988d0b214e222197ceee8 Mon Sep 17 00:00:00 2001 From: xofine Date: Tue, 25 Nov 2025 20:48:15 +0800 Subject: [PATCH] fix:path rewriting & model list --- frontend/js/pages/keys/apiKeyList.js | 2 + frontend/js/pages/logs/index.js | 18 +++- frontend/js/pages/logs/systemLog.js | 43 +++++++--- internal/channel/gemini_channel.go | 15 +++- internal/handlers/proxy_handler.go | 57 +++++++++++- web/static/css/output.css | 86 +++++++++++++++++-- .../js/{keys-HRP4JR7B.js => keys-2IUHJHHE.js} | 2 + .../js/{logs-43KF5HY3.js => logs-MNVRT6ND.js} | 58 +++++++++---- web/static/js/main.js | 4 +- web/templates/logs.html | 51 +++++------ 10 files changed, 262 insertions(+), 74 deletions(-) rename web/static/js/{keys-HRP4JR7B.js => keys-2IUHJHHE.js} (99%) rename web/static/js/{logs-43KF5HY3.js => logs-MNVRT6ND.js} (97%) diff --git a/frontend/js/pages/keys/apiKeyList.js b/frontend/js/pages/keys/apiKeyList.js index c1dfee1..790e0d5 100644 --- a/frontend/js/pages/keys/apiKeyList.js +++ b/frontend/js/pages/keys/apiKeyList.js @@ -1135,6 +1135,8 @@ class ApiKeyList { const actionConfig = this._getQuickActionConfig(action); if (actionConfig && actionConfig.requiresConfirm) { const result = await Swal.fire({ + backdrop: `rgba(0,0,0,0.5)`, + heightAuto: false, target: '#main-content-wrapper', title: '请确认操作', html: actionConfig.confirmText, diff --git a/frontend/js/pages/logs/index.js b/frontend/js/pages/logs/index.js index 32197c1..c23d4fd 100644 --- a/frontend/js/pages/logs/index.js +++ b/frontend/js/pages/logs/index.js @@ -113,12 +113,22 @@ class LogsPage { this.elements.systemControls ); Swal.fire({ - title: '实时系统日志', - text: '您即将连接到实时日志流。这会与服务器建立一个持续的连接。', - icon: 'info', - confirmButtonText: '我明白了,开始连接', + width: '20rem', + backdrop: `rgba(0,0,0,0.5)`, + heightAuto: false, + customClass: { + popup: `swal2-custom-style ${document.documentElement.classList.contains('dark') ? 'swal2-dark' : ''}` + }, + title: '系统终端日志', + text: '您即将连接到实时系统日志流窗口。', showCancelButton: true, + confirmButtonText: '确认', cancelButtonText: '取消', + reverseButtons: false, + confirmButtonColor: 'rgba(31, 102, 255, 0.8)', + cancelButtonColor: '#6b7280', + focusConfirm: false, + focusCancel: false, target: '#main-content-wrapper', }).then((result) => { if (result.isConfirmed) { diff --git a/frontend/js/pages/logs/systemLog.js b/frontend/js/pages/logs/systemLog.js index 8dd87bc..830bccd 100644 --- a/frontend/js/pages/logs/systemLog.js +++ b/frontend/js/pages/logs/systemLog.js @@ -9,6 +9,7 @@ export default class SystemLogTerminal { this.shouldAutoScroll = true; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; + this.isConnected = false; this.elements = { output: this.container.querySelector('#log-terminal-output'), @@ -16,7 +17,8 @@ export default class SystemLogTerminal { clearBtn: this.controlsContainer.querySelector('[data-action="clear-terminal"]'), pauseBtn: this.controlsContainer.querySelector('[data-action="toggle-pause-terminal"]'), scrollBtn: this.controlsContainer.querySelector('[data-action="toggle-scroll-terminal"]'), - disconnectBtn: this.controlsContainer.querySelector('[data-action="disconnect-terminal"]'), + connectBtn: this.controlsContainer.querySelector('[data-action="toggle-connect-terminal"]'), + settingsBtn: this.controlsContainer.querySelector('[data-action="terminal-settings"]'), }; this._initEventListeners(); @@ -26,7 +28,16 @@ export default class SystemLogTerminal { this.elements.clearBtn.addEventListener('click', () => this.clear()); this.elements.pauseBtn.addEventListener('click', () => this.togglePause()); this.elements.scrollBtn.addEventListener('click', () => this.toggleAutoScroll()); - this.elements.disconnectBtn.addEventListener('click', () => this.disconnect()); + this.elements.connectBtn.addEventListener('click', () => this.toggleConnect()); + this.elements.settingsBtn.addEventListener('click', () => this.openSettings()); + } + + toggleConnect() { + if (this.isConnected) { + this.disconnect(); + } else { + this.connect(); + } } connect() { @@ -43,6 +54,9 @@ export default class SystemLogTerminal { this._appendMessage('info', '✓ 已连接到系统日志流'); this._updateStatus('connected', '已连接'); this.reconnectAttempts = 0; + this.isConnected = true; + this.elements.connectBtn.title = '断开'; + this.elements.connectBtn.querySelector('i').classList.replace('fa-plug', 'fa-minus-circle'); }; this.ws.onmessage = (event) => { @@ -53,7 +67,7 @@ export default class SystemLogTerminal { const levelColors = { 'error': 'text-red-500', 'warning': 'text-yellow-400', - 'info': 'text-blue-400', + 'info': 'text-green-400', 'debug': 'text-zinc-400' }; const color = levelColors[data.level] || 'text-zinc-200'; @@ -73,6 +87,9 @@ export default class SystemLogTerminal { this.ws.onclose = () => { this._appendMessage('error', '✗ 连接已断开'); this._updateStatus('disconnected', '未连接'); + this.isConnected = false; + this.elements.connectBtn.title = '连接'; + this.elements.connectBtn.querySelector('i').classList.replace('fa-minus-circle', 'fa-plug'); if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; @@ -90,7 +107,10 @@ export default class SystemLogTerminal { this.ws = null; } this.reconnectAttempts = this.maxReconnectAttempts; + this.isConnected = false; this._updateStatus('disconnected', '未连接'); + this.elements.connectBtn.title = '连接'; + this.elements.connectBtn.querySelector('i').classList.replace('fa-minus-circle', 'fa-plug'); } clear() { @@ -101,25 +121,24 @@ export default class SystemLogTerminal { togglePause() { this.isPaused = !this.isPaused; - const span = this.elements.pauseBtn.querySelector('span'); const icon = this.elements.pauseBtn.querySelector('i'); if (this.isPaused) { - span.textContent = '继续'; + this.elements.pauseBtn.title = '继续'; icon.classList.replace('fa-pause', 'fa-play'); } else { - span.textContent = '暂停'; + this.elements.pauseBtn.title = '暂停'; icon.classList.replace('fa-play', 'fa-pause'); } } toggleAutoScroll() { this.shouldAutoScroll = !this.shouldAutoScroll; - const span = this.elements.scrollBtn.querySelector('span'); - if (this.shouldAutoScroll) { - span.textContent = '自动滚动'; - } else { - span.textContent = '手动滚动'; - } + this.elements.scrollBtn.title = this.shouldAutoScroll ? '自动滚动' : '手动滚动'; + } + + openSettings() { + // 实现设置功能 + console.log('打开设置'); } _appendMessage(colorClass, text) { diff --git a/internal/channel/gemini_channel.go b/internal/channel/gemini_channel.go index e0e4fc8..9a04567 100644 --- a/internal/channel/gemini_channel.go +++ b/internal/channel/gemini_channel.go @@ -62,10 +62,13 @@ func (ch *GeminiChannel) extractModelFromRequest(c *gin.Context, bodyBytes []byt var p struct { Model string `json:"model"` } - if json.Unmarshal(bodyBytes, &p) == nil && p.Model != "" { - return strings.TrimPrefix(p.Model, "models/") + _ = json.Unmarshal(bodyBytes, &p) + modelName := strings.TrimPrefix(p.Model, "models/") + + if modelName == "" { + modelName = ch.extractModelFromPath(c.Request.URL.Path) } - return ch.extractModelFromPath(c.Request.URL.Path) + return modelName } func (ch *GeminiChannel) extractModelFromPath(path string) string { @@ -85,7 +88,11 @@ func (ch *GeminiChannel) IsOpenAICompatibleRequest(c *gin.Context) bool { } func (ch *GeminiChannel) isOpenAIPath(path string) bool { - return strings.Contains(path, "/v1/chat/completions") || strings.Contains(path, "/v1/embeddings") + return strings.Contains(path, "/v1/chat/completions") || + strings.Contains(path, "/v1/completions") || + strings.Contains(path, "/v1/embeddings") || + strings.Contains(path, "/v1/models") || + strings.Contains(path, "/v1/audio/") } func (ch *GeminiChannel) ValidateKey( diff --git a/internal/handlers/proxy_handler.go b/internal/handlers/proxy_handler.go index 1f7afcc..9a57d70 100644 --- a/internal/handlers/proxy_handler.go +++ b/internal/handlers/proxy_handler.go @@ -986,6 +986,7 @@ func (h *ProxyHandler) getMaxRetries(isPreciseRouting bool, finalOpConfig *model } func (h *ProxyHandler) handleListModelsRequest(c *gin.Context) { + authTokenValue, exists := c.Get("authToken") if !exists { errToJSON(c, uuid.New().String(), errors.NewAPIError(errors.ErrUnauthorized, "Auth token not found in context")) @@ -996,7 +997,61 @@ func (h *ProxyHandler) handleListModelsRequest(c *gin.Context) { errToJSON(c, uuid.New().String(), errors.NewAPIError(errors.ErrInternalServer, "Invalid auth token type in context")) return } - modelNames := h.resourceService.GetAllowedModelsForToken(authToken) + + groupName := c.Param("group_name") + h.logger.Infof("List models request: path=%s, groupName=%s", c.Request.URL.Path, groupName) + isPreciseRouting := groupName != "" + + var modelNames []string + + if isPreciseRouting { + group, ok := h.groupManager.GetGroupByName(groupName) + if !ok { + errToJSON(c, uuid.New().String(), errors.NewAPIError(errors.ErrNotFound, "Group not found")) + return + } + + for _, modelMapping := range group.AllowedModels { + modelNames = append(modelNames, modelMapping.ModelName) + } + + if len(modelNames) == 0 { + h.logger.Infof("Triggering passthrough for model list") + initialResources, err := h.resourceService.GetResourceFromGroup(c.Request.Context(), authToken, groupName) + if err != nil { + errToJSON(c, uuid.New().String(), errors.NewAPIError(errors.ErrInternalServer, "Failed to get resources")) + return + } + + targetURL, _ := url.Parse(initialResources.UpstreamEndpoint.URL) + apiPath := strings.TrimPrefix(c.Request.URL.Path, "/proxy/"+groupName) + targetURL.Path = h.channel.RewritePath(targetURL.Path, apiPath) + h.logger.Infof("Final upstream path: %s", targetURL.String()) + targetURL.RawQuery = c.Request.URL.RawQuery + + req, _ := http.NewRequestWithContext(c.Request.Context(), "GET", targetURL.String(), nil) + h.channel.ModifyRequest(req, initialResources.APIKey) + + client := &http.Client{Transport: h.transparentProxy.Transport} + resp, err := client.Do(req) + if err != nil { + errToJSON(c, uuid.New().String(), errors.NewAPIError(errors.ErrBadGateway, "Failed to fetch models")) + return + } + defer resp.Body.Close() + + c.Writer.WriteHeader(resp.StatusCode) + for k, v := range resp.Header { + c.Writer.Header()[k] = v + } + io.Copy(c.Writer, resp.Body) + h.logger.Infof("Passthrough response sent") + return + } + } else { + modelNames = h.resourceService.GetAllowedModelsForToken(authToken) + } + if strings.Contains(c.Request.URL.Path, "/v1beta/") { h.respondWithGeminiFormat(c, modelNames) } else { diff --git a/web/static/css/output.css b/web/static/css/output.css index f2db32d..d0cee36 100644 --- a/web/static/css/output.css +++ b/web/static/css/output.css @@ -496,6 +496,9 @@ .my-1\.5 { margin-block: calc(var(--spacing) * 1.5); } + .mt-0 { + margin-top: calc(var(--spacing) * 0); + } .mt-0\.5 { margin-top: calc(var(--spacing) * 0.5); } @@ -614,6 +617,9 @@ width: calc(var(--spacing) * 6); height: calc(var(--spacing) * 6); } + .h-0 { + height: calc(var(--spacing) * 0); + } .h-0\.5 { height: calc(var(--spacing) * 0.5); } @@ -698,6 +704,9 @@ .w-0 { width: calc(var(--spacing) * 0); } + .w-1 { + width: calc(var(--spacing) * 1); + } .w-1\/4 { width: calc(1/4 * 100%); } @@ -806,6 +815,9 @@ .flex-1 { flex: 1; } + .flex-shrink { + flex-shrink: 1; + } .shrink-0 { flex-shrink: 0; } @@ -818,6 +830,9 @@ .caption-bottom { caption-side: bottom; } + .border-collapse { + border-collapse: collapse; + } .origin-center { transform-origin: center; } @@ -844,6 +859,10 @@ --tw-translate-x: 100%; translate: var(--tw-translate-x) var(--tw-translate-y); } + .-translate-y-1 { + --tw-translate-y: calc(var(--spacing) * -1); + translate: var(--tw-translate-x) var(--tw-translate-y); + } .-translate-y-1\/2 { --tw-translate-y: calc(calc(1/2 * 100%) * -1); translate: var(--tw-translate-x) var(--tw-translate-y); @@ -1000,6 +1019,9 @@ margin-block-end: calc(calc(var(--spacing) * 8) * calc(1 - var(--tw-space-y-reverse))); } } + .gap-x-1 { + column-gap: calc(var(--spacing) * 1); + } .gap-x-1\.5 { column-gap: calc(var(--spacing) * 1.5); } @@ -1145,6 +1167,9 @@ --tw-border-style: none; border-style: none; } + .border-black { + border-color: var(--color-black); + } .border-black\/10 { border-color: color-mix(in srgb, #000 10%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1172,6 +1197,9 @@ .border-green-200 { border-color: var(--color-green-200); } + .border-primary { + border-color: var(--color-primary); + } .border-primary\/20 { border-color: var(--color-primary); @supports (color: color-mix(in lab, red, red)) { @@ -1208,6 +1236,9 @@ .border-zinc-300 { border-color: var(--color-zinc-300); } + .border-zinc-700 { + border-color: var(--color-zinc-700); + } .border-zinc-700\/50 { border-color: color-mix(in srgb, oklch(37% 0.013 285.805) 50%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1280,6 +1311,9 @@ .bg-gray-500 { background-color: var(--color-gray-500); } + .bg-gray-950 { + background-color: var(--color-gray-950); + } .bg-gray-950\/5 { background-color: color-mix(in srgb, oklch(13% 0.028 261.692) 5%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1494,6 +1528,10 @@ --tw-gradient-position: to right in oklab; background-image: linear-gradient(var(--tw-gradient-stops)); } + .from-blue-500 { + --tw-gradient-from: var(--color-blue-500); + --tw-gradient-stops: var(--tw-gradient-via-stops, var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position)); + } .from-blue-500\/30 { --tw-gradient-from: color-mix(in srgb, oklch(62.3% 0.214 259.815) 30%, transparent); @supports (color: color-mix(in lab, red, red)) { @@ -1564,6 +1602,9 @@ .px-8 { padding-inline: calc(var(--spacing) * 8); } + .py-0 { + padding-block: calc(var(--spacing) * 0); + } .py-0\.5 { padding-block: calc(var(--spacing) * 0.5); } @@ -1612,6 +1653,9 @@ .pr-20 { padding-right: calc(var(--spacing) * 20); } + .pb-1 { + padding-bottom: calc(var(--spacing) * 1); + } .pb-1\.5 { padding-bottom: calc(var(--spacing) * 1.5); } @@ -1787,6 +1831,9 @@ .text-gray-950 { color: var(--color-gray-950); } + .text-green-400 { + color: var(--color-green-400); + } .text-green-500 { color: var(--color-green-500); } @@ -1895,6 +1942,9 @@ .italic { font-style: italic; } + .underline { + text-decoration-line: underline; + } .opacity-0 { opacity: 0%; } @@ -1952,6 +2002,10 @@ --tw-inset-shadow: inset 0 2px 4px var(--tw-inset-shadow-color, oklab(from rgb(0 0 0 / 0.05) l a b / 25%)); box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); } + .inset-shadow-sm { + --tw-inset-shadow: inset 0 2px 4px var(--tw-inset-shadow-color, rgb(0 0 0 / 0.05)); + box-shadow: var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + } .ring-black { --tw-ring-color: var(--color-black); } @@ -1973,6 +2027,10 @@ --tw-ring-color: color-mix(in oklab, var(--color-black) 15%, transparent); } } + .outline { + outline-style: var(--tw-outline-style); + outline-width: 1px; + } .blur { --tw-blur: blur(8px); filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,); @@ -2360,6 +2418,13 @@ } } } + .hover\:text-zinc-700 { + &:hover { + @media (hover: hover) { + color: var(--color-zinc-700); + } + } + } .hover\:shadow-lg { &:hover { @media (hover: hover) { @@ -3079,6 +3144,15 @@ } } } + .dark\:hover\:text-zinc-200 { + &:where(.dark, .dark *) { + &:hover { + @media (hover: hover) { + color: var(--color-zinc-200); + } + } + } + } .dark\:focus\:border-blue-500 { &:where(.dark, .dark *) { &:focus { @@ -5062,6 +5136,11 @@ inherits: false; initial-value: 0 0 #0000; } +@property --tw-outline-style { + syntax: "*"; + inherits: false; + initial-value: solid; +} @property --tw-blur { syntax: "*"; inherits: false; @@ -5174,11 +5253,6 @@ inherits: false; initial-value: 1; } -@property --tw-outline-style { - syntax: "*"; - inherits: false; - initial-value: solid; -} @keyframes spin { to { transform: rotate(360deg); @@ -5236,6 +5310,7 @@ --tw-ring-offset-width: 0px; --tw-ring-offset-color: #fff; --tw-ring-offset-shadow: 0 0 #0000; + --tw-outline-style: solid; --tw-blur: initial; --tw-brightness: initial; --tw-contrast: initial; @@ -5263,7 +5338,6 @@ --tw-scale-x: 1; --tw-scale-y: 1; --tw-scale-z: 1; - --tw-outline-style: solid; } } } diff --git a/web/static/js/keys-HRP4JR7B.js b/web/static/js/keys-2IUHJHHE.js similarity index 99% rename from web/static/js/keys-HRP4JR7B.js rename to web/static/js/keys-2IUHJHHE.js index 53abea1..245f6c3 100644 --- a/web/static/js/keys-HRP4JR7B.js +++ b/web/static/js/keys-2IUHJHHE.js @@ -2328,6 +2328,8 @@ var ApiKeyList = class { const actionConfig = this._getQuickActionConfig(action); if (actionConfig && actionConfig.requiresConfirm) { const result = await Swal.fire({ + backdrop: `rgba(0,0,0,0.5)`, + heightAuto: false, target: "#main-content-wrapper", title: "\u8BF7\u786E\u8BA4\u64CD\u4F5C", html: actionConfig.confirmText, diff --git a/web/static/js/logs-43KF5HY3.js b/web/static/js/logs-MNVRT6ND.js similarity index 97% rename from web/static/js/logs-43KF5HY3.js rename to web/static/js/logs-MNVRT6ND.js index 1484c45..8aa63c2 100644 --- a/web/static/js/logs-43KF5HY3.js +++ b/web/static/js/logs-MNVRT6ND.js @@ -853,13 +853,15 @@ var SystemLogTerminal = class { this.shouldAutoScroll = true; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; + this.isConnected = false; this.elements = { output: this.container.querySelector("#log-terminal-output"), statusIndicator: this.controlsContainer.querySelector("#terminal-status-indicator"), clearBtn: this.controlsContainer.querySelector('[data-action="clear-terminal"]'), pauseBtn: this.controlsContainer.querySelector('[data-action="toggle-pause-terminal"]'), scrollBtn: this.controlsContainer.querySelector('[data-action="toggle-scroll-terminal"]'), - disconnectBtn: this.controlsContainer.querySelector('[data-action="disconnect-terminal"]') + connectBtn: this.controlsContainer.querySelector('[data-action="toggle-connect-terminal"]'), + settingsBtn: this.controlsContainer.querySelector('[data-action="terminal-settings"]') }; this._initEventListeners(); } @@ -867,7 +869,15 @@ var SystemLogTerminal = class { this.elements.clearBtn.addEventListener("click", () => this.clear()); this.elements.pauseBtn.addEventListener("click", () => this.togglePause()); this.elements.scrollBtn.addEventListener("click", () => this.toggleAutoScroll()); - this.elements.disconnectBtn.addEventListener("click", () => this.disconnect()); + this.elements.connectBtn.addEventListener("click", () => this.toggleConnect()); + this.elements.settingsBtn.addEventListener("click", () => this.openSettings()); + } + toggleConnect() { + if (this.isConnected) { + this.disconnect(); + } else { + this.connect(); + } } connect() { this.clear(); @@ -880,6 +890,9 @@ var SystemLogTerminal = class { this._appendMessage("info", "\u2713 \u5DF2\u8FDE\u63A5\u5230\u7CFB\u7EDF\u65E5\u5FD7\u6D41"); this._updateStatus("connected", "\u5DF2\u8FDE\u63A5"); this.reconnectAttempts = 0; + this.isConnected = true; + this.elements.connectBtn.title = "\u65AD\u5F00"; + this.elements.connectBtn.querySelector("i").classList.replace("fa-plug", "fa-minus-circle"); }; this.ws.onmessage = (event) => { if (this.isPaused) return; @@ -888,7 +901,7 @@ var SystemLogTerminal = class { const levelColors = { "error": "text-red-500", "warning": "text-yellow-400", - "info": "text-blue-400", + "info": "text-green-400", "debug": "text-zinc-400" }; const color = levelColors[data.level] || "text-zinc-200"; @@ -906,6 +919,9 @@ var SystemLogTerminal = class { this.ws.onclose = () => { this._appendMessage("error", "\u2717 \u8FDE\u63A5\u5DF2\u65AD\u5F00"); this._updateStatus("disconnected", "\u672A\u8FDE\u63A5"); + this.isConnected = false; + this.elements.connectBtn.title = "\u8FDE\u63A5"; + this.elements.connectBtn.querySelector("i").classList.replace("fa-minus-circle", "fa-plug"); if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; setTimeout(() => { @@ -921,7 +937,10 @@ var SystemLogTerminal = class { this.ws = null; } this.reconnectAttempts = this.maxReconnectAttempts; + this.isConnected = false; this._updateStatus("disconnected", "\u672A\u8FDE\u63A5"); + this.elements.connectBtn.title = "\u8FDE\u63A5"; + this.elements.connectBtn.querySelector("i").classList.replace("fa-minus-circle", "fa-plug"); } clear() { if (this.elements.output) { @@ -930,24 +949,21 @@ var SystemLogTerminal = class { } togglePause() { this.isPaused = !this.isPaused; - const span = this.elements.pauseBtn.querySelector("span"); const icon = this.elements.pauseBtn.querySelector("i"); if (this.isPaused) { - span.textContent = "\u7EE7\u7EED"; + this.elements.pauseBtn.title = "\u7EE7\u7EED"; icon.classList.replace("fa-pause", "fa-play"); } else { - span.textContent = "\u6682\u505C"; + this.elements.pauseBtn.title = "\u6682\u505C"; icon.classList.replace("fa-play", "fa-pause"); } } toggleAutoScroll() { this.shouldAutoScroll = !this.shouldAutoScroll; - const span = this.elements.scrollBtn.querySelector("span"); - if (this.shouldAutoScroll) { - span.textContent = "\u81EA\u52A8\u6EDA\u52A8"; - } else { - span.textContent = "\u624B\u52A8\u6EDA\u52A8"; - } + this.elements.scrollBtn.title = this.shouldAutoScroll ? "\u81EA\u52A8\u6EDA\u52A8" : "\u624B\u52A8\u6EDA\u52A8"; + } + openSettings() { + console.log("\u6253\u5F00\u8BBE\u7F6E"); } _appendMessage(colorClass, text) { if (!this.elements.output) return; @@ -1085,12 +1101,22 @@ var LogsPage = class { this.elements.systemControls ); Swal.fire({ - title: "\u5B9E\u65F6\u7CFB\u7EDF\u65E5\u5FD7", - text: "\u60A8\u5373\u5C06\u8FDE\u63A5\u5230\u5B9E\u65F6\u65E5\u5FD7\u6D41\u3002\u8FD9\u4F1A\u4E0E\u670D\u52A1\u5668\u5EFA\u7ACB\u4E00\u4E2A\u6301\u7EED\u7684\u8FDE\u63A5\u3002", - icon: "info", - confirmButtonText: "\u6211\u660E\u767D\u4E86\uFF0C\u5F00\u59CB\u8FDE\u63A5", + width: "20rem", + backdrop: `rgba(0,0,0,0.5)`, + heightAuto: false, + customClass: { + popup: `swal2-custom-style ${document.documentElement.classList.contains("dark") ? "swal2-dark" : ""}` + }, + title: "\u7CFB\u7EDF\u7EC8\u7AEF\u65E5\u5FD7", + text: "\u60A8\u5373\u5C06\u8FDE\u63A5\u5230\u5B9E\u65F6\u7CFB\u7EDF\u65E5\u5FD7\u6D41\u7A97\u53E3\u3002", showCancelButton: true, + confirmButtonText: "\u786E\u8BA4", cancelButtonText: "\u53D6\u6D88", + reverseButtons: false, + confirmButtonColor: "rgba(31, 102, 255, 0.8)", + cancelButtonColor: "#6b7280", + focusConfirm: false, + focusCancel: false, target: "#main-content-wrapper" }).then((result) => { if (result.isConfirmed) { diff --git a/web/static/js/main.js b/web/static/js/main.js index db50da9..98d88ad 100644 --- a/web/static/js/main.js +++ b/web/static/js/main.js @@ -181,8 +181,8 @@ var pageModules = { // 键 'dashboard' 对应一个函数,该函数调用 import() 返回一个 Promise // esbuild 看到这个 import() 语法,就会自动将 dashboard.js 及其依赖打包成一个独立的 chunk 文件 "dashboard": () => import("./dashboard-XFUWX3IN.js"), - "keys": () => import("./keys-HRP4JR7B.js"), - "logs": () => import("./logs-43KF5HY3.js") + "keys": () => import("./keys-2IUHJHHE.js"), + "logs": () => import("./logs-MNVRT6ND.js") // 'settings': () => import('./pages/settings.js'), // 未来启用 settings 页面 // 未来新增的页面,只需在这里添加一行映射,esbuild会自动处理 }; diff --git a/web/templates/logs.html b/web/templates/logs.html index 5599927..0c07cec 100644 --- a/web/templates/logs.html +++ b/web/templates/logs.html @@ -28,8 +28,6 @@
错误日志 系统日志 - 保留标签 - 保留标签 @@ -72,34 +70,29 @@ -