feat(web): distinguish change-report narrative vs factual fields
Panel and view-model label server risk/lineage separately from PI narrative; add change_report_narrative_v1 helper aligned with typed-result patterns. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -89,53 +89,82 @@ export function ChangeReportPanel(props: {
|
||||
<span style={{ marginLeft: 6, opacity: 0.75 }}>({vm.analysisNote})</span>
|
||||
) : null}
|
||||
</p>
|
||||
<h4>摘要</h4>
|
||||
<ul data-testid="change-report-summary">
|
||||
{vm.summary.length === 0 ? <li style={{ opacity: 0.7 }}>(无摘要)</li> : null}
|
||||
{vm.summary.map((s) => (
|
||||
<li key={s}>{s}</li>
|
||||
))}
|
||||
</ul>
|
||||
<h4>风险条目</h4>
|
||||
<ul data-testid="change-report-risk-items">
|
||||
{vm.riskItems.length === 0 ? <li style={{ opacity: 0.7 }}>(无风险条目)</li> : null}
|
||||
{vm.riskItems.map((it, i) => (
|
||||
<li key={`${it.category}-${i}`}>
|
||||
<strong>{it.category || '风险'}</strong>:{it.description}
|
||||
{it.mitigation ? <div style={{ opacity: 0.85 }}>缓解:{it.mitigation}</div> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<h4>项目影响</h4>
|
||||
<ul data-testid="change-report-project-impact">
|
||||
{vm.projectImpactLines.length === 0 ? <li style={{ opacity: 0.7 }}>(无项目影响说明)</li> : null}
|
||||
{vm.projectImpactLines.map((line) => (
|
||||
<li key={line}>{line}</li>
|
||||
))}
|
||||
</ul>
|
||||
<h4>文档影响</h4>
|
||||
<ul data-testid="change-report-doc-impacts">
|
||||
{vm.documentImpacts.length === 0 ? (
|
||||
<li style={{ opacity: 0.7 }}>无(或尚未登记下游 lineage)</li>
|
||||
) : null}
|
||||
{vm.documentImpacts.map((d) => (
|
||||
<li key={`${d.docId}-${d.impactType}`}>
|
||||
<strong>{d.docId}</strong>
|
||||
{d.impactType ? ` [${d.impactType}]` : ''}
|
||||
{d.reason ? `:${d.reason}` : ''}
|
||||
{d.recommendedAction ? (
|
||||
<div style={{ opacity: 0.85 }}>建议:{d.recommendedAction}</div>
|
||||
) : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<h4>开放问题</h4>
|
||||
<ul data-testid="change-report-open-questions">
|
||||
{vm.openQuestions.length === 0 ? <li style={{ opacity: 0.7 }}>(无开放问题)</li> : null}
|
||||
{vm.openQuestions.map((q) => (
|
||||
<li key={q}>{q}</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
<section data-testid="change-report-factual" aria-label="事实字段">
|
||||
<h4>事实字段(服务端)</h4>
|
||||
<p style={{ margin: '0 0 8px', fontSize: 13, opacity: 0.85 }}>
|
||||
风险等级与文档影响由服务端 diff + lineage 计算,PI 不可覆盖审批结论。
|
||||
</p>
|
||||
<ul data-testid="change-report-factual-notes">
|
||||
{vm.factualNotes.length === 0 ? (
|
||||
<li style={{ opacity: 0.7 }}>风险:{vm.riskLevel || '(未评估)'}</li>
|
||||
) : null}
|
||||
{vm.factualNotes.map((n) => (
|
||||
<li key={n}>{n}</li>
|
||||
))}
|
||||
</ul>
|
||||
<h5 style={{ marginBottom: 4 }}>文档影响</h5>
|
||||
<ul data-testid="change-report-doc-impacts">
|
||||
{vm.documentImpacts.length === 0 ? (
|
||||
<li style={{ opacity: 0.7 }}>无(或尚未登记下游 lineage)</li>
|
||||
) : null}
|
||||
{vm.documentImpacts.map((d) => (
|
||||
<li key={`${d.docId}-${d.impactType}`}>
|
||||
<strong>{d.docId}</strong>
|
||||
{d.impactType ? ` [${d.impactType}]` : ''}
|
||||
{d.reason ? `:${d.reason}` : ''}
|
||||
{d.recommendedAction ? (
|
||||
<div style={{ opacity: 0.85 }}>建议:{d.recommendedAction}</div>
|
||||
) : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section data-testid="change-report-narrative" aria-label="叙事字段">
|
||||
<h4>
|
||||
叙事字段({vm.narrativeSourceLabel})
|
||||
<span
|
||||
data-testid="change-report-narrative-source"
|
||||
style={{ marginLeft: 8, fontSize: 12, fontWeight: 400, opacity: 0.75 }}
|
||||
>
|
||||
{vm.isNarrativeComplete ? 'PI' : 'fallback'}
|
||||
</span>
|
||||
</h4>
|
||||
<h5 style={{ marginBottom: 4 }}>摘要</h5>
|
||||
<ul data-testid="change-report-summary">
|
||||
{vm.summary.length === 0 ? <li style={{ opacity: 0.7 }}>(无摘要)</li> : null}
|
||||
{vm.summary.map((s) => (
|
||||
<li key={s}>{s}</li>
|
||||
))}
|
||||
</ul>
|
||||
<h5 style={{ marginBottom: 4 }}>风险条目(说明性)</h5>
|
||||
<ul data-testid="change-report-risk-items">
|
||||
{vm.riskItems.length === 0 ? <li style={{ opacity: 0.7 }}>(无风险条目)</li> : null}
|
||||
{vm.riskItems.map((it, i) => (
|
||||
<li key={`${it.category}-${i}`}>
|
||||
<strong>{it.category || '风险'}</strong>:{it.description}
|
||||
{it.mitigation ? <div style={{ opacity: 0.85 }}>缓解:{it.mitigation}</div> : null}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
<h5 style={{ marginBottom: 4 }}>项目影响</h5>
|
||||
<ul data-testid="change-report-project-impact">
|
||||
{vm.projectImpactLines.length === 0 ? (
|
||||
<li style={{ opacity: 0.7 }}>(无项目影响说明)</li>
|
||||
) : null}
|
||||
{vm.projectImpactLines.map((line) => (
|
||||
<li key={line}>{line}</li>
|
||||
))}
|
||||
</ul>
|
||||
<h5 style={{ marginBottom: 4 }}>开放问题</h5>
|
||||
<ul data-testid="change-report-open-questions">
|
||||
{vm.openQuestions.length === 0 ? <li style={{ opacity: 0.7 }}>(无开放问题)</li> : null}
|
||||
{vm.openQuestions.map((q) => (
|
||||
<li key={q}>{q}</li>
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
</>
|
||||
) : null}
|
||||
{props.pendingDecision ? (
|
||||
|
||||
Reference in New Issue
Block a user