feat(frontend): 结果页组件—MetricCards指标卡+5图(基准/Alpha/Beta/波动率/回撤)+API封装

This commit is contained in:
2026-07-11 13:54:05 +08:00
parent 304844903c
commit d0315ccbdf
13 changed files with 683 additions and 0 deletions
@@ -0,0 +1,87 @@
<script setup lang="ts">
import { computed } from 'vue'
interface RelativeMetrics {
total_return: number
annual_return: number
alpha: number
beta: number
sharpe_ratio: number
sortino_ratio: number
information_ratio: number
annual_volatility: number
max_drawdown: number
benchmark_return: number
benchmark_volatility: number
}
const props = defineProps<{ metrics: RelativeMetrics }>()
// 格式化百分比(×100,保留2位小数)
function formatPercent(value: number): string {
return `${(value * 100).toFixed(2)}%`
}
// 格式化小数(保留3位小数)
function formatDecimal(value: number): string {
return value.toFixed(3)
}
// 格式化Sharpe等比率(保留2位小数)
function formatRatio(value: number): string {
return value.toFixed(2)
}
const metricCards = computed(() => [
{ label: '总收益率', value: formatPercent(props.metrics.total_return) },
{ label: '年化收益率', value: formatPercent(props.metrics.annual_return) },
{ label: 'Alpha', value: formatPercent(props.metrics.alpha) },
{ label: 'Beta', value: formatDecimal(props.metrics.beta) },
{ label: 'Sharpe比率', value: formatRatio(props.metrics.sharpe_ratio) },
{ label: 'Sortino比率', value: formatRatio(props.metrics.sortino_ratio) },
{ label: '信息比率', value: formatRatio(props.metrics.information_ratio) },
{ label: '年化波动率', value: formatPercent(props.metrics.annual_volatility) },
{ label: '最大回撤', value: formatPercent(props.metrics.max_drawdown) },
{ label: '基准收益率', value: formatPercent(props.metrics.benchmark_return) },
{ label: '基准波动率', value: formatPercent(props.metrics.benchmark_volatility) },
])
</script>
<template>
<div class="metric-cards">
<div v-for="card in metricCards" :key="card.label" class="metric-card">
<div class="metric-label">{{ card.label }}</div>
<div class="metric-value">{{ card.value }}</div>
</div>
</div>
</template>
<style scoped>
.metric-cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 16px;
margin-bottom: 24px;
}
.metric-card {
background: #161b22;
border: 1px solid #30363d;
border-radius: 6px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 8px;
}
.metric-label {
color: #8b949e;
font-size: 12px;
}
.metric-value {
color: #e6edf3;
font-size: 20px;
font-weight: 600;
}
</style>