Преглед на файлове

update AdminAccessLog.vue

reghao преди 1 ден
родител
ревизия
812cf7015b
променени са 2 файла, в които са добавени 279 реда и са изтрити 11 реда
  1. 5 0
      src/api/tnb.js
  2. 274 11
      src/views/admin/backend/AdminAccessLog.vue

+ 5 - 0
src/api/tnb.js

@@ -5,6 +5,7 @@ const tfApi = {
   dubboApi: '/api/admin1/zookeeper',
   springCloudApi: '/api/admin1/nacos',
   gatewayRouteApi: '/api/admin1/gateway',
+  logApi: '/api/admin1/log',
   getArticlesApi: '/api/content/admin/video/all'
 }
 
@@ -27,3 +28,7 @@ export function getSpringCloudInstances(queryParams) {
 export function getGatewayRoute() {
   return get(tfApi.gatewayRouteApi + '/route')
 }
+
+export function getAccessLog() {
+  return get(tfApi.logApi + '/access')
+}

+ 274 - 11
src/views/admin/backend/AdminAccessLog.vue

@@ -1,25 +1,127 @@
 <template>
-  <el-container>
-    <el-header height="220">
-      <h3>访问日志</h3>
+  <el-container class="log-container">
+    <el-header height="60px" class="log-header">
+      <div class="header-left">
+        <i class="el-icon-document" />
+        <h3>系统访问日志</h3>
+      </div>
+      <div class="header-right">
+        <el-button
+          type="primary"
+          size="small"
+          icon="el-icon-refresh-right"
+          :loading="loading"
+          @click="handleRefreshLatest"
+        >
+          回到最新(重置)
+        </el-button>
+        <el-tag type="info" size="small" style="margin-left: 12px;">单页容纳: {{ pageSize }} 条</el-tag>
+      </div>
     </el-header>
-    <el-main>
+
+    <el-main v-loading="loading" class="log-main">
+      <el-table
+        :data="dataList"
+        border
+        stripe
+        size="small"
+        style="width: 100%"
+        :header-cell-style="{ background: '#f8fafc', color: '#475569' }"
+      >
+        <el-table-column prop="id" label="日志ID" width="180" show-overflow-tooltip />
+        <el-table-column prop="requestTime" label="请求时间" width="160" />
+
+        <el-table-column prop="requestMethod" label="方法" width="80" align="center">
+          <template slot-scope="scope">
+            <el-tag :type="getMethodTag(scope.row.requestMethod)" size="mini" effect="dark">
+              {{ scope.row.requestMethod }}
+            </el-tag>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="requestUrl" label="请求URL" min-width="220" show-overflow-tooltip />
+
+        <el-table-column prop="statusCode" label="状态码" width="90" align="center">
+          <template slot-scope="scope">
+            <span :class="getStatusClass(scope.row.statusCode)">
+              {{ scope.row.statusCode }}
+            </span>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="executeTime" label="耗时" width="90" align="right">
+          <template slot-scope="scope">
+            <span :style="{ color: scope.row.executeTime > 1000 ? '#ef4444' : '#10b981', fontWeight: 'bold' }">
+              {{ scope.row.executeTime }} ms
+            </span>
+          </template>
+        </el-table-column>
+
+        <el-table-column prop="targetRoute" label="路由网关" width="150" show-overflow-tooltip />
+        <el-table-column prop="targetService" label="下游服务实例" width="160" show-overflow-tooltip />
+        <el-table-column prop="remoteAddr" label="来源IP" width="120" align="center" />
+      </el-table>
+
+      <div class="pagination-wrapper">
+        <span class="total-count">当前批次条数: {{ dataList.length }} / 估算总数: {{ totalSize }}</span>
+
+        <div class="pagination-actions">
+          <el-button
+            size="small"
+            icon="el-icon-refresh"
+            style="margin-right: 12px;"
+            :loading="loading"
+            @click="getData"
+          >
+            刷新当前页
+          </el-button>
+
+          <el-button-group>
+            <el-button
+              type="primary"
+              size="small"
+              icon="el-icon-arrow-left"
+              :disabled="!hasPrev"
+              @click="handleNav('prev')"
+            >
+              上一页
+            </el-button>
+            <el-button
+              type="primary"
+              size="small"
+              :disabled="!hasNext"
+              @click="handleNav('next')"
+            >
+              下一页<i class="el-icon-arrow-right el-icon--right" />
+            </el-button>
+          </el-button-group>
+        </div>
+      </div>
     </el-main>
   </el-container>
 </template>
 
 <script>
+import { getAccessLog } from '@/api/tnb'
+
 export default {
   name: 'AdminAccessLog',
   data() {
     return {
-      // 屏幕宽度, 为了控制分页条的大小
-      screenWidth: document.body.clientWidth,
-      currentPage: 1,
-      pageSize: 12,
-      totalSize: 0,
+      loading: false,
       dataList: [],
-      nextId: 0
+      // 分页相关游标状态
+      pageSize: 20,
+      totalSize: 0,
+      prevId: '',
+      nextId: '',
+      hasPrev: false,
+      hasNext: false,
+      // 当前查询使用的游标和方向
+      currentCursor: {
+        cursorId: '',
+        direction: '' // 'prev' 或 'next',第一页传空
+      }
     }
   },
   created() {
@@ -27,11 +129,172 @@ export default {
     this.getData()
   },
   methods: {
+    // 获取日志数据
     getData() {
+      this.loading = true
+
+      // 组装带游标的入参
+      const params = {
+        pageSize: this.pageSize
+      }
+      if (this.currentCursor.cursorId) {
+        params.cursorId = this.currentCursor.cursorId
+        params.direction = this.currentCursor.direction
+      }
+
+      getAccessLog(params).then(resp => {
+        if (resp.code === 0 && resp.data) {
+          const { list, pageSize, totalSize, prevId, nextId, hasPrev, hasNext } = resp.data
+          this.dataList = list || []
+          this.pageSize = pageSize
+          this.totalSize = totalSize
+          this.prevId = prevId
+          this.nextId = nextId
+          this.hasPrev = hasPrev
+          this.hasNext = hasNext
+        } else {
+          this.$message.error(resp.msg || '获取日志失败')
+        }
+      }).catch(() => {
+        this.$message.error('网关连接异常')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+
+    // 🌟 新增方法:清空游标,直接回到第一页看最新的日志
+    handleRefreshLatest() {
+      this.currentCursor = {
+        cursorId: '',
+        direction: ''
+      }
+      this.getData()
+      this.$message.success('已刷新并展示最新日志')
+    },
+
+    // 翻页流转控制
+    handleNav(action) {
+      if (action === 'prev' && this.hasPrev) {
+        this.currentCursor = {
+          cursorId: this.prevId,
+          direction: 'prev'
+        }
+        this.getData()
+      } else if (action === 'next' && this.hasNext) {
+        this.currentCursor = {
+          cursorId: this.nextId,
+          direction: 'next'
+        }
+        this.getData()
+      }
+    },
+
+    // 状态码视觉渲染器
+    getStatusClass(code) {
+      if (code >= 200 && code < 300) return 'status-2xx'
+      if (code >= 400 && code < 500) return 'status-4xx'
+      if (code >= 500) return 'status-5xx'
+      return 'status-info'
+    },
+
+    // 请求方法标签色划分
+    getMethodTag(method) {
+      const maps = {
+        'GET': 'success',
+        'POST': '',
+        'PUT': 'warning',
+        'DELETE': 'danger'
+      }
+      return maps[method.toUpperCase()] || 'info'
     }
   }
 }
 </script>
 
-<style>
+<style scoped>
+.log-container {
+  background-color: #f4f7f9;
+  min-height: calc(100vh - 40px);
+  margin: 20px;
+  border-radius: 8px;
+  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
+  overflow: hidden;
+}
+
+.log-header {
+  background-color: #ffffff;
+  border-bottom: 1px solid #e2e8f0;
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  padding: 0 24px;
+}
+
+.header-left {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+.header-left i {
+  font-size: 20px;
+  color: #3b82f6;
+}
+.header-left h3 {
+  margin: 0;
+  color: #1e293b;
+  font-weight: 600;
+}
+
+.header-right {
+  display: flex;
+  align-items: center;
+}
+
+.log-main {
+  background: #ffffff;
+  padding: 24px;
+}
+
+/* 翻页组件沙箱 */
+.pagination-wrapper {
+  margin-top: 20px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  background: #f8fafc;
+  padding: 12px 20px;
+  border-radius: 6px;
+  border: 1px solid #e2e8f0;
+}
+
+.pagination-actions {
+  display: flex;
+  align-items: center;
+}
+
+.total-count {
+  font-size: 13px;
+  color: #64748b;
+  font-family: monospace;
+}
+
+/* 状态码样式定义 */
+.status-2xx {
+  color: #10b981;
+  font-weight: bold;
+}
+.status-4xx {
+  color: #f59e0b;
+  font-weight: bold;
+}
+.status-5xx {
+  color: #ef4444;
+  font-weight: bold;
+  background-color: #fee2e2;
+  padding: 2px 6px;
+  border-radius: 4px;
+}
+.status-info {
+  color: #64748b;
+}
 </style>