Browse Source

美化表格滚动条

main
dark 6 months ago
parent
commit
cc2c8f5111
  1. 95
      src/components/table/Table.tsx
  2. 1
      src/components/table/index.ts
  3. 23
      src/components/table/style.ts
  4. 4
      src/hooks/useScrollStyle.ts
  5. 3
      src/layout/ListPageLayout.tsx
  6. 5
      src/layout/TwoColPageLayout.tsx
  7. 36
      src/layout/style.ts
  8. 12
      src/pages/cms/collect/index.tsx
  9. 12
      src/pages/cms/video/index.tsx
  10. 12
      src/pages/cms/video_cloud/index.tsx
  11. 12
      src/pages/cms/video_magnet/index.tsx
  12. 32
      src/pages/system/logs/login/index.tsx
  13. 4
      src/pages/system/menus/index.tsx
  14. 13
      src/pages/system/menus/style.ts
  15. 7
      src/pages/system/roles/index.tsx
  16. 7
      src/pages/system/users/index.tsx
  17. 9
      src/pages/videos/list/index.tsx
  18. 11
      src/pages/websites/ssl/index.tsx
  19. 12
      src/utils/dom.ts

95
src/components/table/Table.tsx

@ -0,0 +1,95 @@
import { ProTable, ProTableProps, ProCard } from '@ant-design/pro-components'
import React, { useEffect, useRef, useState } from 'react'
import { useStyle } from './style'
export interface TableProps<T = any, D = any> extends ProTableProps<T, D> {
}
export const Table = <T extends Record<string, any> = any, D = any>(props: TableProps<T, D>) => {
const { styles } = useStyle()
const toolbarRef = useRef<HTMLDivElement | undefined | null>(undefined)
const alterRef = useRef<HTMLDivElement | undefined | null>(undefined)
const [ toolbarHeight, setHeight ] = useState<number>(65)
const [ alterHeight, setAlterHeight ] = useState<number>(0)
const scroll = props.scroll ? {
...props.scroll,
y: props.scroll.y ?? ` calc(100vh - ${toolbarHeight + 200}px)`
} : undefined
useEffect(() => {
if (!toolbarRef.current) return
setHeight(toolbarRef.current?.offsetHeight ?? 65)
//监听toolbarRef offsetHeight
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.target === toolbarRef.current) {
setHeight(entry.contentRect.height)
}
}
})
observer.observe(toolbarRef.current!)
return () => {
observer.disconnect()
}
}, [ toolbarRef.current ])
useEffect(() => {
if (!alterRef.current) return
setHeight(alterRef.current?.offsetHeight ?? 65)
//监听toolbarRef offsetHeight
const observer = new ResizeObserver(entries => {
for (const entry of entries) {
if (entry.target === alterRef.current && entry.contentRect.height > 0) {
setAlterHeight(entry.contentRect.height + 16)
}
}
})
observer.observe(alterRef.current!)
return () => {
observer.disconnect()
}
}, [ alterRef.current ])
const style = {
'--toolbar-height': `${toolbarHeight}px`,
'--alter-height': `${alterHeight}px`,
} as React.CSSProperties
// @ts-ignore fix dataItem
return <ProTable<T>
{...props}
className={styles.container}
style={style}
tableRender={(props, _dom, domList) => {
return <ProCard
ghost={props.ghost}
{...props.cardProps}
bodyStyle={{
paddingBlockStart: 0,
}}
>
<div ref={toolbarRef as any}>{domList.toolbar}</div>
<div ref={alterRef as any}>{domList.alert}</div>
<>{domList.table}</>
</ProCard>
}}
scroll={scroll}
></ProTable>
}
export default Table

1
src/components/table/index.ts

@ -0,0 +1 @@
export * from './Table.tsx'

23
src/components/table/style.ts

