diff --git a/frontend/src/components/TrustCenterView.vue b/frontend/src/components/TrustCenterView.vue index b8e8a33..561a418 100644 --- a/frontend/src/components/TrustCenterView.vue +++ b/frontend/src/components/TrustCenterView.vue @@ -3,18 +3,25 @@

Trust Operations

-

信任运营中心

-

把 AI 推断、证据路径、open loop 和审查历史放在一个可操作的工作台里。

+

信任工作台

+

先处理高风险判断,证据、open loop 和诊断按需展开。

-
-
- {{ metric.label }} - {{ metric.value }} - {{ metric.caption }} -
+
+
+ 今日焦点 +

{{ focusHeadline }}

+

{{ focusCaption }}

+
+
+
+ {{ metric.label }} + {{ metric.value }} + {{ metric.caption }} +
+
() -const metrics = computed(() => [ +const urgentReviewCount = computed(() => props.review.summary.critical + props.review.summary.high) + +const focusHeadline = computed(() => { + if (props.review.summary.critical) { + return `先确认 ${props.review.summary.critical} 条 critical 推断` + } + if (props.review.summary.high) { + return `先扫完 ${props.review.summary.high} 条高风险判断` + } + if (props.openLoops.summary.total) { + return `把 ${props.openLoops.summary.total} 个 open loop 变成下一步` + } + return '当前没有高压审查项' +}) + +const focusCaption = computed(() => { + if (urgentReviewCount.value) { + return '默认只展示最能帮助你做决定的信息;需要证据、历史和诊断时再展开。' + } + if (props.review.summary.unreviewed) { + return '剩余项目风险较低,可以按空间或关键词慢慢清理,不需要一次看完所有细节。' + } + return '信任边界已经比较干净,后续重点是继续沉淀用户确认过的理由。' +}) + +const compactMetrics = computed(() => [ { - label: 'critical', - value: props.review.summary.critical, - caption: '必须先判断的 AI 推断', + label: '需判断', + value: props.review.summary.unreviewed, + caption: `${urgentReviewCount.value} 条高优先级`, tone: 'tone-critical', }, { - label: 'high', - value: props.review.summary.high, - caption: '高风险证据或未审查项', + label: 'AI 推断', + value: props.review.summary.ai_inferred, + caption: `${props.review.summary.user_stated} 条用户原话`, tone: 'tone-high', }, { - label: 'open loops', + label: 'open loop', value: props.openLoops.summary.total, - caption: '还没有闭环的问题', + caption: `${props.openLoops.summary.by_state.next || 0} 个下一步`, tone: 'tone-loop', }, { - label: 'history', + label: '已审查', value: props.diagnostics?.history_count || 0, - caption: '已经写入的审查记录', + caption: '可追溯记录', tone: 'tone-history', }, ]) diff --git a/frontend/src/components/TrustDiagnosticsPanel.vue b/frontend/src/components/TrustDiagnosticsPanel.vue index 81d9e7a..daad284 100644 --- a/frontend/src/components/TrustDiagnosticsPanel.vue +++ b/frontend/src/components/TrustDiagnosticsPanel.vue @@ -8,6 +8,8 @@ {{ diagnostics?.queue_total || 0 }} +

{{ diagnosticsSummary }}

+
AI 未审查 @@ -27,17 +29,39 @@
-
-

{{ warning }}

-

没有诊断警告。

-
+
+ + 诊断警告 + {{ diagnostics?.warnings.length || 0 }} 条 + +
+

{{ warning }}

+

没有诊断警告。

+
+
diff --git a/frontend/src/components/TrustOpenLoopPanel.vue b/frontend/src/components/TrustOpenLoopPanel.vue index aaffa0c..315fd06 100644 --- a/frontend/src/components/TrustOpenLoopPanel.vue +++ b/frontend/src/components/TrustOpenLoopPanel.vue @@ -16,7 +16,7 @@
-
+
{{ loop.state }} {{ loop.text }} @@ -29,16 +29,19 @@
+

+ 还有 {{ overflowCount }} 个 open loop 已收起,先处理上面这些更高价值的问题。 +

当前没有 open-loop。

diff --git a/frontend/src/components/TrustReviewInbox.vue b/frontend/src/components/TrustReviewInbox.vue index a442450..0ce8c2b 100644 --- a/frontend/src/components/TrustReviewInbox.vue +++ b/frontend/src/components/TrustReviewInbox.vue @@ -3,7 +3,7 @@
Review Inbox -

AI 推断审查队列

+

待判断

{{ items.length }} 条
@@ -48,13 +48,16 @@ -
- {{ item.why_saved_status }} - {{ item.space_name }} - {{ Math.round(item.confidence * 100) }}% - {{ item.open_loops.length }} open loop +
+ {{ actionHint(item) }} +
+
+ {{ boundaryLabel(item.why_saved_status) }} + {{ item.space_name || '未分配空间' }} + 可信度 {{ Math.round(item.confidence * 100) }}% + {{ item.open_loops.length }} 个 open loop

当前筛选下没有待审查项。

@@ -108,4 +111,22 @@ function riskLabel(level: TrustRiskLevel) { if (level === 'medium') return 'medium' return 'low' } + +function compactReason(item: TrustReviewItem) { + const text = item.why_saved || item.summary || '这条材料还没有稳定的保存理由。' + return text.length > 108 ? `${text.slice(0, 108)}...` : text +} + +function boundaryLabel(status: string) { + if (status === 'user-stated') return '用户原话' + if (status === 'AI-inferred') return 'AI 推断' + return status || '边界未知' +} + +function actionHint(item: TrustReviewItem) { + if (item.risk_level === 'critical') return '建议现在处理:确认、改写或拒绝这条推断。' + if (item.risk_level === 'high') return '建议优先扫一眼证据,再决定是否确认。' + if (item.open_loops.length) return '可以转成下一步,避免问题继续悬空。' + return item.recommended_action || '低压力项目,可以稍后批量处理。' +} diff --git a/frontend/src/styles.css b/frontend/src/styles.css index 649f8b4..032c0fa 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -7032,6 +7032,11 @@ button:not(:disabled):hover { padding-bottom: 14px; } +.trust-center-header .paper-button { + flex: 0 0 auto; + white-space: nowrap; +} + .trust-center-header h1 { margin: 3px 0 5px; font-family: var(--snap-title); @@ -7053,6 +7058,57 @@ button:not(:disabled):hover { gap: 10px; } +.trust-focus-strip { + display: grid; + grid-template-columns: minmax(300px, 1fr) minmax(420px, 1.1fr); + gap: 12px; + align-items: stretch; + border: 1px solid rgba(44, 53, 68, 0.12); + border-radius: 8px; + background: linear-gradient(135deg, rgba(250, 250, 246, 0.96), rgba(241, 246, 244, 0.9)); + padding: 12px; +} + +.trust-focus-primary { + display: grid; + align-content: center; + gap: 6px; + min-width: 0; +} + +.trust-focus-primary h2 { + margin: 0; + font-family: var(--snap-title); + font-size: clamp(1.18rem, 1.7vw, 1.6rem); + font-weight: 560; + letter-spacing: 0; +} + +.trust-focus-primary p, +.trust-diagnostics-summary, +.trust-loop-overflow-note { + margin: 0; + color: var(--muted-foreground); + line-height: 1.5; +} + +.trust-focus-stats { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 8px; +} + +.trust-focus-stats article { + border: 1px solid rgba(44, 53, 68, 0.1); + border-radius: 8px; + background: rgba(255, 255, 255, 0.72); + padding: 10px; + display: grid; + gap: 4px; + align-content: start; + min-width: 0; +} + .trust-summary-grid article { min-height: 96px; border: 1px solid var(--line); @@ -7065,7 +7121,10 @@ button:not(:disabled):hover { } .trust-summary-grid span, +.trust-focus-stats span, .trust-batch-bar span, +.trust-detail-brief span, +.trust-detail-disclosure summary span, .trust-detail-section > span, .trust-diagnostics-grid span, .trust-loop-state-grid span { @@ -7075,12 +7134,14 @@ button:not(:disabled):hover { letter-spacing: 0.04em; } -.trust-summary-grid strong { +.trust-summary-grid strong, +.trust-focus-stats strong { font-size: 1.55rem; line-height: 1; } -.trust-summary-grid small { +.trust-summary-grid small, +.trust-focus-stats small { color: var(--muted-foreground); line-height: 1.35; } @@ -7130,6 +7191,9 @@ button:not(:disabled):hover { .trust-filter-row select, .trust-loop-actions input, .trust-detail-actions textarea { + width: 100%; + min-width: 0; + box-sizing: border-box; min-height: 34px; border: 1px solid var(--line); border-radius: 8px; @@ -7242,15 +7306,24 @@ button:not(:disabled):hover { } .trust-select-line, -.trust-review-meta { +.trust-review-meta, +.trust-review-compact-meta { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; } +.trust-batch-actions > *, +.trust-detail-button-row > *, +.trust-loop-actions > *, +.trust-filter-row > * { + min-width: 0; +} + .trust-select-line small, -.trust-review-meta span { +.trust-review-meta span, +.trust-review-compact-meta span { border: 1px solid var(--line); border-radius: 999px; padding: 3px 7px; @@ -7281,6 +7354,19 @@ button:not(:disabled):hover { margin: 0; color: var(--muted-foreground); line-height: 1.45; + overflow-wrap: anywhere; +} + +.trust-review-action-hint { + border-left: 3px solid rgba(58, 105, 97, 0.4); + color: var(--foreground); + font-size: 0.86rem; + line-height: 1.4; + padding-left: 8px; +} + +.trust-review-compact-meta { + gap: 6px; } .trust-detail-panel { @@ -7288,6 +7374,60 @@ button:not(:disabled):hover { top: 14px; } +.trust-detail-brief { + display: grid; + gap: 8px; + border: 1px solid rgba(44, 53, 68, 0.1); + border-radius: 8px; + background: color-mix(in srgb, #f8faf8 78%, white); + padding: 11px; +} + +.trust-detail-brief > div:first-child { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 10px; + flex-wrap: wrap; +} + +.trust-detail-brief strong { + font-size: 0.95rem; +} + +.trust-detail-brief p { + margin: 0; + color: var(--foreground); + line-height: 1.5; +} + +.trust-detail-disclosure { + border-top: 1px solid var(--line); + margin-top: 10px; + padding-top: 8px; +} + +.trust-detail-disclosure summary { + cursor: pointer; + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + list-style-position: inside; +} + +.trust-detail-disclosure summary strong { + color: var(--foreground); + font-size: 0.84rem; +} + +.trust-detail-disclosure .trust-detail-section, +.trust-detail-disclosure .trust-warning-list { + border-top: 0; + margin-top: 8px; + padding-top: 0; +} + .trust-detail-section { border-top: 1px solid var(--line); padding-top: 10px; @@ -7310,6 +7450,8 @@ button:not(:disabled):hover { border-radius: 8px; background: color-mix(in srgb, var(--background) 86%, white); padding: 9px; + min-width: 0; + overflow-wrap: anywhere; } .trust-loop-state-grid, @@ -7333,6 +7475,10 @@ button:not(:disabled):hover { font-size: 1.12rem; } +.trust-diagnostics-summary { + margin-bottom: 10px; +} + .trust-open-loop-card { display: grid; grid-template-columns: minmax(0, 1fr); @@ -7344,6 +7490,13 @@ button:not(:disabled):hover { margin: 4px 0; } +.trust-loop-overflow-note { + border: 1px dashed rgba(44, 53, 68, 0.18); + border-radius: 8px; + padding: 9px; + background: rgba(250, 250, 246, 0.68); +} + .trust-empty { color: var(--muted-foreground); margin: 0; @@ -7351,6 +7504,7 @@ button:not(:disabled):hover { @media (max-width: 980px) { .trust-summary-grid, + .trust-focus-strip, .trust-workbench-grid, .trust-secondary-grid, .trust-filter-row, @@ -7361,6 +7515,34 @@ button:not(:disabled):hover { .trust-detail-panel { position: static; } + + .trust-focus-stats { + grid-template-columns: repeat(auto-fit, minmax(70px, 1fr)); + } + + .trust-loop-state-grid, + .trust-diagnostics-grid { + grid-template-columns: repeat(auto-fit, minmax(68px, 1fr)); + } +} + +@media (max-width: 560px) { + .trust-center-header { + flex-direction: column; + align-items: stretch; + } + + .trust-center-header .paper-button { + align-self: flex-start; + } + + .trust-batch-actions, + .trust-detail-button-row, + .trust-loop-actions { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(58px, 1fr)); + width: 100%; + } } .recall-result-desk { diff --git a/tests/trust_operations_ui.test.ts b/tests/trust_operations_ui.test.ts index 222b83e..30ba720 100644 --- a/tests/trust_operations_ui.test.ts +++ b/tests/trust_operations_ui.test.ts @@ -69,3 +69,31 @@ test('Trust Center components expose review operations, evidence, open loops, an assert.match(styles, /\.trust-filter-row input\s*{[\s\S]*grid-column: 1 \/ -1/) assert.match(styles, /\.trust-filter-row \.ghost-button\s*{[\s\S]*white-space: nowrap/) }) + +test('Trust Center reduces information pressure with compact focus and progressive disclosure', () => { + const view = read('frontend/src/components/TrustCenterView.vue') + const inbox = read('frontend/src/components/TrustReviewInbox.vue') + const detail = read('frontend/src/components/TrustReviewDetail.vue') + const diagnostics = read('frontend/src/components/TrustDiagnosticsPanel.vue') + const loops = read('frontend/src/components/TrustOpenLoopPanel.vue') + const styles = read('frontend/src/styles.css') + + assert.match(view, /trust-focus-strip/) + assert.match(view, /trust-focus-primary/) + assert.match(view, /focusHeadline/) + assert.match(view, /trust-focus-stats/) + assert.match(view, /compactMetrics/) + assert.match(inbox, /trust-review-compact-meta/) + assert.match(inbox, /trust-review-action-hint/) + assert.match(detail, /trust-detail-brief/) + assert.match(detail, /trust-detail-disclosure/) + assert.match(detail, /