import { useTranslation } from '@/i18n.ts' import { getToken } from '@/store/system.ts' import { Button, DatePicker, Form, Image, Popconfirm, Divider, Space, Tooltip, Badge } from 'antd' import dayjs from 'dayjs' import { useAtom, useAtomValue, useSetAtom } from 'jotai' import { deleteVideoAtom, getTypeName, saveOrUpdateVideoAtom, videoAtom, videosAtom, videoSearchAtom, videoTypes } from '@/store/videos/video.ts' import { useEffect, useMemo, useState } from 'react' import Action from '@/components/action/Action.tsx' import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProFormUploadButton, ProTable } from '@ant-design/pro-components' import ListPageLayout from '@/layout/ListPageLayout.tsx' import { categoryByIdAtom, categoryIdAtom } from '@/store/videos/category.ts' import TagPro from '@/components/tag-pro/TagPro.tsx' import TagValue from '@/components/tag-value/TagValue.tsx' import { useStyle } from './style' import { FilterOutlined } from '@ant-design/icons' import { getValueCount } from '@/utils' const i18nPrefix = 'videos.list' const Video = () => { const { styles, cx } = useStyle() const { t } = useTranslation() const [ form ] = Form.useForm() const [ filterForm ] = Form.useForm() const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateVideoAtom) const [ search, setSearch ] = useAtom(videoSearchAtom) const [ currentVideo, setVideo ] = useAtom(videoAtom) const { data, isFetching, isLoading, refetch } = useAtomValue(videosAtom) const { mutate: deleteVideo, isPending: isDeleting } = useAtomValue(deleteVideoAtom) const setCategoryId = useSetAtom(categoryIdAtom) const { data: category, isLoading: isCategoryFetching } = useAtomValue(categoryByIdAtom) const [ open, setOpen ] = useState(false) const [ openFilter, setFilterOpen ] = useState(false) const [ searchKey, setSearchKey ] = useState(search?.title) const columns = useMemo(() => { return [ { title: 'ID', dataIndex: 'id', hideInTable: true, hideInSearch: true, formItemProps: { hidden: true } }, { 'title': t(`${i18nPrefix}.columns.video_id`, 'VideoId'), 'dataIndex': 'video_id', hideInTable: true, hideInSearch: true, hideInSetting: true, formItemProps: { hidden: true }, }, { 'title': t(`${i18nPrefix}.columns.title`, 'Title'), 'dataIndex': 'title', width: 200, fieldProps: { style: { width: '100%' } }, colProps: { span: 8 }, render: (_text, record) => { //高亮搜索关键字, 从search.title中获取 const title = record.title?.replace?.(new RegExp(`(${search?.title})`, 'ig'), '$1') return } }, { 'title': t(`${i18nPrefix}.columns.title_sub`, 'TitleSub'), 'dataIndex': 'title_sub', width: 200, fieldProps: { style: { width: '100%' } }, colProps: { span: 16 }, render: (_text, record) => { //高亮搜索关键字, 从search.title中获取 const title = record.title_sub?.replace?.(new RegExp(`(${search?.title_sub})`, 'ig'), '$1') return } }, { 'title': t(`${i18nPrefix}.columns.type_id`, 'TypeId'), 'dataIndex': 'type_id', valueType: 'select', width: 100, fieldProps: { options: videoTypes, style: { width: '100%' } }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, type_id: values[0], } }) setCategoryId(values[0]) const typeName = getTypeName(values[0]) form.setFieldsValue({ class_name: typeName, }) setFilterOpen(true) }} /> }, colProps: { span: 8 } }, // { // 'title': t(`${i18nPrefix}.columns.source_url`, 'SourceUrl'), // 'dataIndex': 'source_url', // ellipsis: true, // copyable: true, // onHeaderCell: () => { // return { // width: 200, // } // }, // }, { 'title': t(`${i18nPrefix}.columns.year`, 'Year'), 'dataIndex': 'year', width: 100, fieldProps: { style: { width: '100%' } }, valueType: 'dateYear', colProps: { span: 6 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, year: values[0], } }) setFilterOpen(true) }} /> }, renderFormItem: (_schema, config) => { const props = { ...config } as any delete props.mode const isForm = config.type === 'form' let value = isForm && config.value ? dayjs().set('year', config.value) : undefined if (config.value?.$isDayjsObject) { value = config.value as dayjs.Dayjs } return } }, { 'title': t(`${i18nPrefix}.columns.category_id`, 'CategoryId'), 'dataIndex': 'class_name', width: 100, fieldProps: { style: { width: '100%' } }, colProps: { span: 10 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, class_name: values, } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.douban_id`, 'DouBanId'), 'dataIndex': 'douban_id', hideInTable: true, colProps: { span: 6 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, douban_id: values[0], } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.imdb_id`, 'ImdbId'), 'dataIndex': 'imdb_id', hideInTable: true, colProps: { span: 6 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, imdb_id: values[0], } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.rt_id`, 'RtId'), 'dataIndex': 'rt_id', hideInTable: true, colProps: { span: 6 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, rt_id: values[0], } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.mal_id`, 'MalId'), 'dataIndex': 'mal_id', hideInTable: true, colProps: { span: 6 }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, mal_id: values[0], } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.img`, '封面'), 'dataIndex': 'pic', hideInSearch: true, width: 80, colProps: { span: 24 }, renderFormItem: (_schema, _config, form) => { return }, render: (_dom, record) => { const url = `/api/v1/videos/image/${record.video_id}` return cover }, }, { 'title': t(`${i18nPrefix}.columns.actor`, 'Actor'), 'dataIndex': 'actor', ellipsis: true, width: 200, fieldProps: { style: { width: '100%' } }, render: (_dom, record) => { return { setSearch((prev: any) => { return { ...prev, actor: values, } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.director`, 'Director'), 'dataIndex': 'director', width: 200, fieldProps: { style: { width: '100%' } }, render: (_dom, record) => { return { setSearch(prev => { return { ...prev, director: (values as Array) } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.writer`, 'Writer'), 'dataIndex': 'writer', width: 200, fieldProps: { style: { width: '100%' } }, render: (_dom, record) => { return { setSearch(prev => { return { ...prev, writer: (values as Array) } }) setFilterOpen(true) }}/> }, }, { 'title': t(`${i18nPrefix}.columns.content`, 'Content'), 'dataIndex': 'content', valueType: 'textarea', ellipsis: true, width: 200, fieldProps: { style: { width: '100%' } }, }, // { // 'title': t(`${i18nPrefix}.columns.remarks`, 'Remarks'), // valueType: 'textarea', // ellipsis: true, // 'dataIndex': 'remarks' // }, { 'title': t(`${i18nPrefix}.columns.tag`, 'Tag'), 'dataIndex': 'tag', valueType: 'textarea', ellipsis: true, width: 200, fieldProps: { style: { width: '100%' } }, renderFormItem: (schema, config) => { return }, render: (_dom, record) => { return { setSearch(prev => { return { ...prev, tag: (values as Array) } }) setFilterOpen(true) }}/> }, }, { 'title': t(`${i18nPrefix}.columns.area`, 'Area'), 'dataIndex': 'area', ellipsis: true, width: 200, fieldProps: { style: { width: '100%' } }, renderFormItem: (schema, config) => { return }, render: (_dom, record) => { return { setSearch(prev => { return { ...prev, area: (values as Array) } }) setFilterOpen(true) }} /> }, }, { 'title': t(`${i18nPrefix}.columns.lang`, 'Lang'), 'dataIndex': 'lang', ellipsis: true, width: 200, fieldProps: { style: { width: '100%' } }, renderFormItem: (schema, config) => { return }, render: (_dom, record) => { return { setSearch(prev => { return { ...prev, lang: (values as Array) } }) setFilterOpen(true) }}/> }, }, /*{ 'title': t(`${i18nPrefix}.columns.version`, 'Version'), 'dataIndex': 'version', renderFormItem: (schema, config) => { return } }, { 'title': t(`${i18nPrefix}.columns.state`, 'State'), 'dataIndex': 'state', renderFormItem: (schema, config) => { return } },*/ { 'title': t(`${i18nPrefix}.columns.douban_score`, 'DoubanScore'), 'dataIndex': 'douban_score', hideInSearch: true, hideInSetting: true, formItemProps: { hidden: true }, hideInTable: true, }, { 'title': t(`${i18nPrefix}.columns.imdb_score`, 'ImdbScore'), 'dataIndex': 'imdb_score', hideInSearch: true, hideInSetting: true, formItemProps: { hidden: true }, hideInTable: true, }, { title: t(`${i18nPrefix}.columns.option`, '操作'), key: 'option', valueType: 'option', fixed: 'right', render: (_, record) => [ { setCategoryId(record.type_id) form.setFieldsValue(record) setOpen(true) }}>{t('actions.edit')}, { deleteVideo([ record.id ]) }} title={t('message.deleteConfirm')}> {t('actions.delete', '删除')} ] } ] as ProColumns[] }, [ isDeleting, category, isCategoryFetching, currentVideo, search ]) useEffect(() => { setSearchKey(search?.title) filterForm.setFieldsValue(search) }, [ search ]) useEffect(() => { if (isSuccess) { setOpen(false) } }, [ isSuccess ]) return ( { setSearch(prev => ({ ...prev, title: value })) }, allowClear: true, onChange: (e) => { setSearchKey(e.target?.value) }, value: searchKey, placeholder: t(`${i18nPrefix}.placeholder`, '输入视频名称') }, actions: [ ] }} scroll={{ x: 2500, y: 'calc(100vh - 290px)' }} search={false} onRow={(record) => { return { className: cx({ 'ant-table-row-selected': currentVideo?.id === record.id }), onClick: () => { setVideo(record) } } }} dateFormatter="string" loading={isLoading || isFetching} dataSource={data?.rows ?? []} columns={columns} options={{ reload: () => { refetch() }, }} pagination={{ total: data?.total, pageSize: search.pageSize, current: search.page, onChange: (current, pageSize) => { setSearch(prev => { return { ...prev, page: current, pageSize: pageSize, } }) }, }} /> { setOpen(open) }} loading={isSubmitting} onValuesChange={(values) => { if (values.type_id) { setCategoryId(values.type_id) const typeName = getTypeName(values.type_id) form.setFieldsValue({ class_name: typeName, }) } }} onFinish={async (values) => { // console.log('values', values) saveOrUpdate(values) }} columns={columns as ProFormColumnsType[]}/> { setFilterOpen(open) }} layout={'vertical'} scrollToFirstError={true} // colProps={{ span: 24 }} // labelCol={{ span: 8 }} // wrapperCol={{ span: 14 }} layoutType={'DrawerForm'} drawerProps={{ maskClosable: false, mask: false, }} submitter={{ searchConfig: { resetText: t(`${i18nPrefix}.filter.reset`, '清空'), submitText: t(`${i18nPrefix}.filter.submit`, '查询'), }, onReset: () => { filterForm.resetFields() }, render: (props,) => { return (
) }, }} onValuesChange={(values) => { if (values.type_id) { setCategoryId(values.type_id) const typeName = getTypeName(values.type_id) filterForm.setFieldsValue({ class_name: typeName, }) } }} onFinish={async (values) => { // console.log('values', values) //处理,变成数组 Object.keys(values).forEach(key => { if (typeof values[key] === 'string' && values[key].includes(',')) { values[key] = values[key].split(',') } }) setSearch(values) }} columns={columns.filter(item => !item.hideInSearch) as ProFormColumnsType[]}/>
) } export default Video