Complete main UI #37
8
package-lock.json
generated
8
package-lock.json
generated
@@ -23,7 +23,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router": "^6.20.1",
|
"react-router": "^6.20.1",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
"size-sensor": "^1.0.2"
|
"size-sensor": "^1.0.2",
|
||||||
|
"vanilla-tilt": "^1.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/core": "^8.1.0",
|
"@svgr/core": "^8.1.0",
|
||||||
@@ -7933,6 +7934,11 @@
|
|||||||
"spdx-expression-parse": "^3.0.0"
|
"spdx-expression-parse": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vanilla-tilt": {
|
||||||
|
"version": "1.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/vanilla-tilt/-/vanilla-tilt-1.8.1.tgz",
|
||||||
|
"integrity": "sha512-hPB1XUsnh+SIeVSW2beb5RnuFxz4ZNgxjGD78o52F49gS4xaoLeEMh9qrQnJrnEn/vjjBI7IlxrrXmz4tGV0Kw=="
|
||||||
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "5.0.6",
|
"version": "5.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-5.0.6.tgz",
|
||||||
|
|||||||
@@ -29,7 +29,8 @@
|
|||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-router": "^6.20.1",
|
"react-router": "^6.20.1",
|
||||||
"react-router-dom": "^6.20.1",
|
"react-router-dom": "^6.20.1",
|
||||||
"size-sensor": "^1.0.2"
|
"size-sensor": "^1.0.2",
|
||||||
|
"vanilla-tilt": "^1.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/core": "^8.1.0",
|
"@svgr/core": "^8.1.0",
|
||||||
|
|||||||
40
src/assets/css/pages/system/index.scss
Normal file
40
src/assets/css/pages/system/index.scss
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
@use '@/assets/css/constants' as constants;
|
||||||
|
|
||||||
|
[data-component=system] {
|
||||||
|
.root-content {
|
||||||
|
padding: 30px;
|
||||||
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-start;
|
||||||
|
|
||||||
|
> .card-box {
|
||||||
|
width: 200px;
|
||||||
|
height: 360px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.common-card {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
margin-top: 100px;
|
||||||
|
text-align: center;
|
||||||
|
gap: 42px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
color: constants.$production-color;
|
||||||
|
font-size: constants.$SIZE_ICON_XL;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
font-weight: bolder;
|
||||||
|
font-size: 2em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1
src/assets/svg/option.svg
Normal file
1
src/assets/svg/option.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M810.666667 384a128 128 0 0 0-120.32 85.333333H128a42.666667 42.666667 0 0 0 0 85.333334h562.346667A128 128 0 1 0 810.666667 384zM128 298.666667h50.346667a128 128 0 0 0 240.64 0H896a42.666667 42.666667 0 0 0 0-85.333334H418.986667a128 128 0 0 0-240.64 0H128a42.666667 42.666667 0 0 0 0 85.333334zM896 725.333333h-306.346667a128 128 0 0 0-240.64 0H128a42.666667 42.666667 0 0 0 0 85.333334h221.013333a128 128 0 0 0 240.64 0H896a42.666667 42.666667 0 0 0 0-85.333334z" /></svg>
|
||||||
|
After Width: | Height: | Size: 548 B |
@@ -1,12 +1,16 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { hasPermission } from '@/util/auth'
|
import { hasPathPermission, hasPermission } from '@/util/auth'
|
||||||
|
|
||||||
interface PermissionProps extends React.PropsWithChildren {
|
interface PermissionProps extends React.PropsWithChildren {
|
||||||
operationCode?: string
|
operationCode?: string
|
||||||
|
path?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const Permission: React.FC<PermissionProps> = (props) => {
|
const Permission: React.FC<PermissionProps> = (props) => {
|
||||||
if (!props.operationCode || hasPermission(props.operationCode)) {
|
if (
|
||||||
|
(!props.operationCode || hasPermission(props.operationCode)) &&
|
||||||
|
(!props.path || hasPathPermission(props.path))
|
||||||
|
) {
|
||||||
return props.children
|
return props.children
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,7 @@ const OnlineInfo: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsLoading(true)
|
setIsLoading(true)
|
||||||
|
setCurrentOnlineCount(-1)
|
||||||
|
|
||||||
void r_sys_statistics_online({ scope: _scope }).then((res) => {
|
void r_sys_statistics_online({ scope: _scope }).then((res) => {
|
||||||
const response = res.data
|
const response = res.data
|
||||||
|
|||||||
@@ -1,7 +1,105 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
import Icon from '@ant-design/icons'
|
||||||
|
import VanillaTilt, { TiltOptions } from 'vanilla-tilt'
|
||||||
|
import '@/assets/css/pages/system/index.scss'
|
||||||
|
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||||
|
import FitFullScreen from '@/components/common/FitFullScreen'
|
||||||
|
import FlexBox from '@/components/common/FlexBox'
|
||||||
|
import Card from '@/components/common/Card'
|
||||||
|
import Permission from '@/components/common/Permission.tsx'
|
||||||
|
|
||||||
|
interface CommonCardProps
|
||||||
|
extends React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> {
|
||||||
|
icon: IconComponent
|
||||||
|
description?: React.ReactNode
|
||||||
|
options?: TiltOptions
|
||||||
|
url?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const CommonCard = forwardRef<HTMLDivElement, CommonCardProps>((props) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
|
const cardRef = useRef<HTMLDivElement>(null)
|
||||||
|
const {
|
||||||
|
style,
|
||||||
|
ref,
|
||||||
|
icon,
|
||||||
|
description,
|
||||||
|
options = {
|
||||||
|
reverse: true,
|
||||||
|
max: 8,
|
||||||
|
glare: true,
|
||||||
|
scale: 1.03
|
||||||
|
},
|
||||||
|
url,
|
||||||
|
children,
|
||||||
|
..._props
|
||||||
|
} = props
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
cardRef.current && VanillaTilt.init(cardRef.current, options)
|
||||||
|
}, [options])
|
||||||
|
|
||||||
|
const handleCardOnClick = () => {
|
||||||
|
url && navigate(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
style={{ overflow: 'visible', ...style }}
|
||||||
|
ref={cardRef}
|
||||||
|
{..._props}
|
||||||
|
onClick={handleCardOnClick}
|
||||||
|
>
|
||||||
|
<FlexBox className={'common-card'}>
|
||||||
|
<Icon component={icon} className={'icon'} />
|
||||||
|
<div className={'text'}>{children}</div>
|
||||||
|
<div className={'description'}>{description}</div>
|
||||||
|
</FlexBox>
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
const System: React.FC = () => {
|
const System: React.FC = () => {
|
||||||
return <></>
|
return (
|
||||||
|
<>
|
||||||
|
<FitFullScreen data-component={'system'}>
|
||||||
|
<HideScrollbar isShowVerticalScrollbar autoHideWaitingTime={500}>
|
||||||
|
<FlexBox direction={'horizontal'} className={'root-content'}>
|
||||||
|
<Permission path={'/system/statistics'}>
|
||||||
|
<CommonCard icon={IconFatwebAnalysis} url={'statistics'}>
|
||||||
|
系统概况
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
<Permission path={'/system/settings'}>
|
||||||
|
<CommonCard icon={IconFatwebOption} url={'settings'}>
|
||||||
|
系统设置
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
<Permission path={'/system/user'}>
|
||||||
|
<CommonCard icon={IconFatwebUser} url={'user'}>
|
||||||
|
用户管理
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
<Permission path={'/system/role'}>
|
||||||
|
<CommonCard icon={IconFatwebRole} url={'role'}>
|
||||||
|
角色管理
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
<Permission path={'/system/group'}>
|
||||||
|
<CommonCard icon={IconFatwebGroup} url={'group'}>
|
||||||
|
群组管理
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
<Permission path={'/system/log'}>
|
||||||
|
<CommonCard icon={IconFatwebLog} url={'log'}>
|
||||||
|
系统日志
|
||||||
|
</CommonCard>
|
||||||
|
</Permission>
|
||||||
|
</FlexBox>
|
||||||
|
</HideScrollbar>
|
||||||
|
</FitFullScreen>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default System
|
export default System
|
||||||
|
|||||||
@@ -47,8 +47,8 @@ const root: RouteJsonObject[] = [
|
|||||||
absolutePath: '/system',
|
absolutePath: '/system',
|
||||||
id: 'systemFramework',
|
id: 'systemFramework',
|
||||||
component: React.lazy(() => import('@/pages/SystemFramework')),
|
component: React.lazy(() => import('@/pages/SystemFramework')),
|
||||||
children: setTitle(system, '系统设置'),
|
children: setTitle(system, '系统配置'),
|
||||||
name: '系统设置',
|
name: '系统配置',
|
||||||
auth: true,
|
auth: true,
|
||||||
permission: true
|
permission: true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const system: RouteJsonObject[] = [
|
|||||||
id: 'system-settings',
|
id: 'system-settings',
|
||||||
component: React.lazy(() => import('@/pages/system/Settings')),
|
component: React.lazy(() => import('@/pages/system/Settings')),
|
||||||
name: '系统设置',
|
name: '系统设置',
|
||||||
icon: React.lazy(() => import('~icons/fatweb/setting.jsx')),
|
icon: React.lazy(() => import('~icons/fatweb/option.jsx')),
|
||||||
menu: true,
|
menu: true,
|
||||||
autoHide: true
|
autoHide: true
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user