wjx 9 months ago
parent
commit
69caef14c6

+ 19 - 8
src/pages/launchSystemV3/adqv3/ad/index.tsx

@@ -1,5 +1,5 @@
 import { useAjax } from "@/Hook/useAjax";
 import { useAjax } from "@/Hook/useAjax";
-import { DownOutlined, PauseCircleOutlined, PlayCircleOutlined, PlusOutlined, QuestionCircleOutlined, TransactionOutlined } from "@ant-design/icons";
+import { DeleteOutlined, DownOutlined, PauseCircleOutlined, PlayCircleOutlined, PlusOutlined, QuestionCircleOutlined, TransactionOutlined } from "@ant-design/icons";
 import { Button, Checkbox, Col, Dropdown, Input, Menu, Modal, Row, Select, Space, Tooltip, Typography, message } from "antd"
 import { Button, Checkbox, Col, Dropdown, Input, Menu, Modal, Row, Select, Space, Tooltip, Typography, message } from "antd"
 import React, { useCallback, useEffect, useState } from "react"
 import React, { useCallback, useEffect, useState } from "react"
 import { ADGROUP_STATUS } from "../const";
 import { ADGROUP_STATUS } from "../const";
@@ -28,7 +28,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
     const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
     const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
     const [handleType, setHandleType] = useState<number>(1)
     const [handleType, setHandleType] = useState<number>(1)
     const [czjlShow, setCzjlShow] = useState(false)
     const [czjlShow, setCzjlShow] = useState(false)
-    const [updateData, setUpdateDate] = useState<{ visible: boolean, type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' }>({ visible: false, type: '修改出价' })
+    const [updateData, setUpdateDate] = useState<{ visible: boolean, type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI' }>({ visible: false, type: '修改出价' })
 
 
     const syncBatch = useAjax((params) => syncBatchApi(params))
     const syncBatch = useAjax((params) => syncBatchApi(params))
     const modifyStatusBatch = useAjax((params) => modifyStatusBatchApi(params))
     const modifyStatusBatch = useAjax((params) => modifyStatusBatchApi(params))
@@ -53,7 +53,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                 res ? message.success('同步成功!') : message.error('同步失败!')
                 res ? message.success('同步成功!') : message.error('同步失败!')
             })
             })
         } else {
         } else {
-            message.error('请勾选')
+            message.error('请勾选需要同步的广告')
         }
         }
 
 
     }, [getAdqV3AdList, selectedRows])
     }, [getAdqV3AdList, selectedRows])
@@ -247,7 +247,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                             setSelectedRows([])
                             setSelectedRows([])
                         }}
                         }}
                         value={handleType}
                         value={handleType}
-                        options={[{ label: '广告操作', value: 1 }, { label: '创意操作', value: 2 }]}
+                        options={[{ label: '广告操作', value: 1 }, { label: '创意操作', value: 2 }, { label: '修改深度优化', value: 3 }]}
                     /></Col>
                     /></Col>
                     <Col>
                     <Col>
                         <Button type='dashed' onClick={() => { setCzjlShow(true) }}>操作记录</Button>
                         <Button type='dashed' onClick={() => { setCzjlShow(true) }}>操作记录</Button>
@@ -255,8 +255,10 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                     {handleType === 1 ? <>
                     {handleType === 1 ? <>
                         <Col><Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={modifyStatusBatch.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(true)}>启动</Button></Col>
                         <Col><Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={modifyStatusBatch.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(true)}>启动</Button></Col>
                         <Col><Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={modifyStatusBatch.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(false)}>暂停</Button></Col>
                         <Col><Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={modifyStatusBatch.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(false)}>暂停</Button></Col>
-                        <Col><Button type='primary' icon={<TransactionOutlined />} disabled={selectedRows.length === 0} onClick={() => setUpdate({ visible: true })}>修改出价</Button></Col>
-                        {/* <Col><Dropdown
+                        <Col><Button type='primary' danger icon={<DeleteOutlined />} disabled={selectedRows.length === 0} onClick={() => {
+                            setUpdateDate({ visible: true, type: '删除' })
+                        }}>删除</Button></Col>
+                        <Col><Dropdown
                             overlay={<Menu>
                             overlay={<Menu>
                                 <Menu.Item disabled={selectedRows.length === 0} onClick={() => {
                                 <Menu.Item disabled={selectedRows.length === 0} onClick={() => {
                                     setUpdateDate({ visible: true, type: '修改出价' })
                                     setUpdateDate({ visible: true, type: '修改出价' })
@@ -280,7 +282,7 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                     <DownOutlined />
                                     <DownOutlined />
                                 </Space>
                                 </Space>
                             </Button>
                             </Button>
-                        </Dropdown></Col> */}
+                        </Dropdown></Col>
                     </> : handleType === 2 ? <>
                     </> : handleType === 2 ? <>
                         <Col><UserTactics
                         <Col><UserTactics
                             type="updateAd"
                             type="updateAd"
@@ -309,11 +311,16 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                                 </div>}
                                 </div>}
                             </Space>
                             </Space>
                         </Col>
                         </Col>
