feat(frontend): 工厂看板因子名副行展示出生 description [vps]

This commit is contained in:
2026-10-09 19:57:39 +08:00
parent 2b9186b6d6
commit 8d009dc233
4 changed files with 27 additions and 5 deletions
+2
View File
@@ -46,6 +46,7 @@ export interface PipelineFactor {
status: FactorStatus
origin?: string // D7 件②:decomposer/manual 身份戳
hypothesis?: string | null // 来源假设卡回链血统
description?: string // 2026-10-09:出生一句话自述(看板副行)
icRecentT: number | null
icFullT: number | null
promotedAtT: number | null
@@ -180,6 +181,7 @@ export interface FactorDetail {
status: string
origin: string
hypothesis: string | null
description?: string // 2026-10-09:出生一句话自述(档案行)
expression: string | null
source: string | null
justification: string | null
+4 -4
View File
@@ -32,13 +32,13 @@ export const factorsMock: PipelineFactor[] = [
{ id: 'growth', category: 'fundamental', version: 'v1', status: 'promoted', icRecentT: 1.8, icFullT: 2.1, promotedAtT: 2.4, decayMonths: 1, lastEvalDate: '2026-10-04' },
{ id: 'div_yield', category: 'fundamental', version: 'v1', status: 'promoted', icRecentT: 2.0, icFullT: 1.8, promotedAtT: 2.0, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'size', category: 'fundamental', version: 'v1', status: 'promoted', icRecentT: 2.2, icFullT: 2.5, promotedAtT: 2.2, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'pledge_net_chg', category: 'pledge', version: 'v1', status: 'promoted', icRecentT: 3.2, icFullT: 2.1, promotedAtT: 4.01, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'pledge_net_chg', description: '质押比例净变动,量度大股东资金压力', category: 'pledge', version: 'v1', status: 'promoted', icRecentT: 3.2, icFullT: 2.1, promotedAtT: 4.01, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'res_target_upside', category: 'research', version: 'v1', status: 'promoted', icRecentT: 2.8, icFullT: 2.03, promotedAtT: 3.05, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'momentum_20d', category: 'technical', version: 'v2', status: 'promoted', icRecentT: 3.0, icFullT: 2.8, promotedAtT: 3.0, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'fa_gross_margin', category: 'fundamental', version: 'v1', status: 'decaying', icRecentT: 1.1, icFullT: 1.8, promotedAtT: 2.3, decayMonths: 3, lastEvalDate: '2026-10-04' },
{ id: 'momentum_20d', description: '20 日收盘价动量,量度股价短期延续性', category: 'technical', version: 'v2', status: 'promoted', icRecentT: 3.0, icFullT: 2.8, promotedAtT: 3.0, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'fa_gross_margin', description: '毛利率同比变动,盈利质量的核心量度', category: 'fundamental', version: 'v1', status: 'decaying', icRecentT: 1.1, icFullT: 1.8, promotedAtT: 2.3, decayMonths: 3, lastEvalDate: '2026-10-04' },
{ id: 'D16_peg', category: 'fundamental', version: 'v1', status: 'assessable', icRecentT: 2.4, icFullT: 2.1, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'D17_ps', category: 'fundamental', version: 'v1', status: 'assessable', icRecentT: 1.9, icFullT: 1.6, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'S01_sentiment_pos', category: 'sentiment', version: 'v1', status: 'incubating', icRecentT: null, icFullT: null, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'S01_sentiment_pos', description: '正面情绪占比,新闻语料的乐观程度量度', category: 'sentiment', version: 'v1', status: 'incubating', icRecentT: null, icFullT: null, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'S02_sentiment_neg', category: 'sentiment', version: 'v1', status: 'incubating', icRecentT: null, icFullT: null, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-10-04' },
{ id: 'res_fwd_ep', category: 'research', version: 'v1', status: 'retired', icRecentT: -0.4, icFullT: -0.2, promotedAtT: null, decayMonths: 0, lastEvalDate: '2026-09-22' },
]
@@ -44,4 +44,16 @@ describe('FactorFactory.vue', () => {
// IC 趋势卡退役:点击进详情,详情页有同款图
expect(w.text()).not.toContain('IC 趋势')
})
it('因子名下副行渲染 description(无则不渲染副行)', async () => {
const w = mount(FactorFactory, { global: { plugins: [ElementPlus] } })
await flushPromises()
const rows = w.findAll('.factor-cell')
expect(rows.length).toBe(factorsMock.length)
const withDesc = rows.filter((r) => r.find('.desc-line').exists())
expect(withDesc.length).toBe(factorsMock.filter((f) => f.description).length)
// 每条 mock description 都出现在某行副行(集合比较,组件按状态重排序)
for (const d of factorsMock.filter((f) => f.description)) {
expect(withDesc.some((r) => r.text().includes(d.description!))).toBe(true)
}
})
})
@@ -50,7 +50,12 @@ const fmt = (v: number | null): string => (v === null ? '—' : v.toFixed(2))
<PanelCard title="因子注册表" sub="衰减态置顶 · 版本化血统 · 点行进出生档案">
<el-table :data="sorted" size="small" @row-click="(r: PipelineFactor) => router.push(`/pipeline/factors/${r.id}`)">
<el-table-column prop="id" label="因子" min-width="230">
<template #default="{ row }"><span class="mono">{{ row.id }}</span>@{{ row.version }}</template>
<template #default="{ row }">
<div class="factor-cell">
<span><span class="mono">{{ row.id }}</span>@{{ row.version }}</span>
<div v-if="row.description" class="desc-line">{{ row.description }}</div>
</div>
</template>
</el-table-column>
<el-table-column prop="category" label="域" width="90" />
<!-- D7 件②:origin 身份戳+来源卡回链(⚡=AI 分解注册/✍=人工注册) -->
@@ -110,6 +115,9 @@ const fmt = (v: number | null): string => (v === null ? '—' : v.toFixed(2))
.th-h { display: inline-flex; align-items: center; gap: 3px; }
.th-h .q { font-size: 11px; color: var(--text-3); cursor: help; border: 1px solid var(--border); border-radius: 50%; width: 14px; height: 14px; line-height: 12px; text-align: center; flex: none; }
.th-h .q:hover { color: var(--brand); border-color: var(--cyan-dim); }
/* 2026-10-09:因子名下出生自述副行 */
.factor-cell { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 2px 0; }
.desc-line { font-size: 10.5px; color: var(--text-3); line-height: 1.4; }
/* D7 件②:origin 徽标+回链 */
.ob { display: inline-flex; align-items: center; font-size: 10.5px; border-radius: 5px; padding: 0 6px; line-height: 17px; white-space: nowrap; }
.ob.dec { color: var(--brand); border: 1px solid rgba(0, 229, 255, 0.45); background: var(--cyan-soft); }