开发: 添加及修改路由
This commit is contained in:
@@ -29,58 +29,69 @@ export default [
|
|||||||
// component: './Welcome',
|
// component: './Welcome',
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
path: '/departments',
|
path: '/scrm',
|
||||||
name: 'scrm',
|
name: 'scrm',
|
||||||
icon: 'crown',
|
icon: 'crown',
|
||||||
// access: 'canAdmin',
|
// access: 'canAdmin',
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/departments',
|
path: '/scrm',
|
||||||
redirect: '/departments/page/list',
|
redirect: '/scrm/custom/workbench',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/departments/page',
|
path: '/scrm/custom',
|
||||||
name: '部门管理',
|
name: '客户管理',
|
||||||
// hideInBreadcrumb: true,
|
|
||||||
// component: './Admin',
|
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/departments/page',
|
path: '/scrm/custom',
|
||||||
redirect: '/departments/page/list',
|
redirect: '/scrm/custom/workbench',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '工作台',
|
||||||
|
icon: 'table',
|
||||||
|
path: '/scrm/custom/workbench',
|
||||||
|
component: './Workbench',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '客户列表',
|
||||||
|
icon: 'table',
|
||||||
|
path: '/scrm/custom/list',
|
||||||
|
component: './CustomList',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/scrm/dep',
|
||||||
|
name: '部门管理',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/scrm/dep',
|
||||||
|
redirect: '/scrm/dep/list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '部门员工',
|
name: '部门员工',
|
||||||
icon: 'table',
|
icon: 'table',
|
||||||
path: '/departments/page/list',
|
path: '/scrm/dep/list',
|
||||||
component: './DepartmentsList',
|
component: './DepartmentsList',
|
||||||
},
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/scrm/chat',
|
||||||
|
name: '聊天记录',
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/scrm/chat',
|
||||||
|
redirect: '/scrm/chat/list',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: '成员聊天',
|
name: '成员聊天',
|
||||||
icon: 'table',
|
icon: 'table',
|
||||||
path: '/departments/page/list2',
|
path: '/scrm/chat/list',
|
||||||
component: './ChatLogs',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '客户聊天',
|
|
||||||
icon: 'table',
|
|
||||||
path: '/departments/page/list3',
|
|
||||||
component: './ChatLogs',
|
component: './ChatLogs',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// path: '/departments/sub-page2',
|
|
||||||
// name: '商品',
|
|
||||||
// // component: './TableList',
|
|
||||||
// routes: [
|
|
||||||
// {
|
|
||||||
// name: '列表',
|
|
||||||
// icon: 'table',
|
|
||||||
// path: '/departments/sub-page2/list',
|
|
||||||
// component: './TableList',
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -92,7 +103,7 @@ export default [
|
|||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
redirect: '/departments',
|
redirect: '/scrm',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '*',
|
path: '*',
|
||||||
|
@@ -45,6 +45,7 @@
|
|||||||
"not ie <= 10"
|
"not ie <= 10"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ant-design/charts": "^1.4.2",
|
||||||
"@ant-design/icons": "^5.0.1",
|
"@ant-design/icons": "^5.0.1",
|
||||||
"@ant-design/pro-components": "^2.3.57",
|
"@ant-design/pro-components": "^2.3.57",
|
||||||
"@ant-design/use-emotion-css": "1.0.4",
|
"@ant-design/use-emotion-css": "1.0.4",
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
"rc-menu": "^9.8.2",
|
"rc-menu": "^9.8.2",
|
||||||
"rc-util": "^5.27.2",
|
"rc-util": "^5.27.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
"react-countup": "^6.4.2",
|
||||||
"react-dev-inspector": "^1.8.4",
|
"react-dev-inspector": "^1.8.4",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-helmet-async": "^1.3.0"
|
"react-helmet-async": "^1.3.0"
|
||||||
|
@@ -106,7 +106,7 @@ export interface IChat {
|
|||||||
}
|
}
|
||||||
export interface IChatItem {
|
export interface IChatItem {
|
||||||
from?: IStaffsItem;
|
from?: IStaffsItem;
|
||||||
to?: ICustFollow;
|
to?: ICustFollow | IStaffsItem | IGroup;
|
||||||
group?: any;
|
group?: any;
|
||||||
chat?: IChat;
|
chat?: IChat;
|
||||||
}
|
}
|
||||||
|
@@ -5,6 +5,8 @@
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
export const groupMembersCount = (data: any[], state: any) => {
|
export const groupMembersCount = (data: any[], state: any) => {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
data.forEach((item) => {
|
data.forEach((item) => {
|
||||||
@@ -86,3 +88,35 @@ export const formatTags = (data: any) => {
|
|||||||
}
|
}
|
||||||
return <></>;
|
return <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type IGroupIcon = {
|
||||||
|
groupList: any[];
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* todo 群头像拼接
|
||||||
|
* @param props
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const GroupIcon: React.FC<IGroupIcon> = (props) => {
|
||||||
|
const [list, setList] = useState<any>([[], [], []]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
let temp: any = [[], [], []];
|
||||||
|
const { groupList } = props;
|
||||||
|
for (let index = 0; index < 9; index++) {
|
||||||
|
const element = groupList[index];
|
||||||
|
|
||||||
|
if (index < 3) {
|
||||||
|
temp[0].push(element);
|
||||||
|
} else if (index < 6) {
|
||||||
|
temp[1].push(element);
|
||||||
|
} else {
|
||||||
|
temp[2].push(element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(temp);
|
||||||
|
}, [props.groupList]);
|
||||||
|
|
||||||
|
// <div className={styles.avatar}>{item.name ? item.name[0] : '群'}</div>;
|
||||||
|
return <div></div>;
|
||||||
|
};
|
||||||
|
@@ -12,11 +12,7 @@ import { ChatBar } from './components/ChatBar';
|
|||||||
import { ChatTime } from './components/ChatTime';
|
import { ChatTime } from './components/ChatTime';
|
||||||
import { Gender } from './components/Gender';
|
import { Gender } from './components/Gender';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
interface ISearchWord {
|
|
||||||
'0': string;
|
|
||||||
'1': string;
|
|
||||||
'2': string;
|
|
||||||
}
|
|
||||||
const ChatLogs: React.FC = () => {
|
const ChatLogs: React.FC = () => {
|
||||||
const [param] = useState({
|
const [param] = useState({
|
||||||
curr_page: 1,
|
curr_page: 1,
|
||||||
@@ -80,7 +76,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
'3': '离职继承完成',
|
'3': '离职继承完成',
|
||||||
};
|
};
|
||||||
|
|
||||||
const [searchWord, setSearchWord] = useState<ISearchWord>({
|
const [searchWord, setSearchWord] = useState<any>({
|
||||||
'0': '',
|
'0': '',
|
||||||
'1': '',
|
'1': '',
|
||||||
'2': '',
|
'2': '',
|
||||||
@@ -100,72 +96,6 @@ const ChatLogs: React.FC = () => {
|
|||||||
setFlolowsBox(false);
|
setFlolowsBox(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听DOM变动
|
|
||||||
const callback = function (mutationsList: any) {
|
|
||||||
// Use traditional 'for loops' for IE 11
|
|
||||||
for (let mutation of mutationsList) {
|
|
||||||
if (mutation.type === 'childList') {
|
|
||||||
document.querySelector('.curr_page' + param.curr_page)?.scrollIntoView(true);
|
|
||||||
} else if (mutation.type === 'attributes') {
|
|
||||||
console.log('The ' + mutation.attributeName + ' attribute was modified.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const observer = new MutationObserver(callback);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
document.addEventListener('click', show, false);
|
|
||||||
getStaffsList();
|
|
||||||
|
|
||||||
observer.observe(chatBoxRef.current, { childList: true });
|
|
||||||
const myScript = document.createElement('script');
|
|
||||||
myScript.src = '/public/scripts/amrnb.js';
|
|
||||||
myScript.async = false;
|
|
||||||
document.body.appendChild(myScript);
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
document.removeEventListener('click', show, false);
|
|
||||||
observer.disconnect();
|
|
||||||
document.body.removeChild(myScript);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 获取员工
|
|
||||||
const getStaffsList = () => {
|
|
||||||
post({ url: '/Staffs/Data' }).then((res) => {
|
|
||||||
if (res.err_code == 0) {
|
|
||||||
if (Array.isArray(res.data) && res.data.length) {
|
|
||||||
// setSelectStaff(res.data[0]);
|
|
||||||
// selectStaffRef.current = res.data[0];
|
|
||||||
res.data.forEach((element: IStaffsItem) => {
|
|
||||||
if (element.user_id == 'yangxb') {
|
|
||||||
setSelectStaff(element);
|
|
||||||
selectStaffRef.current = element;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
setStaffsList(res.data);
|
|
||||||
setInnerStaffsList(res.data);
|
|
||||||
getCustFollowsList();
|
|
||||||
getGroupList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const page = (curr: number) => {
|
|
||||||
param.curr_page = curr;
|
|
||||||
param.msg_from = selectStaffRef.current?.user_id + '';
|
|
||||||
if (tabKey == '0') {
|
|
||||||
param.msg_to_list = selectInnerStaffRef.current?.user_id + '';
|
|
||||||
} else if (tabKey == '1') {
|
|
||||||
param.msg_to_list = selectCustFollowRef.current?.cust_id + '';
|
|
||||||
} else {
|
|
||||||
param.room_id = selectGroupRef.current?.group_id + '';
|
|
||||||
}
|
|
||||||
timeShowRef.current = false;
|
|
||||||
getChatLogsList();
|
|
||||||
};
|
|
||||||
|
|
||||||
const getChatLogsList = () => {
|
const getChatLogsList = () => {
|
||||||
chatLogLoadingRef.current = true;
|
chatLogLoadingRef.current = true;
|
||||||
setChatLogLoading(true);
|
setChatLogLoading(true);
|
||||||
@@ -216,6 +146,20 @@ const ChatLogs: React.FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const page = (curr: number) => {
|
||||||
|
param.curr_page = curr;
|
||||||
|
param.msg_from = selectStaffRef.current?.user_id + '';
|
||||||
|
if (tabKey == '0') {
|
||||||
|
param.msg_to_list = selectInnerStaffRef.current?.user_id + '';
|
||||||
|
} else if (tabKey == '1') {
|
||||||
|
param.msg_to_list = selectCustFollowRef.current?.cust_id + '';
|
||||||
|
} else {
|
||||||
|
param.room_id = selectGroupRef.current?.group_id + '';
|
||||||
|
}
|
||||||
|
timeShowRef.current = false;
|
||||||
|
getChatLogsList();
|
||||||
|
};
|
||||||
|
|
||||||
const getGroupList = () => {
|
const getGroupList = () => {
|
||||||
post({
|
post({
|
||||||
url: '/Groups/GroupsList',
|
url: '/Groups/GroupsList',
|
||||||
@@ -271,6 +215,58 @@ const ChatLogs: React.FC = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 获取员工
|
||||||
|
const getStaffsList = () => {
|
||||||
|
post({ url: '/Staffs/Data' }).then((res) => {
|
||||||
|
if (res.err_code == 0) {
|
||||||
|
if (Array.isArray(res.data) && res.data.length) {
|
||||||
|
setSelectStaff(res.data[0]);
|
||||||
|
selectStaffRef.current = res.data[0];
|
||||||
|
// res.data.forEach((element: IStaffsItem) => {
|
||||||
|
// if (element.user_id == 'yangxb') {
|
||||||
|
// setSelectStaff(element);
|
||||||
|
// selectStaffRef.current = element;
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
setStaffsList(res.data);
|
||||||
|
setInnerStaffsList(res.data);
|
||||||
|
getCustFollowsList();
|
||||||
|
getGroupList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 监听DOM变动
|
||||||
|
const callback = function (mutationsList: any) {
|
||||||
|
// Use traditional 'for loops' for IE 11
|
||||||
|
for (let mutation of mutationsList) {
|
||||||
|
if (mutation.type === 'childList') {
|
||||||
|
document.querySelector('.curr_page' + param.curr_page)?.scrollIntoView(true);
|
||||||
|
} else if (mutation.type === 'attributes') {
|
||||||
|
console.log('The ' + mutation.attributeName + ' attribute was modified.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const observer = new MutationObserver(callback);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener('click', show, false);
|
||||||
|
getStaffsList();
|
||||||
|
|
||||||
|
observer.observe(chatBoxRef.current, { childList: true });
|
||||||
|
const myScript = document.createElement('script');
|
||||||
|
myScript.src = '/public/scripts/amrnb.js';
|
||||||
|
myScript.async = false;
|
||||||
|
document.body.appendChild(myScript);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', show, false);
|
||||||
|
observer.disconnect();
|
||||||
|
document.body.removeChild(myScript);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
// const { notification } = App.useApp();
|
// const { notification } = App.useApp();
|
||||||
const tabContent = () => {
|
const tabContent = () => {
|
||||||
if (tabKey == '0') {
|
if (tabKey == '0') {
|
||||||
@@ -549,7 +545,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
<div
|
<div
|
||||||
key={item.user_id}
|
key={item.user_id}
|
||||||
className={styles.chatB}
|
className={styles.chatB}
|
||||||
onClick={(e) => {
|
onClick={() => {
|
||||||
setSelectCustFollow(undefined);
|
setSelectCustFollow(undefined);
|
||||||
selectCustFollowRef.current = undefined;
|
selectCustFollowRef.current = undefined;
|
||||||
setSelectInnerStaff(undefined);
|
setSelectInnerStaff(undefined);
|
||||||
@@ -637,7 +633,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
setSearchWord({ ...searchWord });
|
setSearchWord({ ...searchWord });
|
||||||
}}
|
}}
|
||||||
allowClear
|
allowClear
|
||||||
></Input>
|
/>
|
||||||
</Form>
|
</Form>
|
||||||
<Tabs
|
<Tabs
|
||||||
items={tabs}
|
items={tabs}
|
||||||
@@ -647,7 +643,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
onChange={(val) => {
|
onChange={(val) => {
|
||||||
setTabKey(val);
|
setTabKey(val);
|
||||||
}}
|
}}
|
||||||
></Tabs>
|
/>
|
||||||
<div className={styles.chatBBox}>{tabContent()}</div>
|
<div className={styles.chatBBox}>{tabContent()}</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
@@ -688,9 +684,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
footer={false}
|
footer={false}
|
||||||
>
|
>
|
||||||
{tabKeyRef.current == '0' ? (
|
{tabKeyRef.current == '0' ? (
|
||||||
<DepartmentMembersDetail
|
<DepartmentMembersDetail record={selectInnerStaff as IStaffsItem} />
|
||||||
record={selectInnerStaff as IStaffsItem}
|
|
||||||
></DepartmentMembersDetail>
|
|
||||||
) : tabKeyRef.current == '1' ? (
|
) : tabKeyRef.current == '1' ? (
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
@@ -707,7 +701,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
<div style={{ fontSize: 16 }}>
|
<div style={{ fontSize: 16 }}>
|
||||||
<span style={{ marginRight: 8 }}>{selectCustFollow?.name}</span>
|
<span style={{ marginRight: 8 }}>{selectCustFollow?.name}</span>
|
||||||
<Gender gender={selectCustFollow?.gender}></Gender>
|
<Gender gender={selectCustFollow?.gender} />
|
||||||
</div>
|
</div>
|
||||||
<div style={{ color: '#666' }}>{selectCustFollow?.description}</div>
|
<div style={{ color: '#666' }}>{selectCustFollow?.description}</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -718,7 +712,8 @@ const ChatLogs: React.FC = () => {
|
|||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<div style={{ marginBottom: 8, textIndent: '2em' }}>
|
<div style={{ marginBottom: 8, textIndent: '2em' }}>
|
||||||
群主:{groupMembersObjRef.current[selectGroupRef.current?.owner]?.name}
|
群主:
|
||||||
|
{groupMembersObjRef.current[selectGroupRef.current?.owner as string]?.name}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginBottom: 8 }}>
|
<div style={{ marginBottom: 8 }}>
|
||||||
{adminList(selectGroupRef.current?.admin_list, groupMembersObjRef.current)}
|
{adminList(selectGroupRef.current?.admin_list, groupMembersObjRef.current)}
|
||||||
@@ -937,26 +932,26 @@ const ChatLogs: React.FC = () => {
|
|||||||
没有更多聊天记录了
|
没有更多聊天记录了
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{chatLogs.map((item, i) => {
|
{chatLogs.map((item) => {
|
||||||
if (item.curr_page) {
|
if (item.curr_page) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={item.curr_page}
|
key={item.curr_page}
|
||||||
className={`curr_page${param.curr_page}`}
|
className={`curr_page${param.curr_page}`}
|
||||||
style={{ height: 0 }}
|
style={{ height: 0 }}
|
||||||
></div>
|
/>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div key={item.msg_id}>
|
<div key={item.msg_id}>
|
||||||
{/* {item.show_time ? <ChatTime msgtime={item.msg_time}></ChatTime> : null} */}
|
{/* {item.show_time ? <ChatTime msgtime={item.msg_time}></ChatTime> : null} */}
|
||||||
<ChatTime msgtime={item.msg_time}></ChatTime>
|
<ChatTime msgtime={item.msg_time} />
|
||||||
{tabKey == '2' ? (
|
{tabKey == '2' ? (
|
||||||
<ChatBar
|
<ChatBar
|
||||||
from={selectStaff}
|
from={selectStaff}
|
||||||
to={groupMembersObjRef.current[item.msg_from]}
|
to={groupMembersObjRef.current[item.msg_from]}
|
||||||
chat={item}
|
chat={item}
|
||||||
></ChatBar>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ChatBar
|
<ChatBar
|
||||||
from={selectStaff}
|
from={selectStaff}
|
||||||
@@ -966,7 +961,7 @@ const ChatLogs: React.FC = () => {
|
|||||||
: selectCustFollowRef.current
|
: selectCustFollowRef.current
|
||||||
}
|
}
|
||||||
chat={item}
|
chat={item}
|
||||||
></ChatBar>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
0
src/pages/CustomList/index.module.scss
Normal file
0
src/pages/CustomList/index.module.scss
Normal file
252
src/pages/CustomList/index.tsx
Normal file
252
src/pages/CustomList/index.tsx
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
import { SearchBarPlugin, SearchBottonsCardPlugin } from '@/components/SearchBarPlugin';
|
||||||
|
import { post } from '@/services/ajax';
|
||||||
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
|
import { Button, Col, DatePicker, Drawer, Form, Input, Pagination, Row, Table } from 'antd';
|
||||||
|
import { stringify } from 'qs';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { IStaffsItem } from '../ChatLogs/ChatLogsType';
|
||||||
|
|
||||||
|
interface IDepartment {
|
||||||
|
children: null | IDepartment[];
|
||||||
|
department_leader: string;
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
parent_id: number;
|
||||||
|
sort: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IStaffsData {
|
||||||
|
count: number;
|
||||||
|
data?: IStaffsItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type Param = {
|
||||||
|
curr_page: number;
|
||||||
|
page_count: number;
|
||||||
|
dep_id: number;
|
||||||
|
name?: string;
|
||||||
|
position?: string;
|
||||||
|
telephone?: string;
|
||||||
|
mobile?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CustomList: React.FC = () => {
|
||||||
|
const [param] = useState<Param>({
|
||||||
|
curr_page: 1,
|
||||||
|
page_count: 20,
|
||||||
|
dep_id: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const [departmentID, setDepartmentsID] = useState<number>(0);
|
||||||
|
const [departmentsList, setDepartmentsList] = useState<IDepartment[]>([]);
|
||||||
|
const [staffsData, setStaffsData] = useState<IStaffsData>({ count: 0, data: [] });
|
||||||
|
const [loadingL, setLoadingL] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [record, setRecord] = useState<IStaffsItem>();
|
||||||
|
|
||||||
|
const getStaffsList = () => {
|
||||||
|
setLoading(true);
|
||||||
|
post({ url: '/Staffs/List', data: stringify(param) }).then((res) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (res.err_code == 0) {
|
||||||
|
if (!Array.isArray(res.data)) {
|
||||||
|
res.data = [];
|
||||||
|
}
|
||||||
|
setStaffsData(res as IStaffsData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDepartmentsList = () => {
|
||||||
|
setLoadingL(true);
|
||||||
|
post({ url: '/Departments/List' }).then((res) => {
|
||||||
|
setLoadingL(false);
|
||||||
|
if (res.err_code == 0) {
|
||||||
|
if (Array.isArray(res.data) && res.data.length) {
|
||||||
|
param.dep_id = res.data[0].id;
|
||||||
|
setDepartmentsID(param.dep_id);
|
||||||
|
setDepartmentsList(res.data);
|
||||||
|
getStaffsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const page = (page: number) => {
|
||||||
|
param.curr_page = page;
|
||||||
|
getStaffsList();
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getDepartmentsList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<div style={{ flexGrow: 1, minWidth: 0 }}>
|
||||||
|
<SearchBarPlugin>
|
||||||
|
<Form autoComplete="off">
|
||||||
|
<Row gutter={{ xs: 0, sm: 16 }}>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<Form.Item label="客户名称">
|
||||||
|
<Input
|
||||||
|
autoComplete="off"
|
||||||
|
onChange={(e) => {
|
||||||
|
param.name = e.target.value.trim();
|
||||||
|
}}
|
||||||
|
allowClear
|
||||||
|
onPressEnter={() => page(1)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<Form.Item label={<span style={{ textIndent: '2em' }}>职务</span>}>
|
||||||
|
<Input
|
||||||
|
autoComplete="off"
|
||||||
|
onChange={(e) => {
|
||||||
|
param.position = e.target.value.trim();
|
||||||
|
}}
|
||||||
|
allowClear
|
||||||
|
onPressEnter={() => page(1)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<Form.Item label={<span style={{ textIndent: '1em' }}>手机号</span>}>
|
||||||
|
<Input
|
||||||
|
autoComplete="off"
|
||||||
|
onChange={(e) => {
|
||||||
|
param.mobile = e.target.value.trim();
|
||||||
|
}}
|
||||||
|
allowClear
|
||||||
|
onPressEnter={() => page(1)}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col xs={24} sm={12} md={8}>
|
||||||
|
<Form.Item label={<span style={{ textIndent: '1em' }}>手机号</span>}>
|
||||||
|
<DatePicker.RangePicker
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
onChange={(dates, dateStrings) => {
|
||||||
|
console.log(dates, dateStrings);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
{/* <Col xs={24} sm={12} md={6}>
|
||||||
|
<Form.Item label="用户名">
|
||||||
|
<Select
|
||||||
|
defaultValue="lucy"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
onChange={() => {}}
|
||||||
|
options={[
|
||||||
|
{ value: 'jack', label: 'Jack' },
|
||||||
|
{ value: 'lucy', label: 'Lucy' },
|
||||||
|
{ value: 'Yiminghe', label: 'yiminghe' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col> */}
|
||||||
|
</Row>
|
||||||
|
</Form>
|
||||||
|
</SearchBarPlugin>
|
||||||
|
<SearchBottonsCardPlugin>
|
||||||
|
<Row justify={'center'}>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={() => {
|
||||||
|
page(1);
|
||||||
|
}}
|
||||||
|
style={{ marginRight: 12 }}
|
||||||
|
>
|
||||||
|
搜索
|
||||||
|
</Button>
|
||||||
|
</Row>
|
||||||
|
</SearchBottonsCardPlugin>
|
||||||
|
<Table
|
||||||
|
tableLayout="fixed"
|
||||||
|
size="middle"
|
||||||
|
dataSource={staffsData.data}
|
||||||
|
style={{ padding: 16, borderRadius: 6, background: '#fff', marginTop: 16 }}
|
||||||
|
pagination={false}
|
||||||
|
bordered={true}
|
||||||
|
rowKey={'user_id'}
|
||||||
|
loading={loading}
|
||||||
|
>
|
||||||
|
<Table.Column
|
||||||
|
title="客户"
|
||||||
|
dataIndex={'name'}
|
||||||
|
render={(value, record: IStaffsItem) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
setRecord(record);
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
|
style={{ color: '#1890ff', cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
display: 'inline-block',
|
||||||
|
marginRight: record.isleader == 1 ? 4 : 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{value}
|
||||||
|
</span>
|
||||||
|
{record?.isleader == 1 ? (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
color: '#999',
|
||||||
|
fontSize: 12,
|
||||||
|
border: '1px solid #ddd',
|
||||||
|
borderRadius: 4,
|
||||||
|
padding: '2px 4px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
负责人
|
||||||
|
</span>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table.Column title="客户标签" width={160} dataIndex={'position'} />
|
||||||
|
<Table.Column title="跟进员工" width={160} dataIndex={'position'} />
|
||||||
|
<Table.Column title="商机阶段" width={160} dataIndex={'position'} />
|
||||||
|
<Table.Column title="添加方式" width={160} dataIndex={'position'} />
|
||||||
|
<Table.Column title="添加时间" width={160} dataIndex={'position'} />
|
||||||
|
<Table.Column title="操作" width={160} dataIndex={'position'} />
|
||||||
|
</Table>
|
||||||
|
<Drawer title="成员详情" open={open} onClose={() => setOpen(false)} width={800} />
|
||||||
|
<Pagination
|
||||||
|
style={{
|
||||||
|
background: '#fff',
|
||||||
|
borderRadius: 6,
|
||||||
|
marginTop: 16,
|
||||||
|
padding: 16,
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
current={param.curr_page}
|
||||||
|
pageSize={param.page_count}
|
||||||
|
total={staffsData.count}
|
||||||
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
|
onShowSizeChange={(current, size) => {
|
||||||
|
param.page_count = size;
|
||||||
|
page(1);
|
||||||
|
}}
|
||||||
|
showTotal={(total) => {
|
||||||
|
return <span style={{ lineHeight: 1 }}>共{total}条</span>;
|
||||||
|
}}
|
||||||
|
onChange={(curr) => {
|
||||||
|
page(curr);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CustomList;
|
@@ -51,7 +51,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
page_count: 20,
|
page_count: 20,
|
||||||
dep_id: 0,
|
dep_id: 0,
|
||||||
});
|
});
|
||||||
const { notification, modal } = App.useApp();
|
const { notification } = App.useApp();
|
||||||
const [departmentID, setDepartmentsID] = useState<number>(0);
|
const [departmentID, setDepartmentsID] = useState<number>(0);
|
||||||
const [departmentsList, setDepartmentsList] = useState<IDepartment[]>([]);
|
const [departmentsList, setDepartmentsList] = useState<IDepartment[]>([]);
|
||||||
const [staffsData, setStaffsData] = useState<IStaffsData>({ count: 0, data: [] });
|
const [staffsData, setStaffsData] = useState<IStaffsData>({ count: 0, data: [] });
|
||||||
@@ -60,6 +60,19 @@ const DepartmentsList: React.FC = () => {
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [record, setRecord] = useState<IStaffsItem>();
|
const [record, setRecord] = useState<IStaffsItem>();
|
||||||
|
|
||||||
|
const getStaffsList = () => {
|
||||||
|
setLoading(true);
|
||||||
|
post({ url: '/Staffs/List', data: stringify(param) }).then((res) => {
|
||||||
|
setLoading(false);
|
||||||
|
if (res.err_code == 0) {
|
||||||
|
if (!Array.isArray(res.data)) {
|
||||||
|
res.data = [];
|
||||||
|
}
|
||||||
|
setStaffsData(res as IStaffsData);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const getDepartmentsList = () => {
|
const getDepartmentsList = () => {
|
||||||
setLoadingL(true);
|
setLoadingL(true);
|
||||||
post({ url: '/Departments/List' }).then((res) => {
|
post({ url: '/Departments/List' }).then((res) => {
|
||||||
@@ -74,18 +87,6 @@ const DepartmentsList: React.FC = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
const getStaffsList = () => {
|
|
||||||
setLoading(true);
|
|
||||||
post({ url: '/Staffs/List', data: stringify(param) }).then((res) => {
|
|
||||||
setLoading(false);
|
|
||||||
if (res.err_code == 0) {
|
|
||||||
if (!Array.isArray(res.data)) {
|
|
||||||
res.data = [];
|
|
||||||
}
|
|
||||||
setStaffsData(res as IStaffsData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const page = (page: number) => {
|
const page = (page: number) => {
|
||||||
param.curr_page = page;
|
param.curr_page = page;
|
||||||
@@ -162,7 +163,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
blockNode
|
blockNode
|
||||||
selectedKeys={[departmentID]}
|
selectedKeys={[departmentID]}
|
||||||
defaultExpandAll
|
defaultExpandAll
|
||||||
treeData={departmentsList}
|
treeData={departmentsList as any}
|
||||||
fieldNames={{ title: 'name', key: 'id' }}
|
fieldNames={{ title: 'name', key: 'id' }}
|
||||||
onSelect={(selectedKeys) => {
|
onSelect={(selectedKeys) => {
|
||||||
if (selectedKeys.length) {
|
if (selectedKeys.length) {
|
||||||
@@ -212,7 +213,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
></Tree>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
@@ -246,7 +247,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
<Form autoComplete="off">
|
<Form autoComplete="off">
|
||||||
<Row gutter={{ xs: 0, sm: 16 }}>
|
<Row gutter={{ xs: 0, sm: 16 }}>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} md={8}>
|
||||||
<Form.Item label="姓名">
|
<Form.Item label={<span style={{ textIndent: '1em' }}>姓名</span>}>
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -254,11 +255,11 @@ const DepartmentsList: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
allowClear
|
allowClear
|
||||||
onPressEnter={() => page(1)}
|
onPressEnter={() => page(1)}
|
||||||
></Input>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} md={8}>
|
||||||
<Form.Item label="职务">
|
<Form.Item label={<span style={{ textIndent: '1em' }}>职务</span>}>
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
@@ -266,7 +267,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
allowClear
|
allowClear
|
||||||
onPressEnter={() => page(1)}
|
onPressEnter={() => page(1)}
|
||||||
></Input>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} md={8}>
|
||||||
@@ -278,7 +279,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
allowClear
|
allowClear
|
||||||
onPressEnter={() => page(1)}
|
onPressEnter={() => page(1)}
|
||||||
></Input>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
{/* <Col xs={24} sm={12} md={6}>
|
{/* <Col xs={24} sm={12} md={6}>
|
||||||
@@ -374,20 +375,20 @@ const DepartmentsList: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
></Table.Column>
|
/>
|
||||||
<Table.Column title="职务" width={160} dataIndex={'position'}></Table.Column>
|
<Table.Column title="职务" width={160} dataIndex={'position'} />
|
||||||
<Table.Column
|
<Table.Column
|
||||||
title="部门"
|
title="部门"
|
||||||
dataIndex={'dep_name'}
|
dataIndex={'dep_name'}
|
||||||
render={(val) => {
|
render={(val) => {
|
||||||
return <>{val.join(',')}</>;
|
return <>{val.join(',')}</>;
|
||||||
}}
|
}}
|
||||||
></Table.Column>
|
/>
|
||||||
<Table.Column title="手机号" width={160} dataIndex={'mobile'}></Table.Column>
|
<Table.Column title="手机号" width={160} dataIndex={'mobile'} />
|
||||||
<Table.Column title="企业邮箱" dataIndex={'biz_mail'}></Table.Column>
|
<Table.Column title="企业邮箱" dataIndex={'biz_mail'} />
|
||||||
</Table>
|
</Table>
|
||||||
<Drawer title="成员详情" open={open} onClose={() => setOpen(false)} width={800}>
|
<Drawer title="成员详情" open={open} onClose={() => setOpen(false)} width={800}>
|
||||||
<DepartmentMembersDetail record={record as IStaffsItem}></DepartmentMembersDetail>
|
<DepartmentMembersDetail record={record as IStaffsItem} />
|
||||||
</Drawer>
|
</Drawer>
|
||||||
<Pagination
|
<Pagination
|
||||||
style={{
|
style={{
|
||||||
@@ -408,10 +409,10 @@ const DepartmentsList: React.FC = () => {
|
|||||||
// setParam({ ...param });
|
// setParam({ ...param });
|
||||||
page(1);
|
page(1);
|
||||||
}}
|
}}
|
||||||
showTotal={(total, range) => {
|
showTotal={(total) => {
|
||||||
return <span style={{ lineHeight: 1 }}>共{total}条</span>;
|
return <span style={{ lineHeight: 1 }}>共{total}条</span>;
|
||||||
}}
|
}}
|
||||||
onChange={(curr, pageSize) => {
|
onChange={(curr) => {
|
||||||
page(curr);
|
page(curr);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
27
src/pages/Workbench/components/DataItemCard.tsx
Normal file
27
src/pages/Workbench/components/DataItemCard.tsx
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Popover } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import CountUp from 'react-countup';
|
||||||
|
import styles from '../index.module.scss';
|
||||||
|
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
count: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DataItemCard: React.FC<IProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.dataCard}>
|
||||||
|
<div>
|
||||||
|
<span style={{ marginRight: 8 }}>{props.title}</span>
|
||||||
|
<Popover placement="topLeft" content={props.content}>
|
||||||
|
<ExclamationCircleOutlined style={{ cursor: 'pointer', color: '#999' }} />
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
<div className={styles.dataCount}>
|
||||||
|
<CountUp end={props.count} duration={2}></CountUp>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
30
src/pages/Workbench/components/DataSumItemCard.tsx
Normal file
30
src/pages/Workbench/components/DataSumItemCard.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { ExclamationCircleOutlined } from '@ant-design/icons';
|
||||||
|
import { Popover } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import CountUp from 'react-countup';
|
||||||
|
import styles from '../index.module.scss';
|
||||||
|
type IProps = {
|
||||||
|
title: string;
|
||||||
|
content: string;
|
||||||
|
count: number;
|
||||||
|
icon: React.ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const DataSumItemCard: React.FC<IProps> = (props) => {
|
||||||
|
return (
|
||||||
|
<div className={styles.dataItem}>
|
||||||
|
<div className={styles.dataIconBox}>{props.icon}</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<span style={{ marginRight: 8 }}>{props.title}</span>
|
||||||
|
<Popover placement="topLeft" content={props.content}>
|
||||||
|
<ExclamationCircleOutlined style={{ cursor: 'pointer', color: '#999' }} />
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
<div className={styles.dataCount}>
|
||||||
|
<CountUp end={props.count} duration={2} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
48
src/pages/Workbench/index.module.scss
Normal file
48
src/pages/Workbench/index.module.scss
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
.dataSum {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
padding: 24px;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataItem {
|
||||||
|
display: inline-flex;
|
||||||
|
flex: 1;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
border-right: 1px solid #ddd;
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataIconBox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 64px;
|
||||||
|
height: 64px;
|
||||||
|
margin-right: 16px;
|
||||||
|
background-color: #edf2f9;
|
||||||
|
border-radius: 12px;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: #1890ff;
|
||||||
|
font-size: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataCount {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataCardBox {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dataCard {
|
||||||
|
padding: 16px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 12px;
|
||||||
|
flex: 1;
|
||||||
|
}
|
166
src/pages/Workbench/index.tsx
Normal file
166
src/pages/Workbench/index.tsx
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
import { Area, Line } from '@ant-design/charts';
|
||||||
|
import { BarChartOutlined, CommentOutlined, TeamOutlined } from '@ant-design/icons';
|
||||||
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { DataItemCard } from './components/DataItemCard';
|
||||||
|
import { DataSumItemCard } from './components/DataSumItemCard';
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
|
const Workbench: React.FC = () => {
|
||||||
|
const [data, setData] = useState([]);
|
||||||
|
|
||||||
|
const asyncFetch = () => {
|
||||||
|
fetch('https://gw.alipayobjects.com/os/bmw-prod/e00d52f4-2fa6-47ee-a0d7-105dd95bde20.json')
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => setData(json))
|
||||||
|
.catch((error) => {
|
||||||
|
console.log('fetch data failed', error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
asyncFetch();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const [dataArea, setDataArea] = useState([
|
||||||
|
{ type: '订单数', date: '2021-02-01', value: 400 },
|
||||||
|
{ type: '订单数', date: '2021-02-05', value: 900 },
|
||||||
|
{ type: '订单数', date: '2021-02-08', value: 300 },
|
||||||
|
{ type: '收衣数', date: '2021-02-01', value: 700 },
|
||||||
|
{ type: '收衣数', date: '2021-02-05', value: 500 },
|
||||||
|
{ type: '收衣数', date: '2021-02-08', value: 1000 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContainer>
|
||||||
|
<div className={styles.dataSum} style={{ padding: '24px 0' }}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
marginBottom: 24,
|
||||||
|
padding: '0 24px',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontSize: 16 }}>数据总览</span>
|
||||||
|
<span style={{ color: '#999' }}>更新时间:2022-12-12 23:30:30</span>
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex' }}>
|
||||||
|
<DataSumItemCard
|
||||||
|
title="客户数量"
|
||||||
|
content="当前员工权限范围内的全部客户数量(含重复)"
|
||||||
|
icon={<TeamOutlined className={styles.icon} />}
|
||||||
|
count={111}
|
||||||
|
/>
|
||||||
|
<DataSumItemCard
|
||||||
|
title="客群数量"
|
||||||
|
content="当前员工权限范围内的全部客群数量"
|
||||||
|
icon={<CommentOutlined className={styles.icon} />}
|
||||||
|
count={111}
|
||||||
|
/>
|
||||||
|
<DataSumItemCard
|
||||||
|
title="客群成员总数"
|
||||||
|
content="当前员工权限范围内客群成员的总数(含员工)(含重复)"
|
||||||
|
icon={<BarChartOutlined className={styles.icon} />}
|
||||||
|
count={111}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={styles.dataSum}>
|
||||||
|
<div style={{ fontSize: 16 }}>客户数据</div>
|
||||||
|
<div className={styles.dataCardBox}>
|
||||||
|
<DataItemCard
|
||||||
|
title="今日新增客户"
|
||||||
|
content="当前员工权限范围内今日添加的客户数(含重复及流失)"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日跟进客户"
|
||||||
|
content="当前员工权限范围内今日处于跟进中状态的客户数(含重复)"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日净增客户"
|
||||||
|
content="当前员工权限范围内今日添加的客户数(不含重复及流失)"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日流失客户"
|
||||||
|
content="当前员工权限范围内的流失的全部客户数量"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="昨日发送申请"
|
||||||
|
content="当前员工数权限范围内主动向客户发起的申请数"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Line
|
||||||
|
data={data}
|
||||||
|
xField="year"
|
||||||
|
yField="gdp"
|
||||||
|
seriesField="name"
|
||||||
|
// yAxis= {{
|
||||||
|
// label: {
|
||||||
|
// formatter: (v: any) => `${(v / 10e8).toFixed(1)} B`,
|
||||||
|
// },
|
||||||
|
// },}
|
||||||
|
legend={{
|
||||||
|
position: 'top',
|
||||||
|
}}
|
||||||
|
smooth={true}
|
||||||
|
// @TODO 后续会换一种动画方式
|
||||||
|
animation={{
|
||||||
|
appear: {
|
||||||
|
animation: 'path-in',
|
||||||
|
duration: 3000,
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className={styles.dataSum}>
|
||||||
|
<div style={{ fontSize: 16 }}>客群数据</div>
|
||||||
|
<div className={styles.dataCardBox}>
|
||||||
|
<DataItemCard
|
||||||
|
title="今日新增客群"
|
||||||
|
content="当前员工权限范围内今日创建的客群数"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日解散客群"
|
||||||
|
content="当前员工权限范围内今日解散的客群数"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日新增成员"
|
||||||
|
content="当前员工权限范围内今日新增客群成员数(含员工)"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
<span style={{ width: 16 }} />
|
||||||
|
<DataItemCard
|
||||||
|
title="今日退出成员"
|
||||||
|
content="当前员工权限范围内今日退出客群成员数(含员工)"
|
||||||
|
count={11}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Area
|
||||||
|
data={dataArea}
|
||||||
|
xField="date"
|
||||||
|
yField="value"
|
||||||
|
seriesField="type"
|
||||||
|
smooth={true}
|
||||||
|
legend={{ position: 'top' }}
|
||||||
|
isStack={false}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</PageContainer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Workbench;
|
Reference in New Issue
Block a user