feat: 会话窗口

dev/chat
Lei OT 2 years ago
parent 11e4a44de2
commit 58198062ff

@ -1,23 +1,20 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { configure } from 'mobx'
import {
createBrowserRouter,
RouterProvider,
} from 'react-router-dom'
import { AuthContext } from '@/stores/AuthContext'
import { ThemeContext } from '@/stores/ThemeContext'
import ConversationProvider from '@/stores/ConversationProvider';
import Auth from '@/stores/Auth'
import App from '@/views/App'
import Standlone from '@/views/Standlone'
import OrderFollow from '@/views/OrderFollow'
import ChatHistory from '@/views/ChatHistory'
import SalesManagement from '@/views/SalesManagement'
import DingdingQRCode from '@/views/DingdingQRCode'
import DingdingCallbak from '@/views/DingdingCallbak'
import AccountProfile from '@/views/AccountProfile'
import ErrorPage from '@/views/ErrorPage'
import React from 'react';
import ReactDOM from 'react-dom/client';
import { configure } from 'mobx';
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { AuthContext } from '@/stores/AuthContext';
import { ThemeContext } from '@/stores/ThemeContext';
import ConversationProvider from '@/views/Conversations/ConversationProvider';
import Auth from '@/stores/Auth';
import App from '@/views/App';
import Standlone from '@/views/Standlone';
import OrderFollow from '@/views/OrderFollow';
import ChatHistory from '@/views/ChatHistory';
import SalesManagement from '@/views/SalesManagement';
import DingdingQRCode from '@/views/DingdingQRCode';
import DingdingCallbak from '@/views/DingdingCallbak';
import AccountProfile from '@/views/AccountProfile';
import ErrorPage from '@/views/ErrorPage';
import Conversations from '@/views/Conversations/ChatWindow';
// import Conversations from '@/views/Conversations/ChatApp';
@ -28,8 +25,8 @@ configure({
computedRequiresReaction: true,
observableRequiresReaction: false,
reactionRequiresObservable: true,
disableErrorBoundaries: process.env.NODE_ENV == 'production'
})
disableErrorBoundaries: process.env.NODE_ENV == 'production',
});
const router = createBrowserRouter([
{
@ -38,12 +35,12 @@ const router = createBrowserRouter([
errorElement: <ErrorPage />,
children: [
{ index: true, element: <OrderFollow /> },
{ path: 'order/follow', element: <OrderFollow />},
{ path: 'chat/history', element: <ChatHistory />},
{ path: 'sales/management', element: <SalesManagement />},
{ path: 'order/chat', element: <Conversations />},
{ path: 'account/profile', element: <AccountProfile />},
]
{ path: 'order/follow', element: <OrderFollow /> },
{ path: 'chat/history', element: <ChatHistory /> },
{ path: 'sales/management', element: <SalesManagement /> },
{ path: 'order/chat', element: <Conversations /> },
{ path: 'account/profile', element: <AccountProfile /> },
],
},
{
path: '/p',
@ -51,22 +48,18 @@ const router = createBrowserRouter([
children: [
{ path: 'dingding/qrcode', element: <DingdingQRCode /> },
{ path: 'dingding/callback', element: <DingdingCallbak /> },
]
}
])
],
},
]);
ReactDOM.createRoot(document.getElementById('root')).render(
// <React.StrictMode>
<ThemeContext.Provider value={{colorPrimary: '#1ba784', borderRadius: 4}}>
<AuthContext.Provider value={{loginUser: {userId: 1, openId: '123456789'}, permissionList: ['view_chat', 'send_msg']}}>
<ThemeContext.Provider value={{ colorPrimary: '#1ba784', borderRadius: 4 }}>
<AuthContext.Provider value={{ loginUser: { userId: 1, openId: '123456789' }, permissionList: ['view_chat', 'send_msg'] }}>
<ConversationProvider>
<RouterProvider
router={router}
fallbackElement={() => <div>Loading...</div>}
/>
<RouterProvider router={router} fallbackElement={() => <div>Loading...</div>} />
</ConversationProvider>
</AuthContext.Provider>
</ThemeContext.Provider>
// </React.StrictMode>
)
);