@ -0,0 +1,23 @@
import { createStyles } from '@/theme'
export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any) => {
const prefix = `${prefixCls}-${token?.proPrefix}-my-table`
const container = css`
--toolbar-height: 65px;
--alter-height: 0px;
--padding: 37px;
--table-body-height: calc(var(--toolbar-height, 65px) + var(--alter-height, 0px) + var(--header-height, 56px) + var(--padding, 20px) * 4);
.ant-table-body {
overflow: auto scroll;
max-height: calc(100vh - var(--table-body-height)) !important;
height: calc(100vh - var(--table-body-height)) !important;
}
`
return {
container: cx(prefix, props?.className, container),
}
})

4
src/hooks/useScrollStyle.ts

@ -64,11 +64,9 @@ export const useScrollStyle = () => {
background-size: 100% 40px, 100% 40px, 100% 14px, 100% 14px;
background-attachment: local, local, scroll, scroll;
${scrollbar.toString()}
${scrollbar}
`
return {
scrollbarBackground,
scrollbar,

3
src/layout/ListPageLayout.tsx

@ -18,8 +18,9 @@ const ListPageLayout: React.FC<IListPageLayoutProps> = (
<>
<PageContainer
breadcrumbRender={false} title={false}
className={styles.container}
className={cx(styles.container, styles.pageCard)}
{...props}
>
<div className={cx({
[styles.authHeight]: authHeight

5
src/layout/TwoColPageLayout.tsx

@ -12,10 +12,11 @@ interface ITreePageLayoutProps {
}
export const TwoColPageLayout: React.FC<ITreePageLayoutProps> = (props) => {
const { styles } = useStyle({ className: 'two-col' })
const { styles, cx } = useStyle({ className: 'two-col' })
return (
<PageContainer
breadcrumbRender={false} title={false} className={styles.container}
breadcrumbRender={false} title={false}
className={cx(styles.container, styles.pageCard)}
{...props.pageProps}
>
<Flexbox horizontal className={styles.authHeight}>

36
src/layout/style.ts

@ -7,8 +7,6 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
const { scrollbar } = useScrollStyle()
console.log(scrollbar)
const container = {
[prefix]: css`
@ -33,9 +31,36 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
${scrollbar}
}
.ant-pro-layout-content{
padding: 20px;
}
.ant-pro-layout .ant-pro-layout-content-has-page-container{
padding: 0;
}
.ant-pro-page-container-children-container{
padding-inline: 20px;
padding-block-end: 20px;
}
.ant-page-header-no-children {
height: 20px;
}
.ant-pro-card{
height: calc(100vh - 100px)!important;
min-height: calc(100vh - 100px)!important;
}
`,
}
const pageCard = css`
`
const pageContext = css`
box-shadow: ${token.boxShadowSecondary};
`
@ -91,8 +116,12 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
background: ${token.colorBgContainer};
`
const authHeight = css`
min-height: calc(100vh - 122px);
background-color: ${token.colorBgContainer};
.ant-pro-draggable-panel-fixed{
height: calc(100vh - 100px)!important;
min-height: calc(100vh - 100px)!important;
}
`
return {
@ -103,6 +132,7 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }, props: any)
sideMenu,
mySider,
mySiderMenu,
pageCard,
}
})

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

