48 lines
6.8 KiB
HTML
48 lines
6.8 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}错误日志 - 机器人管理后台{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="page-shell logs-page">
|
|
<div class="page-hero"><div class="page-hero-copy"><div class="page-eyebrow">Error Center</div><h1>错误日志</h1><p>统一查看插件异常、用户上下文与错误详情,方便快速定位问题来源。</p></div></div>
|
|
<el-row :gutter="16" class="overview-grid">
|
|
<el-col :span="8"><el-card class="overview-card overview-card--primary"><div class="overview-label">错误总数</div><div class="overview-value">{% raw %}{{ totalErrors }}{% endraw %}</div><div class="overview-note">当前分页查询结果对应总量</div></el-card></el-col>
|
|
<el-col :span="8"><el-card class="overview-card"><div class="overview-label">当前页日志数</div><div class="overview-value">{% raw %}{{ errorLogs.length }}{% endraw %}</div><div class="overview-note">本页已加载的错误记录</div></el-card></el-col>
|
|
<el-col :span="8"><el-card class="overview-card overview-card--soft"><div class="overview-label">分页大小</div><div class="overview-value">{% raw %}{{ pageSize }}{% endraw %}</div><div class="overview-note">每页可查看的错误条目</div></el-card></el-col>
|
|
</el-row>
|
|
<el-card class="workspace-card" shadow="hover">
|
|
<div slot="header" class="workspace-header"><div><h3>错误列表</h3><p>查看插件、命令、错误摘要以及相关用户/群组上下文。</p></div></div>
|
|
<el-table :data="errorLogs" style="width:100%">
|
|
<el-table-column prop="plugin_name" label="插件名称" width="140"></el-table-column>
|
|
<el-table-column prop="command" label="命令" width="120"></el-table-column>
|
|
<el-table-column prop="error_message" label="错误信息" min-width="320" :show-overflow-tooltip="true"></el-table-column>
|
|
<el-table-column prop="created_at" label="时间" width="170"></el-table-column>
|
|
<el-table-column label="用户" min-width="180"><template slot-scope="scope"><span v-if="scope.row.user_id">{% raw %}{{ scope.row.user_name || scope.row.user_id }} ({{ scope.row.user_id }}){% endraw %}</span><span v-else>-</span></template></el-table-column>
|
|
<el-table-column label="群组" min-width="180"><template slot-scope="scope"><span v-if="scope.row.group_id">{% raw %}{{ scope.row.group_name || scope.row.group_id }} ({{ scope.row.group_id }}){% endraw %}</span><span v-else>-</span></template></el-table-column>
|
|
<el-table-column label="操作" width="120" align="center"><template slot-scope="scope"><el-button size="mini" type="primary" plain @click="viewErrorDetail(scope.row)">查看详情</el-button></template></el-table-column>
|
|
</el-table>
|
|
<div class="pagination-container"><el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[10,20,50,100]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="totalErrors"></el-pagination></div>
|
|
</el-card>
|
|
<el-dialog title="错误详情" :visible.sync="errorDetailVisible" width="70%">
|
|
<el-descriptions :column="1" border>
|
|
<el-descriptions-item label="插件名称">{% raw %}{{ errorDetail.plugin_name }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="命令">{% raw %}{{ errorDetail.command }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="用户ID">{% raw %}{{ errorDetail.user_id }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="群组ID">{% raw %}{{ errorDetail.group_id || '无' }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="时间">{% raw %}{{ errorDetail.created_at }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="错误信息">{% raw %}{{ errorDetail.error_message }}{% endraw %}</el-descriptions-item>
|
|
<el-descriptions-item label="堆栈跟踪" v-if="errorDetail.stack_trace"><pre class="stack-trace">{% raw %}{{ errorDetail.stack_trace }}{% endraw %}</pre></el-descriptions-item>
|
|
</el-descriptions>
|
|
</el-dialog>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
new Vue({ el:'#app', mixins:[baseApp], data(){ return { errorLogs:[], errorDetail:{}, errorDetailVisible:false, currentPage:1, pageSize:20, totalErrors:0 } }, mounted(){ this.currentView='5'; this.loadData(); }, methods:{ loadData(){ this.loadErrorLogs(parseInt(this.timeRange)); }, loadErrorLogs(days){ axios.get(`/api/error_logs?days=${days}&limit=${this.pageSize}&offset=${(this.currentPage - 1) * this.pageSize}`).then(r=>{ if(r.data.success){ this.errorLogs=r.data.data.logs||[]; this.totalErrors=r.data.data.total||0; } }).catch(e=>{ console.error('加载错误日志出错:',e); this.$message.error('加载错误日志出错'); }); }, viewErrorDetail(error){ if(error.id){ this.loadErrorDetail(error.id);} else { this.errorDetail=error; this.errorDetailVisible=true; } }, loadErrorDetail(id){ axios.get(`/api/error_detail/${id}`).then(r=>{ if(r.data.success){ this.errorDetail=r.data.data||{}; this.errorDetailVisible=true; } }).catch(e=>{ console.error('加载错误详情出错:',e); this.$message.error('加载错误详情出错'); }); }, handleSizeChange(size){ this.pageSize=size; this.currentPage=1; this.loadData(); }, handleCurrentChange(page){ this.currentPage=page; this.loadData(); } } });
|
|
</script>
|
|
<style>
|
|
.page-shell{display:flex;flex-direction:column;gap:16px}.page-hero{padding:24px 26px;border-radius:24px;background:linear-gradient(135deg, rgba(15,118,110,.10), rgba(14,165,233,.08), rgba(255,255,255,.9));border:1px solid rgba(101,121,113,.16);box-shadow:0 18px 40px rgba(21,33,27,.06)}.page-eyebrow{font-size:12px;text-transform:uppercase;letter-spacing:.08em;color:#0b5e57;font-weight:700;margin-bottom:8px}.page-hero-copy h1{font-size:30px;line-height:1.1;margin-bottom:10px;color:#15211b}.page-hero-copy p{color:#4f6258;font-size:14px}.overview-grid .el-col{margin-bottom:16px}.overview-card{min-height:112px}.overview-card--primary{background:linear-gradient(180deg, rgba(15,118,110,.10), rgba(255,255,255,.94)) !important}.overview-card--soft{background:linear-gradient(180deg, rgba(14,165,233,.08), rgba(255,255,255,.94)) !important}.overview-label{font-size:13px;color:#4f6258;margin-bottom:14px}.overview-value{font-size:30px;font-weight:700;color:#15211b;margin-bottom:10px}.overview-note{font-size:12px;color:#74897f}.workspace-header{display:flex;align-items:center;justify-content:space-between;gap:16px}.workspace-header h3{font-size:18px;margin-bottom:4px}.workspace-header p{font-size:13px;color:#4f6258}.pagination-container{margin-top:20px;text-align:right}.stack-trace{white-space:pre-wrap;word-break:break-word;background:rgba(247,251,248,.85);border:1px solid rgba(101,121,113,.12);border-radius:14px;padding:14px;color:#27443a}
|
|
</style>
|
|
{% endblock %}
|