容错处理

This commit is contained in:
董宏凯 committed 2026-05-18 11:29:40 +08:00
1 parent 0af8ca5f78
commit 836dd73446
6 files changed
+79 -17

No files matched your search

@@ -46,8 +46,14 @@ function MaterialCompleted({ record, expanded, onToggle }: { record: CompletedIn
<CheckCircle2 className="size-3.5 text-green-500 shrink-0" />
<FileText className="size-3.5 text-blue-500 shrink-0" />
<span className="flex-1 font-medium">
已确认{' '}
<span className="text-muted-foreground font-normal">{count} 条素材</span>
{count === 0 && record.action !== 're_search' ? (
'已在无素材的情况下继续写作'
) : (
<>
已确认{' '}
<span className="text-muted-foreground font-normal">{count} 条素材</span>
</>
)}
</span>
{count > 0 && (
expanded
@@ -118,6 +118,50 @@ function MaterialConfirmCard({ materials, onSubmit, disabled }: MaterialConfirmC
const hasExtra = extraKeywords.length > 0;
// 空数据态:未检索到任何素材,提示用户重新搜索或在无素材情况下继续
if (materials.length === 0) {
return (
<div className="rounded-md border border-amber-200 bg-amber-50/50 dark:border-amber-900/40 dark:bg-amber-950/20 space-y-3 p-3">
<div className="flex items-start gap-2">
<ShieldAlert className="size-4 text-amber-500 shrink-0 mt-0.5" />
<div>
<p className="text-xs font-medium">未检索到任何素材</p>
<p className="text-xs text-muted-foreground mt-0.5">
素材收集专家本次没有检索到相关数据。你可以补充关键词重新搜索,或在无素材的情况下直接继续写作(文章将仅依据写作意图生成)。
</p>
</div>
</div>
<MaterialsToolbar
materials={materials}
selectedIds={selectedIds}
onSelectAll={() => setSelectedIds(new Set())}
onDeselectAll={() => setSelectedIds(new Set())}
extraKeywords={extraKeywords}
onAddKeyword={(kw) => setExtraKeywords((prev) => [...prev, kw])}
onRemoveKeyword={(kw) => setExtraKeywords((prev) => prev.filter((k) => k !== kw))}
/>
<div className="flex gap-2 pt-1">
<Button
type="button" size="sm" className="flex-1 h-8 text-xs gap-1.5"
onClick={handleReSearch} disabled={disabled || submitting}
>
{hasExtra
? <><Search className="size-3.5" />追加搜索</>
: <><RotateCcw className="size-3.5" />重新搜索</>}
</Button>
<Button
type="button" variant="outline" size="sm" className="h-8 text-xs gap-1.5 shrink-0"
onClick={handleConfirm} disabled={disabled || submitting}
>
<ArrowRight className="size-3.5" />无数据继续写作
</Button>
</div>
</div>
);
}
return (
<div className="rounded-md border bg-background space-y-3 p-3">
<div className="flex items-start gap-2">
@@ -34,20 +34,22 @@ export function MaterialsToolbar({
return (
<div className="space-y-2">
{/* 全选/取消 */}
<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground">
已选 {selectedIds.size} / {materials.length} 条素材
</span>
<div className="flex-1" />
<button
type="button"
onClick={allSelected ? onDeselectAll : onSelectAll}
className="text-xs text-primary hover:underline"
>
{allSelected ? '取消全选' : '全选'}
</button>
</div>
{/* 全选/取消(无素材时隐藏) */}
{materials.length > 0 && (
<div className="flex items-center gap-2">
<span className="text-xs text-muted-foreground">
已选 {selectedIds.size} / {materials.length} 条素材
</span>
<div className="flex-1" />
<button
type="button"
onClick={allSelected ? onDeselectAll : onSelectAll}
className="text-xs text-primary hover:underline"
>
{allSelected ? '取消全选' : '全选'}
</button>
</div>
)}
{/* 补充关键词 */}
<div className="space-y-1.5">
@@ -204,7 +204,7 @@ export function TextArtifactRenderer({ content, isStreaming }: TextArtifactRende
</h3>
),
p: ({ children }) => (
<p className="mb-4 leading-[1.8] text-[15px] text-foreground">
<p className="mb-4 leading-[1.8] text-[15px] text-foreground indent-[2em]">
{children}
</p>
),
+6
View File
@@ -579,6 +579,7 @@
line-height: 1.8;
font-size: 0.9375rem; /* 15px */
color: var(--foreground);
text-indent: 2em; /* 段落首行缩进 */
}
.tiptap-writing-editor .ProseMirror h1 {
@@ -658,6 +659,7 @@
.tiptap-writing-editor .ProseMirror li > p {
margin-bottom: 0.25rem;
text-indent: 0; /* 列表项内段落不缩进 */
}
.tiptap-writing-editor .ProseMirror blockquote {
@@ -716,6 +718,10 @@
}
/* Placeholder */
.tiptap-writing-editor .ProseMirror p.is-editor-empty:first-child {
text-indent: 0; /* 占位文案不缩进 */
}
.tiptap-writing-editor .ProseMirror p.is-editor-empty:first-child::before {
content: attr(data-placeholder);
color: var(--muted-foreground);
@@ -140,6 +140,10 @@ async def researcher_node(state: AIWritingState, config: RunnableConfig) -> dict
materials = sorted(raw_materials, key=lambda m: m.get("relevance_score", 0), reverse=True)[:_MAX_MATERIALS]
summary = f"共搜索到{len(raw_materials)}条素材,精选{len(materials)}条"
# 空结果兜底:未检索到任何素材时给出明确文案,前端据此弹出「无数据继续」选项
if not materials:
summary = "未检索到相关素材,可重新搜索或在无素材的情况下继续写作"
pkg = MaterialPackage(keywords=keywords, materials=materials, summary=summary)
return {