@ -1,5 +1,5 @@
import { useEffect, useMemo, useState } from 'react'
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components'
import { BetaSchemaForm, ProColumns, ProFormColumnsType } from '@ant-design/pro-components'
import { useTranslation } from '@/i18n.ts'
import { useAtom, useAtomValue } from 'jotai'
import {
@ -14,6 +14,7 @@ import { Button, Form, Popconfirm } from 'antd'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import Switch from '@/components/switch'
import Action from '@/components/action/Action.tsx'
import { Table as ProTable } from '@/components/table'
const i18nPrefix = 'cms.collect'
@ -269,7 +270,7 @@ const Collect = () => {
]
}}
scroll={{
x: 2000,
x: 2000, y: 'calc(100vh - 265px)'
}}
loading={isLoading || isFetching}
dataSource={data?.rows ?? []}
@ -284,6 +285,13 @@ const Collect = () => {
total: data?.total,
pageSize: search.pageSize,
current: search.page,
onShowSizeChange: (current: number, size: number) => {
setSearch({
...search,
pageSize: size,
page: current
})
},
onChange: (current, pageSize) => {
setSearch(prev => {
return {

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

@ -8,7 +8,7 @@ import {
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 { BetaSchemaForm, ProColumns, ProFormColumnsType } from '@ant-design/pro-components'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import TagPro from '@/components/tag-pro/TagPro.tsx'
import { categoriesAtom, categoryByIdAtom, categoryIdAtom } from '@/store/cms/category.ts'
@ -17,6 +17,7 @@ import { FilterOutlined } from '@ant-design/icons'
import TagValue from '@/components/tag-value/TagValue.tsx'
import dayjs from 'dayjs'
import { useStyle } from './style.ts'
import { Table as ProTable } from '@/components/table'
const i18nPrefix = 'cms.video'
@ -677,7 +678,7 @@ const Video = () => {
]
}}
scroll={{
x: 3800, y: 'calc(100vh - 290px)'
x: 3800, y: 'calc(100vh - 265px)'
}}
onRow={(record) => {
return {
@ -703,6 +704,13 @@ const Video = () => {
total: data?.total,
pageSize: search.pageSize,
current: search.page,
onShowSizeChange: (current: number, size: number) => {
setSearch({
...search,
pageSize: size,
page: current
})
},
onChange: (current, pageSize) => {
setSearch(prev => {
return {

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

@ -4,7 +4,7 @@ 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 { BetaSchemaForm, ProColumns, ProFormColumnsType } from '@ant-design/pro-components'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import {
deleteVideoCloudAtom,
@ -22,6 +22,7 @@ import { videoTypes } from '@/store/cms/video.ts'
import { useStyle} from './style'
import { getValueCount } from '@/utils'
import { FilterOutlined } from '@ant-design/icons'
import { Table as ProTable } from '@/components/table'
const i18nPrefix = 'cms.videoCloud'
@ -682,7 +683,7 @@ const VideoCloud = () => {
}}
scroll={{
x: 3800, y: 'calc(100vh - 290px)'
x: 3800, y: 'calc(100vh - 265px)'
}}
onRow={(record) => {
return {
@ -708,6 +709,13 @@ const VideoCloud = () => {
total: data?.total,
pageSize: search.pageSize,
current: search.page,
onShowSizeChange: (current: number, size: number) => {
setSearch({
...search,
pageSize: size,
page: current
})
},
onChange: (current, pageSize) => {
setSearch(prev => {
return {

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

@ -4,7 +4,7 @@ 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 { BetaSchemaForm, ProColumns, ProFormColumnsType } from '@ant-design/pro-components'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import { videoTypes } from '@/store/cms/video.ts'
import {
@ -21,6 +21,7 @@ import TagValue from '@/components/tag-value/TagValue.tsx'
import dayjs from 'dayjs'
import TagPro from '@/components/tag-pro/TagPro.tsx'
import { useStyle } from './style'
import { Table as ProTable } from '@/components/table'
const i18nPrefix = 'cms.videoMagnet'
@ -681,7 +682,7 @@ const VideoMagnet = () => {
]
}}
scroll={{
x: 3800, y: 'calc(100vh - 290px)'
x: 3800, y: 'calc(100vh - 265px)'
}}
onRow={(record) => {
return {
@ -707,6 +708,13 @@ const VideoMagnet = () => {
total: data?.total,
pageSize: search.pageSize,
current: search.page,
onShowSizeChange: (current: number, size: number) => {
setSearch({
...search,
pageSize: size,
page: current
})
},
onChange: (current, pageSize) => {
setSearch(prev => {
return {

32
src/pages/system/logs/login/index.tsx

@ -1,17 +1,17 @@
import Switch from '@/components/switch'
import {
ActionType,
PageContainer,
ProColumns,
ProTable,
} from '@ant-design/pro-components'
import { useStyle } from './style.ts'
import { memo, useMemo, useRef, useState } from 'react'
import { useAtom, useAtomValue } from 'jotai'
import { Table as ProTable } from '@/components/table'
import { useTranslation } from '@/i18n.ts'
import { Button, Space, Table, Popconfirm } from 'antd'
import { deleteLoginLogAtom, loginLogPageAtom, loginLogsAtom, loginLogSearchAtom } from '@/store/system/logs.ts'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
const LoginLog = memo(() => {
@ -43,9 +43,12 @@ const LoginLog = memo(() => {
},
{
title: t('system.logs.login.columns.user_agent', '浏览器'), dataIndex: 'user_agent', valueType: 'text',
width: 500,
ellipsis: true,
},
{
title: t('system.logs.login.columns.status', '状态'), dataIndex: 'status', valueType: 'switch',
width: 80,
render: (_, record) => {
return <Switch value={record.status} size={'small'}/>
},
@ -54,9 +57,10 @@ const LoginLog = memo(() => {
title: t('system.logs.login.columns.created_at', '登录时间'),
dataIndex: 'created_at',
valueType: 'dateTime',
width: 180,
},
{
title: t('system.logs.login.columns.option','操作'), valueType: 'option',
title: t('system.logs.login.columns.option', '操作'), valueType: 'option',
key: 'option',
render: (_, record) => [
<Popconfirm
@ -76,8 +80,8 @@ const LoginLog = memo(() => {
}, [])
return (
<PageContainer breadcrumbRender={false} title={false} className={styles.container}>
<div className={styles.authHeight}>
<ListPageLayout className={styles.container}>
<>
<ProTable
rowKey={'id'}
actionRef={actionRef}
@ -93,6 +97,9 @@ const LoginLog = memo(() => {
selectedRowKeys: ids,
selections: [ Table.SELECTION_ALL, Table.SELECTION_INVERT ],
}}
scroll={{
}}
tableAlertOptionRender={() => {
return (
<Space size={16}>
@ -118,7 +125,7 @@ const LoginLog = memo(() => {
onSearch: (value: string) => {
setSearch({ key: value })
},
placeholder: t('system.logs.login.search.placeholder','请输入用户名查询')
placeholder: t('system.logs.login.search.placeholder', '请输入用户名查询')
},
actions: []
}}
@ -126,6 +133,13 @@ const LoginLog = memo(() => {
total: data?.total,
current: page.page,
pageSize: page.pageSize,
onShowSizeChange: (current: number, size: number) => {
setPage({
...page,
pageSize: size,
page: current
})
},
onChange: (page) => {
setPage((prev) => {
@ -134,10 +148,8 @@ const LoginLog = memo(() => {
}
}}
/>
</div>
</PageContainer>
</>
</ListPageLayout>
)
})

4
src/pages/system/menus/index.tsx

@ -97,7 +97,7 @@ const Menus = () => {
<ProCard title={t('system.menus.setting', '配置')}
className={styles.formSetting}
>
<div className={'ant-pro-card-body-content'}>
<Form.Item hidden={true} label={'id'} name={'id'}>
<Input disabled={true}/>
</Form.Item>
@ -183,7 +183,7 @@ const Menus = () => {
{t('system.menus.form.save', '保存')}
</Button>
</Form.Item>
</div>
</ProCard>
<ProCard title={t('system.menus.button', '按钮')}

13
src/pages/system/menus/style.ts

@ -1,7 +1,9 @@
import { createStyles } from '@/theme'
import { useScrollStyle } from '@/hooks/useScrollStyle'
export const useStyle = createStyles(({ token, css, cx, prefixCls }) => {
const prefix = `${prefixCls}-${token?.proPrefix}-menu-page`
const { scrollbarBackground } = useScrollStyle()
const box = css`
flex: 1;
@ -19,11 +21,20 @@ export const useStyle = createStyles(({ token, css, cx, prefixCls }) => {
const formSetting = css`
flex: 1;
.ant-pro-card-body {
overflow: auto;
${scrollbarBackground}
.ant-pro-card-body-content {
padding-inline: 10px 0;
}
}
`
const formButtons = css`
width: 500px;
.ant-pro-card-body {
overflow: hidden;
}
`
const tree = css`

7
src/pages/system/roles/index.tsx

@ -203,6 +203,13 @@ const Roles = memo(() => {
total: data?.total,
current: page.page,
pageSize: page.pageSize,
onShowSizeChange: (current: number, size: number) => {
setPage({
...page,
pageSize: size,
page: current
})
},
onChange: (page) => {
setPage((prev) => {

7
src/pages/system/users/index.tsx

@ -209,6 +209,13 @@ const Users = () => {
total: data?.total,
current: page.page,
pageSize: page.pageSize,
onShowSizeChange: (current: number, size: number) => {
setPage({
...page,
pageSize: size,
page: current
})
},
onChange: (page) => {
setPage((prev) => {
return { ...prev, page }

9
src/pages/videos/list/index.tsx

@ -14,7 +14,6 @@ import {
ProColumns,
ProFormColumnsType,
ProFormUploadButton,
ProTable
} from '@ant-design/pro-components'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import { categoryByIdAtom, categoryIdAtom } from '@/store/videos/category.ts'
@ -23,6 +22,7 @@ import TagValue from '@/components/tag-value/TagValue.tsx'
import { useStyle } from './style'
import { ExportOutlined, FilterOutlined } from '@ant-design/icons'
import { getValueCount } from '@/utils'
import { Table as ProTable } from '@/components/table'
const i18nPrefix = 'videos.list'
@ -694,6 +694,13 @@ const Video = () => {
total: data?.total,
pageSize: search.pageSize,
current: search.page,
onShowSizeChange: (current: number, size: number) => {
setSearch({
...search,
pageSize: size,
page: current
})
},
onChange: (current, pageSize) => {
setSearch(prev => {
return {

11
src/pages/websites/ssl/index.tsx

@ -10,7 +10,7 @@ import {
sslSearchAtom, uploadSslAtom
} from '@/store/websites/ssl.ts'
import ListPageLayout from '@/layout/ListPageLayout.tsx'
import { BetaSchemaForm, ProColumns, ProFormColumnsType, ProTable } from '@ant-design/pro-components'
import { BetaSchemaForm, ProColumns, ProFormColumnsType } from '@ant-design/pro-components'
import { memo, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from '@/i18n.ts'
import { Button, Form, Popconfirm, Space } from 'antd'
@ -31,6 +31,7 @@ import { detailAtom } from './components/store.ts'
import Upload from './components/Upload.tsx'
import { FormInstance } from 'antd/lib'
import Download from '@/components/download/Download.tsx'
import { Table as ProTable } from '@/components/table'
const SSL = () => {
@ -371,10 +372,18 @@ const SSL = () => {
</Button>,
]
}}
scroll={{}}
pagination={{
pageSize: page?.pageSize ?? 10,
total: data?.total ?? 0,
current: page?.page ?? 1,
onShowSizeChange: (current: number, size: number) => {
setPage({
...page,
pageSize: size,
page: current
})
},
onChange: (page, pageSize) => {
setPage(prev => ({
...prev,

12
src/utils/dom.ts

@ -0,0 +1,12 @@
export function getElementRealHeight(el: Element) {
const style = window.getComputedStyle(el)
const paddingTop = parseInt(style.paddingTop)
const paddingBottom = parseInt(style.paddingBottom)
const marginTop = parseInt(style.marginTop)
const marginBottom = parseInt(style.marginBottom)
const clientHeight = el.clientHeight
return clientHeight + paddingTop + paddingBottom + marginTop + marginBottom
}
Loading…
Cancel
Save