Commit 30e06255 by HoMeTown

feat: 新建会话

parent 7a829213
......@@ -4,6 +4,14 @@ import http from '@/utils/request'
* 查询用户历史会话列表
* @params
*/
export function queryUserConversationPage<T>(data: T) {
export function fetchQueryUserConversationPage<T>(data: T) {
return http.post('/conversation/api/conversation/mobile/v1/query_user_conversation_page', data)
}
/**
* 创建会话
* @params { * }
*/
export function fetchCreateConversation<T>(data: T) {
return http.post('/conversation/api/conversation/mobile/v1/create_conversation', data)
}
......@@ -33,7 +33,7 @@ export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
const [showLoginTip, setShowLoginTip] = useState(!token)
const login = async () => {
const res = await fetchLoginByUid('123')
const res = await fetchLoginByUid('123123')
if (res.data) {
setToken(res.data.token)
setIsLoggedIn(true)
......
......@@ -5,7 +5,7 @@ import EmptyIcon from '@/assets/svg/empty.svg?react'
import { useAppSelector } from '@/store/hook'
export const HistoryBarList: React.FC = () => {
const { conversations } = useAppSelector(state => state.conversation)
const { currentConversationId, conversations } = useAppSelector(state => state.conversation)
return (
conversations.length !== 0
......@@ -30,7 +30,11 @@ export const HistoryBarList: React.FC = () => {
{
item.conversationId
? (
<Button color="primary" variant="light" className="text-left w-full text-[#333] rounded-[23px] data-[hover=true]:bg-[#E5F6FF] data-[hover=true]:text-primary">
<Button
color="primary"
variant="light"
className={`text-left w-full text-[#333] rounded-[23px] data-[hover=true]:bg-[#E5F6FF] data-[hover=true]:text-primary ${currentConversationId === item.conversationId ? 'bg-[#E5F6FF] text-primary' : ''}`}
>
<div className="w-full text-nowrap text-ellipsis overflow-hidden">
<span>{item.conversationTitle}</span>
</div>
......
import type React from 'react'
import { motion } from 'framer-motion'
import { useEffect } from 'react'
import { useNavigate } from 'react-router-dom'
import styles from './Navbar.module.less'
import { NavBarItem } from './components/NavBarItem'
import { User } from './components/User'
import { clearNavigationFlag, createConversation } from '@/store/conversationSlice'
import type { WithAuthProps } from '@/auth/withAuth'
import { withAuth } from '@/auth/withAuth'
import { NAV_BAR_ITEMS } from '@/config/nav'
import { useAppDispatch, useAppSelector } from '@/store/hook'
interface NavbarProps {
isHistoryVisible: boolean
......@@ -13,10 +17,23 @@ interface NavbarProps {
}
const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, checkAuth, onSetHistoryVisible }) => {
const dispatch = useAppDispatch()
const navigate = useNavigate()
const { currentConversationId, shouldNavigateToNewConversation } = useAppSelector(state => state.conversation)
const handleCreateConversation = () => {
dispatch(createConversation({}))
}
const handleClick = (type: string | undefined) => {
if (!checkAuth())
return
if (type === 'add') {
handleCreateConversation()
}
if (type === 'history') {
onSetHistoryVisible(!isHistoryVisible)
}
......@@ -25,6 +42,13 @@ const NavbarBase: React.FC<NavbarProps & WithAuthProps> = ({ isHistoryVisible, c
onSetHistoryVisible(false)
}
useEffect(() => {
if (shouldNavigateToNewConversation && currentConversationId) {
navigate(`/chat/${currentConversationId}`)
dispatch(clearNavigationFlag())
}
}, [shouldNavigateToNewConversation, currentConversationId, navigate, dispatch])
return (
<motion.nav className="h-full flex-shrink-0 flex flex-col items-center justify-center">
<motion.div className={`${styles.layoutNavBarAgent} sm:flex hidden w-[64px] bg-white gap-[24px]`}>
......
import React from 'react'
import { motion } from 'framer-motion'
import { Button, Tooltip } from '@nextui-org/react'
import { useNavigate } from 'react-router-dom'
import { NavBarDivider } from '../NavBarDivider'
import styles from './NavBarItem.module.less'
import Logo from '@/assets/svg/logo.svg?react'
......@@ -12,12 +13,22 @@ interface NavBarItemProps {
type: string
}
export const NavBarItem: React.FC<NavBarItemProps> = ({ onClick, icon, label, type }) => {
const navigate = useNavigate()
const handleClickLogo = () => {
navigate('/')
}
if (label === '' && icon === '') {
return <NavBarDivider />
}
if (label === '' && icon !== '') {
return (
<motion.div className="nav-logo">
<motion.div
whileHover={{ scale: 1.05 }}
transition={{ type: 'spring', stiffness: 400, damping: 10 }}
className="nav-logo cursor-pointer"
onClick={handleClickLogo}
>
<Logo />
</motion.div>
)
......
import React from 'react'
import React, { useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { useAppDispatch, useAppSelector } from '@/store/hook'
import { setCurrentConversation } from '@/store/conversationSlice'
export const Chat: React.FC = () => {
const { chatId } = useParams<{ chatId: string }>()
const { id } = useParams<{ id: string }>()
const dispatch = useAppDispatch()
const { currentConversationId } = useAppSelector(state => state.conversation)
useEffect(() => {
if (id && id !== currentConversationId) {
dispatch(setCurrentConversation(id))
// dispatch(fetchConversationDetails(id))
}
}, [id, currentConversationId, dispatch])
return (
<h1>
聊天页面 - Chat ID:
{chatId}
{id}
</h1>
)
}
......@@ -7,7 +7,7 @@ export const AppRoutes: React.FC = () => {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/chat/:chatId" element={<Chat />} />
<Route path="/chat/:id" element={<Chat />} />
</Routes>
)
}
......@@ -2,20 +2,21 @@ import type { PayloadAction } from '@reduxjs/toolkit'
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { processConversationData } from './conversationSlice.helper'
import type { Conversation, ConversationState } from '@/types/conversation'
import { queryUserConversationPage } from '@/api/conversation'
import { fetchCreateConversation, fetchQueryUserConversationPage } from '@/api/conversation'
const initialState: ConversationState = {
conversations: [],
currentConversationId: null,
isLoading: false,
error: null,
shouldNavigateToNewConversation: false,
}
export const fetchConversations = createAsyncThunk(
'conversation/fetchConversations',
async (_, { rejectWithValue }) => {
try {
const response = await queryUserConversationPage({
const response = await fetchQueryUserConversationPage({
keyword: '',
pageNum: 0,
pageSize: 100,
......@@ -30,6 +31,22 @@ export const fetchConversations = createAsyncThunk(
},
)
export const createConversation = createAsyncThunk<
{ conversation: Conversation, shouldNavigate: boolean },
Partial<Conversation>,
{ state: { conversation: ConversationState } }
>(
'conversation/createConversation',
async (conversationData, { dispatch }) => {
const response = await fetchCreateConversation(conversationData)
const newConversation = response.data
dispatch(fetchConversations())
return { conversation: newConversation, shouldNavigate: true }
},
)
const conversationSlice = createSlice({
name: 'conversation',
initialState,
......@@ -40,6 +57,9 @@ const conversationSlice = createSlice({
addConversation: (state, action: PayloadAction<Conversation>) => {
state.conversations.unshift(action.payload)
},
clearNavigationFlag: (state) => {
state.shouldNavigateToNewConversation = false
},
removeConversation: (state, action: PayloadAction<string>) => {
state.conversations = state.conversations.filter(conv => conv.conversationId !== action.payload)
if (state.currentConversationId === action.payload) {
......@@ -61,9 +81,22 @@ const conversationSlice = createSlice({
state.isLoading = false
state.error = action.payload as string
})
.addCase(createConversation.pending, (state) => {
state.isLoading = true
state.error = null
})
.addCase(createConversation.fulfilled, (state, action) => {
state.isLoading = false
state.currentConversationId = action.payload.conversation.conversationId
state.shouldNavigateToNewConversation = action.payload.shouldNavigate
})
.addCase(createConversation.rejected, (state, action) => {
state.isLoading = false
state.error = action.error.message || 'Failed to create conversation'
})
},
})
export const { setCurrentConversation } = conversationSlice.actions
export const { setCurrentConversation, clearNavigationFlag } = conversationSlice.actions
export default conversationSlice.reducer
......@@ -11,5 +11,6 @@ export interface ConversationState {
conversations: Conversation[]
currentConversationId: string | null
isLoading: boolean
shouldNavigateToNewConversation: boolean
error: 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