Complete main UI #37
1141
package-lock.json
generated
1141
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
12
package.json
12
package.json
@@ -15,10 +15,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.2.6",
|
"@ant-design/icons": "^5.2.6",
|
||||||
"@ant-design/charts": "^2.0.0-beta.0",
|
|
||||||
"antd": "^5.12.1",
|
"antd": "^5.12.1",
|
||||||
"axios": "^1.6.2",
|
"axios": "^1.6.2",
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
|
"echarts": "^5.4.3",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
"localforage": "^1.10.0",
|
"localforage": "^1.10.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@@ -27,14 +28,15 @@
|
|||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"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"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svgr/core": "^8.1.0",
|
"@svgr/core": "^8.1.0",
|
||||||
"@svgr/plugin-jsx": "^8.1.0",
|
"@svgr/plugin-jsx": "^8.1.0",
|
||||||
"@types/jsdom": "^21.1.6",
|
"@types/jsdom": "^21.1.6",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/node": "^20.10.3",
|
"@types/node": "^20.10.4",
|
||||||
"@types/react": "^18.2.42",
|
"@types/react": "^18.2.42",
|
||||||
"@types/react-dom": "^18.2.17",
|
"@types/react-dom": "^18.2.17",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
"@typescript-eslint/eslint-plugin": "^6.13.2",
|
||||||
@@ -52,9 +54,9 @@
|
|||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"stylelint-config-prettier": "^9.0.5",
|
"stylelint-config-prettier": "^9.0.5",
|
||||||
"typescript": "^5.3.2",
|
"typescript": "^5.3.3",
|
||||||
"unplugin-auto-import": "^0.17.2",
|
"unplugin-auto-import": "^0.17.2",
|
||||||
"unplugin-icons": "^0.18.1",
|
"unplugin-icons": "^0.18.1",
|
||||||
"vite": "^5.0.5"
|
"vite": "^5.0.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,12 @@
|
|||||||
.root-content {
|
.root-content {
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
.root-row {
|
>.card-box {
|
||||||
gap: 20px;
|
width: 48%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
.common-card {
|
.common-card {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@@ -48,6 +51,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.value-chart {
|
||||||
|
>div {
|
||||||
|
height: 12px;
|
||||||
|
>* {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
1
src/assets/svg/cpu.svg
Normal file
1
src/assets/svg/cpu.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M256 768h512V256H256v512z m341.3 85.3H426.6v85.3h-85.3v-85.3h-128a42.7 42.7 0 0 1-42.7-42.7v-128H85.3v-85.3h85.3V426.6H85.3v-85.3h85.3v-128a42.7 42.7 0 0 1 42.7-42.7h128V85.3h85.3v85.3h170.7V85.3h85.3v85.3h128a42.7 42.7 0 0 1 42.7 42.7v128h85.3v85.3h-85.3v170.7h85.3v85.3h-85.3v128a42.7 42.7 0 0 1-42.7 42.7h-128v85.3h-85.3v-85.3z m-256-512h341.3v341.3H341.3V341.3z" /></svg>
|
||||||
|
After Width: | Height: | Size: 448 B |
1
src/assets/svg/java.svg
Normal file
1
src/assets/svg/java.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024"><path d="M564 96c44.864 105.888-160.864 170.752-180 259.008-17.504 80.992 121.888 176 122.016 176-21.28-33.504-36.768-61.76-58.016-114.016C412 328.736 667.36 249.12 564 96z m136 147.008s-179.872 11.36-188.992 128.992c-4.16 52.384 47.488 79.872 48.992 118.016 1.28 31.104-31.008 56.96-31.008 56.96s57.888-10.464 76-57.984c20-52.736-38.976-88.736-32.992-131.008 5.76-40.352 128-114.976 128-114.976z m44 270.976c-18.88-0.864-40.128 6.144-59.008 20 37.248-8.224 69.024 15.136 69.024 42.016 0 60.256-86.016 116.992-86.016 116.992s132.992-14.88 132.992-113.984c0-40.896-25.6-63.52-56.992-65.024z m-352.992 1.024c-46.4 1.6-139.008 9.248-139.008 44.992 0 49.76 215.744 53.632 370.016 23.008 0 0 41.984-29.248 52.992-40-101.12 20.992-332 24.256-332 5.984 0-16.736 73.984-33.984 73.984-33.984s-10.496-0.512-25.984 0z m-14.016 92c-25.376 0-63.008 19.744-63.008 38.976 0 38.752 191.04 68.512 332.032 12l-49.024-29.984c-95.616 31.264-272.256 20.864-220-20.992z m24 86.976c-34.624 0-56.992 21.888-56.992 38.016 0 49.6 206.88 54.496 288.992 4l-52-34.016c-61.248 26.4-215.36 30.272-180-8z m-116 45.024C228.512 737.888 192 763.488 192 784.96c0 114.368 579.008 108.896 579.008-8 0-19.36-22.88-28.608-31.008-32.992 47.264 111.744-472.992 103.008-472.992 36.992 0-14.976 38.496-29.984 73.984-22.976l-29.984-17.024a190.784 190.784 0 0 0-26.016-1.984zM832 816c-88 85.12-310.72 115.616-535.008 63.008 224.256 93.76 533.888 41.6 535.008-63.008z" /></svg>
|
||||||
|
After Width: | Height: | Size: 1.5 KiB |
1
src/assets/svg/memory.svg
Normal file
1
src/assets/svg/memory.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1280 1024"><path d="M1280 261.88V192c0-35.34-28.66-64-64-64H64C28.66 128 0 156.66 0 192v69.88c37.2 13.22 64 48.38 64 90.12s-26.8 76.9-64 90.12V640h1280v-197.88c-37.2-13.22-64-48.38-64-90.12s26.8-76.9 64-90.12zM448 512h-128V256h128v256z m256 0h-128V256h128v256z m256 0h-128V256h128v256zM0 896h128v-53.34c0-17.68 14.32-32 32-32s32 14.32 32 32V896h256v-53.34c0-17.68 14.32-32 32-32s32 14.32 32 32V896h256v-53.34c0-17.68 14.32-32 32-32s32 14.32 32 32V896h256v-53.34c0-17.68 14.32-32 32-32s32 14.32 32 32V896h128v-192H0v192z" /></svg>
|
||||||
|
After Width: | Height: | Size: 582 B |
181
src/components/common/echarts/EChartReact.tsx
Normal file
181
src/components/common/echarts/EChartReact.tsx
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
import React, { CSSProperties, useState } from 'react'
|
||||||
|
import echarts, { EChartsCoreOption, EChartsType } from 'echarts/core'
|
||||||
|
import { RendererType } from 'echarts/types/src/util/types'
|
||||||
|
import { LocaleOption } from 'echarts/types/src/core/locale'
|
||||||
|
import { bind, clear } from 'size-sensor'
|
||||||
|
import isEqual from 'fast-deep-equal'
|
||||||
|
import { usePrevious } from '@/util/hooks'
|
||||||
|
|
||||||
|
interface EChartsInitOpts {
|
||||||
|
locale?: string | LocaleOption
|
||||||
|
renderer?: RendererType
|
||||||
|
devicePixelRatio?: number
|
||||||
|
useDirtyRect?: boolean
|
||||||
|
useCoarsePointer?: boolean
|
||||||
|
pointerSize?: number
|
||||||
|
ssr?: boolean
|
||||||
|
width?: number | string
|
||||||
|
height?: number | string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EChartsReactProps {
|
||||||
|
echarts: typeof echarts
|
||||||
|
className?: string
|
||||||
|
style?: CSSProperties
|
||||||
|
option: EChartsCoreOption
|
||||||
|
theme?: string | object | null
|
||||||
|
notMerge?: boolean
|
||||||
|
lazyUpdate?: boolean
|
||||||
|
showLoading?: boolean
|
||||||
|
loadingOption?: object
|
||||||
|
opts?: EChartsInitOpts
|
||||||
|
onChartReady?: (instance: EChartsType) => void
|
||||||
|
onEvents?: Record<string, () => void>
|
||||||
|
shouldSetOption?: (prevProps: EChartsReactProps, props: EChartsReactProps) => boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const EChartReact: React.FC<EChartsReactProps> = (props) => {
|
||||||
|
const elementRef = useRef<HTMLDivElement>(null)
|
||||||
|
const prevProps = usePrevious(props)
|
||||||
|
const [echarts] = useState(props.echarts)
|
||||||
|
const [isInitialResize, setIsInitialResize] = useState(true)
|
||||||
|
|
||||||
|
const { style, className = '', theme, opts } = props
|
||||||
|
|
||||||
|
const renderNewECharts = () => {
|
||||||
|
const { onEvents, onChartReady } = props
|
||||||
|
|
||||||
|
const eChartsInstance = updateEChartsOption()
|
||||||
|
|
||||||
|
bindEvents(eChartsInstance, onEvents || {})
|
||||||
|
|
||||||
|
if (typeof onChartReady === 'function') {
|
||||||
|
onChartReady(eChartsInstance)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (elementRef.current) {
|
||||||
|
bind(elementRef.current, () => {
|
||||||
|
resize()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
dispose()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const updateEChartsOption = () => {
|
||||||
|
const { option, notMerge = false, lazyUpdate = false, showLoading, loadingOption } = props
|
||||||
|
|
||||||
|
const eChartsInstance = getEChartsInstance()
|
||||||
|
eChartsInstance.setOption(option, notMerge, lazyUpdate)
|
||||||
|
if (showLoading) {
|
||||||
|
eChartsInstance.showLoading(loadingOption)
|
||||||
|
} else {
|
||||||
|
eChartsInstance.hideLoading()
|
||||||
|
}
|
||||||
|
|
||||||
|
return eChartsInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
const getEChartsInstance = () =>
|
||||||
|
(elementRef.current && echarts.getInstanceByDom(elementRef.current)) ||
|
||||||
|
echarts.init(elementRef.current, theme, opts)
|
||||||
|
|
||||||
|
const bindEvents = (instance: EChartsType, events: EChartsReactProps['onEvents']) => {
|
||||||
|
const _bindEvents = (
|
||||||
|
eventName: string,
|
||||||
|
func: (param: unknown, instance: EChartsType) => void
|
||||||
|
) => {
|
||||||
|
if (typeof func === 'function') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-call
|
||||||
|
instance.on(eventName, (param: unknown) => {
|
||||||
|
func(param, instance)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const eventName in events) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(events, eventName)) {
|
||||||
|
_bindEvents(eventName, events[eventName])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const resize = () => {
|
||||||
|
const eChartsInstance = getEChartsInstance()
|
||||||
|
|
||||||
|
if (!isInitialResize) {
|
||||||
|
try {
|
||||||
|
eChartsInstance.resize()
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsInitialResize(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
const dispose = () => {
|
||||||
|
if (elementRef.current) {
|
||||||
|
try {
|
||||||
|
clear(elementRef.current)
|
||||||
|
} catch (e) {
|
||||||
|
console.warn(e)
|
||||||
|
}
|
||||||
|
echarts.dispose(elementRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pick = (obj: EChartsReactProps | undefined, keys: string[]): Record<string, unknown> => {
|
||||||
|
const r = {}
|
||||||
|
keys.forEach((key) => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-expect-error
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
|
r[key] = obj[key]
|
||||||
|
})
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
renderNewECharts()
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const { shouldSetOption } = props
|
||||||
|
if (
|
||||||
|
typeof shouldSetOption === 'function' &&
|
||||||
|
prevProps &&
|
||||||
|
!shouldSetOption(prevProps, props)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isEqual(prevProps?.theme, props.theme) ||
|
||||||
|
!isEqual(prevProps?.opts, props.opts) ||
|
||||||
|
!isEqual(prevProps?.onEvents, props.onEvents)
|
||||||
|
) {
|
||||||
|
dispose()
|
||||||
|
renderNewECharts()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const pickKeys = ['option', 'notMerge', 'lazyUpdate', 'showLoading', 'loadingOption']
|
||||||
|
if (!isEqual(pick(props, pickKeys), pick(prevProps, pickKeys))) {
|
||||||
|
updateEChartsOption()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isEqual(prevProps?.style, props.style) ||
|
||||||
|
!isEqual(prevProps?.className, props.className)
|
||||||
|
) {
|
||||||
|
resize()
|
||||||
|
}
|
||||||
|
}, [props])
|
||||||
|
|
||||||
|
return <div ref={elementRef} style={style} className={`echarts-react ${className}`}></div>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EChartReact
|
||||||
@@ -14,6 +14,9 @@ export const URL_SYS_SETTINGS_MAIL = `${URL_SYS_SETTINGS}/mail`
|
|||||||
export const URL_SYS_STATISTICS = '/system/statistics'
|
export const URL_SYS_STATISTICS = '/system/statistics'
|
||||||
export const URL_SYS_STATISTICS_SOFTWARE = `${URL_SYS_STATISTICS}/software`
|
export const URL_SYS_STATISTICS_SOFTWARE = `${URL_SYS_STATISTICS}/software`
|
||||||
export const URL_SYS_STATISTICS_HARDWARE = `${URL_SYS_STATISTICS}/hardware`
|
export const URL_SYS_STATISTICS_HARDWARE = `${URL_SYS_STATISTICS}/hardware`
|
||||||
|
export const URL_SYS_STATISTICS_CPU = `${URL_SYS_STATISTICS}/cpu`
|
||||||
|
export const URL_SYS_STATISTICS_MEMORY = `${URL_SYS_STATISTICS}/memory`
|
||||||
|
export const URL_SYS_STATISTICS_JVM = `${URL_SYS_STATISTICS}/jvm`
|
||||||
|
|
||||||
export const URL_API_V1 = '/api/v1'
|
export const URL_API_V1 = '/api/v1'
|
||||||
export const URL_API_V1_AVATAR_RANDOM_BASE64 = `${URL_API_V1}/avatar/base64`
|
export const URL_API_V1_AVATAR_RANDOM_BASE64 = `${URL_API_V1}/avatar/base64`
|
||||||
|
|||||||
21
src/global.d.ts
vendored
21
src/global.d.ts
vendored
@@ -351,3 +351,24 @@ interface HardwareInfoVo {
|
|||||||
memories: string
|
memories: string
|
||||||
disks: string
|
disks: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CpuInfoVo {
|
||||||
|
user: number
|
||||||
|
nice: number
|
||||||
|
system: number
|
||||||
|
idle: number
|
||||||
|
iowait: number
|
||||||
|
irq: number
|
||||||
|
softirq: number
|
||||||
|
steal: number
|
||||||
|
processors: CpuInfoVo[]
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MemoryInfoVo {
|
||||||
|
total: number
|
||||||
|
free: number
|
||||||
|
virtualInUse: number
|
||||||
|
virtualMax: number
|
||||||
|
swapTotal: number
|
||||||
|
swapUsed: number
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,16 +1,33 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import Icon from '@ant-design/icons'
|
import Icon from '@ant-design/icons'
|
||||||
// import { DualAxes, DualAxesConfig } from '@ant-design/plots'
|
import * as echarts from 'echarts/core'
|
||||||
|
import {
|
||||||
|
TooltipComponent,
|
||||||
|
TooltipComponentOption,
|
||||||
|
GridComponent,
|
||||||
|
GridComponentOption
|
||||||
|
} from 'echarts/components'
|
||||||
|
import { BarChart, BarSeriesOption } from 'echarts/charts'
|
||||||
|
import { CanvasRenderer } from 'echarts/renderers'
|
||||||
import '@/assets/css/pages/system/index.scss'
|
import '@/assets/css/pages/system/index.scss'
|
||||||
import { useUpdatedEffect } from '@/util/hooks'
|
import { useUpdatedEffect } from '@/util/hooks'
|
||||||
import { utcToLocalTime } from '@/util/datetime'
|
import { utcToLocalTime } from '@/util/datetime'
|
||||||
import { r_sys_statistics_hardware, r_sys_statistics_software } from '@/services/system'
|
import {
|
||||||
|
r_sys_statistics_cpu,
|
||||||
|
r_sys_statistics_hardware,
|
||||||
|
r_sys_statistics_software
|
||||||
|
} from '@/services/system'
|
||||||
import Card from '@/components/common/Card'
|
import Card from '@/components/common/Card'
|
||||||
import FlexBox from '@/components/common/FlexBox'
|
import FlexBox from '@/components/common/FlexBox'
|
||||||
import FitFullScreen from '@/components/common/FitFullScreen'
|
import FitFullScreen from '@/components/common/FitFullScreen'
|
||||||
import HideScrollbar from '@/components/common/HideScrollbar'
|
import HideScrollbar from '@/components/common/HideScrollbar'
|
||||||
import LoadingMask from '@/components/common/LoadingMask'
|
import LoadingMask from '@/components/common/LoadingMask'
|
||||||
|
import EChartReact from '@/components/common/echarts/EChartReact'
|
||||||
|
|
||||||
|
echarts.use([TooltipComponent, GridComponent, BarChart, CanvasRenderer])
|
||||||
|
type EChartsOption = echarts.ComposeOption<
|
||||||
|
TooltipComponentOption | GridComponentOption | BarSeriesOption
|
||||||
|
>
|
||||||
interface CommonCardProps extends React.PropsWithChildren {
|
interface CommonCardProps extends React.PropsWithChildren {
|
||||||
icon: IconComponent
|
icon: IconComponent
|
||||||
title: string
|
title: string
|
||||||
@@ -19,7 +36,7 @@ interface CommonCardProps extends React.PropsWithChildren {
|
|||||||
|
|
||||||
const CommonCard: React.FC<CommonCardProps> = (props) => {
|
const CommonCard: React.FC<CommonCardProps> = (props) => {
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card style={{ overflow: 'visible' }}>
|
||||||
<FlexBox className={'common-card'}>
|
<FlexBox className={'common-card'}>
|
||||||
<FlexBox direction={'horizontal'} className={'head'}>
|
<FlexBox direction={'horizontal'} className={'head'}>
|
||||||
<Icon component={props.icon} className={'icon'} />
|
<Icon component={props.icon} className={'icon'} />
|
||||||
@@ -27,7 +44,7 @@ const CommonCard: React.FC<CommonCardProps> = (props) => {
|
|||||||
</FlexBox>
|
</FlexBox>
|
||||||
<LoadingMask
|
<LoadingMask
|
||||||
hidden={!props.loading}
|
hidden={!props.loading}
|
||||||
maskContent={<AntdSkeleton active paragraph={{ rows: 10 }} />}
|
maskContent={<AntdSkeleton active paragraph={{ rows: 6 }} />}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</LoadingMask>
|
</LoadingMask>
|
||||||
@@ -124,9 +141,9 @@ const HardwareInfo: React.FC = () => {
|
|||||||
<div>CPU 架构</div>
|
<div>CPU 架构</div>
|
||||||
<div>微架构</div>
|
<div>微架构</div>
|
||||||
<div>64位</div>
|
<div>64位</div>
|
||||||
<div>CPU 插槽</div>
|
<div>物理 CPU</div>
|
||||||
<div>CPU 内核</div>
|
<div>物理核心</div>
|
||||||
<div>CPU 逻辑处理器</div>
|
<div>逻辑核心</div>
|
||||||
<div>内存</div>
|
<div>内存</div>
|
||||||
<div>磁盘</div>
|
<div>磁盘</div>
|
||||||
</FlexBox>
|
</FlexBox>
|
||||||
@@ -156,75 +173,121 @@ const HardwareInfo: React.FC = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const System: React.FC = () => {
|
const CPUInfo: React.FC = () => {
|
||||||
/*
|
const [cpuInfoData, setCpuInfoData] = useState<BarSeriesOption[]>()
|
||||||
const dualAxesData = [
|
|
||||||
{ year: '1991', value: 3, count: 10 },
|
|
||||||
{ year: '1992', value: 4, count: 4 },
|
|
||||||
{ year: '1993', value: 3.5, count: 5 },
|
|
||||||
{ year: '1994', value: 5, count: 5 },
|
|
||||||
{ year: '1995', value: 4.9, count: 4.9 },
|
|
||||||
{ year: '1996', value: 6, count: 35 },
|
|
||||||
{ year: '1997', value: 7, count: 7 },
|
|
||||||
{ year: '1998', value: 9, count: 1 },
|
|
||||||
{ year: '1999', value: 13, count: 20 }
|
|
||||||
]
|
|
||||||
|
|
||||||
const userStatisticsData = [
|
const defaultSeriesOption: BarSeriesOption = {
|
||||||
{ time: '2023-12-01', type: 'register', number: 23 },
|
type: 'bar',
|
||||||
{ time: '2023-12-02', type: 'register', number: 123 },
|
stack: 'total',
|
||||||
{ time: '2023-12-03', type: 'register', number: 1432 },
|
emphasis: {
|
||||||
{ time: '2023-12-05', type: 'register', number: 1 },
|
focus: 'series'
|
||||||
{ time: '2023-12-04', type: 'register', number: 234 },
|
}
|
||||||
{ time: '2023-12-06', type: 'register', number: 23 },
|
|
||||||
{ time: '2023-12-07', type: 'register', number: 54 },
|
|
||||||
{ time: '2023-12-08', type: 'register', number: 87 },
|
|
||||||
{ time: '2023-12-09', type: 'register', number: 12 },
|
|
||||||
{ time: '2023-12-10', type: 'register', number: 123 },
|
|
||||||
{ time: '2023-12-11', type: 'register', number: 20 },
|
|
||||||
{ time: '2023-12-01', type: 'login', number: 433 },
|
|
||||||
{ time: '2023-12-02', type: 'login', number: 2 },
|
|
||||||
{ time: '2023-12-03', type: 'login', number: 34 },
|
|
||||||
{ time: '2023-12-05', type: 'login', number: 12 },
|
|
||||||
{ time: '2023-12-04', type: 'login', number: 345 },
|
|
||||||
{ time: '2023-12-06', type: 'login', number: 121 },
|
|
||||||
{ time: '2023-12-07', type: 'login', number: 2 },
|
|
||||||
{ time: '2023-12-08', type: 'login', number: 435 },
|
|
||||||
{ time: '2023-12-09', type: 'login', number: 1 },
|
|
||||||
{ time: '2023-12-10', type: 'login', number: 54 },
|
|
||||||
{ time: '2023-12-11', type: 'login', number: 56 }
|
|
||||||
]
|
|
||||||
|
|
||||||
const dualAxesConfig: DualAxesConfig = {
|
|
||||||
data: userStatisticsData,
|
|
||||||
slider: { x: true },
|
|
||||||
shapeField: 'smooth',
|
|
||||||
xField: 'time',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
yField: 'number',
|
|
||||||
colorField: 'type'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
|
useUpdatedEffect(() => {
|
||||||
|
setInterval(
|
||||||
|
() =>
|
||||||
|
r_sys_statistics_cpu().then((res) => {
|
||||||
|
const response = res.data
|
||||||
|
if (response.success) {
|
||||||
|
const data = response.data
|
||||||
|
if (data) {
|
||||||
|
const cpuInfoData = Object.entries(data)
|
||||||
|
.filter(([key]) => key !== 'processors')
|
||||||
|
.map(([key, value]) => ({
|
||||||
|
...defaultSeriesOption,
|
||||||
|
name: key,
|
||||||
|
data: [value as number]
|
||||||
|
}))
|
||||||
|
console.log(cpuInfoData)
|
||||||
|
setCpuInfoData(cpuInfoData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
5000
|
||||||
|
)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const option: EChartsOption = {
|
||||||
|
tooltip: {},
|
||||||
|
xAxis: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
data: ['总使用'],
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisPointer: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: cpuInfoData
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CommonCard icon={IconFatwebCpu} title={'CPU 信息'} loading={false}>
|
||||||
|
<FlexBox className={'card-content'} direction={'horizontal'}>
|
||||||
|
<FlexBox className={'key'}>
|
||||||
|
<div>总占用</div>
|
||||||
|
<div>总占用</div>
|
||||||
|
<div>总占用</div>
|
||||||
|
</FlexBox>
|
||||||
|
<FlexBox className={'value-chart'}>
|
||||||
|
<div>
|
||||||
|
<EChartReact
|
||||||
|
echarts={echarts}
|
||||||
|
opts={{ renderer: 'svg', height: 12 }}
|
||||||
|
option={option}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</FlexBox>
|
||||||
|
</FlexBox>
|
||||||
|
</CommonCard>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MemoryInfo: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CommonCard icon={IconFatwebMemory} title={'内存信息'} loading={true}></CommonCard>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const JvmInfo: React.FC = () => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<CommonCard icon={IconFatwebJava} title={'JVM 信息'} loading={true}></CommonCard>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const System: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FitFullScreen>
|
<FitFullScreen>
|
||||||
<HideScrollbar isShowVerticalScrollbar autoHideWaitingTime={500}>
|
<HideScrollbar isShowVerticalScrollbar autoHideWaitingTime={500}>
|
||||||
<FlexBox className={'root-content'}>
|
<FlexBox direction={'horizontal'} className={'root-content'}>
|
||||||
<FlexBox direction={'horizontal'} className={'root-row'}>
|
<SoftwareInfo />
|
||||||
<SoftwareInfo />
|
<HardwareInfo />
|
||||||
<HardwareInfo />
|
<CPUInfo />
|
||||||
</FlexBox>
|
<MemoryInfo />
|
||||||
<FlexBox direction={'horizontal'} className={'root-row'}>
|
<JvmInfo />
|
||||||
<Card style={{ height: '400px' }}>
|
<div />
|
||||||
{/*<DualAxes {...dualAxesConfig} />*/}
|
|
||||||
</Card>
|
|
||||||
<div />
|
|
||||||
</FlexBox>
|
|
||||||
</FlexBox>
|
</FlexBox>
|
||||||
</HideScrollbar>
|
</HideScrollbar>
|
||||||
</FitFullScreen>
|
</FitFullScreen>
|
||||||
|
|||||||
@@ -10,7 +10,10 @@ import {
|
|||||||
URL_SYS_LOG,
|
URL_SYS_LOG,
|
||||||
URL_SYS_SETTINGS_MAIL,
|
URL_SYS_SETTINGS_MAIL,
|
||||||
URL_SYS_STATISTICS_SOFTWARE,
|
URL_SYS_STATISTICS_SOFTWARE,
|
||||||
URL_SYS_STATISTICS_HARDWARE
|
URL_SYS_STATISTICS_HARDWARE,
|
||||||
|
URL_SYS_STATISTICS_CPU,
|
||||||
|
URL_SYS_STATISTICS_MEMORY,
|
||||||
|
URL_SYS_STATISTICS_JVM
|
||||||
} from '@/constants/urls.constants'
|
} from '@/constants/urls.constants'
|
||||||
import request from '@/services/index'
|
import request from '@/services/index'
|
||||||
|
|
||||||
@@ -80,3 +83,9 @@ export const r_sys_statistics_software = () =>
|
|||||||
|
|
||||||
export const r_sys_statistics_hardware = () =>
|
export const r_sys_statistics_hardware = () =>
|
||||||
request.get<HardwareInfoVo>(URL_SYS_STATISTICS_HARDWARE)
|
request.get<HardwareInfoVo>(URL_SYS_STATISTICS_HARDWARE)
|
||||||
|
|
||||||
|
export const r_sys_statistics_cpu = () => request.get<CpuInfoVo>(URL_SYS_STATISTICS_CPU)
|
||||||
|
|
||||||
|
export const r_sys_statistics_memory = () => request.get<MemoryInfoVo>(URL_SYS_STATISTICS_MEMORY)
|
||||||
|
|
||||||
|
export const r_sys_statistics_jvm = () => request.get<MemoryInfoVo>(URL_SYS_STATISTICS_JVM)
|
||||||
|
|||||||
@@ -14,3 +14,11 @@ export const useUpdatedEffect = (
|
|||||||
}
|
}
|
||||||
}, dependencies)
|
}, dependencies)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const usePrevious = <T,>(value: T): T | undefined => {
|
||||||
|
const ref = useRef<T>()
|
||||||
|
useEffect(() => {
|
||||||
|
ref.current = value
|
||||||
|
})
|
||||||
|
return ref.current
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user