优化log显示效果
This commit is contained in:
@@ -5,32 +5,44 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<div>
|
<div>
|
||||||
<el-card class="log-card">
|
<el-card class="log-card">
|
||||||
<div slot="header" class="clearfix">
|
<template slot="header">
|
||||||
<span>日志查看</span>
|
<div class="flex items-center justify-between">
|
||||||
<el-radio-group v-model="logType" size="small" style="margin-left: 20px;" @change="loadLogs">
|
<span class="text-lg font-semibold">日志查看</span>
|
||||||
<el-radio-button label="info">信息日志</el-radio-button>
|
<div class="flex items-center space-x-4">
|
||||||
<el-radio-button label="error">错误日志</el-radio-button>
|
<el-radio-group v-model="logType" size="small" @change="loadLogs">
|
||||||
<el-radio-button label="debug">调试日志</el-radio-button>
|
<el-radio-button label="info">信息日志</el-radio-button>
|
||||||
</el-radio-group>
|
<el-radio-button label="error">错误日志</el-radio-button>
|
||||||
<el-select v-model="logLines" size="small" style="margin-left: 20px;" @change="loadLogs">
|
<el-radio-button label="debug">调试日志</el-radio-button>
|
||||||
<el-option label="最近100行" :value="100"></el-option>
|
</el-radio-group>
|
||||||
<el-option label="最近500行" :value="500"></el-option>
|
<el-select v-model="logLines" size="small" @change="loadLogs">
|
||||||
<el-option label="最近1000行" :value="1000"></el-option>
|
<el-option label="最近100行" :value="100"></el-option>
|
||||||
</el-select>
|
<el-option label="最近500行" :value="500"></el-option>
|
||||||
<el-select v-model="refreshInterval" size="small" style="margin-left: 20px; width: 100px;" @change="handleRefreshInterval">
|
<el-option label="最近1000行" :value="1000"></el-option>
|
||||||
<el-option label="手动" :value="0"></el-option>
|
</el-select>
|
||||||
<el-option label="1秒" :value="1"></el-option>
|
<el-select v-model="refreshInterval" size="small" style="width: 100px;" @change="handleRefreshInterval">
|
||||||
<el-option label="3秒" :value="3"></el-option>
|
<el-option label="手动" :value="0"></el-option>
|
||||||
<el-option label="5秒" :value="5"></el-option>
|
<el-option label="1秒" :value="1"></el-option>
|
||||||
<el-option label="10秒" :value="10"></el-option>
|
<el-option label="3秒" :value="3"></el-option>
|
||||||
<el-option label="60秒" :value="60"></el-option>
|
<el-option label="5秒" :value="5"></el-option>
|
||||||
</el-select>
|
<el-option label="10秒" :value="10"></el-option>
|
||||||
<el-button style="float: right; padding: 3px 0" type="text" @click="loadLogs">刷新</el-button>
|
<el-option label="60秒" :value="60"></el-option>
|
||||||
</div>
|
</el-select>
|
||||||
|
<el-button size="small" type="primary" @click="loadLogs">刷新</el-button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
<div v-loading="loading">
|
<div v-loading="loading" class="relative">
|
||||||
<div v-if="logContent && logContent.length > 0" class="log-content">
|
<div class="mb-4 flex items-center">
|
||||||
<pre>{% raw %}{{ logContent.join('') }}{% endraw %}</pre>
|
<el-input v-model="searchQuery" placeholder="搜索日志内容" clearable @input="filterLogs" size="small" style="width: 300px;"></el-input>
|
||||||
|
<el-checkbox v-model="autoScroll" class="ml-4">自动滚动到底部</el-checkbox>
|
||||||
|
</div>
|
||||||
|
<div v-if="filteredLogs.length > 0" class="log-content">
|
||||||
|
<div v-for="(log, index) in filteredLogs" :key="index" :class="['log-entry', `log-level-${log.level}`]">
|
||||||
|
<span class="log-timestamp">{{ formatTimestamp(log.timestamp) }}</span>
|
||||||
|
<span class="log-level" :class="{'text-blue-500': log.level === 'INFO', 'text-yellow-500': log.level === 'WARNING', 'text-red-500': log.level === 'ERROR'}">{{ log.level }}</span>
|
||||||
|
<span class="log-message">{{ log.message }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="empty-log">
|
<div v-else class="empty-log">
|
||||||
<el-empty description="暂无日志内容"></el-empty>
|
<el-empty description="暂无日志内容"></el-empty>
|
||||||
@@ -51,9 +63,12 @@
|
|||||||
logType: 'info',
|
logType: 'info',
|
||||||
logLines: 100,
|
logLines: 100,
|
||||||
logContent: [],
|
logContent: [],
|
||||||
refreshInterval: 0, // 新增,定时刷新间隔(秒),0为不自动刷新
|
filteredLogs: [],
|
||||||
refreshTimer: null, // 新增,定时器句柄
|
searchQuery: '',
|
||||||
currentView: '9' // 设置当前菜单项
|
autoScroll: true,
|
||||||
|
refreshInterval: 0,
|
||||||
|
refreshTimer: null,
|
||||||
|
currentView: '9'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@@ -63,30 +78,52 @@
|
|||||||
this.clearRefreshTimer();
|
this.clearRefreshTimer();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
loadLogs() {
|
async loadLogs() {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
axios.get(`/api/wx_logs?type=${this.logType}&lines=${this.logLines}`)
|
try {
|
||||||
.then(response => {
|
const response = await axios.get(`/api/wx_logs?type=${this.logType}&lines=${this.logLines}`);
|
||||||
if (response.data.success) {
|
if (response.data.success) {
|
||||||
this.logContent = response.data.data.content || [];
|
this.logContent = response.data.data.content || [];
|
||||||
// 日志内容更新后自动滚动到底部
|
this.filterLogs();
|
||||||
this.$nextTick(() => {
|
this.scrollToBottom();
|
||||||
const logDiv = this.$el.querySelector('.log-content');
|
} else {
|
||||||
if (logDiv) {
|
this.$message.error('加载日志失败');
|
||||||
logDiv.scrollTop = logDiv.scrollHeight;
|
}
|
||||||
}
|
} catch (error) {
|
||||||
});
|
console.error('加载日志出错:', error);
|
||||||
} else {
|
this.$message.error('加载日志出错');
|
||||||
this.$message.error('加载日志失败');
|
} finally {
|
||||||
|
this.loading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
filterLogs() {
|
||||||
|
if (!this.searchQuery) {
|
||||||
|
this.filteredLogs = this.logContent;
|
||||||
|
} else {
|
||||||
|
const query = this.searchQuery.toLowerCase();
|
||||||
|
this.filteredLogs = this.logContent.filter(log =>
|
||||||
|
log.message.toLowerCase().includes(query) ||
|
||||||
|
log.level.toLowerCase().includes(query) ||
|
||||||
|
log.timestamp.toLowerCase().includes(query)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
this.$nextTick(() => this.scrollToBottom());
|
||||||
|
},
|
||||||
|
formatTimestamp(timestamp) {
|
||||||
|
return new Date(timestamp).toLocaleString('zh-CN', {
|
||||||
|
year: 'numeric', month: '2-digit', day: '2-digit',
|
||||||
|
hour: '2-digit', minute: '2-digit', second: '2-digit'
|
||||||
|
});
|
||||||
|
},
|
||||||
|
scrollToBottom() {
|
||||||
|
if (this.autoScroll) {
|
||||||
|
this.$nextTick(() => {
|
||||||
|
const logDiv = this.$el.querySelector('.log-content');
|
||||||
|
if (logDiv) {
|
||||||
|
logDiv.scrollTop = logDiv.scrollHeight;
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('加载日志出错:', error);
|
|
||||||
this.$message.error('加载日志出错');
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
this.loading = false;
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
handleRefreshInterval() {
|
handleRefreshInterval() {
|
||||||
this.clearRefreshTimer();
|
this.clearRefreshTimer();
|
||||||
@@ -106,30 +143,53 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style scoped>
|
||||||
.log-card {
|
.log-card {
|
||||||
margin-bottom: 20px;
|
margin: 20px;
|
||||||
}
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
.log-content {
|
}
|
||||||
max-height: 700px;
|
|
||||||
overflow-y: auto;
|
.log-content {
|
||||||
overflow-x: auto;
|
max-height: 600px;
|
||||||
background-color: #f5f5f5;
|
overflow-y: auto;
|
||||||
padding: 10px;
|
background-color: #f8fafc;
|
||||||
border-radius: 4px;
|
padding: 16px;
|
||||||
}
|
border-radius: 4px;
|
||||||
|
font-family: 'Courier New', Courier, monospace;
|
||||||
.log-content pre {
|
}
|
||||||
margin: 0;
|
|
||||||
white-space: pre;
|
.log-entry {
|
||||||
word-break: normal;
|
display: flex;
|
||||||
word-wrap: normal;
|
padding: 8px 0;
|
||||||
font-family: monospace;
|
border-bottom: 1px solid #e2e8f0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.empty-log {
|
.log-timestamp {
|
||||||
padding: 40px 0;
|
flex: 0 0 180px;
|
||||||
}
|
color: #6b7280;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-level {
|
||||||
|
flex: 0 0 100px;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-message {
|
||||||
|
flex: 1;
|
||||||
|
word-break: break-all;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.log-level-INFO { background-color: #e6f3ff; }
|
||||||
|
.log-level-WARNING { background-color: #fefcbf; }
|
||||||
|
.log-level-ERROR { background-color: #fee2e2; }
|
||||||
|
|
||||||
|
.empty-log {
|
||||||
|
padding: 40px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user