fix: harden controlled AI session consistency
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
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'
|
||||
@@ -14,8 +14,8 @@ export function ProjectAi({
|
||||
}: {
|
||||
activeWorkspace: ProjectWorkspace
|
||||
onSelectItem: (title: string) => void
|
||||
onListSessions: (projectId: string) => Promise<AISessionDTO[]>
|
||||
onCreateSession: (projectId: string, input: CreateAISessionInput) => Promise<AISessionDTO>
|
||||
onListSessions: (projectId: string, signal?: AbortSignal) => Promise<AISessionDTO[]>
|
||||
onCreateSession: (projectId: string, input: CreateAISessionInput, signal?: AbortSignal) => Promise<AISessionDTO>
|
||||
}) {
|
||||
const [sessions, setSessions] = useState<AISessionDTO[]>([])
|
||||
const [title, setTitle] = useState('')
|
||||
@@ -24,23 +24,47 @@ export function ProjectAi({
|
||||
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<AbortController | null>(null)
|
||||
const createControllerRef = useRef<AbortController | null>(null)
|
||||
projectRef.current = projectId
|
||||
|
||||
useEffect(() => {
|
||||
let current = true
|
||||
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('')
|
||||
void onListSessions(projectId)
|
||||
const isCurrent = () => projectRef.current === projectId && generationRef.current === generation && !controller.signal.aborted
|
||||
|
||||
void onListSessions(projectId, controller.signal)
|
||||
.then((items) => {
|
||||
if (current) setSessions(items)
|
||||
if (isCurrent()) setSessions(items)
|
||||
})
|
||||
.catch((requestError: unknown) => {
|
||||
if (current) setError(requestError instanceof Error ? requestError.message : 'AI 会话加载失败,请稍后重试')
|
||||
if (isCurrent()) setError(requestError instanceof Error ? requestError.message : 'AI 会话加载失败,请稍后重试')
|
||||
})
|
||||
.finally(() => {
|
||||
if (current) setLoading(false)
|
||||
if (isCurrent()) {
|
||||
setLoading(false)
|
||||
listControllerRef.current = null
|
||||
}
|
||||
})
|
||||
|
||||
return () => {
|
||||
current = false
|
||||
generationRef.current += 1
|
||||
controller.abort()
|
||||
if (listControllerRef.current === controller) listControllerRef.current = null
|
||||
createControllerRef.current?.abort()
|
||||
createControllerRef.current = null
|
||||
}
|
||||
}, [onListSessions, projectId])
|
||||
|
||||
@@ -50,21 +74,35 @@ export function ProjectAi({
|
||||
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 {
|
||||
setCreating(false)
|
||||
if (isCurrent()) {
|
||||
setCreating(false)
|
||||
createControllerRef.current = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user