| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534 |
- import { useAjax } from '@/Hook/useAjax';
- import React, { useEffect, useState } from 'react';
- import { getCorpExternalUserRepeatListApi, getExternalUserRepeatByCorpListApi, getExternalUserRepeatCorpApi, getExternalUserRepeatCorpUserApi } from '../../API/home';
- import { Avatar, Card, Col, Flex, Input, Row, Spin, Statistic, Table, Tabs, Typography } from 'antd';
- import { BarChartOutlined, GlobalOutlined, RetweetOutlined, UserOutlined } from '@ant-design/icons';
- import useEcharts from '@/Hook/useEcharts';
- const { Title } = Typography;
- import style from './index.less'
- const Home: React.FC = () => {
- /*******************************************/
- const { Bar, Pie } = useEcharts()
- const [queryParmas, setQueryParmas] = useState<{ pageNum: number, pageSize: number, corpName?: string }>({ pageNum: 1, pageSize: 20 })
- const [queryParmasZt, setQueryParmasZt] = useState<{ pageNum: number, pageSize: number, corpName?: string }>({ pageNum: 1, pageSize: 20 })
- const [corpRepeat, setCorpRepeat] = useState<{ [x: string]: any }>({})
- const [corpUserRepeat, setCorpUserRepeat] = useState<{ [x: string]: any }>({})
- const [barCorpData, setBarCorpData] = useState<{ name: string, value: number }[]>([])
- const [barCorpUserData, setBarCorpUserData] = useState<{ name: string, value: number }[]>([])
- const [activeKey, setActiveKey] = useState<string>('1')
- const [pieData, setPieData] = useState<{ name: string, value: number }[]>([])
- const [overflowData, setOverflowData] = useState<{ avgCorpRepeatUserRate: number, repeatUserRate: number, userCount: number }>({ avgCorpRepeatUserRate: 0, repeatUserRate: 0, userCount: 0 })
- const getExternalUserRepeatCorp = useAjax(() => getExternalUserRepeatCorpApi())
- const getExternalUserRepeatCorpUser = useAjax(() => getExternalUserRepeatCorpUserApi())
- const getExternalUserRepeatByCorpList = useAjax((params) => getExternalUserRepeatByCorpListApi(params))
- const getCorpExternalUserRepeatList = useAjax((params) => getCorpExternalUserRepeatListApi(params))
- /*******************************************/
- useEffect(() => {
- getExternalUserRepeatByCorpList.run(queryParmas).then(res => {
- if (res?.data?.records?.length) {
- setPieData(res?.data?.records?.map(item => {
- return { name: item.corpName, value: item.externalUserRepeatCount }
- }))
- } else {
- setPieData([])
- }
- })
- }, [queryParmas])
- useEffect(() => {
- getCorpExternalUserRepeatList.run(queryParmasZt)
- }, [queryParmasZt])
- useEffect(() => {
- getExternalUserRepeatCorp.run().then(res => {
- if (res?.data) {
- const cr = res.data
- setCorpRepeat(cr)
- setBarCorpData([
- { name: '非重复添加', value: cr?.oneRepeatCount },
- { name: '重复添加2名', value: cr?.twoRepeatCount },
- { name: '重复添加3名', value: cr?.threeRepeatCount },
- { name: '重复添加4名', value: cr?.fourRepeatCount },
- { name: '重复添加5名', value: cr?.fiveRepeatCount },
- { name: '重复添加5名以上', value: cr?.gtFiveRepeatCount }
- ])
- } else {
- setCorpRepeat({})
- setBarCorpData([])
- }
- })
- 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 })
- setBarCorpUserData([
- { name: '非重复添加', value: cur?.oneRepeatCount },
- { name: '重复添加2名', value: cur?.twoRepeatCount },
- { name: '重复添加3名', value: cur?.threeRepeatCount },
- { name: '重复添加4名', value: cur?.fourRepeatCount },
- { name: '重复添加5名', value: cur?.fiveRepeatCount },
- { name: '重复添加5名以上', value: cur?.gtFiveRepeatCount }
- ])
- } else {
- setCorpUserRepeat({})
- setOverflowData({ avgCorpRepeatUserRate: 0, repeatUserRate: 0, userCount: 0 })
- setBarCorpUserData([])
- }
- })
- }, [])
- return <div>
- <Spin spinning={getExternalUserRepeatCorpUser.loading}>
- <Row gutter={16}>
- <Col span={8}>
- <Card variant="borderless">
- <Flex justify='space-between'>
- <Statistic
- title={<strong style={{ fontSize: 14 }}>集团总粉丝数</strong>}
- value={overflowData.userCount}
- />
- <Avatar style={{ backgroundColor: '#DBEAFE', color: '#2563eb' }} size={40}><UserOutlined /></Avatar>
- </Flex>
- </Card>
- </Col>
- <Col span={8}>
- <Card variant="borderless">
- <Flex justify='space-between'>
- <Statistic
- title={<strong style={{ fontSize: 14 }}>平均主体重粉率</strong>}
- value={overflowData.avgCorpRepeatUserRate ? overflowData.avgCorpRepeatUserRate * 100 : 0}
- precision={4}
- suffix="%"
- />
- <Avatar style={{ backgroundColor: '#DCFCE7', color: '#16a34a' }} size={40}><RetweetOutlined /></Avatar>
- </Flex>
- </Card>
- </Col>
- <Col span={8}>
- <Card variant="borderless">
- <Flex justify='space-between'>
- <Statistic
- title={<strong style={{ fontSize: 14 }}>集团重粉率</strong>}
- value={overflowData.repeatUserRate ? overflowData.repeatUserRate * 100 : 0}
- precision={4}
- suffix="%"
- />
- <Avatar style={{ backgroundColor: '#F3E8FF', color: '#9333ea' }} size={40}><GlobalOutlined /></Avatar>
- </Flex>
- </Card>
- </Col>
- </Row>
- </Spin>
- <Spin spinning={getExternalUserRepeatByCorpList.loading}>
- <Flex justify='space-between' style={{ margin: '20px 0 10px' }}>
- <Title level={3} style={{ margin: 0 }}><RetweetOutlined style={{ color: '#1890ff' }} /> 主体重粉次数统计</Title>
- <Input.Search
- placeholder="请输入企业名称"
- onSearch={(e) => { setQueryParmas({ ...queryParmas, corpName: e, pageNum: 1 }); }}
- style={{ width: 200 }}
- allowClear
- />
- </Flex>
- <Row gutter={16}>
- <Col span={12}>
- <Card style={{ height: '100%' }}>
- <Pie data={pieData} title="主体重粉占比" />
- </Card>
- </Col>
- <Col span={12}>
- <Card style={{ height: '100%' }}>
- <Table
- columns={[
- {
- title: '企业名称',
- dataIndex: 'corpName',
- key: 'corpName',
- ellipsis: true,
- width: 150,
- },
- {
- title: '集团粉丝总数',
- dataIndex: 'totalExternalUserCount',
- key: 'totalExternalUserCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '集团内重粉数',
- dataIndex: 'externalUserRepeatCount',
- key: 'externalUserRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '集团内重粉率',
- dataIndex: 'externalUserRepeatRate',
- key: 'externalUserRepeatRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.2 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '主体粉丝总数',
- dataIndex: 'corpExternalUserCount',
- key: 'corpExternalUserCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '主体粉丝在集团占比',
- dataIndex: 'corpExternalUserRate',
- key: 'corpExternalUserRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.2 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '主体客服号数量',
- dataIndex: 'corpUserCount',
- key: 'corpUserCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '主体内重粉数',
- dataIndex: 'corpExternalUserRepeatCount',
- key: 'corpExternalUserRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '主体内重粉率',
- dataIndex: 'corpExternalUserRepeatRate',
- key: 'corpExternalUserRepeatRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.2 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- ]}
- 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 || 20,
- onChange: (page: number, pageSize: number) => {
- setQueryParmas({ ...queryParmas, pageNum: page, pageSize })
- }
- }}
- />
- </Card>
- </Col>
- </Row>
- </Spin>
- <Spin spinning={getExternalUserRepeatCorp.loading || getExternalUserRepeatCorpUser.loading || getCorpExternalUserRepeatList.loading}>
- <Title level={3}><BarChartOutlined style={{ color: '#22c55e' }} /> 用户重粉次数统计</Title>
- <Tabs
- tabBarExtraContent={activeKey === '1' && <Input.Search
- placeholder="请输入企业名称"
- onSearch={(e) => { setQueryParmasZt({ ...queryParmasZt, corpName: e, pageNum: 1 }); }}
- style={{ width: 200 }}
- allowClear
- />}
- items={[
- {
- key: '1',
- label: '主体维度',
- children: <Card>
- <Table
- columns={[
- {
- title: '企业名称',
- dataIndex: 'corpName',
- key: 'corpName',
- ellipsis: true,
- width: 150,
- },
- {
- title: '粉丝总数',
- dataIndex: 'userCount',
- key: 'userCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '非重复添加人数',
- dataIndex: 'oneRepeatCount',
- key: 'oneRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '非重复添加人数比例',
- dataIndex: 'oneRepeatCountRate',
- key: 'oneRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.5 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '重复添加2名人数',
- dataIndex: 'twoRepeatCount',
- key: 'twoRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '重复添加2名人数比例',
- dataIndex: 'twoRepeatCountRate',
- key: 'twoRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.1 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '重复添加3名人数',
- dataIndex: 'threeRepeatCount',
- key: 'threeRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '重复添加3名人数比例',
- dataIndex: 'threeRepeatCountRate',
- key: 'threeRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.09 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '重复添加4名人数',
- dataIndex: 'fourRepeatCount',
- key: 'fourRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '重复添加4名人数比例',
- dataIndex: 'fourRepeatCountRate',
- key: 'fourRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.08 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '重复添加5名人数',
- dataIndex: 'fiveRepeatCount',
- key: 'fiveRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '重复添加5名人数比例',
- dataIndex: 'fiveRepeatCountRate',
- key: 'fiveRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.07 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- {
- title: '重复添加5名以上人数',
- dataIndex: 'gtFiveRepeatCount',
- key: 'gtFiveRepeatCount',
- align: 'center',
- render: (text: any) => <Statistic value={text || 0} valueStyle={{ fontSize: 12 }} />
- },
- {
- title: '重复添加5名以上人数比例',
- dataIndex: 'gtFiveRepeatCountRate',
- key: 'gtFiveRepeatCountRate',
- align: 'center',
- render: (text: any) => <Statistic
- value={text ? text * 100 : 0}
- valueStyle={text > 0.06 ? { color: '#cf1322', fontSize: 12 } : { color: '#3f8600', fontSize: 12 }}
- suffix="%"
- precision={4}
- />
- },
- ]}
- scroll={{ y: 300, x: 900 }}
- 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: (page: number, pageSize: number) => {
- setQueryParmasZt({ ...queryParmasZt, pageNum: page, pageSize })
- }
- }}
- />
- </Card>
- },
- {
- key: '2',
- label: '企业维度',
- children: <Row gutter={16}>
- <Col span={12}>
- <Card style={{ height: '100%' }}>
- <Bar data={barCorpData} title="企业维度重粉次数分布" horizontal />
- </Card>
- </Col>
- <Col span={12}>
- <DetailsTemplate data={corpRepeat} title='企业维度重粉详细数据' />
- </Col>
- </Row>
- },
- {
- 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>
- },
- ]}
- onChange={(e) => { setActiveKey(e) }}
- activeKey={activeKey}
- />
- </Spin>
- </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: 16 }} />
- </div>
- </div>
- <div className={style.item}>
- <span>非重复添加人数</span>
- <div className={style.num}>
- <Statistic value={data?.oneRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.oneRepeatCountRate ? data?.oneRepeatCountRate * 100 : 0}
- valueStyle={data?.oneRepeatCountRate > 0.5 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- <div className={style.item}>
- <span>重复添加2名人数</span>
- <div className={style.num}>
- <Statistic value={data?.twoRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.twoRepeatCountRate ? data?.twoRepeatCountRate * 100 : 0}
- valueStyle={data?.twoRepeatCountRate > 0.1 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- <div className={style.item}>
- <span>重复添加3名人数</span>
- <div className={style.num}>
- <Statistic value={data?.threeRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.threeRepeatCountRate ? data?.threeRepeatCountRate * 100 : 0}
- valueStyle={data?.threeRepeatCountRate > 0.09 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- <div className={style.item}>
- <span>重复添加4名人数</span>
- <div className={style.num}>
- <Statistic value={data?.fourRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.fourRepeatCountRate ? data?.fourRepeatCountRate * 100 : 0}
- valueStyle={data?.fourRepeatCountRate > 0.08 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- <div className={style.item}>
- <span>重复添加5名人数</span>
- <div className={style.num}>
- <Statistic value={data?.fiveRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.fiveRepeatCountRate ? data?.fiveRepeatCountRate * 100 : 0}
- valueStyle={data?.fiveRepeatCountRate > 0.07 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- <div className={style.item}>
- <span>重复添加5名以上人数</span>
- <div className={style.num}>
- <Statistic value={data?.gtFiveRepeatCount || 0} valueStyle={{ fontSize: 16 }} />
- (<Statistic
- value={data?.gtFiveRepeatCountRate ? data?.gtFiveRepeatCountRate * 100 : 0}
- valueStyle={data?.gtFiveRepeatCountRate > 0.06 ? { color: '#cf1322', fontSize: 16 } : { color: '#3f8600', fontSize: 16 }}
- suffix="%"
- precision={4}
- />)
- </div>
- </div>
- </Flex>
- </Card>
- };
- export default Home;
|