Browse Source

采集站点collect完善

main
dark 4 months ago
parent
commit
70a41eb715
  1. 35
      src/layout/ListPageLayout.tsx
  2. 36
      src/locales/lang/pages/cms/collect/zh-CN.ts
  3. 4
      src/locales/lang/zh-CN.ts
  4. 315
      src/pages/cms/collect/index.tsx
  5. 13
      src/pages/cms/collect/style.ts
  6. 26
      src/store/cms/collect.ts

35
src/layout/ListPageLayout.tsx

@ -3,23 +3,32 @@ import { useStyle } from '@/layout/style.ts'
import { PageContainer, PageContainerProps } from '@ant-design/pro-components' import { PageContainer, PageContainerProps } from '@ant-design/pro-components'
interface IListPageLayoutProps extends PageContainerProps { interface IListPageLayoutProps extends PageContainerProps {
children: React.ReactNode
children: React.ReactNode
authHeight?: boolean
} }
const ListPageLayout: React.FC<IListPageLayoutProps> = ({ children, ...props }) => {
const { styles } = useStyle({ className: 'two-col' })
const ListPageLayout: React.FC<IListPageLayoutProps> = (
{
children, authHeight = true, ...props
}) => {
const { styles, cx } = useStyle({ className: 'two-col' })
return (
<>
<PageContainer
breadcrumbRender={false} title={false} className={styles.container}
{...props}
>
{children}
</PageContainer>
</>
)
return (
<>
<PageContainer
breadcrumbRender={false} title={false}
className={styles.container}
{...props}
>
<div className={cx({
[styles.authHeight]: authHeight
})}>
{children}
</div>
</PageContainer>
</>
)
} }
export default ListPageLayout export default ListPageLayout

36
src/locales/lang/pages/cms/collect/zh-CN.ts

@ -0,0 +1,36 @@
export default {
title: '采集站点管理',
description: '采集站点管理',
list: '采集列表',
add: '新增采集',
edit: '编辑采集',
delete: '删除采集',
detail: '采集详情',
type_id: [
'在线观看', '磁链', '网盘'
],
sync_pic: [
'关闭', '开启', '全局'
],
columns: {
name: '站点名称',
url: '采集地址',
param: '参数',
type_id: '类型',
opt: '操作',
filter: '过滤器',
filter_form: '过滤表单',
sync_pic: '同步图片',
icon_cdn: '图标CDN',
class: '分类',
weights: '权重',
status: '状态',
open_replace: '开启替换',
replace_str: '替换字符串',
site_auth: '搜片认证站点',
site_cooperation: '搜片合作优质站点',
categories_rules: '采集规则',
create_time: '创建时间',
update_time: '更新时间'
}
}

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

