wjx 3 周之前
父节点
当前提交
a23abac37c
共有 24 个文件被更改,包括 774 次插入296 次删除
  1. 9 0
      src/global.less
  2. 25 36
      src/layout/index.tsx
  3. 44 0
      src/pages/weComTask/API/logs/index.tsx
  4. 2 2
      src/pages/weComTask/components/filterUser/filterUserText.ts
  5. 2 2
      src/pages/weComTask/components/filterUser/filterUserTooltip.tsx
  6. 2 2
      src/pages/weComTask/components/filterUser/newFiterUser.tsx
  7. 9 1
      src/pages/weComTask/page/businessPlan/taskList/components/externalUserTransferTask/index.tsx
  8. 9 1
      src/pages/weComTask/page/businessPlan/taskList/components/groupTask/index.tsx
  9. 11 0
      src/pages/weComTask/page/businessPlan/taskList/index.tsx
  10. 24 11
      src/pages/weComTask/page/businessPlan/taskList/log.tsx
  11. 17 3
      src/pages/weComTask/page/groupChat/taskList/details.tsx
  12. 11 0
      src/pages/weComTask/page/groupChat/taskList/index.tsx
  13. 9 1
      src/pages/weComTask/page/groupChatSend/official/taskList/components/groupTask/index.tsx
  14. 11 0
      src/pages/weComTask/page/groupChatSend/official/taskList/index.tsx
  15. 8 3
      src/pages/weComTask/page/groupChatSend/official/taskList/log.tsx
  16. 11 0
      src/pages/weComTask/page/groupChatSend/robot/taskList/index.tsx
  17. 8 3
      src/pages/weComTask/page/groupChatSend/robot/taskList/log.tsx
  18. 46 32
      src/pages/weComTask/page/home/index.tsx
  19. 1 1
      src/pages/weComTask/page/home/uuidTem.tsx
  20. 157 0
      src/pages/weComTask/page/logs/calendarItem.tsx
  21. 24 3
      src/pages/weComTask/page/logs/index.less
  22. 306 192
      src/pages/weComTask/page/logs/index.tsx
  23. 11 0
      src/pages/weComTask/page/moments/taskList/index.tsx
  24. 17 3
      src/pages/weComTask/page/moments/taskList/log.tsx

+ 9 - 0
src/global.less

@@ -67,4 +67,13 @@ ol {
     border-start-start-radius: 0 !important;
     border-end-start-radius: 0 !important;
   }
+}
+
+
+// spin 高度100%
+.summaryCardSpin {
+  .ant-spin-container,
+  .ant-spin-nested-loading {
+    height: 100%;
+  }
 }

+ 25 - 36
src/layout/index.tsx

