151 行
3.9 KiB
Vue
151 行
3.9 KiB
Vue
|
|
<template>
|
||
|
|
<div>
|
||
|
|
<h2 style="margin-bottom: 24px">事件流水</h2>
|
||
|
|
|
||
|
|
<el-card shadow="never">
|
||
|
|
<div class="toolbar responsive-toolbar">
|
||
|
|
<el-input
|
||
|
|
v-model="filters.eventName"
|
||
|
|
placeholder="事件名"
|
||
|
|
style="width: 200px"
|
||
|
|
clearable
|
||
|
|
@clear="loadData"
|
||
|
|
@keyup.enter="loadData"
|
||
|
|
/>
|
||
|
|
<el-input
|
||
|
|
v-model="filters.userId"
|
||
|
|
placeholder="用户 ID"
|
||
|
|
style="width: 200px"
|
||
|
|
clearable
|
||
|
|
@clear="loadData"
|
||
|
|
@keyup.enter="loadData"
|
||
|
|
/>
|
||
|
|
<el-date-picker
|
||
|
|
v-model="filters.dateRange"
|
||
|
|
type="daterange"
|
||
|
|
range-separator="至"
|
||
|
|
start-placeholder="开始日期"
|
||
|
|
end-placeholder="结束日期"
|
||
|
|
value-format="YYYY-MM-DD"
|
||
|
|
style="width: 280px"
|
||
|
|
@change="loadData"
|
||
|
|
/>
|
||
|
|
<el-button type="primary" @click="loadData">搜索</el-button>
|
||
|
|
<el-button :loading="loading" @click="loadData">刷新</el-button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="table-wrap">
|
||
|
|
<el-table :data="events" v-loading="loading" border stripe>
|
||
|
|
<el-table-column prop="eventName" label="事件名" width="180" />
|
||
|
|
<el-table-column prop="userId" label="用户 ID" width="200" show-overflow-tooltip />
|
||
|
|
<el-table-column prop="timestamp" label="时间" width="170" sortable>
|
||
|
|
<template #default="{ row }">
|
||
|
|
<span class="time-text">{{ formatTime(row.timestamp) }}</span>
|
||
|
|
</template>
|
||
|
|
</el-table-column>
|
||
|
|
<el-table-column label="属性" min-width="300">
|
||
|
|
<template #default="{ row }">
|
||
|
|
<el-popover trigger="click" :width="420">
|
||
|
|
<template #reference>
|
||
|
|
<el-button link type="primary" size="small">查看属性</el-button>
|
||
|
|
</template>
|
||
|
|
<pre class="props-json">{{ JSON.stringify(row.properties, null, 2) }}</pre>
|
||
|
|
</el-popover>
|
||
|
|
</template>
|
||
|
|
</el-table-column>
|
||
|
|
</el-table>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<el-pagination
|
||
|
|
style="margin-top: 16px"
|
||
|
|
layout="total, sizes, prev, pager, next"
|
||
|
|
:total="total"
|
||
|
|
:page-size="pageSize"
|
||
|
|
:current-page="currentPage"
|
||
|
|
:page-sizes="[20, 50, 100]"
|
||
|
|
@current-change="handlePageChange"
|
||
|
|
@size-change="handleSizeChange"
|
||
|
|
/>
|
||
|
|
</el-card>
|
||
|
|
</div>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script setup lang="ts">
|
||
|
|
import { ref, onMounted } from 'vue'
|
||
|
|
import { logApi, type LogEventItem } from '@/api/log'
|
||
|
|
|
||
|
|
const events = ref<LogEventItem[]>([])
|
||
|
|
const loading = ref(false)
|
||
|
|
const total = ref(0)
|
||
|
|
const currentPage = ref(1)
|
||
|
|
const pageSize = ref(20)
|
||
|
|
|
||
|
|
const filters = ref({
|
||
|
|
eventName: '',
|
||
|
|
userId: '',
|
||
|
|
dateRange: null as [string, string] | null,
|
||
|
|
})
|
||
|
|
|
||
|
|
function formatTime(ts: string) {
|
||
|
|
if (!ts) return '-'
|
||
|
|
return new Date(ts).toLocaleString('zh-CN')
|
||
|
|
}
|
||
|
|
|
||
|
|
async function loadData() {
|
||
|
|
loading.value = true
|
||
|
|
try {
|
||
|
|
const res = await logApi.events({
|
||
|
|
eventName: filters.value.eventName || undefined,
|
||
|
|
userId: filters.value.userId || undefined,
|
||
|
|
startDate: filters.value.dateRange?.[0] || undefined,
|
||
|
|
endDate: filters.value.dateRange?.[1] || undefined,
|
||
|
|
page: currentPage.value - 1,
|
||
|
|
size: pageSize.value,
|
||
|
|
})
|
||
|
|
const data = res.data.data
|
||
|
|
events.value = data.content
|
||
|
|
total.value = data.totalElements
|
||
|
|
} catch {
|
||
|
|
} finally {
|
||
|
|
loading.value = false
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function handlePageChange(page: number) {
|
||
|
|
currentPage.value = page
|
||
|
|
loadData()
|
||
|
|
}
|
||
|
|
|
||
|
|
function handleSizeChange(size: number) {
|
||
|
|
pageSize.value = size
|
||
|
|
currentPage.value = 1
|
||
|
|
loadData()
|
||
|
|
}
|
||
|
|
|
||
|
|
onMounted(loadData)
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<style scoped>
|
||
|
|
.responsive-toolbar {
|
||
|
|
display: flex;
|
||
|
|
gap: 12px;
|
||
|
|
flex-wrap: wrap;
|
||
|
|
margin-bottom: 16px;
|
||
|
|
}
|
||
|
|
.table-wrap {
|
||
|
|
overflow-x: auto;
|
||
|
|
}
|
||
|
|
.time-text {
|
||
|
|
font-size: 13px;
|
||
|
|
color: #666;
|
||
|
|
}
|
||
|
|
.props-json {
|
||
|
|
background: #f5f5f5;
|
||
|
|
padding: 12px;
|
||
|
|
border-radius: 6px;
|
||
|
|
font-size: 12px;
|
||
|
|
overflow-x: auto;
|
||
|
|
max-height: 400px;
|
||
|
|
}
|
||
|
|
</style>
|