Commit 5432087d authored by IanShaw027's avatar IanShaw027
Browse files

refactor(frontend): 优化ops错误详情模态框代码格式和功能

- 重构OpsErrorDetailModal.vue代码格式,提升可读性
- 添加上游错误tab显示功能
- 完善i18n翻译(upstream_http)
- 优化其他ops组件代码格式
parent 514c0562
...@@ -2080,6 +2080,9 @@ export default { ...@@ -2080,6 +2080,9 @@ export default {
resolvedRetryId: 'Resolved Retry', resolvedRetryId: 'Resolved Retry',
retryCount: 'Retry Count' retryCount: 'Retry Count'
}, },
source: {
upstream_http: 'Upstream HTTP'
},
upstreamKeys: { upstreamKeys: {
status: 'Status', status: 'Status',
message: 'Message', message: 'Message',
......
...@@ -2224,6 +2224,9 @@ export default { ...@@ -2224,6 +2224,9 @@ export default {
resolvedRetryId: '解决重试ID', resolvedRetryId: '解决重试ID',
retryCount: '重试次数' retryCount: '重试次数'
}, },
source: {
upstream_http: '上游 HTTP'
},
upstreamKeys: { upstreamKeys: {
status: '状态码', status: '状态码',
message: '消息', message: '消息',
......
...@@ -12,7 +12,7 @@ import { formatDateTime } from '../utils/opsFormatters' ...@@ -12,7 +12,7 @@ import { formatDateTime } from '../utils/opsFormatters'
const { t } = useI18n() const { t } = useI18n()
const appStore = useAppStore() const appStore = useAppStore()
const PAGE_SIZE = 20 const PAGE_SIZE = 10
const loading = ref(false) const loading = ref(false)
const loadingMore = ref(false) const loadingMore = ref(false)
......
<script setup lang="ts"> <script setup lang="ts">
import { computed, ref, watch } from 'vue' import { computed, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n' import { useI18n } from 'vue-i18n'
import { useAppStore } from '@/stores'
import BaseDialog from '@/components/common/BaseDialog.vue' import BaseDialog from '@/components/common/BaseDialog.vue'
import Select from '@/components/common/Select.vue' import Select from '@/components/common/Select.vue'
import OpsErrorLogTable from './OpsErrorLogTable.vue' import OpsErrorLogTable from './OpsErrorLogTable.vue'
...@@ -21,19 +22,36 @@ const emit = defineEmits<{ ...@@ -21,19 +22,36 @@ const emit = defineEmits<{
}>() }>()
const { t } = useI18n() const { t } = useI18n()
const appStore = useAppStore()
const retryingUpstream = ref<number | null>(null)
async function retryUpstreamError(id: number) {
try {
retryingUpstream.value = id
const res = await opsAPI.retryUpstreamError(id)
const summary = res.status === 'succeeded' ? t('admin.ops.errorDetail.retrySuccess') : t('admin.ops.errorDetail.retryFailed')
appStore.showSuccess(summary)
page.value = 1
await fetchErrorLogs()
} catch (err: any) {
appStore.showError(err?.message || t('admin.ops.retryFailed'))
} finally {
retryingUpstream.value = null
}
}
const loading = ref(false) const loading = ref(false)
const rows = ref<OpsErrorLog[]>([]) const rows = ref<OpsErrorLog[]>([])
const total = ref(0) const total = ref(0)
const page = ref(1) const page = ref(1)
const pageSize = ref(20) const pageSize = ref(10)
const q = ref('') const q = ref('')
const statusCode = ref<number | 'other' | null>(null) const statusCode = ref<number | 'other' | null>(null)
const phase = ref<string>('') const phase = ref<string>('')
const errorOwner = ref<string>('') const errorOwner = ref<string>('')
const resolvedStatus = ref<string>('unresolved') const resolvedStatus = ref<string>('unresolved')
const viewMode = ref<'errors' | 'excluded' | 'all'>('errors') const viewMode = ref<'errors' | 'excluded' | 'all'>('errors')
const modalTitle = computed(() => { const modalTitle = computed(() => {
...@@ -153,7 +171,7 @@ watch( ...@@ -153,7 +171,7 @@ watch(
(open) => { (open) => {
if (!open) return if (!open) return
page.value = 1 page.value = 1
pageSize.value = 20 pageSize.value = 10
resetFilters() resetFilters()
} }
) )
...@@ -259,17 +277,19 @@ watch( ...@@ -259,17 +277,19 @@ watch(
{{ t('admin.ops.errorDetails.total') }} {{ total }} {{ t('admin.ops.errorDetails.total') }} {{ total }}
</div> </div>
<OpsErrorLogTable <OpsErrorLogTable
class="min-h-0 flex-1" class="min-h-0 flex-1"
:rows="rows" :rows="rows"
:total="total" :total="total"
:loading="loading" :loading="loading"
:page="page" :page="page"
:page-size="pageSize" :page-size="pageSize"
@openErrorDetail="emit('openErrorDetail', $event)" @openErrorDetail="emit('openErrorDetail', $event)"
@update:page="page = $event" @retryUpstream="retryUpstreamError"
@update:pageSize="pageSize = $event" @update:page="page = $event"
/> @update:pageSize="pageSize = $event"
/>
</div> </div>
</div> </div>
</BaseDialog> </BaseDialog>
......
...@@ -142,9 +142,11 @@ ...@@ -142,9 +142,11 @@
<!-- Actions --> <!-- Actions -->
<td class="whitespace-nowrap px-4 py-2 text-right" @click.stop> <td class="whitespace-nowrap px-4 py-2 text-right" @click.stop>
<button type="button" class="text-primary-600 hover:text-primary-700 dark:text-primary-400 text-xs font-bold" @click="emit('openErrorDetail', log.id)"> <div class="flex items-center justify-end gap-3">
{{ t('admin.ops.errorLog.details') }} <button type="button" class="text-primary-600 hover:text-primary-700 dark:text-primary-400 text-xs font-bold" @click="emit('openErrorDetail', log.id)">
</button> {{ t('admin.ops.errorLog.details') }}
</button>
</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
...@@ -158,7 +160,7 @@ ...@@ -158,7 +160,7 @@
:total="total" :total="total"
:page="page" :page="page"
:page-size="pageSize" :page-size="pageSize"
:page-size-options="[10, 20, 50, 100, 200, 500]" :page-size-options="[10]"
@update:page="emit('update:page', $event)" @update:page="emit('update:page', $event)"
@update:pageSize="emit('update:pageSize', $event)" @update:pageSize="emit('update:pageSize', $event)"
/> />
...@@ -175,11 +177,17 @@ import { getSeverityClass, formatDateTime } from '../utils/opsFormatters' ...@@ -175,11 +177,17 @@ import { getSeverityClass, formatDateTime } from '../utils/opsFormatters'
const { t } = useI18n() const { t } = useI18n()
function isUpstreamRow(log: OpsErrorLog): boolean {
const phase = String(log.phase || '').toLowerCase()
const owner = String(log.error_owner || '').toLowerCase()
return phase === 'upstream' && owner === 'provider'
}
function getTypeBadge(log: OpsErrorLog): { label: string; className: string } { function getTypeBadge(log: OpsErrorLog): { label: string; className: string } {
const phase = String(log.phase || '').toLowerCase() const phase = String(log.phase || '').toLowerCase()
const owner = String(log.error_owner || '').toLowerCase() const owner = String(log.error_owner || '').toLowerCase()
if (phase === 'upstream' && owner === 'provider') { if (isUpstreamRow(log)) {
return { label: t('admin.ops.errorLog.typeUpstream'), className: 'bg-red-50 text-red-700 ring-red-600/20 dark:bg-red-900/30 dark:text-red-400 dark:ring-red-500/30' } return { label: t('admin.ops.errorLog.typeUpstream'), className: 'bg-red-50 text-red-700 ring-red-600/20 dark:bg-red-900/30 dark:text-red-400 dark:ring-red-500/30' }
} }
if (phase === 'request' && owner === 'client') { if (phase === 'request' && owner === 'client') {
...@@ -238,10 +246,11 @@ function formatSmartMessage(msg: string): string { ...@@ -238,10 +246,11 @@ function formatSmartMessage(msg: string): string {
} }
} }
if (msg.includes('context deadline exceeded')) return t('admin.ops.errorLog.commonErrors.contextDeadlineExceeded') if (msg.includes('context deadline exceeded')) return t('admin.ops.errorLog.commonErrors.contextDeadlineExceeded')
if (msg.includes('connection refused')) return t('admin.ops.errorLog.commonErrors.connectionRefused') if (msg.includes('connection refused')) return t('admin.ops.errorLog.commonErrors.connectionRefused')
if (msg.toLowerCase().includes('rate limit')) return t('admin.ops.errorLog.commonErrors.rateLimit') if (msg.toLowerCase().includes('rate limit')) return t('admin.ops.errorLog.commonErrors.rateLimit')
return msg.length > 200 ? msg.substring(0, 200) + '...' : msg return msg.length > 200 ? msg.substring(0, 200) + '...' : msg
} }
</script> </script>
\ No newline at end of file
...@@ -38,7 +38,7 @@ const loading = ref(false) ...@@ -38,7 +38,7 @@ const loading = ref(false)
const items = ref<OpsRequestDetail[]>([]) const items = ref<OpsRequestDetail[]>([])
const total = ref(0) const total = ref(0)
const page = ref(1) const page = ref(1)
const pageSize = ref(20) const pageSize = ref(10)
const close = () => emit('update:modelValue', false) const close = () => emit('update:modelValue', false)
...@@ -95,7 +95,7 @@ watch( ...@@ -95,7 +95,7 @@ watch(
(open) => { (open) => {
if (open) { if (open) {
page.value = 1 page.value = 1
pageSize.value = 20 pageSize.value = 10
fetchData() fetchData()
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment