wjx 4 dni temu
rodzic
commit
05a123ae6b

+ 58 - 0
src/pages/weComTask/API/heavyPowderMAS/index.ts

@@ -61,4 +61,62 @@ export function getCorpDuplicateFanFansDetailListApi(data: GetFansDetailProps) {
         method: 'POST',
         data
     })
+}
+
+
+
+export interface GetFansDetailListApiProps {
+    pageNum: number,
+    pageSize: number,
+    aCorpIds: string[]
+    bCorpIds: string[]
+    corpName?: string,
+    name?: string,
+    minCorpIdCount?: number,
+    maxCorpIdCount?: number,
+    minCorpUserIdCount?: number,
+    maxCorpUserIdCount?: number,
+    sortType?: string,
+    orderByField?: string
+}
+
+/**
+ * 重复粉丝用户详情(同时添加查询组、对照组的企微用户详情)
+ * @param data 
+ * @returns 
+ */
+export function getFansDetailListApi(data: GetFansDetailListApiProps) {
+    return request({
+        url: api + `/corpOperation/corpDuplicateFan/fansDetail`,
+        method: 'POST',
+        data
+    })
+}
+
+
+/**
+ * 企业id个数 详情
+ * @param params 
+ * @returns 
+ */
+export function getDztSelectCorpIdsByQcUuidListApi(data: { qcUuid: string, aCorpIds: string[], bCorpIds: string[] }) {
+    return request({
+        url: api + `/corpOperation/corpDuplicateFan/selectCorpIdsByQcUuid`,
+        method: 'POST',
+        data
+    })
+}
+
+
+/**
+ * 客服号个数 详情
+ * @param data 
+ * @returns 
+ */
+export function getDztSelectCorpUserIdsByQcUuidListApi(data: { qcUuid: string, aCorpIds: string[], bCorpIds: string[] }) {
+    return request({
+        url: api + `/corpOperation/corpDuplicateFan/selectCorpUserIdsByQcUuid`,
+        method: 'POST',
+        data
+    })
 }

+ 28 - 1
src/pages/weComTask/API/logs/index.tsx

