容错处理
This commit is contained in:
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" />
|
<CheckCircle2 className="size-3.5 text-green-500 shrink-0" />
|
||||||
<FileText className="size-3.5 text-blue-500 shrink-0" />
|
<FileText className="size-3.5 text-blue-500 shrink-0" />
|
||||||
<span className="flex-1 font-medium">
|
<span className="flex-1 font-medium">
|
||||||
已确认{' '}
|
{count === 0 && record.action !== 're_search' ? (
|
||||||
<span className="text-muted-foreground font-normal">{count} 条素材</span>
|
'已在无素材的情况下继续写作'
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
已确认{' '}
|
||||||
|
<span className="text-muted-foreground font-normal">{count} 条素材</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
{count > 0 && (
|
{count > 0 && (
|
||||||
expanded
|
expanded
|
||||||
|
|||||||
@@ -118,6 +118,50 @@ function MaterialConfirmCard({ materials, onSubmit, disabled }: MaterialConfirmC
|
|||||||
|
|
||||||
const hasExtra = extraKeywords.length > 0;
|
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 (
|
return (
|
||||||
<div className="rounded-md border bg-background space-y-3 p-3">
|
<div className="rounded-md border bg-background space-y-3 p-3">
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
|
|||||||
@@ -34,20 +34,22 @@ export function MaterialsToolbar({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{/* 全选/取消 */}
|
{/* 全选/取消(无素材时隐藏) */}
|
||||||
<div className="flex items-center gap-2">
|
{materials.length > 0 && (
|
||||||
<span className="text-xs text-muted-foreground">
|
<div className="flex items-center gap-2">
|
||||||
已选 {selectedIds.size} / {materials.length} 条素材
|
<span className="text-xs text-muted-foreground">
|
||||||
</span>
|
已选 {selectedIds.size} / {materials.length} 条素材
|
||||||
<div className="flex-1" />
|
</span>
|
||||||
<button
|
<div className="flex-1" />
|
||||||
type="button"
|
<button
|
||||||
onClick={allSelected ? onDeselectAll : onSelectAll}
|
type="button"
|
||||||
className="text-xs text-primary hover:underline"
|
onClick={allSelected ? onDeselectAll : onSelectAll}
|
||||||
>
|
className="text-xs text-primary hover:underline"
|
||||||
{allSelected ? '取消全选' : '全选'}
|
>
|
||||||
</button>
|
{allSelected ? '取消全选' : '全选'}
|
||||||
</div>
|
</button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* 补充关键词 */}
|
{/* 补充关键词 */}
|
||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ export function TextArtifactRenderer({ content, isStreaming }: TextArtifactRende
|
|||||||
</h3>
|
</h3>
|
||||||
),
|
),
|
||||||
p: ({ children }) => (
|
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}
|
{children}
|
||||||
</p>
|
</p>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -579,6 +579,7 @@
|
|||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
font-size: 0.9375rem; /* 15px */
|
font-size: 0.9375rem; /* 15px */
|
||||||
color: var(--foreground);
|
color: var(--foreground);
|
||||||
|
text-indent: 2em; /* 段落首行缩进 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.tiptap-writing-editor .ProseMirror h1 {
|
.tiptap-writing-editor .ProseMirror h1 {
|
||||||
@@ -658,6 +659,7 @@
|
|||||||
|
|
||||||
.tiptap-writing-editor .ProseMirror li > p {
|
.tiptap-writing-editor .ProseMirror li > p {
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
|
text-indent: 0; /* 列表项内段落不缩进 */
|
||||||
}
|
}
|
||||||
|
|
||||||
.tiptap-writing-editor .ProseMirror blockquote {
|
.tiptap-writing-editor .ProseMirror blockquote {
|
||||||
@@ -716,6 +718,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Placeholder */
|
/* 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 {
|
.tiptap-writing-editor .ProseMirror p.is-editor-empty:first-child::before {
|
||||||
content: attr(data-placeholder);
|
content: attr(data-placeholder);
|
||||||
color: var(--muted-foreground);
|
color: var(--muted-foreground);
|
||||||
|
|||||||
+4
@@ -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]
|
materials = sorted(raw_materials, key=lambda m: m.get("relevance_score", 0), reverse=True)[:_MAX_MATERIALS]
|
||||||
summary = f"共搜索到{len(raw_materials)}条素材,精选{len(materials)}条"
|
summary = f"共搜索到{len(raw_materials)}条素材,精选{len(materials)}条"
|
||||||
|
|
||||||
|
# 空结果兜底:未检索到任何素材时给出明确文案,前端据此弹出「无数据继续」选项
|
||||||
|
if not materials:
|
||||||
|
summary = "未检索到相关素材,可重新搜索或在无素材的情况下继续写作"
|
||||||
|
|
||||||
pkg = MaterialPackage(keywords=keywords, materials=materials, summary=summary)
|
pkg = MaterialPackage(keywords=keywords, materials=materials, summary=summary)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in new issue
Block a user