From de9a921c49787131949cb4a9e6c38e57d48ae491 Mon Sep 17 00:00:00 2001 From: lijiahang Date: Mon, 10 Feb 2025 09:51:53 +0800 Subject: [PATCH] =?UTF-8?q?:hammer:=20=E4=BF=AE=E6=94=B9=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E6=9F=A5=E7=9C=8B=E9=80=BB=E8=BE=91.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/components/exec/log/const.ts | 18 ++-- .../src/components/exec/log/panel/index.vue | 86 +++++++++---------- .../components/exec/log/panel/log-appender.ts | 82 ++++++++++-------- .../components/exec/log/panel/log-view.vue | 15 +++- 4 files changed, 111 insertions(+), 90 deletions(-) diff --git a/orion-visor-ui/src/components/exec/log/const.ts b/orion-visor-ui/src/components/exec/log/const.ts index 516b475f..2d6170e3 100644 --- a/orion-visor-ui/src/components/exec/log/const.ts +++ b/orion-visor-ui/src/components/exec/log/const.ts @@ -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): Promise; + init(refs: Array): Promise; + + // 打开日志 + openLog(id: number): void; // 设置当前元素 setCurrent(id: number): void; diff --git a/orion-visor-ui/src/components/exec/log/panel/index.vue b/orion-visor-ui/src/components/exec/log/panel/index.vue index fceb5972..c9805140 100644 --- a/orion-visor-ui/src/components/exec/log/panel/index.vue +++ b/orion-visor-ui/src/components/exec/log/panel/index.vue @@ -4,7 +4,7 @@ @@ -13,7 +13,8 @@ :type="type" :current="currentHostExecId" :exec-log="execLog" - :appender="appender" /> + :appender="appender" + @ready="openLog(currentHostExecId)" /> @@ -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(); const appender = ref(); // 打开 - 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); + } }; // 清理并且关闭 diff --git a/orion-visor-ui/src/components/exec/log/panel/log-appender.ts b/orion-visor-ui/src/components/exec/log/panel/log-appender.ts index bfe4d87e..e4965a69 100644 --- a/orion-visor-ui/src/components/exec/log/panel/log-appender.ts +++ b/orion-visor-ui/src/components/exec/log/panel/log-appender.ts @@ -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; - private readonly appenderRel: Record; + 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) { + async init(configs: Array) { // 初始化 appender - await this.initAppender(logDomRefs); + await this.initAppender(configs); // 初始化 client await this.openClient(); } // 初始化 appender - async initAppender(logDomRefs: Array) { + async initAppender(configs: Array) { // 打开 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); } } diff --git a/orion-visor-ui/src/components/exec/log/panel/log-view.vue b/orion-visor-ui/src/components/exec/log/panel/log-view.vue index 6a7d47f0..701745a5 100644 --- a/orion-visor-ui/src/components/exec/log/panel/log-view.vue +++ b/orion-visor-ui/src/components/exec/log/panel/log-view.vue @@ -1,8 +1,8 @@