Commit 2115e7da by Liu

feat(chat): 工作流卡片字段、会话状态与聊天页联动

- 新增 CardWorkflowField,调整 CardWorkflowForm 与附件展示
- 扩展 conversation/chat 类型与 conversationSlice 业务洞察工作流状态
- Chat 与 HomeNew 对接工作流提交与参数逻辑

Co-authored-by: Cursor <cursoragent@cursor.com>
parent 69439c2d
......@@ -14,8 +14,9 @@ import type { ChatRecord } from '@/types/chat'
import { fetchSessionConversationId, fetchUserQaRecordPage } from '@/api/conversation'
import { fetchCheckTokenApi, fetchStreamResponse } from '@/api/chat'
import { fetchToolList } from '@/api/home'
import { clearCurrentToolId, clearShouldSendQuestion, fetchConversations, setCurrentToolId } from '@/store/conversationSlice'
import { clearBusinessInsightWorkflow, clearCurrentToolId, clearShouldSendQuestion, exitBusinessInsightSubWorkflow, fetchConversations, setBusinessInsightMainWorkflow, setBusinessInsightPendingQuestion, setBusinessInsightSubWorkflow, setCurrentToolId, updateBusinessInsightParamMap } from '@/store/conversationSlice'
import { getUserRolesForApi, safeSessionStorageGetItem, waitForToken } from '@/lib/utils'
import { getWorkflowToolIdAndRecordTypeForSubmit, setWorkflowLastToolPair } from '@/lib/workflowToolParams'
import type { RootState } from '@/store'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import ScrollBtoIcon from '@/assets/svg/scrollBto.svg?react'
......@@ -48,7 +49,7 @@ export const Chat: React.FC = () => {
const [isLoading, setIsLoading] = useState(false)
const [allItems, setAllItems] = useState<ChatRecord[]>([])
const dispatch = useAppDispatch()
const { shouldSendQuestion, currentToolId, conversations } = useAppSelector((state: RootState) => state.conversation)
const { shouldSendQuestion, currentToolId, conversations, businessInsightWorkflow } = useAppSelector((state: RootState) => state.conversation)
const isAsking = useAppSelector((state: RootState) => state.chat.isAsking)
// 标记历史记录是否已加载完成,用于确保自动发送问题在历史记录加载后执行
const historyLoadedRef = useRef<{ conversationId: string | null }>({ conversationId: null })
......@@ -75,6 +76,22 @@ export const Chat: React.FC = () => {
// 提质增效自动调用欢迎语候选(用于流结束后写入 sessionStorage)
const autoWelcomeCandidateRef = useRef<string>('')
const hasAutoWelcomeCandidateRef = useRef<boolean>(false)
// 业务洞察工作流状态 ref(用于在流结束后访问最新状态)
const businessInsightWorkflowRef = useRef<{
mainWorkflowSessionId: string | null
subWorkflowSessionId: string | null
subWorkflowRecordType: string | null
paramMap: Record<string, string>
isInSubWorkflow: boolean
pendingQuestion: string | null
}>({
mainWorkflowSessionId: null,
subWorkflowSessionId: null,
subWorkflowRecordType: null,
paramMap: {},
isInSubWorkflow: false,
pendingQuestion: null,
})
// 当外部系统直接以 /chat/:id 链接进入(没有 location.state,且 URL 中也没有 toolId)时,
// 视为一次新的会话入口:重置为制度活化,清除历史遗留的工具模式状态
......@@ -161,6 +178,11 @@ export const Chat: React.FC = () => {
}
}, [dispatch, initialToolId])
// 同步业务洞察工作流状态到 ref
useEffect(() => {
businessInsightWorkflowRef.current = businessInsightWorkflow
}, [businessInsightWorkflow])
/** 处理正常stream的数据 */
const handleStreamMesageData = (msg: any, question: string) => {
setAllItems((prevItems) => {
......@@ -231,6 +253,10 @@ export const Chat: React.FC = () => {
// 在流式响应过程中,忽略服务器返回的 endAnswerFlag,避免过早禁用输入框
const { endAnswerFlag: _omitEndAnswerFlag, ...dataWithoutEndFlag } = msg.content.data || {}
const chunkToolId = dataWithoutEndFlag.toolId != null ? String(dataWithoutEndFlag.toolId).trim() : ''
const chunkRecordType = dataWithoutEndFlag.recordType != null ? String(dataWithoutEndFlag.recordType).trim() : ''
if (chunkToolId && chunkRecordType)
setWorkflowLastToolPair(chunkToolId, chunkRecordType)
// 保留之前保存的 workFlowSessionId 和 recordId,避免被覆盖
newItems[currentIndex] = {
...newItems[currentIndex],
......@@ -302,10 +328,29 @@ export const Chat: React.FC = () => {
// 优先读取缓存中的 toolId,再回退到传参或 Redux
const sessionToolId = sessionStorage.getItem('currentToolId') ?? undefined
const resolvedToolId = toolId ?? sessionToolId ?? currentToolId ?? undefined
// 判断是否为提质增效模式的自动调用(空问题)
// 业务洞察等工作流参数:有主/子会话态时合并进 extra(不依赖写死 toolId)
let workflowExtraParams = extraParams
if (businessInsightWorkflowRef.current) {
const workflowState = businessInsightWorkflowRef.current
if (workflowState.isInSubWorkflow) {
workflowExtraParams = {
...extraParams,
recordType: workflowState.subWorkflowRecordType || undefined,
workFlowSessionId: workflowState.subWorkflowSessionId || workFlowSessionId,
paramMap: workflowState.paramMap,
}
}
else if (workflowState.mainWorkflowSessionId) {
workflowExtraParams = {
...extraParams,
workFlowSessionId: workflowState.mainWorkflowSessionId,
}
}
}
// 空问题 + 显式传入 recordType/busiType(如工具入口 autoSubmit)时走自动欢迎语流式逻辑
const isEmptyQuestion = !question.trim()
const isQualityImprovement = resolvedToolId === '6712395743241'
isAutoSubmitQualityImprovementRef.current = isEmptyQuestion && isQualityImprovement
const isAutoToolEmptySubmit = isEmptyQuestion && Boolean(extraParams?.recordType && extraParams?.busiType)
isAutoSubmitQualityImprovementRef.current = isAutoToolEmptySubmit
if (isAutoSubmitQualityImprovementRef.current) {
// 重置欢迎语候选
autoWelcomeCandidateRef.current = ''
......@@ -366,12 +411,12 @@ export const Chat: React.FC = () => {
}
// 如果是 workflow 提交,添加 paramMap、recordId 和 workFlowSessionId
if (extraParams?.paramMap) {
requestBody.paramMap = extraParams.paramMap
if (workflowExtraParams?.paramMap) {
requestBody.paramMap = workflowExtraParams.paramMap
}
// 优先使用 extraParams 中的值,其次使用直接传递的参数
if (extraParams?.recordId) {
requestBody.recordId = extraParams.recordId
// 优先使用 workflowExtraParams 中的值,其次使用直接传递的参数
if (workflowExtraParams?.recordId) {
requestBody.recordId = workflowExtraParams.recordId
}
else if (recordId) {
requestBody.recordId = recordId
......@@ -380,17 +425,16 @@ export const Chat: React.FC = () => {
// workFlowSessionId 的传递逻辑:
// 1. 如果是重新问答(isReask === true),不传递 workFlowSessionId
// 2. 如果是提质增效模式的自动调用(空问题),不传递 workFlowSessionId
// 3. 优先使用 extraParams 中的值
// 3. 优先使用 workflowExtraParams 中的值
// 4. 其次使用直接传递的参数
// 5. 如果都没有,从会话历史中找到最后一个有 workFlowSessionId 的答案
const isReask = extraParams?.isReask === true
// 判断是否为提质增效自动调用:空问题且 toolId 为提质增效
const isReask = workflowExtraParams?.isReask === true
const isAutoQualityImprovement = isAutoSubmitQualityImprovementRef.current
// 仅在指定工具下传递/回填 workFlowSessionId,避免其他工具被误带
const shouldUseWorkflowSession = resolvedToolId === '6712395743241' || resolvedToolId === '6712395743242'
// 已选择工具(非制度活化)时允许携带 / 回填 workFlowSessionId
const shouldUseWorkflowSession = Boolean(resolvedToolId && String(resolvedToolId).trim() !== '')
if (shouldUseWorkflowSession && !isReask && !isAutoQualityImprovement) {
if (extraParams?.workFlowSessionId) {
requestBody.workFlowSessionId = extraParams.workFlowSessionId
if (workflowExtraParams?.workFlowSessionId) {
requestBody.workFlowSessionId = workflowExtraParams.workFlowSessionId
}
else if (workFlowSessionId) {
requestBody.workFlowSessionId = workFlowSessionId
......@@ -409,11 +453,11 @@ export const Chat: React.FC = () => {
}
// 如果传入了 recordType,优先使用传入的值(workflow 提交场景)
if (extraParams?.recordType) {
requestBody.recordType = extraParams.recordType
if (workflowExtraParams?.recordType) {
requestBody.recordType = workflowExtraParams.recordType
// 如果同时传入了 busiType,也使用传入的值
if (extraParams?.busiType) {
requestBody.busiType = extraParams.busiType
if (workflowExtraParams?.busiType) {
requestBody.busiType = workflowExtraParams.busiType
}
}
// 制度活化:toolId 为空字符串或 undefined
......@@ -422,22 +466,19 @@ export const Chat: React.FC = () => {
requestBody.busiType = '01'
requestBody.recordType = '01'
}
// 提质增效:toolId 为 6712395743241
else if (resolvedToolId === '6712395743241') {
requestBody.busiType = '01'
requestBody.recordType = 'B03'
}
// 数据助手:toolId 为 6712395743240
else if (resolvedToolId === '6712395743240') {
requestBody.busiType = '01'
requestBody.recordType = '01'
else {
const workflowPair = getWorkflowToolIdAndRecordTypeForSubmit()
if (workflowPair?.toolId && workflowPair?.recordType) {
requestBody.toolId = workflowPair.toolId
requestBody.busiType = workflowExtraParams?.busiType ?? extraParams?.busiType ?? '01'
requestBody.recordType = workflowPair.recordType
}
// 兜底逻辑:如果 toolId 不在预期范围内,默认使用制度活化的参数
else {
requestBody.toolId = resolvedToolId
requestBody.busiType = '01'
requestBody.recordType = '01'
}
}
fetchStreamResponse(
fetchUrl,
......@@ -538,6 +579,46 @@ export const Chat: React.FC = () => {
dispatch(fetchConversations())
}, 2000)
}
// 业务洞察工作流处理:检查 AI 返回的 answer 是否需要开启子工作流
const currentItems = allItems
let lastAiItem = null
for (let i = currentItems.length - 1; i >= 0; i--) {
if (currentItems[i].role === 'ai' && currentItems[i].answerList?.[0]) {
lastAiItem = currentItems[i]
break
}
}
if (lastAiItem) {
const lastAnswer = lastAiItem.answerList?.[0]
const wf = businessInsightWorkflowRef.current
const shouldHandleWorkflowAnswer = Boolean(lastAnswer?.workFlowSessionId)
|| Boolean(wf?.mainWorkflowSessionId)
|| Boolean(wf?.isInSubWorkflow)
if (lastAnswer && shouldHandleWorkflowAnswer) {
let parsedAnswer = null
try {
parsedAnswer = JSON.parse(lastAnswer.answer || '')
}
catch {
// 不是 JSON,保持正常回答
}
if (parsedAnswer && parsedAnswer.recordType && parsedAnswer.question) {
dispatch(setBusinessInsightSubWorkflow({
sessionId: '',
recordType: parsedAnswer.recordType,
}))
dispatch(setBusinessInsightPendingQuestion(parsedAnswer.question))
}
else if (businessInsightWorkflowRef.current.isInSubWorkflow) {
if (parsedAnswer && parsedAnswer.end === true) {
dispatch(exitBusinessInsightSubWorkflow())
}
}
else if (lastAnswer.workFlowSessionId && !businessInsightWorkflowRef.current.mainWorkflowSessionId) {
dispatch(setBusinessInsightMainWorkflow(lastAnswer.workFlowSessionId))
}
}
}
})
.catch(() => {
// 流式请求出错时的处理
......
import React from 'react'
import { Input } from '@heroui/react'
export interface WorkflowFieldOption {
id?: string
text?: string
type?: string
}
export interface WorkflowFieldItem {
key: string
label: string
type: string
required?: boolean
multiple?: boolean
options?: WorkflowFieldOption[]
}
interface CardWorkflowFieldProps {
field: WorkflowFieldItem
value: string | string[]
disabled: boolean
onChange: (key: string, value: string | string[]) => void
}
export const CardWorkflowField: React.FC<CardWorkflowFieldProps> = ({
field,
value,
disabled,
onChange,
}) => {
const requiredMark = field.required ? '*' : ''
const label = `${requiredMark}${field.label}`
if (field.type === 'select') {
if (field.multiple) {
const selectedValues = Array.isArray(value) ? value : []
return (
<div>
<label className="block text-[14px] text-[#4b5563] mb-[6px]">{label}</label>
<select
multiple
value={selectedValues}
disabled={disabled}
onChange={(e) => {
const nextValues = Array.from(e.target.selectedOptions).map(option => option.value)
onChange(field.key, nextValues)
}}
className="w-full min-h-[96px] border border-[#d4d4d8] rounded-[12px] px-[12px] py-[8px] text-[14px] bg-white"
>
{(field.options || []).map(option => (
<option key={option.id || option.text} value={option.id || ''}>
{option.text || option.id}
</option>
))}
</select>
</div>
)
}
const selectedValue = typeof value === 'string' ? value : ''
return (
<div>
<label className="block text-[14px] text-[#4b5563] mb-[6px]">{label}</label>
<select
value={selectedValue}
disabled={disabled}
onChange={e => onChange(field.key, e.target.value)}
className="w-full h-[40px] border border-[#d4d4d8] rounded-[12px] px-[12px] text-[14px] bg-white"
>
<option value="">
请选择
{field.label}
</option>
{(field.options || []).map(option => (
<option key={option.id || option.text} value={option.id || ''}>
{option.text || option.id}
</option>
))}
</select>
</div>
)
}
return (
<Input
label={label}
value={typeof value === 'string' ? value : ''}
onChange={e => onChange(field.key, e.target.value)}
isDisabled={disabled}
variant="bordered"
className="w-full"
/>
)
}
import React, { useEffect, useMemo, useRef, useState } from 'react'
import { Button, Input } from '@heroui/react'
import { Button } from '@heroui/react'
import { useSearchParams } from 'react-router-dom'
import { CardWorkflowField, type WorkflowFieldItem } from './CardWorkflowField'
import type { Answer, Attachment } from '@/types/chat'
interface CardWorkflowFormProps {
......@@ -18,7 +19,7 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
isSubmitting = false,
isCompleted = false,
}) => {
const [formValues, setFormValues] = useState<Record<string, string>>({})
const [formValues, setFormValues] = useState<Record<string, string | string[]>>({})
const [searchParams] = useSearchParams()
const hasAutoSubmittedRef = useRef(false) // 防止重复自动提交
const lastFirstQaFlagRef = useRef<boolean | undefined>(undefined) // 记录上次的 firstQaFlag 值
......@@ -29,31 +30,50 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
onSubmitWorkflowRef.current = onSubmitWorkflow
}, [onSubmitWorkflow])
// 获取 text 类型的字段,使用 useMemo 稳定引用
const textFields = useMemo(() => {
return attachment.content?.fieldList?.filter(field => field.type === 'text') || []
// 获取 workflow 字段(支持 text/select 等),使用 useMemo 稳定引用
const workflowFields = useMemo<WorkflowFieldItem[]>(() => {
return (attachment.content?.fieldList || []).filter(field => Boolean(field?.key) && Boolean(field?.type))
}, [attachment.content?.fieldList])
const isFieldValueFilled = (field: WorkflowFieldItem, value: string | string[] | undefined) => {
if (Array.isArray(value)) {
return value.length > 0
}
return !!value && value.trim() !== ''
}
const buildParamValue = (value: string | string[] | undefined) => {
if (Array.isArray(value)) {
return value.join(',')
}
return value || ''
}
// 初始化表单值,如果 firstQaFlag 为 true,从 URL query 中读取值
useEffect(() => {
const initialValues: Record<string, string> = {}
const initialValues: Record<string, string | string[]> = {}
if (answer.firstQaFlag === true) {
// 从 URL query 参数中读取值,匹配 fieldList 中的 key
textFields.forEach((field) => {
workflowFields.forEach((field) => {
const queryValue = searchParams.get(field.key)
if (field.type === 'select' && field.multiple) {
initialValues[field.key] = queryValue ? queryValue.split(',').map(item => item.trim()).filter(Boolean) : []
}
else {
initialValues[field.key] = queryValue || ''
}
})
}
else {
// 正常初始化,所有字段为空
textFields.forEach((field) => {
initialValues[field.key] = ''
workflowFields.forEach((field) => {
initialValues[field.key] = field.type === 'select' && field.multiple ? [] : ''
})
}
setFormValues(initialValues)
}, [textFields, searchParams, answer.firstQaFlag])
}, [workflowFields, searchParams, answer.firstQaFlag])
// 单独处理 firstQaFlag 的变化,重置自动提交标志
useEffect(() => {
......@@ -61,7 +81,8 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
if (answer.firstQaFlag !== true) {
hasAutoSubmittedRef.current = false
lastFirstQaFlagRef.current = false // 重置记录的值,确保下次变为 true 时能正确触发
} else {
}
else {
// 如果 firstQaFlag 为 true,初始化 lastFirstQaFlagRef(如果还没有设置)
// 这样可以处理组件首次渲染时 firstQaFlag 已经是 true 的情况
if (lastFirstQaFlagRef.current === undefined) {
......@@ -78,9 +99,9 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
// 只在 firstQaFlag 首次变为 true 且尚未自动提交时执行
if (isFirstQaFlagChangedToTrue && !hasAutoSubmittedRef.current && !isSubmitting && !isCompleted) {
// 检查是否有字段(textFields 不为空)
if (textFields.length === 0) {
console.log('[CardWorkflowForm] 自动提交:textFields 为空,跳过')
// 检查是否有字段(workflowFields 不为空)
if (workflowFields.length === 0) {
console.log('[CardWorkflowForm] 自动提交:workflowFields 为空,跳过')
// 更新记录的值
lastFirstQaFlagRef.current = answer.firstQaFlag
return
......@@ -88,10 +109,13 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
// 检查是否所有必填字段都有值(从 URL query 中读取的)
// 只校验 required === true 的字段
const requiredFields = textFields.filter(field => field.required === true)
const requiredFields = workflowFields.filter(field => field.required === true)
const allRequiredFieldsHaveValues = requiredFields.length === 0 || requiredFields.every((field) => {
const queryValue = searchParams.get(field.key)
return queryValue && queryValue.trim() !== ''
if (field.type === 'select' && field.multiple) {
return !!queryValue && queryValue.split(',').map(item => item.trim()).filter(Boolean).length > 0
}
return !!queryValue && queryValue.trim() !== ''
})
console.log('[CardWorkflowForm] 自动提交检查:', {
......@@ -99,11 +123,11 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
hasAutoSubmitted: hasAutoSubmittedRef.current,
isSubmitting,
isCompleted,
textFieldsCount: textFields.length,
workflowFieldsCount: workflowFields.length,
requiredFieldsCount: requiredFields.length,
allRequiredFieldsHaveValues,
requiredFields: requiredFields.map(f => ({ key: f.key, label: f.label })),
textFields: textFields.map(f => ({ key: f.key, label: f.label, required: f.required })),
workflowFields: workflowFields.map(f => ({ key: f.key, label: f.label, required: f.required, type: f.type })),
})
if (allRequiredFieldsHaveValues) {
......@@ -114,9 +138,15 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
// 构建 paramMap
const paramMap: Record<string, string> = {}
textFields.forEach((field) => {
workflowFields.forEach((field) => {
const queryValue = searchParams.get(field.key)
if (field.type === 'select' && field.multiple) {
const values = queryValue ? queryValue.split(',').map(item => item.trim()).filter(Boolean) : []
paramMap[field.key] = values.join(',')
}
else {
paramMap[field.key] = queryValue || ''
}
})
// 获取 recordId 和 workFlowSessionId(从 answer 中获取,第一次可能没有)
......@@ -136,24 +166,25 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
return () => {
clearTimeout(timeoutId)
}
} else {
}
else {
console.log('[CardWorkflowForm] 自动提交:必填字段值不完整,跳过', {
requiredFields: requiredFields.map(f => ({ key: f.key, label: f.label, value: searchParams.get(f.key) })),
allFields: textFields.map(f => ({ key: f.key, label: f.label, required: f.required, value: searchParams.get(f.key) })),
allFields: workflowFields.map(f => ({ key: f.key, label: f.label, required: f.required, value: searchParams.get(f.key), type: f.type })),
})
// 更新记录的值
lastFirstQaFlagRef.current = answer.firstQaFlag
}
} else {
}
else {
// 更新记录的值(即使不执行自动提交,也要更新记录)
lastFirstQaFlagRef.current = answer.firstQaFlag
}
// 移除 onSubmitWorkflow 和 textFields 作为依赖项,使用 useRef 保存引用,避免函数引用变化或 textFields 更新导致重复触发
// textFields 更新不应该触发重新提交,因为我们已经检查了 firstQaFlag 的变化
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [answer.firstQaFlag, isSubmitting, isCompleted, searchParams])
const handleInputChange = (key: string, value: string) => {
const handleFieldChange = (key: string, value: string | string[]) => {
setFormValues(prev => ({
...prev,
[key]: value,
......@@ -163,8 +194,8 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
const handleSubmit = () => {
// 构建 paramMap
const paramMap: Record<string, string> = {}
textFields.forEach((field) => {
paramMap[field.key] = formValues[field.key] || ''
workflowFields.forEach((field) => {
paramMap[field.key] = buildParamValue(formValues[field.key])
})
// 获取 recordId 和 workFlowSessionId(从 answer 中获取,第一次可能没有)
......@@ -174,8 +205,10 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
onSubmitWorkflow(paramMap, recordId, workFlowSessionId)
}
// 检查是否有 text 类型的字段
if (textFields.length === 0) {
const hasRequiredMissing = workflowFields.some(field => field.required && !isFieldValueFilled(field, formValues[field.key]))
// 检查是否有可渲染字段
if (workflowFields.length === 0) {
return null
}
......@@ -187,22 +220,20 @@ export const CardWorkflowForm: React.FC<CardWorkflowFormProps> = ({
return (
<div className="card-workflow-form">
<div className="flex flex-col gap-[12px]">
{textFields.map(field => (
{workflowFields.map(field => (
<div key={field.key}>
<Input
label={field.label}
value={formValues[field.key] || ''}
onChange={e => handleInputChange(field.key, e.target.value)}
isDisabled={isSubmitting || isCompleted || (answer.firstQaFlag === true && hasAutoSubmittedRef.current)}
variant="bordered"
className="w-full"
<CardWorkflowField
field={field}
value={formValues[field.key] ?? (field.type === 'select' && field.multiple ? [] : '')}
onChange={handleFieldChange}
disabled={isSubmitting || isCompleted || (answer.firstQaFlag === true && hasAutoSubmittedRef.current)}
/>
</div>
))}
<Button
color="primary"
onPress={handleSubmit}
isDisabled={isSubmitting || isCompleted || (answer.firstQaFlag === true && hasAutoSubmittedRef.current)}
isDisabled={isSubmitting || isCompleted || hasRequiredMissing || (answer.firstQaFlag === true && hasAutoSubmittedRef.current)}
isLoading={isSubmitting}
className="mt-[8px]"
>
......
......@@ -174,7 +174,7 @@ export const ChatAnswerAttachment: React.FC<ChatAnswerAttachmentProps> = ({
{/* 工作流卡片:card-workflow */}
{attachment.type === 'card-workflow'
&& attachment.content?.name === 'form_input'
&& attachment.content?.fieldList?.some(field => field.type === 'text') && (
&& attachment.content?.fieldList?.length > 0 && (
<CardWorkflowForm
key={`workflow-form-${attachment.id || index}-${answer.recordId || 'new'}`}
attachment={attachment}
......
......@@ -7,7 +7,7 @@ import styles from './Home.module.less'
import { QuestionList } from './components/QuestionList'
import HomeIcon2 from '@/assets/homeIcon2.png'
import SmartIce from '@/assets/smart-ice.png'
import { clearCurrentToolId, fetchConversations, setCurrentConversation, setCurrentToolId, setNavigationFlag } from '@/store/conversationSlice'
import { clearBusinessInsightWorkflow, clearCurrentToolId, fetchConversations, setCurrentConversation, setCurrentToolId, setNavigationFlag } from '@/store/conversationSlice'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import { fetchEfficiencyQuestionList } from '@/api/home'
import SdreamLoading from '@/components/SdreamLoading'
......@@ -297,6 +297,11 @@ export const Home: React.FC = () => {
// 仅在点击“业务洞察”工具按钮时调用业务洞察常见问题接口;其余情况保持原有逻辑
if (isBusinessInsightClick) {
setIsBusinessInsightMode(true)
// 清空业务洞察工作流状态
dispatch(clearBusinessInsightWorkflow())
// 保存业务洞察工具ID
dispatch(setCurrentToolId('6712395743242'))
safeSessionStorageSetItem('currentToolId', '6712395743242')
// 先清空旧数据
setOtherQuestions((prev: any) => ({
...prev,
......
......@@ -13,6 +13,14 @@ const initialState: ConversationState = {
shouldNavigateToNewConversation: false,
shouldSendQuestion: '',
currentToolId: undefined,
businessInsightWorkflow: {
mainWorkflowSessionId: null,
subWorkflowSessionId: null,
subWorkflowRecordType: null,
paramMap: {},
isInSubWorkflow: false,
pendingQuestion: null,
},
}
export const fetchConversations = createAsyncThunk(
......@@ -119,6 +127,47 @@ const conversationSlice = createSlice({
clearCurrentToolId: (state) => {
state.currentToolId = undefined
},
setBusinessInsightMainWorkflow: (state, action: PayloadAction<string>) => {
state.businessInsightWorkflow.mainWorkflowSessionId = action.payload
state.businessInsightWorkflow.isInSubWorkflow = false
},
setBusinessInsightSubWorkflow: (state, action: PayloadAction<{ sessionId: string, recordType: string }>) => {
state.businessInsightWorkflow.subWorkflowSessionId = action.payload.sessionId
state.businessInsightWorkflow.subWorkflowRecordType = action.payload.recordType
state.businessInsightWorkflow.isInSubWorkflow = true
state.businessInsightWorkflow.paramMap = {}
},
updateBusinessInsightParamMap: (state, action: PayloadAction<Record<string, string>>) => {
state.businessInsightWorkflow.paramMap = {
...state.businessInsightWorkflow.paramMap,
...action.payload,
}
},
clearBusinessInsightSubWorkflow: (state) => {
state.businessInsightWorkflow.subWorkflowSessionId = null
state.businessInsightWorkflow.subWorkflowRecordType = null
state.businessInsightWorkflow.isInSubWorkflow = false
state.businessInsightWorkflow.paramMap = {}
},
exitBusinessInsightSubWorkflow: (state) => {
state.businessInsightWorkflow.isInSubWorkflow = false
state.businessInsightWorkflow.subWorkflowSessionId = null
state.businessInsightWorkflow.subWorkflowRecordType = null
state.businessInsightWorkflow.paramMap = {}
},
setBusinessInsightPendingQuestion: (state, action: PayloadAction<string | null>) => {
state.businessInsightWorkflow.pendingQuestion = action.payload
},
clearBusinessInsightWorkflow: (state) => {
state.businessInsightWorkflow = {
mainWorkflowSessionId: null,
subWorkflowSessionId: null,
subWorkflowRecordType: null,
paramMap: {},
isInSubWorkflow: false,
pendingQuestion: null,
}
},
removeConversation: (state, action: PayloadAction<string>) => {
state.conversations = state.conversations.filter(conv => conv.conversationId !== action.payload)
if (state.currentConversationId === action.payload) {
......@@ -164,6 +213,6 @@ const conversationSlice = createSlice({
},
})
export const { setCurrentConversation, clearCurrentConversation, clearNavigationFlag, setNavigationFlag, clearShouldSendQuestion, setShouldSendQuestion, setCurrentToolId, clearCurrentToolId } = conversationSlice.actions
export const { setCurrentConversation, clearCurrentConversation, clearNavigationFlag, setNavigationFlag, clearShouldSendQuestion, setShouldSendQuestion, setCurrentToolId, clearCurrentToolId, setBusinessInsightMainWorkflow, setBusinessInsightSubWorkflow, updateBusinessInsightParamMap, clearBusinessInsightSubWorkflow, exitBusinessInsightSubWorkflow, setBusinessInsightPendingQuestion, clearBusinessInsightWorkflow } = conversationSlice.actions
export default conversationSlice.reducer
......@@ -21,6 +21,13 @@ interface AttachmentContentField {
label: string
type: string
required?: boolean
multiple?: boolean
value?: string
options?: {
id?: string
text?: string
type?: string
}[]
}
interface AttachmentContent {
......
......@@ -16,4 +16,12 @@ export interface ConversationState {
error: string | null
shouldSendQuestion: string
currentToolId: string | undefined
businessInsightWorkflow: {
mainWorkflowSessionId: string | null
subWorkflowSessionId: string | null
subWorkflowRecordType: string | null
paramMap: Record<string, string>
isInSubWorkflow: boolean
pendingQuestion: string | null
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment