123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539 |
- import { useAjax } from "@/Hook/useAjax";
- import { DeleteOutlined, DownOutlined, PauseCircleOutlined, PlayCircleOutlined, PlusOutlined, QuestionCircleOutlined } from "@ant-design/icons";
- import { Button, Checkbox, Col, DatePicker, Dropdown, Input, Menu, Modal, Row, Select, Space, Tooltip, Typography, message } from "antd"
- import React, { useCallback, useEffect, useState } from "react"
- import { ADGROUP_STATUS } from "../const";
- import { getAdqV3AdListApi, modifyStatusBatchApi, syncBatchApi } from "@/services/launchAdq/adqv3";
- import tableConfig from "./tableConfig";
- import { txAdConfig } from "../config";
- import UpdateAd from "./updateAd";
- import TableData from "@/pages/launchSystemNew/components/TableData";
- import AddDynamic from "../../tencentAdPutIn/create/addDynamic";
- import { arraysHaveSameValues } from "@/utils/utils";
- import { MARKETING_CARRIER_TYPE_ENUM, MARKETING_GOAL_ENUM, MARKETING_SUB_GOAL_ENUM, MARKETING_TARGET_TYPE_ENUM, MARKETING_TARGET_TYPE_GAME_ENUM, SITE_SET_ENUM } from "../../tencentAdPutIn/const";
- import Log from "../components/log";
- import '../../tencentAdPutIn/index.less'
- import UserTactics from "../../tencentAdPutIn/create/TacticsS/userTactics";
- import UpdateAd3 from "./updateAd3";
- import { useLocalStorageState } from "ahooks";
- import AutoAcquisitionSet from "./autoAcquisitionSet";
- const { Text } = Typography;
- const Ad: React.FC<ADQV3.AdProps> = ({ userId, creativeHandle }) => {
- /*****************************************/
- const [useType, setUseType] = useLocalStorageState<1 | 2>('AD_USETYPE', 1);
- const [pageSize, setPageSize] = useLocalStorageState<number>('AD_PAGESIZE', 20);
- const [queryFrom, set_queryFrom] = useState<ADQV3.GetAdListProps>({ pageNum: 1, pageSize: pageSize || 20, useType: useType || 1 })
- const [isClearSelect, setIsClearSelect] = useState(true)
- const [selectedRows, setSelectedRows] = useState<any[]>([])
- const [tactics, setTactics] = useState<any>()
- const [update, setUpdate] = useState<{ visible: boolean }>({ visible: false })
- const [addDynamicVisible, setAddDynamicVisible] = useState<boolean>(false)
- const [handleType, setHandleType] = useState<number>(1)
- const [czjlShow, setCzjlShow] = useState(false)
- const [updateData, setUpdateDate] = useState<{ visible: boolean, type: '修改出价' | '修改名称' | '修改日限额' | '修改投放时间' | '删除' | '深度优化ROI' | '修改投放首日开始时间' }>({ visible: false, type: '修改出价' })
- const [autoAcqVisible, setAutoAcqVisible] = useState<boolean>(false)
- const syncBatch = useAjax((params) => syncBatchApi(params))
- const modifyStatusBatch = useAjax((params) => modifyStatusBatchApi(params))
- const getAdqV3AdList = useAjax((params) => getAdqV3AdListApi(params), { formatResult: true })
- /*****************************************/
- useEffect(() => {
- getList({ pageNum: 1, pageSize: pageSize || 20, useType: useType || 1 })
- }, [userId, pageSize])
- // 获取列表
- const getList = useCallback((params: ADQV3.GetAdListProps) => {
- getAdqV3AdList.run({ ...params, userId })
- }, [userId, getAdqV3AdList])
- // 同步
- const sync = useCallback(() => {
- if (selectedRows?.length > 0) {
- let accountAdgroupMaps = [...new Set(selectedRows?.map(item => item.accountId + ',' + item.adgroupId))]
- syncBatch.run({ accountAdgroupMaps }).then(res => {
- res && getAdqV3AdList.refresh()
- res ? message.success('同步成功!') : message.error('同步失败!')
- })
- } else {
- message.error('请勾选需要同步的广告')
- }
- }, [getAdqV3AdList, selectedRows])
- // 批量启停
- const adStatus = (type: boolean) => {
- let newSelectedRows = []
- if (type) {
- newSelectedRows = selectedRows.filter((item: { configuredStatus: string, adgroupId: number }) => item.configuredStatus === 'AD_STATUS_SUSPEND')
- } else {
- newSelectedRows = selectedRows.filter((item: { configuredStatus: string, adgroupId: number }) => item.configuredStatus === 'AD_STATUS_NORMAL')
- }
- if (newSelectedRows.length === 0) {
- message.warn(`所有广告都是${type ? '启动' : '暂停'}状态,无需${type ? '启动' : '暂停'}操作`)
- return
- }
- let accountAdgroupMaps = [...new Set(newSelectedRows?.map(item => item.accountId + ',' + item.adgroupId))]
- modifyStatusBatch.run({ accountAdgroupMaps, suspend: !type }).then(res => {
- message.success(`${type ? '启动' : '暂停'}成功`)
- getAdqV3AdList.refresh()
- setSelectedRows([])
- })
- }
- // 添加创意
- const addDynamic = () => {
- setAddDynamicVisible(true)
- }
- return <div>
- <Row gutter={[6, 6]} align='middle' style={{ marginBottom: 15 }}>
- <Col>
- <Select
- placeholder='应用类型'
- style={{ width: 90 }}
- showSearch
- filterOption={(input: any, option: any) =>
- (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
- }
- value={useType}
- onChange={(value: any) => {
- let params = { ...queryFrom, useType: value, pageNum: 1 }
- setUseType(value)
- set_queryFrom(params)
- getList(params)
- }}
- >
- <Select.Option value={1}>小说</Select.Option>
- <Select.Option value={2}>游戏</Select.Option>
- </Select>
- </Col>
- <Col>
- <Input
- placeholder='广告账号(多个,分割)'
- allowClear
- style={{ width: 160 }}
- onChange={(e) => {
- let value = e.target.value
- let arr: any = []
- if (value) {
- value = value.replace(/[,,\s]/g, ',')
- arr = value.split(',').filter((a: any) => a)
- }
- set_queryFrom({ ...queryFrom, accountIdList: arr })
- }}
- />
- </Col>
- <Col>
- <Input
- placeholder='广告ID(多个,分割)'
- allowClear
- style={{ width: 150 }}
- onChange={(e) => {
- let value = e.target.value
- let arr: any = []
- if (value) {
- value = value.replace(/[,,\s]/g, ',')
- arr = value.split(',').filter((a: any) => a)
- }
- set_queryFrom({ ...queryFrom, adgroupIdList: arr })
- }}
- />
- </Col>
- <Col>
- <Select
- placeholder='广告状态'
- mode="multiple"
- style={{ minWidth: 120 }}
- showSearch
- filterOption={(input: any, option: any) =>
- (option!.children as unknown as string).toLowerCase().includes(input.toLowerCase())
- }
- allowClear
- onChange={(value: any) => {
- set_queryFrom({ ...queryFrom, systemStatusList: value })
- }}
- >
- {Object.keys(ADGROUP_STATUS).map(key => {
- return <Select.Option value={key} key={key}>{ADGROUP_STATUS[key as keyof typeof ADGROUP_STATUS]}</Select.Option>
- })}
- </Select>
- </Col>
- <Col>
- <Input
- placeholder='广告名称'
- allowClear
- style={{ width: 120 }}
- onChange={(e) => {
- let value = e.target.value
- set_queryFrom({ ...queryFrom, adgroupName: value })
- }}
- />
- </Col>
- <Col>
- <Input
- placeholder='腾讯备注'
- allowClear
- style={{ width: 120 }}
- onChange={(e) => {
- let value = e.target.value
- let arr: any = []
- if (value) {
- value = value.replace(/[,,\s]/g, ',')
- arr = value.split(',').filter((a: any) => a)
- }
- set_queryFrom({ ...queryFrom, accountMemo: arr })
- }}
- />
- </Col>
- <Col>
- <Input
- placeholder='本地备注'
- allowClear
- style={{ width: 120 }}
- onChange={(e) => {
- let value = e.target.value
- let arr: any = []
- if (value) {
- value = value.replace(/[,,\s]/g, ',')
- arr = value.split(',').filter((a: any) => a)
- }
- set_queryFrom({ ...queryFrom, accountRemark: arr })
- }}
- />
- </Col>
- <Col>
- <DatePicker.RangePicker
- placeholder={['创建开始日期', '创建结束日期']}
- onChange={(e, options) => {
- set_queryFrom({ ...queryFrom, beginDate: options[0], endDate: options[1] })
- }}
- />
- </Col>
- <Col>
- <Space>
- <Button
- type="primary"
- onClick={() => {
- if (isClearSelect) {
- setSelectedRows([])
- }
- getList({ ...queryFrom, pageNum: 1 })
- }}
- >
- <Space>
- <span>搜索</span>
- <Checkbox className='clearCheckbox' onClick={(e) => e.stopPropagation()} checked={isClearSelect} onChange={(e) => setIsClearSelect(e.target.checked)} />
- <Tooltip title="勾选搜索清空已选">
- <QuestionCircleOutlined />
- </Tooltip>
- </Space>
- </Button>
- {selectedRows?.length > 0 && <Button type='link' style={{ padding: 0, color: 'red' }} onClick={() => {
- setSelectedRows([])
- }}>清空已选({selectedRows?.length})</Button>}
- </Space>
- </Col>
- </Row>
- <TableData
- isCard={false}
- columns={() => tableConfig(() => getAdqV3AdList.refresh(), creativeHandle, useType)}
- ajax={getAdqV3AdList}
- syncAjax={sync}
- fixed={{ left: 2, right: 5 }}
- dataSource={getAdqV3AdList?.data?.data?.records}
- loading={getAdqV3AdList?.loading || syncBatch?.loading}
- scroll={{ y: 560 }}
- total={getAdqV3AdList?.data?.data?.total}
- page={getAdqV3AdList?.data?.data?.current}
- pageSize={getAdqV3AdList?.data?.data?.size}
- myKey={'adgroupId'}
- gutter={[0, 10]}
- config={txAdConfig}
- configName="腾讯广告3.0"
- leftChild={<Space direction='vertical'>
- <Row gutter={[10, 10]} align='middle'>
- <Col><Select
- style={{ width: 120 }}
- onChange={(e) => {
- setHandleType(e)
- setSelectedRows([])
- }}
- value={handleType}
- dropdownMatchSelectWidth={false}
- options={[{ label: '广告操作', value: 1 }, { label: '创意操作', value: 2 }, { label: '修改首日付费 ROI', value: 3 }, { label: '修改首日变现 ROI', value: 4 }]}
- /></Col>
- <Col>
- <Button type='dashed' onClick={() => { setCzjlShow(true) }}>操作记录</Button>
- </Col>
- {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: '#e6a23c', borderColor: '#e6a23c' }} loading={modifyStatusBatch.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus(false)}>暂停</Button></Col>
- <Col><Button type='primary' danger icon={<DeleteOutlined />} disabled={selectedRows.length === 0} onClick={() => {
- setUpdateDate({ visible: true, type: '删除' })
- }}>删除</Button></Col>
- <Col><Dropdown
- menu={{
- items: [
- {
- label: <span style={{ display: 'inline-block', width: 120 }}>修改出价</span>,
- key: '1',
- disabled: selectedRows.length === 0,
- onClick: () => { setUpdateDate({ visible: true, type: '修改出价' }) }
- },
- {
- label: '修改名称',
- key: '2',
- disabled: selectedRows.length === 0,
- onClick: () => { setUpdateDate({ visible: true, type: '修改名称' }) }
- },
- {
- label: '修改日限额',
- key: '3',
- disabled: selectedRows.length === 0,
- onClick: () => { setUpdateDate({ visible: true, type: '修改日限额' }) }
- },
- {
- label: '修改投放日期',
- key: '4',
- disabled: selectedRows.length === 0,
- onClick: () => { setUpdateDate({ visible: true, type: '修改投放时间' }) }
- },
- {
- label: '修改投放首日开始时间',
- key: '5',
- disabled: selectedRows.length === 0,
- onClick: () => { setUpdateDate({ visible: true, type: '修改投放首日开始时间' }) }
- },
- {
- label: '一键起量',
- key: '6',
- disabled: selectedRows.length === 0,
- onClick: () => { setAutoAcqVisible(true) }
- }
- ]
- }}
- placement="bottomLeft"
- arrow
- >
- <Button>
- <Space>
- 修改广告
- <DownOutlined />
- </Space>
- </Button>
- </Dropdown></Col>
- </> : handleType === 2 ? <>
- <Col><UserTactics
- type="updateAd"
- onChange={(value) => {
- setTactics(value)
- addDynamic()
- }}
- userId={userId}
- putInType={useType === 1 ? 'NOVEL' : 'GAME'}
- /></Col>
- <Col><Button type='primary' icon={<PlusOutlined />} disabled={selectedRows.length === 0} onClick={addDynamic}>添加创意</Button></Col>
- <Col>
- <Space>
- <Tooltip title="选择的广告必须与已选广告的营销目的、营销载体、推广内容、广告版位、微信公众号与小程序定投、版位选择一致">
- <QuestionCircleOutlined style={{ color: 'red' }} />
- </Tooltip>
- {selectedRows?.length > 0 && <div style={{ maxWidth: '380px' }}>
- <Text type="danger" ellipsis={{ tooltip: true }} strong style={{ fontSize: 12 }}>
- {`当前广告选择:
- 营销目的:${useType === 2 ? MARKETING_SUB_GOAL_ENUM[selectedRows?.[0]?.marketingSubGoal as keyof typeof MARKETING_SUB_GOAL_ENUM] : MARKETING_GOAL_ENUM[selectedRows?.[0]?.marketingGoal as keyof typeof MARKETING_GOAL_ENUM]},
- 推广产品类型:${useType === 2 ? MARKETING_TARGET_TYPE_GAME_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_GAME_ENUM] : MARKETING_TARGET_TYPE_ENUM[selectedRows?.[0]?.marketingTargetType as keyof typeof MARKETING_TARGET_TYPE_ENUM]},
- 营销载体类型:${MARKETING_CARRIER_TYPE_ENUM[selectedRows?.[0]?.marketingCarrierType as keyof typeof MARKETING_CARRIER_TYPE_ENUM]},
- 版位选择:${selectedRows?.[0]?.automaticSiteEnabled ? '自动版位' : '选择特定版位'},
- ${!selectedRows?.[0]?.automaticSiteEnabled && `广告版位:${selectedRows?.[0]?.siteSet.map((item: string | number) => SITE_SET_ENUM[item as keyof typeof SITE_SET_ENUM]).toString()}`}
- `}
- </Text>
- </div>}
- </Space>
- </Col>
- </> : handleType === 3 ? <>
- <Col><Button type='primary' disabled={selectedRows.length === 0} onClick={() => {
- setUpdateDate({ visible: true, type: '深度优化ROI' })
- }}>修改首日付费 ROI</Button></Col>
- </> : handleType === 4 ? <>
- <Col><Button type='primary' disabled={selectedRows.length === 0} onClick={() => {
- setUpdateDate({ visible: true, type: '深度优化ROI' })
- }}>修改首日变现 ROI</Button></Col>
- </> : null}
- </Row>
- </Space>}
- rowSelection={{
- selectedRowKeys: selectedRows.map(item => item.adgroupId.toString()),
- // hideSelectAll: handleType === 3,
- getCheckboxProps: (record: any) => {
- if (handleType === 2 && selectedRows?.length > 0) {
- const { siteSet, marketingCarrierType, marketingGoal, marketingSubGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = selectedRows[0]
- return {
- disabled: record.isDeleted || !(
- record?.marketingGoal === marketingGoal && // 营销内容
- record?.marketingSubGoal === marketingSubGoal && // 二级营销内容
- record?.marketingCarrierType === marketingCarrierType && // 营销载体
- record?.marketingTargetType === marketingTargetType && // 推广产品
- record?.automaticSiteEnabled === automaticSiteEnabled && // 自动版位
- arraysHaveSameValues(siteSet || [], record?.siteSet || []) && // 版位选择
- arraysHaveSameValues(record?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
- )
- }
- } else {
- return {
- disabled:
- handleType === 3 ? record.isDeleted || !(record?.deepConversionSpec?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_PURCHASE_ROAS') :
- handleType === 4 ? record.isDeleted || !(record?.deepConversionSpec?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_MONETIZATION_ROAS')
- : record.isDeleted
- }
- }
- },
- onSelect: (record: { adgroupId: number, mpName: string }, selected: boolean) => {
- if (selected) {
- selectedRows.push({ ...record })
- setSelectedRows([...selectedRows])
- } else {
- let newSelectAccData = selectedRows.filter((item: { adgroupId: number }) => item.adgroupId !== record.adgroupId)
- setSelectedRows([...newSelectAccData])
- }
- },
- onSelectAll: (selected: boolean, selectedRowss: { adgroupId: number }[], changeRows: { adgroupId: number }[]) => {
- if (selected) {
- let newSelectAccData = [...selectedRows]
- let firstRow = newSelectAccData?.[0] || changeRows?.[0] || {}
- changeRows.forEach((item: { adgroupId: number }) => {
- let index = newSelectAccData.findIndex((ite: { adgroupId: number }) => ite.adgroupId === item.adgroupId)
- if (index === -1) {
- let data: any = { ...item }
- if (handleType === 2) {
- const { siteSet, marketingCarrierType, marketingGoal, marketingTargetType, sceneSpec, automaticSiteEnabled } = firstRow
- if (
- data?.marketingGoal === marketingGoal && // 营销内容
- data?.marketingCarrierType === marketingCarrierType && // 营销载体
- data?.marketingTargetType === marketingTargetType && // 推广产品
- data?.automaticSiteEnabled === automaticSiteEnabled && // 自动版位
- arraysHaveSameValues(siteSet || [], data?.siteSet || []) && // 版位选择
- arraysHaveSameValues(data?.sceneSpec?.wechatPosition || [], sceneSpec?.wechatPosition || []) // 微信公众号与小程序定投
- ) {
- newSelectAccData.push(data)
- }
- } else {
- newSelectAccData.push(data)
- }
- }
- })
- setSelectedRows([...newSelectAccData])
- } else {
- let newSelectAccData = selectedRows.filter((item: { adgroupId: number }) => {
- let index = changeRows.findIndex((ite: { adgroupId: number }) => ite.adgroupId === item.adgroupId)
- if (index !== -1) {
- return false
- } else {
- return true
- }
- })
- setSelectedRows([...newSelectAccData])
- }
- }
- }}
- onChange={(props: any) => {
- let { pagination, sortData } = props
- let { current, pageSize } = pagination
- let newQueryForm = JSON.parse(JSON.stringify(queryFrom))
- if (sortData && sortData?.order) {
- newQueryForm['isAsc'] = sortData?.order === 'ascend'
- newQueryForm['orderByColumn'] = [sortData?.field]
- } else {
- delete newQueryForm['isAsc']
- delete newQueryForm['orderByColumn']
- }
- newQueryForm.pageNum = current
- newQueryForm.pageSize = pageSize
- setPageSize(pageSize)
- set_queryFrom(newQueryForm)
- getList(newQueryForm)
- }}
- />
- {/* 修改广告 */}
- {update.visible && <UpdateAd
- {...update}
- selectedRows={selectedRows}
- onChange={() => {
- setUpdate({ visible: false })
- getAdqV3AdList.refresh()
- setSelectedRows([])
- }}
- onClose={() => { setUpdate({ visible: false }) }}
- />}
- {/* 新增创意 */}
- {addDynamicVisible && <AddDynamic
- adData={selectedRows}
- putInType={useType === 1 ? 'NOVEL' : 'GAME'}
- visible={addDynamicVisible}
- onClose={() => {
- setAddDynamicVisible(false)
- setTactics(undefined)
- getAdqV3AdList.refresh()
- }}
- tactics={tactics}
- onChange={() => {
- setAddDynamicVisible(false)
- getAdqV3AdList.refresh()
- setSelectedRows([])
- setTactics(undefined)
- }}
- />}
- {czjlShow && <Modal
- open={czjlShow}
- onCancel={() => { setCzjlShow(false) }}
- onOk={() => { setCzjlShow(false) }}
- width={1200}
- footer={null}
- title={<strong>广告操作记录</strong>}
- className="modalResetCss"
- >
- <Log userId={userId} />
- </Modal>}
- {/* 修改广告 */}
- {updateData.visible && <UpdateAd3
- {...updateData}
- updateData={selectedRows}
- onClose={() => {
- setUpdateDate({ visible: false, type: '修改出价' })
- }}
- onChange={() => {
- setUpdateDate({ visible: false, type: '修改出价' })
- getAdqV3AdList.refresh()
- if (updateData.type === '删除') {
- setSelectedRows([])
- }
- }}
- />}
- {/* 批量一键起量 */}
- {autoAcqVisible && <AutoAcquisitionSet
- selectAdList={selectedRows}
- visible={autoAcqVisible}
- onClose={() => {
- setAutoAcqVisible(false)
- }}
- onChange={() => {
- setAutoAcqVisible(false)
- getAdqV3AdList.refresh()
- setSelectedRows([])
- }}
- />}
- </div>
- }
- export default React.memo(Ad)
|