|
@@ -1,11 +1,14 @@
|
|
|
|
|
|
import { useAjax } from '@/Hook/useAjax'
|
|
|
import { PromotedObjectType } from '@/services/launchAdq/enum'
|
|
|
-import { Col, Row, Input, Select, message } from 'antd'
|
|
|
-import React, { useEffect, useCallback } from 'react'
|
|
|
+import { Col, Row, Input, Select, message, Space, Button, Popconfirm, Switch, notification } from 'antd'
|
|
|
+import React, { useEffect, useCallback, useState } from 'react'
|
|
|
import TableData from '../../components/TableData'
|
|
|
import tableConfig from './tableConfig'
|
|
|
-import { putAdqAdgroupsSync, getAdqAdgroupsList,putAdqAdgroupsConfigStatus } from '@/services/launchAdq/adq'
|
|
|
+import { putAdqAdgroupsSync, getAdqAdgroupsList, delListAdqAdgroupsApi, editAdqAdgroupsDataApi } from '@/services/launchAdq/adq'
|
|
|
+import { CopyOutlined, DeleteOutlined, FieldTimeOutlined, PauseCircleOutlined, PlayCircleOutlined, TransactionOutlined } from '@ant-design/icons'
|
|
|
+import UpdateAd from './updateAd'
|
|
|
+import Copy from './copy'
|
|
|
type Props = {
|
|
|
accountId: string,
|
|
|
adAccountId: string,
|
|
@@ -30,84 +33,182 @@ type Props = {
|
|
|
}) => void
|
|
|
}
|
|
|
|
|
|
-function Ad(props:Props) {
|
|
|
- let { accountId, adAccountId,userId,tableIdClick,queryParmas } = props
|
|
|
- // api方法
|
|
|
+const Ad: React.FC<Props> = (props) => {
|
|
|
+
|
|
|
+ /***********************/
|
|
|
+ let { accountId, adAccountId, userId, tableIdClick, queryParmas } = props
|
|
|
+ const [selectedRows, setSelectedRows] = useState<any[]>([])
|
|
|
+ const [update, setUpdate] = useState<{ visible: boolean, title: string }>({ visible: false, title: '' })
|
|
|
+ const [model, setModel] = useState(true)
|
|
|
+ const [copyData, setCopyData] = useState<{ visible: boolean }>({ visible: false })
|
|
|
+
|
|
|
const listAjax = useAjax((params) => getAdqAdgroupsList(params), { formatResult: true })
|
|
|
const syncAjax = useAjax((adAccountId) => putAdqAdgroupsSync(adAccountId))
|
|
|
- const switchAjax = useAjax((params) => putAdqAdgroupsConfigStatus(params))
|
|
|
- console.log('创意=====》')
|
|
|
+ const delListAdqAdgroups = useAjax((params) => delListAdqAdgroupsApi(params))
|
|
|
+ const editAdqAdgroupsData = useAjax((params) => editAdqAdgroupsDataApi(params))
|
|
|
+ /************************/
|
|
|
+
|
|
|
useEffect(() => {
|
|
|
- getList({ pageNum: 1, pageSize: 20,...queryParmas })
|
|
|
- }, [accountId,userId,queryParmas])
|
|
|
+ getList({ pageNum: 1, pageSize: 20, accountId, ...queryParmas })
|
|
|
+ }, [accountId, userId, queryParmas])
|
|
|
+
|
|
|
// 获取列表
|
|
|
const getList = useCallback((params: {
|
|
|
pageNum: number;
|
|
|
pageSize: number;
|
|
|
accountId?: string;
|
|
|
- adcreativeName?: string;
|
|
|
- adgroupId?:string
|
|
|
+ adgroupName?: string;
|
|
|
+ adgroupId?: string;
|
|
|
+ promotedObjectType?: string;
|
|
|
+ isDeleted?: boolean
|
|
|
+ campaignId?: string
|
|
|
}) => {
|
|
|
- if (!params.adcreativeName || params.adcreativeName !== listAjax?.params[0]?.adcreativeName) {
|
|
|
- !params.adcreativeName && delete params.adcreativeName
|
|
|
- listAjax.run({ ...params,userId, accountId })
|
|
|
+ if (!params.adgroupName || params.adgroupName !== listAjax?.params[0]?.adgroupName) {
|
|
|
+ !params.adgroupName && delete params.adgroupName
|
|
|
+ listAjax.run({ ...params, userId })
|
|
|
}
|
|
|
- }, [accountId,userId,listAjax])
|
|
|
+ }, [userId, listAjax])
|
|
|
// 同步
|
|
|
const sync = useCallback(() => {
|
|
|
- if(!adAccountId){
|
|
|
+ if (!adAccountId) {
|
|
|
message.error('请先选择要同步的广点通账号!')
|
|
|
return
|
|
|
}
|
|
|
- syncAjax.run({adAccountId}).then(res => {
|
|
|
+ syncAjax.run({ adAccountId }).then(res => {
|
|
|
res && listAjax.refresh()
|
|
|
res ? message.success('同步成功!') : message.error('同步失败!')
|
|
|
|
|
|
})
|
|
|
}, [adAccountId, listAjax])
|
|
|
- // 启停
|
|
|
- const switchHandle=useCallback((data,checked)=>{
|
|
|
- let { accountId,adgroupId}=data
|
|
|
- console.log(checked)
|
|
|
- let configuredStatus = checked ? 'AD_STATUS_NORMAL' : 'AD_STATUS_SUSPEND'
|
|
|
- switchAjax.run({accountId,adgroupId,configuredStatus}).then(res=>{
|
|
|
- res && listAjax.refresh()
|
|
|
- res ? message.success(checked?'开启广告成功!':'关闭广告成功!') : message.error(checked?'开启广告失败':'关闭广告失败!')
|
|
|
+
|
|
|
+ /** 删除 */
|
|
|
+ const deleteHandle = (type: 0 | 1, adgroupId?: number) => {
|
|
|
+ delListAdqAdgroups.run({ adgroupIds: type === 1 ? selectedRows.map(item => item.adgroupId) : [adgroupId] }).then(res => {
|
|
|
+ message.success('删除成功')
|
|
|
+ setSelectedRows([])
|
|
|
+ listAjax.refresh()
|
|
|
})
|
|
|
- },[])
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 修改排期出价 */
|
|
|
+ const editScheduling = () => {
|
|
|
+ setUpdate({ visible: true, title: '批量修改' })
|
|
|
+ }
|
|
|
+ /** 修改排期出价 */
|
|
|
+ const editDeepConversion = () => {
|
|
|
+ setUpdate({ visible: true, title: '批量修改深度优化' })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 单个启停
|
|
|
+ const onChange = () => {
|
|
|
+ listAjax.refresh()
|
|
|
+ setSelectedRows([])
|
|
|
+ }
|
|
|
+ // 批量启停
|
|
|
+ const adStatus = (type: 'play' | 'suspend') => {
|
|
|
+ let params: any = {}
|
|
|
+ if (type === 'play') {
|
|
|
+ params.configuredStatus = 'AD_STATUS_NORMAL'
|
|
|
+ params.adgroupIds = selectedRows.filter((item: { configuredStatus: string, adgroupId: number }) => item.configuredStatus === 'AD_STATUS_SUSPEND').map(item => item.adgroupId)
|
|
|
+ } else {
|
|
|
+ params.configuredStatus = 'AD_STATUS_SUSPEND'
|
|
|
+ params.adgroupIds = selectedRows.filter((item: { configuredStatus: string, adgroupId: number }) => item.configuredStatus === 'AD_STATUS_NORMAL').map(item => item.adgroupId)
|
|
|
+ }
|
|
|
+ if (params.adgroupIds.length === 0) {
|
|
|
+ message.warn(`所以账号都是${type === 'play' ? '启动' : '暂停'}状态,无需${type === 'play' ? '启动' : '暂停'}操作`)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ editAdqAdgroupsData.run(params).then(res => {
|
|
|
+ message.success(`${type === 'play' ? '启动' : '暂停'}完成.成功: ${res.success},失败: ${res.fail}`)
|
|
|
+ if (res?.fail) {
|
|
|
+ notification.error({
|
|
|
+ message: `${type === 'play' ? '启动' : '暂停'}失败`,
|
|
|
+ description: `成功: ${res.success},修改失败${res.fail}条,失败的请到任务列表查看`,
|
|
|
+ duration: 0
|
|
|
+ });
|
|
|
+ }
|
|
|
+ listAjax.refresh()
|
|
|
+ setSelectedRows([])
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ // 批量复制
|
|
|
+ const copyHandle = () => {
|
|
|
+ setCopyData({ visible: true })
|
|
|
+ }
|
|
|
+
|
|
|
return <div>
|
|
|
+ {/* 修改广告 */}
|
|
|
+ {update.visible && <UpdateAd
|
|
|
+ {...update}
|
|
|
+ selectedRows={selectedRows}
|
|
|
+ onChange={() => {
|
|
|
+ setUpdate({ visible: false, title: '' })
|
|
|
+ listAjax.refresh()
|
|
|
+ setSelectedRows([])
|
|
|
+ }}
|
|
|
+ onClose={() => { setUpdate({ visible: false, title: '' }) }}
|
|
|
+ />}
|
|
|
+ {/* 复制广告 */}
|
|
|
+ {copyData.visible && <Copy selectedRows={selectedRows} {...copyData} onClose={() => setCopyData({ visible: false })} onChange={() => { setCopyData({ visible: false }); listAjax.refresh(); setSelectedRows([]) }} />}
|
|
|
<TableData
|
|
|
- columns={()=>tableConfig(switchHandle,tableIdClick)}
|
|
|
+ isCard={false}
|
|
|
+ columns={() => tableConfig(onChange, tableIdClick)}
|
|
|
ajax={listAjax}
|
|
|
syncAjax={sync}
|
|
|
dataSource={listAjax?.data?.data?.records}
|
|
|
loading={listAjax?.loading || syncAjax?.loading}
|
|
|
- scroll={{ x: 2500,y:550 }}
|
|
|
+ scroll={{ y: 560 }}
|
|
|
total={listAjax?.data?.data?.total}
|
|
|
page={listAjax?.data?.data?.current}
|
|
|
pageSize={listAjax?.data?.data?.size}
|
|
|
myKey={'adgroupId'}
|
|
|
- leftChild={<>
|
|
|
- <Row gutter={[10, 10]}>
|
|
|
+ leftChild={<Space direction='vertical'>
|
|
|
+ <Row gutter={[10, 10]} align='middle'>
|
|
|
+ <Col>
|
|
|
+ <Input
|
|
|
+ placeholder='广告账号'
|
|
|
+ allowClear
|
|
|
+ style={{ width: 150 }}
|
|
|
+ onBlur={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ getList({ pageNum: 1, pageSize: 20, accountId: value })
|
|
|
+ }}
|
|
|
+ onKeyDownCapture={(e: any) => {
|
|
|
+ let key = e.key
|
|
|
+ if (key === 'Enter') {
|
|
|
+ let value = e.target.value
|
|
|
+ getList({ pageNum: 1, pageSize: 20, accountId: value })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ onChange={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ if (!value) {
|
|
|
+ getList({ pageNum: 1, pageSize: 20, accountId: value })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
<Col>
|
|
|
<Input
|
|
|
placeholder='广告名称'
|
|
|
allowClear
|
|
|
+ style={{ width: 150 }}
|
|
|
onBlur={(e) => {
|
|
|
let value = e.target.value
|
|
|
- getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
|
|
|
+ getList({ pageNum: 1, pageSize: 20, adgroupName: value })
|
|
|
}}
|
|
|
onKeyDownCapture={(e: any) => {
|
|
|
let key = e.key
|
|
|
if (key === 'Enter') {
|
|
|
let value = e.target.value
|
|
|
- getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
|
|
|
+ getList({ pageNum: 1, pageSize: 20, adgroupName: value })
|
|
|
}
|
|
|
}}
|
|
|
onChange={(e) => {
|
|
|
let value = e.target.value
|
|
|
if (!value) {
|
|
|
- getList({ pageNum: 1, pageSize: 20, adcreativeName: value })
|
|
|
+ getList({ pageNum: 1, pageSize: 20, adgroupName: value })
|
|
|
}
|
|
|
}}
|
|
|
/>
|
|
@@ -116,6 +217,7 @@ function Ad(props:Props) {
|
|
|
<Input
|
|
|
placeholder='广告ID'
|
|
|
allowClear
|
|
|
+ style={{ width: 150 }}
|
|
|
onBlur={(e) => {
|
|
|
let value = e.target.value
|
|
|
getList({ pageNum: 1, pageSize: 20, adgroupId: value })
|
|
@@ -136,21 +238,104 @@ function Ad(props:Props) {
|
|
|
/>
|
|
|
</Col>
|
|
|
<Col>
|
|
|
- <Select placeholder='推广目标选择' style={{ minWidth: 200 }} showSearch filterOption={(input: any, option: any) =>
|
|
|
- (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
|
|
|
- } allowClear onChange={(value: any) => {
|
|
|
- getList({ pageNum: 1, pageSize: 20, accountId })
|
|
|
- }}>
|
|
|
- {
|
|
|
- Object.keys(PromotedObjectType).map(key => {
|
|
|
- // let obj = JSON.parse(PromotedObjectType[key])
|
|
|
- return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
|
|
|
- })
|
|
|
+ <Input
|
|
|
+ placeholder='计划ID'
|
|
|
+ allowClear
|
|
|
+ style={{ width: 150 }}
|
|
|
+ onBlur={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ getList({ pageNum: 1, pageSize: 20, campaignId: value })
|
|
|
+ }}
|
|
|
+ onKeyDownCapture={(e: any) => {
|
|
|
+ let key = e.key
|
|
|
+ if (key === 'Enter') {
|
|
|
+ let value = e.target.value
|
|
|
+ getList({ pageNum: 1, pageSize: 20, campaignId: value })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ onChange={(e) => {
|
|
|
+ let value = e.target.value
|
|
|
+ if (!value) {
|
|
|
+ getList({ pageNum: 1, pageSize: 20, campaignId: value })
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Col>
|
|
|
+ <Col>
|
|
|
+ <Select
|
|
|
+ placeholder='推广目标选择'
|
|
|
+ style={{ width: 150 }}
|
|
|
+ showSearch
|
|
|
+ filterOption={(input: any, option: any) =>
|
|
|
+ (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
|
|
|
+ }
|
|
|
+ allowClear
|
|
|
+ onChange={(value: any) => {
|
|
|
+ getList({ pageNum: 1, pageSize: 20, promotedObjectType: value })
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {Object.keys(PromotedObjectType).map(key => {
|
|
|
+ return <Select.Option value={key} key={key}>{PromotedObjectType[key]}</Select.Option>
|
|
|
+ })}
|
|
|
+ </Select>
|
|
|
+ </Col>
|
|
|
+ <Col>
|
|
|
+ <Select
|
|
|
+ placeholder='是否已删除'
|
|
|
+ style={{ width: 150 }}
|
|
|
+ showSearch
|
|
|
+ filterOption={(input: any, option: any) =>
|
|
|
+ (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
|
|
|
}
|
|
|
+ allowClear
|
|
|
+ onChange={(value: any) => {
|
|
|
+ getList({ pageNum: 1, pageSize: 20, isDeleted: value })
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <Select.Option value={true}>已删除</Select.Option>
|
|
|
+ <Select.Option value={false}>未删除</Select.Option>
|
|
|
</Select>
|
|
|
</Col>
|
|
|
</Row>
|
|
|
- </>}
|
|
|
+ <Row gutter={[10, 10]} align='middle'>
|
|
|
+ <Col>
|
|
|
+ <Switch checkedChildren="普通模式" unCheckedChildren="深度优化" checked={model} onChange={(checked) => { setModel(checked); setSelectedRows([]) }} style={model ? {} : { background: '#67c23a' }} />
|
|
|
+ </Col>
|
|
|
+ {model ? <>
|
|
|
+ <Col><Button type='primary' style={{ background: '#1890ff' }} icon={<FieldTimeOutlined />} disabled={selectedRows.length === 0} onClick={editScheduling}>修改排期出价</Button></Col>
|
|
|
+ <Col><Button type='primary' style={{ background: '#1890ff' }} icon={<CopyOutlined />} disabled={selectedRows.length === 0} onClick={copyHandle}>批量复制</Button></Col>
|
|
|
+ <Col><Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动广告</Button></Col>
|
|
|
+ <Col><Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停广告</Button></Col>
|
|
|
+ <Col>
|
|
|
+ <Popconfirm
|
|
|
+ title="确定删除?"
|
|
|
+ onConfirm={() => deleteHandle(1)}
|
|
|
+ okText="是"
|
|
|
+ cancelText="否"
|
|
|
+ disabled={selectedRows.length === 0}
|
|
|
+ >
|
|
|
+ <Button danger type='primary' loading={delListAdqAdgroups.loading} icon={<DeleteOutlined />} disabled={selectedRows.length === 0}>删除</Button>
|
|
|
+ </Popconfirm>
|
|
|
+ </Col>
|
|
|
+ </> : <Col><Button type='primary' icon={<TransactionOutlined />} disabled={selectedRows.length === 0} onClick={editDeepConversion}>修改深度优化ROI</Button></Col>}
|
|
|
+ </Row>
|
|
|
+ </Space>}
|
|
|
+ rowSelection={{
|
|
|
+ selectedRowKeys: selectedRows.map(item => item.adgroupId.toString()),
|
|
|
+ getCheckboxProps: (record: any) => ({
|
|
|
+ disabled: model ?
|
|
|
+ record.status === 'STATUS_DELETED' :
|
|
|
+ record.status === 'STATUS_DELETED' ||
|
|
|
+ !(!model &&
|
|
|
+ record?.promotedObjectType === 'PROMOTED_OBJECT_TYPE_WECHAT_OFFICIAL_ACCOUNT' &&
|
|
|
+ record?.optimizationGoal === 'OPTIMIZATIONGOAL_FOLLOW' &&
|
|
|
+ record?.deepConversionSpec?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_PURCHASE_ROAS'
|
|
|
+ )
|
|
|
+ }),
|
|
|
+ onChange: (selectedRowKeys: any, selectedRows: any) => {
|
|
|
+ setSelectedRows(selectedRows)
|
|
|
+ }
|
|
|
+ }}
|
|
|
onChange={(props: any) => {
|
|
|
let { sortData, pagination } = props
|
|
|
let { current, pageSize } = pagination
|