Преглед на файлове

refactor(convertible): 移除历史分位KPI与指标解读区并修正时序图图例颜色

ligb преди 5 дни
родител
ревизия
3132b636f7
променени са 2 файла, в които са добавени 16 реда и са изтрити 193 реда
  1. 8 1
      web-app/src/views/multiasset/convertible/charts.js
  2. 8 192
      web-app/src/views/multiasset/convertible/index.vue

+ 8 - 1
web-app/src/views/multiasset/convertible/charts.js

@@ -41,7 +41,14 @@ export function impliedSpreadSeriesOption(series, latest) {
       },
     },
     legend: {
-      data: ['隐含利差', '均值', '+1σ', '-1σ', '+2σ', '-2σ'],
+      data: [
+        { name: '隐含利差', itemStyle: { color: C.brand } },
+        { name: '均值',     itemStyle: { color: C.faint } },
+        { name: '+1σ',      itemStyle: { color: C.brand } },
+        { name: '-1σ',      itemStyle: { color: C.brand } },
+        { name: '+2σ',      itemStyle: { color: C.warn } },
+        { name: '-2σ',      itemStyle: { color: C.warn } },
+      ],
       top: 4,
       textStyle: { color: C.mut, fontSize: 11 },
       itemWidth: 14,

+ 8 - 192
web-app/src/views/multiasset/convertible/index.vue

@@ -45,11 +45,6 @@
         <div class="value">{{ formatPct(stats.up2) }}</div>
         <div class="chg">下沿 {{ formatPct(stats.down2) }}</div>
       </div>
-      <div class="kpi-card">
-        <div class="label">历史分位</div>
-        <div class="value">{{ formatPctP(pos * 100 - 100) }}</div>
-        <div class="chg">{{ posLabel }}</div>
-      </div>
     </section>
 
     <!-- 隐含利差主图 -->
@@ -80,75 +75,6 @@
       </div>
     </section>
 
-    <!-- 历史分位 + 指标解读 -->
-    <section class="section">
-      <div class="section-hd">
-        <span class="dot"></span>
-        <h2>历史分位区间 · 指标解读</h2>
-        <span class="meta">基于 2017 年以来日度数据 · 百分位越大代表估值越便宜</span>
-      </div>
-
-      <div class="card-grid cols-2-1">
-        <div class="card">
-          <div class="card-head">
-            <div class="title">
-              <span class="ic">分</span>
-              <span class="title-text">当前隐含利差 · 在历史分布中的位置</span>
-            </div>
-            <div class="acts">
-              <span class="meta">位于 {{ formatPctP(pos * 100 - 100) }} 分位</span>
-            </div>
-          </div>
-          <div class="card-body">
-            <Chart :option="gaugeOpt" height="220px" />
-
-            <div class="band-list">
-              <div
-                v-for="b in bands"
-                :key="b.label"
-                class="band-row"
-                :class="{ on: bandLabel === b.label }"
-              >
-                <div class="band-bar" :style="{ background: b.axisColor }"></div>
-                <div class="band-label">{{ b.label }}</div>
-                <div class="band-range">{{ b.range }}</div>
-              </div>
-            </div>
-          </div>
-        </div>
-
-        <div class="card">
-          <div class="card-head">
-            <div class="title">
-              <span class="ic">说</span>
-              <span class="title-text">指标解读</span>
-            </div>
-          </div>
-          <div class="card-body">
-            <div class="note-block" v-for="n in notes" :key="n.title">
-              <div class="note-t">{{ n.title }}</div>
-              <div class="note-d">{{ n.desc }}</div>
-            </div>
-
-            <div class="quick-row">
-              <div class="qk">
-                <div class="qk-k">位置结论</div>
-                <div class="qk-v" :style="{ color: bandColor }">{{ bandLabel }}</div>
-              </div>
-              <div class="qk">
-                <div class="qk-k">距均值差</div>
-                <div class="qk-v">{{ formatPct(latest.value - stats.mean) }}</div>
-              </div>
-              <div class="qk">
-                <div class="qk-k">距 -1σ 差</div>
-                <div class="qk-v">{{ formatPct(latest.value - stats.down1) }}</div>
-              </div>
-            </div>
-          </div>
-        </div>
-      </div>
-    </section>
-
     <footer class="footer">
       数据源:4.3-多资产分析.xlsx · 1-转债 sheet · 数据截至 {{ latest.date }} · 转债隐含利差反映转债相对纯债的估值溢价
     </footer>
@@ -163,36 +89,19 @@ import {
   BOND_STATS as stats,
   BOND_LATEST as latest,
   BOND_PREV as prev,
-  BOND_HISTORICAL_VALUES,
-  BOND_NOTES as notes,
-  classifyPercentile,
 } from './data'
-import {
-  impliedSpreadSeriesOption,
-  percentileGaugeOption,
-} from './charts'
+import { impliedSpreadSeriesOption } from './charts'
 
 const loading = ref(false)
 
-// 计算历史分位
-const percentile = computed(() => classifyPercentile(latest.value, BOND_HISTORICAL_VALUES))
-const pos = computed(() => percentile.value.pos)
-const posLabel = computed(() => {
-  if (pos.value < 0.1) return '历史最低 10% 区间内'
-  if (pos.value < 0.25) return '历史 10%-25% 区间内'
-  if (pos.value < 0.5) return '历史 25%-50% 区间内'
-  if (pos.value < 0.75) return '历史 50%-75% 区间内'
-  return '历史 75% 分位以上(估值最便宜)'
-})
-
 // 区间标签(按当前隐含利差 vs 标准差区间)
 const BAND_DEFS = [
-  { lo: -Infinity, hi: stats.down2, label: '极低估',    cls: 'deep-low',  bg: '#0BB0A2', fg: '#0A8A7E', axisColor: '#0BB0A2', range: '< -2σ' },
-  { lo: stats.down2, hi: stats.down1, label: '低估',     cls: 'low',       bg: '#E4F5EE', fg: '#189A65', axisColor: '#189A65', range: '[-2σ, -1σ)' },
-  { lo: stats.down1, hi: stats.mean,  label: '中性偏低', cls: 'mid-low',   bg: '#EEF2F7', fg: '#6B7A96', axisColor: '#6B7A96', range: '[-1σ, 均值)' },
-  { lo: stats.mean,  hi: stats.up1,   label: '中性偏高', cls: 'mid-high',  bg: '#FFF4E5', fg: '#E8912D', axisColor: '#E8912D', range: '[均值, +1σ)' },
-  { lo: stats.up1,   hi: stats.up2,   label: '高估',     cls: 'high',      bg: '#FDEAEA', fg: '#E13B3B', axisColor: '#E13B3B', range: '[+1σ, +2σ)' },
-  { lo: stats.up2,   hi: Infinity,    label: '极高估',   cls: 'deep-high', bg: '#B72828', fg: '#fff',    axisColor: '#B72828', range: '≥ +2σ' },
+  { lo: -Infinity, hi: stats.down2, label: '极低估',    cls: 'deep-low' },
+  { lo: stats.down2, hi: stats.down1, label: '低估',     cls: 'low' },
+  { lo: stats.down1, hi: stats.mean,  label: '中性偏低', cls: 'mid-low' },
+  { lo: stats.mean,  hi: stats.up1,   label: '中性偏高', cls: 'mid-high' },
+  { lo: stats.up1,   hi: stats.up2,   label: '高估',     cls: 'high' },
+  { lo: stats.up2,   hi: Infinity,    label: '极高估',   cls: 'deep-high' },
 ]
 
 function classify(v) {
@@ -203,13 +112,6 @@ function classify(v) {
 const currentBand = computed(() => classify(latest.value))
 const bandCls = computed(() => currentBand.value.cls)
 const bandLabel = computed(() => currentBand.value.label)
-const bandColor = computed(() => currentBand.value.fg)
-
-const bands = BAND_DEFS.map((b) => ({
-  label: b.label,
-  range: b.range,
-  axisColor: b.axisColor,
-}))
 
 const arrow = computed(() => {
   const d = +(latest.value - prev.value).toFixed(4)
@@ -225,14 +127,8 @@ function formatPct(v) {
   if (v == null) return '—'
   return (v * 100).toFixed(2) + '%'
 }
-function formatPctP(v) {
-  if (v == null) return '—'
-  // v is the relative position (e.g. -52.3 means 52.3% from low)
-  return Math.abs(v).toFixed(1) + '%'
-}
 
 const seriesOpt = computed(() => impliedSpreadSeriesOption(BOND_RECENT, latest))
-const gaugeOpt = computed(() => percentileGaugeOption(latest.value, BOND_HISTORICAL_VALUES))
 
 function reload() {
   loading.value = true
@@ -314,7 +210,7 @@ function reload() {
 
 .kpi-grid {
   display: grid;
-  grid-template-columns: 1.4fr repeat(4, 1fr);
+  grid-template-columns: 1.4fr repeat(3, 1fr);
   gap: 10px;
   margin-bottom: 16px;
 }
@@ -410,7 +306,6 @@ function reload() {
   display: grid;
   gap: 14px;
 }
-.card-grid.cols-2-1 { grid-template-columns: 2fr 1fr; }
 .card-grid.cols-1 { grid-template-columns: 1fr; }
 .card-grid.cols-2 { grid-template-columns: 1fr 1fr; }
 
@@ -471,84 +366,6 @@ function reload() {
   min-height: 0;
 }
 
-.band-list {
-  display: flex;
-  flex-direction: column;
-  gap: 6px;
-  margin-top: 12px;
-}
-.band-row {
-  display: flex;
-  align-items: center;
-  gap: 10px;
-  padding: 7px 10px;
-  border-radius: 6px;
-  background: #FAFBFE;
-  border: 1px solid transparent;
-  transition: 0.15s;
-}
-.band-row.on {
-  background: #fff;
-  border-color: var(--brand-lt, #E0F7F4);
-  box-shadow: 0 1px 3px rgba(16,32,64,0.06);
-}
-.band-bar {
-  width: 4px;
-  height: 18px;
-  border-radius: 2px;
-}
-.band-label {
-  font-size: 12.5px;
-  font-weight: 600;
-  color: var(--ink);
-  flex: 1;
-}
-.band-range {
-  font-size: 11.5px;
-  color: var(--mut, #6B7A96);
-  font-variant-numeric: tabular-nums;
-}
-
-.note-block {
-  margin-bottom: 12px;
-}
-.note-t {
-  font-size: 13px;
-  font-weight: 600;
-  color: var(--ink, #1A2438);
-  margin-bottom: 4px;
-}
-.note-d {
-  font-size: 12px;
-  color: var(--mut, #6B7A96);
-  line-height: 1.6;
-}
-
-.quick-row {
-  display: flex;
-  gap: 8px;
-  margin-top: 14px;
-  padding-top: 12px;
-  border-top: 1px dashed var(--line, #E4E9F2);
-}
-.qk {
-  flex: 1;
-  background: #FAFBFE;
-  padding: 9px 10px;
-  border-radius: 6px;
-}
-.qk-k {
-  font-size: 11px;
-  color: var(--mut, #6B7A96);
-  margin-bottom: 4px;
-}
-.qk-v {
-  font-size: 14px;
-  font-weight: 600;
-  color: var(--ink, #1A2438);
-  font-variant-numeric: tabular-nums;
-}
-
 .footer {
   padding: 18px 24px 12px;
   color: #98A5BD;
@@ -566,7 +383,6 @@ function reload() {
 }
 @media (max-width: 980px) {
   .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
-  .card-grid.cols-2-1,
   .card-grid.cols-2 { grid-template-columns: 1fr; }
 }
 </style>