Browse Source

视频模块完善

main
dark 6 months ago
parent
commit
122881d2ee
  1. 53
      src/locales/lang/pages/cms/video/zh-CN.ts
  2. 52
      src/locales/lang/pages/cms/videoCloud/zh-CN.ts
  3. 52
      src/locales/lang/pages/cms/videoMagnet/zh-CN.ts
  4. 5
      src/locales/lang/zh-CN.ts
  5. 388
      src/pages/cms/video/index.tsx
  6. 395
      src/pages/cms/video_cloud/index.tsx
  7. 396
      src/pages/cms/video_magnet/index.tsx
  8. 19
      src/store/cms/video.ts
  9. 12
      src/store/cms/video_cloud.ts
  10. 12
      src/store/cms/video_magnet.ts

53
src/locales/lang/pages/cms/video/zh-CN.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: '更新时间'
}
}

52
src/locales/lang/pages/cms/videoCloud/zh-CN.ts

@ -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: '更新时间'
}
}

52
src/locales/lang/pages/cms/videoMagnet/zh-CN.ts

@ -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: '更新时间'
}
}

5
src/locales/lang/zh-CN.ts

@ -3,6 +3,9 @@ import menus from './pages/system/menus/zh-CN.ts'
import roles from './pages/system/roles/zh-CN.ts' import roles from './pages/system/roles/zh-CN.ts'
import status from './status/zh-CN.ts' import status from './status/zh-CN.ts'
import collect from './pages/cms/collect/zh-CN.ts' import collect from './pages/cms/collect/zh-CN.ts'
import video from './pages/cms/video/zh-CN.ts'
import videoCloud from './pages/cms/videoCloud/zh-CN.ts'
import videoMagnet from './pages/cms/videoMagnet/zh-CN.ts'
export default { export default {
...antdZh, ...antdZh,
@ -48,7 +51,7 @@ export default {
roles roles
}, },
cms: { cms: {
collect,
collect, video, videoCloud, videoMagnet,
}, },
actions: { actions: {
news: '新增', news: '新增',

388
src/pages/cms/video/index.tsx

@ -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

395
src/pages/cms/video_cloud/index.tsx

@ -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

396
src/pages/cms/video_magnet/index.tsx

@ -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

19
src/store/cms/video.ts

@ -6,29 +6,36 @@ import { t } from 'i18next'
import { Cms } from '@/types' import { Cms } from '@/types'
import cmsServ from '@/service/cms.ts' import cmsServ from '@/service/cms.ts'
const i18nPrefix = 'cms.video'
type SearchParams = IPage & { type SearchParams = IPage & {
key?: string key?: string
} }
export const idAtom = atom(0)
export const videoTypes = [
{ label: t(`${i18nPrefix}.type_id.0`), value: 0 },
{ label: t(`${i18nPrefix}.type_id.1`), value: 1 },
{ label: t(`${i18nPrefix}.type_id.2`), value: 2 },
]
export const videoIdAtom = atom(0)
export const videoIdsAtom = atom<number[]>([]) export const videoIdsAtom = atom<number[]>([])
export const videoAtom = atom<Cms.IVideo>(undefined as unknown as Cms.IVideo) export const videoAtom = atom<Cms.IVideo>(undefined as unknown as Cms.IVideo)
export const searchAtom = atom<SearchParams>({
export const videoSearchAtom = atom<SearchParams>({
key: '' key: ''
} as SearchParams) } as SearchParams)
export const pageAtom = atom<IPage>({
export const videoPageAtom = atom<IPage>({
pageSize: 10, pageSize: 10,
page: 1, page: 1,
}) })
export const videosAtom = atomWithQuery((get) => { export const videosAtom = atomWithQuery((get) => {
return { return {
queryKey: [ 'videos', get(searchAtom) ],
queryKey: [ 'videos', get(videoSearchAtom) ],
queryFn: async ({ queryKey: [ , params ] }) => { queryFn: async ({ queryKey: [ , params ] }) => {
return await cmsServ.video.list(params as SearchParams) return await cmsServ.video.list(params as SearchParams)
}, },
@ -64,7 +71,7 @@ export const saveOrUpdateVideoAtom = atomWithMutation<IApiResult, Cms.IVideo>((g
//更新列表 //更新列表
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore fix // @ts-ignore fix
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videos', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videos', get(videoSearchAtom) ] })
return res return res
} }
@ -80,7 +87,7 @@ export const deleteVideoAtom = atomWithMutation((get) => {
onSuccess: (res) => { onSuccess: (res) => {
message.success('message.deleteSuccess') message.success('message.deleteSuccess')
//更新列表 //更新列表
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videos', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videos', get(videoSearchAtom) ] })
return res return res
} }
} }

12
src/store/cms/video_cloud.ts

@ -11,24 +11,24 @@ type SearchParams = IPage & {
key?: string key?: string
} }
export const idAtom = atom(0)
export const videoCloudIdAtom = atom(0)
export const videoCloudIdsAtom = atom<number[]>([]) export const videoCloudIdsAtom = atom<number[]>([])
export const videoCloudAtom = atom<Cms.IVideoCloud>(undefined as unknown as Cms.IVideoCloud) export const videoCloudAtom = atom<Cms.IVideoCloud>(undefined as unknown as Cms.IVideoCloud)
export const searchAtom = atom<SearchParams>({
export const videoCloudSearchAtom = atom<SearchParams>({
key: '' key: ''
} as SearchParams) } as SearchParams)
export const pageAtom = atom<IPage>({
export const videoCloudPageAtom = atom<IPage>({
pageSize: 10, pageSize: 10,
page: 1, page: 1,
}) })
export const videoCloudsAtom = atomWithQuery((get) => { export const videoCloudsAtom = atomWithQuery((get) => {
return { return {
queryKey: [ 'videoClouds', get(searchAtom) ],
queryKey: [ 'videoClouds', get(videoCloudSearchAtom) ],
queryFn: async ({ queryKey: [ , params ] }) => { queryFn: async ({ queryKey: [ , params ] }) => {
return await cmsServ.videoCloud.list(params as SearchParams) return await cmsServ.videoCloud.list(params as SearchParams)
}, },
@ -64,7 +64,7 @@ export const saveOrUpdateVideoCloudAtom = atomWithMutation<IApiResult, Cms.IVide
//更新列表 //更新列表
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore fix // @ts-ignore fix
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoClouds', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoClouds', get(videoCloudSearchAtom) ] })
return res return res
} }
@ -80,7 +80,7 @@ export const deleteVideoCloudAtom = atomWithMutation((get) => {
onSuccess: (res) => { onSuccess: (res) => {
message.success('message.deleteSuccess') message.success('message.deleteSuccess')
//更新列表 //更新列表
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoClouds', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoClouds', get(videoCloudSearchAtom) ] })
return res return res
} }
} }

