diff --git a/src/assets/css/pages/system/index.scss b/src/assets/css/pages/system/index.scss
index ecf9e7a..a41552d 100644
--- a/src/assets/css/pages/system/index.scss
+++ b/src/assets/css/pages/system/index.scss
@@ -74,6 +74,11 @@
text-align: right;
}
+ .big-chart {
+ width: 0;
+ height: 400px;
+ }
+
> * {
gap: 5px;
}
diff --git a/src/assets/svg/online.svg b/src/assets/svg/online.svg
new file mode 100644
index 0000000..a6b0741
--- /dev/null
+++ b/src/assets/svg/online.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/constants/urls.constants.ts b/src/constants/urls.constants.ts
index c4eadc9..ab5a1e2 100644
--- a/src/constants/urls.constants.ts
+++ b/src/constants/urls.constants.ts
@@ -16,6 +16,7 @@ export const URL_SYS_STATISTIC_SOFTWARE = `${URL_SYS_STATISTIC}/software`
export const URL_SYS_STATISTIC_HARDWARE = `${URL_SYS_STATISTIC}/hardware`
export const URL_SYS_STATISTIC_CPU = `${URL_SYS_STATISTIC}/cpu`
export const URL_SYS_STATISTIC_STORAGE = `${URL_SYS_STATISTIC}/storage`
+export const URL_SYS_STATISTIC_ONLINE = `${URL_SYS_STATISTIC}/online`
export const URL_API_V1 = '/api/v1'
export const URL_API_V1_AVATAR_RANDOM_BASE64 = `${URL_API_V1}/avatar/base64`
diff --git a/src/global.d.ts b/src/global.d.ts
index e7fe359..e51602e 100644
--- a/src/global.d.ts
+++ b/src/global.d.ts
@@ -294,10 +294,6 @@ interface AvatarBase64Vo {
base64: string
}
-interface SystemSettingsVo {
- mail: MailSettingsVo
-}
-
interface MailSettingsVo {
host?: string
port?: number
@@ -381,3 +377,11 @@ interface FileStoreInfoVo {
total: number
free: number
}
+
+interface OnlineInfoVo {
+ current: number
+ history: {
+ time: string
+ record: string
+ }[]
+}
diff --git a/src/pages/system/index.tsx b/src/pages/system/index.tsx
index 851cf37..55e65dd 100644
--- a/src/pages/system/index.tsx
+++ b/src/pages/system/index.tsx
@@ -5,9 +5,14 @@ import {
TooltipComponent,
TooltipComponentOption,
GridComponent,
- GridComponentOption
+ GridComponentOption,
+ ToolboxComponentOption,
+ DataZoomComponentOption,
+ ToolboxComponent,
+ DataZoomComponent
} from 'echarts/components'
-import { BarChart, BarSeriesOption } from 'echarts/charts'
+import { BarChart, BarSeriesOption, LineChart, LineSeriesOption } from 'echarts/charts'
+import { UniversalTransition } from 'echarts/features'
import { SVGRenderer } from 'echarts/renderers'
import '@/assets/css/pages/system/index.scss'
import { useUpdatedEffect } from '@/util/hooks'
@@ -16,6 +21,7 @@ import { utcToLocalTime } from '@/util/datetime'
import {
r_sys_statistic_cpu,
r_sys_statistic_hardware,
+ r_sys_statistic_online,
r_sys_statistic_software,
r_sys_statistic_storage
} from '@/services/system'
@@ -25,9 +31,23 @@ import FitFullScreen from '@/components/common/FitFullScreen'
import HideScrollbar from '@/components/common/HideScrollbar'
import LoadingMask from '@/components/common/LoadingMask'
-echarts.use([TooltipComponent, GridComponent, BarChart, SVGRenderer])
+echarts.use([
+ TooltipComponent,
+ ToolboxComponent,
+ GridComponent,
+ DataZoomComponent,
+ BarChart,
+ LineChart,
+ SVGRenderer,
+ UniversalTransition
+])
type EChartsOption = echarts.ComposeOption<
- TooltipComponentOption | GridComponentOption | BarSeriesOption
+ | TooltipComponentOption
+ | ToolboxComponentOption
+ | GridComponentOption
+ | BarSeriesOption
+ | DataZoomComponentOption
+ | LineSeriesOption
>
const barDefaultSeriesOption: BarSeriesOption = {
@@ -46,7 +66,7 @@ const barDefaultSeriesOption: BarSeriesOption = {
}
}
-const eChartsBaseOption: EChartsOption = {
+const barEChartsBaseOption: EChartsOption = {
tooltip: {},
xAxis: {
show: false
@@ -70,9 +90,43 @@ const eChartsBaseOption: EChartsOption = {
}
}
+const lineEChartsBaseOption: EChartsOption = {
+ tooltip: {
+ trigger: 'axis'
+ },
+ toolbox: {
+ feature: {
+ dataZoom: {
+ yAxisIndex: 'none'
+ },
+ restore: {},
+ saveAsImage: {}
+ }
+ },
+ xAxis: {
+ type: 'time'
+ },
+ yAxis: {
+ type: 'value',
+ interval: 1
+ },
+ dataZoom: [
+ {
+ type: 'inside',
+ start: 0,
+ end: 100
+ },
+ {
+ start: 0,
+ end: 100
+ }
+ ],
+ series: [{}]
+}
+
interface CommonCardProps extends React.PropsWithChildren {
icon: IconComponent
- title: string
+ title: React.ReactNode
loading?: boolean
expand?: React.ReactNode
}
@@ -97,6 +151,97 @@ const CommonCard: React.FC = (props) => {
)
}
+const OnlineInfo: React.FC = () => {
+ const onlineInfoDivRef = useRef(null)
+ const onlineInfoEChartsRef = useRef(null)
+ const [isLoading, setIsLoading] = useState(false)
+ const [currentOnlineCount, setCurrentOnlineCount] = useState(-1)
+
+ useUpdatedEffect(() => {
+ const chartResizeObserver = new ResizeObserver(() => {
+ onlineInfoEChartsRef.current?.resize()
+ })
+
+ onlineInfoDivRef.current && chartResizeObserver.observe(onlineInfoDivRef.current)
+
+ return () => {
+ onlineInfoDivRef.current && chartResizeObserver.unobserve(onlineInfoDivRef.current)
+ }
+ }, [isLoading])
+
+ useUpdatedEffect(() => {
+ getOnlineInfo()
+ }, [])
+
+ const getOnlineInfo = () => {
+ if (isLoading) {
+ return
+ }
+
+ setIsLoading(true)
+
+ void r_sys_statistic_online().then((res) => {
+ const response = res.data
+ if (response.success) {
+ const data = response.data
+ if (data) {
+ setIsLoading(false)
+
+ setCurrentOnlineCount(data.current)
+
+ setTimeout(() => {
+ const dataList = data.history.map((value) => [value.time, value.record])
+
+ onlineInfoEChartsRef.current = echarts.init(
+ onlineInfoDivRef.current,
+ null,
+ { renderer: 'svg' }
+ )
+
+ onlineInfoEChartsRef.current?.setOption({
+ ...lineEChartsBaseOption,
+ series: [
+ {
+ name: '在线人数',
+ type: 'line',
+ smooth: true,
+ symbol: 'none',
+ areaStyle: {},
+ data: dataList
+ }
+ ]
+ })
+ })
+ }
+ }
+ })
+ }
+
+ return (
+
+
+ 在线用户
+ 当前 {currentOnlineCount}
+
+ >
+ }
+ loading={isLoading}
+ expand={
+ getOnlineInfo()}>
+
+
+ }
+ >
+
+
+
+
+ )
+}
+
const SoftwareInfo: React.FC = () => {
const [softwareInfoData, setSoftwareInfoData] = useState()
@@ -271,9 +416,9 @@ const CPUInfo: React.FC = () => {
setCpuInfoEChartsOption(
dataList.map((value, index) => ({
- ...eChartsBaseOption,
+ ...barEChartsBaseOption,
yAxis: {
- ...eChartsBaseOption.yAxis,
+ ...barEChartsBaseOption.yAxis,
data: [index === 0 ? '总占用' : `CPU ${index - 1}`]
},
series: value
@@ -501,13 +646,13 @@ const StorageInfo: React.FC = () => {
}
const storageInfoVoToStorageEChartsOption = (label: string, used: number, free: number) => ({
- ...eChartsBaseOption,
+ ...barEChartsBaseOption,
xAxis: {
- ...eChartsBaseOption.xAxis,
+ ...barEChartsBaseOption.xAxis,
max: used + free
},
yAxis: {
- ...eChartsBaseOption.yAxis,
+ ...barEChartsBaseOption.yAxis,
data: [label]
},
series: [
@@ -577,6 +722,7 @@ const System: React.FC = () => {
+
diff --git a/src/services/system.tsx b/src/services/system.tsx
index 7c0b6a1..5945a13 100644
--- a/src/services/system.tsx
+++ b/src/services/system.tsx
@@ -12,7 +12,8 @@ import {
URL_SYS_STATISTIC_SOFTWARE,
URL_SYS_STATISTIC_HARDWARE,
URL_SYS_STATISTIC_CPU,
- URL_SYS_STATISTIC_STORAGE
+ URL_SYS_STATISTIC_STORAGE,
+ URL_SYS_STATISTIC_ONLINE
} from '@/constants/urls.constants'
import request from '@/services/index'
@@ -86,3 +87,5 @@ export const r_sys_statistic_hardware = () =>
export const r_sys_statistic_cpu = () => request.get(URL_SYS_STATISTIC_CPU)
export const r_sys_statistic_storage = () => request.get(URL_SYS_STATISTIC_STORAGE)
+
+export const r_sys_statistic_online = () => request.get(URL_SYS_STATISTIC_ONLINE)