UI改版测试V0
This commit is contained in:
@@ -3,38 +3,21 @@
|
||||
{% block title %}微信日志查看{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="log-page-container">
|
||||
<el-card class="log-card">
|
||||
<div slot="header" class="clearfix">
|
||||
<span>日志查看</span>
|
||||
<el-radio-group v-model="logType" size="small" style="margin-left: 20px;" @change="loadLogs">
|
||||
<el-radio-button label="info">信息日志</el-radio-button>
|
||||
<el-radio-button label="error">错误日志</el-radio-button>
|
||||
<el-radio-button label="debug">调试日志</el-radio-button>
|
||||
</el-radio-group>
|
||||
<el-select v-model="logLines" size="small" style="margin-left: 20px;" @change="loadLogs">
|
||||
<el-option label="最近100行" :value="100"></el-option>
|
||||
<el-option label="最近500行" :value="500"></el-option>
|
||||
<el-option label="最近1000行" :value="1000"></el-option>
|
||||
</el-select>
|
||||
<el-select v-model="refreshInterval" size="small" style="margin-left: 20px; width: 100px;" @change="handleRefreshInterval">
|
||||
<el-option label="手动" :value="0"></el-option>
|
||||
<el-option label="1秒" :value="1"></el-option>
|
||||
<el-option label="3秒" :value="3"></el-option>
|
||||
<el-option label="5秒" :value="5"></el-option>
|
||||
<el-option label="10秒" :value="10"></el-option>
|
||||
<el-option label="60秒" :value="60"></el-option>
|
||||
</el-select>
|
||||
<el-button style="float: right; padding: 3px 0" type="text" @click="loadLogs">刷新</el-button>
|
||||
<div class="page-shell logs-page">
|
||||
<div class="page-hero"><div class="page-hero-copy"><div class="page-eyebrow">Logs Console</div><h1>微信日志查看</h1><p>把日志查看器纳入统一的运维面板,支持切换类型、行数与自动刷新。</p></div></div>
|
||||
<el-card class="workspace-card log-card" shadow="hover">
|
||||
<div slot="header" class="workspace-header workspace-header--wrap">
|
||||
<div><h3>日志控制台</h3><p>选择日志类型、查看行数与自动刷新频率。</p></div>
|
||||
<div class="toolbar-row">
|
||||
<el-radio-group v-model="logType" size="small" @change="loadLogs"><el-radio-button label="info">信息日志</el-radio-button><el-radio-button label="error">错误日志</el-radio-button><el-radio-button label="debug">调试日志</el-radio-button></el-radio-group>
|
||||
<el-select v-model="logLines" size="small" style="width:120px;" @change="loadLogs"><el-option label="100行" :value="100"></el-option><el-option label="500行" :value="500"></el-option><el-option label="1000行" :value="1000"></el-option></el-select>
|
||||
<el-select v-model="refreshInterval" size="small" style="width:110px;" @change="handleRefreshInterval"><el-option label="手动" :value="0"></el-option><el-option label="1秒" :value="1"></el-option><el-option label="3秒" :value="3"></el-option><el-option label="5秒" :value="5"></el-option><el-option label="10秒" :value="10"></el-option><el-option label="60秒" :value="60"></el-option></el-select>
|
||||
<el-button type="primary" plain @click="loadLogs">刷新</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-loading="loading" class="log-content-wrapper">
|
||||
<div v-if="logContent && logContent.length > 0" class="log-content">
|
||||
<pre ref="logPre"></pre>
|
||||
</div>
|
||||
<div v-else class="empty-log">
|
||||
<el-empty description="暂无日志内容"></el-empty>
|
||||
</div>
|
||||
<div v-if="logContent && logContent.length > 0" class="log-content"><pre ref="logPre"></pre></div>
|
||||
<div v-else class="empty-log"><el-empty description="暂无日志内容"></el-empty></div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
@@ -42,159 +25,9 @@
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#app',
|
||||
mixins: [baseApp],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
logType: 'info',
|
||||
logLines: 100,
|
||||
logContent: [],
|
||||
logText: '',
|
||||
refreshInterval: 0,
|
||||
refreshTimer: null,
|
||||
currentView: '9',
|
||||
showTimeRangeSelector: false,
|
||||
cancelSource: null,
|
||||
isAutoScroll: true
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.loadLogs();
|
||||
this.$nextTick(() => {
|
||||
const logDiv = this.$el.querySelector('.log-content');
|
||||
if (logDiv) {
|
||||
logDiv.addEventListener('scroll', () => {
|
||||
const nearBottom = (logDiv.scrollHeight - logDiv.scrollTop - logDiv.clientHeight) < 50;
|
||||
this.isAutoScroll = nearBottom;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.clearRefreshTimer();
|
||||
if (this.cancelSource) {
|
||||
this.cancelSource.cancel('component destroyed');
|
||||
this.cancelSource = null;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
loadLogs() {
|
||||
this.loading = true;
|
||||
if (this.cancelSource) {
|
||||
this.cancelSource.cancel('new request');
|
||||
}
|
||||
this.cancelSource = axios.CancelToken.source();
|
||||
axios.get(`/api/wx_logs`, {
|
||||
params: { type: this.logType, lines: this.logLines },
|
||||
cancelToken: this.cancelSource.token
|
||||
})
|
||||
.then(response => {
|
||||
if (response.data.success) {
|
||||
this.logContent = response.data.data.content || [];
|
||||
this.logText = this.logContent.join('\n');
|
||||
this.$nextTick(() => {
|
||||
const logDiv = this.$el.querySelector('.log-content');
|
||||
const pre = this.$refs.logPre;
|
||||
if (pre) {
|
||||
pre.textContent = this.logText;
|
||||
}
|
||||
if (logDiv) {
|
||||
if (this.isAutoScroll) {
|
||||
logDiv.scrollTop = logDiv.scrollHeight;
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$message.error('加载日志失败');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
if (!axios.isCancel(error)) {
|
||||
console.error('加载日志出错:', error);
|
||||
this.$message.error('加载日志出错');
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
handleRefreshInterval() {
|
||||
this.clearRefreshTimer();
|
||||
if (this.refreshInterval > 0) {
|
||||
this.refreshTimer = setInterval(() => {
|
||||
this.loadLogs();
|
||||
}, this.refreshInterval * 1000);
|
||||
}
|
||||
},
|
||||
clearRefreshTimer() {
|
||||
if (this.refreshTimer) {
|
||||
clearInterval(this.refreshTimer);
|
||||
this.refreshTimer = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
new Vue({ el:'#app', mixins:[baseApp], data(){ return { loading:false, logType:'info', logLines:100, logContent:[], logText:'', refreshInterval:0, refreshTimer:null, currentView:'9', showTimeRangeSelector:false, cancelSource:null, isAutoScroll:true } }, mounted(){ this.loadLogs(); this.$nextTick(()=>{ const logDiv=this.$el.querySelector('.log-content'); if(logDiv){ logDiv.addEventListener('scroll',()=>{ const nearBottom=(logDiv.scrollHeight-logDiv.scrollTop-logDiv.clientHeight)<50; this.isAutoScroll=nearBottom; }); } }); }, beforeDestroy(){ this.clearRefreshTimer(); if(this.cancelSource){ this.cancelSource.cancel('component destroyed'); this.cancelSource=null; } }, methods:{ loadLogs(){ this.loading=true; if(this.cancelSource){ this.cancelSource.cancel('new request'); } this.cancelSource=axios.CancelToken.source(); axios.get(`/api/wx_logs`,{ params:{ type:this.logType, lines:this.logLines }, cancelToken:this.cancelSource.token }).then(response=>{ if(response.data.success){ this.logContent=response.data.data.content||[]; this.logText=this.logContent.join('\n'); this.$nextTick(()=>{ const logDiv=this.$el.querySelector('.log-content'); const pre=this.$refs.logPre; if(pre) pre.textContent=this.logText; if(logDiv&&this.isAutoScroll) logDiv.scrollTop=logDiv.scrollHeight; }); } else { this.$message.error('加载日志失败'); } }).catch(error=>{ if(!axios.isCancel(error)){ console.error('加载日志出错:',error); this.$message.error('加载日志出错'); } }).finally(()=>{ this.loading=false; }); }, handleRefreshInterval(){ this.clearRefreshTimer(); if(this.refreshInterval>0){ this.refreshTimer=setInterval(()=>this.loadLogs(), this.refreshInterval*1000); } }, clearRefreshTimer(){ if(this.refreshTimer){ clearInterval(this.refreshTimer); this.refreshTimer=null; } } } });
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.log-page-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.log-card {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.el-card__body {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.log-content-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.log-content {
|
||||
flex: 1;
|
||||
overflow-y: auto !important;
|
||||
overflow-x: scroll !important;
|
||||
background-color: var(--tech-panel-2);
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid var(--tech-border);
|
||||
box-sizing: border-box;
|
||||
min-height: 0;
|
||||
color: var(--tech-text);
|
||||
}
|
||||
|
||||
.log-content pre {
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
word-break: break-all;
|
||||
font-family: monospace;
|
||||
line-height: 1;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.empty-log {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
}
|
||||
.page-shell{display:flex;flex-direction:column;gap:16px}.page-hero{padding:24px 26px;border-radius:24px;background:linear-gradient(135deg, rgba(79,70,229,.10), rgba(59,130,246,.08), rgba(255,255,255,.9));border:1px solid rgba(148,163,184,.16);box-shadow:0 18px 40px rgba(15,23,42,.06)}.page-eyebrow{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:#6366f1;font-weight:700;margin-bottom:8px}.page-hero-copy h1{font-size:30px;line-height:1.1;margin-bottom:10px;color:#0f172a}.page-hero-copy p{color:#64748b;font-size:14px}.log-card{height:calc(100vh - 230px)}.log-card .el-card__body{height:calc(100% - 73px);display:flex;flex-direction:column;overflow:hidden}.workspace-header{display:flex;align-items:center;justify-content:space-between;gap:16px}.workspace-header--wrap{align-items:flex-start}.workspace-header h3{font-size:18px;margin-bottom:4px}.workspace-header p{font-size:13px;color:#64748b}.toolbar-row{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}.log-content-wrapper{flex:1;display:flex;flex-direction:column;overflow:hidden}.log-content{flex:1;overflow-y:auto !important;overflow-x:scroll !important;background:#0f172a;padding:14px;border-radius:18px;border:1px solid rgba(148,163,184,.12);box-sizing:border-box;min-height:0;color:#dbeafe}.log-content pre{margin:0;white-space:pre;word-break:break-all;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.45;color:inherit}.empty-log{flex:1;display:flex;align-items:center;justify-content:center;overflow:hidden}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user