12
src/store/cms/video_magnet.ts

@ -11,24 +11,24 @@ type SearchParams = IPage & {
key?: string key?: string
} }
export const idAtom = atom(0)
export const videoMagnetIdAtom = atom(0)
export const videoMagnetIdsAtom = atom<number[]>([]) export const videoMagnetIdsAtom = atom<number[]>([])
export const videoMagnetAtom = atom<Cms.IVideoMagnet>(undefined as unknown as Cms.IVideoMagnet) export const videoMagnetAtom = atom<Cms.IVideoMagnet>(undefined as unknown as Cms.IVideoMagnet)
export const searchAtom = atom<SearchParams>({
export const videoMagnetSearchAtom = atom<SearchParams>({
key: '' key: ''
} as SearchParams) } as SearchParams)
export const pageAtom = atom<IPage>({
export const videoMagnetPageAtom = atom<IPage>({
pageSize: 10, pageSize: 10,
page: 1, page: 1,
}) })
export const videoMagnetsAtom = atomWithQuery((get) => { export const videoMagnetsAtom = atomWithQuery((get) => {
return { return {
queryKey: [ 'videoMagnets', get(searchAtom) ],
queryKey: [ 'videoMagnets', get(videoMagnetSearchAtom) ],
queryFn: async ({ queryKey: [ , params ] }) => { queryFn: async ({ queryKey: [ , params ] }) => {
return await cmsServ.videoMagnet.list(params as SearchParams) return await cmsServ.videoMagnet.list(params as SearchParams)
}, },
@ -64,7 +64,7 @@ export const saveOrUpdateVideoMagnetAtom = atomWithMutation<IApiResult, Cms.IVid
//更新列表 //更新列表
// eslint-disable-next-line @typescript-eslint/ban-ts-comment // eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore fix // @ts-ignore fix
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoMagnets', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoMagnets', get(videoMagnetSearchAtom) ] })
return res return res
} }
@ -80,7 +80,7 @@ export const deleteVideoMagnetAtom = atomWithMutation((get) => {
onSuccess: (res) => { onSuccess: (res) => {
message.success('message.deleteSuccess') message.success('message.deleteSuccess')
//更新列表 //更新列表
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoMagnets', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'videoMagnets', get(videoMagnetSearchAtom) ] })
return res return res
} }
} }

Loading…
Cancel
Save