feat(frontend): 对接工作台页面真实接口
This commit is contained in:
@@ -1,5 +1,75 @@
|
||||
<script setup lang="ts">
|
||||
import { recentRuns, traceSteps } from '@/data/studioMock';
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
|
||||
import type { ObservabilityRunSummary, ObservabilityTrace } from '@/api/observability';
|
||||
import { exportObservabilityTrace, getObservabilityTrace, listObservabilityRuns } from '@/api/observability';
|
||||
|
||||
const loading = ref(false);
|
||||
const runs = ref<ObservabilityRunSummary[]>([]);
|
||||
const trace = ref<ObservabilityTrace | null>(null);
|
||||
const exportSummary = ref('');
|
||||
|
||||
const selectedRequestId = computed(() => trace.value?.requestId || runs.value[0]?.requestId || '');
|
||||
|
||||
function formatLatency(durationMs?: number) {
|
||||
if (durationMs == null) {
|
||||
return '-';
|
||||
}
|
||||
if (durationMs >= 1000) {
|
||||
return `${(durationMs / 1000).toFixed(2)}s`;
|
||||
}
|
||||
return `${durationMs}ms`;
|
||||
}
|
||||
|
||||
function formatCost(cost?: number) {
|
||||
if (cost == null) {
|
||||
return '-';
|
||||
}
|
||||
return `¥${cost}`;
|
||||
}
|
||||
|
||||
function formatStatus(status?: string) {
|
||||
if (status === 'SUCCESS') {
|
||||
return '成功';
|
||||
}
|
||||
if (status === 'FAILED') {
|
||||
return '失败';
|
||||
}
|
||||
if (status === 'RUNNING') {
|
||||
return '运行中';
|
||||
}
|
||||
return status || '-';
|
||||
}
|
||||
|
||||
async function loadRuns() {
|
||||
loading.value = true;
|
||||
try {
|
||||
const response = await listObservabilityRuns();
|
||||
runs.value = response.data ?? [];
|
||||
if (runs.value.length > 0) {
|
||||
await loadTrace(runs.value[0].requestId);
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function loadTrace(requestId: string) {
|
||||
const response = await getObservabilityTrace(requestId);
|
||||
trace.value = response.data;
|
||||
}
|
||||
|
||||
async function exportTrace() {
|
||||
if (!selectedRequestId.value) {
|
||||
return;
|
||||
}
|
||||
const response = await exportObservabilityTrace(selectedRequestId.value);
|
||||
exportSummary.value = response.data.exportSummary ?? '';
|
||||
ElMessage.success('脱敏日志导出成功');
|
||||
}
|
||||
|
||||
onMounted(loadRuns);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -9,10 +79,10 @@ import { recentRuns, traceSteps } from '@/data/studioMock';
|
||||
<p class="studio-kicker">ObservabilityView</p>
|
||||
<h1>运行观测</h1>
|
||||
</div>
|
||||
<el-button>导出日志</el-button>
|
||||
<el-button data-test="observability-export" @click="exportTrace">导出日志</el-button>
|
||||
</header>
|
||||
|
||||
<div class="observability-layout">
|
||||
<div class="observability-layout" v-loading="loading">
|
||||
<section class="studio-panel">
|
||||
<div class="panel-heading">
|
||||
<h2>运行记录</h2>
|
||||
@@ -20,18 +90,23 @@ import { recentRuns, traceSteps } from '@/data/studioMock';
|
||||
</div>
|
||||
<div class="run-table">
|
||||
<div class="run-row run-head">
|
||||
<span>名称</span><span>类型</span><span>状态</span><span>延迟</span><span>成本</span>
|
||||
<span>请求ID</span><span>状态</span><span>延迟</span><span>成本</span>
|
||||
</div>
|
||||
<div v-for="run in recentRuns" :key="run.id" class="run-row">
|
||||
<strong>{{ run.name }}</strong>
|
||||
<span>{{ run.type }}</span>
|
||||
<div
|
||||
v-for="run in runs"
|
||||
:key="run.requestId"
|
||||
class="run-row"
|
||||
:data-test="`observability-run-${run.requestId}`"
|
||||
@click="loadTrace(run.requestId)"
|
||||
>
|
||||
<strong>{{ run.requestId }}</strong>
|
||||
<span class="status-cell">
|
||||
<span class="status-pill" :class="run.status === '成功' ? 'is-success' : 'is-warning'">
|
||||
{{ run.status }}
|
||||
<span class="status-pill" :class="formatStatus(run.status) === '成功' ? 'is-success' : 'is-warning'">
|
||||
{{ formatStatus(run.status) }}
|
||||
</span>
|
||||
</span>
|
||||
<span>{{ run.latency }}</span>
|
||||
<span>{{ run.cost }}</span>
|
||||
<span>{{ formatLatency(run.durationMs) }}</span>
|
||||
<span>{{ formatCost(run.estimatedCost) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -39,12 +114,13 @@ import { recentRuns, traceSteps } from '@/data/studioMock';
|
||||
<aside class="studio-panel">
|
||||
<div class="panel-heading compact">
|
||||
<h2>步骤日志</h2>
|
||||
<span>run-1842</span>
|
||||
<span data-test="observability-trace-id">{{ selectedRequestId || '暂无请求' }}</span>
|
||||
</div>
|
||||
<p v-if="exportSummary" class="export-summary" data-test="observability-export-summary">{{ exportSummary }}</p>
|
||||
<ol class="log-list">
|
||||
<li v-for="step in traceSteps" :key="step.node">
|
||||
<time>{{ step.duration }}</time>
|
||||
<span>{{ step.node }} · {{ step.status }} · {{ step.output }}</span>
|
||||
<li v-for="step in trace?.stepLogs ?? []" :key="`${step.nodeName}-${step.durationMs}`" :data-test="`observability-step-${step.nodeName}`">
|
||||
<time>{{ formatLatency(step.durationMs) }}</time>
|
||||
<span>{{ step.nodeName }} · {{ formatStatus(step.status) }} · {{ step.outputSummary || step.errorMessage || '-' }}</span>
|
||||
</li>
|
||||
</ol>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user