adPlanList.tsx 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. import { useAjax } from '@/Hook/useAjax'
  2. import { Col, Row, message, Space, Button, Switch, notification, Modal, Tooltip, Dropdown, Menu, Table, Statistic } from 'antd'
  3. import React, { useEffect, useCallback, useState, useRef } from 'react'
  4. import TableData from '../../components/TableData'
  5. import { putAdqAdgroupsSync, delListAdqAdgroupsApi, newEditAdqAdgroupsDataApi, editAdqAdgroupsDataApi, putAdqAdgroupsSyncBatch, putModifyCustomAudienceApi, getPutUserApi, delUserTagApi } from '@/services/launchAdq/adq'
  6. import { CopyOutlined, DeleteOutlined, DownOutlined, ExclamationCircleOutlined, FieldTimeOutlined, FormOutlined, LineChartOutlined, PauseCircleOutlined, PlayCircleOutlined, QuestionCircleOutlined, SyncOutlined, TransactionOutlined } from '@ant-design/icons'
  7. import UpdateAd from './updateAd'
  8. import Copy from './copy'
  9. import { planAdConfig } from '../config'
  10. import Log from '../log'
  11. import SetEarlyWarning from '@/components/EarlyWarning/setEarlyWarning'
  12. import CrowdPackModal from '../../components/crowdPackModal'
  13. import './index.less'
  14. import tablePlanConfig from './tablePlanListConfig'
  15. import { AdListProps, getAdListApi } from '@/services/adMonitor/adMonitor'
  16. import FilterQuery from './FilterQuery'
  17. import Details from '@/pages/adMonitor/adMonitorList/components/Details'
  18. import AdExpandedRowRender from './adExpandedRowRender'
  19. import { useSize, useUpdateEffect } from 'ahooks'
  20. import RuleAccountLog from '@/components/EarlyWarning/ruleAccountLog'
  21. import PlanTag from './planTag'
  22. import moment from 'moment'
  23. import ColumnTrend from '@/pages/adMonitor/adMonitorList/columnTrend'
  24. const AdPlanList: React.FC<{ userId: string }> = (props) => {
  25. /***********************/
  26. const { userId } = props
  27. const [selectedRows, setSelectedRows] = useState<any[]>([])
  28. const [update, setUpdate] = useState<{ visible: boolean, title: string }>({ visible: false, title: '' })
  29. const [model, setModel] = useState(true)
  30. const [copyData, setCopyData] = useState<{ visible: boolean }>({ visible: false })
  31. const [detailShow, setDetailShow] = useState<boolean>(false)
  32. const [detailData, setDetailData] = useState<any>({})
  33. const [czjlShow, setCzjlShow] = useState(false)
  34. const [cpVisible, setCpVisible] = useState(false)
  35. const [accountCreateLogs, setAccountCreateLogs] = useState<{ adAccountId: number, id: number, customAudienceList?: any[], excludedCustomAudienceList?: any[] }[]>([])
  36. const [queryForm, setQueryForm] = useState<AdListProps>({ pageNum: 1, pageSize: 20, columns: [], isDeleted: false, dataTimeMin: moment().subtract(7, 'days').format('YYYY-MM-DD'), dataTimeMax: moment().format('YYYY-MM-DD') })
  37. const [filterForm, setFilterForm] = useState<AdListProps>()
  38. const getAdList = useAjax((params) => getAdListApi(params), { formatResult: true })
  39. const syncAjax = useAjax((adAccountId) => putAdqAdgroupsSync(adAccountId))
  40. const delListAdqAdgroups = useAjax((params) => delListAdqAdgroupsApi(params))
  41. const editAdqAdgroupsData = useAjax((params) => newEditAdqAdgroupsDataApi(params))
  42. const editAdqAdgroups = useAjax((params) => editAdqAdgroupsDataApi(params))
  43. const putModifyCustomAudience = useAjax((params) => putModifyCustomAudienceApi(params))
  44. const putAdqAdgroupsSyncBatchApi = useAjax((params) => putAdqAdgroupsSyncBatch(params))
  45. const getPutUser = useAjax((params) => getPutUserApi(params))
  46. const delUserTag = useAjax((params) => delUserTagApi(params))
  47. const [logVisible, setLogVisible] = useState<boolean>(false)
  48. const [adgroupId, setAdgroupId] = useState<string>('')
  49. const [adgroupName, setAdgroupName] = useState<string>('')
  50. const [accountIdRule, setAccountIdRule] = useState<string>('')
  51. const [tagVisible, setTagVisible] = useState<boolean>(false)
  52. const [tagData, setTagData] = useState<any>({})
  53. const configName = '广告列表New'
  54. const ref = useRef(null)
  55. const size = useSize(ref)
  56. const [scrollLeft, setScrollLeft] = useState<number>(0)
  57. const [totalData, setTotalData] = useState<any>({})
  58. const [tableField, setTableField] = useState<{ title: string, dataIndex: string }[]>([])
  59. const [trendVisible, setTrendVisible] = useState<boolean>(false)
  60. const [trendData, setTrendData] = useState<any>({})
  61. /************************/
  62. useEffect(() => {
  63. getList()
  64. }, [filterForm, queryForm])
  65. const getList = () => {
  66. let message = localStorage.getItem(`myAdMonitorConfig1.0.0_${configName}`)
  67. if (message) {
  68. message = JSON.parse(message)
  69. }
  70. let columns: string[] = []
  71. if (message && Array.isArray(message)) {
  72. message.forEach((item: { serverIndex: any; dataIndex: string; }) => {
  73. if (!['cz', 'cost_speed'].includes(item.dataIndex)) {
  74. columns.push(item?.serverIndex || 'adgroup_data.' + item.dataIndex)
  75. }
  76. })
  77. } else {
  78. planAdConfig.forEach((item: any) => {
  79. item?.data?.forEach((d: { default: any, serverIndex: string, dataIndex: string }) => {
  80. if (d.default && !['cz', 'cost_speed'].includes(d.dataIndex)) {
  81. columns.push(d?.serverIndex || 'adgroup_data.' + d.dataIndex)
  82. }
  83. })
  84. })
  85. }
  86. getAdList.run({ ...queryForm, ...filterForm, columns })
  87. }
  88. useUpdateEffect(() => {
  89. let data: any = {}
  90. if (getAdList.data?.data?.sumRecord) {
  91. data = getAdList.data?.data?.sumRecord
  92. }
  93. setTotalData(data)
  94. }, [getAdList.data])
  95. useEffect(() => {
  96. let localData = localStorage.getItem('myAdMonitorConfig1.0.0_广告列表New')
  97. let data: any[] = []
  98. if (localData) {
  99. data = JSON.parse(localData)
  100. } else {
  101. let newSelectData: any[] = [];
  102. (planAdConfig as any).forEach((item: { data: { default: any }[] }) => {
  103. item?.data?.forEach((d: { default: any }) => {
  104. if (d.default) {
  105. newSelectData[d.default - 1] = d
  106. }
  107. })
  108. })
  109. data = newSelectData
  110. }
  111. data.unshift({ title: '选择框', dataIndex: 'xzk' })
  112. data.unshift({ title: '总计', dataIndex: 'zj' })
  113. setTableField(data)
  114. }, [localStorage.getItem('myAdMonitorConfig1.0.0_广告列表New')])
  115. useEffect(() => {
  116. getPutUser.run({ userId })
  117. }, [userId])
  118. // 同步
  119. const sync = useCallback(() => {
  120. let arr = [...new Set(selectedRows?.map(item => item.accountId))]
  121. syncAjax.run({ accountIdList: arr }).then(res => {
  122. res && getAdList.refresh()
  123. res ? message.success('同步成功!') : message.error('同步失败!')
  124. })
  125. }, [getAdList, selectedRows])
  126. /** 删除 */
  127. const deleteHandle = (type: 0 | 1, adgroupId?: number) => {
  128. const hide = message.loading('删除中。。。', 0)
  129. delListAdqAdgroups.run({ adgroupIds: type === 1 ? selectedRows.map(item => item.adgroup_id) : [adgroupId] }).then(res => {
  130. hide()
  131. message.success('删除成功')
  132. setSelectedRows([])
  133. getAdList.refresh()
  134. }).catch(() => hide())
  135. }
  136. /** 修改排期出价 */
  137. const editScheduling = () => {
  138. setUpdate({ visible: true, title: '批量修改' })
  139. }
  140. /** 修改排期出价 */
  141. const editDeepConversion = () => {
  142. setUpdate({ visible: true, title: '批量修改深度优化' })
  143. }
  144. // 单个启停
  145. const onChange = () => {
  146. getAdList.refresh()
  147. setSelectedRows([])
  148. }
  149. // 批量启停
  150. const adStatus = (type: 'play' | 'suspend') => {
  151. let params: any = {}
  152. if (type === 'play') {
  153. params.configuredStatus = 'AD_STATUS_NORMAL'
  154. params.adgroupIds = selectedRows.filter((item: { configuredStatus: string, adgroup_id: number }) => item.configuredStatus === 'AD_STATUS_SUSPEND').map(item => item.adgroup_id)
  155. } else {
  156. params.configuredStatus = 'AD_STATUS_SUSPEND'
  157. params.adgroupIds = selectedRows.filter((item: { configuredStatus: string, adgroup_id: number }) => item.configuredStatus === 'AD_STATUS_NORMAL').map(item => item.adgroup_id)
  158. }
  159. if (params.adgroupIds.length === 0) {
  160. message.warn(`所以账号都是${type === 'play' ? '启动' : '暂停'}状态,无需${type === 'play' ? '启动' : '暂停'}操作`)
  161. return
  162. }
  163. editAdqAdgroupsData.run(params).then(res => {
  164. message.success(`${type === 'play' ? '启动' : '暂停'}成功: ${res.success},失败: ${res.fail}`)//
  165. if (res?.fail) {
  166. notification.error({
  167. message: `${type === 'play' ? '启动' : '暂停'}失败`,
  168. description: `成功: ${res.success},修改失败${res.fail}条,失败的请到任务列表查看`,
  169. duration: 0
  170. });
  171. }
  172. getAdList.refresh()
  173. setSelectedRows([])
  174. })
  175. }
  176. //同步广告
  177. const syncAd = useCallback(() => {
  178. const hide = message.loading('同步中。。。', 0)
  179. putAdqAdgroupsSyncBatchApi.run({ adgroupIds: selectedRows?.map(item => item.adgroup_id) }).then(res => {
  180. hide()
  181. if (res) {
  182. message.success('同步成功!')
  183. getAdList.refresh()
  184. }
  185. }).catch(() => hide())
  186. }, [selectedRows])
  187. // 批量复制
  188. const copyHandle = () => {
  189. setCopyData({ visible: true })
  190. }
  191. const handleSave = (row: any) => {
  192. const hide = message.loading(`广告“${row.adgroup_id}”广告名称修改成<${row.adgroup_name}>,修改中`, 0, () => {
  193. message.success('修改成功');
  194. });
  195. editAdqAdgroups.run({ adgroupIds: [row.adgroup_id], adgroupName: row.adgroup_name }).then(res => {
  196. message.success('修改广告名称成功')
  197. getAdList.refresh()
  198. hide()
  199. })
  200. }
  201. const handleSaveDaily = (row: any) => {
  202. console.log('row--->', row)
  203. const hide = message.loading(`广告“${row.adgroup_id}”广告预算修改成<${row.daily_budget}元>,修改中`, 0, () => {
  204. message.success('修改成功');
  205. });
  206. editAdqAdgroups.run({ adgroupIds: [row.adgroup_id], dailyBudget: row.daily_budget * 100 }).then(res => {
  207. message.success('修改广告预算成功')
  208. getAdList.refresh()
  209. hide()
  210. })
  211. }
  212. const details = (data: any) => {
  213. setDetailData(data)
  214. setDetailShow(true)
  215. }
  216. // 设置人群包
  217. const setRqb = () => {
  218. const { accountId } = selectedRows[0]
  219. setAccountCreateLogs([{ id: accountId, adAccountId: accountId }])
  220. setCpVisible(true)
  221. }
  222. // 确认提交人群包
  223. const handleRqb = (value: any[]) => {
  224. if ((value[0]?.customAudienceList && value[0]?.customAudienceList?.length > 0) || (value[0]?.excludedCustomAudienceList && value[0]?.excludedCustomAudienceList?.length > 0)) {
  225. let { adAccountId, customAudienceList = [], excludedCustomAudienceList = [] } = value[0]
  226. let adgroupIds = selectedRows.map((item: { adgroup_id: number }) => item.adgroup_id)
  227. let customAudienceIds = customAudienceList.map((item: { id: number }) => item.id)
  228. let excludedCustomAudienceIds = excludedCustomAudienceList.map((item: { id: number }) => item.id)
  229. const hide = message.loading('正在修改。。。', 0)
  230. setAccountCreateLogs([])
  231. setCpVisible(false)
  232. let params: any = { adAccountId, adgroupIds };
  233. if (excludedCustomAudienceIds.length > 0) {
  234. params['excludedCustomAudienceIds'] = excludedCustomAudienceIds
  235. }
  236. if (customAudienceIds?.length > 0) {
  237. params['customAudienceIds'] = customAudienceIds
  238. }
  239. putModifyCustomAudience.run(params).then(res => {
  240. hide()
  241. setSelectedRows([])
  242. message.success('修改成功,请到腾讯广告平台查看')
  243. }).catch(err => hide())
  244. } else {
  245. message.error('请选择用户群')
  246. }
  247. }
  248. useEffect(() => {
  249. const headerBodyScroll = (e: any) => {
  250. let el = document.querySelector(`.expandClassname .expendTable .ant-table-body`);
  251. if (el) {
  252. setScrollLeft(e.target.scrollLeft)
  253. }
  254. }
  255. document.querySelector(`.expandClassname .expendTable .ant-table-body`)?.addEventListener('scroll', headerBodyScroll);
  256. () => {
  257. document.querySelector(`.expandClassname .expendTable .ant-table-body`)?.removeEventListener('scroll', headerBodyScroll);
  258. }
  259. }, [])
  260. const log = (value: any) => {
  261. setAccountIdRule(value.account_id)
  262. setAdgroupId(value.adgroup_id)
  263. setAdgroupName(value.adgroup_name)
  264. setLogVisible(true)
  265. }
  266. const handleTag = (value: any) => {
  267. setTagData(value)
  268. setTagVisible(true)
  269. }
  270. const delTag = (value: any) => {
  271. delUserTag.run({ accountId: value.account_id, adgroupId: value.adgroup_id }).then(res => {
  272. if (res) {
  273. message.success('删除成功')
  274. getAdList.refresh()
  275. }
  276. })
  277. }
  278. const handleColumnTrend = (value: string) => {
  279. let message = localStorage.getItem(`myAdMonitorConfig1.0.0_${configName}`)
  280. if (message) {
  281. message = JSON.parse(message)
  282. }
  283. let columns: string[] = []
  284. if (message && Array.isArray(message)) {
  285. message.forEach((item: { serverIndex: any; dataIndex: string; }) => {
  286. if (!['cz', 'cost_speed'].includes(item.dataIndex)) {
  287. columns.push(item?.serverIndex || 'adgroup_data.' + item.dataIndex)
  288. }
  289. })
  290. } else {
  291. planAdConfig.forEach((item: any) => {
  292. item?.data?.forEach((d: { default: any, serverIndex: string, dataIndex: string }) => {
  293. if (d.default && !['cz', 'cost_speed'].includes(d.dataIndex)) {
  294. columns.push(d?.serverIndex || 'adgroup_data.' + d.dataIndex)
  295. }
  296. })
  297. })
  298. }
  299. setTrendData({ ...queryForm, ...filterForm, columns, field: value.replace('_total', '') })
  300. setTrendVisible(true)
  301. }
  302. const countDecimals = (num: number) => {
  303. // 匹配数字的小数部分
  304. const match = String(num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
  305. // 返回小数位数
  306. return match ? Math.max(0, (match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0)) : 0;
  307. }
  308. return <div>
  309. {/* 列表指标趋势 */}
  310. {trendVisible && <ColumnTrend visible={trendVisible} data={trendData} onClose={() => { setTrendVisible(false) }} />}
  311. {/* 打标签 */}
  312. {tagVisible && <PlanTag
  313. visible={tagVisible}
  314. data={tagData}
  315. onClose={() => setTagVisible(false)}
  316. onChange={() => {
  317. getAdList.refresh()
  318. setTagVisible(false)
  319. }}
  320. />}
  321. {/* 修改广告 */}
  322. {update.visible && <UpdateAd
  323. {...update}
  324. selectedRows={selectedRows}
  325. onChange={() => {
  326. setUpdate({ visible: false, title: '' })
  327. getAdList.refresh()
  328. setSelectedRows([])
  329. }}
  330. onClose={() => { setUpdate({ visible: false, title: '' }) }}
  331. />}
  332. {/* 复制广告 */}
  333. {copyData.visible && <Copy selectedRows={selectedRows} {...copyData} onClose={() => setCopyData({ visible: false })} onChange={() => { setCopyData({ visible: false }); getAdList.refresh(); setSelectedRows([]) }} />}
  334. <Row gutter={[6, 6]} align='middle' style={{ marginBottom: 10 }}>
  335. <FilterQuery
  336. queryForm={queryForm}
  337. setQueryForm={setQueryForm}
  338. onChange={(value) => {
  339. setFilterForm({ ...value })
  340. }}
  341. />
  342. </Row>
  343. <div ref={ref} className='expandClassname'>
  344. <TableData
  345. refreshData={getList}
  346. isCard={false}
  347. className='expendTable'
  348. columns={() => tablePlanConfig(onChange, details, handleSave, handleSaveDaily, log, handleTag, delTag)}
  349. ajax={getAdList}
  350. syncAjax={sync}
  351. fixed={{ left: 2, right: 4 }}
  352. dataSource={getAdList?.data?.data?.records}
  353. loading={getAdList?.loading || syncAjax?.loading}
  354. scroll={{ y: 560 }}
  355. total={getAdList?.data?.data?.total}
  356. page={getAdList?.data?.data?.current}
  357. pageSize={getAdList?.data?.data?.size}
  358. myKey={'adgroup_id'}
  359. gutter={[0, 10]}
  360. config={planAdConfig}
  361. configName={configName}
  362. rowClassName={(record) => {
  363. if (record?.tag_value === 100) {
  364. return 'row_error'
  365. } else if (record?.tag_value === 90) {
  366. return 'row_warning'
  367. } else {
  368. return ''
  369. }
  370. }}
  371. leftChild={<Space direction='vertical'>
  372. <Row gutter={[10, 10]} align='middle'>
  373. <Col>
  374. <Switch checkedChildren="普通" unCheckedChildren="ROI" checked={model} onChange={(checked) => { setModel(checked); setSelectedRows([]) }} style={model ? {} : { background: '#67c23a' }} />
  375. </Col>
  376. {!model && <Col><Button type='primary' icon={<TransactionOutlined />} disabled={selectedRows.length === 0} onClick={editDeepConversion}>修改深度优化ROI</Button></Col>}
  377. <Col><Button type='primary' style={{ background: '#1890ff' }} icon={<CopyOutlined />} disabled={selectedRows.length === 0} onClick={copyHandle}>复制</Button></Col>
  378. <Col><Button type='primary' style={{ background: '#67c23a', borderColor: '#67c23a' }} loading={editAdqAdgroupsData.loading} icon={<PlayCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('play')}>启动</Button></Col>
  379. <Col><Button type='primary' style={{ background: '#e6a23c', borderColor: '#e6a23c' }} loading={editAdqAdgroupsData.loading} icon={<PauseCircleOutlined />} disabled={selectedRows.length === 0} onClick={() => adStatus('suspend')}>暂停</Button></Col>
  380. <Col><SetEarlyWarning selectedRows={selectedRows} onChange={() => getAdList.refresh()} /></Col>
  381. <Col>
  382. <Dropdown overlay={<Menu
  383. onClick={(e) => {
  384. switch (e.key) {
  385. case '1':
  386. editScheduling()
  387. break
  388. case '2':
  389. setRqb()
  390. break
  391. case '3':
  392. syncAd()
  393. break
  394. case '4':
  395. Modal.confirm({
  396. title: '删除',
  397. content: '确定删除?',
  398. icon: <ExclamationCircleOutlined />,
  399. okType: 'danger',
  400. onOk() {
  401. deleteHandle(1)
  402. }
  403. });
  404. break
  405. }
  406. }}
  407. items={[
  408. {
  409. key: '1',
  410. disabled: selectedRows.length === 0,
  411. label: <Button type="link" size='small' style={{ padding: 0 }} icon={<FieldTimeOutlined />} disabled={selectedRows.length === 0}>修改排期出价名称</Button>,
  412. },
  413. {
  414. key: '2',
  415. disabled: selectedRows.length > 0 ? !selectedRows.every((item: { accountId: number }) => item.accountId === selectedRows[0].accountId) : true,
  416. label: <Button type="link" size='small' style={{ padding: 0 }} icon={<FormOutlined />} loading={putModifyCustomAudience.loading} disabled={selectedRows.length > 0 ? !selectedRows.every((item: { accountId: number }) => item.accountId === selectedRows[0].accountId) : true}>
  417. 修改人群包
  418. <Tooltip title="2023/4/20 16:20:00刷新页面后平台创建的广告可修改,或者其它平台使用定向包创建广告可用">
  419. <QuestionCircleOutlined />
  420. </Tooltip>
  421. </Button>,
  422. },
  423. {
  424. key: '3',
  425. disabled: selectedRows.length === 0,
  426. label: <Button type="link" size='small' style={{ padding: 0 }} loading={putAdqAdgroupsSyncBatchApi.loading} icon={<SyncOutlined />} disabled={selectedRows.length === 0}>同步广告</Button>,
  427. },
  428. {
  429. key: '4',
  430. disabled: selectedRows.length === 0,
  431. label: <Button danger type="link" size='small' style={{ padding: 0 }} loading={delListAdqAdgroups.loading} icon={<DeleteOutlined />} disabled={selectedRows.length === 0}>删除</Button>,
  432. },
  433. ]} />}>
  434. <a onClick={(e) => e.preventDefault()}>
  435. <Space>
  436. 更多
  437. <DownOutlined />
  438. </Space>
  439. </a>
  440. </Dropdown>
  441. </Col>
  442. <Col>
  443. <Button type='dashed' onClick={() => { setCzjlShow(true) }}>操作记录</Button>
  444. </Col>
  445. </Row>
  446. </Space>}
  447. rowSelection={{
  448. selectedRowKeys: selectedRows.map(item => item.adgroup_id.toString()),
  449. getCheckboxProps: (record: any) => ({
  450. disabled: model ?
  451. record.status === 'STATUS_DELETED' :
  452. record.status === 'STATUS_DELETED' ||
  453. !(!model &&
  454. JSON.parse(record?.deep_conversion_spec_json)?.deepConversionWorthSpec?.goal === 'GOAL_1DAY_PURCHASE_ROAS'
  455. )
  456. }),
  457. onSelect: (record: { adgroup_id: number, mpName: string }, selected: boolean) => {
  458. if (selected) {
  459. selectedRows.push({ ...record })
  460. setSelectedRows([...selectedRows])
  461. } else {
  462. let newSelectAccData = selectedRows.filter((item: { adgroup_id: number }) => item.adgroup_id !== record.adgroup_id)
  463. setSelectedRows([...newSelectAccData])
  464. }
  465. },
  466. onSelectAll: (selected: boolean, selectedRowss: { adgroup_id: number }[], changeRows: { adgroup_id: number }[]) => {
  467. if (selected) {
  468. let newSelectAccData = [...selectedRows]
  469. changeRows.forEach((item: { adgroup_id: number }) => {
  470. let index = newSelectAccData.findIndex((ite: { adgroup_id: number }) => ite.adgroup_id === item.adgroup_id)
  471. if (index === -1) {
  472. newSelectAccData.push({ ...item })
  473. }
  474. })
  475. setSelectedRows([...newSelectAccData])
  476. } else {
  477. let newSelectAccData = selectedRows.filter((item: { adgroup_id: number }) => {
  478. let index = changeRows.findIndex((ite: { adgroup_id: number }) => ite.adgroup_id === item.adgroup_id)
  479. if (index !== -1) {
  480. return false
  481. } else {
  482. return true
  483. }
  484. })
  485. setSelectedRows([...newSelectAccData])
  486. }
  487. }
  488. }}
  489. onChange={(props: any) => {
  490. let { sortData, pagination } = props
  491. let { current, pageSize } = pagination
  492. let newQueryForm = JSON.parse(JSON.stringify(queryForm))
  493. newQueryForm.pageNum = current
  494. newQueryForm.pageSize = pageSize
  495. if (sortData && JSON.stringify('sortData') !== '{}') {
  496. let { field, order } = sortData // descend 降序 大到小 ascend 升序 小到大
  497. if (order) {
  498. newQueryForm.sortColumn = field
  499. newQueryForm.sortAsc = order === 'ascend'
  500. } else {
  501. Object.keys(newQueryForm).forEach(key => {
  502. if (key === 'sortColumn' || key === 'sortAsc') {
  503. delete newQueryForm[key]
  504. }
  505. })
  506. }
  507. } else {
  508. Object.keys(newQueryForm).forEach(key => {
  509. if (key === 'sortField' || key === 'sort') {
  510. delete newQueryForm[key]
  511. }
  512. })
  513. }
  514. setQueryForm({ ...newQueryForm })
  515. }}
  516. expandedRowRender={(data) => <AdExpandedRowRender data={data} scrollLeft={scrollLeft} width={size?.width} />}
  517. summary={() => (
  518. <Table.Summary fixed>
  519. <Table.Summary.Row className='s_summary'>
  520. {tableField.map((item, index) => {
  521. let data = totalData[item.dataIndex]
  522. let value = (data === 0 || data) ? countDecimals(data) > 2 ? data.toFixed(2) : data : '--'
  523. if (item.dataIndex === 'zj') {
  524. return <Table.Summary.Cell index={index} key={item.dataIndex} align="center"><strong>总计</strong></Table.Summary.Cell>
  525. } else if (['ctr_total', 'mp_follow_rate_total',
  526. 'add_quick_app_rate_total', 'scan_follow_rate_total',
  527. 'first_day_order_roi_total', 'order_rate_total',
  528. 'order_roi_total', 'conversions_rate_total'
  529. ].includes(item.dataIndex)) {
  530. return <Table.Summary.Cell index={index} key={item.dataIndex} align="center">
  531. <Space size={4}>
  532. <strong>
  533. {value !== '--' ? <Statistic value={value} precision={2} valueStyle={{ color: '#3f8600' }} suffix="%" /> : '--'}
  534. </strong>
  535. {value !== '--' && <a onClick={() => handleColumnTrend(item.dataIndex)}><LineChartOutlined /></a>}
  536. </Space>
  537. </Table.Summary.Cell>
  538. } else {
  539. return <Table.Summary.Cell index={index} key={item.dataIndex} align="center">
  540. <Space size={4}>
  541. <strong><Statistic value={value} /></strong>
  542. {value !== '--' && <a onClick={() => handleColumnTrend(item.dataIndex)}><LineChartOutlined /></a>}
  543. </Space>
  544. </Table.Summary.Cell>
  545. }
  546. })}
  547. </Table.Summary.Row>
  548. </Table.Summary>
  549. )}
  550. />
  551. </div>
  552. {detailShow && <Details visible={detailShow} onClose={() => { setDetailShow(false) }} data={detailData} />}
  553. {czjlShow && <Modal
  554. visible={czjlShow}
  555. onCancel={() => { setCzjlShow(false) }}
  556. onOk={() => { setCzjlShow(false) }}
  557. width={1200}
  558. footer={null}
  559. title={"广告操作记录"}
  560. >
  561. <Log {...props} />
  562. </Modal>}
  563. {cpVisible && <CrowdPackModal visible={cpVisible} data={accountCreateLogs} onClose={() => setCpVisible(false)} onChange={(e) => { handleRqb(e) }} />}
  564. {logVisible && <RuleAccountLog accountId={accountIdRule} adgroupName={adgroupName} adgroupId={adgroupId} visible={logVisible} onClose={() => setLogVisible(false)} />}
  565. </div>
  566. }
  567. export default AdPlanList