fix
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
<template>
|
||||
<div class="container">
|
||||
<Breadcrumb :items="['menu.ops.systemSettings', 'menu.ops.systemSettings.systemLogs']" />
|
||||
|
||||
<!-- 使用 SearchTable 公共组件 -->
|
||||
|
||||
<SearchTable
|
||||
:form-model="formModel"
|
||||
:form-items="formItems"
|
||||
@@ -23,24 +22,57 @@
|
||||
@refresh="handleRefresh"
|
||||
@download="handleDownload"
|
||||
>
|
||||
<!-- 表格自定义列:日志级别 -->
|
||||
<template #level="{ record }">
|
||||
<a-tag :color="getLevelColor(record.level)">
|
||||
{{ record.level }}
|
||||
</a-tag>
|
||||
</template>
|
||||
<!-- 表格自定义列:序号 -->
|
||||
<template #index="{ rowIndex }">
|
||||
<template #index="{ rowIndex }">
|
||||
{{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }}
|
||||
</template>
|
||||
|
||||
<!-- 表格自定义列:操作 -->
|
||||
<template #operations="{ record }">
|
||||
<a-button type="text" size="small" @click="handleView(record)">
|
||||
查看
|
||||
</a-button>
|
||||
</template>
|
||||
</SearchTable>
|
||||
|
||||
<a-drawer
|
||||
v-model:visible="detailVisible"
|
||||
:width="480"
|
||||
placement="right"
|
||||
:title="detailRecord ? `日志详情 #${detailRecord.id}` : '日志详情'"
|
||||
:footer="false"
|
||||
unmount-on-close
|
||||
>
|
||||
<template v-if="detailRecord">
|
||||
<a-descriptions :column="1" size="large" bordered>
|
||||
<a-descriptions-item label="日志级别">
|
||||
<a-tag :color="getLevelColor(detailRecord.level)">
|
||||
{{ detailRecord.level }}
|
||||
</a-tag>
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="模块">
|
||||
{{ detailRecord.module }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="操作人">
|
||||
{{ detailRecord.operator }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="IP 地址">
|
||||
{{ detailRecord.ip }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="操作时间">
|
||||
{{ detailRecord.createdAt }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="请求 ID">
|
||||
{{ detailRecord.requestId }}
|
||||
</a-descriptions-item>
|
||||
<a-descriptions-item label="日志内容">
|
||||
<div class="detail-content">{{ detailRecord.content }}</div>
|
||||
</a-descriptions-item>
|
||||
</a-descriptions>
|
||||
</template>
|
||||
</a-drawer>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -50,7 +82,6 @@ import { Message } from '@arco-design/web-vue'
|
||||
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface'
|
||||
import type { FormItem } from '@/components/search-form/types'
|
||||
|
||||
// 定义表格数据类型
|
||||
interface LogRecord {
|
||||
id: number
|
||||
level: string
|
||||
@@ -59,32 +90,42 @@ interface LogRecord {
|
||||
operator: string
|
||||
ip: string
|
||||
createdAt: string
|
||||
/** 用于时间范围筛选(毫秒时间戳) */
|
||||
timestamp: number
|
||||
requestId: string
|
||||
}
|
||||
|
||||
// 模拟数据生成
|
||||
const generateMockData = (count: number): LogRecord[] => {
|
||||
const levels = ['INFO', 'WARN', 'ERROR', 'DEBUG']
|
||||
const modules = ['用户管理', '权限管理', '系统配置', '数据备份', '登录认证']
|
||||
const operators = ['管理员', '张三', '李四', '系统', '定时任务']
|
||||
|
||||
return Array.from({ length: count }, (_, i) => ({
|
||||
id: i + 1,
|
||||
level: levels[i % levels.length],
|
||||
module: modules[i % modules.length],
|
||||
content: `日志内容描述 ${i + 1}`,
|
||||
operator: operators[i % operators.length],
|
||||
ip: `192.168.${Math.floor(i / 255)}.${i % 255}`,
|
||||
createdAt: new Date(Date.now() - i * 3600000).toLocaleString('zh-CN'),
|
||||
}))
|
||||
|
||||
return Array.from({ length: count }, (_, i) => {
|
||||
const timestamp = Date.now() - i * 3600000
|
||||
return {
|
||||
id: i + 1,
|
||||
level: levels[i % levels.length],
|
||||
module: modules[i % modules.length],
|
||||
content: `日志内容描述 ${i + 1}:系统执行例行检查与状态同步。`,
|
||||
operator: operators[i % operators.length],
|
||||
ip: `192.168.${Math.floor(i / 255) % 256}.${i % 256}`,
|
||||
createdAt: new Date(timestamp).toLocaleString('zh-CN'),
|
||||
timestamp,
|
||||
requestId: `req-${10000 + i}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 状态管理
|
||||
const loading = ref(false)
|
||||
const tableData = ref<LogRecord[]>([])
|
||||
const allFilteredData = ref<LogRecord[]>([])
|
||||
|
||||
const formModel = ref({
|
||||
level: '',
|
||||
module: '',
|
||||
operator: '',
|
||||
keyword: '',
|
||||
dateRange: [] as unknown[],
|
||||
})
|
||||
|
||||
const pagination = reactive({
|
||||
@@ -93,7 +134,9 @@ const pagination = reactive({
|
||||
total: 0,
|
||||
})
|
||||
|
||||
// 表单项配置
|
||||
const detailVisible = ref(false)
|
||||
const detailRecord = ref<LogRecord | null>(null)
|
||||
|
||||
const formItems = computed<FormItem[]>(() => [
|
||||
{
|
||||
field: 'level',
|
||||
@@ -126,9 +169,21 @@ const formItems = computed<FormItem[]>(() => [
|
||||
type: 'input',
|
||||
placeholder: '请输入操作人',
|
||||
},
|
||||
{
|
||||
field: 'keyword',
|
||||
label: '关键词',
|
||||
type: 'input',
|
||||
placeholder: '搜索日志内容',
|
||||
},
|
||||
{
|
||||
field: 'dateRange',
|
||||
label: '时间范围',
|
||||
type: 'dateRange',
|
||||
placeholder: '选择时间范围',
|
||||
span: 16,
|
||||
},
|
||||
])
|
||||
|
||||
// 表格列配置
|
||||
const columns = computed<TableColumnData[]>(() => [
|
||||
{
|
||||
title: '序号',
|
||||
@@ -177,7 +232,6 @@ const columns = computed<TableColumnData[]>(() => [
|
||||
},
|
||||
])
|
||||
|
||||
// 获取日志级别颜色
|
||||
const getLevelColor = (level: string) => {
|
||||
const colorMap: Record<string, string> = {
|
||||
INFO: 'arcoblue',
|
||||
@@ -188,38 +242,54 @@ const getLevelColor = (level: string) => {
|
||||
return colorMap[level] || 'gray'
|
||||
}
|
||||
|
||||
// 模拟异步获取数据
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
|
||||
// 模拟网络延迟
|
||||
await new Promise(resolve => setTimeout(resolve, 500))
|
||||
|
||||
let data = generateMockData(100)
|
||||
|
||||
// 根据搜索条件过滤
|
||||
if (formModel.value.level) {
|
||||
data = data.filter(item => item.level === formModel.value.level)
|
||||
function applyFilters(source: LogRecord[]): LogRecord[] {
|
||||
let data = source
|
||||
const f = formModel.value
|
||||
|
||||
if (f.level) {
|
||||
data = data.filter(item => item.level === f.level)
|
||||
}
|
||||
if (formModel.value.module) {
|
||||
data = data.filter(item => item.module === formModel.value.module)
|
||||
if (f.module) {
|
||||
data = data.filter(item => item.module === f.module)
|
||||
}
|
||||
if (formModel.value.operator) {
|
||||
data = data.filter(item => item.operator.includes(formModel.value.operator))
|
||||
if (f.operator) {
|
||||
data = data.filter(item => item.operator.includes(f.operator))
|
||||
}
|
||||
|
||||
// 更新分页
|
||||
pagination.total = data.length
|
||||
|
||||
// 分页截取
|
||||
if (f.keyword?.trim()) {
|
||||
const kw = f.keyword.trim()
|
||||
data = data.filter(item => item.content.includes(kw))
|
||||
}
|
||||
if (f.dateRange && f.dateRange.length === 2) {
|
||||
const [start, end] = f.dateRange
|
||||
const startMs = new Date(start as string | Date).getTime()
|
||||
const endMs = new Date(end as string | Date).getTime()
|
||||
if (!Number.isNaN(startMs) && !Number.isNaN(endMs)) {
|
||||
data = data.filter(item => item.timestamp >= startMs && item.timestamp <= endMs)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
function slicePage(data: LogRecord[]) {
|
||||
const start = (pagination.current - 1) * pagination.pageSize
|
||||
const end = start + pagination.pageSize
|
||||
tableData.value = data.slice(start, end)
|
||||
|
||||
}
|
||||
|
||||
const fetchData = async () => {
|
||||
loading.value = true
|
||||
await new Promise(resolve => setTimeout(resolve, 400))
|
||||
|
||||
const base = generateMockData(100)
|
||||
const filtered = applyFilters(base)
|
||||
allFilteredData.value = filtered
|
||||
pagination.total = filtered.length
|
||||
slicePage(filtered)
|
||||
|
||||
loading.value = false
|
||||
}
|
||||
|
||||
// 事件处理
|
||||
const handleSearch = () => {
|
||||
pagination.current = 1
|
||||
fetchData()
|
||||
@@ -230,6 +300,8 @@ const handleReset = () => {
|
||||
level: '',
|
||||
module: '',
|
||||
operator: '',
|
||||
keyword: '',
|
||||
dateRange: [],
|
||||
}
|
||||
pagination.current = 1
|
||||
fetchData()
|
||||
@@ -237,7 +309,7 @@ const handleReset = () => {
|
||||
|
||||
const handlePageChange = (current: number) => {
|
||||
pagination.current = current
|
||||
fetchData()
|
||||
slicePage(allFilteredData.value)
|
||||
}
|
||||
|
||||
const handleRefresh = () => {
|
||||
@@ -250,10 +322,10 @@ const handleDownload = () => {
|
||||
}
|
||||
|
||||
const handleView = (record: LogRecord) => {
|
||||
Message.info(`查看日志详情:${record.id}`)
|
||||
detailRecord.value = record
|
||||
detailVisible.value = true
|
||||
}
|
||||
|
||||
// 初始化加载数据
|
||||
fetchData()
|
||||
</script>
|
||||
|
||||
@@ -267,4 +339,11 @@ export default {
|
||||
.container {
|
||||
padding: 0 20px 20px 20px;
|
||||
}
|
||||
|
||||
.detail-content {
|
||||
white-space: pre-wrap;
|
||||
word-break: break-word;
|
||||
line-height: 1.6;
|
||||
color: var(--color-text-1);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user