测试过程问题修改
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ hs_err_pid*
|
||||
**/target/
|
||||
|
||||
/log/
|
||||
/.trae/
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
package com.ruoyi.web.controller.schedule;
|
||||
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.schedule.ScheduleThread;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* 线程管理控制器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/schedule/thread")
|
||||
public class ThreadManageController {
|
||||
|
||||
@Autowired
|
||||
private ScheduleThread scheduleThread;
|
||||
|
||||
/**
|
||||
* 获取线程列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public AjaxResult list() {
|
||||
if (scheduleThread.threadTypeMap.isEmpty()) {
|
||||
scheduleThread.refreshThreadMap();
|
||||
}
|
||||
return AjaxResult.success(scheduleThread.getAllThreadStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动线程
|
||||
*/
|
||||
@PostMapping("/start/{key}")
|
||||
public AjaxResult start(@PathVariable String key) {
|
||||
try {
|
||||
scheduleThread.startThread(key);
|
||||
return AjaxResult.success("启动成功");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("启动失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止线程
|
||||
*/
|
||||
@PostMapping("/stop/{key}")
|
||||
public AjaxResult stop(@PathVariable String key) {
|
||||
try {
|
||||
scheduleThread.stopThread(key);
|
||||
return AjaxResult.success("停止指令已下发");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("停止失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动全部线程
|
||||
*/
|
||||
@PostMapping("/startAll")
|
||||
public AjaxResult startAll() {
|
||||
try {
|
||||
for (String key : scheduleThread.threadMap.keySet()) {
|
||||
try {
|
||||
scheduleThread.startThread(key);
|
||||
} catch (Exception e) {
|
||||
// 忽略单个启动失败,继续启动下一个
|
||||
}
|
||||
}
|
||||
return AjaxResult.success("全部启动指令已下发");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止全部线程
|
||||
*/
|
||||
@PostMapping("/stopAll")
|
||||
public AjaxResult stopAll() {
|
||||
try {
|
||||
for (String key : scheduleThread.threadMap.keySet()) {
|
||||
scheduleThread.stopThread(key);
|
||||
}
|
||||
return AjaxResult.success("全部停止指令已下发");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动分组线程
|
||||
*/
|
||||
@PostMapping("/startGroup/{type}")
|
||||
public AjaxResult startGroup(@PathVariable String type) {
|
||||
try {
|
||||
for (Map.Entry<String, String> entry : scheduleThread.threadTypeMap.entrySet()) {
|
||||
if (type.equals(entry.getValue())) {
|
||||
try {
|
||||
scheduleThread.startThread(entry.getKey());
|
||||
} catch (Exception e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return AjaxResult.success("分组启动指令已下发");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止分组线程
|
||||
*/
|
||||
@PostMapping("/stopGroup/{type}")
|
||||
public AjaxResult stopGroup(@PathVariable String type) {
|
||||
try {
|
||||
for (Map.Entry<String, String> entry : scheduleThread.threadTypeMap.entrySet()) {
|
||||
if (type.equals(entry.getValue())) {
|
||||
scheduleThread.stopThread(entry.getKey());
|
||||
}
|
||||
}
|
||||
return AjaxResult.success("分组停止指令已下发");
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("操作失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取线程日志
|
||||
*/
|
||||
@GetMapping("/log/{key}")
|
||||
public AjaxResult log(@PathVariable String key) {
|
||||
// 如果key是"ALL",则不进行关键词过滤,显示所有日志(除了堆栈合并逻辑外)
|
||||
String target = "ALL".equals(key) ? null : key;
|
||||
|
||||
// 日志路径,根据logback配置及实际环境确认
|
||||
File file = new File("D:/home/ruoyi/logs/sys-info.log");
|
||||
if (!file.exists()) {
|
||||
return AjaxResult.error("日志文件不存在");
|
||||
}
|
||||
|
||||
LinkedList<String> lines = new LinkedList<>();
|
||||
// 简单的日志行首匹配模式 (yyyy-MM-dd HH:mm:ss)
|
||||
Pattern logStartPattern = Pattern.compile("^\\d{4}-\\d{2}-\\d{2}\\s+\\d{2}:\\d{2}:\\d{2}");
|
||||
boolean isMatchingStack = false;
|
||||
// 如果是查看所有日志,默认所有行都匹配,除非遇到新的日志行且我们想做更复杂的过滤(目前全显)
|
||||
// 但为了支持堆栈合并,我们还是需要判断行首
|
||||
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
boolean isLogStart = logStartPattern.matcher(line).find();
|
||||
|
||||
if (target == null) {
|
||||
// 查看所有日志:直接添加,或者如果是异常日志查看模式可以在这里过滤
|
||||
// 暂时逻辑:全部添加
|
||||
lines.add(line);
|
||||
} else {
|
||||
// 查看特定线程日志
|
||||
if (line.contains(target)) {
|
||||
isMatchingStack = true;
|
||||
lines.add(line);
|
||||
} else if (isLogStart) {
|
||||
isMatchingStack = false;
|
||||
} else if (isMatchingStack) {
|
||||
lines.add(line);
|
||||
}
|
||||
}
|
||||
|
||||
// 限制行数,避免内存溢出,保留最后1000行
|
||||
if (lines.size() > 1000) {
|
||||
lines.removeFirst();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("读取日志失败: " + e.getMessage());
|
||||
}
|
||||
|
||||
return AjaxResult.success(lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取异常日志
|
||||
*/
|
||||
@GetMapping("/errorLog")
|
||||
public AjaxResult errorLog() {
|
||||
File file = new File("D:/home/ruoyi/logs/sys-error.log");
|
||||
if (!file.exists()) {
|
||||
// 如果没有单独的error log,尝试从info log中过滤ERROR级别?
|
||||
// 假设有 sys-error.log
|
||||
return AjaxResult.error("异常日志文件不存在");
|
||||
}
|
||||
|
||||
LinkedList<String> lines = new LinkedList<>();
|
||||
try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file), "GBK"))) {
|
||||
String line;
|
||||
while ((line = br.readLine()) != null) {
|
||||
lines.add(line);
|
||||
if (lines.size() > 1000) {
|
||||
lines.removeFirst();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
return AjaxResult.error("读取日志失败: " + e.getMessage());
|
||||
}
|
||||
return AjaxResult.success(lines);
|
||||
}
|
||||
}
|
||||
73
ruoyi-ui/src/api/schedule/thread.js
Normal file
73
ruoyi-ui/src/api/schedule/thread.js
Normal file
@@ -0,0 +1,73 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 查询线程列表
|
||||
export function listThread() {
|
||||
return request({
|
||||
url: '/schedule/thread/list',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 启动线程
|
||||
export function startThread(key) {
|
||||
return request({
|
||||
url: '/schedule/thread/start/' + key,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 停止线程
|
||||
export function stopThread(key) {
|
||||
return request({
|
||||
url: '/schedule/thread/stop/' + key,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取日志
|
||||
export function getThreadLog(key) {
|
||||
return request({
|
||||
url: '/schedule/thread/log/' + key,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
// 启动全部线程
|
||||
export function startAllThread() {
|
||||
return request({
|
||||
url: '/schedule/thread/startAll',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 停止全部线程
|
||||
export function stopAllThread() {
|
||||
return request({
|
||||
url: '/schedule/thread/stopAll',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 启动分组线程
|
||||
export function startGroupThread(type) {
|
||||
return request({
|
||||
url: '/schedule/thread/startGroup/' + type,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 停止分组线程
|
||||
export function stopGroupThread(type) {
|
||||
return request({
|
||||
url: '/schedule/thread/stopGroup/' + type,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
// 获取异常日志
|
||||
export function getErrorLog() {
|
||||
return request({
|
||||
url: '/schedule/thread/errorLog',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
331
ruoyi-ui/src/views/schedule/thread/index.vue
Normal file
331
ruoyi-ui/src/views/schedule/thread/index.vue
Normal file
@@ -0,0 +1,331 @@
|
||||
<template>
|
||||
<div class="app-container">
|
||||
<!-- 全局控制卡片 -->
|
||||
<el-card class="box-card" shadow="hover" style="margin-bottom: 20px;">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-weight: bold; font-size: 18px;"><i class="el-icon-setting"></i> 全局控制中心</span>
|
||||
</div>
|
||||
<el-row :gutter="20" type="flex" align="middle">
|
||||
<el-col :span="7">
|
||||
<div class="control-group">
|
||||
<span class="control-label">系统总控:</span>
|
||||
<el-button type="success" size="small" icon="el-icon-video-play" @click="handleStartAll">全部开启</el-button>
|
||||
<el-button type="danger" size="small" icon="el-icon-video-pause" @click="handleStopAll">全部关闭</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="11" style="border-left: 1px solid #EBEEF5; border-right: 1px solid #EBEEF5;">
|
||||
<div class="control-group" style="justify-content: space-evenly;">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<span class="control-label"><i class="el-icon-cpu"></i> 通讯组:</span>
|
||||
<el-button-group>
|
||||
<el-button type="primary" size="mini" icon="el-icon-video-play" @click="handleStartGroup('read')">开启</el-button>
|
||||
<el-button type="info" size="mini" icon="el-icon-video-pause" @click="handleStopGroup('read')">停止</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
|
||||
<el-divider direction="vertical" style="height: 20px;"></el-divider>
|
||||
|
||||
<div style="display: flex; align-items: center;">
|
||||
<span class="control-label"><i class="el-icon-s-operation"></i> 调度组:</span>
|
||||
<el-button-group>
|
||||
<el-button type="primary" size="mini" icon="el-icon-video-play" @click="handleStartGroup('schedule')">开启</el-button>
|
||||
<el-button type="info" size="mini" icon="el-icon-video-pause" @click="handleStopGroup('schedule')">停止</el-button>
|
||||
</el-button-group>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<div class="control-group" style="justify-content: flex-end;">
|
||||
<span class="control-label">日志:</span>
|
||||
<el-button type="primary" plain size="small" icon="el-icon-document" @click="handleGlobalLog">系统日志</el-button>
|
||||
<el-button type="danger" plain size="small" icon="el-icon-warning-outline" @click="handleErrorLog">异常日志</el-button>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-card>
|
||||
|
||||
<el-row :gutter="20">
|
||||
<!-- 读取线程组 -->
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card" shadow="hover">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-cpu"></i> PLC读取线程</span>
|
||||
<el-tag size="small" type="info" style="float: right">硬件通信</el-tag>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="readThreads" size="small" :show-header="true">
|
||||
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
|
||||
<!-- 调度线程组 -->
|
||||
<el-col :span="12">
|
||||
<el-card class="box-card" shadow="hover">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-s-operation"></i> 调度控制线程</span>
|
||||
<el-tag size="small" type="primary" style="float: right">业务逻辑</el-tag>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="scheduleThreads" size="small" :show-header="true">
|
||||
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<el-row :gutter="20" style="margin-top: 20px;">
|
||||
<!-- 监控线程组 -->
|
||||
<el-col :span="24">
|
||||
<el-card class="box-card" shadow="hover">
|
||||
<div slot="header" class="clearfix">
|
||||
<span style="font-weight: bold; font-size: 16px;"><i class="el-icon-monitor"></i> 系统监控线程</span>
|
||||
<el-tag size="small" type="warning" style="float: right">状态监控</el-tag>
|
||||
</div>
|
||||
<el-table v-loading="loading" :data="monitorThreads" size="small" :show-header="true">
|
||||
<el-table-column label="线程名称" prop="name" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="标识" prop="key" :show-overflow-tooltip="true" />
|
||||
<el-table-column label="状态" align="center" width="100">
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="scope.row.isRun ? 'success' : 'danger'" size="mini" effect="dark">
|
||||
{{ scope.row.isRun ? '运行中' : '已停止' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" align="center" width="150">
|
||||
<template slot-scope="scope">
|
||||
<el-button size="mini" type="text" icon="el-icon-video-play" v-if="!scope.row.isRun" @click="handleStart(scope.row)">启动</el-button>
|
||||
<el-button size="mini" type="text" icon="el-icon-video-pause" v-if="scope.row.isRun" @click="handleStop(scope.row)">停止</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
|
||||
<!-- 日志弹窗 -->
|
||||
<el-dialog :title="logTitle" :visible.sync="openLog" width="800px" append-to-body>
|
||||
<div class="log-container" v-loading="logLoading">
|
||||
<pre v-if="logContent.length > 0">{{ logContent.join('\n') }}</pre>
|
||||
<div v-else style="text-align: center; color: #909399; padding-top: 200px;">暂无日志</div>
|
||||
</div>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button type="primary" @click="refreshLog">刷 新</el-button>
|
||||
<el-button @click="openLog = false">关 闭</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { listThread, startThread, stopThread, getThreadLog, startAllThread, stopAllThread, startGroupThread, stopGroupThread, getErrorLog } from "@/api/schedule/thread";
|
||||
|
||||
export default {
|
||||
name: "Thread",
|
||||
data() {
|
||||
return {
|
||||
// 遮罩层
|
||||
loading: true,
|
||||
// 线程表格数据
|
||||
threadList: [],
|
||||
// 日志弹窗
|
||||
openLog: false,
|
||||
logTitle: "",
|
||||
logLoading: false,
|
||||
logContent: [],
|
||||
logType: 'system', // system, error
|
||||
currentLogKey: null // for refresh
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
readThreads() {
|
||||
return this.threadList.filter(item => item.type === 'read' || !item.type);
|
||||
},
|
||||
scheduleThreads() {
|
||||
return this.threadList.filter(item => item.type === 'schedule');
|
||||
},
|
||||
monitorThreads() {
|
||||
return this.threadList.filter(item => item.type === 'monitor');
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getList();
|
||||
},
|
||||
methods: {
|
||||
/** 查询线程列表 */
|
||||
getList() {
|
||||
this.loading = true;
|
||||
listThread().then(response => {
|
||||
this.threadList = response.data;
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
/** 启动按钮操作 */
|
||||
handleStart(row) {
|
||||
this.$confirm('确认要启动 "' + row.name + '" 吗?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return startThread(row.key);
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess("启动指令已下发");
|
||||
setTimeout(() => {
|
||||
this.getList();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
console.error("启动失败:", error);
|
||||
});
|
||||
},
|
||||
/** 停止按钮操作 */
|
||||
handleStop(row) {
|
||||
this.$confirm('确认要停止 "' + row.name + '" 吗?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return stopThread(row.key);
|
||||
}).then(response => {
|
||||
this.$modal.msgSuccess("停止指令已下发");
|
||||
// 稍微延迟一下刷新,等待线程退出
|
||||
setTimeout(() => {
|
||||
this.getList();
|
||||
}, 1000);
|
||||
}).catch(error => {
|
||||
console.error("停止失败:", error);
|
||||
});
|
||||
},
|
||||
/** 一键开启所有 */
|
||||
handleStartAll() {
|
||||
this.$confirm('确认要启动所有线程吗?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "warning"
|
||||
}).then(() => {
|
||||
return startAllThread();
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess("操作成功");
|
||||
setTimeout(() => { this.getList(); }, 2000);
|
||||
});
|
||||
},
|
||||
/** 一键关闭所有 */
|
||||
handleStopAll() {
|
||||
this.$confirm('确认要停止所有线程吗?', "警告", {
|
||||
confirmButtonText: "确定",
|
||||
cancelButtonText: "取消",
|
||||
type: "error"
|
||||
}).then(() => {
|
||||
return stopAllThread();
|
||||
}).then(() => {
|
||||
this.$modal.msgSuccess("操作成功");
|
||||
setTimeout(() => { this.getList(); }, 2000);
|
||||
});
|
||||
},
|
||||
/** 分组开启 */
|
||||
handleStartGroup(type) {
|
||||
startGroupThread(type).then(() => {
|
||||
this.$modal.msgSuccess("操作成功");
|
||||
setTimeout(() => { this.getList(); }, 1500);
|
||||
});
|
||||
},
|
||||
/** 分组停止 */
|
||||
handleStopGroup(type) {
|
||||
stopGroupThread(type).then(() => {
|
||||
this.$modal.msgSuccess("操作成功");
|
||||
setTimeout(() => { this.getList(); }, 1500);
|
||||
});
|
||||
},
|
||||
/** 系统日志 */
|
||||
handleGlobalLog() {
|
||||
this.logTitle = "系统运行日志";
|
||||
this.logType = 'system';
|
||||
this.currentLogKey = 'ALL';
|
||||
this.openLog = true;
|
||||
this.refreshLog();
|
||||
},
|
||||
/** 异常日志 */
|
||||
handleErrorLog() {
|
||||
this.logTitle = "系统异常日志";
|
||||
this.logType = 'error';
|
||||
this.openLog = true;
|
||||
this.refreshLog();
|
||||
},
|
||||
refreshLog() {
|
||||
this.logLoading = true;
|
||||
if (this.logType === 'system') {
|
||||
getThreadLog(this.currentLogKey).then(response => {
|
||||
this.logContent = response.data;
|
||||
this.logLoading = false;
|
||||
this.$nextTick(() => {
|
||||
const container = this.$el.querySelector('.log-container');
|
||||
if (container) container.scrollTop = container.scrollHeight;
|
||||
});
|
||||
});
|
||||
} else {
|
||||
getErrorLog().then(response => {
|
||||
this.logContent = response.data;
|
||||
this.logLoading = false;
|
||||
this.$nextTick(() => {
|
||||
const container = this.$el.querySelector('.log-container');
|
||||
if (container) container.scrollTop = container.scrollHeight;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.log-container {
|
||||
height: 500px;
|
||||
overflow-y: auto;
|
||||
background-color: #f5f7fa;
|
||||
padding: 10px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
}
|
||||
pre {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-size: 12px;
|
||||
margin: 0;
|
||||
}
|
||||
.box-card {
|
||||
height: 100%;
|
||||
}
|
||||
.control-group {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 40px;
|
||||
}
|
||||
.control-label {
|
||||
font-weight: bold;
|
||||
margin-right: 10px;
|
||||
color: #606266;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user