@ -1,5 +1,94 @@
import { createContext, useContext } from 'react';
import React, { createContext, useContext, useState, useEffect } from 'react';
import { RealTimeAPI } from '@/lib/realTimeAPI';
import { useGetJson } from '@/hooks/userFetch';
export const ConversationContext = createContext();
export const useConversations = () => useContext(ConversationContext);
const URL = {
conversationList: 'http://127.0.0.1:4523/m2/3888351-0-default/142426823',
};
const WS_URL = 'ws://202.103.68.144:8888/whatever/';
// let realtimeAPI = new RealTimeAPI({ url: URL, protocol: 'aaa' });
let realtimeAPI = new RealTimeAPI({ url: WS_URL, protocol: 'WhatsApp' });
export const useConversations = () => {
const [errors, setErrors] = useState([]);
const [messages, setMessages] = useState([]);
const [conversations, setConversations] = useState({});
const [currentID, setCurrentID] = useState();
const [conversationsList, setConversationsList] = useState([]);
const [currentConversation, setCurrentConversation] = useState({
id: '', name: ''
});
const [url, setUrl] = useState(URL.conversationList);
const data = useGetJson(url);
const fetchConversations = () => {
setUrl(null); // reset url
setUrl(URL.conversationList);
}
useEffect(() => {
setConversationsList(data);
if (data && data.length) {
switchConversation(data[0]);
}
return () => {};
}, [data]);
const switchConversation = (cc) => {
console.log('switch to ', cc.id, cc);
setCurrentID(cc.id);
setCurrentConversation(cc);
};
const addError = (reason) => {
setErrors(prevErrors => [...prevErrors, { reason }]);
}
const addMessageToConversations = (customerId, message) => {
setConversations((prevList) => ({
...prevList,
[customerId]: [...(prevList[customerId] || []), message],
}));
};
const addMessage = (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
};
const handleMessage = (data) => {
const msg = data.result;
if (!msg) {
return false;
}
if (typeof msg.type === 'string' && msg.type === 'error') {
addError('Error Connecting to Server');
}
addMessage({ ...msg.message, sender: 'other', id: Date.now().toString(16) });
};
const sendMessage = (msg) => {
const msgObj = {
type: 'message',
message: msg,
};
realtimeAPI.sendMessage(msgObj);
addMessage(msgObj.message);
// debug:
// const msgObjR = {
// type: 'message',
// message: { type: 'text', text: { body: 'Received: ' + msg.text.body,} },
// };
// addMessage({ ...msgObjR.message, sender: 'other', id: Date.now().toString(16) });
};
realtimeAPI.onError(addError.bind(null, 'Error'));
realtimeAPI.onMessage(handleMessage);
realtimeAPI.onCompletion(addError.bind(null, 'Not Connected to Server'));
realtimeAPI.keepAlive(); // Ping Server
return { errors, messages, conversationsList, currentConversation, sendMessage, fetchConversations, switchConversation };
}
export const useConversationContext = () => useContext(ConversationContext);

@ -1,53 +0,0 @@
import React, { createContext, useContext, useState } from 'react';
import { ConversationContext } from '@/stores/ConversationContext';
import { RealTimeAPI } from '@/lib/realTimeAPI';
const URL = 'ws://202.103.68.144:8888/whatever/';
// let realtimeAPI = new RealTimeAPI({ url: URL, protocol: 'aaa' });
let realtimeAPI = new RealTimeAPI({ url: URL, protocol: 'WhatsApp' });
export const ConversationProvider = ({ children }) => {
const [errors, setErrors] = useState([]);
const [messages, setMessages] = useState([]);
const addError = (reason) => {
setErrors(prevErrors => [...prevErrors, { reason }]);
}
const addMessage = (message) => {
setMessages(prevMessages => [...prevMessages, message]);
}
const handleMessage = (data) => {
const msg = data.result;
if (!msg) {
return false;
}
if (typeof msg.type === 'string' && msg.type === 'error') {
addError('Error Connecting to Server');
}
addMessage({ ...msg.message, sender: 'other', id: Date.now().toString(16) });
}
const sendMessage = (msg) => {
const msgObj = {
type: 'message',
message: msg,
};
realtimeAPI.sendMessage(msgObj);
addMessage(msgObj.message);
}
realtimeAPI.onError(addError.bind(null, 'Error'));
realtimeAPI.onMessage(handleMessage);
realtimeAPI.onCompletion(addError.bind(null, 'Not Connected to Server'));
realtimeAPI.keepAlive(); // Ping Server
return (
<ConversationContext.Provider value={{ errors, messages, sendMessage }}>
{children}
</ConversationContext.Provider>
);
}
export default ConversationProvider;

