Files
fe.ems.vue3/src/views/tool/ping/index.vue
2024-10-17 15:05:21 +08:00

375 lines
10 KiB
Vue

<script setup lang="ts">
import { reactive, onMounted, onBeforeUnmount, ref, toRaw } from 'vue';
import { PageContainer } from 'antdv-pro-layout';
import { message } from 'ant-design-vue/lib';
import useI18n from '@/hooks/useI18n';
import {
RESULT_CODE_ERROR,
RESULT_CODE_SUCCESS,
} from '@/constants/result-constants';
import TerminalSSHView from '@/components/TerminalSSHView/index.vue';
import useNeInfoStore from '@/store/modules/neinfo';
import { pingV } from '@/api/tool/ping';
const neInfoStore = useNeInfoStore();
const { t } = useI18n();
/**网元参数 */
let neCascaderOptions = ref<Record<string, any>[]>([]);
/**状态对象 */
let state = reactive({
/**初始化 */
initialized: false,
/**运行中 */
running: false,
/**版本信息 */
versionInfo: '',
/**网元类型 */
neType: [],
/**数据类型 */
dataType: 'options' as 'options' | 'command',
/**ws参数 */
params: {
neType: '',
neId: '',
cols: 120,
rows: 40,
},
/**ws数据 */
data: {
command: '', // 命令字符串
desAddr: '8.8.8.8', // dns name or ip address
// Options
interval: 1, // seconds between sending each packet
ttl: 255, // define time to live
count: 4, // <count> 次回复后停止
size: 56, // 使用 <size> 作为要发送的数据字节数
timeout: 10, // seconds time to wait for response
},
});
/**连接发送 */
async function fnPing() {
const [neType, neId] = state.neType;
if (!neType || !neId) {
message.warning({
content: 'No Found NE Type',
duration: 2,
});
return;
}
if (state.dataType === 'options' && state.data.desAddr === '') {
message.warning({
content: 'Please fill in the Destination',
duration: 2,
});
return;
}
if (state.dataType === 'command' && state.data.command === '') {
message.warning({
content: 'Please fill in the Command',
duration: 2,
});
return;
}
if (state.initialized) {
fnResend();
return;
}
state.params.neType = neType;
state.params.neId = neId;
const resVersion = await pingV({ neType, neId });
if (resVersion.code !== RESULT_CODE_SUCCESS) {
message.warning({
content: 'No Found ping iputils',
duration: 2,
});
return;
} else {
state.versionInfo = resVersion.data;
}
state.initialized = true;
}
/**终端实例 */
const toolTerminal = ref();
/**重置并停止 */
function fnReset() {
if (!toolTerminal.value) return;
toolTerminal.value.ctrlC();
// toolTerminal.value.clear();
state.running = false;
}
/**重载发送 */
function fnResend() {
if (!toolTerminal.value) return;
state.running = true;
toolTerminal.value.ctrlC();
toolTerminal.value.clear();
setTimeout(() => {
const data = JSON.parse(JSON.stringify(state.data));
if (state.dataType === 'options') data.command = '';
toolTerminal.value.send('ping', data);
}, 1000);
}
/**终端初始连接*/
function fnConnect() {
fnResend();
}
/**终端消息监听*/
function fnMessage(res: Record<string, any>) {
const { code, requestId, data } = res;
if (code === RESULT_CODE_ERROR) {
console.warn(res.msg);
return;
}
if (!requestId) return;
let lestIndex = data.lastIndexOf('ping statistics ---');
if (lestIndex !== -1) {
state.running = false;
return;
}
lestIndex = data.lastIndexOf('failure');
if (lestIndex !== -1) {
state.running = false;
return;
}
}
/**钩子函数,界面打开初始化*/
onMounted(() => {
// 获取网元网元列表
neInfoStore.fnNelist().then(res => {
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.data)) {
if (res.data.length > 0) {
// 过滤不可用的网元
for (const item of neInfoStore.getNeCascaderOptions) {
neCascaderOptions.value.push(item);
}
if (neCascaderOptions.value.length === 0) {
message.warning({
content: t('common.noData'),
duration: 2,
});
return;
}
}
} else {
message.warning({
content: t('common.noData'),
duration: 2,
});
}
});
});
/**钩子函数,界面关闭*/
onBeforeUnmount(() => {});
</script>
<template>
<PageContainer>
<a-card :bordered="false" :body-style="{ padding: '0px' }">
<!-- 插槽-卡片左侧侧 -->
<template #title>
<a-space :size="8">
<span>
{{ t('views.ne.common.neType') }}:
<a-cascader
v-model:value="state.neType"
:options="neCascaderOptions"
:placeholder="t('common.selectPlease')"
:disabled="state.running"
/>
</span>
<a-radio-group
v-model:value="state.dataType"
button-style="solid"
:disabled="state.running"
>
<a-radio-button value="options">Options</a-radio-button>
<a-radio-button value="command">Command</a-radio-button>
</a-radio-group>
</a-space>
</template>
<!-- 插槽-卡片右侧 -->
<template #extra>
<a-space :size="8">
<a-button
@click.prevent="fnPing()"
type="primary"
:loading="state.running"
>
<template #icon><PlayCircleOutlined /></template>
{{ state.running ? 'Running' : 'Launch' }}
</a-button>
<a-button v-if="state.running" @click.prevent="fnReset()" danger>
<template #icon><CloseCircleOutlined /></template>
Stop
</a-button>
<!-- 版本信息 -->
<a-popover
trigger="click"
placement="bottomRight"
v-if="state.versionInfo"
>
<template #content>
{{ state.versionInfo }}
</template>
<InfoCircleOutlined />
</a-popover>
</a-space>
</template>
<!-- options -->
<a-form
v-if="state.dataType === 'options'"
:model="state.data"
name="queryParams"
layout="horizontal"
:label-col="{ span: 6 }"
:label-wrap="true"
style="padding: 12px"
>
<a-form-item
label="Destination"
name="desAddr"
help="dns name or ip address"
:label-col="{ span: 3 }"
:label-wrap="true"
>
<a-input
v-model:value="state.data.desAddr"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
>
</a-input>
</a-form-item>
<a-row :gutter="16">
<a-col :lg="12" :md="12" :xs="12">
<a-form-item
label="Interval"
name="Interval"
help="seconds between sending each packet"
>
<a-input-number
v-model:value="state.data.interval"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
:min="1"
:max="120"
>
</a-input-number>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="12">
<a-form-item label="TTL" name="ttl" help="define time to live">
<a-input-number
v-model:value="state.data.ttl"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
:min="1"
:max="255"
></a-input-number>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="12">
<a-form-item
label="Count"
name="count"
help="stop after <count> replies"
>
<a-input-number
v-model:value="state.data.count"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
:min="1"
:max="120"
></a-input-number>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="12">
<a-form-item
label="Size"
name="size"
help="use <size> as number of data bytes to be sent"
>
<a-input-number
v-model:value="state.data.size"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
:min="1"
:max="128"
></a-input-number>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :xs="12">
<a-form-item
label="Deadline"
name="timeout"
help="reply wait <deadline> in seconds"
>
<a-input-number
v-model:value="state.data.timeout"
:disabled="state.running"
allow-clear
:placeholder="t('common.inputPlease')"
style="width: 100%"
:min="1"
:max="60"
></a-input-number>
</a-form-item>
</a-col>
</a-row>
</a-form>
<!-- command -->
<div v-else style="padding: 12px">
<a-auto-complete
v-model:value="state.data.command"
:disabled="state.running"
:dropdown-match-select-width="500"
style="width: 100%"
>
<a-input addon-before="ping" placeholder="eg: -i 1 -c 4 8.8.8.8" />
</a-auto-complete>
</div>
<!-- 运行过程 -->
<TerminalSSHView
v-if="state.initialized"
ref="toolTerminal"
:id="`V${Date.now()}`"
prefix="ping"
url="/tool/ping/run"
:ne-type="state.params.neType"
:ne-id="state.params.neId"
:rows="state.params.rows"
:cols="state.params.cols"
style="height: 400px"
@connect="fnConnect"
@message="fnMessage"
></TerminalSSHView>
</a-card>
</PageContainer>
</template>
<style lang="less" scoped></style>