From cfecc8d113053f58ec93897b95eaec92a410249a Mon Sep 17 00:00:00 2001 From: spongehah <2635879218@qq.com> Date: Mon, 24 Aug 2026 11:24:51 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=BF=90=E7=BB=B4=E7=9B=91=E6=8E=A7?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E8=AF=A6=E6=83=85=E6=94=AF=E6=8C=81=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=88=97=E8=A1=A8=E5=B9=B6=E4=BF=9D=E7=95=99=E7=AD=9B?= =?UTF-8?q?=E9=80=89=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 进入单条错误详情后新增"返回列表"按钮,可回到来源明细列表并保留 筛选/分页状态,避免只能退出到运维监控总览后重新筛选。记录来源列表 类型,返回时跳过列表重开时的筛选重置。 --- frontend/src/i18n/locales/en/admin/ops.ts | 1 + frontend/src/i18n/locales/zh/admin/ops.ts | 1 + frontend/src/views/admin/ops/OpsDashboard.vue | 33 ++++++++++++++++++- .../ops/components/OpsErrorDetailModal.vue | 17 ++++++++++ .../ops/components/OpsErrorDetailsModal.vue | 2 ++ .../ops/components/OpsRequestDetailsModal.vue | 3 +- 6 files changed, 55 insertions(+), 2 deletions(-) diff --git a/frontend/src/i18n/locales/en/admin/ops.ts b/frontend/src/i18n/locales/en/admin/ops.ts index fe6a7a28bb..4bb48c64da 100644 --- a/frontend/src/i18n/locales/en/admin/ops.ts +++ b/frontend/src/i18n/locales/en/admin/ops.ts @@ -307,6 +307,7 @@ export default { title: 'Error Detail', titleWithId: 'Error #{id}', noErrorSelected: 'No error selected.', + backToList: 'Back to List', resolution: 'Resolved:', failedToUpdateResolvedStatus: 'Failed to update resolved status', classificationKeys: { diff --git a/frontend/src/i18n/locales/zh/admin/ops.ts b/frontend/src/i18n/locales/zh/admin/ops.ts index 1e521c8914..3e568e1dd7 100644 --- a/frontend/src/i18n/locales/zh/admin/ops.ts +++ b/frontend/src/i18n/locales/zh/admin/ops.ts @@ -307,6 +307,7 @@ export default { title: '错误详情', titleWithId: '错误 #{id}', noErrorSelected: '未选择错误。', + backToList: '返回列表', resolution: '已解决:', failedToUpdateResolvedStatus: '更新解决状态失败', classificationKeys: { diff --git a/frontend/src/views/admin/ops/OpsDashboard.vue b/frontend/src/views/admin/ops/OpsDashboard.vue index cd5c672963..dc482ab074 100644 --- a/frontend/src/views/admin/ops/OpsDashboard.vue +++ b/frontend/src/views/admin/ops/OpsDashboard.vue @@ -119,11 +119,12 @@ :platform="platform" :group-id="groupId" :error-type="errorDetailsType" + :resume-state="resumeListState" @update:show="showErrorDetails = $event" @openErrorDetail="openError" /> - + @@ -377,6 +379,13 @@ const requestDetailsPreset = ref({ sort: 'created_at_desc' }) +// 记录单条错误详情来自哪个列表,便于"返回列表"时重新打开对应弹窗并保留状态。 +type DetailReturnTarget = 'errorList' | 'requestList' | null +const detailReturnTarget = ref(null) + +// 从详情返回时,列表弹窗应保留上一次的筛选/分页状态而非重置。 +const resumeListState = ref(false) + const showSettingsDialog = ref(false) const showAlertRulesCard = ref(false) @@ -508,12 +517,34 @@ function onQueryModeChange(v: string | number | boolean | null) { function openError(id: number) { selectedErrorId.value = id + // 记录来源列表,便于详情页"返回列表"。 + detailReturnTarget.value = showRequestDetails.value ? 'requestList' : showErrorDetails.value ? 'errorList' : null // Ensure only one modal visible at a time. showErrorDetails.value = false showRequestDetails.value = false showErrorModal.value = true } +// 从单条错误详情返回其来源列表,重新打开关联弹窗(保留筛选/分页状态)。 +function handleBackToList() { + const target = detailReturnTarget.value + resumeListState.value = true + if (target === 'requestList') { + showErrorModal.value = false + showErrorDetails.value = false + showRequestDetails.value = true + } else if (target === 'errorList') { + showErrorModal.value = false + showRequestDetails.value = false + showErrorDetails.value = true + } + detailReturnTarget.value = null + // 子组件 watch 在本次 show 变化中消费 resumeState 后复位,保证下次手动打开仍会重置筛选。 + window.setTimeout(() => { + resumeListState.value = false + }, 0) +} + function buildApiParams() { const params: any = { platform: platform.value || undefined, diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue index 407c671ca9..8b0dc388f8 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue @@ -211,6 +211,16 @@ + @@ -228,10 +238,12 @@ interface Props { show: boolean errorId: number | null errorType?: 'request' | 'upstream' + backToList?: boolean } interface Emits { (e: 'update:show', value: boolean): void + (e: 'back'): void } const props = defineProps() @@ -363,6 +375,11 @@ function close() { emit('update:show', false) } +function goBack() { + emit('update:show', false) + emit('back') +} + function prettyJSON(raw?: string): string { if (!raw) return 'N/A' try { diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue index 0c513a5f1d..e97e919f6a 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue @@ -15,6 +15,7 @@ interface Props { platform?: string groupId?: number | null errorType: 'request' | 'upstream' + resumeState?: boolean } const props = defineProps() @@ -167,6 +168,7 @@ watch( () => props.show, (open) => { if (!open) return + if (props.resumeState) return page.value = 1 pageSize.value = 10 resetFilters() diff --git a/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue b/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue index 33ce058149..2d8e885a0c 100644 --- a/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue +++ b/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue @@ -23,6 +23,7 @@ interface Props { preset: OpsRequestDetailsPreset platform?: string groupId?: number | null + resumeState?: boolean } const props = defineProps() @@ -98,6 +99,7 @@ watch( () => props.modelValue, (open) => { if (open) { + if (props.resumeState) return page.value = 1 pageSize.value = 10 fetchData() @@ -142,7 +144,6 @@ async function handleCopyRequestId(requestId: string) { function openErrorDetail(errorId: number | null | undefined) { if (!errorId) return - close() emit('openErrorDetail', errorId) }