增加日志查询页面。
This commit is contained in:
parent
cc8b00446c
commit
1b65954943
@ -58,6 +58,16 @@
|
|||||||
<router-link to="/merchant/products">商品列表</router-link>
|
<router-link to="/merchant/products">商品列表</router-link>
|
||||||
</a-menu-item>
|
</a-menu-item>
|
||||||
</a-sub-menu>
|
</a-sub-menu>
|
||||||
|
|
||||||
|
<a-sub-menu key="system">
|
||||||
|
<template #icon>
|
||||||
|
<setting-outlined />
|
||||||
|
</template>
|
||||||
|
<template #title>系统管理</template>
|
||||||
|
<a-menu-item key="system-logs">
|
||||||
|
<router-link to="/system/logs">日志查询</router-link>
|
||||||
|
</a-menu-item>
|
||||||
|
</a-sub-menu>
|
||||||
</a-menu>
|
</a-menu>
|
||||||
</a-layout-sider>
|
</a-layout-sider>
|
||||||
<a-layout>
|
<a-layout>
|
||||||
@ -109,6 +119,7 @@ import {
|
|||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
DashboardOutlined,
|
DashboardOutlined,
|
||||||
ShopOutlined,
|
ShopOutlined,
|
||||||
|
SettingOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
|
|
||||||
@ -123,12 +134,13 @@ export default defineComponent({
|
|||||||
LogoutOutlined,
|
LogoutOutlined,
|
||||||
DashboardOutlined,
|
DashboardOutlined,
|
||||||
ShopOutlined,
|
ShopOutlined,
|
||||||
|
SettingOutlined,
|
||||||
},
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const collapsed = ref(false)
|
const collapsed = ref(false)
|
||||||
const selectedKeys = ref(['dashboard'])
|
const selectedKeys = ref(['dashboard'])
|
||||||
const openKeys = ref(['user', 'community', 'merchant'])
|
const openKeys = ref(['user', 'community', 'merchant', 'system'])
|
||||||
|
|
||||||
const userInfo = ref(JSON.parse(localStorage.getItem('userInfo') || '{}'))
|
const userInfo = ref(JSON.parse(localStorage.getItem('userInfo') || '{}'))
|
||||||
|
|
||||||
|
|||||||
@ -67,6 +67,17 @@ const routes = [
|
|||||||
meta: { title: '商品列表' }
|
meta: { title: '商品列表' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/system',
|
||||||
|
component: BasicLayout,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'logs',
|
||||||
|
component: () => import('@/views/system/LogList.vue'),
|
||||||
|
meta: { title: '日志查询' }
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
341
src/views/system/LogList.vue
Normal file
341
src/views/system/LogList.vue
Normal file
@ -0,0 +1,341 @@
|
|||||||
|
<template>
|
||||||
|
<page-container>
|
||||||
|
<div class="log-list">
|
||||||
|
<div class="table-header">
|
||||||
|
<h1>日志查询</h1>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 过滤区域 -->
|
||||||
|
<div class="table-filter">
|
||||||
|
<a-form layout="inline">
|
||||||
|
<a-form-item label="日期范围">
|
||||||
|
<a-select
|
||||||
|
v-model:value="filterForm.dateType"
|
||||||
|
style="width: 200px"
|
||||||
|
@change="handleDateTypeChange"
|
||||||
|
>
|
||||||
|
<a-select-option value="">全部</a-select-option>
|
||||||
|
<a-select-option value="today">今天</a-select-option>
|
||||||
|
<a-select-option value="yesterday">昨天</a-select-option>
|
||||||
|
<a-select-option value="last7days">过去7天</a-select-option>
|
||||||
|
<a-select-option value="last30days">过去30天</a-select-option>
|
||||||
|
</a-select>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item label="用户ID">
|
||||||
|
<a-input-number
|
||||||
|
v-model:value="filterForm.user_id"
|
||||||
|
style="width: 160px"
|
||||||
|
placeholder="请输入用户ID"
|
||||||
|
:min="1"
|
||||||
|
/>
|
||||||
|
</a-form-item>
|
||||||
|
|
||||||
|
<a-form-item>
|
||||||
|
<a-button type="primary" :loading="loading" @click="handleSearch">
|
||||||
|
查询
|
||||||
|
</a-button>
|
||||||
|
<a-button style="margin-left: 8px" @click="handleReset">
|
||||||
|
重置
|
||||||
|
</a-button>
|
||||||
|
</a-form-item>
|
||||||
|
</a-form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a-table
|
||||||
|
:columns="columns"
|
||||||
|
:data-source="tableData"
|
||||||
|
:pagination="pagination"
|
||||||
|
:loading="loading"
|
||||||
|
@change="handleTableChange"
|
||||||
|
row-key="id"
|
||||||
|
:scroll="{ x: 1200 }"
|
||||||
|
>
|
||||||
|
<template #bodyCell="{ column, text, record }">
|
||||||
|
<!-- 时间列 -->
|
||||||
|
<template v-if="column.key === 'create_time'">
|
||||||
|
{{ formatDateTime(text) }}
|
||||||
|
</template>
|
||||||
|
<!-- 状态码列 -->
|
||||||
|
<template v-if="column.key === 'status_code'">
|
||||||
|
<a-tag :color="text >= 400 ? 'red' : (text >= 300 ? 'orange' : 'green')">
|
||||||
|
{{ text }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<!-- 请求方法列 -->
|
||||||
|
<template v-if="column.key === 'method'">
|
||||||
|
<a-tag :color="methodColors[text] || 'default'">
|
||||||
|
{{ text }}
|
||||||
|
</a-tag>
|
||||||
|
</template>
|
||||||
|
<!-- 请求路径列 -->
|
||||||
|
<template v-if="column.key === 'path'">
|
||||||
|
<a-tooltip :title="text">
|
||||||
|
{{ text }}
|
||||||
|
</a-tooltip>
|
||||||
|
</template>
|
||||||
|
</template>
|
||||||
|
</a-table>
|
||||||
|
</div>
|
||||||
|
</page-container>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { defineComponent, ref, onMounted } from 'vue'
|
||||||
|
import { message, DatePicker, Tag, InputNumber, Select } from 'ant-design-vue'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import PageContainer from '@/components/PageContainer.vue'
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export default defineComponent({
|
||||||
|
components: {
|
||||||
|
PageContainer,
|
||||||
|
ATag: Tag,
|
||||||
|
AInputNumber: InputNumber,
|
||||||
|
ASelect: Select,
|
||||||
|
ASelectOption: Select.Option
|
||||||
|
},
|
||||||
|
setup() {
|
||||||
|
const loading = ref(false)
|
||||||
|
const tableData = ref([])
|
||||||
|
|
||||||
|
const filterForm = ref({
|
||||||
|
dateType: '',
|
||||||
|
user_id: undefined,
|
||||||
|
start_time: undefined,
|
||||||
|
end_time: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
const pagination = ref({
|
||||||
|
current: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
total: 0,
|
||||||
|
showSizeChanger: true,
|
||||||
|
showTotal: (total) => `共 ${total} 条记录`
|
||||||
|
})
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'ID',
|
||||||
|
dataIndex: 'id',
|
||||||
|
key: 'id',
|
||||||
|
width: 80,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '用户ID',
|
||||||
|
dataIndex: 'user_id',
|
||||||
|
key: 'user_id',
|
||||||
|
width: 100,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '请求路径',
|
||||||
|
dataIndex: 'path',
|
||||||
|
key: 'path',
|
||||||
|
width: 300,
|
||||||
|
ellipsis: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '请求方法',
|
||||||
|
dataIndex: 'method',
|
||||||
|
key: 'method',
|
||||||
|
width: 100,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '状态码',
|
||||||
|
dataIndex: 'status_code',
|
||||||
|
key: 'status_code',
|
||||||
|
width: 100,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'IP地址',
|
||||||
|
dataIndex: 'ip_address',
|
||||||
|
key: 'ip_address',
|
||||||
|
width: 140,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '响应时间(ms)',
|
||||||
|
dataIndex: 'response_time',
|
||||||
|
key: 'response_time',
|
||||||
|
width: 120,
|
||||||
|
align: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '请求时间',
|
||||||
|
dataIndex: 'create_time',
|
||||||
|
key: 'create_time',
|
||||||
|
width: 180,
|
||||||
|
align: 'center'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const methodColors = {
|
||||||
|
GET: 'blue',
|
||||||
|
POST: 'green',
|
||||||
|
PUT: 'orange',
|
||||||
|
DELETE: 'red'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取日志列表
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true
|
||||||
|
const params = {
|
||||||
|
user_id: filterForm.value.user_id
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filterForm.value.start_time) {
|
||||||
|
params.start_time = filterForm.value.start_time
|
||||||
|
}
|
||||||
|
if (filterForm.value.end_time) {
|
||||||
|
params.end_time = filterForm.value.end_time
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await request.get('/api/logs/request-logs', { params })
|
||||||
|
if (res.code === 200 && res.data?.items) {
|
||||||
|
tableData.value = res.data.items
|
||||||
|
pagination.value.total = res.data.total
|
||||||
|
} else {
|
||||||
|
tableData.value = []
|
||||||
|
pagination.value.total = 0
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取日志列表失败:', error)
|
||||||
|
message.error('获取日志列表失败')
|
||||||
|
tableData.value = []
|
||||||
|
pagination.value.total = 0
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理日期类型变化
|
||||||
|
const handleDateTypeChange = (value) => {
|
||||||
|
const now = dayjs()
|
||||||
|
let start, end
|
||||||
|
|
||||||
|
switch (value) {
|
||||||
|
case 'today':
|
||||||
|
start = now.startOf('day')
|
||||||
|
end = now.endOf('day')
|
||||||
|
break
|
||||||
|
case 'yesterday':
|
||||||
|
start = now.subtract(1, 'day').startOf('day')
|
||||||
|
end = now.subtract(1, 'day').endOf('day')
|
||||||
|
break
|
||||||
|
case 'last7days':
|
||||||
|
start = now.subtract(6, 'day').startOf('day')
|
||||||
|
end = now.endOf('day')
|
||||||
|
break
|
||||||
|
case 'last30days':
|
||||||
|
start = now.subtract(29, 'day').startOf('day')
|
||||||
|
end = now.endOf('day')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
start = undefined
|
||||||
|
end = undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
filterForm.value.start_time = start ? start.format('YYYY-MM-DDTHH:mm:ss') : undefined
|
||||||
|
filterForm.value.end_time = end ? end.format('YYYY-MM-DDTHH:mm:ss') : undefined
|
||||||
|
|
||||||
|
// 自动触发查询
|
||||||
|
handleSearch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询
|
||||||
|
const handleSearch = () => {
|
||||||
|
pagination.value.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置
|
||||||
|
const handleReset = () => {
|
||||||
|
filterForm.value = {
|
||||||
|
dateType: '',
|
||||||
|
user_id: undefined,
|
||||||
|
start_time: undefined,
|
||||||
|
end_time: undefined
|
||||||
|
}
|
||||||
|
pagination.value.current = 1
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
fetchData()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 表格变化处理
|
||||||
|
const handleTableChange = (pag) => {
|
||||||
|
pagination.value.current = pag.current
|
||||||
|
pagination.value.pageSize = pag.pageSize
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 格式化日期时间
|
||||||
|
const formatDateTime = (dateStr) => {
|
||||||
|
if (!dateStr) return ''
|
||||||
|
return dayjs(dateStr).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
columns,
|
||||||
|
tableData,
|
||||||
|
pagination,
|
||||||
|
filterForm,
|
||||||
|
handleDateTypeChange,
|
||||||
|
handleSearch,
|
||||||
|
handleReset,
|
||||||
|
handleTableChange,
|
||||||
|
formatDateTime,
|
||||||
|
methodColors
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.log-list {
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header h1 {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-filter {
|
||||||
|
margin-bottom: 16px;
|
||||||
|
padding: 16px 24px;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-form-item) {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-right: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-cell) {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-table-body) {
|
||||||
|
overflow-x: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.ant-select) {
|
||||||
|
width: 200px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue
Block a user