|
|
@@ -0,0 +1,724 @@
|
|
|
+import React, { useEffect, useState } from "react";
|
|
|
+import style from './index.less';
|
|
|
+import { Avatar, Badge, Button, Card, DatePicker, Drawer, Input, Modal, Select, Space, Table, Tabs, Tag, Tooltip } from "antd";
|
|
|
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
|
+import { IconDefinition } from "@fortawesome/free-solid-svg-icons";
|
|
|
+import { getProjectGroupsAllListApi } from "../../API/groupManage";
|
|
|
+import { useAjax } from "@/Hook/useAjax";
|
|
|
+import { getSendUserListApi, GetSendUserListProps, getSendUserLogListApi, GetSendUserLogListProps } from "../../API/logs";
|
|
|
+import SearchBox from "../../components/searchBox";
|
|
|
+import { ExclamationCircleOutlined, InfoCircleOutlined, QuestionCircleOutlined, SearchOutlined } from "@ant-design/icons";
|
|
|
+import dayJs from "dayjs";
|
|
|
+import useNewToken from "@/Hook/useNewToken";
|
|
|
+import { copy } from "@/utils/utils";
|
|
|
+import GroupErrorCountList from "../businessPlan/taskList/components/groupTask/groupErrorCountList";
|
|
|
+import PreviewMsg from "../../components/previewMsg";
|
|
|
+import { emoList } from "../../components/textEditor/Expression";
|
|
|
+
|
|
|
+
|
|
|
+interface IProps {
|
|
|
+ title: string
|
|
|
+ icon: IconDefinition
|
|
|
+ taskTotal: number
|
|
|
+ todayAddTask: number
|
|
|
+ todayFinishTaskRate: number
|
|
|
+ todayFailTask: number
|
|
|
+ projectType?: 1 | 2
|
|
|
+}
|
|
|
+
|
|
|
+const GroupItem: React.FC<IProps> = ({ title, icon, taskTotal, todayAddTask, todayFinishTaskRate, todayFailTask, projectType }) => {
|
|
|
+
|
|
|
+ /***********************************************/
|
|
|
+ const [visible, setVisible] = useState<boolean>(false);
|
|
|
+ const [groupList, setGroupList] = useState<{ label: string, value: number }[]>([]);
|
|
|
+ const [activeKey, setActiveKey] = useState<string>('2')
|
|
|
+
|
|
|
+ const getProjectGroupsAllList = useAjax(() => getProjectGroupsAllListApi())
|
|
|
+ /***********************************************/
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getProjectGroupsAllList.run().then(res => {
|
|
|
+ setGroupList([{ label: '空项目组', value: 0 }, ...res?.data?.map(item => ({ label: item.name, value: item.id })) || []])
|
|
|
+ })
|
|
|
+ }, [])
|
|
|
+
|
|
|
+ return <>
|
|
|
+ <div className={style.moduleCard} onClick={() => setVisible(true)}>
|
|
|
+ <div className={style.moduleCard_header}>
|
|
|
+ <Avatar style={projectType === 1 ? { backgroundColor: '#f3e8ff', color: '#9333ea' } : projectType === 2 ? { backgroundColor: '#fff0f6', color: '#f759ab' } : { backgroundColor: '#dbeafe', color: '#2563eb' }} size={30}>
|
|
|
+ <FontAwesomeIcon icon={icon} />
|
|
|
+ </Avatar>
|
|
|
+ {title}
|
|
|
+ </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={title}
|
|
|
+ onClose={() => setVisible(false)}
|
|
|
+ open={visible}
|
|
|
+ width={'70%'}
|
|
|
+ >
|
|
|
+ <Tabs
|
|
|
+ destroyOnHidden={false}
|
|
|
+ onChange={(key) => {
|
|
|
+ setActiveKey(key)
|
|
|
+ }}
|
|
|
+ activeKey={activeKey}
|
|
|
+ type="card"
|
|
|
+ items={[
|
|
|
+ {
|
|
|
+ key: '2',
|
|
|
+ label: '下发企微号',
|
|
|
+ children: <>
|
|
|
+ {activeKey == '2' && <GroupXfCorpTabls groupList={groupList} projectType={projectType} />}
|
|
|
+ </>
|
|
|
+ },
|
|
|
+ {
|
|
|
+ key: '4',
|
|
|
+ label: '群发记录',
|
|
|
+ children: <>
|
|
|
+ {activeKey == '4' && <GroupTaskNotes groupList={groupList} projectType={projectType} />}
|
|
|
+ </>
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ />
|
|
|
+
|
|
|
+ </Drawer>
|
|
|
+ </>
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * 下发企微号
|
|
|
+ * @param param0
|
|
|
+ * @returns
|
|
|
+ */
|
|
|
+const GroupXfCorpTabls: React.FC<{ groupList: { label: string, value: number }[], projectType?: 1 | 2 }> = ({ groupList, projectType }) => {
|
|
|
+
|
|
|
+ /***********************************/
|
|
|
+ const taskType = projectType === 1 ? 'TASK_STAT_GROUP_SEND_CHAT' : projectType === 2 ? 'TASK_STAT_GROUP_ROBOT' : 'TASK_STAT_GROUP_SEND'
|
|
|
+ const [queryParams, setQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20 })
|
|
|
+ const [oldQueryParams, setOldQueryParams] = useState<GetSendUserListProps>({ pageNum: 1, pageSize: 20 })
|
|
|
+ const { token } = useNewToken()
|
|
|
+ const [modal, contextHolder] = Modal.useModal();
|
|
|
+
|
|
|
+ const getSendUserList = useAjax((params) => getSendUserListApi(params))
|
|
|
+ /***********************************/
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getSendUserList.run({ ...queryParams, projectType })
|
|
|
+ }, [queryParams, projectType])
|
|
|
+
|
|
|
+ return <div>
|
|
|
+ {contextHolder}
|
|
|
+ <SearchBox
|
|
|
+ bodyPadding={`0 0 10px`}
|
|
|
+ buttons={<>
|
|
|
+ <Button type="primary" onClick={() => {
|
|
|
+ setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
|
|
|
+ }} loading={getSendUserList.loading} icon={<SearchOutlined />}>搜索</Button>
|
|
|
+ </>}
|
|
|
+ >
|
|
|
+ <>
|
|
|
+ <Input
|
|
|
+ placeholder="消息ID"
|
|
|
+ style={{ width: 120 }}
|
|
|
+ allowClear
|
|
|
+ onChange={(e) => setOldQueryParams({ ...oldQueryParams, msgId: e.target.value })}
|
|
|
+ value={oldQueryParams?.msgId}
|
|
|
+ />
|
|
|
+ <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: <Badge status="error" text='未发送' />, value: 0 }, { label: <Badge status="success" text='已发送' />, value: 2 }]}
|
|
|
+ />
|
|
|
+ <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}
|
|
|
+ />
|
|
|
+ <DatePicker.RangePicker
|
|
|
+ placeholder={['预计送达时间(起始)', '预计送达时间(结束)']}
|
|
|
+ onChange={(e, date) => { setOldQueryParams({ ...oldQueryParams, expectStartDay: date[0], expectEndDay: date[1] }) }}
|
|
|
+ allowClear
|
|
|
+ value={oldQueryParams?.expectStartDay ? [dayJs(oldQueryParams?.expectStartDay), dayJs(oldQueryParams?.expectEndDay)] : undefined}
|
|
|
+ />
|
|
|
+ </>
|
|
|
+ </SearchBox>
|
|
|
+
|
|
|
+ {/* 表 */}
|
|
|
+ <Table
|
|
|
+ style={{ marginTop: 10 }}
|
|
|
+ dataSource={getSendUserList?.data?.data?.records}
|
|
|
+ loading={getSendUserList?.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,
|
|
|
+ taskId: record.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_GROUP_SEND': // 官方群发
|
|
|
+ window.open(`/weComTask#/weComTask/businessPlan/taskList`)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }}>任务跳转</a>
|
|
|
+ </Space>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '任务名称',
|
|
|
+ dataIndex: 'projectName',
|
|
|
+ key: 'projectName',
|
|
|
+ width: 180,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (text) => <a onClick={() => copy(text)}>{text}</a>
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '子任务ID',
|
|
|
+ dataIndex: 'taskId',
|
|
|
+ key: 'taskId',
|
|
|
+ width: 70,
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '项目组名称',
|
|
|
+ dataIndex: 'projectGroupName',
|
|
|
+ key: 'projectGroupName',
|
|
|
+ width: 100,
|
|
|
+ ellipsis: true,
|
|
|
+ align: 'center',
|
|
|
+ render: (text) => text ? <a onClick={() => copy(text)}>{text}</a> : '--'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '项目组ID',
|
|
|
+ dataIndex: 'projectGroupId',
|
|
|
+ key: 'projectGroupId',
|
|
|
+ width: 70,
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '所属企业',
|
|
|
+ dataIndex: 'corpName',
|
|
|
+ key: 'corpName',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '企微号',
|
|
|
+ dataIndex: 'userName',
|
|
|
+ key: 'userName',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (a: string, b: any) => {
|
|
|
+ return a + `(${b?.userId})`
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送时间',
|
|
|
+ dataIndex: 'sendTime',
|
|
|
+ key: 'sendTime',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '预计发送时间',
|
|
|
+ dataIndex: 'createTime',
|
|
|
+ key: 'createTime',
|
|
|
+ align: 'center',
|
|
|
+ width: 120,
|
|
|
+ ellipsis: true,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送状态',
|
|
|
+ dataIndex: 'status',
|
|
|
+ key: 'status',
|
|
|
+ align: 'center',
|
|
|
+ width: 100,
|
|
|
+ render: (a: number) => {
|
|
|
+ return <span>{{ '0': <Badge status="error" text='未发送' />, '2': <Badge status="success" text='已发送' /> }[a]}</span>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送对象',
|
|
|
+ dataIndex: 'userCount',
|
|
|
+ key: 'userCount',
|
|
|
+ align: 'center',
|
|
|
+ width: 100,
|
|
|
+ render: (a: number) => {
|
|
|
+ return <span>好友{a > 0 ? a : 0}个</span>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送成功',
|
|
|
+ dataIndex: 'sendSuccessCount',
|
|
|
+ key: 'sendSuccessCount',
|
|
|
+ align: 'center',
|
|
|
+ width: 70,
|
|
|
+ render: (a) => {
|
|
|
+ return a > 0 ? a : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送失败',
|
|
|
+ dataIndex: 'sendFailCount',
|
|
|
+ key: 'sendFailCount',
|
|
|
+ align: 'center',
|
|
|
+ width: 70,
|
|
|
+ render: (a) => {
|
|
|
+ return a > 0 ? a : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '因客户不是好友导致发送失败',
|
|
|
+ dataIndex: 'unFriendCount',
|
|
|
+ key: 'unFriendCount',
|
|
|
+ align: 'center',
|
|
|
+ width: 70,
|
|
|
+ render: (a) => {
|
|
|
+ return a > 0 ? a : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '因客户已经收到其他群发消息导致发送失败',
|
|
|
+ dataIndex: 'othersSendCount',
|
|
|
+ key: 'othersSendCount',
|
|
|
+ align: 'center',
|
|
|
+ width: 95,
|
|
|
+ render: (a) => {
|
|
|
+ return a > 0 ? a : 0
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '消息ID',
|
|
|
+ dataIndex: 'msgId',
|
|
|
+ key: 'msgId',
|
|
|
+ align: 'center',
|
|
|
+ width: 150,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (a: string) => {
|
|
|
+ return <a onClick={() => copy(a)}>{a}</a>
|
|
|
+ }
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ scroll={{ x: 1000 }}
|
|
|
+ rowKey={'id'}
|
|
|
+ size='small'
|
|
|
+ onRow={(row: any) => {
|
|
|
+ return !row?.status ? {
|
|
|
+ style: { background: token.colorPrimaryBgHover }
|
|
|
+ } : {}
|
|
|
+ }}
|
|
|
+ pagination={{
|
|
|
+ total: getSendUserList?.data?.data?.total,
|
|
|
+ showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
|
|
|
+ showSizeChanger: true,
|
|
|
+ showLessItems: true,
|
|
|
+ defaultCurrent: 1,
|
|
|
+ defaultPageSize: 200,//默认初始的每页条数
|
|
|
+ current: getSendUserList?.data?.data?.current || 1,
|
|
|
+ pageSize: getSendUserList?.data?.data?.size || 20,
|
|
|
+ onChange: (page, pageSize) => {
|
|
|
+ setQueryParams({ ...queryParams, pageNum: page, pageSize })
|
|
|
+ setOldQueryParams({ ...oldQueryParams, pageNum: page, pageSize })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+const GroupTaskNotes: React.FC<{ groupList: { label: string, value: number }[], projectType?: 1 | 2 }> = ({ groupList, projectType }) => {
|
|
|
+
|
|
|
+ /***********************************/
|
|
|
+ const taskType = projectType === 1 ? 'TASK_STAT_GROUP_SEND_CHAT' : projectType === 2 ? 'TASK_STAT_GROUP_ROBOT' : 'TASK_STAT_GROUP_SEND'
|
|
|
+ const [queryParams, setQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20 })
|
|
|
+ const [oldQueryParams, setOldQueryParams] = useState<GetSendUserLogListProps>({ pageNum: 1, pageSize: 20 })
|
|
|
+ const { token } = useNewToken()
|
|
|
+ const [modal, contextHolder] = Modal.useModal();
|
|
|
+
|
|
|
+ const getSendUserLogList = useAjax((params) => getSendUserLogListApi(params))
|
|
|
+ /***********************************/
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ getSendUserLogList.run({ ...queryParams, projectType })
|
|
|
+ }, [queryParams, projectType])
|
|
|
+
|
|
|
+ const groupBody = (item) => {
|
|
|
+ let msgData = []
|
|
|
+ if (item?.text?.content) {
|
|
|
+ let newValue = item?.text?.content
|
|
|
+ let newEmo = emoList.reduce((prev, cur) => {
|
|
|
+ return [...prev, ...cur]
|
|
|
+ }, [])
|
|
|
+ let emos = newValue.match(/\[[\u4e00-\u9fa5]+\]/g)
|
|
|
+ if (emos && emos?.length) {
|
|
|
+ emos.forEach((emo: any) => {
|
|
|
+ let emoData = newEmo.find(o => `[${o.name}]` === emo)
|
|
|
+ if (emoData) {
|
|
|
+ newValue = newValue.replace(emo, `<img src="${emoData.url}" alt="${emoData.name}" style="width:20px;height:20px"/>`)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (newValue.includes('\n')) {
|
|
|
+ newValue = newValue.replace('\n', `<br/>`)
|
|
|
+ }
|
|
|
+ let names = newValue.match(/%[\u4e00-\u9fa5]+%/g)
|
|
|
+ if (names && names?.length) {
|
|
|
+ newValue = newValue.replace('%昵称%', ` <span style="display: inline-block;margin:0 1px;position: relative; border: 1px solid ${token.colorBorder}; padding: ${token.paddingXS}px; border-radius: ${token.borderRadius}px;color: ${token.colorTextBase}; background: ${token.colorSuccess};color:${token.colorTextLightSolid}" contenteditable="false">昵称<strong data-name="昵称" style="padding: 0 6px;cursor:pointer" onclick="let html =document.querySelector('[data-name=昵称').parentElement.parentElement.innerHTML;let span = ' '+document.querySelector('[data-name=昵称]').parentElement.outerHTML+' ';console.log('=',html,'=');console.log('=',span,'=');document.execCommand('selectAll');document.execCommand('delete'); document.execCommand('insertHTML', true, html.replace(span,''));">X</strong></span> `)
|
|
|
+ }
|
|
|
+ msgData.push({
|
|
|
+ textContent: newValue,
|
|
|
+ mediaType: 'text'
|
|
|
+ })
|
|
|
+ }
|
|
|
+ if (item?.attachmentList && item?.attachmentList?.length > 0) {
|
|
|
+ let newAttachmentList = item?.attachmentList.map((item: any) => {
|
|
|
+ switch (item.msgType) {
|
|
|
+ case 'TASK_CONTENT_IMAGE':
|
|
|
+ return { mediaType: 'image', imageUrl: item?.image?.picUrl }
|
|
|
+ case 'TASK_CONTENT_LINK':
|
|
|
+ return { mediaType: 'link', linkDesc: item?.link?.desc, linkPicurl: item?.link?.picUrl, linkTitle: item?.link?.title, linkUrl: item?.link?.url }
|
|
|
+ case 'TASK_STATUS_FILE':
|
|
|
+ return { mediaType: 'file', fileUrl: item?.file?.fileUrl }
|
|
|
+ case 'TASK_STATUS_VIDEO':
|
|
|
+ return { mediaType: 'video', videoUrl: item?.video?.videoUrl }
|
|
|
+ case 'TASK_STATUS_MINIPROGRAM':
|
|
|
+ return {
|
|
|
+ mediaType: 'miniprogram',
|
|
|
+ miniprogramAppid: item.miniprogram?.appId,
|
|
|
+ miniprogramPage: item?.miniprogram?.page,
|
|
|
+ miniprogramPicurl: item?.miniprogram?.picUrl,
|
|
|
+ miniprogramTitle: item?.miniprogram?.title
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ msgData = msgData.concat(newAttachmentList)
|
|
|
+ }
|
|
|
+ return msgData
|
|
|
+ }
|
|
|
+
|
|
|
+ return <div>
|
|
|
+ {contextHolder}
|
|
|
+ <SearchBox
|
|
|
+ bodyPadding={`0 0 10px`}
|
|
|
+ buttons={<>
|
|
|
+ <Button type="primary" onClick={() => {
|
|
|
+ setQueryParams({ ...oldQueryParams, pageNum: 1, pageSize: queryParams.pageSize })
|
|
|
+ }} loading={getSendUserLogList.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
|
|
|
+ placeholder='请选择项目组'
|
|
|
+ allowClear
|
|
|
+ options={groupList}
|
|
|
+ showSearch
|
|
|
+ style={{ minWidth: 150 }}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
+ }
|
|
|
+ maxTagCount={1}
|
|
|
+ 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={getSendUserLogList?.data?.data?.records}
|
|
|
+ loading={getSendUserLogList?.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,
|
|
|
+ taskId: record.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_GROUP_SEND': // 官方群发
|
|
|
+ window.open(`/weComTask#/weComTask/businessPlan/taskList`)
|
|
|
+ break
|
|
|
+ }
|
|
|
+ },
|
|
|
+ });
|
|
|
+ }}>任务跳转</a>
|
|
|
+ </Space>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '任务名称',
|
|
|
+ dataIndex: 'projectName',
|
|
|
+ key: 'projectName',
|
|
|
+ width: 180,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (text) => <a onClick={() => copy(text)}>{text}</a>
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '子任务ID',
|
|
|
+ dataIndex: 'taskId',
|
|
|
+ key: 'taskId',
|
|
|
+ width: 70,
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '项目组名称',
|
|
|
+ dataIndex: 'projectGroupName',
|
|
|
+ key: 'projectGroupName',
|
|
|
+ width: 100,
|
|
|
+ ellipsis: true,
|
|
|
+ align: 'center',
|
|
|
+ render: (text) => text ? <a onClick={() => copy(text)}>{text}</a> : '--'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '项目组ID',
|
|
|
+ dataIndex: 'projectGroupId',
|
|
|
+ key: 'projectGroupId',
|
|
|
+ width: 70,
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '任务ID',
|
|
|
+ dataIndex: 'taskId',
|
|
|
+ key: 'taskId',
|
|
|
+ align: 'center',
|
|
|
+ width: 65
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '客服号名称',
|
|
|
+ dataIndex: 'corpUserName',
|
|
|
+ key: 'corpUserName',
|
|
|
+ align: 'center',
|
|
|
+ width: 150,
|
|
|
+ ellipsis: true
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '消息ID',
|
|
|
+ dataIndex: 'msgId',
|
|
|
+ key: 'msgId',
|
|
|
+ align: 'center',
|
|
|
+ width: 250,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (a: string) => {
|
|
|
+ return <a onClick={() => copy(a)}>{a}</a>
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: <div>发送内容<Tooltip title="2025-01-10前的群发无法查看内容"><InfoCircleOutlined /></Tooltip></div>,
|
|
|
+ dataIndex: 'contentDTO',
|
|
|
+ key: 'contentDTO',
|
|
|
+ align: 'center',
|
|
|
+ width: 90,
|
|
|
+ ellipsis: true,
|
|
|
+ render: (a, b) => {
|
|
|
+ let data = []
|
|
|
+ if (a) {
|
|
|
+ data = groupBody(a)
|
|
|
+ }
|
|
|
+
|
|
|
+ return data?.length > 0 ? <Tooltip color={"#fff"} title={<PreviewMsg type="MSG" minWidth={"200px"} height={'calc(100vh - 400px)'} content={{ data }} />}>
|
|
|
+ <a>查看内容</a>
|
|
|
+ </Tooltip> : "无内容"
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '发送时间',
|
|
|
+ dataIndex: 'createTime',
|
|
|
+ key: 'createTime',
|
|
|
+ ellipsis: true,
|
|
|
+ align: 'center',
|
|
|
+ width: 130
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: <>执行结果 <Tooltip title={<span>此结果为任务在后台创建后是否成功提交到腾讯。腾讯下发至手机和手机的最终执行结果请查看下发企微号。</span>}><QuestionCircleOutlined style={{ color: 'red' }} /></Tooltip></>,
|
|
|
+ dataIndex: 'errCode',
|
|
|
+ key: 'errCode',
|
|
|
+ width: 60,
|
|
|
+ align: 'center',
|
|
|
+ ellipsis: true,
|
|
|
+ render: (a: number) => {
|
|
|
+ return { 0: '成功', 1: '失败' }[a]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '失败人数',
|
|
|
+ dataIndex: 'failCount',
|
|
|
+ key: 'failCount',
|
|
|
+ align: 'center',
|
|
|
+ ellipsis: true,
|
|
|
+ width: 60,
|
|
|
+ render: (a: any, b: any) => {
|
|
|
+ return <GroupErrorCountList failCount={a} corpId={b?.corpId} msgId={b?.msgId} taskId={b?.taskId} />
|
|
|
+ }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '错误信息',
|
|
|
+ dataIndex: 'errMsg',
|
|
|
+ key: 'errMsg',
|
|
|
+ ellipsis: true,
|
|
|
+ width: 150
|
|
|
+ }
|
|
|
+ ]}
|
|
|
+ scroll={{ x: 1000 }}
|
|
|
+ rowKey={(s) => {
|
|
|
+ return s.id
|
|
|
+ }}
|
|
|
+ size='small'
|
|
|
+ rowClassName={(record) => record?.errCode === 1 ? 'errorClassName' : ''}
|
|
|
+ pagination={{
|
|
|
+ total: getSendUserLogList?.data?.data?.total,
|
|
|
+ showTotal: (total) => <Tag color="cyan">总共{total}数据</Tag>,
|
|
|
+ showSizeChanger: true,
|
|
|
+ showLessItems: true,
|
|
|
+ defaultCurrent: 1,
|
|
|
+ defaultPageSize: 200,//默认初始的每页条数
|
|
|
+ current: getSendUserLogList?.data?.data?.current || 1,
|
|
|
+ pageSize: getSendUserLogList?.data?.data?.size || 20,
|
|
|
+ onChange: (page, pageSize) => {
|
|
|
+ setQueryParams({ ...queryParams, pageNum: page, pageSize })
|
|
|
+ setOldQueryParams({ ...oldQueryParams, pageNum: page, pageSize })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+}
|
|
|
+
|
|
|
+export default React.memo(GroupItem);
|