201 lines
5.2 KiB
Vue
201 lines
5.2 KiB
Vue
<script setup lang="ts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { Table, Button, Space, Input, Select, DatePicker, Tag, message } from 'ant-design-vue'
|
|
import { SearchOutlined, ReloadOutlined } from '@ant-design/icons-vue'
|
|
import dayjs from 'dayjs'
|
|
|
|
// 审计日志类型
|
|
interface AuditLog {
|
|
id: string
|
|
time: string
|
|
operator: string
|
|
type: 'PERMISSION' | 'ROLE' | 'PROJECT'
|
|
content: string
|
|
target: string
|
|
ip: string
|
|
}
|
|
|
|
// 表格列定义
|
|
const columns = [
|
|
{ title: '时间', dataIndex: 'time', key: 'time', width: 180 },
|
|
{ title: '操作用户', dataIndex: 'operator', key: 'operator', width: 120 },
|
|
{ title: '操作类型', dataIndex: 'type', key: 'type', width: 100 },
|
|
{ title: '操作内容', dataIndex: 'content', key: 'content', ellipsis: true },
|
|
{ title: '目标对象', dataIndex: 'target', key: 'target', width: 150 },
|
|
{ title: 'IP地址', dataIndex: 'ip', key: 'ip', width: 140 }
|
|
]
|
|
|
|
// 数据
|
|
const logs = ref<AuditLog[]>([])
|
|
const loading = ref(false)
|
|
|
|
// 筛选
|
|
const filters = ref({
|
|
type: undefined as string | undefined,
|
|
dateRange: [] as [dayjs.Dayjs, dayjs.Dayjs] | null,
|
|
operator: ''
|
|
})
|
|
|
|
// 操作类型选项
|
|
const typeOptions = [
|
|
{ value: 'PERMISSION', label: '权限变更' },
|
|
{ value: 'ROLE', label: '角色分配' },
|
|
{ value: 'PROJECT', label: '项目参与' }
|
|
]
|
|
|
|
// 模拟数据
|
|
const mockLogs: AuditLog[] = [
|
|
{
|
|
id: '1',
|
|
time: '2026-03-21 10:30:25',
|
|
operator: 'admin',
|
|
type: 'PERMISSION',
|
|
content: '修改用户「张三」的项目权限,添加「数据导出」权限',
|
|
target: '用户:张三',
|
|
ip: '192.168.1.100'
|
|
},
|
|
{
|
|
id: '2',
|
|
time: '2026-03-21 09:15:42',
|
|
operator: 'admin',
|
|
type: 'ROLE',
|
|
content: '为用户「李四」分配「项目经理」角色',
|
|
target: '用户:李四',
|
|
ip: '192.168.1.100'
|
|
},
|
|
{
|
|
id: '3',
|
|
time: '2026-03-20 16:45:33',
|
|
operator: 'manager',
|
|
type: 'PROJECT',
|
|
content: '将「王五」从「智慧社区项目」中移除',
|
|
target: '智慧社区项目',
|
|
ip: '192.168.1.105'
|
|
},
|
|
{
|
|
id: '4',
|
|
time: '2026-03-20 14:20:18',
|
|
operator: 'admin',
|
|
type: 'PERMISSION',
|
|
content: '撤销用户「赵六」的「系统管理」权限',
|
|
target: '用户:赵六',
|
|
ip: '192.168.1.100'
|
|
},
|
|
{
|
|
id: '5',
|
|
time: '2026-03-19 11:05:56',
|
|
operator: 'manager',
|
|
type: 'ROLE',
|
|
content: '更新角色「审计员」的权限配置',
|
|
target: '角色:审计员',
|
|
ip: '192.168.1.105'
|
|
}
|
|
]
|
|
|
|
// 获取操作类型标签
|
|
const getTypeColor = (type: string) => {
|
|
const map: Record<string, string> = {
|
|
PERMISSION: 'blue',
|
|
ROLE: 'green',
|
|
PROJECT: 'orange'
|
|
}
|
|
return map[type] || 'default'
|
|
}
|
|
|
|
const getTypeLabel = (type: string) => {
|
|
const map: Record<string, string> = {
|
|
PERMISSION: '权限变更',
|
|
ROLE: '角色分配',
|
|
PROJECT: '项目参与'
|
|
}
|
|
return map[type] || type
|
|
}
|
|
|
|
// 加载数据
|
|
const loadData = () => {
|
|
loading.value = true
|
|
// 模拟API延迟
|
|
setTimeout(() => {
|
|
logs.value = mockLogs.filter((log) => {
|
|
// 按类型筛选
|
|
if (filters.value.type && log.type !== filters.value.type) return false
|
|
// 按用户筛选
|
|
if (filters.value.operator && !log.operator.includes(filters.value.operator)) return false
|
|
// 按日期范围筛选
|
|
if (filters.value.dateRange && filters.value.dateRange.length === 2) {
|
|
const logDate = dayjs(log.time).startOf('day')
|
|
const [start, end] = filters.value.dateRange
|
|
if (logDate.isBefore(start, 'day') || logDate.isAfter(end, 'day')) return false
|
|
}
|
|
return true
|
|
})
|
|
loading.value = false
|
|
}, 300)
|
|
}
|
|
|
|
// 重置
|
|
const handleReset = () => {
|
|
filters.value = {
|
|
type: undefined,
|
|
dateRange: null,
|
|
operator: ''
|
|
}
|
|
loadData()
|
|
}
|
|
|
|
onMounted(loadData)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="page-container">
|
|
<!-- 页面标题 -->
|
|
<div class="page-header">
|
|
<h2 class="page-title">操作审计日志</h2>
|
|
</div>
|
|
|
|
<!-- 筛选区 -->
|
|
<div class="filter-bar">
|
|
<Space wrap>
|
|
<Select
|
|
v-model:value="filters.type"
|
|
placeholder="操作类型"
|
|
:options="typeOptions"
|
|
allow-clear
|
|
style="width: 140px"
|
|
/>
|
|
<DatePicker.RangePicker v-model:value="filters.dateRange" style="width: 260px" />
|
|
<Input
|
|
v-model:value="filters.operator"
|
|
placeholder="操作用户"
|
|
style="width: 140px"
|
|
/>
|
|
<Button type="primary" @click="loadData">
|
|
<SearchOutlined /> 查询
|
|
</Button>
|
|
<Button @click="handleReset">
|
|
<ReloadOutlined /> 重置
|
|
</Button>
|
|
</Space>
|
|
</div>
|
|
|
|
<!-- 表格 -->
|
|
<div class="table-card">
|
|
<Table
|
|
:columns="columns"
|
|
:data-source="logs"
|
|
:loading="loading"
|
|
:row-key="(record: AuditLog) => record.id"
|
|
:pagination="{ pageSize: 10, showSizeChanger: true, showTotal: (total: number) => `共 ${total} 条` }"
|
|
>
|
|
<template #bodyCell="{ column, record }">
|
|
<template v-if="column.key === 'type'">
|
|
<Tag :color="getTypeColor(record.type)">
|
|
{{ getTypeLabel(record.type) }}
|
|
</Tag>
|
|
</template>
|
|
</template>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
</template>
|