wjx 1 dia atrás
pai
commit
ae7b9be2c8

+ 29 - 0
src/pages/weComTask/API/logs/index.tsx

@@ -56,6 +56,8 @@ export interface GetPullGroupListProps {
     projectGroupIds?: string[] // 项目组ID列表
     sortFiled?: string
     sortAsc?: boolean
+    mpAccountIds?: number[]
+    includeCreateBy?: boolean
 }
 
 
@@ -72,6 +74,33 @@ export function getPullGroupListApi(data: GetPullGroupListProps) {
     })
 }
 
+/**
+ * 总计
+ * @param data 
+ * @returns 
+ */
+export function getPullGroupTotalApi(data: GetPullGroupListProps) {
+    return request({
+        url: api + `/corpOperation/corp/stats/listOfPage/pullGroup/total`,
+        method: 'POST',
+        data
+    })
+}
+
+/**
+ * 下载
+ * @param data 
+ * @returns 
+ */
+export function downPullGroupExcelApi(data: GetPullGroupListProps) {
+    return request({
+        url: api + `/corpOperation/corp/stats/listOfPage/pullGroup/excel`,
+        method: 'POST',
+        data,
+        responseType: 'blob'
+    })
+}
+
 export interface GetSendUserListProps {
     pageNum: number,
     pageSize: number,

+ 263 - 205
src/pages/weComTask/page/home/pullGroup.tsx

@@ -1,17 +1,20 @@
-import { Avatar, Button, DatePicker, Drawer, Input, Modal, Select, Space, Table } from "antd";
+import { Avatar, Button, Checkbox, 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 { downPullGroupExcelApi, getPullGroupListApi, GetPullGroupListProps, getPullGroupTotalApi } from "../../API/logs";
 import SearchBox from "../../components/searchBox";
-import { ExclamationCircleOutlined, SearchOutlined } from "@ant-design/icons";
+import { DownloadOutlined, 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";
+import { getBindMpListApi } from "../../API/corpUserAssign";
+import { ColumnsType } from "antd/es/table";
+import { downloadFile1, formatDate } from "@/utils/downloadFile";
 
 interface Props {
     pullGroupCount: number,
@@ -29,14 +32,18 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
 
     /**************************************/
     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 [queryParams, setQueryParams] = useState<GetPullGroupListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
+    const [oldQueryParams, setOldQueryParams] = useState<GetPullGroupListProps>({ pageNum: 1, pageSize: 20, includeCreateBy: true })
     const [groupList, setGroupList] = useState<{ label: string, value: number }[]>([])
     const [detalisData, setDetalisData] = useState<{ visible?: boolean, taskLogId?: number }>()
     const [modal, contextHolder] = Modal.useModal();
+    const [totalData, setTotalData] = useState<Record<string, any>>({})
 
     const getPullGroupList = useAjax((params) => getPullGroupListApi(params))
+    const getPullGroupTotal = useAjax((params) => getPullGroupTotalApi(params))
+    const downPullGroupExcel = useAjax((params) => downPullGroupExcelApi(params))
     const getProjectGroupsAllList = useAjax(() => getProjectGroupsAllListApi())
+    const getBindMpList = useAjax(() => getBindMpListApi())
     /**************************************/
 
     useEffect(() => {
@@ -49,6 +56,9 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                 delete params?.corpChatUserIds
             }
             getPullGroupList.run(params)
+            getPullGroupTotal.run(params).then(res => {
+                setTotalData(res?.data || {})
+            })
         }
     }, [queryParams, visible])
 
@@ -57,9 +67,223 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
             getProjectGroupsAllList.run().then(res => {
                 setGroupList([{ label: '空项目组', value: 0 }, ...res?.data?.map(item => ({ label: item.name, value: item.id })) || []])
             })
+            getBindMpList.run()
         }
     }, [visible])
 
+    const columns: ColumnsType<any> = [
+        {
+            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,
+            align: 'center',
+            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',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '实际拉群数',
+            dataIndex: 'pullSuccessCount',
+            key: 'pullSuccessCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '预计拉群客户数',
+            dataIndex: 'pullGroupUserCount',
+            key: 'pullGroupUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '实际拉群客户数',
+            dataIndex: 'pullSuccessUserCount',
+            key: 'pullSuccessUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '上次失败补拉数量',
+            dataIndex: 'lastFailedRetryCount',
+            key: 'lastFailedRetryCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '失败客户数',
+            dataIndex: 'pullFailedUserCount',
+            key: 'pullFailedUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => <span style={value > 5 ? { color: 'red' } : {}}>{value || 0}</span>
+        },
+        {
+            title: '删除或拉黑客户数',
+            dataIndex: 'pullBlackUserCount',
+            key: 'pullBlackUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '发送邀请客户数',
+            dataIndex: 'sendInviteUserCount',
+            key: 'sendInviteUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        },
+        {
+            title: '退群客户数',
+            dataIndex: 'quitUserCount',
+            key: 'quitUserCount',
+            width: 90,
+            align: 'center',
+            sorter: true,
+            render: (value) => value || 0
+        }
+    ]
+
+    /**下载 */
+    const handleDownload = () => {
+        const { corpChatUserIds, ...p } = queryParams
+        let params: any = { ...p }
+        if (corpChatUserIds?.length) {
+            params.corpChatUserIds = corpChatUserIds.map(item => item.value)
+        } else {
+            delete params?.corpChatUserIds
+        }
+        downPullGroupExcel.run(params).then((res: any) => {
+            downloadFile1(res, 'octet-stream', formatDate(new Date()) + ".xlsx")
+        })
+    }
+
     return <>
         {contextHolder}
         <div className={style.moduleCard} onClick={() => setVisible(true)}>
@@ -89,6 +313,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                     <Button type="primary" onClick={() => {
                         setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
                     }} loading={getPullGroupList.loading} icon={<SearchOutlined />}>搜索</Button>
+                    <Button icon={<DownloadOutlined />} loading={downPullGroupExcel.loading} onClick={handleDownload}>下载</Button>
                 </>}
             >
                 <>
