feat: mml命令操作支持输入多行发送
This commit is contained in:
@@ -216,7 +216,7 @@ export default {
|
||||
tabPane1: 'Account password login',
|
||||
tabPane2: 'Login with phone number',
|
||||
registerBtn: 'Register an account',
|
||||
loginBtn: 'Login',
|
||||
loginBtn: 'Sign In',
|
||||
loginSuccess: 'Login successful',
|
||||
loginMethod: 'Other login methods:',
|
||||
loginMethodWX: 'WeChat Scan Login',
|
||||
@@ -1252,7 +1252,6 @@ export default {
|
||||
},
|
||||
},
|
||||
mmlManage: {
|
||||
operationtitle: "Interface Settings",
|
||||
cmdTitle: "Command Navigator",
|
||||
cmdConsole: "consoles",
|
||||
cmdOpTip: "Select the item to be operated in the left command navigation!",
|
||||
@@ -1265,8 +1264,10 @@ export default {
|
||||
requireIpv6: "{display} Not a legitimate IPV6 address.",
|
||||
requireEnum: "{display} is not a reasonable enumeration value.",
|
||||
requireBool: "{display} is not a reasonable boolean value.",
|
||||
clearForm: "Clear Forms",
|
||||
clearLog: "Clearing logs",
|
||||
cmdQuickEntry: "Command Quick Entry",
|
||||
cmdParamPanel: "Parameter Panel",
|
||||
clearForm: "Reset",
|
||||
clearLog: "Clear Logs",
|
||||
exec: "Execute",
|
||||
cmdAwait: "Waiting for a command to be sent",
|
||||
omcOperate:{
|
||||
@@ -1276,6 +1277,7 @@ export default {
|
||||
noUDM: "No UDM network elements",
|
||||
},
|
||||
mmlSet: {
|
||||
operationtitle: "Interface Settings",
|
||||
saveText: "Save Settings",
|
||||
ipadd: "Listening to IP addresses",
|
||||
ipaddPlease: "Please enter the listening IP address",
|
||||
|
||||
@@ -1264,7 +1264,9 @@ export default {
|
||||
requireIpv6: "{display} 不是合法的IPV6地址",
|
||||
requireEnum: "{display} 不是合理的枚举值",
|
||||
requireBool: "{display} 不是合理的布尔类型的值",
|
||||
clearForm: "清除表单",
|
||||
cmdQuickEntry: "命令快速输入",
|
||||
cmdParamPanel: "参数面板",
|
||||
clearForm: "重置",
|
||||
clearLog: "清除日志",
|
||||
exec: "执行",
|
||||
cmdAwait: "等待发送命令",
|
||||
|
||||
@@ -11,7 +11,7 @@ import { getMMLByNE, sendMMlByNE } from '@/api/mmlManage/neOperate';
|
||||
const { t } = useI18n();
|
||||
|
||||
/**网元参数 */
|
||||
let neCascaderOtions = ref<Record<string, any>[]>([]);
|
||||
let neCascaderOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**对象信息状态类型 */
|
||||
type StateType = {
|
||||
@@ -25,6 +25,12 @@ type StateType = {
|
||||
mmlSelect: Record<string, any>;
|
||||
/**表单数据 */
|
||||
from: Record<string, any>;
|
||||
/**自动完成 input */
|
||||
autoCompleteValue: string;
|
||||
/**自动完成 options */
|
||||
autoCompleteData: any[];
|
||||
/**自动完成 options */
|
||||
autoCompleteSearch: any[];
|
||||
/**命令发送日志 */
|
||||
mmlCmdLog: string;
|
||||
};
|
||||
@@ -34,10 +40,19 @@ let state: StateType = reactive({
|
||||
neType: [],
|
||||
mmlNeType: '',
|
||||
mmlTreeData: [],
|
||||
mmlSelect: {},
|
||||
mmlSelect: {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
},
|
||||
from: {
|
||||
sendLoading: false,
|
||||
},
|
||||
autoCompleteValue: '',
|
||||
autoCompleteData: [],
|
||||
autoCompleteSearch: [],
|
||||
mmlCmdLog: '',
|
||||
});
|
||||
|
||||
@@ -45,6 +60,8 @@ let state: StateType = reactive({
|
||||
function fnTreeSelect(_: any, info: any) {
|
||||
state.mmlSelect = info.node.dataRef;
|
||||
state.from = {};
|
||||
state.autoCompleteValue =
|
||||
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
|
||||
// state.mmlCmdLog = '';
|
||||
}
|
||||
|
||||
@@ -55,6 +72,13 @@ function fnCleanCmdLog() {
|
||||
|
||||
/**清空表单 */
|
||||
function fnCleanFrom() {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
state.from = {};
|
||||
}
|
||||
|
||||
@@ -63,51 +87,64 @@ function fnSendMML() {
|
||||
if (state.from.sendLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cmdStr = '';
|
||||
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];
|
||||
if (operation && Array.isArray(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(t('views.mmlManage.require', { num: item.display }), 2);
|
||||
return;
|
||||
// 是否必填项且有效值
|
||||
const notV = value === null || value === undefined || value === '';
|
||||
if (item.optional === 'false' && notV) {
|
||||
message.warning(t('views.mmlManage.require', { num: 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]}`);
|
||||
}
|
||||
|
||||
// 检查是否存在值
|
||||
if (!Reflect.has(from, item.name) || notV) {
|
||||
continue;
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object} ${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
}
|
||||
|
||||
// 检查规则
|
||||
const [ok, msg] = ruleVerification(item, from[item.name]);
|
||||
if (!ok) {
|
||||
message.warning({
|
||||
content: `${msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
argsArr.push(`${item.name}=${from[item.name]}`);
|
||||
cmdStr = cmdStr.trim();
|
||||
}
|
||||
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object} ${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
if (cmdStr) {
|
||||
state.autoCompleteValue = cmdStr;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
let value = state.autoCompleteValue;
|
||||
if (value.indexOf('\n') !== -1) {
|
||||
value = value.replace(/(\r\n|\n)/g, ';');
|
||||
}
|
||||
cmdStr = value;
|
||||
}
|
||||
cmdStr = cmdStr.trim();
|
||||
|
||||
// 发送
|
||||
state.mmlCmdLog += `${cmdStr}\n`;
|
||||
@@ -215,7 +252,7 @@ function ruleVerification(
|
||||
break;
|
||||
|
||||
default:
|
||||
return [false, t('views.mmlManage.requireUn', { display })];
|
||||
console.warn(t('views.mmlManage.requireUn', { display }), type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -224,8 +261,16 @@ function ruleVerification(
|
||||
function fnNeChange(keys: any, _: any) {
|
||||
// 不是同类型时需要重新加载
|
||||
if (state.mmlNeType !== keys[0]) {
|
||||
state.autoCompleteSearch = [];
|
||||
state.autoCompleteData = [];
|
||||
state.mmlTreeData = [];
|
||||
state.mmlSelect = {};
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: {},
|
||||
};
|
||||
fnGetList();
|
||||
}
|
||||
}
|
||||
@@ -236,6 +281,8 @@ function fnGetList() {
|
||||
state.mmlNeType = neType;
|
||||
getMMLByNE(neType).then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
// 构建自动完成筛选结构
|
||||
const autoCompleteArr: Record<string, any>[] = [];
|
||||
// 构建树结构
|
||||
const treeArr: Record<string, any>[] = [];
|
||||
for (const item of res.data) {
|
||||
@@ -252,8 +299,8 @@ function fnGetList() {
|
||||
}
|
||||
|
||||
// 遍历检查大类
|
||||
const treeItem = treeArr.find(i => i.key == item['category']);
|
||||
if (!treeItem) {
|
||||
const treeItemIndex = treeArr.findIndex(i => i.key == item['category']);
|
||||
if (treeItemIndex < 0) {
|
||||
treeArr.push({
|
||||
title: item['catDisplay'],
|
||||
key: item['category'],
|
||||
@@ -262,17 +309,31 @@ function fnGetList() {
|
||||
{ key: id, title: mmlDisplay, object, operation, param },
|
||||
],
|
||||
});
|
||||
autoCompleteArr.push({
|
||||
value: item['catDisplay'],
|
||||
key: item['category'],
|
||||
selectable: false,
|
||||
options: [{ key: id, value: mmlDisplay, object, operation, param }],
|
||||
});
|
||||
} else {
|
||||
treeItem.children.push({
|
||||
treeArr[treeItemIndex].children.push({
|
||||
key: id,
|
||||
title: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
autoCompleteArr[treeItemIndex].options.push({
|
||||
key: id,
|
||||
value: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
}
|
||||
}
|
||||
state.mmlTreeData = treeArr;
|
||||
state.autoCompleteData = autoCompleteArr;
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.mmlManage.cmdNoTip', { num: neType }),
|
||||
@@ -282,6 +343,82 @@ function fnGetList() {
|
||||
});
|
||||
}
|
||||
|
||||
/**自动完成搜索匹配前缀 */
|
||||
function fnAutoCompleteSearch(value: string) {
|
||||
state.autoCompleteSearch = [];
|
||||
for (const item of state.autoCompleteData) {
|
||||
const filterOptions = item.options.filter((s: any) => {
|
||||
return `${s.operation} ${s.object}`.indexOf(value.toLowerCase()) >= 0;
|
||||
});
|
||||
if (filterOptions.length > 0) {
|
||||
state.autoCompleteSearch.push({
|
||||
value: item.value,
|
||||
key: item.value,
|
||||
selectable: false,
|
||||
options: filterOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteSelect(_: any, option: any) {
|
||||
state.mmlSelect = {
|
||||
title: option.value,
|
||||
key: option.key,
|
||||
operation: option.operation,
|
||||
object: option.object,
|
||||
param: option.param,
|
||||
};
|
||||
state.from = {};
|
||||
state.autoCompleteValue = `${option.operation} ${option.object}`.trim();
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteChange(value: any, _: any) {
|
||||
if (value.indexOf(';') !== -1 || value.indexOf('\n') !== -1) {
|
||||
fnCleanFrom();
|
||||
return;
|
||||
}
|
||||
for (const item of state.autoCompleteData) {
|
||||
const findItem = item.options.find((s: any) => {
|
||||
const prefix = `${s.operation} ${s.object}`;
|
||||
return value.startsWith(prefix);
|
||||
});
|
||||
if (findItem) {
|
||||
state.mmlSelect = {
|
||||
title: findItem.value,
|
||||
key: findItem.key,
|
||||
operation: findItem.operation,
|
||||
object: findItem.object,
|
||||
param: findItem.param,
|
||||
};
|
||||
state.from = {};
|
||||
// 截取拆分赋值
|
||||
const prefix = `${findItem.operation} ${findItem.object} `;
|
||||
const argsStr = value.replace(prefix, '');
|
||||
if (argsStr.length > 3) {
|
||||
const argsArr = argsStr.split(',');
|
||||
for (const arg of argsArr) {
|
||||
const kvArr = arg.split('=');
|
||||
if (kvArr.length >= 2) {
|
||||
state.from[kvArr[0]] = kvArr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
useNeInfoStore()
|
||||
@@ -290,18 +427,18 @@ onMounted(() => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
if (res.data.length > 0) {
|
||||
// 过滤不可用的网元
|
||||
neCascaderOtions.value = useNeInfoStore().getNeCascaderOtions.filter(
|
||||
neCascaderOptions.value = useNeInfoStore().getNeCascaderOtions.filter(
|
||||
(item: any) => {
|
||||
return !['OMC'].includes(item.value);
|
||||
}
|
||||
);
|
||||
// 默认选择AMF
|
||||
const item = neCascaderOtions.value.find(s => s.value === 'AMF');
|
||||
const item = neCascaderOptions.value.find(s => s.value === 'AMF');
|
||||
if (item && item.children) {
|
||||
const info = item.children[0];
|
||||
state.neType = [info.neType, info.neId];
|
||||
} else {
|
||||
const info = neCascaderOtions.value[0].children[0];
|
||||
const info = neCascaderOptions.value[0].children[0];
|
||||
state.neType = [info.neType, info.neId];
|
||||
}
|
||||
fnGetList();
|
||||
@@ -330,16 +467,18 @@ onMounted(() => {
|
||||
<a-form-item name="neType">
|
||||
<a-cascader
|
||||
v-model:value="state.neType"
|
||||
:options="neCascaderOtions"
|
||||
:options="neCascaderOptions"
|
||||
@change="fnNeChange"
|
||||
:allow-clear="false"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="listeningPort">
|
||||
<a-form-item name="mmlTree" v-if="state.mmlTreeData.length > 0">
|
||||
<a-directory-tree
|
||||
:tree-data="state.mmlTreeData"
|
||||
default-expand-all
|
||||
@select="fnTreeSelect"
|
||||
:selectedKeys="[state.mmlSelect.key]"
|
||||
></a-directory-tree>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@@ -347,11 +486,7 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :span="18">
|
||||
<!-- 命令参数输入 -->
|
||||
<a-card
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:loading="!state.mmlSelect.title"
|
||||
>
|
||||
<a-card size="small" :bordered="false">
|
||||
<template #title>
|
||||
<a-typography-text strong v-if="state.mmlSelect.title">
|
||||
{{ state.mmlSelect.title }}
|
||||
@@ -377,7 +512,6 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!state.mmlSelect.title"
|
||||
:loading="state.from.sendLoading"
|
||||
@click.prevent="fnSendMML"
|
||||
>
|
||||
@@ -395,58 +529,74 @@ onMounted(() => {
|
||||
: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="t('views.mmlManage.cmdQuickEntry')">
|
||||
<a-auto-complete
|
||||
v-model:value="state.autoCompleteValue"
|
||||
:dropdown-match-select-width="500"
|
||||
style="width: 100%"
|
||||
:options="state.autoCompleteSearch"
|
||||
@search="fnAutoCompleteSearch"
|
||||
@select="fnAutoCompleteSelect"
|
||||
@change="fnAutoCompleteChange"
|
||||
>
|
||||
<a-form-item
|
||||
:label="item.display"
|
||||
:name="item.name"
|
||||
:required="item.optional === 'false'"
|
||||
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
|
||||
</a-auto-complete>
|
||||
</a-form-item>
|
||||
|
||||
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.mmlManage.cmdParamPanel') }}
|
||||
</a-divider>
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
:lg="6"
|
||||
:md="12"
|
||||
:xs="24"
|
||||
v-for="item in state.mmlSelect.param"
|
||||
>
|
||||
<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]"
|
||||
></a-input>
|
||||
<a-input-number
|
||||
v-else-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
:min="0"
|
||||
:max="65535"
|
||||
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]"
|
||||
:allow-clear="true"
|
||||
>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
<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-number
|
||||
v-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
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]"
|
||||
:allow-clear="item.optional === 'true'"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="state.from[item.name]"
|
||||
></a-input>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
@@ -457,7 +607,7 @@ onMounted(() => {
|
||||
size="small"
|
||||
:body-style="{ padding: 0 }"
|
||||
style="margin-top: 16px"
|
||||
v-show="state.mmlSelect.title"
|
||||
v-show="state.mmlCmdLog"
|
||||
>
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
|
||||
@@ -11,20 +11,24 @@ import { getMMLByOMC, sendMMlByOMC } from '@/api/mmlManage/omcOperate';
|
||||
const { t } = useI18n();
|
||||
|
||||
/**网元参数 */
|
||||
let neOtions = ref<Record<string, any>[]>([]);
|
||||
let neOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**对象信息状态类型 */
|
||||
type StateType = {
|
||||
/**网元ID */
|
||||
neId: string;
|
||||
/**命令数据 loading */
|
||||
mmlLoading: boolean;
|
||||
/**命令数据 tree */
|
||||
mmlTreeData: any[];
|
||||
/**命令选中 */
|
||||
mmlSelect: Record<string, any>;
|
||||
/**表单数据 */
|
||||
from: Record<string, any>;
|
||||
/**自动完成 input */
|
||||
autoCompleteValue: string;
|
||||
/**自动完成 options */
|
||||
autoCompleteData: any[];
|
||||
/**自动完成 options */
|
||||
autoCompleteSearch: any[];
|
||||
/**命令发送日志 */
|
||||
mmlCmdLog: string;
|
||||
};
|
||||
@@ -32,12 +36,20 @@ type StateType = {
|
||||
/**对象信息状态 */
|
||||
let state: StateType = reactive({
|
||||
neId: '',
|
||||
mmlLoading: true,
|
||||
mmlTreeData: [],
|
||||
mmlSelect: {},
|
||||
mmlSelect: {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
},
|
||||
from: {
|
||||
sendLoading: false,
|
||||
},
|
||||
autoCompleteValue: '',
|
||||
autoCompleteData: [],
|
||||
autoCompleteSearch: [],
|
||||
mmlCmdLog: '',
|
||||
});
|
||||
|
||||
@@ -45,6 +57,8 @@ let state: StateType = reactive({
|
||||
function fnTreeSelect(_: any, info: any) {
|
||||
state.mmlSelect = info.node.dataRef;
|
||||
state.from = {};
|
||||
state.autoCompleteValue =
|
||||
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
|
||||
// state.mmlCmdLog = '';
|
||||
}
|
||||
|
||||
@@ -55,6 +69,13 @@ function fnCleanCmdLog() {
|
||||
|
||||
/**清空表单 */
|
||||
function fnCleanFrom() {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
state.from = {};
|
||||
}
|
||||
|
||||
@@ -63,51 +84,64 @@ function fnSendMML() {
|
||||
if (state.from.sendLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cmdStr = '';
|
||||
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];
|
||||
if (operation && Array.isArray(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(t('views.mmlManage.require', { num: item.display }), 2);
|
||||
return;
|
||||
// 是否必填项且有效值
|
||||
const notV = value === null || value === undefined || value === '';
|
||||
if (item.optional === 'false' && notV) {
|
||||
message.warning(t('views.mmlManage.require', { num: 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]}`);
|
||||
}
|
||||
|
||||
// 检查是否存在值
|
||||
if (!Reflect.has(from, item.name) || notV) {
|
||||
continue;
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object}:${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
}
|
||||
|
||||
// 检查规则
|
||||
const [ok, msg] = ruleVerification(item, from[item.name]);
|
||||
if (!ok) {
|
||||
message.warning({
|
||||
content: `${msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
argsArr.push(`${item.name}=${from[item.name]}`);
|
||||
cmdStr = cmdStr.trim();
|
||||
}
|
||||
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object}:${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
if (cmdStr) {
|
||||
state.autoCompleteValue = cmdStr;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
let value = state.autoCompleteValue;
|
||||
if (value.indexOf('\n') !== -1) {
|
||||
value = value.replace(/(\r\n|\n)/g, ';');
|
||||
}
|
||||
cmdStr = value;
|
||||
}
|
||||
cmdStr = cmdStr.trim();
|
||||
|
||||
// 发送
|
||||
state.mmlCmdLog += `${cmdStr}\n`;
|
||||
@@ -214,7 +248,7 @@ function ruleVerification(
|
||||
break;
|
||||
|
||||
default:
|
||||
return [false, t('views.mmlManage.requireUn', { display })];
|
||||
console.warn(t('views.mmlManage.requireUn', { display }), type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -223,6 +257,8 @@ function ruleVerification(
|
||||
function fnGetList() {
|
||||
getMMLByOMC().then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
// 构建自动完成筛选结构
|
||||
const autoCompleteArr: Record<string, any>[] = [];
|
||||
// 构建树结构
|
||||
const treeArr: Record<string, any>[] = [];
|
||||
for (const item of res.data) {
|
||||
@@ -239,8 +275,8 @@ function fnGetList() {
|
||||
}
|
||||
|
||||
// 遍历检查大类
|
||||
const treeItem = treeArr.find(i => i.key == item['category']);
|
||||
if (!treeItem) {
|
||||
const treeItemIndex = treeArr.findIndex(i => i.key == item['category']);
|
||||
if (treeItemIndex < 0) {
|
||||
treeArr.push({
|
||||
title: item['catDisplay'],
|
||||
key: item['category'],
|
||||
@@ -249,22 +285,116 @@ function fnGetList() {
|
||||
{ key: id, title: mmlDisplay, object, operation, param },
|
||||
],
|
||||
});
|
||||
autoCompleteArr.push({
|
||||
value: item['catDisplay'],
|
||||
key: item['category'],
|
||||
selectable: false,
|
||||
options: [{ key: id, value: mmlDisplay, object, operation, param }],
|
||||
});
|
||||
} else {
|
||||
treeItem.children.push({
|
||||
treeArr[treeItemIndex].children.push({
|
||||
key: id,
|
||||
title: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
autoCompleteArr[treeItemIndex].options.push({
|
||||
key: id,
|
||||
value: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
}
|
||||
}
|
||||
state.mmlTreeData = treeArr;
|
||||
state.autoCompleteData = autoCompleteArr;
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.mmlManage.cmdNoTip', { num: 'OMC' }),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
state.mmlLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**自动完成搜索匹配前缀 */
|
||||
function fnAutoCompleteSearch(value: string) {
|
||||
state.autoCompleteSearch = [];
|
||||
for (const item of state.autoCompleteData) {
|
||||
const filterOptions = item.options.filter((s: any) => {
|
||||
return `${s.operation} ${s.object}`.indexOf(value.toLowerCase()) >= 0;
|
||||
});
|
||||
if (filterOptions.length > 0) {
|
||||
state.autoCompleteSearch.push({
|
||||
value: item.value,
|
||||
key: item.value,
|
||||
selectable: false,
|
||||
options: filterOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteSelect(_: any, option: any) {
|
||||
state.mmlSelect = {
|
||||
title: option.value,
|
||||
key: option.key,
|
||||
operation: option.operation,
|
||||
object: option.object,
|
||||
param: option.param,
|
||||
};
|
||||
state.from = {};
|
||||
state.autoCompleteValue = `${option.operation} ${option.object}`.trim();
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteChange(value: any, _: any) {
|
||||
if (value.indexOf(';') !== -1 || value.indexOf('\n') !== -1) {
|
||||
fnCleanFrom();
|
||||
return;
|
||||
}
|
||||
for (const item of state.autoCompleteData) {
|
||||
const findItem = item.options.find((s: any) => {
|
||||
const prefix = `${s.operation} ${s.object}`;
|
||||
return value.startsWith(prefix);
|
||||
});
|
||||
if (findItem) {
|
||||
state.mmlSelect = {
|
||||
title: findItem.value,
|
||||
key: findItem.key,
|
||||
operation: findItem.operation,
|
||||
object: findItem.object,
|
||||
param: findItem.param,
|
||||
};
|
||||
state.from = {};
|
||||
// 截取拆分赋值
|
||||
const prefix = `${findItem.operation} ${findItem.object}:`;
|
||||
const argsStr = value.replace(prefix, '');
|
||||
if (argsStr.length > 3) {
|
||||
const argsArr = argsStr.split(',');
|
||||
for (const arg of argsArr) {
|
||||
const kvArr = arg.split('=');
|
||||
if (kvArr.length >= 2) {
|
||||
state.from[kvArr[0]] = kvArr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
useNeInfoStore()
|
||||
@@ -278,7 +408,7 @@ onMounted(() => {
|
||||
arr.push({ value: i.neId, label: i.neName });
|
||||
}
|
||||
});
|
||||
neOtions.value = arr;
|
||||
neOptions.value = arr;
|
||||
if (arr.length > 0) {
|
||||
state.neId = arr[0].value;
|
||||
// 获取列表数据
|
||||
@@ -309,20 +439,21 @@ onMounted(() => {
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:title="t('views.mmlManage.cmdTitle')"
|
||||
:loading="state.mmlLoading"
|
||||
>
|
||||
<a-form layout="vertical" autocomplete="off">
|
||||
<a-form-item name="neId ">
|
||||
<a-select
|
||||
v-model:value="state.neId"
|
||||
:options="neOtions"
|
||||
:options="neOptions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="listeningPort">
|
||||
<a-form-item name="mmlTree" v-if="state.mmlTreeData.length > 0">
|
||||
<a-directory-tree
|
||||
:tree-data="state.mmlTreeData"
|
||||
default-expand-all
|
||||
@select="fnTreeSelect"
|
||||
:selectedKeys="[state.mmlSelect.key]"
|
||||
></a-directory-tree>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@@ -330,11 +461,7 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :span="18">
|
||||
<!-- 命令参数输入 -->
|
||||
<a-card
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:loading="!state.mmlSelect.title"
|
||||
>
|
||||
<a-card size="small" :bordered="false">
|
||||
<template #title>
|
||||
<a-typography-text strong v-if="state.mmlSelect.title">
|
||||
{{ state.mmlSelect.title }}
|
||||
@@ -360,7 +487,6 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!state.mmlSelect.title"
|
||||
:loading="state.from.sendLoading"
|
||||
@click.prevent="fnSendMML"
|
||||
>
|
||||
@@ -378,58 +504,74 @@ onMounted(() => {
|
||||
: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="t('views.mmlManage.cmdQuickEntry')">
|
||||
<a-auto-complete
|
||||
v-model:value="state.autoCompleteValue"
|
||||
:dropdown-match-select-width="500"
|
||||
style="width: 100%"
|
||||
:options="state.autoCompleteSearch"
|
||||
@search="fnAutoCompleteSearch"
|
||||
@select="fnAutoCompleteSelect"
|
||||
@change="fnAutoCompleteChange"
|
||||
>
|
||||
<a-form-item
|
||||
:label="item.display"
|
||||
:name="item.name"
|
||||
:required="item.optional === 'false'"
|
||||
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
|
||||
</a-auto-complete>
|
||||
</a-form-item>
|
||||
|
||||
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.mmlManage.cmdParamPanel') }}
|
||||
</a-divider>
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
:lg="6"
|
||||
:md="12"
|
||||
:xs="24"
|
||||
v-for="item in state.mmlSelect.param"
|
||||
>
|
||||
<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]"
|
||||
></a-input>
|
||||
<a-input-number
|
||||
v-else-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
:min="0"
|
||||
:max="65535"
|
||||
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]"
|
||||
:allow-clear="true"
|
||||
>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
<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-number
|
||||
v-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
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]"
|
||||
:allow-clear="item.optional === 'true'"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="state.from[item.name]"
|
||||
></a-input>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
@@ -440,7 +582,7 @@ onMounted(() => {
|
||||
size="small"
|
||||
:body-style="{ padding: 0 }"
|
||||
style="margin-top: 16px"
|
||||
v-show="state.mmlSelect.title"
|
||||
v-show="state.mmlSelect.operation || state.autoCompleteValue"
|
||||
>
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
|
||||
@@ -11,20 +11,24 @@ import { getMMLByUDM, sendMMlByUDM } from '@/api/mmlManage/udmOperate';
|
||||
const { t } = useI18n();
|
||||
|
||||
/**网元参数 */
|
||||
let neOtions = ref<Record<string, any>[]>([]);
|
||||
let neOptions = ref<Record<string, any>[]>([]);
|
||||
|
||||
/**对象信息状态类型 */
|
||||
type StateType = {
|
||||
/**网元ID */
|
||||
neId: string;
|
||||
/**命令数据 loading */
|
||||
mmlLoading: boolean;
|
||||
/**命令数据 tree */
|
||||
mmlTreeData: any[];
|
||||
/**命令选中 */
|
||||
mmlSelect: Record<string, any>;
|
||||
/**表单数据 */
|
||||
from: Record<string, any>;
|
||||
/**自动完成 input */
|
||||
autoCompleteValue: string;
|
||||
/**自动完成 options */
|
||||
autoCompleteData: any[];
|
||||
/**自动完成 options */
|
||||
autoCompleteSearch: any[];
|
||||
/**命令发送日志 */
|
||||
mmlCmdLog: string;
|
||||
};
|
||||
@@ -32,12 +36,20 @@ type StateType = {
|
||||
/**对象信息状态 */
|
||||
let state: StateType = reactive({
|
||||
neId: '',
|
||||
mmlLoading: true,
|
||||
mmlTreeData: [],
|
||||
mmlSelect: {},
|
||||
mmlSelect: {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
},
|
||||
from: {
|
||||
sendLoading: false,
|
||||
},
|
||||
autoCompleteValue: '',
|
||||
autoCompleteData: [],
|
||||
autoCompleteSearch: [],
|
||||
mmlCmdLog: '',
|
||||
});
|
||||
|
||||
@@ -45,6 +57,8 @@ let state: StateType = reactive({
|
||||
function fnTreeSelect(_: any, info: any) {
|
||||
state.mmlSelect = info.node.dataRef;
|
||||
state.from = {};
|
||||
state.autoCompleteValue =
|
||||
`${state.mmlSelect.operation} ${state.mmlSelect.object}`.trim();
|
||||
// state.mmlCmdLog = '';
|
||||
}
|
||||
|
||||
@@ -55,6 +69,13 @@ function fnCleanCmdLog() {
|
||||
|
||||
/**清空表单 */
|
||||
function fnCleanFrom() {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
state.from = {};
|
||||
}
|
||||
|
||||
@@ -63,51 +84,64 @@ function fnSendMML() {
|
||||
if (state.from.sendLoading) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cmdStr = '';
|
||||
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];
|
||||
if (operation && Array.isArray(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(t('views.mmlManage.require', { num: item.display }), 2);
|
||||
return;
|
||||
// 是否必填项且有效值
|
||||
const notV = value === null || value === undefined || value === '';
|
||||
if (item.optional === 'false' && notV) {
|
||||
message.warning(t('views.mmlManage.require', { num: 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]}`);
|
||||
}
|
||||
|
||||
// 检查是否存在值
|
||||
if (!Reflect.has(from, item.name) || notV) {
|
||||
continue;
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object}:${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
}
|
||||
|
||||
// 检查规则
|
||||
const [ok, msg] = ruleVerification(item, from[item.name]);
|
||||
if (!ok) {
|
||||
message.warning({
|
||||
content: `${msg}`,
|
||||
duration: 3,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
argsArr.push(`${item.name}=${from[item.name]}`);
|
||||
cmdStr = cmdStr.trim();
|
||||
}
|
||||
|
||||
// 拼装命令
|
||||
const argsStr = argsArr.join(',');
|
||||
if (object && argsStr) {
|
||||
cmdStr = `${operation} ${object}:${argsStr}`;
|
||||
} else if (object) {
|
||||
cmdStr = `${operation} ${object}`;
|
||||
if (cmdStr) {
|
||||
state.autoCompleteValue = cmdStr;
|
||||
} else {
|
||||
cmdStr = `${operation} ${argsStr}`;
|
||||
let value = state.autoCompleteValue;
|
||||
if (value.indexOf('\n') !== -1) {
|
||||
value = value.replace(/(\r\n|\n)/g, ';');
|
||||
}
|
||||
cmdStr = value;
|
||||
}
|
||||
cmdStr = cmdStr.trim();
|
||||
|
||||
// 发送
|
||||
state.mmlCmdLog += `${cmdStr}\n`;
|
||||
@@ -214,7 +248,7 @@ function ruleVerification(
|
||||
break;
|
||||
|
||||
default:
|
||||
return [false, t('views.mmlManage.requireUn', { display })];
|
||||
console.warn(t('views.mmlManage.requireUn', { display }), type);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -223,6 +257,8 @@ function ruleVerification(
|
||||
function fnGetList() {
|
||||
getMMLByUDM().then(res => {
|
||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
|
||||
// 构建自动完成筛选结构
|
||||
const autoCompleteArr: Record<string, any>[] = [];
|
||||
// 构建树结构
|
||||
const treeArr: Record<string, any>[] = [];
|
||||
for (const item of res.data) {
|
||||
@@ -239,8 +275,8 @@ function fnGetList() {
|
||||
}
|
||||
|
||||
// 遍历检查大类
|
||||
const treeItem = treeArr.find(i => i.key == item['category']);
|
||||
if (!treeItem) {
|
||||
const treeItemIndex = treeArr.findIndex(i => i.key == item['category']);
|
||||
if (treeItemIndex < 0) {
|
||||
treeArr.push({
|
||||
title: item['catDisplay'],
|
||||
key: item['category'],
|
||||
@@ -249,22 +285,116 @@ function fnGetList() {
|
||||
{ key: id, title: mmlDisplay, object, operation, param },
|
||||
],
|
||||
});
|
||||
autoCompleteArr.push({
|
||||
value: item['catDisplay'],
|
||||
key: item['category'],
|
||||
selectable: false,
|
||||
options: [{ key: id, value: mmlDisplay, object, operation, param }],
|
||||
});
|
||||
} else {
|
||||
treeItem.children.push({
|
||||
treeArr[treeItemIndex].children.push({
|
||||
key: id,
|
||||
title: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
autoCompleteArr[treeItemIndex].options.push({
|
||||
key: id,
|
||||
value: mmlDisplay,
|
||||
object,
|
||||
operation,
|
||||
param,
|
||||
});
|
||||
}
|
||||
}
|
||||
state.mmlTreeData = treeArr;
|
||||
state.autoCompleteData = autoCompleteArr;
|
||||
} else {
|
||||
message.warning({
|
||||
content: t('views.mmlManage.cmdNoTip', { num: 'UDM' }),
|
||||
duration: 2,
|
||||
});
|
||||
}
|
||||
state.mmlLoading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/**自动完成搜索匹配前缀 */
|
||||
function fnAutoCompleteSearch(value: string) {
|
||||
state.autoCompleteSearch = [];
|
||||
for (const item of state.autoCompleteData) {
|
||||
const filterOptions = item.options.filter((s: any) => {
|
||||
return `${s.operation} ${s.object}`.indexOf(value.toLowerCase()) >= 0;
|
||||
});
|
||||
if (filterOptions.length > 0) {
|
||||
state.autoCompleteSearch.push({
|
||||
value: item.value,
|
||||
key: item.value,
|
||||
selectable: false,
|
||||
options: filterOptions,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteSelect(_: any, option: any) {
|
||||
state.mmlSelect = {
|
||||
title: option.value,
|
||||
key: option.key,
|
||||
operation: option.operation,
|
||||
object: option.object,
|
||||
param: option.param,
|
||||
};
|
||||
state.from = {};
|
||||
state.autoCompleteValue = `${option.operation} ${option.object}`.trim();
|
||||
}
|
||||
|
||||
/**自动完成搜索选择 */
|
||||
function fnAutoCompleteChange(value: any, _: any) {
|
||||
if (value.indexOf(';') !== -1 || value.indexOf('\n') !== -1) {
|
||||
fnCleanFrom();
|
||||
return;
|
||||
}
|
||||
for (const item of state.autoCompleteData) {
|
||||
const findItem = item.options.find((s: any) => {
|
||||
const prefix = `${s.operation} ${s.object}`;
|
||||
return value.startsWith(prefix);
|
||||
});
|
||||
if (findItem) {
|
||||
state.mmlSelect = {
|
||||
title: findItem.value,
|
||||
key: findItem.key,
|
||||
operation: findItem.operation,
|
||||
object: findItem.object,
|
||||
param: findItem.param,
|
||||
};
|
||||
state.from = {};
|
||||
// 截取拆分赋值
|
||||
const prefix = `${findItem.operation} ${findItem.object}:`;
|
||||
const argsStr = value.replace(prefix, '');
|
||||
if (argsStr.length > 3) {
|
||||
const argsArr = argsStr.split(',');
|
||||
for (const arg of argsArr) {
|
||||
const kvArr = arg.split('=');
|
||||
if (kvArr.length >= 2) {
|
||||
state.from[kvArr[0]] = kvArr[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
state.mmlSelect = {
|
||||
title: '',
|
||||
key: '',
|
||||
operation: '',
|
||||
object: '',
|
||||
param: [],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
// 获取网元网元列表
|
||||
useNeInfoStore()
|
||||
@@ -278,7 +408,7 @@ onMounted(() => {
|
||||
arr.push({ value: i.neId, label: i.neName });
|
||||
}
|
||||
});
|
||||
neOtions.value = arr;
|
||||
neOptions.value = arr;
|
||||
if (arr.length > 0) {
|
||||
state.neId = arr[0].value;
|
||||
// 获取列表数据
|
||||
@@ -309,20 +439,21 @@ onMounted(() => {
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:title="t('views.mmlManage.cmdTitle')"
|
||||
:loading="state.mmlLoading"
|
||||
>
|
||||
<a-form layout="vertical" autocomplete="off">
|
||||
<a-form-item name="neId ">
|
||||
<a-select
|
||||
v-model:value="state.neId"
|
||||
:options="neOtions"
|
||||
:options="neOptions"
|
||||
:placeholder="t('common.selectPlease')"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item name="listeningPort">
|
||||
<a-form-item name="mmlTree" v-if="state.mmlTreeData.length > 0">
|
||||
<a-directory-tree
|
||||
:tree-data="state.mmlTreeData"
|
||||
default-expand-all
|
||||
@select="fnTreeSelect"
|
||||
:selectedKeys="[state.mmlSelect.key]"
|
||||
></a-directory-tree>
|
||||
</a-form-item>
|
||||
</a-form>
|
||||
@@ -330,11 +461,7 @@ onMounted(() => {
|
||||
</a-col>
|
||||
<a-col :span="18">
|
||||
<!-- 命令参数输入 -->
|
||||
<a-card
|
||||
size="small"
|
||||
:bordered="false"
|
||||
:loading="!state.mmlSelect.title"
|
||||
>
|
||||
<a-card size="small" :bordered="false">
|
||||
<template #title>
|
||||
<a-typography-text strong v-if="state.mmlSelect.title">
|
||||
{{ state.mmlSelect.title }}
|
||||
@@ -360,7 +487,6 @@ onMounted(() => {
|
||||
<a-button
|
||||
type="primary"
|
||||
size="small"
|
||||
:disabled="!state.mmlSelect.title"
|
||||
:loading="state.from.sendLoading"
|
||||
@click.prevent="fnSendMML"
|
||||
>
|
||||
@@ -378,58 +504,74 @@ onMounted(() => {
|
||||
: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="t('views.mmlManage.cmdQuickEntry')">
|
||||
<a-auto-complete
|
||||
v-model:value="state.autoCompleteValue"
|
||||
:dropdown-match-select-width="500"
|
||||
style="width: 100%"
|
||||
:options="state.autoCompleteSearch"
|
||||
@search="fnAutoCompleteSearch"
|
||||
@select="fnAutoCompleteSelect"
|
||||
@change="fnAutoCompleteChange"
|
||||
>
|
||||
<a-form-item
|
||||
:label="item.display"
|
||||
:name="item.name"
|
||||
:required="item.optional === 'false'"
|
||||
<a-textarea :placeholder="t('common.ipnutPlease')" auto-size />
|
||||
</a-auto-complete>
|
||||
</a-form-item>
|
||||
{{ state.from }}
|
||||
<template v-if="state.mmlSelect.operation && state.mmlSelect.param">
|
||||
<a-divider orientation="left">
|
||||
{{ t('views.mmlManage.cmdParamPanel') }}
|
||||
</a-divider>
|
||||
<a-row :gutter="16">
|
||||
<a-col
|
||||
:lg="6"
|
||||
:md="12"
|
||||
:xs="24"
|
||||
v-for="item in state.mmlSelect.param"
|
||||
>
|
||||
<a-tooltip placement="topLeft">
|
||||
<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]"
|
||||
></a-input>
|
||||
<a-input-number
|
||||
v-else-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
:min="0"
|
||||
:max="65535"
|
||||
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]"
|
||||
:allow-clear="true"
|
||||
>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
<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-number
|
||||
v-if="item.type === 'int'"
|
||||
v-model:value="state.from[item.name]"
|
||||
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]"
|
||||
:allow-clear="item.optional === 'true'"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
<a-select-option
|
||||
:value="v"
|
||||
:key="v"
|
||||
v-for="(k, v) in JSON.parse(item.filter)"
|
||||
>
|
||||
{{ k }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
<a-input
|
||||
v-else
|
||||
v-model:value="state.from[item.name]"
|
||||
></a-input>
|
||||
</a-tooltip>
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
</template>
|
||||
</a-form>
|
||||
</a-card>
|
||||
|
||||
@@ -440,7 +582,7 @@ onMounted(() => {
|
||||
size="small"
|
||||
:body-style="{ padding: 0 }"
|
||||
style="margin-top: 16px"
|
||||
v-show="state.mmlSelect.title"
|
||||
v-show="state.mmlCmdLog"
|
||||
>
|
||||
<!-- 插槽-卡片右侧 -->
|
||||
<template #extra>
|
||||
|
||||
Reference in New Issue
Block a user