From ad734ff20455cbadde423eeb55d5f9c223dc58f6 Mon Sep 17 00:00:00 2001 From: XuqmGroup Date: Fri, 22 May 2026 23:22:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(system-logs):=20=E4=B8=A4=E7=AB=AF?= =?UTF-8?q?=E5=B9=B3=E5=8F=B0=E6=96=B0=E5=A2=9E=E6=9C=8D=E5=8A=A1=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=9F=A5=E7=9C=8B=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - tenant-platform: /system-logs 页面,私有化模式下侧边栏显示;支持服务切换、 行数选择、刷新间隔配置(5s/10s/30s/1min)、自动滚动 - ops-platform: /system-logs 页面,始终可见;复用相同交互,通过 ROLE_OPS 接口获取日志 Co-Authored-By: Claude Sonnet 4.6 --- ops-platform/src/api/ops.ts | 9 + ops-platform/src/router/index.ts | 1 + ops-platform/src/views/layout/MainLayout.vue | 3 +- .../src/views/system/ServerLogsView.vue | 292 ++++++++++++++++ tenant-platform/src/api/system.ts | 20 ++ tenant-platform/src/router/index.ts | 4 + .../src/views/layout/MainLayout.vue | 14 +- .../src/views/system/ServerLogsView.vue | 321 ++++++++++++++++++ 8 files changed, 661 insertions(+), 3 deletions(-) create mode 100644 ops-platform/src/views/system/ServerLogsView.vue create mode 100644 tenant-platform/src/views/system/ServerLogsView.vue diff --git a/ops-platform/src/api/ops.ts b/ops-platform/src/api/ops.ts index 43c5dd9..fa94929 100644 --- a/ops-platform/src/api/ops.ts +++ b/ops-platform/src/api/ops.ts @@ -279,4 +279,13 @@ export const opsApi = { sendPushTestOffline: (payload: { appKey: string; userId: string; title: string; body: string; payload?: string }) => client.post<{ data: PushTestResult }>('/ops/push/test-offline', payload), + + getRunningServices: () => + client.get<{ data: string[] }>('/ops/system/services'), + + fetchServiceLogs: (service: string, lines: number) => + client.get(`/ops/system/logs/${encodeURIComponent(service)}`, { + params: { lines }, + responseType: 'text', + }), } diff --git a/ops-platform/src/router/index.ts b/ops-platform/src/router/index.ts index ec4569d..dadc959 100644 --- a/ops-platform/src/router/index.ts +++ b/ops-platform/src/router/index.ts @@ -19,6 +19,7 @@ const router = createRouter({ { path: 'push', component: () => import('@/views/push/PushDiagnosticsView.vue') }, { path: 'operation-logs', component: () => import('@/views/logs/OperationLogView.vue') }, { path: 'risk-control', component: () => import('@/views/risk/RiskControlView.vue') }, + { path: 'system-logs', component: () => import('@/views/system/ServerLogsView.vue') }, ], }, ], diff --git a/ops-platform/src/views/layout/MainLayout.vue b/ops-platform/src/views/layout/MainLayout.vue index 9dba907..4db4564 100644 --- a/ops-platform/src/views/layout/MainLayout.vue +++ b/ops-platform/src/views/layout/MainLayout.vue @@ -66,7 +66,7 @@ + + diff --git a/tenant-platform/src/api/system.ts b/tenant-platform/src/api/system.ts index de2ccfa..27c3322 100644 --- a/tenant-platform/src/api/system.ts +++ b/tenant-platform/src/api/system.ts @@ -43,6 +43,26 @@ async function streamOperation( if (buf) onLine(buf) } +export async function getRunningServices(): Promise { + const token = localStorage.getItem('token') ?? '' + const res = await fetch(`${BASE}/system/services`, { + headers: { Authorization: `Bearer ${token}` }, + }) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + const json = await res.json() + return json.data as string[] +} + +export async function fetchServiceLogs(service: string, lines: number): Promise { + const token = localStorage.getItem('token') ?? '' + const res = await fetch( + `${BASE}/system/logs/${encodeURIComponent(service)}?lines=${lines}`, + { headers: { Authorization: `Bearer ${token}` } }, + ) + if (!res.ok) throw new Error(`HTTP ${res.status}`) + return res.text() +} + export async function getSystemVersion(): Promise<{ currentVersion: string }> { const token = localStorage.getItem('token') ?? '' const res = await fetch(`${BASE}/system/version`, { diff --git a/tenant-platform/src/router/index.ts b/tenant-platform/src/router/index.ts index 0d193bd..2f0022e 100644 --- a/tenant-platform/src/router/index.ts +++ b/tenant-platform/src/router/index.ts @@ -101,6 +101,10 @@ const router = createRouter({ path: 'services/license/:appKey?', component: () => import('@/views/license/LicenseManagementView.vue'), }, + { + path: 'system-logs', + component: () => import('@/views/system/ServerLogsView.vue'), + }, { path: 'accounts', component: () => import('@/views/accounts/SubAccountView.vue'), diff --git a/tenant-platform/src/views/layout/MainLayout.vue b/tenant-platform/src/views/layout/MainLayout.vue index c275b73..5067b4a 100644 --- a/tenant-platform/src/views/layout/MainLayout.vue +++ b/tenant-platform/src/views/layout/MainLayout.vue @@ -23,6 +23,7 @@ 授权管理 安全中心 + 服务日志 操作日志 子账号管理 @@ -58,6 +59,7 @@ 授权管理 安全中心 + 服务日志 操作日志 子账号管理 @@ -106,13 +108,15 @@ import { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue' import { useAuthStore } from '@/stores/auth' import { useRoute, useRouter } from 'vue-router' -import { Bell, ChatDotRound, Document, Grid, Key, List, Lock, Menu, Odometer, Upload, User } from '@element-plus/icons-vue' +import { Bell, ChatDotRound, Document, Grid, Key, List, Lock, Menu, Monitor, Odometer, Upload, User } from '@element-plus/icons-vue' +import { getDeploymentStatus } from '@/api/system' const auth = useAuthStore() const route = useRoute() const router = useRouter() const isMobile = ref(false) const drawerVisible = ref(false) +const isPrivateDeploy = ref(false) const openedMenus = computed(() => route.path.startsWith('/services/') ? ['services'] : [], @@ -143,9 +147,15 @@ watch( }, ) -onMounted(() => { +onMounted(async () => { updateViewport() window.addEventListener('resize', updateViewport) + try { + const status = await getDeploymentStatus() + isPrivateDeploy.value = status.mode === 'PRIVATE' + } catch { + isPrivateDeploy.value = false + } }) onBeforeUnmount(() => { diff --git a/tenant-platform/src/views/system/ServerLogsView.vue b/tenant-platform/src/views/system/ServerLogsView.vue new file mode 100644 index 0000000..ae55e92 --- /dev/null +++ b/tenant-platform/src/views/system/ServerLogsView.vue @@ -0,0 +1,321 @@ + + + + +