@@ -111,7 +111,6 @@ function MainLayout(props: Props) {
     const [letKey, setLetKey] = useState([])
     const [topMenu, setTopMenu] = useState<any>([])
     const [leftMenu, setLeftMenu] = useState<any>([])
-    const [jump, setJump] = useLocalStorageState<string>('JUMP');
     const { themeConfig } = useNewToken();
     const [config] = useState(themeConfig);
     const navigate = useNavigate();//跳转
@@ -165,47 +164,38 @@ function MainLayout(props: Props) {
             clickName = ''
             sessionStorage.removeItem('name')
         }
-        let oldPath = sessionStorage.getItem('oldPath')
-        let thatName = name
-        // 当前菜单刷新
-        if (jump) {
-            setTimeout(() => {
-                setLetKey([jump])
-                sessionStorage.setItem('oldPath', jump)
-                setJump()
-            }, 200)
-        } else {
-            if (clickName && data[clickName]) {
-                if (thatName !== clickName) {//更换一级菜单
-                    handleTopKey({
-                        key: clickName,
-                        pData: data
-                    })
-                }
+        const oldPath = location.hash.replace('#', '').split('?')?.[0]
+        const thatName = name
+        if (clickName && data[clickName]) {
+            if (thatName !== clickName) {//更换一级菜单
+                handleTopKey({
+                    key: clickName,
+                    pData: data
+                })
             }
-            if (data[name]) {
-                let item = data[thatName][0].children[0]
-                if (!data[thatName][0].children[0]) {
-                    message.error('没有下级菜单,请联系管理员,确认是否开通了系统及菜单')
-                    return
-                }
-                let path = ''
-                if (oldPath && oldPath?.split('/').length > 2) {//刷新页面时
-                    path = oldPath
-                } else if (item?.children?.length > 0) {//假如有子菜单
-                    path = item?.children[0]?.path
+        }
+        if (data[name]) {
+            const item = data[thatName][0].children[0]
+            if (!data[thatName][0].children[0]) {
+                message.error('没有下级菜单,请联系管理员,确认是否开通了系统及菜单')
+                return
+            }
+            let path = ''
+            if (oldPath && oldPath?.split('/').length > 2) {//刷新页面时
+                path = oldPath
+            } else if (item?.children?.length > 0) {//假如有子菜单
+                path = item?.children[0]?.path
 
-                } else {//没有子菜单
-                    path = item?.path
-                }
-                navigate(path)//跳转到指定页面
-                setLetKey([path])//指定页面名称选中样式
+            } else {//没有子菜单
+                path = item?.path
             }
+            navigate(path)//跳转到指定页面
+            setLetKey([path])//指定页面名称选中样式
         }
 
         if (data) {
             // 顶部菜单
-            let TopMenu = Object.values(data).sort((a: any, b: any) => { return a[0]?.orderNum - b[0]?.orderNum }).map((r: any) => {
+            const TopMenu = Object.values(data).sort((a: any, b: any) => { return a[0]?.orderNum - b[0]?.orderNum }).map((r: any) => {
                 return getItem(r[0]?.title, r[0]?.belongPlatform, IconMap[r[0]?.icon as keyof typeof IconMap])
             })
             if (!sessionStorage.getItem('name') && TopMenu?.length > 0) {
@@ -218,7 +208,6 @@ function MainLayout(props: Props) {
     useUpdateEffect(() => {
         const newKey = location.hash.replace('#', '').split('?')?.[0]
         if (newKey !== letKey?.[0]) {
-            // sessionStorage.setItem('oldPath', newKey);
             setLetKey([newKey])
         }
     }, [location.href])

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

@@ -0,0 +1,44 @@
+import request from "@/utils/request";
+const { api } = process.env.CONFIG;
+
+/**
+ * 获取任务统计
+ * @returns 
+ */
+export function getTotalTaslApi() {
+    return request({
+        url: api + `/corpOperation/corp/stats/total/task`,
+        method: 'GET'
+    })
+}
+
+
+/**
+ * 获取各模型任务统计
+ * @returns 
+ */
+export function getTotalModelApi() {
+    return request({
+        url: api + `/corpOperation/corp/stats/task/model`,
+        method: 'GET'
+    })
+}
+
+export interface GetTaskdayProps {
+    pageNum: number,
+    pageSize: number,
+    taskDay: string,
+    taskType: string,
+}
+
+/**
+ * 获取各模型任务统计
+ * @returns 
+ */
+export function getTaskdayApi(data: GetTaskdayProps) {
+    return request({
+        url: api + `/corpOperation/corp/stats/task/day`,
+        method: 'post',
+        data
+    })
+}

+ 2 - 2
src/pages/weComTask/components/filterUser/filterUserText.ts

@@ -257,10 +257,10 @@ export const resetFilterUserData = (data: { [x: string]: any }): ContentProps =>
     if (retentionGroupCountMin || retentionGroupCountMax) {
         newData.retentionGroupCount = { retentionGroupCountMin, retentionGroupCountMax }
     }
-    if (minCorpIdCount || maxCorpIdCount) {
+    if (minCorpIdCount || minCorpIdCount === 0 || maxCorpIdCount || maxCorpIdCount === 0) {
         newData.corpIdCount = { minCorpIdCount, maxCorpIdCount }
     }
-    if (minCorpUserIdCount || maxCorpUserIdCount) {
+    if (minCorpUserIdCount || maxCorpUserIdCount || minCorpUserIdCount  === 0 || maxCorpUserIdCount === 0) {
         newData.corpUserIdCount = { minCorpUserIdCount, maxCorpUserIdCount }
     }
     return newData

+ 2 - 2
src/pages/weComTask/components/filterUser/filterUserTooltip.tsx

@@ -265,10 +265,10 @@ export const resetFilterUserData = (data: { [x: string]: any }): ContentProps =>
     if (retentionGroupCountMin || retentionGroupCountMax) {
         newData.retentionGroupCount = { retentionGroupCountMin, retentionGroupCountMax }
     }
-    if (minCorpIdCount || maxCorpIdCount) {
+    if (minCorpIdCount || maxCorpIdCount || minCorpIdCount === 0 || maxCorpIdCount === 0) {
         newData.corpIdCount = { minCorpIdCount, maxCorpIdCount }
     }
-    if (minCorpUserIdCount || maxCorpUserIdCount) {
+    if (minCorpUserIdCount || maxCorpUserIdCount || minCorpUserIdCount === 0 || maxCorpUserIdCount === 0) {
         newData.corpUserIdCount = { minCorpUserIdCount, maxCorpUserIdCount }
     }
     return newData

+ 2 - 2
src/pages/weComTask/components/filterUser/newFiterUser.tsx

@@ -68,14 +68,14 @@ const NewFilterUser: React.FC<NewFilterUserProps> = ({ bookCityList, configType
             if (groupChatNames?.length) {
                 params.groupChatNames = groupChatNames.join(',')
             }
-            if (!params?.repeatOperateType || params?.repeatOperateType === 0) {
+            if (params?.repeatOperateType || params?.repeatOperateType === 0) {
                 if (params.repeatRang) {
                     params.repeatRang = Object.entries(params.repeatRang || {}).map(([corpId, corpName]: [string, string]) => `${corpId}&&${corpName}`)
                 }
                 params.isRepeat = true
             }
 
-            if (!params?.groupOperateType || params?.groupOperateType === 0) {
+            if (params?.groupOperateType || params?.groupOperateType === 0) {
                 params.groupNameList = groupNameList?.join(',')
                 params.isGroupRepeat = true
                 console.log('groupNameList', groupRepeatRang)

+ 9 - 1
src/pages/weComTask/page/businessPlan/taskList/components/externalUserTransferTask/index.tsx

@@ -38,11 +38,19 @@ const ExternalUserTransferTask: React.FC<Props> = ({ externalUserTransferTasksVO
                     title: '任务名称',
                     dataIndex: 'taskName',
                     key: 'taskName',
-                    width: 100,
+                    width: 180,
                     ellipsis: true,
                     align: 'center',
                     fixed: 'left'
                 },
+                {
+                    title: '任务ID',
+                    dataIndex: 'id',
+                    key: 'id',
+                    width: 70,
+                    ellipsis: true,
+                    align: 'center',
+                },
                 {
                     title: '企业ID',
                     dataIndex: 'corpId',

+ 9 - 1
src/pages/weComTask/page/businessPlan/taskList/components/groupTask/index.tsx

@@ -34,7 +34,15 @@ const GroupTask: React.FC<Props> = ({ groupSendTaskVOList }) => {
                 title: '任务名称',
                 dataIndex: 'taskName',
                 key: 'taskName',
-                width: 100,
+                width: 180,
+                ellipsis: true,
+                align: 'center'
+            },
+            {
+                title: '任务ID',
+                dataIndex: 'id',
+                key: 'id',
+                width: 70,
                 ellipsis: true,
                 align: 'center'
             },

+ 11 - 0
src/pages/weComTask/page/businessPlan/taskList/index.tsx

@@ -34,6 +34,17 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     const cancelProject = useAjax((params) => cancelProjectApi(params))
     /***********************************************/
 
+    useEffect(() => {
+        const openTask = localStorage.getItem('OPENTASK')
+        if (openTask) {
+            localStorage.removeItem('OPENTASK')
+            const data = JSON.parse(openTask)
+            setLogOpenData({ visible: true, data })
+            setQueryForm({ ...queryForm, projectName: data.projectName })
+            setQueryFormNew({ ...queryFormNew, projectName: data.projectName })
+        }
+    }, [])
+
     useEffect(() => {
         const projectName = sessionStorage.getItem('CAMPCORP')
         if (projectName) {

+ 24 - 11
src/pages/weComTask/page/businessPlan/taskList/log.tsx

@@ -1,12 +1,10 @@
 import { useAjax } from '@/Hook/useAjax';
 import { getProjectLogListApi } from '@/pages/weComTask/API/businessPlan/create';
-import { Drawer, Spin, Tabs } from 'antd';
+import { Drawer, Input, Spin, Tabs } from 'antd';
 import React, { useEffect, useState } from 'react';
 import WelcomeTask from './components/welcomeTask';
 import ExternalUserTransferTask from './components/externalUserTransferTask';
 import GroupTask from './components/groupTask';
-import HighGroupTask from './components/highGroupTask';
-import MomentTask from './components/momentTask';
 
 
 interface Props {
@@ -27,14 +25,31 @@ const Log: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClose }
 
     /******************************************************/
     const [previewData, setPreviewData] = useState<{ welcomeMsgTemplateVO?: any, groupSendTaskVOList?: any[], externalUserTransferTasksVOList?: any[] }>({})
+    const [taskId, setTaskId] = useState<string>()
+    const [accessKey, setActiveKey] = useState<string>()
+
     const getProjectLogList = useAjax((params) => getProjectLogListApi(params))
     /******************************************************/
 
     useEffect(() => {
         console.log(data.id)
+        if (data?.msg === '跳转日志详情') {
+            setTaskId(data.taskId)
+        }
         getProjectLogList.run(data.id).then(res => {
             if (res?.data) {
                 setPreviewData(res.data)
+                setActiveKey(Object.keys(previewData)?.[0])
+                if (data?.msg === '跳转日志详情') {
+                    switch (data.taskType) {
+                        case 'TASK_STAT_TRANSFER': // 继承
+                            setActiveKey('externalUserTransferTasksVOList')
+                            break
+                        case 'TASK_STAT_GROUP_SEND': // 官方群发
+                            setActiveKey('groupSendTaskVOList')
+                            break
+                    }
+                }
             }
         })
     }, [])
@@ -46,27 +61,25 @@ const Log: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClose }
         width={1400}
         styles={{ body: { paddingTop: 5 } }}
     >
-
+        {accessKey !== 'welcomeMsgTemplateVO' && <Input.Search placeholder="请输入任务ID" allowClear defaultValue={data?.taskId} onSearch={(value) => { setTaskId(value); }} style={{ marginBottom: 10, width: 250 }} />}
         <Spin spinning={getProjectLogList.loading}>
             <DispatchTaskDetails.Provider
                 value={{ bookPlatForm, bookList }}
             >
                 <Tabs
-                    items={Object.keys(previewData).filter(key => key === 'welcomeMsgTemplateVO' ? previewData[key] : previewData[key]?.length).map(key => ({
+                    items={Object.keys(previewData).filter(key => key === 'welcomeMsgTemplateVO' ? previewData[key] : previewData[key]?.length).map((key, index) => ({
                         key: key,
                         label: { 'externalUserTransferTasksVOList': '客户继承', 'groupSendTaskVOList': '客户群发', 'welcomeMsgTemplateVO': '欢迎语', 'messageSendTaskVOS': '高级群发', 'momentsTaskVOList': '朋友圈' }[key],
                         children: key === 'externalUserTransferTasksVOList' ? <>
-                            <ExternalUserTransferTask externalUserTransferTasksVOList={previewData[key]} />
+                            <ExternalUserTransferTask externalUserTransferTasksVOList={taskId ? previewData?.[key]?.filter(item => item.id == taskId) : previewData[key]} />
                         </> : key === 'groupSendTaskVOList' ? <>
-                            <GroupTask groupSendTaskVOList={previewData[key]} />
+                            <GroupTask groupSendTaskVOList={taskId ? previewData?.[key]?.filter(item => item.id == taskId) : previewData[key]} />
                         </> : key === 'welcomeMsgTemplateVO' ? <>
                             <WelcomeTask welcomeMsgTemplateVO={previewData[key]} />
-                        </> : key === 'messageSendTaskVOS' ? <>
-                            <HighGroupTask groupSendTaskVOList={previewData[key]} />
-                        </> : key === 'momentsTaskVOList' ? <>
-                            <MomentTask momentTaskVOList={previewData[key]} />
                         </> : undefined
                     }))}
+                    accessKey={accessKey}
+                    onChange={(key) => setActiveKey(key)}
                 />
             </DispatchTaskDetails.Provider>
         </Spin>

+ 17 - 3
src/pages/weComTask/page/groupChat/taskList/details.tsx

@@ -1,7 +1,7 @@
 import { useAjax } from "@/Hook/useAjax"
 import { getProjectLogDetailsListApi, getProjectLogListApi, getProjectTaskLogCountApi, getProjectTaskLogListApi } from "@/pages/weComTask/API/groupChat"
 import FilterUserTooltip from "@/pages/weComTask/components/filterUser/filterUserTooltip";
-import { Badge, Button, Drawer, Flex, Modal, Popover, Space, Table, Typography } from "antd"
+import { Badge, Button, Drawer, Flex, Input, Modal, Popover, Space, Table, Typography } from "antd"
 import React, { useEffect, useState } from "react"
 import { QuestionCircleFilled } from "@ant-design/icons"
 import { businessPlanData, LQTaskStatus, TIME_TYPE_ZJ } from "../../businessPlan/create/const";
@@ -19,10 +19,15 @@ interface Props {
 const Details: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClose }) => {
 
     /*******************************************/
+    const [taskId, setTaskId] = useState<string>()
+
     const getProjectLogList = useAjax((params) => getProjectLogListApi(params))
     /*******************************************/
 
     useEffect(() => {
+        if (data?.msg === '跳转日志详情') {
+            setTaskId(data.taskId)
+        }
         getProjectLogList.run(data.id)
     }, [])
 
@@ -36,12 +41,12 @@ const Details: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClo
         width={1400}
         styles={{ body: { paddingTop: 5 } }}
     >
-
+        <Input.Search placeholder="请输入任务ID" allowClear defaultValue={data?.taskId} onSearch={(value) => { setTaskId(value); }} style={{ marginBottom: 10, width: 250 }} />
         <Table
             size='small'
             bordered
             rowKey={'id'}
-            dataSource={getProjectLogList?.data?.data || []}
+            dataSource={taskId ? getProjectLogList?.data?.data?.filter(item => item.id == taskId) : getProjectLogList?.data?.data}
             scroll={{ y: 1000 }}
             columns={[
                 {
@@ -52,6 +57,15 @@ const Details: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClo
                     ellipsis: true,
                     fixed: 'left'
                 },
+                {
+                    title: '任务ID',
+                    dataIndex: 'id',
+                    key: 'id',
+                    width: 70,
+                    align: 'center',
+                    ellipsis: true,
+                    fixed: 'left'
+                },
                 {
                     title: '群名称',
                     dataIndex: 'groupName',

+ 11 - 0
src/pages/weComTask/page/groupChat/taskList/index.tsx

@@ -32,6 +32,17 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     const cancelProject = useAjax((params) => cancelProjectApi(params))
     /**********************************************/
 
+    useEffect(() => {
+        const openTask = localStorage.getItem('OPENTASK')
+        if (openTask) {
+            localStorage.removeItem('OPENTASK')
+            const data = JSON.parse(openTask)
+            setLogOpenData({ visible: true, data })
+            setQueryForm({ ...queryForm, projectName: data.projectName })
+            setQueryFormNew({ ...queryFormNew, projectName: data.projectName })
+        }
+    }, [])
+
     useEffect(() => {
         const projectName = sessionStorage.getItem('CAMPCORP_PG')
         if (projectName) {

+ 9 - 1
src/pages/weComTask/page/groupChatSend/official/taskList/components/groupTask/index.tsx

@@ -34,7 +34,15 @@ const GroupTask: React.FC<Props> = ({ groupSendTaskVOList }) => {
                 title: '任务名称',
                 dataIndex: 'taskName',
                 key: 'taskName',
-                width: 100,
+                width: 180,
+                ellipsis: true,
+                align: 'center'
+            },
+            {
+                title: '任务ID',
+                dataIndex: 'id',
+                key: 'id',
+                width: 70,
                 ellipsis: true,
                 align: 'center'
             },

+ 11 - 0
src/pages/weComTask/page/groupChatSend/official/taskList/index.tsx

@@ -41,6 +41,17 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     const getCorpAllList = useAjax((param) => getCorpAllListApi(param))
     /***********************************************/
 
+    useEffect(() => {
+        const openTask = localStorage.getItem('OPENTASK')
+        if (openTask) {
+            localStorage.removeItem('OPENTASK')
+            const data = JSON.parse(openTask)
+            setLogOpenData({ visible: true, data })
+            setQueryForm({ ...queryForm, projectName: data.projectName })
+            setQueryFormNew({ ...queryFormNew, projectName: data.projectName })
+        }
+    }, [])
+
     useEffect(() => {
         getBindMpList.run().then(res => {
             if (res?.data)

+ 8 - 3
src/pages/weComTask/page/groupChatSend/official/taskList/log.tsx

@@ -1,6 +1,6 @@
 import { useAjax } from '@/Hook/useAjax';
 import { getProjectLogListApi } from '@/pages/weComTask/API/businessPlan/create';
-import { Drawer, Spin } from 'antd';
+import { Drawer, Input, Spin } from 'antd';
 import React, { useEffect, useState } from 'react';
 import GroupTask from './components/groupTask';
 
@@ -23,10 +23,15 @@ const Log: React.FC<Props> = ({ data, visible, onClose, bookPlatForm, bookList }
 
     /******************************************************/
     const [previewData, setPreviewData] = useState<{ groupChatSendTaskVOList?: any[] }>({})
+    const [taskId, setTaskId] = useState<string>()
+
     const getProjectLogList = useAjax((params) => getProjectLogListApi(params))
     /******************************************************/
 
     useEffect(() => {
+        if (data?.msg === '跳转日志详情') {
+            setTaskId(data.taskId)
+        }
         getProjectLogList.run(data.id).then(res => {
             if (res?.data) {
                 setPreviewData(res.data)
@@ -41,12 +46,12 @@ const Log: React.FC<Props> = ({ data, visible, onClose, bookPlatForm, bookList }
         width={1400}
         styles={{ body: { paddingTop: 5 } }}
     >
-
+        <Input.Search placeholder="请输入任务ID" allowClear defaultValue={data?.taskId} onSearch={(value) => { setTaskId(value); }} style={{ marginBottom: 10, width: 250 }} />
         <Spin spinning={getProjectLogList.loading}>
             <DispatchTaskDetails.Provider
                 value={{ bookPlatForm, bookList }}
             >
-                <GroupTask groupSendTaskVOList={previewData?.groupChatSendTaskVOList} />
+                <GroupTask groupSendTaskVOList={taskId ? previewData?.groupChatSendTaskVOList?.filter(item => item.id == taskId) : previewData?.groupChatSendTaskVOList} />
             </DispatchTaskDetails.Provider>
         </Spin>
     </Drawer>

+ 11 - 0
src/pages/weComTask/page/groupChatSend/robot/taskList/index.tsx

@@ -41,6 +41,17 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     const getCorpAllList = useAjax((param) => getCorpAllListApi(param))
     /***********************************************/
 
+    useEffect(() => {
+        const openTask = localStorage.getItem('OPENTASK')
+        if (openTask) {
+            localStorage.removeItem('OPENTASK')
+            const data = JSON.parse(openTask)
+            setLogOpenData({ visible: true, data })
+            setQueryForm({ ...queryForm, projectName: data.projectName })
+            setQueryFormNew({ ...queryFormNew, projectName: data.projectName })
+        }
+    }, [])
+
     useEffect(() => {
         getBindMpList.run().then(res => {
             if (res?.data)

+ 8 - 3
src/pages/weComTask/page/groupChatSend/robot/taskList/log.tsx

@@ -1,6 +1,6 @@
 import { useAjax } from '@/Hook/useAjax';
 import { getProjectLogListApi } from '@/pages/weComTask/API/businessPlan/create';
-import { Drawer, Spin } from 'antd';
+import { Drawer, Input, Spin } from 'antd';
 import React, { useEffect, useState } from 'react';
 import GroupTask from './components/groupTask';
 
@@ -23,10 +23,15 @@ const Log: React.FC<Props> = ({ data, visible, onClose, bookPlatForm, bookList }
 
     /******************************************************/
     const [previewData, setPreviewData] = useState<{ robotGroupChatSendTaskVOList?: any[] }>({})
+    const [taskId, setTaskId] = useState<string>()
+
     const getProjectLogList = useAjax((params) => getProjectLogListApi(params))
     /******************************************************/
 
     useEffect(() => {
+        if (data?.msg === '跳转日志详情') {
+            setTaskId(data.taskId)
+        }
         getProjectLogList.run(data.id).then(res => {
             if (res?.data) {
                 setPreviewData(res.data)
@@ -41,12 +46,12 @@ const Log: React.FC<Props> = ({ data, visible, onClose, bookPlatForm, bookList }
         width={1400}
         styles={{ body: { paddingTop: 5 } }}
     >
-
+        <Input.Search placeholder="请输入任务ID" allowClear defaultValue={data?.taskId} onSearch={(value) => { setTaskId(value); }} style={{ marginBottom: 10, width: 250 }} />
         <Spin spinning={getProjectLogList.loading}>
             <DispatchTaskDetails.Provider
                 value={{ bookPlatForm, bookList }}
             >
-                <GroupTask robotGroupChatSendTaskVOList={previewData?.robotGroupChatSendTaskVOList} />
+                <GroupTask robotGroupChatSendTaskVOList={taskId ? previewData?.robotGroupChatSendTaskVOList?.filter(item => item.id == taskId) : previewData?.robotGroupChatSendTaskVOList} />
             </DispatchTaskDetails.Provider>
         </Spin>
     </Drawer>

+ 46 - 32
src/pages/weComTask/page/home/index.tsx

@@ -14,8 +14,8 @@ const Home: React.FC = () => {
 
     /*******************************************/
     const { Bar } = useEcharts()
-    const [queryParmas, setQueryParmas] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[] }>({ pageNum: 1, pageSize: 30 })
-    const [queryParmasZt, setQueryParmasZt] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[] }>({ pageNum: 1, pageSize: 30 })
+    const [queryParmas, setQueryParmas] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[], corpName?: string }>({ pageNum: 1, pageSize: 30 })
+    const [queryParmasZt, setQueryParmasZt] = useState<{ pageNum: number, pageSize: number, corpIdList?: string[], corpName?: string }>({ pageNum: 1, pageSize: 30 })
     const [corpRepeat, setCorpRepeat] = useState<{ [x: string]: any }>({})
     const [corpUserRepeat, setCorpUserRepeat] = useState<{ [x: string]: any }>({})
     const [barCorpData, setBarCorpData] = useState<Record<string, any>[]>([])
@@ -245,34 +245,42 @@ const Home: React.FC = () => {
 
         <Flex justify='space-between' style={{ margin: '20px 0 10px' }}>
             <Title level={3} style={{ margin: 0 }}><RetweetOutlined style={{ color: '#1890ff' }} /> 单主体内重粉分布</Title>
-            <Select
-                value={queryParmas?.corpIdList}
-                onChange={(e) => setQueryParmas({ ...queryParmas, corpIdList: e })}
-                showSearch
-                style={{ minWidth: 200 }}
-                maxTagCount={1}
-                mode='multiple'
-                placeholder="选择企业"
-                filterOption={false}
-                onSearch={handleSearch}
-                allowClear
-                options={filtered}
-                popupRender={(menu) => (
-                    <>
-                        {menu}
-                        <Divider style={{ margin: '8px 0' }} />
-                        <Space style={{ padding: '0 8px 4px' }}>
-                            <Checkbox onChange={(e) => {
-                                if (e.target.checked) {
-                                    setQueryParmas({ ...queryParmas, corpIdList: filtered.map(item => item.value) })
-                                } else {
-                                    setQueryParmas({ ...queryParmas, corpIdList: [] })
-                                }
-                            }}>全选</Checkbox>
-                        </Space>
-                    </>
-                )}
-            />
+            <Flex gap={10}>
+                <Input.Search
+                    placeholder="请输入企业名称"
+                    onSearch={(e) => { setQueryParmas({ ...queryParmas, corpName: e, pageNum: 1 }); }}
+                    style={{ width: 200 }}
+                    allowClear
+                />
+                <Select
+                    value={queryParmas?.corpIdList}
+                    onChange={(e) => setQueryParmas({ ...queryParmas, corpIdList: e })}
+                    showSearch
+                    style={{ minWidth: 200 }}
+                    maxTagCount={1}
+                    mode='multiple'
+                    placeholder="选择企业"
+                    filterOption={false}
+                    onSearch={handleSearch}
+                    allowClear
+                    options={filtered}
+                    popupRender={(menu) => (
+                        <>
+                            {menu}
+                            <Divider style={{ margin: '8px 0' }} />
+                            <Space style={{ padding: '0 8px 4px' }}>
+                                <Checkbox onChange={(e) => {
+                                    if (e.target.checked) {
+                                        setQueryParmas({ ...queryParmas, corpIdList: filtered.map(item => item.value) })
+                                    } else {
+                                        setQueryParmas({ ...queryParmas, corpIdList: [] })
+                                    }
+                                }}>全选</Checkbox>
+                            </Space>
+                        </>
+                    )}
+                />
+            </Flex>
         </Flex>
         <Row gutter={16}>
             <Col span={10}>
@@ -319,7 +327,13 @@ const Home: React.FC = () => {
         <Spin spinning={getExternalUserRepeatCorp.loading || getExternalUserRepeatCorpUser.loading || getCorpExternalUserRepeatList.loading}>
             <Title level={3}><BarChartOutlined style={{ color: '#22c55e' }} /> 用户在集团内重粉分布</Title>
             <Tabs
-                tabBarExtraContent={activeKey === '1' &&
+                tabBarExtraContent={activeKey === '1' && <Flex gap={10}>
+                    <Input.Search
+                        placeholder="请输入企业名称"
+                        onSearch={(e) => { setQueryParmasZt({ ...queryParmasZt, corpName: e, pageNum: 1 }); }}
+                        style={{ width: 200 }}
+                        allowClear
+                    />
                     <Select
                         value={queryParmasZt?.corpIdList}
                         onChange={(e) => setQueryParmasZt({ ...queryParmasZt, corpIdList: e, pageNum: 1 })}
@@ -348,7 +362,7 @@ const Home: React.FC = () => {
                             </>
                         )}
                     />
-                }
+                </Flex>}
                 items={[
                     {
                         key: '3',

+ 1 - 1
src/pages/weComTask/page/home/uuidTem.tsx

@@ -82,7 +82,7 @@ const UuidTem: React.FC<{ getCorpAllList: { label: string, value: string }[] }>
                         </>
                     )}
                 />
-                {/* <Input onChange={(e) => setQueryParmasNew({ ...queryParmasNew, corpName: e.target.value })} value={queryParmasNew?.corpName} placeholder="企微名称" allowClear /> */}
+                <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 })} />

+ 157 - 0
src/pages/weComTask/page/logs/calendarItem.tsx

@@ -0,0 +1,157 @@
+import React, { useEffect, useState } from "react";
+import Dayjs from "dayjs";
+import { useAjax } from "@/Hook/useAjax";
+import { getTaskdayApi, GetTaskdayProps } from "../../API/logs";
+import InfiniteScroll from 'react-infinite-scroll-component';
+import style from "./index.less";
+import { Divider, Empty, Flex, Modal, Skeleton, Spin } from "antd";
+import { ExclamationCircleOutlined } from "@ant-design/icons";
+import { copy } from "@/utils/utils";
+
+const TaskStatusMap = {
+    'TASK_STATUS_SUCCESS': '执行成功',
+    'TASK_STATUS_FAIL': '任务失败',
+    'TASK_STATUS_ERROR': '任务异常',
+    'TASK_STATUS_WAIT': '等待执行',
+    'TASK_STATUS_EMPTY_LOG': '无记录'
+}
+
+interface CalendarProps {
+    weekday: string;
+    date: string;
+    taskDay: string;
+    taskType: string;
+    index: number
+    endDay: string
+}
+
+const CalendarItem: React.FC<CalendarProps> = ({ weekday, date, taskDay, taskType, index, endDay }) => {
+
+    /********************************************/
+    const [queryParmas, setQueryParmas] = useState<GetTaskdayProps>({ pageNum: 1, pageSize: 10, taskDay, taskType })
+    const [data, setData] = useState<any[]>([])
+    const [total, setTotal] = useState<number>(0)
+    const [modal, contextHolder] = Modal.useModal();
+    const getTaskday = useAjax((params) => getTaskdayApi(params))
+    /********************************************/
+
+    useEffect(() => {
+        if (Dayjs(taskDay) <= Dayjs(endDay)) {
+            getList({ pageNum: 1, pageSize: 15, taskDay, taskType })
+        }
+    }, [taskDay, taskType])
+
+    const getList = (params: GetTaskdayProps) => {
+        setQueryParmas(params)
+        getTaskday.run(params).then(res => {
+            if (res?.data) {
+                setTotal(res?.data?.total || 0)
+                if (params.pageNum === 1) {
+                    setData(res?.data?.records)
+                } else {
+                    setData(data.concat(res?.data?.records))
+                }
+            } else {
+                setTotal(0)
+                setData([])
+            }
+        })
+    }
+
+    // 下一页
+    const loadMoreData = () => {
+        getList({ ...queryParmas, pageNum: queryParmas.pageNum + 1 })
+    }
+
+    return <div className={style.dataList}>
+        <Flex justify="space-between" align="center" className={style.dataList_header}>
+            <strong style={{ fontSize: 14 }}>{weekday}</strong>
+            <a style={{ fontSize: 12 }}>{total}个任务</a>
+            <span>{date}</span>
+        </Flex>
+        <div className={style.dataList_content} id={'scrollableDiv' + index}>
+            {contextHolder}
+            {getTaskday?.loading && queryParmas.pageNum === 1 ? <div className={style.summaryCardSpin}>
+                <Spin />
+            </div> : null}
+            {Dayjs(taskDay) <= Dayjs(endDay) ? <InfiniteScroll
+                dataLength={data?.length}
+                next={loadMoreData}
+                hasMore={data?.length < total}
+                loader={<div style={{ display: 'flex', marginTop: 10, padding: '0 10px' }}>
+                    <Skeleton.Input active style={{ width: '100%' }} />
+                </div>}
+                endMessage={<Divider plain>没有更多了</Divider>}
+                scrollableTarget={'scrollableDiv' + index}
+            >
+                <div style={{ padding: '0 10px' }}>
+                    {data.map(item => <div
+                        key={item.taskId}
+                        title={`${TaskStatusMap[item?.taskStatus]}: ${item.taskName}`}
+                        className={`${style.dataList_content_item} ${style.calendar_task}`}
+                        style={{
+                            backgroundColor:
+                                item?.taskStatus === 'TASK_STATUS_WAIT' ? '#f3f4f6' :
+                                    item?.taskStatus === 'TASK_STATUS_SUCCESS' ? '#dcfce7' :
+                                        item?.taskStatus === 'TASK_STATUS_FAIL' ? '#fee2e2' :
+                                            item?.taskStatus === 'TASK_STATUS_ERROR' ? '#fff2e8' : '#ffd6e7'
+                        }}
+                        onClick={() => {
+                            modal.confirm({
+                                title: '确认',
+                                icon: <ExclamationCircleOutlined />,
+                                content: '是否跳转到日志详情?',
+                                okText: '确认',
+                                cancelText: '复制',
+                                onCancel: () => {
+                                    copy(item.projectName + '任务Id:' + item.taskId)
+                                },
+                                onOk: () => {
+                                    localStorage.setItem('OPENTASK', JSON.stringify({
+                                        id: item.projectId,
+                                        projectName: item.projectName,
+                                        taskType,
+                                        taskId: item.taskId,
+                                        msg: '跳转日志详情'
+                                    }))
+                                    switch (taskType) {
+                                        case 'TASK_STAT_GROUP_SEND_CHAT': // 官方群群发
+                                            window.open(`/weComTask#/weComTask/groupChatSend/official/taskList`)
+                                            break
+                                        case 'TASK_STAT_GROUP_ROBOT': // 机器人群发
+                                            window.open(`/weComTask#/weComTask/groupChatSend/robot/taskList`)
+                                            break
+                                        case 'TASK_STAT_TRANSFER': // 继承
+                                        case 'TASK_STAT_GROUP_SEND': // 官方群发
+                                            window.open(`/weComTask#/weComTask/businessPlan/taskList`)
+                                            break
+                                        case 'TASK_STAT_MOMENT': // 朋友圈
+                                            window.open(`/weComTask#/weComTask/moments/taskList`)
+                                            break
+                                        case 'TASK_STAT_PULL_GROUP': // 群聊创建 - 拉群
+                                            window.open(`/weComTask#/weComTask/groupChat/taskList`)
+                                            break
+                                    }
+                                },
+                            });
+                        }}
+                    >
+                        <div
+                            className={style.title}
+                            style={{
+                                color:
+                                    item?.taskStatus === 'TASK_STATUS_WAIT' ? '#6b7280' :
+                                        item?.taskStatus === 'TASK_STATUS_SUCCESS' ? '#166534' :
+                                            item?.taskStatus === 'TASK_STATUS_FAIL' ? '#991b1b' :
+                                                item?.taskStatus === 'TASK_STATUS_ERROR' ? '#ff7a45' : '#eb2f96'
+                            }}
+                        >{item.taskName}</div>
+                        <div className={style.time}>{item.sendTime}</div>
+                    </div>)}
+                </div>
+            </InfiniteScroll> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
+        </div>
+    </div>
+};
+
+export default React.memo(CalendarItem);

+ 24 - 3
src/pages/weComTask/page/logs/index.less

@@ -18,6 +18,7 @@
     padding-bottom: 10px;
     flex-direction: column;
     box-sizing: border-box;
+    overflow: hidden;
 
     .dataList_header {
         padding: 10px;
@@ -27,9 +28,18 @@
 
 .dataList_content {
     height: calc(100% - 24px);
-    padding: 0 10px;
-    // overflow: hidden;
     overflow-y: auto;
+    position: relative;
+}
+
+.summaryCardSpin {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    background-color: rgba(0, 0, 0, 0.2);
 }
 
 .dataList_content_item {
@@ -45,6 +55,13 @@
     cursor: pointer;
     transition: all 0.2s ease;
 
+    .title {
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        color: #000;
+    }
+
     .time {
         font-size: 12px;
     }
@@ -55,7 +72,7 @@
 }
 
 .summaryList {
-    height: calc(100% - 46px);
+    height: calc(100% - 38px);
     overflow-y: auto;
 }
 
@@ -97,4 +114,8 @@
             color: #dc2626;
         }
     }
+}
+
+.summaryCardSpin {
+    height: 100%;
 }

+ 306 - 192
src/pages/weComTask/page/logs/index.tsx

@@ -1,15 +1,26 @@
-import { Avatar, Card, Col, DatePicker, Flex, Row, Spin, Statistic } from "antd";
-import { ArrowDownOutlined, ArrowUpOutlined, UnorderedListOutlined } from "@ant-design/icons";
+import { Avatar, Card, Col, DatePicker, Flex, Popover, Row, Select, Spin, Statistic } from "antd";
+import { ArrowDownOutlined, ArrowUpOutlined, QuestionCircleOutlined } from "@ant-design/icons";
 import useNewToken from "@/Hook/useNewToken";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { faListAlt, faPlusCircle, faExclamationTriangle, faChartPie, faUsers, faCommentDots, faUsersCog } from "@fortawesome/free-solid-svg-icons";
-import { useRef, useState } from "react";
+import { faListAlt, faPlusCircle, faExclamationTriangle, faChartPie, faUsers, faCommentDots, faUsersCog, faRobot, faUserFriends } from "@fortawesome/free-solid-svg-icons";
+import { useEffect, useRef, useState } from "react";
 import dayjs from "dayjs";
 import style from "./index.less";
 import { useSize } from "ahooks";
 import { RangePickerProps } from "antd/es/date-picker";
+import { useAjax } from "@/Hook/useAjax";
+import { getTotalModelApi, getTotalTaslApi } from "../../API/logs";
+import CalendarItem from "./calendarItem";
 
 const weekMap = ["周日", "周一", "周二", "周三", "周四", "周五", "周六"];
+const taskTypeMap = {
+    'TASK_STAT_GROUP_SEND': '官方群发',
+    'TASK_STAT_GROUP_SEND_CHAT': '官方群群发',
+    'TASK_STAT_GROUP_ROBOT': '机器人群发',
+    'TASK_STAT_MOMENT': '朋友圈',
+    'TASK_STAT_TRANSFER': '继承',
+    'TASK_STAT_PULL_GROUP': '群聊创建 - 拉群'
+}
 
 const Logs: React.FC = () => {
 
@@ -23,14 +34,26 @@ const Logs: React.FC = () => {
         startTime: dayjs().subtract(6, 'day').format('YYYY-MM-DD'),
         endTime: dayjs().format('YYYY-MM-DD')
     })
+    const [dates, setDates] = useState<any>([]);
     const [startClickDate, setStartClickDate] = useState<string>()
     const [endClickDate, setEndClickDate] = useState<string>()
     const [rangeStart, setRangeStart] = useState<boolean>(false)
+    const [taskType, setTaskType] = useState<string>('TASK_STAT_GROUP_SEND_CHAT')
+
+    const getTotalTasl = useAjax(() => getTotalTaslApi())
+    const getTotalModel = useAjax(() => getTotalModelApi())
     /****************************************/
 
+    useEffect(() => {
+        getTotalTasl.run()
+        getTotalModel.run()
+    }, [])
+
     const disabledDate: RangePickerProps['disabledDate'] = (current) => {
         // console.log(dayjs(current).format('YYYY-MM-DD'))
         // Can not select days before today and today
+        if (current > dayjs().endOf("day")) return true;
+
         if (startClickDate) {
             return current && current >= dayjs(startClickDate).add(7, 'day');
         }
@@ -40,232 +63,323 @@ const Logs: React.FC = () => {
         return false
     };
 
-    const height = size?.height ? `calc(100vh - ${size?.height}px - 105px)` : 600
+    const height = size?.height ? `calc(100vh - ${size?.height}px - 96px)` : 600
     return <div className={style.logsPage}>
-        <Flex vertical gap={16} className={style.container}>
-            <Spin spinning={false}>
-                <Row gutter={[16, 16]} style={{ marginInline: 0 }} ref={ref}>
-                    <Col xs={24} sm={12} lg={6}>
-                        <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative' } }}>
-                            <Flex vertical>
-                                <Statistic
-                                    title={<strong style={{ fontSize: 14 }}>总任务数</strong>}
-                                    value={2846}
-                                    style={{ flex: 1 }}
-                                    valueStyle={{ fontSize: 30, fontWeight: 'bold' }}
-                                />
+        <Row gutter={[10, 10]} style={{ marginInline: 0 }} className={style.container}>
+            <Col xs={24} xl={19}>
+                <Flex vertical gap={10}>
+                    <Spin spinning={getTotalTasl.loading}>
+                        <Flex gap={10} ref={ref}>
+                            <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
                                 <Flex vertical>
                                     <Statistic
-                                        value={11.28}
-                                        precision={2}
-                                        valueStyle={{ color: '#3f8600', fontSize: 14 }}
-                                        prefix={<ArrowUpOutlined />}
-                                        suffix="%"
+                                        title={<strong style={{ fontSize: 14 }}>总任务数</strong>}
+                                        value={getTotalTasl?.data?.data?.taskTotal}
+                                        style={{ flex: 1 }}
+                                        valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
                                     />
-                                    <span style={{ fontSize: 13, color: token.colorTextDescription }}>较上月变化百分比</span>
+                                    <Flex vertical>
+                                        <Statistic
+                                            value={Math.abs(getTotalTasl?.data?.data?.compareLastMonthTaskTotal || 0) * 100}
+                                            precision={2}
+                                            {...(getTotalTasl?.data?.data?.compareLastMonthTaskTotal >= 0 ? {
+                                                valueStyle: { color: '#3f8600', fontSize: 14 },
+                                                prefix: <ArrowUpOutlined />
+                                            } : {
+                                                valueStyle: { color: '#cf1322', fontSize: 14 },
+                                                prefix: <ArrowDownOutlined />
+                                            })}
+                                            suffix="%"
+                                        />
+                                        <span style={{ fontSize: 13, color: token.colorTextDescription }}>较上月变化百分比</span>
+                                    </Flex>
                                 </Flex>
-                            </Flex>
-                            <Avatar style={{ backgroundColor: '#DBEAFE', color: '#2563eb', position: 'absolute', right: 15, top: 15 }} size={38}>
-                                <FontAwesomeIcon icon={faListAlt} />
-                            </Avatar>
-                        </Card>
-                    </Col>
-
-                    <Col xs={24} sm={12} lg={6}>
-                        <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative' } }}>
-                            <Flex vertical>
-                                <Statistic
-                                    title={<strong style={{ fontSize: 14 }}>今日新增任务数</strong>}
-                                    value={128}
-                                    style={{ flex: 1 }}
-                                    valueStyle={{ fontSize: 30, fontWeight: 'bold' }}
-                                />
+                                <Avatar style={{ backgroundColor: '#DBEAFE', color: '#2563eb', position: 'absolute', right: 15, top: 15 }} size={38}>
+                                    <FontAwesomeIcon icon={faListAlt} />
+                                </Avatar>
+                            </Card>
+                            <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
                                 <Flex vertical>
                                     <Statistic
-                                        value={8.28}
-                                        precision={2}
-                                        valueStyle={{ color: '#cf1322', fontSize: 14 }}
-                                        prefix={<ArrowDownOutlined />}
-                                        suffix="%"
+                                        title={<strong style={{ fontSize: 14 }}>今日新增任务数</strong>}
+                                        value={getTotalTasl?.data?.data?.todayAddTask}
+                                        style={{ flex: 1 }}
+                                        valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
                                     />
-                                    <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日新增变化百分比</span>
+                                    <Flex vertical>
+                                        <Statistic
+                                            value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayAddTask || 0) * 100}
+                                            precision={2}
+                                            {...(getTotalTasl?.data?.data?.compareYesterdayAddTask >= 0 ? {
+                                                valueStyle: { color: '#3f8600', fontSize: 14 },
+                                                prefix: <ArrowUpOutlined />
+                                            } : {
+                                                valueStyle: { color: '#cf1322', fontSize: 14 },
+                                                prefix: <ArrowDownOutlined />
+                                            })}
+                                            suffix="%"
+                                        />
+                                        <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日新增变化百分比</span>
+                                    </Flex>
                                 </Flex>
-                            </Flex>
-                            <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a', position: 'absolute', right: 15, top: 15 }} size={38}>
-                                <FontAwesomeIcon icon={faPlusCircle} />
-                            </Avatar>
-                        </Card>
-                    </Col>
+                                <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a', position: 'absolute', right: 15, top: 15 }} size={38}>
+                                    <FontAwesomeIcon icon={faPlusCircle} />
+                                </Avatar>
+                            </Card>
 
-                    <Col xs={24} sm={12} lg={6}>
-                        <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative' } }}>
-                            <Flex vertical>
-                                <Statistic
-                                    title={<strong style={{ fontSize: 14 }}>今日异常/失败任务数</strong>}
-                                    value={42}
-                                    style={{ flex: 1 }}
-                                    valueStyle={{ fontSize: 30, fontWeight: 'bold' }}
-                                />
+                            <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
                                 <Flex vertical>
                                     <Statistic
-                                        value={3.28}
-                                        precision={2}
-                                        valueStyle={{ color: '#3f8600', fontSize: 14 }}
-                                        prefix={<ArrowUpOutlined />}
-                                        suffix="%"
+                                        title={<strong style={{ fontSize: 14 }}>今日异常/失败任务数</strong>}
+                                        value={getTotalTasl?.data?.data?.todayFailTask}
+                                        style={{ flex: 1 }}
+                                        valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
                                     />
-                                    <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
+                                    <Flex vertical>
+                                        <Statistic
+                                            value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayFailTask || 0) * 100}
+                                            precision={2}
+                                            {...(getTotalTasl?.data?.data?.compareYesterdayFailTask >= 0 ? {
+                                                valueStyle: { color: '#3f8600', fontSize: 14 },
+                                                prefix: <ArrowUpOutlined />
+                                            } : {
+                                                valueStyle: { color: '#cf1322', fontSize: 14 },
+                                                prefix: <ArrowDownOutlined />
+                                            })}
+                                            suffix="%"
+                                        />
+                                        <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
+                                    </Flex>
                                 </Flex>
-                            </Flex>
-                            <Avatar style={{ backgroundColor: '#fee2e2', color: '#dc2626', position: 'absolute', right: 15, top: 15 }} size={38}>
-                                <FontAwesomeIcon icon={faExclamationTriangle} />
-                            </Avatar>
-                        </Card>
-                    </Col>
+                                <Avatar style={{ backgroundColor: '#fee2e2', color: '#dc2626', position: 'absolute', right: 15, top: 15 }} size={38}>
+                                    <FontAwesomeIcon icon={faExclamationTriangle} />
+                                </Avatar>
+                            </Card>
 
-                    <Col xs={24} sm={12} lg={6}>
-                        <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative' } }}>
-                            <Flex vertical>
-                                <Statistic
-                                    title={<strong style={{ fontSize: 14 }}>今日任务完成率</strong>}
-                                    value={80}
-                                    style={{ flex: 1 }}
-                                    suffix="%"
-                                    precision={2}
-                                    valueStyle={{ fontSize: 30, fontWeight: 'bold' }}
-                                />
+                            <Card variant="borderless" style={{ width: '100%' }} hoverable styles={{ body: { position: 'relative', padding: '10px 16px' } }}>
                                 <Flex vertical>
                                     <Statistic
-                                        value={1.28}
-                                        precision={2}
-                                        valueStyle={{ color: '#3f8600', fontSize: 14 }}
-                                        prefix={<ArrowUpOutlined />}
+                                        title={<strong style={{ fontSize: 14 }}>今日任务完成率</strong>}
+                                        value={(getTotalTasl?.data?.data?.todayFinishTaskRate || 0) * 100}
+                                        style={{ flex: 1 }}
                                         suffix="%"
+                                        precision={2}
+                                        valueStyle={{ fontSize: 26, fontWeight: 'bold', lineHeight: 1.2 }}
                                     />
-                                    <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
+                                    <Flex vertical>
+                                        <Statistic
+                                            value={Math.abs(getTotalTasl?.data?.data?.compareYesterdayFinishTaskRate || 0) * 100}
+                                            precision={2}
+                                            {...(getTotalTasl?.data?.data?.compareYesterdayFinishTaskRate >= 0 ? {
+                                                valueStyle: { color: '#3f8600', fontSize: 14 },
+                                                prefix: <ArrowUpOutlined />
+                                            } : {
+                                                valueStyle: { color: '#cf1322', fontSize: 14 },
+                                                prefix: <ArrowDownOutlined />
+                                            })}
+                                            suffix="%"
+                                        />
+                                        <span style={{ fontSize: 13, color: token.colorTextDescription }}>较昨日变化百分比</span>
+                                    </Flex>
                                 </Flex>
-                            </Flex>
-                            <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea', position: 'absolute', right: 15, top: 15 }} size={38}>
-                                <FontAwesomeIcon icon={faChartPie} />
-                            </Avatar>
-                        </Card>
-                    </Col>
-                </Row>
-            </Spin>
-            <Row gutter={[16, 16]} style={{ marginInline: 0 }}>
-                <Col xs={24} xl={18}>
-                    <Card style={{ width: '100%', height }} hoverable styles={{ body: { height: '100%' } }}>
-                        <Flex justify="space-between" gap={8} align="center" style={{ marginBottom: 16, height: 30 }}>
-                            <DatePicker.RangePicker
-                                placeholder={['开始日期', '结束日期']}
-                                variant="filled"
-                                onCalendarChange={(e, dateStrings, info) => {
-                                    if (rangeStart) { // 点过一次
-                                        setWeekQuery({ ...weekQuery, startTime: dateStrings[0], endTime: dateStrings[1] })
-                                    } else {
-                                        if (info.range === 'start') {
-                                            setStartClickDate(dateStrings[0])
-                                            setWeekQuery({ ...weekQuery, startTime: dateStrings[0], endTime: dateStrings[0] })
+                                <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea', position: 'absolute', right: 15, top: 15 }} size={38}>
+                                    <FontAwesomeIcon icon={faChartPie} />
+                                </Avatar>
+                            </Card>
+                        </Flex>
+                    </Spin>
+                    <Card style={{ width: '100%', height, minHeight: 380 }} hoverable styles={{ body: { height: '100%' } }}>
+                        <Flex justify="space-between" gap={8} align="center" style={{ marginBottom: 8, height: 30 }}>
+                            <Flex gap={10}>
+                                <Popover
+                                    placement="bottomLeft"
+                                    content={<div style={token?.Checkbox ? { display: 'flex', flexFlow: 'column', color: "#fff" } : { display: 'flex', flexFlow: 'column' }}>
+                                        <strong style={{ fontSize: 15 }}>任务列表的颜色状态说明:</strong>
+                                        <span><span style={{ backgroundColor: '#f3f4f6', lineHeight: "20px", display: 'inline-block', color: "initial" }}>等待执行</span>:该任务发送时间未到,或该任务已被暂停、取消、删除;</span>
+                                        <span><span style={{ backgroundColor: '#88e1aa', lineHeight: "20px", display: 'inline-block', color: "initial" }}>执行成功</span>:该任务已被正常发送,并且任务结果没有异常情况;</span>
+                                        <span><span style={{ backgroundColor: '#e38989', lineHeight: "20px", display: 'inline-block', color: "initial" }}>任务失败</span>:该任务存在未正常发送情况,包含任务中部分企微号未点击发送、由于手机设备不在线导致任务未发送等多种任务未发送的异常;</span>
+                                        <span><span style={{ backgroundColor: '#ffd8bf', lineHeight: "20px", display: 'inline-block', color: "initial" }}>任务异常</span>:该任务已被正常发送,但任务结果中存在异常客户(单向好友或当日接受推送额度达到上限)未接收到任务推送;</span>
+                                        <span><span style={{ backgroundColor: '#ffadd2', lineHeight: "20px", display: 'inline-block', color: "initial" }}>无记录</span>:该任务在当天不满足条件未创建发送任务异常;</span>
+                                    </div>}>
+                                    <QuestionCircleOutlined style={{ color: 'red', fontSize: 20 }} />
+                                </Popover>
+                                <DatePicker.RangePicker
+                                    placeholder={['开始日期', '结束日期']}
+                                    variant="filled"
+                                    onCalendarChange={(e, dateStrings, info) => {
+                                        setDates(e)
+                                        if (rangeStart) { // 点过一次
+                                            setWeekQuery({ ...weekQuery, startTime: dateStrings[0], endTime: dateStrings[1] })
                                         } else {
-                                            setEndClickDate(dateStrings[1])
-                                            setWeekQuery({ ...weekQuery, startTime: dateStrings[1], endTime: dateStrings[1] })
+                                            if (info.range === 'start') {
+                                                setStartClickDate(dateStrings[0])
+                                            } else {
+                                                setEndClickDate(dateStrings[1])
+                                            }
+                                            setRangeStart(true)
                                         }
-                                        setRangeStart(true)
-                                    }
-                                }}
-                                onOpenChange={(open) => {
-                                    if (!open) {
-                                        setRangeStart(false)
-                                        setStartClickDate(undefined)
-                                        setEndClickDate(undefined)
-                                    }
+                                    }}
+                                    onOpenChange={(open) => {
+                                        if (!open) {
+                                            setDates([])
+                                            setRangeStart(false)
+                                            setStartClickDate(undefined)
+                                            setEndClickDate(undefined)
+                                        }
+                                    }}
+                                    allowClear={false}
+                                    disabledDate={disabledDate}
+                                    value={dates?.length > 1 ? dates : (weekQuery.startTime && weekQuery.endTime) ? [dayjs(weekQuery.startTime), dayjs(weekQuery.endTime)] : undefined}
+                                />
+                            </Flex>
+                            <Select
+                                style={{ width: 130 }}
+                                value={taskType}
+                                placeholder="请选择任务类型"
+                                variant="filled"
+                                onChange={(value) => {
+                                    setTaskType(value)
                                 }}
-                                allowClear={false}
-                                disabledDate={disabledDate}
-                                value={(weekQuery.startTime && weekQuery.endTime) ? [dayjs(weekQuery.startTime), dayjs(weekQuery.endTime)] : undefined}
+                                options={Object.keys(taskTypeMap).map(key => ({ label: taskTypeMap[key], value: key }))}
                             />
                         </Flex>
-                        <Flex gap={8} style={{ height: 'calc(100% - 46px)' }}>
+                        <Flex gap={8} style={{ height: 'calc(100% - 38px)' }}>
                             {Array.from({ length: 7 }, (_, i) => {
                                 const date = i === 0 ? dayjs(weekQuery.startTime) : dayjs(weekQuery.startTime).add(i, "day");
                                 return {
                                     date: date.format("MM/DD"),
                                     weekday: weekMap[date.day()],
+                                    nowDate: date.format("YYYY-MM-DD"),
+                                    index: i
                                 };
-                            }).map(item => <div key={item.date} className={style.dataList}>
-                                <Flex justify="space-between" align="center" className={style.dataList_header}>
-                                    <strong style={{ fontSize: 14 }}>{item.weekday}</strong>
-                                    <span>{item.date}</span>
-                                </Flex>
-                                <div className={style.dataList_content}>
-                                    <div title="待发送:将在指定时间发送" className={`${style.dataList_content_item} ${style.calendar_task}`}>
-                                        <div className={style.title}>官方用户群发</div>
-                                        <div className={style.time}>14:30-15:00</div>
-                                    </div>
-                                </div>
-                            </div>)}
+                            }).map(item => <CalendarItem
+                                key={item.date}
+                                weekday={item.weekday}
+                                date={item.date}
+                                taskDay={item.nowDate}
+                                taskType={taskType}
+                                index={item.index}
+                                endDay={weekQuery.endTime}
+                            />)}
                         </Flex>
 
                     </Card>
-                </Col>
-                <Col xs={24} xl={6}>
-                    <Card style={{ width: '100%', height }} hoverable styles={{ body: { height: '100%', paddingInline: 0 } }}>
-                        <Flex justify="space-between" gap={8} align="center" style={{ paddingInline: token.paddingLG, marginBottom: 16, height: 30 }}>
+                </Flex>
+            </Col>
+            <Col xs={24} xl={5}>
+                <Card style={{ width: '100%', height: `calc(100vh - 86px)` }} hoverable classNames={{ body: 'summaryCardSpin' }} styles={{ body: { height: '100%', paddingInline: 0 } }}>
+                    <Spin spinning={getTotalModel.loading}>
+                        <Flex justify="space-between" gap={8} align="center" style={{ paddingInline: token.paddingLG, marginBottom: 8, height: 30 }}>
                             <strong style={{ fontSize: 16 }}>任务列表摘要</strong>
                         </Flex>
                         <div className={style.summaryList} style={{ paddingInline: token.paddingLG }}>
-                            <div className={style.moduleCard}>
-                                <div className={style.moduleCard_header}>
-                                    <Avatar style={{ backgroundColor: '#dbeafe', color: '#2563eb' }} size={30}>
-                                        <FontAwesomeIcon icon={faUsers} />
-                                    </Avatar>
-                                    官方用户群发
-                                </div>
-                                <div className={style.moduleCard_center}>
-                                    总任务数:586 | 今日新增:24
-                                </div>
-                                <div className={style.moduleCard_footer}>
-                                    <span>完成率:96.2%</span>
-                                    <span className={style.error}>异常:2</span>
-                                </div>
-                            </div>
-
-                            <div className={style.moduleCard}>
-                                <div className={style.moduleCard_header}>
-                                    <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a' }} size={30}>
-                                        <FontAwesomeIcon icon={faCommentDots} />
-                                    </Avatar>
-                                    朋友圈
-                                </div>
-                                <div className={style.moduleCard_center}>
-                                    总任务数:666 | 今日新增:111
-                                </div>
-                                <div className={style.moduleCard_footer}>
-                                    <span>完成率:96.2%</span>
-                                    <span className={style.error}>异常:2</span>
-                                </div>
-                            </div>
-                            
-                            <div className={style.moduleCard}>
-                                <div className={style.moduleCard_header}>
-                                    <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea' }} size={30}>
-                                        <FontAwesomeIcon icon={faUsersCog} />
-                                    </Avatar>
-                                    群聊群发
-                                </div>
-                                <div className={style.moduleCard_center}>
-                                    总任务数:234 | 今日新增:123
-                                </div>
-                                <div className={style.moduleCard_footer}>
-                                    <span>完成率:96.2%</span>
-                                    <span className={style.error}>异常:2</span>
-                                </div>
-                            </div>
+                            {getTotalModel?.data?.data?.map((item: any, index: number) => {
+                                switch (item.taskType) {
+                                    case 'TASK_STAT_GROUP_SEND': // 官方用户群发
+                                        return <div className={style.moduleCard} key={index}>
+                                            <div className={style.moduleCard_header}>
+                                                <Avatar style={{ backgroundColor: '#dbeafe', color: '#2563eb' }} size={30}>
+                                                    <FontAwesomeIcon icon={faUsers} />
+                                                </Avatar>
+                                                官方用户群发
+                                            </div>
+                                            <div 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>
+                                    case 'TASK_STAT_GROUP_SEND_CHAT': // 官方群群发
+                                        return <div className={style.moduleCard} key={index}>
+                                            <div className={style.moduleCard_header}>
+                                                <Avatar style={{ backgroundColor: '#f3e8ff', color: '#9333ea' }} size={30}>
+                                                    <FontAwesomeIcon icon={faUsersCog} />
+                                                </Avatar>
+                                                群聊群发
+                                            </div>
+                                            <div 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>
+                                    case 'TASK_STAT_GROUP_ROBOT': // 机器人群发
+                                        return <div className={style.moduleCard} key={index}>
+                                            <div className={style.moduleCard_header}>
+                                                <Avatar style={{ backgroundColor: '#fff0f6', color: '#f759ab' }} size={30}>
+                                                    <FontAwesomeIcon icon={faRobot} />
+                                                </Avatar>
+                                                机器人群发
+                                            </div>
+                                            <div className={style.moduleCard_center}>
+                                                总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
+                                            </div>
+                                            <div className={style.moduleCard_footer}>
+                                                <span>完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
+                                                <span className={style.error}>异常:{item?.todayFailTask}</span>
+                                            </div>
+                                        </div>
+                                    case 'TASK_STAT_MOMENT': // 朋友圈
+                                        return <div className={style.moduleCard} key={index}>
+                                            <div className={style.moduleCard_header}>
+                                                <Avatar style={{ backgroundColor: '#dcfce7', color: '#16a34a' }} size={30}>
+                                                    <FontAwesomeIcon icon={faCommentDots} />
+                                                </Avatar>
+                                                朋友圈
+                                            </div>
+                                            <div className={style.moduleCard_center}>
+                                                总任务数:{item?.taskTotal || 0} | 今日新增:{item?.todayAddTask || 0}
+                                            </div>
+                                            <div className={style.moduleCard_footer}>
+                                                <span>完成率:{((item?.todayFinishTaskRate || 0) * 100).toFixed(2)} %</span>
+                                                <span className={style.error}>异常:{item?.todayFailTask}</span>
+                                            </div>
+                                        </div>
+                                    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>
+                                    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>
+                                    default:
+                                        return null;
+                                }
+                            })}
                         </div>
-                    </Card>
-                </Col>
-            </Row>
-        </Flex>
+                    </Spin>
+                </Card>
+            </Col>
+        </Row>
     </div>
 }
 

+ 11 - 0
src/pages/weComTask/page/moments/taskList/index.tsx

@@ -34,6 +34,17 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     const cancelProject = useAjax((params) => cancelProjectApi(params))
     /***********************************************/
 
+    useEffect(() => {
+        const openTask = localStorage.getItem('OPENTASK')
+        if (openTask) {
+            localStorage.removeItem('OPENTASK')
+            const data = JSON.parse(openTask)
+            setLogOpenData({ visible: true, data })
+            setQueryForm({ ...queryForm, projectName: data.projectName })
+            setQueryFormNew({ ...queryFormNew, projectName: data.projectName })
+        }
+    }, [])
+
     useEffect(() => {
         const projectName = sessionStorage.getItem('CAMPCORP')
         if (projectName) {

+ 17 - 3
src/pages/weComTask/page/moments/taskList/log.tsx

@@ -1,6 +1,6 @@
 import { useAjax } from '@/Hook/useAjax';
 import { getProjectLogListApi } from '@/pages/weComTask/API/businessPlan/create';
-import { Card, Drawer, Popover, Spin, Table, Tabs, Tag, Typography } from 'antd';
+import { Card, Drawer, Input, Popover, Spin, Table, Tabs, Tag, Typography } from 'antd';
 import React, { useEffect, useState } from 'react';
 import { STATUS_ZJ, TIME_TYPE_ZJ } from '../../businessPlan/create/const';
 import PreviewTime from '@/pages/weComTask/components/previewTime';
@@ -31,11 +31,16 @@ const Log: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClose }
 
     /******************************************************/
     const [previewData, setPreviewData] = useState<{ momentsTaskVOList?: any[] }>({})
+    const [taskId, setTaskId] = useState<string>()
+    
     const getProjectLogList = useAjax((params) => getProjectLogListApi(params))
     /******************************************************/
 
     useEffect(() => {
         console.log(data.id)
+         if (data?.msg === '跳转日志详情') {
+            setTaskId(data.taskId)
+        }
         getProjectLogList.run(data.id).then(res => {
             if (res?.data) {
                 setPreviewData(res.data)
@@ -50,14 +55,23 @@ const Log: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClose }
         width={1400}
         styles={{ body: { paddingTop: 5 } }}
     >
+        <Input.Search placeholder="请输入任务ID" allowClear defaultValue={data?.taskId} onSearch={(value) => { setTaskId(value); }} style={{ marginBottom: 10, width: 250 }} />
         <Table
-            dataSource={previewData?.momentsTaskVOList || []}
+            dataSource={taskId ? previewData?.momentsTaskVOList?.filter(item => item.id == taskId) : previewData?.momentsTaskVOList}
             columns={[
                 {
                     title: '任务名称',
                     dataIndex: 'momentJobTitle',
                     key: 'momentJobTitle',
-                    width: 100,
+                    width: 180,
+                    ellipsis: true,
+                    align: 'center'
+                },
+                {
+                    title: '任务ID',
+                    dataIndex: 'id',
+                    key: 'id',
+                    width: 70,
                     ellipsis: true,
                     align: 'center'
                 },