Merge branch 'main' into dev/chat

# Conflicts:
#	src/views/ChatHistory.jsx
dev/chat
Lei OT 2 years ago
commit 4ceeff2ef3

@ -1,9 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { createBrowserRouter, RouterProvider, useNavigate } from 'react-router-dom'
import { ThemeContext } from '@/stores/ThemeContext'
import AuthApp from '@/views/AuthApp'
import Standlone from '@/views/Standlone'
import MobileApp from '@/views/MobileApp'
import OrderFollow from '@/views/OrderFollow'
import ChatHistory from '@/views/ChatHistory'
import SalesManagement from '@/views/SalesManagement'
@ -12,6 +13,8 @@ import DingdingCallback from '@/views/dingding/Callback'
import AccountProfile from '@/views/AccountProfile'
import ErrorPage from '@/components/ErrorPage'
import Conversations from '@/views/Conversations/ChatWindow'
import MobileConversation from '@/views/mobile/Conversation'
import MobileChat from '@/views/mobile/Chat'
import MobileLogin from '@/views/mobile/Login'
import useAuthStore from '@/stores/AuthStore'
import '@/assets/index.css'
@ -39,13 +42,15 @@ const router = createBrowserRouter([
children: [
{ path: 'dingding/qrcode', element: <DingdingQRCode /> },
{ path: 'dingding/callback', element: <DingdingCallback /> },
{ path: 'mobile-login', element: <MobileLogin />},
],
},
{
path: '/m',
element: <Standlone />,
element: <MobileApp />,
children: [
{ path: 'login', element: <MobileLogin /> },
{ path: 'conversation', element: <MobileConversation /> },
{ path: 'chat', element: <MobileChat /> },
],
},
])

