feat: 添加导出所有学生配置功能,优化提示信息

This commit is contained in:
TsMask
2025-03-08 10:31:54 +08:00
parent 0cb892e7f3
commit 20007f4732
14 changed files with 1067 additions and 1107 deletions

View File

@@ -44,7 +44,7 @@ export function ptContrastAsDefault(params: Record<string, any>) {
* @param student 仅教师 student * @param student 仅教师 student
* @returns object * @returns object
*/ */
export function ptExport(student: string|undefined) { export function ptExport(student: string | undefined) {
return request({ return request({
url: `/pt/neConfigData/export`, url: `/pt/neConfigData/export`,
method: 'get', method: 'get',
@@ -54,6 +54,19 @@ export function ptExport(student: string|undefined) {
}); });
} }
/**
* 配置数据导出Excel (仅教师全量)
* @returns object
*/
export function ptExportAll() {
return request({
url: `/pt/neConfigData/export-all`,
method: 'get',
responseType: 'blob',
timeout: 180_000,
});
}
/** /**
* 网元参数配置信息 * 网元参数配置信息
* @param params 数据 {neType,paramName} * @param params 数据 {neType,paramName}

View File

@@ -514,13 +514,17 @@ export default {
ptDiffRest: 'Restore this version', ptDiffRest: 'Restore this version',
ptHistory: 'History', ptHistory: 'History',
ptReset: 'Reset To Example', ptReset: 'Reset To Example',
ptResetTip: 'Confirmed to reset to the sample configuration?',
ptLoad: 'Load Current Configuration', ptLoad: 'Load Current Configuration',
ptLoadTip: 'Confirm that you want to load the current network element configuration?',
ptExport: "Export Excel", ptExport: "Export Excel",
ptExportTip: "Exporting NE Configuration Data to an Excel file", ptExportTip: "Confirm that you want to export the network element configuration data to an Excel file?",
ptExportAll: "导出所有学生配置",
ptApplyShow: 'View Student', ptApplyShow: 'View Student',
ptApply: 'request', ptApply: 'request',
ptApplyNE: 'Application To NE', ptApplyNE: 'Application To NE',
ptApplyStu: 'Application To {ne}', ptApplyStu: 'Application To {ne}',
ptApplyStuTip: 'Confirm that you want to initiate a Configure Application to {ne} request to the teacher?',
ptApplyStuRack: 'Return Request', ptApplyStuRack: 'Return Request',
ptApplyStuNE: 'Application Request', ptApplyStuNE: 'Application Request',
}, },

View File

@@ -514,13 +514,17 @@ export default {
ptDiffRest: '还原此版本', ptDiffRest: '还原此版本',
ptHistory: '历史记录', ptHistory: '历史记录',
ptReset: '重置为示例', ptReset: '重置为示例',
ptResetTip: '确认要重置为示例配置吗?',
ptLoad: '载入当前网元配置', ptLoad: '载入当前网元配置',
ptLoadTip: '确认要载入当前网元配置吗?',
ptExport: "导出Excel", ptExport: "导出Excel",
ptExportTip: "导出网元配置数据到Excel文件中", ptExportTip: "确认要导出网元配置数据到Excel文件中吗?",
ptExportAll: "导出所有学生配置",
ptApplyShow: '查看学生', ptApplyShow: '查看学生',
ptApply: '申请', ptApply: '申请',
ptApplyNE: '应用配置到网元', ptApplyNE: '应用配置到网元',
ptApplyStu: '申请配置应用到 {ne}', ptApplyStu: '申请配置应用到 {ne}',
ptApplyStuTip: '确认要向教师发起配置应用到 {ne} 的申请吗?',
ptApplyStuRack: '退回该学生配置', ptApplyStuRack: '退回该学生配置',
ptApplyStuNE: '应用该学生配置', ptApplyStuNE: '应用该学生配置',
}, },

View File

@@ -5,9 +5,9 @@ import {
updatePtNeConfigApply, updatePtNeConfigApply,
} from '@/api/pt/neConfigApply'; } from '@/api/pt/neConfigApply';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { hasRoles } from '@/plugins/auth-user'; import { Modal } from 'ant-design-vue/es';
import { message } from 'ant-design-vue/lib'; import { message } from 'ant-design-vue/lib';
import { computed, onMounted, reactive } from 'vue'; import { computed, reactive } from 'vue';
/** /**
* 实训教学函数 * 实训教学函数
@@ -22,48 +22,60 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
}); });
/**(管理员)保存网元下所有配置为示例配置 */ /**(管理员)保存网元下所有配置为示例配置 */
function ptConfigSave(neType: string) { function ptConfigSave(neType: string) {
ptConfigState.saveLoading = true; Modal.confirm({
ptSaveAsDefault(neType, '001') title: t('common.tipTitle'),
.then(res => { content: t('views.configManage.configParamForm.ptLoadTip'),
if (res.code === RESULT_CODE_SUCCESS) { onOk() {
message.success({ ptConfigState.saveLoading = true;
content: t('common.operateOk'), ptSaveAsDefault(neType, '001')
duration: 3, .then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 3,
});
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.saveLoading = false;
fnActiveConfigNode('#');
}); });
} else { },
message.error({ });
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.saveLoading = false;
fnActiveConfigNode('#');
});
} }
/**重置网元下所有配置 */ /**重置网元下所有配置 */
function ptConfigReset(neType: string) { function ptConfigReset(neType: string) {
ptConfigState.restLoading = true; Modal.confirm({
ptResetAsDefault(neType) title: t('common.tipTitle'),
.then(res => { content: t('views.configManage.configParamForm.ptResetTip'),
if (res.code === RESULT_CODE_SUCCESS) { onOk() {
message.success({ ptConfigState.restLoading = true;
content: t('common.operateOk'), ptResetAsDefault(neType)
duration: 3, .then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 3,
});
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.restLoading = false;
fnActiveConfigNode('#');
}); });
} else { },
message.error({ });
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.restLoading = false;
fnActiveConfigNode('#');
});
} }
/**配置下方应用(学生)申请撤回和(管理/教师)应用退回 */ /**配置下方应用(学生)申请撤回和(管理/教师)应用退回 */
@@ -97,33 +109,42 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
result = stuPtNeConfigApply({ neType, status }); result = stuPtNeConfigApply({ neType, status });
} }
if (!result) return; if (!result) return;
ptConfigState.applyLoading = true;
result Modal.confirm({
.then((res: any) => { title: t('common.tipTitle'),
if (res.code === RESULT_CODE_SUCCESS) { content: t('views.configManage.configParamForm.ptApplyStuTip', {
message.success({ ne: neType,
content: t('common.operateOk'), }),
duration: 3, onOk() {
}); ptConfigState.applyLoading = true;
// 教师修改学生时改变状态 result
if (student) { .then((res: any) => {
const item = classState.studentOptionsDef.find( if (res.code === RESULT_CODE_SUCCESS) {
s => s.value === classState.student message.success({
); content: t('common.operateOk'),
if (item) { duration: 3,
item.applyStatus = status; });
// 教师修改学生时改变状态
if (student) {
const item = classState.studentOptionsDef.find(
s => s.value === classState.student
);
if (item) {
item.applyStatus = status;
}
}
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
} }
} })
} else { .finally(() => {
message.error({ ptConfigState.applyLoading = false;
content: `${res.msg}`,
duration: 3,
}); });
} },
}) });
.finally(() => {
ptConfigState.applyLoading = false;
});
} }
const classState = reactive<{ const classState = reactive<{
@@ -148,13 +169,6 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
studentOptionsDef: [], studentOptionsDef: [],
}); });
// 仅教师加载
if (hasRoles(['teacher'])) {
onMounted(() => {
classStudents(); // 初始学生列表
});
}
/**学生选择搜索 */ /**学生选择搜索 */
function studentChange(v: any) { function studentChange(v: any) {
if (!v) { if (!v) {
@@ -166,7 +180,7 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
let timeout: any; let timeout: any;
/**学生选择搜索 */ /**学生选择搜索 */
function studentSearch(val: string) { function studentSearch(neType: string, val: string) {
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
timeout = null; timeout = null;
@@ -175,12 +189,12 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
Object.assign(classState.studentOptions, classState.studentOptionsDef); Object.assign(classState.studentOptions, classState.studentOptionsDef);
return; return;
} }
timeout = setTimeout(() => classStudents(val), 500); timeout = setTimeout(() => classStudents(neType, val), 500);
} }
/**班级学生列表 */ /**班级学生列表 */
function classStudents(val?: string) { function classStudents(neType: string, val?: string) {
getPtClassStudents({ userName: val }).then(res => { getPtClassStudents({ neType, userName: val }).then(res => {
classState.studentOptions = []; classState.studentOptions = [];
if (!Array.isArray(res.data) || res.data.length <= 0) { if (!Array.isArray(res.data) || res.data.length <= 0) {
return; return;
@@ -221,6 +235,7 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
ptConfigReset, ptConfigReset,
ptConfigApply, ptConfigApply,
classState, classState,
classStudents,
studentStatus, studentStatus,
studentSearch, studentSearch,
studentChange, studentChange,

View File

@@ -1,5 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, toRaw, watch, defineAsyncComponent } from 'vue'; import {
reactive,
ref,
onMounted,
toRaw,
watch,
defineAsyncComponent,
} from 'vue';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal'; import { ProModal } from 'antdv-pro-modal';
import { message, Modal } from 'ant-design-vue/es'; import { message, Modal } from 'ant-design-vue/es';
@@ -18,8 +25,10 @@ import {
getPtNeConfigData, getPtNeConfigData,
ptContrastAsDefault, ptContrastAsDefault,
ptExport, ptExport,
ptExportAll,
} from '@/api/pt/neConfig'; } from '@/api/pt/neConfig';
import { isSystemAdmin, hasRoles } from '@/plugins/auth-user';const neInfoStore = useNeInfoStore(); import { isSystemAdmin, hasRoles } from '@/plugins/auth-user';
const neInfoStore = useNeInfoStore();
import saveAs from 'file-saver'; import saveAs from 'file-saver';
const { t } = useI18n(); const { t } = useI18n();
const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({ const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
@@ -232,35 +241,42 @@ function fnGetNeConfig() {
treeState.loading = true; treeState.loading = true;
// 获取数据 // 获取数据
getAllNeConfig(neType).then(res => { getAllNeConfig(neType)
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { .then(res => {
const arr = []; if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
for (const item of res.data) { const arr = [];
let paramPerms: string[] = []; for (const item of res.data) {
if (item.paramPerms) { let paramPerms: string[] = [];
paramPerms = item.paramPerms.split(','); if (item.paramPerms) {
} else { paramPerms = item.paramPerms.split(',');
paramPerms = ['post', 'put', 'delete']; } else {
paramPerms = ['post', 'put', 'delete'];
}
arr.push({
...item,
children: undefined,
title: item.paramDisplay,
key: item.paramName,
paramPerms,
});
}
treeState.data = arr;
treeState.loading = false;
// 取首个tag
if (res.data.length > 0) {
const item = JSON.parse(JSON.stringify(treeState.data[0]));
treeState.selectNode = item;
treeState.selectLoading = false;
fnActiveConfigNode(item.key);
} }
arr.push({
...item,
children: undefined,
title: item.paramDisplay,
key: item.paramName,
paramPerms,
});
} }
treeState.data = arr; })
treeState.loading = false; .finally(() => {
// 取首个tag // 仅教师加载
if (res.data.length > 0) { if (hasRoles(['teacher'])) {
const item = JSON.parse(JSON.stringify(treeState.data[0])); classStudents(neType);
treeState.selectNode = item;
treeState.selectLoading = false;
fnActiveConfigNode(item.key);
} }
} });
});
} }
/**对话框对象信息状态类型 */ /**对话框对象信息状态类型 */
@@ -344,6 +360,7 @@ const {
studentStatus, studentStatus,
studentSearch, studentSearch,
studentChange, studentChange,
classStudents,
} = usePtOptions({ t, fnActiveConfigNode }); } = usePtOptions({ t, fnActiveConfigNode });
const { tablePagination, listState, listEdit, listEditClose, listEditOk } = const { tablePagination, listState, listEdit, listEditClose, listEditOk } =
@@ -450,6 +467,35 @@ function fnDataExport() {
}); });
} }
// 数据导出Excel
function fnDataExportAll() {
Modal.confirm({
title: t('common.tipTitle'),
content: t('views.configManage.configParamForm.ptExportTip'),
onOk() {
const hide = message.loading(t('common.loading'), 0);
ptExportAll()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 2,
});
saveAs(res.data, `students_config_data_${Date.now()}.zip`);
} else {
message.error({
content: `${res.msg}`,
duration: 2,
});
}
})
.finally(() => {
hide();
});
},
});
}
onMounted(() => { onMounted(() => {
// 获取网元网元列表 // 获取网元网元列表
neInfoStore.fnNelist().then(res => { neInfoStore.fnNelist().then(res => {
@@ -500,7 +546,7 @@ onMounted(() => {
<a-col :lg="8" :md="12" :xs="24" v-roles:has="['teacher']"> <a-col :lg="8" :md="12" :xs="24" v-roles:has="['teacher']">
<a-form-item <a-form-item
:label="t('views.configManage.configParamForm.ptApplyShow')" :label="t('views.configManage.configParamForm.ptApplyShow')"
name="neType " name="student "
> >
<a-select <a-select
v-model:value="classState.student" v-model:value="classState.student"
@@ -512,7 +558,7 @@ onMounted(() => {
:filter-option="false" :filter-option="false"
:not-found-content="null" :not-found-content="null"
:options="classState.studentOptions" :options="classState.studentOptions"
@search="studentSearch" @search="(v:any)=> studentSearch(treeState.neType, v)"
@change="studentChange" @change="studentChange"
> >
<template #option="{ value, label, applyStatus }"> <template #option="{ value, label, applyStatus }">
@@ -586,6 +632,9 @@ onMounted(() => {
<a-button @click="fnDataExport()" v-roles:has="['teacher']"> <a-button @click="fnDataExport()" v-roles:has="['teacher']">
{{ t('views.configManage.configParamForm.ptExport') }} {{ t('views.configManage.configParamForm.ptExport') }}
</a-button> </a-button>
<a-button @click="fnDataExportAll()" v-roles:has="['teacher']">
{{ t('views.configManage.configParamForm.ptExportAll') }}
</a-button>
<!-- 学生 --> <!-- 学生 -->
<a-button <a-button

File diff suppressed because it is too large Load Diff

View File

@@ -44,7 +44,7 @@ export function ptContrastAsDefault(params: Record<string, any>) {
* @param student 仅教师 student * @param student 仅教师 student
* @returns object * @returns object
*/ */
export function ptExport(student: string|undefined) { export function ptExport(student: string | undefined) {
return request({ return request({
url: `/pt/neConfigData/export`, url: `/pt/neConfigData/export`,
method: 'get', method: 'get',
@@ -54,6 +54,19 @@ export function ptExport(student: string|undefined) {
}); });
} }
/**
* 配置数据导出Excel (仅教师全量)
* @returns object
*/
export function ptExportAll() {
return request({
url: `/pt/neConfigData/export-all`,
method: 'get',
responseType: 'blob',
timeout: 180_000,
});
}
/** /**
* 网元参数配置信息 * 网元参数配置信息
* @param params 数据 {neType,paramName} * @param params 数据 {neType,paramName}

View File

@@ -514,13 +514,17 @@ export default {
ptDiffRest: 'Restore this version', ptDiffRest: 'Restore this version',
ptHistory: 'History', ptHistory: 'History',
ptReset: 'Reset To Example', ptReset: 'Reset To Example',
ptResetTip: 'Confirmed to reset to the sample configuration?',
ptLoad: 'Load Current Configuration', ptLoad: 'Load Current Configuration',
ptLoadTip: 'Confirm that you want to load the current network element configuration?',
ptExport: "Export Excel", ptExport: "Export Excel",
ptExportTip: "Exporting NE Configuration Data to an Excel file", ptExportTip: "Confirm that you want to export the network element configuration data to an Excel file?",
ptExportAll: "导出所有学生配置",
ptApplyShow: 'View Student', ptApplyShow: 'View Student',
ptApply: 'request', ptApply: 'request',
ptApplyNE: 'Application To NE', ptApplyNE: 'Application To NE',
ptApplyStu: 'Application To {ne}', ptApplyStu: 'Application To {ne}',
ptApplyStuTip: 'Confirm that you want to initiate a Configure Application to {ne} request to the teacher?',
ptApplyStuRack: 'Return Request', ptApplyStuRack: 'Return Request',
ptApplyStuNE: 'Application Request', ptApplyStuNE: 'Application Request',
}, },

View File

@@ -514,13 +514,17 @@ export default {
ptDiffRest: '还原此版本', ptDiffRest: '还原此版本',
ptHistory: '历史记录', ptHistory: '历史记录',
ptReset: '重置为示例', ptReset: '重置为示例',
ptResetTip: '确认要重置为示例配置吗?',
ptLoad: '载入当前网元配置', ptLoad: '载入当前网元配置',
ptLoadTip: '确认要载入当前网元配置吗?',
ptExport: "导出Excel", ptExport: "导出Excel",
ptExportTip: "导出网元配置数据到Excel文件中", ptExportTip: "确认要导出网元配置数据到Excel文件中吗?",
ptExportAll: "导出所有学生配置",
ptApplyShow: '查看学生', ptApplyShow: '查看学生',
ptApply: '申请', ptApply: '申请',
ptApplyNE: '应用配置到网元', ptApplyNE: '应用配置到网元',
ptApplyStu: '申请配置应用到 {ne}', ptApplyStu: '申请配置应用到 {ne}',
ptApplyStuTip: '确认要向教师发起配置应用到 {ne} 的申请吗?',
ptApplyStuRack: '退回该学生配置', ptApplyStuRack: '退回该学生配置',
ptApplyStuNE: '应用该学生配置', ptApplyStuNE: '应用该学生配置',
}, },

View File

@@ -5,9 +5,9 @@ import {
updatePtNeConfigApply, updatePtNeConfigApply,
} from '@/api/pt/neConfigApply'; } from '@/api/pt/neConfigApply';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants'; import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import { hasRoles } from '@/plugins/auth-user'; import { Modal } from 'ant-design-vue/es';
import { message } from 'ant-design-vue/lib'; import { message } from 'ant-design-vue/lib';
import { computed, onMounted, reactive } from 'vue'; import { computed, reactive } from 'vue';
/** /**
* 实训教学函数 * 实训教学函数
@@ -22,48 +22,60 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
}); });
/**(管理员)保存网元下所有配置为示例配置 */ /**(管理员)保存网元下所有配置为示例配置 */
function ptConfigSave(neType: string) { function ptConfigSave(neType: string) {
ptConfigState.saveLoading = true; Modal.confirm({
ptSaveAsDefault(neType, '001') title: t('common.tipTitle'),
.then(res => { content: t('views.configManage.configParamForm.ptLoadTip'),
if (res.code === RESULT_CODE_SUCCESS) { onOk() {
message.success({ ptConfigState.saveLoading = true;
content: t('common.operateOk'), ptSaveAsDefault(neType, '001')
duration: 3, .then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 3,
});
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.saveLoading = false;
fnActiveConfigNode('#');
}); });
} else { },
message.error({ });
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.saveLoading = false;
fnActiveConfigNode('#');
});
} }
/**重置网元下所有配置 */ /**重置网元下所有配置 */
function ptConfigReset(neType: string) { function ptConfigReset(neType: string) {
ptConfigState.restLoading = true; Modal.confirm({
ptResetAsDefault(neType) title: t('common.tipTitle'),
.then(res => { content: t('views.configManage.configParamForm.ptResetTip'),
if (res.code === RESULT_CODE_SUCCESS) { onOk() {
message.success({ ptConfigState.restLoading = true;
content: t('common.operateOk'), ptResetAsDefault(neType)
duration: 3, .then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 3,
});
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.restLoading = false;
fnActiveConfigNode('#');
}); });
} else { },
message.error({ });
content: `${res.msg}`,
duration: 3,
});
}
})
.finally(() => {
ptConfigState.restLoading = false;
fnActiveConfigNode('#');
});
} }
/**配置下方应用(学生)申请撤回和(管理/教师)应用退回 */ /**配置下方应用(学生)申请撤回和(管理/教师)应用退回 */
@@ -97,33 +109,42 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
result = stuPtNeConfigApply({ neType, status }); result = stuPtNeConfigApply({ neType, status });
} }
if (!result) return; if (!result) return;
ptConfigState.applyLoading = true;
result Modal.confirm({
.then((res: any) => { title: t('common.tipTitle'),
if (res.code === RESULT_CODE_SUCCESS) { content: t('views.configManage.configParamForm.ptApplyStuTip', {
message.success({ ne: neType,
content: t('common.operateOk'), }),
duration: 3, onOk() {
}); ptConfigState.applyLoading = true;
// 教师修改学生时改变状态 result
if (student) { .then((res: any) => {
const item = classState.studentOptionsDef.find( if (res.code === RESULT_CODE_SUCCESS) {
s => s.value === classState.student message.success({
); content: t('common.operateOk'),
if (item) { duration: 3,
item.applyStatus = status; });
// 教师修改学生时改变状态
if (student) {
const item = classState.studentOptionsDef.find(
s => s.value === classState.student
);
if (item) {
item.applyStatus = status;
}
}
} else {
message.error({
content: `${res.msg}`,
duration: 3,
});
} }
} })
} else { .finally(() => {
message.error({ ptConfigState.applyLoading = false;
content: `${res.msg}`,
duration: 3,
}); });
} },
}) });
.finally(() => {
ptConfigState.applyLoading = false;
});
} }
const classState = reactive<{ const classState = reactive<{
@@ -148,13 +169,6 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
studentOptionsDef: [], studentOptionsDef: [],
}); });
// 仅教师加载
if (hasRoles(['teacher'])) {
onMounted(() => {
classStudents(); // 初始学生列表
});
}
/**学生选择搜索 */ /**学生选择搜索 */
function studentChange(v: any) { function studentChange(v: any) {
if (!v) { if (!v) {
@@ -166,7 +180,7 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
let timeout: any; let timeout: any;
/**学生选择搜索 */ /**学生选择搜索 */
function studentSearch(val: string) { function studentSearch(neType: string, val: string) {
if (timeout) { if (timeout) {
clearTimeout(timeout); clearTimeout(timeout);
timeout = null; timeout = null;
@@ -175,12 +189,12 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
Object.assign(classState.studentOptions, classState.studentOptionsDef); Object.assign(classState.studentOptions, classState.studentOptionsDef);
return; return;
} }
timeout = setTimeout(() => classStudents(val), 500); timeout = setTimeout(() => classStudents(neType, val), 500);
} }
/**班级学生列表 */ /**班级学生列表 */
function classStudents(val?: string) { function classStudents(neType: string, val?: string) {
getPtClassStudents({ userName: val }).then(res => { getPtClassStudents({ neType, userName: val }).then(res => {
classState.studentOptions = []; classState.studentOptions = [];
if (!Array.isArray(res.data) || res.data.length <= 0) { if (!Array.isArray(res.data) || res.data.length <= 0) {
return; return;
@@ -221,6 +235,7 @@ export default function usePtOptions({ t, fnActiveConfigNode }: any) {
ptConfigReset, ptConfigReset,
ptConfigApply, ptConfigApply,
classState, classState,
classStudents,
studentStatus, studentStatus,
studentSearch, studentSearch,
studentChange, studentChange,

View File

@@ -1,5 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { reactive, ref, onMounted, toRaw, watch, defineAsyncComponent } from 'vue'; import {
reactive,
ref,
onMounted,
toRaw,
watch,
defineAsyncComponent,
} from 'vue';
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { ProModal } from 'antdv-pro-modal'; import { ProModal } from 'antdv-pro-modal';
import { message, Modal } from 'ant-design-vue/es'; import { message, Modal } from 'ant-design-vue/es';
@@ -18,8 +25,10 @@ import {
getPtNeConfigData, getPtNeConfigData,
ptContrastAsDefault, ptContrastAsDefault,
ptExport, ptExport,
ptExportAll,
} from '@/api/pt/neConfig'; } from '@/api/pt/neConfig';
import { isSystemAdmin, hasRoles } from '@/plugins/auth-user';const neInfoStore = useNeInfoStore(); import { isSystemAdmin, hasRoles } from '@/plugins/auth-user';
const neInfoStore = useNeInfoStore();
import saveAs from 'file-saver'; import saveAs from 'file-saver';
const { t } = useI18n(); const { t } = useI18n();
const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({ const { ruleVerification, smfByUPFIdLoadData, smfByUPFIdOptions } = useOptions({
@@ -232,35 +241,42 @@ function fnGetNeConfig() {
treeState.loading = true; treeState.loading = true;
// 获取数据 // 获取数据
getAllNeConfig(neType).then(res => { getAllNeConfig(neType)
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) { .then(res => {
const arr = []; if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
for (const item of res.data) { const arr = [];
let paramPerms: string[] = []; for (const item of res.data) {
if (item.paramPerms) { let paramPerms: string[] = [];
paramPerms = item.paramPerms.split(','); if (item.paramPerms) {
} else { paramPerms = item.paramPerms.split(',');
paramPerms = ['post', 'put', 'delete']; } else {
paramPerms = ['post', 'put', 'delete'];
}
arr.push({
...item,
children: undefined,
title: item.paramDisplay,
key: item.paramName,
paramPerms,
});
}
treeState.data = arr;
treeState.loading = false;
// 取首个tag
if (res.data.length > 0) {
const item = JSON.parse(JSON.stringify(treeState.data[0]));
treeState.selectNode = item;
treeState.selectLoading = false;
fnActiveConfigNode(item.key);
} }
arr.push({
...item,
children: undefined,
title: item.paramDisplay,
key: item.paramName,
paramPerms,
});
} }
treeState.data = arr; })
treeState.loading = false; .finally(() => {
// 取首个tag // 仅教师加载
if (res.data.length > 0) { if (hasRoles(['teacher'])) {
const item = JSON.parse(JSON.stringify(treeState.data[0])); classStudents(neType);
treeState.selectNode = item;
treeState.selectLoading = false;
fnActiveConfigNode(item.key);
} }
} });
});
} }
/**对话框对象信息状态类型 */ /**对话框对象信息状态类型 */
@@ -344,6 +360,7 @@ const {
studentStatus, studentStatus,
studentSearch, studentSearch,
studentChange, studentChange,
classStudents,
} = usePtOptions({ t, fnActiveConfigNode }); } = usePtOptions({ t, fnActiveConfigNode });
const { tablePagination, listState, listEdit, listEditClose, listEditOk } = const { tablePagination, listState, listEdit, listEditClose, listEditOk } =
@@ -450,6 +467,35 @@ function fnDataExport() {
}); });
} }
// 数据导出Excel
function fnDataExportAll() {
Modal.confirm({
title: t('common.tipTitle'),
content: t('views.configManage.configParamForm.ptExportTip'),
onOk() {
const hide = message.loading(t('common.loading'), 0);
ptExportAll()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS) {
message.success({
content: t('common.operateOk'),
duration: 2,
});
saveAs(res.data, `students_config_data_${Date.now()}.zip`);
} else {
message.error({
content: `${res.msg}`,
duration: 2,
});
}
})
.finally(() => {
hide();
});
},
});
}
onMounted(() => { onMounted(() => {
// 获取网元网元列表 // 获取网元网元列表
neInfoStore.fnNelist().then(res => { neInfoStore.fnNelist().then(res => {
@@ -500,7 +546,7 @@ onMounted(() => {
<a-col :lg="8" :md="12" :xs="24" v-roles:has="['teacher']"> <a-col :lg="8" :md="12" :xs="24" v-roles:has="['teacher']">
<a-form-item <a-form-item
:label="t('views.configManage.configParamForm.ptApplyShow')" :label="t('views.configManage.configParamForm.ptApplyShow')"
name="neType " name="student "
> >
<a-select <a-select
v-model:value="classState.student" v-model:value="classState.student"
@@ -512,7 +558,7 @@ onMounted(() => {
:filter-option="false" :filter-option="false"
:not-found-content="null" :not-found-content="null"
:options="classState.studentOptions" :options="classState.studentOptions"
@search="studentSearch" @search="(v:any)=> studentSearch(treeState.neType, v)"
@change="studentChange" @change="studentChange"
> >
<template #option="{ value, label, applyStatus }"> <template #option="{ value, label, applyStatus }">
@@ -586,6 +632,9 @@ onMounted(() => {
<a-button @click="fnDataExport()" v-roles:has="['teacher']"> <a-button @click="fnDataExport()" v-roles:has="['teacher']">
{{ t('views.configManage.configParamForm.ptExport') }} {{ t('views.configManage.configParamForm.ptExport') }}
</a-button> </a-button>
<a-button @click="fnDataExportAll()" v-roles:has="['teacher']">
{{ t('views.configManage.configParamForm.ptExportAll') }}
</a-button>
<!-- 学生 --> <!-- 学生 -->
<a-button <a-button

View File

@@ -2,7 +2,14 @@
import { PageContainer } from 'antdv-pro-layout'; import { PageContainer } from 'antdv-pro-layout';
import { ColumnsType } from 'ant-design-vue/es/table'; import { ColumnsType } from 'ant-design-vue/es/table';
import { message } from 'ant-design-vue/es'; import { message } from 'ant-design-vue/es';
import { reactive, ref, onMounted, onBeforeUnmount, markRaw } from 'vue'; import {
reactive,
ref,
onMounted,
onBeforeUnmount,
markRaw,
useTemplateRef,
} from 'vue';
import useI18n from '@/hooks/useI18n'; import useI18n from '@/hooks/useI18n';
import { TooltipComponent } from 'echarts/components'; import { TooltipComponent } from 'echarts/components';
import { GaugeChart } from 'echarts/charts'; import { GaugeChart } from 'echarts/charts';
@@ -32,24 +39,12 @@ echarts.use([
]); ]);
/**图DOM节点实例对象 */ /**图DOM节点实例对象 */
const statusBar = ref<HTMLElement | undefined>(undefined); const statusBar = useTemplateRef<HTMLDivElement>('statusBar');
/**图实例对象 */ /**图实例对象 */
const statusBarChart = ref<any>(null); const statusBarChart = ref<any>(null);
/**网元状态字典数据 */
let indexColor = ref<DictType[]>([
{ label: 'Normal', value: 'normal', tagType: '', tagClass: '#91cc75' },
{
label: 'Abnormal',
value: 'abnormal',
tagType: '',
tagClass: '#ee6666',
},
]);
/**表格字段列 */ /**表格字段列 */
//customRender(){} ----单元格处理
let tableColumns: ColumnsType = [ let tableColumns: ColumnsType = [
{ {
title: t('views.index.object'), title: t('views.index.object'),
@@ -67,7 +62,9 @@ let tableColumns: ColumnsType = [
dataIndex: 'serverState', dataIndex: 'serverState',
align: 'left', align: 'left',
customRender(opt) { customRender(opt) {
if (opt.value?.refreshTime) return parseDateToStr(opt.value?.refreshTime); if (opt.value?.refreshTime) {
return parseDateToStr(opt.value?.refreshTime, 'HH:mm:ss');
}
return '-'; return '-';
}, },
}, },
@@ -104,12 +101,13 @@ let tableColumns: ColumnsType = [
}, },
}, },
]; ];
/**表格状态类型 */ /**表格状态类型 */
type TabeStateType = { type TabeStateType = {
/**加载等待 */ /**加载等待 */
loading: boolean; loading: boolean;
/**记录数据 */ /**记录数据 */
data: object[]; data: Record<string, any>[];
/**勾选记录 */ /**勾选记录 */
selectedRowKeys: (string | number)[]; selectedRowKeys: (string | number)[];
}; };
@@ -121,114 +119,92 @@ let tableState: TabeStateType = reactive({
selectedRowKeys: [], selectedRowKeys: [],
}); });
/**表格状态 */ /**状态 */
let nfInfo: any = reactive({ let serverState: any = ref({});
obj: 'OMC',
version: appStore.version,
status: t('views.index.normal'),
outTimeDate: '',
serialNum: appStore.serialNum,
});
/**表格状态类型 */
type nfStateType = {
/**主机名 */
hostName: string;
/**操作系统信息 */
osInfo: string;
/**IP地址 */
ipAddress: string;
/**版本 */
version: string;
/**CPU利用率 */
cpuUse: string;
/**内存使用 */
memoryUse: string;
/**用户容量 */
capability: number;
/**序列号 */
serialNum: string;
/**许可证到期日期 */
/* selectedRowKeys: (string | number)[];*/
expiryDate: string;
};
/**网元详细信息 */
let pronInfo: nfStateType = reactive({
hostName: '5gc',
osInfo: 'Linux 5gc 4.15.0-112-generic 2020 x86_64 GNU/Linux',
ipAddress: '-',
version: '-',
cpuUse: '-',
memoryUse: '-',
capability: 0,
serialNum: '-',
expiryDate: '-',
});
/**查询网元状态列表 */ /**查询网元状态列表 */
function fnGetList(one: boolean) { async function fnGetList(reload: boolean = false) {
if (tableState.loading) return; tableState.loading = !reload;
one && (tableState.loading = true); try {
listAllNeInfo({ bandStatus: true }).then(res => { const res = await listAllNeInfo({ bandStatus: true });
tableState.data = res.data; tableState.data = res.data;
tableState.loading = false; } catch (error) {
var rightNum = 0; console.error(error);
var errorNum = 0; tableState.data = [];
res.data.forEach((item: any) => { }
if (item.serverState.online) { tableState.loading = false;
rightNum++; if (tableState.data.length == 0) {
} else { return;
errorNum++; }
}
}); var rightNum = 0;
const optionData: any = { var errorNum = 0;
title: { for (const v of tableState.data) {
text: '', if (v?.serverState?.online) {
subtext: '', rightNum++;
left: 'center', } else {
}, errorNum++;
tooltip: { }
trigger: 'item', }
},
legend: { // 初始
orient: 'vertical', if (!reload) {
left: 'left', // 选择第一个
}, if (tableState.data.length > 0) {
color: indexColor.value.map(item => item.tagClass), const id = tableState.data[0].id;
fnTableSelectedRowKeys([id]);
} else {
fnTableSelectedRowKeys(tableState.selectedRowKeys);
}
if (statusBar.value) {
fnDesign(statusBar.value, rightNum, errorNum);
}
} else {
statusBarChart.value.setOption({
series: [ series: [
{ {
name: t('views.index.realNeStatus'),
type: 'pie',
radius: '70%',
center: ['50%', '50%'],
data: [ data: [
{ value: rightNum, name: t('views.index.normal') }, { value: rightNum, name: t('views.index.normal') },
{ value: errorNum, name: t('views.index.abnormal') }, { value: errorNum, name: t('views.index.abnormal') },
], ],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)',
},
},
label: {},
}, },
], ],
}; });
}
fnDesign(statusBar.value, optionData);
});
} }
function fnDesign(container: HTMLElement | undefined, option: any) { function fnDesign(container: HTMLElement, rightNum: number, errorNum: number) {
if (!container) return; /// 图表数据
const optionData: any = {
if (!statusBarChart.value) { title: {
statusBarChart.value = markRaw(echarts.init(container, 'light')); text: '',
} subtext: '',
option && statusBarChart.value.setOption(option); left: 'center',
},
tooltip: {
trigger: 'item',
},
legend: {
orient: 'vertical',
left: 'left',
},
color: dict.indexStatus.map(item => item.tagClass),
series: [
{
name: t('views.index.runStatus'),
type: 'pie',
radius: '70%',
center: ['50%', '50%'],
data: [
{ value: rightNum, name: t('views.index.normal') },
{ value: errorNum, name: t('views.index.abnormal') },
],
},
],
};
statusBarChart.value = markRaw(echarts.init(container, 'light'));
statusBarChart.value.setOption(optionData);
// 创建 ResizeObserver 实例 // 创建 ResizeObserver 实例
var observer = new ResizeObserver(entries => { var observer = new ResizeObserver(entries => {
@@ -240,66 +216,43 @@ function fnDesign(container: HTMLElement | undefined, option: any) {
observer.observe(container); observer.observe(container);
} }
/**抽屉 网元详细信息 */ /**表格多选 */
const open = ref(false); function fnTableSelectedRowKeys(keys: (string | number)[]) {
const closeDrawer = () => { if (keys.length <= 0) return;
open.value = false; const id = keys[0];
}; const row: any = tableState.data.find((item: any) => item.id === id);
/**抽屉 网元详细信息 */ if (!row) {
message.error(t('views.index.neStatus'), 2);
return;
}
const neState = row.serverState;
if (!neState?.online) {
message.error(t('views.index.neStatus'), 2);
return;
}
tableState.selectedRowKeys = keys;
// Mem 将KB转换为MB
// const totalMemInKB = neState.mem?.totalMem;
// const nfUsedMemInKB = neState.mem?.nfUsedMem;
// const sysMemUsageInKB = neState.mem?.sysMemUsage;
// const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100;
// const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100;
// const sysMemUsageInMB = Math.round((sysMemUsageInKB / 1024) * 100) / 100;
/**监听表格行事件*/ // CPU
function rowClick(record: any, index: any) { // const nfCpu = neState.cpu?.nfCpuUsage;
return { // const sysCpu = neState.cpu?.sysCpuUsage;
onClick: (event: any) => { // const nfCpuP = Math.round(nfCpu) / 100;
let pronData = JSON.parse(JSON.stringify(record.serverState)); // const sysCpuP = Math.round(sysCpu) / 100;
if (!pronData.online) {
message.error(t('views.index.neStatus'), 2);
return false;
} else {
const totalMemInKB = pronData.mem?.totalMem;
const nfUsedMemInKB = pronData.mem?.nfUsedMem;
const sysMemUsageInKB = pronData.mem?.sysMemUsage;
// 将KB转换为MB serverState.value = Object.assign(
const totalMemInMB = Math.round((totalMemInKB / 1024) * 100) / 100; {
const nfUsedMemInMB = Math.round((nfUsedMemInKB / 1024) * 100) / 100; // cpuUse: `NE:${nfCpuP}%; SYS:${sysCpuP}%`,
const sysMemUsageInMB = // memoryUse: `Total: ${totalMemInMB}MB; NE: ${nfUsedMemInMB}MB; SYS: ${sysMemUsageInMB}MB`,
Math.round((sysMemUsageInKB / 1024) * 100) / 100;
//渲染详细信息
pronInfo = {
hostName: pronData.hostname,
osInfo: pronData.os,
ipAddress: pronData.neIP,
version: pronData.version,
cpuUse:
pronData.neName +
':' +
pronData.cpu?.nfCpuUsage / 100 +
'%; ' +
'SYS:' +
pronData.cpu?.sysCpuUsage / 100 +
'%',
memoryUse:
'Total:' +
totalMemInMB +
'MB; ' +
pronData.name +
':' +
nfUsedMemInMB +
'MB; SYS:' +
sysMemUsageInMB +
'MB',
capability: pronData.capability,
serialNum: pronData.sn,
expiryDate: pronData.expire,
};
}
open.value = true;
}, },
}; neState
);
} }
let timer: any;
/** /**
* 国际化翻译转换 * 国际化翻译转换
@@ -312,63 +265,50 @@ function fnLocale() {
appStore.setTitle(title); appStore.setTitle(title);
} }
/**字典数据 */
let dict: {
/**网元信息状态 */
neInfoStatus: DictType[];
/**主页状态 */
indexStatus: DictType[];
} = reactive({
neInfoStatus: [],
indexStatus: [],
});
let timer: any;
let timerFlag: boolean = false;
onMounted(() => { onMounted(() => {
getDict('index_status') // 初始字典数据
.then(res => { Promise.allSettled([getDict('ne_info_status'), getDict('index_status')])
if (res.length > 0) { .then(resArr => {
indexColor.value = res; if (resArr[0].status === 'fulfilled') {
dict.neInfoStatus = resArr[0].value;
}
if (resArr[1].status === 'fulfilled') {
dict.indexStatus = resArr[1].value;
} }
}) })
.finally(() => { .finally(async () => {
fnLocale(); fnLocale();
fnGetList(true); await fnGetList(false);
timer = setInterval(() => fnGetList(false), 10000); // 每隔10秒执行一次 timer = setInterval(() => {
if (timerFlag) return;
fnGetList(true);
}, 10_000); // 每隔10秒执行一次
}); });
}); });
// 在组件卸载之前清除定时器 // 在组件卸载之前清除定时器
onBeforeUnmount(() => { onBeforeUnmount(() => {
clearInterval(timer); clearInterval(timer);
timer = null;
timerFlag = true;
}); });
</script> </script>
<template> <template>
<PageContainer :breadcrumb="{}"> <PageContainer :breadcrumb="{}">
<div>
<a-drawer :open="open" @close="closeDrawer" :width="700">
<a-descriptions bordered :column="1" :label-style="{ width: '160px' }">
<a-descriptions-item :label="t('views.index.hostName')">{{
pronInfo.hostName
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.osInfo')">{{
pronInfo.osInfo
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.ipAddress')">{{
pronInfo.ipAddress
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.version')">{{
pronInfo.version
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.capability')">{{
pronInfo.capability
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.cpuUse')">{{
pronInfo.cpuUse
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.memoryUse')">{{
pronInfo.memoryUse
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.serialNum')">{{
pronInfo.serialNum
}}</a-descriptions-item>
<a-descriptions-item :label="t('views.index.expiryDate')">{{
pronInfo.expiryDate
}}</a-descriptions-item>
</a-descriptions>
</a-drawer>
</div>
<a-row :gutter="16"> <a-row :gutter="16">
<a-col :lg="14" :md="16" :xs="24"> <a-col :lg="14" :md="16" :xs="24">
<!-- 表格列表 --> <!-- 表格列表 -->
@@ -377,20 +317,20 @@ onBeforeUnmount(() => {
row-key="id" row-key="id"
size="small" size="small"
:columns="tableColumns" :columns="tableColumns"
:loading="tableState.loading"
:data-source="tableState.data" :data-source="tableState.data"
:loading="tableState.loading"
:pagination="false" :pagination="false"
:scroll="{ x: true }" :scroll="{ x: true }"
:customRow="rowClick" :row-selection="{
type: 'radio',
columnWidth: '48px',
selectedRowKeys: tableState.selectedRowKeys,
onChange: fnTableSelectedRowKeys,
}"
> >
<template #bodyCell="{ column, record }"> <template #bodyCell="{ column, record }">
<template v-if="column.key === 'status'"> <template v-if="column.key === 'status'">
<div v-if="record.serverState.online"> <DictTag :options="dict.neInfoStatus" :value="record.status" />
<a-tag color="blue">{{ t('views.index.normal') }}</a-tag>
</div>
<div v-else>
<a-tag color="pink">{{ t('views.index.abnormal') }}</a-tag>
</div>
</template> </template>
</template> </template>
</a-table> </a-table>
@@ -404,7 +344,8 @@ onBeforeUnmount(() => {
<div style="width: 100%; min-height: 200px" ref="statusBar"></div> <div style="width: 100%; min-height: 200px" ref="statusBar"></div>
</a-card> </a-card>
<a-card <a-card
:title="t('views.index.mark')" :loading="tableState.loading"
:title="`${t('views.index.mark')} - ${serverState.neName || 'OMC'}`"
style="margin-top: 16px" style="margin-top: 16px"
size="small" size="small"
> >
@@ -413,25 +354,33 @@ onBeforeUnmount(() => {
:column="1" :column="1"
:label-style="{ width: '160px' }" :label-style="{ width: '160px' }"
> >
<a-descriptions-item :label="t('views.index.object')">{{ <a-descriptions-item :label="t('views.index.hostName')">
nfInfo.obj {{ serverState.hostname }}
}}</a-descriptions-item> </a-descriptions-item>
<template v-if="nfInfo.obj === 'OMC'"> <a-descriptions-item :label="t('views.index.osInfo')">
<a-descriptions-item :label="t('views.index.versionNum')">{{ {{ serverState.os }}
nfInfo.version </a-descriptions-item>
}}</a-descriptions-item> <a-descriptions-item :label="t('views.index.ipAddress')">
<a-descriptions-item :label="t('views.index.systemStatus')">{{ {{ serverState.neIP }}
nfInfo.status </a-descriptions-item>
}}</a-descriptions-item> <a-descriptions-item :label="t('views.index.version')">
</template> {{ serverState.version }}
<template v-else> </a-descriptions-item>
<a-descriptions-item :label="t('views.index.serialNum')">{{ <a-descriptions-item :label="t('views.index.capability')">
nfInfo.serialNum {{ serverState.capability }}
}}</a-descriptions-item> </a-descriptions-item>
<a-descriptions-item :label="t('views.index.expiryDate')">{{ <!-- <a-descriptions-item :label="t('views.index.cpuUse')">
nfInfo.outTimeDate {{ serverState.cpuUse }}
}}</a-descriptions-item> </a-descriptions-item>
</template> <a-descriptions-item :label="t('views.index.memoryUse')">
{{ serverState.memoryUse }}
</a-descriptions-item> -->
<a-descriptions-item :label="t('views.index.serialNum')">
{{ serverState.sn }}
</a-descriptions-item>
<a-descriptions-item :label="t('views.index.expiryDate')">
{{ serverState.expire }}
</a-descriptions-item>
</a-descriptions> </a-descriptions>
</a-card> </a-card>
</a-col> </a-col>

View File

@@ -50,6 +50,7 @@ async function fnGetState() {
graphG6.value.setItemState(neShape, 'neState', ne.serverState.online); graphG6.value.setItemState(neShape, 'neState', ne.serverState.online);
} }
} }
await new Promise(resolve => setTimeout(resolve, 15_000));
} }
/**查询全部网元数据列表 */ /**查询全部网元数据列表 */

View File

@@ -96,13 +96,13 @@ const graphNodeMenu = new Menu({
${neState.neName ?? '--'} ${neState.neName ?? '--'}
</h3> </h3>
<div id="restart" style="cursor: pointer; margin-bottom: 4px"> <div id="restart" style="cursor: pointer; margin-bottom: 4px">
> ${t('views.configManage.neManage.restart')} > ${t('views.ne.common.restart')}
</div> </div>
<div id="stop" style="cursor: pointer; margin-bottom: 4px;"> <div id="stop" style="cursor: pointer; margin-bottom: 4px;">
> ${t('views.configManage.neManage.stop')} > ${t('views.ne.common.stop')}
</div> </div>
<div id="log" style="cursor: pointer; margin-bottom: 4px;"> <div id="log" style="cursor: pointer; margin-bottom: 4px;">
> ${t('views.configManage.neManage.log')} > ${t('views.ne.common.log')}
</div> </div>
</div> </div>
`; `;