@ -3,10 +3,10 @@ import { observer } from 'mobx-react';
import { Layout, List, Avatar } from 'antd';
import Messages from './Components/Messages';
import InputBox from './Components/InputBox';
import Conversations from './Components/ConversationsList';
import ConversationsList from './Components/ConversationsList';
import CustomerProfile from './Components/CustomerProfile';
import { useConversations } from '@/stores/ConversationContext';
import { useConversationContext } from '@/stores/ConversationContext';
import './Conversations.css';
import { useAuthContext } from '@/stores/AuthContext.js'
@ -24,19 +24,20 @@ const CList = [
*/
const ChatWindow = observer(() => {
const { loginUser: currentUser } = useAuthContext()
const { errors, messages, sendMessage } = useConversations();
const { errors, messages, sendMessage, currentConversation } = useConversationContext();
return (
<Layout className='full-height' style={{ maxHeight: 'calc(100% - 150px)', height: 'calc(100% - 150px)' }}>
<Sider width={220} theme={'light'} className='scrollable-column' style={{ height: '70vh' }}>
<Conversations conversations={CList} />
<ConversationsList />
</Sider>
<Content className='h70' style={{ maxHeight: '70vh', height: '70vh' }}>
<Layout style={{ height: '100%' }}>
<Header className='ant-layout-sider-light ant-card' style={{ paddingLeft: '10px' }}>
<List
dataSource={[{ name: 'Customer_1', label: 'Customer_1', key: 'Customer_1', value: 'Customer_1' }]}
<div>{currentConversation.name}</div>
{/* <List
dataSource={[]}
renderItem={(item, ii) => (
<List.Item actions={[<a key='list-loadmore-edit'>mark</a>]}>
<List.Item.Meta
@ -51,7 +52,7 @@ const ChatWindow = observer(() => {
/>
</List.Item>
)}
/>
/> */}
</Header>
<Content style={{ maxHeight: '70vh', height: '70vh' }}>
<div className='scrollable-column'>

@ -1,15 +1,18 @@
import { observer } from 'mobx-react';
import { List, Avatar } from 'antd';
import { useConversationContext } from '@/stores/ConversationContext';
/**
* []
*/
const Conversations = observer(({ conversations }) => {
const { switchConversation, conversationsList } = useConversationContext()
console.log(conversationsList);
return (
<List
dataSource={conversations}
dataSource={conversationsList || []}
renderItem={(item, ii) => (
<List.Item actions={[<a key='list-loadmore-edit'>mark</a>]}>
<List.Item onClick={() => switchConversation(item)} actions={[<a key='list-loadmore-edit'>mark</a>]}>
<List.Item.Meta
avatar={
<Avatar src={`https://api.dicebear.com/7.x/avataaars/svg?seed=${item.name}`} >
@ -17,7 +20,7 @@ const Conversations = observer(({ conversations }) => {
</Avatar>
}
title={item.name}
description='{最近的消息}'
// description='{}'
/>
</List.Item>
)}

@ -2,7 +2,7 @@ import { useEffect } from 'react';
import { observer } from 'mobx-react';
import { List, Avatar, Timeline } from 'antd';
import { MessageBox } from 'react-chat-elements';
import { useConversations } from '@/stores/ConversationContext';
import { useConversationContext } from '@/stores/ConversationContext';
const messagesTemplate = [
{
@ -14,7 +14,7 @@ const messagesTemplate = [
];
const Messages = observer(() => {
const { messages } = useConversations()
const { messages } = useConversationContext()
return (
<>

@ -0,0 +1,9 @@
import { ConversationContext, useConversations } from '@/stores/ConversationContext';
export const ConversationProvider = ({ children }) => {
const conversations = useConversations();
return <ConversationContext.Provider value={conversations}>{children}</ConversationContext.Provider>;
};
export default ConversationProvider;
Loading…
Cancel
Save