@ -4,23 +4,24 @@ import { useEffect } from 'react'
import { useParams } from 'react-router-dom'
import useOrderStore from '@/stores/OrderStore'
import useConversationStore from '@/stores/ConversationStore'
import QuotesHistory from './QuotesHistory'
const CustomerProfile = (() => {
const { notification } = App.useApp()
const { order_sn: order_sn } = useParams()
const currentOrder = useConversationStore((state) => state.currentConversation?.coli_sn || '')
const { orderDetail, customerDetail, lastQuotation, quotationList,
fetchOrderDetail, setOrderPropValue
} = useOrderStore()
useEffect(() => {
if (order_sn) fetchOrderDetail(order_sn)
}, [order_sn])
if (currentOrder) fetchOrderDetail(currentOrder)
}, [currentOrder])
let regularText = ''
if (orderDetail.buytime > 0) regularText = '(R' + orderDetail.buytime + ')'
if (order_sn) {
if (currentOrder) {
return (
<div className=' divide-x-0 divide-y divide-dashed divide-gray-300 '>
<Card className='p-2 '
@ -80,7 +81,7 @@ const CustomerProfile = (() => {
<QuotesHistory dataSource={quotationList} />
</Flex>
</Flex>
<p className='p-2 shadow-inner overflow-auto m-0 break-words whitespace-pre-wrap ' dangerouslySetInnerHTML={{__html: orderDetail.order_detail}}></p>
<p className='p-2 shadow-inner overflow-auto m-0 break-words whitespace-pre-wrap' dangerouslySetInnerHTML={{__html: orderDetail.order_detail}}></p>
</div>
)
} else {

@ -0,0 +1,68 @@
import '@/assets/App.css'
import AppLogo from '@/assets/logo-gh.png'
import { useThemeContext } from '@/stores/ThemeContext'
import useAuthStore from '@/stores/AuthStore'
import { App as AntApp, Col, ConfigProvider, Empty, Layout, Row, Typography, theme, Space, Avatar } from 'antd'
import { DownOutlined } from '@ant-design/icons'
import { NavLink, Outlet } from 'react-router-dom'
const { Header, Footer, Content } = Layout
const { Title } = Typography
function MobileApp() {
const {colorPrimary, borderRadius} = useThemeContext()
const loginUser = useAuthStore(state => state.loginUser)
const {
token: { colorBgContainer },
} = theme.useToken()
function renderLayout() {
return (
<Layout>
<Header className='header' style={{ position: 'sticky', top: 0, zIndex: 1, width: '100%', background: 'white' }}>
<Row gutter={{ md: 24 }} align='middle'>
<Col flex="auto" style={{ color: "white", marginBottom: "0", display: "flex", justifyContent: "center" }}>
<NavLink to='/'>
<img src={AppLogo} className='logo' alt='App logo' />
</NavLink>
<Space><Avatar
src={loginUser.avatarUrl}>{loginUser?.username?.substring(1)}</Avatar><span style={{ color: colorPrimary }}>{loginUser.username}</span><DownOutlined /></Space>
</Col>
</Row>
</Header>
<Layout>
<Content
style={{
padding: 0,
margin: 0,
minHeight: 200,
background: colorBgContainer,
}}>
<Outlet />
</Content>
</Layout>
<Footer>桂林海纳国际旅行社有限公司</Footer>
</Layout>
)
}
return (
<ConfigProvider
theme={{
token: {
colorPrimary: colorPrimary,
borderRadius: borderRadius
},
algorithm: theme.defaultAlgorithm,
}}
renderEmpty={() => <Empty description={false} />}
>
<AntApp>
{renderLayout()}
</AntApp>
</ConfigProvider>
)
}
export default MobileApp

@ -15,8 +15,7 @@ import { useShallow } from 'zustand/react/shallow'
const { RangePicker } = DatePicker
// eslint-disable-next-line react/display-name
const AdvanceSearchForm = memo(function ({ initialValues, onSubmit }) {
const AdvanceSearchForm = memo(function noName({ initialValues, onSubmit }) {
const DATE_RANGE_PRESETS = [
{
@ -43,11 +42,14 @@ const AdvanceSearchForm = memo(function ({ initialValues, onSubmit }) {
label: '本年',
value: [dayjs().startOf('y'), dayjs().endOf('y')],
},
];
]
const [form] = Form.useForm()
function handleSubmit(values) {
onSubmit?.(values)
}
return (
<Form
layout={'vertical'}
@ -217,6 +219,7 @@ function OrderGroupTable({ formValues }) {
dataIndex: 'COLI_Introduction',
},
]
const { notification } = App.useApp()
const [loading, setLoading] = useState(false)
const { orderList, fetchOrderList } = useOrderStore()
@ -306,11 +309,11 @@ function OrderGroupTable({ formValues }) {
const groupOrderData = groupByParam(orderList, 'OPI_DEI_SN')
const deptKeys = Object.keys(groupOrderData)
const collapseItems = []
const deptItems = []
deptKeys.forEach((deptNo, index) => {
const deptOrderList = groupOrderData[deptNo]
collapseItems.push(
deptItems.push(
{
key: index,
label: deptMap.get(deptNo),
@ -321,11 +324,13 @@ function OrderGroupTable({ formValues }) {
)
})
return (<Conditional
condition={orderList.length > 0}
whenTrue={<Tabs defaultActiveKey={0} items={collapseItems} />}
whenFalse={<Empty />}
/>)
return (
<Conditional
condition={orderList.length > 0}
whenTrue={<Tabs defaultActiveKey={0} items={deptItems} />}
whenFalse={<Empty />}
/>
)
}
function OrderFollow() {

@ -42,7 +42,7 @@ function Callback() {
</Flex>
)
} else if (loginStatus === 302) {
navigate('/m/login')
navigate('/m/conversation')
} else if (loginStatus === 403) {
return (
<Flex justify='center' align='center' gap='middle' vertical>

@ -0,0 +1,68 @@
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react';
import { App, Avatar, List, Layout, Input, DatePicker, Button, Spin } from 'antd';
import { ChatItem, MessageBox } from 'react-chat-elements';
import { fetchConversationsList, fetchMessages, MESSAGE_PAGE_SIZE } from '@/actions/ConversationActions';
import { isEmpty } from '@/utils/utils';
import useFormStore from '@/stores/FormStore';
import { useShallow } from 'zustand/react/shallow';
import { RightOutlined } from '@ant-design/icons'
import { fetchSalesAgent, fetchCustomerList } from '@/actions/CommonActions';
import SearchInput from '@/components/SearchInput';
const { Sider, Content, Header, Footer } = Layout;
const { TextArea } = Input
const { RangePicker } = DatePicker;
const data = [
{
title: 'Tyler Dru Kelly',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'Hi Nazly Parlindungan Siregar, this is Sharon , travel advisor of Asia Highlights. We got your inquiry for your trip toJapan , are you available for a quick chat to discuss about your trip? I have some ideas to share with you . Looking forward to talking with you!',
},
{
title: 'Chhavi',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'Hi Sharon, thanks for reaching out. I am extremely busy person, please feel free to write down or send me any note and I will respond to you immediately. Cheers🙏',
},
{
title: 'Nathan Posey',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'It is too late to see cherry blossom from April 28, is it ok for you? For your 7 days tour, visit Tokyo and Kyoto is ok. I will suggest a tour with private car for you because your mother cannot walk too much.',
},
]
function Chat() {
const { notification } = App.useApp()
return (
<>
<List
itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
<List.Item>
<List.Item.Meta
avatar={<Avatar src={item.avatarUrl} />}
title={<a href='https://ant.design'>{item.title}</a>}
description={item.msgTime}
/>
</List.Item>
)}
/>
<TextArea rows={4} placeholder='聊天窗口' maxLength={2000} />
<Button type='primary' onClick={() => {
notification.info({
message: '温馨提示',
description: '功能还在开发中,敬请期待',
placement: 'top',
duration: 60,
})
}}>发送</Button>
</>
);
}
export default Chat

@ -0,0 +1,90 @@
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react';
import { Avatar, List, Button, Input, Layout, Select, DatePicker, Form, Spin } from 'antd';
import { ChatItem, MessageBox } from 'react-chat-elements';
import { fetchConversationsList, fetchMessages, MESSAGE_PAGE_SIZE } from '@/actions/ConversationActions';
import { isEmpty } from '@/utils/utils';
import useFormStore from '@/stores/FormStore';
import { useShallow } from 'zustand/react/shallow'
import { useNavigate, useHref } from 'react-router-dom'
import { RightOutlined } from '@ant-design/icons'
import { fetchSalesAgent, fetchCustomerList } from '@/actions/CommonActions';
import SearchInput from '@/components/SearchInput';
const { Sider, Content, Header, Footer } = Layout;
const { Search } = Input;
const { RangePicker } = DatePicker;
const data = [
{
title: 'Tyler Dru Kelly',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: '15127570944',
},
{
title: 'Chhavi',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240311112',
},
{
title: 'Nathan Posey',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240311114',
},
{
title: 'Philip',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240312062',
},
{
title: 'Jeanne',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240313032',
},
{
title: 'Susan Puls',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240311213',
},
{
title: 'Ana Beatriz',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240312073',
},
{
title: 'Kathleen Anne Workman',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'HXY240104171',
},
]
function Login() {
const navigate = useNavigate()
return (
<>
<List
itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
<List.Item
onClick={() => {
navigate('/m/chat')}}
actions={[<RightOutlined key='goto' />]}
>
<List.Item.Meta
avatar={<Avatar src={item.avatarUrl} />}
title={<a href='https://ant.design'>{item.title}</a>}
description={item.msgTime}
/>
</List.Item>
)}
/>
</>
);
}
export default Login

@ -1,85 +1,22 @@
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react';
import { Avatar, List, Button, Input, Layout, Select, DatePicker, Form, Spin } from 'antd';
import { ChatItem, MessageBox } from 'react-chat-elements';
import { fetchConversationsList, fetchMessages, MESSAGE_PAGE_SIZE } from '@/actions/ConversationActions';
import { isEmpty } from '@/utils/utils';
import useFormStore from '@/stores/FormStore';
import { useShallow } from 'zustand/react/shallow';
import { memo, useCallback, useEffect, useRef, useState, forwardRef } from 'react'
import { App, Avatar, List, Layout, Input, DatePicker, Flex, Result, Spin } from 'antd'
function Chat() {
import { RightOutlined } from '@ant-design/icons'
window.location = 'https://login.dingtalk.com/oauth2/auth?redirect_uri=https%3A%2F%2Fsales.mycht.cn%2Fp%2Fdingding%2Fcallback&response_type=code&client_id=dingwgdx6emlxr3fcrg8&scope=openid&state=global-saels&prompt=consent'
import { fetchSalesAgent, fetchCustomerList } from '@/actions/CommonActions';
import SearchInput from '@/components/SearchInput';
const { Sider, Content, Header, Footer } = Layout;
const { Search } = Input;
const { RangePicker } = DatePicker;
const data = [
{
title: 'Tyler Dru Kelly',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: '15127570944',
},
{
title: 'Chhavi',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240311112',
},
{
title: 'Nathan Posey',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240311114',
},
{
title: 'Philip',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'WLJ240312062',
},
{
title: 'Jeanne',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240313032',
},
{
title: 'Susan Puls',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240311213',
},
{
title: 'Ana Beatriz',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'H240312073',
},
{
title: 'Kathleen Anne Workman',
avatarUrl: 'https://api.dicebear.com/7.x/miniavs/svg?seed=' + Math.random() * 10000,
msgTime: 'HXY240104171',
},
]
function Login() {
return (
<>
<List
itemLayout='horizontal'
dataSource={data}
renderItem={(item, index) => (
<List.Item
actions={[<RightOutlined key='goto' />]}
>
<List.Item.Meta
avatar={<Avatar src={item.avatarUrl} />}
title={<a href='https://ant.design'>{item.title}</a>}
description={item.msgTime}
/>
</List.Item>
)}
<Flex justify='center' align='center' gap='middle' vertical>
<Result
status='success'
title='欢迎使用'
subTitle='正在跳转到钉钉登录页面'
extra={[
<Spin key='mobile-login' size='small' />
]}
/>
</>
</Flex>
);
}
export default Login;
export default Chat

Loading…
Cancel
Save