开发: 添加客户列表
This commit is contained in:
@@ -69,7 +69,7 @@ export const formatTags = (data: any) => {
|
|||||||
if (data) {
|
if (data) {
|
||||||
try {
|
try {
|
||||||
const tags = JSON.parse(data);
|
const tags = JSON.parse(data);
|
||||||
if (Array.isArray(tags)) {
|
if (Array.isArray(tags) && tags.length) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{tags.map((item) => {
|
{tags.map((item) => {
|
||||||
@@ -82,11 +82,9 @@ export const formatTags = (data: any) => {
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {}
|
||||||
return <></>;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return <></>;
|
return <div>无标签</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
type IGroupIcon = {
|
type IGroupIcon = {
|
||||||
|
@@ -22,7 +22,14 @@ export const Gender: React.FC<IProps> = (props) => {
|
|||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : (
|
||||||
|
<svg viewBox="0 0 1024 1024" width="16" height="16">
|
||||||
|
<path
|
||||||
|
d="M880.864 704.346c-56.813-25.397-141.118-90.818-265.945-113.298 31.924-34.36 56.084-88.097 80.937-151.754 14.403-36.893 11.935-68.343 11.935-113.121 0-33.073 6.193-86.156-1.97-115.329-27.533-98.59-97.1-125.79-178.61-125.79-81.577 0-151.229 27.328-178.71 126.087-8.097 29.083-1.888 82.044-1.888 115.037 0 44.875-2.422 76.432 12.019 113.383 25.044 63.984 48.854 117.644 80.655 151.86-123.826 22.89-207.498 87.822-263.95 113.138C58.523 756.945 57.95 814.296 57.95 814.296v97.42l940.724-0.112v-97.308s-0.547-57.548-117.809-109.95z"
|
||||||
|
fill="#1890ff"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@@ -150,7 +150,7 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
|
||||||
&.show {
|
&.show {
|
||||||
z-index: 1;
|
z-index: 11;
|
||||||
transform: translateY(0px);
|
transform: translateY(0px);
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
@@ -109,8 +109,8 @@ const ChatLogs: React.FC = () => {
|
|||||||
setChatLogLoading(false);
|
setChatLogLoading(false);
|
||||||
isAllChatRef.current = count < param.page_count * param.curr_page;
|
isAllChatRef.current = count < param.page_count * param.curr_page;
|
||||||
if (res.err_code == 0) {
|
if (res.err_code == 0) {
|
||||||
|
let arr: IChat[] = [];
|
||||||
if (Array.isArray(res.data) && res.data.length) {
|
if (Array.isArray(res.data) && res.data.length) {
|
||||||
let arr: IChat[] = [];
|
|
||||||
const temp = res.data.reverse();
|
const temp = res.data.reverse();
|
||||||
const mark = { curr_page: param.curr_page, msg_time: temp[temp.length - 1].msg_time };
|
const mark = { curr_page: param.curr_page, msg_time: temp[temp.length - 1].msg_time };
|
||||||
if (param.curr_page == 1) {
|
if (param.curr_page == 1) {
|
||||||
@@ -140,8 +140,8 @@ const ChatLogs: React.FC = () => {
|
|||||||
// }
|
// }
|
||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
setChatLogs(arr);
|
|
||||||
}
|
}
|
||||||
|
setChatLogs(arr);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -708,6 +708,18 @@ const ChatLogs: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>备注名称:{selectCustFollow?.remark}</div>
|
<div>备注名称:{selectCustFollow?.remark}</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
paddingTop: 12,
|
||||||
|
marginBottom: 12,
|
||||||
|
paddingBottom: 12,
|
||||||
|
borderBottom: '1px solid #ddd',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
标签
|
||||||
|
</div>
|
||||||
{formatTags(selectCustFollow?.tags)}
|
{formatTags(selectCustFollow?.tags)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
@@ -0,0 +1,17 @@
|
|||||||
|
.modalAvatar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
margin-right: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: #69b1ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -1,85 +1,92 @@
|
|||||||
import { SearchBarPlugin, SearchBottonsCardPlugin } from '@/components/SearchBarPlugin';
|
import { SearchBarPlugin, SearchBottonsCardPlugin } from '@/components/SearchBarPlugin';
|
||||||
import { post } from '@/services/ajax';
|
import { post } from '@/services/ajax';
|
||||||
|
import { AddWay, CustType } from '@/services/config';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
import { Button, Col, DatePicker, Drawer, Form, Input, Pagination, Row, Table } from 'antd';
|
import {
|
||||||
|
Button,
|
||||||
|
Col,
|
||||||
|
DatePicker,
|
||||||
|
Drawer,
|
||||||
|
Form,
|
||||||
|
Image,
|
||||||
|
Input,
|
||||||
|
Pagination,
|
||||||
|
Popover,
|
||||||
|
Row,
|
||||||
|
Select,
|
||||||
|
Table,
|
||||||
|
Tag,
|
||||||
|
} from 'antd';
|
||||||
import { stringify } from 'qs';
|
import { stringify } from 'qs';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { IStaffsItem } from '../ChatLogs/ChatLogsType';
|
import { formatTags } from '../ChatLogs/ChatUtils';
|
||||||
|
import { Gender } from '../ChatLogs/components/Gender';
|
||||||
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
interface IDepartment {
|
interface ICustItem {
|
||||||
children: null | IDepartment[];
|
add_way: number;
|
||||||
department_leader: string;
|
avatar: string;
|
||||||
id: number;
|
create_time: string;
|
||||||
|
cust_id: string;
|
||||||
|
description: string;
|
||||||
|
gender: number;
|
||||||
name: string;
|
name: string;
|
||||||
parent_id: number;
|
oper_user_id: string;
|
||||||
sort: number;
|
remark: string;
|
||||||
}
|
remark_mobiles: string;
|
||||||
|
state: number;
|
||||||
interface IStaffsData {
|
tags: string;
|
||||||
count: number;
|
type: number;
|
||||||
data?: IStaffsItem[];
|
user_id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Param = {
|
type Param = {
|
||||||
curr_page: number;
|
curr_page: number;
|
||||||
page_count: number;
|
page_count: number;
|
||||||
dep_id: number;
|
type?: number | string;
|
||||||
name?: string;
|
name?: string;
|
||||||
position?: string;
|
add_way?: string;
|
||||||
telephone?: string;
|
create_timeL?: string;
|
||||||
mobile?: string;
|
create_timeU?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
const CustomList: React.FC = () => {
|
const CustomList: React.FC = () => {
|
||||||
const [param] = useState<Param>({
|
const [param] = useState<Param>({
|
||||||
curr_page: 1,
|
curr_page: 1,
|
||||||
page_count: 20,
|
page_count: 20,
|
||||||
dep_id: 0,
|
type: '',
|
||||||
|
name: '',
|
||||||
|
add_way: '',
|
||||||
|
create_timeL: '',
|
||||||
|
create_timeU: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
const [departmentID, setDepartmentsID] = useState<number>(0);
|
const [custsList, setCustsList] = useState<ICustItem[]>([]);
|
||||||
const [departmentsList, setDepartmentsList] = useState<IDepartment[]>([]);
|
const [count, setCount] = useState(0);
|
||||||
const [staffsData, setStaffsData] = useState<IStaffsData>({ count: 0, data: [] });
|
|
||||||
const [loadingL, setLoadingL] = useState(false);
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [record, setRecord] = useState<IStaffsItem>();
|
const [record, setRecord] = useState<ICustItem>();
|
||||||
|
|
||||||
const getStaffsList = () => {
|
const getCustsList = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
post({ url: '/Staffs/List', data: stringify(param) }).then((res) => {
|
post({ url: '/CustFollows/CustsList', data: stringify(param) }).then((res) => {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (res.err_code == 0) {
|
if (res.err_code == 0) {
|
||||||
if (!Array.isArray(res.data)) {
|
if (Array.isArray(res.data)) {
|
||||||
res.data = [];
|
setCustsList(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();
|
|
||||||
}
|
}
|
||||||
|
setCount(res.count || 0);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const page = (page: number) => {
|
const page = (page: number) => {
|
||||||
param.curr_page = page;
|
param.curr_page = page;
|
||||||
getStaffsList();
|
getCustsList();
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getDepartmentsList();
|
getCustsList();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -88,9 +95,10 @@ const CustomList: React.FC = () => {
|
|||||||
<SearchBarPlugin>
|
<SearchBarPlugin>
|
||||||
<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} lg={8} xxl={6}>
|
||||||
<Form.Item label="客户名称">
|
<Form.Item label="客户名称">
|
||||||
<Input
|
<Input
|
||||||
|
placeholder="请输入客户名称"
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
param.name = e.target.value.trim();
|
param.name = e.target.value.trim();
|
||||||
@@ -100,54 +108,58 @@ const CustomList: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} lg={8} xxl={6}>
|
||||||
<Form.Item label={<span style={{ textIndent: '2em' }}>职务</span>}>
|
<Form.Item label={<span>客户类型</span>}>
|
||||||
<Input
|
<Select
|
||||||
autoComplete="off"
|
defaultValue={param.type}
|
||||||
onChange={(e) => {
|
style={{ width: '100%' }}
|
||||||
param.position = e.target.value.trim();
|
onChange={(val) => {
|
||||||
|
param.type = val;
|
||||||
}}
|
}}
|
||||||
allowClear
|
>
|
||||||
onPressEnter={() => page(1)}
|
<Select.Option value="">全部</Select.Option>
|
||||||
/>
|
{Object.keys(CustType).map((key) => {
|
||||||
|
return (
|
||||||
|
<Select.Option key={key} value={key}>
|
||||||
|
{CustType[key]}
|
||||||
|
</Select.Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} lg={8} xxl={6}>
|
||||||
<Form.Item label={<span style={{ textIndent: '1em' }}>手机号</span>}>
|
<Form.Item label={<span>添加方式</span>}>
|
||||||
<Input
|
<Select
|
||||||
autoComplete="off"
|
defaultValue={param.add_way}
|
||||||
onChange={(e) => {
|
style={{ width: '100%' }}
|
||||||
param.mobile = e.target.value.trim();
|
onChange={(val) => {
|
||||||
|
param.add_way = val;
|
||||||
}}
|
}}
|
||||||
allowClear
|
>
|
||||||
onPressEnter={() => page(1)}
|
<Select.Option value="">全部</Select.Option>
|
||||||
/>
|
{Object.keys(AddWay).map((key) => {
|
||||||
|
return (
|
||||||
|
<Select.Option key={key} value={key}>
|
||||||
|
{AddWay[key]}
|
||||||
|
</Select.Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} sm={12} lg={8} xxl={6}>
|
||||||
<Form.Item label={<span style={{ textIndent: '1em' }}>手机号</span>}>
|
<Form.Item label={<span>添加日期</span>}>
|
||||||
<DatePicker.RangePicker
|
<DatePicker.RangePicker
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
onChange={(dates, dateStrings) => {
|
onChange={(dates, dateStrings) => {
|
||||||
console.log(dates, dateStrings);
|
// console.log(dateStrings);
|
||||||
|
param.create_timeL = dateStrings[0];
|
||||||
|
param.create_timeU = dateStrings[1];
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</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>
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
</SearchBarPlugin>
|
</SearchBarPlugin>
|
||||||
@@ -167,58 +179,203 @@ const CustomList: React.FC = () => {
|
|||||||
<Table
|
<Table
|
||||||
tableLayout="fixed"
|
tableLayout="fixed"
|
||||||
size="middle"
|
size="middle"
|
||||||
dataSource={staffsData.data}
|
dataSource={custsList}
|
||||||
style={{ padding: 16, borderRadius: 6, background: '#fff', marginTop: 16 }}
|
style={{ padding: 16, borderRadius: 6, background: '#fff', marginTop: 16 }}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
bordered={true}
|
bordered={true}
|
||||||
rowKey={'user_id'}
|
rowKey={(record) => {
|
||||||
|
return `${record.cust_id}_${record.user_id}`;
|
||||||
|
}}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
>
|
>
|
||||||
<Table.Column
|
<Table.Column
|
||||||
title="客户"
|
title="客户"
|
||||||
|
width={200}
|
||||||
dataIndex={'name'}
|
dataIndex={'name'}
|
||||||
render={(value, record: IStaffsItem) => {
|
render={(value, record: ICustItem) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setRecord(record);
|
setRecord(record);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
style={{ color: '#1890ff', cursor: 'pointer' }}
|
style={{ cursor: 'pointer', display: 'flex' }}
|
||||||
>
|
>
|
||||||
<span
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
width: 56,
|
||||||
marginRight: record.isleader == 1 ? 4 : 0,
|
height: 56,
|
||||||
|
flexShrink: 0,
|
||||||
|
borderRadius: 4,
|
||||||
|
overflow: 'hidden',
|
||||||
|
}}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{value}
|
<Image width={56} height={56} src={record.avatar}></Image>
|
||||||
</span>
|
</div>
|
||||||
{record?.isleader == 1 ? (
|
<div style={{ marginLeft: 8 }}>
|
||||||
<span
|
<div style={{ color: '#1890ff', wordBreak: 'break-all' }}>
|
||||||
style={{
|
{value}[{record.remark}]
|
||||||
color: '#999',
|
</div>
|
||||||
fontSize: 12,
|
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||||
border: '1px solid #ddd',
|
<Gender gender={record.gender}></Gender>
|
||||||
borderRadius: 4,
|
<span style={{ marginLeft: 4, color: '#389e0d' }}>
|
||||||
padding: '2px 4px',
|
@{CustType[record.type]}
|
||||||
}}
|
</span>
|
||||||
>
|
</div>
|
||||||
负责人
|
</div>
|
||||||
</span>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Table.Column title="客户标签" width={160} dataIndex={'position'} />
|
<Table.Column
|
||||||
<Table.Column title="跟进员工" width={160} dataIndex={'position'} />
|
title="客户标签"
|
||||||
<Table.Column title="商机阶段" width={160} dataIndex={'position'} />
|
width={160}
|
||||||
<Table.Column title="添加方式" width={160} dataIndex={'position'} />
|
onCell={() => {
|
||||||
<Table.Column title="添加时间" width={160} dataIndex={'position'} />
|
return {
|
||||||
<Table.Column title="操作" width={160} dataIndex={'position'} />
|
style: {
|
||||||
|
paddingBottom: 8,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
render={(value) => {
|
||||||
|
try {
|
||||||
|
let arr = JSON.parse(value);
|
||||||
|
if (arr.length) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{arr.length >= 3 ? (
|
||||||
|
<Popover
|
||||||
|
content={() => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{arr.map((item: any) => {
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
key={`${item?.group_name}:${item?.tag_name}`}
|
||||||
|
color="green"
|
||||||
|
title={`${item?.group_name}:${item?.tag_name}`}
|
||||||
|
style={{ marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
{item?.tag_name}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Tag
|
||||||
|
color="green"
|
||||||
|
title={`${arr[0]?.group_name}:${arr[0]?.tag_name}`}
|
||||||
|
style={{ marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
{arr[0]?.tag_name}
|
||||||
|
</Tag>
|
||||||
|
{arr[1] ? (
|
||||||
|
<Tag
|
||||||
|
color="green"
|
||||||
|
title={`${arr[1]?.group_name}:${arr[1]?.tag_name}`}
|
||||||
|
style={{ marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
{arr[1]?.tag_name}
|
||||||
|
</Tag>
|
||||||
|
) : null}
|
||||||
|
<Tag color="green" style={{ marginBottom: 4 }}>
|
||||||
|
...
|
||||||
|
</Tag>
|
||||||
|
</Popover>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<Tag
|
||||||
|
color="green"
|
||||||
|
title={`${arr[0]?.group_name}:${arr[0]?.tag_name}`}
|
||||||
|
style={{ marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
{arr[0]?.tag_name}
|
||||||
|
</Tag>
|
||||||
|
{arr[1] ? (
|
||||||
|
<Tag
|
||||||
|
color="green"
|
||||||
|
title={`${arr[1]?.group_name}:${arr[1]?.tag_name}`}
|
||||||
|
style={{ marginBottom: 4 }}
|
||||||
|
>
|
||||||
|
{arr[1]?.tag_name}
|
||||||
|
</Tag>
|
||||||
|
) : null}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
return <div style={{ marginBottom: 4 }}>无标签</div>;
|
||||||
|
}}
|
||||||
|
dataIndex={'tags'}
|
||||||
|
/>
|
||||||
|
<Table.Column title="跟进员工" width={120} dataIndex={'user_id'} />
|
||||||
|
{/* <Table.Column title="商机阶段" width={160} dataIndex={'position'} /> */}
|
||||||
|
<Table.Column
|
||||||
|
title="添加方式"
|
||||||
|
width={140}
|
||||||
|
dataIndex={'add_way'}
|
||||||
|
render={(value) => {
|
||||||
|
return <>{AddWay[value]}</>;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Table.Column title="添加时间" width={140} dataIndex={'create_time'} />
|
||||||
|
{/* <Table.Column title="操作" width={160} dataIndex={'position'} /> */}
|
||||||
</Table>
|
</Table>
|
||||||
<Drawer title="成员详情" open={open} onClose={() => setOpen(false)} width={800} />
|
<Drawer
|
||||||
|
title={`${record?.name} 客户详情`}
|
||||||
|
open={open}
|
||||||
|
onClose={() => setOpen(false)}
|
||||||
|
width={800}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
borderBottom: '1px solid #ddd',
|
||||||
|
paddingBottom: 12,
|
||||||
|
marginBottom: 12,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className={styles.modalAvatar}>
|
||||||
|
<img src={record?.avatar} alt="" />
|
||||||
|
</div>
|
||||||
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
||||||
|
<div style={{ fontSize: 16 }}>
|
||||||
|
<span style={{ marginRight: 8 }}>{record?.name}</span>
|
||||||
|
<Gender gender={record?.gender} />
|
||||||
|
</div>
|
||||||
|
<span style={{ marginLeft: 4, color: '#389e0d' }}>
|
||||||
|
@{record ? CustType[record?.type] : ''}
|
||||||
|
</span>
|
||||||
|
<div style={{ color: '#666' }}>{record?.description}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>备注名称:{record?.remark}</div>
|
||||||
|
<div>添加方式:{record ? AddWay[record?.add_way] : ''}</div>
|
||||||
|
<div>跟进员工:{record?.user_id}</div>
|
||||||
|
<div>添加时间:{record?.create_time}</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
paddingTop: 12,
|
||||||
|
marginBottom: 12,
|
||||||
|
paddingBottom: 12,
|
||||||
|
borderBottom: '1px solid #ddd',
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'bold',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
标签
|
||||||
|
</div>
|
||||||
|
{formatTags(record?.tags)}
|
||||||
|
</div>
|
||||||
|
</Drawer>
|
||||||
<Pagination
|
<Pagination
|
||||||
style={{
|
style={{
|
||||||
background: '#fff',
|
background: '#fff',
|
||||||
@@ -231,7 +388,7 @@ const CustomList: React.FC = () => {
|
|||||||
}}
|
}}
|
||||||
current={param.curr_page}
|
current={param.curr_page}
|
||||||
pageSize={param.page_count}
|
pageSize={param.page_count}
|
||||||
total={staffsData.count}
|
total={count}
|
||||||
pageSizeOptions={[10, 20, 50, 100]}
|
pageSizeOptions={[10, 20, 50, 100]}
|
||||||
onShowSizeChange={(current, size) => {
|
onShowSizeChange={(current, size) => {
|
||||||
param.page_count = size;
|
param.page_count = size;
|
||||||
|
@@ -78,11 +78,13 @@ const DepartmentsList: React.FC = () => {
|
|||||||
post({ url: '/Departments/List' }).then((res) => {
|
post({ url: '/Departments/List' }).then((res) => {
|
||||||
setLoadingL(false);
|
setLoadingL(false);
|
||||||
if (res.err_code == 0) {
|
if (res.err_code == 0) {
|
||||||
if (Array.isArray(res.data) && res.data.length) {
|
if (Array.isArray(res.data)) {
|
||||||
param.dep_id = res.data[0].id;
|
|
||||||
setDepartmentsID(param.dep_id);
|
|
||||||
setDepartmentsList(res.data);
|
setDepartmentsList(res.data);
|
||||||
getStaffsList();
|
if (res.data.length) {
|
||||||
|
param.dep_id = res.data[0].id;
|
||||||
|
setDepartmentsID(param.dep_id);
|
||||||
|
getStaffsList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -246,7 +248,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
<SearchBarPlugin>
|
<SearchBarPlugin>
|
||||||
<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} lg={12} xl={8}>
|
||||||
<Form.Item label={<span style={{ textIndent: '1em' }}>姓名</span>}>
|
<Form.Item label={<span style={{ textIndent: '1em' }}>姓名</span>}>
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -258,7 +260,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} lg={12} xl={8}>
|
||||||
<Form.Item label={<span style={{ textIndent: '1em' }}>职务</span>}>
|
<Form.Item label={<span style={{ textIndent: '1em' }}>职务</span>}>
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -270,7 +272,7 @@ const DepartmentsList: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={12} md={8}>
|
<Col xs={24} lg={12} xl={8}>
|
||||||
<Form.Item label="手机号">
|
<Form.Item label="手机号">
|
||||||
<Input
|
<Input
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -282,20 +284,6 @@ const DepartmentsList: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</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>
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
</SearchBarPlugin>
|
</SearchBarPlugin>
|
||||||
|
@@ -1,13 +1,6 @@
|
|||||||
import Footer from '@/components/Footer';
|
import Footer from '@/components/Footer';
|
||||||
import { IAjaxReturn, post } from '@/services/ajax';
|
import { IAjaxReturn, post } from '@/services/ajax';
|
||||||
import {
|
import { LockOutlined, MobileOutlined, UserOutlined } from '@ant-design/icons';
|
||||||
AlipayCircleOutlined,
|
|
||||||
LockOutlined,
|
|
||||||
MobileOutlined,
|
|
||||||
TaobaoCircleOutlined,
|
|
||||||
UserOutlined,
|
|
||||||
WeiboCircleOutlined,
|
|
||||||
} from '@ant-design/icons';
|
|
||||||
import {
|
import {
|
||||||
LoginForm,
|
LoginForm,
|
||||||
ProFormCaptcha,
|
ProFormCaptcha,
|
||||||
@@ -15,59 +8,13 @@ import {
|
|||||||
ProFormText,
|
ProFormText,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { useEmotionCss } from '@ant-design/use-emotion-css';
|
import { useEmotionCss } from '@ant-design/use-emotion-css';
|
||||||
import { FormattedMessage, Helmet, history, SelectLang, useModel } from '@umijs/max';
|
import { FormattedMessage, Helmet, history, useModel } from '@umijs/max';
|
||||||
import { Alert, App, Tabs } from 'antd';
|
import { Alert, App, Tabs } from 'antd';
|
||||||
import { stringify as qsStringify } from 'qs';
|
import { stringify as qsStringify } from 'qs';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { flushSync } from 'react-dom';
|
import { flushSync } from 'react-dom';
|
||||||
import Settings from '../../../../config/defaultSettings';
|
import Settings from '../../../../config/defaultSettings';
|
||||||
|
|
||||||
const ActionIcons = () => {
|
|
||||||
const langClassName = useEmotionCss(({ token }) => {
|
|
||||||
return {
|
|
||||||
marginLeft: '8px',
|
|
||||||
color: 'rgba(0, 0, 0, 0.2)',
|
|
||||||
fontSize: '24px',
|
|
||||||
verticalAlign: 'middle',
|
|
||||||
cursor: 'pointer',
|
|
||||||
transition: 'color 0.3s',
|
|
||||||
'&:hover': {
|
|
||||||
color: token.colorPrimaryActive,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<AlipayCircleOutlined key="AlipayCircleOutlined" className={langClassName} />
|
|
||||||
<TaobaoCircleOutlined key="TaobaoCircleOutlined" className={langClassName} />
|
|
||||||
<WeiboCircleOutlined key="WeiboCircleOutlined" className={langClassName} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const Lang = () => {
|
|
||||||
const langClassName = useEmotionCss(({ token }) => {
|
|
||||||
return {
|
|
||||||
width: 42,
|
|
||||||
height: 42,
|
|
||||||
lineHeight: '42px',
|
|
||||||
position: 'fixed',
|
|
||||||
right: 16,
|
|
||||||
borderRadius: token.borderRadius,
|
|
||||||
':hover': {
|
|
||||||
backgroundColor: token.colorBgTextHover,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={langClassName} data-lang>
|
|
||||||
{SelectLang && <SelectLang />}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const LoginMessage: React.FC<{
|
const LoginMessage: React.FC<{
|
||||||
content: string;
|
content: string;
|
||||||
}> = ({ content }) => {
|
}> = ({ content }) => {
|
||||||
@@ -100,17 +47,6 @@ const Login: React.FC = () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const fetchUserInfo = async () => {
|
|
||||||
const userInfo = await initialState?.fetchUserInfo?.();
|
|
||||||
if (userInfo) {
|
|
||||||
flushSync(() => {
|
|
||||||
setInitialState((s) => ({
|
|
||||||
...s,
|
|
||||||
currentUser: userInfo,
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const { notification } = App.useApp();
|
const { notification } = App.useApp();
|
||||||
|
|
||||||
window.NotificationCF = notification;
|
window.NotificationCF = notification;
|
||||||
@@ -154,24 +90,6 @@ const Login: React.FC = () => {
|
|||||||
padding: '32px 0',
|
padding: '32px 0',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* <ChatTime msgtime={1680713999000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680763041000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680710399000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680623999000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680537599000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680451199000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680331041000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680195599000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680244641000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680191999000}></ChatTime>
|
|
||||||
<ChatTime msgtime={1680158241000}></ChatTime>
|
|
||||||
<ChatRevoke></ChatRevoke>
|
|
||||||
<ChatAgreeOrNot />
|
|
||||||
<ChatVoice></ChatVoice>
|
|
||||||
<ChatVideo></ChatVideo>
|
|
||||||
<ChatCard></ChatCard>
|
|
||||||
<ChatEmotion></ChatEmotion>
|
|
||||||
<ChatBar></ChatBar> */}
|
|
||||||
<LoginForm
|
<LoginForm
|
||||||
contentStyle={{
|
contentStyle={{
|
||||||
minWidth: 280,
|
minWidth: 280,
|
||||||
|
@@ -1,3 +1,4 @@
|
|||||||
|
import { post } from '@/services/ajax';
|
||||||
import { Area, Line } from '@ant-design/charts';
|
import { Area, Line } from '@ant-design/charts';
|
||||||
import { BarChartOutlined, CommentOutlined, TeamOutlined } from '@ant-design/icons';
|
import { BarChartOutlined, CommentOutlined, TeamOutlined } from '@ant-design/icons';
|
||||||
import { PageContainer } from '@ant-design/pro-components';
|
import { PageContainer } from '@ant-design/pro-components';
|
||||||
@@ -6,31 +7,84 @@ import { DataItemCard } from './components/DataItemCard';
|
|||||||
import { DataSumItemCard } from './components/DataSumItemCard';
|
import { DataSumItemCard } from './components/DataSumItemCard';
|
||||||
import styles from './index.module.scss';
|
import styles from './index.module.scss';
|
||||||
|
|
||||||
const Workbench: React.FC = () => {
|
type ICustChartItem = {
|
||||||
const [data, setData] = useState([]);
|
name: string;
|
||||||
|
num: number;
|
||||||
|
time: string;
|
||||||
|
};
|
||||||
|
|
||||||
const asyncFetch = () => {
|
type IData = {
|
||||||
fetch('https://gw.alipayobjects.com/os/bmw-prod/e00d52f4-2fa6-47ee-a0d7-105dd95bde20.json')
|
overView: {
|
||||||
.then((response) => response.json())
|
custs_total: number;
|
||||||
.then((json) => setData(json))
|
groups_members_total: number;
|
||||||
.catch((error) => {
|
groups_total: number;
|
||||||
console.log('fetch data failed', error);
|
};
|
||||||
});
|
custsInfo: {
|
||||||
|
month_custs: number;
|
||||||
|
today_custs: number;
|
||||||
|
today_loss: number;
|
||||||
|
today_net_growth: number;
|
||||||
|
};
|
||||||
|
groupsInfo: {
|
||||||
|
today_diss_groups: number;
|
||||||
|
today_diss_groups_members: number;
|
||||||
|
today_groups: number;
|
||||||
|
today_groups_members: number;
|
||||||
|
};
|
||||||
|
custsChart: ICustChartItem[];
|
||||||
|
groupsChart: ICustChartItem[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const Workbench: React.FC = () => {
|
||||||
|
const [data, setData] = useState<IData>({
|
||||||
|
overView: {
|
||||||
|
custs_total: 0,
|
||||||
|
groups_members_total: 0,
|
||||||
|
groups_total: 0,
|
||||||
|
},
|
||||||
|
custsInfo: {
|
||||||
|
month_custs: 0,
|
||||||
|
today_custs: 0,
|
||||||
|
today_loss: 0,
|
||||||
|
today_net_growth: 0,
|
||||||
|
},
|
||||||
|
groupsInfo: {
|
||||||
|
today_diss_groups: 0,
|
||||||
|
today_diss_groups_members: 0,
|
||||||
|
today_groups: 0,
|
||||||
|
today_groups_members: 0,
|
||||||
|
},
|
||||||
|
custsChart: [],
|
||||||
|
groupsChart: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const getWorkBenchInfo = () => {
|
||||||
|
post({ url: '/WorkBench/Info' }).then((res) => {
|
||||||
|
if (res.err_code == 0) {
|
||||||
|
if (res.over_view) {
|
||||||
|
data.overView = res.over_view;
|
||||||
|
}
|
||||||
|
if (res.groups_info) {
|
||||||
|
data.groupsInfo = res.groups_info;
|
||||||
|
}
|
||||||
|
if (res.custs_info) {
|
||||||
|
data.custsInfo = res.custs_info;
|
||||||
|
}
|
||||||
|
if (Array.isArray(res.custs_chart)) {
|
||||||
|
data.custsChart = res.custs_chart;
|
||||||
|
}
|
||||||
|
if (Array.isArray(res.groups_chart)) {
|
||||||
|
data.groupsChart = res.groups_chart;
|
||||||
|
}
|
||||||
|
setData({ ...data });
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
asyncFetch();
|
getWorkBenchInfo();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
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 (
|
return (
|
||||||
<PageContainer>
|
<PageContainer>
|
||||||
<div className={styles.dataSum} style={{ padding: '24px 0' }}>
|
<div className={styles.dataSum} style={{ padding: '24px 0' }}>
|
||||||
@@ -42,67 +96,72 @@ const Workbench: React.FC = () => {
|
|||||||
padding: '0 24px',
|
padding: '0 24px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: 16 }}>数据总览</span>
|
<span style={{ fontSize: 18 }}>数据总览</span>
|
||||||
<span style={{ color: '#999' }}>更新时间:2022-12-12 23:30:30</span>
|
{/* <span style={{ color: '#999' }}>更新时间:2022-12-12 23:30:30</span> */}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
<DataSumItemCard
|
<DataSumItemCard
|
||||||
title="客户数量"
|
title="客户数量"
|
||||||
content="当前员工权限范围内的全部客户数量(含重复)"
|
content="当前员工权限范围内的全部客户数量(含重复)"
|
||||||
icon={<TeamOutlined className={styles.icon} />}
|
icon={<TeamOutlined className={styles.icon} />}
|
||||||
count={111}
|
count={data.overView.custs_total}
|
||||||
/>
|
/>
|
||||||
<DataSumItemCard
|
<DataSumItemCard
|
||||||
title="客群数量"
|
title="客群数量"
|
||||||
content="当前员工权限范围内的全部客群数量"
|
content="当前员工权限范围内的全部客群数量"
|
||||||
icon={<CommentOutlined className={styles.icon} />}
|
icon={<CommentOutlined className={styles.icon} />}
|
||||||
count={111}
|
count={data.overView.groups_total}
|
||||||
/>
|
/>
|
||||||
<DataSumItemCard
|
<DataSumItemCard
|
||||||
title="客群成员总数"
|
title="客群成员总数"
|
||||||
content="当前员工权限范围内客群成员的总数(含员工)(含重复)"
|
content="当前员工权限范围内客群成员的总数(含员工)(含重复)"
|
||||||
icon={<BarChartOutlined className={styles.icon} />}
|
icon={<BarChartOutlined className={styles.icon} />}
|
||||||
count={111}
|
count={data.overView.groups_members_total}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.dataSum}>
|
<div className={styles.dataSum}>
|
||||||
<div style={{ fontSize: 16 }}>客户数据</div>
|
<div style={{ fontSize: 18 }}>客户数据</div>
|
||||||
<div className={styles.dataCardBox}>
|
<div className={styles.dataCardBox}>
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日新增客户"
|
title="今日新增客户"
|
||||||
content="当前员工权限范围内今日添加的客户数(含重复及流失)"
|
content="当前员工权限范围内今日添加的客户数(含重复及流失)"
|
||||||
count={11}
|
count={data.custsInfo.today_custs}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
{/* <DataItemCard
|
||||||
title="今日跟进客户"
|
title="今日跟进客户"
|
||||||
content="当前员工权限范围内今日处于跟进中状态的客户数(含重复)"
|
content="当前员工权限范围内今日处于跟进中状态的客户数(含重复)"
|
||||||
count={11}
|
count={11}
|
||||||
/>
|
/> */}
|
||||||
<span style={{ width: 16 }} />
|
{/* <span style={{ width: 16 }} /> */}
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日净增客户"
|
title="今日净增客户"
|
||||||
content="当前员工权限范围内今日添加的客户数(不含重复及流失)"
|
content="当前员工权限范围内今日添加的客户数(不含重复及流失)"
|
||||||
count={11}
|
count={data.custsInfo.today_net_growth}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日流失客户"
|
title="今日流失客户"
|
||||||
content="当前员工权限范围内的流失的全部客户数量"
|
content="当前员工权限范围内的流失的全部客户数量"
|
||||||
count={11}
|
count={data.custsInfo.today_loss}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
|
title="本月新增客户"
|
||||||
|
content="当前员工权限范围内本月添加的客户数(含重复及流失)"
|
||||||
|
count={data.custsInfo.month_custs}
|
||||||
|
/>
|
||||||
|
{/* <DataItemCard
|
||||||
title="昨日发送申请"
|
title="昨日发送申请"
|
||||||
content="当前员工数权限范围内主动向客户发起的申请数"
|
content="当前员工数权限范围内主动向客户发起的申请数"
|
||||||
count={11}
|
count={11}
|
||||||
/>
|
/> */}
|
||||||
</div>
|
</div>
|
||||||
<Line
|
<Line
|
||||||
data={data}
|
data={data.custsChart}
|
||||||
xField="year"
|
xField="time"
|
||||||
yField="gdp"
|
yField="num"
|
||||||
seriesField="name"
|
seriesField="name"
|
||||||
// yAxis= {{
|
// yAxis= {{
|
||||||
// label: {
|
// label: {
|
||||||
@@ -123,37 +182,37 @@ const Workbench: React.FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.dataSum}>
|
<div className={styles.dataSum}>
|
||||||
<div style={{ fontSize: 16 }}>客群数据</div>
|
<div style={{ fontSize: 18 }}>客群数据</div>
|
||||||
<div className={styles.dataCardBox}>
|
<div className={styles.dataCardBox}>
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日新增客群"
|
title="今日新增客群"
|
||||||
content="当前员工权限范围内今日创建的客群数"
|
content="当前员工权限范围内今日创建的客群数"
|
||||||
count={11}
|
count={data.groupsInfo.today_groups}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日解散客群"
|
title="今日解散客群"
|
||||||
content="当前员工权限范围内今日解散的客群数"
|
content="当前员工权限范围内今日解散的客群数"
|
||||||
count={11}
|
count={data.groupsInfo.today_diss_groups}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日新增成员"
|
title="今日新增成员"
|
||||||
content="当前员工权限范围内今日新增客群成员数(含员工)"
|
content="当前员工权限范围内今日新增客群成员数(含员工)"
|
||||||
count={11}
|
count={data.groupsInfo.today_groups_members}
|
||||||
/>
|
/>
|
||||||
<span style={{ width: 16 }} />
|
<span style={{ width: 16 }} />
|
||||||
<DataItemCard
|
<DataItemCard
|
||||||
title="今日退出成员"
|
title="今日退出成员"
|
||||||
content="当前员工权限范围内今日退出客群成员数(含员工)"
|
content="当前员工权限范围内今日退出客群成员数(含员工)"
|
||||||
count={11}
|
count={data.groupsInfo.today_diss_groups_members}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Area
|
<Area
|
||||||
data={dataArea}
|
data={data.groupsChart}
|
||||||
xField="date"
|
xField="time"
|
||||||
yField="value"
|
yField="num"
|
||||||
seriesField="type"
|
seriesField="name"
|
||||||
smooth={true}
|
smooth={true}
|
||||||
legend={{ position: 'top' }}
|
legend={{ position: 'top' }}
|
||||||
isStack={false}
|
isStack={false}
|
||||||
|
31
src/services/config.ts
Normal file
31
src/services/config.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 添加客户的来源
|
||||||
|
*/
|
||||||
|
export const AddWay: any = {
|
||||||
|
0: '未知来源',
|
||||||
|
1: '扫描二维码',
|
||||||
|
2: '搜索手机号',
|
||||||
|
3: '名片分享',
|
||||||
|
4: '群聊',
|
||||||
|
5: '手机通讯录',
|
||||||
|
6: '微信联系人',
|
||||||
|
8: '安装第三方应用时自动添加的客服人员',
|
||||||
|
9: '搜索邮箱',
|
||||||
|
10: '视频号添加',
|
||||||
|
11: '通过日程参与人添加',
|
||||||
|
12: '通过会议参与人添加',
|
||||||
|
13: '添加微信好友对应的企业微信',
|
||||||
|
14: '通过智慧硬件专属客服添加',
|
||||||
|
15: '通过上门服务客服添加',
|
||||||
|
16: '通过获客链接添加',
|
||||||
|
201: '内部成员共享',
|
||||||
|
202: '管理员/负责人分配',
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 外部联系人的类型
|
||||||
|
*/
|
||||||
|
export const CustType: any = {
|
||||||
|
1: '微信',
|
||||||
|
2: '企业微信',
|
||||||
|
};
|
Reference in New Issue
Block a user