Commit 49fe1fae by weiyudumei

feat: 修复历史记录切换和字体大小问题

parent 7f5041ba
<?xml version="1.0" encoding="UTF-8"?>
<svg width="26px" height="26px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>历史对话</title>
<title>历史记录</title>
<defs>
<rect id="path-1" x="0" y="0" width="24" height="24"></rect>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="晓得-PC端---默认页" transform="translate(-32.000000, -601.000000)">
<g id="左侧导航栏" transform="translate(12.000000, 290.000000)">
<g id="历史对话备份" transform="translate(12.000000, 303.000000)">
<g id="历史记录备份" transform="translate(12.000000, 303.000000)">
<rect id="矩形" x="0" y="0" width="40" height="40" rx="14.2857143"></rect>
<g id="历史对话" transform="translate(8.000000, 8.000000)">
<g id="历史记录" transform="translate(8.000000, 8.000000)">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
......
......@@ -68,7 +68,7 @@
</filter>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="晓得-PC端---历史对话-空" transform="translate(-146.000000, -462.000000)">
<g id="晓得-PC端---历史记录-空" transform="translate(-146.000000, -462.000000)">
<g id="编组-2" transform="translate(80.000000, 152.000000)">
<g id="编组-10" transform="translate(66.000000, 310.000000)">
<mask id="mask-2" fill="white">
......
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>历史对话</title>
<title>历史记录</title>
<defs>
<rect id="path-1" x="0" y="0" width="24" height="24"></rect>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="晓得-PC端---默认页" transform="translate(-32.000000, -507.000000)">
<g id="左侧导航栏" transform="translate(12.000000, 290.000000)">
<g id="历史对话" transform="translate(8.000000, 209.000000)">
<g id="历史记录" transform="translate(8.000000, 209.000000)">
<rect id="矩形" x="4" y="0" width="40" height="40" rx="14.2857143"></rect>
<g transform="translate(12.000000, 8.000000)">
<mask id="mask-2" fill="white">
......
......@@ -5,7 +5,7 @@
<rect id="path-1" x="0" y="0" width="16" height="16"></rect>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="晓得-PC端---历史对话" transform="translate(-162.000000, -920.000000)">
<g id="晓得-PC端---历史记录" transform="translate(-162.000000, -920.000000)">
<g id="编组-2" transform="translate(80.000000, 152.000000)">
<g id="编组-13" transform="translate(8.000000, 751.000000)">
<g id="形状结合" transform="translate(74.000000, 17.000000)">
......
......@@ -5,7 +5,7 @@
<rect id="path-1" x="0" y="0" width="16" height="16"></rect>
</defs>
<g id="晓得---PC端页面-草稿" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="晓得-PC端---历史对话" transform="translate(-132.000000, -186.000000)">
<g id="晓得-PC端---历史记录" transform="translate(-132.000000, -186.000000)">
<g id="编组-2" transform="translate(80.000000, 152.000000)">
<g id="编组-5" transform="translate(32.000000, 24.000000)">
<g id="编组-4" transform="translate(20.000000, 8.000000)">
......
......@@ -14,11 +14,12 @@ interface ChatEditorProps {
onSubmit?: (value: string) => void
placeholders: string[]
showContentTips?: boolean
initialValue?: string
}
const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth, onChange, onFocus, onSubmit, placeholders, showContentTips = false }) => {
const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth, onChange, onFocus, onSubmit, placeholders, showContentTips = false, initialValue = '' }) => {
// const dispatch = useAppDispatch()
const [content, setContent] = useState('')
const [content, setContent] = useState(initialValue)
const editorRef = useRef<HTMLDivElement>(null)
const [currentPlaceholder, setCurrentPlaceholder] = useState(0)
const intervalRef = useRef<NodeJS.Timeout | null>(null)
......@@ -99,6 +100,17 @@ const ChatEditorBase: React.FC<ChatEditorProps & WithAuthProps> = ({ checkAuth,
}
}, [content])
// 处理initialValue的变化
useEffect(() => {
if (initialValue && editorRef.current) {
setContent(initialValue)
editorRef.current.textContent = initialValue
// 触发高度调整
editorRef.current.style.height = 'auto'
editorRef.current.style.height = `${editorRef.current.scrollHeight}px`
}
}, [initialValue])
const [token] = useLocalStorageState<string | undefined>(
'__TOKEN__',
{
......
......@@ -6,7 +6,7 @@ export const NAV_BAR_ITEMS = [
// { icon: Logo, label: '', key: 'logo' },
// { icon: '', label: '', key: 'line1' },
{ icon: AddNewChat, label: '新建对话', key: 'add' },
{ icon: HistoryChat, label: '历史对话', key: 'history' },
{ icon: HistoryChat, label: '历史记录', key: 'history' },
{ icon: Collect, label: '收藏', key: 'collect' },
// { icon: '', label: '', key: 'line2' },
// { icon: Tools, label: '工具', key: 'tools' },
......
......@@ -5,10 +5,12 @@ import { useEffect, useState } from 'react'
import { useDebounceFn } from 'ahooks'
import { containerVariants, itemVariants } from '../../motionAnimate'
import EmptyIcon from '@/assets/svg/empty.svg?react'
import { useAppSelector } from '@/store/hook'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import type { Conversation } from '@/types/conversation'
import { processConversationData } from '@/store/conversationSlice.helper'
import { setShouldSendQuestion } from '@/store/conversationSlice'
import { isMobile } from '@/utils'
import { fetchUserQaRecordPage } from '@/api/conversation'
interface HistoryBarListProps {
searchValue: string
......@@ -17,12 +19,36 @@ interface HistoryBarListProps {
export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onSetHistoryVisible }) => {
const navigate = useNavigate()
const dispatch = useAppDispatch()
const { currentConversationId, conversations } = useAppSelector(state => state.conversation)
const [allItems, setAllItems] = useState<Conversation[]>([])
const handleClick = (conversation: Conversation) => {
const handleClick = async (conversation: Conversation) => {
if (isMobile()) {
onSetHistoryVisible(false)
}
try {
// 获取该对话的详细记录
const res = await fetchUserQaRecordPage(conversation.conversationId)
if (res && res.data && res.data.length > 0) {
// 获取最后一条用户问题
const lastRecord = res.data[res.data.length - 1]
if (lastRecord.question) {
// 设置shouldSendQuestion,这样用户就可以继续对话
dispatch(setShouldSendQuestion(lastRecord.question))
// 等待状态设置完成后再导航
setTimeout(() => {
navigate(`/chat/${conversation.conversationId}`)
}, 50)
return
}
}
}
catch (error) {
console.error('Failed to fetch conversation details:', error)
}
navigate(`/chat/${conversation.conversationId}`)
}
......@@ -47,7 +73,7 @@ export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onS
{
allItems.map((item, index) => (
<motion.li
key={`${item.conversationId}-${index}`}
key={item.conversationId || `item-${item.conversationTitle}`}
custom={index}
variants={itemVariants}
initial="hidden"
......@@ -82,7 +108,7 @@ export const HistoryBarList: React.FC<HistoryBarListProps> = ({ searchValue, onS
: (
<div className="flex w-full h-full items-center justify-center flex-col">
<EmptyIcon />
<p className="text-[13px] text-[#27353C] mt-[16px]">暂无历史对话</p>
<p className="text-[13px] text-[#27353C] mt-[16px]">暂无历史记录</p>
</div>
)
)
......
......@@ -27,6 +27,7 @@ export const Chat: React.FC = () => {
const { shouldSendQuestion } = useAppSelector((state: RootState) => state.conversation)
const scrollableRef = useRef<HTMLDivElement | any>(null)
const position = useScroll(scrollableRef)
const currentIdRef = useRef<string | undefined>(id)
/** 处理正常stream的数据 */
const handleStreamMesageData = (msg: any, question: string) => {
......@@ -42,7 +43,7 @@ export const Chat: React.FC = () => {
{
...msg.content.data,
isShow: false,
answer: (newItems[lastIndex].answerList[0].answer || '') + msg.content.data.answer,
answer: (newItems[lastIndex].answerList?.[0]?.answer || '') + msg.content.data.answer,
},
],
}
......@@ -107,24 +108,20 @@ export const Chat: React.FC = () => {
const handleSubmitQuestion = async (question: string, productCode?: string) => {
const isNew = allItems.length <= 1
dispatch(setIsAsking(true))
// 添加用户提问的问题
setAllItems(prevItems => [
...prevItems,
{
role: 'user',
question,
} as ChatRecord,
])
// 检查token
await fetchCheckTokenApi()
// 添加一条空的ai问题
// 一次性添加用户问题和空的AI回答
setAllItems(prevItems => [
...prevItems,
{
role: 'user',
question,
} as ChatRecord,
{
role: 'ai',
answerList: [{}],
answerList: [{ answer: '' }],
} as ChatRecord,
])
let fetchUrl = `/conversation/api/conversation/mobile/v1/submit_question_stream`
......@@ -135,7 +132,7 @@ export const Chat: React.FC = () => {
fetchUrl,
{
question,
conversationId: id,
conversationId: currentIdRef.current,
stream: true,
productCode,
},
......@@ -166,10 +163,6 @@ export const Chat: React.FC = () => {
const res = await fetchUserQaRecordPage(conversationId)
const messages = [{ role: 'system' } as ChatRecord, ...processApiResponse(res.data)]
setAllItems(messages) // 假设 API 返回的数据结构符合 ChatRecord[]
if (shouldSendQuestion) {
handleSubmitQuestion(shouldSendQuestion)
dispatch(clearShouldSendQuestion())
}
}
catch (error) {
console.error('Failed to fetch chat records:', error)
......@@ -178,7 +171,7 @@ export const Chat: React.FC = () => {
finally {
setIsLoading(false)
}
}, [shouldSendQuestion])
}, [])
/** 点击滚动到底部 */
const scrollToBottom = () => {
......@@ -187,10 +180,22 @@ export const Chat: React.FC = () => {
useEffect(() => {
if (id) {
currentIdRef.current = id
getUserQaRecordPage(id)
}
}, [id])
// 处理shouldSendQuestion的变化 - 自动发送问题
useEffect(() => {
if (shouldSendQuestion && currentIdRef.current && !isLoading) {
// 确保历史记录加载完成后再发送问题
setTimeout(() => {
handleSubmitQuestion(shouldSendQuestion)
dispatch(clearShouldSendQuestion())
}, 100)
}
}, [shouldSendQuestion, isLoading])
return (
<div className={styles.scrollView}>
<div className={`${styles.chatPage} relative`}>
......@@ -211,7 +216,7 @@ export const Chat: React.FC = () => {
>
<div className={styles.inter}>
{allItems.map((record, index) => (
<div className="w-full chatItem max-w-[912px] mx-auto" key={index}>
<div className="w-full chatItem max-w-[912px] mx-auto" key={`${record.role}-${index}-${record.question || record.answerList?.[0]?.answer || ''}`}>
{record.role === 'system' && <ChatWelcome />}
{record.role === 'user' && <ChatItemUser record={record} />}
{record.role === 'ai' && <ChatAnswerBox onSubmitQuestion={handleSubmitQuestion} isLastAnswer={index === allItems.length - 1} showIndex={0} record={record} index={index} />}
......
......@@ -13,7 +13,12 @@ export const ChatWelcome: React.FC = () => {
style={{ background: '#F7FAFD' }}
>
<div className="content">
<p className="text-[16px] sm:text-[18px] font-medium text-[#333]">您好,有什么我可以帮您的吗?</p>
<p
className="font-medium text-[#333]"
style={{ fontSize: '16px' }}
>
您好,有什么我可以帮您的吗?
</p>
{/* <p className="text-[15px] mt-[4px] sm:mt-[8px] sm:text-13px text-[#27353C] font-300">作为您的智能保险伙伴,您有各类专业相关的问题都可以抛给我哟~让我们互相帮助共同成长吧~</p> */}
</div>
</motion.div>
......
......@@ -16,7 +16,8 @@ export function processApiResponse(data: OriginalRecord[]): ChatRecord[] {
})
chatRecord.push({
role: 'ai',
...record,
answerList: record.answerList,
question: record.question,
})
}
})
......
......@@ -11,7 +11,8 @@ import { createConversation, fetchConversations } from '@/store/conversationSlic
import { useAppDispatch } from '@/store/hook'
import { fetchQuestionList } from '@/api/home'
import SdreamLoading from '@/components/SdreamLoading'
import { fetchLoginByToken } from '@/api/common'
// import { fetchLoginByToken } from '@/api/common'
import { fetchLoginByUid } from '@/api/common'
function getAnimationProps(delay: number) {
return {
......@@ -71,7 +72,7 @@ export const Home: React.FC = () => {
configTypeList: ['06', '07'],
}
const res = await fetchQuestionList(param)
if (res.ok) {
if (res && res.data) {
for (let index = 0; index < res.data.length; index++) {
const element = res.data[index]
if (element.configType === '06') {
......@@ -96,8 +97,8 @@ export const Home: React.FC = () => {
const initConversation = () => {
const fromCollect = location.state?.fromCollect
// 在组件挂载时执行dispatch,但只执行一次
if (!fromCollect) {
// 只有在访问首页时才创建新对话,如果已经在聊天页面则不创建
if (!fromCollect && location.pathname === '/') {
dispatch(
createConversation({
conversationData: {},
......@@ -123,11 +124,11 @@ export const Home: React.FC = () => {
const url = new URL(window.location.href)
// 获取查询参数
const searchParams = new URLSearchParams(url.search)
const loginCode = searchParams.get('loginCode')
const _loginCode = searchParams.get('loginCode')
const res = await fetchLoginByToken(loginCode)
// const res = await fetchLoginByToken(loginCode)
// 模拟登录 可以用来测试
// const res = await fetchLoginByUid('123123')
const res = await fetchLoginByUid('123123')
if (res.data) {
setToken(res.data.token)
......
......@@ -303,7 +303,7 @@ const dummyContent02 = [
<br />
您有权查询、复制、更正或补充您的个人信息。您可以通过以下方式进行:
<br />
(1)您可以通过点击页面左侧导航键进入“历史会话”板块,查询您的历史对话信息。
(1)您可以通过点击页面左侧导航键进入“历史会话”板块,查询您的历史记录信息。
<br />
(2)您可以点击会话输入框底部的“会话收藏”按键,查询您收藏的会话信息。
<br />
......@@ -313,7 +313,7 @@ const dummyContent02 = [
<br />
您有权删除您的个人信息。您可以通过以下方式进行:
<br />
(1)您可以通过点击页面左侧导航键进入“历史会话”板块,删除您的历史对话信息。
(1)您可以通过点击页面左侧导航键进入“历史会话”板块,删除您的历史记录信息。
<br />
(2)如您无法通过服务页面删除您的个人信息,您可以拨打“(一)查询、复制、更正和补充您的信息”中列明的联系电话,联系我们协助删除您的个人信息。
<br />
......
......@@ -84,6 +84,9 @@ const conversationSlice = createSlice({
clearShouldSendQuestion: (state) => {
state.shouldSendQuestion = ''
},
setShouldSendQuestion: (state, action: PayloadAction<string>) => {
state.shouldSendQuestion = action.payload
},
addConversation: (state, action: PayloadAction<Conversation>) => {
state.conversations.unshift(action.payload)
},
......@@ -117,7 +120,10 @@ const conversationSlice = createSlice({
})
.addCase(createConversation.fulfilled, (state, action) => {
state.isLoading = false
// 只有在需要导航到新对话时才更新currentConversationId
if (action.payload.shouldNavigate) {
state.currentConversationId = action.payload.conversation.conversationId
}
state.shouldNavigateToNewConversation = action.payload.shouldNavigate
state.shouldSendQuestion = action.payload.shouldSendQuestion
})
......@@ -132,6 +138,6 @@ const conversationSlice = createSlice({
},
})
export const { setCurrentConversation, clearCurrentConversation, clearNavigationFlag, clearShouldSendQuestion } = conversationSlice.actions
export const { setCurrentConversation, clearCurrentConversation, clearNavigationFlag, clearShouldSendQuestion, setShouldSendQuestion } = conversationSlice.actions
export default conversationSlice.reducer
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