feat: 文本日志文件实时查看功能
This commit is contained in:
227
src/components/TerminalSSHView/index.vue
Normal file
227
src/components/TerminalSSHView/index.vue
Normal file
@@ -0,0 +1,227 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, onMounted, onBeforeUnmount, nextTick } from 'vue';
|
||||||
|
import { FitAddon } from '@xterm/addon-fit';
|
||||||
|
import { Terminal } from '@xterm/xterm';
|
||||||
|
import '@xterm/xterm/css/xterm.css';
|
||||||
|
import { RESULT_CODE_ERROR } from '@/constants/result-constants';
|
||||||
|
import { OptionsType, WS } from '@/plugins/ws-websocket';
|
||||||
|
const ws = new WS();
|
||||||
|
const emit = defineEmits(['connect', 'close', 'message']);
|
||||||
|
const props = defineProps({
|
||||||
|
/**终端ID,必传 */
|
||||||
|
id: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元类型,必传 */
|
||||||
|
neType: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元ID,必传 */
|
||||||
|
neId: {
|
||||||
|
type: String,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**窗口单行字符数 */
|
||||||
|
cols: {
|
||||||
|
type: Number,
|
||||||
|
default: 80,
|
||||||
|
},
|
||||||
|
/**窗口行数 */
|
||||||
|
rows: {
|
||||||
|
type: Number,
|
||||||
|
default: 40,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**终端输入DOM节点实例对象 */
|
||||||
|
const terminalDom = ref<HTMLElement | undefined>(undefined);
|
||||||
|
|
||||||
|
/**终端输入实例对象 */
|
||||||
|
const terminal = ref<any>(null);
|
||||||
|
|
||||||
|
/**终端输入渲染 */
|
||||||
|
function handleRanderXterm(container: HTMLElement | undefined) {
|
||||||
|
if (!container) return;
|
||||||
|
const xterm = new Terminal({
|
||||||
|
cols: props.cols,
|
||||||
|
rows: props.rows,
|
||||||
|
lineHeight: 1.2,
|
||||||
|
fontSize: 12,
|
||||||
|
fontFamily: "Monaco, Menlo, Consolas, 'Courier New', monospace",
|
||||||
|
theme: {
|
||||||
|
background: '#000000',
|
||||||
|
},
|
||||||
|
cursorBlink: true, // 光标闪烁
|
||||||
|
cursorStyle: 'block',
|
||||||
|
scrollback: 1000, // 设置历史缓冲区大小为 1000 行
|
||||||
|
scrollSensitivity: 15,
|
||||||
|
tabStopWidth: 4,
|
||||||
|
disableStdin: true, // 禁止输入
|
||||||
|
});
|
||||||
|
// 挂载
|
||||||
|
xterm.open(container);
|
||||||
|
// 自适应尺寸
|
||||||
|
const fitAddon = new FitAddon();
|
||||||
|
xterm.loadAddon(fitAddon);
|
||||||
|
// 终端尺寸变化触发
|
||||||
|
xterm.onResize(({ cols, rows }) => {
|
||||||
|
// console.log('尺寸', cols, rows);
|
||||||
|
ws.send({
|
||||||
|
requestId: `resize_${props.id}`,
|
||||||
|
type: 'resize',
|
||||||
|
data: { cols, rows },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建 ResizeObserver 实例
|
||||||
|
var observer = new ResizeObserver(entries => {
|
||||||
|
fitAddon.fit();
|
||||||
|
});
|
||||||
|
// 监听元素大小变化
|
||||||
|
observer.observe(container);
|
||||||
|
|
||||||
|
terminal.value = xterm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接打开后回调 */
|
||||||
|
function wsOpen(ev: any) {
|
||||||
|
// console.info('wsOpen', ev);
|
||||||
|
nextTick(() => {
|
||||||
|
handleRanderXterm(terminalDom.value);
|
||||||
|
// 连接事件
|
||||||
|
emit('connect', {
|
||||||
|
timeStamp: ev.timeStamp,
|
||||||
|
cols: terminal.value.cols,
|
||||||
|
rows: terminal.value.rows,
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
id: props.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接错误后回调 */
|
||||||
|
function wsError(ev: any) {
|
||||||
|
console.error('wsError', ev);
|
||||||
|
if (terminal.value != null) {
|
||||||
|
let message = 'disconnected';
|
||||||
|
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||||
|
} else if (terminalDom.value) {
|
||||||
|
terminalDom.value.style.background = '#000';
|
||||||
|
terminalDom.value.style.color = '#ff4d4f';
|
||||||
|
terminalDom.value.style.height = '60%';
|
||||||
|
terminalDom.value.innerText = 'disconnected';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**连接关闭后回调 */
|
||||||
|
function wsClose(code: number) {
|
||||||
|
// console.warn('wsClose', code);
|
||||||
|
if (terminal.value != null) {
|
||||||
|
let message = 'disconnected ' + code;
|
||||||
|
terminal.value.write(`\x1b[31m${message}\x1b[m\r\n`);
|
||||||
|
}
|
||||||
|
// 关闭事件
|
||||||
|
emit('close', {
|
||||||
|
code: code,
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
id: props.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**接收消息后回调 */
|
||||||
|
function wsMessage(res: Record<string, any>) {
|
||||||
|
emit('message', res);
|
||||||
|
// console.log('wsMessage', res);
|
||||||
|
const { code, requestId, data } = res;
|
||||||
|
if (code === RESULT_CODE_ERROR) {
|
||||||
|
console.warn(res.msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!requestId) return;
|
||||||
|
if (terminal.value != null) {
|
||||||
|
// 查找的开始输出标记
|
||||||
|
const parts: string[] = data.split('\u001b[?2004l\r');
|
||||||
|
if (parts.length > 0) {
|
||||||
|
let text = parts[parts.length - 1];
|
||||||
|
// 找到最后输出标记
|
||||||
|
const lestIndex = text.lastIndexOf('\u001b[?2004h\u001b]0;');
|
||||||
|
if (lestIndex !== -1) {
|
||||||
|
text = text.substring(0, lestIndex);
|
||||||
|
}
|
||||||
|
if (text === '' || text === '\r\n' || text.startsWith("^C\r\n") ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log({ parts, text });
|
||||||
|
terminal.value.write(text);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 无标记
|
||||||
|
terminal.value.write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.neType && props.neId) {
|
||||||
|
// 建立链接
|
||||||
|
const options: OptionsType = {
|
||||||
|
url: '/ws/view',
|
||||||
|
params: {
|
||||||
|
neType: props.neType,
|
||||||
|
neId: props.neId,
|
||||||
|
cols: props.cols,
|
||||||
|
rows: props.rows,
|
||||||
|
},
|
||||||
|
onmessage: wsMessage,
|
||||||
|
onerror: wsError,
|
||||||
|
onopen: wsOpen,
|
||||||
|
onclose: wsClose,
|
||||||
|
};
|
||||||
|
ws.connect(options);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
ws.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 给组件设置属性 ref="xxxTerminal"
|
||||||
|
// setup内使用 const xxxTerminal = ref();
|
||||||
|
defineExpose({
|
||||||
|
/**清除 */
|
||||||
|
clear: () => {
|
||||||
|
if (terminal.value != null) {
|
||||||
|
terminal.value.clear();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
/**发送命令 */
|
||||||
|
send: (type: string, data: Record<string, any>) => {
|
||||||
|
ws.send({
|
||||||
|
requestId: `ssh_${props.id}`,
|
||||||
|
type,
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
/**模拟按下 Ctrl+C */
|
||||||
|
ctrlC: () => {
|
||||||
|
ws.send({
|
||||||
|
requestId: `ssh_${props.id}`,
|
||||||
|
type: 'ctrl-c',
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div ref="terminalDom" :id="id" class="terminal"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="css" scoped>
|
||||||
|
.terminal {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1258,6 +1258,11 @@ export default {
|
|||||||
downTip: "Confirm the download file name is [{fileName}] File?",
|
downTip: "Confirm the download file name is [{fileName}] File?",
|
||||||
downTipErr: "Failed to get file",
|
downTipErr: "Failed to get file",
|
||||||
dirCd: "Enter Dir",
|
dirCd: "Enter Dir",
|
||||||
|
viewAs: 'View Action',
|
||||||
|
reload: "Reload",
|
||||||
|
follow: 'Monitoring Content',
|
||||||
|
tailChar: 'End Characters',
|
||||||
|
tailLines: 'End Lines',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
|
|||||||
@@ -1258,6 +1258,11 @@ export default {
|
|||||||
downTip: "确认下载文件名为 【{fileName}】 文件?",
|
downTip: "确认下载文件名为 【{fileName}】 文件?",
|
||||||
downTipErr: "文件获取失败",
|
downTipErr: "文件获取失败",
|
||||||
dirCd: "进入目录",
|
dirCd: "进入目录",
|
||||||
|
viewAs: '查看操作',
|
||||||
|
reload: "重载",
|
||||||
|
follow: '监视内容变化',
|
||||||
|
tailChar: '末尾字数',
|
||||||
|
tailLines: '末尾行数',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
monitor: {
|
monitor: {
|
||||||
|
|||||||
174
src/views/logManage/neFile/components/ViewDrawer.vue
Normal file
174
src/views/logManage/neFile/components/ViewDrawer.vue
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { reactive, onMounted, watch, ref, nextTick } from 'vue';
|
||||||
|
import { ProModal } from 'antdv-pro-modal';
|
||||||
|
import TerminalSSHView from '@/components/TerminalSSHView/index.vue';
|
||||||
|
import useI18n from '@/hooks/useI18n';
|
||||||
|
const { t } = useI18n();
|
||||||
|
const emit = defineEmits(['ok', 'cancel', 'update:visible']);
|
||||||
|
const props = defineProps({
|
||||||
|
visible: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**文件地址 */
|
||||||
|
filePath: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元类型 */
|
||||||
|
neType: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
/**网元ID */
|
||||||
|
neId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/**对话框对象信息状态类型 */
|
||||||
|
type StateType = {
|
||||||
|
/**框是否显示 */
|
||||||
|
visible: boolean;
|
||||||
|
/**标题 */
|
||||||
|
title: string;
|
||||||
|
/**查看命令 */
|
||||||
|
form: Record<string, any>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**对话框对象信息状态 */
|
||||||
|
let state: StateType = reactive({
|
||||||
|
visible: false,
|
||||||
|
title: '文件查看',
|
||||||
|
form: {
|
||||||
|
follow: true,
|
||||||
|
showType: 'lines', // lines/char
|
||||||
|
lines: 10,
|
||||||
|
char: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
function onClose() {
|
||||||
|
state.visible = false;
|
||||||
|
emit('cancel');
|
||||||
|
emit('update:visible', false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**监听是否显示,初始数据 */
|
||||||
|
watch(
|
||||||
|
() => props.visible,
|
||||||
|
val => {
|
||||||
|
if (val) {
|
||||||
|
if (props.neType && props.neId) {
|
||||||
|
const filePath = props.filePath;
|
||||||
|
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
|
||||||
|
state.title = fileName;
|
||||||
|
state.visible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**终端实例 */
|
||||||
|
const viewTerminal = ref();
|
||||||
|
|
||||||
|
/**终端初始连接 */
|
||||||
|
function fnInit() {
|
||||||
|
setTimeout(fnReload, 1_500);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**重载查看方式 */
|
||||||
|
function fnReload() {
|
||||||
|
if (!viewTerminal.value) return;
|
||||||
|
viewTerminal.value.ctrlC();
|
||||||
|
|
||||||
|
if (state.form.showType !== 'lines') {
|
||||||
|
state.form.lines = 10;
|
||||||
|
} else {
|
||||||
|
state.form.char = 0;
|
||||||
|
}
|
||||||
|
viewTerminal.value.clear();
|
||||||
|
viewTerminal.value.send('tail', {
|
||||||
|
filePath: props.filePath,
|
||||||
|
lines: state.form.lines,
|
||||||
|
char: state.form.char,
|
||||||
|
follow: state.form.follow,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<ProModal
|
||||||
|
:drag="true"
|
||||||
|
:fullscreen="true"
|
||||||
|
:borderDraw="true"
|
||||||
|
:min-width="800"
|
||||||
|
:min-height="500"
|
||||||
|
:center-y="true"
|
||||||
|
:destroyOnClose="true"
|
||||||
|
:keyboard="false"
|
||||||
|
:mask-closable="false"
|
||||||
|
:visible="state.visible"
|
||||||
|
:title="state.title"
|
||||||
|
:body-style="{ padding: '12px', overflow: 'hidden' }"
|
||||||
|
:footer="null"
|
||||||
|
@cancel="onClose"
|
||||||
|
>
|
||||||
|
<TerminalSSHView
|
||||||
|
ref="viewTerminal"
|
||||||
|
:id="`V${Date.now()}`"
|
||||||
|
style="height: calc(100% - 36px)"
|
||||||
|
:ne-type="neType"
|
||||||
|
:ne-id="neId"
|
||||||
|
@connect="fnInit()"
|
||||||
|
></TerminalSSHView>
|
||||||
|
<!-- 命令控制属性 -->
|
||||||
|
<a-form name="form" layout="horizontal">
|
||||||
|
<a-row :gutter="16">
|
||||||
|
<a-col :lg="12" :md="12" :xs="24">
|
||||||
|
<a-form-item :label="t('views.logManage.neFile.viewAs')">
|
||||||
|
<a-input-group compact>
|
||||||
|
<a-select v-model:value="state.form.showType" style="width: 50%">
|
||||||
|
<a-select-option value="lines">
|
||||||
|
{{ t('views.logManage.neFile.tailLines') }}
|
||||||
|
</a-select-option>
|
||||||
|
<a-select-option value="char">
|
||||||
|
{{ t('views.logManage.neFile.tailChar') }}
|
||||||
|
</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
<a-input-number
|
||||||
|
style="width: 25%"
|
||||||
|
v-model:value="state.form[state.form.showType]"
|
||||||
|
:min="0"
|
||||||
|
:max="1000"
|
||||||
|
:placeholder="t('common.inputPlease')"
|
||||||
|
></a-input-number>
|
||||||
|
<a-button type="primary" style="width: 25%" @click="fnReload()">
|
||||||
|
{{ t('views.logManage.neFile.reload') }}
|
||||||
|
</a-button>
|
||||||
|
</a-input-group>
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
<a-col :lg="6" :md="12" :xs="24">
|
||||||
|
<a-form-item
|
||||||
|
:label="t('views.logManage.neFile.follow')"
|
||||||
|
name="follow"
|
||||||
|
>
|
||||||
|
<a-switch v-model:checked="state.form.follow" />
|
||||||
|
</a-form-item>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</a-form>
|
||||||
|
</ProModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
.ant-form :deep(.ant-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,12 +3,13 @@ import { reactive, ref, onMounted, toRaw } from 'vue';
|
|||||||
import { PageContainer } from 'antdv-pro-layout';
|
import { PageContainer } from 'antdv-pro-layout';
|
||||||
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
import { SizeType } from 'ant-design-vue/lib/config-provider';
|
||||||
import { ColumnsType } from 'ant-design-vue/lib/table';
|
import { ColumnsType } from 'ant-design-vue/lib/table';
|
||||||
|
import { Modal, message } from 'ant-design-vue/lib';
|
||||||
import { parseDateToStr } from '@/utils/date-utils';
|
import { parseDateToStr } from '@/utils/date-utils';
|
||||||
import { getNeFile, listNeFiles } from '@/api/tool/neFile';
|
import { getNeFile, listNeFiles } from '@/api/tool/neFile';
|
||||||
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
import { RESULT_CODE_SUCCESS } from '@/constants/result-constants';
|
||||||
import useNeInfoStore from '@/store/modules/neinfo';
|
import useNeInfoStore from '@/store/modules/neinfo';
|
||||||
import useI18n from '@/hooks/useI18n';
|
import useI18n from '@/hooks/useI18n';
|
||||||
import { Modal, message } from 'ant-design-vue/lib';
|
import ViewDrawer from './components/ViewDrawer.vue';
|
||||||
import saveAs from 'file-saver';
|
import saveAs from 'file-saver';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
const neInfoStore = useNeInfoStore();
|
const neInfoStore = useNeInfoStore();
|
||||||
@@ -19,11 +20,7 @@ const route = useRoute();
|
|||||||
const routeParams = route.query as Record<string, any>;
|
const routeParams = route.query as Record<string, any>;
|
||||||
|
|
||||||
/**网元参数 */
|
/**网元参数 */
|
||||||
let neType = ref<string[]>([]);
|
let neTypeSelect = ref<string[]>([]);
|
||||||
/**下载触发等待 */
|
|
||||||
let loading = ref(false);
|
|
||||||
/**访问路径 */
|
|
||||||
let nePathArr = ref<string[]>([]);
|
|
||||||
|
|
||||||
/**查询参数 */
|
/**查询参数 */
|
||||||
let queryParams = reactive({
|
let queryParams = reactive({
|
||||||
@@ -134,14 +131,17 @@ let tablePagination = reactive({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**下载触发等待 */
|
||||||
|
let downLoading = ref<boolean>(false);
|
||||||
|
|
||||||
/**信息文件下载 */
|
/**信息文件下载 */
|
||||||
function fnDownloadFile(row: Record<string, any>) {
|
function fnDownloadFile(row: Record<string, any>) {
|
||||||
if (loading.value) return;
|
if (downLoading.value) return;
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
title: t('common.tipTitle'),
|
title: t('common.tipTitle'),
|
||||||
content: t('views.logManage.neFile.downTip', { fileName: row.fileName }),
|
content: t('views.logManage.neFile.downTip', { fileName: row.fileName }),
|
||||||
onOk() {
|
onOk() {
|
||||||
loading.value = true;
|
downLoading.value = true;
|
||||||
const hide = message.loading(t('common.loading'), 0);
|
const hide = message.loading(t('common.loading'), 0);
|
||||||
getNeFile({
|
getNeFile({
|
||||||
neType: queryParams.neType,
|
neType: queryParams.neType,
|
||||||
@@ -167,12 +167,15 @@ function fnDownloadFile(row: Record<string, any>) {
|
|||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
hide();
|
hide();
|
||||||
loading.value = false;
|
downLoading.value = false;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**访问路径 */
|
||||||
|
let nePathArr = ref<string[]>([]);
|
||||||
|
|
||||||
/**进入目录 */
|
/**进入目录 */
|
||||||
function fnDirCD(dir: string, index?: number) {
|
function fnDirCD(dir: string, index?: number) {
|
||||||
if (index === undefined) {
|
if (index === undefined) {
|
||||||
@@ -235,15 +238,42 @@ function fnGetList(pageNum?: number) {
|
|||||||
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
if (res.code === RESULT_CODE_SUCCESS && Array.isArray(res.rows)) {
|
||||||
tablePagination.total = res.total;
|
tablePagination.total = res.total;
|
||||||
tableState.data = res.rows;
|
tableState.data = res.rows;
|
||||||
if (tablePagination.total <=(queryParams.pageNum - 1) * tablePagination.pageSize &&queryParams.pageNum !== 1) {
|
if (
|
||||||
|
tablePagination.total <=
|
||||||
|
(queryParams.pageNum - 1) * tablePagination.pageSize &&
|
||||||
|
queryParams.pageNum !== 1
|
||||||
|
) {
|
||||||
tableState.loading = false;
|
tableState.loading = false;
|
||||||
fnGetList(queryParams.pageNum - 1);
|
fnGetList(queryParams.pageNum - 1);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
message.error(res.msg, 3);
|
||||||
|
tablePagination.total = 0;
|
||||||
|
tableState.data = [];
|
||||||
}
|
}
|
||||||
tableState.loading = false;
|
tableState.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**抽屉状态 */
|
||||||
|
const viewDrawerState = reactive({
|
||||||
|
visible: false,
|
||||||
|
/**文件路径 /var/log/amf.log */
|
||||||
|
filePath: '',
|
||||||
|
/**网元类型 */
|
||||||
|
neType: '',
|
||||||
|
/**网元ID */
|
||||||
|
neId: '',
|
||||||
|
});
|
||||||
|
|
||||||
|
/**打开抽屉查看 */
|
||||||
|
function fnDrawerOpen(row: Record<string, any>) {
|
||||||
|
viewDrawerState.filePath = [...nePathArr.value, row.fileName].join('/');
|
||||||
|
viewDrawerState.neType = neTypeSelect.value[0];
|
||||||
|
viewDrawerState.neId = neTypeSelect.value[1];
|
||||||
|
viewDrawerState.visible = !viewDrawerState.visible;
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// 获取网元网元列表
|
// 获取网元网元列表
|
||||||
neInfoStore.fnNelist().then(res => {
|
neInfoStore.fnNelist().then(res => {
|
||||||
@@ -254,8 +284,8 @@ onMounted(() => {
|
|||||||
duration: 2,
|
duration: 2,
|
||||||
});
|
});
|
||||||
} else if (routeParams.neType) {
|
} else if (routeParams.neType) {
|
||||||
neType.value = [routeParams.neType, routeParams.neId]
|
neTypeSelect.value = [routeParams.neType, routeParams.neId];
|
||||||
fnNeChange(neType.value, undefined);
|
fnNeChange(neTypeSelect.value, undefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -276,12 +306,12 @@ onMounted(() => {
|
|||||||
style="margin-bottom: 0"
|
style="margin-bottom: 0"
|
||||||
>
|
>
|
||||||
<a-cascader
|
<a-cascader
|
||||||
v-model:value="neType"
|
v-model:value="neTypeSelect"
|
||||||
:options="neInfoStore.getNeCascaderOptions"
|
:options="neInfoStore.getNeCascaderOptions"
|
||||||
@change="fnNeChange"
|
@change="fnNeChange"
|
||||||
:allow-clear="false"
|
:allow-clear="false"
|
||||||
:placeholder="t('views.logManage.neFile.neTypePlease')"
|
:placeholder="t('views.logManage.neFile.neTypePlease')"
|
||||||
:disabled="loading || tableState.loading"
|
:disabled="downLoading || tableState.loading"
|
||||||
/>
|
/>
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-col>
|
</a-col>
|
||||||
@@ -332,8 +362,15 @@ onMounted(() => {
|
|||||||
<template #bodyCell="{ column, record }">
|
<template #bodyCell="{ column, record }">
|
||||||
<template v-if="column.key === 'fileName'">
|
<template v-if="column.key === 'fileName'">
|
||||||
<a-space :size="8" align="center">
|
<a-space :size="8" align="center">
|
||||||
|
<a-tooltip v-if="record.fileType === 'file'">
|
||||||
|
<template #title>{{ t('common.viewText') }}</template>
|
||||||
|
<a-button type="link" @click.prevent="fnDrawerOpen(record)">
|
||||||
|
<template #icon><ProfileOutlined /></template>
|
||||||
|
</a-button>
|
||||||
|
</a-tooltip>
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
|
:loading="downLoading"
|
||||||
@click.prevent="fnDownloadFile(record)"
|
@click.prevent="fnDownloadFile(record)"
|
||||||
v-if="record.fileType === 'file'"
|
v-if="record.fileType === 'file'"
|
||||||
>
|
>
|
||||||
@@ -342,6 +379,7 @@ onMounted(() => {
|
|||||||
</a-button>
|
</a-button>
|
||||||
<a-button
|
<a-button
|
||||||
type="link"
|
type="link"
|
||||||
|
:loading="downLoading"
|
||||||
@click.prevent="fnDirCD(record.fileName)"
|
@click.prevent="fnDirCD(record.fileName)"
|
||||||
v-if="record.fileType === 'dir'"
|
v-if="record.fileType === 'dir'"
|
||||||
>
|
>
|
||||||
@@ -353,6 +391,14 @@ onMounted(() => {
|
|||||||
</template>
|
</template>
|
||||||
</a-table>
|
</a-table>
|
||||||
</a-card>
|
</a-card>
|
||||||
|
|
||||||
|
<!-- 文件内容查看抽屉 -->
|
||||||
|
<ViewDrawer
|
||||||
|
v-model:visible="viewDrawerState.visible"
|
||||||
|
:file-path="viewDrawerState.filePath"
|
||||||
|
:ne-type="viewDrawerState.neType"
|
||||||
|
:ne-id="viewDrawerState.neId"
|
||||||
|
></ViewDrawer>
|
||||||
</PageContainer>
|
</PageContainer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user