Files
fe.ems.vue3/src/views/ne/neInfo/index.vue
2025-09-09 19:13:30 +08:00

947 lines
30 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup lang="ts">
import { reactive, onMounted, toRaw, defineAsyncComponent, ref, computed } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { message, Modal, Table } from 'ant-design-vue/es';
import { SizeType } from 'ant-design-vue/es/config-provider';
import { MenuInfo } from 'ant-design-vue/es/menu/src/interface';
import { ColumnsType } from 'ant-design-vue/es/table';
import useI18n from '@/hooks/useI18n';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import { listNeInfo, delNeInfo, stateNeInfo } from '@/api/ne/neInfo';
import { NE_TYPE_LIST } from '@/constants/ne-constants';
import useDictStore from '@/store/modules/dict';
import useNeOptions from './hooks/useNeOptions';
import { hasPermissions } from '@/plugins/auth-user';
const { getDict } = useDictStore();
const { t } = useI18n();
const { fnNeStart, fnNeRestart, fnNeStop, fnNeReload, fnNeLogFile } =
useNeOptions();
// 异步加载组件
const EditModal = defineAsyncComponent(
() => import('./components/EditModal.vue')
);
const OAMModal = defineAsyncComponent(
() => import('./components/OAMModal.vue')
);
// 配置备份文件导入
const BackConfModal = defineAsyncComponent(
() => import('./components/BackConfModal.vue')
);
const backConf = ref(); // 引用句柄,取导出函数
// 计算是否至少拥有一个批量操作权限
const hasAnyBatchPermission = computed(() => {
return hasPermissions(['ne:neInfo:logs']) ||
hasPermissions(['ne:neInfo:start']) ||
hasPermissions(['ne:neInfo:stop'])||
hasPermissions(['ne:neInfo:delete'])||
hasPermissions(['ne:neInfo:export'])||
hasPermissions(['ne:neInfo:import']);
});
/**字典数据 */
let dict: {
/**网元信息状态 */
neInfoStatus: DictType[];
} = reactive({
neInfoStatus: [],
});
/**查询参数 */
let queryParams = reactive({
/**网元类型 */
neType: '',
/**带状态信息 */
bandStatus: true,
/**当前页数 */
pageNum: 1,
/**每页条数 */
pageSize: 20,
});
/**查询参数重置 */
function fnQueryReset() {
queryParams = Object.assign(queryParams, {
neType: '',
pageNum: 1,
pageSize: 20,
});
tablePagination.current = 1;
tablePagination.pageSize = 20;
fnGetList();
}
/**表格状态类型 */
type TabeStateType = {
/**加载等待 */
loading: boolean;
/**紧凑型 */
size: SizeType;
/**搜索栏 */
seached: boolean;
/**记录数据 */
data: Record<string, any>[];
/**勾选记录 */
selectedRowKeys: (string | number)[];
};
/**表格状态 */
let tableState: TabeStateType = reactive({
loading: false,
size: 'middle',
seached: false,
data: [],
selectedRowKeys: [],
});
/**父表格列配置(网元类型分组) */
let parentTableColumns: ColumnsType = [
Table.EXPAND_COLUMN,
{
title: t('views.ne.common.neType'),
dataIndex: 'neType',
align: 'left',
width: 700,
},
// {
// title: t('views.ne.neInfo.neCount'),
// dataIndex: 'neName',
// align: 'left',
// width: 150,
// },
// {
// title: t('views.ne.neInfo.summary'),
// key: 'summary',
// align: 'left',
// },
];
/**子表格列配置(具体网元) */
let childTableColumns: ColumnsType = [
Table.EXPAND_COLUMN,
{
title: t('views.ne.common.neId'),
dataIndex: 'neId',
align: 'left',
width: 100,
},
{
title: t('views.ne.common.rmUid'),
dataIndex: 'rmUid',
align: 'left',
width: 150,
},
{
title: t('views.ne.common.neName'),
dataIndex: 'neName',
align: 'left',
width: 150,
},
{
title: t('views.ne.common.ipAddr'),
dataIndex: 'ip',
align: 'left',
width: 150,
},
{
title: t('views.ne.common.port'),
dataIndex: 'port',
align: 'left',
width: 100,
},
{
title: t('views.ne.neInfo.state'),
dataIndex: 'status',
key: 'status',
align: 'left',
width: 100,
},
{
title: t('common.operate'),
key: 'id',
align: 'left',
},
];
/**表格分页器参数 */
let tablePagination = reactive({
/**当前页数 */
current: 1,
/**每页条数 */
pageSize: 20,
/**默认的每页条数 */
defaultPageSize: 20,
/**指定每页可以显示多少条 */
pageSizeOptions: ['10', '20', '50', '100'],
/**只有一页时是否隐藏分页器 */
hideOnSinglePage: false,
/**是否可以快速跳转至某页 */
showQuickJumper: true,
/**是否可以改变 pageSize */
showSizeChanger: true,
/**数据总数 */
total: 0,
showTotal: (total: number) => t('common.tablePaginationTotal', { total }),
onChange: (page: number, pageSize: number) => {
tablePagination.current = page;
tablePagination.pageSize = pageSize;
queryParams.pageNum = page;
queryParams.pageSize = pageSize;
fnGetList();
},
});
/**表格紧凑型变更操作 */
function fnTableSize({ key }: MenuInfo) {
tableState.size = key as SizeType;
}
/**表格多选 */
function fnTableSelectedRowKeys(keys: (string | number)[]) {
// 过滤掉父节点的key只保留子节点的key
const childKeys = keys.filter(key => !String(key).startsWith('parent_'));
tableState.selectedRowKeys = childKeys;
}
/**对话框对象信息状态类型 */
type ModalStateType = {
/**配置备份框是否显示 */
openByBackConf: boolean;
/**OAM文件配置框是否显示 */
openByOAM: boolean;
/**新增框或修改框是否显示 */
openByEdit: boolean;
/**新增框或修改框ID */
editId: string;
/**OAM框网元类型ID */
neId: string;
neType: string;
/**确定按钮 loading */
confirmLoading: boolean;
};
/**对话框对象信息状态 */
let modalState: ModalStateType = reactive({
openByBackConf: false,
openByOAM: false,
openByEdit: false,
editId: '',
neId: '',
neType: '',
confirmLoading: false,
});
/**
* 对话框弹出显示为 新增或者修改
* @param noticeId 网元id, 不传为新增
*/
function fnModalVisibleByEdit(row?: Record<string, any>) {
if (!row) {
modalState.editId = '';
} else {
modalState.editId = row.id;
}
modalState.openByEdit = !modalState.openByEdit;
}
/**
* 对话框弹出确认执行函数
* 进行表达规则校验
*/
function fnModalEditOk(from: Record<string, any>) {
// 新增时刷新列表
if (!from.id) {
fnGetList();
return;
}
// 编辑时局部更新信息
stateNeInfo(from.neType, from.neId)
.then(res => {
// 在树状结构中找到编辑更新的网元
let foundItem = null;
let parentItem = null;
for (const parent of tableState.data) {
if (parent.childrenData && Array.isArray(parent.childrenData)) {
const child = parent.childrenData.find(c => c.id === from.id);
if (child) {
foundItem = child;
parentItem = parent;
break;
}
}
}
if (foundItem && res.code === RESULT_CODE_SUCCESS) {
// 检查网元类型是否发生变化
const oldNeType = foundItem.neType;
const newNeType = from.neType;
// 更新网元信息
foundItem.neType = from.neType;
foundItem.neId = from.neId;
foundItem.rmUid = from.rmUid;
foundItem.neName = from.neName;
foundItem.ip = from.ip;
foundItem.port = from.port;
if (res.data.online) {
foundItem.status = '1';
if (res.data.standby) {
foundItem.status = '3';
}
} else {
foundItem.status = '0';
}
Object.assign(foundItem.serverState, res.data);
const resouresUsage = parseResouresUsage(foundItem.serverState);
Reflect.set(foundItem, 'resoures', resouresUsage);
// 如果网元类型发生变化,需要重新组织数据结构
if (oldNeType !== newNeType) {
fnGetList(); // 重新获取数据以重新组织树状结构
}
}
})
.finally(() => {
useNeInfoStore().fnRefreshNelist();
});
}
/**
* 对话框弹出关闭执行函数
* 进行表达规则校验
*/
function fnModalEditCancel() {
modalState.editId = '';
modalState.openByEdit = false;
modalState.openByOAM = false;
modalState.openByBackConf = false;
}
/**
* 记录删除
* @param id 编号
*/
function fnRecordDelete(id: string) {
if (!id || modalState.confirmLoading) return;
let msg = t('views.ne.neInfo.delTip');
if (id === '0') {
msg = `${msg} ...${tableState.selectedRowKeys.length}`;
id = tableState.selectedRowKeys.join(',');
}
Modal.confirm({
title: t('common.tipTitle'),
content: msg,
onOk() {
modalState.confirmLoading = true;
const hide = message.loading(t('common.loading'), 0);
delNeInfo(id)
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success(t('common.operateOk'), 3);
// 树状结构中过滤掉删除的id
const deletedIds = id.indexOf(',') > -1 ? id.split(',') : [id];
tableState.data = tableState.data.map(parentItem => {
if (parentItem.childrenData && Array.isArray(parentItem.childrenData)) {
// 过滤子节点
const filteredChildren = parentItem.childrenData.filter(child =>
!deletedIds.includes(child.id)
);
// 如果该分组下没有子节点了,移除整个父节点
if (filteredChildren.length === 0) {
return null;
}
// 更新子节点数量显示和汇总信息
const onlineCount = filteredChildren.filter(item => item.status === '1' || item.status === '3').length;
const offlineCount = filteredChildren.length - onlineCount;
return {
...parentItem,
neName: `${filteredChildren.length} 个网元`,
summary: `在线 ${onlineCount} | 离线 ${offlineCount}`,
childrenData: filteredChildren
};
}
return parentItem;
}).filter(item => item !== null);
// 清空选择
tableState.selectedRowKeys = [];
// 刷新缓存
useNeInfoStore().fnRefreshNelist();
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
hide();
modalState.confirmLoading = false;
});
},
});
}
/**
* 记录多项选择
*/
function fnRecordMore(type: string | number, row: Record<string, any>) {
switch (type) {
case 'delete':
fnRecordDelete(row.id);
break;
case 'start':
fnNeStart(row);
break;
case 'restart':
fnNeRestart(row);
break;
case 'stop':
fnNeStop(row);
break;
case 'reload':
fnNeReload(row);
break;
case 'log':
fnNeLogFile(row);
break;
case 'oam':
modalState.neId = row.neId;
modalState.neType = row.neType;
modalState.openByOAM = !modalState.openByOAM;
break;
case 'backConfExport':
backConf.value.exportConf(row.neType, row.neId);
break;
case 'backConfImport':
modalState.neId = row.neId;
modalState.neType = row.neType;
modalState.openByBackConf = !modalState.openByBackConf;
break;
default:
console.warn(type);
break;
}
}
/**将扁平数据转换为分组结构 */
function transformToNestedTableData(flatData: Record<string, any>[]) {
// 按 neType 分组
const groupedData = flatData.reduce((groups, item) => {
const neType = item.neType;
if (!groups[neType]) {
groups[neType] = [];
}
groups[neType].push(item);
return groups;
}, {} as Record<string, any[]>);
// 转换为父表格数据结构(只包含父节点)
const parentTableData = Object.entries(groupedData).map(([neType, items]) => {
// 按 neId 排序子节点
const sortedItems = items.sort((a: Record<string, any>, b: Record<string, any>) => a.neId.localeCompare(b.neId));
// 统计在线/离线数量
const onlineCount = sortedItems.filter((item: Record<string, any>) => item.status === '1' || item.status === '3').length;
const offlineCount = sortedItems.length - onlineCount;
// 清理子节点数据,移除可能干扰父表格显示的属性
const cleanedChildren = sortedItems.map((item: Record<string, any>) => ({
...item,
isParent: false
}));
// 创建父节点(分组节点)- 确保这是唯一的父节点数据
const parentNode = {
id: `parent_${neType}`,
neType: neType,
neName: `${items.length} 个网元`,
summary: `在线 ${onlineCount} | 离线 ${offlineCount}`,
childrenData: cleanedChildren, // 重命名避免与ant-design的children属性冲突
isParent: true, // 明确标识为父节点
};
return parentNode;
});
// 确保只返回父节点,不包含子节点
return parentTableData;
}
/**查询列表, pageNum初始页数 */
function fnGetList(pageNum?: number) {
if (tableState.loading) return;
tableState.loading = true;
if (pageNum) {
queryParams.pageNum = pageNum;
}
listNeInfo(toRaw(queryParams))
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
// 取消勾选
if (tableState.selectedRowKeys.length > 0) {
tableState.selectedRowKeys = [];
}
tablePagination.total = res.total;
// 遍历处理资源情况数值
const processedData = res.rows.map(item => {
let resouresUsage = {
sysDiskUsage: 0,
sysMemUsage: 0,
sysCpuUsage: 0,
nfCpuUsage: 0,
};
const neState = item.serverState;
if (neState) {
resouresUsage = parseResouresUsage(neState);
} else {
item.serverState = { online: false };
}
Reflect.set(item, 'resoures', resouresUsage);
return item;
});
// 转换为嵌套表格结构
tableState.data = transformToNestedTableData(processedData);
}
tableState.loading = false;
})
.finally(() => {
// 刷新缓存的网元信息
useNeInfoStore().fnRefreshNelist();
});
}
/**解析网元状态携带的资源利用率 */
function parseResouresUsage(neState: Record<string, any>) {
let sysCpuUsage = 0;
let nfCpuUsage = 0;
if (neState.cpu) {
nfCpuUsage = neState.cpu.nfCpuUsage;
const nfCpu = +(nfCpuUsage / 100);
nfCpuUsage = +nfCpu.toFixed(2);
if (nfCpuUsage > 100) {
nfCpuUsage = 100;
}
sysCpuUsage = neState.cpu.sysCpuUsage;
const sysCpu = +(sysCpuUsage / 100);
sysCpuUsage = +sysCpu.toFixed(2);
if (sysCpuUsage > 100) {
sysCpuUsage = 100;
}
}
let sysMemUsage = 0;
if (neState.mem) {
const men = neState.mem.sysMemUsage;
sysMemUsage = +(men / 100).toFixed(2);
if (sysMemUsage > 100) {
sysMemUsage = 100;
}
}
let sysDiskUsage = 0;
if (neState.disk && Array.isArray(neState.disk.partitionInfo)) {
let disks: any[] = neState.disk.partitionInfo;
disks = disks.sort((a, b) => +b.used - +a.used);
if (disks.length > 0) {
const { total, used } = disks[0];
sysDiskUsage = +((used / total) * 100).toFixed(2);
}
}
return {
sysDiskUsage,
sysMemUsage,
sysCpuUsage,
nfCpuUsage,
};
}
onMounted(() => {
// 初始字典数据
Promise.allSettled([getDict('ne_info_status')]).then(resArr => {
if (resArr[0].status === 'fulfilled') {
dict.neInfoStatus = resArr[0].value;
}
});
// 获取列表数据
fnGetList();
});
</script>
<template>
<PageContainer>
<a-card
v-show="tableState.seached"
:bordered="false"
:body-style="{ marginBottom: '24px', paddingBottom: 0 }"
>
<!-- 表格搜索栏 -->
<a-form :model="queryParams" name="queryParams" layout="horizontal">
<a-row :gutter="16">
<a-col :lg="6" :md="12" :xs="24">
<a-form-item :label="t('views.ne.common.neType')" name="neType ">
<a-auto-complete
v-model:value="queryParams.neType"
:options="NE_TYPE_LIST.map(v => ({ value: v }))"
allow-clear
:placeholder="t('common.inputPlease')"
/>
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :xs="24">
<a-form-item>
<a-space :size="8">
<a-button type="primary" @click.prevent="fnGetList(1)">
<template #icon><SearchOutlined /></template>
{{ t('common.search') }}
</a-button>
<a-button type="default" @click.prevent="fnQueryReset">
<template #icon><ClearOutlined /></template>
{{ t('common.reset') }}
</a-button>
</a-space>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8" align="center">
<a-button type="primary" @click.prevent="fnModalVisibleByEdit()" v-perms:has="['ne:neInfo:add']">
<template #icon><PlusOutlined /></template>
{{ t('common.addText') }}
</a-button>
<a-button
type="default"
danger
:disabled="tableState.selectedRowKeys.length <= 0"
:loading="modalState.confirmLoading"
@click.prevent="fnRecordDelete('0')"
v-perms:has="['ne:neInfo:delete']"
>
<template #icon><DeleteOutlined /></template>
{{ t('common.deleteText') }}
</a-button>
</a-space>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.searchBarText') }}</template>
<a-switch
v-model:checked="tableState.seached"
:checked-children="t('common.switch.show')"
:un-checked-children="t('common.switch.hide')"
size="small"
/>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.reloadText') }}</template>
<a-button type="text" @click.prevent="fnGetList()">
<template #icon><ReloadOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>{{ t('common.sizeText') }}</template>
<a-dropdown trigger="click" placement="bottomRight">
<a-button type="text">
<template #icon><ColumnHeightOutlined /></template>
</a-button>
<template #overlay>
<a-menu
:selected-keys="[tableState.size as string]"
@click="fnTableSize"
>
<a-menu-item key="default">
{{ t('common.size.default') }}
</a-menu-item>
<a-menu-item key="middle">
{{ t('common.size.middle') }}
</a-menu-item>
<a-menu-item key="small">
{{ t('common.size.small') }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</template>
<!-- 外层表格网元类型分组 -->
<a-table
class="parent-table"
row-key="id"
:columns="parentTableColumns"
:loading="tableState.loading"
:data-source="tableState.data"
:size="tableState.size"
:pagination="tablePagination"
:scroll="{ x: parentTableColumns.length * 120 }"
:default-expand-all-rows="false"
:expandRowByClick="false"
:show-header="true"
:childrenColumnName="undefined"
>
<template #bodyCell="{ column, record }">
<!-- 父表格只处理汇总列 -->
<template v-if="column.key === 'summary'">
<span class="text-gray-600">{{ record.summary }}</span>
</template>
</template>
<!-- 父表格展开行嵌套子表格 -->
<template #expandedRowRender="{ record }">
<!-- 子表格显示具体网元 -->
<a-table
row-key="id"
:columns="childTableColumns"
:data-source="record.childrenData"
:size="tableState.size"
:pagination="false"
:bordered="false"
:show-header="true"
:scroll="{ x: childTableColumns.length * 120 }"
:row-selection="{
type: 'checkbox',
columnWidth: '48px',
selectedRowKeys: tableState.selectedRowKeys,
onChange: fnTableSelectedRowKeys,
}"
>
<template #bodyCell="{ column, record: childRecord }">
<!-- 子表格状态列 -->
<template v-if="column.key === 'status'">
<DictTag :options="dict.neInfoStatus" :value="childRecord.status" />
</template>
<!-- 子表格操作列 -->
<template v-if="column.key === 'id'">
<a-space :size="8" align="center">
<a-tooltip>
<template #title>{{ t('common.editText') }}</template>
<a-button
type="link"
@click.prevent="fnModalVisibleByEdit(childRecord)"
v-perms:has="['ne:neInfo:edit']"
>
<template #icon><FormOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip>
<template #title>
{{ t('views.ne.common.restart') }}
</template>
<a-button
type="link"
@click.prevent="fnRecordMore('restart', childRecord)"
v-perms:has="['ne:neInfo:restart']"
>
<template #icon><UndoOutlined /></template>
</a-button>
</a-tooltip>
<a-tooltip placement="left">
<template #title>{{ t('common.moreText') }}</template>
<a-dropdown placement="bottomRight" trigger="click" v-if="hasAnyBatchPermission">
<a-button type="link">
<template #icon><EllipsisOutlined /> </template>
</a-button>
<template #overlay>
<a-menu @click="({ key }:any) => fnRecordMore(key, childRecord)">
<a-menu-item key="log" v-if="hasPermissions(['ne:neInfo:logs'])">
<FileTextOutlined />
{{ t('views.ne.common.log') }}
</a-menu-item>
<a-menu-item key="start" v-if="hasPermissions(['ne:neInfo:start'])">
<ThunderboltOutlined />
{{ t('views.ne.common.start') }}
</a-menu-item>
<a-menu-item key="stop" v-if="hasPermissions(['ne:neInfo:stop'])">
<CloseSquareOutlined />
{{ t('views.ne.common.stop') }}
</a-menu-item>
<a-menu-item
key="reload"
v-if="
!['OMC', 'PCF', 'IMS', 'MME'].includes(childRecord.neType)
"
>
<SyncOutlined />
{{ t('views.ne.common.reload') }}
</a-menu-item>
<a-menu-item key="delete" v-if="hasPermissions(['ne:neInfo:delete'])">
<DeleteOutlined />
{{ t('common.deleteText') }}
</a-menu-item>
<a-menu-item
key="oam"
v-if="!['OMC'].includes(childRecord.neType)"
>
<FileTextOutlined />
{{ t('views.ne.common.oam') }}
</a-menu-item>
<!-- 配置备份 -->
<a-menu-item key="backConfExport" v-if="hasPermissions(['ne:neInfo:export'])">
<ExportOutlined />
{{ t('views.ne.neInfo.backConf.export') }}
</a-menu-item>
<a-menu-item key="backConfImport" v-if="hasPermissions(['ne:neInfo:import'])">
<ImportOutlined />
{{ t('views.ne.neInfo.backConf.import') }}
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</a-tooltip>
</a-space>
</template>
</template>
<!-- 子表格展开行:显示详细监控信息 -->
<template #expandedRowRender="{ record: childRecord }">
<a-row>
<a-col :offset="2" :lg="8" :md="8" :xs="8">
<a-divider orientation="left">
{{ t('views.ne.neInfo.info') }}
</a-divider>
<div>
<span>{{ t('views.ne.neInfo.serviceState') }}</span>
<DictTag :options="dict.neInfoStatus" :value="childRecord.status" />
</div>
<div>
<span>{{ t('views.ne.neVersion.version') }}</span>
<span>{{ childRecord.serverState?.version || '—' }}</span>
</div>
<div>
<span>{{ t('views.ne.common.serialNum') }}</span>
<span>{{ childRecord.serverState?.sn || '—' }}</span>
</div>
<div>
<span>{{ t('views.ne.common.expiryDate') }}</span>
<span>{{ childRecord.serverState?.expire || '—' }}</span>
</div>
</a-col>
<a-col :offset="2" :lg="8" :md="8" :xs="8">
<a-divider orientation="left">
{{ t('views.ne.neInfo.resourceInfo') }}
</a-divider>
<div>
<span>{{ t('views.ne.neInfo.neCpu') }}</span>
<a-progress
status="normal"
:stroke-color="
childRecord.resoures?.nfCpuUsage < 30
? '#52c41a'
: childRecord.resoures?.nfCpuUsage > 70
? '#ff4d4f'
: '#1890ff'
"
:percent="childRecord.resoures?.nfCpuUsage || 0"
/>
</div>
<div>
<span>{{ t('views.ne.neInfo.sysCpu') }}</span>
<a-progress
status="normal"
:stroke-color="
childRecord.resoures?.sysCpuUsage < 30
? '#52c41a'
: childRecord.resoures?.sysCpuUsage > 70
? '#ff4d4f'
: '#1890ff'
"
:percent="childRecord.resoures?.sysCpuUsage || 0"
/>
</div>
<div>
<span>{{ t('views.ne.neInfo.sysMem') }}</span>
<a-progress
status="normal"
:stroke-color="
childRecord.resoures?.sysMemUsage < 30
? '#52c41a'
: childRecord.resoures?.sysMemUsage > 70
? '#ff4d4f'
: '#1890ff'
"
:percent="childRecord.resoures?.sysMemUsage || 0"
/>
</div>
<div>
<span>{{ t('views.ne.neInfo.sysDisk') }}</span>
<a-progress
status="normal"
:stroke-color="
childRecord.resoures?.sysDiskUsage < 30
? '#52c41a'
: childRecord.resoures?.sysDiskUsage > 70
? '#ff4d4f'
: '#1890ff'
"
:percent="childRecord.resoures?.sysDiskUsage || 0"
/>
</div>
</a-col>
</a-row>
</template>
</a-table>
</template>
</a-table>
</a-card>
<!-- 新增框或修改框 -->
<EditModal
v-model:open="modalState.openByEdit"
:edit-id="modalState.editId"
:ne-list-data="tableState.data"
@ok="fnModalEditOk"
@cancel="fnModalEditCancel"
></EditModal>
<!-- OAM编辑框 -->
<OAMModal
v-model:open="modalState.openByOAM"
:ne-id="modalState.neId"
:ne-type="modalState.neType"
@cancel="fnModalEditCancel"
></OAMModal>
<!-- 配置文件备份框 -->
<BackConfModal
ref="backConf"
v-model:open="modalState.openByBackConf"
:ne-id="modalState.neId"
:ne-type="modalState.neType"
@cancel="fnModalEditCancel"
></BackConfModal>
</PageContainer>
</template>
<style lang="less" scoped>
.parent-table :deep(.ant-pagination) {
padding: 0 24px;
}
/* 简洁的父表格样式 */
.parent-table :deep(.ant-table-tbody) {
tr[data-row-key*="parent_"] {
font-weight: 600;
}
}
</style>