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-col :span="12">
<el-card class="chart-card" shadow="never"> <el-card class="chart-card" shadow="never">
<div slot="header"><span>事件名称分布</span></div> <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-card>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<el-card class="chart-card" shadow="never"> <el-card class="chart-card" shadow="never">
<div slot="header"><span>事件类型分布</span></div> <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-card>
</el-col> </el-col>
</el-row> </el-row>
@@ -75,6 +75,52 @@
</el-card> </el-card>
</el-col> </el-col>
</el-row> </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>
</div> </div>
</template> </template>
@@ -145,12 +191,27 @@
], ],
}, },
list: [], list: [],
filteredList: [],
currentPage: 1,
pageSize: 10,
isFiltered: false,
filterText: '',
trendOption: {}, trendOption: {},
eventNameOption: {}, eventNameOption: {},
eventTypeOption: {}, eventTypeOption: {},
pageOption: {}, 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() { created() {
// 默认选中今天 // 默认选中今天
const end = new Date() const end = new Date()
@@ -162,6 +223,9 @@
this.fetchData() this.fetchData()
}, },
methods: { methods: {
formatTime(time) {
return dayjs(time).format('YYYY-MM-DD HH:mm:ss')
},
async fetchData() { async fetchData() {
this.loading = true this.loading = true
try { try {
@@ -177,6 +241,10 @@
const { data } = await getTrackingLogsList(params) const { data } = await getTrackingLogsList(params)
this.list = data.list || [] this.list = data.list || []
this.filteredList = [...this.list]
this.isFiltered = false
this.filterText = ''
this.currentPage = 1
this.processData() this.processData()
} catch (error) { } catch (error) {
console.error(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.queryForm.dateRange = [dayjs(start).format('YYYY-MM-DD HH:mm:ss'), dayjs(end).format('YYYY-MM-DD HH:mm:ss')]
this.fetchData() 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() { processData() {
// 1. 时段趋势 // 1. 时段趋势
const logsByHour = groupBy(this.list, (item) => dayjs(item.createdAt).format('HH:00')) const logsByHour = groupBy(this.list, (item) => dayjs(item.createdAt).format('HH:00'))
@@ -235,10 +359,12 @@
const eventNameData = Object.keys(eventNameCounts).map((key) => ({ const eventNameData = Object.keys(eventNameCounts).map((key) => ({
name: this.eventNameMap[key] || key, name: this.eventNameMap[key] || key,
value: eventNameCounts[key], value: eventNameCounts[key],
key: key, // 保存原始key
})) }))
this.eventNameOption = { this.eventNameOption = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: '{b}: {c} ({d}%)',
}, },
legend: { legend: {
orient: 'vertical', orient: 'vertical',
@@ -266,10 +392,12 @@
const eventTypeData = Object.keys(eventTypeCounts).map((key) => ({ const eventTypeData = Object.keys(eventTypeCounts).map((key) => ({
name: this.eventTypeMap[key] || key, name: this.eventTypeMap[key] || key,
value: eventTypeCounts[key], value: eventTypeCounts[key],
key: key, // 保存原始key
})) }))
this.eventTypeOption = { this.eventTypeOption = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: '{b}: {c} ({d}%)',
}, },
legend: { legend: {
orient: 'vertical', orient: 'vertical',

View File

@@ -8,7 +8,7 @@
<vab-query-form-left-panel :span="12"> <vab-query-form-left-panel :span="12">
<el-form :inline="true" :model="queryForm" @submit.native.prevent> <el-form :inline="true" :model="queryForm" @submit.native.prevent>
<el-form-item> <el-form-item>
<el-input v-model.trim="queryForm.permission" clearable placeholder="请输入查询条件" /> <el-input v-model.trim="queryForm.userId" clearable placeholder="请输入查询条件" />
</el-form-item> </el-form-item>
<el-form-item> <el-form-item>
<el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button> <el-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
@@ -104,7 +104,7 @@
queryForm: { queryForm: {
pageNo: 1, pageNo: 1,
pageSize: 10, pageSize: 10,
permission: '', userId: '',
}, },
timeOutID: null, timeOutID: null,
} }