dark
7 months ago
10 changed files with 1446 additions and 100 deletions
-
53src/locales/lang/pages/cms/video/zh-CN.ts
-
52src/locales/lang/pages/cms/videoCloud/zh-CN.ts
-
52src/locales/lang/pages/cms/videoMagnet/zh-CN.ts
-
5src/locales/lang/zh-CN.ts
-
388src/pages/cms/video/index.tsx
-
395src/pages/cms/video_cloud/index.tsx
-
396src/pages/cms/video_magnet/index.tsx
-
19src/store/cms/video.ts
-
12src/store/cms/video_cloud.ts
-
12src/store/cms/video_magnet.ts
@ -0,0 +1,53 @@ |
|||
export default { |
|||
title: '视频管理', |
|||
description: '视频管理', |
|||
search: '搜索', |
|||
add: '新增', |
|||
edit: '编辑', |
|||
delete: '删除', |
|||
type_id: [ |
|||
'在线观看', '下载', '网盘' |
|||
], |
|||
lock: [ |
|||
'未锁', '锁定' |
|||
], |
|||
columns: { |
|||
id: 'ID', |
|||
source_url: '源站点地址', |
|||
collect_id: '站点id', |
|||
type_id: '类型', |
|||
title: '标题', |
|||
title_sub: '副标', |
|||
letter: '首字母', |
|||
tag: 'TAG', |
|||
lock: '锁定后显示', |
|||
copyright: '版权', |
|||
is_end: '完结', |
|||
status: '状态', |
|||
category_id: '分类', |
|||
pic: '图片', |
|||
pic_local: '图片本地路径或MD5', |
|||
pic_status: '图片状态', |
|||
actor: '演员', |
|||
director: '导演', |
|||
writer: '编剧', |
|||
remarks: '备注', |
|||
pubdate: '发布时间', |
|||
total: '总集数', |
|||
serial: '连载数', |
|||
duration: '视频时长', |
|||
area: '地区', |
|||
lang: '语言', |
|||
version: '资源版本', |
|||
year: '年份', |
|||
state: '资源类别', |
|||
douban_score: '豆瓣评分', |
|||
douban_id: '豆瓣ID', |
|||
imdb_score: 'imdb评分', |
|||
imdb_id: 'imdb的id', |
|||
content: '内容', |
|||
created_at: '创建时间', |
|||
updated_at: '更新时间' |
|||
|
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
export default { |
|||
title: '云盘视频管理', |
|||
description: '云盘视频管理', |
|||
search: '搜索', |
|||
add: '新增', |
|||
edit: '编辑', |
|||
delete: '删除', |
|||
type_id: [ |
|||
'在线观看', '下载', '网盘' |
|||
], |
|||
lock: [ |
|||
'未锁', '锁定' |
|||
], |
|||
columns: { |
|||
source_url: '源站点地址', |
|||
collect_id: '站点id', |
|||
type_id: '类型', |
|||
title: '标题', |
|||
title_sub: '副标', |
|||
letter: '首字母', |
|||
tag: 'TAG', |
|||
lock: '锁定后显示', |
|||
copyright: '版权', |
|||
is_end: '完结', |
|||
status: '状态', |
|||
category_id: '分类', |
|||
pic: '图片', |
|||
pic_local: '图片本地路径或MD5', |
|||
pic_status: '图片状态', |
|||
actor: '演员', |
|||
director: '导演', |
|||
writer: '编剧', |
|||
remarks: '备注', |
|||
pubdate: '发布时间', |
|||
total: '总集数', |
|||
serial: '连载数', |
|||
duration: '视频时长', |
|||
class: '分类', |
|||
area: '地区', |
|||
lang: '语言', |
|||
version: '资源版本', |
|||
year: '年份', |
|||
state: '资源类别', |
|||
douban_score: '豆瓣评分', |
|||
douban_id: '豆瓣ID', |
|||
imdb_score: 'imdb评分', |
|||
imdb_id: 'imdb的id', |
|||
content: '内容', |
|||
created_at: '创建时间', |
|||
updated_at: '更新时间' |
|||
} |
|||
} |
@ -0,0 +1,52 @@ |
|||
export default { |
|||
title: '磁链视频管理', |
|||
description: '磁链视频管理', |
|||
search: '搜索', |
|||
add: '新增', |
|||
edit: '编辑', |
|||
delete: '删除', |
|||
type_id: [ |
|||
'在线观看', '下载', '网盘' |
|||
], |
|||
lock: [ |
|||
'未锁', '锁定' |
|||
], |
|||
columns: { |
|||
source_url: '源站点地址', |
|||
collect_id: '站点id', |
|||
type_id: '类型', |
|||
title: '标题', |
|||
title_sub: '副标', |
|||
letter: '首字母', |
|||
tag: 'TAG', |
|||
lock: '锁定后显示', |
|||
copyright: '版权', |
|||
is_end: '完结', |
|||
status: '状态', |
|||
category_id: '分类', |
|||
pic: '图片', |
|||
pic_local: '图片本地路径或MD5', |
|||
pic_status: '图片状态', |
|||
actor: '演员', |
|||
director: '导演', |
|||
writer: '编剧', |
|||
remarks: '备注', |
|||
pubdate: '发布时间', |
|||
total: '总集数', |
|||
serial: '连载数', |
|||
duration: '视频时长', |
|||
class: '分类', |
|||
area: '地区', |
|||
lang: '语言', |
|||
version: '资源版本', |
|||
year: '年份', |
|||
state: '资源类别', |
|||
douban_score: '豆瓣评分', |
|||
douban_id: '豆瓣ID', |
|||
imdb_score: 'imdb评分', |
|||
imdb_id: 'imdb的id', |
|||
content: '内容', |
|||
created_at: '创建时间', |
|||
updated_at: '更新时间' |
|||
} |
|||
} |
@ -0,0 +1,388 @@ |
|||
import { useTranslation } from '@/i18n.ts' |
|||
import { Button, Form, Popconfirm } from 'antd' |
|||
import { useAtom, useAtomValue } from 'jotai' |
|||
import { |
|||
deleteVideoAtom, |
|||
saveOrUpdateVideoAtom, videosAtom, videoSearchAtom, videoTypes |
|||
} from '@/store/cms/video.ts' |
|||
import { useEffect, useMemo, useState } from 'react' |
|||
import Switch from '@/components/switch' |
|||
import Action from '@/components/action/Action.tsx' |
|||
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components' |
|||
import ListPageLayout from '@/layout/ListPageLayout.tsx' |
|||
|
|||
const i18nPrefix = 'cms.video' |
|||
|
|||
const Video = () => { |
|||
|
|||
// const { styles } = useStyle()
|
|||
const { t } = useTranslation() |
|||
const [ form ] = Form.useForm() |
|||
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateVideoAtom) |
|||
const [ search, setSearch ] = useAtom(videoSearchAtom) |
|||
const { data, isFetching, isLoading, refetch } = useAtomValue(videosAtom) |
|||
const { mutate: deleteVideo, isPending: isDeleting } = useAtomValue(deleteVideoAtom) |
|||
const [ open, setOpen ] = useState(false) |
|||
|
|||
const columns = useMemo(() => { |
|||
return [ |
|||
{ |
|||
title: 'ID', |
|||
dataIndex: 'id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
formItemProps: { hidden: true } |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title`, 'Title'), |
|||
'dataIndex': 'title', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title_sub`, 'TitleSub'), |
|||
'dataIndex': 'title_sub', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.source_url`, 'SourceUrl'), |
|||
'dataIndex': 'source_url', |
|||
ellipsis: true, |
|||
copyable: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.collect_id`, 'CollectId'), |
|||
'dataIndex': 'collect_id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.type_id`, 'TypeId'), |
|||
'dataIndex': 'type_id', |
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: videoTypes, |
|||
}, |
|||
render: (_dom, record) => { |
|||
return t(`${i18nPrefix}.type_id.${record.type_id}`) |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.letter`, 'Letter'), |
|||
'dataIndex': 'letter' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.tag`, 'Tag'), |
|||
'dataIndex': 'tag', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lock`, 'Lock'), |
|||
'dataIndex': 'lock', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.copyright`, 'Copyright'), |
|||
'dataIndex': 'copyright', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.is_end`, 'IsEnd'), |
|||
'dataIndex': 'is_end', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.status`, 'Status'), |
|||
'dataIndex': 'status', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.category_id`, 'CategoryId'), |
|||
'dataIndex': 'category_id', |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic`, 'Pic'), |
|||
'dataIndex': 'pic', |
|||
render: (_dom, record) => { |
|||
return <img src={record.pic} alt="" style={{ width: 100 }}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic_local`, 'PicLocal'), |
|||
'dataIndex': 'pic_local', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic_status`, 'PicStatus'), |
|||
'dataIndex': 'pic_status', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.actor`, 'Actor'), |
|||
'dataIndex': 'actor', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.director`, 'Director'), |
|||
'dataIndex': 'director' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.writer`, 'Writer'), |
|||
'dataIndex': 'writer' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.remarks`, 'Remarks'), |
|||
'dataIndex': 'remarks' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pubdate`, 'Pubdate'), |
|||
'dataIndex': 'pubdate', |
|||
valueType: 'dateTime' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.total`, 'Total'), |
|||
'dataIndex': 'total', |
|||
valueType: 'digit' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.serial`, 'Serial'), |
|||
'dataIndex': 'serial', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.duration`, 'Duration'), |
|||
'dataIndex': 'duration', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.area`, 'Area'), |
|||
'dataIndex': 'area', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lang`, 'Lang'), |
|||
'dataIndex': 'lang', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.version`, 'Version'), |
|||
'dataIndex': 'version' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.year`, 'Year'), |
|||
'dataIndex': 'year', |
|||
valueType: 'dateYear' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.state`, 'State'), |
|||
'dataIndex': 'state' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_score`, 'DoubanScore'), |
|||
'dataIndex': 'douban_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_id`, 'DoubanId'), |
|||
'dataIndex': 'douban_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_score`, 'ImdbScore'), |
|||
'dataIndex': 'imdb_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_id`, 'ImdbId'), |
|||
'dataIndex': 'imdb_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.content`, 'Content'), |
|||
'dataIndex': 'content', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => ({ |
|||
width: 200, |
|||
}), |
|||
}, |
|||
|
|||
{ |
|||
title: t(`${i18nPrefix}.columns.option`, '操作'), |
|||
key: 'option', |
|||
valueType: 'option', |
|||
fixed: 'right', |
|||
render: (_, record) => [ |
|||
<Action key="edit" |
|||
as={'a'} |
|||
onClick={() => { |
|||
form.setFieldsValue(record) |
|||
setOpen(true) |
|||
}}>{t('actions.edit')}</Action>, |
|||
<Popconfirm |
|||
key={'del_confirm'} |
|||
disabled={isDeleting} |
|||
onConfirm={() => { |
|||
deleteVideo([ record.id ]) |
|||
}} |
|||
title={t('message.deleteConfirm')}> |
|||
<a key="del"> |
|||
{t('actions.delete', '删除')} |
|||
</a> |
|||
</Popconfirm> |
|||
] |
|||
} |
|||
] as ProColumns[] |
|||
}, [ isDeleting ]) |
|||
|
|||
useEffect(() => { |
|||
if (isSuccess) { |
|||
setOpen(false) |
|||
} |
|||
}, [ isSuccess ]) |
|||
|
|||
return ( |
|||
<ListPageLayout> |
|||
<ProTable |
|||
rowKey="id" |
|||
headerTitle={t(`${i18nPrefix}.title`, '视频管理')} |
|||
toolbar={{ |
|||
search: { |
|||
loading: isFetching && !!search.key, |
|||
onSearch: (value: string) => { |
|||
setSearch(prev => ({ |
|||
...prev, |
|||
key: value |
|||
})) |
|||
}, |
|||
allowClear: true, |
|||
placeholder: t(`${i18nPrefix}.placeholder`, '输入视频名称') |
|||
}, |
|||
actions: [ |
|||
<Button |
|||
onClick={() => { |
|||
form.resetFields() |
|||
form.setFieldsValue({ |
|||
id: 0, |
|||
}) |
|||
setOpen(true) |
|||
}} |
|||
type={'primary'}>{t(`${i18nPrefix}.add`, '添加')}</Button> |
|||
] |
|||
}} |
|||
scroll={{ |
|||
x: 3500, |
|||
}} |
|||
loading={isLoading || isFetching} |
|||
dataSource={data?.rows ?? []} |
|||
columns={columns} |
|||
search={false} |
|||
options={{ |
|||
reload: () => { |
|||
refetch() |
|||
}, |
|||
}} |
|||
pagination={{ |
|||
total: data?.total, |
|||
pageSize: search.pageSize, |
|||
current: search.page, |
|||
onChange: (current, pageSize) => { |
|||
setSearch(prev => { |
|||
return { |
|||
...prev, |
|||
page: current, |
|||
pageSize: pageSize, |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
}} |
|||
/> |
|||
<BetaSchemaForm |
|||
shouldUpdate={false} |
|||
width={600} |
|||
form={form} |
|||
layout={'vertical'} |
|||
scrollToFirstError={true} |
|||
title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '视频编辑' : '视频添加')} |
|||
// colProps={{ span: 24 }}
|
|||
labelCol={{ span: 6 }} |
|||
// wrapperCol={{ span: 14 }}
|
|||
layoutType={'DrawerForm'} |
|||
open={open} |
|||
drawerProps={{ |
|||
maskClosable: false, |
|||
}} |
|||
onOpenChange={(open) => { |
|||
setOpen(open) |
|||
}} |
|||
loading={isSubmitting} |
|||
onFinish={async (values) => { |
|||
// console.log('values', values)
|
|||
saveOrUpdate(values) |
|||
|
|||
}} |
|||
columns={columns as ProFormColumnsType[]}/> |
|||
</ListPageLayout> |
|||
) |
|||
} |
|||
|
|||
export default Video |
@ -0,0 +1,395 @@ |
|||
import { useTranslation } from '@/i18n.ts' |
|||
import { Button, Form, Image, Popconfirm } from 'antd' |
|||
import { useAtom, useAtomValue } from 'jotai' |
|||
import { useEffect, useMemo, useState } from 'react' |
|||
import Switch from '@/components/switch' |
|||
import Action from '@/components/action/Action.tsx' |
|||
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components' |
|||
import ListPageLayout from '@/layout/ListPageLayout.tsx' |
|||
import { |
|||
deleteVideoCloudAtom, |
|||
saveOrUpdateVideoCloudAtom, |
|||
videoCloudsAtom, |
|||
videoCloudSearchAtom |
|||
} from '@/store/cms/video_cloud.ts' |
|||
import { videoTypes } from '@/store/cms/video.ts' |
|||
|
|||
|
|||
const i18nPrefix = 'cms.videoCloud' |
|||
|
|||
const VideoCloud = () => { |
|||
|
|||
// const { styles } = useStyle()
|
|||
const { t } = useTranslation() |
|||
const [ form ] = Form.useForm() |
|||
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateVideoCloudAtom) |
|||
const [ search, setSearch ] = useAtom(videoCloudSearchAtom) |
|||
const { data, isFetching, isLoading, refetch } = useAtomValue(videoCloudsAtom) |
|||
const { mutate: deleteVideo, isPending: isDeleting } = useAtomValue(deleteVideoCloudAtom) |
|||
const [ open, setOpen ] = useState(false) |
|||
|
|||
const columns = useMemo(() => { |
|||
return [ |
|||
{ |
|||
title: 'ID', |
|||
dataIndex: 'id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
formItemProps: { hidden: true } |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title`, 'Title'), |
|||
'dataIndex': 'title', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title_sub`, 'TitleSub'), |
|||
'dataIndex': 'title_sub', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.source_url`, 'SourceUrl'), |
|||
'dataIndex': 'source_url', |
|||
ellipsis: true, |
|||
copyable: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.collect_id`, 'CollectId'), |
|||
'dataIndex': 'collect_id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.type_id`, 'TypeId'), |
|||
'dataIndex': 'type_id', |
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: videoTypes, |
|||
}, |
|||
render: (_dom, record) => { |
|||
return t(`${i18nPrefix}.type_id.${record.type_id}`) |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.letter`, 'Letter'), |
|||
'dataIndex': 'letter' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.tag`, 'Tag'), |
|||
'dataIndex': 'tag', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lock`, 'Lock'), |
|||
'dataIndex': 'lock', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.copyright`, 'Copyright'), |
|||
'dataIndex': 'copyright', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.is_end`, 'IsEnd'), |
|||
'dataIndex': 'is_end', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.status`, 'Status'), |
|||
'dataIndex': 'status', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.category_id`, 'CategoryId'), |
|||
'dataIndex': 'category_id', |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic`, 'Pic'), |
|||
'dataIndex': 'pic', |
|||
render: (_dom, record) => { |
|||
return <Image src={record.pic} height={40}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic_local`, 'PicLocal'), |
|||
'dataIndex': 'pic_local', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.actor`, 'Actor'), |
|||
'dataIndex': 'actor', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.director`, 'Director'), |
|||
'dataIndex': 'director', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.writer`, 'Writer'), |
|||
'dataIndex': 'writer', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pubdate`, 'Pubdate'), |
|||
'dataIndex': 'pubdate', |
|||
valueType: 'dateTime' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.total`, 'Total'), |
|||
'dataIndex': 'total', |
|||
valueType: 'digit' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.serial`, 'Serial'), |
|||
'dataIndex': 'serial', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.duration`, 'Duration'), |
|||
'dataIndex': 'duration', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.class`, 'Class'), |
|||
'dataIndex': 'class', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.area`, 'Area'), |
|||
'dataIndex': 'area', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lang`, 'Lang'), |
|||
'dataIndex': 'lang', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.version`, 'Version'), |
|||
'dataIndex': 'version' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.year`, 'Year'), |
|||
'dataIndex': 'year', |
|||
valueType: 'dateYear' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.state`, 'State'), |
|||
'dataIndex': 'state' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_score`, 'DoubanScore'), |
|||
'dataIndex': 'douban_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_id`, 'DoubanId'), |
|||
'dataIndex': 'douban_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_score`, 'ImdbScore'), |
|||
'dataIndex': 'imdb_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_id`, 'ImdbId'), |
|||
'dataIndex': 'imdb_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.content`, 'Content'), |
|||
'dataIndex': 'content', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => ({ |
|||
width: 200, |
|||
}), |
|||
}, |
|||
|
|||
{ |
|||
title: t(`${i18nPrefix}.columns.option`, '操作'), |
|||
key: 'option', |
|||
valueType: 'option', |
|||
fixed: 'right', |
|||
render: (_, record) => [ |
|||
<Action key="edit" |
|||
as={'a'} |
|||
onClick={() => { |
|||
form.setFieldsValue(record) |
|||
setOpen(true) |
|||
}}>{t('actions.edit')}</Action>, |
|||
<Popconfirm |
|||
key={'del_confirm'} |
|||
disabled={isDeleting} |
|||
onConfirm={() => { |
|||
deleteVideo([ record.id ]) |
|||
}} |
|||
title={t('message.deleteConfirm')}> |
|||
<a key="del"> |
|||
{t('actions.delete', '删除')} |
|||
</a> |
|||
</Popconfirm> |
|||
] |
|||
} |
|||
] as ProColumns[] |
|||
}, [ isDeleting ]) |
|||
|
|||
useEffect(() => { |
|||
if (isSuccess) { |
|||
setOpen(false) |
|||
} |
|||
}, [ isSuccess ]) |
|||
|
|||
return ( |
|||
<ListPageLayout> |
|||
<ProTable |
|||
rowKey="id" |
|||
headerTitle={t(`${i18nPrefix}.title`, '云盘视频管理')} |
|||
toolbar={{ |
|||
search: { |
|||
loading: isFetching && !!search.key, |
|||
onSearch: (value: string) => { |
|||
setSearch(prev => ({ |
|||
...prev, |
|||
key: value |
|||
})) |
|||
}, |
|||
allowClear: true, |
|||
placeholder: t(`${i18nPrefix}.placeholder`, '输入云盘视频名称') |
|||
}, |
|||
actions: [ |
|||
<Button |
|||
onClick={() => { |
|||
form.resetFields() |
|||
form.setFieldsValue({ |
|||
id: 0, |
|||
}) |
|||
setOpen(true) |
|||
}} |
|||
type={'primary'}>{t(`${i18nPrefix}.add`, '添加')}</Button> |
|||
] |
|||
}} |
|||
scroll={{ |
|||
x: 3500, |
|||
}} |
|||
loading={isLoading || isFetching} |
|||
dataSource={data?.rows ?? []} |
|||
columns={columns} |
|||
search={false} |
|||
options={{ |
|||
reload: () => { |
|||
refetch() |
|||
}, |
|||
}} |
|||
pagination={{ |
|||
total: data?.total, |
|||
pageSize: search.pageSize, |
|||
current: search.page, |
|||
onChange: (current, pageSize) => { |
|||
setSearch(prev => { |
|||
return { |
|||
...prev, |
|||
page: current, |
|||
pageSize: pageSize, |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
}} |
|||
/> |
|||
<BetaSchemaForm |
|||
shouldUpdate={false} |
|||
width={600} |
|||
form={form} |
|||
layout={'vertical'} |
|||
scrollToFirstError={true} |
|||
title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '云盘视频编辑' : '云盘视频添加')} |
|||
// colProps={{ span: 24 }}
|
|||
labelCol={{ span: 6 }} |
|||
// wrapperCol={{ span: 14 }}
|
|||
layoutType={'DrawerForm'} |
|||
open={open} |
|||
drawerProps={{ |
|||
maskClosable: false, |
|||
}} |
|||
onOpenChange={(open) => { |
|||
setOpen(open) |
|||
}} |
|||
loading={isSubmitting} |
|||
onFinish={async (values) => { |
|||
// console.log('values', values)
|
|||
saveOrUpdate(values) |
|||
|
|||
}} |
|||
columns={columns as ProFormColumnsType[]}/> |
|||
</ListPageLayout> |
|||
) |
|||
} |
|||
|
|||
export default VideoCloud |
@ -0,0 +1,396 @@ |
|||
import { useTranslation } from '@/i18n.ts' |
|||
import { Button, Form, Popconfirm, Image } from 'antd' |
|||
import { useAtom, useAtomValue } from 'jotai' |
|||
import { useEffect, useMemo, useState } from 'react' |
|||
import Switch from '@/components/switch' |
|||
import Action from '@/components/action/Action.tsx' |
|||
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components' |
|||
import ListPageLayout from '@/layout/ListPageLayout.tsx' |
|||
import { videoTypes } from '@/store/cms/video.ts' |
|||
import { |
|||
deleteVideoMagnetAtom, |
|||
saveOrUpdateVideoMagnetAtom, |
|||
videoMagnetsAtom, |
|||
videoMagnetSearchAtom |
|||
} from '@/store/cms/video_magnet.ts' |
|||
|
|||
const i18nPrefix = 'cms.videoMagnet' |
|||
|
|||
const VideoMagnet = () => { |
|||
|
|||
// const { styles } = useStyle()
|
|||
const { t } = useTranslation() |
|||
const [ form ] = Form.useForm() |
|||
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateVideoMagnetAtom) |
|||
const [ search, setSearch ] = useAtom(videoMagnetSearchAtom) |
|||
const { data, isFetching, isLoading, refetch } = useAtomValue(videoMagnetsAtom) |
|||
const { mutate: deleteVideo, isPending: isDeleting } = useAtomValue(deleteVideoMagnetAtom) |
|||
const [ open, setOpen ] = useState(false) |
|||
|
|||
const columns = useMemo(() => { |
|||
return [ |
|||
{ |
|||
title: 'ID', |
|||
dataIndex: 'id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
formItemProps: { hidden: true } |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title`, 'Title'), |
|||
'dataIndex': 'title', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.title_sub`, 'TitleSub'), |
|||
'dataIndex': 'title_sub', |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.source_url`, 'SourceUrl'), |
|||
'dataIndex': 'source_url', |
|||
ellipsis: true, |
|||
copyable: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.collect_id`, 'CollectId'), |
|||
'dataIndex': 'collect_id', |
|||
hideInTable: true, |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.type_id`, 'TypeId'), |
|||
'dataIndex': 'type_id', |
|||
valueType: 'select', |
|||
fieldProps: { |
|||
options: videoTypes, |
|||
}, |
|||
render: (_dom, record) => { |
|||
return t(`${i18nPrefix}.type_id.${record.type_id}`) |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.letter`, 'Letter'), |
|||
'dataIndex': 'letter' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.tag`, 'Tag'), |
|||
'dataIndex': 'tag', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lock`, 'Lock'), |
|||
'dataIndex': 'lock', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.copyright`, 'Copyright'), |
|||
'dataIndex': 'copyright', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.is_end`, 'IsEnd'), |
|||
'dataIndex': 'is_end', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.status`, 'Status'), |
|||
'dataIndex': 'status', |
|||
valueType: 'switch', |
|||
render: (_dom, record) => { |
|||
return <Switch value={record.lock} size={'small'}/> |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.category_id`, 'CategoryId'), |
|||
'dataIndex': 'category_id', |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic`, 'Pic'), |
|||
'dataIndex': 'pic', |
|||
render: (_dom, record) => { |
|||
return <Image src={record.pic} height={40}/> |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pic_local`, 'PicLocal'), |
|||
'dataIndex': 'pic_local', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.actor`, 'Actor'), |
|||
'dataIndex': 'actor', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
|
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.director`, 'Director'), |
|||
'dataIndex': 'director', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.writer`, 'Writer'), |
|||
'dataIndex': 'writer', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.pubdate`, 'Pubdate'), |
|||
'dataIndex': 'pubdate', |
|||
valueType: 'dateTime' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.total`, 'Total'), |
|||
'dataIndex': 'total', |
|||
valueType: 'digit' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.serial`, 'Serial'), |
|||
'dataIndex': 'serial', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.duration`, 'Duration'), |
|||
'dataIndex': 'duration', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.class`, 'Class'), |
|||
'dataIndex': 'class', |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.area`, 'Area'), |
|||
'dataIndex': 'area', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.lang`, 'Lang'), |
|||
'dataIndex': 'lang', |
|||
ellipsis: true, |
|||
onHeaderCell: () => { |
|||
return { |
|||
width: 200, |
|||
} |
|||
}, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.version`, 'Version'), |
|||
'dataIndex': 'version' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.year`, 'Year'), |
|||
'dataIndex': 'year', |
|||
valueType: 'dateYear' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.state`, 'State'), |
|||
'dataIndex': 'state' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_score`, 'DoubanScore'), |
|||
'dataIndex': 'douban_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.douban_id`, 'DoubanId'), |
|||
'dataIndex': 'douban_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_score`, 'ImdbScore'), |
|||
'dataIndex': 'imdb_score' |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.imdb_id`, 'ImdbId'), |
|||
'dataIndex': 'imdb_id', |
|||
hideInSearch: true, |
|||
hideInSetting: true, |
|||
formItemProps: { hidden: true }, |
|||
hideInTable: true, |
|||
}, |
|||
{ |
|||
'title': t(`${i18nPrefix}.columns.content`, 'Content'), |
|||
'dataIndex': 'content', |
|||
valueType: 'textarea', |
|||
ellipsis: true, |
|||
onHeaderCell: () => ({ |
|||
width: 200, |
|||
}), |
|||
}, |
|||
|
|||
|
|||
{ |
|||
title: t(`${i18nPrefix}.columns.option`, '操作'), |
|||
key: 'option', |
|||
valueType: 'option', |
|||
fixed: 'right', |
|||
render: (_, record) => [ |
|||
<Action key="edit" |
|||
as={'a'} |
|||
onClick={() => { |
|||
form.setFieldsValue(record) |
|||
setOpen(true) |
|||
}}>{t('actions.edit')}</Action>, |
|||
<Popconfirm |
|||
key={'del_confirm'} |
|||
disabled={isDeleting} |
|||
onConfirm={() => { |
|||
deleteVideo([ record.id ]) |
|||
}} |
|||
title={t('message.deleteConfirm')}> |
|||
<a key="del"> |
|||
{t('actions.delete', '删除')} |
|||
</a> |
|||
</Popconfirm> |
|||
] |
|||
} |
|||
] as ProColumns[] |
|||
}, [ isDeleting ]) |
|||
|
|||
useEffect(() => { |
|||
if (isSuccess) { |
|||
setOpen(false) |
|||
} |
|||
}, [ isSuccess ]) |
|||
|
|||
return ( |
|||
<ListPageLayout> |
|||
<ProTable |
|||
rowKey="id" |
|||
headerTitle={t(`${i18nPrefix}.title`, '磁链视频管理')} |
|||
toolbar={{ |
|||
search: { |
|||
loading: isFetching && !!search.key, |
|||
onSearch: (value: string) => { |
|||
setSearch(prev => ({ |
|||
...prev, |
|||
key: value |
|||
})) |
|||
}, |
|||
allowClear: true, |
|||
placeholder: t(`${i18nPrefix}.placeholder`, '输入磁链视频名称') |
|||
}, |
|||
actions: [ |
|||
<Button |
|||
onClick={() => { |
|||
form.resetFields() |
|||
form.setFieldsValue({ |
|||
id: 0, |
|||
}) |
|||
setOpen(true) |
|||
}} |
|||
type={'primary'}>{t(`${i18nPrefix}.add`, '添加')}</Button> |
|||
] |
|||
}} |
|||
scroll={{ |
|||
x: 3500, |
|||
}} |
|||
loading={isLoading || isFetching} |
|||
dataSource={data?.rows ?? []} |
|||
columns={columns} |
|||
search={false} |
|||
options={{ |
|||
reload: () => { |
|||
refetch() |
|||
}, |
|||
}} |
|||
pagination={{ |
|||
total: data?.total, |
|||
pageSize: search.pageSize, |
|||
current: search.page, |
|||
onChange: (current, pageSize) => { |
|||
setSearch(prev => { |
|||
return { |
|||
...prev, |
|||
page: current, |
|||
pageSize: pageSize, |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
}} |
|||
/> |
|||
<BetaSchemaForm |
|||
shouldUpdate={false} |
|||
width={600} |
|||
form={form} |
|||
layout={'vertical'} |
|||
scrollToFirstError={true} |
|||
title={t(`${i18nPrefix}.title_${form.getFieldValue('id') !== 0 ? 'edit' : 'add'}`, form.getFieldValue('id') !== 0 ? '磁链视频编辑' : '磁链视频添加')} |
|||
// colProps={{ span: 24 }}
|
|||
labelCol={{ span: 6 }} |
|||
// wrapperCol={{ span: 14 }}
|
|||
layoutType={'DrawerForm'} |
|||
open={open} |
|||
drawerProps={{ |
|||
maskClosable: false, |
|||
}} |
|||
onOpenChange={(open) => { |
|||
setOpen(open) |
|||
}} |
|||
loading={isSubmitting} |
|||
onFinish={async (values) => { |
|||
// console.log('values', values)
|
|||
saveOrUpdate(values) |
|||
|
|||
}} |
|||
columns={columns as ProFormColumnsType[]}/> |
|||
</ListPageLayout> |
|||
) |
|||
} |
|||
|
|||
export default VideoMagnet |
Write
Preview
Loading…
Cancel
Save
Reference in new issue