This commit is contained in:
ygx
2026-03-21 16:19:06 +08:00
parent 4708a8bbf7
commit 69e421834b
8 changed files with 501 additions and 364 deletions

View File

@@ -7,7 +7,7 @@
<a-layout>
<a-layout-sider
v-if="renderMenu"
v-show="!hideMenu && !route?.meta?.isNewTab && !route?.meta?.is_full"
v-show="!route?.meta?.is_full"
class="layout-sider"
:breakpoint="'xl'"
:collapsible="true"

View File

@@ -2,44 +2,42 @@ import { DEFAULT_LAYOUT } from '../base'
import { AppRouteRecordRaw } from '../types'
const REMOTE: AppRouteRecordRaw = {
path: '/dc',
name: 'DC',
component: DEFAULT_LAYOUT,
meta: {
locale: 'menu.dc',
requiresAuth: true,
icon: 'icon-desktop',
order: 99,
hideInMenu: true,
},
children: [
{
path: 'detail',
name: 'DCDetail',
component: () => import('@/views/ops/pages/dc/detail/index.vue'),
meta: {
locale: 'menu.dc.detail',
requiresAuth: true,
roles: ['*'],
hideInMenu: true,
is_full: true,
isNewTab: true,
},
},
{
path: 'remote',
name: 'DCRemote',
component: () => import('@/views/ops/pages/dc/remote/index.vue'),
meta: {
locale: 'menu.dc.remote',
requiresAuth: true,
roles: ['*'],
hideInMenu: true,
is_full: true,
isNewTab: true,
},
},
],
// path: '/dc',
// name: 'DC',
// component: DEFAULT_LAYOUT,
// meta: {
// locale: 'menu.dc',
// requiresAuth: true,
// icon: 'icon-desktop',
// order: 99,
// hideInMenu: true,
// },
// children: [
// {
// path: 'detail',
// name: 'DCDetail',
// component: () => import('@/views/ops/pages/dc/detail/index.vue'),
// meta: {
// locale: 'menu.dc.detail',
// requiresAuth: true,
// roles: ['*'],
// // is_full: true,
// isNewTab: true,
// },
// },
// {
// path: 'remote',
// name: 'DCRemote',
// component: () => import('@/views/ops/pages/dc/remote/index.vue'),
// meta: {
// locale: 'menu.dc.remote',
// requiresAuth: true,
// roles: ['*'],
// // is_full: true,
// isNewTab: true,
// },
// },
// ],
}
export default REMOTE

View File

