feat:maidian
This commit is contained in:
@@ -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',
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<vab-query-form-left-panel :span="12">
|
||||
<el-form :inline="true" :model="queryForm" @submit.native.prevent>
|
||||
<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-button icon="el-icon-search" type="primary" @click="queryData">查询</el-button>
|
||||
@@ -104,7 +104,7 @@
|
||||
queryForm: {
|
||||
pageNo: 1,
|
||||
pageSize: 10,
|
||||
permission: '',
|
||||
userId: '',
|
||||
},
|
||||
timeOutID: null,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user