Files
fe.ems.vue3/src/views/mmlManage/omcOperate/index.vue
2023-11-03 20:17:07 +08:00

477 lines
13 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, ref, onMounted, toRaw } from 'vue';
import { PageContainer } from '@ant-design-vue/pro-layout';
import { message } from 'ant-design-vue/lib';
import CodemirrorEdite from '@/components/CodemirrorEdite/index.vue';
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
import useNeInfoStore from '@/store/modules/neinfo';
import { regExpIPv4, regExpIPv6 } from '@/utils/regular-utils';
import useI18n from '@/hooks/useI18n';
import { getMMLByOMC, sendMMlByOMC } from '@/api/mmlManage/omcOperate';
const { t } = useI18n();
/**网元参数 */
let neOtions = ref<Record<string, any>[]>([]);
/**对象信息状态类型 */
type StateType = {
/**网元ID */
neId: string;
/**命令数据 loading */
mmlLoading: boolean;
/**命令数据 tree */
mmlTreeData: any[];
/**命令选中 */
mmlSelect: Record<string, any>;
/**表单数据 */
from: Record<string, any>;
/**命令发送日志 */
mmlCmdLog: string;
};
/**对象信息状态 */
let state: StateType = reactive({
neId: '',
mmlLoading: true,
mmlTreeData: [],
mmlSelect: {},
from: {
sendLoading: false,
},
mmlCmdLog: '',
});
/**查询可选命令列表 */
function fnTreeSelect(_: any, info: any) {
state.mmlSelect = info.node.dataRef;
state.from = {};
// state.mmlCmdLog = '';
}
/**清空控制台日志 */
function fnCleanCmdLog() {
state.mmlCmdLog = '';
}
/**清空表单 */
function fnCleanFrom() {
state.from = {};
}
/**命令发送 */
function fnSendMML() {
if (state.from.sendLoading) {
return;
}
const operation = state.mmlSelect.operation;
const object = state.mmlSelect.object;
let cmdStr = '';
// 根据参数取值
let argsArr: string[] = [];
const param = toRaw(state.mmlSelect.param) || [];
const from = toRaw(state.from);
for (const item of param) {
const value = from[item.name];
// 是否必填项且有效值
const notV = value === null || value === undefined || value === '';
if (item.optional === 'false' && notV) {
message.warning(`必填参数:${item.display}`, 2);
return;
}
// 检查是否存在值
if (!Reflect.has(from, item.name) || notV) {
continue;
}
// 检查规则
const [ok, msg] = ruleVerification(item, from[item.name]);
if (!ok) {
message.warning({
content: `${msg}`,
duration: 3,
});
return;
}
argsArr.push(`${item.name}=${from[item.name]}`);
}
// 拼装命令
const argsStr = argsArr.join(',');
if (object && argsStr) {
cmdStr = `${operation} ${object}:${argsStr}`;
} else if (object) {
cmdStr = `${operation} ${object}`;
} else {
cmdStr = `${operation} ${argsStr}`;
}
cmdStr = cmdStr.trim();
// 发送
state.mmlCmdLog += `${cmdStr}\n`;
state.from.sendLoading = true;
sendMMlByOMC(state.neId, cmdStr).then(res => {
state.from.sendLoading = false;
if (res.code === RESULT_CODE_SUCCESS) {
let resultStr = res.data;
resultStr = resultStr.replace(/(\r\n|\n)/g, '\n');
state.mmlCmdLog += `${resultStr}\n`;
} else {
state.mmlCmdLog += `${res.msg}\n`;
}
});
}
/**规则校验 */
function ruleVerification(
row: Record<string, any>,
value: any
): (string | boolean)[] {
let result = [true, ''];
const type = row.type;
const filter = row.filter;
const display = row.display;
switch (type) {
case 'int':
if (filter && filter.indexOf('~') !== -1) {
const filterArr = filter.split('~');
const minInt = parseInt(filterArr[0]);
const maxInt = parseInt(filterArr[1]);
const valueInt = parseInt(value);
if (valueInt < minInt || valueInt > maxInt) {
return [false, `${display} 参数值不在合理范围 ${filter}`];
}
}
break;
case 'ipv4':
if (!regExpIPv4.test(value)) {
return [false, `${display} 不是合法的IPV4地址`];
}
break;
case 'ipv6':
if (!regExpIPv6.test(value)) {
return [false, `${display} 不是合法的IPV6地址`];
}
break;
case 'enum':
if (filter && filter.indexOf('{') === 1) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
if (!Object.keys(filterJson).includes(`${value}`)) {
return [false, `${display} 不是合理的枚举值`];
}
}
break;
case 'bool':
if (filter && filter.indexOf('{') === 1) {
let filterJson: Record<string, any> = {};
try {
filterJson = JSON.parse(filter); //string---json
} catch (error) {
console.error(error);
}
if (!Object.values(filterJson).includes(`${value}`)) {
return [false, `${display} 不是合理的布尔类型的值`];
}
}
break;
case 'string':
if (filter && filter.indexOf('~') !== -1) {
try {
const filterArr = filter.split('~');
let rule = new RegExp(
'^\\S{' + filterArr[0] + ',' + filterArr[1] + '}$'
);
if (!rule.test(value)) {
return [false, `${display} 参数值不合理`];
}
} catch (error) {
console.error(error);
}
}
break;
case 'regex':
if (filter) {
try {
let regex = new RegExp(filter);
if (!regex.test(value)) {
return [false, `${display} 参数值不合理`];
}
} catch (error) {
console.error(error);
}
}
break;
default:
return [false, `${display} 输入值是未知类型`];
}
return result;
}
/**查询可选命令列表 */
function fnGetList() {
getMMLByOMC().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
// 构建树结构
const treeArr: Record<string, any>[] = [];
for (const item of res.data) {
const id = item['id'];
const object = item['object'];
const operation = item['operation'];
const mmlDisplay = item['mmlDisplay'];
// 可选属性参数
let param = [];
try {
param = JSON.parse(item['paramJson']);
} catch (error) {
console.error(error);
}
// 遍历检查大类
const treeItem = treeArr.find(i => i.key == item['category']);
if (!treeItem) {
treeArr.push({
title: item['catDisplay'],
key: item['category'],
selectable: false,
children: [
{ key: id, title: mmlDisplay, object, operation, param },
],
});
} else {
treeItem.children.push({
key: id,
title: mmlDisplay,
object,
operation,
param,
});
}
}
state.mmlTreeData = treeArr;
}
state.mmlLoading = false;
});
}
onMounted(() => {
// 获取网元网元列表
useNeInfoStore()
.fnNelist()
.then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
let arr: Record<string, any>[] = [];
res.data.forEach(i => {
if (i.neType === 'OMC') {
arr.push({ value: i.neId, label: i.neName });
}
});
neOtions.value = arr;
if (arr.length > 0) {
state.neId = arr[0].value;
// 获取列表数据
fnGetList();
}
} else {
message.warning({
content: `暂无OMC网元`,
duration: 5,
});
}
} else {
message.warning({
content: `暂无网元列表数据`,
duration: 2,
});
}
});
});
</script>
<template>
<PageContainer>
<a-row :gutter="16">
<a-col :span="6">
<!-- 命令导航 -->
<a-card
size="small"
:bordered="false"
title="命令导航"
:loading="state.mmlLoading"
>
<a-form layout="vertical" autocomplete="off">
<a-form-item name="neId ">
<a-select
v-model:value="state.neId"
:options="neOtions"
placeholder="请选择OMC操作命令"
/>
</a-form-item>
<a-form-item name="listeningPort">
<a-directory-tree
:tree-data="state.mmlTreeData"
@select="fnTreeSelect"
></a-directory-tree>
</a-form-item>
</a-form>
</a-card>
</a-col>
<a-col :span="18">
<!-- 命令参数输入 -->
<a-card
size="small"
:bordered="false"
:loading="!state.mmlSelect.title"
>
<template #title>
<a-typography-text strong v-if="state.mmlSelect.title">
{{ state.mmlSelect.title }}
</a-typography-text>
<a-typography-text type="danger" v-else>
左侧命令导航中选择要操作项
</a-typography-text>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8">
<a-button
type="default"
size="small"
@click.prevent="fnCleanFrom"
v-if="!!state.mmlSelect.param"
>
<template #icon>
<ClearOutlined />
</template>
清除表单
</a-button>
<a-button
type="primary"
size="small"
:disabled="!state.mmlSelect.title"
:loading="state.from.sendLoading"
@click.prevent="fnSendMML"
>
<template #icon>
<SendOutlined />
</template>
执行
</a-button>
</a-space>
</template>
<a-form
layout="vertical"
autocomplete="off"
:validate-on-rule-change="false"
:validateTrigger="[]"
>
<a-row :gutter="16">
<a-col
:lg="6"
:md="12"
:xs="24"
v-for="item in state.mmlSelect.param"
>
<a-form-item
:label="item.display"
:name="item.name"
:required="item.optional === 'false'"
>
<a-tooltip>
<template #title v-if="item.comment">
{{ item.comment }}
</template>
<a-input
v-if="
['string', 'ipv6', 'ipv4', 'regex'].includes(item.type)
"
v-model:value="state.from[item.name]"
:placeholder="item.filter"
></a-input>
<a-input-number
v-else-if="item.type === 'int'"
v-model:value="state.from[item.name]"
:min="0"
:max="65535"
:placeholder="item.filter"
style="width: 100%"
></a-input-number>
<a-switch
v-else-if="item.type === 'bool'"
v-model:checked="state.from[item.name]"
:checked-children="t('common.switch.open')"
:un-checked-children="t('common.switch.shut')"
></a-switch>
<a-select
v-else-if="item.type === 'enum'"
v-model:value="state.from[item.name]"
:placeholder="item.filter"
:allow-clear="true"
>
<a-select-option
:value="v"
:key="v"
v-for="(k, v) in JSON.parse(item.filter)"
>
{{ k }}
</a-select-option>
</a-select>
</a-tooltip>
</a-form-item>
</a-col>
</a-row>
</a-form>
</a-card>
<!-- 命令展示 -->
<a-card
title="控制台"
:bordered="false"
size="small"
:body-style="{ padding: 0 }"
style="margin-top: 16px"
v-show="state.mmlSelect.title"
>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8" align="center">
<a-button
type="default"
size="small"
@click.prevent="fnCleanCmdLog"
>
<template #icon>
<ClearOutlined />
</template>
清除日志
</a-button>
</a-space>
</template>
<CodemirrorEdite
v-model:value="state.mmlCmdLog"
:disabled="true"
:editor-style="{ height: '500px !important' }"
placeholder="等待发送命令"
></CodemirrorEdite>
</a-card>
</a-col>
</a-row>
</PageContainer>
</template>
<style lang="less" scoped></style>