diff --git a/frontend/src/i18n/locales/en.ts b/frontend/src/i18n/locales/en.ts index eb75785e..06fb95e9 100644 --- a/frontend/src/i18n/locales/en.ts +++ b/frontend/src/i18n/locales/en.ts @@ -2080,6 +2080,9 @@ export default { resolvedRetryId: 'Resolved Retry', retryCount: 'Retry Count' }, + source: { + upstream_http: 'Upstream HTTP' + }, upstreamKeys: { status: 'Status', message: 'Message', diff --git a/frontend/src/i18n/locales/zh.ts b/frontend/src/i18n/locales/zh.ts index ef650133..71864498 100644 --- a/frontend/src/i18n/locales/zh.ts +++ b/frontend/src/i18n/locales/zh.ts @@ -2224,6 +2224,9 @@ export default { resolvedRetryId: '解决重试ID', retryCount: '重试次数' }, + source: { + upstream_http: '上游 HTTP' + }, upstreamKeys: { status: '状态码', message: '消息', diff --git a/frontend/src/views/admin/ops/components/OpsAlertEventsCard.vue b/frontend/src/views/admin/ops/components/OpsAlertEventsCard.vue index ef6e8f80..06b9b290 100644 --- a/frontend/src/views/admin/ops/components/OpsAlertEventsCard.vue +++ b/frontend/src/views/admin/ops/components/OpsAlertEventsCard.vue @@ -12,7 +12,7 @@ import { formatDateTime } from '../utils/opsFormatters' const { t } = useI18n() const appStore = useAppStore() -const PAGE_SIZE = 20 +const PAGE_SIZE = 10 const loading = ref(false) const loadingMore = ref(false) diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue index 67eda179..d2f185d5 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorDetailModal.vue @@ -30,123 +30,178 @@ > {{ t('admin.ops.errorDetail.markResolved') }} - -
- - - - +
+ + + + +
-
+ +
-
-
{{ t('admin.ops.errorDetail.requestId') }}
-
- {{ detail.request_id || detail.client_request_id || '—' }} +
+
{{ t('admin.ops.errorDetail.requestId') }}
+
+ {{ detail.request_id || detail.client_request_id || '—' }} +
+
+ +
+
{{ t('admin.ops.errorDetail.time') }}
+
+ {{ formatDateTime(detail.created_at) }} +
+
+ +
+
{{ t('admin.ops.errorDetail.phase') }}
+
+ {{ detail.phase || '—' }} +
+
+ {{ detail.type || '—' }} +
+
+ +
+
{{ t('admin.ops.errorDetail.status') }}
+
+ + {{ detail.status_code }} + + + {{ detail.severity }} + +
-
-
{{ t('admin.ops.errorDetail.time') }}
-
- {{ formatDateTime(detail.created_at) }} + +
+
+

+ {{ t('admin.ops.errorDetail.message') }} +

+ +
+ + +
+
+ +
+ {{ detail.message || '—' }}
-
-
{{ t('admin.ops.errorDetail.phase') }}
-
- {{ detail.phase || '—' }} -
-
- {{ detail.type || '—' }} -
-
- -
-
{{ t('admin.ops.errorDetail.status') }}
-
- - {{ detail.status_code }} + +
+

+ {{ t('admin.ops.errorDetail.classification') }} +

+
+ + {{ t('admin.ops.errorDetail.classificationKeys.phase') }}: + {{ phaseLabel }} + + + {{ t('admin.ops.errorDetail.classificationKeys.owner') }}: + {{ ownerLabel }} + + + {{ t('admin.ops.errorDetail.classificationKeys.source') }}: + {{ sourceLabel }} + + + {{ t('admin.ops.errorDetail.classificationKeys.retryable') }}: + {{ (detail as any).is_retryable ? t('common.yes') : t('common.no') }} - {{ detail.severity }} + {{ t('admin.ops.errorDetail.classificationKeys.resolvedAt') }}: {{ (detail as any).resolved_at }} + + + {{ t('admin.ops.errorDetail.classificationKeys.resolvedBy') }}: + {{ (detail as any).resolved_by_user_id }} + + + {{ t('admin.ops.errorDetail.classificationKeys.resolvedRetryId') }}: + {{ (detail as any).resolved_retry_id }} + + + {{ t('admin.ops.errorDetail.classificationKeys.retryCount') }}: {{ (detail as any).retry_count }} -
-
-
- - -
-

{{ t('admin.ops.errorDetail.message') }}

-
- {{ detail.message || '—' }} -
-
- - -
-

{{ t('admin.ops.errorDetail.suggestion') }}

-
- {{ handlingSuggestion }} -
-
- - -
-

{{ t('admin.ops.errorDetail.classification') }}

-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.phase') }}
-
{{ detail.phase || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.owner') }}
-
{{ (detail as any).error_owner || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.source') }}
-
{{ (detail as any).error_source || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.retryable') }}
-
{{ (detail as any).is_retryable ? t('common.yes') : t('common.no') }}
-
-
- -
-
-
{{ t('admin.ops.errorDetail.classificationKeys.resolvedAt') }}
-
{{ (detail as any).resolved_at || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.resolvedBy') }}
-
{{ (detail as any).resolved_by_user_id ?? '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.resolvedRetryId') }}
-
{{ (detail as any).resolved_retry_id ?? '—' }}
-
-
-
{{ t('admin.ops.errorDetail.classificationKeys.retryCount') }}
-
{{ (detail as any).retry_count ?? '—' }}
-
@@ -154,254 +209,187 @@

{{ t('admin.ops.errorDetail.basicInfo') }}

-
-
{{ t('admin.ops.errorDetail.platform') }}
-
{{ detail.platform || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.model') }}
-
{{ detail.model || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.group') }}
-
- - {{ detail.group_name || detail.group_id }} - - +
+
{{ t('admin.ops.errorDetail.platform') }}
+
{{ detail.platform || '—' }}
-
-
-
{{ t('admin.ops.errorDetail.account') }}
-
- - {{ detail.account_name || detail.account_id }} - - +
+
{{ t('admin.ops.errorDetail.model') }}
+
{{ detail.model || '—' }}
-
-
-
TTFT
-
- {{ detail.time_to_first_token_ms != null ? `${detail.time_to_first_token_ms}ms` : '—' }} +
+
{{ t('admin.ops.errorDetail.group') }}
+
+ + {{ detail.group_name || detail.group_id }} + + +
-
-
-
{{ t('admin.ops.errorDetail.businessLimited') }}
-
- {{ detail.is_business_limited ? 'true' : 'false' }} +
+
{{ t('admin.ops.errorDetail.account') }}
+
+ + {{ detail.account_name || detail.account_id }} + + +
-
-
-
{{ t('admin.ops.errorDetail.requestPath') }}
-
- {{ detail.request_path || '—' }} +
+
TTFT
+
+ {{ detail.time_to_first_token_ms != null ? `${detail.time_to_first_token_ms}ms` : '—' }} +
+
+
+
{{ t('admin.ops.errorDetail.businessLimited') }}
+
+ {{ detail.is_business_limited ? 'true' : 'false' }} +
+
+
+
{{ t('admin.ops.errorDetail.requestPath') }}
+
+ {{ detail.request_path || '—' }} +
-
- -
-

{{ t('admin.ops.errorDetail.timings') }}

-
-
-
{{ t('admin.ops.errorDetail.auth') }}
-
- {{ detail.auth_latency_ms != null ? `${detail.auth_latency_ms}ms` : '—' }} -
-
-
-
{{ t('admin.ops.errorDetail.routing') }}
-
- {{ detail.routing_latency_ms != null ? `${detail.routing_latency_ms}ms` : '—' }} -
-
-
-
{{ t('admin.ops.errorDetail.upstream') }}
-
- {{ detail.upstream_latency_ms != null ? `${detail.upstream_latency_ms}ms` : '—' }} -
-
-
-
{{ t('admin.ops.errorDetail.response') }}
-
- {{ detail.response_latency_ms != null ? `${detail.response_latency_ms}ms` : '—' }} -
-
-
-
- - -
-
-
-

{{ t('admin.ops.errorDetail.retry') }}

-
- {{ t('admin.ops.errorDetail.retryNote1') }} -
-
-
- - -
-
- - -
-
- - -
- {{ t('admin.ops.errorDetail.pinnedToOriginalAccountId') }} -
-
-
+ +
+

{{ t('admin.ops.errorDetail.timings') }}

+
-
{{ t('admin.ops.errorDetail.retryNotes') }}
-
    -
  • {{ t('admin.ops.errorDetail.retryNote3') }}
  • -
  • {{ t('admin.ops.errorDetail.retryNote4') }}
  • -
+
{{ t('admin.ops.errorDetail.auth') }}
+
+ {{ detail.auth_latency_ms != null ? `${detail.auth_latency_ms}ms` : '—' }} +
+
+
+
{{ t('admin.ops.errorDetail.routing') }}
+
+ {{ detail.routing_latency_ms != null ? `${detail.routing_latency_ms}ms` : '—' }} +
+
+
+
{{ t('admin.ops.errorDetail.upstream') }}
+
+ {{ detail.upstream_latency_ms != null ? `${detail.upstream_latency_ms}ms` : '—' }} +
+
+
+
{{ t('admin.ops.errorDetail.response') }}
+
+ {{ detail.response_latency_ms != null ? `${detail.response_latency_ms}ms` : '—' }} +
+ +
+ + +
{{ t('admin.ops.errorDetail.pinnedToOriginalAccountId') }}
+
- -
-

- {{ t('admin.ops.errorDetails.upstreamErrors') }} -

+ +
+
+

+ {{ t('admin.ops.errorDetails.upstreamErrors') }} +

-
-
-
{{ t('admin.ops.errorDetail.upstreamKeys.status') }}
-
- {{ detail.upstream_status_code != null ? detail.upstream_status_code : '—' }} +
+
+
{{ t('admin.ops.errorDetail.upstreamKeys.status') }}
+
+ {{ detail.upstream_status_code != null ? detail.upstream_status_code : '—' }} +
+
+
+
{{ t('admin.ops.errorDetail.upstreamKeys.message') }}
+
+ {{ detail.upstream_error_message || '—' }} +
-
-
{{ t('admin.ops.errorDetail.upstreamKeys.message') }}
-
- {{ detail.upstream_error_message || '—' }} -
+ +
+
{{ t('admin.ops.errorDetail.upstreamKeys.detail') }}
+
{{ prettyJSON(detail.upstream_error_detail) }}
-
-
-
{{ t('admin.ops.errorDetail.upstreamKeys.detail') }}
-
{{ prettyJSON(detail.upstream_error_detail) }}
-
+
+
{{ t('admin.ops.errorDetail.upstreamKeys.upstreamErrors') }}
-
-
{{ t('admin.ops.errorDetail.upstreamKeys.upstreamErrors') }}
- -
-
-
-
- #{{ idx + 1 }} {{ ev.kind }} -
-
- -
- {{ ev.at_unix_ms ? formatDateTime(new Date(ev.at_unix_ms)) : '' }} +
+
+
+
#{{ idx + 1 }} {{ ev.kind }}
+
+ +
+ {{ ev.at_unix_ms ? formatDateTime(new Date(ev.at_unix_ms)) : '' }} +
-
-
-
- {{ t('admin.ops.errorDetail.upstreamEvent.account') }}: - - {{ ev.account_name || ev.account_id }} - - +
+
+ {{ t('admin.ops.errorDetail.upstreamEvent.account') }}: + + {{ ev.account_name || ev.account_id }} + + +
+
+ {{ t('admin.ops.errorDetail.upstreamEvent.status') }}: + {{ ev.upstream_status_code ?? '—' }} +
+
+ {{ t('admin.ops.errorDetail.upstreamEvent.requestId') }}: + {{ ev.upstream_request_id || '—' }} +
-
{{ t('admin.ops.errorDetail.upstreamEvent.status') }}: {{ ev.upstream_status_code ?? '—' }}
-
- {{ t('admin.ops.errorDetail.upstreamEvent.requestId') }}: {{ ev.upstream_request_id || '—' }} + +
+ {{ ev.message }}
-
-
- {{ ev.message }} +
{{ prettyJSON(ev.detail) }}
- -
{{ prettyJSON(ev.detail) }}
-
-
{{ prettyJSON(detail.upstream_errors) }}
-
-
- - -
-
-

{{ t('admin.ops.errorDetail.requestBody') }}

-
- {{ t('admin.ops.errorDetail.trimmed') }} +
{{ prettyJSON(detail.upstream_errors) }}
-
{{ prettyJSON(detail.request_body) }}
- -
-

{{ t('admin.ops.errorDetail.errorBody') }}

-
{{ prettyJSON(detail.error_body) }}
-
-
- -
+ +
{{ t('admin.ops.errorDetail.retryHistory') }}
@@ -434,8 +422,8 @@
{{ selectedA ? `#${selectedA.id} · ${selectedA.mode} · ${selectedA.status}` : '—' }}
- HTTP: {{ selectedA?.http_status_code ?? '—' }} · - {{ t('admin.ops.errorDetail.retryMeta.used') }}: + HTTP: {{ selectedA?.http_status_code ?? '—' }} · {{ t('admin.ops.errorDetail.retryMeta.used') }}: + {{ selectedA.used_account_name || selectedA.used_account_id }} @@ -445,11 +433,12 @@
{{ selectedA?.response_preview || '' }}
{{ selectedA.error_message }}
+
{{ selectedB ? `#${selectedB.id} · ${selectedB.mode} · ${selectedB.status}` : '—' }}
- HTTP: {{ selectedB?.http_status_code ?? '—' }} · - {{ t('admin.ops.errorDetail.retryMeta.used') }}: + HTTP: {{ selectedB?.http_status_code ?? '—' }} · {{ t('admin.ops.errorDetail.retryMeta.used') }}: + {{ selectedB.used_account_name || selectedB.used_account_id }} @@ -468,7 +457,9 @@
{{ a.created_at }}
-
{{ t('admin.ops.errorDetail.retryMeta.success') }}: {{ a.success ?? '—' }}
+
+ {{ t('admin.ops.errorDetail.retryMeta.success') }}: {{ a.success ?? '—' }} +
HTTP: {{ a.http_status_code ?? '—' }}
{{ t('admin.ops.errorDetail.retryMeta.pinned') }}: @@ -493,25 +484,26 @@
-
+ +

{{ t('admin.ops.errorDetail.requestBody') }}

-
{{ prettyJSON(detail.request_body) }}
+
{{ prettyJSON(detail.request_body || '') }}
-
+ +

{{ t('admin.ops.errorDetail.responseBody') }}

{{ responseTabHint }}
-
{{ prettyJSON(responseTabBody) }}
+
{{ prettyJSON(responseTabBody || '') }}
-
- - +
+
- \ No newline at end of file + diff --git a/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue b/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue index 8c6c116b..acf9254a 100644 --- a/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue +++ b/frontend/src/views/admin/ops/components/OpsErrorDetailsModal.vue @@ -1,6 +1,7 @@ \ No newline at end of file diff --git a/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue b/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue index d3edd745..3a70b4f2 100644 --- a/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue +++ b/frontend/src/views/admin/ops/components/OpsRequestDetailsModal.vue @@ -38,7 +38,7 @@ const loading = ref(false) const items = ref([]) const total = ref(0) const page = ref(1) -const pageSize = ref(20) +const pageSize = ref(10) const close = () => emit('update:modelValue', false) @@ -95,7 +95,7 @@ watch( (open) => { if (open) { page.value = 1 - pageSize.value = 20 + pageSize.value = 10 fetchData() } }