@ -2,6 +2,7 @@ import antdZh from 'antd/locale/zh_CN'
import menus from './pages/system/menus/zh-CN.ts' 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'
export default { export default {
...antdZh, ...antdZh,
@ -46,6 +47,9 @@ export default {
menus, menus,
roles roles
}, },
cms: {
collect,
},
actions: { actions: {
news: '新增', news: '新增',
add: '添加', add: '添加',

315
src/pages/cms/collect/index.tsx

@ -0,0 +1,315 @@
import { useEffect, useMemo, useState } from 'react'
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components'
import { useTranslation } from '@/i18n.ts'
import { useAtom, useAtomValue } from 'jotai'
import {
collectsAtom,
deleteCollectAtom,
saveOrUpdateCollectAtom,
collectSearchAtom,
syncPicTypes,
types
} from '@/store/cms/collect.ts'
import { Button, Form, Popconfirm } from 'antd'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import Switch from '@/components/switch'
import Action from '@/components/action/Action.tsx'
const i18nPrefix = 'cms.collect'
const Collect = () => {
// const { styles } = useStyle()
const { t } = useTranslation()
const [ form ] = Form.useForm()
const { mutate: saveOrUpdate, isPending: isSubmitting, isSuccess } = useAtomValue(saveOrUpdateCollectAtom)
const [ search, setSearch ] = useAtom(collectSearchAtom)
const { data, isFetching, isLoading, refetch } = useAtomValue(collectsAtom)
const { mutate: deleteCollect, isPending: isDeleting } = useAtomValue(deleteCollectAtom)
const [ open, setOpen ] = useState(false)
const columns = useMemo(() => {
return [
{
title: 'ID',
dataIndex: 'id',
hideInTable: true,
hideInSearch: true,
formItemProps: { hidden: true }
},
{
'title': t(`${i18nPrefix}.columns.name`, '站点名称'),
'dataIndex': 'name',
onHeaderCell: () => ({
width: 200,
}),
ellipsis: true,
formItemProps: {
width: undefined,
rules: [
{ required: true, message: t(`${i18nPrefix}.columns.name`, '站点名称') }
]
},
},
{
'title': t(`${i18nPrefix}.columns.icon_cdn`, '站点图标'),
'dataIndex': 'icon_cdn',
onHeaderCell: () => ({
width: 80,
}),
render: (_text, record) => {
return <img src={record.icon_cdn} style={{ width: 20, height: 20 }}/>
},
},
{
'title': t(`${i18nPrefix}.columns.url`, '站点URL'),
'dataIndex': 'url',
onHeaderCell: () => ({
width: 150,
}),
ellipsis: true,
copyable: true,
},
{
'title': t(`${i18nPrefix}.columns.param`, '参数'),
'dataIndex': 'param',
hideInTable: true,
},
{
'title': t(`${i18nPrefix}.columns.type_id`, '类型'),
'dataIndex': 'type_id',
valueType: 'select',
onHeaderCell: () => ({
width: 100,
}),
render: (_text, record) => {
return t(`${i18nPrefix}.type_id.${record.type_id}`, '')
},
fieldProps: {
options: types
}
},
{
'title': t(`${i18nPrefix}.columns.opt`, '操作方式'),
'dataIndex': 'opt',
hideInTable: true,
},
{
'title': t(`${i18nPrefix}.columns.filter`, '过滤模式'),
'dataIndex': 'filter',
hideInTable: true,
},
{
'title': t(`${i18nPrefix}.columns.filter_form`, '过滤表单'),
'dataIndex': 'filter_form',
hideInTable: true,
},
{
'title': t(`${i18nPrefix}.columns.sync_pic`, '同步图片'),
'dataIndex': 'sync_pic',
valueType: 'select',
onHeaderCell: () => ({
width: 100,
}),
render: (_text, record) => {
return t(`${i18nPrefix}.sync_pic.${record.sync_pic}`, '')
},
fieldProps: {
options: syncPicTypes
}
},
{
'title': t(`${i18nPrefix}.columns.class`, '扩展分类'),
'dataIndex': 'class',
valueType: 'textarea',
},
{
'title': t(`${i18nPrefix}.columns.weights`, '权重'),
'dataIndex': 'weights',
valueType: 'digit',
onHeaderCell: () => ({
width: 80,
}),
},
{
'title': t(`${i18nPrefix}.columns.status`, '启用'),
'dataIndex': 'status',
valueType: 'switch',
onHeaderCell: () => ({
width: 80,
}),
render: (_dom, record) => {
return <Switch value={record.status} size={'small'}/>
}
},
{
'title': t(`${i18nPrefix}.columns.open_replace`, '开启替换'),
'dataIndex': 'open_replace',
valueType: 'switch',
onHeaderCell: () => ({
width: 80,
}),
render: (_dom, record) => {
return <Switch value={record.open_replace} size={'small'}/>
}
},
{
'title': t(`${i18nPrefix}.columns.replace_str`, '替换内容'),
'dataIndex': 'replace_str',
valueType: 'textarea',
ellipsis: true,
},
{
'title': t(`${i18nPrefix}.columns.site_auth`, '搜片认证站点'),
'dataIndex': 'site_auth',
valueType: 'switch',
onHeaderCell: () => ({
width: 100,
}),
render: (_dom, record) => {
return <Switch value={record.site_auth} size={'small'}/>
}
},
{
'title': t(`${i18nPrefix}.columns.site_cooperation`, '搜片合作优质站点'),
'dataIndex': 'site_cooperation',
valueType: 'switch',
onHeaderCell: () => ({
width: 130,
}),
render: (_dom, record) => {
return <Switch value={record.site_cooperation} size={'small'}/>
}
},
{
'title': t(`${i18nPrefix}.columns.categories_rules`, '站点采集规则'),
'dataIndex': 'categories_rules',
valueType: 'textarea',
onHeaderCell: () => ({
width: 200,
}),
ellipsis: true,
},
{
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={() => {
deleteCollect([ 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: 2000,
}}
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 Collect

13
src/pages/cms/collect/style.ts

@ -0,0 +1,13 @@
import { createStyles } from '@/theme'
export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => {
const prefix = `${prefixCls}-${token?.proPrefix}-cms-collect-page`
const container = css`
`
return {
container: cx(prefix, props?.className, container),
}
})

26
src/store/cms/collect.ts

@ -6,29 +6,41 @@ import { message } from 'antd'
import { t } from 'i18next' import { t } from 'i18next'
import cmsServ from '@/service/cms.ts' import cmsServ from '@/service/cms.ts'
const i18nPrefix = 'cms.collect'
type SearchParams = IPage & { type SearchParams = IPage & {
key?: string key?: string
} }
export const idAtom = atom(0)
export const types = [
{ 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 syncPicTypes = [
{ label: t(`${i18nPrefix}.sync_pic.0`), value: 0 },
{ label: t(`${i18nPrefix}.sync_pic.1`), value: 1 },
{ label: t(`${i18nPrefix}.sync_pic.2`), value: 2 },
]
export const collectIdAtom = atom(0)
export const collectIdsAtom = atom<number[]>([]) export const collectIdsAtom = atom<number[]>([])
export const collectAtom = atom<Cms.ICollect>(undefined as unknown as Cms.ICollect) export const collectAtom = atom<Cms.ICollect>(undefined as unknown as Cms.ICollect)
export const searchAtom = atom<SearchParams>({
export const collectSearchAtom = atom<SearchParams>({
key: '' key: ''
} as SearchParams) } as SearchParams)
export const pageAtom = atom<IPage>({
export const collectPageAtom = atom<IPage>({
pageSize: 10, pageSize: 10,
page: 1, page: 1,
}) })
export const collectsAtom = atomWithQuery((get) => { export const collectsAtom = atomWithQuery((get) => {
return { return {
queryKey: [ 'collects', get(searchAtom) ],
queryKey: [ 'collects', get(collectSearchAtom) ],
queryFn: async ({ queryKey: [ , params ] }) => { queryFn: async ({ queryKey: [ , params ] }) => {
return await cmsServ.collect.list(params as SearchParams) return await cmsServ.collect.list(params as SearchParams)
}, },
@ -63,7 +75,7 @@ export const saveOrUpdateCollectAtom = atomWithMutation<IApiResult, Cms.ICollect
//更新列表 //更新列表
// 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: [ 'collects', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'collects', get(collectSearchAtom) ] })
return res return res
} }
@ -79,7 +91,7 @@ export const deleteCollectAtom = atomWithMutation((get) => {
onSuccess: (res) => { onSuccess: (res) => {
message.success('message.deleteSuccess') message.success('message.deleteSuccess')
//更新列表 //更新列表
get(queryClientAtom).invalidateQueries({ queryKey: [ 'collects', get(searchAtom) ] })
get(queryClientAtom).invalidateQueries({ queryKey: [ 'collects', get(collectSearchAtom) ] })
return res return res
} }
} }

Loading…
Cancel
Save