@@ -38,7 +38,34 @@ export interface GetTaskdayProps {
 export function getTaskdayApi(data: GetTaskdayProps) {
     return request({
         url: api + `/corpOperation/corp/stats/task/day`,
-        method: 'post',
+        method: 'POST',
+        data
+    })
+}
+
+export interface GetPullGroupListProps {
+    pageNum: number,
+    pageSize: number,
+    projectName?: string, // 项目名称
+    groupName?: string,   // 群名称
+    taskId?: string,      // 任务ID
+    taskName?: string,    // 任务名称
+    corpChatUserIds?: any[], // 企业群成员ID列表
+    startDay?: string,  // 开始日期
+    endDay?: string     // 结束日期
+    projectGroupIds?: string[] // 项目组ID列表
+}
+
+
+/**
+ * 群聊创建
+ * @param data 
+ * @returns 
+ */
+export function getPullGroupListApi(data: GetPullGroupListProps) {
+    return request({
+        url: api + `/corpOperation/corp/stats/listOfPage/pullGroup`,
+        method: 'POST',
         data
     })
 }

+ 89 - 0
src/pages/weComTask/page/corpData/heavyPowderMAS/corpDetails.tsx

@@ -0,0 +1,89 @@
+import { Avatar, Modal, Space, Table, Typography } from "antd"
+import React, { useEffect, useState } from "react"
+import { EyeOutlined, UserOutlined } from "@ant-design/icons"
+import { useAjax } from "@/Hook/useAjax"
+import { getDztSelectCorpIdsByQcUuidListApi, GetProps } from "@/pages/weComTask/API/heavyPowderMAS"
+const { Text } = Typography;
+
+const CorpDetails: React.FC<{ name: string, avatar: string, corpIdCount: number, qcUuid: string, corpS: GetProps }> = ({ name, avatar, corpIdCount, qcUuid, corpS }) => {
+
+    /*******************************************/
+    const [visible, setVisible] = useState<boolean>(false)
+
+    const getSelectCorpIdsByQcUuidList = useAjax((params) => getDztSelectCorpIdsByQcUuidListApi(params))
+    /*******************************************/
+
+    useEffect(() => {
+        if (visible && qcUuid && corpS?.aCorpIds.length > 0 && corpS?.bCorpIds.length > 0) {
+            getSelectCorpIdsByQcUuidList.run({ qcUuid, ...corpS })
+        }
+    }, [qcUuid, corpS, visible])
+
+    return <>
+        <Space>
+            <span>{corpIdCount}</span>
+            <a onClick={() => setVisible(true)}><EyeOutlined /></a>
+        </Space>
+
+        {visible && <Modal
+            title={<strong>所在企业详情</strong>}
+            open={visible}
+            onCancel={() => setVisible(false)}
+            width={1000}
+            footer={null}
+        >
+            <Table
+                columns={[
+                    {
+                        title: '企业名称',
+                        dataIndex: 'corpName',
+                        key: 'corpName',
+                        width: 180,
+                        ellipsis: true,
+                    },
+                    {
+                        title: '企业ID',
+                        dataIndex: 'corpId',
+                        key: 'corpId',
+                        width: 280,
+                        ellipsis: true,
+                        render: (text: string) => {
+                            return <Text copyable>{text}</Text>
+                        }
+                    },
+                    {
+                        title: '客户名称',
+                        dataIndex: 'name',
+                        key: 'name',
+                        align: 'center',
+                        width: 145,
+                        render: () => {
+                            return <Space>
+                                <Avatar shape="square" size={20} icon={<UserOutlined />} src={avatar} />
+                                <Text>{name}</Text>
+                            </Space>
+                        }
+                    },
+                    {
+                        title: '客户ID',
+                        dataIndex: 'externalUserId',
+                        key: 'externalUserId',
+                        render: (text: string) => {
+                            return <Text copyable>{text}</Text>
+                        }
+                    }
+                ]}
+                scroll={{ y: 460 }}
+                bordered
+                pagination={{
+                    defaultPageSize: 20
+                }}
+                dataSource={getSelectCorpIdsByQcUuidList.data?.data}
+                loading={getSelectCorpIdsByQcUuidList.loading}
+                rowKey="corpId"
+            />
+        </Modal>}
+    </>
+}
+
+export default React.memo(CorpDetails)

+ 100 - 0
src/pages/weComTask/page/corpData/heavyPowderMAS/corpUserDetails.tsx

@@ -0,0 +1,100 @@
+import { Avatar, Modal, Space, Table, Typography } from "antd"
+import React, { useEffect, useState } from "react"
+import { EyeOutlined, UserOutlined } from "@ant-design/icons"
+import { useAjax } from "@/Hook/useAjax"
+import { getDztSelectCorpUserIdsByQcUuidListApi, GetProps } from "@/pages/weComTask/API/heavyPowderMAS"
+const { Text } = Typography;
+
+const CorpUserDetails: React.FC<{ name: string, avatar: string, corpUserIdCount: number, qcUuid: string, corpS: GetProps }> = ({ name, avatar, corpUserIdCount, qcUuid, corpS }) => {
+
+    /*******************************************/
+    const [visible, setVisible] = useState<boolean>(false)
+
+    const getDztSelectCorpUserIdsByQcUuidList = useAjax((params) => getDztSelectCorpUserIdsByQcUuidListApi(params))
+    /*******************************************/
+
+    useEffect(() => {
+        if (visible && qcUuid && corpS?.aCorpIds.length > 0 && corpS?.bCorpIds.length > 0) {
+            getDztSelectCorpUserIdsByQcUuidList.run({ qcUuid, ...corpS })
+        }
+    }, [qcUuid, visible, corpS])
+
+    return <>
+        <Space>
+            <span>{corpUserIdCount}</span>
+            <a onClick={() => setVisible(true)}><EyeOutlined /></a>
+        </Space>
+
+        {visible && <Modal
+            title={<strong>所在客服下详情</strong>}
+            open={visible}
+            onCancel={() => setVisible(false)}
+            width={1000}
+            footer={null}
+        >
+            <Table
+                columns={[
+                    {
+                        title: '企业名称',
+                        dataIndex: 'corpName',
+                        key: 'corpName',
+                        width: 180,
+                        ellipsis: true,
+                        render: (text: string) => text || '--'
+                    },
+                    {
+                        title: '企业ID',
+                        dataIndex: 'corpId',
+                        key: 'corpId',
+                        width: 300,
+                        ellipsis: true,
+                        render: (text: string) => {
+                            return text ? <Text copyable>{text}</Text> : '--'
+                        }
+                    },
+                    {
+                        title: '客户名称',
+                        dataIndex: 'name',
+                        key: 'name',
+                        width: 150,
+                        align: 'center',
+                        render: () => {
+                            return <Space>
+                                <Avatar shape="square" size={20} icon={<UserOutlined />} src={avatar} />
+                                <Text>{name}</Text>
+                            </Space>
+                        }
+                    },
+                    {
+                        title: '客服号名称',
+                        dataIndex: 'corpUserName',
+                        key: 'corpUserName',
+                        ellipsis: true,
+                        width: 150,
+                        render: (text: string) => text || '--'
+                    },
+                    {
+                        title: '客服号ID',
+                        dataIndex: 'corpUserId',
+                        key: 'corpUserId',
+                        ellipsis: true,
+                        width: 300,
+                        render: (text: string) => {
+                            return text ? <Text copyable>{text}</Text> : '--'
+                        }
+                    }
+                ]}
+                scroll={{ y: 460 }}
+                bordered
+                pagination={{
+                    defaultPageSize: 20
+                }}
+                dataSource={getDztSelectCorpUserIdsByQcUuidList.data?.data}
+                loading={getDztSelectCorpUserIdsByQcUuidList.loading}
+                rowKey="corpUserId"
+            />
+        </Modal>}
+    </>
+}
+
+export default React.memo(CorpUserDetails)

+ 55 - 1
src/pages/weComTask/page/corpData/heavyPowderMAS/index.tsx

@@ -1,7 +1,7 @@
 import { getCorpAllListApi } from "@/API/global";
 import { useAjax } from "@/Hook/useAjax";
 import { getCorpDuplicateFanOverviewListApi, GetProps } from "@/pages/weComTask/API/heavyPowderMAS";
-import { Card, Col, Flex, Row, Space, Table, Typography } from "antd";
+import { Card, Col, Flex, Row, Space, Statistic, Table, Typography } from "antd";
 import { useEffect, useState } from "react";
 import SelectCorp from "./SelectCorp";
 import { Columns1 } from "./tableConfig";
@@ -84,6 +84,33 @@ const HeavyPowderMAS: React.FC = () => {
                         bordered
                         scroll={{ y: 300 }}
                         rowKey={'corp_id'}
+                        summary={() => {
+                            return (
+                                <Table.Summary fixed='top'><Table.Summary.Row>
+                                    <Table.Summary.Cell index={0} align="center">
+                                        <Title level={5} style={{ margin: 0, marginBottom: 0 }}>总计</Title>
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={1} align="center">--</Table.Summary.Cell>
+                                    <Table.Summary.Cell index={2} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.total_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={3} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.only_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={4} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.qc_null_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={5} align="center">
+                                        <Statistic
+                                            value={getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.only_rate ? getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.only_rate * 100 : 0}
+                                            valueStyle={getCorpDuplicateFanOverviewList?.data?.data?.aTotalData?.only_rate < 0.8 ? { color: '#cf1322', fontSize: 12, fontWeight: 'bold' } : { color: '#3f8600', fontSize: 12, fontWeight: 'bold' }}
+                                            suffix="%"
+                                            precision={2}
+                                        />
+                                    </Table.Summary.Cell>
+                                </Table.Summary.Row></Table.Summary>
+                            )
+                        }}
                     />
                 </Col>
                 <Col span={12}>
@@ -95,6 +122,33 @@ const HeavyPowderMAS: React.FC = () => {
                         bordered
                         scroll={{ y: 300 }}
                         rowKey={'corp_id'}
+                        summary={() => {
+                            return (
+                                <Table.Summary fixed='top'><Table.Summary.Row>
+                                    <Table.Summary.Cell index={0} align="center">
+                                        <Title level={5} style={{ margin: 0, marginBottom: 0 }}>总计</Title>
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={1} align="center">--</Table.Summary.Cell>
+                                    <Table.Summary.Cell index={2} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.total_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={3} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.only_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={4} align="center">
+                                        <Statistic value={getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.qc_null_num || 0} valueStyle={{ fontSize: 12, fontWeight: 'bold' }} />
+                                    </Table.Summary.Cell>
+                                    <Table.Summary.Cell index={5} align="center">
+                                        <Statistic
+                                            value={getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.only_rate ? getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.only_rate * 100 : 0}
+                                            valueStyle={getCorpDuplicateFanOverviewList?.data?.data?.bTotalData?.only_rate < 0.8 ? { color: '#cf1322', fontSize: 12, fontWeight: 'bold' } : { color: '#3f8600', fontSize: 12, fontWeight: 'bold' }}
+                                            suffix="%"
+                                            precision={2}
+                                        />
+                                    </Table.Summary.Cell>
+                                </Table.Summary.Row></Table.Summary>
+                            )
+                        }}
                     />
                 </Col>
             </Row>

+ 16 - 5
src/pages/weComTask/page/corpData/heavyPowderMAS/repeatAnalyze.tsx

@@ -1,9 +1,10 @@
 import { useAjax } from "@/Hook/useAjax";
 import { getCorpDuplicateFanRepeatAnalyzeListApi, GetProps } from "@/pages/weComTask/API/heavyPowderMAS";
-import { Card, Flex, Spin, Statistic } from "antd";
+import { Card, Flex, Space, Spin, Statistic, Tooltip } from "antd";
 import React, { useState } from "react";
 import { useEffect } from "react";
 import style from '../heavyPowder/index.less';
+import { QuestionCircleOutlined } from "@ant-design/icons";
 
 
 const RepeatAnalyze: React.FC<{ queryParmas: GetProps }> = ({ queryParmas }) => {
@@ -74,13 +75,18 @@ const RepeatAnalyze: React.FC<{ queryParmas: GetProps }> = ({ queryParmas }) =>
                     </div>
                 </div>
                 <div className={style.item}>
-                    <span>重粉比</span>
+                    <Space>
+                       <span>重粉比</span>
+                        <Tooltip title="(查询组内用户在对照组内重粉数)/查询组净值企微用户数">
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>
                     <div className={style.num}>
                         <Statistic
                             value={data?.query_overlap_rate ? data?.query_overlap_rate * 100 : 0}
                             valueStyle={data?.query_overlap_rate > 0.2 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />
                     </div>
                 </div>
@@ -91,13 +97,18 @@ const RepeatAnalyze: React.FC<{ queryParmas: GetProps }> = ({ queryParmas }) =>
                     </div>
                 </div>
                 <div className={style.item}>
-                    <span>查询组非重粉占比</span>
+                    <Space>
+                        <span>查询组非重粉占比</span>
+                        <Tooltip title="(查询组总企微用户数-交叉重粉数)/查询组总企微用户数">
+                            <QuestionCircleOutlined />
+                        </Tooltip>
+                    </Space>
                     <div className={style.num}>
                         <Statistic
                             value={data?.query_non_overlap_rate ? data?.query_non_overlap_rate * 100 : 0}
                             valueStyle={data?.query_non_overlap_rate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />
                     </div>
                 </div>

+ 7 - 7
src/pages/weComTask/page/corpData/heavyPowderMAS/repeatOfCorpUser.tsx

@@ -62,7 +62,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_gt1_rate ? data?.add_gt1_rate * 100 : 0}
                             valueStyle={data?.add_gt1_rate > 0.3 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -74,7 +74,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_1_rate ? data?.add_1_rate * 100 : 0}
                             valueStyle={data?.add_1_rate > 0.5 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -86,7 +86,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_2_rate ? data?.add_2_rate * 100 : 0}
                             valueStyle={data?.add_2_rate > 0.1 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -98,7 +98,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_3_rate ? data?.add_3_rate * 100 : 0}
                             valueStyle={data?.add_3_rate > 0.09 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -110,7 +110,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_4_rate ? data?.add_4_rate * 100 : 0}
                             valueStyle={data?.add_4_rate > 0.08 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -122,7 +122,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_5_rate ? data?.add_5_rate * 100 : 0}
                             valueStyle={data?.add_5_rate > 0.07 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>
@@ -134,7 +134,7 @@ const RepeatOfCorpUser: React.FC<{ queryParmas: GetProps }> = ({ queryParmas })
                             value={data?.add_gt5_rate ? data?.add_gt5_rate * 100 : 0}
                             valueStyle={data?.add_gt5_rate > 0.06 ? { color: '#cf1322', fontSize: 14 } : { color: '#3f8600', fontSize: 14 }}
                             suffix="%"
-                            precision={4}
+                            precision={2}
                         />)
                     </div>
                 </div>

+ 15 - 18
src/pages/weComTask/page/corpData/heavyPowderMAS/userDetails.tsx

@@ -1,12 +1,12 @@
 import { useAjax } from "@/Hook/useAjax";
-import { GetProps } from "@/pages/weComTask/API/heavyPowderMAS";
-import { GetExternalUserRepeatByCorpListApiProps, getSelectQcUuidStatisticPageListApi } from "@/pages/weComTask/API/home";
+import { getFansDetailListApi, GetProps } from "@/pages/weComTask/API/heavyPowderMAS";
+import { GetExternalUserRepeatByCorpListApiProps } from "@/pages/weComTask/API/home";
 import SearchBox from "@/pages/weComTask/components/searchBox";
 import { Card, Space, Table, Image, Typography, Button, Input, InputNumber } from "antd";
 import React, { useEffect, useState } from "react";
-import CorpUserDetails from "../heavyPowder/corpUserDetails";
-import CorpDetails from "../heavyPowder/corpDetails";
 import { SearchOutlined } from "@ant-design/icons";
+import CorpDetails from "./corpDetails";
+import CorpUserDetails from "./corpUserDetails";
 
 const { Text } = Typography;
 
@@ -15,12 +15,12 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
     /**************************************/
     const [queryParmas, setQueryParmas] = useState<GetExternalUserRepeatByCorpListApiProps>({ pageNum: 1, pageSize: 20 })
     const [queryParmasNew, setQueryParmasNew] = useState<GetExternalUserRepeatByCorpListApiProps>({ pageNum: 1, pageSize: 20 })
-    const getSelectQcUuidStatisticPageList = useAjax((params) => getSelectQcUuidStatisticPageListApi(params))
+    const getFansDetailList = useAjax((params) => getFansDetailListApi(params))
     /**************************************/
 
     useEffect(() => {
         if (q?.aCorpIds.length > 0 && q?.bCorpIds.length > 0) {
-            getSelectQcUuidStatisticPageList.run({ corpIdList: [...new Set([...q.aCorpIds, ...q.bCorpIds])], ...queryParmas })
+            getFansDetailList.run({ ...q, ...queryParmas })
         }
     }, [queryParmas, q])
 
@@ -37,16 +37,13 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
                 }}>重置</Button>
                 <Button type="primary" onClick={() => {
                     setQueryParmas({ ...queryParmasNew, pageNum: 1, pageSize: queryParmas.pageSize })
-                }} loading={getSelectQcUuidStatisticPageList.loading} icon={<SearchOutlined />}>搜索</Button>
+                }} loading={getFansDetailList.loading} icon={<SearchOutlined />}>搜索</Button>
             </>}
         >
             <>
