wjx 8 小时之前
父节点
当前提交
bf4d0aac3a

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

@@ -54,6 +54,8 @@ export interface GetPullGroupListProps {
     startDay?: string,  // 开始日期
     endDay?: string     // 结束日期
     projectGroupIds?: string[] // 项目组ID列表
+    sortFiled?: string
+    sortAsc?: boolean
 }
 
 
@@ -182,4 +184,28 @@ export function getMomentJobLogListApi(data: GetSendMomentLogListProps) {
         method: 'POST',
         data
     })
-}
+}
+
+export interface GetTransferLogListProps {
+    pageNum: number,
+    pageSize: number,
+    projectName?: string,
+    taskId?: string,
+    status?: 0 | 1 | 2 | 3,
+    startDay?: string,
+    endDay?: string
+    projectGroupIds?: number[]
+}
+
+/**
+ * 客户继承
+ * @param data 
+ * @returns 
+ */
+export function getTransferLogListApi(data: GetTransferLogListProps) {
+    return request({
+        url: api + `/corpOperation/corp/stats/listOfPage/transfer/log`,
+        method: 'POST',
+        data
+    })
+}

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

@@ -2,7 +2,7 @@ import { Avatar, Card, Col, DatePicker, Flex, Popover, Row, Select, Spin, Statis
 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 { faListAlt, faPlusCircle, faExclamationTriangle, faChartPie, faUsers, faUsersCog, faRobot, faUserFriends } from "@fortawesome/free-solid-svg-icons";
 import { useEffect, useRef, useState } from "react";
 import dayjs from "dayjs";
 import style from "./index.less";
@@ -14,6 +14,9 @@ import CalendarItem from "./calendarItem";
 import PullGroup from "./pullGroup";
 import GroupItem from "./groupItem";
 import MomentItem from "./momentItem";
+import TransferItem from "./transferItem";
+import { inject, observer } from "mobx-react";
+import { toJS } from "mobx";
 
 const weekMap = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
 const taskTypeMap = {
@@ -25,11 +28,11 @@ const taskTypeMap = {
     'TASK_STAT_PULL_GROUP': '群聊创建 - 拉群'
 }
 
-const Logs: React.FC = () => {
+const Logs: React.FC<{ weComTaskStore: { data: { bookPlatForm: TASK_CREATE.BookPlatFormProps[] } } }> = ({ weComTaskStore }) => {
 
     /****************************************/
     const { token } = useNewToken()
-
+    const { bookPlatForm } = toJS(weComTaskStore.data)
     const ref = useRef<HTMLDivElement>(null)
     const size = useSize(ref);
 
@@ -327,21 +330,14 @@ const Logs: React.FC = () => {
                                             pullFailCount={item?.pullFailCount}
                                         />
                                     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>
+                                        return <TransferItem 
+                                            key={index}
+                                            taskTotal={item?.taskTotal}
+                                            todayAddTask={item?.todayAddTask}
+                                            todayFailTask={item?.todayFailTask}
+                                            todayFinishTaskRate={item?.todayFinishTaskRate}
+                                            bookPlatForm={bookPlatForm}
+                                        />
                                     default:
                                         return null;
                                 }
@@ -354,4 +350,4 @@ const Logs: React.FC = () => {
     </div>
 }
 
-export default Logs;
+export default inject('store')(observer((props: any) => Logs(props.store)));

+ 26 - 5
src/pages/weComTask/page/home/pullGroup.tsx

@@ -265,6 +265,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullGroupCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -273,6 +274,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullSuccessCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -281,6 +283,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullGroupUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -289,6 +292,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullSuccessUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -297,6 +301,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'lastFailedRetryCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -305,6 +310,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullFailedUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => <span style={value > 5 ? { color: 'red' } : {}}>{value || 0}</span>
                     },
                     {
@@ -313,6 +319,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'pullBlackUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -321,6 +328,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'sendInviteUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                     {
@@ -329,6 +337,7 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                         key: 'quitUserCount',
                         width: 90,
                         align: 'center',
+                        sorter: true,
                         render: (value) => value || 0
                     },
                 ]}
@@ -337,15 +346,27 @@ const PullGroup: React.FC<Props> = ({ pullFailCount, pullGroupCount, pullSuccess
                 size='small'
                 scroll={{ x: 1200 }}
                 loading={getPullGroupList?.loading}
+                onChange={(pagination, _, sortData: any) => {
+                    let { current, pageSize } = pagination
+                    let newQueryForm = JSON.parse(JSON.stringify(queryParams))
+                    let newOldQueryParams = JSON.parse(JSON.stringify(oldQueryParams))
+                    if (sortData && sortData?.order) {
+                        newQueryForm['sortAsc'] = sortData?.order === 'ascend' ? true : false
+                        newQueryForm['sortFiled'] = sortData?.field
+                    } else {
+                        delete newQueryForm['sortAsc']
+                        delete newQueryForm['sortFiled']
+                    }
+                    newQueryForm.pageNum = current || newQueryForm.pageNum
+                    newQueryForm.pageSize = pageSize || newQueryForm.pageSize
+                    setQueryParams({ ...newQueryForm })
+                    setOldQueryParams({ ...newOldQueryParams })
+                }}
                 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 })
-                    }
+                    showSizeChanger: true
                 }}
             />
         </Drawer>

