Commit b94fe07a by Liu

Merge branch 'test01' into test-tactics

# Conflicts:
#	src/pages/Home/HomeNew.tsx
parents a7da634c 407bb3c3
......@@ -149,7 +149,8 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const storedToolId = safeSessionStorageGetItem('currentToolId')
// 如果 currentToolId 是空字符串,视为 null,确保通用模式能正确高亮
setSessionToolId(storedToolId && storedToolId.trim() ? storedToolId : null)
}, [toolIdFromUrl])
// 当路由切换(如点击历史记录)时,同步最新的 sessionStorage,避免同标签页删除后状态不同步
}, [toolIdFromUrl, location.pathname])
const startAnimation = () => {
intervalRef.current = setInterval(() => {
......@@ -403,10 +404,9 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
const toolIdStr = String(tool.toolId)
const isSelectedByState = selectedToolId && toolIdStr === String(selectedToolId)
const isSelectedBySession = !selectedToolId && sessionToolId && toolIdStr === String(sessionToolId)
const isSelectedByUrl = !selectedToolId && !sessionToolId && toolIdFromUrl && toolIdStr === String(toolIdFromUrl)
// 通用模式高亮:路由内没有 toolId 或 toolId 为空时默认高亮,点击后也要高亮
const isGeneralMode = tool.toolName === '通用模式' && isToolBtnActive && !selectedToolId && !sessionToolId && !toolIdFromUrl
const isSelected = isSelectedByState || isSelectedBySession || isSelectedByUrl || isGeneralMode
const isSelected = isSelectedByState || isSelectedBySession || isGeneralMode
const baseBtnClass
= 'w-auto h-[32px] px-3 rounded-full shadow-none text-[12px] flex items-center gap-2 transition-all duration-200 border'
......
......@@ -33,8 +33,6 @@ export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onS
})
if (conversation.toolId) {
sessionStorage.setItem('currentToolId', conversation.toolId)
// eslint-disable-next-line no-console
console.log('889999999999:', conversation.toolId)
dispatch(setCurrentToolId(conversation.toolId))
}
else {
......
......@@ -12,8 +12,7 @@ import { ChatEditor } from '@/components/ChatEditor'
import type { ChatRecord } from '@/types/chat'
import { fetchUserQaRecordPage } from '@/api/conversation'
import { fetchCheckTokenApi, fetchStreamResponse } from '@/api/chat'
import { fetchEfficiencyQuestionList, fetchToolList } from '@/api/home'
// import { mockFetchToolList } from '@/api/mock/home'
import { fetchToolList } from '@/api/home'
import { clearCurrentToolId, clearShouldSendQuestion, fetchConversations, setCurrentToolId } from '@/store/conversationSlice'
import { getUserRolesForApi } from '@/lib/utils'
import type { RootState } from '@/store'
......@@ -93,23 +92,6 @@ export const Chat: React.FC = () => {
sessionToolId: null,
})
// 首次进入 /chat/:id 时,拉取一次通用模式下的常见问题(toolId: ''),后续仍按现有逻辑走
useEffect(() => {
;(async () => {
try {
// 仅在本标签页首次进入时调用一次
if (sessionStorage.getItem('__INITIAL_FAQ_LOADED__'))
return
sessionStorage.setItem('__INITIAL_FAQ_LOADED__', 'true')
const sessionToolId = sessionStorage.getItem('currentToolId') || ''
await fetchEfficiencyQuestionList({ toolId: sessionToolId })
}
catch (error) {
console.error('初始化通用模式常见问题失败:', error)
}
})()
}, [])
// 进入聊天页时,同步当前链接和缓存中的 toolId 到页面上展示
useEffect(() => {
try {
......@@ -238,7 +220,9 @@ export const Chat: React.FC = () => {
/** 提交问题 */
const handleSubmitQuestion = async (question: string, productCode?: string, toolId?: string) => {
const resolvedToolId = toolId ?? currentToolId ?? undefined
// 优先读取缓存中的 toolId,再回退到传参或 Redux
const sessionToolId = sessionStorage.getItem('currentToolId') ?? undefined
const resolvedToolId = toolId ?? sessionToolId ?? currentToolId ?? undefined
// 停止之前的请求
if (abortControllerRef.current) {
abortControllerRef.current.abort()
......
......@@ -80,6 +80,42 @@ export const Home: React.FC = () => {
}
}
// 刷新问题列表
const handleRefreshQuestions = useCallback(async () => {
// 先清空旧数据
setOtherQuestions((prev: any) => ({
...prev,
content: [],
}))
setIsDataLoaded(false) // 重置加载状态
try {
// 获取当前的 toolId,优先从 sessionStorage 获取,其次从 Redux 获取
const sessionToolId = safeSessionStorageGetItem('currentToolId') || ''
const searchParams = new URLSearchParams(location.search)
const urlToolId = searchParams.get('toolId') || ''
const finalToolId = sessionToolId || urlToolId
// 调用接口重新获取问题列表
const res = await fetchEfficiencyQuestionList({
toolId: finalToolId,
})
if (res && res.data && res.data.questions) {
setOtherQuestions((prev: any) => ({
...prev,
content: res.data.questions || [],
}))
}
}
catch (error) {
console.error('刷新问题列表失败:', error)
throw error // 抛出错误,让 QuestionList 组件处理
}
finally {
setIsDataLoaded(true) // 无论成功失败都标记为已加载
}
}, [location.search])
// 处理工具按钮点击
const requestIdRef = useRef(0) // 标记最新请求,避免旧响应覆盖
const _handleToolClick = useCallback(async (isToolBtn: boolean, toolId?: string, ignoreUrlToolId?: boolean) => {
......@@ -174,8 +210,26 @@ export const Home: React.FC = () => {
let res = {} as any
if (viteOutputObj === 'inner') {
if (_loginCode) {
// 每次进入页面调用 sso_login 时,先清空 sessionStorage 中的 currentToolId
// 避免关闭标签页后再次打开时使用上次的历史 toolId
safeSessionStorageRemoveItem('currentToolId')
res = await fetchLoginByToken(_loginCode)
if (res.data) {
// 登录成功后先打印完整的原始链接(删除之前)
// eslint-disable-next-line no-console
console.log('登录成功,删除前完整链接:', window.location.href)
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch(clearCurrentToolId())
safeSessionStorageRemoveItem('currentToolId')
const currentUrl = new URL(window.location.href)
if (currentUrl.searchParams.has('toolId')) {
currentUrl.searchParams.delete('toolId')
// 使用 replace 避免产生新的历史记录
window.history.replaceState({}, '', currentUrl.toString())
}
// 删除后打印链接
// eslint-disable-next-line no-console
console.log('登录成功,删除后完整链接:', window.location.href)
setToken(res.data.token)
// 主动触发 storage 事件,确保其他组件能监听到变化
window.dispatchEvent(
......@@ -187,19 +241,7 @@ export const Home: React.FC = () => {
storageArea: localStorage,
}),
)
// 登录成功后强制重置为通用模式:清除所有 toolId 相关状态
// 1. 清除 Redux 中的 currentToolId
dispatch(clearCurrentToolId())
// 2. 清除 sessionStorage 中的 currentToolId
safeSessionStorageRemoveItem('currentToolId')
// 3. 清除 URL 中的 toolId 参数(如果存在)
const currentUrl = new URL(window.location.href)
if (currentUrl.searchParams.has('toolId')) {
currentUrl.searchParams.delete('toolId')
// 使用 replace 避免产生新的历史记录
window.history.replaceState({}, '', currentUrl.toString())
}
// 4. 触发自定义事件,通知 ChatEditor 强制重置为通用模式
// 触发自定义事件,通知 ChatEditor 强制重置为通用模式
window.dispatchEvent(new CustomEvent('forceResetToGeneralMode'))
initConversation()
dispatch(fetchConversations())
......@@ -214,6 +256,14 @@ export const Home: React.FC = () => {
// 模拟登录 可以用来测试
res = await fetchLoginByUid('123123')
if (res.data) {
// 登录成功后先清理旧状态,避免沿用上一次的工具模式
dispatch(clearCurrentToolId())
safeSessionStorageRemoveItem('currentToolId')
const currentUrl = new URL(window.location.href)
if (currentUrl.searchParams.has('toolId')) {
currentUrl.searchParams.delete('toolId')
window.history.replaceState({}, '', currentUrl.toString())
}
setToken(res.data.token)
// 主动触发 storage 事件,确保其他组件能监听到变化
window.dispatchEvent(
......@@ -225,18 +275,7 @@ export const Home: React.FC = () => {
storageArea: localStorage,
}),
)
// 登录成功后强制重置为通用模式:清除所有 toolId 相关状态
// 1. 清除 Redux 中的 currentToolId
dispatch(clearCurrentToolId())
// 2. 清除 sessionStorage 中的 currentToolId
safeSessionStorageRemoveItem('currentToolId')
// 3. 清除 URL 中的 toolId 参数(如果存在)
const currentUrl = new URL(window.location.href)
if (currentUrl.searchParams.has('toolId')) {
currentUrl.searchParams.delete('toolId')
window.history.replaceState({}, '', currentUrl.toString())
}
// 4. 触发自定义事件,通知 ChatEditor 强制重置为通用模式
// 触发自定义事件,通知 ChatEditor 强制重置为通用模式
window.dispatchEvent(new CustomEvent('forceResetToGeneralMode'))
initConversation()
dispatch(fetchConversations())
......@@ -290,8 +329,6 @@ export const Home: React.FC = () => {
)}
<div className="w-full">
<div className="flex justify-center gap-[20px]">
{!isFromTactics && (
<>
{/* 左侧区域 - 产品问答和您可以试着问我 */}
<div
className="flex flex-col gap-[20px] items-center overflow-y-auto scrollbar-hide"
......@@ -320,6 +357,7 @@ export const Home: React.FC = () => {
iconImg={HomeIcon2}
isToolBtn={shouldChangeStyle}
isLoaded={isDataLoaded}
onRefresh={handleRefreshQuestions}
/>
</motion.div>
{shouldChangeStyle && (
......@@ -328,8 +366,6 @@ export const Home: React.FC = () => {
</div>
)}
</div>
</>
)}
{/* 右侧区域 */}
<div className="hidden sm:flex flex-1 h-full">
<div
......
......@@ -22,6 +22,7 @@ interface QuestionListProps {
height?: string
isToolBtn?: boolean
isLoaded?: boolean
onRefresh?: () => Promise<void>
}
const containerVariants = {
hidden: {},
......@@ -69,6 +70,7 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({
displayCount: _displayCount = 6,
isToolBtn = false,
isLoaded = false,
onRefresh,
}) => {
const [isRotating, setIsRotating] = useState(false)
const [displayedItems, setDisplayedItems] = useState<string[]>([])
......@@ -85,11 +87,25 @@ const QuestionListBase: React.FC<QuestionListProps & WithAuthProps> = ({
setDisplayedItems(indices.map(index => questions[index]))
}, [questions, actualDisplayCount])
const handleRefresh = () => {
const handleRefresh = async () => {
// 如果没有提供 onRefresh 回调,则不执行任何操作
if (!onRefresh) {
return
}
setIsRotating(true)
updateDisplayedItems()
try {
// 重新调用接口获取新问题
await onRefresh()
}
catch (error) {
console.error('刷新问题列表失败:', error)
// 接口调用失败时不回退到随机选择,保持当前状态
}
finally {
setIsRotating(false)
}
}
const handleClick = (item: string) => {
if (checkAuth() && !isClicking) {
setIsClicking(true)
......
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