From 722c4f381282e9fc38483cafc0b919006b71f9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Wed, 16 Oct 2024 22:54:57 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=A6=96=E9=A1=B5=E5=85=A8=E6=96=B0?= =?UTF-8?q?=E8=AE=BE=E8=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/data/monitor.go | 2 +- internal/service/dashboard.go | 27 +- pkg/tools/tools.go | 25 +- pkg/types/system.go | 2 + web/package.json | 1 + web/pnpm-lock.yaml | 8 + web/src/api/panel/dashboard/index.ts | 29 + web/src/api/panel/info/index.ts | 28 - web/src/main.ts | 4 +- web/src/utils/common/common.ts | 6 +- web/src/utils/http/index.ts | 1 + web/src/views/cron/IndexView.vue | 4 +- web/src/views/home/IndexView.vue | 1041 +++++++++++++++----------- web/src/views/home/UpdateView.vue | 6 +- web/src/views/home/types.ts | 14 +- web/src/views/website/EditView.vue | 4 +- web/src/views/website/IndexView.vue | 4 +- 17 files changed, 699 insertions(+), 507 deletions(-) create mode 100644 web/src/api/panel/dashboard/index.ts delete mode 100644 web/src/api/panel/info/index.ts diff --git a/internal/data/monitor.go b/internal/data/monitor.go index 63182dee..67f09c56 100644 --- a/internal/data/monitor.go +++ b/internal/data/monitor.go @@ -50,7 +50,7 @@ func (r monitorRepo) UpdateSetting(setting *request.MonitorSetting) error { } func (r monitorRepo) Clear() error { - return app.Orm.Delete(&biz.Monitor{}).Error + return app.Orm.Where("1 = 1").Delete(&biz.Monitor{}).Error } func (r monitorRepo) List(start, end time.Time) ([]*biz.Monitor, error) { diff --git a/internal/service/dashboard.go b/internal/service/dashboard.go index 2e6fecc2..2b5a0f66 100644 --- a/internal/service/dashboard.go +++ b/internal/service/dashboard.go @@ -2,6 +2,8 @@ package service import ( "fmt" + "github.com/shirou/gopsutil/disk" + "net" "net/http" "regexp" "strings" @@ -82,15 +84,36 @@ func (s *DashboardService) SystemInfo(w http.ResponseWriter, r *http.Request) { return } + // 所有网卡名称 + var nets []types.LV + netInterfaces, _ := net.Interfaces() + for _, v := range netInterfaces { + nets = append(nets, types.LV{ + Value: v.Name, + Label: v.Name, + }) + } + // 所有硬盘名称 + var disks []types.LV + partitions, _ := disk.Partitions(false) + for _, v := range partitions { + disks = append(disks, types.LV{ + Value: v.Device, + Label: fmt.Sprintf("%s (%s)", v.Device, v.Mountpoint), + }) + } + Success(w, chix.M{ "procs": hostInfo.Procs, "hostname": hostInfo.Hostname, + "panel_version": app.Version, "kernel_arch": hostInfo.KernelArch, "kernel_version": hostInfo.KernelVersion, "os_name": hostInfo.Platform + " " + hostInfo.PlatformVersion, "boot_time": hostInfo.BootTime, - "uptime": fmt.Sprintf("%.2f", float64(hostInfo.Uptime)/86400), - "panel_version": app.Version, + "uptime": hostInfo.Uptime, + "nets": nets, + "disks": disks, }) } diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index 0104c186..22016e41 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -32,30 +32,34 @@ func CurrentInfo(nets, disks []string) types.CurrentInfo { res.Host, _ = host.Info() res.Mem, _ = mem.VirtualMemory() res.Swap, _ = mem.SwapMemory() - res.Disk, _ = disk.Partitions(true) - + // 硬盘IO ioCounters, _ := disk.IOCounters(disks...) for _, info := range ioCounters { res.DiskIO = append(res.DiskIO, info) } - + // 硬盘使用 var excludes = []string{"/dev", "/boot", "/sys", "/dev", "/run", "/proc", "/usr", "/var", "/snap"} excludes = append(excludes, "/mnt/cdrom") // CDROM excludes = append(excludes, "/mnt/wsl") // Windows WSL - for _, partition := range res.Disk { + res.Disk, _ = disk.Partitions(false) + res.Disk = slices.DeleteFunc(res.Disk, func(d disk.PartitionStat) bool { for _, exclude := range excludes { - if strings.HasPrefix(partition.Mountpoint, exclude) { + if strings.HasPrefix(d.Mountpoint, exclude) { + return true + } + // 去除内存盘和overlay容器盘 + if slices.Contains([]string{"tmpfs", "overlay"}, d.Fstype) { continue } } - // 去除内存盘和overlay容器盘 - if slices.Contains([]string{"tmpfs", "overlay"}, partition.Fstype) { - continue - } + return false + }) + // 分区使用 + for _, partition := range res.Disk { usage, _ := disk.Usage(partition.Mountpoint) res.DiskUsage = append(res.DiskUsage, *usage) } - + // 网络 if len(nets) == 0 { netInfo, _ := net.IOCounters(false) res.Net = netInfo @@ -70,6 +74,7 @@ func CurrentInfo(nets, disks []string) types.CurrentInfo { res.Net = netStats } + res.Time = time.Now() return res } diff --git a/pkg/types/system.go b/pkg/types/system.go index b853b10c..007a2d24 100644 --- a/pkg/types/system.go +++ b/pkg/types/system.go @@ -7,6 +7,7 @@ import ( "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/net" + "time" ) // CurrentInfo 监控信息 @@ -22,4 +23,5 @@ type CurrentInfo struct { DiskIO []disk.IOCountersStat `json:"disk_io"` Disk []disk.PartitionStat `json:"disk"` DiskUsage []disk.UsageStat `json:"disk_usage"` + Time time.Time `json:"time"` } diff --git a/web/package.json b/web/package.json index 87a93bf1..2b4b4832 100644 --- a/web/package.json +++ b/web/package.json @@ -45,6 +45,7 @@ "@tsconfig/node20": "^20.1.4", "@types/crypto-js": "^4.2.2", "@types/lodash-es": "^4.17.12", + "@types/luxon": "^3.4.2", "@types/node": "^20.16.11", "@unocss/eslint-config": "^0.63.4", "@vitejs/plugin-vue": "^5.1.4", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index 63ba506e..748cde58 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -78,6 +78,9 @@ importers: '@types/lodash-es': specifier: ^4.17.12 version: 4.17.12 + '@types/luxon': + specifier: ^3.4.2 + version: 3.4.2 '@types/node': specifier: ^20.16.11 version: 20.16.11 @@ -946,6 +949,9 @@ packages: '@types/lodash@4.17.10': resolution: {integrity: sha512-YpS0zzoduEhuOWjAotS6A5AVCva7X4lVlYLF0FYHAY9sdraBfnatttHItlWeZdGhuEkf+OzMNg2ZYAx8t+52uQ==} + '@types/luxon@3.4.2': + resolution: {integrity: sha512-TifLZlFudklWlMBfhubvgqTXRzLDI5pCbGa4P8a3wPyUQSW+1xQ5eDsreP9DWHX3tjq1ke96uYG/nwundroWcA==} + '@types/markdown-it@14.1.2': resolution: {integrity: sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==} @@ -3669,6 +3675,8 @@ snapshots: '@types/lodash@4.17.10': {} + '@types/luxon@3.4.2': {} + '@types/markdown-it@14.1.2': dependencies: '@types/linkify-it': 5.0.0 diff --git a/web/src/api/panel/dashboard/index.ts b/web/src/api/panel/dashboard/index.ts new file mode 100644 index 00000000..4ec63949 --- /dev/null +++ b/web/src/api/panel/dashboard/index.ts @@ -0,0 +1,29 @@ +import type { AxiosResponse } from 'axios' + +import { request } from '@/utils' + +export default { + // 面板信息 + panel: (): Promise => fetch('/api/dashboard/panel'), + // 面板菜单 + menu: (): Promise> => request.get('/dashboard/menu'), + // 首页应用 + homeApps: (): Promise> => request.get('/dashboard/homeApps'), + // 实时信息 + current: (nets: string[], disks: string[]): Promise> => + request.post('/dashboard/current', { nets, disks }), + // 系统信息 + systemInfo: (): Promise> => request.get('/dashboard/systemInfo'), + // 统计信息 + countInfo: (): Promise> => request.get('/dashboard/countInfo'), + // 已安装的数据库和PHP + installedDbAndPhp: (): Promise> => request.get('/dashboard/installedDbAndPhp'), + // 检查更新 + checkUpdate: (): Promise> => request.get('/dashboard/checkUpdate'), + // 更新日志 + updateInfo: (): Promise> => request.get('/dashboard/updateInfo'), + // 更新面板 + update: (): Promise> => request.post('/dashboard/update', null), + // 重启面板 + restart: (): Promise> => request.post('/dashboard/restart') +} diff --git a/web/src/api/panel/info/index.ts b/web/src/api/panel/info/index.ts deleted file mode 100644 index 1e7d30a1..00000000 --- a/web/src/api/panel/info/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { AxiosResponse } from 'axios' - -import { request } from '@/utils' - -export default { - // 面板信息 - panel: (): Promise => fetch('/api/info/panel'), - // 面板菜单 - menu: (): Promise> => request.get('/info/menu'), - // 首页应用 - homeApps: (): Promise> => request.get('/info/homeApps'), - // 实时监控 - realtime: (): Promise> => request.get('/info/realtime'), - // 系统信息 - systemInfo: (): Promise> => request.get('/info/systemInfo'), - // 统计信息 - countInfo: (): Promise> => request.get('/info/countInfo'), - // 已安装的数据库和PHP - installedDbAndPhp: (): Promise> => request.get('/info/installedDbAndPhp'), - // 检查更新 - checkUpdate: (): Promise> => request.get('/info/checkUpdate'), - // 更新日志 - updateInfo: (): Promise> => request.get('/info/updateInfo'), - // 更新面板 - update: (): Promise> => request.post('/info/update', null), - // 重启面板 - restart: (): Promise> => request.post('/info/restart') -} diff --git a/web/src/main.ts b/web/src/main.ts index 9053a5e0..f06a11db 100644 --- a/web/src/main.ts +++ b/web/src/main.ts @@ -12,7 +12,7 @@ import { setupNaiveDiscreteApi } from './utils' import { install as VueMonacoEditorPlugin } from '@guolao/vue-monaco-editor' -import info from '@/api/panel/info' +import dashboard from '@/api/panel/dashboard' async function setupApp() { const app = createApp(App) @@ -37,7 +37,7 @@ const title = ref('') const setupPanel = async () => { const themeStore = useThemeStore() - await info + await dashboard .panel() .then((response) => response.json()) .then((data) => { diff --git a/web/src/utils/common/common.ts b/web/src/utils/common/common.ts index 498107b0..1a89f4ac 100644 --- a/web/src/utils/common/common.ts +++ b/web/src/utils/common/common.ts @@ -15,13 +15,13 @@ export function formatDate(date: Time = undefined, format = 'yyyy-MM-dd') { /** 格式化持续时间,转为 x天x小时x分钟x秒 */ export function formatDuration(seconds: number) { - const duration = Duration.fromObject({ seconds }) - const days = Math.floor(duration.as('days')) + const duration = Duration.fromObject({ seconds }).shiftTo('days', 'hours', 'minutes', 'seconds') + const days = duration.days const hours = duration.hours const minutes = duration.minutes const secs = duration.seconds - return `${days}天${hours}时${minutes}分${secs}秒` + return `${days}天${hours}小时${minutes}分钟${secs}秒` } /** 生成随机字符串 */ diff --git a/web/src/utils/http/index.ts b/web/src/utils/http/index.ts index 299994aa..8c43806e 100644 --- a/web/src/utils/http/index.ts +++ b/web/src/utils/http/index.ts @@ -3,6 +3,7 @@ import { reqReject, reqResolve, resReject, resResolve } from './interceptors' export function createAxios(options = {}) { const defaultOptions = { + adapter: 'fetch', timeout: 0 } const service = axios.create({ diff --git a/web/src/views/cron/IndexView.vue b/web/src/views/cron/IndexView.vue index 37ad9225..eb53590a 100644 --- a/web/src/views/cron/IndexView.vue +++ b/web/src/views/cron/IndexView.vue @@ -3,8 +3,8 @@ import Editor from '@guolao/vue-monaco-editor' import { NButton, NDataTable, NInput, NPopconfirm, NSwitch } from 'naive-ui' import cron from '@/api/panel/cron' +import dashboard from '@/api/panel/dashboard' import file from '@/api/panel/file' -import info from '@/api/panel/info' import website from '@/api/panel/website' import { formatDateTime, renderIcon } from '@/utils' import type { CronTask } from '@/views/cron/types' @@ -197,7 +197,7 @@ const getWebsiteList = async (page: number, limit: number) => { } const getPhpAndDb = async () => { - const { data } = await info.installedDbAndPhp() + const { data } = await dashboard.installedDbAndPhp() installedDbAndPhp.value = data } diff --git a/web/src/views/home/IndexView.vue b/web/src/views/home/IndexView.vue index 6c452eb9..51b8db17 100644 --- a/web/src/views/home/IndexView.vue +++ b/web/src/views/home/IndexView.vue @@ -1,13 +1,35 @@