Merge remote-tracking branch 'origin/main' into dev/chat

# Conflicts:
#	src/main.jsx
#	src/views/App.jsx
dev/chat
Lei OT 2 years ago
commit d80b83b1f3

@ -9,13 +9,13 @@ import { Result } from 'antd'
class ErrorBoundary extends PureComponent { class ErrorBoundary extends PureComponent {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { hasError: false } this.state = { hasError: false, info: '' }
} }
componentDidCatch(error, info) { componentDidCatch(error, info) {
console.error('Sorry, Something went wrong.') console.error('Sorry, Something went wrong.')
console.error(error) console.error(error)
this.setState({ hasError: true }) this.setState({ hasError: true, info: error.message })
} }
render() { render() {
@ -23,7 +23,7 @@ class ErrorBoundary extends PureComponent {
return <Result return <Result
status='500' status='500'
title='Sorry, Something went wrong.' title='Sorry, Something went wrong.'
subTitle='...' subTitle={this.state.info}
/> />
} }
return this.props.children return this.props.children

@ -13,7 +13,7 @@ function checkStatus(response) {
} }
} }
export function useJson(url) { export function useGetJson(url) {
const [data, setData] = useState(null) const [data, setData] = useState(null)
useEffect(() => { useEffect(() => {
if (url) { if (url) {
@ -26,9 +26,34 @@ export function useJson(url) {
setData(json) setData(json)
} }
}) })
return () => {
ignore = true return () => { ignore = true }
} }
}, [url])
return data
}
export function usePostForm(url, formData) {
const [data, setData] = useState(null)
useEffect(() => {
if (url) {
let ignore = false
fetch(url, {
method: 'POST',
body: formData
}).then(checkStatus)
.then(response => response.json())
.then(json => {
if (!ignore) {
setData(json)
}
})
.catch(error => {
throw error
})
return () => { ignore = true }
} }
}, [url]) }, [url])

