wjx 1 周之前
父節點
當前提交
aad5483267

+ 0 - 4
src/Hook/useNewToken.tsx

@@ -123,7 +123,6 @@ let themeConfig = {
         },
         components: {
             Table: {
-                colorBgContainer: 'rgba(247, 247, 247, 0)',
                 paddingXS: 4,
             },
             Aside: {
@@ -132,9 +131,6 @@ let themeConfig = {
             Layout: {
                 borderRadiusSM: 0,
             },
-            Menu: {
-                borderRadiusSM: 0,
-            },
             Card: {
 
             },

文件差異過大導致無法顯示
+ 22 - 38
src/layout/index.tsx


+ 2 - 2
src/pages/weComTask/API/groupChat/index.ts

@@ -110,9 +110,9 @@ export async function delProjectApi(data: { projectIds: number[] }) {
  * @param data 
  * @returns 
  */
-export async function cancelProjectApi(data: { projectIds: number[] }) {
+export async function cancelProjectApi(data: { projectIds: number[], pause: boolean }) {
     return request({
-        url: api + `/corpOperation/corp/pullGroup/project/cancel`,
+        url: api + `/corpOperation/corp/pullGroup/project/cancel/${data.pause}`,
         method: 'POST',
         data: data.projectIds
     });

+ 2 - 0
src/pages/weComTask/page/businessPlan/create/const.tsx

@@ -100,6 +100,8 @@ export const GENDER_TYPE: { [x: string]: string } = {
 }
 
 export const EUTTaskStatus = { 0: <Badge status="default" text="创建中" />, 1: <Badge status="processing" text='执行中' />, 2: <Badge status="success" text="执行完成" />, 3: <Badge status="warning" text="暂停" /> }
+// 拉群
+export const LQTaskStatus = { 1: <Badge status="processing" text='执行中' />, 2: <Badge status="success" text="执行完成" />, 3: <Badge status="warning" text="暂停" />, '-1': <Badge status="error" text="执行失败" /> }
 
 /**
  * 返回处理过的客户继承数据

+ 7 - 2
src/pages/weComTask/page/groupChat/create/components/groupUser/addGroupObject.tsx

@@ -39,7 +39,7 @@ const AddGroupObject: React.FC<GROUP_CHAT_CREATE.AddGroupObjectProps> = ({ value
                 setVisible(true)
             }}
             handleCopy={(record) => {
-                const newValue = { ...record, groupObjectName: `copy策略${index + 1}_` + record.groupObjectName }
+                const newValue = { ...record, id: Date.now(), groupObjectName: `copy策略${index + 1}_` + record.groupObjectName }
                 setCopyData({ visible: true, data: newValue })
             }}
         /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} description='暂无群配置' />}
@@ -263,7 +263,7 @@ export const ShowGroupUserTable: React.FC<GROUP_CHAT_CREATE.ShowGroupUserTablePr
         size='small'
         bordered
         rowKey={'id'}
-        dataSource={value?.map((item, index) => ({ ...item, id: index + 1 }))}
+        dataSource={value}
         scroll={{ y: 1000 }}
         columns={columns}
     />
@@ -286,6 +286,11 @@ const AddGroupObjectModal: React.FC<GROUP_CHAT_CREATE.AddGroupObjectModalProps>
 
     const handleOk = () => {
         form.validateFields().then((values) => {
+            if (initialValues?.id) {
+                values.id = initialValues.id
+            } else {
+                values.id = Date.now();
+            }
             console.log(values)
             onChange?.(values)
         }).catch(() => {

+ 3 - 9
src/pages/weComTask/page/groupChat/create/components/strategy/settingsStrategy.tsx

@@ -20,7 +20,7 @@ const SettingsStrategy: React.FC<GROUP_CHAT_CREATE.FoundationProps<any>> = ({ vi
     const strategyList = Form.useWatch('strategyList', form)
 
     const [stepsList, setStepsList] = useState<any>([
-        { title: '群聊创建配置', description: '任务名称', id: 'basicInfo' },
+        // { title: '群聊创建配置', description: '任务名称', id: 'basicInfo' },
         { title: '策略配置', children: [{ title: `策略${1}`, id: 'strategy_1' }] },
         { title: '完成' }
     ])
@@ -90,7 +90,7 @@ const SettingsStrategy: React.FC<GROUP_CHAT_CREATE.FoundationProps<any>> = ({ vi
         });
     };
 
-    const filedUpdateChange = ({ taskName, strategyList }: any) => {
+    const filedUpdateChange = ({ strategyList }: any) => {
         const strategyChildren = strategyList?.map((item, index) => {
             const { strategyName, timeRepeatType, sendDay, startTime, sendTime, repeatArray } = item
             const sendTimeChecked =
@@ -101,10 +101,9 @@ const SettingsStrategy: React.FC<GROUP_CHAT_CREATE.FoundationProps<any>> = ({ vi
             return { title: `策略${index + 1}`, description: `策略名称、执行时间`, id: `strategy_${index + 1}`, checked: sendTimeChecked && strategyName }
         })
         const stepsData = [
-            { title: '群聊创建配置', description: '任务名称', id: 'basicInfo', checked: taskName },
             { title: '策略配置', children: strategyChildren, checked: strategyChildren.some(item => item.checked) },
             {
-                title: '完成', checked: strategyChildren.some(item => item.checked) && taskName
+                title: '完成', checked: strategyChildren.some(item => item.checked)
             }
         ]
         setStepsList(stepsData)
@@ -150,11 +149,6 @@ const SettingsStrategy: React.FC<GROUP_CHAT_CREATE.FoundationProps<any>> = ({ vi
                 }}
                 preserve={true}
             >
-                {/* <Card title={<strong>基础信息配置</strong>} style={{ background: '#fff', marginBottom: 10 }} id='basicInfo'>
-                    <Form.Item label={<strong>任务名称</strong>} name="taskName" rules={[{ required: true, message: '请输入任务名称!' }]}>
-                        <Input placeholder="请输入任务名称" style={{ width: 358 }} allowClear />
-                    </Form.Item>
-                </Card> */}
                 <Form.List name="strategyList">
                     {(fields, { add, remove }) => (
                         <>

+ 6 - 3
src/pages/weComTask/page/groupChat/create/const.ts

@@ -7,13 +7,16 @@ export const getPullGroupData = (strategyList: any[]) => {
     const nowTime = Date.now()
     return {
         strategyList: strategyList.map(({ taskDetail, ...item }, index) => {
-
+            const id = item.id || nowTime + (index * 1000)
+            const nowTime_inherit = Date.now()
             return {
                 ...item,
-                id: nowTime + (index * 1000),
-                groupObjectList: taskDetail.map(({ externalUserFilter, weChatAppid, mpAccountInfo, msgTagDTO, groupName, ...go }) => {
+                id,
+                groupObjectList: taskDetail.map(({ externalUserFilter, weChatAppid, mpAccountInfo, msgTagDTO, groupName, ...go }, i) => {
+                    const id = go.id || nowTime_inherit + (index * 1000) + (i * 100)
                     const inherit: { [x: string]: any } = {
                         ...go,
+                        id,
                         weChatAppid: mpAccountInfo?.name ? mpAccountInfo?.name + '_' + mpAccountInfo?.id : undefined,
                         tagDTO: msgTagDTO,
                         groupObjectName: groupName

+ 1 - 2
src/pages/weComTask/page/groupChat/create/index.tsx

@@ -240,7 +240,6 @@ const GroupChatCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREAT
                 corpName: item.corpName
             })),
             strategyList: strategyDTO.strategyList.map(({ groupObjectList, ...item }) => {
-                delete item?.id // 删除id
                 return {
                     ...item,
                     taskDetail: groupObjectList.map(go => {
@@ -300,7 +299,7 @@ const GroupChatCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREAT
     }
 
     return <div className={style.create}>
-        <Spin spinning={false}>
+        <Spin spinning={getCreateDetails.loading}>
             <Card title={<strong>{projectId ? getCreateDetails?.data?.data?.taskName + '任务编辑' : ''}配置区</strong>} className={`${style.card} ${style.config}`}>
                 <Space wrap>
                     <Space.Compact>

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

@@ -4,7 +4,7 @@ import FilterUserTooltip from "@/pages/weComTask/components/filterUser/filterUse
 import { Badge, Button, Drawer, Flex, Modal, Popover, Space, Table, Typography } from "antd"
 import React, { useEffect, useState } from "react"
 import { QuestionCircleFilled } from "@ant-design/icons"
-import { businessPlanData, TIME_TYPE_ZJ } from "../../businessPlan/create/const";
+import { businessPlanData, LQTaskStatus, TIME_TYPE_ZJ } from "../../businessPlan/create/const";
 import PreviewTime from "@/pages/weComTask/components/previewTime";
 const { Text, Paragraph, Title } = Typography;
 
@@ -48,7 +48,7 @@ const Details: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClo
                     title: '任务名称',
                     dataIndex: 'taskName',
                     key: 'taskName',
-                    width: 120,
+                    width: 180,
                     ellipsis: true,
                     fixed: 'left'
                 },
@@ -60,6 +60,17 @@ const Details: React.FC<Props> = ({ data, bookPlatForm, bookList, visible, onClo
                     ellipsis: true,
                     fixed: 'left'
                 },
+                {
+                    title: '计划状态',
+                    dataIndex: 'taskStatus',
+                    key: 'taskStatus',
+                    width: 90,
+                    align: 'center',
+                    fixed: 'left',
+                    render(value) {
+                        return LQTaskStatus[value] || '--'
+                    },
+                },
                 {
                     title: '执行时间',
                     dataIndex: 'timeRepeatType',

+ 16 - 8
src/pages/weComTask/page/groupChat/taskList/index.tsx

@@ -27,9 +27,9 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
     /**********************************************/
 
     useEffect(() => {
-        const projectName = sessionStorage.getItem('CAMPCORP')
+        const projectName = sessionStorage.getItem('CAMPCORP_PG')
         if (projectName) {
-            sessionStorage.removeItem('CAMPCORP')
+            sessionStorage.removeItem('CAMPCORP_PG')
         }
     }, [])
 
@@ -49,7 +49,7 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
         setLogOpenData({ visible: true, data })
     }
     // 删除
-    const handleDel = (data: { projectIds: number[] }, type: 'del' | 'cancel') => {
+    const handleDel = (data: { projectIds: number[] }, type: 'del' | 'cancel' | 'open') => {
         const hide = message.loading(type === 'del' ? '正在删除...' : '正在取消...', 0)
         switch (type) {
             case 'del':
@@ -65,14 +65,15 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
                 }).catch(() => hide())
                 break
             case 'cancel':
-                cancelProject.run(data).then(res => {
+            case 'open':
+                cancelProject.run({...data, pause: type === 'cancel' ? false : true}).then(res => {
                     hide()
                     setselectedRows([])
                     if (res?.data) {
-                        message.success('取消成功')
+                        message.success(type === 'cancel' ? '取消成功' : '启用成功')
                         getProjectList.refresh()
                     } else {
-                        message.error('取消失败')
+                        message.error(type === 'cancel' ? '取消失败' : '启用失败')
                     }
                 }).catch(() => hide())
                 break
@@ -119,11 +120,18 @@ const TaskList: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookL
                 <Button type='primary' danger icon={<DeleteOutlined />} loading={delProject.loading} disabled={selectedRows.length === 0}>删除</Button>
             </Popconfirm>
             <Popconfirm
-                title="确定取消?"
+                title="确定暂停?"
                 onConfirm={() => { handleDel({ projectIds: selectedRows.map(i => i.id) }, 'cancel') }}
                 disabled={selectedRows.length === 0}
             >
-                <Button type='primary' style={{ backgroundColor: 'orange', borderColor: 'orange' }} loading={cancelProject.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0}>取消任务</Button>
+                <Button type='primary' style={{ backgroundColor: 'orange', borderColor: 'orange' }} loading={cancelProject.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0}>暂停任务</Button>
+            </Popconfirm>
+            <Popconfirm
+                title="确定启用?"
+                onConfirm={() => { handleDel({ projectIds: selectedRows.map(i => i.id) }, 'open') }}
+                disabled={selectedRows.length === 0}
+            >
+                <Button type='primary' style={{ backgroundColor: '#87d068', borderColor: '#87d068' }} loading={cancelProject.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0}>启用任务</Button>
             </Popconfirm>
         </div>
 

+ 12 - 7
src/pages/weComTask/page/groupChat/taskList/tableConfig.tsx

@@ -13,7 +13,7 @@ const taskListColumns = (
     bookList: TASK_CREATE.BookListProps[],
     handleLog: (data: any) => void,
     handleCopy: (data: any, isCopy: boolean) => void,
-    handleDel: (data: any, type: 'del' | 'cancel') => void,
+    handleDel: (data: any, type: 'del' | 'cancel' | 'open') => void,
 ): ColumnsType<AnyObject> => {
 
     return [
@@ -24,12 +24,17 @@ const taskListColumns = (
             width: 160,
             render(_, record) {
                 return <Space>
-                    <Popconfirm
-                        title="确定取消?"
+                    {record?.status === 1 ? <Popconfirm
+                        title="确定暂停?"
                         onConfirm={() => { handleDel({ projectIds: [record.id] }, 'cancel') }}
                     >
-                        <a style={{ color: 'orange' }}>取消任务</a>
-                    </Popconfirm>
+                        <a style={{ color: 'orange' }}>暂停任务</a>
+                    </Popconfirm> : record?.status === 3 ? <Popconfirm
+                        title="确定启用?"
+                        onConfirm={() => { handleDel({ projectIds: [record.id] }, 'open') }}
+                    >
+                        <a style={{ color: '#87d068' }}>启用任务</a>
+                    </Popconfirm> : undefined}
                     <a onClick={() => handleCopy(record, true)}>复制</a>
                     <a onClick={() => handleCopy(record, false)}>编辑</a>
                     <a onClick={() => handleLog(record)}>详情</a>
@@ -106,7 +111,7 @@ const taskListColumns = (
                             </div>}
                             styles={{ body: { width: 300, overflow: 'hidden', overflowY: 'auto', maxHeight: 400 } }}
                         >
-                            <a>策略<QuestionCircleFilled /></a>
+                            <a>策略 <QuestionCircleFilled /></a>
                         </Popover>
                         <Popover
                             placement="left"
@@ -119,7 +124,7 @@ const taskListColumns = (
                             </div>}
                             styles={{ body: { width: 700, overflow: 'hidden', overflowY: 'auto', maxHeight: 400 } }}
                         >
-                            <a>群配置<QuestionCircleFilled /></a>
+                            <a>群配置 <QuestionCircleFilled /></a>
                         </Popover>
                     </div>
                 }

+ 66 - 0
src/pages/weComTask/page/groupChatSend/official/create/components/Strategy/index.tsx

@@ -0,0 +1,66 @@
+import React, { useContext, useState } from "react";
+import style from '../../../../../businessPlan/create/index.less'
+import { App, Button, Empty } from "antd";
+import useNewToken from "@/Hook/useNewToken";
+import { DispatchOfficialChatCreate } from "../..";
+import SettingsStrategy from "./settingsStrategy";
+
+const Strategy: React.FC = () => {
+
+    /*********************************/
+    const { message } = App.useApp()
+    const { token } = useNewToken()
+    const { setSettings, settings, onPreviewReset, mpList } = useContext(DispatchOfficialChatCreate)!;
+    const [newVisible, setNewVisible] = useState<boolean>(false);
+    /*********************************/
+
+    return <>
+        <div className={`${style.settingsBody_content_row}`} style={{ width: '35%' }}>
+            <div className={`${style.settingsBody_content_col}`} style={{ width: '100%' }}>
+                <div className={style.title}>
+                    <span>策略</span>
+                    {/* {settings?.strategyDTO && Object.keys(settings?.strategyDTO).length > 0 && <Popconfirm
+                        title="确定清空?"
+                        onConfirm={() => {
+                            setSettings(undefined)
+                            onPreviewReset();
+                        }}
+                    >
+                        <a style={{ color: 'red' }}>清空</a>
+                    </Popconfirm>} */}
+                </div>
+                <div className={style.detail}>
+                    <div className={style.detail_title}>群发策略配置</div>
+                    <div className={style.detail_body}>
+                        {settings?.strategyDTO && Object.keys(settings?.strategyDTO).length > 0 ? <>
+                            {/* <PreviewStrategy strategyDTO={settings?.strategyDTO} /> */}
+                        </> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />}
+                    </div>
+                </div>
+                <div className={style.detail_footer}>
+                    <Button type="link" style={{ padding: 0, fontSize: 12, color: token.colorPrimary }} size="small" onClick={() => setNewVisible(true)}>编辑</Button>
+                </div>
+            </div>
+        </div>
+
+        {/* 配置基础信息 */}
+        {newVisible && <SettingsStrategy
+            visible={newVisible}
+            value={settings?.strategyDTO}
+            mpList={mpList}
+            onClose={() => {
+                setNewVisible(false);
+            }}
+            onChange={(values) => {
+                setSettings({
+                    ...settings,
+                    strategyDTO: values
+                });
+                onPreviewReset();
+                setNewVisible(false);
+            }}
+        />}
+    </>
+}
+
+export default React.memo(Strategy);

+ 176 - 0
src/pages/weComTask/page/groupChatSend/official/create/components/Strategy/settingsStrategy.tsx

@@ -0,0 +1,176 @@
+import { App, Button, Card, Form, Input, Modal, Radio, Select } from "antd";
+import React, { useRef } from "react";
+import '../../../../../businessPlan/create/global.less'
+import SendTimeSet from "@/pages/weComTask/components/sendTimeSet";
+import { MinusCircleOutlined, PlusOutlined, DeleteOutlined } from "@ant-design/icons";
+import FilterUser from "@/pages/weComTask/components/filterUser";
+import { DefaultOptionType } from "antd/es/select";
+
+interface Props extends GROUP_CHAT_CREATE.FoundationProps<any> {
+    mpList: DefaultOptionType[]
+}
+/**
+ * 官方 群聊群发策略配置
+ * @param param0 
+ * @returns 
+ */
+const SettingsStrategy: React.FC<Props> = ({ visible, onClose, value, onChange, mpList }) => {
+
+    /************************************/
+    const { message } = App.useApp()
+    const [form] = Form.useForm();
+    const ref1 = useRef<HTMLDivElement>(null)
+    const strategyList = Form.useWatch('strategyList', form)
+    /************************************/
+
+    const handleOk = () => {
+        form.validateFields().then((values) => {
+
+        }).catch(() => {
+            form.submit()
+        });
+    };
+
+    return <Modal
+        title={<strong>群聊群发策略配置  &nbsp;&nbsp;&nbsp;<span style={{ color: 'red' }}>对于执行时间冲突的策略,按照策略的排序执行</span></strong>}
+        open={visible}
+        onCancel={onClose}
+        width={850}
+        onOk={handleOk}
+        className={`settingsModal`}
+    >
+        <div className={`body_steps`}>
+
+        </div>
+        <div className={`body_content`} ref={ref1}>
+            <Form
+                form={form}
+                name="newGroupChatSendStrategy"
+                labelAlign='left'
+                labelCol={{ span: 5 }}
+                colon={false}
+                scrollToFirstError={{
+                    behavior: 'smooth',
+                    block: 'center'
+                }}
+                onFinishFailed={({ errorFields }) => {
+                    message.error(errorFields?.[0]?.errors?.[0])
+                }}
+                onFinish={handleOk}
+                initialValues={{
+                    strategyList: [{ id: Date.now(), sendData: [{ externalUserType: 'all', id: Date.now() }] }]
+                }}
+                onFieldsChange={() => {
+                    // filedUpdateChange(form.getFieldsValue())
+                }}
+                preserve={true}
+            >
+                <Card title={<strong>基础信息配置</strong>} style={{ background: '#fff', marginBottom: 10 }} id='basicInfo'>
+                    <Form.Item label={<strong>任务名称</strong>} name="taskName" rules={[{ required: true, message: '请输入任务名称!' }]}>
+                        <Input placeholder="请输入任务名称" style={{ width: 358 }} allowClear />
+                    </Form.Item>
+                </Card>
+
+                <Form.List name="strategyList">
+                    {(fields, { add, remove }) => (
+                        <>
+                            {fields.map(({ key, name, ...restField }, index) => {
+                                const timeRepeatType = strategyList?.[index]?.timeRepeatType
+                                const sendData = strategyList?.[index]?.sendData
+
+                                return <Card
+                                    key={key}
+                                    title={<strong>策略{index + 1} 配置</strong>}
+                                    style={{ background: '#fff', marginBottom: 10 }}
+                                    extra={strategyList?.length > 1 && <div style={{ color: 'red', cursor: 'pointer' }} onClick={() => remove(name)}>
+                                        <MinusCircleOutlined />
+                                    </div>}
+                                    id={`strategy_${index + 1}`}
+                                >
+                                    <Form.Item
+                                        {...restField}
+                                        name={[name, 'strategyName']}
+                                        label={<strong>策略名称</strong>}
+                                        rules={[{ required: true, message: '请输入策略名称!' }]}
+                                    >
+                                        <Input placeholder='请输入策略名称' allowClear style={{ width: 358 }} />
+                                    </Form.Item>
+                                    <SendTimeSet active='all' form={form} restField={restField} name={name} timeRepeatType={timeRepeatType} />
+                                    <Form.List name={[name, 'sendData']}>
+                                        {(fields, { add, remove }) => (
+                                            <>
+                                                {fields.map(({ key, name, ...restField }, i) => {
+                                                    return <Card
+                                                        key={i}
+                                                        title={<strong>策略{index + 1} 发送群对象{i + 1} 配置</strong>}
+                                                        style={{ background: '#fff', marginBottom: 10 }}
+                                                        extra={sendData?.length > 1 ? <Button icon={<DeleteOutlined />} type='link' style={{ color: 'red' }} onClick={() => remove(name)}></Button> : null}
+                                                        id={`strategy_${index}_${i}_sendData`}
+                                                    >
+                                                        <Form.Item
+                                                            {...restField}
+                                                            label={<strong>群聊关联公众号</strong>}
+                                                            name={[name, 'weChatAppid']}
+                                                        >
+                                                            <Select
+                                                                showSearch
+                                                                allowClear
+                                                                placeholder="选择公众号"
+                                                                filterOption={(input, option) =>
+                                                                    (option?.label as any)?.toLowerCase().indexOf(input.toLowerCase()) >= 0
+                                                                }
+                                                                style={{ width: 358 }}
+                                                                options={mpList}
+                                                            />
+                                                        </Form.Item>
+                                                        <Form.Item
+                                                            label={<strong>发送群对象配置</strong>}
+                                                            required
+                                                        >
+                                                            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start' }}>
+                                                                <Form.Item
+                                                                    {...restField}
+                                                                    name={[name, 'externalUserType']}
+                                                                    rules={[{ required: true, message: '请选择转移对象!' }]}
+                                                                    noStyle
+                                                                >
+                                                                    <Radio.Group options={[{ label: '全部', value: 'all' }, { label: '指定', value: 'specify' }]} />
+                                                                </Form.Item>
+                                                                {sendData?.[i]?.externalUserType === 'specify' && <div style={{ marginTop: 8, width: '100%' }}>
+                                                                    <Form.Item
+                                                                        {...restField}
+                                                                        name={[name, 'externalUserFilter']}
+                                                                        rules={[{ required: true, message: '请选择人群包!' }]}
+                                                                        noStyle
+                                                                    >
+                                                                        <FilterUser configType={'GROUP_GROUP'} />
+                                                                    </Form.Item>
+                                                                </div>}
+                                                            </div>
+                                                        </Form.Item>
+                                                    </Card>
+                                                })}
+                                                <Form.Item>
+                                                    <Button type="dashed" onClick={() => add({ externalUserType: 'all', id: Date.now() })} block icon={<PlusOutlined />}>
+                                                        新增发送群对象
+                                                    </Button>
+                                                </Form.Item>
+                                            </>
+                                        )}
+                                    </Form.List>
+                                </Card>
+                            })}
+                            <Form.Item>
+                                <Button type="primary" onClick={() => add({ id: Date.now() })} block icon={<PlusOutlined />}>
+                                    新增策略
+                                </Button>
+                            </Form.Item>
+                        </>
+                    )}
+                </Form.List>
+            </Form>
+        </div>
+    </Modal>
+}
+
+export default React.memo(SettingsStrategy);

+ 153 - 0
src/pages/weComTask/page/groupChatSend/official/create/index.tsx

@@ -0,0 +1,153 @@
+import React, { useEffect, useState } from 'react';
+import style from '../../../businessPlan/create/index.less'
+import { Button, Card, Input, Select, Space, Spin } from 'antd';
+import { toJS } from 'mobx';
+import { inject, observer } from 'mobx-react';
+import { welcomeMsgJobTypeApi } from '@/pages/weComTask/API/weMaterial/weMaterial';
+import { useAjax } from '@/Hook/useAjax';
+import Strategy from './components/Strategy';
+import { getBindMpListApi } from '@/pages/weComTask/API/corpUserAssign';
+import { DefaultOptionType } from 'antd/es/select';
+
+
+export const DispatchOfficialChatCreate = React.createContext<OFFICIAL_CHAT_CREATE.DispatchOfficialChatCreate | null>(null);
+/**
+ * 官方群发任务创建
+ * @returns 
+ */
+const OfficialCreate: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookListProps[], bookPlatForm: TASK_CREATE.BookPlatFormProps[] } } }> = ({ weComTaskStore }) => {
+
+    /*******************************************/
+    const { bookList, bookPlatForm } = toJS(weComTaskStore.data)
+    const [settings, setSettings] = useState<OFFICIAL_CHAT_CREATE.SettingsProps>();
+    const [msgJobTypeList, setMsgJobTypeList] = useState<{ value: string, label: string }[]>([])
+    const [projectId, setProjectId] = useState<number>()
+    const [previewData, setPreviewData] = useState<any[]>([])
+    const [previewDataOld, setPreviewDataOld] = useState<any[]>([])
+    const [mpList, setMpList] = useState<DefaultOptionType[]>([])
+
+    const welcomeMsgJobType = useAjax(() => welcomeMsgJobTypeApi())//获取业务类型
+    const getBindMpList = useAjax(() => getBindMpListApi())
+    /*******************************************/
+
+    useEffect(() => {
+        getBindMpList.run().then(res => {
+            if (res?.data)
+                setMpList(res.data.map((item: any) => ({ label: item.name, value: item.id, appId: item.appId })))
+        })
+    }, [])
+
+    useEffect(() => {
+        welcomeMsgJobType.run().then(res => {
+            if (res?.data) {
+                setMsgJobTypeList(Object.keys(res.data).map(key => ({ value: key, label: res.data[key] })))
+            }
+        })
+    }, [])
+
+    console.log('settings--->', settings)
+
+    // 重置表格
+    const onPreviewReset = () => {
+        setPreviewData([])
+        setPreviewDataOld([])
+    }
+
+    return <div className={style.create}>
+        <Spin spinning={false}>
+            <Card title={<strong>官方群发{projectId ? ' xxxx' + '任务编辑' : ''}配置区</strong>} className={`${style.card} ${style.config}`}>
+                <Space wrap>
+                    <Space.Compact>
+                        <Button>业务类型</Button>
+                        <Select
+                            showSearch
+                            style={{ width: 120 }}
+                            allowClear
+                            placeholder="请选择类型"
+                            filterOption={(input, option) =>
+                                ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                            }
+                            value={settings?.bizType}
+                            onChange={(e) => {
+                                setSettings({ ...settings, bizType: e })
+                                onPreviewReset()
+                            }}
+                            options={msgJobTypeList.filter(item => item.value === 'novel')}
+                        />
+                    </Space.Compact>
+
+                    {settings?.bizType === 'novel' ? <>
+                        <Space.Compact>
+                            <Button>书城</Button>
+                            <Select
+                                showSearch
+                                allowClear
+                                placeholder="请选择书城"
+                                style={{ width: 120 }}
+                                filterOption={(input, option) =>
+                                    ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                                }
+                                value={settings?.platform}
+                                onChange={(e) => {
+                                    setSettings({ ...settings, platform: e })
+                                    onPreviewReset()
+                                }}
+                                options={bookPlatForm.map(item => ({ value: item.id, label: item.platformName }))}
+                            />
+                        </Space.Compact>
+                        <Space.Compact>
+                            <Button>适用产品</Button>
+                            <Select
+                                showSearch
+                                style={{ width: 150 }}
+                                allowClear
+                                placeholder="请选择模板适用产品"
+                                filterOption={(input, option) =>
+                                    ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                                }
+                                value={settings?.templateProductId}
+                                onChange={(e) => {
+                                    setSettings({ ...settings, templateProductId: e })
+                                    onPreviewReset()
+                                }}
+                                options={bookList.map(item => ({ value: item.id, label: item.bookName }))}
+                            />
+                        </Space.Compact>
+                    </> : settings?.bizType === 'game' ? <Space.Compact>
+                        <Button>游戏渠道</Button>
+                        <Input
+                            style={{ width: 200 }}
+                            allowClear
+                            placeholder="请输入游戏渠道"
+                            value={settings.channel}
+                            onChange={(e) => {
+                                setSettings({ ...settings, channel: e.target.value })
+                                onPreviewReset()
+                            }}
+                        />
+                    </Space.Compact> : undefined}
+                </Space>
+
+                <div className={style.settingsBody}>
+                    <div className={style.settingsBody_content}>
+                        <DispatchOfficialChatCreate.Provider
+                            value={{
+                                settings, setSettings,
+                                onPreviewReset,
+                                bookPlatForm, bookList,
+                                mpList
+                            }}
+                        >
+                            {/* 策略配置 */}
+                            <Strategy />
+                            {/* 进群对象 */}
+                            {/* <GroupUser /> */}
+                        </DispatchOfficialChatCreate.Provider>
+                    </div>
+                </div>
+            </Card>
+        </Spin>
+    </div>;
+};
+
+export default inject('store')(observer((props: any) => OfficialCreate(props.store)))

+ 18 - 0
src/pages/weComTask/page/groupChatSend/official/typings.d.ts

@@ -0,0 +1,18 @@
+declare namespace OFFICIAL_CHAT_CREATE {
+    interface DispatchOfficialChatCreate {
+        settings: SettingsProps
+        setSettings: React.Dispatch<React.SetStateAction<SettingsProps>>
+        onPreviewReset: () => void
+        bookPlatForm: TASK_CREATE.BookPlatFormProps[]
+        bookList: TASK_CREATE.BookListProps[]
+        mpList: DefaultOptionType[]
+    }
+    // 官方群发创建参数配置
+    interface SettingsProps {
+        bizType?: string; // 业务类型
+        platform?: string; // 书城
+        channel?: string;   // 渠道
+        templateProductId?: string; // 适用产品
+        strategyDTO?: { [x: string]: any };
+    }
+}

+ 16 - 0
src/pages/weComTask/page/groupChatSend/robot/create/index.tsx

@@ -0,0 +1,16 @@
+import React from 'react';
+
+/**
+ * 机器人群发
+ * @returns 
+ */
+const RobotCreate: React.FC = () => {
+    return (
+        <div>
+            <h2>创建群聊机器人</h2>
+            {/* 这里可以添加表单或其他内容 */}
+        </div>
+    );
+};
+
+export default RobotCreate;

+ 1 - 0
src/public/svg/groupChatSend.svg

@@ -0,0 +1 @@
+<svg viewBox="64 64 896 896" focusable="false" data-icon="fund-view" width="1em" height="1em" fill="currentColor" aria-hidden="true"><path d="M658.358857 365.714286s13.458286-229.668571 218.843429-276.918857V0L1024 147.090286l-146.212571 145.92V203.849143s-132.827429-17.554286-219.428572 161.792z" fill="#5361FF" p-id="5369"></path><path d="M623.177143 73.874286a36.571429 36.571429 0 0 1 6.582857 72.411428l-6.582857 0.658286-403.456 0.146286v657.115428h656.530286V400.896a36.498286 36.498286 0 0 1 72.411428-6.582857l0.585143 6.582857v403.309714a73.142857 73.142857 0 0 1-64.585143 72.630857l-8.557714 0.512h-73.142857v72.411429a73.142857 73.142857 0 0 1-64.585143 72.704l-8.557714 0.512H73.142857l-8.557714-0.512a73.142857 73.142857 0 0 1-64-64.146286L0 949.833143 0.292571 292.571429c0.073143-37.522286 28.306286-68.388571 64.658286-72.630858L73.508571 219.428571h72.704V147.017143a73.142857 73.142857 0 0 1 64.658286-72.630857l8.484572-0.512h403.748571zM146.285714 292.571429h-72.850285v657.188571H729.965714v-72.484571H146.285714V292.571429z m550.034286 293.449142a36.425143 36.425143 0 0 1 0 72.923429H329.362286a36.425143 36.425143 0 0 1 0-72.923429H696.32zM549.522286 292.937143a36.498286 36.498286 0 0 1 0 72.996571h-220.16a36.498286 36.498286 0 1 1 0-72.996571h220.16z" fill="currentColor" p-id="5370"></path></svg>

部分文件因文件數量過多而無法顯示