wjx 1 week ago
parent
commit
9e268c3763

+ 1 - 1
src/layout/index.less

@@ -13,7 +13,7 @@
 }
 
 .sider {
-  max-height: calc(100vh - 50px);
+  max-height: calc(100vh - 48px);
   overflow: hidden;
   overflow-y: auto;
   >div {

+ 1 - 5
src/pages/weComTask/components/filterUser/newFiterUser.tsx

@@ -223,7 +223,6 @@ const NewFilterUser: React.FC<NewFilterUserProps> = ({ bookCityList, configType
                 <div className={style.newSpace}>
                     <Form.Item
                         label={<strong>智能标签</strong>}
-                        required
                     >
                         <Card
                             styles={{
@@ -238,10 +237,7 @@ const NewFilterUser: React.FC<NewFilterUserProps> = ({ bookCityList, configType
                     </Form.Item>
                 </div>
                 <div className={style.newSpace}>
-                    <Form.Item
-                        label={<strong>排除智能标签</strong>}
-                        required
-                    >
+                    <Form.Item label={<strong>排除智能标签</strong>}>
                         <Card
                             styles={{
                                 body: { padding: '6px 0 6px 16px' }

+ 225 - 0
src/pages/weComTask/page/businessPlan/create/components/friends/content.tsx

@@ -0,0 +1,225 @@
+import NewSteps from '@/pages/weComTask/components/newSteps';
+import { App, Button, Card, Form, Select } from 'antd';
+import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
+import '../../global.less';
+import { welcomeContentData } from '../../const';
+import { PlusOutlined, MinusOutlined } from '@ant-design/icons'
+import MaterialNoTextMould from '../massSending/materialNoTextMould';
+
+
+/**
+ * 群发内容
+ * @param param0 
+ * @returns 
+ */
+const Content = forwardRef(({ massSendingStrategy, value, onChange }: TASK_CREATE.ContentProps, ref: React.ForwardedRef<{ handleOk: (type: string) => void }>) => {
+
+    /****************************************/
+    const { message } = App.useApp()
+    const ref1 = useRef<HTMLDivElement>(null)
+    const [form] = Form.useForm();
+
+    const [stepsList, setStepsList] = useState<any>([])
+    /****************************************/
+
+    useImperativeHandle(ref, () => ({
+        handleOk(type) {
+            handleOk(type)
+        }
+    }));
+
+    // 回填
+    useEffect(() => {
+        if (!massSendingStrategy?.strategySettings) {
+            message.error('请先设置群发策略')
+            return
+        }
+
+        if (value && Object.keys(value).length) {
+            filedUpdateChange(value)
+            form.setFieldsValue(value)
+        } else {
+            const data = {
+                massSendingContentDTO: massSendingStrategy.strategySettings.map(item => {
+                    return {
+                        sendContentDto: item.sendData.map(() => ({ contentDTO: [undefined], sendMode: undefined }))
+                    }
+                })
+            }
+            filedUpdateChange(data)
+            form.setFieldsValue(data)
+        }
+    }, [value, massSendingStrategy])
+
+    const handleOk = (type: string) => {
+        form.validateFields().then((values) => {
+            console.log(values)
+            onChange(values, type)
+        }).catch(() => {
+            form.submit()
+        });
+    };
+
+    const filedUpdateChange = ({ massSendingContentDTO }: { massSendingContentDTO: { sendContentDto: any }[] }) => {
+        const stepsData = massSendingContentDTO.map((item, index) => {
+
+            const children = item.sendContentDto.map((ci, c_index) => {
+
+                const content = ci?.contentDTO?.map((i, i_index) => {
+                    return { title: `内容${i_index + 1}`, checked: (i?.attachmentList?.length || i?.text?.content), id: 'clientId' + '_' + index + '_' + c_index + 'contentDTO' }
+                })
+
+                const contentChildren = [
+                    { title: '发送模式', checked: ci?.sendMode || ci?.sendMode === 0, id: 'clientId' + '_' + index + '_' + c_index + 'sendMode' },
+                    ...content
+                ]
+
+                return {
+                    title: `发送对象 ${c_index + 1}`,
+                    id: 'clientId' + '_' + index + '_' + c_index,
+                    children: contentChildren,
+                    checked: (ci?.sendMode || ci?.sendMode === 0) && contentChildren?.every(item => item.checked)
+                }
+            })
+
+            return {
+                title: '策略' + (index + 1),
+                id: 'clientId' + '_' + index,
+                children: [
+                    ...children,
+                    { title: '完成', checked: children?.every(item => item.checked) }
+                ],
+                checked: children?.every(item => item.checked)
+            }
+        })
+
+        setStepsList([
+            ...stepsData,
+            { title: '完成', checked: stepsData?.every(item => item.checked) }
+        ])
+    }
+
+    return <>
+        <div className={`body_steps`}>
+            <NewSteps
+                items={stepsList}
+                onChange={(e) => {
+                    if (e?.id)
+                        ref1.current?.querySelector('#' + e?.id)?.scrollIntoView({ behavior: 'smooth' })
+                }}
+            />
+        </div>
+        <div className={`body_content`} ref={ref1}>
+            <Form
+                form={form}
+                name="newContent"
+                labelAlign='left'
+                labelCol={{ span: 5 }}
+                colon={false}
+                scrollToFirstError={{
+                    behavior: 'smooth',
+                    block: 'center'
+                }}
+                onFinishFailed={({ errorFields }) => {
+                    message.error(errorFields?.[0]?.errors?.[0])
+                }}
+                onFinish={handleOk}
+                initialValues={{ massSendingContentDTO: [undefined] }}
+                onFieldsChange={() => {
+                    console.log(form.getFieldsValue())
+                    filedUpdateChange(form.getFieldsValue())
+                }}
+                preserve={true}
+            >
+                <Form.List name='massSendingContentDTO'>
+                    {(fields) => (
+                        <>
+                            {fields.map(({ key, name, ...restField }, index) => {
+                                return <Card key={index} title={<strong>策略 {index + 1}</strong>} style={{ background: '#fff', marginBottom: 10 }} id={'clientId' + '_' + index}>
+                                    <Form.List {...restField} name={[name, 'sendContentDto']}>
+                                        {(fields) => (
+                                            <>
+                                                {fields.map(({ key, name, ...restField }, i) => {
+                                                    return <Card
+                                                        key={i}
+                                                        title={<strong>发送对象{i + 1} 内容配置</strong>}
+                                                        style={{ background: '#fff', marginBottom: 10 }}
+                                                        id={'clientId' + '_' + index + '_' + i}
+                                                    >
+                                                        <div id={'clientId' + '_' + index + '_' + i + 'sendMode'}>
+                                                            <Form.Item
+                                                                {...restField}
+                                                                label={<strong>内容组发送模式</strong>}
+                                                                name={[name, 'sendMode']}
+                                                                rules={[{ required: true, message: '请选择内容组发送模式!' }]}
+                                                            >
+                                                                <Select
+                                                                    showSearch
+                                                                    style={{ width: 358 }}
+                                                                    allowClear
+                                                                    placeholder="请选择内容组发送模式"
+                                                                    filterOption={(input, option) =>
+                                                                        ((option?.label ?? '') as string).toLowerCase().includes(input.toLowerCase())
+                                                                    }
+                                                                    options={welcomeContentData}
+                                                                />
+                                                            </Form.Item>
+                                                        </div>
+                                                        <div id={'clientId' + '_' + index + '_' + i + 'contentDTO'}>
+                                                            <Form.List {...restField} name={[name, 'contentDTO']} >
+                                                                {(fields, { add, remove }) => {
+                                                                    return <>
+                                                                        {fields.map(({ key, name, ...restField }, index) => {
+                                                                            return <div key={index}>
+                                                                                <h3 style={{ display: 'flex', justifyContent: 'space-between', margin: 0 }}>内容{index + 1}
+                                                                                    {fields?.length > 1 && <Button
+                                                                                        type="dashed"
+                                                                                        danger
+                                                                                        onClick={() => remove(index)}
+                                                                                        icon={<MinusOutlined />}
+                                                                                        size='small'
+                                                                                    >
+                                                                                        移除内容
+                                                                                    </Button>}
+                                                                                </h3>
+                                                                                <Form.Item
+                                                                                    {...restField}
+                                                                                    name={name}
+                                                                                    rules={[{
+                                                                                        validator: (_, value) => {
+                                                                                            if ((value && !(value?.text?.content || value?.attachmentList?.length)) || !value) {
+                                                                                                return Promise.reject('请填写内容或上传附件');
+                                                                                            }
+                                                                                            return Promise.resolve();
+                                                                                        }
+                                                                                    }]}
+                                                                                >
+                                                                                    <MaterialNoTextMould />
+                                                                                </Form.Item>
+                                                                            </div>
+                                                                        })}
+                                                                        <Form.Item noStyle>
+                                                                            <Button type="dashed" onClick={() => add()} style={{ width: '100%' }} icon={<PlusOutlined />}>
+                                                                                新增内容
+                                                                            </Button>
+                                                                        </Form.Item>
+                                                                    </>
+                                                                }}
+                                                            </Form.List>
+                                                        </div>
+                                                    </Card>
+                                                })}
+                                            </>
+                                        )}
+                                    </Form.List>
+                                </Card>
+                            })}
+                        </>
+                    )}
+                </Form.List>
+            </Form>
+        </div>
+    </>
+});
+
+export default React.memo(Content);

+ 159 - 0
src/pages/weComTask/page/businessPlan/create/components/friends/index.tsx

@@ -0,0 +1,159 @@
+import React, { useContext, useState } from 'react';
+import style from '../../index.less';
+import { App, Button, Empty, Space, Upload } from 'antd';
+import { DispatchTaskCreate } from '../..';
+import dayjs from 'dayjs';
+import '../../global.less'
+import useNewToken from '@/Hook/useNewToken';
+import { getGroupData, headerJsMustStyle, headerJsStyle, TIME_TYPE, welcomeContentData } from '../../const';
+import ExcelJS from 'exceljs';
+import FilterUserText from '@/pages/weComTask/components/filterUser/filterUserText';
+import { RcFile } from 'antd/es/upload';
+import { groupBy, readFileAsBuffer } from '@/utils/utils';
+import { saveAs } from 'file-saver';
+
+const Friends: React.FC = () => {
+
+    /***************************************************/
+    const { token } = useNewToken()
+    const { message } = App.useApp()
+    const { setSettings, settings, bookPlatForm, bookList, onPreviewReset } = useContext(DispatchTaskCreate)!;
+
+    const [newVisible, setNewVisible] = React.useState(false);
+    const [createType, setCreateType] = useState<'STRATEGY' | 'CONTENT'>()
+    const [downloadLoading, setDownloadLoading] = useState<boolean>(false)
+    /***************************************************/
+
+    return <>
+        <div className={`${style.settingsBody_content_row}`}>
+            <div className={`${style.settingsBody_content_col}`}>
+                <div className={style.title}>
+                    <span>朋友圈</span>
+                </div>
+                <div className={style.detail}>
+                    <div className={style.detail_title}>朋友圈策略配置</div>
+                    <div className={style.detail_body}>
+                        {/* {settings?.massSendingStrategy && Object.keys(settings?.massSendingStrategy).length > 0 ? <>
+                            <PreviewMassSendingStrategy massSendingStrategy={settings?.massSendingStrategy} />
+                        </> : <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); setCreateType('STRATEGY') }}>编辑</Button>
+                </div>
+            </div>
+            <div className={`${style.settingsBody_content_col}`}>
+                <div className={style.title}>
+                    <span></span>
+                    {/* {(settings?.massSendingStrategy && Object.keys(settings?.massSendingStrategy).length > 0) && <Space>
+                        {settings?.massSendingContent?.massSendingContentDTO?.some(item => item?.sendContentDto?.some(si => si?.contentDTO?.some(i => i?.attachmentList?.some(a => ['TASK_CONTENT_LINK', 'TASK_STATUS_MINIPROGRAM'].includes(a?.msgType))))) && <>
+                            <Button
+                                type="link"
+                                style={{ padding: 0, fontSize: 12 }}
+                                loading={downloadLoading}
+                                onClick={() => { exportExcel() }}
+                            >下载</Button>
+                            <Upload
+                                accept={'.xlsx'}
+                                action="#"
+                                showUploadList={false}
+                                customRequest={() => { }}
+                                beforeUpload={async (file: RcFile): Promise<any> => {
+                                    readExcelContent(file)
+                                    onPreviewReset()
+                                }}
+                            >
+                                <Button
+                                    type="link"
+                                    style={{ padding: 0, fontSize: 12 }}
+                                >{settings?.corpUsers?.every(item => item?.groupMsgContent?.length) ? 'Excel内容已上传,重新上传' : '上传Excel'}</Button>
+                            </Upload>
+                        </>}
+                        <Button
+                            type="link"
+                            danger
+                            style={{ padding: 0, fontSize: 12 }}
+                            onClick={() => {
+                                const corpUsers = settings?.corpUsers?.map(item => {
+                                    delete item?.groupMsgContent
+                                    return item
+                                })
+                                setSettings({
+                                    ...settings,
+                                    corpUsers,
+                                    massSendingStrategy: undefined,
+                                    massSendingContent: undefined
+                                })
+                                onPreviewReset()
+                            }}
+                        >清空</Button>
+                    </Space>} */}
+                </div>
+                <div className={style.detail}>
+                    <div className={style.detail_title}>朋友圈内容配置</div>
+                    <div className={style.detail_body} style={{ padding: 0 }}>
+                        {/* {settings?.massSendingContent && Object.keys(settings?.massSendingContent) ? <>
+                            <ShowContent
+                                strategySettings={settings?.massSendingStrategy?.strategySettings}
+                                massSendingContent={settings?.massSendingContent}
+                            />
+                        </> : <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={() => {
+                            if (!(settings?.massSendingStrategy && Object.keys(settings?.massSendingStrategy))) {
+                                message.error('请先配置策略')
+                                return
+                            }
+                            setNewVisible(true); setCreateType('CONTENT')
+                        }}
+                    >编辑</Button>
+                </div>
+            </div>
+        </div>
+
+        {/* 模板配置 */}
+        {/* {newVisible && <SettingsMassSending
+            visible={newVisible}
+            createType={createType}
+            value={{
+                massSendingContent: settings?.massSendingContent,
+                massSendingStrategy: settings?.massSendingStrategy
+            }}
+            onClose={() => {
+                setNewVisible(false)
+            }}
+            onChange={(values, type) => {
+                const corpUsers = settings?.corpUsers?.map(item => {
+                    delete item?.groupMsgContent
+                    return item
+                })
+                if (!values?.massSendingContent && settings?.corpUsers?.some(item => item?.groupMsgContent?.length)) {
+                    setSettings({
+                        ...settings,
+                        ...values,
+                        corpUsers
+                    })
+                } else {
+                    setSettings({
+                        ...settings,
+                        ...values,
+                        corpUsers
+                    })
+                }
+
+                if (type === 'OK') {
+                    setNewVisible(false)
+                }
+                onPreviewReset()
+            }}
+        />} */}
+    </>
+};
+
+export default Friends;

+ 79 - 0
src/pages/weComTask/page/businessPlan/create/components/friends/settingsFriends.tsx

@@ -0,0 +1,79 @@
+import { App, Button, Modal, Space } from 'antd';
+import React, { useRef, useState } from 'react';
+import '../../global.less';
+import Strategy from './strategy';
+import Content from './content';
+
+/**
+ * 群发配置
+ * @param param0 
+ * @returns 
+ */
+const SettingsFriends: React.FC<TASK_CREATE.MassSendingProps<any>> = ({ value: { massSendingContent, massSendingStrategy }, createType, onChange, visible, onClose }) => {
+
+    /****************************************/
+    const { message } = App.useApp()
+    const ref = useRef(null)
+    const ref1 = useRef(null)
+    const [type, setType] = useState<'STRATEGY' | 'CONTENT'>(createType)
+    /****************************************/
+
+    const handleOk = (p: string) => {
+        if (type === 'STRATEGY') {
+            ref?.current?.handleOk(p)
+        } else {
+            ref1?.current?.handleOk(p)
+        }
+    };
+
+    return <Modal
+        title={<strong>{type === 'STRATEGY' ? '群发模板配置' : '群发内容配置'}</strong>}
+        open={visible}
+        onCancel={onClose}
+        width={850}
+        className={`settingsModal`}
+        footer={<Space>
+            <Button onClick={onClose}>取消</Button>
+            {type === 'STRATEGY' && <>
+                <Button type="primary" onClick={() => handleOk('CREATE_CONTENT')}>编辑群发内容</Button>
+            </>}
+            <Button type="primary" onClick={() => handleOk('OK')}>确定</Button>
+        </Space>}
+    >
+        {/* 策略 */}
+        {type === 'STRATEGY' ? <Strategy
+            ref={ref}
+            value={massSendingStrategy}
+            onChange={(value, type) => {
+                console.log(value, type)
+                if (type === 'CREATE_CONTENT') {
+                    setType('CONTENT')
+                }
+                if (massSendingContent && (value?.strategySettings?.length !== massSendingContent?.massSendingContentDTO?.length || value?.strategySettings?.some((item, index) => massSendingContent?.massSendingContentDTO?.[index]?.sendContentDto?.length !== item?.sendData?.length))) {
+                    message.error('策略配置和内容配置不一致,内容已重置,请重新配置!')
+                    onChange({
+                        massSendingContent: undefined,
+                        massSendingStrategy: value
+                    }, type)
+                    return
+                }
+
+                onChange({
+                    massSendingStrategy: value
+                }, type)
+            }}
+        /> : <Content
+            ref={ref1}
+            massSendingStrategy={massSendingStrategy}
+            value={massSendingContent}
+            onChange={(value, type) => {
+                onChange({
+                    massSendingContent: value
+                }, type)
+            }}
+        />}
+
+    </Modal>;
+};
+
+export default React.memo(SettingsFriends);

+ 279 - 0
src/pages/weComTask/page/businessPlan/create/components/friends/strategy.tsx

@@ -0,0 +1,279 @@
+import NewSteps, { NewStepsItem } from '@/pages/weComTask/components/newSteps';
+import { App, Button, Card, Form, Input, Radio } from 'antd';
+import React, { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react';
+import '../../global.less';
+import { PlusOutlined, DeleteOutlined } from '@ant-design/icons'
+import SendTimeSet from '@/pages/weComTask/components/sendTimeSet';
+import style from '../massSending/index.less';
+import dayjs from 'dayjs';
+import FilterUser from '@/pages/weComTask/components/filterUser';
+
+/**
+ * 群发策略
+ * @param param0 
+ * @returns 
+ */
+const Strategy = forwardRef(({ value, onChange }: TASK_CREATE.StrategyProps, ref: React.ForwardedRef<{ handleOk: (type: string) => void }>) => {
+
+    /****************************************/
+    const { message } = App.useApp()
+    const ref1 = useRef<HTMLDivElement>(null)
+    const [form] = Form.useForm();
+    const strategySettings = Form.useWatch('strategySettings', form);
+
+    const [stepsList, setStepsList] = useState<NewStepsItem[]>([
+        { title: '群发配置', description: '群发类型、群发标题、适用产品', id: 'basicInfo' },
+        {
+            title: '群发策略', children: [{ title: `策略1`, id: 'strategy_0', children: [{ title: `发送时间`, id: `strategy_0_strategyName` }, { title: `发送对象1`, id: `strategy_0_sendData` }] }, { title: `完成` }]
+        },
+        { title: '完成' }
+    ])
+    /****************************************/
+
+    useImperativeHandle(ref, () => ({
+        handleOk(type) {
+            handleOk(type)
+        }
+    }));
+
+    // 回填
+    useEffect(() => {
+        if (value && Object.keys(value).length) {
+            const data = {
+                ...value, strategySettings: value?.strategySettings?.map(item => {
+                    const { sendTime, startTime, endTime, sendDay, timeRepeatType } = item
+                    if (timeRepeatType === 'TIME_TYPE_SINGLE_PLACE') {
+                        return {
+                            ...item,
+                            timeRepeatType,
+                            sendDay: sendDay ? dayjs(sendDay + ' ' + sendTime) : undefined
+                        }
+                    }
+                    return {
+                        ...item,
+                        timeRepeatType,
+                        sendTime: sendTime ? dayjs('2025-04-25 ' + sendTime) : undefined,
+                        startTime: startTime ? dayjs(startTime) : undefined,
+                        endTime: endTime ? dayjs(endTime) : undefined,
+                        sendDay: sendDay ? dayjs(sendDay) : undefined
+                    }
+                })
+            }
+            filedUpdateChange(data)
+            form.setFieldsValue(data)
+        }
+    }, [value])
+
+    const handleOk = (type: string) => {
+        form.validateFields().then((values) => {
+            const data = {
+                ...values,
+                strategySettings: values?.strategySettings?.map(item => {
+                    const { startTime, endTime, sendDay, sendTime, timeRepeatType, repeatArray, ...rest } = item
+                    const data = { ...rest, timeRepeatType }
+                    if (timeRepeatType === 'TIME_TYPE_SINGLE_PLACE') {
+                        // 定时发送
+                        data.sendDay = dayjs(sendDay).format('YYYY-MM-DD')
+                        data.sendTime = dayjs(sendDay).format('HH:mm:ss')
+                    } else if (timeRepeatType === 'TIME_TYPE_REPEAT_DAY') {
+                        // 每日循环
+                        data.startTime = dayjs(startTime).format('YYYY-MM-DD')
+                        if (endTime) {
+                            data.endTime = dayjs(endTime).format('YYYY-MM-DD')
+                        }
+                        data.sendTime = dayjs(sendTime).format('HH:mm:ss')
+                    } else if (timeRepeatType === 'TIME_TYPE_REPEAT_WEEK' || timeRepeatType === 'TIME_TYPE_REPEAT_MONTH') {
+                        // 每周循环、每月循环
+                        data.startTime = dayjs(startTime).format('YYYY-MM-DD')
+                        data.sendTime = dayjs(sendTime).format('HH:mm:ss')
+                        if (endTime) {
+                            data.endTime = dayjs(endTime).format('YYYY-MM-DD')
+                        }
+                        data.repeatArray = repeatArray
+                    }
+                    return data
+                })
+            }
+            onChange?.(data, type)
+        }).catch((err) => {
+            console.log('err', err)
+            form.submit()
+        });
+    };
+
+    const filedUpdateChange = ({ groupSendName, strategySettings }: any) => {
+        const isChecked = (content: NewStepsItem[]) => {
+            return content.every(item => {
+                if (item.children) {
+                    return isChecked(item.children)
+                }
+                return item.checked
+            })
+        }
+
+        const content = strategySettings?.map((item, index) => {
+            const { timeRepeatType, sendDay, startTime, sendTime, repeatArray } = item
+            const sendTimeChecked =
+                timeRepeatType === "TIME_TYPE_SINGLE_TIMELY" ||
+                (timeRepeatType === "TIME_TYPE_SINGLE_PLACE" && sendDay) ||
+                (timeRepeatType === "TIME_TYPE_REPEAT_DAY" && startTime && sendTime) ||
+                ((timeRepeatType === "TIME_TYPE_REPEAT_WEEK" || timeRepeatType === "TIME_TYPE_REPEAT_MONTH") && startTime && sendTime && repeatArray)
+
+            const children = [
+                {
+                    title: `发送时间`, checked: sendTimeChecked, id: `strategy_${index}_strategyName`
+                },
+                ...item.sendData.map((i, n) => {
+                    return { title: `发送对象${n + 1}`, description: '对象筛选,人群包', id: `strategy_${index}_${n}_sendData`, checked: i?.externalUserType ? i?.externalUserType === 'all' ? true : i?.externalUserFilter && Object.values(i.externalUserFilter).some(item => item) : false }
+                })
+            ]
+
+            return {
+                title: `策略${index + 1}`,
+                id: `strategy_${index}`,
+                children: children,
+                checked: isChecked(children)
+            }
+        })
+
+        const isChecked1 = !!groupSendName
+        const isChecked2 = isChecked(content)
+        const stepsData = [
+            { title: '群发配置', description: '群发标题', checked: isChecked1, id: 'basicInfo' },
+            {
+                title: '群发策略', checked: isChecked2, children: [...content, { title: `完成`, checked: isChecked2 }]
+            },
+            { title: '完成', checked: isChecked1 && isChecked2 }
+        ]
+        setStepsList(stepsData)
+    }
+
+    return <>
+        <div className={`body_steps`}>
+            <NewSteps
+                items={stepsList}
+                onChange={(e) => {
+                    if (e?.id)
+                        ref1.current?.querySelector('#' + e?.id)?.scrollIntoView({ behavior: 'smooth' })
+                }}
+            />
+        </div>
+        <div className={`body_content`} ref={ref1}>
+            <Form
+                form={form}
+                name="newMassSending"
+                labelAlign='left'
+                labelCol={{ span: 5 }}
+                colon={false}
+                scrollToFirstError={{
+                    behavior: 'smooth',
+                    block: 'center'
+                }}
+                onFinishFailed={({ errorFields }) => {
+                    message.error(errorFields?.[0]?.errors?.[0])
+                }}
+                initialValues={{
+                    taskType: 'novel',
+                    strategySettings: [{ sendData: [{ externalUserType: 'all' }] }],
+                }}
+                onFieldsChange={() => {
+                    filedUpdateChange(form.getFieldsValue())
+                }}
+                preserve={true}
+            >
+                <Card title={<strong>基础信息配置</strong>} style={{ background: '#fff', marginBottom: 10 }} hoverable id='basicInfo'>
+
+                    <Form.Item label={<strong>群发标题</strong>} name="groupSendName" rules={[{ required: true, message: '请输入标题!' }]}>
+                        <Input placeholder="请输入标题" style={{ width: 358 }} allowClear />
+                    </Form.Item>
+                </Card>
+
+                <Form.List name="strategySettings">
+                    {(fields, { add, remove }) => (
+                        <>
+                            {fields.map(({ key, name, ...restField }, index) => {
+                                const timeRepeatType = strategySettings?.[index]?.timeRepeatType
+                                const sendData = strategySettings?.[index]?.sendData
+
+                                return <Card
+                                    key={key}
+                                    title={<strong>策略{index + 1}配置</strong>}
+                                    style={{ background: '#fff', marginBottom: 10 }}
+                                    hoverable
+                                    id={`strategy_${index}`}
+                                    extra={strategySettings?.length > 1 ? <Button icon={<DeleteOutlined />} type='link' style={{ color: 'red' }} onClick={() => remove(name)}></Button> : null}
+                                >
+                                    <div className={style.strategy_item} id={`strategy_${index}_strategyName`}>
+                                        <Form.Item
+                                            {...restField}
+                                            label={<strong>策略名称</strong>}
+                                            name={[name, 'strategyName']}
+                                            rules={[{ required: false, message: '请输入策略名称!' }]}
+                                        >
+                                            <Input placeholder="请输入标题" style={{ width: 358 }} allowClear />
+                                        </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
+                                                                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={'USER_GROUP'} />
+                                                                        </Form.Item>
+                                                                    </div>}
+                                                                </div>
+                                                            </Form.Item>
+                                                        </Card>
+                                                    })}
+                                                    <Form.Item>
+                                                        <Button type="dashed" onClick={() => add({ externalUserType: 'all' })} block icon={<PlusOutlined />}>
+                                                            新增发送对象
+                                                        </Button>
+                                                    </Form.Item>
+                                                </>
+                                            )}
+                                        </Form.List>
+                                    </div>
+                                </Card>
+                            })}
+                            <Form.Item>
+                                <Button type="primary" onClick={() => add({ sendData: [{ externalUserType: 'all' }] })} block icon={<PlusOutlined />}>
+                                    新增策略组
+                                </Button>
+                            </Form.Item>
+                        </>
+                    )}
+                </Form.List>
+            </Form>
+        </div>
+    </>
+});
+
+export default React.memo(Strategy);

+ 12 - 2
src/pages/weComTask/page/businessPlan/create/index.tsx

@@ -17,6 +17,7 @@ import Welcome from './components/welcome';
 import UserInherit from './components/userInherit';
 import HighMassSending from './components/highMassSending';
 import { toJS } from 'mobx';
+import Friends from './components/friends';
 
 export const DispatchTaskCreate = React.createContext<TASK_CREATE.DispatchTaskCreate | null>(null);
 /**
@@ -113,13 +114,14 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                         platform: settings?.platform,
                         templateProductId: settings?.templateProductId,
                         id: i * row.length + (index + 1),
-                        rowSpan: index === 0 ? corpUsersLength : 0
+                        rowSpan: index === 0 ? row.length : 0
                     })
                     return true
                 })
             })) {
                 return
             }
+            console.log('welcome--->', welcome)
             newPreviewData.welcome = welcome
         }
 
@@ -546,7 +548,12 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                             value={settings?.corpUsers}
                             onChange={(corpUsers) => {
                                 console.log(corpUsers)
-                                setSettings({ ...settings, corpUsers })
+                                setSettings({
+                                    ...settings, corpUsers: corpUsers.map(item => {
+                                        const { corpUserId, name, corpName, corpId } = item
+                                        return { corpUserId, name, corpName, corpId }
+                                    })
+                                })
                                 onPreviewReset()
                             }}
                         />
@@ -650,6 +657,8 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                                 <MassSending />
                                 {/* 高级群发 */}
                                 <HighMassSending />
+                                {/* 朋友圈 */}
+                                {/* <Friends /> */}
                                 {/* 客户继承 */}
                                 <UserInherit />
                             </div>
@@ -705,6 +714,7 @@ const Create: React.FC<{ weComTaskStore: { data: { bookList: TASK_CREATE.BookLis
                                 rowKey={'id'}
                                 bordered={true}
                                 scroll={{ y: 550 }}
+                                pagination={false}
                             />
                         </> : key === 'highMassSending' ? <>
                             <Table

+ 10 - 0
src/pages/weComTask/page/businessPlan/create/typings.d.ts

@@ -45,6 +45,14 @@ declare namespace TASK_CREATE {
         onChange?: (value?: { [x: string]: any }, type?: string) => void;
         createType?: 'STRATEGY' | 'CONTENT'
     }
+    interface FriendsProps<T> extends DefaultProps, DefaultChangeProps<T> {
+        value?: {
+            friendsStrategy?: { [x: string]: any };
+            friendsContent?: { friendsContentDTO: any };
+        };
+        onChange?: (value?: { [x: string]: any }, type?: string) => void;
+        createType?: 'STRATEGY' | 'CONTENT'
+    }
     interface UserInheritProps<T> extends DefaultProps, DefaultChangeProps<T> {
         value?: { [x: string]: any };
     }
@@ -72,6 +80,8 @@ declare namespace TASK_CREATE {
         highMassSendingStrategy?: { [x: string]: any };
         highMassSendingContent?: { massSendingContentDTO: any };
         userInherit?: { [x: string]: any };
+        friendsStrategy?: { [x: string]: any };
+        friendsContent?: { friendsContentDTO: any };
     }
     // 群发策略
     interface StrategyProps {

+ 4 - 0
src/pages/weComTask/page/corpUserManage/selectCorpUser.tsx

@@ -147,6 +147,7 @@ const SelectCorpUser: React.FC<Props> = ({ value = [], onChange, placeholder })
                         pageSize: getCorpUser?.data?.data?.size || 20,
                         total: getCorpUser?.data?.data?.total,
                         showTotal: (total) => `共 ${total} 条数据`,
+                        showSizeChanger: true
                     }}
                     rowSelection={{
                         type: 'checkbox',
@@ -167,6 +168,9 @@ const SelectCorpUser: React.FC<Props> = ({ value = [], onChange, placeholder })
                             }
                         }
                     }}
+                    onChange={(pagination) => {
+                        setQueryForm({ ...queryForm, pageNum: pagination.current || 1, pageSize: pagination.pageSize || 20 })
+                    }}
                 />
             </div>
             <div className='selectCorpUserBody_footer'>