《前端日志的哲学表达:Vue 3 的日志的折叠宇宙》(Vue 3 + Element Plus)

290 阅读3分钟

在前端开发中,日志展示是一个常见的需求,尤其是在后台管理系统、运维平台、审计模块等场景中。本文将带你一步步构建一个功能强大的日志时间轴组件 LogTimeline,支持以下功能:

  • ✅ 展示日志列表(时间轴形式)
  • ✅ 点击展开/折叠日志详情
  • ✅ 按日志级别筛选
  • ✅ 分页加载
  • ✅ 导出日志为 JSON 文件

我们将使用 Vue 3 + Element Plus 实现该组件,代码结构清晰,易于扩展。

image.png

🧱 一、组件设计思路

1. 数据结构

每条日志包含以下字段:

interface LogItem {
  logId: number
  logCodeName: string
  logContent: string
  logDate: string
  loggedBy: string
  logLevel: 'I' | 'D' | 'T' | 'P' | 'E'
}

2. 功能模块划分

模块实现方式
日志展示<el-timeline> + <el-timeline-item>
展开/折叠使用 Set 存储展开项 ID
日志级别筛选<el-select> + v-model
分页<el-pagination>
导出Blob + URL.createObjectURL()

🧩 二、核心组件实现(LogTimeline.vue)

<template>
  <div>
    <!-- 筛选器 -->
    <div style="margin-bottom: 16px;">
      <el-select v-model="selectedLevel" placeholder="筛选日志级别" clearable style="width: 200px;">
        <el-option
          v-for="level in logLevelOptions"
          :key="level.value"
          :label="level.label"
          :value="level.value"
        />
      </el-select>
      <el-button type="primary" @click="exportLogs" style="margin-left: 12px;">导出日志</el-button>
    </div>

    <!-- 时间轴 -->
    <el-timeline style="max-width: 800px">
      <el-timeline-item
        v-for="log in paginatedLogs"
        :key="log.logId"
        :timestamp="formatTimestamp(log.logDate)"
        :type="getLogLevelType(log.logLevel)"
        placement="top"
      >
        <el-card>
          <h4 @click="toggleExpand(log)" style="cursor: pointer;">
            {{ log.logCodeName }}
            <span style="float: right;">
              {{ expandedLogs.has(log.logId) ? '收起' : '展开' }}
            </span>
          </h4>
          <p>{{ log.logContent }}</p>
          <p><strong>记录者:</strong>{{ log.loggedBy }}</p>
          <p><strong>日志级别:</strong>{{ log.logLevel }}</p>

          <!-- 展开详情 -->
          
        </el-card>
      </el-timeline-item>
    </el-timeline>

    <!-- 分页器 -->
    <el-pagination
      v-model:currentPage="currentPage"
      :page-size="pageSize"
      :total="filteredLogs.length"
      layout="prev, pager, next"
      style="margin-top: 20px;"
    />
  </div>
</template>

<script setup>
import { computed, ref } from 'vue'
import JsonRenderer from './JsonRenderer.vue'

const props = defineProps({
  logs: {
    type: Array,
    required: true
  }
})

// 日志级别选项
const logLevelOptions = [
  { label: '所有', value: '' },
  { label: '信息 (I)', value: 'I' },
  { label: '调试 (D)', value: 'D' },
  { label: '追踪 (T)', value: 'T' },
  { label: '提示 (P)', value: 'P' },
  { label: '错误 (E)', value: 'E' }
]

// 筛选
const selectedLevel = ref('')

// 展开状态
const expandedLogs = ref(new Set())

// 分页
const currentPage = ref(1)
const pageSize = 5

// 筛选后的日志
const filteredLogs = computed(() => {
  if (!selectedLevel.value) return props.logs
  return props.logs.filter(log => log.logLevel === selectedLevel.value)
})

// 当前页日志
const paginatedLogs = computed(() => {
  const start = (currentPage.value - 1) * pageSize
  const end = start + pageSize
  return filteredLogs.value.slice(start, end)
})

// 展开/折叠
function toggleExpand(log) {
  if (expandedLogs.value.has(log.logId)) {
    expandedLogs.value.delete(log.logId)
  } else {
    expandedLogs.value.add(log.logId)
  }
}

// 格式化时间
function formatTimestamp(dateStr) {
  return dateStr.replace(' ', ' / ')
}

// 日志级别颜色
function getLogLevelType(level) {
  switch (level) {
    case 'I': return 'primary'
    case 'D': return 'success'
    case 'T': return 'warning'
    case 'P': return 'info'
    case 'E': return 'danger'
    default: return ''
  }
}

// 导出日志
function exportLogs() {
  const dataStr = JSON.stringify(filteredLogs.value, null, 2)
  const blob = new Blob([dataStr], { type: 'application/json' })
  const url = URL.createObjectURL(blob)
  const a = document.createElement('a')
  a.href = url
  a.download = 'logs.json'
  a.click()
  URL.revokeObjectURL(url)
}
</script>

<style scoped>
h4 {
  margin: 0 0 8px;
  font-size: 16px;
}
p {
  margin: 4px 0;
  font-size: 14px;
}
</style>


🧪 四、使用示例

<template>
  <LogTimeline :logs="logList" />
</template>

<script setup>
import LogTimeline from '@/components/LogTimeline.vue'

const logList = [
  {
    logId: 220,
    logCodeName: '制单实例#制单完成',
    logContent: '制单实例运行完成',
    logDate: '2025-07-09 11:39:16',
    loggedBy: '日志记录代理[log_agent]',
    logLevel: 'I'
  },
  {
    logId: 219,
    logCodeName: '单证配置#生成单证完成',
    logContent: '单证配置生成单证完成',
    logDate: '2025-07-09 11:39:16',
    loggedBy: '日志记录代理[log_agent]',
    logLevel: 'D'
  },
  // ... 更多日志
]
</script>

🚀 五、可扩展方向

功能说明
🔍 搜索关键词输入框过滤日志内容
📅 时间范围筛选使用 el-date-picker
📤 导出为 CSV / Excel使用 xlsx
🎨 主题切换支持暗色模式
📱 响应式布局移动端适配

✅ 六、总结

通过本文,你学会了如何:

  • 使用 Vue 3 + Element Plus 构建日志时间轴组件
  • 实现展开/折叠、筛选、分页、导出等实用功能
  • 保持组件结构清晰、可维护、可扩展

这个组件非常适合用于:

  • 后台管理系统
  • 审计日志模块
  • 运维监控平台
  • 用户行为追踪