You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

775 lines
26 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. import { useTranslation } from '@/i18n.ts'
  2. import { getToken } from '@/store/system.ts'
  3. import { Button, DatePicker, Form, Image, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd'
  4. import dayjs from 'dayjs'
  5. import { useAtom, useAtomValue, useSetAtom } from 'jotai'
  6. import {
  7. deleteVideoAtom, getTypeName,
  8. saveOrUpdateVideoAtom, videoAtom, videosAtom, videoSearchAtom, videoTypes
  9. } from '@/store/videos/video.ts'
  10. import { useEffect, useMemo, useState } from 'react'
  11. import Action from '@/components/action/Action.tsx'
  12. import {
  13. BetaSchemaForm,
  14. ProColumns,
  15. ProFormColumnsType,
  16. ProFormUploadButton,
  17. ProTable
  18. } from '@ant-design/pro-components'
  19. import ListPageLayout from '@/layout/ListPageLayout.tsx'
  20. import { categoryByIdAtom, categoryIdAtom } from '@/store/videos/category.ts'
  21. import TagPro from '@/components/tag-pro/TagPro.tsx'
  22. import TagValue from '@/components/tag-value/TagValue.tsx'
  23. import { useStyle } from './style'
  24. import { FilterOutlined } from '@ant-design/icons'
  25. import { getValueCount } from '@/utils'
  26. const i18nPrefix = 'videos.list'
  27. const Video = () => {
  28. const { styles, cx } = useStyle()
  29. const { t } = useTranslation()
  30. const [ form ] = Form.useForm()
  31. const [ filterForm ] = Form.useForm()
  32. const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateVideoAtom)
  33. const [ search, setSearch ] = useAtom(videoSearchAtom)
  34. const [ currentVideo, setVideo ] = useAtom(videoAtom)
  35. const { data, isFetching, isLoading, refetch } = useAtomValue(videosAtom)
  36. const { mutate: deleteVideo, isPending: isDeleting } = useAtomValue(deleteVideoAtom)
  37. const setCategoryId = useSetAtom(categoryIdAtom)
  38. const { data: category, isLoading: isCategoryFetching } = useAtomValue(categoryByIdAtom)
  39. const [ open, setOpen ] = useState(false)
  40. const [ openFilter, setFilterOpen ] = useState(false)
  41. const [ searchKey, setSearchKey ] = useState(search?.title)
  42. const columns = useMemo(() => {
  43. return [
  44. {
  45. title: 'ID',
  46. dataIndex: 'id',
  47. hideInTable: true,
  48. hideInSearch: true,
  49. formItemProps: { hidden: true }
  50. },
  51. {
  52. 'title': t(`${i18nPrefix}.columns.video_id`, 'VideoId'),
  53. 'dataIndex': 'video_id',
  54. hideInTable: true,
  55. hideInSearch: true,
  56. hideInSetting: true,
  57. formItemProps: { hidden: true },
  58. },
  59. {
  60. 'title': t(`${i18nPrefix}.columns.title`, 'Title'),
  61. 'dataIndex': 'title',
  62. width: 200,
  63. fieldProps: {
  64. style: { width: '100%' }
  65. },
  66. colProps: {
  67. span: 8
  68. },
  69. render: (_text, record) => {
  70. //高亮搜索关键字, 从search.title中获取
  71. const title = record.title?.replace?.(new RegExp(`(${search?.title})`, 'ig'), '<span class="ant-pro-table-highlight">$1</span>')
  72. return <span dangerouslySetInnerHTML={{ __html: title }}></span>
  73. }
  74. },
  75. {
  76. 'title': t(`${i18nPrefix}.columns.title_sub`, 'TitleSub'),
  77. 'dataIndex': 'title_sub',
  78. width: 200,
  79. fieldProps: {
  80. style: { width: '100%' }
  81. },
  82. colProps: {
  83. span: 16
  84. },
  85. render: (_text, record) => {
  86. //高亮搜索关键字, 从search.title中获取
  87. const title = record.title_sub?.replace?.(new RegExp(`(${search?.title_sub})`, 'ig'), '<span class="ant-pro-table-highlight">$1</span>')
  88. return <span dangerouslySetInnerHTML={{ __html: title }}></span>
  89. }
  90. },
  91. {
  92. 'title': t(`${i18nPrefix}.columns.type_id`, 'TypeId'),
  93. 'dataIndex': 'type_id',
  94. valueType: 'select',
  95. width: 100,
  96. fieldProps: {
  97. options: videoTypes,
  98. style: { width: '100%' }
  99. },
  100. render: (_dom, record) => {
  101. return <TagValue
  102. tags={[ { label: t(`${i18nPrefix}.type_id.${record.type_id}`), value: record.type_id } ]}
  103. wrap={currentVideo?.id === record.id}
  104. value={search?.type_id}
  105. onChange={(values) => {
  106. setSearch((prev: any) => {
  107. return {
  108. ...prev,
  109. type_id: values[0],
  110. }
  111. })
  112. setCategoryId(values[0])
  113. const typeName = getTypeName(values[0])
  114. form.setFieldsValue({
  115. class_name: typeName,
  116. })
  117. setFilterOpen(true)
  118. }}
  119. />
  120. },
  121. colProps: {
  122. span: 8
  123. }
  124. },
  125. // {
  126. // 'title': t(`${i18nPrefix}.columns.source_url`, 'SourceUrl'),
  127. // 'dataIndex': 'source_url',
  128. // ellipsis: true,
  129. // copyable: true,
  130. // onHeaderCell: () => {
  131. // return {
  132. // width: 200,
  133. // }
  134. // },
  135. // },
  136. {
  137. 'title': t(`${i18nPrefix}.columns.year`, 'Year'),
  138. 'dataIndex': 'year',
  139. width: 100,
  140. fieldProps: {
  141. style: { width: '100%' }
  142. },
  143. valueType: 'dateYear',
  144. colProps: {
  145. span: 6
  146. },
  147. render: (_dom, record) => {
  148. return <TagValue
  149. tags={[ record.year ]}
  150. wrap={currentVideo?.id === record.id}
  151. value={search?.year}
  152. single={true}
  153. onChange={(values) => {
  154. setSearch((prev: any) => {
  155. return {
  156. ...prev,
  157. year: values[0],
  158. }
  159. })
  160. setFilterOpen(true)
  161. }}
  162. />
  163. },
  164. renderFormItem: (_schema, config) => {
  165. const props = { ...config } as any
  166. delete props.mode
  167. const isForm = config.type === 'form'
  168. let value = isForm && config.value ? dayjs().set('year', config.value) : undefined
  169. if (config.value?.$isDayjsObject) {
  170. value = config.value as dayjs.Dayjs
  171. }
  172. return <DatePicker
  173. {..._schema.formItemProps}
  174. {...props}
  175. picker={'year'}
  176. value={value}
  177. />
  178. }
  179. },
  180. {
  181. 'title': t(`${i18nPrefix}.columns.category_id`, 'CategoryId'),
  182. 'dataIndex': 'class_name',
  183. width: 100,
  184. fieldProps: {
  185. style: { width: '100%' }
  186. },
  187. colProps: {
  188. span: 10
  189. },
  190. render: (_dom, record) => {
  191. return <TagValue
  192. tags={record.class_name?.split(',')}
  193. wrap={currentVideo?.id === record.id}
  194. value={search?.class_name}
  195. onChange={(values) => {
  196. setSearch((prev: any) => {
  197. return {
  198. ...prev,
  199. class_name: values,
  200. }
  201. })
  202. setFilterOpen(true)
  203. }}
  204. />
  205. },
  206. },
  207. {
  208. 'title': t(`${i18nPrefix}.columns.douban_id`, 'DouBanId'),
  209. 'dataIndex': 'douban_id',
  210. hideInTable: true,
  211. colProps: {
  212. span: 6
  213. }, render: (_dom, record) => {
  214. return <TagValue
  215. tags={[ record.douban_id ]}
  216. wrap={currentVideo?.id === record.id}
  217. value={search?.douban_id}
  218. onChange={(values) => {
  219. setSearch((prev: any) => {
  220. return {
  221. ...prev,
  222. douban_id: values[0],
  223. }
  224. })
  225. setFilterOpen(true)
  226. }}
  227. />
  228. },
  229. },
  230. {
  231. 'title': t(`${i18nPrefix}.columns.imdb_id`, 'ImdbId'),
  232. 'dataIndex': 'imdb_id',
  233. hideInTable: true,
  234. colProps: {
  235. span: 6
  236. }, render: (_dom, record) => {
  237. return <TagValue
  238. tags={[ record.imdb_id ]}
  239. wrap={currentVideo?.id === record.id}
  240. value={search?.imdb_id}
  241. onChange={(values) => {
  242. setSearch((prev: any) => {
  243. return {
  244. ...prev,
  245. imdb_id: values[0],
  246. }
  247. })
  248. setFilterOpen(true)
  249. }}
  250. />
  251. },
  252. },
  253. {
  254. 'title': t(`${i18nPrefix}.columns.rt_id`, 'RtId'),
  255. 'dataIndex': 'rt_id',
  256. hideInTable: true,
  257. colProps: {
  258. span: 6
  259. }, render: (_dom, record) => {
  260. return <TagValue
  261. tags={[ record.rt_id ]}
  262. wrap={currentVideo?.id === record.id}
  263. value={search?.rt_id}
  264. onChange={(values) => {
  265. setSearch((prev: any) => {
  266. return {
  267. ...prev,
  268. rt_id: values[0],
  269. }
  270. })
  271. setFilterOpen(true)
  272. }}
  273. />
  274. },
  275. },
  276. {
  277. 'title': t(`${i18nPrefix}.columns.mal_id`, 'MalId'),
  278. 'dataIndex': 'mal_id',
  279. hideInTable: true,
  280. colProps: {
  281. span: 6
  282. }, render: (_dom, record) => {
  283. return <TagValue
  284. tags={[ record.mal_id ]}
  285. wrap={currentVideo?.id === record.id}
  286. value={search?.mal_id}
  287. onChange={(values) => {
  288. setSearch((prev: any) => {
  289. return {
  290. ...prev,
  291. mal_id: values[0],
  292. }
  293. })
  294. setFilterOpen(true)
  295. }}
  296. />
  297. },
  298. },
  299. {
  300. 'title': t(`${i18nPrefix}.columns.img`, '封面'),
  301. 'dataIndex': 'pic',
  302. hideInSearch: true,
  303. width: 80,
  304. colProps: {
  305. span: 24
  306. },
  307. renderFormItem: (_schema, _config, form) => {
  308. return <ProFormUploadButton
  309. fieldProps={{
  310. name: 'file',
  311. listType: 'picture-card',
  312. data: { videoId: form.getFieldValue('video_id') },
  313. headers: {
  314. 'Authorization': `Bearer ${getToken()}`
  315. },
  316. }}
  317. fileList={[]}
  318. action="/api/v1/videos/image/upload"
  319. />
  320. },
  321. render: (_dom, record) => {
  322. const url = `/api/v1/videos/image/${record.video_id}`
  323. return <Image src={`${url}?width=60&height=80`} alt="cover" preview={{
  324. src: url,
  325. }} style={{ width: 80 }}/>
  326. },
  327. },
  328. {
  329. 'title': t(`${i18nPrefix}.columns.actor`, 'Actor'),
  330. 'dataIndex': 'actor',
  331. ellipsis: true,
  332. width: 200,
  333. fieldProps: {
  334. style: { width: '100%' }
  335. },
  336. render: (_dom, record) => {
  337. return <TagValue
  338. tags={record.actor?.split(',') ?? []}
  339. wrap={currentVideo?.id === record.id}
  340. value={search?.actor ?? []}
  341. onChange={(values) => {
  342. setSearch((prev: any) => {
  343. return {
  344. ...prev,
  345. actor: values,
  346. }
  347. })
  348. setFilterOpen(true)
  349. }}
  350. />
  351. },
  352. },
  353. {
  354. 'title': t(`${i18nPrefix}.columns.director`, 'Director'),
  355. 'dataIndex': 'director',
  356. width: 200,
  357. fieldProps: {
  358. style: { width: '100%' }
  359. },
  360. render: (_dom, record) => {
  361. return <TagValue
  362. tags={record.director?.split(',') ?? []}
  363. wrap={!currentVideo?.id === record.id}
  364. value={search?.director ?? []}
  365. onChange={(values) => {
  366. setSearch(prev => {
  367. return {
  368. ...prev,
  369. director: (values as Array<any>)
  370. }
  371. })
  372. setFilterOpen(true)
  373. }}
  374. />
  375. },
  376. },
  377. {
  378. 'title': t(`${i18nPrefix}.columns.writer`, 'Writer'),
  379. 'dataIndex': 'writer',
  380. width: 200,
  381. fieldProps: {
  382. style: { width: '100%' }
  383. },
  384. render: (_dom, record) => {
  385. return <TagValue
  386. tags={record.writer?.split(',') ?? []}
  387. wrap={!currentVideo?.id === record.id}
  388. value={search?.writer ?? []}
  389. onChange={(values) => {
  390. setSearch(prev => {
  391. return {
  392. ...prev,
  393. writer: (values as Array<any>)
  394. }
  395. })
  396. setFilterOpen(true)
  397. }}/>
  398. },
  399. },
  400. {
  401. 'title': t(`${i18nPrefix}.columns.content`, 'Content'),
  402. 'dataIndex': 'content',
  403. valueType: 'textarea',
  404. ellipsis: true,
  405. width: 200,
  406. fieldProps: {
  407. style: { width: '100%' }
  408. },
  409. },
  410. // {
  411. // 'title': t(`${i18nPrefix}.columns.remarks`, 'Remarks'),
  412. // valueType: 'textarea',
  413. // ellipsis: true,
  414. // 'dataIndex': 'remarks'
  415. // },
  416. {
  417. 'title': t(`${i18nPrefix}.columns.tag`, 'Tag'),
  418. 'dataIndex': 'tag',
  419. valueType: 'textarea',
  420. ellipsis: true,
  421. width: 200,
  422. fieldProps: {
  423. style: { width: '100%' }
  424. },
  425. renderFormItem: (schema, config) => {
  426. return <TagPro loading={isCategoryFetching}
  427. tags={category?.extend?.class?.split(',') ?? []} {...config} {...schema.fieldProps} />
  428. },
  429. render: (_dom, record) => {
  430. return <TagValue
  431. tags={record.tag?.split(',') ?? []}
  432. wrap={!currentVideo?.id === record.id}
  433. value={search?.tag ?? []}
  434. onChange={(values) => {
  435. setSearch(prev => {
  436. return {
  437. ...prev,
  438. tag: (values as Array<any>)
  439. }
  440. })
  441. setFilterOpen(true)
  442. }}/>
  443. },
  444. },
  445. {
  446. 'title': t(`${i18nPrefix}.columns.area`, 'Area'),
  447. 'dataIndex': 'area',
  448. ellipsis: true,
  449. width: 200,
  450. fieldProps: {
  451. style: { width: '100%' }
  452. },
  453. renderFormItem: (schema, config) => {
  454. return <TagPro loading={isCategoryFetching}
  455. tags={category?.extend?.area?.split(',') ?? []} {...config} {...schema.fieldProps} />
  456. },
  457. render: (_dom, record) => {
  458. return <TagValue
  459. tags={record.area?.split(',') ?? []}
  460. wrap={!currentVideo?.id === record.id}
  461. value={search?.area ?? []}
  462. onChange={(values) => {
  463. setSearch(prev => {
  464. return {
  465. ...prev,
  466. area: (values as Array<any>)
  467. }
  468. })
  469. setFilterOpen(true)
  470. }}
  471. />
  472. },
  473. },
  474. {
  475. 'title': t(`${i18nPrefix}.columns.lang`, 'Lang'),
  476. 'dataIndex': 'lang',
  477. ellipsis: true,
  478. width: 200,
  479. fieldProps: {
  480. style: { width: '100%' }
  481. },
  482. renderFormItem: (schema, config) => {
  483. return <TagPro loading={isCategoryFetching}
  484. tags={category?.extend?.lang?.split(',') ?? []} {...config} {...schema.fieldProps} />
  485. },
  486. render: (_dom, record) => {
  487. return <TagValue
  488. tags={record.lang?.split(',') ?? []}
  489. wrap={!currentVideo?.id === record.id}
  490. value={search?.lang ?? []}
  491. onChange={(values) => {
  492. setSearch(prev => {
  493. return {
  494. ...prev,
  495. lang: (values as Array<any>)
  496. }
  497. })
  498. setFilterOpen(true)
  499. }}/>
  500. },
  501. },
  502. /*{
  503. 'title': t(`${i18nPrefix}.columns.version`, 'Version'),
  504. 'dataIndex': 'version',
  505. renderFormItem: (schema, config) => {
  506. return <TagPro loading={isCategoryFetching}
  507. tags={category?.extend?.version?.split(',') ?? []} {...config} {...schema.fieldProps} />
  508. }
  509. },
  510. {
  511. 'title': t(`${i18nPrefix}.columns.state`, 'State'),
  512. 'dataIndex': 'state',
  513. renderFormItem: (schema, config) => {
  514. return <TagPro loading={isCategoryFetching}
  515. tags={category?.extend?.state?.split(',') ?? []} {...config} {...schema.fieldProps} />
  516. }
  517. },*/
  518. {
  519. 'title': t(`${i18nPrefix}.columns.douban_score`, 'DoubanScore'),
  520. 'dataIndex': 'douban_score',
  521. hideInSearch: true,
  522. hideInSetting: true,
  523. formItemProps: { hidden: true },
  524. hideInTable: true,
  525. },
  526. {
  527. 'title': t(`${i18nPrefix}.columns.imdb_score`, 'ImdbScore'),
  528. 'dataIndex': 'imdb_score',
  529. hideInSearch: true,
  530. hideInSetting: true,
  531. formItemProps: { hidden: true },
  532. hideInTable: true,
  533. },
  534. {
  535. title: t(`${i18nPrefix}.columns.option`, '操作'),
  536. key: 'option',
  537. valueType: 'option',
  538. fixed: 'right',
  539. render: (_, record) => [
  540. <Action key="edit"
  541. as={'a'}
  542. onClick={() => {
  543. setCategoryId(record.type_id)
  544. form.setFieldsValue(record)
  545. setOpen(true)
  546. }}>{t('actions.edit')}</Action>,
  547. <Popconfirm
  548. key={'del_confirm'}
  549. disabled={isDeleting}
  550. onConfirm={() => {
  551. deleteVideo([ record.id ])
  552. }}
  553. title={t('message.deleteConfirm')}>
  554. <a key="del">
  555. {t('actions.delete', '删除')}
  556. </a>
  557. </Popconfirm>
  558. ]
  559. }
  560. ] as ProColumns[]
  561. }, [ isDeleting, category, isCategoryFetching, currentVideo, search ])
  562. useEffect(() => {
  563. setSearchKey(search?.title)
  564. filterForm.setFieldsValue(search)
  565. }, [ search ])
  566. useEffect(() => {
  567. if (isSuccess) {
  568. setOpen(false)
  569. }
  570. }, [ isSuccess ])
  571. return (
  572. <ListPageLayout className={styles.container}>
  573. <ProTable
  574. rowKey="id"
  575. headerTitle={t(`${i18nPrefix}.title`, '视频管理')}
  576. toolbar={{
  577. search: {
  578. loading: isFetching && !!search.title,
  579. onSearch: (value: string) => {
  580. setSearch(prev => ({
  581. ...prev,
  582. title: value
  583. }))
  584. },
  585. allowClear: true,
  586. onChange: (e) => {
  587. setSearchKey(e.target?.value)
  588. },
  589. value: searchKey,
  590. placeholder: t(`${i18nPrefix}.placeholder`, '输入视频名称')
  591. },
  592. actions: [
  593. <Tooltip key={'filter'} title={t(`${i18nPrefix}.filter.tooltip`, '高级查询')}>
  594. <Badge count={getValueCount(search)}>
  595. <Button
  596. onClick={() => {
  597. setFilterOpen(true)
  598. }}
  599. icon={<FilterOutlined/>} shape={'circle'} size={'small'}/>
  600. </Badge>
  601. </Tooltip>,
  602. <Divider type={'vertical'} key={'divider'}/>,
  603. <Button key={'add'}
  604. onClick={() => {
  605. form.resetFields()
  606. form.setFieldsValue({
  607. id: 0,
  608. })
  609. setOpen(true)
  610. }}
  611. type={'primary'}>{t(`${i18nPrefix}.add`, '添加')}</Button>
  612. ]
  613. }}
  614. scroll={{
  615. x: 2500, y: 'calc(100vh - 290px)'
  616. }}
  617. search={false}
  618. onRow={(record) => {
  619. return {
  620. className: cx({
  621. 'ant-table-row-selected': currentVideo?.id === record.id
  622. }),
  623. onClick: () => {
  624. setVideo(record)
  625. }
  626. }
  627. }}
  628. dateFormatter="string"
  629. loading={isLoading || isFetching}
  630. dataSource={data?.rows ?? []}
  631. columns={columns}
  632. options={{
  633. reload: () => {
  634. refetch()
  635. },
  636. }}
  637. pagination={{
  638. total: data?.total,
  639. pageSize: search.pageSize,
  640. current: search.page,
  641. onChange: (current, pageSize) => {
  642. setSearch(prev => {
  643. return {
  644. ...prev,
  645. page: current,
  646. pageSize: pageSize,
  647. }
  648. })
  649. },
  650. }}
  651. />
  652. <BetaSchemaForm
  653. grid={true}
  654. shouldUpdate={false}
  655. width={1000}
  656. form={form}
  657. layout={'vertical'}
  658. scrollToFirstError={true}
  659. title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '视频编辑' : '视频添加')}
  660. // colProps={{ span: 24 }}
  661. // labelCol={{ span: 8 }}
  662. // wrapperCol={{ span: 14 }}
  663. layoutType={'DrawerForm'}
  664. open={open}
  665. drawerProps={{
  666. maskClosable: false,
  667. }}
  668. onOpenChange={(open) => {
  669. setOpen(open)
  670. }}
  671. loading={isSubmitting}
  672. onValuesChange={(values) => {
  673. if (values.type_id) {
  674. setCategoryId(values.type_id)
  675. const typeName = getTypeName(values.type_id)
  676. form.setFieldsValue({
  677. class_name: typeName,
  678. })
  679. }
  680. }}
  681. onFinish={async (values) => {
  682. // console.log('values', values)
  683. saveOrUpdate(values)
  684. }}
  685. columns={columns as ProFormColumnsType[]}/>
  686. <BetaSchemaForm
  687. title={t(`${i18nPrefix}.filter.title`, '视频高级查询')}
  688. grid={true}
  689. shouldUpdate={false}
  690. width={500}
  691. form={filterForm}
  692. open={openFilter}
  693. onOpenChange={open => {
  694. setFilterOpen(open)
  695. }}
  696. layout={'vertical'}
  697. scrollToFirstError={true}
  698. // colProps={{ span: 24 }}
  699. // labelCol={{ span: 8 }}
  700. // wrapperCol={{ span: 14 }}
  701. layoutType={'DrawerForm'}
  702. drawerProps={{
  703. maskClosable: false,
  704. mask: false,
  705. }}
  706. submitter={{
  707. searchConfig: {
  708. resetText: t(`${i18nPrefix}.filter.reset`, '清空'),
  709. submitText: t(`${i18nPrefix}.filter.submit`, '查询'),
  710. },
  711. onReset: () => {
  712. filterForm.resetFields()
  713. },
  714. render: (props,) => {
  715. return (
  716. <div style={{ textAlign: 'right' }}>
  717. <Space>
  718. <Button onClick={() => {
  719. props.reset()
  720. }}>{props.searchConfig?.resetText}</Button>
  721. <Button type="primary"
  722. onClick={() => {
  723. props.submit()
  724. }}
  725. >{props.searchConfig?.submitText}</Button>
  726. </Space>
  727. </div>
  728. )
  729. },
  730. }}
  731. onValuesChange={(values) => {
  732. if (values.type_id) {
  733. setCategoryId(values.type_id)
  734. const typeName = getTypeName(values.type_id)
  735. filterForm.setFieldsValue({
  736. class_name: typeName,
  737. })
  738. }
  739. }}
  740. onFinish={async (values) => {
  741. // console.log('values', values)
  742. //处理,变成数组
  743. Object.keys(values).forEach(key => {
  744. if (typeof values[key] === 'string' && values[key].includes(',')) {
  745. values[key] = values[key].split(',')
  746. }
  747. })
  748. setSearch(values)
  749. }}
  750. columns={columns.filter(item => !item.hideInSearch) as ProFormColumnsType[]}/>
  751. </ListPageLayout>
  752. )
  753. }
  754. export default Video