feat(review-ai): 平板 AI 助手面板 MVP
新增功能: - src/api/review/ai.ts:5 个 AI API(摘要、重建、会话、流式问答、清空) - 平板页右侧 AI 助手面板(toggleable 抽屉,三栏布局) - 摘要状态卡片:未生成/生成中(轮询4s)/已完成/失败 - 结构化摘要展示:概述/目标/范围/计划/预算/来源文件 - 共享问答区:历史消息加载 + 流式生成气泡 - 4个快捷问题按钮 - 停止生成 / 清空当前项目问答 按钮 - 回车快捷发送 Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>pull/874/head
parent
302772ecb9
commit
e6cf930062
|
|
@ -0,0 +1,99 @@
|
|||
import request from '@/config/axios'
|
||||
import { fetchEventSource } from '@microsoft/fetch-event-source'
|
||||
import { getAccessToken } from '@/utils/auth'
|
||||
import { config } from '@/config/axios/config'
|
||||
|
||||
// ============================================================
|
||||
// 类型定义
|
||||
// ============================================================
|
||||
|
||||
export const AI_SUMMARY_STATUS = {
|
||||
NOT_BUILT: 0,
|
||||
BUILDING: 1,
|
||||
SUCCESS: 2,
|
||||
FAILED: 3
|
||||
} as const
|
||||
|
||||
export interface ReviewAiSummaryVO {
|
||||
reviewMeetingProjectId: number
|
||||
status: number
|
||||
statusName: string
|
||||
updatedTime: string | null
|
||||
summaryMarkdown: string | null
|
||||
sourceFileIds: number[]
|
||||
errorMessage: string | null
|
||||
summary: {
|
||||
projectOverview: string
|
||||
businessGoal: string
|
||||
constructionScope: string
|
||||
implementationPlan: string
|
||||
budgetInfo: string
|
||||
keyEntities: string[]
|
||||
readingGuide: string[]
|
||||
sourceFiles: string[]
|
||||
} | null
|
||||
}
|
||||
|
||||
export interface ReviewAiConversationVO {
|
||||
conversationId: number
|
||||
title: string
|
||||
knowledgeId: number
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// API 调用
|
||||
// ============================================================
|
||||
|
||||
/** 获取评审项目 AI 摘要 */
|
||||
export const getProjectAiSummary = (reviewMeetingProjectId: number): Promise<ReviewAiSummaryVO> =>
|
||||
request.get({ url: `/project/review-ai/project/${reviewMeetingProjectId}/summary` })
|
||||
|
||||
/** 触发重建 AI 摘要(管理端) */
|
||||
export const rebuildProjectAiSummary = (reviewMeetingProjectId: number) =>
|
||||
request.post({ url: `/project/review-ai/project/${reviewMeetingProjectId}/rebuild` })
|
||||
|
||||
/** 打开 / 获取当前项目共享会话 */
|
||||
export const openProjectAiConversation = (
|
||||
reviewMeetingProjectId: number
|
||||
): Promise<ReviewAiConversationVO> =>
|
||||
request.post({ url: `/project/review-ai/project/${reviewMeetingProjectId}/conversation/open` })
|
||||
|
||||
/** 清空当前项目共享会话消息 */
|
||||
export const clearProjectAiMessages = (reviewMeetingProjectId: number) =>
|
||||
request.delete({ url: `/project/review-ai/project/${reviewMeetingProjectId}/chat/messages` })
|
||||
|
||||
/**
|
||||
* 流式发送评审项目 AI 消息
|
||||
* 使用 fetchEventSource(axios 不支持 SSE)
|
||||
*/
|
||||
export const sendProjectAiChatStream = (
|
||||
reviewMeetingProjectId: number,
|
||||
conversationId: number,
|
||||
content: string,
|
||||
ctrl: AbortController,
|
||||
onMessage: (event: any) => void,
|
||||
onError: (error: any) => void,
|
||||
onClose: () => void
|
||||
) => {
|
||||
const token = getAccessToken()
|
||||
return fetchEventSource(
|
||||
`${config.base_url}/project/review-ai/project/${reviewMeetingProjectId}/chat/send-stream`,
|
||||
{
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${token}`
|
||||
},
|
||||
openWhenHidden: true,
|
||||
body: JSON.stringify({
|
||||
conversationId,
|
||||
content,
|
||||
useContext: true
|
||||
}),
|
||||
onmessage: onMessage,
|
||||
onerror: onError,
|
||||
onclose: onClose,
|
||||
signal: ctrl.signal
|
||||
}
|
||||
)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue