feat(ux): F3 流式进度感 + F4 友好错误文案(纯前端)

F4:新 lib/errors/messages.ts —— friendlyError(code, fallback) 把错误码映射为
中文文案 + 可选「去设置提供商」动作;覆盖后端 ErrorCode + 前端 NETWORK/
STREAM_FAILED;未知码回退原 message。写作页与审稿页错误块改用之,不再暴露
raw error code。+4 vitest。

F3:写作页工具条字数计数器流式时显示「生成中… N 字」+ 朱砂脉冲
(motion-safe:animate-pulse,尊重 prefers-reduced-motion),停后回「字数 N」。
纯 text.length,无后端改动。

前端门禁绿:lint/typecheck/vitest 171/build。无契约变更。
This commit is contained in:
Yaojia Wang
2026-06-20 11:02:27 +02:00
parent 8058cfb11a
commit b18310bcb7
6 changed files with 139 additions and 24 deletions

View File

@@ -4,6 +4,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { AppShell } from "@/components/AppShell";
import type { ProjectResponse, ReviewHistoryItem } from "@/lib/api/types";
import { friendlyError } from "@/lib/errors/messages";
import {
allResolved,
emptyDecisions,
@@ -226,21 +227,7 @@ export function ReviewReport({
</div>
{review.state.error ? (
<p className="border-b border-line bg-panel px-6 py-2 text-sm text-conflict">
稿{review.state.error.code}
{review.state.error.message}
{review.state.error.code === "LLM_UNAVAILABLE" ? (
<>
{" "}
<a
href="/settings/providers"
className="underline hover:text-cinnabar"
>
</a>
</>
) : null}
</p>
<ReviewErrorNote error={review.state.error} />
) : null}
<div className="flex-1 overflow-auto px-6 py-6">
@@ -346,6 +333,31 @@ export function ReviewReport({
);
}
// 审稿失败提示:友好文案(不暴露 raw code+ 可选「去设置」动作F4
function ReviewErrorNote({
error,
}: {
error: { code: string; message: string };
}) {
const friendly = friendlyError(error.code, error.message);
return (
<p className="border-b border-line bg-panel px-6 py-2 text-sm text-conflict">
{friendly.text}
{friendly.actionHref ? (
<>
{" "}
<a
href={friendly.actionHref}
className="underline hover:text-cinnabar"
>
{friendly.actionLabel}
</a>
</>
) : null}
</p>
);
}
interface SectionStatusLineProps {
reviewing: boolean;
done: boolean;