@@ -446,7 +446,7 @@ const handleEdit = (record: any) => {
formDialogVisible.value = true
}
// 详情 - 跳转到独立页面
// 详情 - 在当前窗口打开
const handleDetail = (record: any) => {
router.push({
path: '/dc/detail',
@@ -470,9 +470,9 @@ const handleRestart = (record: any) => {
})
}
// 远程控制 - 跳转到独立页面
// 远程控制 - 在新窗口打开
const handleRemoteControl = (record: any) => {
router.push({
const url = router.resolve({
path: '/dc/remote',
query: {
id: record.id,
@@ -480,7 +480,8 @@ const handleRemoteControl = (record: any) => {
ip: record.ip,
status: record.status,
},
})
}).href
window.open(url, '_blank')
}
// 表单提交成功

View File

@@ -3,11 +3,11 @@
<!-- 顶部导航栏 -->
<div class="page-header">
<div class="header-left">
<a-button type="text" @click="goBack">
<!-- <a-button type="text" @click="goBack">
<template #icon><icon-left /></template>
返回
</a-button>
<a-divider direction="vertical" />
</a-button> -->
<!-- <a-divider direction="vertical" /> -->
<span class="server-name">{{ serverName }}</span>
<a-tag :color="getStatusColor(serverStatus)" size="small">{{ getStatusText(serverStatus) }}</a-tag>
</div>

View File

@@ -148,6 +148,13 @@
</a-dropdown>
</template>
</search-table>
<!-- 新增/编辑对话框 -->
<ServerFormDialog
v-model:visible="formDialogVisible"
:record="currentRecord"
@success="handleFormSuccess"
/>
</div>
</template>
@@ -167,6 +174,7 @@ import {
import type { FormItem } from '@/components/search-form/types'
import SearchTable from '@/components/search-table/index.vue'
import { searchFormConfig } from './config/search-form'
import ServerFormDialog from '../pc/components/ServerFormDialog.vue'
import { columns as columnsConfig } from './config/columns'
import {
fetchServerList,
@@ -382,6 +390,8 @@ const mockServerData = [
// 状态管理
const loading = ref(false)
const tableData = ref<any[]>([])
const formDialogVisible = ref(false)
const currentRecord = ref<any>(null)
const formModel = ref({
keyword: '',
datacenter_id: undefined,
@@ -510,8 +520,19 @@ const handleRefresh = () => {
// 新增服务器
const handleAdd = () => {
Message.info('新增服务器功能待实现')
// TODO: 实现新增服务器对话框
currentRecord.value = null
formDialogVisible.value = true
}
// 编辑服务器
const handleEdit = (record: any) => {
currentRecord.value = record
formDialogVisible.value = true
}
// 表单提交成功
const handleFormSuccess = () => {
fetchServers()
}
// 重启服务器
@@ -525,7 +546,7 @@ const handleRestart = (record: any) => {
})
}
// 查看详情 - 跳转到独立页面
// 查看详情 - 在当前窗口打开
const handleDetail = (record: any) => {
router.push({
path: '/dc/detail',
@@ -538,15 +559,9 @@ const handleDetail = (record: any) => {
})
}
// 编辑服务器
const handleEdit = (record: any) => {
Message.info('编辑服务器功能待实现')
// TODO: 实现编辑服务器对话框
}
// 远程控制 - 跳转到独立页面
// 远程控制 - 在新窗口打开
const handleRemoteControl = (record: any) => {
router.push({
const url = router.resolve({
path: '/dc/remote',
query: {
id: record.id,
@@ -554,7 +569,8 @@ const handleRemoteControl = (record: any) => {
ip: record.ip,
status: record.status,
},
})
}).href
window.open(url, '_blank')
}
// 删除服务器

View File

@@ -1,127 +1,81 @@
<template>
<div class="network-device-status-panel">
<!-- 查询表单 -->
<a-form :model="formModel" layout="inline" class="search-form">
<a-form-item label="服务标识" field="service_identities">
<a-input
v-model="formModel.service_identities"
placeholder="多个标识,逗号分隔"
style="width: 250px"
/>
</a-form-item>
<a-form-item label="指标名称" field="metric_names">
<a-input
v-model="formModel.metric_names"
placeholder="多个指标名称,逗号分隔(可选)"
style="width: 250px"
/>
</a-form-item>
<a-form-item label="聚合方式" field="aggregation">
<a-select
v-model="formModel.aggregation"
placeholder="请选择聚合方式"
style="width: 120px"
>
<a-option value="avg">平均值</a-option>
<a-option value="max">最大值</a-option>
<a-option value="min">最小值</a-option>
<a-option value="sum">求和</a-option>
<a-option value="count">计数</a-option>
</a-select>
</a-form-item>
<a-form-item label="时间范围" field="timeRange">
<a-range-picker
v-model="formModel.timeRange"
show-time
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 380px"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" :loading="loading" @click="handleSearch">
查询
</a-button>
<a-button @click="handleReset">
重置
</a-button>
</a-space>
</a-form-item>
</a-form>
<search-table
:form-model="formModel"
:form-items="formItems"
:data="tableData"
:columns="columns"
:loading="loading"
:pagination="pagination"
title="网络设备状态"
@update:form-model="handleFormModelUpdate"
@search="handleSearch"
@reset="handleReset"
@refresh="handleRefresh"
>
<!-- 时间范围选择器插槽 -->
<template #form-items>
<a-col :span="8">
<a-form-item label="时间范围" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
<a-range-picker
v-model="formModel.timeRange"
show-time
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 380px"
/>
</a-form-item>
</a-col>
</template>
<!-- 结果表格 -->
<a-table
:data="tableData"
:loading="loading"
:pagination="false"
:bordered="false"
stripe
class="result-table"
>
<template #columns>
<a-table-column title="服务标识" data-index="service_identity" width="200" fixed="left" />
<a-table-column title="服务器标识" data-index="server_identity" width="180" />
<a-table-column title="名称" data-index="name" width="150" />
<a-table-column title="类型" data-index="type" width="120" />
<a-table-column title="主机" data-index="host" width="150" />
<a-table-column title="状态" data-index="status" width="100">
<template #cell="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ record.status || '-' }}
</a-tag>
</template>
</a-table-column>
<a-table-column title="响应时间" data-index="response_time" width="120">
<template #cell="{ record }">
<span>{{ formatResponseTime(record.response_time) }}</span>
</template>
</a-table-column>
<a-table-column title="运行时间" data-index="uptime" width="120">
<template #cell="{ record }">
<span>{{ formatUptime(record.uptime) }}</span>
</template>
</a-table-column>
<a-table-column title="启用" data-index="enabled" width="80">
<template #cell="{ record }">
<span>{{ record.enabled ? '是' : '否' }}</span>
</template>
</a-table-column>
<a-table-column title="最后检查时间" data-index="last_check_time" width="180">
<template #cell="{ record }">
<span>{{ formatTime(record.last_check_time) }}</span>
</template>
</a-table-column>
<a-table-column title="指标数据" width="300">
<template #cell="{ record }">
<div v-if="record.metrics && Object.keys(record.metrics).length > 0" class="metrics-cell">
<div v-for="(value, key) in record.metrics" :key="key" class="metric-item">
<span class="metric-name">{{ key }}:</span>
<span class="metric-value">{{ formatMetricValue(value) }}</span>
</div>
</div>
<span v-else>-</span>
</template>
</a-table-column>
</template>
</a-table>
<!-- 状态 -->
<template #status="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ record.status || '-' }}
</a-tag>
</template>
<!-- 空状态 -->
<a-empty v-if="!loading && tableData.length === 0" description="暂无数据" />
</div>
<!-- 响应时间 -->
<template #response_time="{ record }">
{{ formatResponseTime(record.response_time) }}
</template>
<!-- 运行时间 -->
<template #uptime="{ record }">
{{ formatUptime(record.uptime) }}
</template>
<!-- 启用 -->
<template #enabled="{ record }">
<span>{{ record.enabled ? '是' : '否' }}</span>
</template>
<!-- 最后检查时间 -->
<template #last_check_time="{ record }">
{{ formatTime(record.last_check_time) }}
</template>
<!-- 指标数据 -->
<template #metrics="{ record }">
<div v-if="record.metrics && Object.keys(record.metrics).length > 0" class="metrics-cell">
<div v-for="(value, key) in record.metrics" :key="key" class="metric-item">
<span class="metric-name">{{ key }}:</span>
<span class="metric-value">{{ formatMetricValue(value) }}</span>
</div>
</div>
<span v-else>-</span>
</template>
</search-table>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { ref, reactive, computed } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { FormItem } from '@/components/search-form/types'
import SearchTable from '@/components/search-table/index.vue'
import { fetchNetworkDeviceStatus } from '@/api/ops/report'
// 表单模型
const formModel = reactive({
const formModel = ref({
service_identities: '',
metric_names: '',
aggregation: 'avg',
@@ -134,6 +88,111 @@ const loading = ref(false)
// 表格数据
const tableData = ref<any[]>([])
// 分页配置
const pagination = reactive({
current: 1,
pageSize: 20,
total: 0,
})
// 表单项配置
const formItems = computed<FormItem[]>(() => [
{
field: 'service_identities',
label: '服务标识',
type: 'input',
placeholder: '多个标识,逗号分隔',
colProps: { span: 8 },
},
{
field: 'metric_names',
label: '指标名称',
type: 'input',
placeholder: '多个指标名称,逗号分隔(可选)',
colProps: { span: 8 },
},
{
field: 'aggregation',
label: '聚合方式',
type: 'select',
placeholder: '请选择聚合方式',
options: [
{ label: '平均值', value: 'avg' },
{ label: '最大值', value: 'max' },
{ label: '最小值', value: 'min' },
{ label: '求和', value: 'sum' },
{ label: '计数', value: 'count' },
],
colProps: { span: 8 },
},
])
// 表格列配置
const columns = computed(() => [
{
title: '服务标识',
dataIndex: 'service_identity',
width: 200,
fixed: 'left' as const,
},
{
title: '服务器标识',
dataIndex: 'server_identity',
width: 180,
},
{
title: '名称',
dataIndex: 'name',
width: 150,
},
{
title: '类型',
dataIndex: 'type',
width: 120,
},
{
title: '主机',
dataIndex: 'host',
width: 150,
},
{
title: '状态',
dataIndex: 'status',
width: 100,
slotName: 'status',
},
{
title: '响应时间',
dataIndex: 'response_time',
width: 120,
slotName: 'response_time',
},
{
title: '运行时间',
dataIndex: 'uptime',
width: 120,
slotName: 'uptime',
},
{
title: '启用',
dataIndex: 'enabled',
width: 80,
slotName: 'enabled',
},
{
title: '最后检查时间',
dataIndex: 'last_check_time',
width: 180,
slotName: 'last_check_time',
},
{
title: '指标数据',
dataIndex: 'metrics',
width: 300,
slotName: 'metrics',
},
])
// 获取状态颜色
const getStatusColor = (status: string) => {
if (!status) return 'gray'
@@ -193,64 +252,91 @@ const formatMetricValue = (metric: any) => {
// 查询
const handleSearch = async () => {
// 验证必填项
if (!formModel.service_identities) {
if (!formModel.value.service_identities) {
Message.warning('请输入服务标识')
return
}
// 如果填写了指标名称,必须同时填写时间范围
if (formModel.metric_names && (!formModel.timeRange || formModel.timeRange.length !== 2)) {
if (formModel.value.metric_names && (!formModel.value.timeRange || formModel.value.timeRange.length !== 2)) {
Message.warning('填写指标名称时必须选择时间范围')
return
}
// 如果填写了时间范围,必须同时填写指标名称
if (formModel.timeRange && formModel.timeRange.length === 2 && !formModel.metric_names) {
if (formModel.value.timeRange && formModel.value.timeRange.length === 2 && !formModel.value.metric_names) {
Message.warning('选择时间范围时必须填写指标名称')
return
}
pagination.current = 1
await fetchTableData()
}
// 获取表格数据
const fetchTableData = async () => {
loading.value = true
try {
const params: any = {
service_identities: formModel.service_identities,
service_identities: formModel.value.service_identities,
}
if (formModel.metric_names) {
params.metric_names = formModel.metric_names
params.aggregation = formModel.aggregation
params.start_time = formModel.timeRange[0]
params.end_time = formModel.timeRange[1]
if (formModel.value.metric_names) {
params.metric_names = formModel.value.metric_names
params.aggregation = formModel.value.aggregation
params.start_time = formModel.value.timeRange[0]
params.end_time = formModel.value.timeRange[1]
}
const res = await fetchNetworkDeviceStatus(params)
if (res.code === 0) {
tableData.value = res.data?.data || []
pagination.total = res.data?.total || 0
if (tableData.value.length === 0) {
Message.info('未查询到数据')
}
} else {
Message.error(res.message || '查询失败')
tableData.value = []
pagination.total = 0
}
} catch (error: any) {
console.error('查询失败:', error)
Message.error(error.message || '查询失败')
tableData.value = []
pagination.total = 0
} finally {
loading.value = false
}
}
// 处理表单模型更新
const handleFormModelUpdate = (value: any) => {
formModel.value = {
...formModel.value,
...value,
}
}
// 重置
const handleReset = () => {
formModel.service_identities = ''
formModel.metric_names = ''
formModel.aggregation = 'avg'
formModel.timeRange = []
formModel.value = {
service_identities: '',
metric_names: '',
aggregation: 'avg',
timeRange: [],
}
pagination.current = 1
tableData.value = []
pagination.total = 0
}
// 刷新
const handleRefresh = () => {
fetchTableData()
Message.success('数据已刷新')
}
</script>
@@ -261,39 +347,22 @@ export default {
</script>
<style scoped lang="less">
.network-device-status-panel {
.search-form {
margin-bottom: 20px;
padding: 16px;
background-color: var(--color-fill-2);
border-radius: 4px;
:deep(.arco-form-item) {
margin-bottom: 12px;
}
}
.metrics-cell {
max-height: 200px;
overflow-y: auto;
.result-table {
background-color: #fff;
.metric-item {
margin-bottom: 4px;
font-size: 12px;
.metrics-cell {
max-height: 200px;
overflow-y: auto;
.metric-item {
margin-bottom: 4px;
font-size: 12px;
.metric-name {
color: var(--color-text-2);
margin-right: 4px;
}
.metric-value {
color: var(--color-text-1);
font-weight: 500;
}
}
.metric-name {
color: var(--color-text-2);
margin-right: 4px;
}
.metric-value {
color: var(--color-text-1);
font-weight: 500;
}
}
}

View File

@@ -1,116 +1,71 @@
<template>
<div class="server-status-panel">
<!-- 查询表单 -->
<a-form :model="formModel" layout="inline" class="search-form">
<a-form-item label="服务器标识" field="server_identities">
<a-input
v-model="formModel.server_identities"
placeholder="多个标识,逗号分隔"
style="width: 250px"
/>
</a-form-item>
<a-form-item label="指标名称" field="metric_names">
<a-input
v-model="formModel.metric_names"
placeholder="多个指标名称,逗号分隔(可选)"
style="width: 250px"
/>
</a-form-item>
<a-form-item label="聚合方式" field="aggregation">
<a-select
v-model="formModel.aggregation"
placeholder="请选择聚合方式"
style="width: 120px"
>
<a-option value="avg">平均值</a-option>
<a-option value="max">最大值</a-option>
<a-option value="min">最小值</a-option>
<a-option value="sum">求和</a-option>
<a-option value="count">计数</a-option>
</a-select>
</a-form-item>
<a-form-item label="时间范围" field="timeRange">
<a-range-picker
v-model="formModel.timeRange"
show-time
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 380px"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" :loading="loading" @click="handleSearch">
查询
</a-button>
<a-button @click="handleReset">
重置
</a-button>
</a-space>
</a-form-item>
</a-form>
<search-table
:form-model="formModel"
:form-items="formItems"
:data="tableData"
:columns="columns"
:loading="loading"
:pagination="pagination"
title="服务器状态"
@update:form-model="handleFormModelUpdate"
@search="handleSearch"
@reset="handleReset"
@refresh="handleRefresh"
>
<!-- 时间范围选择器插槽 -->
<template #form-items>
<a-col :span="8">
<a-form-item label="时间范围" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }">
<a-range-picker
v-model="formModel.timeRange"
show-time
format="YYYY-MM-DD HH:mm:ss"
value-format="YYYY-MM-DD HH:mm:ss"
style="width: 380px"
/>
</a-form-item>
</a-col>
</template>
<!-- 结果表格 -->
<a-table
:data="tableData"
:loading="loading"
:pagination="false"
:bordered="false"
stripe
class="result-table"
>
<template #columns>
<a-table-column title="服务器标识" data-index="server_identity" width="180" fixed="left" />
<a-table-column title="名称" data-index="name" width="150" />
<a-table-column title="主机" data-index="host" width="150" />
<a-table-column title="IP 地址" data-index="ip_address" width="150" />
<a-table-column title="状态" data-index="status" width="100">
<template #cell="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ record.status || '-' }}
</a-tag>
</template>
</a-table-column>
<a-table-column title="启用" data-index="enable" width="80">
<template #cell="{ record }">
<span>{{ record.enable ? '是' : '否' }}</span>
</template>
</a-table-column>
<a-table-column title="最后检查时间" data-index="last_check_time" width="180">
<template #cell="{ record }">
<span>{{ formatTime(record.last_check_time) }}</span>
</template>
</a-table-column>
<a-table-column title="指标数据" width="300">
<template #cell="{ record }">
<div v-if="record.metrics && Object.keys(record.metrics).length > 0" class="metrics-cell">
<div v-for="(value, key) in record.metrics" :key="key" class="metric-item">
<span class="metric-name">{{ key }}:</span>
<span class="metric-value">{{ formatMetricValue(value) }}</span>
</div>
</div>
<span v-else>-</span>
</template>
</a-table-column>
</template>
</a-table>
<!-- 状态 -->
<template #status="{ record }">
<a-tag :color="getStatusColor(record.status)">
{{ record.status || '-' }}
</a-tag>
</template>
<!-- 空状态 -->
<a-empty v-if="!loading && tableData.length === 0" description="暂无数据" />
</div>
<!-- 启用 -->
<template #enable="{ record }">
<span>{{ record.enable ? '是' : '否' }}</span>
</template>
<!-- 最后检查时间 -->
<template #last_check_time="{ record }">
{{ formatTime(record.last_check_time) }}
</template>
<!-- 指标数据 -->
<template #metrics="{ record }">
<div v-if="record.metrics && Object.keys(record.metrics).length > 0" class="metrics-cell">
<div v-for="(value, key) in record.metrics" :key="key" class="metric-item">
<span class="metric-name">{{ key }}:</span>
<span class="metric-value">{{ formatMetricValue(value) }}</span>
</div>
</div>
<span v-else>-</span>
</template>
</search-table>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue'
import { ref, reactive, computed } from 'vue'
import { Message } from '@arco-design/web-vue'
import type { FormItem } from '@/components/search-form/types'
import SearchTable from '@/components/search-table/index.vue'
import { fetchServerStatus } from '@/api/ops/report'
// 表单模型
const formModel = reactive({
const formModel = ref({
server_identities: '',
metric_names: '',
aggregation: 'avg',
@@ -123,6 +78,94 @@ const loading = ref(false)
// 表格数据
const tableData = ref<any[]>([])
// 分页配置
const pagination = reactive({
current: 1,
pageSize: 20,
total: 0,
})
// 表单项配置
const formItems = computed<FormItem[]>(() => [
{
field: 'server_identities',
label: '服务器标识',
type: 'input',
placeholder: '多个标识,逗号分隔',
colProps: { span: 8 },
},
{
field: 'metric_names',
label: '指标名称',
type: 'input',
placeholder: '多个指标名称,逗号分隔(可选)',
colProps: { span: 8 },
},
{
field: 'aggregation',
label: '聚合方式',
type: 'select',
placeholder: '请选择聚合方式',
options: [
{ label: '平均值', value: 'avg' },
{ label: '最大值', value: 'max' },
{ label: '最小值', value: 'min' },
{ label: '求和', value: 'sum' },
{ label: '计数', value: 'count' },
],
colProps: { span: 8 },
},
])
// 表格列配置
const columns = computed(() => [
{
title: '服务器标识',
dataIndex: 'server_identity',
width: 180,
fixed: 'left' as const,
},
{
title: '名称',
dataIndex: 'name',
width: 150,
},
{
title: '主机',
dataIndex: 'host',
width: 150,
},
{
title: 'IP 地址',
dataIndex: 'ip_address',
width: 150,
},
{
title: '状态',
dataIndex: 'status',
width: 100,
slotName: 'status',
},
{
title: '启用',
dataIndex: 'enable',
width: 80,
slotName: 'enable',
},
{
title: '最后检查时间',
dataIndex: 'last_check_time',
width: 180,
slotName: 'last_check_time',
},
{
title: '指标数据',
dataIndex: 'metrics',
width: 300,
slotName: 'metrics',
},
])
// 获取状态颜色
const getStatusColor = (status: string) => {
if (!status) return 'gray'
@@ -159,64 +202,91 @@ const formatMetricValue = (metric: any) => {
// 查询
const handleSearch = async () => {
// 验证必填项
if (!formModel.server_identities) {
if (!formModel.value.server_identities) {
Message.warning('请输入服务器标识')
return
}
// 如果填写了指标名称,必须同时填写时间范围
if (formModel.metric_names && (!formModel.timeRange || formModel.timeRange.length !== 2)) {
if (formModel.value.metric_names && (!formModel.value.timeRange || formModel.value.timeRange.length !== 2)) {
Message.warning('填写指标名称时必须选择时间范围')
return
}
// 如果填写了时间范围,必须同时填写指标名称
if (formModel.timeRange && formModel.timeRange.length === 2 && !formModel.metric_names) {
if (formModel.value.timeRange && formModel.value.timeRange.length === 2 && !formModel.value.metric_names) {
Message.warning('选择时间范围时必须填写指标名称')
return
}
pagination.current = 1
await fetchTableData()
}
// 获取表格数据
const fetchTableData = async () => {
loading.value = true
try {
const params: any = {
server_identities: formModel.server_identities,
server_identities: formModel.value.server_identities,
}
if (formModel.metric_names) {
params.metric_names = formModel.metric_names
params.aggregation = formModel.aggregation
params.start_time = formModel.timeRange[0]
params.end_time = formModel.timeRange[1]
if (formModel.value.metric_names) {
params.metric_names = formModel.value.metric_names
params.aggregation = formModel.value.aggregation
params.start_time = formModel.value.timeRange[0]
params.end_time = formModel.value.timeRange[1]
}
const res = await fetchServerStatus(params)
if (res.code === 0) {
tableData.value = res.data?.data || []
pagination.total = res.data?.total || 0
if (tableData.value.length === 0) {
Message.info('未查询到数据')
}
} else {
Message.error(res.message || '查询失败')
tableData.value = []
pagination.total = 0
}
} catch (error: any) {
console.error('查询失败:', error)
Message.error(error.message || '查询失败')
tableData.value = []
pagination.total = 0
} finally {
loading.value = false
}
}
// 处理表单模型更新
const handleFormModelUpdate = (value: any) => {
formModel.value = {
...formModel.value,
...value,
}
}
// 重置
const handleReset = () => {
formModel.server_identities = ''
formModel.metric_names = ''
formModel.aggregation = 'avg'
formModel.timeRange = []
formModel.value = {
server_identities: '',
metric_names: '',
aggregation: 'avg',
timeRange: [],
}
pagination.current = 1
tableData.value = []
pagination.total = 0
}
// 刷新
const handleRefresh = () => {
fetchTableData()
Message.success('数据已刷新')
}
</script>
@@ -227,39 +297,22 @@ export default {
</script>
<style scoped lang="less">
.server-status-panel {
.search-form {
margin-bottom: 20px;
padding: 16px;
background-color: var(--color-fill-2);
border-radius: 4px;
:deep(.arco-form-item) {
margin-bottom: 12px;
}
}
.metrics-cell {
max-height: 200px;
overflow-y: auto;
.result-table {
background-color: #fff;
.metric-item {
margin-bottom: 4px;
font-size: 12px;
.metrics-cell {
max-height: 200px;
overflow-y: auto;
.metric-item {
margin-bottom: 4px;
font-size: 12px;
.metric-name {
color: var(--color-text-2);
margin-right: 4px;
}
.metric-value {
color: var(--color-text-1);
font-weight: 500;
}
}
.metric-name {
color: var(--color-text-2);
margin-right: 4px;
}
.metric-value {
color: var(--color-text-1);
font-weight: 500;
}
}
}

View File

@@ -47,7 +47,7 @@ import MetricsSummaryPanel from './components/MetricsSummaryPanel.vue'
import TrafficSummaryPanel from './components/TrafficSummaryPanel.vue'
import TrafficTrendPanel from './components/TrafficTrendPanel.vue'
import ServerStatusPanel from './components/ServerStatusPanel.vue'
import NetworkStatusPanel from './components/NetworkStatusPanel.vue'
import NetworkStatusPanel from './components/NetworkDeviceStatusPanel.vue'
// 当前激活的标签页
const activeTab = ref('metrics-topn')