|
|
@@ -1,715 +1,386 @@
|
|
|
-import { useAjax } from '@/Hook/useAjax';
|
|
|
-import React, { useEffect, useState } from 'react';
|
|
|
-import { getCorpExternalUserRepeatListApi, getExternalUserRepeatByCorpAtlasApi, getExternalUserRepeatByCorpListApi, getExternalUserRepeatCorpApi, getExternalUserRepeatCorpUserApi } from '../../API/home';
|
|
|
-import { Avatar, Card, Checkbox, Col, Divider, Flex, Input, Row, Select, Space, Spin, Statistic, Table, Tabs, Tooltip, Typography } from 'antd';
|
|
|
-import { BarChartOutlined, CheckOutlined, DeleteOutlined, ExclamationOutlined, GlobalOutlined, QuestionCircleOutlined, RetweetOutlined, UserOutlined } from '@ant-design/icons';
|
|
|
-import useEcharts from '@/Hook/useEcharts';
|
|
|
-const { Title } = Typography;
|
|
|
-import style from './index.less'
|
|
|
-import { CorpExternalUserColumns, ExternalUserColumns } from './tableConfig';
|
|
|
-import UuidTem from './uuidTem';
|
|
|
-import { getCorpAllListApi } from '@/API/global';
|
|
|
+import { Avatar, Card, Col, DatePicker, Flex, Popover, Row, Select, Spin, Statistic } from "antd";
|
|
|
+import { ArrowDownOutlined, ArrowUpOutlined, QuestionCircleOutlined } from "@ant-design/icons";
|
|
|
+import useNewToken from "@/Hook/useNewToken";
|
|
|
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
+import { faListAlt, faPlusCircle, faExclamationTriangle, faChartPie, faUsers, faCommentDots, faUsersCog, faRobot, faUserFriends } from "@fortawesome/free-solid-svg-icons";
|
|
|
+import { useEffect, useRef, useState } from "react";
|
|
|
+import dayjs from "dayjs";
|
|
|
+import style from "./index.less";
|
|
|
+import { useSize } from "ahooks";
|
|
|
+import { RangePickerProps } from "antd/es/date-picker";
|
|
|
+import { useAjax } from "@/Hook/useAjax";
|
|
|
+import { getTotalModelApi, getTotalTaslApi } from "../../API/logs";
|
|
|
+import CalendarItem from "./calendarItem";
|
|
|
|
|
|
-const Home: React.FC = () => {
|
|
|
+const weekMap = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
|
|
|
+const taskTypeMap = {
|
|
|
+ 'TASK_STAT_GROUP_SEND': '官方群发',
|
|
|
+ 'TASK_STAT_GROUP_SEND_CHAT': '官方群群发',
|
|
|
+ 'TASK_STAT_GROUP_ROBOT': '机器人群发',
|
|
|
+ 'TASK_STAT_MOMENT': '朋友圈',
|
|
|
+ 'TASK_STAT_TRANSFER': '继承',
|
|
|
+ 'TASK_STAT_PULL_GROUP': '群聊创建 - 拉群'
|
|
|
+}
|
|
|
|
|
|
- /*******************************************/
|
|
|
- const { Bar } = useEcharts()
|
|
|
- const [queryParmas, setQueryParmas] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[], corpName?: string }>({ pageNum: 1, pageSize: 30 })
|
|
|
- const [queryParmasZt, setQueryParmasZt] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[], corpName?: string }>({ pageNum: 1, pageSize: 30 })
|
|
|
- const [corpRepeat, setCorpRepeat] = useState<{ [x: string]: any }>({})
|
|
|
- const [corpUserRepeat, setCorpUserRepeat] = useState<{ [x: string]: any }>({})
|
|
|
- const [barCorpData, setBarCorpData] = useState<Record<string, any>[]>([])
|
|
|
- const [barCorpUserData, setBarCorpUserData] = useState<Record<string, any>[]>([])
|
|
|
- const [activeKey, setActiveKey] = useState<string>('3')
|
|
|
- const [userData, setUserData] = useState<Record<string, any>[]>([])
|
|
|
- const [overflowData, setOverflowData] = useState<{
|
|
|
- avgCorpRepeatUserRate: number,
|
|
|
- repeatUserRate: number,
|
|
|
- userCount: number,
|
|
|
- qcUuidCount: number,
|
|
|
- qcUuidCountRate: number,
|
|
|
- qcUuidNullCount: number,
|
|
|
- qcUuidNullCountRate: number,
|
|
|
- deletedUserCount: number,
|
|
|
- deletedUserCountRate: number
|
|
|
- qcUuidUserCount: number
|
|
|
- }>({ avgCorpRepeatUserRate: 0, repeatUserRate: 0, userCount: 0, qcUuidCount: 0, qcUuidCountRate: 0, qcUuidNullCount: 0, qcUuidNullCountRate: 0, deletedUserCount: 0, deletedUserCountRate: 0, qcUuidUserCount: 0 })
|
|
|
- const [oldFiltered, setOldFiltered] = useState<{ label: string, value: string }[]>([]);
|
|
|
- const [filtered, setFiltered] = useState<{ label: string, value: string }[]>([]);
|
|
|
- const [filtered1, setFiltered1] = useState<{ label: string, value: string }[]>([]);
|
|
|
+const Logs: React.FC = () => {
|
|
|
|
|
|
- const getExternalUserRepeatCorp = useAjax(() => getExternalUserRepeatCorpApi())
|
|
|
- const getExternalUserRepeatCorpUser = useAjax(() => getExternalUserRepeatCorpUserApi())
|
|
|
- const getExternalUserRepeatByCorpAtlas = useAjax(() => getExternalUserRepeatByCorpAtlasApi())
|
|
|
- const getExternalUserRepeatByCorpList = useAjax((params) => getExternalUserRepeatByCorpListApi(params))
|
|
|
- const getCorpExternalUserRepeatList = useAjax((params) => getCorpExternalUserRepeatListApi(params))
|
|
|
- const getCorpAllList = useAjax((params) => getCorpAllListApi(params))
|
|
|
- /*******************************************/
|
|
|
+ /****************************************/
|
|
|
+ const { token } = useNewToken()
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- getCorpAllList.run({}).then(res => {
|
|
|
- console.log('getCorpAllList', res)
|
|
|
- setFiltered(res?.data?.map(item => ({ label: item.corpName, value: item.corpId })))
|
|
|
- setFiltered1(res?.data?.map(item => ({ label: item.corpName, value: item.corpId })))
|
|
|
- setOldFiltered(res?.data?.map(item => ({ label: item.corpName, value: item.corpId })))
|
|
|
- })
|
|
|
- }, [])
|
|
|
+ const ref = useRef<HTMLDivElement>(null)
|
|
|
+ const size = useSize(ref);
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- getExternalUserRepeatByCorpList.run(queryParmas)
|
|
|
- }, [queryParmas])
|
|
|
+ const [weekQuery, setWeekQuery] = useState<{ startTime: string, endTime: string }>({
|
|
|
+ startTime: dayjs().subtract(6, 'day').format('YYYY-MM-DD'),
|
|
|
+ endTime: dayjs().format('YYYY-MM-DD')
|
|
|
+ })
|
|
|
+ const [dates, setDates] = useState<any>([]);
|
|
|
+ const [startClickDate, setStartClickDate] = useState<string>()
|
|
|
+ const [endClickDate, setEndClickDate] = useState<string>()
|
|
|
+ const [rangeStart, setRangeStart] = useState<boolean>(false)
|
|
|
+ const [taskType, setTaskType] = useState<string>('TASK_STAT_GROUP_SEND_CHAT')
|
|
|
|
|
|
- useEffect(() => {
|
|
|
- if (activeKey === '1')
|
|
|
- getCorpExternalUserRepeatList.run(queryParmasZt)
|
|
|
- }, [queryParmasZt, activeKey])
|
|
|
+ const getTotalTasl = useAjax(() => getTotalTaslApi())
|
|
|
+ const getTotalModel = useAjax(() => getTotalModelApi())
|
|
|
+ /****************************************/
|
|
|
|
|
|
useEffect(() => {
|
|
|
- if (activeKey === '2') {
|
|
|
- getExternalUserRepeatCorp.run().then(res => {
|
|
|
- if (res?.data) {
|
|
|
- const cr = res.data
|
|
|
- setCorpRepeat(cr)
|
|
|
- setBarCorpData([
|
|
|
- { name: '仅添加1个主体', '人数': cr?.oneRepeatCount },
|
|
|
- { name: '添加2个主体', '人数': cr?.twoRepeatCount },
|
|
|
- { name: '添加3个主体', '人数': cr?.threeRepeatCount },
|
|
|
- { name: '添加4个主体', '人数': cr?.fourRepeatCount },
|
|
|
- { name: '添加5个主体', '人数': cr?.fiveRepeatCount },
|
|
|
- { name: '添加5个主体以上', '人数': cr?.gtFiveRepeatCount }
|
|
|
- ])
|
|
|
- } else {
|
|
|
- setCorpRepeat({})
|
|
|
- setBarCorpData([])
|
|
|
- }
|
|
|
+ getTotalTasl.run()
|
|
|
+ getTotalModel.run()
|
|
|
+ }, [])
|
|
|
|
|
|
- })
|
|
|
- } else if (activeKey === '3') {
|
|
|
- getExternalUserRepeatCorpUser.run().then(res => {
|
|
|
- if (res?.data) {
|
|
|
- const cur = res.data
|
|
|
- setCorpUserRepeat(cur)
|
|
|
- setOverflowData({
|
|
|
- avgCorpRepeatUserRate: cur?.avgCorpRepeatUserRate || 0,
|
|
|
- repeatUserRate: cur?.repeatUserRate || 0,
|
|
|
- userCount: cur?.userCount || 0,
|
|
|
- qcUuidCount: cur?.qcUuidCount || 0,
|
|
|
- qcUuidCountRate: cur?.qcUuidCountRate || 0,
|
|
|
- qcUuidNullCount: cur?.qcUuidNullCount || 0,
|
|
|
- qcUuidNullCountRate: cur?.qcUuidNullCountRate || 0,
|
|
|
- deletedUserCount: cur?.deletedUserCount || 0,
|
|
|
- deletedUserCountRate: cur?.deletedUserCountRate || 0,
|
|
|
- qcUuidUserCount: cur?.qcUuidUserCount || 0,
|
|
|
- })
|
|
|
- setBarCorpUserData([
|
|
|
- { name: '仅添加1名客服', '人数': cur?.oneRepeatCount },
|
|
|
- { name: '添加2名客服', '人数': cur?.twoRepeatCount },
|
|
|
- { name: '添加3名客服', '人数': cur?.threeRepeatCount },
|
|
|
- { name: '添加4名客服', '人数': cur?.fourRepeatCount },
|
|
|
- { name: '添加5名客服', '人数': cur?.fiveRepeatCount },
|
|
|
- { name: '添加5名客服以上', '人数': cur?.gtFiveRepeatCount }
|
|
|
- ])
|
|
|
- } else {
|
|
|
- setCorpUserRepeat({})
|
|
|
- setOverflowData({ avgCorpRepeatUserRate: 0, repeatUserRate: 0, userCount: 0, qcUuidCount: 0, qcUuidCountRate: 0, qcUuidNullCount: 0, qcUuidNullCountRate: 0, deletedUserCount: 0, deletedUserCountRate: 0, qcUuidUserCount: 0 })
|
|
|
- setBarCorpUserData([])
|
|
|
- }
|
|
|
+ const disabledDate: RangePickerProps['disabledDate'] = (current) => {
|
|
|
+ // console.log(dayjs(current).format('YYYY-MM-DD'))
|
|
|
+ // Can not select days before today and today
|
|
|
+ if (current > dayjs().endOf("day")) return true;
|
|
|
|
|
|
- })
|
|
|
+ if (startClickDate) {
|
|
|
+ return current && current >= dayjs(startClickDate).add(7, 'day');
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- }, [activeKey])
|
|
|
-
|
|
|
- useEffect(() => {
|
|
|
- getExternalUserRepeatByCorpAtlas.run().then(res => {
|
|
|
- if (res?.data) {
|
|
|
- setUserData(res?.data?.map(item => {
|
|
|
- return { name: item.corpName, '主体粉丝总数': item.corpExternalUserCount, '主体内重粉数': item.corpExternalUserRepeatCount }
|
|
|
- }))
|
|
|
- } else {
|
|
|
- setUserData([])
|
|
|
- }
|
|
|
- })
|
|
|
- }, [])
|
|
|
-
|
|
|
- const handleSearch = (val, isOne?: boolean) => {
|
|
|
- const f = oldFiltered.filter((item) => {
|
|
|
- const inputStr = val.replace(/[,,\s]/g, ',');
|
|
|
- if (inputStr && inputStr.includes(',')) {
|
|
|
- const inputList = inputStr.split(',').filter((it) => it).map(i => i.toLowerCase());
|
|
|
- return inputList.includes(((item?.label ?? '') as string).toLowerCase())
|
|
|
- }
|
|
|
- return ((item?.label ?? '') as string).toLowerCase().includes(val.toLowerCase())
|
|
|
- });
|
|
|
- !isOne ? setFiltered(f) : setFiltered1(f);
|
|
|
+ if (endClickDate) {
|
|
|
+ return current && current <= dayjs(endClickDate).subtract(7, 'day');
|
|
|
+ }
|
|
|
+ return false
|
|
|
};
|
|
|
|
|
|
- return <div>
|
|
|
- <Spin spinning={getExternalUserRepeatCorpUser.loading}>
|
|
|
- <Flex gap={16}>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<strong style={{ fontSize: 14 }}>集团总企微用户数</strong>}
|
|
|
- value={overflowData.userCount}
|
|
|
- style={{ flex: 1 }}
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: '#DBEAFE', color: '#2563eb' }} size={40}><UserOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<strong style={{ fontSize: 14 }}>集团跨主体去重企微用户数</strong>}
|
|
|
- style={{ flex: 1 }}
|
|
|
- value={overflowData.qcUuidUserCount}
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: '#fff0f6', color: '#f759ab' }} size={40}><UserOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<strong style={{ fontSize: 14 }}>已识别用户数</strong>}
|
|
|
- value={overflowData.qcUuidCount}
|
|
|
- style={{ flex: 1 }}
|
|
|
- suffix={<div style={{ display: 'flex' }}>
|
|
|
- (<Statistic
|
|
|
- value={overflowData.qcUuidCountRate ? overflowData.qcUuidCountRate * 100 : 0}
|
|
|
- precision={2}
|
|
|
- suffix="%"
|
|
|
- valueStyle={overflowData?.qcUuidCountRate < 0.8 ? { color: '#cf1322' } : { color: '#3f8600' }}
|
|
|
- />)
|
|
|
- </div>}
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: '#DCFCE7', color: '#16a34a' }} size={40}><CheckOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<strong style={{ fontSize: 14 }}>未识别用户数</strong>}
|
|
|
- value={overflowData?.qcUuidNullCount}
|
|
|
- style={{ flex: 1 }}
|
|
|
- suffix={<div style={{ display: 'flex' }}>
|
|
|
- (<Statistic
|
|
|
- value={overflowData.qcUuidNullCountRate ? overflowData.qcUuidNullCountRate * 100 : 0}
|
|
|
- precision={2}
|
|
|
- suffix="%"
|
|
|
- valueStyle={overflowData?.qcUuidNullCountRate > 0.05 ? { color: '#cf1322' } : { color: '#3f8600' }}
|
|
|
- />)
|
|
|
- </div>}
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: 'rgba(251, 192, 163, 1)', color: '#f50' }} size={40}><ExclamationOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<strong style={{ fontSize: 14 }}>双删用户数</strong>}
|
|
|
- value={overflowData?.deletedUserCount}
|
|
|
- style={{ flex: 1 }}
|
|
|
- suffix={<div style={{ display: 'flex' }}>
|
|
|
- (<Statistic
|
|
|
- value={overflowData.deletedUserCountRate ? overflowData.deletedUserCountRate * 100 : 0}
|
|
|
- precision={2}
|
|
|
- suffix="%"
|
|
|
- valueStyle={overflowData?.deletedUserCountRate > 0.4 ? { color: '#cf1322' } : { color: '#3f8600' }}
|
|
|
- />)
|
|
|
- </div>}
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: '#ffcece', color: '#ff0606' }} size={40}><DeleteOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- <Card variant="borderless" style={{ width: '20%' }}>
|
|
|
- <Flex justify='space-between'>
|
|
|
- <Statistic
|
|
|
- title={<Space>
|
|
|
- <strong style={{ fontSize: 14 }}>集团重粉率</strong>
|
|
|
- <Tooltip title="所有主体的重复粉丝去重数量/集团跨主体去重企微用户数">
|
|
|
- <QuestionCircleOutlined />
|
|
|
- </Tooltip>
|
|
|
- </Space>}
|
|
|
- style={{ flex: 1 }}
|
|
|
- value={overflowData.repeatUserRate ? overflowData.repeatUserRate * 100 : 0}
|
|
|
- precision={2}
|
|
|
- suffix="%"
|
|
|
- />
|
|
|
- <Avatar style={{ backgroundColor: '#F3E8FF', color: '#9333ea' }} size={40}><GlobalOutlined /></Avatar>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- </Flex>
|
|
|
- </Spin>
|
|
|
-
|
|
|
-
|
|
|
- <Flex justify='space-between' style={{ margin: '20px 0 10px' }}>
|
|
|
- <Title level={3} style={{ margin: 0 }}><RetweetOutlined style={{ color: '#1890ff' }} /> 单主体内重粉分布</Title>
|
|
|
- <Flex gap={10}>
|
|
|
- <Input.Search
|
|
|
- placeholder="请输入企业名称"
|
|
|
- onSearch={(e) => { setQueryParmas({ ...queryParmas, corpName: e, pageNum: 1 }); }}
|
|
|
- style={{ width: 200 }}
|
|
|
- allowClear
|
|
|
- />
|
|
|
- <Select
|
|
|
- value={queryParmas?.corpIdList}
|
|
|
- onChange={(e) => setQueryParmas({ ...queryParmas, corpIdList: e })}
|
|
|
- showSearch
|
|
|
- style={{ minWidth: 200 }}
|
|
|
- maxTagCount={1}
|
|
|
- mode='multiple'
|
|
|
- placeholder="选择企业"
|
|
|
- filterOption={false}
|
|
|
- onSearch={handleSearch}
|
|
|
- allowClear
|
|
|
- options={filtered}
|
|
|
- popupRender={(menu) => (
|
|
|
- <>
|
|
|
- {menu}
|
|
|
- <Divider style={{ margin: '8px 0' }} />
|
|
|
- <Space style={{ padding: '0 8px 4px' }}>
|
|
|
- <Checkbox onChange={(e) => {
|
|
|
- if (e.target.checked) {
|
|
|
- setQueryParmas({ ...queryParmas, corpIdList: filtered.map(item => item.value) })
|
|
|
- } else {
|
|
|
- setQueryParmas({ ...queryParmas, corpIdList: [] })
|
|
|
- }
|
|
|
- }}>全选</Checkbox>
|
|
|
- </Space>
|
|
|
- </>
|
|
|
- )}
|
|
|
- />
|
|
|
- </Flex>
|
|
|
- </Flex>
|
|
|
- <Row gutter={16}>
|
|
|
- <Col span={10}>
|
|
|
- <Spin spinning={getExternalUserRepeatByCorpAtlas.loading}>
|
|
|
- <Card style={{ height: '100%' }}>
|
|
|
- <Bar data={userData} title="粉丝前20单主体总用户数, 主体内重粉数" />
|
|
|
- </Card>
|
|
|
- </Spin>
|
|
|
- </Col>
|
|
|
- <Col span={14}>
|
|
|
- <Card style={{ height: '100%' }}>
|
|
|
- <Table
|
|
|
- columns={ExternalUserColumns()}
|
|
|
- scroll={{ y: 300, x: 900 }}
|
|
|
- bordered
|
|
|
- dataSource={getExternalUserRepeatByCorpList.data?.data?.records}
|
|
|
- loading={getExternalUserRepeatByCorpList.loading}
|
|
|
- rowKey="corpId"
|
|
|
- pagination={{
|
|
|
- total: getExternalUserRepeatByCorpList.data?.data?.total,
|
|
|
- current: getExternalUserRepeatByCorpList?.data?.data?.current || 1,
|
|
|
- pageSize: getExternalUserRepeatByCorpList?.data?.data?.size || 10
|
|
|
- }}
|
|
|
- onChange={(pagination: any, _: any, sortData: any) => {
|
|
|
- let { current, pageSize } = pagination
|
|
|
- let newQueryForm = JSON.parse(JSON.stringify(queryParmas))
|
|
|
- if (sortData && sortData?.order) {
|
|
|
- newQueryForm['sortType'] = sortData?.order === 'ascend' ? 'ASC' : 'DESC'
|
|
|
- newQueryForm['orderByField'] = sortData?.field
|
|
|
- } else {
|
|
|
- delete newQueryForm['sortType']
|
|
|
- delete newQueryForm['orderByField']
|
|
|
- }
|
|
|
- newQueryForm.pageNum = current || newQueryForm.pageNum
|
|
|
- newQueryForm.pageSize = pageSize || newQueryForm.pageSize
|
|
|
- setQueryParmas({ ...newQueryForm })
|
|
|
- }}
|
|
|
- />
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- </Row>
|
|
|
+ const height = size?.height ? `calc(100vh - ${size?.height}px - 96px)` : 600
|
|
|
+ return <div className={style.logsPage}>
|
|
|
+ <Row gutter={[10, 10]} style={{ marginInline: 0 }} className={style.container}>
|
|
|
+ <Col xs={24} xl={19}>
|
|
|
+ <Flex vertical gap={10}>
|
|
|
+ <Spin spinning={getTotalTasl.loading}>
|
|
|
+ <Flex gap={10} ref={ref}>
|
|
|
+ <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ title={<strong style={{ fontSize: 14 }}>总任务数</strong>}
|
|
|
+ value={getTotalTasl?.data?.data?.taskTotal}
|
|
|
+ style={{ flex: 1 }}
|
|
|
+ valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
|
|
|
+ />
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ value={Math.abs(getTotalTasl?.data?.data?.compareLastMonthTaskTotal || 0) * 100}
|
|
|
+ precision={2}
|
|
|
+ {...(getTotalTasl?.data?.data?.compareLastMonthTaskTotal >= 0 ? {
|
|
|
+ valueStyle: { color: '#3f8600', fontSize: 14 },
|
|
|
+ prefix: <ArrowUpOutlined />
|
|
|
+ } : {
|
|
|
+ valueStyle: { color: '#cf1322', fontSize: 14 },
|
|
|
+ prefix: <ArrowDownOutlined />
|
|
|
+ })}
|
|
|
+ suffix="%"
|
|
|
+ />
|
|
|
+ <span style={{ fontSize: 13, color: token.colorTextDescription }}>较上月变化百分比</span>
|
|
|
+ </Flex>
|
|
|
+ </Flex>
|
|
|
+ <Avatar style={{ backgroundColor: '#DBEAFE', color: '#2563eb', position: 'absolute', right: 15, top: 15 }} size={38}>
|
|
|
+ <FontAwesomeIcon icon={faListAlt} />
|
|
|
+ </Avatar>
|
|
|
+ </Card>
|
|
|
+ <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ title={<strong style={{ fontSize: 14 }}>今日新增任务数</strong>}
|
|
|
+ value={getTotalTasl?.data?.data?.todayAddTask}
|
|
|
+ style={{ flex: 1 }}
|
|
|
+ valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
|
|
|
+ />
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayAddTask || 0) * 100}
|
|
|
+ precision={2}
|
|
|
+ {...(getTotalTasl?.data?.data?.compareYesterdayAddTask >= 0 ? {
|
|
|
+ valueStyle: { color: '#3f8600', fontSize: 14 },
|
|
|
+ prefix: <ArrowUpOutlined />
|
|
|
+ } : {
|
|
|
+ valueStyle: { color: '#cf1322', fontSize: 14 },
|
|
|
+ prefix: <ArrowDownOutlined />
|
|
|
+ })}
|
|
|
+ suffix="%"
|
|
|
+ />
|
|
|
+ <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日新增变化百分比</span>
|
|
|
+ </Flex>
|
|
|
+ </Flex>
|
|
|
+ <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a', position: 'absolute', right: 15, top: 15 }} size={38}>
|
|
|
+ <FontAwesomeIcon icon={faPlusCircle} />
|
|
|
+ </Avatar>
|
|
|
+ </Card>
|
|
|
|
|
|
+ <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ title={<strong style={{ fontSize: 14 }}>今日异常/失败任务数</strong>}
|
|
|
+ value={getTotalTasl?.data?.data?.todayFailTask}
|
|
|
+ style={{ flex: 1 }}
|
|
|
+ valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
|
|
|
+ />
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayFailTask || 0) * 100}
|
|
|
+ precision={2}
|
|
|
+ {...(getTotalTasl?.data?.data?.compareYesterdayFailTask >= 0 ? {
|
|
|
+ valueStyle: { color: '#3f8600', fontSize: 14 },
|
|
|
+ prefix: <ArrowUpOutlined />
|
|
|
+ } : {
|
|
|
+ valueStyle: { color: '#cf1322', fontSize: 14 },
|
|
|
+ prefix: <ArrowDownOutlined />
|
|
|
+ })}
|
|
|
+ suffix="%"
|
|
|
+ />
|
|
|
+ <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
|
|
|
+ </Flex>
|
|
|
+ </Flex>
|
|
|
+ <Avatar style={{ backgroundColor: '#fee2e2', color: '#dc2626', position: 'absolute', right: 15, top: 15 }} size={38}>
|
|
|
+ <FontAwesomeIcon icon={faExclamationTriangle} />
|
|
|
+ </Avatar>
|
|
|
+ </Card>
|
|
|
|
|
|
- <Spin spinning={getExternalUserRepeatCorp.loading || getExternalUserRepeatCorpUser.loading || getCorpExternalUserRepeatList.loading}>
|
|
|
- <Title level={3}><BarChartOutlined style={{ color: '#22c55e' }} /> 用户在集团内重粉分布</Title>
|
|
|
- <Tabs
|
|
|
- tabBarExtraContent={activeKey === '1' && <Flex gap={10}>
|
|
|
- <Input.Search
|
|
|
- placeholder="请输入企业名称"
|
|
|
- onSearch={(e) => { setQueryParmasZt({ ...queryParmasZt, corpName: e, pageNum: 1 }); }}
|
|
|
- style={{ width: 200 }}
|
|
|
- allowClear
|
|
|
- />
|
|
|
- <Select
|
|
|
- value={queryParmasZt?.corpIdList}
|
|
|
- onChange={(e) => setQueryParmasZt({ ...queryParmasZt, corpIdList: e, pageNum: 1 })}
|
|
|
- showSearch
|
|
|
- style={{ minWidth: 200 }}
|
|
|
- maxTagCount={1}
|
|
|
- mode='multiple'
|
|
|
- placeholder="选择企业"
|
|
|
- filterOption={false}
|
|
|
- onSearch={(val) => handleSearch(val, true)}
|
|
|
- allowClear
|
|
|
- options={filtered1}
|
|
|
- popupRender={(menu) => (
|
|
|
- <>
|
|
|
- {menu}
|
|
|
- <Divider style={{ margin: '8px 0' }} />
|
|
|
- <Space style={{ padding: '0 8px 4px' }}>
|
|
|
- <Checkbox onChange={(e) => {
|
|
|
- if (e.target.checked) {
|
|
|
- setQueryParmasZt({ ...queryParmasZt, corpIdList: filtered1.map(item => item.value) })
|
|
|
+ <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ title={<strong style={{ fontSize: 14 }}>今日任务完成率</strong>}
|
|
|
+ value={(getTotalTasl?.data?.data?.todayFinishTaskRate || 0) * 100}
|
|
|
+ style={{ flex: 1 }}
|
|
|
+ suffix="%"
|
|
|
+ precision={2}
|
|
|
+ valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
|
|
|
+ />
|
|
|
+ <Flex vertical>
|
|
|
+ <Statistic
|
|
|
+ value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayFinishTaskRate || 0) * 100}
|
|
|
+ precision={2}
|
|
|
+ {...(getTotalTasl?.data?.data?.compareYesterdayFinishTaskRate >= 0 ? {
|
|
|
+ valueStyle: { color: '#3f8600', fontSize: 14 },
|
|
|
+ prefix: <ArrowUpOutlined />
|
|
|
+ } : {
|
|
|
+ valueStyle: { color: '#cf1322', fontSize: 14 },
|
|
|
+ prefix: <ArrowDownOutlined />
|
|
|
+ })}
|
|
|
+ suffix="%"
|
|
|
+ />
|
|
|
+ <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
|
|
|
+ </Flex>
|
|
|
+ </Flex>
|
|
|
+ <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea', position: 'absolute', right: 15, top: 15 }} size={38}>
|
|
|
+ <FontAwesomeIcon icon={faChartPie} />
|
|
|
+ </Avatar>
|
|
|
+ </Card>
|
|
|
+ </Flex>
|
|
|
+ </Spin>
|
|
|
+ <Card style={{ width: '100%', height, minHeight: 380 }} hoverable styles={{ body: { height: '100%' } }}>
|
|
|
+ <Flex justify="space-between" gap={8} align="center" style={{ marginBottom: 8, height: 30 }}>
|
|
|
+ <Flex gap={10}>
|
|
|
+ <Popover
|
|
|
+ placement="bottomLeft"
|
|
|
+ content={<div style={token?.Checkbox ? { display: 'flex', flexFlow: 'column', color: "#fff" } : { display: 'flex', flexFlow: 'column' }}>
|
|
|
+ <strong style={{ fontSize: 15 }}>任务列表的颜色状态说明:</strong>
|
|
|
+ <span><span style={{ backgroundColor: '#f3f4f6', lineHeight: "20px", display: 'inline-block', color: "initial" }}>等待执行</span>:该任务发送时间未到,或该任务已被暂停、取消、删除;</span>
|
|
|
+ <span><span style={{ backgroundColor: '#88e1aa', lineHeight: "20px", display: 'inline-block', color: "initial" }}>执行成功</span>:该任务已被正常发送,并且任务结果没有异常情况;</span>
|
|
|
+ <span><span style={{ backgroundColor: '#e38989', lineHeight: "20px", display: 'inline-block', color: "initial" }}>任务失败</span>:该任务存在未正常发送情况,包含任务中部分企微号未点击发送、由于手机设备不在线导致任务未发送等多种任务未发送的异常;</span>
|
|
|
+ <span><span style={{ backgroundColor: '#ffd8bf', lineHeight: "20px", display: 'inline-block', color: "initial" }}>任务异常</span>:该任务已被正常发送,但任务结果中存在异常客户(单向好友或当日接受推送额度达到上限)未接收到任务推送;</span>
|
|
|
+ <span><span style={{ backgroundColor: '#ffadd2', lineHeight: "20px", display: 'inline-block', color: "initial" }}>无记录</span>:该任务在当天不满足条件未创建发送任务异常;</span>
|
|
|
+ </div>}>
|
|
|
+ <QuestionCircleOutlined style={{ color: 'red', fontSize: 20 }} />
|
|
|
+ </Popover>
|
|
|
+ <DatePicker.RangePicker
|
|
|
+ placeholder={['开始日期', '结束日期']}
|
|
|
+ variant="filled"
|
|
|
+ onCalendarChange={(e, dateStrings, info) => {
|
|
|
+ setDates(e)
|
|
|
+ if (rangeStart) { // 点过一次
|
|
|
+ setWeekQuery({ ...weekQuery, startTime: dateStrings[0], endTime: dateStrings[1] })
|
|
|
} else {
|
|
|
- setQueryParmasZt({ ...queryParmasZt, corpIdList: [] })
|
|
|
+ if (info.range === 'start') {
|
|
|
+ setStartClickDate(dateStrings[0])
|
|
|
+ } else {
|
|
|
+ setEndClickDate(dateStrings[1])
|
|
|
+ }
|
|
|
+ setRangeStart(true)
|
|
|
}
|
|
|
- }}>全选</Checkbox>
|
|
|
- </Space>
|
|
|
- </>
|
|
|
- )}
|
|
|
- />
|
|
|
- </Flex>}
|
|
|
- items={[
|
|
|
- {
|
|
|
- key: '3',
|
|
|
- label: '用户添加客服号分布',
|
|
|
- children: <Row gutter={16}>
|
|
|
- <Col span={12}>
|
|
|
- <Card style={{ height: '100%' }}>
|
|
|
- <Bar data={barCorpUserData} title="用户添加客服号分布" horizontal />
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- <Col span={12}>
|
|
|
- <DetailsTemplate data={corpUserRepeat} title='用户添加客服号详细数据' />
|
|
|
- </Col>
|
|
|
- </Row>
|
|
|
- },
|
|
|
- {
|
|
|
- key: '2',
|
|
|
- label: '用户添加主体分布',
|
|
|
- children: <Row gutter={16}>
|
|
|
- <Col span={12}>
|
|
|
- <Card style={{ height: '100%' }}>
|
|
|
- <Bar data={barCorpData} title="用户添加主体分布" horizontal />
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- <Col span={12}>
|
|
|
- <Card style={{ height: '100%' }}>
|
|
|
- <Title level={3} style={{ marginTop: 0, textAlign: 'center', fontSize: 18, color: '#313131' }}>用户添加主体分布重粉详细数据</Title>
|
|
|
- <Flex vertical gap={7}>
|
|
|
- <div className={style.item}>
|
|
|
- <span>粉丝总数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.userCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
+ }}
|
|
|
+ onOpenChange={(open) => {
|
|
|
+ if (!open) {
|
|
|
+ setDates([])
|
|
|
+ setRangeStart(false)
|
|
|
+ setStartClickDate(undefined)
|
|
|
+ setEndClickDate(undefined)
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ allowClear={false}
|
|
|
+ disabledDate={disabledDate}
|
|
|
+ value={dates?.length > 1 ? dates : (weekQuery.startTime && weekQuery.endTime) ? [dayjs(weekQuery.startTime), dayjs(weekQuery.endTime)] : undefined}
|
|
|
+ />
|
|
|
+ </Flex>
|
|
|
+ <Select
|
|
|
+ style={{ width: 130 }}
|
|
|
+ value={taskType}
|
|
|
+ placeholder="请选择任务类型"
|
|
|
+ variant="filled"
|
|
|
+ onChange={(value) => {
|
|
|
+ setTaskType(value)
|
|
|
+ }}
|
|
|
+ options={Object.keys(taskTypeMap).map(key => ({ label: taskTypeMap[key], value: key }))}
|
|
|
+ />
|
|
|
+ </Flex>
|
|
|
+ <Flex gap={8} style={{ height: 'calc(100% - 38px)' }}>
|
|
|
+ {Array.from({ length: 7 }, (_, i) => {
|
|
|
+ const date = i === 0 ? dayjs(weekQuery.startTime) : dayjs(weekQuery.startTime).add(i, "day");
|
|
|
+ return {
|
|
|
+ date: date.format("MM/DD"),
|
|
|
+ weekday: weekMap[date.day()],
|
|
|
+ nowDate: date.format("YYYY-MM-DD"),
|
|
|
+ index: i
|
|
|
+ };
|
|
|
+ }).map(item => <CalendarItem
|
|
|
+ key={item.date}
|
|
|
+ weekday={item.weekday}
|
|
|
+ date={item.date}
|
|
|
+ taskDay={item.nowDate}
|
|
|
+ taskType={taskType}
|
|
|
+ index={item.index}
|
|
|
+ endDay={weekQuery.endTime}
|
|
|
+ />)}
|
|
|
+ </Flex>
|
|
|
+
|
|
|
+ </Card>
|
|
|
+ </Flex>
|
|
|
+ </Col>
|
|
|
+ <Col xs={24} xl={5}>
|
|
|
+ <Card style={{ width: '100%', height: `calc(100vh - 86px)` }} hoverable classNames={{ body: 'summaryCardSpin' }} styles={{ body: { height: '100%', paddingInline: 0 } }}>
|
|
|
+ <Spin spinning={getTotalModel.loading}>
|
|
|
+ <Flex justify="space-between" gap={8} align="center" style={{ paddingInline: token.paddingLG, marginBottom: 8, height: 30 }}>
|
|
|
+ <strong style={{ fontSize: 16 }}>任务列表摘要</strong>
|
|
|
+ </Flex>
|
|
|
+ <div className={style.summaryList} style={{ paddingInline: token.paddingLG }}>
|
|
|
+ {getTotalModel?.data?.data?.map((item: any, index: number) => {
|
|
|
+ switch (item.taskType) {
|
|
|
+ case 'TASK_STAT_GROUP_SEND': // 官方用户群发
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#dbeafe', color: '#2563eb' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faUsers} />
|
|
|
+ </Avatar>
|
|
|
+ 官方用户群发
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <Space>
|
|
|
- <span>集团跨主体去重企微用户数</span>
|
|
|
- <Tooltip title="集团跨主体去重企微用户数=未识别人数+添加1个主体人数+添加多个(>1)主体人数">
|
|
|
- <QuestionCircleOutlined />
|
|
|
- </Tooltip>
|
|
|
- </Space>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.qcUuidUserCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>未识别用户数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.qcUuidNullCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.qcUuidNullCountRate ? corpRepeat?.qcUuidNullCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.qcUuidNullCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日异常:{item?.todayFailTask}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>{`用户添加>1主体人数`}</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.gtOneRepeatCountTotal || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.gtOneRepeatCountTotalRate ? corpRepeat?.gtOneRepeatCountTotalRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.gtOneRepeatCountTotalRate > 0.2 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ case 'TASK_STAT_GROUP_SEND_CHAT': // 官方群群发
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faUsersCog} />
|
|
|
+ </Avatar>
|
|
|
+ 群聊群发
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>仅添加1个主体人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.oneRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.oneRepeatCountRate ? corpRepeat?.oneRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.oneRepeatCountRate > 0.5 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
|
|
|
</div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加2个主体人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.twoRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.twoRepeatCountRate ? corpRepeat?.twoRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.twoRepeatCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日异常:{item?.todayFailTask}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加3个主体人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.threeRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.threeRepeatCountRate ? corpRepeat?.threeRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.threeRepeatCountRate > 0.09 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ case 'TASK_STAT_GROUP_ROBOT': // 机器人群发
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#fff0f6', color: '#f759ab' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faRobot} />
|
|
|
+ </Avatar>
|
|
|
+ 机器人群发
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日异常:{item?.todayFailTask}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加4个主体人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.fourRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.fourRepeatCountRate ? corpRepeat?.fourRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.fourRepeatCountRate > 0.08 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ case 'TASK_STAT_MOMENT': // 朋友圈
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faCommentDots} />
|
|
|
+ </Avatar>
|
|
|
+ 朋友圈
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日异常:{item?.todayFailTask}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加5个主体人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.fiveRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.fiveRepeatCountRate ? corpRepeat?.fiveRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.fiveRepeatCountRate > 0.07 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ case 'TASK_STAT_PULL_GROUP': // 群聊创建 - 拉群
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#f6ffed', color: '#73d13d' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faUserFriends} />
|
|
|
+ </Avatar>
|
|
|
+ 群聊创建-拉群
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 预计拉群数:{item?.pullGroupCount || 0} | 拉群成功数:{item?.pullSuccessCount || 0}
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日拉群成功率:{((item?.pullSuccessRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日拉群失败数:{item?.pullFailCount}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加5个主体以上人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={corpRepeat?.gtFiveRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={corpRepeat?.gtFiveRepeatCountRate ? corpRepeat?.gtFiveRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={corpRepeat?.gtFiveRepeatCountRate > 0.06 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
+ case 'TASK_STAT_TRANSFER': // 继承
|
|
|
+ return <div className={style.moduleCard} key={index}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={{ backgroundColor: '#e6fffb', color: '#36cfc9' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={faUserFriends} />
|
|
|
+ </Avatar>
|
|
|
+ 客户继承
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_center}>
|
|
|
+ 总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
|
|
|
+ </div>
|
|
|
+ <div className={style.moduleCard_footer}>
|
|
|
+ <span>今日完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
|
|
|
+ <span className={style.error}>今日异常:{item?.todayFailTask}</span>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
- </Col>
|
|
|
- </Row>
|
|
|
- },
|
|
|
- {
|
|
|
- key: '1',
|
|
|
- label: '主体内用户分布',
|
|
|
- children: <Card>
|
|
|
- <Table
|
|
|
- columns={CorpExternalUserColumns()}
|
|
|
- scroll={{ y: 300, x: 1000 }}
|
|
|
- bordered
|
|
|
- dataSource={getCorpExternalUserRepeatList.data?.data?.records}
|
|
|
- loading={getCorpExternalUserRepeatList.loading}
|
|
|
- rowKey="corpId"
|
|
|
- pagination={{
|
|
|
- total: getCorpExternalUserRepeatList.data?.data?.total,
|
|
|
- current: getCorpExternalUserRepeatList?.data?.data?.current || 1,
|
|
|
- pageSize: getCorpExternalUserRepeatList?.data?.data?.size || 20,
|
|
|
- }}
|
|
|
- onChange={(pagination: any, _: any, sortData: any) => {
|
|
|
- let { current, pageSize } = pagination
|
|
|
- let newQueryForm = JSON.parse(JSON.stringify(queryParmasZt))
|
|
|
- if (sortData && sortData?.order) {
|
|
|
- newQueryForm['sortType'] = sortData?.order === 'ascend' ? 'ASC' : 'DESC'
|
|
|
- newQueryForm['orderByField'] = sortData?.field
|
|
|
- } else {
|
|
|
- delete newQueryForm['sortType']
|
|
|
- delete newQueryForm['orderByField']
|
|
|
- }
|
|
|
- newQueryForm.pageNum = current || newQueryForm.pageNum
|
|
|
- newQueryForm.pageSize = pageSize || newQueryForm.pageSize
|
|
|
- setQueryParmasZt({ ...newQueryForm })
|
|
|
- }}
|
|
|
- />
|
|
|
- </Card>
|
|
|
- }
|
|
|
- ]}
|
|
|
- onChange={(e) => { setActiveKey(e) }}
|
|
|
- activeKey={activeKey}
|
|
|
- />
|
|
|
- </Spin>
|
|
|
-
|
|
|
- {/* uuid */}
|
|
|
- <UuidTem getCorpAllList={oldFiltered} />
|
|
|
+ default:
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ })}
|
|
|
+ </div>
|
|
|
+ </Spin>
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
</div>
|
|
|
-};
|
|
|
-
|
|
|
-const DetailsTemplate: React.FC<{ data: { [x: string]: any }, title: string }> = ({ data, title }) => {
|
|
|
-
|
|
|
-
|
|
|
- return <Card style={{ height: '100%' }}>
|
|
|
- <Title level={3} style={{ marginTop: 0, textAlign: 'center', fontSize: 18, color: '#313131' }}>{title || '详细数据'}</Title>
|
|
|
- <Flex vertical gap={7}>
|
|
|
- <div className={style.item}>
|
|
|
- <span>粉丝总数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.userCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>已激活集团客服号数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.activatedCorpUserCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.activatedCorpUserCountRate ? data?.activatedCorpUserCountRate * 100 : 0}
|
|
|
- valueStyle={data?.activatedCorpUserCountRate < 0.6 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>退出集团客服号数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.quitCorpUserCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.quitCorpUserCountRate ? data?.quitCorpUserCountRate * 100 : 0}
|
|
|
- valueStyle={data?.quitCorpUserCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>未激活集团客服号数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.unactivatedCorpUserCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.unactivatedCorpUserCountRate ? data?.unactivatedCorpUserCountRate * 100 : 0}
|
|
|
- valueStyle={data?.unactivatedCorpUserCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <Space>
|
|
|
- <span>集团跨主体去重企微用户数</span>
|
|
|
- <Tooltip title="集团跨主体去重企微用户数=未识别人数+添加1个客服人数+添加多个(>1)客服人数">
|
|
|
- <QuestionCircleOutlined />
|
|
|
- </Tooltip>
|
|
|
- </Space>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.qcUuidUserCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>未识别用户数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.qcUuidNullCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.qcUuidNullCountRate ? data?.qcUuidNullCountRate * 100 : 0}
|
|
|
- valueStyle={data?.qcUuidNullCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>{`用户添加>1客服号人数`}</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.gtOneRepeatCountTotal || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.gtOneRepeatCountTotalRate ? data?.gtOneRepeatCountTotalRate * 100 : 0}
|
|
|
- valueStyle={data?.gtOneRepeatCountTotalRate > 0.3 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>仅添加1名客服人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.oneRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.oneRepeatCountRate ? data?.oneRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.oneRepeatCountRate > 0.5 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加2名客服人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.twoRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.twoRepeatCountRate ? data?.twoRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.twoRepeatCountRate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加3名客服人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.threeRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.threeRepeatCountRate ? data?.threeRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.threeRepeatCountRate > 0.09 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加4名客服人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.fourRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.fourRepeatCountRate ? data?.fourRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.fourRepeatCountRate > 0.08 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加5名客服人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.fiveRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.fiveRepeatCountRate ? data?.fiveRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.fiveRepeatCountRate > 0.07 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div className={style.item}>
|
|
|
- <span>添加5名客服以上人数</span>
|
|
|
- <div className={style.num}>
|
|
|
- <Statistic value={data?.gtFiveRepeatCount || 0} valueStyle={{ fontSize: 14 }} />
|
|
|
- (<Statistic
|
|
|
- value={data?.gtFiveRepeatCountRate ? data?.gtFiveRepeatCountRate * 100 : 0}
|
|
|
- valueStyle={data?.gtFiveRepeatCountRate > 0.06 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
|
|
|
- suffix="%"
|
|
|
- precision={4}
|
|
|
- />)
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </Flex>
|
|
|
- </Card>
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-export default Home;
|
|
|
+export default Logs;
|