fix: Improve system monitoring settings (#10784)

Refs #5121 #8390
This commit is contained in:
ssongliu 2025-10-27 18:04:17 +08:00 committed by GitHub
parent b0fbb39cd3
commit 606d3c1717
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 336 additions and 74 deletions

View file

@ -20,9 +20,10 @@ type MonitorSetting struct {
MonitorStoreDays string `json:"monitorStoreDays"`
MonitorInterval string `json:"monitorInterval"`
DefaultNetwork string `json:"defaultNetwork"`
DefaultIO string `json:"defaultIO"`
}
type MonitorSettingUpdate struct {
Key string `json:"key" validate:"required,oneof=MonitorStatus MonitorStoreDays MonitorInterval DefaultNetwork"`
Key string `json:"key" validate:"required,oneof=MonitorStatus MonitorStoreDays MonitorInterval DefaultNetwork DefaultIO"`
Value string `json:"value"`
}

View file

@ -10,6 +10,7 @@ type SettingInfo struct {
NtpSite string `json:"ntpSite"`
DefaultNetwork string `json:"defaultNetwork"`
DefaultIO string `json:"defaultIO"`
LastCleanTime string `json:"lastCleanTime"`
LastCleanSize string `json:"lastCleanSize"`
LastCleanData string `json:"lastCleanData"`

View file

@ -69,7 +69,7 @@ func (m *MonitorService) LoadMonitorData(req dto.MonitorSearch) ([]dto.MonitorDa
data = append(data, itemData)
}
if req.Param == "all" || req.Param == "io" {
bases, err := monitorRepo.GetIO(repo.WithByCreatedAt(req.StartTime, req.EndTime))
bases, err := monitorRepo.GetIO(repo.WithByName(req.Info), repo.WithByCreatedAt(req.StartTime, req.EndTime))
if err != nil {
return nil, err
}
@ -201,9 +201,18 @@ func (m *MonitorService) Run() {
func (m *MonitorService) loadDiskIO() {
ioStat, _ := disk.IOCounters()
var diskIOList []disk.IOCountersStat
var ioStatAll disk.IOCountersStat
for _, io := range ioStat {
ioStatAll.Name = "all"
ioStatAll.ReadBytes += io.ReadBytes
ioStatAll.WriteBytes += io.WriteBytes
ioStatAll.ReadTime += io.ReadTime
ioStatAll.WriteTime += io.WriteTime
ioStatAll.WriteCount += io.WriteCount
ioStatAll.ReadCount += io.ReadCount
diskIOList = append(diskIOList, io)
}
diskIOList = append(diskIOList, ioStatAll)
m.DiskIO <- diskIOList
}
@ -234,29 +243,29 @@ func (m *MonitorService) saveIODataToDB(ctx context.Context, interval float64) {
var itemIO model.MonitorIO
itemIO.Name = io1.Name
if io2.ReadBytes != 0 && io1.ReadBytes != 0 && io2.ReadBytes > io1.ReadBytes {
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / interval / 60)
itemIO.Read = uint64(float64(io2.ReadBytes-io1.ReadBytes) / interval)
}
if io2.WriteBytes != 0 && io1.WriteBytes != 0 && io2.WriteBytes > io1.WriteBytes {
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / interval / 60)
itemIO.Write = uint64(float64(io2.WriteBytes-io1.WriteBytes) / interval)
}
if io2.ReadCount != 0 && io1.ReadCount != 0 && io2.ReadCount > io1.ReadCount {
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / interval / 60)
itemIO.Count = uint64(float64(io2.ReadCount-io1.ReadCount) / interval)
}
writeCount := uint64(0)
if io2.WriteCount != 0 && io1.WriteCount != 0 && io2.WriteCount > io1.WriteCount {
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / interval * 60)
writeCount = uint64(float64(io2.WriteCount-io1.WriteCount) / interval)
}
if writeCount > itemIO.Count {
itemIO.Count = writeCount
}
if io2.ReadTime != 0 && io1.ReadTime != 0 && io2.ReadTime > io1.ReadTime {
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / interval / 60)
itemIO.Time = uint64(float64(io2.ReadTime-io1.ReadTime) / interval)
}
writeTime := uint64(0)
if io2.WriteTime != 0 && io1.WriteTime != 0 && io2.WriteTime > io1.WriteTime {
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / interval / 60)
writeTime = uint64(float64(io2.WriteTime-io1.WriteTime) / interval)
}
if writeTime > itemIO.Time {
itemIO.Time = writeTime
@ -294,10 +303,10 @@ func (m *MonitorService) saveNetDataToDB(ctx context.Context, interval float64)
itemNet.Name = net1.Name
if net2.BytesSent != 0 && net1.BytesSent != 0 && net2.BytesSent > net1.BytesSent {
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval / 60
itemNet.Up = float64(net2.BytesSent-net1.BytesSent) / 1024 / interval
}
if net2.BytesRecv != 0 && net1.BytesRecv != 0 && net2.BytesRecv > net1.BytesRecv {
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval / 60
itemNet.Down = float64(net2.BytesRecv-net1.BytesRecv) / 1024 / interval
}
netList = append(netList, itemNet)
break
@ -330,7 +339,7 @@ func StartMonitor(removeBefore bool, interval string) error {
now := time.Now()
nextMinute := now.Truncate(time.Minute).Add(time.Minute)
time.AfterFunc(time.Until(nextMinute), func() {
monitorID, err := global.Cron.AddJob(fmt.Sprintf("@every %sm", interval), service)
monitorID, err := global.Cron.AddJob(fmt.Sprintf("@every %ss", interval), service)
if err != nil {
return
}

View file

@ -47,6 +47,7 @@ func InitAgentDB() {
migrations.UpdateCronjobSpec,
migrations.UpdateWebsiteSSLAddColumn,
migrations.AddTensorRTLLMModel,
migrations.UpdateMonitorInterval,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View file

@ -6,6 +6,7 @@ import (
"os"
"os/user"
"path"
"strconv"
"strings"
"time"
@ -634,3 +635,27 @@ var AddTensorRTLLMModel = &gormigrate.Migration{
return tx.AutoMigrate(&model.TensorRTLLM{})
},
}
var UpdateMonitorInterval = &gormigrate.Migration{
ID: "20251026-update-monitor-interval",
Migrate: func(tx *gorm.DB) error {
var monitorInterval model.Setting
if err := tx.Where("key = ?", "MonitorInterval").First(&monitorInterval).Error; err != nil {
return err
}
interval, _ := strconv.Atoi(monitorInterval.Value)
if interval == 0 {
interval = 300
}
if err := tx.Model(&model.Setting{}).
Where("key = ?", "MonitorInterval").
Updates(map[string]interface{}{"value": fmt.Sprintf("%v", interval*60)}).
Error; err != nil {
return err
}
if err := tx.Create(&model.Setting{Key: "DefaultIO", Value: "all"}).Error; err != nil {
return err
}
return nil
},
}

View file

@ -137,6 +137,7 @@ export namespace Host {
export interface MonitorSetting {
defaultNetwork: string;
defaultIO: string;
monitorStatus: string;
monitorStoreDays: string;
monitorInterval: string;

View file

@ -1168,11 +1168,13 @@ const message = {
},
monitor: {
globalFilter: 'Global Filter',
enableMonitor: 'Enable',
storeDays: 'Expiration days',
defaultNetwork: 'Default Network Adapter',
defaultNetworkHelper: 'Network adapter option displayed in the default monitoring and overview interface',
cleanMonitor: 'Clean monitoring records',
enableMonitor: 'Monitoring Status',
storeDays: 'Retention Days',
defaultNetwork: 'Default Network Card',
defaultNetworkHelper: 'Default network card option displayed in monitoring and overview interfaces',
defaultIO: 'Default Disk',
defaultIOHelper: 'Default disk option displayed in monitoring and overview interfaces',
cleanMonitor: 'Clear Monitoring Records',
avgLoad: 'Load average',
loadDetail: 'Load detail',
@ -1193,7 +1195,8 @@ const message = {
network: 'Network',
up: 'Up',
down: 'Down',
interval: 'Interval(minute)',
interval: 'Collection Interval',
intervalHelper: 'Please enter an appropriate monitoring collection interval (5 seconds - 12 hours)',
gpuUtil: 'GPU Utilization',
temperature: 'Temperature',

View file

@ -1171,13 +1171,16 @@ const message = {
},
},
monitor: {
globalFilter: 'Filtro global',
enableMonitor: 'Habilitar',
storeDays: 'Días de retención',
defaultNetwork: 'Adaptador de red predeterminado',
globalFilter: 'Filtro Global',
enableMonitor: 'Estado de Monitoreo',
storeDays: 'Días de Retención',
defaultNetwork: 'Tarjeta de Red Predeterminada',
defaultNetworkHelper:
'Opción de adaptador de red mostrada en la vista predeterminada de monitorización y resumen',
cleanMonitor: 'Limpiar registros de monitorización',
'Opción de tarjeta de red predeterminada mostrada en las interfaces de monitoreo y resumen',
defaultIO: 'Disco Predeterminado',
defaultIOHelper: 'Opción de disco predeterminada mostrada en las interfaces de monitoreo y resumen',
cleanMonitor: 'Limpiar Registros de Monitoreo',
avgLoad: 'Carga promedio',
loadDetail: 'Detalle de carga',
resourceUsage: 'Utilización',
@ -1197,7 +1200,8 @@ const message = {
network: 'Red',
up: 'Subida',
down: 'Bajada',
interval: 'Intervalo (minutos)',
interval: 'Intervalo de Recolección',
intervalHelper: 'Ingrese un intervalo de recolección de monitoreo apropiado (5 segundos - 12 horas)',
gpuUtil: 'Uso de GPU',
temperature: 'Temperatura',
performanceState: 'Estado de rendimiento',

View file

@ -1131,9 +1131,13 @@ const message = {
},
monitor: {
globalFilter: 'グローバルフィルター',
enableMonitor: '有効にする',
storeDays: '有効期限',
cleanMonitor: '監視記録をきれいにします',
enableMonitor: '監視ステータス',
storeDays: '保存日数',
defaultNetwork: 'デフォルトネットワークカード',
defaultNetworkHelper: '監視および概要インターフェースに表示されるデフォルトのネットワークカードオプション',
defaultIO: 'デフォルトディスク',
defaultIOHelper: '監視および概要インターフェースに表示されるデフォルトのディスクオプション',
cleanMonitor: '監視記録をクリア',
avgLoad: 'ロード平均',
loadDetail: '詳細を読み込みます',
@ -1152,7 +1156,8 @@ const message = {
network: 'ネットワーク',
up: '上',
down: '下',
interval: '間隔',
interval: '収集間隔',
intervalHelper: '適切な監視収集間隔を入力してください5 - 12時間',
gpuUtil: 'GPU利用',
temperature: '温度',

View file

@ -1123,9 +1123,13 @@ const message = {
},
monitor: {
globalFilter: '전역 필터',
enableMonitor: '활성화',
storeDays: '만료일',
cleanMonitor: '모니터링 기록 정리',
enableMonitor: '모니터링 상태',
storeDays: '보관 일수',
defaultNetwork: '기본 네트워크 카드',
defaultNetworkHelper: '모니터링 개요 인터페이스에 표시되는 기본 네트워크 카드 옵션',
defaultIO: '기본 디스크',
defaultIOHelper: '모니터링 개요 인터페이스에 표시되는 기본 디스크 옵션',
cleanMonitor: '모니터링 기록 지우기',
avgLoad: '평균 부하',
loadDetail: '부하 세부사항',
@ -1144,7 +1148,8 @@ const message = {
network: '네트워크',
up: '업',
down: '다운',
interval: '간격()',
interval: '수집 간격',
intervalHelper: '적절한 모니터링 수집 간격을 입력하세요 (5 - 12시간)',
gpuUtil: 'GPU 사용률',
temperature: '온도',

View file

@ -1163,9 +1163,14 @@ const message = {
},
monitor: {
globalFilter: 'Penapis Global',
enableMonitor: 'Aktifkan',
storeDays: 'Hari luput',
cleanMonitor: 'Bersihkan rekod pemantauan',
enableMonitor: 'Status Pemantauan',
storeDays: 'Hari Penyimpanan',
defaultNetwork: 'Kad Rangkaian Lalai',
defaultNetworkHelper:
'Pilihan kad rangkaian lalai yang dipaparkan dalam antara muka pemantauan dan gambaran keseluruhan',
defaultIO: 'Cakera Lalai',
defaultIOHelper: 'Pilihan cakera lalai yang dipaparkan dalam antara muka pemantauan dan gambaran keseluruhan',
cleanMonitor: 'Kosongkan Rekod Pemantauan',
avgLoad: 'Purata beban',
loadDetail: 'Butiran beban',
@ -1184,7 +1189,8 @@ const message = {
network: 'Rangkaian',
up: 'Naik',
down: 'Turun',
interval: 'Selang (minit)',
interval: 'Selang Kumpulan',
intervalHelper: 'Sila masukkan selang kumpulan pemantauan yang sesuai (5 saat - 12 jam)',
gpuUtil: 'Penggunaan GPU',
temperature: 'Suhu',

View file

@ -1156,10 +1156,14 @@ const message = {
},
},
monitor: {
globalFilter: 'Filtro global',
enableMonitor: 'Ativar',
storeDays: 'Dias de expiração',
cleanMonitor: 'Limpar registros de monitoramento',
globalFilter: 'Filtro Global',
enableMonitor: 'Status de Monitoramento',
storeDays: 'Dias de Retenção',
defaultNetwork: 'Placa de Rede Padrão',
defaultNetworkHelper: 'Opção de placa de rede padrão exibida nas interfaces de monitoramento e visão geral',
defaultIO: 'Disco Padrão',
defaultIOHelper: 'Opção de disco padrão exibida nas interfaces de monitoramento e visão geral',
cleanMonitor: 'Limpar Registros de Monitoramento',
avgLoad: 'Média de carga',
loadDetail: 'Detalhes da carga',
@ -1178,7 +1182,8 @@ const message = {
network: 'Rede',
up: 'Para cima',
down: 'Para baixo',
interval: 'Intervalo (minuto)',
interval: 'Intervalo de Coleta',
intervalHelper: 'Insira um intervalo de coleta de monitoramento apropriado (5 segundos - 12 horas)',
gpuUtil: 'Utilização da GPU',
temperature: 'Temperatura',

View file

@ -1160,10 +1160,14 @@ const message = {
},
},
monitor: {
globalFilter: 'Глобальный фильтр',
enableMonitor: 'Включить',
storeDays: 'Дни хранения',
cleanMonitor: 'Очистить записи мониторинга',
globalFilter: 'Глобальный Фильтр',
enableMonitor: 'Статус Мониторинга',
storeDays: 'Дни Хранения',
defaultNetwork: 'Сетевая Карта по Умолчанию',
defaultNetworkHelper: 'Опция сетевой карты по умолчанию, отображаемая в интерфейсах мониторинга и обзора',
defaultIO: 'Диск по Умолчанию',
defaultIOHelper: 'Опция диска по умолчанию, отображаемая в интерфейсах мониторинга и обзора',
cleanMonitor: 'Очистить Записи Мониторинга',
avgLoad: 'Средняя нагрузка',
loadDetail: 'Детали нагрузки',
@ -1182,7 +1186,8 @@ const message = {
network: 'Сеть',
up: 'Исходящий',
down: 'Входящий',
interval: 'Интервал(минут)',
interval: 'Интервал Сбора',
intervalHelper: 'Пожалуйста, введите подходящий интервал сбора мониторинга (5 секунд - 12 часов)',
gpuUtil: 'Использование GPU',
temperature: 'Температура',

View file

@ -1182,11 +1182,13 @@ const message = {
},
monitor: {
globalFilter: 'Genel Filtre',
enableMonitor: 'Etkinleştir',
storeDays: 'Son kullanma günleri',
defaultNetwork: 'Varsayılan Adaptörü',
defaultNetworkHelper: 'Varsayılan izleme ve genel bakış arayüzünde görüntülenen adaptörü seçeneği',
cleanMonitor: 'İzleme kayıtlarını temizle',
enableMonitor: 'İzleme Durumu',
storeDays: 'Saklama Günleri',
defaultNetwork: 'Varsayılan Kartı',
defaultNetworkHelper: 'İzleme ve genel bakış arayüzlerinde görüntülenen varsayılan kartı seçeneği',
defaultIO: 'Varsayılan Disk',
defaultIOHelper: 'İzleme ve genel bakış arayüzlerinde görüntülenen varsayılan disk seçeneği',
cleanMonitor: 'İzleme Kayıtlarını Temizle',
avgLoad: 'Ortalama yük',
loadDetail: 'Yük detayı',
@ -1207,7 +1209,8 @@ const message = {
network: '',
up: 'Yukarı',
down: 'Aşağı',
interval: 'Aralık(dakika)',
interval: 'Toplama Aralığı',
intervalHelper: 'Lütfen uygun bir izleme toplama aralığı girin (5 saniye - 12 saat)',
gpuUtil: 'GPU Kullanımı',
temperature: 'Sıcaklık',

View file

@ -1107,9 +1107,11 @@ const message = {
monitor: {
globalFilter: '全域過濾',
enableMonitor: '監控狀態',
storeDays: '存天數',
storeDays: '存天數',
defaultNetwork: '預設網卡',
defaultNetworkHelper: '預設監控和概覽介面顯示的網卡選項',
defaultIO: '預設磁碟',
defaultIOHelper: '預設監控和概覽介面顯示的磁碟選項',
cleanMonitor: '清空監控記錄',
avgLoad: '平均負載',
@ -1131,7 +1133,8 @@ const message = {
network: '網路',
up: '上行',
down: '下行',
interval: '採集間隔分鐘',
interval: '採集間隔',
intervalHelper: '請輸入合適的監控採集時間間隔5 - 12小時',
gpuUtil: 'GPU 使用率',
temperature: '溫度',

View file

@ -1111,6 +1111,8 @@ const message = {
storeDays: '保存天数',
defaultNetwork: '默认网卡',
defaultNetworkHelper: '默认监控和概览界面显示的网卡选项',
defaultIO: '默认磁盘',
defaultIOHelper: '默认监控和概览界面显示的磁盘选项',
cleanMonitor: '清空监控记录',
avgLoad: '平均负载',
@ -1132,7 +1134,8 @@ const message = {
network: '网络',
up: '上行',
down: '下行',
interval: '采集间隔分钟',
interval: '采集间隔',
intervalHelper: '请输入合适的监控采集时间间隔5 - 12小时',
gpuUtil: 'GPU 使用率',
temperature: '温度',

View file

@ -46,6 +46,7 @@ export interface GlobalState {
currentRedisDB: string;
showEntranceWarn: boolean;
defaultNetwork: string;
defaultIO: string;
isFxplay: boolean;
isProductPro: boolean;

View file

@ -40,6 +40,7 @@ const GlobalStore = defineStore({
currentRedisDB: '',
showEntranceWarn: true,
defaultNetwork: 'all',
defaultIO: 'all',
isFxplay: false,
isProductPro: false,
@ -117,6 +118,9 @@ const GlobalStore = defineStore({
setDefaultNetwork(net: string) {
this.defaultNetwork = net;
},
setDefaultIO(net: string) {
this.defaultIO = net;
},
},
persist: piniaPersistConfig('GlobalState'),
});

View file

@ -165,7 +165,9 @@ export function dateFormatWithoutYear(dataStr: any) {
h = h < 10 ? `0${String(h)}` : h;
let minute: string | number = date.getMinutes();
minute = minute < 10 ? `0${String(minute)}` : minute;
return `${String(m)}-${String(d)}\n${String(h)}:${String(minute)}`;
let s: string | number = date.getSeconds();
s = s < 10 ? `0${String(s)}` : s;
return `${String(m)}-${String(d)}\n${String(h)}:${String(minute)}:${String(s)}`;
}
// 20221013151302

View file

@ -458,7 +458,7 @@ const onLoadSimpleNode = async () => {
const onLoadIOOptions = async () => {
const res = await getIOOptions();
ioOptions.value = res.data;
searchInfo.ioOption = ioOptions.value && ioOptions.value[0];
searchInfo.ioOption = globalStore.defaultIO || (ioOptions.value && ioOptions.value[0]);
};
const onLoadBaseInfo = async (isInit: boolean, range: string) => {

View file

@ -16,6 +16,7 @@
style="max-width: 360px; width: 100%"
:size="mobile ? 'small' : 'default'"
></el-date-picker>
<TableRefresh class="float-right" @search="searchGlobal()" />
</div>
</el-card>
</div>
@ -118,7 +119,26 @@
<el-card style="overflow: inherit">
<template #header>
<div :class="mobile ? 'flx-wrap' : 'flex justify-between'">
<span class="title">{{ $t('monitor.disk') }} I/O</span>
<div>
<span class="title">{{ $t('monitor.disk') }} I/O{{ $t('commons.colon') }}</span>
<el-dropdown max-height="300px">
<span class="networkOption">
{{ ioChoose === 'all' ? $t('commons.table.all') : ioChoose }}
</span>
<template #dropdown>
<el-dropdown-menu>
<div v-for="item in ioOptions" :key="item">
<el-dropdown-item v-if="item === 'all'" @click="changeIO('all')">
{{ $t('commons.table.all') }}
</el-dropdown-item>
<el-dropdown-item v-else @click="changeIO(item)">
{{ item }}
</el-dropdown-item>
</div>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<el-date-picker
@change="search('io')"
v-model="timeRangeIO"
@ -199,7 +219,7 @@
<script setup lang="ts">
import { ref, reactive, onMounted, computed } from 'vue';
import { loadMonitor, getNetworkOptions } from '@/api/modules/host';
import { loadMonitor, getNetworkOptions, getIOOptions } from '@/api/modules/host';
import { computeSizeFromKBs, dateFormatWithoutYear } from '@/utils/util';
import i18n from '@/lang';
import MonitorRouter from '@/views/host/monitor/index.vue';
@ -223,6 +243,8 @@ const timeRangeIO = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0))
const timeRangeNetwork = ref<[Date, Date]>([new Date(new Date().setHours(0, 0, 0, 0)), new Date()]);
const networkChoose = ref();
const netOptions = ref();
const ioChoose = ref();
const ioOptions = ref();
const chartsOption = ref({ loadLoadChart: null, loadCPUChart: null, loadMemoryChart: null, loadNetworkChart: null });
const searchTime = ref();
@ -260,6 +282,7 @@ const search = async (param: string) => {
break;
case 'io':
searchTime.value = timeRangeIO.value;
searchInfo.info = ioChoose.value;
break;
case 'network':
searchTime.value = timeRangeNetwork.value;
@ -366,6 +389,11 @@ const changeNetwork = (item: string) => {
search('network');
};
const changeIO = (item: string) => {
ioChoose.value = item;
search('io');
};
const loadNetworkOptions = async () => {
const res = await getNetworkOptions();
netOptions.value = res.data;
@ -374,6 +402,14 @@ const loadNetworkOptions = async () => {
search('all');
};
const loadIOOptions = async () => {
const res = await getIOOptions();
ioOptions.value = res.data;
searchInfo.info = globalStore.defaultIO || (ioOptions.value && ioOptions.value[0]);
ioChoose.value = searchInfo.info;
search('all');
};
function initLoadCharts(item: Host.MonitorData) {
let itemLoadDate = item.date.length === 0 ? loadEmptyDate(timeRangeLoad.value) : item.date;
let loadDate = itemLoadDate.map(function (item: any) {
@ -565,6 +601,7 @@ function getSideWidth(b: boolean) {
onMounted(() => {
zoomStart.value = dateFormatWithoutYear(new Date(new Date().setHours(0, 0, 0, 0)));
loadNetworkOptions();
loadIOOptions();
});
</script>

View file

@ -0,0 +1,87 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('monitor.defaultIO')" @close="handleClose" size="small">
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
<el-form-item :label="$t('monitor.defaultIO')" prop="defaultIO" :rules="Rules.requiredSelect">
<el-select v-model="form.defaultIO" filterable>
<el-option
v-for="item in ioOptions"
:key="item"
:label="item == 'all' ? $t('commons.table.all') : item"
:value="item"
/>
</el-select>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="drawerVisible = false">{{ $t('commons.button.cancel') }}</el-button>
<el-button :disabled="loading" type="primary" @click="onSave(formRef)">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</DrawerPro>
</template>
<script lang="ts" setup>
import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { Rules } from '@/global/form-rules';
import { getIOOptions, updateMonitorSetting } from '@/api/modules/host';
import { GlobalStore } from '@/store';
const globalStore = GlobalStore();
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
defaultIO: string;
}
const drawerVisible = ref();
const loading = ref();
const ioOptions = ref();
const form = reactive({
defaultIO: '',
});
const formRef = ref<FormInstance>();
const acceptParams = (params: DialogProps): void => {
form.defaultIO = params.defaultIO;
loadIOOptions();
drawerVisible.value = true;
};
const loadIOOptions = async () => {
const res = await getIOOptions();
ioOptions.value = res.data;
};
const onSave = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
await updateMonitorSetting('DefaultIO', form.defaultIO)
.then(async () => {
globalStore.setDefaultIO(form.defaultIO);
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
loading.value = false;
drawerVisible.value = false;
emit('search');
return;
})
.catch(() => {
loading.value = false;
});
});
};
const handleClose = () => {
drawerVisible.value = false;
};
defineExpose({
acceptParams,
});
</script>

View file

@ -25,8 +25,8 @@
</template>
</el-input>
</el-form-item>
<el-form-item :label="$t('monitor.interval')" prop="monitorInterval">
<el-input disabled v-model="form.monitorInterval">
<el-form-item :label="$t('monitor.interval')" prop="monitorIntervalItem">
<el-input disabled v-model="form.monitorIntervalItem">
<template #append>
<el-button @click="onChangeInterval" icon="Setting">
{{ $t('commons.button.set') }}
@ -44,6 +44,16 @@
</el-input>
<span class="input-help">{{ $t('monitor.defaultNetworkHelper') }}</span>
</el-form-item>
<el-form-item :label="$t('monitor.defaultIO')">
<el-input disabled v-model="form.defaultIO">
<template #append>
<el-button @click="onChangeIO" icon="Setting">
{{ $t('commons.button.set') }}
</el-button>
</template>
</el-input>
<span class="input-help">{{ $t('monitor.defaultIOHelper') }}</span>
</el-form-item>
<el-form-item>
<el-button @click="onClean()" icon="Delete">{{ $t('monitor.cleanMonitor') }}</el-button>
</el-form-item>
@ -56,6 +66,7 @@
<Interval ref="intervalRef" @search="search" />
<StoreDays ref="daysRef" @search="search" />
<Network ref="networkRef" @search="search()" />
<IO ref="ioRef" @search="search()" />
</div>
</template>
@ -67,29 +78,42 @@ import MonitorRouter from '@/views/host/monitor/index.vue';
import Interval from '@/views/host/monitor/setting/interval/index.vue';
import StoreDays from '@/views/host/monitor/setting/days/index.vue';
import Network from '@/views/host/monitor/setting/default-network/index.vue';
import IO from '@/views/host/monitor/setting/default-io/index.vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { splitTimeFromSecond, transTimeUnit } from '@/utils/util';
const loading = ref();
const form = reactive({
monitorStatus: 'Disable',
monitorStoreDays: 30,
monitorInterval: 1,
monitorInterval: 300,
timeItem: 5,
timeUnit: 'm',
monitorIntervalItem: '',
defaultNetwork: '',
defaultIO: '',
});
const panelFormRef = ref<FormInstance>();
const intervalRef = ref();
const daysRef = ref();
const networkRef = ref();
const ioRef = ref();
const search = async () => {
const res = await loadMonitorSetting();
form.monitorStatus = res.data.monitorStatus;
form.monitorInterval = Number(res.data.monitorInterval);
let item = splitTimeFromSecond(form.monitorInterval);
form.timeItem = item.timeItem;
form.timeUnit = item.timeUnit;
form.monitorIntervalItem = transTimeUnit(form.timeItem + form.timeUnit);
form.monitorStoreDays = Number(res.data.monitorStoreDays);
form.defaultNetwork =
res.data.defaultNetwork === 'all' ? i18n.global.t('commons.table.all') : res.data.defaultNetwork;
form.defaultIO = res.data.defaultIO === 'all' ? i18n.global.t('commons.table.all') : res.data.defaultIO;
};
const onSaveStatus = async () => {
@ -108,11 +132,14 @@ const onChangeStoreDays = () => {
daysRef.value.acceptParams({ monitorStoreDays: form.monitorStoreDays });
};
const onChangeInterval = () => {
intervalRef.value.acceptParams({ monitorInterval: form.monitorInterval });
intervalRef.value.acceptParams({ timeItem: form.timeItem, timeUnit: form.timeUnit });
};
const onChangeNetwork = () => {
networkRef.value.acceptParams({ defaultNetwork: form.defaultNetwork });
};
const onChangeIO = () => {
ioRef.value.acceptParams({ defaultIO: form.defaultIO });
};
const onClean = async () => {
ElMessageBox.confirm(i18n.global.t('commons.msg.clean'), i18n.global.t('monitor.cleanMonitor'), {

View file

@ -1,12 +1,16 @@
<template>
<DrawerPro v-model="drawerVisible" :header="$t('monitor.interval')" @close="handleClose" size="small">
<el-form ref="formRef" label-position="top" :model="form" @submit.prevent v-loading="loading">
<el-form-item
:label="$t('monitor.interval')"
:rules="[Rules.integerNumber, checkNumberRange(1, 60)]"
prop="monitorInterval"
>
<el-input clearable v-model.number="form.monitorInterval" />
<el-form ref="formRef" label-position="top" :model="form" :rules="rules" @submit.prevent v-loading="loading">
<el-form-item :label="$t('monitor.interval')" prop="monitorInterval">
<el-input type="number" @input="loadInterval()" class="selectClass" v-model.number="form.timeItem">
<template #append>
<el-select v-model="form.timeUnit" @change="loadInterval" style="width: 80px">
<el-option :label="$t('commons.units.second')" value="s" />
<el-option :label="$t('commons.units.minute')" value="m" />
<el-option :label="$t('commons.units.hour')" value="h" />
</el-select>
</template>
</el-input>
</el-form-item>
</el-form>
<template #footer>
@ -24,28 +28,48 @@ import { reactive, ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { FormInstance } from 'element-plus';
import { Rules, checkNumberRange } from '@/global/form-rules';
import { Rules } from '@/global/form-rules';
import { updateMonitorSetting } from '@/api/modules/host';
import { transferTimeToSecond } from '@/utils/util';
const emit = defineEmits<{ (e: 'search'): void }>();
interface DialogProps {
monitorInterval: number;
timeItem: number;
timeUnit: string;
}
const drawerVisible = ref();
const loading = ref();
const form = reactive({
monitorInterval: 1,
timeItem: 5,
timeUnit: 'h',
monitorInterval: 300,
});
const verifyInterval = (rule: any, value: any, callback: any) => {
if (value < 10 || value > 43200) {
callback(new Error(i18n.global.t('monitor.intervalHelper')));
return;
}
callback();
};
const rules = reactive({
monitorInterval: [Rules.integerNumber, { validator: verifyInterval, trigger: 'blur', required: true }],
});
const formRef = ref<FormInstance>();
const acceptParams = (params: DialogProps): void => {
form.monitorInterval = params.monitorInterval;
form.timeItem = params.timeItem;
form.timeUnit = params.timeUnit;
drawerVisible.value = true;
};
const loadInterval = () => {
form.monitorInterval = transferTimeToSecond(form.timeItem + form.timeUnit);
};
const onSave = async (formEl: FormInstance | undefined) => {
if (!formEl) return;
formEl.validate(async (valid) => {