@ -35,13 +35,6 @@ const router = createBrowserRouter([
path: '/', path: '/',
element: <App />, element: <App />,
errorElement: <ErrorPage />, errorElement: <ErrorPage />,
children: [
{ index: true, element: <OrderFollow /> },
]
},
{
path: '/s',
element: <App />,
children: [ children: [
{ index: true, element: <OrderFollow /> }, { index: true, element: <OrderFollow /> },
{ path: 'order/follow', element: <OrderFollow />}, { path: 'order/follow', element: <OrderFollow />},
@ -52,10 +45,11 @@ const router = createBrowserRouter([
] ]
}, },
{ {
path: '/p',
element: <Standlone />, element: <Standlone />,
children: [ children: [
{ path: '/dingding/qrcode', element: <DingdingQRCode /> }, { path: 'dingding/qrcode', element: <DingdingQRCode /> },
{ path: '/dingding/callback', element: <DingdingCallbak /> }, { path: 'dingding/callback', element: <DingdingCallbak /> },
] ]
} }
]) ])
@ -64,7 +58,7 @@ ReactDOM.createRoot(document.getElementById('root')).render(
// <React.StrictMode> // <React.StrictMode>
<ThemeContext.Provider value={{colorPrimary: '#1ba784', borderRadius: 4}}> <ThemeContext.Provider value={{colorPrimary: '#1ba784', borderRadius: 4}}>
<AuthContext.Provider value={{loginUser: {userId: 1, openId: '123456789'}, permissionList: []}}> <AuthContext.Provider value={{loginUser: {userId: 1, openId: '123456789'}, permissionList: ['view_chat', 'send_msg']}}>
<RouterProvider <RouterProvider
router={router} router={router}
fallbackElement={() => <div>Loading...</div>} fallbackElement={() => <div>Loading...</div>}

@ -1,25 +1,28 @@
import { Outlet, Link, useHref, NavLink } from 'react-router-dom' import { Outlet, Link, useHref, NavLink } from 'react-router-dom';
import { useRef, useEffect, useState } from 'react' import { Layout, Menu, ConfigProvider, theme, Empty, Row, Col, Dropdown, Space, Typography, App as AntApp } from 'antd';
import { Layout, Menu, ConfigProvider, theme, Empty, Row, Col, Dropdown, Space, Typography, Result, Select, App as AntApp } from 'antd' import { DownOutlined } from '@ant-design/icons';
import { DownOutlined } from "@ant-design/icons";
import ErrorBoundary from '@/components/ErrorBoundary'; import ErrorBoundary from '@/components/ErrorBoundary';
import zhLocale from 'antd/locale/zh_CN'; import zhLocale from 'antd/locale/zh_CN';
import { useThemeContext } from '@/stores/ThemeContext' import { useThemeContext } from '@/stores/ThemeContext';
import { useAuthContext } from '@/stores/AuthContext'
import 'dayjs/locale/zh-cn'; import 'dayjs/locale/zh-cn';
import 'react-chat-elements/dist/main.css' import 'react-chat-elements/dist/main.css'
import '@/assets/App.css' import '@/assets/App.css';
import AppLogo from '@/assets/logo-gh.png' import AppLogo from '@/assets/logo-gh.png';
import { isEmpty } from '@/utils/commons' import { isEmpty } from '@/utils/commons';
const { Header, Footer, Content } = Layout const { Header, Footer, Content } = Layout
const { Title } = Typography const { Title } = Typography
// SecurityApp
function App() { function App() {
const {colorPrimary, borderRadius} = useThemeContext() const { colorPrimary, borderRadius } = useThemeContext()
const { loginUser, permissionList } = useAuthContext()
const href = useHref() const href = useHref()
//const shouldBeLogin = (isEmpty(userId) || isEmpty(website)) && (href.indexOf('/authorise/') == -1) // /p...
const shouldBeLogin = isEmpty(loginUser) && (href.indexOf('/p/') == -1)
let defaultPath = 'follow' let defaultPath = 'follow'
if (href !== '/') { if (href !== '/') {
@ -30,28 +33,24 @@ function App() {
token: { colorBgContainer }, token: { colorBgContainer },
} = theme.useToken() } = theme.useToken()
function globalEmpty() {
return (
<Empty description={false} />
)
}
function renderLogin() {
return (
<Result
status='403'
title='授权失败'
subTitle='请登陆信息平台,通过指定链接打开。'
/>
)
}
function renderLayout() {
return ( return (
<ConfigProvider
theme={{
token: {
colorPrimary: colorPrimary,
borderRadius: borderRadius
},
algorithm: theme.defaultAlgorithm,
}}
locale={zhLocale}
renderEmpty={() => <Empty description={false} />}
>
<AntApp>
<ErrorBoundary>
<Layout> <Layout>
<Header className='header' style={{ position: 'sticky', top: 0, zIndex: 2, width: '100%', background: 'white' }}> <Header className='header' style={{ position: 'sticky', top: 0, zIndex: 2, width: '100%', background: 'white' }}>
<Row gutter={{ md: 24 }} align='middle'> <Row gutter={{ md: 24 }} align='middle'>
<Col flex="300px"> <Col flex='300px'>
<NavLink to='/'> <NavLink to='/'>
<img src={AppLogo} className='logo' alt='App logo' /> <img src={AppLogo} className='logo' alt='App logo' />
</NavLink> </NavLink>
@ -64,33 +63,33 @@ function App() {
mode='horizontal' mode='horizontal'
selectedKeys={[defaultPath]} selectedKeys={[defaultPath]}
items={[ items={[
{ key: '/s/order/follow', label: <Link to='/s/order/follow'>订单跟踪</Link> }, { key: '/order/follow', label: <Link to='/order/follow'>订单跟踪</Link> },
{ key: '/s/order/chat', label: <Link to='/s/order/chat'>销售聊天</Link> }, { key: '/order/chat', label: <Link to='/order/chat'>销售聊天</Link> },
{ key: '/s/chat/history', label: <Link to='/s/chat/history'>聊天历史</Link> }, { key: '/chat/history', label: <Link to='/chat/history'>聊天历史</Link> },
{ key: '/s/sales/management', label: <Link to='/s/sales/management'>销售管理</Link> } { key: '/sales/management', label: <Link to='/sales/management'>销售管理</Link> }
]} ]}
/> />
</Col> </Col>
<Col flex="auto" style={{ color: "white", marginBottom: "0", display: "flex", justifyContent: "end" }}> <Col flex='auto' style={{ color: 'white', marginBottom: '0', display: 'flex', justifyContent: 'end' }}>
<Dropdown <Dropdown
menu={{ menu={{
items: [ items: [
{ {
label: <Link to="/s/account/profile">个人资料</Link>, label: <Link to='/account/profile'>个人资料</Link>,
key: "1", key: '1',
}, },
{ {
type: "divider", type: 'divider',
}, },
{ {
label: <Link to="/login?out">退出</Link>, label: <Link to='/login?out'>退出</Link>,
key: "3", key: '3',
}, },
] ]
}} }}
trigger={['click']} trigger={['click']}
> >
<a onClick={(e) => e.preventDefault()}> <a onClick={(e) => e.preventDefault()} style={{ color: colorPrimary }}>
<Space> <Space>
廖一军 廖一军
<DownOutlined /> <DownOutlined />
@ -114,24 +113,6 @@ function App() {
</Layout> </Layout>
<Footer>桂林海纳国际旅行社有限公司</Footer> <Footer>桂林海纳国际旅行社有限公司</Footer>
</Layout> </Layout>
)
}
return (
<ConfigProvider
theme={{
token: {
colorPrimary: colorPrimary,
borderRadius: borderRadius
},
algorithm: theme.defaultAlgorithm,
}}
locale={zhLocale}
renderEmpty={globalEmpty}
>
<AntApp>
<ErrorBoundary>
{renderLayout()}
</ErrorBoundary> </ErrorBoundary>
</AntApp> </AntApp>
</ConfigProvider> </ConfigProvider>

@ -1,6 +1,5 @@
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useRef, useEffect, useState } from 'react' import { useRef, useEffect, useState } from 'react'
import { observer } from 'mobx-react'
import { Row, Col, Divider, Table , Card, Button, Input, import { Row, Col, Divider, Table , Card, Button, Input,
Space, Empty, Radio, AutoComplete, DatePicker, Spin, List, Avatar Space, Empty, Radio, AutoComplete, DatePicker, Spin, List, Avatar
} from 'antd' } from 'antd'
@ -92,4 +91,4 @@ function ChatHistory() {
) )
} }
export default observer(ChatHistory) export default ChatHistory

@ -6,7 +6,7 @@ import { useRequest } from 'ahooks'
const { Title } = Typography const { Title } = Typography
const { Meta } = Card const { Meta } = Card
import { useAuthContext } from '@/stores/AuthContext.js' import { useAuthContext } from '@/stores/AuthContext'
function DingdingCallbak() { function DingdingCallbak() {

@ -1,9 +1,8 @@
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useRef, useEffect, useState } from 'react' import { useRef, useEffect, useState } from 'react'
import { observer } from 'mobx-react'
import { import {
Row, Col, Divider, Table, Card, Button, Input, Row, Col, Divider, Table, Card, Button, Input,
Space, Segmented, Radio, Select, AutoComplete, Spin, Typography, Flex, DatePicker, List, Avatar Space, Segmented, Radio, Select, AutoComplete, Spin, Typography, Switch, DatePicker, List, Avatar
} from 'antd' } from 'antd'
import { import {
StarFilled, ZoomInOutlined, StarOutlined, BarsOutlined, AppstoreOutlined, SearchOutlined StarFilled, ZoomInOutlined, StarOutlined, BarsOutlined, AppstoreOutlined, SearchOutlined
@ -184,10 +183,63 @@ const columns = [
function OrderFollow() { function OrderFollow() {
const [taskCategory, setTaskCategory] = useState('today') const [taskCategory, setTaskCategory] = useState('today')
const [advanceChecked, toggleAdvance] = useState(false)
useEffect(() => { useEffect(() => {
}, []) }, [])
return (
<Spin spinning={false} delay={500}>
<Space direction='vertical' style={{ width: '100%' }}>
<Row gutter={[16, 16]} justify='start' align='middle'>
<Col span={10}>
<Radio.Group
options={[
{ label: '今日任务', value: 'today' },
{ label: '潜力客户', value: 'star' },
{ label: '重点订单', value: 'important' },
{ label: '成行', value: 'myfavorites' },
{ label: '走团中', value: 'ing' },
{ label: '走团后一月', value: 'lastMonth' }
]}
value={taskCategory}
onChange={({ target: { value } }) => {
setTaskCategory(value)
}}
optionType='button'
buttonStyle='solid'
/>
</Col>
<Col span={4}>
<Switch checkedChildren='高级查询' unCheckedChildren='高级查询'
defaultChecked={false}
onChange={() => {toggleAdvance(!advanceChecked)}} />
</Col>
</Row>
<Conditional condition={advanceChecked} whenTrue={<AdvanceCriteria />} />
</Space>
<Divider plain orientation='left'></Divider>
<Space
direction='vertical'
size='middle'
style={{
display: 'flex',
}}
>
<OrderList taskCategory={taskCategory} />
</Space>
</Spin>
)
function OrderList({ taskCategory }) {
console.info('taskCategory: ' + taskCategory)
return (
<>
<Table dataSource={dataSource} columns={columns} />
</>
)
}
function AdvanceCriteria() { function AdvanceCriteria() {
return ( return (
<Space direction='vertical' style={{ width: '100%' }}> <Space direction='vertical' style={{ width: '100%' }}>
@ -250,9 +302,8 @@ function OrderFollow() {
/> />
</Col> </Col>
<Col span={6}> <Col span={6}>
<Input placeholder="订单号" allowClear /> <Input placeholder='订单号' allowClear />
</Col> </Col>
<Col span={4}> <Col span={4}>
<RangePicker /> <RangePicker />
</Col> </Col>
@ -265,45 +316,6 @@ function OrderFollow() {
</Space> </Space>
) )
} }
return (
<Spin spinning={false} delay={500}>
<Space direction='vertical' style={{ width: '100%' }}>
<Row gutter={[16, 16]} justify='start' align='middle'>
<Col span={24}>
<Radio.Group
options={[
{ label: '今日任务', value: 'today' },
{ label: '潜力客户', value: 'star' },
{ label: '重点订单', value: 'important' },
{ label: '成行', value: 'myfavorites' },
{ label: '走团中', value: 'ing' },
{ label: '走团后一月', value: 'lastMonth' },
{ label: '高级查询', value: 'advance' }
]}
value={taskCategory}
onChange={({ target: { value } }) => {
setTaskCategory(value)
}}
optionType='button'
buttonStyle='solid'
/>
</Col>
</Row>
<Conditional condition={taskCategory==='advance'} whenTrue={<AdvanceCriteria />} />
</Space>
<Divider plain orientation='left'></Divider>
<Space
direction='vertical'
size='middle'
style={{
display: 'flex',
}}
>
<Table dataSource={dataSource} columns={columns} />
</Space>
</Spin>
)
} }
export default observer(OrderFollow) export default OrderFollow

@ -1,6 +1,5 @@
import { useNavigate } from 'react-router-dom' import { useNavigate } from 'react-router-dom'
import { useRef, useEffect, useState } from 'react' import { useRef, useEffect, useState } from 'react'
import { observer } from 'mobx-react'
import { Row, Col, Divider, Table , Card, Button, Input, import { Row, Col, Divider, Table , Card, Button, Input,
Space, Empty, Radio, Select, DatePicker, Spin, List, Avatar Space, Empty, Radio, Select, DatePicker, Spin, List, Avatar
} from 'antd' } from 'antd'
@ -9,7 +8,7 @@ import {
} from '@ant-design/icons' } from '@ant-design/icons'
import {useFormInput} from '@/hooks/useFormInput' import {useFormInput} from '@/hooks/useFormInput'
import {useJson} from '@/hooks/userFetch' import {useGetJson} from '@/hooks/userFetch'
const { Search } = Input; const { Search } = Input;
const { RangePicker } = DatePicker; const { RangePicker } = DatePicker;
@ -104,7 +103,7 @@ const columns = [
function SalesManagement() { function SalesManagement() {
const keywordProps = useFormInput('') const keywordProps = useFormInput('')
const countryList = useJson(`https://p9axztuwd7x8a7.mycht.cn/service-InfoSys/InfoSys/GetCountryList`) const countryList = useGetJson(`https://p9axztuwd7x8a7.mycht.cn/service-InfoSys/InfoSys/GetCountryList`)
console.info(countryList) console.info(countryList)
useEffect(() => { useEffect(() => {
@ -140,4 +139,4 @@ function SalesManagement() {
) )
} }
export default observer(SalesManagement) export default SalesManagement

@ -10,23 +10,6 @@ import { isEmpty } from '@/utils/commons'
const { Header, Footer, Content } = Layout const { Header, Footer, Content } = Layout
const { Title } = Typography const { Title } = Typography
const items = [
{
label: <Link to="/account/change-password">Change password</Link>,
key: "0",
},
{
label: <Link to="/account/profile">Profile</Link>,
key: "1",
},
{
type: "divider",
},
{
label: <Link to="/login?out">Logout</Link>,
key: "3",
},
];
function Standlone() { function Standlone() {
const {colorPrimary, borderRadius} = useThemeContext() const {colorPrimary, borderRadius} = useThemeContext()
@ -35,22 +18,6 @@ function Standlone() {
token: { colorBgContainer }, token: { colorBgContainer },
} = theme.useToken() } = theme.useToken()
function globalEmpty() {
return (
<Empty description={false} />
)
}
function renderLogin() {
return (
<Result
status='403'
title='授权失败'
subTitle='请登陆信息平台,通过指定链接打开。'
/>
)
}
function renderLayout() { function renderLayout() {
return ( return (
<Layout> <Layout>
@ -91,7 +58,7 @@ function Standlone() {
}, },
algorithm: theme.defaultAlgorithm, algorithm: theme.defaultAlgorithm,
}} }}
renderEmpty={globalEmpty} renderEmpty={() => <Empty description={false} />}
> >
<AntApp> <AntApp>
{renderLayout()} {renderLayout()}

Loading…
Cancel
Save