2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 06:47:20 +08:00

feat: 首页全新设计

This commit is contained in:
耗子
2024-10-16 22:54:57 +08:00
parent 9cf3a0e2b6
commit 722c4f3812
17 changed files with 699 additions and 507 deletions

View File

@@ -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) {

View File

@@ -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,
})
}

View File

@@ -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
}

View File

@@ -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"`
}

View File

@@ -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",

8
web/pnpm-lock.yaml generated
View File

@@ -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

View File

@@ -0,0 +1,29 @@
import type { AxiosResponse } from 'axios'
import { request } from '@/utils'
export default {
// 面板信息
panel: (): Promise<Response> => fetch('/api/dashboard/panel'),
// 面板菜单
menu: (): Promise<AxiosResponse<any>> => request.get('/dashboard/menu'),
// 首页应用
homeApps: (): Promise<AxiosResponse<any>> => request.get('/dashboard/homeApps'),
// 实时信息
current: (nets: string[], disks: string[]): Promise<AxiosResponse<any>> =>
request.post('/dashboard/current', { nets, disks }),
// 系统信息
systemInfo: (): Promise<AxiosResponse<any>> => request.get('/dashboard/systemInfo'),
// 统计信息
countInfo: (): Promise<AxiosResponse<any>> => request.get('/dashboard/countInfo'),
// 已安装的数据库和PHP
installedDbAndPhp: (): Promise<AxiosResponse<any>> => request.get('/dashboard/installedDbAndPhp'),
// 检查更新
checkUpdate: (): Promise<AxiosResponse<any>> => request.get('/dashboard/checkUpdate'),
// 更新日志
updateInfo: (): Promise<AxiosResponse<any>> => request.get('/dashboard/updateInfo'),
// 更新面板
update: (): Promise<AxiosResponse<any>> => request.post('/dashboard/update', null),
// 重启面板
restart: (): Promise<AxiosResponse<any>> => request.post('/dashboard/restart')
}

View File

@@ -1,28 +0,0 @@
import type { AxiosResponse } from 'axios'
import { request } from '@/utils'
export default {
// 面板信息
panel: (): Promise<Response> => fetch('/api/info/panel'),
// 面板菜单
menu: (): Promise<AxiosResponse<any>> => request.get('/info/menu'),
// 首页应用
homeApps: (): Promise<AxiosResponse<any>> => request.get('/info/homeApps'),
// 实时监控
realtime: (): Promise<AxiosResponse<any>> => request.get('/info/realtime'),
// 系统信息
systemInfo: (): Promise<AxiosResponse<any>> => request.get('/info/systemInfo'),
// 统计信息
countInfo: (): Promise<AxiosResponse<any>> => request.get('/info/countInfo'),
// 已安装的数据库和PHP
installedDbAndPhp: (): Promise<AxiosResponse<any>> => request.get('/info/installedDbAndPhp'),
// 检查更新
checkUpdate: (): Promise<AxiosResponse<any>> => request.get('/info/checkUpdate'),
// 更新日志
updateInfo: (): Promise<AxiosResponse<any>> => request.get('/info/updateInfo'),
// 更新面板
update: (): Promise<AxiosResponse<any>> => request.post('/info/update', null),
// 重启面板
restart: (): Promise<AxiosResponse<any>> => request.post('/info/restart')
}

View File

@@ -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) => {

View File

@@ -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}秒`
}
/** 生成随机字符串 */

View File

@@ -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({

View File

@@ -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
}

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ import type { MessageReactive } from 'naive-ui'
import { NButton } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import info from '@/api/panel/info'
import dashboard from '@/api/panel/dashboard'
import { router } from '@/router'
import { formatDateTime } from '@/utils'
import type { Version } from '@/views/home/types'
@@ -15,7 +15,7 @@ const versions = ref<Version[] | null>(null)
let messageReactive: MessageReactive | null = null
const getVersions = () => {
info.updateInfo().then((res: any) => {
dashboard.updateInfo().then((res: any) => {
versions.value = res.data
})
}
@@ -30,7 +30,7 @@ const handleUpdate = () => {
messageReactive = window.$message.loading(t('homeUpdate.confirm.update.loading'), {
duration: 0
})
info
dashboard
.update()
.then(() => {
messageReactive?.destroy()

View File

@@ -140,7 +140,8 @@ interface DiskUsageStat {
export interface Realtime {
cpus: CpuInfoStat[]
percent: number[]
percent: number
percents: number[]
load: LoadAvgStat
host: HostInfoStat
mem: VirtualMemoryStat
@@ -152,9 +153,16 @@ export interface Realtime {
}
export interface SystemInfo {
os_name: string
uptime: string
procs: number
hostname: string
panel_version: string
kernel_arch: string
kernel_version: string
os_name: string
boot_time: number
uptime: number
nets: any[]
disks: any[]
}
export interface CountInfo {

View File

@@ -2,7 +2,7 @@
import Editor from '@guolao/vue-monaco-editor'
import { NButton } from 'naive-ui'
import info from '@/api/panel/info'
import dashboard from '@/api/panel/dashboard'
import website from '@/api/panel/website'
import type { WebsiteListen, WebsiteSetting } from '@/views/website/types'
@@ -50,7 +50,7 @@ const installedDbAndPhp = ref({
})
const getPhpAndDb = async () => {
const { data } = await info.installedDbAndPhp()
const { data } = await dashboard.installedDbAndPhp()
installedDbAndPhp.value = data
}

View File

@@ -12,7 +12,7 @@ import {
} from 'naive-ui'
import { useI18n } from 'vue-i18n'
import info from '@/api/panel/info'
import dashboard from '@/api/panel/dashboard'
import website from '@/api/panel/website'
import { generateRandomString, isNullOrUndef, renderIcon } from '@/utils'
import type { Website } from './types'
@@ -225,7 +225,7 @@ const installedDbAndPhp = ref({
})
const getPhpAndDb = async () => {
const { data } = await info.installedDbAndPhp()
const { data } = await dashboard.installedDbAndPhp()
installedDbAndPhp.value = data
}