index.tsx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. import Selector from "@/pages/launchSystemNew/launchManage/createAd/selector"
  2. import React, { useEffect, useState } from "react"
  3. import style from './index.less'
  4. import { Button, Input, message, Modal, Select, Table, Tag, Tooltip, Typography } from "antd";
  5. import { CloseCircleFilled } from "@ant-design/icons";
  6. import { getGroupListApi, getAccountListApi } from "@/services/launchAdq/subgroup";
  7. import { useAjax } from "@/Hook/useAjax";
  8. import { getAccountAssetsGroupListAllApi } from "@/services/adqV3/global";
  9. import { getAllUserAccountApi } from "@/services/launchAdq/adAuthorize";
  10. import { arraysHaveSameValues, groupBy } from "@/utils/utils";
  11. import { DELIVERY_MODE_ENUM } from "../../const";
  12. import '../../index.less'
  13. const { Text } = Typography;
  14. interface Props {
  15. setAccountCreateLogs: React.Dispatch<React.SetStateAction<PULLIN.AccountCreateLogsProps[]>>
  16. accountCreateLogs: PULLIN.AccountCreateLogsProps[]
  17. setOwnerAccountId: React.Dispatch<React.SetStateAction<number | undefined>>
  18. ownerAccountId: number | undefined
  19. deliveryMode?: keyof typeof DELIVERY_MODE_ENUM
  20. mType?: string,
  21. putInType?: 'NOVEL' | 'GAME'
  22. onChange?: (value?: any[], isClear?: boolean) => void
  23. dynamicGroup?: any[]
  24. }
  25. /**
  26. * 选择账户
  27. * @returns
  28. */
  29. const SelectAccount: React.FC<Props> = ({ putInType, accountCreateLogs, setAccountCreateLogs, onChange, dynamicGroup, deliveryMode, mType }) => {
  30. /***********************************/
  31. const [visible, setVisible] = useState<boolean>(false)
  32. const [assetSharingDeta, setAssetSharingDeta] = useState<{ authMainAccountId: number, groupId: number }>() // 资产共享组
  33. const [dataSource, setDataSource] = useState<any[]>([])
  34. const [options, setOptions] = useState<any[]>([])
  35. const [selectedRows, setSelectedRows] = useState<any[]>([])
  36. const [mediaTypeGroupIds, setMediaTypeGroupIds] = useState<number[]>([])
  37. const [loading, setLoading] = useState<boolean>(false)
  38. const [inputAccountList, setInputAccountList] = useState<string[]>([])
  39. const [tipsVisible, setTipsVisible] = useState<boolean>(false)
  40. const getGroupList = useAjax(() => getGroupListApi())
  41. const getAccountAssetsGroupListAll = useAjax((params) => getAccountAssetsGroupListAllApi(params))
  42. const getAllUserAccount = useAjax(() => getAllUserAccountApi())
  43. /***********************************/
  44. // 判断选择的账号是否在同一个资产组,允许选择云端素材的关键
  45. const getauthMainAccountData = (accountCreateLogs: PULLIN.AccountCreateLogsProps[]) => {
  46. console.log('---->', getAllUserAccount?.data)
  47. if (getAllUserAccount?.data?.length && accountCreateLogs?.length) {
  48. const list = accountCreateLogs.map(item => item.accountId)
  49. const selectAccountList = getAllUserAccount.data.filter((item: { accountId: any }) => list.includes(item.accountId))
  50. const groupAccount = groupBy(selectAccountList, (item) => item.groupId, true)
  51. const GrounpArray = Object.keys(groupAccount).map(function (group) {
  52. return groupAccount[group];
  53. })
  54. if (GrounpArray.length === 1) {
  55. return { authMainAccountId: GrounpArray?.[0]?.[0]?.authMainAccountId || GrounpArray?.[0]?.[0]?.accountId, isSelectRemote: true }
  56. } else if (GrounpArray.length === 2 && groupAccount?.['undefined']?.length === 1) {
  57. const undefinedAccount = groupAccount?.['undefined'][0].accountId
  58. let authMainAccountId: any
  59. Object.keys(groupAccount).forEach(key => {
  60. if (key !== 'undefined') {
  61. authMainAccountId = groupAccount[key][0].authMainAccountId
  62. }
  63. })
  64. if (undefinedAccount === authMainAccountId) {
  65. return { authMainAccountId: authMainAccountId, isSelectRemote: true }
  66. } else {
  67. return { authMainAccountId: -1, isSelectRemote: false }
  68. }
  69. } else {
  70. return { authMainAccountId: -1, isSelectRemote: false }
  71. }
  72. } else {
  73. return { authMainAccountId: undefined, isSelectRemote: false }
  74. }
  75. }
  76. useEffect(() => {
  77. if (visible && accountCreateLogs?.length) {
  78. setSelectedRows(accountCreateLogs)
  79. }
  80. }, [accountCreateLogs, visible])
  81. useEffect(() => {
  82. if (putInType) {
  83. // 获取账户组
  84. getGroupList.run()
  85. // 获取资产共享组
  86. getAccountAssetsGroupListAll.run({})
  87. // 账户
  88. getAllUserAccount.run().then(res => {
  89. if (res) {
  90. let options = res?.filter((item: any) => putInType === 'NOVEL' ? ['NOVEL', 'NOVEL_IAA'].includes(item.adUnitType) : putInType === 'GAME' ? ['GAME', 'GAME_IAA'].includes(item.adUnitType) : false)
  91. setOptions(options || [])
  92. setDataSource(options || [])
  93. }
  94. })
  95. }
  96. return () => {
  97. document.body.style.overflow = 'auto';
  98. }
  99. }, [putInType])
  100. /** 获取分组里账号 */
  101. const getGroupAccountList = (ids: number[]) => {
  102. setMediaTypeGroupIds(ids)
  103. setAssetSharingDeta(undefined)
  104. if (ids.length > 0) {
  105. setLoading(true)
  106. let data = ids.map(id => getAccountListApi(id))
  107. Promise.all(data).then(res => {
  108. setLoading(false)
  109. if (res?.length > 0 && res.every((item: { code: number }) => item.code === 200)) {
  110. let userArr: any[] = []
  111. res.forEach((item: { data: { adAccountList: { accountId: number, id: number }[] } }) => {
  112. item.data.adAccountList.forEach(acc => {
  113. let obj = userArr.find((item: { accountId: number }) => item.accountId === acc.accountId)
  114. if (!obj) {
  115. userArr.push(acc.accountId)
  116. }
  117. })
  118. })
  119. setDataSource(options.filter(item => userArr.includes(item.accountId)))
  120. } else {
  121. message.error('操作异常')
  122. }
  123. })
  124. } else {
  125. setDataSource(options)
  126. }
  127. }
  128. const handleOk = (isClear: boolean) => {
  129. document.body.style.overflow = 'auto';
  130. onChange?.(selectedRows, isClear)
  131. setSelectedRows([])
  132. setInputAccountList([])
  133. setMediaTypeGroupIds([])
  134. setAssetSharingDeta(undefined)
  135. setVisible(false)
  136. setTipsVisible(false)
  137. }
  138. const handleCancel = () => {
  139. document.body.style.overflow = 'auto';
  140. setSelectedRows([])
  141. setInputAccountList([])
  142. setMediaTypeGroupIds([])
  143. setAssetSharingDeta(undefined)
  144. setVisible(false)
  145. }
  146. return <div className={style.selectAccount}>
  147. <div className={style.selectAccount_row} style={{ zIndex: visible ? 1000 : 1 }}>
  148. <Selector
  149. label={visible ? '选择账户' : '媒体账户'}
  150. style={visible ? { borderColor: '#1890ff' } : {}}
  151. titleStyle={visible ? { borderColor: '#1890ff', color: '#1890ff' } : {}}
  152. >
  153. <div
  154. className={style.selectAccount_select}
  155. onClick={() => {
  156. document.body.style.overflow = 'hidden';
  157. setVisible(true)
  158. }}
  159. >
  160. <div className={style.selectAccount_select_content}>
  161. {(visible && selectedRows.length > 0) ? <>
  162. <Tag
  163. closable
  164. color="#F5F5F5"
  165. key={selectedRows[0].accountId}
  166. className={style.content_tag}
  167. onClose={() => {
  168. setSelectedRows(selectedRows.slice(1))
  169. }}
  170. >{selectedRows[0].accountId}</Tag>
  171. {selectedRows?.length > 1 && <Tooltip
  172. color="#FFF"
  173. title={<span style={{ color: '#000' }}>
  174. {selectedRows?.filter((_, index) => index !== 0)?.map((item) => <Tag
  175. color="#F5F5F5"
  176. className={style.content_tag}
  177. key={item.accountId}
  178. closable
  179. onClose={() => {
  180. setSelectedRows(selectedRows?.filter(item1 => item1.accountId !== item.accountId))
  181. }}
  182. >{item.accountId}</Tag>)}</span>
  183. }
  184. >
  185. <Tag color="#F5F5F5" className={style.content_tag}>+{selectedRows.length - 1}</Tag>
  186. </Tooltip>}
  187. </> : (!visible && accountCreateLogs?.length > 0) ? <>
  188. <Tag
  189. closable
  190. color="#F5F5F5"
  191. className={style.content_tag}
  192. key={accountCreateLogs[0].accountId}
  193. onClose={() => {
  194. setAccountCreateLogs(accountCreateLogs.slice(1))
  195. }}
  196. >{accountCreateLogs[0].accountId}</Tag>
  197. {accountCreateLogs?.length > 1 && <Tooltip
  198. color="#FFF"
  199. title={<span style={{ color: '#000' }}>
  200. {accountCreateLogs?.filter((_, index) => index !== 0)?.map((item) => <Tag
  201. className={style.content_tag}
  202. color="#F5F5F5"
  203. key={item.accountId}
  204. closable
  205. onClose={() => {
  206. setAccountCreateLogs(accountCreateLogs?.filter(item1 => item1.accountId !== item.accountId))
  207. }}
  208. >{item.accountId}</Tag>)}</span>
  209. }
  210. >
  211. <Tag color="#F5F5F5" className={style.content_tag}>+{accountCreateLogs.length - 1}</Tag>
  212. </Tooltip>}
  213. </> : <Text type="secondary">请选择媒体账户</Text>}
  214. </div>
  215. {visible}
  216. {((visible && selectedRows.length > 0) || (!visible && accountCreateLogs?.length > 0)) && <a className={style.clear} onClick={(e) => {
  217. e.stopPropagation()
  218. if (visible) {
  219. setSelectedRows([])
  220. } else {
  221. setAccountCreateLogs([])
  222. }
  223. }}><CloseCircleFilled /></a>}
  224. </div>
  225. </Selector>
  226. {visible && <div className={style.selectAccount_list}>
  227. <div className={style.selectAccount_list_header}>
  228. <Input.TextArea
  229. rows={1}
  230. autoSize={{ minRows: 1, maxRows: 1 }}
  231. placeholder="账户/备注(多个,,空格换行)"
  232. style={{ width: 200 }}
  233. allowClear
  234. onChange={e => {
  235. let input = e.target.value
  236. let newInput: string[] = input ? input?.split(/[,,\n\s]+/ig).filter((item: any) => item) : []
  237. setInputAccountList(newInput)
  238. }}
  239. />
  240. <Select
  241. mode="multiple"
  242. style={{ minWidth: 200 }}
  243. placeholder="快捷选择媒体账户组"
  244. maxTagCount={1}
  245. allowClear
  246. filterOption={(input: any, option: any) => {
  247. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  248. }}
  249. value={mediaTypeGroupIds}
  250. onChange={(e) => { getGroupAccountList(e) }}
  251. >
  252. {getGroupList?.data && getGroupList?.data?.map((item: any) => <Select.Option value={item.groupId} key={item.groupId}>{item.groupName}</Select.Option>)}
  253. </Select>
  254. <Select
  255. allowClear
  256. showSearch
  257. placeholder="账户资产共享组"
  258. filterOption={(input: any, option: any) => {
  259. return option!.children?.toString().toLowerCase().includes(input.toLowerCase())
  260. }}
  261. style={{ width: 145 }}
  262. value={assetSharingDeta?.groupId}
  263. onChange={(_, option) => {
  264. setMediaTypeGroupIds([])
  265. if (option) {
  266. let assetSharingDeta = { groupId: option.value, authMainAccountId: option.authMainAccountId }
  267. setAssetSharingDeta({ groupId: option.value, authMainAccountId: option.authMainAccountId })
  268. setDataSource(options?.filter((item: { accountId: number; groupId: number }) => assetSharingDeta?.groupId ? (item.accountId?.toString() === assetSharingDeta?.authMainAccountId?.toString() || item?.groupId?.toString() === assetSharingDeta?.groupId?.toString()) : true))
  269. } else {
  270. setAssetSharingDeta(undefined)
  271. setDataSource(options)
  272. }
  273. }}
  274. >
  275. {getAccountAssetsGroupListAll?.data?.map((item: { accountId: any; authMainAccountId: number; id: number; accountGroupName: string }) => <Select.Option value={item.accountId} authMainAccountId={item.authMainAccountId} key={item.id}>{item.accountGroupName}({item.authMainAccountId})</Select.Option>)}
  276. </Select>
  277. </div>
  278. <div className={style.selectAccount_list_table}>
  279. <Table
  280. size={'small'}
  281. bordered
  282. dataSource={dataSource.filter(item => inputAccountList?.length > 0 ? inputAccountList?.some(val => item.accountId?.toString().toLowerCase()?.includes(val) || item?.remark?.toString().toLowerCase()?.includes(val)) : true)}
  283. rowKey={'accountId'}
  284. scroll={{ y: 220 }}
  285. pagination={{
  286. pageSize: 50,
  287. showTotal: total => `总共 ${total} 账户`
  288. }}
  289. loading={getAllUserAccount.loading || loading}
  290. columns={[
  291. {
  292. title: '账号',
  293. dataIndex: 'accountId',
  294. key: 'accountId',
  295. width: 80,
  296. align: 'center',
  297. render(value) {
  298. return <span style={{ fontSize: 12 }}>{value}</span>
  299. }
  300. },
  301. {
  302. title: '企业',
  303. dataIndex: 'corporationName',
  304. key: 'corporationName',
  305. width: 180,
  306. ellipsis: true,
  307. render(value) {
  308. return <span style={{ fontSize: 12 }}>{value}</span>
  309. }
  310. },
  311. {
  312. title: '企业标识',
  313. dataIndex: 'corporationLicence',
  314. key: 'corporationLicence',
  315. width: 150,
  316. ellipsis: true,
  317. render(value) {
  318. return <span style={{ fontSize: 12 }}>{value}</span>
  319. }
  320. },
  321. {
  322. title: '备注',
  323. dataIndex: 'remark',
  324. key: 'remark',
  325. ellipsis: true,
  326. render(value) {
  327. return <span style={{ fontSize: 12 }}>{value || '--'}</span>
  328. }
  329. },
  330. ]}
  331. rowSelection={{
  332. selectedRowKeys: selectedRows.map(item => item.accountId),
  333. onSelect: (record: { accountId: number }, selected: boolean) => {
  334. if (selected) {
  335. selectedRows.push({ ...record })
  336. setSelectedRows([...selectedRows])
  337. } else {
  338. let newSelectAccData = selectedRows.filter((item: { accountId: number }) => item.accountId !== record.accountId)
  339. setSelectedRows([...newSelectAccData])
  340. }
  341. },
  342. onSelectAll: (selected: boolean, selectedRowss: { accountId: number }[], changeRows: { accountId: number }[]) => {
  343. if (selected) {
  344. let newSelectAccData = [...selectedRows]
  345. changeRows.forEach((item: { accountId: number }) => {
  346. let index = newSelectAccData.findIndex((ite: { accountId: number }) => ite.accountId === item.accountId)
  347. if (index === -1) {
  348. let data: any = { ...item }
  349. newSelectAccData.push(data)
  350. }
  351. })
  352. setSelectedRows([...newSelectAccData])
  353. } else {
  354. let newSelectAccData = selectedRows.filter((item: { accountId: number }) => {
  355. let index = changeRows.findIndex((ite: { accountId: number }) => ite.accountId === item.accountId)
  356. if (index !== -1) {
  357. return false
  358. } else {
  359. return true
  360. }
  361. })
  362. setSelectedRows([...newSelectAccData])
  363. }
  364. }
  365. }}
  366. />
  367. </div>
  368. <div className={style.selectAccount_list_footer}>
  369. <Button className={style.resetCss} onClick={handleCancel}>取消</Button>
  370. <Button
  371. className={style.resetCss}
  372. type="primary"
  373. style={{ marginLeft: 8 }}
  374. onClick={() => {
  375. if (accountCreateLogs?.length && arraysHaveSameValues(accountCreateLogs.map(item => item.accountId), selectedRows.map(item => item.accountId))) {
  376. handleCancel()
  377. return
  378. }
  379. let authMainAccountId: any
  380. let isY = false
  381. // 1.判断是否有账户组素材 有的话 获取账户组ID
  382. if (dynamicGroup && dynamicGroup?.length > 0) {
  383. if (deliveryMode && mType) {
  384. if (dynamicGroup.some((item: any) => {
  385. if (deliveryMode === 'DELIVERY_MODE_CUSTOMIZE') {
  386. if (['short_video', 'video'].includes(mType) && (item?.video_id?.materialType || item?.short_video1?.materialType) === 1) {
  387. authMainAccountId = item?.video_id?.accountId || item?.short_video1?.accountId
  388. return true
  389. } else if (['image_list'].includes(mType) && item?.image_list?.some((list: any) => {
  390. if (list?.materialType === 1) {
  391. authMainAccountId = list?.accountId
  392. return true
  393. } else {
  394. return false
  395. }
  396. })) {
  397. return true
  398. } else if (['element_story'].includes(mType) && item?.element_story?.some((list: any) => {
  399. if (list?.materialType === 1) {
  400. authMainAccountId = list?.accountId
  401. return true
  402. } else {
  403. return false
  404. }
  405. })) {
  406. return true
  407. } else if (['image'].includes(mType) && item?.image_id?.materialType === 1) {
  408. authMainAccountId = item?.image_id?.accountId
  409. return true
  410. } else {
  411. return false
  412. }
  413. } else {
  414. if (item?.list?.some((list: any) => {
  415. if (Array.isArray(list) && list.some((l: any) => {
  416. if (l.materialType === 1) {
  417. authMainAccountId = l?.accountId
  418. return true
  419. } else {
  420. return false
  421. }
  422. })) {
  423. return true
  424. } else if (list.materialType === 1) {
  425. authMainAccountId = list?.accountId
  426. return true
  427. } else {
  428. return false
  429. }
  430. })) {
  431. return true
  432. } else {
  433. return false
  434. }
  435. }
  436. })) {
  437. isY = true
  438. }
  439. } else {
  440. message.error('请联系管理员')
  441. }
  442. }
  443. if (isY && authMainAccountId) {
  444. // 2.有的话判断 判断账户是否为一组
  445. console.log('authMainAccountId---->', authMainAccountId, getauthMainAccountData(selectedRows))
  446. const authMainData = getauthMainAccountData(selectedRows)
  447. if (authMainData.isSelectRemote && authMainData.authMainAccountId === authMainAccountId) {
  448. handleOk(false)
  449. } else {
  450. setTipsVisible(true)
  451. }
  452. // 3.是的话 判断是以前那组吗
  453. } else {
  454. handleOk(false)
  455. }
  456. }}
  457. >确定</Button>
  458. </div>
  459. </div>}
  460. </div>
  461. {visible && <div className={style.selectAccount_mask}></div>}
  462. {tipsVisible && <Modal
  463. title={<strong>提示</strong>}
  464. open={tipsVisible}
  465. onCancel={() => {
  466. setTipsVisible(false)
  467. }}
  468. onOk={() => handleOk(true)}
  469. className="modalResetCss"
  470. okText="清空"
  471. cancelText="留下来修改账户"
  472. >选择的素材有账户组素材,但是与当前账户不匹配,是否使用当前账号清空素材?</Modal>}
  473. </div>
  474. }
  475. export default React.memo(SelectAccount)