164 lines
3.0 KiB
Vue
164 lines
3.0 KiB
Vue
<template>
|
|
<div class="page-log">
|
|
<h2 class="page-title">运行日志</h2>
|
|
|
|
<!-- 日志控制 -->
|
|
<div class="log-controls-section">
|
|
<div class="log-controls">
|
|
<Button class="btn" @click="handleClearLogs">清空日志</Button>
|
|
<Button class="btn" @click="handleExportLogs">导出日志</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- 日志内容 -->
|
|
<div class="log-content-section">
|
|
<div class="log-container" id="log-container">
|
|
<div v-for="(log, index) in logEntries" :key="index" class="log-entry">
|
|
<span class="log-time">[{{ log.time }}]</span>
|
|
<span :class="['log-level', log.level.toLowerCase()]">[{{ log.level }}]</span>
|
|
<span class="log-message">{{ log.message }}</span>
|
|
</div>
|
|
<div v-if="logEntries.length === 0" class="log-empty">
|
|
<p>暂无日志记录</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { Button } from '../components/PrimeVue';
|
|
import { mapState, mapActions } from 'vuex';
|
|
|
|
export default {
|
|
name: 'LogPage',
|
|
components: {
|
|
Button
|
|
},
|
|
computed: {
|
|
...mapState('log', ['logs']),
|
|
logEntries() {
|
|
return this.logs;
|
|
}
|
|
},
|
|
mounted() {
|
|
this.scrollToBottom();
|
|
},
|
|
updated() {
|
|
this.scrollToBottom();
|
|
},
|
|
methods: {
|
|
...mapActions('log', ['clearLogs', 'exportLogs']),
|
|
handleClearLogs() {
|
|
this.clearLogs();
|
|
},
|
|
handleExportLogs() {
|
|
this.exportLogs();
|
|
},
|
|
scrollToBottom() {
|
|
this.$nextTick(() => {
|
|
const logContainer = document.getElementById('log-container');
|
|
if (logContainer) {
|
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|
}
|
|
});
|
|
}
|
|
},
|
|
watch: {
|
|
logEntries() {
|
|
this.scrollToBottom();
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="less" scoped>
|
|
.page-log {
|
|
padding: 0;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.log-controls-section {
|
|
margin-bottom: 10px;
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
}
|
|
|
|
.log-controls {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.log-content-section {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
overflow: hidden;
|
|
}
|
|
|
|
.log-container {
|
|
flex: 1;
|
|
padding: 12px;
|
|
overflow-y: auto;
|
|
background: #1e1e1e;
|
|
color: #d4d4d4;
|
|
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
|
font-size: 12px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.log-entry {
|
|
margin-bottom: 4px;
|
|
word-wrap: break-word;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.log-time {
|
|
color: #808080;
|
|
margin-right: 8px;
|
|
}
|
|
|
|
.log-level {
|
|
margin-right: 8px;
|
|
font-weight: 600;
|
|
|
|
&.info {
|
|
color: #4ec9b0;
|
|
}
|
|
|
|
&.success {
|
|
color: #4caf50;
|
|
}
|
|
|
|
&.warn {
|
|
color: #ffa726;
|
|
}
|
|
|
|
&.error {
|
|
color: #f44336;
|
|
}
|
|
|
|
&.debug {
|
|
color: #90caf9;
|
|
}
|
|
}
|
|
|
|
.log-message {
|
|
color: #d4d4d4;
|
|
}
|
|
|
|
.log-empty {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100%;
|
|
color: #808080;
|
|
font-size: 14px;
|
|
}
|
|
</style>
|