+                    </> : handleType === 3 ? <>
+                        <Col><Button type='primary' disabled={selectedRows.length === 0} onClick={() => {
+                            setUpdateDate({ visible: true, type: '深度优化ROI' })
+                        }}>修改深度优化ROI</Button></Col>
                     </> : null}
                     </> : null}
                 </Row>
                 </Row>
             </Space>}
             </Space>}
             rowSelection={{
             rowSelection={{
                 selectedRowKeys: selectedRows.map(item => item.adgroupId.toString()),
                 selectedRowKeys: selectedRows.map(item => item.adgroupId.toString()),
+                hideSelectAll: handleType === 3,
                 getCheckboxProps: (record: any) => {
                 getCheckboxProps: (record: any) => {
                     if (handleType === 2 && selectedRows?.length > 0) {
                     if (handleType === 2 && selectedRows?.length > 0) {
                         const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectedRows[0]
                         const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectedRows[0]
@@ -329,7 +336,8 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
                         }
                         }
                     } else {
                     } else {
                         return {
                         return {
-                            disabled: record.isDeleted
+                            disabled: handleType === 3 ? record.isDeleted || !(record?.deepConversionSpec?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_PURCHASE_ROAS')
+                                : record.isDeleted
                         }
                         }
                     }
                     }
 
 
@@ -440,6 +448,9 @@ const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
             onChange={() => {
             onChange={() => {
                 setUpdateDate({ visible: false, type: '修改出价' })
                 setUpdateDate({ visible: false, type: '修改出价' })
                 getAdqV3AdList.refresh()
                 getAdqV3AdList.refresh()
+                if (updateData.type === '删除') {
+                    setSelectedRows([])
+                }
             }}
             }}
         />}
         />}
     </div>
     </div>

+ 3 - 2
src/pages/launchSystemV3/adqv3/ad/tableConfig.tsx

@@ -121,6 +121,7 @@ function tableConfig(onChange: () => void, creativeHandle?: (id: number) => void
             dataIndex: 'bidAmount',
             dataIndex: 'bidAmount',
             key: 'bidAmount',
             key: 'bidAmount',
             width: 140,
             width: 140,
+            align: 'right',
             ellipsis: true,
             ellipsis: true,
             render: (a: string, b: { bidMode: string, optimizationGoal: string }) => {
             render: (a: string, b: { bidMode: string, optimizationGoal: string }) => {
                 return `${BID_MODE_ENUM[b?.bidMode]} ${a}元/${b?.bidMode === 'BID_MODE_CPM' ? '千次曝光' : b?.bidMode === 'BID_MODE_CPC' ? '点击' : OPTIMIZATIONGOAL_ENUM[b?.optimizationGoal]}`
                 return `${BID_MODE_ENUM[b?.bidMode]} ${a}元/${b?.bidMode === 'BID_MODE_CPM' ? '千次曝光' : b?.bidMode === 'BID_MODE_CPC' ? '点击' : OPTIMIZATIONGOAL_ENUM[b?.optimizationGoal]}`
@@ -132,8 +133,8 @@ function tableConfig(onChange: () => void, creativeHandle?: (id: number) => void
             key: 'deepConversionBehaviorBid',
             key: 'deepConversionBehaviorBid',
             width: 140,
             width: 140,
             align: 'center',
             align: 'center',
-            render: (a: string) => {
-                return a || '--'
+            render: (a: string, b: any) => {
+                return b?.deepConversionSpec?.deepConversionWorthSpec?.expectedRoi || '--'
             }
             }
         },
         },
         {
         {

+ 89 - 14
src/pages/launchSystemV3/adqv3/ad/updateAd3.tsx

@@ -1,16 +1,19 @@
 import { useAjax } from "@/Hook/useAjax"
 import { useAjax } from "@/Hook/useAjax"
-import { modifyAdTimeBatchApi, modifyAmountBatchApi, modifyDailyBudgetBatchApi, updateBatchAdgroupInfoApi } from "@/services/launchAdq/adqv3"
-import { Button, Card, DatePicker, Form, Input, InputNumber, Modal, Radio, Space, Table, message } from "antd"
-import React, { useState } from "react"
+import { delBatchApi, modifyAdTimeBatchApi, modifyAmountBatchApi, modifyDailyBudgetBatchApi, updateBatchAdgroupInfoApi } from "@/services/launchAdq/adqv3"
+import { Button, Card, DatePicker, Form, Input, InputNumber, Modal, Radio, Select, Space, Table, message } from "antd"
+import React, { useEffect, useState } from "react"
 import '../../tencentAdPutIn/index.less'
 import '../../tencentAdPutIn/index.less'
 import { RangePickerProps } from "antd/lib/date-picker"
 import { RangePickerProps } from "antd/lib/date-picker"
 import moment from "moment"
 import moment from "moment"
 import style from '../../tencentAdPutIn/create/index.less'
 import style from '../../tencentAdPutIn/create/index.less'
 import TimeInSelect from "@/pages/launchSystemNew/components/timeInSelect"
 import TimeInSelect from "@/pages/launchSystemNew/components/timeInSelect"
 import { getTimeSeriesList } from "@/pages/launchSystemNew/adq/ad/const"
 import { getTimeSeriesList } from "@/pages/launchSystemNew/adq/ad/const"
+import { txtLength } from "@/utils/utils"
+import InputName from "@/components/InputName"
+import New1Radio from "../../components/New1Radio"
 
 
 interface Props {
 interface Props {
-    type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间'
+    type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI'
     updateData: any[],
     updateData: any[],
     visible?: boolean,
     visible?: boolean,
     onClose?: () => void
     onClose?: () => void
@@ -30,25 +33,41 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
     const modifyAdTimeBatch = useAjax((params) => modifyAdTimeBatchApi(params)) // 时间
     const modifyAdTimeBatch = useAjax((params) => modifyAdTimeBatchApi(params)) // 时间
     const updateBatchAdgroupInfo = useAjax((params) => updateBatchAdgroupInfoApi(params)) // 名称
     const updateBatchAdgroupInfo = useAjax((params) => updateBatchAdgroupInfoApi(params)) // 名称
     const modifyDailyBudgetBatch = useAjax((params) => modifyDailyBudgetBatchApi(params)) // 日限额
     const modifyDailyBudgetBatch = useAjax((params) => modifyDailyBudgetBatchApi(params)) // 日限额
+    const delBatch = useAjax((params) => delBatchApi(params)) // 删除
     /****************************************/
     /****************************************/
 
 
+    useEffect(() => {
+        if (type === '删除') {
+            form.setFieldsValue({ delAd: updateData.map(item => item.adgroupName) })
+        } else if (type === '深度优化ROI') {
+            form.setFieldsValue({ deepConversionSpec: updateData?.[0]?.deepConversionSpec })
+        }
+    }, [type, updateData])
+
     const handleOk = (values: any) => {
     const handleOk = (values: any) => {
         console.log(values)
         console.log(values)
         let accountAdgroupMaps = [...new Set(updateData?.map(item => item.accountId + ',' + item.adgroupId))]
         let accountAdgroupMaps = [...new Set(updateData?.map(item => item.accountId + ',' + item.adgroupId))]
         switch (type) {
         switch (type) {
             case '修改出价':
             case '修改出价':
                 modifyAmountBatch.run({ accountAdgroupMaps, ...values }).then(res => {
                 modifyAmountBatch.run({ accountAdgroupMaps, ...values }).then(res => {
-                    if (res) {
+                    if (res?.failIdList?.length === 0) {
                         message.success(`修改操作完成!`)
                         message.success(`修改操作完成!`)
                         onChange?.()
                         onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
                     }
                     }
                 })
                 })
                 break
                 break
             case '修改名称':
             case '修改名称':
+            case '深度优化ROI':
                 updateBatchAdgroupInfo.run({ accountAdgroupMaps, ...values }).then(res => {
                 updateBatchAdgroupInfo.run({ accountAdgroupMaps, ...values }).then(res => {
-                    if (res) {
+                    if (res?.failIdList?.length === 0) {
                         message.success(`修改操作完成!`)
                         message.success(`修改操作完成!`)
                         onChange?.()
                         onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
                     }
                     }
                 })
                 })
                 break
                 break
@@ -57,14 +76,13 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                 params.beginDate = moment(params.date[0]).format('YYYY-MM-DD')
                 params.beginDate = moment(params.date[0]).format('YYYY-MM-DD')
                 params.endDate = moment(params.date[1]).format('YYYY-MM-DD')
                 params.endDate = moment(params.date[1]).format('YYYY-MM-DD')
                 if (params.timeSeriesType === '0') {
                 if (params.timeSeriesType === '0') {
-                    params.timeSeries = Array(336).fill(1).join('');
+                    // params.timeSeries = Array(336).fill(1).join('');
                 } else {
                 } else {
                     params.timeSeries = params.timeSeries.join('');
                     params.timeSeries = params.timeSeries.join('');
                 }
                 }
                 delete params.timeSeriesType
                 delete params.timeSeriesType
                 delete params.date
                 delete params.date
                 modifyAdTimeBatch.run(params).then(res => {
                 modifyAdTimeBatch.run(params).then(res => {
-                    console.log('2222->', res)
                     if (res?.failIdList?.length === 0) {
                     if (res?.failIdList?.length === 0) {
                         message.success(`修改操作完成!`)
                         message.success(`修改操作完成!`)
                         onChange?.()
                         onChange?.()
@@ -76,7 +94,6 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                 break
                 break
             case '修改日限额':
             case '修改日限额':
                 modifyDailyBudgetBatch.run({ accountAdgroupMaps, ...values }).then(res => {
                 modifyDailyBudgetBatch.run({ accountAdgroupMaps, ...values }).then(res => {
-                    console.log('2222->', res)
                     if (res?.failIdList?.length === 0) {
                     if (res?.failIdList?.length === 0) {
                         message.success(`修改操作完成!`)
                         message.success(`修改操作完成!`)
                         onChange?.()
                         onChange?.()
@@ -86,6 +103,17 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                     }
                     }
                 })
                 })
                 break
                 break
+            case '删除':
+                delBatch.run({ accountAdgroupMaps }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`删除广告操作完成!`)
+                        onChange?.()
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
         }
         }
 
 
     }
     }
@@ -104,7 +132,7 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
             onCancel={onClose}
             onCancel={onClose}
             bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
             bodyStyle={{ padding: '0 0 40px', position: 'relative', borderRadius: '0 0 8px 8px' }}
             className='modalResetCss'
             className='modalResetCss'
-            width={900}
+            width={type === '修改投放时间' ? 900 : type === '深度优化ROI' ? 800 : 600}
         >
         >
             <Form
             <Form
                 form={form}
                 form={form}
@@ -121,7 +149,7 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                 initialValues={{ timeSeriesType: '0', timeSeries: getTimeSeriesList() }}
                 initialValues={{ timeSeriesType: '0', timeSeries: getTimeSeriesList() }}
             >
             >
                 <Card
                 <Card
-                    title={<strong style={{ fontSize: 14 }}>修改设置</strong>}
+                    title={<strong style={{ fontSize: 14 }}>{type === '删除' ? '确认删除?' : '修改设置'}</strong>}
                     className="cardResetCss"
                     className="cardResetCss"
                 >
                 >
                     {type === '修改出价' ? <Form.Item
                     {type === '修改出价' ? <Form.Item
@@ -135,11 +163,29 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                     </Form.Item> : type === '修改名称' ? <Form.Item
                     </Form.Item> : type === '修改名称' ? <Form.Item
                         label={<strong>广告名称</strong>}
                         label={<strong>广告名称</strong>}
                         name='adgroupName'
                         name='adgroupName'
+                        // tooltip="下标、日期时分秒、广告账户创建时默认自带"
                         rules={[
                         rules={[
-                            { required: true, message: '请输入' }
+                            { required: true, message: '请输入广告名称!' },
+                            {
+                                required: true, message: '广告名称不能包含特殊字符:< > & ‘ ” / 以及TAB、换行、回车键,请修改', validator(_, value) {
+                                    let reg = /[&‘’“”/\n\t\f]/ig
+                                    if (value && reg.test(value)) {
+                                        return Promise.reject()
+                                    }
+                                    return Promise.resolve()
+                                }
+                            },
+                            {
+                                required: true, message: '请确保广告名称长度不超过60个字(1个汉字等于2个字符)', validator(_, value) {
+                                    if (value && txtLength(value) > 50) {
+                                        return Promise.reject()
+                                    }
+                                    return Promise.resolve()
+                                }
+                            }
                         ]}
                         ]}
                     >
                     >
-                        <Input placeholder="请输入广告名称" />
+                        <InputName placeholder='广告名称' style={{ width: 420 }} length={50} />
                     </Form.Item> : type === '修改日限额' ? <Form.Item
                     </Form.Item> : type === '修改日限额' ? <Form.Item
                         label={<strong>日限额</strong>}
                         label={<strong>日限额</strong>}
                         name='bidAmount'
                         name='bidAmount'
@@ -172,12 +218,41 @@ const UpdateAd3: React.FC<Props> = ({ visible, type, onClose, onChange, updateDa
                                 </div>
                                 </div>
                             </Card>
                             </Card>
                         </Form.Item>
                         </Form.Item>
+                    </> : type === '删除' ? <Form.Item label={<strong>广告名称</strong>} name='delAd' rules={[{ required: true, message: '请选择广告' }]}>
+                        <Input.TextArea disabled />
+                    </Form.Item> : type === '深度优化ROI' ? <>
+                        <Form.Item label={<strong>深度优化类型</strong>} name={['deepConversionSpec', 'deepConversionType']} rules={[{ required: true, message: '请选择深度优化类型' }]}>
+                            <New1Radio data={[{ label: '优化ROI', value: 'DEEP_CONVERSION_WORTH', disabled: true }]} />
+                        </Form.Item>
+                        <Form.Item label={<strong>深度优化目标</strong>} name={['deepConversionSpec', 'deepConversionWorthSpec', 'goal']} rules={[{ required: true, message: '请选择深度优化目标' }]}>
+                            <Select style={{ width: 480 }} placeholder='请选择'>
+                                <Select.Option value={'GOAL_1DAY_PURCHASE_ROAS'}>首日付费ROI</Select.Option>
+                            </Select>
+                        </Form.Item>
+                        <Form.Item
+                            label={<strong>期望ROI</strong>}
+                            name={['deepConversionSpec', 'deepConversionWorthSpec', 'expectedRoi']}
+                            rules={[
+                                { required: true, message: '请输入期望ROI' },
+                                { type: 'number', min: 0.001, max: 1000, message: '范围0.001~1000' },
+                                {
+                                    validator: (_: any, value: string) => {
+                                        if (!value || /^\d+(\.\d{0,3})?$/.test(value)) {
+                                            return Promise.resolve();
+                                        }
+                                        return Promise.reject(new Error('请输入最多三位小数'));
+                                    }
+                                }
+                            ]}
+                        >
+                            <InputNumber style={{ width: 480 }} placeholder={`期望ROI目标范围0.001~1000,输入0.05,表示ROI目标为5%`} />
+                        </Form.Item>
                     </> : null}
                     </> : null}
                 </Card>
                 </Card>
                 <Form.Item className="submit_pull">
                 <Form.Item className="submit_pull">
                     <Space>
                     <Space>
                         <Button onClick={onClose}>取消</Button>
                         <Button onClick={onClose}>取消</Button>
-                        <Button type="primary" htmlType="submit" className="modalResetCss" loading={modifyAmountBatch.loading || modifyAdTimeBatch.loading || updateBatchAdgroupInfo.loading || modifyDailyBudgetBatch.loading}>
+                        <Button type="primary" htmlType="submit" className="modalResetCss" loading={modifyAmountBatch.loading || modifyAdTimeBatch.loading || updateBatchAdgroupInfo.loading || modifyDailyBudgetBatch.loading || delBatch.loading}>
                             确定
                             确定
                         </Button>
                         </Button>
                     </Space>
                     </Space>

+ 200 - 48
src/pages/launchSystemV3/adqv3/creative/index.tsx

@@ -1,18 +1,21 @@
 import { useAjax } from "@/Hook/useAjax"
 import { useAjax } from "@/Hook/useAjax"
-import { getDynamicCreativeV3ListApi } from "@/services/launchAdq/adqv3"
-import { Badge, Button, Col, Form, Input, Row, Select, Space } from "antd"
+import { delBatchCreativeApi, getDynamicCreativeV3ListApi, syncBatchCreativeApi, updateBatchDynamicCreativesInfoApi } from "@/services/launchAdq/adqv3"
+import { Badge, Button, Col, Form, Input, Modal, Popconfirm, Row, Select, Space, Table, message } from "antd"
 import React, { useEffect, useState } from "react"
 import React, { useEffect, useState } from "react"
 import { txDynamicConfig } from "../config"
 import { txDynamicConfig } from "../config"
 import tableConfig from "./tableConfig"
 import tableConfig from "./tableConfig"
 import TableData from "@/pages/launchSystemNew/components/TableData"
 import TableData from "@/pages/launchSystemNew/components/TableData"
 import ReviewDetails from "./reviewDetails"
 import ReviewDetails from "./reviewDetails"
+import { DeleteOutlined, PauseCircleOutlined, PlayCircleOutlined } from "@ant-design/icons"
+import '../../tencentAdPutIn/index.less'
+import { MessageApi } from "antd/lib/message"
 
 
 /** 审核结果 */
 /** 审核结果 */
 export const AD_STATUS = {
 export const AD_STATUS = {
-	NORMAL: <Badge status="success" text="审核通过" />,
-	PENDING: <Badge status="default" text="审核中" />,
-	DENIED: <Badge status="error" text="有违规" />,
-	PARTIALLY_NORMAL: <Badge status="warning" text="部分审核通过" />,
+    NORMAL: <Badge status="success" text="审核通过" />,
+    PENDING: <Badge status="default" text="审核中" />,
+    DENIED: <Badge status="error" text="有违规" />,
+    PARTIALLY_NORMAL: <Badge status="warning" text="部分审核通过" />,
 }
 }
 
 
 const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, userId }) => {
 const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, userId }) => {
@@ -21,8 +24,14 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
     const [form] = Form.useForm();
     const [form] = Form.useForm();
     const [dynimicData, setDynamicData] = useState<any>({})
     const [dynimicData, setDynamicData] = useState<any>({})
     const [dynimicVisible, setDynamicVisible] = useState<boolean>(false)
     const [dynimicVisible, setDynamicVisible] = useState<boolean>(false)
+    const [selectedRows, setSelectedRows] = useState<any[]>([])
+    const [failIdList, setFailIdList] = useState<{ adgroupId: number, code: number, message: string, messageCn: string }[]>([])
+    const [failVisible, setFailVisible] = useState<boolean>(false)
 
 
     const getDynamicCreativeV3List = useAjax((params) => getDynamicCreativeV3ListApi(params), { formatResult: true })
     const getDynamicCreativeV3List = useAjax((params) => getDynamicCreativeV3ListApi(params), { formatResult: true })
+    const delBatchCreative = useAjax((params) => delBatchCreativeApi(params))
+    const updateBatchDynamicCreativesInfo = useAjax((params) => updateBatchDynamicCreativesInfoApi(params))
+    const syncBatchCreative = useAjax((params) => syncBatchCreativeApi(params))
     /*********************************/
     /*********************************/
 
 
     useEffect(() => {
     useEffect(() => {
@@ -47,15 +56,115 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
         setDynamicVisible(true)
         setDynamicVisible(true)
     }
     }
 
 
+    const dynamicHandle = (type: '删除' | '启动' | '暂停', data?: any) => {
+        let accountAdgroupMaps = data ? [data.accountId + ',' + data.dynamicCreativeId] :[...new Set(selectedRows?.map(item => item.accountId + ',' + item.dynamicCreativeId))]
+        let hide: any
+        if (data) {
+            hide = message.loading(`正在设置...`, 0, () => {
+                message.success('设置成功');
+            });
+        }
+        switch (type) {
+            case '删除':
+                delBatchCreative.run({ accountAdgroupMaps }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        getDynamicCreativeV3List.refresh()
+                        setSelectedRows([])
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                })
+                break
+            case '启动':
+            case '暂停':
+                updateBatchDynamicCreativesInfo.run({ accountAdgroupMaps, suspend: type === '暂停' }).then(res => {
+                    if (res?.failIdList?.length === 0) {
+                        message.success(`修改操作完成!`)
+                        getDynamicCreativeV3List.refresh()
+                        setSelectedRows([])
+                    } else {
+                        setFailIdList(res?.list || [])
+                        setFailVisible(true)
+                    }
+                    if (hide) {
+                        hide()
+                    }
+                })
+                break
+        }
+    }
+
+    const sync = () => {
+        if (selectedRows?.length > 0) {
+            const hide = message.loading(`正在同步...`, 0, () => {
+                message.success('设置成功');
+            });
+            let accountAdgroupMaps = [...new Set(selectedRows?.map(item => item.accountId + ',' + item.dynamicCreativeId))]
+            syncBatchCreative.run({ accountAdgroupMaps }).then(res => {
+                res && getDynamicCreativeV3List.refresh()
+                res ? message.success('同步成功!') : message.error('同步失败!')
+                hide()
+            }).catch(() => hide())
+        } else {
+            message.error('请勾选需要同步的创意')
+        }
+    }
+
     return <>
     return <>
+        <Form
+            layout="inline"
+            form={form}
+            name="basignCreative"
+            initialValues={queryForm}
+            onFinish={onFinish}
+            style={{ marginBottom: 6 }}
+        >
+            <Row gutter={[10, 10]}>
+                <Col><Form.Item name='accountId' style={{ marginRight: 0 }}>
+                    <Input placeholder="广告账号,多个逗号隔开" style={{ width: 180 }} allowClear />
+                </Form.Item></Col>
+                <Col><Form.Item name='adgroupId' style={{ marginRight: 0 }}>
+                    <Input placeholder="广告ID" style={{ width: 120 }} allowClear />
+                </Form.Item></Col>
+                <Col><Form.Item name='creativeName' style={{ marginRight: 0 }}>
+                    <Input placeholder="创意名称" style={{ width: 150 }} allowClear />
+                </Form.Item></Col>
+                <Col><Form.Item name='creativeId' style={{ marginRight: 0 }}>
+                    <Input placeholder="创意ID" style={{ width: 120 }} allowClear />
+                </Form.Item></Col>
+                <Col><Form.Item name='isDeleted'>
+                    <Select
+                        placeholder='是否删除?'
+                        style={{ width: 100 }}
+                        showSearch
+                        filterOption={(input: any, option: any) =>
+                            (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+                        }
+                    >
+                        <Select.Option value={true}>是</Select.Option>
+                        <Select.Option value={false}>否</Select.Option>
+                    </Select>
+                </Form.Item></Col>
+                <Col><Form.Item style={{ marginRight: 0 }}>
+                    <Space>
+                        <Button type="primary" htmlType="submit">搜索</Button>
+                        <Button onClick={() => form.resetFields()}>重置</Button>
+                        <Button disabled={selectedRows.length === 0} style={{ padding: 0 }} danger type="link" onClick={() => setSelectedRows([])}>清空已选({selectedRows.length})</Button>
+                    </Space>
+                </Form.Item></Col>
+            </Row>
+        </Form>
         <TableData
         <TableData
             isCard={false}
             isCard={false}
-            columns={() => tableConfig(reviewStatusDetails)}
+            columns={() => tableConfig(reviewStatusDetails, (data, type) => dynamicHandle(type, data))}
             ajax={getDynamicCreativeV3List}
             ajax={getDynamicCreativeV3List}
             fixed={{ left: 2, right: 4 }}
             fixed={{ left: 2, right: 4 }}
             dataSource={getDynamicCreativeV3List?.data?.data?.records}
             dataSource={getDynamicCreativeV3List?.data?.data?.records}
-            loading={getDynamicCreativeV3List?.loading}
+            loading={getDynamicCreativeV3List?.loading || syncBatchCreative.loading || updateBatchDynamicCreativesInfo.loading}
             scroll={{ y: 560 }}
             scroll={{ y: 560 }}
+            syncAjax={sync}
             total={getDynamicCreativeV3List?.data?.data?.total}
             total={getDynamicCreativeV3List?.data?.data?.total}
             page={getDynamicCreativeV3List?.data?.data?.current}
             page={getDynamicCreativeV3List?.data?.data?.current}
             pageSize={getDynamicCreativeV3List?.data?.data?.size}
             pageSize={getDynamicCreativeV3List?.data?.data?.size}
@@ -63,47 +172,55 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
             gutter={[0, 10]}
             gutter={[0, 10]}
             config={txDynamicConfig}
             config={txDynamicConfig}
             configName="创意3.0"
             configName="创意3.0"
-            leftChild={<Form
-                layout="inline"
-                form={form}
-                name="basignCreative"
-                initialValues={queryForm}
-                onFinish={onFinish}
-            >
-                <Row gutter={[10, 10]}>
-                    <Col><Form.Item name='accountId' style={{ marginRight: 0 }}>
-                        <Input placeholder="广告账号,多个逗号隔开" style={{ width: 150 }} allowClear />
-                    </Form.Item></Col>
-                    <Col><Form.Item name='adgroupId' style={{ marginRight: 0 }}>
-                        <Input placeholder="广告ID" style={{ width: 120 }} allowClear />
-                    </Form.Item></Col>
-                    <Col><Form.Item name='creativeName' style={{ marginRight: 0 }}>
-                        <Input placeholder="创意名称" style={{ width: 150 }} allowClear />
-                    </Form.Item></Col>
-                    <Col><Form.Item name='creativeId' style={{ marginRight: 0 }}>
-                        <Input placeholder="创意ID" style={{ width: 120 }} allowClear />
-                    </Form.Item></Col>
-                    <Col><Form.Item name='isDeleted'>
-                        <Select
-                            placeholder='是否删除?'
-                            style={{ width: 100 }}
-                            showSearch
-                            filterOption={(input: any, option: any) =>
-                                (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
+            leftChild={<Space>
+                <Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={updateBatchDynamicCreativesInfo.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => dynamicHandle('启动')}>启动</Button>
+                <Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={updateBatchDynamicCreativesInfo.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => dynamicHandle('暂停')}>暂停</Button>
+                <Popconfirm
+                    title="确定删除?"
+                    onConfirm={() => dynamicHandle('删除')}
+                    disabled={selectedRows.length === 0}
+                >
+                    <Button type='primary' danger icon={<DeleteOutlined />} loading={delBatchCreative.loading} disabled={selectedRows.length === 0}>删除</Button>
+                </Popconfirm>
+            </Space>}
+            rowSelection={{
+                selectedRowKeys: selectedRows.map(item => item.dynamicCreativeId.toString()),
+                getCheckboxProps: (record: any) => ({
+                    disabled: record.isDeleted
+                }),
+                onSelect: (record: { dynamicCreativeId: number }, selected: boolean) => {
+                    if (selected) {
+                        selectedRows.push({ ...record })
+                        setSelectedRows([...selectedRows])
+                    } else {
+                        let newSelectAccData = selectedRows.filter((item: { dynamicCreativeId: number }) => item.dynamicCreativeId !== record.dynamicCreativeId)
+                        setSelectedRows([...newSelectAccData])
+                    }
+                },
+                onSelectAll: (selected: boolean, selectedRowss: { dynamicCreativeId: number }[], changeRows: { dynamicCreativeId: number }[]) => {
+                    if (selected) {
+                        let newSelectAccData = [...selectedRows]
+                        changeRows.forEach((item: { dynamicCreativeId: number }) => {
+                            let index = newSelectAccData.findIndex((ite: { dynamicCreativeId: number }) => ite.dynamicCreativeId === item.dynamicCreativeId)
+                            if (index === -1) {
+                                let data: any = { ...item }
+                                newSelectAccData.push(data)
+                            }
+                        })
+                        setSelectedRows([...newSelectAccData])
+                    } else {
+                        let newSelectAccData = selectedRows.filter((item: { dynamicCreativeId: number }) => {
+                            let index = changeRows.findIndex((ite: { dynamicCreativeId: number }) => ite.dynamicCreativeId === item.dynamicCreativeId)
+                            if (index !== -1) {
+                                return false
+                            } else {
+                                return true
                             }
                             }
-                        >
-                            <Select.Option value={true}>是</Select.Option>
-                            <Select.Option value={false}>否</Select.Option>
-                        </Select>
-                    </Form.Item></Col>
-                    <Col><Form.Item style={{ marginRight: 0 }}>
-                        <Space>
-                            <Button type="primary" htmlType="submit">搜索</Button>
-                            <Button onClick={() => form.resetFields()}>重置</Button>
-                        </Space>
-                    </Form.Item></Col>
-                </Row>
-            </Form>}
+                        })
+                        setSelectedRows([...newSelectAccData])
+                    }
+                }
+            }}
             onChange={(props: any) => {
             onChange={(props: any) => {
                 let { pagination } = props
                 let { pagination } = props
                 let { current, pageSize } = pagination
                 let { current, pageSize } = pagination
@@ -118,6 +235,41 @@ const Creative: React.FC<ADQV3.CreativeProps> = ({ queryForm, setQueryForm, user
                 setDynamicVisible(false)
                 setDynamicVisible(false)
             }}
             }}
         />}
         />}
+
+        {failVisible && <Modal
+            title={<strong>报错信息</strong>}
+            visible={failVisible}
+            className='modalResetCss'
+            width={650}
+            onCancel={() => { setFailVisible(false); setFailIdList([]) }}
+            footer={null}
+        >
+            <Table
+                size="small"
+                bordered
+                rowKey={'creativeId'}
+                columns={[{
+                    title: '创意ID',
+                    dataIndex: 'creativeId',
+                    key: 'creativeId',
+                    width: 110,
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: 'code',
+                    dataIndex: 'code',
+                    key: 'code',
+                    width: 70,
+                    align: 'center',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }, {
+                    title: '错误信息',
+                    dataIndex: 'messageCn',
+                    key: 'messageCn',
+                    render: (value) => <span style={{ fontSize: 12 }}>{value}</span>,
+                }]}
+                dataSource={failIdList}
+            />
+        </Modal>}
     </>
     </>
 }
 }
 
 

+ 3 - 3
src/pages/launchSystemV3/adqv3/creative/tableConfig.tsx

@@ -7,7 +7,7 @@ import { ELEMENT_ENUM, SITE_SET_ENUM, creativeTemplate } from '../../tencentAdPu
 import { AD_STATUS } from '.'
 import { AD_STATUS } from '.'
 const { Text } = Typography;
 const { Text } = Typography;
 
 
-function tableConfig(reviewStatusDetails: (value: any) => void): any {
+function tableConfig(reviewStatusDetails: (value: any) => void, suspendHandle: (b: any, suspend: '启动' | '暂停') => void): any {
     return [
     return [
         {
         {
             title: '启停',
             title: '启停',
@@ -17,7 +17,7 @@ function tableConfig(reviewStatusDetails: (value: any) => void): any {
             width: 40,
             width: 40,
             fixed: 'left',
             fixed: 'left',
             render: (a: string, b: any) => {
             render: (a: string, b: any) => {
-                return <Switch size="small" checked={a === 'AD_STATUS_NORMAL'} onChange={(checked) => { }} />
+                return <Switch size="small" checked={a === 'AD_STATUS_NORMAL'} onChange={(checked) => { suspendHandle(b, checked ? '启动' : '暂停') }} />
             }
             }
         },
         },
         {
         {
@@ -206,7 +206,7 @@ function tableConfig(reviewStatusDetails: (value: any) => void): any {
             width: 120,
             width: 120,
             ellipsis: true,
             ellipsis: true,
             render: (a: string) => {
             render: (a: string) => {
-                return creativeTemplate[a]
+                return creativeTemplate[a] || '--'
             }
             }
         },
         },
         {
         {

+ 1 - 1
src/pages/launchSystemV3/tencentAdPutIn/create/Target/generateTarget.tsx

@@ -139,7 +139,7 @@ const GenerateTarget: React.FC<Props> = ({ target, visible, onChange, onClose })
             }}
             }}
         >
         >
             <Card
             <Card
-                title={<strong style={{ fontSize: 18 }}>生成设置</strong>}
+                title={<strong style={{ fontSize: 14 }}>生成设置</strong>}
                 className="cardResetCss"
                 className="cardResetCss"
             >
             >
                 <Form.Item
                 <Form.Item

+ 48 - 0
src/services/launchAdq/adqv3.ts

@@ -95,4 +95,52 @@ export async function modifyDailyBudgetBatchApi(data: ADQV3.ModifyDailyBudgetBat
         method: 'PUT',
         method: 'PUT',
         data
         data
     });
     });
+}
+
+/**
+ * 删除广告
+ * @param data 
+ * @returns 
+ */
+export async function delBatchApi(data: ADQV3.AccountAdgroupMapsProps) {
+    return request(api + '/adq/adgroup/delBatch', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 删除创意
+ * @param data 
+ * @returns 
+ */
+export async function delBatchCreativeApi(data: ADQV3.AccountAdgroupMapsProps) {
+    return request(api + '/adq/adgroup/delBatchCreative', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 批量修改创意信息
+ * @param data 
+ * @returns 
+ */
+export async function updateBatchDynamicCreativesInfoApi(data: ADQV3.ModifyStatusBatchProps) {
+    return request(api + '/adq/adgroup/updateBatchDynamicCreativesInfo', {
+        method: 'PUT',
+        data
+    });
+}
+
+/**
+ * 同步创意
+ * @param data 
+ * @returns 
+ */
+export async function syncBatchCreativeApi(data: ADQV3.AccountAdgroupMapsProps) {
+    return request(api + '/adq/adgroup/syncBatchCreative', {
+        method: 'PUT',
+        data
+    });
 }
 }