+ 381 - 0
src/pages/weComTask/page/home/transferItem.tsx

@@ -0,0 +1,381 @@
+import React, { useEffect, useState } from "react";
+import style from './index.less';
+import { Avatar, Button, DatePicker, Drawer, Input, Modal, Popover, Select, Space, Table, Tag, Typography } from "antd";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faUserFriends } from "@fortawesome/free-solid-svg-icons";
+import { getProjectGroupsAllListApi } from "../../API/groupManage";
+import { useAjax } from "@/Hook/useAjax";
+import { getTransferLogListApi, GetTransferLogListProps } from "../../API/logs";
+import SearchBox from "../../components/searchBox";
+import { ExclamationCircleOutlined, QuestionCircleFilled, SearchOutlined } from '@ant-design/icons';
+import dayJs from "dayjs";
+import useNewToken from "@/Hook/useNewToken";
+import { copy } from "@/utils/utils";
+import FilterUserTooltip from "../../components/filterUser/filterUserTooltip";
+import { EUTTaskStatus, TIME_TYPE_ZJ } from "../businessPlan/create/const";
+import PreviewTime from "../../components/previewTime";
+import Log from "../businessPlan/taskList/components/externalUserTransferTask/log";
+const { Text } = Typography;
+
+interface Props {
+    taskTotal: number;
+    todayAddTask: number;
+    todayFinishTaskRate: number;
+    todayFailTask: number,
+    bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+}
+
+/**
+ * 客户继承
+ * @param param0 
+ * @returns 
+ */
+const TransferItem: React.FC<Props> = ({ taskTotal, todayAddTask, todayFinishTaskRate, todayFailTask, bookPlatForm }) => {
+
+    /******************************************/
+    const { token } = useNewToken()
+    const [visible, setVisible] = useState<boolean>(false)
+    const [groupList, setGroupList] = useState<{ label: string, value: number }[]>([]);
+    const [queryParams, setQueryParams] = useState<GetTransferLogListProps>({ pageNum: 1, pageSize: 20 })
+    const [oldQueryParams, setOldQueryParams] = useState<GetTransferLogListProps>({ pageNum: 1, pageSize: 20 })
+    const [modal, contextHolder] = Modal.useModal();
+    const [logVisible, setLogVisible] = useState<boolean>(false)
+    const [logData, setLogData] = useState<{ taskId: number, taskName: string }>()
+
+    const getProjectGroupsAllList = useAjax(() => getProjectGroupsAllListApi())
+    const getTransferLogList = useAjax((params) => getTransferLogListApi(params))
+    /******************************************/
+
+    useEffect(() => {
+        if (visible) {
+            getProjectGroupsAllList.run().then(res => {
+                setGroupList([{ label: '空项目组', value: 0 }, ...res?.data?.map(item => ({ label: item.name, value: item.id })) || []])
+            })
+        }
+    }, [visible])
+
+    useEffect(() => {
+        if (visible) {
+            getTransferLogList.run(queryParams)
+        }
+    }, [queryParams, visible])
+
+    const lookLog = (value: any) => {
+        setLogData({ taskId: value.id, taskName: value.taskName })
+        setLogVisible(true)
+    }
+
+    return <>
+        {contextHolder}
+        <div className={style.moduleCard} onClick={() => setVisible(true)}>
+            <div className={style.moduleCard_header}>
+                <Avatar style={{ backgroundColor: '#e6fffb', color: '#36cfc9' }} size={30}>
+                    <FontAwesomeIcon icon={faUserFriends} />
+                </Avatar>
+                客户继承
+            </div>
+            <div className={style.moduleCard_center}>
+                总任务数:{taskTotal || 0} | 今日新增:{todayAddTask || 0}
+            </div>
+            <div className={style.moduleCard_footer}>
+                <span>今日完成率:{((todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
+                <span className={style.error}>今日异常:{todayFailTask}</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={getTransferLogList.loading} icon={<SearchOutlined />}>搜索</Button>
+                </>}
+            >
+                <>
+                    <Input
+                        placeholder="任务名称"
+                        style={{ width: 120 }}
+                        allowClear
+                        onChange={(e) => setOldQueryParams({ ...oldQueryParams, projectName: e.target.value })}
+                        value={oldQueryParams?.projectName}
+                    />
+                    <Input
+                        placeholder="子任务ID"
+                        style={{ width: 120 }}
+                        allowClear
+                        onChange={(e) => setOldQueryParams({ ...oldQueryParams, taskId: e.target.value })}
+                        value={oldQueryParams?.taskId}
+                    />
+                    <Select
+                        showSearch
+                        style={{ minWidth: 100 }}
+                        allowClear
+                        onChange={(value) => {
+                            setOldQueryParams({ ...oldQueryParams, status: value })
+                        }}
+                        value={oldQueryParams?.status}
+                        placeholder="发送状态"
+                        filterOption={(input, option) =>
+                            ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                        }
+                        options={[{ label: '创建中', value: 0 }, { label: '执行中', value: 1 }, { label: '已发送', value: 2 }, { label: '暂停', value: 3 }]}
+                    />
+                    <Select
+                        placeholder='请选择项目组'
+                        allowClear
+                        options={groupList}
+                        showSearch
+                        maxTagCount={1}
+                        style={{ minWidth: 150 }}
+                        filterOption={(input, option) =>
+                            (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
+                        }
+                        mode="multiple"
+                        value={oldQueryParams?.projectGroupIds}
+                        onChange={(value) => setOldQueryParams({ ...oldQueryParams, projectGroupIds: value })}
+                    />
+                    <DatePicker
+                        placeholder="发送开始时间"
+                        onChange={(e, date) => { setOldQueryParams({ ...oldQueryParams, startDay: date as string }) }}
+                        allowClear
+                        value={oldQueryParams?.startDay ? dayJs(oldQueryParams?.startDay) : undefined}
+                    />
+                    <DatePicker
+                        placeholder="发送结束时间"
+                        onChange={(e, date) => { setOldQueryParams({ ...oldQueryParams, endDay: date as string }) }}
+                        allowClear
+                        value={oldQueryParams?.endDay ? dayJs(oldQueryParams?.endDay) : undefined}
+                    />
+                </>
+            </SearchBox>
+
+            {/* 表 */}
+            <Table
+                style={{ marginTop: 10 }}
+                dataSource={getTransferLogList?.data?.data?.records}
+                loading={getTransferLogList?.loading}
+                bordered
+                columns={[
+                    {
+                        title: '操作',
+                        dataIndex: 'cz',
+                        key: 'cz',
+                        width: 100,
+                        align: 'center',
+                        render: (_, record: any) => {
+                            return <Space>
+                                <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_TRANSFER',
+                                                taskId: record.taskId,
+                                                msg: '跳转日志详情'
+                                            }))
+                                            window.open(`/weComTask#/weComTask/businessPlan/taskList`)
+                                        },
+                                    });
+                                }}>任务跳转</a>
+                                {[1, 2].includes(record?.taskStatus) && <a onClick={() => { lookLog(record) }}>日志</a>}
+                            </Space>
+                        }
+                    },
+                    {
+                        title: '任务名称',
+                        dataIndex: 'projectName',
+                        key: 'projectName',
+                        width: 180,
+                        ellipsis: true,
+                        render: (text) => <a onClick={() => copy(text)}>{text}</a>
+                    },
+                    {
+                        title: '子任务ID',
+                        dataIndex: 'id',
+                        key: 'id',
+                        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: 'taskName',
+                        key: 'taskName',
+                        width: 180,
+                        ellipsis: true,
+                        align: 'center',
+                    },
+                    {
+                        title: '企业ID',
+                        dataIndex: 'corpId',
+                        key: 'corpId',
+                        width: 150,
+                        ellipsis: true,
+                        align: 'center'
+                    },
+                    {
+                        title: '接替人员',
+                        dataIndex: 'takeoverUserName',
+                        key: 'takeoverUserName',
+                        align: 'center',
+                        width: 100,
+                        ellipsis: true,
+                        render: (text: string) => text || '--'
+                    },
+                    {
+                        title: '原跟进成员',
+                        dataIndex: 'corpUserId',
+                        key: 'corpUserId',
+                        width: 100,
+                        ellipsis: true,
+                        align: 'center',
+                        render(value) {
+                            return value || '--'
+                        },
+                    },
+                    {
+                        title: '任务提交状态',
+                        dataIndex: 'taskStatus',
+                        key: 'taskStatus',
+                        width: 100,
+                        ellipsis: true,
+                        align: 'center',
+                        render(value) {
+                            return EUTTaskStatus[value]
+                        },
+                    },
+                    {
+                        title: '执行时间',
+                        dataIndex: 'timeRepeatType',
+                        key: 'timeRepeatType',
+                        width: 100,
+                        ellipsis: true,
+                        align: 'center',
+                        render(value, records: any) {
+                            return <>
+                                {TIME_TYPE_ZJ[value] || '--'}
+                                {value !== 'TIME_TYPE_SINGLE_TIMELY' && <Popover
+                                    placement="left"
+                                    content={<div>
+                                        <PreviewTime
+                                            {...records}
+                                        />
+                                    </div>}
+                                    styles={{ body: { width: 300, overflow: 'hidden', overflowY: 'auto', maxHeight: 400 } }}
+                                >
+                                    <a style={{ color: '#000' }}><QuestionCircleFilled /></a>
+                                </Popover>}
+                            </>
+                        },
+                    },
+                    {
+                        title: '继承对象',
+                        dataIndex: 'siftPopulationConfigContentDTO',
+                        key: 'siftPopulationConfigContentDTO',
+                        width: 100,
+                        align: 'center',
+                        render(value) {
+                            return value ? <div className={style.nameBox}>
+                                <div>
+                                    <Text ellipsis>指定</Text>
+                                </div>
+                                <Popover
+                                    placement="right"
+                                    styles={{ body: { maxWidth: 350, maxHeight: 350, overflow: 'hidden', overflowY: 'auto' } }}
+                                    mouseEnterDelay={0.5}
+                                    content={<FilterUserTooltip
+                                        bookCityList={bookPlatForm?.map(item => ({ label: item.platformName, value: item.platformKey }))}
+                                        configName={value?.configName}
+                                        data={value}
+                                    />}
+                                >
+                                    <a style={{ color: '#000' }}><QuestionCircleFilled /></a>
+                                </Popover>
+                            </div> : '全部'
+                        },
+                    },
+                    {
+                        title: '继承成功发送文案',
+                        dataIndex: 'transferSuccessMsg',
+                        key: 'transferSuccessMsg',
+                        width: 150,
+                        ellipsis: true
+                    },
+                    {
+                        title: '创建人',
+                        dataIndex: 'createByName',
+                        key: 'createByName',
+                        width: 100,
+                        ellipsis: true,
+                        align: 'center'
+                    },
+                    {
+                        title: '创建时间',
+                        dataIndex: 'createTime',
+                        key: 'createTime',
+                        width: 135,
+                        ellipsis: true,
+                        align: 'center'
+                    }
+                ]}
+                scroll={{ x: 1000 }}
+                rowKey={'id'}
+                size='small'
+                onRow={(row: any) => {
+                    return !row?.status ? {
+                        style: { background: token.colorPrimaryBgHover }
+                    } : {}
+                }}
+                pagination={{
+                    total: getTransferLogList?.data?.data?.total,
+                    showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
+                    showSizeChanger: true,
+                    showLessItems: true,
+                    defaultCurrent: 1,
+                    defaultPageSize: 200,//默认初始的每页条数
+                    current: getTransferLogList?.data?.data?.current || 1,
+                    pageSize: getTransferLogList?.data?.data?.size || 20,
+                    onChange: (page, pageSize) => {
+                        setQueryParams({ ...queryParams, pageNum: page, pageSize })
+                        setOldQueryParams({ ...oldQueryParams, pageNum: page, pageSize })
+                    }
+                }}
+            />
+        </Drawer>
+
+        {/* 日志 */}
+        {(logVisible && logData) && <Log {...logData} visible={logVisible} onClose={() => { setLogVisible(false); setLogData(undefined) }} />}
+    </>
+};
+
+export default React.memo(TransferItem);