|
@@ -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);
|