zzw
昨天 1332cc511936d7dbe804921bc733c83d5e4d1400
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
<template>
  <div class="page">
    <div class="page-title">
      <div><h2>错误日志</h2><p>记录程序运行中的未处理异常,便于定位和修复缺陷</p></div>
    </div>
    <div class="table-panel">
      <div class="toolbar">
        <el-input v-model="filters.keyword" clearable placeholder="账户名 / 姓名 / 请求地址 / 异常信息" style="width:280px" @keyup.enter.native="search"></el-input>
        <el-select v-model="filters.module" clearable placeholder="模块" style="width:150px">
          <el-option v-for="item in modules" :key="item" :label="item" :value="item"></el-option>
        </el-select>
        <el-input v-model="filters.exceptionType" clearable placeholder="异常类型" style="width:220px" @keyup.enter.native="search"></el-input>
        <el-date-picker
          v-model="filters.dates"
          type="daterange"
          value-format="yyyy-MM-dd"
          range-separator="至"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
          style="width:260px"
        ></el-date-picker>
        <el-button type="primary" icon="el-icon-search" v-permission="'system:error-logs:query'" @click="search">查询</el-button>
        <el-button icon="el-icon-refresh-left" @click="reset">重置</el-button>
      </div>
      <el-table v-loading="loading" :data="rows" border stripe height="calc(100vh - 250px)">
        <el-table-column prop="errorTime" label="发生时间" width="180"></el-table-column>
        <el-table-column prop="userName" label="账户名" width="120"></el-table-column>
        <el-table-column prop="nickName" label="姓名" width="110"></el-table-column>
        <el-table-column prop="module" label="模块" width="120"></el-table-column>
        <el-table-column prop="requestMethod" label="方式" width="75" align="center"></el-table-column>
        <el-table-column prop="requestUri" label="请求地址" min-width="230" show-overflow-tooltip></el-table-column>
        <el-table-column prop="exceptionType" label="异常类型" min-width="220" show-overflow-tooltip></el-table-column>
        <el-table-column prop="message" label="异常信息" min-width="280" show-overflow-tooltip></el-table-column>
        <el-table-column label="操作" width="80" fixed="right">
          <template slot-scope="{ row }">
            <el-button type="text" v-permission="'system:error-logs:detail'" @click="openDetail(row)">详情</el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
        class="pager"
        background
        layout="total, sizes, prev, pager, next"
        :total="total"
        :current-page="current"
        :page-size="size"
        :page-sizes="[20, 50, 100]"
        @current-change="handleCurrentChange"
        @size-change="handleSizeChange"
      ></el-pagination>
    </div>
 
    <el-dialog title="错误详情" :visible.sync="detailVisible" width="900px" append-to-body>
      <div v-loading="detailLoading">
        <div class="detail-meta">
          <span><b>发生时间:</b>{{ detail.errorTime }}</span>
          <span><b>操作人:</b>{{ detail.userName || '-' }}{{ detail.nickName ? ' / ' + detail.nickName : '' }}</span>
          <span><b>模块:</b>{{ detail.module || '-' }}</span>
        </div>
        <div class="detail-meta">
          <span><b>请求:</b>{{ (detail.requestMethod || '') + ' ' + (detail.requestUri || '') }}</span>
        </div>
        <div class="detail-meta">
          <span><b>异常类型:</b>{{ detail.exceptionType }}</span>
        </div>
        <div class="detail-meta">
          <span><b>异常信息:</b>{{ detail.message }}</span>
        </div>
        <pre class="stack-trace">{{ detail.stackTrace || '无堆栈信息' }}</pre>
      </div>
      <template slot="footer"><el-button @click="detailVisible = false">关闭</el-button></template>
    </el-dialog>
  </div>
</template>
 
<script>
import api from '@/api'
export default {
  name: 'ErrorLogManage',
  data() {
    return {
      rows: [],
      total: 0,
      current: 1,
      size: 20,
      loading: false,
      detailVisible: false,
      detailLoading: false,
      detail: {},
      modules: ['故障管理', '完工管理', '完工验收', '统计报表', '用户管理', '角色管理', '菜单管理', '承修单位管理', '系统管理', '其他'],
      filters: { keyword: '', module: '', exceptionType: '', dates: [] }
    }
  },
  created() { this.load() },
  methods: {
    load() {
      this.loading = true
      const dates = this.filters.dates || []
      api.get('/system/error-logs', {
        params: {
          keyword: this.filters.keyword || undefined,
          module: this.filters.module || undefined,
          exceptionType: this.filters.exceptionType || undefined,
          startDate: dates[0] || undefined,
          endDate: dates[1] || undefined,
          current: this.current,
          size: this.size
        }
      }).then(res => {
        const data = res.data || {}
        this.rows = data.records || []
        this.total = data.total || 0
      }).finally(() => { this.loading = false })
    },
    search() { this.current = 1; this.load() },
    reset() { this.filters = { keyword: '', module: '', exceptionType: '', dates: [] }; this.search() },
    openDetail(row) {
      this.detailLoading = true
      this.detail = {}
      this.detailVisible = true
      api.get('/system/error-logs/' + row.id).then(res => {
        this.detail = res.data || {}
      }).finally(() => { this.detailLoading = false })
    },
    handleCurrentChange(page) { this.current = page; this.load() },
    handleSizeChange(size) { this.size = size; this.current = 1; this.load() }
  }
}
</script>
 
<style scoped>
.toolbar { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.pager { margin-top: 12px; text-align: right; }
.detail-meta { margin-bottom: 8px; color: #42566b; line-height: 22px; word-break: break-all; }
.detail-meta b { color: #26394d; }
.stack-trace {
  max-height: 520px;
  margin: 12px 0 0;
  padding: 12px;
  border: 1px solid #dce4ec;
  border-radius: 4px;
  color: #30445a;
  background: #f7f9fb;
  font-family: Consolas, "Courier New", monospace;
  font-size: 12px;
  line-height: 18px;
  white-space: pre-wrap;
  word-break: break-all;
  overflow: auto;
}
</style>