-                <Input onChange={(e) => setQueryParmasNew({ ...queryParmasNew, corpName: e.target.value })} value={queryParmasNew?.corpName} placeholder="企微名称" allowClear />
                 <Input onChange={(e) => setQueryParmasNew({ ...queryParmasNew, name: e.target.value })} value={queryParmasNew?.name} placeholder="客户昵称" allowClear />
                 <InputNumber placeholder="最小企业id个数" style={{ width: 125 }} value={queryParmasNew?.minCorpIdCount} onChange={(e) => setQueryParmasNew({ ...queryParmasNew, minCorpIdCount: e })} />
                 <InputNumber placeholder="最大企业id个数" style={{ width: 125 }} value={queryParmasNew?.maxCorpIdCount} onChange={(e) => setQueryParmasNew({ ...queryParmasNew, maxCorpIdCount: e })} />
-                <InputNumber placeholder="最小客服号id个数" style={{ width: 125 }} value={queryParmasNew?.minCorpUserIdCount} onChange={(e) => setQueryParmasNew({ ...queryParmasNew, minCorpUserIdCount: e })} />
-                <InputNumber placeholder="最大客服号id个数" style={{ width: 125 }} value={queryParmasNew?.maxCorpUserIdCount} onChange={(e) => setQueryParmasNew({ ...queryParmasNew, maxCorpUserIdCount: e })} />
             </>
         </SearchBox>
 
