feat:maidian

This commit is contained in:
zzc
2026-02-20 15:45:23 +08:00
parent 2a6b88619e
commit 2b9a6e109c
2 changed files with 132 additions and 4 deletions

View File

@@ -56,13 +56,13 @@
<el-col :span="12">
<el-card class="chart-card" shadow="never">
<div slot="header"><span>事件名称分布</span></div>
<v-chart autoresize class="chart" :option="eventNameOption" />
<v-chart autoresize class="chart" :option="eventNameOption" @click="handleEventNameClick" />
</el-card>
</el-col>
<el-col :span="12">
<el-card class="chart-card" shadow="never">
<div slot="header"><span>事件类型分布</span></div>
<v-chart autoresize class="chart" :option="eventTypeOption" />
<v-chart autoresize class="chart" :option="eventTypeOption" @click="handleEventTypeClick" />
</el-card>
</el-col>
</el-row>
@@ -75,6 +75,52 @@
</el-card>
</el-col>
</el-row>
<el-row :gutter="20" style="margin-top: 20px">
<el-col :span="24">
<el-card shadow="never">
<div slot="header" style="display: flex; justify-content: space-between; align-items: center">
<span>
详细日志列表
<span v-if="filterText" style="font-size: 12px; color: #666">({{ filterText }})</span>
</span>
<el-button v-if="isFiltered" size="mini" type="text" @click="clearFilter">清除筛选</el-button>
</div>
<el-table :data="paginatedList" style="width: 100%">
<el-table-column label="时间" prop="createdAt" width="160">
<template slot-scope="{ row }">
{{ formatTime(row.createdAt) }}
</template>
</el-table-column>
<el-table-column label="事件名称" prop="eventName" show-overflow-tooltip>
<template slot-scope="{ row }">
{{ eventNameMap[row.eventName] || row.eventName }}
</template>
</el-table-column>
<el-table-column label="事件类型" prop="eventType" show-overflow-tooltip>
<template slot-scope="{ row }">
{{ eventTypeMap[row.eventType] || row.eventType }}
</template>
</el-table-column>
<el-table-column label="页面" prop="page" show-overflow-tooltip />
<el-table-column label="元素ID" prop="elementId" show-overflow-tooltip />
<el-table-column label="元素内容" prop="elementContent" show-overflow-tooltip />
<el-table-column label="User ID" prop="userId" show-overflow-tooltip />
</el-table>
<el-pagination
background
:current-page="currentPage"
layout="total, sizes, prev, pager, next, jumper"
:page-size="pageSize"
:page-sizes="[10, 20, 50, 100]"
style="margin-top: 20px; text-align: right"
:total="total"
@current-change="handleCurrentChange"
@size-change="handleSizeChange"
/>
</el-card>
</el-col>
</el-row>
</div>
</div>
</template>
@@ -145,12 +191,27 @@
],
},
list: [],
filteredList: [],
currentPage: 1,
pageSize: 10,
isFiltered: false,
filterText: '',
trendOption: {},
eventNameOption: {},
eventTypeOption: {},
pageOption: {},
}
},
computed: {
total() {
return this.filteredList.length
},
paginatedList() {
const start = (this.currentPage - 1) * this.pageSize
const end = start + this.pageSize
return this.filteredList.slice(start, end)
},
},
created() {
// 默认选中今天
const end = new Date()
@@ -162,6 +223,9 @@
this.fetchData()
},
methods: {
formatTime(time) {
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
async fetchData() {
this.loading = true
try {
@@ -177,6 +241,10 @@
const { data } = await getTrackingLogsList(params)
this.list = data.list || []
this.filteredList = [...this.list]
this.isFiltered = false
this.filterText = ''
this.currentPage = 1
this.processData()
} catch (error) {
console.error(error)
@@ -199,6 +267,62 @@
this.queryForm.dateRange = [dayjs(start).format('YYYY-MM-DD HH:mm:ss'), dayjs(end).format('YYYY-MM-DD HH:mm:ss')]
this.fetchData()
},
handleSizeChange(val) {
this.pageSize = val
this.currentPage = 1
},
handleCurrentChange(val) {
this.currentPage = val
},
clearFilter() {
this.filteredList = [...this.list]
this.isFiltered = false
this.filterText = ''
this.currentPage = 1
},
handleEventNameClick(params) {
const name = params.name
// name 可能是中文映射名,需要反向查找 key或者在 processData 时把 key 存入
// 简单起见processData 中 name 已经是中文名或者 key 了。
// 如果我们用中文名展示,过滤时比较麻烦。
// 最好在 processData 中让 echarts data item 包含原始 key。
// 重新检查 processData
// const eventNameData = Object.keys(eventNameCounts).map((key) => ({
// name: this.eventNameMap[key] || key,
// value: eventNameCounts[key],
// key: key // 添加原始 key
// }))
const key = params.data.key || params.name // 如果没有 key 属性,回退到 name
this.filteredList = this.list.filter((item) => {
const itemKey = item.eventName
const itemName = this.eventNameMap[itemKey] || itemKey
// 如果 params.data.key 存在,则精确匹配 key
if (params.data.key) {
return item.eventName === params.data.key
}
return itemName === name
})
this.isFiltered = true
this.filterText = `筛选事件: ${name}`
this.currentPage = 1
},
handleEventTypeClick(params) {
const name = params.name
const key = params.data.key || params.name
this.filteredList = this.list.filter((item) => {
if (params.data.key) {
return item.eventType === params.data.key
}
const itemKey = item.eventType
const itemName = this.eventTypeMap[itemKey] || itemKey
return itemName === name
})
this.isFiltered = true
this.filterText = `筛选类型: ${name}`
this.currentPage = 1
},
processData() {
// 1. 时段趋势
const logsByHour = groupBy(this.list, (item) => dayjs(item.createdAt).format('HH:00'))
@@ -235,10 +359,12 @@
const eventNameData = Object.keys(eventNameCounts).map((key) => ({
name: this.eventNameMap[key] || key,
value: eventNameCounts[key],
key: key, // 保存原始key
}))
this.eventNameOption = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)',
},
legend: {
orient: 'vertical',
@@ -266,10 +392,12 @@
const eventTypeData = Object.keys(eventTypeCounts).map((key) => ({
name: this.eventTypeMap[key] || key,
value: eventTypeCounts[key],
key: key, // 保存原始key
}))
this.eventTypeOption = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)',
},
legend: {
orient: 'vertical',