import { useEffect, useRef, useState } from 'react' import { Alert, Button, Card, Empty, Input, Space, Spin, Tag, Typography } from '@arco-design/web-react' import { IconPlusCircle, IconRobot } from '@arco-design/web-react/icon' import type { AISessionDTO, CreateAISessionInput } from '../../api/ai' import type { ProjectWorkspace } from './project-types' const { Title, Text } = Typography export function ProjectAi({ activeWorkspace, onSelectItem, onListSessions, onCreateSession, }: { activeWorkspace: ProjectWorkspace onSelectItem: (title: string) => void onListSessions: (projectId: string, signal?: AbortSignal) => Promise onCreateSession: (projectId: string, input: CreateAISessionInput, signal?: AbortSignal) => Promise }) { const [sessions, setSessions] = useState([]) const [title, setTitle] = useState('') const [context, setContext] = useState('') const [loading, setLoading] = useState(true) const [creating, setCreating] = useState(false) const [error, setError] = useState('') const projectId = activeWorkspace.project.id const projectRef = useRef(projectId) const generationRef = useRef(0) const listControllerRef = useRef(null) const createControllerRef = useRef(null) projectRef.current = projectId useEffect(() => { const generation = ++generationRef.current const controller = new AbortController() listControllerRef.current?.abort() createControllerRef.current?.abort() listControllerRef.current = controller createControllerRef.current = null setSessions([]) setTitle('') setContext('') setLoading(true) setCreating(false) setError('') const isCurrent = () => projectRef.current === projectId && generationRef.current === generation && !controller.signal.aborted void onListSessions(projectId, controller.signal) .then((items) => { if (isCurrent()) setSessions(items) }) .catch((requestError: unknown) => { if (isCurrent()) setError(requestError instanceof Error ? requestError.message : 'AI 会话加载失败,请稍后重试') }) .finally(() => { if (isCurrent()) { setLoading(false) listControllerRef.current = null } }) return () => { generationRef.current += 1 controller.abort() if (listControllerRef.current === controller) listControllerRef.current = null createControllerRef.current?.abort() createControllerRef.current = null } }, [onListSessions, projectId]) const createSession = async () => { const trimmedTitle = title.trim() if (!trimmedTitle) { setError('请输入 AI 会话标题') return } const generation = ++generationRef.current listControllerRef.current?.abort() listControllerRef.current = null createControllerRef.current?.abort() const controller = new AbortController() createControllerRef.current = controller const isCurrent = () => projectRef.current === projectId && generationRef.current === generation && !controller.signal.aborted setLoading(false) setCreating(true) setError('') try { const created = await onCreateSession(projectId, { title: trimmedTitle, context: context.trim(), }, controller.signal) if (!isCurrent()) return setSessions((current) => [created, ...current.filter((session) => session.id !== created.id)]) setTitle('') setContext('') onSelectItem(created.title) } catch (requestError) { if (!isCurrent()) return setError(requestError instanceof Error ? requestError.message : 'AI 会话创建失败,请稍后重试') } finally { if (isCurrent()) { setCreating(false) createControllerRef.current = null } } } return (
AI 对话 创建项目内普通会话;不会自动生成任务、笔记或资料。
{error ? setError('')} /> : null}
{sessions.length ? (
{sessions.map((session) => ( ))}
) : loading ? null : }
创建会话 会话状态为“待开始”只表示入口已建立,不代表 AI 已完成处理。
AI 输出如需转为正式对象,必须另行确认。
) } function sessionStatusLabel(status: string) { if (status === 'ready') return '待开始' if (status === 'failed') return '创建失败' return status || '未知状态' }