@@ -56,7 +53,7 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
                     title: '客户名称',
                     dataIndex: 'name',
                     key: 'name',
-                    width: 180,
+                    width: 260,
                     render: (text: any, record: any) => {
                         return <Space>
                             <Image src={record?.avatar} style={{ width: 20, borderRadius: 4 }} />
@@ -72,7 +69,7 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
                     align: 'center',
                     sorter: true,
                     render: (text: number, record: any) => {
-                        return <CorpDetails name={record?.name} avatar={record?.avatar} corpIdCount={text} qcUuid={record?.qcUuid} />
+                        return <CorpDetails corpS={q} name={record?.name} avatar={record?.avatar} corpIdCount={text} qcUuid={record?.qcUuid} />
                     }
                 },
                 {
@@ -83,7 +80,7 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
                     align: 'center',
                     sorter: true,
                     render: (text: number, record: any) => {
-                        return <CorpUserDetails name={record?.name} avatar={record?.avatar} corpUserIdCount={text} qcUuid={record?.qcUuid} />
+                        return <CorpUserDetails corpS={q} name={record?.name} avatar={record?.avatar} corpUserIdCount={text} qcUuid={record?.qcUuid} />
                     }
                 },
                 {
@@ -98,13 +95,13 @@ const UserDetails: React.FC<{ queryParmas: GetProps }> = ({ queryParmas: q }) =>
             ]}
             scroll={{ y: 300, x: 1000 }}
             bordered
