import { useMemo, useRef, useState } from 'react' import { Alert, Button, Card, Checkbox, Empty, Space, Tag, Typography } from '@arco-design/web-react' import { IconCheckCircle, IconRobot } from '@arco-design/web-react/icon' import { ApiError } from '../../api/client' import type { InboxSuggestionDTO } from '../../api/inbox' import type { InboxConfirmationOutcome, InboxItem, ProjectWorkspace } from './project-types' const { Title, Text, Paragraph } = Typography type ProjectInboxProps = { activeWorkspace: ProjectWorkspace onAnalyze: (inboxId: string) => Promise onConfirm: (inboxId: string, suggestionIds: string[]) => Promise } export function ProjectInbox({ activeWorkspace, onAnalyze, onConfirm }: ProjectInboxProps) { const [selectedItemId, setSelectedItemId] = useState(activeWorkspace.inbox[0]?.id ?? '') const [draftSuggestions, setDraftSuggestions] = useState([]) const [selectedSuggestionIds, setSelectedSuggestionIds] = useState([]) const [analyzing, setAnalyzing] = useState(false) const [confirming, setConfirming] = useState(false) const [error, setError] = useState('') const [success, setSuccess] = useState('') const [refreshWarning, setRefreshWarning] = useState('') const [locallyConfirmedItemIds, setLocallyConfirmedItemIds] = useState([]) const analysisGeneration = useRef(0) const selectedItem = useMemo( () => activeWorkspace.inbox.find((item) => item.id === selectedItemId) ?? activeWorkspace.inbox[0], [activeWorkspace.inbox, selectedItemId], ) function selectItem(item: InboxItem) { analysisGeneration.current += 1 setSelectedItemId(item.id) setDraftSuggestions([]) setSelectedSuggestionIds([]) setError('') setSuccess('') setRefreshWarning('') setAnalyzing(false) } async function analyzeSelectedItem() { if (!selectedItem || selectedItem.status !== 'open') return setAnalyzing(true) setError('') setSuccess('') setRefreshWarning('') const generation = analysisGeneration.current + 1 analysisGeneration.current = generation const analyzedItemId = selectedItem.id try { const suggestions = await onAnalyze(analyzedItemId) if (analysisGeneration.current !== generation || selectedItemId !== analyzedItemId) return setDraftSuggestions(suggestions) setSelectedSuggestionIds(suggestions.map((suggestion) => suggestion.id)) } catch (reason) { if (analysisGeneration.current !== generation) return setError(reason instanceof Error ? reason.message : '分析失败,请稍后重试') } finally { if (analysisGeneration.current === generation) setAnalyzing(false) } } async function confirmSelectedSuggestions() { if (!selectedItem) return if (selectedSuggestionIds.length === 0) { setError('请至少勾选一条建议') return } setConfirming(true) setError('') setSuccess('') try { const outcome = await onConfirm(selectedItem.id, selectedSuggestionIds) setLocallyConfirmedItemIds((current) => current.includes(selectedItem.id) ? current : [...current, selectedItem.id]) setSuccess(`已创建 ${outcome.createdCount} 个对象`) setRefreshWarning(outcome.refreshError ?? '') } catch (reason) { setError(confirmationErrorMessage(reason)) } finally { setConfirming(false) } } function toggleSuggestion(identity: string, checked: boolean) { setSelectedSuggestionIds((current) => checked ? current.includes(identity) ? current : [...current, identity] : current.filter((value) => value !== identity)) } return (
Inbox 消息流 查看原始内容,分析为候选草稿,并在确认后创建正式对象。
{activeWorkspace.inbox.length === 0 ? ( ) : (
收集内容({activeWorkspace.inbox.length})
{activeWorkspace.inbox.map((item) => ( ))}
{selectedItem ? ( <>
{selectedItem.title} {isInboxItemProcessed(selectedItem, locallyConfirmedItemIds) ? '已处理' : '待处理'} {selectedItem.meta} · {selectedItem.time}
原始内容 {selectedItem.summary || '暂无内容'}
分析建议 仅勾选内容会在确认后创建
{draftSuggestions.length === 0 ? ( 点击“分析内容”生成候选草稿,分析不会创建正式对象。 ) : (
{draftSuggestions.map((suggestion) => ( toggleSuggestion(suggestion.id, checked)} > {suggestionLabel(suggestion.kind)} {suggestion.title} {suggestion.body || '暂无补充内容'} ))}
)}
{error && } {success && } />} {refreshWarning && }
正式写入前请核对勾选项
) : null}
)}
) } function confirmationErrorMessage(reason: unknown) { if (reason instanceof ApiError && (reason.code === 'network_error' || reason.code === 'invalid_response')) { return '确认结果未知,服务端支持幂等处理,可安全重试' } return reason instanceof Error ? reason.message : '确认创建失败,请稍后重试' } function isInboxItemProcessed(item: InboxItem, locallyConfirmedItemIds: string[]) { return item.status !== 'open' || locallyConfirmedItemIds.includes(item.id) } function suggestionLabel(kind: InboxSuggestionDTO['kind']) { if (kind === 'task') return '任务' if (kind === 'note') return '笔记' return '资料' } function suggestionColor(kind: InboxSuggestionDTO['kind']) { if (kind === 'task') return 'arcoblue' if (kind === 'note') return 'green' return 'purple' }