@@ -113,6 +338,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         value={oldQueryParams?.groupName}
                         onChange={(e) => setOldQueryParams({ ...oldQueryParams, groupName: e.target.value })}
                     />
+                    <Checkbox checked={oldQueryParams?.includeCreateBy} onChange={(e) => setOldQueryParams({ ...oldQueryParams, includeCreateBy: e.target.checked })}>是否包含创建人</Checkbox>
                     <SelectGroupLeader
                         value={oldQueryParams?.corpChatUserIds}
                         onChange={(corpChatUserIds) => {
@@ -124,7 +350,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         allowClear
                         options={groupList}
                         showSearch
-                        style={{ width: 150 }}
+                        style={{ minWidth: 120 }}
                         filterOption={(input, option) =>
                             (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
                         }
@@ -132,6 +358,20 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         value={oldQueryParams?.projectGroupIds}
                         onChange={(value) => setOldQueryParams({ ...oldQueryParams, projectGroupIds: value })}
                     />
+                    <Select
+                        showSearch
+                        allowClear
+                        placeholder="选择公众号"
+                        mode="multiple"
+                        value={oldQueryParams?.mpAccountIds}
+                        maxTagCount={1}
+                        style={{ minWidth: 120 }}
+                        onChange={(value) => setOldQueryParams({ ...oldQueryParams, mpAccountIds: value })}
+                        filterOption={(input, option) =>
+                            (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                        }
+                        options={getBindMpList?.data?.data?.map(item => ({ label: item.name, value: item.id }))}
+                    />
                     <DatePicker.RangePicker
                         placeholder={['执行开始日期', '执行结束日期']}
                         allowClear
@@ -143,209 +383,12 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
 
             <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,
-                        align: 'center',
-                        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',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '实际拉群数',
-                        dataIndex: 'pullSuccessCount',
-                        key: 'pullSuccessCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '预计拉群客户数',
-                        dataIndex: 'pullGroupUserCount',
-                        key: 'pullGroupUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '实际拉群客户数',
-                        dataIndex: 'pullSuccessUserCount',
-                        key: 'pullSuccessUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '上次失败补拉数量',
-                        dataIndex: 'lastFailedRetryCount',
-                        key: 'lastFailedRetryCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '失败客户数',
-                        dataIndex: 'pullFailedUserCount',
-                        key: 'pullFailedUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => <span style={value > 5 ? { color: 'red' } : {}}>{value || 0}</span>
-                    },
-                    {
-                        title: '删除或拉黑客户数',
-                        dataIndex: 'pullBlackUserCount',
-                        key: 'pullBlackUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '发送邀请客户数',
-                        dataIndex: 'sendInviteUserCount',
-                        key: 'sendInviteUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                    {
-                        title: '退群客户数',
-                        dataIndex: 'quitUserCount',
-                        key: 'quitUserCount',
-                        width: 90,
-                        align: 'center',
-                        sorter: true,
-                        render: (value) => value || 0
-                    },
-                ]}
+                columns={columns}
                 rowKey={'id'}
                 bordered={true}
                 size='small'
                 scroll={{ x: 1200 }}
-                loading={getPullGroupList?.loading}
+                loading={getPullGroupList?.loading || getPullGroupTotal?.loading}
                 onChange={(pagination, _, sortData: any) => {
                     let { current, pageSize } = pagination
                     let newQueryForm = JSON.parse(JSON.stringify(queryParams))
@@ -368,6 +411,21 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                     total: getPullGroupList?.data?.data?.total,
                     showSizeChanger: true
                 }}
+                summary={() => {
+                    return <Table.Summary fixed="top">
+                        <Table.Summary.Row style={{ fontWeight: 'bold' }}>
+                            {columns.map((item, index) => {
+                                if (index === 0) {
+                                    return <Table.Summary.Cell index={index} key={index} align="center">总计</Table.Summary.Cell>
+                                } else if (['cz', 'projectName', 'taskId', 'projectGroupName', 'projectGroupId', 'groupName', 'corpChatUserList', 'corpUserList', 'corpRobotList', 'mpAccountInfo', 'createTime'].includes((item as any).key)) {
+                                    return <Table.Summary.Cell index={index} key={index} align="center">--</Table.Summary.Cell>
+                                } else {
+                                    return <Table.Summary.Cell index={index} key={index} align="center">{totalData?.[item.key] || 0}</Table.Summary.Cell>
+                                }
+                            })}
+                        </Table.Summary.Row>
+                    </Table.Summary>
+                }}
             />
         </Drawer>
         {/* 详情 */}