| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090 |
- <template>
- <div class="us-page">
- <header class="page-hd">
- <div>
- <div class="page-title">美股分析</div>
- <div class="page-sub">
- 美股资产评分表 · 政治与宏观 · 估值与盈利 · 市场情绪与动量 · 数据截至 {{ summary.asOf }}
- </div>
- </div>
- <div class="page-actions">
- <span class="chip" :class="summaryCls">
- 综合 · {{ summaryBand.label }}
- </span>
- <button class="btn" @click="reload" :disabled="loading">
- <span :class="['ic-refresh', { spinning: loading }]">↻</span> 刷新
- </button>
- </div>
- </header>
- <!-- KPI 概览条 -->
- <section class="kpi-grid">
- <div class="kpi-card hero" :class="summaryCls">
- <div class="label">综合加权得分</div>
- <div class="value">
- {{ formatScore(summary.current) }}<span class="unit"> / 10</span>
- </div>
- <div class="chg">
- <span class="arrow">{{ summaryDelta.arrow }}</span>
- 较上期 {{ summaryDelta.text }}
- · {{ summaryBand.label }}
- </div>
- </div>
- <div class="kpi-card">
- <div class="label">政治与宏观</div>
- <div class="value">{{ formatScore(catScore('macro')) }}</div>
- <div class="chg">权重 33.33% · 4 项简单平均</div>
- </div>
- <div class="kpi-card">
- <div class="label">估值与盈利</div>
- <div class="value">{{ formatScore(catScore('profit')) }}</div>
- <div class="chg">权重 33.33% · 4 项简单平均</div>
- </div>
- <div class="kpi-card">
- <div class="label">市场情绪与动量</div>
- <div class="value">{{ formatScore(catScore('momentum')) }}</div>
- <div class="chg">权重 33.33% · 4 项简单平均</div>
- </div>
- <div class="kpi-card">
- <div class="label">投资小组评分</div>
- <div class="value">{{ formatScore(summary.groupScore) }}</div>
- <div class="chg">较上期 +{{ summary.groupDelta.toFixed(2) }} · 中性偏多</div>
- </div>
- </section>
- <!-- 综合得分仪表 + 评分区间说明 -->
- <section class="section">
- <div class="section-hd">
- <span class="dot"></span>
- <h2>综合得分仪表 · 评分区间映射</h2>
- <span class="meta">{{ summary.asOf }} · 上期对比 {{ summary.prevAsOf }}</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">本期 {{ formatScore(summary.current) }} · 上期 {{ formatScore(summary.previous) }}</span>
- </div>
- </div>
- <div class="card-body">
- <Chart :option="gaugeOpt" height="320px" />
- </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="band-list">
- <div
- v-for="b in bands"
- :key="b.label"
- class="band-row"
- :class="{ on: summaryBand.label === b.label }"
- >
- <div class="band-bar" :style="{ background: b.axisColor }"></div>
- <div class="band-label">{{ b.label }}</div>
- <div class="band-range">
- <template v-if="b.lo === 0">(0, {{ b.hi }}]</template>
- <template v-else-if="b.hi === 10">[{{ b.lo }}, 10)</template>
- <template v-else-if="b.hi === 8">[{{ b.lo }}, {{ b.hi }})</template>
- <template v-else>({{ b.lo }}, {{ b.hi }}]</template>
- </div>
- </div>
- </div>
- <div class="note">
- <div class="note-row">
- <span class="note-k">综合评分</span>
- <span class="note-v">{{ formatScore(summary.current) }} 分</span>
- </div>
- <div class="note-row">
- <span class="note-k">所在区间</span>
- <span class="note-v" :style="{ color: summaryBand.fg }">{{ summaryBand.label }}</span>
- </div>
- <div class="note-row">
- <span class="note-k">上期得分</span>
- <span class="note-v">{{ formatScore(summary.previous) }} 分</span>
- </div>
- <div class="note-row">
- <span class="note-k">环比变动</span>
- <span class="note-v">{{ summaryDelta.arrow }} {{ summaryDelta.text }}</span>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
- <!-- 一级类别横向对比 + 贡献度 + 本月解读 -->
- <section class="section">
- <div class="section-hd">
- <span class="dot"></span>
- <h2>一级类别综合得分 · 类别贡献度 · 本月解读</h2>
- <span class="meta">12 项因子简单平均 · 含投资小组 / 综合评分</span>
- </div>
- <div class="card-grid cols-2-1-1">
- <div class="card">
- <div class="card-head">
- <div class="title">
- <span class="ic">图</span>
- <span class="title-text">一级类别综合得分 · 本期 vs 上期</span>
- </div>
- </div>
- <div class="card-body">
- <Chart :option="barOpt" height="300px" />
- </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">
- <Chart :option="contribOpt" height="300px" />
- </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="rating-block">
- <div class="rating-row">
- <span class="r-k">评级</span>
- <span class="chip" :class="summaryCls">{{ summary.rating }}</span>
- </div>
- <div class="rating-row">
- <span class="r-k">投资小组评分</span>
- <span class="r-v">
- {{ formatScore(summary.groupScore) }}
- <span class="r-delta up">+{{ summary.groupDelta.toFixed(2) }}</span>
- </span>
- </div>
- <div class="rating-row">
- <span class="r-k">综合评分(12 项简单平均)</span>
- <span class="r-v">{{ formatScore(summary.current) }}</span>
- </div>
- <div class="highlight">
- <div class="hl-title">本月主要变化</div>
- <ul class="hl-list">
- <li v-for="(h, i) in summary.highlights" :key="i">{{ h }}</li>
- </ul>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
- <!-- 分项因子明细 -->
- <section class="section">
- <div class="section-hd">
- <span class="dot"></span>
- <h2>分项因子明细 · 评分对比</h2>
- <span class="meta">{{ allFactors.length }} 项因子 · 雷达对比本期与上期</span>
- </div>
- <div class="card-grid cols-1">
- <div class="card">
- <div class="card-head">
- <div class="title">
- <span class="ic">图</span>
- <span class="title-text">分项因子 · 雷达图(本期 vs 上期)</span>
- </div>
- <div class="acts">
- <span class="meta">满值 10 · 中性 5</span>
- </div>
- </div>
- <div class="card-body">
- <Chart :option="radarOpt" height="380px" />
- </div>
- </div>
- <div class="card" style="margin-top:14px">
- <div class="card-head">
- <div class="title">
- <span class="ic">表</span>
- <span class="title-text">分项因子 · 明细表</span>
- </div>
- <div class="acts">
- <span class="meta">Δ = 本期 − 上期</span>
- </div>
- </div>
- <div class="card-body">
- <div class="table-wrap">
- <table class="score-tbl">
- <thead>
- <tr>
- <th>类别</th>
- <th>指标因子</th>
- <th>指标释义</th>
- <th>评分规则</th>
- <th class="num">权重</th>
- <th class="num">本期</th>
- <th class="num">上期</th>
- <th class="num">Δ</th>
- <th>区间</th>
- </tr>
- </thead>
- <tbody>
- <tr v-for="(f, i) in factorCompare" :key="i">
- <td>
- <span class="cat-pill" :class="f.categoryKey">{{ f.category }}</span>
- </td>
- <td><b>{{ f.name }}</b></td>
- <td class="def">{{ f.definition }}</td>
- <td class="rule">{{ f.rule }}</td>
- <td class="num">{{ f.weight }}%</td>
- <td class="num">
- <span class="score-pill" :class="bandCls(f.current)">{{ f.current }}</span>
- </td>
- <td class="num">{{ f.previous }}</td>
- <td class="num">
- <span :class="['delta', deltaCls(f.delta)]">
- {{ f.delta > 0 ? '+' : '' }}{{ f.delta }}
- </span>
- </td>
- <td>
- <span class="band-tag" :class="bandCls(f.current)">
- {{ classify(f.current).label }}
- </span>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </div>
- </div>
- </div>
- </section>
- <!-- 类别分组详情卡 -->
- <section class="section">
- <div class="section-hd">
- <span class="dot"></span>
- <h2>类别分组 · 子因子快速浏览</h2>
- <span class="meta">点击卡片展开 / 收起</span>
- </div>
- <div class="cat-grid">
- <div
- v-for="cat in categories"
- :key="cat.key"
- class="cat-card"
- :style="{ borderTopColor: cat.color }"
- >
- <div class="cat-head" @click="toggle(cat.key)">
- <div class="cat-title">
- <span class="cat-dot" :style="{ background: cat.color }"></span>
- <span class="cat-name">{{ cat.name }}</span>
- <span class="cat-weight">{{ totalWeight(cat) }}%</span>
- </div>
- <div class="cat-score">
- <span class="cat-score-val" :style="{ color: cat.color }">
- {{ formatScore(catScore(cat.key)) }}
- </span>
- <span class="cat-score-delta">
- <span :class="['arrow', deltaCls(catDelta(cat.key))]">
- {{ catDeltaArrow(cat.key) }}
- </span>
- {{ Math.abs(catDelta(cat.key)).toFixed(2) }}
- </span>
- <span class="cat-toggle">{{ expanded[cat.key] ? '收起' : '展开' }}</span>
- </div>
- </div>
- <div v-show="expanded[cat.key]" class="cat-body">
- <div
- v-for="f in cat.factors"
- :key="f.name"
- class="factor-row"
- >
- <div class="factor-meta">
- <div class="factor-name">
- <span class="factor-name-t">{{ f.name }}</span>
- <span class="factor-w">{{ f.weight }}%</span>
- </div>
- <div class="factor-def">{{ f.definition }}</div>
- <div class="factor-rule">规则:{{ f.rule }}</div>
- </div>
- <div class="factor-score">
- <div class="factor-cur" :class="bandCls(f.current)">
- {{ f.current }}
- </div>
- <div class="factor-prev">{{ f.previous }}</div>
- <div class="factor-bar">
- <div
- class="factor-bar-fill"
- :style="{
- width: (f.current / 10 * 100) + '%',
- background: bandColor(f.current),
- }"
- ></div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </section>
- <footer class="footer">
- 数据源:内部权益部模型 · 4.3.1-美股打分表202609 · 截至 {{ summary.asOf }} · 评分区间 (0,3] 看空 / (3,4] 中性偏空 / (4,6) 中性 / [6,8) 中性偏多 / [8,10) 看多
- </footer>
- </div>
- </template>
- <script setup>
- import { computed, reactive, ref } from 'vue'
- import Chart from '@/components/Chart.vue'
- import {
- scoreSummary,
- categories,
- allFactors,
- categoryWeightedCurrent,
- categoryWeightedPrev,
- factorCompare,
- SCORE_BANDS,
- classifyScore,
- } from './data'
- import {
- scoreGaugeOption,
- categoryBarOption,
- categoryContribOption,
- factorRadarOption,
- } from './charts'
- const loading = ref(false)
- const summary = scoreSummary
- const bands = SCORE_BANDS
- const summaryBand = computed(() => classifyScore(summary.current))
- const summaryCls = computed(() => summaryBand.value.cls)
- const summaryDelta = computed(() => {
- const d = +(summary.current - summary.previous).toFixed(3)
- return {
- arrow: d > 0.005 ? '▲' : (d < -0.005 ? '▼' : '—'),
- text: (d > 0 ? '+' : '') + d.toFixed(2) + ' 分',
- }
- })
- function catScore(key) {
- const c = categoryWeightedCurrent.find((x) => x.key === key)
- return c ? c.score : 0
- }
- function catDelta(key) {
- const cur = categoryWeightedCurrent.find((x) => x.key === key)
- const pre = categoryWeightedPrev.find((x) => x.key === key)
- if (!cur || !pre) return 0
- return +(cur.score - pre.score).toFixed(2)
- }
- function catDeltaArrow(key) {
- const d = catDelta(key)
- return d > 0.005 ? '▲' : (d < -0.005 ? '▼' : '—')
- }
- function totalWeight(cat) {
- return cat.factors.reduce((s, f) => s + f.weight, 0).toFixed(2)
- }
- function formatScore(v) {
- if (v == null) return '—'
- return Number(v).toFixed(2)
- }
- function bandCls(v) {
- return classifyScore(v).cls
- }
- function bandColor(v) {
- return classifyScore(v).axisColor
- }
- function classify(v) {
- return classifyScore(v)
- }
- function deltaCls(d) {
- if (d > 0.005) return 'up'
- if (d < -0.005) return 'down'
- return 'flat'
- }
- const expanded = reactive({
- macro: true,
- profit: true,
- momentum: false,
- })
- function toggle(k) {
- expanded[k] = !expanded[k]
- }
- const gaugeOpt = computed(() => scoreGaugeOption(summary.current, summary.previous))
- const barOpt = computed(() => categoryBarOption(categoryWeightedCurrent, categoryWeightedPrev))
- const contribOpt = computed(() => categoryContribOption(categoryWeightedCurrent))
- const radarOpt = computed(() => factorRadarOption(allFactors))
- function reload() {
- loading.value = true
- setTimeout(() => { loading.value = false }, 600)
- }
- </script>
- <style scoped>
- .us-page {
- padding: 18px 24px 32px;
- color: var(--ink, #1A2438);
- }
- /* === 顶部 === */
- .page-hd {
- display: flex;
- align-items: flex-end;
- justify-content: space-between;
- margin-bottom: 14px;
- flex-wrap: wrap;
- gap: 12px;
- }
- .page-title {
- font-size: 18px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- margin-bottom: 3px;
- }
- .page-sub {
- font-size: 12px;
- color: var(--mut, #6B7A96);
- }
- .page-actions {
- display: flex;
- gap: 8px;
- align-items: center;
- }
- .btn {
- height: 30px;
- padding: 0 14px;
- border: 1px solid var(--line, #E4E9F2);
- border-radius: 6px;
- background: #fff;
- color: var(--ink, #1A2438);
- font-size: 12.5px;
- cursor: pointer;
- display: inline-flex;
- align-items: center;
- gap: 5px;
- transition: 0.15s;
- }
- .btn:hover {
- border-color: var(--brand, #1552D0);
- color: var(--brand, #1552D0);
- }
- .chip {
- display: inline-block;
- padding: 4px 11px;
- border-radius: 12px;
- font-size: 12px;
- font-weight: 600;
- white-space: nowrap;
- }
- .chip.bear { background: #FDEAEA; color: #E13B3B; }
- .chip.mild-bear { background: #FFE9D6; color: #E8912D; }
- .chip.neutral { background: #EEF2F7; color: #6B7A96; }
- .chip.mild-bull { background: #E4F5EE; color: #189A65; }
- .chip.bull { background: #FDEAEA; color: #E13B3B; }
- .ic-refresh {
- display: inline-block;
- transition: transform 0.6s;
- }
- .ic-refresh.spinning { animation: spin 0.8s linear infinite; }
- @keyframes spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
- /* === KPI === */
- .kpi-grid {
- display: grid;
- grid-template-columns: 1.4fr repeat(4, 1fr);
- gap: 10px;
- margin-bottom: 16px;
- }
- .kpi-card {
- background: #fff;
- border: 1px solid var(--line, #E4E9F2);
- border-radius: 8px;
- padding: 13px 14px;
- position: relative;
- transition: 0.15s;
- min-width: 0;
- }
- .kpi-card:hover {
- box-shadow: 0 1px 3px rgba(16, 32, 64, 0.06);
- border-color: #D1D8E5;
- }
- .kpi-card.hero {
- background: linear-gradient(135deg, #0E3A96, #1552D0);
- color: #fff;
- border-color: #0E3A96;
- }
- .kpi-card.hero .label { color: rgba(255,255,255,0.78); }
- .kpi-card.hero .unit { color: rgba(255,255,255,0.7); }
- .kpi-card.hero .chg { color: rgba(255,255,255,0.85); }
- .kpi-card.hero.bear { background: linear-gradient(135deg, #B72828, #E13B3B); border-color: #B72828; }
- .kpi-card.hero.mild-bear { background: linear-gradient(135deg, #B86A1F, #E8912D); border-color: #B86A1F; }
- .kpi-card.hero.neutral { background: linear-gradient(135deg, #4D5A75, #6B7A96); border-color: #4D5A75; }
- .kpi-card.hero.mild-bull { background: linear-gradient(135deg, #13754C, #189A65); border-color: #13754C; }
- .kpi-card.hero.bull { background: linear-gradient(135deg, #B72828, #E13B3B); border-color: #B72828; }
- .kpi-card .label {
- font-size: 11.5px;
- color: var(--mut, #6B7A96);
- margin-bottom: 6px;
- display: flex;
- align-items: center;
- gap: 4px;
- }
- .kpi-card .value {
- font-size: 22px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- font-variant-numeric: tabular-nums;
- letter-spacing: -0.5px;
- line-height: 1.1;
- }
- .kpi-card .value .unit {
- font-size: 12px;
- color: var(--mut, #6B7A96);
- font-weight: 500;
- margin-left: 2px;
- }
- .kpi-card .chg {
- font-size: 11px;
- margin-top: 5px;
- color: var(--mut, #6B7A96);
- font-variant-numeric: tabular-nums;
- display: flex;
- align-items: center;
- gap: 3px;
- }
- .kpi-card .chg .arrow { font-size: 9px; }
- /* === 章节 === */
- .section {
- margin-top: 18px;
- }
- .section-hd {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 12px;
- }
- .section-hd .dot {
- width: 4px;
- height: 18px;
- background: var(--brand, #1552D0);
- border-radius: 2px;
- }
- .section-hd h2 {
- font-size: 14.5px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- margin: 0;
- }
- .section-hd .meta {
- font-size: 11.5px;
- color: #98A5BD;
- margin-left: 8px;
- }
- /* === 卡片网格 === */
- .card-grid {
- display: grid;
- gap: 14px;
- }
- .card-grid.cols-2-1 { grid-template-columns: 2fr 1fr; }
- .card-grid.cols-2-1-1 { grid-template-columns: 1.6fr 1fr 1fr; }
- .card-grid.cols-1-1 { grid-template-columns: 1fr 1fr; }
- .card-grid.cols-1 { grid-template-columns: 1fr; }
- .card-grid.cols-2 { grid-template-columns: 1fr 1fr; }
- .card {
- background: #fff;
- border: 1px solid var(--line, #E4E9F2);
- border-radius: 8px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- }
- .card:hover { box-shadow: 0 1px 3px rgba(16, 32, 64, 0.06); }
- .card-head {
- padding: 11px 16px;
- border-bottom: 1px solid var(--line, #E4E9F2);
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .card-head .title {
- font-size: 13.5px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- display: flex;
- align-items: center;
- gap: 6px;
- flex: 1;
- min-width: 0;
- }
- .card-head .title .ic {
- display: inline-grid;
- place-items: center;
- width: 18px;
- height: 18px;
- background: var(--brand-lt, #EAF1FF);
- color: var(--brand, #1552D0);
- font-size: 10px;
- border-radius: 4px;
- font-weight: 700;
- flex: none;
- }
- .card-head .title-text {
- white-space: nowrap;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- .card-head .acts {
- display: flex;
- align-items: center;
- gap: 6px;
- flex: none;
- font-size: 11px;
- color: var(--mut, #6B7A96);
- }
- .card-body {
- padding: 14px 16px;
- flex: 1;
- min-height: 0;
- }
- /* === 评分区间说明 === */
- .band-list {
- display: flex;
- flex-direction: column;
- gap: 6px;
- margin-bottom: 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, #EAF1FF);
- box-shadow: 0 1px 3px rgba(16,32,64,0.06);
- }
- .band-bar {
- width: 4px;
- height: 18px;
- border-radius: 2px;
- }
- .band-label {
- font-size: 13px;
- font-weight: 600;
- color: var(--ink);
- flex: 1;
- }
- .band-range {
- font-size: 11.5px;
- color: var(--mut, #6B7A96);
- font-variant-numeric: tabular-nums;
- }
- .note {
- padding-top: 12px;
- border-top: 1px dashed var(--line, #E4E9F2);
- font-size: 12px;
- display: flex;
- flex-direction: column;
- gap: 6px;
- }
- .note-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- }
- .note-k {
- color: var(--mut, #6B7A96);
- }
- .note-v {
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- color: var(--ink, #1A2438);
- }
- /* === 评级解读块 === */
- .rating-block {
- display: flex;
- flex-direction: column;
- gap: 10px;
- }
- .rating-row {
- display: flex;
- justify-content: space-between;
- align-items: center;
- font-size: 12.5px;
- padding: 6px 0;
- border-bottom: 1px dashed var(--line, #E4E9F2);
- }
- .rating-row:last-of-type {
- border-bottom: none;
- }
- .r-k {
- color: var(--mut, #6B7A96);
- }
- .r-v {
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- color: var(--ink, #1A2438);
- display: inline-flex;
- align-items: center;
- gap: 6px;
- }
- .r-delta {
- font-size: 11px;
- padding: 1px 6px;
- border-radius: 8px;
- font-weight: 600;
- }
- .r-delta.up { background: #E4F5EE; color: #189A65; }
- .r-delta.down { background: #FDEAEA; color: #E13B3B; }
- .highlight {
- margin-top: 4px;
- padding: 10px 12px;
- background: #FAFBFE;
- border: 1px dashed var(--line, #E4E9F2);
- border-radius: 6px;
- }
- .hl-title {
- font-size: 12px;
- font-weight: 700;
- color: var(--brand, #1552D0);
- margin-bottom: 6px;
- display: flex;
- align-items: center;
- gap: 4px;
- }
- .hl-title::before {
- content: '▸';
- color: var(--brand, #1552D0);
- }
- .hl-list {
- margin: 0;
- padding: 0 0 0 16px;
- font-size: 12px;
- color: var(--ink, #1A2438);
- line-height: 1.7;
- }
- .hl-list li {
- list-style: disc;
- }
- /* === 表格 === */
- .table-wrap {
- overflow-x: auto;
- }
- .score-tbl {
- width: 100%;
- border-collapse: collapse;
- font-size: 12px;
- }
- .score-tbl th,
- .score-tbl td {
- padding: 9px 10px;
- border-bottom: 1px solid var(--line, #E4E9F2);
- text-align: left;
- vertical-align: top;
- }
- .score-tbl th {
- background: #F5F7FB;
- color: var(--mut, #6B7A96);
- font-weight: 600;
- font-size: 11.5px;
- }
- .score-tbl td.num,
- .score-tbl th.num {
- text-align: right;
- font-variant-numeric: tabular-nums;
- white-space: nowrap;
- }
- .score-tbl td.def {
- color: var(--mut, #6B7A96);
- font-size: 11.5px;
- max-width: 280px;
- line-height: 1.5;
- }
- .score-tbl td.rule {
- color: var(--mut, #6B7A96);
- font-size: 11.5px;
- max-width: 260px;
- line-height: 1.5;
- }
- .score-tbl tbody tr:hover {
- background: #FAFBFE;
- }
- .cat-pill {
- display: inline-block;
- padding: 2px 8px;
- border-radius: 9px;
- font-size: 11px;
- font-weight: 600;
- white-space: nowrap;
- }
- .cat-pill.macro { background: #EAF1FF; color: #1552D0; }
- .cat-pill.profit { background: #EAF1FF; color: #0E3A96; }
- .cat-pill.momentum { background: #FDEAEA; color: #E13B3B; }
- .score-pill {
- display: inline-block;
- min-width: 28px;
- padding: 2px 8px;
- border-radius: 4px;
- font-size: 11.5px;
- font-weight: 700;
- text-align: center;
- font-variant-numeric: tabular-nums;
- }
- .score-pill.bear { background: #FDEAEA; color: #E13B3B; }
- .score-pill.mild-bear { background: #FFE9D6; color: #E8912D; }
- .score-pill.neutral { background: #EEF2F7; color: #6B7A96; }
- .score-pill.mild-bull { background: #E4F5EE; color: #189A65; }
- .score-pill.bull { background: #FDEAEA; color: #E13B3B; }
- .delta {
- display: inline-block;
- font-weight: 600;
- font-variant-numeric: tabular-nums;
- }
- .delta.up { color: #189A65; }
- .delta.down { color: #E13B3B; }
- .delta.flat { color: var(--mut, #6B7A96); }
- .band-tag {
- display: inline-block;
- padding: 2px 8px;
- border-radius: 4px;
- font-size: 11px;
- font-weight: 600;
- white-space: nowrap;
- }
- .band-tag.bear { background: #FDEAEA; color: #E13B3B; }
- .band-tag.mild-bear { background: #FFE9D6; color: #E8912D; }
- .band-tag.neutral { background: #EEF2F7; color: #6B7A96; }
- .band-tag.mild-bull { background: #E4F5EE; color: #189A65; }
- .band-tag.bull { background: #FDEAEA; color: #E13B3B; }
- /* === 类别分组卡片 === */
- .cat-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 14px;
- }
- .cat-card {
- background: #fff;
- border: 1px solid var(--line, #E4E9F2);
- border-top: 3px solid var(--brand);
- border-radius: 8px;
- overflow: hidden;
- display: flex;
- flex-direction: column;
- }
- .cat-head {
- padding: 12px 16px;
- display: flex;
- justify-content: space-between;
- align-items: center;
- cursor: pointer;
- user-select: none;
- transition: 0.15s;
- }
- .cat-head:hover { background: #FAFBFE; }
- .cat-title {
- display: flex;
- align-items: center;
- gap: 8px;
- }
- .cat-dot {
- width: 8px;
- height: 8px;
- border-radius: 50%;
- display: inline-block;
- }
- .cat-name {
- font-size: 14px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- }
- .cat-weight {
- font-size: 11px;
- color: var(--mut, #6B7A96);
- background: #F2F5FA;
- padding: 1px 7px;
- border-radius: 8px;
- font-weight: 600;
- }
- .cat-score {
- display: flex;
- align-items: center;
- gap: 10px;
- }
- .cat-score-val {
- font-size: 18px;
- font-weight: 700;
- font-variant-numeric: tabular-nums;
- letter-spacing: -0.5px;
- }
- .cat-score-delta {
- font-size: 11px;
- color: var(--mut, #6B7A96);
- font-variant-numeric: tabular-nums;
- min-width: 50px;
- text-align: right;
- }
- .cat-score-delta .arrow.up { color: #189A65; }
- .cat-score-delta .arrow.down { color: #E13B3B; }
- .cat-score-delta .arrow.flat { color: var(--mut, #6B7A96); }
- .cat-toggle {
- font-size: 11px;
- color: var(--mut, #6B7A96);
- padding-left: 10px;
- border-left: 1px dashed var(--line);
- }
- .cat-body {
- border-top: 1px solid var(--line, #E4E9F2);
- padding: 4px 16px 8px;
- }
- .factor-row {
- display: flex;
- align-items: center;
- gap: 14px;
- padding: 11px 0;
- border-bottom: 1px dashed var(--line, #E4E9F2);
- }
- .factor-row:last-child { border-bottom: none; }
- .factor-meta { flex: 1; min-width: 0; }
- .factor-name {
- display: flex;
- align-items: center;
- gap: 8px;
- margin-bottom: 3px;
- }
- .factor-name-t {
- font-size: 12.5px;
- font-weight: 600;
- color: var(--ink, #1A2438);
- }
- .factor-w {
- font-size: 10.5px;
- color: var(--mut, #6B7A96);
- background: #F2F5FA;
- padding: 1px 6px;
- border-radius: 8px;
- font-weight: 600;
- }
- .factor-def {
- font-size: 11.5px;
- color: var(--mut, #6B7A96);
- line-height: 1.5;
- margin-bottom: 2px;
- }
- .factor-rule {
- font-size: 11px;
- color: #98A5BD;
- line-height: 1.4;
- }
- .factor-score {
- display: flex;
- align-items: center;
- gap: 10px;
- flex: none;
- }
- .factor-cur {
- min-width: 36px;
- height: 36px;
- border-radius: 6px;
- display: inline-grid;
- place-items: center;
- font-size: 16px;
- font-weight: 700;
- font-variant-numeric: tabular-nums;
- border: 1px solid currentColor;
- }
- .factor-cur.bear { color: #E13B3B; background: #FDEAEA; }
- .factor-cur.mild-bear { color: #E8912D; background: #FFE9D6; }
- .factor-cur.neutral { color: #6B7A96; background: #EEF2F7; }
- .factor-cur.mild-bull { color: #189A65; background: #E4F5EE; }
- .factor-cur.bull { color: #E13B3B; background: #FDEAEA; }
- .factor-prev {
- font-size: 11px;
- color: var(--mut, #6B7A96);
- font-variant-numeric: tabular-nums;
- min-width: 24px;
- text-align: center;
- }
- .factor-bar {
- width: 80px;
- height: 6px;
- background: #F2F5FA;
- border-radius: 3px;
- overflow: hidden;
- }
- .factor-bar-fill {
- height: 100%;
- border-radius: 3px;
- transition: width 0.6s;
- }
- .footer {
- padding: 18px 24px 12px;
- color: #98A5BD;
- font-size: 11.5px;
- text-align: center;
- border-top: 1px solid var(--line, #E4E9F2);
- background: #FAFBFE;
- margin-top: 14px;
- border-radius: 8px;
- }
- @media (max-width: 1280px) {
- .kpi-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
- .kpi-card.hero { grid-column: span 2; }
- }
- @media (max-width: 980px) {
- .kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
- .kpi-card.hero { grid-column: span 2; }
- .card-grid.cols-2-1,
- .card-grid.cols-2-1-1,
- .card-grid.cols-1-2,
- .card-grid.cols-1-1,
- .card-grid.cols-2 { grid-template-columns: 1fr; }
- .cat-grid { grid-template-columns: 1fr; }
- }
- </style>
|