-            dataSource={getSelectQcUuidStatisticPageList.data?.data?.records}
-            loading={getSelectQcUuidStatisticPageList.loading}
+            dataSource={getFansDetailList.data?.data?.records}
+            loading={getFansDetailList.loading}
             rowKey="qcUuid"
             pagination={{
-                total: getSelectQcUuidStatisticPageList.data?.data?.total,
-                current: getSelectQcUuidStatisticPageList?.data?.data?.current || 1,
-                pageSize: getSelectQcUuidStatisticPageList?.data?.data?.size || 20,
+                total: getFansDetailList.data?.data?.total,
+                current: getFansDetailList?.data?.data?.current || 1,
+                pageSize: getFansDetailList?.data?.data?.size || 20,
             }}
             onChange={(pagination: any, _: any, sortData: any) => {
                 let { current, pageSize } = pagination

+ 2 - 1
src/pages/weComTask/page/groupChat/taskList/details.tsx

@@ -437,7 +437,7 @@ const ExpandedRow: React.FC<{ record: any }> = ({ record }) => {
 }
 
 
-const TaskDetails: React.FC<{
+export const TaskDetails: React.FC<{
     visible?: boolean,
     taskLogId?: number,
     onClose?: () => void
@@ -464,6 +464,7 @@ const TaskDetails: React.FC<{
             rowKey={'id'}
             dataSource={getProjectLogDetailsList?.data?.data || []}
             scroll={{ y: 1000 }}
+            loading={getProjectLogDetailsList.loading}
             columns={[
                 {
                     title: '群名称',

+ 8 - 15
src/pages/weComTask/page/home/index.tsx

@@ -11,6 +11,7 @@ import { RangePickerProps } from "antd/es/date-picker";
 import { useAjax } from "@/Hook/useAjax";
 import { getTotalModelApi, getTotalTaslApi } from "../../API/logs";
 import CalendarItem from "./calendarItem";
+import PullGroup from "./pullGroup";
 
 const weekMap = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
 const taskTypeMap = {
@@ -340,21 +341,13 @@ const Logs: React.FC = () => {
                                             </div>
                                         </div>
                                     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>
+                                        return <PullGroup 
+                                            key={index} 
+                                            pullGroupCount={item?.pullGroupCount}
+                                            pullSuccessCount={item?.pullSuccessCount}
+                                            pullSuccessRate={item?.pullSuccessRate}
+                                            pullFailCount={item?.pullFailCount}
+                                        />
                                     case 'TASK_STAT_TRANSFER': // 继承
                                         return <div className={style.moduleCard} key={index}>
                                             <div className={style.moduleCard_header}>

+ 357 - 0
src/pages/weComTask/page/home/pullGroup.tsx

@@ -0,0 +1,357 @@
+import { Avatar, Button, DatePicker, Drawer, Input, Modal, Select, Space, Table } from "antd";
+import React, { useEffect, useState } from "react";
+import style from './index.less';
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faUserFriends } from "@fortawesome/free-solid-svg-icons";
+import { useAjax } from "@/Hook/useAjax";
+import { getPullGroupListApi, GetPullGroupListProps } from "../../API/logs";
+import SearchBox from "../../components/searchBox";
+import { ExclamationCircleOutlined, SearchOutlined } from "@ant-design/icons";
+import dayJs from "dayjs";
+import { getProjectGroupsAllListApi } from "../../API/groupManage";
+import SelectGroupLeader from "../groupLeaderManage/selectGroupLeader";
+import { copy } from "@/utils/utils";
+import { TaskDetails } from "../groupChat/taskList/details";
+
+interface Props {
+    pullGroupCount: number,
+    pullSuccessCount: number,
+    pullSuccessRate: number,
+    pullFailCount: number
+}
+
+/**
+ * 群聊创建
+ * @param param0 
+ * @returns 
+ */
+const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccessCount, pullSuccessRate }) => {
+
+    /**************************************/
+    const [visible, setVisible] = useState<boolean>(false)
+    const [queryParams, setQueryParams] = useState<GetPullGroupListProps>({ pageNum: 1, pageSize: 20 })
+    const [oldQueryParams, setOldQueryParams] = useState<GetPullGroupListProps>({ pageNum: 1, pageSize: 20 })
+    const [groupList, setGroupList] = useState<{ label: string, value: number }[]>([])
+    const [detalisData, setDetalisData] = useState<{ visible?: boolean, taskLogId?: number }>()
+    const [modal, contextHolder] = Modal.useModal();
+
+    const getPullGroupList = useAjax((params) => getPullGroupListApi(params))
+    const getProjectGroupsAllList = useAjax(() => getProjectGroupsAllListApi())
+    /**************************************/
+
+    useEffect(() => {
+        if (visible) {
+            const { corpChatUserIds, ...p } = queryParams
+            let params: any = { ...p }
+            if (corpChatUserIds?.length) {
+                params.corpChatUserIds = corpChatUserIds.map(item => item.value)
+            } else {
+                delete params?.corpChatUserIds
+            }
+            getPullGroupList.run(params)
+        }
+    }, [queryParams, visible])
+
+    useEffect(() => {
+        getProjectGroupsAllList.run().then(res => {
+            setGroupList([{ label: '空项目组', value: 0 }, ...res?.data?.map(item => ({ label: item.name, value: item.id })) || []])
+        })
+    }, [])
+
+    return <>
+        {contextHolder}
+        <div className={style.moduleCard} onClick={() => setVisible(true)}>
+            <div className={style.moduleCard_header}>
+                <Avatar style={{ backgroundColor: '#f6ffed', color: '#73d13d' }} size={30}>
+                    <FontAwesomeIcon icon={faUserFriends} />
+                </Avatar>
+                群聊创建-拉群
+            </div>
+            <div className={style.moduleCard_center}>
+                预计拉群数:{pullGroupCount || 0} | 拉群成功数:{pullSuccessCount || 0}
+            </div>
+            <div className={style.moduleCard_footer}>
+                <span>今日拉群成功率:{((pullSuccessRate || 0) * 100).toFixed(2)} %</span>
+                <span className={style.error}>今日拉群失败数:{pullFailCount}</span>
+            </div>
+        </div>
+        <Drawer
+            title="群聊创建"
+            onClose={() => setVisible(false)}
+            open={visible}
+            width={'70%'}
+        >
+            <SearchBox
+                bodyPadding={`0 0 10px`}
+                buttons={<>
+                    <Button type="primary" onClick={() => {
+                        setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
+                    }} loading={getPullGroupList.loading} icon={<SearchOutlined />}>搜索</Button>
+                </>}
+            >
+                <>
+                    <Input
+                        placeholder='任务名称'
+                        style={{ width: 150 }}
+                        allowClear
+                        value={oldQueryParams?.projectName}
+                        onChange={(e) => setOldQueryParams({ ...oldQueryParams, projectName: e.target.value })}
+                    />
+                    <Input
+                        placeholder='任务ID'
+                        style={{ width: 150 }}
+                        allowClear
+                        value={oldQueryParams?.taskId}
+                        onChange={(e) => setOldQueryParams({ ...oldQueryParams, taskId: e.target.value })}
+                    />
+                    <Input
+                        placeholder='群名称'
+                        style={{ width: 150 }}
+                        allowClear
+                        value={oldQueryParams?.groupName}
+                        onChange={(e) => setOldQueryParams({ ...oldQueryParams, groupName: e.target.value })}
+                    />
+                    <SelectGroupLeader
+                        value={oldQueryParams?.corpChatUserIds}
+                        onChange={(corpChatUserIds) => {
+                            setOldQueryParams({ ...oldQueryParams, corpChatUserIds })
+                        }}
+                    />
+                    <Select
+                        placeholder='请选择项目组'
+                        allowClear
+                        options={groupList}
+                        showSearch
+                        style={{ width: 150 }}
+                        filterOption={(input, option) =>
+                            (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
+                        }
+                        mode="multiple"
+                        value={oldQueryParams?.projectGroupIds}
+                        onChange={(value) => setOldQueryParams({ ...oldQueryParams, projectGroupIds: value })}
+                    />
+                    <DatePicker.RangePicker
+                        placeholder={['执行开始日期', '执行结束日期']}
+                        allowClear
+                        value={oldQueryParams?.startDay ? [dayJs(oldQueryParams?.startDay), dayJs(oldQueryParams?.endDay)] : undefined}
+                        onChange={(_, options) => setOldQueryParams({ ...oldQueryParams, startDay: options?.[0], endDay: options?.[1] })}
+                    />
+                </>
+            </SearchBox>
+
+            <Table
+                dataSource={getPullGroupList?.data?.data?.records}
+                columns={[
+                    {
+                        title: '操作',
+                        dataIndex: 'cz',
+                        key: 'cz',
+                        width: 100,
+                        align: 'center',
+                        render: (_, record: any) => {
+                            return <Space>
+                                <a onClick={() => setDetalisData({ visible: true, taskLogId: record.id })}>详情</a>
+                                <a onClick={() => {
+                                    modal.confirm({
+                                        title: '确认',
+                                        icon: <ExclamationCircleOutlined />,
+                                        content: '是否跳转到日志详情?',
+                                        okText: '确认',
+                                        cancelText: '复制',
+                                        onCancel: () => {
+                                            copy(record.projectName + '任务Id:' + record.taskId)
+                                        },
+                                        onOk: () => {
+                                            localStorage.setItem('OPENTASK', JSON.stringify({
+                                                id: record.projectId,
+                                                projectName: record.projectName,
+                                                taskType: 'TASK_STAT_PULL_GROUP',
+                                                taskId: record.taskId,
+                                                msg: '跳转日志详情'
+                                            }))
+                                            window.open(`/weComTask#/weComTask/groupChat/taskList`)
+                                        },
+                                    });
+                                }}>任务跳转</a>
+                            </Space>
+                        }
+                    },
+                    {
+                        title: '任务名称',
+                        dataIndex: 'projectName',
+                        key: 'projectName',
+                        width: 180,
+                        ellipsis: true,
+                        render: (text) => <a onClick={() => copy(text)}>{text}</a>
+                    },
+                    {
+                        title: '子任务ID',
+                        dataIndex: 'taskId',
+                        key: 'taskId',
+                        width: 70,
+                        align: 'center'
+                    },
+                    {
+                        title: '项目组名称',
+                        dataIndex: 'projectGroupName',
+                        key: 'projectGroupName',
+                        width: 100,
+                        ellipsis: true,
+                        render: (text) => text ? <a onClick={() => copy(text)}>{text}</a> : '--'
+                    },
+                    {
+                        title: '项目组ID',
+                        dataIndex: 'projectGroupId',
+                        key: 'projectGroupId',
+                        width: 70,
+                        align: 'center'
+                    },
+                    {
+                        title: '群聊名称',
+                        dataIndex: 'groupName',
+                        key: 'groupName',
+                        width: 150,
+                        ellipsis: true,
+                        render: (text) => <a onClick={() => copy(text)}>{text}</a>
+                    },
+                    {
+                        title: '群主号',
+                        dataIndex: 'corpChatUserList',
+                        key: 'corpChatUserList',
+                        width: 150,
+                        ellipsis: true,
+                        align: 'center',
+                        render: (value) => value?.map((item) => `${item.corpUserName}(${item.corpName})`).join(',')
+                    },
+                    {
+                        title: '企微号',
+                        dataIndex: 'corpUserList',
+                        key: 'corpUserList',
+                        width: 200,
+                        ellipsis: true,
+                        render: (value) => value?.map((item) => `${item.corpUserName}(${item.corpName})`).join(',')
+                    },
+                    {
+                        title: '机器人号',
+                        dataIndex: 'corpRobotList',
+                        key: 'corpRobotList',
+                        width: 120,
+                        align: 'center',
+                        ellipsis: true,
+                        render: (value) => value?.map((item) => `${item.corpUserName}(${item.corpName})`).join(',')
+                    },
+                    {
+                        title: '公众号',
+                        dataIndex: 'mpAccountInfo',
+                        key: 'mpAccountInfo',
+                        width: 100,
+                        align: 'center',
+                        ellipsis: true,
+                        render: (value) => value?.name || '--'
+                    },
+                    {
+                        title: '执行时间',
+                        dataIndex: 'createTime',
+                        key: 'createTime',
+                        width: 130,
+                        ellipsis: true,
+                    },
+                    {
+                        title: '预计拉群数',
+                        dataIndex: 'pullGroupCount',
+                        key: 'pullGroupCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '实际拉群数',
+                        dataIndex: 'pullSuccessCount',
+                        key: 'pullSuccessCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '预计拉群客户数',
+                        dataIndex: 'pullGroupUserCount',
+                        key: 'pullGroupUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '实际拉群客户数',
+                        dataIndex: 'pullSuccessUserCount',
+                        key: 'pullSuccessUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '上次失败补拉数量',
+                        dataIndex: 'lastFailedRetryCount',
+                        key: 'lastFailedRetryCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '失败客户数',
+                        dataIndex: 'pullFailedUserCount',
+                        key: 'pullFailedUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '删除或拉黑客户数',
+                        dataIndex: 'pullBlackUserCount',
+                        key: 'pullBlackUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '发送邀请客户数',
+                        dataIndex: 'sendInviteUserCount',
+                        key: 'sendInviteUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                    {
+                        title: '退群客户数',
+                        dataIndex: 'quitUserCount',
+                        key: 'quitUserCount',
+                        width: 90,
+                        align: 'center',
+                        render: (value) => value || 0
+                    },
+                ]}
+                rowKey={'id'}
+                bordered={true}
+                size='small'
+                scroll={{ x: 1200 }}
+                loading={getPullGroupList?.loading}
+                pagination={{
+                    current: getPullGroupList?.data?.data?.current,
+                    pageSize: getPullGroupList?.data?.data?.size,
+                    total: getPullGroupList?.data?.data?.total,
+                    showSizeChanger: true,
+                    onChange: (page, pageSize) => {
+                        setQueryParams({ ...queryParams, pageNum: page, pageSize })
+                        setOldQueryParams({ ...oldQueryParams, pageNum: page, pageSize })
+                    }
+                }}
+            />
+        </Drawer>
+        {/* 详情 */}
+        {detalisData?.visible && <TaskDetails
+            {...detalisData}
+            onClose={() => setDetalisData(undefined)}
+        />}
+    </>
+}
+
+export default React.memo(PullGroup);