🔨 修改日志查看逻辑.
This commit is contained in:
@@ -65,17 +65,18 @@ export const LogAppenderOptions: ITerminalOptions & ITerminalInitOnlyOptions = {
|
||||
fontFamily: defaultFontFamily,
|
||||
};
|
||||
|
||||
// dom 引用
|
||||
export interface LogDomRef {
|
||||
// append 配置
|
||||
export interface LogAppenderConfig {
|
||||
id: number;
|
||||
el: HTMLElement;
|
||||
openSearch: () => {};
|
||||
type: ExecType;
|
||||
scrollLines: number;
|
||||
}
|
||||
|
||||
// appender 配置
|
||||
export interface LogAppenderConf {
|
||||
// appender 视口
|
||||
export interface LogAppenderView {
|
||||
id: number;
|
||||
el: HTMLElement;
|
||||
opened: boolean;
|
||||
openSearch: () => {};
|
||||
terminal: Terminal;
|
||||
addons: XtermAddons;
|
||||
@@ -84,7 +85,10 @@ export interface LogAppenderConf {
|
||||
// 执行日志 appender 定义
|
||||
export interface ILogAppender {
|
||||
// 初始化
|
||||
init(refs: Array<LogDomRef>): Promise<void>;
|
||||
init(refs: Array<LogAppenderView>): Promise<void>;
|
||||
|
||||
// 打开日志
|
||||
openLog(id: number): void;
|
||||
|
||||
// 设置当前元素
|
||||
setCurrent(id: number): void;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<exec-host class="exec-host-container"
|
||||
:visibleBack="visibleBack"
|
||||
:current="currentHostExecId"
|
||||
:hosts="execLog.hosts"
|
||||
:hosts="execLog.hosts as any"
|
||||
@selected="selectedHost"
|
||||
@back="emits('back')" />
|
||||
<!-- 日志容器 -->
|
||||
@@ -13,7 +13,8 @@
|
||||
:type="type"
|
||||
:current="currentHostExecId"
|
||||
:exec-log="execLog"
|
||||
:appender="appender" />
|
||||
:appender="appender"
|
||||
@ready="openLog(currentHostExecId)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -30,7 +31,8 @@
|
||||
import { getExecCommandLogStatus } from '@/api/exec/exec-command-log';
|
||||
import { getExecJobLogStatus } from '@/api/exec/exec-job-log';
|
||||
import { dictKeys, ExecHostStatus, ExecStatus } from '../const';
|
||||
import { useDictStore } from '@/store';
|
||||
import { useCacheStore, useDictStore } from '@/store';
|
||||
import { toAnonymousNumber } from '@/utils';
|
||||
import ExecHost from './exec-host.vue';
|
||||
import LogView from './log-view.vue';
|
||||
import LogAppender from './log-appender';
|
||||
@@ -43,16 +45,24 @@
|
||||
const emits = defineEmits(['back']);
|
||||
|
||||
const logViewRef = ref();
|
||||
const currentHostExecId = ref();
|
||||
const currentHostExecId = ref(0);
|
||||
const pullIntervalId = ref();
|
||||
const execLog = ref<ExecLogQueryResponse>();
|
||||
const appender = ref<ILogAppender>();
|
||||
|
||||
// 打开
|
||||
const open = (record: ExecLogQueryResponse) => {
|
||||
appender.value = new LogAppender(props.type, { execId: record.id });
|
||||
execLog.value = record;
|
||||
const open = async (record: ExecLogQueryResponse) => {
|
||||
execLog.value = { ...record };
|
||||
currentHostExecId.value = record.hosts[0].id;
|
||||
// 获取最大显示行数
|
||||
const { log_webScrollLines } = await useCacheStore().loadSystemSetting();
|
||||
const scrollLines = toAnonymousNumber(log_webScrollLines) || 1000;
|
||||
// 创建 appender
|
||||
appender.value = new LogAppender({
|
||||
id: record.id,
|
||||
type: props.type,
|
||||
scrollLines,
|
||||
});
|
||||
// 定时查询执行状态
|
||||
if (record.status === ExecStatus.WAITING ||
|
||||
record.status === ExecStatus.RUNNING) {
|
||||
@@ -88,55 +98,45 @@
|
||||
execLog.value.finishTime = logList[0].finishTime;
|
||||
}
|
||||
// 设置主机状态
|
||||
for (let host of execLog.value.hosts) {
|
||||
const hostStatus = hostList.find(s => s.id === host.id);
|
||||
if (hostStatus) {
|
||||
host.status = hostStatus.status;
|
||||
host.startTime = hostStatus.startTime;
|
||||
for (let hostRow of hostList) {
|
||||
const execLogHost = execLog.value.hosts.find(s => s.id === hostRow.id);
|
||||
if (execLogHost) {
|
||||
execLogHost.status = hostRow.status;
|
||||
execLogHost.startTime = hostRow.startTime;
|
||||
// 结束时间绑定了使用时间 如果未完成则使用当前时间
|
||||
host.finishTime = hostStatus.finishTime || Date.now();
|
||||
host.exitCode = hostStatus.exitCode;
|
||||
host.errorMessage = hostStatus.errorMessage;
|
||||
execLogHost.finishTime = hostRow.finishTime || Date.now();
|
||||
execLogHost.exitCode = hostRow.exitCode;
|
||||
execLogHost.errorMessage = hostRow.errorMessage;
|
||||
}
|
||||
// 当前选中主机非等待状态则打开日志
|
||||
if (hostRow.id === currentHostExecId.value) {
|
||||
openLog(hostRow.id);
|
||||
}
|
||||
}
|
||||
// 已完成跳过
|
||||
// 已完成关闭轮询
|
||||
if (execLog.value.status === ExecStatus.COMPLETED ||
|
||||
execLog.value.status === ExecStatus.FAILED) {
|
||||
closeClient();
|
||||
clearAllInterval();
|
||||
}
|
||||
};
|
||||
|
||||
// 设置完成时间
|
||||
const setTaskFinishTime = () => {
|
||||
const hosts = execLog.value?.hosts;
|
||||
if (!hosts) {
|
||||
return;
|
||||
}
|
||||
hosts.forEach(s => {
|
||||
// 未完成自动设置完成时间为当前时间 用于展示使用时间
|
||||
if (s.status === ExecHostStatus.WAITING ||
|
||||
s.status === ExecHostStatus.RUNNING) {
|
||||
if (!s.startTime) {
|
||||
s.startTime = Date.now();
|
||||
}
|
||||
s.finishTime = Date.now();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
// 选中主机
|
||||
const selectedHost = (hostId: number) => {
|
||||
currentHostExecId.value = hostId;
|
||||
const selectedHost = (id: number) => {
|
||||
currentHostExecId.value = id;
|
||||
// 打开日志
|
||||
openLog(id);
|
||||
};
|
||||
|
||||
// 关闭连接
|
||||
const closeClient = () => {
|
||||
// 清理轮询
|
||||
clearAllInterval();
|
||||
// 关闭 client
|
||||
appender.value?.closeClient();
|
||||
// 打开日志
|
||||
const openLog = (id: number) => {
|
||||
// 获取状态
|
||||
const status = execLog.value?.hosts.find(s => s.id === id)?.status;
|
||||
if (status && status !== ExecHostStatus.WAITING) {
|
||||
// 打开日志
|
||||
appender.value?.openLog(id);
|
||||
}
|
||||
};
|
||||
|
||||
// 清理并且关闭
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import type { ExecType, ILogAppender, LogAppenderConf, LogDomRef } from '../const';
|
||||
import type { ILogAppender, LogAppenderConfig, LogAppenderView } from '../const';
|
||||
import { LogAppenderOptions } from '../const';
|
||||
import type { XtermAddons } from '@/types/xterm';
|
||||
import type { ExecLogTailRequest } from '@/api/exec/exec-log';
|
||||
import { openExecLogChannel } from '@/api/exec/exec-log';
|
||||
import { getExecCommandLogTailToken } from '@/api/exec/exec-command-log';
|
||||
import { getExecJobLogTailToken } from '@/api/exec/exec-job-log';
|
||||
@@ -19,58 +18,58 @@ import { Unicode11Addon } from '@xterm/addon-unicode11';
|
||||
// 执行日志 appender 实现
|
||||
export default class LogAppender implements ILogAppender {
|
||||
|
||||
private current: LogAppenderConf;
|
||||
private current: LogAppenderView;
|
||||
|
||||
private client?: WebSocket;
|
||||
|
||||
private readonly config: ExecLogTailRequest;
|
||||
private readonly appenderViews: Record<string, LogAppenderView>;
|
||||
|
||||
private readonly appenderRel: Record<string, LogAppenderConf>;
|
||||
private readonly config: LogAppenderConfig;
|
||||
|
||||
private keepAliveTask?: number;
|
||||
|
||||
private readonly fitAllFn: () => {};
|
||||
private readonly fitAllFn: () => void;
|
||||
|
||||
private readonly type: ExecType;
|
||||
|
||||
constructor(type: ExecType, config: ExecLogTailRequest) {
|
||||
this.current = undefined as unknown as LogAppenderConf;
|
||||
this.type = type;
|
||||
constructor(config: LogAppenderConfig) {
|
||||
this.config = config;
|
||||
this.appenderRel = {};
|
||||
this.current = undefined as unknown as LogAppenderView;
|
||||
this.appenderViews = {};
|
||||
this.fitAllFn = useDebounceFn(this.fitAll).bind(this);
|
||||
}
|
||||
|
||||
// 初始化
|
||||
async init(logDomRefs: Array<LogDomRef>) {
|
||||
async init(configs: Array<LogAppenderView>) {
|
||||
// 初始化 appender
|
||||
await this.initAppender(logDomRefs);
|
||||
await this.initAppender(configs);
|
||||
// 初始化 client
|
||||
await this.openClient();
|
||||
}
|
||||
|
||||
// 初始化 appender
|
||||
async initAppender(logDomRefs: Array<LogDomRef>) {
|
||||
async initAppender(configs: Array<LogAppenderView>) {
|
||||
// 打开 log-view
|
||||
for (let logDomRef of logDomRefs) {
|
||||
for (let config of configs) {
|
||||
// 初始化 terminal
|
||||
const terminal = new Terminal(LogAppenderOptions);
|
||||
const terminal = new Terminal({
|
||||
...LogAppenderOptions,
|
||||
scrollback: this.config.scrollLines,
|
||||
});
|
||||
// 初始化快捷键
|
||||
this.initCustomKey(terminal);
|
||||
// 初始化插件
|
||||
const addons = this.initAddons(terminal);
|
||||
// 打开终端
|
||||
terminal.open(logDomRef.el);
|
||||
terminal.open(config.el);
|
||||
// 自适应
|
||||
addons.fit.fit();
|
||||
this.appenderRel[logDomRef.id] = {
|
||||
...logDomRef,
|
||||
this.appenderViews[config.id] = {
|
||||
...config,
|
||||
terminal,
|
||||
addons
|
||||
};
|
||||
}
|
||||
// 设置当前对象
|
||||
this.current = this.appenderRel[logDomRefs[0].id];
|
||||
this.current = this.appenderViews[configs[0].id];
|
||||
// 注册自适应事件
|
||||
addEventListen(window, 'resize', this.fitAllFn);
|
||||
}
|
||||
@@ -152,12 +151,12 @@ export default class LogAppender implements ILogAppender {
|
||||
async openClient() {
|
||||
let tokenMaker;
|
||||
// 获取 token
|
||||
if (this.type === 'BATCH') {
|
||||
if (this.config.type === 'BATCH') {
|
||||
// 获取批量执行日志 token
|
||||
tokenMaker = getExecCommandLogTailToken(this.config);
|
||||
tokenMaker = getExecCommandLogTailToken(this.config.id);
|
||||
} else {
|
||||
// 获取计划任务日志 token
|
||||
tokenMaker = getExecJobLogTailToken(this.config);
|
||||
tokenMaker = getExecJobLogTailToken(this.config.id);
|
||||
}
|
||||
const { data } = await tokenMaker;
|
||||
// 打开会话
|
||||
@@ -180,15 +179,26 @@ export default class LogAppender implements ILogAppender {
|
||||
}, 15000) as unknown as number;
|
||||
}
|
||||
|
||||
// 设置当前元素
|
||||
setCurrent(id: number): void {
|
||||
const rel = this.appenderRel[id];
|
||||
if (!rel) {
|
||||
// 打开日志
|
||||
openLog(id: number): void {
|
||||
const view = this.appenderViews[id];
|
||||
if (!view || view.opened || this.client?.readyState !== WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
this.current = rel;
|
||||
// 发送打开日志
|
||||
this.client?.send(id.toString());
|
||||
view.opened = true;
|
||||
}
|
||||
|
||||
// 设置当前元素
|
||||
setCurrent(id: number): void {
|
||||
const view = this.appenderViews[id];
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
this.current = view;
|
||||
// 自适应
|
||||
rel.addons.fit.fit();
|
||||
view.addons.fit.fit();
|
||||
this.focus();
|
||||
}
|
||||
|
||||
@@ -259,7 +269,7 @@ export default class LogAppender implements ILogAppender {
|
||||
|
||||
// 自适应全部
|
||||
fitAll(): void {
|
||||
Object.values(this.appenderRel).forEach(s => {
|
||||
Object.values(this.appenderViews).forEach(s => {
|
||||
s.addons.fit.fit();
|
||||
});
|
||||
}
|
||||
@@ -282,7 +292,7 @@ export default class LogAppender implements ILogAppender {
|
||||
// 移除自适应事件
|
||||
removeEventListen(window, 'resize', this.fitAllFn);
|
||||
// 关闭 terminal
|
||||
Object.values(this.appenderRel).forEach(s => {
|
||||
Object.values(this.appenderViews).forEach(s => {
|
||||
try {
|
||||
// 卸载插件
|
||||
Object.values(s.addons)
|
||||
@@ -313,12 +323,12 @@ export default class LogAppender implements ILogAppender {
|
||||
const separatorIndex = data.indexOf('|');
|
||||
const id = data.substring(0, separatorIndex);
|
||||
const text = data.substring(separatorIndex + 1, data.length);
|
||||
// 获取 appender
|
||||
const appender = this.appenderRel[id];
|
||||
if (!appender) {
|
||||
// 获取 view
|
||||
const view = this.appenderViews[id];
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
appender.terminal.write(text);
|
||||
view.terminal.write(text);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<log-item class="log-item"
|
||||
v-show="current === host.id"
|
||||
v-for="host in execLog.hosts"
|
||||
v-show="current === host.id"
|
||||
:key="host.id"
|
||||
:ref="addRef as unknown as VNodeRef"
|
||||
:type="type"
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { VNodeRef } from 'vue';
|
||||
import type { LogDomRef, ILogAppender } from '../const';
|
||||
import type { ILogAppender, LogAppenderView } from '../const';
|
||||
import type { ExecLogQueryResponse } from '@/api/exec/exec-log';
|
||||
import type { ExecType } from '../const';
|
||||
import { nextTick, ref, watch } from 'vue';
|
||||
@@ -33,7 +33,9 @@
|
||||
type: ExecType;
|
||||
}>();
|
||||
|
||||
const logRefs = ref<Array<LogDomRef>>([]);
|
||||
const emits = defineEmits(['ready']);
|
||||
|
||||
const logRefs = ref<Array<LogAppenderView>>([]);
|
||||
|
||||
// 切换标签
|
||||
watch(() => props.current, (val) => {
|
||||
@@ -50,6 +52,7 @@
|
||||
if (props.appender) {
|
||||
// 初始化
|
||||
await props.appender.init(logRefs.value);
|
||||
emits('ready');
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -61,12 +64,16 @@
|
||||
if (!ref) {
|
||||
return;
|
||||
}
|
||||
if (logRefs.value.find(s => s.id === ref.id)) {
|
||||
return;
|
||||
}
|
||||
nextTick(() => {
|
||||
logRefs.value.push({
|
||||
id: ref.id,
|
||||
el: ref.appenderRef,
|
||||
opened: false,
|
||||
openSearch: ref.openSearch,
|
||||
});
|
||||
} as LogAppenderView);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user